Make ssl_parse_extensions a little easier to use.

std::initializer_list appears to work by instantiating a T[N] at the
call site (which is what we were doing anyway), so I don't believe there
is a runtime dependency.

This also adds a way for individual entries to turn themselves off,
which means we don't need to manually check for some unsolicited
extensions.

Change-Id: I40f79b6a0e9c005fc621f4a798fe201bfbf08411
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/48910
Commit-Queue: David Benjamin <davidben@google.com>
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/ssl/tls13_client.cc b/ssl/tls13_client.cc
index 7a19b2a..bd7e63f 100644
--- a/ssl/tls13_client.cc
+++ b/ssl/tls13_client.cc
@@ -162,31 +162,25 @@
     return ssl_hs_ok;
   }
 
-  bool have_cookie, have_key_share, have_supported_versions;
-  CBS cookie, key_share, supported_versions;
-  SSL_EXTENSION_TYPE ext_types[] = {
-      {TLSEXT_TYPE_key_share, &have_key_share, &key_share},
-      {TLSEXT_TYPE_cookie, &have_cookie, &cookie},
-      {TLSEXT_TYPE_supported_versions, &have_supported_versions,
-       &supported_versions},
-  };
-
-  if (!ssl_parse_extensions(&server_hello.extensions, &alert, ext_types,
+  SSLExtension cookie(TLSEXT_TYPE_cookie), key_share(TLSEXT_TYPE_key_share),
+      supported_versions(TLSEXT_TYPE_supported_versions);
+  if (!ssl_parse_extensions(&server_hello.extensions, &alert,
+                            {&cookie, &key_share, &supported_versions},
                             /*ignore_unknown=*/false)) {
     ssl_send_alert(ssl, SSL3_AL_FATAL, alert);
     return ssl_hs_error;
   }
 
-  if (!have_cookie && !have_key_share) {
+  if (!cookie.present && !key_share.present) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_EMPTY_HELLO_RETRY_REQUEST);
     ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
     return ssl_hs_error;
   }
-  if (have_cookie) {
+  if (cookie.present) {
     CBS cookie_value;
-    if (!CBS_get_u16_length_prefixed(&cookie, &cookie_value) ||
+    if (!CBS_get_u16_length_prefixed(&cookie.data, &cookie_value) ||
         CBS_len(&cookie_value) == 0 ||
-        CBS_len(&cookie) != 0) {
+        CBS_len(&cookie.data) != 0) {
       OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
       ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
       return ssl_hs_error;
@@ -197,9 +191,10 @@
     }
   }
 
-  if (have_key_share) {
+  if (key_share.present) {
     uint16_t group_id;
-    if (!CBS_get_u16(&key_share, &group_id) || CBS_len(&key_share) != 0) {
+    if (!CBS_get_u16(&key_share.data, &group_id) ||
+        CBS_len(&key_share.data) != 0) {
       OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
       ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
       return ssl_hs_error;
@@ -316,18 +311,11 @@
   OPENSSL_memcpy(ssl->s3->server_random, CBS_data(&server_hello.random),
                  SSL3_RANDOM_SIZE);
 
-  // Parse out the extensions.
-  bool have_key_share = false, have_pre_shared_key = false,
-       have_supported_versions = false;
-  CBS key_share, pre_shared_key, supported_versions;
-  SSL_EXTENSION_TYPE ext_types[] = {
-      {TLSEXT_TYPE_key_share, &have_key_share, &key_share},
-      {TLSEXT_TYPE_pre_shared_key, &have_pre_shared_key, &pre_shared_key},
-      {TLSEXT_TYPE_supported_versions, &have_supported_versions,
-       &supported_versions},
-  };
-
-  if (!ssl_parse_extensions(&server_hello.extensions, &alert, ext_types,
+  SSLExtension key_share(TLSEXT_TYPE_key_share),
+      pre_shared_key(TLSEXT_TYPE_pre_shared_key, ssl->session != nullptr),
+      supported_versions(TLSEXT_TYPE_supported_versions);
+  if (!ssl_parse_extensions(&server_hello.extensions, &alert,
+                            {&key_share, &pre_shared_key, &supported_versions},
                             /*ignore_unknown=*/false)) {
     ssl_send_alert(ssl, SSL3_AL_FATAL, alert);
     return ssl_hs_error;
@@ -335,8 +323,9 @@
 
   // Recheck supported_versions, in case this is after HelloRetryRequest.
   uint16_t version;
-  if (!have_supported_versions ||
-      !CBS_get_u16(&supported_versions, &version) ||
+  if (!supported_versions.present ||
+      !CBS_get_u16(&supported_versions.data, &version) ||
+      CBS_len(&supported_versions.data) != 0 ||
       version != ssl->version) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_SECOND_SERVERHELLO_VERSION_MISMATCH);
     ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
@@ -344,15 +333,9 @@
   }
 
   alert = SSL_AD_DECODE_ERROR;
-  if (have_pre_shared_key) {
-    if (ssl->session == NULL) {
-      OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION);
-      ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNSUPPORTED_EXTENSION);
-      return ssl_hs_error;
-    }
-
+  if (pre_shared_key.present) {
     if (!ssl_ext_pre_shared_key_parse_serverhello(hs, &alert,
-                                                  &pre_shared_key)) {
+                                                  &pre_shared_key.data)) {
       ssl_send_alert(ssl, SSL3_AL_FATAL, alert);
       return ssl_hs_error;
     }
@@ -409,7 +392,7 @@
     return ssl_hs_error;
   }
 
-  if (!have_key_share) {
+  if (!key_share.present) {
     // We do not support psk_ke and thus always require a key share.
     OPENSSL_PUT_ERROR(SSL, SSL_R_MISSING_KEY_SHARE);
     ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_MISSING_EXTENSION);
@@ -420,7 +403,7 @@
   Array<uint8_t> dhe_secret;
   alert = SSL_AD_DECODE_ERROR;
   if (!ssl_ext_key_share_parse_serverhello(hs, &dhe_secret, &alert,
-                                           &key_share)) {
+                                           &key_share.data)) {
     ssl_send_alert(ssl, SSL3_AL_FATAL, alert);
     return ssl_hs_error;
   }
@@ -456,7 +439,7 @@
                      SSL3_RANDOM_SIZE);
     } else {
       // Resuming against the ClientHelloOuter was an unsolicited extension.
-      if (have_pre_shared_key) {
+      if (pre_shared_key.present) {
         OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION);
         ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNSUPPORTED_EXTENSION);
         return ssl_hs_error;
@@ -600,25 +583,19 @@
   }
 
 
-  bool have_sigalgs = false, have_ca = false;
-  CBS sigalgs, ca;
-  const SSL_EXTENSION_TYPE ext_types[] = {
-    {TLSEXT_TYPE_signature_algorithms, &have_sigalgs, &sigalgs},
-    {TLSEXT_TYPE_certificate_authorities, &have_ca, &ca},
-  };
-
+  SSLExtension sigalgs(TLSEXT_TYPE_signature_algorithms),
+      ca(TLSEXT_TYPE_certificate_authorities);
   CBS body = msg.body, context, extensions, supported_signature_algorithms;
   uint8_t alert = SSL_AD_DECODE_ERROR;
   if (!CBS_get_u8_length_prefixed(&body, &context) ||
       // The request context is always empty during the handshake.
       CBS_len(&context) != 0 ||
-      !CBS_get_u16_length_prefixed(&body, &extensions) ||
+      !CBS_get_u16_length_prefixed(&body, &extensions) ||  //
       CBS_len(&body) != 0 ||
-      !ssl_parse_extensions(&extensions, &alert, ext_types,
+      !ssl_parse_extensions(&extensions, &alert, {&sigalgs, &ca},
                             /*ignore_unknown=*/true) ||
-      (have_ca && CBS_len(&ca) == 0) ||
-      !have_sigalgs ||
-      !CBS_get_u16_length_prefixed(&sigalgs,
+      !sigalgs.present ||
+      !CBS_get_u16_length_prefixed(&sigalgs.data,
                                    &supported_signature_algorithms) ||
       !tls1_parse_peer_sigalgs(hs, &supported_signature_algorithms)) {
     ssl_send_alert(ssl, SSL3_AL_FATAL, alert);
@@ -626,8 +603,8 @@
     return ssl_hs_error;
   }
 
-  if (have_ca) {
-    hs->ca_names = ssl_parse_client_CA_list(ssl, &alert, &ca);
+  if (ca.present) {
+    hs->ca_names = ssl_parse_client_CA_list(ssl, &alert, &ca.data);
     if (!hs->ca_names) {
       ssl_send_alert(ssl, SSL3_AL_FATAL, alert);
       return ssl_hs_error;
@@ -1050,23 +1027,17 @@
     return nullptr;
   }
 
-  // Parse out the extensions.
-  bool have_early_data = false;
-  CBS early_data;
-  const SSL_EXTENSION_TYPE ext_types[] = {
-      {TLSEXT_TYPE_early_data, &have_early_data, &early_data},
-  };
-
+  SSLExtension early_data(TLSEXT_TYPE_early_data);
   uint8_t alert = SSL_AD_DECODE_ERROR;
-  if (!ssl_parse_extensions(&extensions, &alert, ext_types,
+  if (!ssl_parse_extensions(&extensions, &alert, {&early_data},
                             /*ignore_unknown=*/true)) {
     ssl_send_alert(ssl, SSL3_AL_FATAL, alert);
     return nullptr;
   }
 
-  if (have_early_data) {
-    if (!CBS_get_u32(&early_data, &session->ticket_max_early_data) ||
-        CBS_len(&early_data) != 0) {
+  if (early_data.present) {
+    if (!CBS_get_u32(&early_data.data, &session->ticket_max_early_data) ||
+        CBS_len(&early_data.data) != 0) {
       ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
       OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
       return nullptr;