Remove custom extensions support.

Update-Note: Custom extensions APIs are removed.
Change-Id: Ic5e0fb3c018bf15d35d9149623f6b29940041b59
Reviewed-on: https://boringssl-review.googlesource.com/29685
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index f693030..a16a367 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -1533,92 +1533,6 @@
     const uint8_t *context, size_t context_len, int use_context);
 
 
-// Custom extensions.
-//
-// The custom extension functions allow TLS extensions to be added to
-// ClientHello and ServerHello messages.
-
-// SSL_custom_ext_add_cb is a callback function that is called when the
-// ClientHello (for clients) or ServerHello (for servers) is constructed. In
-// the case of a server, this callback will only be called for a given
-// extension if the ClientHello contained that extension – it's not possible to
-// inject extensions into a ServerHello that the client didn't request.
-//
-// When called, |extension_value| will contain the extension number that is
-// being considered for addition (so that a single callback can handle multiple
-// extensions). If the callback wishes to include the extension, it must set
-// |*out| to point to |*out_len| bytes of extension contents and return one. In
-// this case, the corresponding |SSL_custom_ext_free_cb| callback will later be
-// called with the value of |*out| once that data has been copied.
-//
-// If the callback does not wish to add an extension it must return zero.
-//
-// Alternatively, the callback can abort the connection by setting
-// |*out_alert_value| to a TLS alert number and returning -1.
-typedef int (*SSL_custom_ext_add_cb)(SSL *ssl, unsigned extension_value,
-                                     const uint8_t **out, size_t *out_len,
-                                     int *out_alert_value, void *add_arg);
-
-// SSL_custom_ext_free_cb is a callback function that is called by OpenSSL iff
-// an |SSL_custom_ext_add_cb| callback previously returned one. In that case,
-// this callback is called and passed the |out| pointer that was returned by
-// the add callback. This is to free any dynamically allocated data created by
-// the add callback.
-typedef void (*SSL_custom_ext_free_cb)(SSL *ssl, unsigned extension_value,
-                                       const uint8_t *out, void *add_arg);
-
-// SSL_custom_ext_parse_cb is a callback function that is called by OpenSSL to
-// parse an extension from the peer: that is from the ServerHello for a client
-// and from the ClientHello for a server.
-//
-// When called, |extension_value| will contain the extension number and the
-// contents of the extension are |contents_len| bytes at |contents|.
-//
-// The callback must return one to continue the handshake. Otherwise, if it
-// returns zero, a fatal alert with value |*out_alert_value| is sent and the
-// handshake is aborted.
-typedef int (*SSL_custom_ext_parse_cb)(SSL *ssl, unsigned extension_value,
-                                       const uint8_t *contents,
-                                       size_t contents_len,
-                                       int *out_alert_value, void *parse_arg);
-
-// SSL_extension_supported returns one iff OpenSSL internally handles
-// extensions of type |extension_value|. This can be used to avoid registering
-// custom extension handlers for extensions that a future version of OpenSSL
-// may handle internally.
-OPENSSL_EXPORT int SSL_extension_supported(unsigned extension_value);
-
-// SSL_CTX_add_client_custom_ext registers callback functions for handling
-// custom TLS extensions for client connections.
-//
-// If |add_cb| is NULL then an empty extension will be added in each
-// ClientHello. Otherwise, see the comment for |SSL_custom_ext_add_cb| about
-// this callback.
-//
-// The |free_cb| may be NULL if |add_cb| doesn't dynamically allocate data that
-// needs to be freed.
-//
-// It returns one on success or zero on error. It's always an error to register
-// callbacks for the same extension twice, or to register callbacks for an
-// extension that OpenSSL handles internally. See |SSL_extension_supported| to
-// discover, at runtime, which extensions OpenSSL handles internally.
-OPENSSL_EXPORT int SSL_CTX_add_client_custom_ext(
-    SSL_CTX *ctx, unsigned extension_value, SSL_custom_ext_add_cb add_cb,
-    SSL_custom_ext_free_cb free_cb, void *add_arg,
-    SSL_custom_ext_parse_cb parse_cb, void *parse_arg);
-
-// SSL_CTX_add_server_custom_ext is the same as
-// |SSL_CTX_add_client_custom_ext|, but for server connections.
-//
-// Unlike on the client side, if |add_cb| is NULL no extension will be added.
-// The |add_cb|, if any, will only be called if the ClientHello contained a
-// matching extension.
-OPENSSL_EXPORT int SSL_CTX_add_server_custom_ext(
-    SSL_CTX *ctx, unsigned extension_value, SSL_custom_ext_add_cb add_cb,
-    SSL_custom_ext_free_cb free_cb, void *add_arg,
-    SSL_custom_ext_parse_cb parse_cb, void *parse_arg);
-
-
 // Sessions.
 //
 // An |SSL_SESSION| represents an SSL session that may be resumed in an
diff --git a/ssl/CMakeLists.txt b/ssl/CMakeLists.txt
index 3eab0b5..f2f60ca 100644
--- a/ssl/CMakeLists.txt
+++ b/ssl/CMakeLists.txt
@@ -4,7 +4,6 @@
   ssl
 
   bio_ssl.cc
