Tidy up extensions stuff and drop fastradio support.

Fastradio was a trick where the ClientHello was padding to at least 1024
bytes in order to trick some mobile radios into entering high-power mode
immediately. After experimentation, the feature is being dropped.

This change also tidies up a bit of the extensions code now that
everything is using the new system.

Change-Id: Icf7892e0ac1fbe5d66a5d7b405ec455c6850a41c
Reviewed-on: https://boringssl-review.googlesource.com/5466
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/crypto/err/ssl.errordata b/crypto/err/ssl.errordata
index 690ea2b..4fc89d4 100644
--- a/crypto/err/ssl.errordata
+++ b/crypto/err/ssl.errordata
@@ -50,7 +50,9 @@
 SSL,148,EMPTY_SRTP_PROTECTION_PROFILE_LIST
 SSL,276,EMS_STATE_INCONSISTENT
 SSL,149,ENCRYPTED_LENGTH_TOO_LONG
+SSL,281,ERROR_ADDING_EXTENSION
 SSL,150,ERROR_IN_RECEIVED_CIPHER_LIST
+SSL,282,ERROR_PARSING_EXTENSION
 SSL,151,EVP_DIGESTSIGNFINAL_FAILED
 SSL,152,EVP_DIGESTSIGNINIT_FAILED
 SSL,153,EXCESSIVE_MESSAGE_SIZE
@@ -73,6 +75,7 @@
 SSL,169,LIBRARY_HAS_NO_CIPHERS
 SSL,170,MISSING_DH_KEY
 SSL,171,MISSING_ECDSA_SIGNING_CERT
+SSL,283,MISSING_EXTENSION
 SSL,172,MISSING_RSA_CERTIFICATE
 SSL,173,MISSING_RSA_ENCRYPTING_CERT
 SSL,174,MISSING_RSA_SIGNING_CERT
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index ebede0b..656a901 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -1496,11 +1496,6 @@
 OPENSSL_EXPORT void SSL_get0_alpn_selected(const SSL *ssl, const uint8_t **data,
                                            unsigned *len);
 
-/* SSL_enable_fastradio_padding controls whether fastradio padding is enabled
- * on |ssl|. If it is, ClientHello messages are padded to 1024 bytes. This
- * causes 3G radios to switch to DCH mode (high data rate). */
-OPENSSL_EXPORT void SSL_enable_fastradio_padding(SSL *ssl, char on_off);
-
 /* SSL_set_reject_peer_renegotiations controls whether renegotiation attempts by
  * the peer are rejected. It may be set at any point in a connection's lifetime
  * to control future renegotiations programmatically. By default, renegotiations
@@ -1743,11 +1738,6 @@
   uint8_t *alpn_client_proto_list;
   unsigned alpn_client_proto_list_len;
 
-  /* fastradio_padding, if true, causes ClientHellos to be padded to 1024
-   * bytes. This ensures that the cellular radio is fast forwarded to DCH (high
-   * data rate) state in 3G networks. */
-  char fastradio_padding;
-
   /* accept_peer_renegotiations, if one, accepts renegotiation attempts from the
    * peer. Otherwise, they will be rejected with a fatal error. */
   char accept_peer_renegotiations;
@@ -2952,6 +2942,9 @@
 #define SSL_R_TOO_MANY_WARNING_ALERTS 278
 #define SSL_R_UNEXPECTED_EXTENSION 279
 #define SSL_R_SIGNATURE_ALGORITHMS_EXTENSION_SENT_BY_SERVER 280
+#define SSL_R_ERROR_ADDING_EXTENSION 281
+#define SSL_R_ERROR_PARSING_EXTENSION 282
+#define SSL_R_MISSING_EXTENSION 283
 #define SSL_R_SSLV3_ALERT_CLOSE_NOTIFY 1000
 #define SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE 1010
 #define SSL_R_SSLV3_ALERT_BAD_RECORD_MAC 1020
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index a7e3b9c..61f0626 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -2824,10 +2824,6 @@
   ctx->dos_protection_cb = cb;
 }
 
