CertificateStatus is optional.

Because RFC 6066 is obnoxious like that and IIS servers actually do this
when OCSP-stapling is configured, but the OCSP server cannot be reached.

BUG=478947

Change-Id: I3d34c1497e0b6b02d706278dcea5ceb684ff60ae
Reviewed-on: https://boringssl-review.googlesource.com/4461
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c
index 00f15cc..dda637d 100644
--- a/ssl/s3_clnt.c
+++ b/ssl/s3_clnt.c
@@ -1575,12 +1575,19 @@
 
   n = s->method->ssl_get_message(
       s, SSL3_ST_CR_CERT_STATUS_A, SSL3_ST_CR_CERT_STATUS_B,
-      SSL3_MT_CERTIFICATE_STATUS, 16384, ssl_hash_message, &ok);
+      -1, 16384, ssl_hash_message, &ok);
 
   if (!ok) {
     return n;
   }
 
+  if (s->s3->tmp.message_type != SSL3_MT_CERTIFICATE_STATUS) {
+    /* A server may send status_request in ServerHello and then change
+     * its mind about sending CertificateStatus. */
+    s->s3->tmp.reuse_message = 1;
+    return 1;
+  }
+
   CBS_init(&certificate_status, s->init_msg, n);
   if (!CBS_get_u8(&certificate_status, &status_type) ||
       status_type != TLSEXT_STATUSTYPE_ocsp ||
diff --git a/ssl/test/runner/common.go b/ssl/test/runner/common.go
index abed611..75fa4b4 100644
--- a/ssl/test/runner/common.go
+++ b/ssl/test/runner/common.go
@@ -434,6 +434,11 @@
 	// HelloVerifyRequest message.
 	SkipHelloVerifyRequest bool
 
+	// SkipCertificateStatus, if true, causes the server to skip the
+	// CertificateStatus message. This is legal because CertificateStatus is
+	// optional, even with a status_request in ServerHello.
+	SkipCertificateStatus bool
+
 	// SkipServerKeyExchange causes the server to skip sending
 	// ServerKeyExchange messages.
 	SkipServerKeyExchange bool
diff --git a/ssl/test/runner/handshake_server.go b/ssl/test/runner/handshake_server.go
index e18cf22..59ed9df 100644
--- a/ssl/test/runner/handshake_server.go
+++ b/ssl/test/runner/handshake_server.go
@@ -521,7 +521,7 @@
 		}
 	}
 
-	if hs.hello.ocspStapling {
+	if hs.hello.ocspStapling && !c.config.Bugs.SkipCertificateStatus {
 		certStatus := new(certificateStatusMsg)
 		certStatus.statusType = statusTypeOCSP
 		certStatus.response = hs.cert.OCSPStaple
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go
index 8178def..57aee74 100644
--- a/ssl/test/runner/runner.go
+++ b/ssl/test/runner/runner.go
@@ -301,6 +301,18 @@
 		expectedError: ":UNEXPECTED_MESSAGE:",
 	},
 	{
+		name: "SkipCertificateStatus",
+		config: Config{
+			CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+			Bugs: ProtocolBugs{
+				SkipCertificateStatus: true,
+			},
+		},
+		flags: []string{
+			"-enable-ocsp-stapling",
+		},
+	},
+	{
 		name: "SkipServerKeyExchange",
 		config: Config{
 			CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},