-  custom_extensions.cc
   d1_both.cc
   d1_lib.cc
   d1_pkt.cc
diff --git a/ssl/custom_extensions.cc b/ssl/custom_extensions.cc
deleted file mode 100644
index 85b8a33..0000000
--- a/ssl/custom_extensions.cc
+++ /dev/null
@@ -1,265 +0,0 @@
-/* Copyright (c) 2014, Google Inc.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
-
-#include <openssl/ssl.h>
-
-#include <assert.h>
-#include <string.h>
-
-#include <openssl/bytestring.h>
-#include <openssl/err.h>
-#include <openssl/mem.h>
-#include <openssl/stack.h>
-
-#include "internal.h"
-
-
-namespace bssl {
-
-void SSL_CUSTOM_EXTENSION_free(SSL_CUSTOM_EXTENSION *custom_extension) {
-  OPENSSL_free(custom_extension);
-}
-
-static const SSL_CUSTOM_EXTENSION *custom_ext_find(
-    STACK_OF(SSL_CUSTOM_EXTENSION) *stack,
-    unsigned *out_index, uint16_t value) {
-  for (size_t i = 0; i < sk_SSL_CUSTOM_EXTENSION_num(stack); i++) {
-    const SSL_CUSTOM_EXTENSION *ext = sk_SSL_CUSTOM_EXTENSION_value(stack, i);
-    if (ext->value == value) {
-      if (out_index != NULL) {
-        *out_index = i;
-      }
-      return ext;
-    }
-  }
-
-  return NULL;
-}
-
-// default_add_callback is used as the |add_callback| when the user doesn't
-// provide one. For servers, it does nothing while, for clients, it causes an
-// empty extension to be included.
-static int default_add_callback(SSL *ssl, unsigned extension_value,
-                                const uint8_t **out, size_t *out_len,
-                                int *out_alert_value, void *add_arg) {
-  if (ssl->server) {
-    return 0;
-  }
-  *out_len = 0;
-  return 1;
-}
-
-static int custom_ext_add_hello(SSL_HANDSHAKE *hs, CBB *extensions) {
-  SSL *const ssl = hs->ssl;
-  STACK_OF(SSL_CUSTOM_EXTENSION) *stack = ssl->ctx->client_custom_extensions;
-  if (ssl->server) {
-    stack = ssl->ctx->server_custom_extensions;
-  }
-
-  if (stack == NULL) {
-    return 1;
-  }
-
-  for (size_t i = 0; i < sk_SSL_CUSTOM_EXTENSION_num(stack); i++) {
-    const SSL_CUSTOM_EXTENSION *ext = sk_SSL_CUSTOM_EXTENSION_value(stack, i);
-
-    if (ssl->server &&
-        !(hs->custom_extensions.received & (1u << i))) {
-      // Servers cannot echo extensions that the client didn't send.
-      continue;
-    }
-
-    const uint8_t *contents;
-    size_t contents_len;
-    int alert = SSL_AD_DECODE_ERROR;
-    CBB contents_cbb;
-
-    switch (ext->add_callback(ssl, ext->value, &contents, &contents_len, &alert,
-                              ext->add_arg)) {
-      case 1:
-        if (!CBB_add_u16(extensions, ext->value) ||
-            !CBB_add_u16_length_prefixed(extensions, &contents_cbb) ||
-            !CBB_add_bytes(&contents_cbb, contents, contents_len) ||
-            !CBB_flush(extensions)) {
-          OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
-          ERR_add_error_dataf("extension %u", (unsigned) ext->value);
-          if (ext->free_callback && 0 < contents_len) {
-            ext->free_callback(ssl, ext->value, contents, ext->add_arg);
-          }
-          return 0;
-        }
-
-        if (ext->free_callback && 0 < contents_len) {
-          ext->free_callback(ssl, ext->value, contents, ext->add_arg);
-        }
-
-        if (!ssl->server) {
-          assert((hs->custom_extensions.sent & (1u << i)) == 0);
-          hs->custom_extensions.sent |= (1u << i);
-        }
-        break;
-
-      case 0:
-        break;
-
-      default:
-        ssl_send_alert(ssl, SSL3_AL_FATAL, alert);
-        OPENSSL_PUT_ERROR(SSL, SSL_R_CUSTOM_EXTENSION_ERROR);
-        ERR_add_error_dataf("extension %u", (unsigned) ext->value);
-        return 0;
-    }
-  }
-
-  return 1;
-}
-
-int custom_ext_add_clienthello(SSL_HANDSHAKE *hs, CBB *extensions) {
-  return custom_ext_add_hello(hs, extensions);
-}
-
-int custom_ext_parse_serverhello(SSL_HANDSHAKE *hs, int *out_alert,
-                                 uint16_t value, const CBS *extension) {
-  SSL *const ssl = hs->ssl;
-  unsigned index;
-  const SSL_CUSTOM_EXTENSION *ext =
-      custom_ext_find(ssl->ctx->client_custom_extensions, &index, value);
-
-  if (// Unknown extensions are not allowed in a ServerHello.
-      ext == NULL ||
-      // Also, if we didn't send the extension, that's also unacceptable.
-      !(hs->custom_extensions.sent & (1u << index))) {
-    OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION);
-    ERR_add_error_dataf("extension %u", (unsigned)value);
-    *out_alert = SSL_AD_UNSUPPORTED_EXTENSION;
-    return 0;
-  }
-
-  if (ext->parse_callback != NULL &&
-      !ext->parse_callback(ssl, value, CBS_data(extension), CBS_len(extension),
-                           out_alert, ext->parse_arg)) {
-    OPENSSL_PUT_ERROR(SSL, SSL_R_CUSTOM_EXTENSION_ERROR);
-    ERR_add_error_dataf("extension %u", (unsigned)ext->value);
-    return 0;
-  }
-
-  return 1;
-}
-
-int custom_ext_parse_clienthello(SSL_HANDSHAKE *hs, int *out_alert,
-                                 uint16_t value, const CBS *extension) {
-  SSL *const ssl = hs->ssl;
-  unsigned index;
-  const SSL_CUSTOM_EXTENSION *ext =
-      custom_ext_find(ssl->ctx->server_custom_extensions, &index, value);
-
-  if (ext == NULL) {
-    return 1;
-  }
-
-  assert((hs->custom_extensions.received & (1u << index)) == 0);
-  hs->custom_extensions.received |= (1u << index);
-
-  if (ext->parse_callback &&
-      !ext->parse_callback(ssl, value, CBS_data(extension), CBS_len(extension),
-                           out_alert, ext->parse_arg)) {
-    OPENSSL_PUT_ERROR(SSL, SSL_R_CUSTOM_EXTENSION_ERROR);
-    ERR_add_error_dataf("extension %u", (unsigned)ext->value);
-    return 0;
-  }
-
-  return 1;
-}
-
-int custom_ext_add_serverhello(SSL_HANDSHAKE *hs, CBB *extensions) {
-  return custom_ext_add_hello(hs, extensions);
-}
-
-// MAX_NUM_CUSTOM_EXTENSIONS is the maximum number of custom extensions that
-// can be set on an |SSL_CTX|. It's determined by the size of the bitset used
-// to track when an extension has been sent.
-#define MAX_NUM_CUSTOM_EXTENSIONS \
-  (sizeof(((SSL_HANDSHAKE *)NULL)->custom_extensions.sent) * 8)
-
-static int custom_ext_append(STACK_OF(SSL_CUSTOM_EXTENSION) **stack,
-                             unsigned extension_value,
-                             SSL_custom_ext_add_cb add_cb,
-                             SSL_custom_ext_free_cb free_cb, void *add_arg,
-                             SSL_custom_ext_parse_cb parse_cb,
-                             void *parse_arg) {
-  if (add_cb == NULL ||
-      0xffff < extension_value ||
-      SSL_extension_supported(extension_value) ||
-      // Specifying a free callback without an add callback is nonsensical
-      // and an error.
-      (*stack != NULL &&
-       (MAX_NUM_CUSTOM_EXTENSIONS <= sk_SSL_CUSTOM_EXTENSION_num(*stack) ||
-        custom_ext_find(*stack, NULL, extension_value) != NULL))) {
-    return 0;
-  }
-
-  SSL_CUSTOM_EXTENSION *ext =
-      (SSL_CUSTOM_EXTENSION *)OPENSSL_malloc(sizeof(SSL_CUSTOM_EXTENSION));
-  if (ext == NULL) {
-    return 0;
-  }
-  ext->add_callback = add_cb;
-  ext->add_arg = add_arg;
-  ext->free_callback = free_cb;
-  ext->parse_callback = parse_cb;
-  ext->parse_arg = parse_arg;
-  ext->value = extension_value;
-
-  if (*stack == NULL) {
-    *stack = sk_SSL_CUSTOM_EXTENSION_new_null();
-    if (*stack == NULL) {
-      SSL_CUSTOM_EXTENSION_free(ext);
-      return 0;
-    }
-  }
-
-  if (!sk_SSL_CUSTOM_EXTENSION_push(*stack, ext)) {
-    SSL_CUSTOM_EXTENSION_free(ext);
-    if (sk_SSL_CUSTOM_EXTENSION_num(*stack) == 0) {
-      sk_SSL_CUSTOM_EXTENSION_free(*stack);
-      *stack = NULL;
-    }
-    return 0;
-  }
-
-  return 1;
-}
-
-}  // namespace bssl
-
-using namespace bssl;
-
-int SSL_CTX_add_client_custom_ext(SSL_CTX *ctx, unsigned extension_value,
-                                  SSL_custom_ext_add_cb add_cb,
-                                  SSL_custom_ext_free_cb free_cb, void *add_arg,
-                                  SSL_custom_ext_parse_cb parse_cb,
-                                  void *parse_arg) {
-  return custom_ext_append(&ctx->client_custom_extensions, extension_value,
-                           add_cb ? add_cb : default_add_callback, free_cb,
-                           add_arg, parse_cb, parse_arg);
-}
-
-int SSL_CTX_add_server_custom_ext(SSL_CTX *ctx, unsigned extension_value,
-                                  SSL_custom_ext_add_cb add_cb,
-                                  SSL_custom_ext_free_cb free_cb, void *add_arg,
-                                  SSL_custom_ext_parse_cb parse_cb,
-                                  void *parse_arg) {
-  return custom_ext_append(&ctx->server_custom_extensions, extension_value,
-                           add_cb ? add_cb : default_add_callback, free_cb,
-                           add_arg, parse_cb, parse_arg);
-}
diff --git a/ssl/handshake.cc b/ssl/handshake.cc
index 9549f7c..4683ac5 100644
--- a/ssl/handshake.cc
+++ b/ssl/handshake.cc
@@ -130,7 +130,6 @@
       needs_psk_binder(false),
       received_hello_retry_request(false),
       sent_hello_retry_request(false),
-      received_custom_extension(false),
       handshake_finalized(false),
       accept_psk_mode(false),
       cert_request(false),
diff --git a/ssl/internal.h b/ssl/internal.h
index 20efc9d..14daeff 100644
--- a/ssl/internal.h
+++ b/ssl/internal.h
@@ -929,36 +929,6 @@
                            Span<const uint8_t> in);
 
 
-// Custom extensions
-
-}  // namespace bssl
-
-// |SSL_CUSTOM_EXTENSION| is a structure that contains information about
-// custom-extension callbacks. It is defined unnamespaced for compatibility with
-// |STACK_OF(SSL_CUSTOM_EXTENSION)|.
-typedef struct ssl_custom_extension {
-  SSL_custom_ext_add_cb add_callback;
-  void *add_arg;
-  SSL_custom_ext_free_cb free_callback;
-  SSL_custom_ext_parse_cb parse_callback;
-  void *parse_arg;
-  uint16_t value;
-} SSL_CUSTOM_EXTENSION;
-
-DEFINE_STACK_OF(SSL_CUSTOM_EXTENSION)
-
-namespace bssl {
-
-void SSL_CUSTOM_EXTENSION_free(SSL_CUSTOM_EXTENSION *custom_extension);
-
-int custom_ext_add_clienthello(SSL_HANDSHAKE *hs, CBB *extensions);
-int custom_ext_parse_serverhello(SSL_HANDSHAKE *hs, int *out_alert,
-                                 uint16_t value, const CBS *extension);
-int custom_ext_parse_clienthello(SSL_HANDSHAKE *hs, int *out_alert,
-                                 uint16_t value, const CBS *extension);
-int custom_ext_add_serverhello(SSL_HANDSHAKE *hs, CBB *extensions);
-
-
 // Key shares.
 
 // SSLKeyShare abstracts over Diffie-Hellman-like key exchanges.
@@ -1421,17 +1391,6 @@
     uint32_t received;
   } extensions;
 
-  union {
-    // sent is a bitset where the bits correspond to elements of
-    // |client_custom_extensions| in the |SSL_CTX|. Each bit is set if that
-    // extension was sent in a ClientHello. It's not used by servers.
-    uint16_t sent = 0;
-    // received is a bitset, like |sent|, but is used by servers to record
-    // which custom extensions were received from a client. The bits here
-    // correspond to |server_custom_extensions|.
-    uint16_t received;
-  } custom_extensions;
-
   // retry_group is the group ID selected by the server in HelloRetryRequest in
   // TLS 1.3.
   uint16_t retry_group = 0;
@@ -1532,8 +1491,6 @@
   bool received_hello_retry_request:1;
   bool sent_hello_retry_request:1;
 
-  bool received_custom_extension:1;
-
   // handshake_finalized is true once the handshake has completed, at which
   // point accessors should use the established state.
   bool handshake_finalized:1;
@@ -2889,11 +2846,6 @@
 
   CRYPTO_EX_DATA ex_data;
 
-  // custom_*_extensions stores any callback sets for custom extensions. Note
-  // that these pointers will be NULL if the stack would otherwise be empty.
-  STACK_OF(SSL_CUSTOM_EXTENSION) *client_custom_extensions = nullptr;
-  STACK_OF(SSL_CUSTOM_EXTENSION) *server_custom_extensions = nullptr;
-
   // Default values used when no per-SSL value is defined follow
 
   void (*info_callback)(const SSL *ssl, int type, int value) = nullptr;
diff --git a/ssl/ssl_lib.cc b/ssl/ssl_lib.cc
index 7e26fa0..572e79d 100644
--- a/ssl/ssl_lib.cc
+++ b/ssl/ssl_lib.cc
@@ -562,10 +562,6 @@
 
   CRYPTO_MUTEX_cleanup(&lock);
   lh_SSL_SESSION_free(sessions);
-  sk_SSL_CUSTOM_EXTENSION_pop_free(client_custom_extensions,
-                                   SSL_CUSTOM_EXTENSION_free);
-  sk_SSL_CUSTOM_EXTENSION_pop_free(server_custom_extensions,
-                                   SSL_CUSTOM_EXTENSION_free);
   x509_method->ssl_ctx_free(this);
   sk_CertCompressionAlg_pop_free(cert_compression_algs,
                                  Delete<CertCompressionAlg>);
diff --git a/ssl/t1_lib.cc b/ssl/t1_lib.cc
index 3cb1063..cfb4cef 100644
--- a/ssl/t1_lib.cc
+++ b/ssl/t1_lib.cc
@@ -3068,7 +3068,6 @@
   }
 
   hs->extensions.sent = 0;
-  hs->custom_extensions.sent = 0;
 
   for (size_t i = 0; i < kNumExtensions; i++) {
     if (kExtensions[i].init != NULL) {
@@ -3100,11 +3099,6 @@
     }
   }
 
-  if (!custom_ext_add_clienthello(hs, &extensions)) {
-    OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
-    return 0;
-  }
-
   if (ssl->ctx->grease_enabled) {
     // Add a fake non-empty extension. See draft-davidben-tls-grease-01.
     uint16_t grease_ext2 = ssl_get_grease_value(hs, ssl_grease_extension2);
@@ -3189,10 +3183,6 @@
     }
   }
 
-  if (!custom_ext_add_serverhello(hs, &extensions)) {
-    goto err;
-  }
-
   // Discard empty extensions blocks before TLS 1.3.
   if (ssl_protocol_version(ssl) < TLS1_3_VERSION &&
       CBB_len(&extensions) == 0) {
@@ -3216,7 +3206,6 @@
   }
 
   hs->extensions.received = 0;
-  hs->custom_extensions.received = 0;
   CBS extensions;
   CBS_init(&extensions, client_hello->extensions, client_hello->extensions_len);
   while (CBS_len(&extensions) != 0) {
@@ -3234,10 +3223,6 @@
     const struct tls_extension *const ext =
         tls_extension_find(&ext_index, type);
     if (ext == NULL) {
-      if (!custom_ext_parse_clienthello(hs, out_alert, type, &extension)) {
-        OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_PARSING_EXTENSION);
-        return 0;
-      }
       continue;
     }
 
@@ -3333,11 +3318,10 @@
         tls_extension_find(&ext_index, type);
 
     if (ext == NULL) {
-      hs->received_custom_extension = true;
-      if (!custom_ext_parse_serverhello(hs, out_alert, type, &extension)) {
-        return 0;
-      }
-      continue;
+      OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION);
+      ERR_add_error_dataf("extension %u", (unsigned)type);
+      *out_alert = SSL_AD_UNSUPPORTED_EXTENSION;
+      return 0;
     }
 
     static_assert(kNumExtensions <= sizeof(hs->extensions.sent) * 8,
@@ -3941,9 +3925,3 @@
 void SSL_CTX_set_rsa_pss_rsae_certs_enabled(SSL_CTX *ctx, int enabled) {
   ctx->rsa_pss_rsae_certs_enabled = !!enabled;
 }
-
-int SSL_extension_supported(unsigned extension_value) {
-  uint32_t index;
-  return extension_value == TLSEXT_TYPE_padding ||
-         tls_extension_find(&index, extension_value) != NULL;
-}
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go
index b296260..d88e389 100644
--- a/ssl/test/runner/runner.go
+++ b/ssl/test/runner/runner.go
@@ -10259,278 +10259,6 @@
 }
 
 func addCustomExtensionTests() {
-	expectedContents := "custom extension"
-	emptyString := ""
-
-	for _, isClient := range []bool{false, true} {
-		suffix := "Server"
-		flag := "-enable-server-custom-extension"
-		testType := serverTest
-		if isClient {
-			suffix = "Client"
-			flag = "-enable-client-custom-extension"
-			testType = clientTest
-		}
-
-		testCases = append(testCases, testCase{
-			testType: testType,
-			name:     "CustomExtensions-" + suffix,
-			config: Config{
-				MaxVersion: VersionTLS12,
-				Bugs: ProtocolBugs{
-					CustomExtension:         expectedContents,
-					ExpectedCustomExtension: &expectedContents,
-				},
-			},
-			flags: []string{flag},
-		})
-		testCases = append(testCases, testCase{
-			testType: testType,
-			name:     "CustomExtensions-" + suffix + "-TLS13",
-			config: Config{
-				MaxVersion: VersionTLS13,
-				Bugs: ProtocolBugs{
-					CustomExtension:         expectedContents,
-					ExpectedCustomExtension: &expectedContents,
-				},
-			},
-			flags: []string{flag},
-		})
-
-		// If the parse callback fails, the handshake should also fail.
-		testCases = append(testCases, testCase{
-			testType: testType,
-			name:     "CustomExtensions-ParseError-" + suffix,
-			config: Config{
-				MaxVersion: VersionTLS12,
-				Bugs: ProtocolBugs{
-					CustomExtension:         expectedContents + "foo",
-					ExpectedCustomExtension: &expectedContents,
-				},
-			},
-			flags:         []string{flag},
-			shouldFail:    true,
-			expectedError: ":CUSTOM_EXTENSION_ERROR:",
-		})
-		testCases = append(testCases, testCase{
-			testType: testType,
-			name:     "CustomExtensions-ParseError-" + suffix + "-TLS13",
-			config: Config{
-				MaxVersion: VersionTLS13,
-				Bugs: ProtocolBugs{
-					CustomExtension:         expectedContents + "foo",
-					ExpectedCustomExtension: &expectedContents,
-				},
-			},
-			flags:         []string{flag},
-			shouldFail:    true,
-			expectedError: ":CUSTOM_EXTENSION_ERROR:",
-		})
-
-		// If the add callback fails, the handshake should also fail.
-		testCases = append(testCases, testCase{
-			testType: testType,
-			name:     "CustomExtensions-FailAdd-" + suffix,
-			config: Config{
-				MaxVersion: VersionTLS12,
-				Bugs: ProtocolBugs{
-					CustomExtension:         expectedContents,
-					ExpectedCustomExtension: &expectedContents,
-				},
-			},
-			flags:         []string{flag, "-custom-extension-fail-add"},
-			shouldFail:    true,
-			expectedError: ":CUSTOM_EXTENSION_ERROR:",
-		})
-		testCases = append(testCases, testCase{
-			testType: testType,
-			name:     "CustomExtensions-FailAdd-" + suffix + "-TLS13",
-			config: Config{
-				MaxVersion: VersionTLS13,
-				Bugs: ProtocolBugs{
-					CustomExtension:         expectedContents,
-					ExpectedCustomExtension: &expectedContents,
-				},
-			},
-			flags:         []string{flag, "-custom-extension-fail-add"},
-			shouldFail:    true,
-			expectedError: ":CUSTOM_EXTENSION_ERROR:",
-		})
-
-		// If the add callback returns zero, no extension should be
-		// added.
-		skipCustomExtension := expectedContents
-		if isClient {
-			// For the case where the client skips sending the
-			// custom extension, the server must not “echo” it.
-			skipCustomExtension = ""
-		}
-		testCases = append(testCases, testCase{
-			testType: testType,
-			name:     "CustomExtensions-Skip-" + suffix,
-			config: Config{
-				MaxVersion: VersionTLS12,
-				Bugs: ProtocolBugs{
-					CustomExtension:         skipCustomExtension,
-					ExpectedCustomExtension: &emptyString,
-				},
-			},
-			flags: []string{flag, "-custom-extension-skip"},
-		})
-		testCases = append(testCases, testCase{
-			testType: testType,
-			name:     "CustomExtensions-Skip-" + suffix + "-TLS13",
-			config: Config{
-				MaxVersion: VersionTLS13,
-				Bugs: ProtocolBugs{
-					CustomExtension:         skipCustomExtension,
-					ExpectedCustomExtension: &emptyString,
-				},
-			},
-			flags: []string{flag, "-custom-extension-skip"},
-		})
-	}
-
-	// If the client sends both early data and custom extension, the handshake
-	// should succeed as long as both the extensions aren't returned by the
-	// server.
-	testCases = append(testCases, testCase{
-		testType: clientTest,
-		name:     "CustomExtensions-Client-EarlyData-None",
-		config: Config{
-			MaxVersion:       VersionTLS13,
-			MaxEarlyDataSize: 16384,
-			Bugs: ProtocolBugs{
-				ExpectedCustomExtension: &expectedContents,
-				AlwaysRejectEarlyData:   true,
-			},
-		},
-		resumeSession: true,
-		flags: []string{
-			"-enable-client-custom-extension",
-			"-enable-early-data",
-			"-expect-ticket-supports-early-data",
-			"-expect-reject-early-data",
-		},
-	})
-
-	testCases = append(testCases, testCase{
-		testType: clientTest,
-		name:     "CustomExtensions-Client-EarlyData-EarlyDataAccepted",
-		config: Config{
-			MaxVersion:       VersionTLS13,
-			MaxEarlyDataSize: 16384,
-			Bugs: ProtocolBugs{
-				ExpectedCustomExtension: &expectedContents,
-			},
-		},
-		resumeSession: true,
-		flags: []string{
-			"-enable-client-custom-extension",
-			"-enable-early-data",
-			"-expect-ticket-supports-early-data",
-			"-expect-accept-early-data",
-		},
-	})
-
-	testCases = append(testCases, testCase{
-		testType: clientTest,
-		name:     "CustomExtensions-Client-EarlyData-CustomExtensionAccepted",
-		config: Config{
-			MaxVersion:       VersionTLS13,
-			MaxEarlyDataSize: 16384,
-			Bugs: ProtocolBugs{
-				AlwaysRejectEarlyData:   true,
-				CustomExtension:         expectedContents,
-				ExpectedCustomExtension: &expectedContents,
-			},
-		},
-		resumeSession: true,
-		flags: []string{
-			"-enable-client-custom-extension",
-			"-enable-early-data",
-			"-expect-ticket-supports-early-data",
-			"-expect-reject-early-data",
-		},
-	})
-
-	testCases = append(testCases, testCase{
-		testType: clientTest,
-		name:     "CustomExtensions-Client-EarlyDataAndCustomExtensions",
-		config: Config{
-			MaxVersion:       VersionTLS13,
-			MaxEarlyDataSize: 16384,
-			Bugs: ProtocolBugs{
-				CustomExtension:         expectedContents,
-				ExpectedCustomExtension: &expectedContents,
-			},
-		},
-		resumeConfig: &Config{
-			MaxVersion:       VersionTLS13,
-			MaxEarlyDataSize: 16384,
-			Bugs: ProtocolBugs{
-				CustomExtension:         expectedContents,
-				ExpectedCustomExtension: &expectedContents,
-				SendEarlyDataExtension:  true,
-			},
-		},
-		resumeSession: true,
-		shouldFail:    true,
-		expectedError: ":UNEXPECTED_EXTENSION_ON_EARLY_DATA:",
-		flags: []string{
-			"-enable-client-custom-extension",
-			"-enable-early-data",
-			"-expect-ticket-supports-early-data",
-		},
-	})
-
-	// If the server receives both early data and custom extension, only the
-	// custom extension should be accepted.
-	testCases = append(testCases, testCase{
-		testType: serverTest,
-		name:     "CustomExtensions-Server-EarlyDataOffered",
-		config: Config{
-			MaxVersion: VersionTLS13,
-			Bugs: ProtocolBugs{
-				SendEarlyData:           [][]byte{{1, 2, 3, 4}},
-				CustomExtension:         expectedContents,
-				ExpectedCustomExtension: &expectedContents,
-				ExpectEarlyDataAccepted: false,
-			},
-		},
-		resumeSession: true,
-		flags: []string{
-			"-enable-server-custom-extension",
-			"-enable-early-data",
-		},
-	})
-
-	// The custom extension add callback should not be called if the client
-	// doesn't send the extension.
-	testCases = append(testCases, testCase{
-		testType: serverTest,
-		name:     "CustomExtensions-NotCalled-Server",
-		config: Config{
-			MaxVersion: VersionTLS12,
-			Bugs: ProtocolBugs{
-				ExpectedCustomExtension: &emptyString,
-			},
-		},
-		flags: []string{"-enable-server-custom-extension", "-custom-extension-fail-add"},
-	})
-
-	testCases = append(testCases, testCase{
-		testType: serverTest,
-		name:     "CustomExtensions-NotCalled-Server-TLS13",
-		config: Config{
-			MaxVersion: VersionTLS13,
-			Bugs: ProtocolBugs{
-				ExpectedCustomExtension: &emptyString,
-			},
-		},
-		flags: []string{"-enable-server-custom-extension", "-custom-extension-fail-add"},
-	})
-
 	// Test an unknown extension from the server.
 	testCases = append(testCases, testCase{
 		testType: clientTest,
@@ -10538,7 +10266,7 @@
 		config: Config{
 			MaxVersion: VersionTLS12,
 			Bugs: ProtocolBugs{
-				CustomExtension: expectedContents,
+				CustomExtension: "custom extension",
 			},
 		},
 		shouldFail:         true,
@@ -10551,7 +10279,7 @@
 		config: Config{
 			MaxVersion: VersionTLS13,
 			Bugs: ProtocolBugs{
-				CustomExtension: expectedContents,
+				CustomExtension: "custom extension",
 			},
 		},
 		shouldFail:         true,
@@ -10564,7 +10292,7 @@
 		config: Config{
 			MaxVersion: VersionTLS13,
 			Bugs: ProtocolBugs{
-				CustomUnencryptedExtension: expectedContents,
+				CustomUnencryptedExtension: "custom extension",
 			},
 		},
 		shouldFail:    true,
diff --git a/ssl/test/test_config.cc b/ssl/test/test_config.cc
index 3c5046e..3b9bcd9 100644
--- a/ssl/test/test_config.cc
+++ b/ssl/test/test_config.cc
@@ -92,12 +92,6 @@
   { "-use-ticket-callback", &TestConfig::use_ticket_callback },
   { "-renew-ticket", &TestConfig::renew_ticket },
   { "-enable-early-data", &TestConfig::enable_early_data },
-  { "-enable-client-custom-extension",
-    &TestConfig::enable_client_custom_extension },
-  { "-enable-server-custom-extension",
-    &TestConfig::enable_server_custom_extension },
-  { "-custom-extension-skip", &TestConfig::custom_extension_skip },
-  { "-custom-extension-fail-add", &TestConfig::custom_extension_fail_add },
   { "-check-close-notify", &TestConfig::check_close_notify },
   { "-shim-shuts-down", &TestConfig::shim_shuts_down },
   { "-verify-fail", &TestConfig::verify_fail },
@@ -392,63 +386,6 @@
   return SSL_TLSEXT_ERR_OK;
 }
 
-// kCustomExtensionValue is the extension value that the custom extension
-// callbacks will add.
-static const uint16_t kCustomExtensionValue = 1234;
-static void *const kCustomExtensionAddArg =
-    reinterpret_cast<void *>(kCustomExtensionValue);
-static void *const kCustomExtensionParseArg =
-    reinterpret_cast<void *>(kCustomExtensionValue + 1);
-static const char kCustomExtensionContents[] = "custom extension";
-
-static int CustomExtensionAddCallback(SSL *ssl, unsigned extension_value,
-                                      const uint8_t **out, size_t *out_len,
-                                      int *out_alert_value, void *add_arg) {
-  if (extension_value != kCustomExtensionValue ||
-      add_arg != kCustomExtensionAddArg) {
-    abort();
-  }
-
-  if (GetTestConfig(ssl)->custom_extension_skip) {
-    return 0;
-  }
-  if (GetTestConfig(ssl)->custom_extension_fail_add) {
-    return -1;
-  }
-
-  *out = reinterpret_cast<const uint8_t *>(kCustomExtensionContents);
-  *out_len = sizeof(kCustomExtensionContents) - 1;
-
-  return 1;
-}
-
-static void CustomExtensionFreeCallback(SSL *ssl, unsigned extension_value,
-                                        const uint8_t *out, void *add_arg) {
-  if (extension_value != kCustomExtensionValue ||
-      add_arg != kCustomExtensionAddArg ||
-      out != reinterpret_cast<const uint8_t *>(kCustomExtensionContents)) {
-    abort();
-  }
-}
-
-static int CustomExtensionParseCallback(SSL *ssl, unsigned extension_value,
-                                        const uint8_t *contents,
-                                        size_t contents_len,
-                                        int *out_alert_value, void *parse_arg) {
-  if (extension_value != kCustomExtensionValue ||
-      parse_arg != kCustomExtensionParseArg) {
-    abort();
-  }
-
-  if (contents_len != sizeof(kCustomExtensionContents) - 1 ||
-      OPENSSL_memcmp(contents, kCustomExtensionContents, contents_len) != 0) {
-    *out_alert_value = SSL_AD_DECODE_ERROR;
-    return 0;
-  }
-
-  return 1;
-}
-
 static int ServerNameCallback(SSL *ssl, int *out_alert, void *arg) {
   // SNI must be accessible from the SNI callback.
   const TestConfig *config = GetTestConfig(ssl);
@@ -1234,22 +1171,6 @@
     SSL_CTX_set_tlsext_ticket_key_cb(ssl_ctx.get(), TicketKeyCallback);
   }
 
-  if (enable_client_custom_extension &&
-      !SSL_CTX_add_client_custom_ext(
-          ssl_ctx.get(), kCustomExtensionValue, CustomExtensionAddCallback,
-          CustomExtensionFreeCallback, kCustomExtensionAddArg,
-          CustomExtensionParseCallback, kCustomExtensionParseArg)) {
-    return nullptr;
-  }
-
-  if (enable_server_custom_extension &&
-      !SSL_CTX_add_server_custom_ext(
-          ssl_ctx.get(), kCustomExtensionValue, CustomExtensionAddCallback,
-          CustomExtensionFreeCallback, kCustomExtensionAddArg,
-          CustomExtensionParseCallback, kCustomExtensionParseArg)) {
-    return nullptr;
-  }
-
   if (!use_custom_verify_callback) {
     SSL_CTX_set_cert_verify_callback(ssl_ctx.get(), CertVerifyCallback, NULL);
   }
diff --git a/ssl/tls13_client.cc b/ssl/tls13_client.cc
index 9fdd313..40281a0 100644
--- a/ssl/tls13_client.cc
+++ b/ssl/tls13_client.cc
@@ -442,8 +442,7 @@
       OPENSSL_PUT_ERROR(SSL, SSL_R_ALPN_MISMATCH_ON_EARLY_DATA);
       return ssl_hs_error;
     }
-    if (ssl->s3->channel_id_valid || hs->received_custom_extension ||
-        ssl->s3->token_binding_negotiated) {
+    if (ssl->s3->channel_id_valid || ssl->s3->token_binding_negotiated) {
       OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION_ON_EARLY_DATA);
       return ssl_hs_error;
     }
diff --git a/ssl/tls13_server.cc b/ssl/tls13_server.cc
index 67aa5d0..3c2c774 100644
--- a/ssl/tls13_server.cc
+++ b/ssl/tls13_server.cc
@@ -392,8 +392,6 @@
           !ssl->s3->channel_id_valid &&
           // If Token Binding is negotiated, reject 0-RTT.
           !ssl->s3->token_binding_negotiated &&
-          // Custom extensions is incompatible with 0-RTT.
-          hs->custom_extensions.received == 0 &&
           // The negotiated ALPN must match the one in the ticket.
           MakeConstSpan(ssl->s3->alpn_selected) == session->early_alpn) {
         ssl->s3->early_data_accepted = true;