-void SSL_enable_fastradio_padding(SSL *s, char on_off) {
-  s->fastradio_padding = on_off;
-}
-
 void SSL_set_reject_peer_renegotiations(SSL *s, int reject) {
   s->accept_peer_renegotiations = !reject;
 }
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index 70743df..56df2af 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -2241,19 +2241,16 @@
  * is to be done. */
 uint8_t *ssl_add_clienthello_tlsext(SSL *s, uint8_t *const buf,
                                     uint8_t *const limit, size_t header_len) {
-  int extdatalen = 0;
-  uint8_t *ret = buf;
-  uint8_t *orig = buf;
-
   /* don't add extensions for SSLv3 unless doing secure renegotiation */
   if (s->client_version == SSL3_VERSION && !s->s3->send_connection_binding) {
-    return orig;
+    return buf;
   }
 
-  ret += 2;
-
-  if (ret >= limit) {
-    return NULL; /* should never occur. */
+  CBB cbb, extensions;
+  CBB_zero(&cbb);
+  if (!CBB_init_fixed(&cbb, buf, limit - buf) ||
+      !CBB_add_u16_length_prefixed(&cbb, &extensions)) {
+    goto err;
   }
 
   s->s3->tmp.extensions.sent = 0;
@@ -2265,32 +2262,22 @@
     }
   }
 
-  CBB cbb;
-  if (!CBB_init_fixed(&cbb, ret, limit - ret)) {
-    OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
-    return NULL;
-  }
-
   for (i = 0; i < kNumExtensions; i++) {
-    const size_t len_before = CBB_len(&cbb);
-    if (!kExtensions[i].add_clienthello(s, &cbb)) {
-      CBB_cleanup(&cbb);
-      OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
-      return NULL;
+    const size_t len_before = CBB_len(&extensions);
+    if (!kExtensions[i].add_clienthello(s, &extensions)) {
+      OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_ADDING_EXTENSION);
+      ERR_add_error_dataf("extension: %u", (unsigned)kExtensions[i].value);
+      goto err;
     }
-    const size_t len_after = CBB_len(&cbb);
 
-    if (len_after != len_before) {
+    if (CBB_len(&extensions) != len_before) {
       s->s3->tmp.extensions.sent |= (1u << i);
     }
   }
 
-  ret += CBB_len(&cbb);
-  CBB_cleanup(&cbb);
-
   if (header_len > 0) {
     size_t clienthello_minsize = 0;
-    header_len += ret - orig;
+    header_len += CBB_len(&extensions);
     if (header_len > 0xff && header_len < 0x200) {
       /* Add padding to workaround bugs in F5 terminators. See
        * https://tools.ietf.org/html/draft-agl-tls-padding-03
@@ -2299,15 +2286,6 @@
        * it MUST always appear last. */
       clienthello_minsize = 0x200;
     }
-    if (s->fastradio_padding) {
-      /* Pad the ClientHello record to 1024 bytes to fast forward the radio
-       * into DCH (high data rate) state in 3G networks. Note that when
-       * fastradio_padding is enabled, even if the header_len is less than 255
-       * bytes, the padding will be applied regardless. This is slightly
-       * different from the TLS padding extension suggested in
-       * https://tools.ietf.org/html/draft-agl-tls-padding-03 */
-      clienthello_minsize = 0x400;
-    }
     if (header_len < clienthello_minsize) {
       size_t padding_len = clienthello_minsize - header_len;
       /* Extensions take at least four bytes to encode. Always include least
@@ -2319,46 +2297,51 @@
         padding_len = 1;
       }
 
-      if (limit - ret - 4 - (long)padding_len < 0) {
-        return NULL;
+      uint8_t *padding_bytes;
+      if (!CBB_add_u16(&extensions, TLSEXT_TYPE_padding) ||
+          !CBB_add_u16(&extensions, padding_len) ||
+          !CBB_add_space(&extensions, &padding_bytes, padding_len)) {
+        goto err;
       }
 
-      s2n(TLSEXT_TYPE_padding, ret);
-      s2n(padding_len, ret);
-      memset(ret, 0, padding_len);
-      ret += padding_len;
+      memset(padding_bytes, 0, padding_len);
     }
   }
 
-  extdatalen = ret - orig - 2;
-  if (extdatalen == 0) {
-    return orig;
+  if (!CBB_flush(&cbb)) {
+    goto err;
   }
 
-  s2n(extdatalen, orig);
+  uint8_t *ret = buf;
+  const size_t cbb_len = CBB_len(&cbb);
+  /* If only two bytes have been written then the extensions are actually empty
+   * and those two bytes are the zero length. In that case, we don't bother
+   * sending the extensions length. */
+  if (cbb_len > 2) {
+    ret += cbb_len;
+  }
+
+  CBB_cleanup(&cbb);
   return ret;
+
+err:
+  CBB_cleanup(&cbb);
+  OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+  return NULL;
 }
 
 uint8_t *ssl_add_serverhello_tlsext(SSL *s, uint8_t *const buf,
                                     uint8_t *const limit) {
-  int extdatalen = 0;
-  uint8_t *orig = buf;
-  uint8_t *ret = buf;
-
   /* don't add extensions for SSLv3, unless doing secure renegotiation */
   if (s->version == SSL3_VERSION && !s->s3->send_connection_binding) {
-    return orig;
+    return buf;
   }
 
-  ret += 2;
-  if (ret >= limit) {
-    return NULL; /* should never happen. */
-  }
-
-  CBB cbb;
-  if (!CBB_init_fixed(&cbb, ret, limit - ret)) {
-    OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
-    return NULL;
+  CBB cbb, extensions;
+  CBB_zero(&cbb);
+  if (!CBB_init_fixed(&cbb, buf, limit - buf) ||
+      !CBB_add_u16_length_prefixed(&cbb, &extensions)) {
+    goto err;
   }
 
   unsigned i;
@@ -2368,28 +2351,36 @@
       continue;
     }
 
-    if (!kExtensions[i].add_serverhello(s, &cbb)) {
-      CBB_cleanup(&cbb);
-      OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
-      return NULL;
+    if (!kExtensions[i].add_serverhello(s, &extensions)) {
+      OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_ADDING_EXTENSION);
+      ERR_add_error_dataf("extension: %u", (unsigned)kExtensions[i].value);
+      goto err;
     }
   }
 
-  ret += CBB_len(&cbb);
-  CBB_cleanup(&cbb);
-
-  extdatalen = ret - orig - 2;
-  if (extdatalen == 0) {
-    return orig;
+  if (!CBB_flush(&cbb)) {
+    goto err;
   }
 
-  s2n(extdatalen, orig);
+  uint8_t *ret = buf;
+  const size_t cbb_len = CBB_len(&cbb);
+  /* If only two bytes have been written then the extensions are actually empty
+   * and those two bytes are the zero length. In that case, we don't bother
+   * sending the extensions length. */
+  if (cbb_len > 2) {
+    ret += cbb_len;
+  }
+
+  CBB_cleanup(&cbb);
   return ret;
+
+err:
+  CBB_cleanup(&cbb);
+  OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+  return NULL;
 }
 
 static int ssl_scan_clienthello_tlsext(SSL *s, CBS *cbs, int *out_alert) {
-  CBS extensions;
-
   size_t i;
   for (i = 0; i < kNumExtensions; i++) {
     if (kExtensions[i].init != NULL) {
@@ -2404,51 +2395,53 @@
   assert(kExtensions[0].value == TLSEXT_TYPE_renegotiate);
 
   /* There may be no extensions. */
-  if (CBS_len(cbs) == 0) {
-    goto no_extensions;
-  }
-
-  /* Decode the extensions block and check it is valid. */
-  if (!CBS_get_u16_length_prefixed(cbs, &extensions) ||
-      !tls1_check_duplicate_extensions(&extensions)) {
-    *out_alert = SSL_AD_DECODE_ERROR;
-    return 0;
-  }
-
-  while (CBS_len(&extensions) != 0) {
-    uint16_t type;
-    CBS extension;
-
-    /* Decode the next extension. */
-    if (!CBS_get_u16(&extensions, &type) ||
-        !CBS_get_u16_length_prefixed(&extensions, &extension)) {
+  if (CBS_len(cbs) != 0) {
+    /* Decode the extensions block and check it is valid. */
+    CBS extensions;
+    if (!CBS_get_u16_length_prefixed(cbs, &extensions) ||
+        !tls1_check_duplicate_extensions(&extensions)) {
       *out_alert = SSL_AD_DECODE_ERROR;
       return 0;
     }
 
-    unsigned ext_index;
-    const struct tls_extension *const ext =
-        tls_extension_find(&ext_index, type);
+    while (CBS_len(&extensions) != 0) {
+      uint16_t type;
+      CBS extension;
 
-    if (ext != NULL) {
+      /* Decode the next extension. */
+      if (!CBS_get_u16(&extensions, &type) ||
+          !CBS_get_u16_length_prefixed(&extensions, &extension)) {
+        *out_alert = SSL_AD_DECODE_ERROR;
+        return 0;
+      }
+
+      unsigned ext_index;
+      const struct tls_extension *const ext =
+          tls_extension_find(&ext_index, type);
+
+      if (ext == NULL) {
+        continue;
+      }
+
       s->s3->tmp.extensions.received |= (1u << ext_index);
       uint8_t alert = SSL_AD_DECODE_ERROR;
       if (!ext->parse_clienthello(s, &alert, &extension)) {
         *out_alert = alert;
+        OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_PARSING_EXTENSION);
+        ERR_add_error_dataf("extension: %u", (unsigned)type);
         return 0;
       }
-
-      continue;
     }
   }
 
-no_extensions:
   for (i = 0; i < kNumExtensions; i++) {
     if (!(s->s3->tmp.extensions.received & (1u << i))) {
       /* Extension wasn't observed so call the callback with a NULL
        * parameter. */
       uint8_t alert = SSL_AD_DECODE_ERROR;
       if (!kExtensions[i].parse_clienthello(s, &alert, NULL)) {
+        OPENSSL_PUT_ERROR(SSL, SSL_R_MISSING_EXTENSION);
+        ERR_add_error_dataf("extension: %u", (unsigned)kExtensions[i].value);
         *out_alert = alert;
         return 0;
       }
@@ -2474,47 +2467,41 @@
 }
 
 static int ssl_scan_serverhello_tlsext(SSL *s, CBS *cbs, int *out_alert) {
-  CBS extensions;
-
   uint32_t received = 0;
-  size_t i;
   assert(kNumExtensions <= sizeof(received) * 8);
 
-  /* There may be no extensions. */
-  if (CBS_len(cbs) == 0) {
-    goto no_extensions;
-  }
-
-  /* Decode the extensions block and check it is valid. */
-  if (!CBS_get_u16_length_prefixed(cbs, &extensions) ||
-      !tls1_check_duplicate_extensions(&extensions)) {
-    *out_alert = SSL_AD_DECODE_ERROR;
-    return 0;
-  }
-
-  while (CBS_len(&extensions) != 0) {
-    uint16_t type;
-    CBS extension;
-
-    /* Decode the next extension. */
-    if (!CBS_get_u16(&extensions, &type) ||
-        !CBS_get_u16_length_prefixed(&extensions, &extension)) {
+  if (CBS_len(cbs) != 0) {
+    /* Decode the extensions block and check it is valid. */
+    CBS extensions;
+    if (!CBS_get_u16_length_prefixed(cbs, &extensions) ||
+        !tls1_check_duplicate_extensions(&extensions)) {
       *out_alert = SSL_AD_DECODE_ERROR;
       return 0;
     }
 
-    unsigned ext_index;
-    const struct tls_extension *const ext =
-        tls_extension_find(&ext_index, type);
 
-    /* While we have extensions that don't use tls_extension this conditional
-     * needs to be guarded on |ext != NULL|. In the future, ext being NULL will
-     * be fatal. */
-    if (ext != NULL) {
-      if (!(s->s3->tmp.extensions.sent & (1u << ext_index))) {
-        /* Received an extension that was never sent. */
+    while (CBS_len(&extensions) != 0) {
+      uint16_t type;
+      CBS extension;
+
+      /* Decode the next extension. */
+      if (!CBS_get_u16(&extensions, &type) ||
+          !CBS_get_u16_length_prefixed(&extensions, &extension)) {
+        *out_alert = SSL_AD_DECODE_ERROR;
+        return 0;
+      }
+
+      unsigned ext_index;
+      const struct tls_extension *const ext =
+          tls_extension_find(&ext_index, type);
+
+      if (/* If ext == NULL then an unknown extension was received. Since we
+           * cannot have sent an unknown extension, this is illegal. */
+          ext == NULL ||
+          /* If the extension was never sent then it is also illegal. */
+          !(s->s3->tmp.extensions.sent & (1u << ext_index))) {
         OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION);
-        ERR_add_error_dataf("ext:%u", (unsigned) type);
+        ERR_add_error_dataf("extension :%u", (unsigned)type);
         *out_alert = SSL_AD_DECODE_ERROR;
         return 0;
       }
@@ -2523,21 +2510,23 @@
 
       uint8_t alert = SSL_AD_DECODE_ERROR;
       if (!ext->parse_serverhello(s, &alert, &extension)) {
+        OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_PARSING_EXTENSION);
+        ERR_add_error_dataf("extension: %u", (unsigned)type);
         *out_alert = alert;
         return 0;
       }
-
-      continue;
     }
   }
 
-no_extensions:
+  size_t i;
   for (i = 0; i < kNumExtensions; i++) {
     if (!(received & (1u << i))) {
       /* Extension wasn't observed so call the callback with a NULL
        * parameter. */
       uint8_t alert = SSL_AD_DECODE_ERROR;
       if (!kExtensions[i].parse_serverhello(s, &alert, NULL)) {
+        OPENSSL_PUT_ERROR(SSL, SSL_R_MISSING_EXTENSION);
+        ERR_add_error_dataf("extension: %u", (unsigned)kExtensions[i].value);
         *out_alert = alert;
         return 0;
       }
diff --git a/ssl/test/bssl_shim.cc b/ssl/test/bssl_shim.cc
index 261344a..add45ae 100644
--- a/ssl/test/bssl_shim.cc
+++ b/ssl/test/bssl_shim.cc
@@ -921,7 +921,6 @@
       !SSL_enable_signed_cert_timestamps(ssl.get())) {
     return false;
   }
-  SSL_enable_fastradio_padding(ssl.get(), config->fastradio_padding);
   if (config->min_version != 0) {
     SSL_set_min_version(ssl.get(), (uint16_t)config->min_version);
   }
diff --git a/ssl/test/runner/common.go b/ssl/test/runner/common.go
index bad3ebe..fb78ef1 100644
--- a/ssl/test/runner/common.go
+++ b/ssl/test/runner/common.go
@@ -621,10 +621,6 @@
 	// across a renego.
 	RequireSameRenegoClientVersion bool
 
-	// RequireFastradioPadding, if true, requires that ClientHello messages
-	// be at least 1000 bytes long.
-	RequireFastradioPadding bool
-
 	// ExpectInitialRecordVersion, if non-zero, is the expected
 	// version of the records before the version is determined.
 	ExpectInitialRecordVersion uint16
@@ -736,6 +732,10 @@
 	// ExpectNewTicket, if true, causes the client to abort if it does not
 	// receive a new ticket.
 	ExpectNewTicket bool
+
+	// RequireClientHelloSize, if not zero, is the required length in bytes
+	// of the ClientHello /record/. This is checked by the server.
+	RequireClientHelloSize int
 }
 
 func (c *Config) serverInit() {
diff --git a/ssl/test/runner/handshake_server.go b/ssl/test/runner/handshake_server.go
index 3902ed3..5d37674 100644
--- a/ssl/test/runner/handshake_server.go
+++ b/ssl/test/runner/handshake_server.go
@@ -139,8 +139,8 @@
 		c.sendAlert(alertUnexpectedMessage)
 		return false, unexpectedMessageError(hs.clientHello, msg)
 	}
-	if config.Bugs.RequireFastradioPadding && len(hs.clientHello.raw) < 1000 {
-		return false, errors.New("tls: ClientHello record size should be larger than 1000 bytes when padding enabled.")
+	if size := config.Bugs.RequireClientHelloSize; size != 0 && len(hs.clientHello.raw) != size {
+		return false, fmt.Errorf("tls: ClientHello record size is %d, but expected %d", len(hs.clientHello.raw), size)
 	}
 
 	if c.isDTLS && !config.Bugs.SkipHelloVerifyRequest {
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go
index d4804bf..ff10c05 100644
--- a/ssl/test/runner/runner.go
+++ b/ssl/test/runner/runner.go
@@ -2997,6 +2997,19 @@
 			base64.StdEncoding.EncodeToString(testSCTList),
 		},
 	})
+	testCases = append(testCases, testCase{
+		testType: clientTest,
+		name:     "ClientHelloPadding",
+		config: Config{
+			Bugs: ProtocolBugs{
+				RequireClientHelloSize: 512,
+			},
+		},
+		// This hostname just needs to be long enough to push the
+		// ClientHello into F5's danger zone between 256 and 511 bytes
+		// long.
+		flags: []string{"-host-name", "01234567890123456789012345678901234567890123456789012345678901234567890123456789.com"},
+	})
 }
 
 func addResumptionVersionTests() {
@@ -3263,29 +3276,6 @@
 	})
 }
 
-func addFastRadioPaddingTests() {
-	testCases = append(testCases, testCase{
-		protocol: tls,
-		name:     "FastRadio-Padding",
-		config: Config{
-			Bugs: ProtocolBugs{
-				RequireFastradioPadding: true,
-			},
-		},
-		flags: []string{"-fastradio-padding"},
-	})
-	testCases = append(testCases, testCase{
-		protocol: dtls,
-		name:     "FastRadio-Padding-DTLS",
-		config: Config{
-			Bugs: ProtocolBugs{
-				RequireFastradioPadding: true,
-			},
-		},
-		flags: []string{"-fastradio-padding"},
-	})
-}
-
 var testHashes = []struct {
 	name string
 	id   uint8
@@ -3730,7 +3720,6 @@
 	addRenegotiationTests()
 	addDTLSReplayTests()
 	addSigningHashTests()
-	addFastRadioPaddingTests()
 	addDTLSRetransmitTests()
 	addExportKeyingMaterialTests()
 	addTLSUniqueTests()
diff --git a/ssl/test/test_config.cc b/ssl/test/test_config.cc
index 6b831f0..fef51ed 100644
--- a/ssl/test/test_config.cc
+++ b/ssl/test/test_config.cc
@@ -68,7 +68,6 @@
   { "-enable-ocsp-stapling", &TestConfig::enable_ocsp_stapling },
   { "-enable-signed-cert-timestamps",
     &TestConfig::enable_signed_cert_timestamps },
-  { "-fastradio-padding", &TestConfig::fastradio_padding },
   { "-implicit-handshake", &TestConfig::implicit_handshake },
   { "-use-early-callback", &TestConfig::use_early_callback },
   { "-fail-early-callback", &TestConfig::fail_early_callback },
diff --git a/ssl/test/test_config.h b/ssl/test/test_config.h
index b05db16..67655f4 100644
--- a/ssl/test/test_config.h
+++ b/ssl/test/test_config.h
@@ -59,7 +59,6 @@
   std::string expected_ocsp_response;
   bool enable_signed_cert_timestamps = false;
   std::string expected_signed_cert_timestamps;
-  bool fastradio_padding = false;
   int min_version = 0;
   int max_version = 0;
   int mtu = 0;