Commit 09c2bc5f6c for openssl.org

commit 09c2bc5f6c107ce97c396f2b7cc9118646085a0f
Author: Kurt Roeckx <kurt@roeckx.be>
Date:   Tue Jul 15 11:38:21 2025 +0200

    Remove support for SSLv2 Client Hello

    Drop support for the SSLv2 Client Hello. We allowed that a client send
    an SSLv2 compatible Client Hello.

    Reviewed-by: Dmitry Belyavskiy <beldmit@gmail.com>
    Reviewed-by: Alicja Kario <hkario@redhat.com>
    Reviewed-by: Tomas Mraz <tomas@openssl.org>
    Reviewed-by: Matt Caswell <matt@openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/28041)

diff --git a/CHANGES.md b/CHANGES.md
index 067a2b0752..ff960d0dcc 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -32,6 +32,15 @@ OpenSSL 4.0

 ### Changes between 3.6 and 4.0 [xx XXX xxxx]

+ * Remove support for an SSLv2 Client Hello. When a client wanted to support
+   both SSLv2 and higher versions like SSLv3 or even TLSv1, it needed to
+   send an SSLv2 Client Hello. SSLv2 support itself was removed in version
+   1.1.0, but there was still compatibility code for clients sending an SSLv2
+   Client Hello. Since we no longer support SSLv2 Client Hello,
+   SSL_client_hello_isv2() is now deprecated and always returns 0.
+
+   *Kurt Roeckx*
+
  * Added "ML-DSA-MU" digest algorithm support.

    *Shane Lontis*
diff --git a/NEWS.md b/NEWS.md
index f966d8cfda..30542709ce 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -36,6 +36,8 @@ OpenSSL 4.0

   * The crypto-mdebug-backtrace configuration option has been entirely removed.

+  * Support for the SSLv2 Client Hello was removed
+
 OpenSSL 3.6
 -----------

diff --git a/doc/man3/SSL_CTX_set_client_hello_cb.pod b/doc/man3/SSL_CTX_set_client_hello_cb.pod
index 6367c68a62..41defadf30 100644
--- a/doc/man3/SSL_CTX_set_client_hello_cb.pod
+++ b/doc/man3/SSL_CTX_set_client_hello_cb.pod
@@ -9,7 +9,6 @@ SSL_CTX_set_client_hello_cb, SSL_client_hello_cb_fn, SSL_client_hello_isv2, SSL_
  typedef int (*SSL_client_hello_cb_fn)(SSL *s, int *al, void *arg);
  void SSL_CTX_set_client_hello_cb(SSL_CTX *c, SSL_client_hello_cb_fn *f,
                                   void *arg);
- int SSL_client_hello_isv2(SSL *s);
  unsigned int SSL_client_hello_get0_legacy_version(SSL *s);
  size_t SSL_client_hello_get0_random(SSL *s, const unsigned char **out);
  size_t SSL_client_hello_get0_session_id(SSL *s, const unsigned char **out);
@@ -23,6 +22,12 @@ SSL_CTX_set_client_hello_cb, SSL_client_hello_cb_fn, SSL_client_hello_isv2, SSL_
  int SSL_client_hello_get0_ext(SSL *s, unsigned int type, const unsigned char **out,
                                size_t *outlen);

+The following functions have been deprecated since OpenSSL 4.0, and can be
+hidden entirely by defining B<OPENSSL_API_COMPAT> with a suitable version value,
+see L<openssl_user_macros(7)>:
+
+ int SSL_client_hello_isv2(SSL *s);
+
 =head1 DESCRIPTION

 SSL_CTX_set_client_hello_cb() sets the callback function, which is automatically
@@ -40,14 +45,9 @@ function, the ClientHello callback will be called again, and, if it returns
 success, normal handshake processing will continue from that point.

 SSL_client_hello_isv2() indicates whether the ClientHello was carried in a
-SSLv2 record and is in the SSLv2 format.  The SSLv2 format has substantial
-differences from the normal SSLv3 format, including using three bytes per
-cipher suite, and not allowing extensions.  Additionally, the SSLv2 format
-'challenge' field is exposed via SSL_client_hello_get0_random(), padded to
-SSL3_RANDOM_SIZE bytes with zeros if needed.  For SSLv2 format ClientHellos,
-SSL_client_hello_get0_compression_methods() returns a dummy list that only includes
-the null compression method, since the SSLv2 format does not include a
-mechanism by which to negotiate compression.
+SSLv2 record and is in the SSLv2 format.
+Support for the SSLv2 format was removed in 4.0 and this function
+will always return 0.

 SSL_client_hello_get0_random(), SSL_client_hello_get0_session_id(),
 SSL_client_hello_get0_ciphers(), and
@@ -117,7 +117,7 @@ The application's supplied ClientHello callback returns
 SSL_CLIENT_HELLO_SUCCESS on success, SSL_CLIENT_HELLO_ERROR on failure, and
 SSL_CLIENT_HELLO_RETRY to suspend processing.

-SSL_client_hello_isv2() returns 1 for SSLv2-format ClientHellos and 0 otherwise.
+SSL_client_hello_isv2() returns 0.

 SSL_client_hello_get0_random(), SSL_client_hello_get0_session_id(),
 SSL_client_hello_get0_ciphers(), and
diff --git a/doc/man3/SSL_get_ciphers.pod b/doc/man3/SSL_get_ciphers.pod
index add0fc4cd0..307f27e52d 100644
--- a/doc/man3/SSL_get_ciphers.pod
+++ b/doc/man3/SSL_get_ciphers.pod
@@ -51,12 +51,13 @@ list received from the client on B<ssl>. If B<ssl> is NULL, no ciphers are
 available, or B<ssl> is not operating in server mode, NULL is returned.

 SSL_bytes_to_cipher_list() treats the supplied B<len> octets in B<bytes>
-as a wire-protocol cipher suite specification (in the three-octet-per-cipher
-SSLv2 wire format if B<isv2format> is nonzero; otherwise the two-octet
-SSLv3/TLS wire format), and parses the cipher suites supported by the library
+as a wire-protocol cipher suite specification in the two-octet
+SSLv3/TLS wire format, and parses the cipher suites supported by the library
 into the returned stacks of SSL_CIPHER objects sk and Signalling Cipher-Suite
-Values scsvs.  Unsupported cipher suites are ignored.  Returns 1 on success
-and 0 on failure.
+Values scsvs.
+The B<isv2format> is no longer supported and should always be set to 0.
+Unsupported cipher suites are ignored.
+Returns 1 on success and 0 on failure.

 SSL_get_cipher_list() returns a pointer to the name of the SSL_CIPHER
 listed for B<ssl> with B<priority>. If B<ssl> is NULL, no ciphers are
diff --git a/include/openssl/ssl.h.in b/include/openssl/ssl.h.in
index 7882b8bc67..83d72e6fa8 100644
--- a/include/openssl/ssl.h.in
+++ b/include/openssl/ssl.h.in
@@ -1922,7 +1922,9 @@ typedef int (*SSL_new_pending_conn_cb_fn)(SSL_CTX *ctx, SSL *new_ssl,
 void SSL_CTX_set_new_pending_conn_cb(SSL_CTX *c, SSL_new_pending_conn_cb_fn cb,
     void *arg);

-int SSL_client_hello_isv2(SSL *s);
+#ifndef OPENSSL_NO_DEPRECATED_4_0
+OSSL_DEPRECATEDIN_4_0 int SSL_client_hello_isv2(SSL *s);
+#endif
 unsigned int SSL_client_hello_get0_legacy_version(SSL *s);
 size_t SSL_client_hello_get0_random(SSL *s, const unsigned char **out);
 size_t SSL_client_hello_get0_session_id(SSL *s, const unsigned char **out);
diff --git a/ssl/record/rec_layer_s3.c b/ssl/record/rec_layer_s3.c
index f4b249bf32..670b03ab0b 100644
--- a/ssl/record/rec_layer_s3.c
+++ b/ssl/record/rec_layer_s3.c
@@ -1122,17 +1122,6 @@ start:
     }
 }

-/*
- * Returns true if the current rrec was sent in SSLv2 backwards compatible
- * format and false otherwise.
- */
-int RECORD_LAYER_is_sslv2_record(RECORD_LAYER *rl)
-{
-    if (SSL_CONNECTION_IS_DTLS(rl->s))
-        return 0;
-    return rl->tlsrecs[0].version == SSL2_VERSION;
-}
-
 static OSSL_FUNC_rlayer_msg_callback_fn rlayer_msg_callback_wrapper;
 static void rlayer_msg_callback_wrapper(int write_p, int version,
     int content_type, const void *buf,
diff --git a/ssl/record/record.h b/ssl/record/record.h
index 8e7b883845..23c15f3b41 100644
--- a/ssl/record/record.h
+++ b/ssl/record/record.h
@@ -140,7 +140,6 @@ int RECORD_LAYER_reset(RECORD_LAYER *rl);
 int RECORD_LAYER_read_pending(const RECORD_LAYER *rl);
 int RECORD_LAYER_processed_read_pending(const RECORD_LAYER *rl);
 int RECORD_LAYER_write_pending(const RECORD_LAYER *rl);
-int RECORD_LAYER_is_sslv2_record(RECORD_LAYER *rl);
 __owur size_t ssl3_pending(const SSL *s);
 __owur int ssl3_write_bytes(SSL *s, uint8_t type, const void *buf, size_t len,
     size_t *written);
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index e82ac8c040..43ca1e46d7 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -6732,17 +6732,12 @@ void SSL_CTX_set_new_pending_conn_cb(SSL_CTX *c, SSL_new_pending_conn_cb_fn cb,
     c->new_pending_conn_arg = arg;
 }

+#ifndef OPENSSL_NO_DEPRECATED_4_0
 int SSL_client_hello_isv2(SSL *s)
 {
-    const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
-
-    if (sc == NULL)
-        return 0;
-
-    if (sc->clienthello == NULL)
-        return 0;
-    return sc->clienthello->isv2;
+    return 0;
 }
+#endif

 unsigned int SSL_client_hello_get0_legacy_version(SSL *s)
 {
@@ -7045,20 +7040,14 @@ int ssl_log_secret(SSL_CONNECTION *sc,
         secret_len);
 }

-#define SSLV2_CIPHER_LEN 3
-
-int ssl_cache_cipherlist(SSL_CONNECTION *s, PACKET *cipher_suites, int sslv2format)
+int ssl_cache_cipherlist(SSL_CONNECTION *s, PACKET *cipher_suites)
 {
-    int n;
-
-    n = sslv2format ? SSLV2_CIPHER_LEN : TLS_CIPHER_LEN;
-
     if (PACKET_remaining(cipher_suites) == 0) {
         SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_NO_CIPHERS_SPECIFIED);
         return 0;
     }

-    if (PACKET_remaining(cipher_suites) % n != 0) {
+    if (PACKET_remaining(cipher_suites) % TLS_CIPHER_LEN != 0) {
         SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST);
         return 0;
     }
@@ -7067,45 +7056,8 @@ int ssl_cache_cipherlist(SSL_CONNECTION *s, PACKET *cipher_suites, int sslv2form
     s->s3.tmp.ciphers_raw = NULL;
     s->s3.tmp.ciphers_rawlen = 0;

-    if (sslv2format) {
-        size_t numciphers = PACKET_remaining(cipher_suites) / n;
-        PACKET sslv2ciphers = *cipher_suites;
-        unsigned int leadbyte;
-        unsigned char *raw;
-
-        /*
-         * We store the raw ciphers list in SSLv3+ format so we need to do some
-         * preprocessing to convert the list first. If there are any SSLv2 only
-         * ciphersuites with a non-zero leading byte then we are going to
-         * slightly over allocate because we won't store those. But that isn't a
-         * problem.
-         */
-        raw = OPENSSL_malloc_array(numciphers, TLS_CIPHER_LEN);
-        s->s3.tmp.ciphers_raw = raw;
-        if (raw == NULL) {
-            SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_CRYPTO_LIB);
-            return 0;
-        }
-        for (s->s3.tmp.ciphers_rawlen = 0;
-            PACKET_remaining(&sslv2ciphers) > 0;
-            raw += TLS_CIPHER_LEN) {
-            if (!PACKET_get_1(&sslv2ciphers, &leadbyte)
-                || (leadbyte == 0
-                    && !PACKET_copy_bytes(&sslv2ciphers, raw,
-                        TLS_CIPHER_LEN))
-                || (leadbyte != 0
-                    && !PACKET_forward(&sslv2ciphers, TLS_CIPHER_LEN))) {
-                SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_BAD_PACKET);
-                OPENSSL_free(s->s3.tmp.ciphers_raw);
-                s->s3.tmp.ciphers_raw = NULL;
-                s->s3.tmp.ciphers_rawlen = 0;
-                return 0;
-            }
-            if (leadbyte == 0)
-                s->s3.tmp.ciphers_rawlen += TLS_CIPHER_LEN;
-        }
-    } else if (!PACKET_memdup(cipher_suites, &s->s3.tmp.ciphers_raw,
-                   &s->s3.tmp.ciphers_rawlen)) {
+    if (!PACKET_memdup(cipher_suites, &s->s3.tmp.ciphers_raw,
+            &s->s3.tmp.ciphers_rawlen)) {
         SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
         return 0;
     }
@@ -7119,27 +7071,24 @@ int SSL_bytes_to_cipher_list(SSL *s, const unsigned char *bytes, size_t len,
     PACKET pkt;
     SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);

-    if (sc == NULL)
+    if (sc == NULL || isv2format)
         return 0;

     if (!PACKET_buf_init(&pkt, bytes, len))
         return 0;
-    return ossl_bytes_to_cipher_list(sc, &pkt, sk, scsvs, isv2format, 0);
+    return ossl_bytes_to_cipher_list(sc, &pkt, sk, scsvs, 0);
 }

 int ossl_bytes_to_cipher_list(SSL_CONNECTION *s, PACKET *cipher_suites,
     STACK_OF(SSL_CIPHER) **skp,
     STACK_OF(SSL_CIPHER) **scsvs_out,
-    int sslv2format, int fatal)
+    int fatal)
 {
     const SSL_CIPHER *c;
     STACK_OF(SSL_CIPHER) *sk = NULL;
     STACK_OF(SSL_CIPHER) *scsvs = NULL;
-    int n;
-    /* 3 = SSLV2_CIPHER_LEN > TLS_CIPHER_LEN = 2. */
-    unsigned char cipher[SSLV2_CIPHER_LEN];
-
-    n = sslv2format ? SSLV2_CIPHER_LEN : TLS_CIPHER_LEN;
+    int n = TLS_CIPHER_LEN;
+    unsigned char cipher[TLS_CIPHER_LEN];

     if (PACKET_remaining(cipher_suites) == 0) {
         if (fatal)
@@ -7169,16 +7118,7 @@ int ossl_bytes_to_cipher_list(SSL_CONNECTION *s, PACKET *cipher_suites,
     }

     while (PACKET_copy_bytes(cipher_suites, cipher, n)) {
-        /*
-         * SSLv3 ciphers wrapped in an SSLv2-compatible ClientHello have the
-         * first byte set to zero, while true SSLv2 ciphers have a non-zero
-         * first byte. We don't support any true SSLv2 ciphers, so skip them.
-         */
-        if (sslv2format && cipher[0] != '\0')
-            continue;
-
-        /* For SSLv2-compat, ignore leading 0-byte. */
-        c = ssl_get_cipher_by_char(s, sslv2format ? &cipher[1] : cipher, 1);
+        c = ssl_get_cipher_by_char(s, cipher, 1);
         if (c != NULL) {
             if ((c->valid && !sk_SSL_CIPHER_push(sk, c)) || (!c->valid && !sk_SSL_CIPHER_push(scsvs, c))) {
                 if (fatal)
diff --git a/ssl/ssl_local.h b/ssl/ssl_local.h
index 994bfb7943..606fded111 100644
--- a/ssl/ssl_local.h
+++ b/ssl/ssl_local.h
@@ -639,7 +639,6 @@ typedef struct raw_extension_st {
 } RAW_EXTENSION;

 typedef struct {
-    unsigned int isv2;
     unsigned int legacy_version;
     unsigned char random[SSL3_RANDOM_SIZE];
     size_t session_id_len;
@@ -2506,11 +2505,10 @@ __owur STACK_OF(SSL_CIPHER) *ssl_create_cipher_list(SSL_CTX *ctx,
     STACK_OF(SSL_CIPHER) **cipher_list_by_id,
     const char *rule_str,
     CERT *c);
-__owur int ssl_cache_cipherlist(SSL_CONNECTION *s, PACKET *cipher_suites,
-    int sslv2format);
+__owur int ssl_cache_cipherlist(SSL_CONNECTION *s, PACKET *cipher_suites);
 __owur int ossl_bytes_to_cipher_list(SSL_CONNECTION *s, PACKET *cipher_suites,
     STACK_OF(SSL_CIPHER) **skp,
-    STACK_OF(SSL_CIPHER) **scsvs, int sslv2format,
+    STACK_OF(SSL_CIPHER) **scsvs,
     int fatal);
 void ssl_update_cache(SSL_CONNECTION *s, int mode);
 __owur int ssl_cipher_get_evp_cipher(SSL_CTX *ctx, const SSL_CIPHER *sslc,
diff --git a/ssl/statem/statem_lib.c b/ssl/statem/statem_lib.c
index 9e0c853c0d..3e3d00a8be 100644
--- a/ssl/statem/statem_lib.c
+++ b/ssl/statem/statem_lib.c
@@ -1595,32 +1595,16 @@ int tls_get_message_header(SSL_CONNECTION *s, int *mt)
     *mt = *p;
     s->s3.tmp.message_type = *(p++);

-    if (RECORD_LAYER_is_sslv2_record(&s->rlayer)) {
-        /*
-         * Only happens with SSLv3+ in an SSLv2 backward compatible
-         * ClientHello
-         *
-         * Total message size is the remaining record bytes to read
-         * plus the SSL3_HM_HEADER_LENGTH bytes that we already read
-         */
-        l = s->rlayer.tlsrecs[0].length + SSL3_HM_HEADER_LENGTH;
-        s->s3.tmp.message_size = l;
-
-        s->init_msg = s->init_buf->data;
-        s->init_num = SSL3_HM_HEADER_LENGTH;
-    } else {
-        n2l3(p, l);
-        /* BUF_MEM_grow takes an 'int' parameter */
-        if (l > (INT_MAX - SSL3_HM_HEADER_LENGTH)) {
-            SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER,
-                SSL_R_EXCESSIVE_MESSAGE_SIZE);
-            return 0;
-        }
-        s->s3.tmp.message_size = l;
-
-        s->init_msg = s->init_buf->data + SSL3_HM_HEADER_LENGTH;
-        s->init_num = 0;
+    n2l3(p, l);
+    /* BUF_MEM_grow takes an 'int' parameter */
+    if (l > (INT_MAX - SSL3_HM_HEADER_LENGTH)) {
+        SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_R_EXCESSIVE_MESSAGE_SIZE);
+        return 0;
     }
+    s->s3.tmp.message_size = l;
+
+    s->init_msg = s->init_buf->data + SSL3_HM_HEADER_LENGTH;
+    s->init_num = 0;

     return 1;
 }
@@ -1663,48 +1647,35 @@ int tls_get_message_body(SSL_CONNECTION *s, size_t *len)
         return 0;
     }

-    /* Feed this message into MAC computation. */
-    if (RECORD_LAYER_is_sslv2_record(&s->rlayer)) {
-        if (!ssl3_finish_mac(s, (unsigned char *)s->init_buf->data,
-                s->init_num)) {
-            /* SSLfatal() already called */
-            *len = 0;
-            return 0;
-        }
-        if (s->msg_callback)
-            s->msg_callback(0, SSL2_VERSION, 0, s->init_buf->data,
-                (size_t)s->init_num, ussl, s->msg_callback_arg);
-    } else {
-        /*
-         * We defer feeding in the HRR until later. We'll do it as part of
-         * processing the message
-         * The TLsv1.3 handshake transcript stops at the ClientFinished
-         * message.
-         */
+    /*
+     * We defer feeding in the HRR until later. We'll do it as part of
+     * processing the message
+     * The TLsv1.3 handshake transcript stops at the ClientFinished
+     * message.
+     */
 #define SERVER_HELLO_RANDOM_OFFSET (SSL3_HM_HEADER_LENGTH + 2)
-        /* KeyUpdate and NewSessionTicket do not need to be added */
-        if (!SSL_CONNECTION_IS_TLS13(s)
-            || (s->s3.tmp.message_type != SSL3_MT_NEWSESSION_TICKET
-                && s->s3.tmp.message_type != SSL3_MT_KEY_UPDATE)) {
-            if (s->s3.tmp.message_type != SSL3_MT_SERVER_HELLO
-                || s->init_num < SERVER_HELLO_RANDOM_OFFSET + SSL3_RANDOM_SIZE
-                || memcmp(hrrrandom,
-                       s->init_buf->data + SERVER_HELLO_RANDOM_OFFSET,
-                       SSL3_RANDOM_SIZE)
-                    != 0) {
-                if (!ssl3_finish_mac(s, (unsigned char *)s->init_buf->data,
-                        s->init_num + SSL3_HM_HEADER_LENGTH)) {
-                    /* SSLfatal() already called */
-                    *len = 0;
-                    return 0;
-                }
+    /* KeyUpdate and NewSessionTicket do not need to be added */
+    if (!SSL_CONNECTION_IS_TLS13(s)
+        || (s->s3.tmp.message_type != SSL3_MT_NEWSESSION_TICKET
+            && s->s3.tmp.message_type != SSL3_MT_KEY_UPDATE)) {
+        if (s->s3.tmp.message_type != SSL3_MT_SERVER_HELLO
+            || s->init_num < SERVER_HELLO_RANDOM_OFFSET + SSL3_RANDOM_SIZE
+            || memcmp(hrrrandom,
+                   s->init_buf->data + SERVER_HELLO_RANDOM_OFFSET,
+                   SSL3_RANDOM_SIZE)
+                != 0) {
+            if (!ssl3_finish_mac(s, (unsigned char *)s->init_buf->data,
+                    s->init_num + SSL3_HM_HEADER_LENGTH)) {
+                /* SSLfatal() already called */
+                *len = 0;
+                return 0;
             }
         }
-        if (s->msg_callback)
-            s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, s->init_buf->data,
-                (size_t)s->init_num + SSL3_HM_HEADER_LENGTH, ussl,
-                s->msg_callback_arg);
     }
+    if (s->msg_callback)
+        s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, s->init_buf->data,
+            (size_t)s->init_num + SSL3_HM_HEADER_LENGTH, ussl,
+            s->msg_callback_arg);

     *len = s->init_num;
     return 1;
diff --git a/ssl/statem/statem_srvr.c b/ssl/statem/statem_srvr.c
index db99d49706..bdb46716ef 100644
--- a/ssl/statem/statem_srvr.c
+++ b/ssl/statem/statem_srvr.c
@@ -1627,7 +1627,6 @@ MSG_PROCESS_RETURN tls_process_client_hello(SSL_CONNECTION *s, PACKET *pkt)
 {
     /* |cookie| will only be initialized for DTLS. */
     PACKET session_id, compression, extensions, cookie;
-    static const unsigned char null_compression = 0;
     CLIENTHELLO_MSG *clienthello = NULL;

     /* Check if this is actually an unexpected renegotiation ClientHello */
@@ -1657,156 +1656,65 @@ MSG_PROCESS_RETURN tls_process_client_hello(SSL_CONNECTION *s, PACKET *pkt)
     /*
      * First, parse the raw ClientHello data into the CLIENTHELLO_MSG structure.
      */
-    clienthello->isv2 = RECORD_LAYER_is_sslv2_record(&s->rlayer);
     PACKET_null_init(&cookie);

-    if (clienthello->isv2) {
-        unsigned int mt;
-
-        if (!SSL_IS_FIRST_HANDSHAKE(s)
-            || s->hello_retry_request != SSL_HRR_NONE) {
-            SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_R_UNEXPECTED_MESSAGE);
-            goto err;
-        }
-
-        /*-
-         * An SSLv3/TLSv1 backwards-compatible CLIENT-HELLO in an SSLv2
-         * header is sent directly on the wire, not wrapped as a TLS
-         * record. Our record layer just processes the message length and passes
-         * the rest right through. Its format is:
-         * Byte  Content
-         * 0-1   msg_length - decoded by the record layer
-         * 2     msg_type - s->init_msg points here
-         * 3-4   version
-         * 5-6   cipher_spec_length
-         * 7-8   session_id_length
-         * 9-10  challenge_length
-         * ...   ...
-         */
-
-        if (!PACKET_get_1(pkt, &mt)
-            || mt != SSL2_MT_CLIENT_HELLO) {
-            /*
-             * Should never happen. We should have tested this in the record
-             * layer in order to have determined that this is an SSLv2 record
-             * in the first place
-             */
-            SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
-            goto err;
-        }
-    }
-
     if (!PACKET_get_net_2(pkt, &clienthello->legacy_version)) {
         SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_LENGTH_TOO_SHORT);
         goto err;
     }

-    /* Parse the message and load client random. */
-    if (clienthello->isv2) {
-        /*
-         * Handle an SSLv2 backwards compatible ClientHello
-         * Note, this is only for SSLv3+ using the backward compatible format.
-         * Real SSLv2 is not supported, and is rejected below.
-         */
-        unsigned int ciphersuite_len, session_id_len, challenge_len;
-        PACKET challenge;
-
-        if (!PACKET_get_net_2(pkt, &ciphersuite_len)
-            || !PACKET_get_net_2(pkt, &session_id_len)
-            || !PACKET_get_net_2(pkt, &challenge_len)) {
-            SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_RECORD_LENGTH_MISMATCH);
-            goto err;
-        }
-
-        if (session_id_len > SSL_MAX_SSL_SESSION_ID_LENGTH) {
-            SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_R_LENGTH_MISMATCH);
-            goto err;
-        }
+    if (!PACKET_copy_bytes(pkt, clienthello->random, SSL3_RANDOM_SIZE)
+        || !PACKET_get_length_prefixed_1(pkt, &session_id)
+        || !PACKET_copy_all(&session_id, clienthello->session_id,
+            SSL_MAX_SSL_SESSION_ID_LENGTH,
+            &clienthello->session_id_len)) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_LENGTH_MISMATCH);
+        goto err;
+    }

-        if (!PACKET_get_sub_packet(pkt, &clienthello->ciphersuites,
-                ciphersuite_len)
-            || !PACKET_copy_bytes(pkt, clienthello->session_id, session_id_len)
-            || !PACKET_get_sub_packet(pkt, &challenge, challenge_len)
-            /* No extensions. */
-            || PACKET_remaining(pkt) != 0) {
-            SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_RECORD_LENGTH_MISMATCH);
+    if (SSL_CONNECTION_IS_DTLS(s)) {
+        if (!PACKET_get_length_prefixed_1(pkt, &cookie)) {
+            SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_LENGTH_MISMATCH);
             goto err;
         }
-        clienthello->session_id_len = session_id_len;
-
-        /* Load the client random and compression list. We use SSL3_RANDOM_SIZE
-         * here rather than sizeof(clienthello->random) because that is the limit
-         * for SSLv3 and it is fixed. It won't change even if
-         * sizeof(clienthello->random) does.
-         */
-        challenge_len = challenge_len > SSL3_RANDOM_SIZE
-            ? SSL3_RANDOM_SIZE
-            : challenge_len;
-        memset(clienthello->random, 0, SSL3_RANDOM_SIZE);
-        if (!PACKET_copy_bytes(&challenge,
-                clienthello->random + SSL3_RANDOM_SIZE - challenge_len, challenge_len)
-            /* Advertise only null compression. */
-            || !PACKET_buf_init(&compression, &null_compression, 1)) {
+        if (!PACKET_copy_all(&cookie, clienthello->dtls_cookie,
+                DTLS1_COOKIE_LENGTH,
+                &clienthello->dtls_cookie_len)) {
             SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
             goto err;
         }
-
-        PACKET_null_init(&clienthello->extensions);
-    } else {
-        /* Regular ClientHello. */
-        if (!PACKET_copy_bytes(pkt, clienthello->random, SSL3_RANDOM_SIZE)
-            || !PACKET_get_length_prefixed_1(pkt, &session_id)
-            || !PACKET_copy_all(&session_id, clienthello->session_id,
-                SSL_MAX_SSL_SESSION_ID_LENGTH,
-                &clienthello->session_id_len)) {
-            SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_LENGTH_MISMATCH);
-            goto err;
-        }
-
-        if (SSL_CONNECTION_IS_DTLS(s)) {
-            if (!PACKET_get_length_prefixed_1(pkt, &cookie)) {
-                SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_LENGTH_MISMATCH);
-                goto err;
-            }
-            if (!PACKET_copy_all(&cookie, clienthello->dtls_cookie,
-                    sizeof(clienthello->dtls_cookie),
-                    &clienthello->dtls_cookie_len)) {
-                SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
-                goto err;
-            }
-            /*
-             * If we require cookies and this ClientHello doesn't contain one,
-             * just return since we do not want to allocate any memory yet.
-             * So check cookie length...
-             */
-            if (SSL_get_options(SSL_CONNECTION_GET_SSL(s)) & SSL_OP_COOKIE_EXCHANGE) {
-                if (clienthello->dtls_cookie_len == 0) {
-                    OPENSSL_free(clienthello);
-                    return MSG_PROCESS_FINISHED_READING;
-                }
+        /*
+         * If we require cookies and this ClientHello doesn't contain one,
+         * just return since we do not want to allocate any memory yet.
+         * So check cookie length...
+         */
+        if (SSL_get_options(SSL_CONNECTION_GET_SSL(s)) & SSL_OP_COOKIE_EXCHANGE) {
+            if (clienthello->dtls_cookie_len == 0) {
+                OPENSSL_free(clienthello);
+                return MSG_PROCESS_FINISHED_READING;
             }
         }
+    }

-        if (!PACKET_get_length_prefixed_2(pkt, &clienthello->ciphersuites)) {
-            SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_LENGTH_MISMATCH);
-            goto err;
-        }
+    if (!PACKET_get_length_prefixed_2(pkt, &clienthello->ciphersuites)) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_LENGTH_MISMATCH);
+        goto err;
+    }

-        if (!PACKET_get_length_prefixed_1(pkt, &compression)) {
+    if (!PACKET_get_length_prefixed_1(pkt, &compression)) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_LENGTH_MISMATCH);
+        goto err;
+    }
+
+    /* Could be empty. */
+    if (PACKET_remaining(pkt) == 0) {
+        PACKET_null_init(&clienthello->extensions);
+    } else {
+        if (!PACKET_get_length_prefixed_2(pkt, &clienthello->extensions)
+            || PACKET_remaining(pkt) != 0) {
             SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_LENGTH_MISMATCH);
             goto err;
         }
-
-        /* Could be empty. */
-        if (PACKET_remaining(pkt) == 0) {
-            PACKET_null_init(&clienthello->extensions);
-        } else {
-            if (!PACKET_get_length_prefixed_2(pkt, &clienthello->extensions)
-                || PACKET_remaining(pkt) != 0) {
-                SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_LENGTH_MISMATCH);
-                goto err;
-            }
-        }
     }

     if (!PACKET_copy_all(&compression, clienthello->compressions,
@@ -1874,23 +1782,6 @@ static int tls_early_post_process_client_hello(SSL_CONNECTION *s)
     /* Set up the client_random */
     memcpy(s->s3.client_random, clienthello->random, SSL3_RANDOM_SIZE);

-    /* Choose the version */
-
-    if (clienthello->isv2) {
-        if (clienthello->legacy_version == SSL2_VERSION
-            || (clienthello->legacy_version & 0xff00)
-                != (SSL3_VERSION_MAJOR << 8)) {
-            /*
-             * This is real SSLv2 or something completely unknown. We don't
-             * support it.
-             */
-            SSLfatal(s, SSL_AD_PROTOCOL_VERSION, SSL_R_UNKNOWN_PROTOCOL);
-            goto err;
-        }
-        /* SSLv3/TLS */
-        s->client_version = clienthello->legacy_version;
-    }
-
     /* Choose the server SSL/TLS/DTLS version. */
     protverr = ssl_choose_server_version(s, clienthello, &dgrd);

@@ -1936,10 +1827,8 @@ static int tls_early_post_process_client_hello(SSL_CONNECTION *s)

     s->hit = 0;

-    if (!ssl_cache_cipherlist(s, &clienthello->ciphersuites,
-            clienthello->isv2)
-        || !ossl_bytes_to_cipher_list(s, &clienthello->ciphersuites, &ciphers,
-            &scsvs, clienthello->isv2, 1)) {
+    if (!ssl_cache_cipherlist(s, &clienthello->ciphersuites)
+        || !ossl_bytes_to_cipher_list(s, &clienthello->ciphersuites, &ciphers, &scsvs, 1)) {
         /* SSLfatal() already called */
         goto err;
     }
@@ -2017,7 +1906,7 @@ static int tls_early_post_process_client_hello(SSL_CONNECTION *s)
      * SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION setting will be
      * ignored.
      */
-    if (clienthello->isv2 || (s->new_session && (s->options & SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION))) {
+    if (s->new_session && (s->options & SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION)) {
         if (!ssl_get_new_session(s, 1)) {
             /* SSLfatal() already called */
             goto err;
diff --git a/test/cipherbytes_test.c b/test/cipherbytes_test.c
index 3e73781cfe..981a9cc13b 100644
--- a/test/cipherbytes_test.c
+++ b/test/cipherbytes_test.c
@@ -66,38 +66,6 @@ err:
     return ret;
 }

-static int test_v2(void)
-{
-    STACK_OF(SSL_CIPHER) *sk, *scsv;
-    /* ECDHE-ECDSA-AES256GCM, SSL2_RC4_1238_WITH_MD5,
-     * ECDHE-ECDSA-CHACHA20-POLY1305 */
-    const unsigned char bytes[] = { 0x00, 0x00, 0x35, 0x01, 0x00, 0x80,
-        0x00, 0x00, 0x33 };
-    int ret = 0;
-
-    if (!TEST_true(SSL_bytes_to_cipher_list(s, bytes, sizeof(bytes), 1,
-            &sk, &scsv))
-        || !TEST_ptr(sk)
-        || !TEST_int_eq(sk_SSL_CIPHER_num(sk), 2)
-        || !TEST_ptr(scsv)
-        || !TEST_int_eq(sk_SSL_CIPHER_num(scsv), 0))
-        goto err;
-    if (strcmp(SSL_CIPHER_get_name(sk_SSL_CIPHER_value(sk, 0)),
-            "AES256-SHA")
-            != 0
-        || strcmp(SSL_CIPHER_get_name(sk_SSL_CIPHER_value(sk, 1)),
-               "DHE-RSA-AES128-SHA")
-            != 0)
-        goto err;
-
-    ret = 1;
-
-err:
-    sk_SSL_CIPHER_free(sk);
-    sk_SSL_CIPHER_free(scsv);
-    return ret;
-}
-
 static int test_v3(void)
 {
     STACK_OF(SSL_CIPHER) *sk = NULL, *scsv = NULL;
@@ -139,7 +107,6 @@ int setup_tests(void)

     ADD_TEST(test_empty);
     ADD_TEST(test_unsupported);
-    ADD_TEST(test_v2);
     ADD_TEST(test_v3);
     return 1;
 }
diff --git a/test/recipes/70-test_sslrecords.t b/test/recipes/70-test_sslrecords.t
index fe26564d50..4f90929560 100644
--- a/test/recipes/70-test_sslrecords.t
+++ b/test/recipes/70-test_sslrecords.t
@@ -33,20 +33,19 @@ my $inject_recs_num = undef;
 my $content_type = undef;
 my $boundary_test_type = undef;
 my $fatal_alert = undef; # set by filters at expected fatal alerts
-my $sslv2testtype = undef;
 my $proxy_start_success = 0;

-plan tests => 44;
+plan tests => 34;

 SKIP: {
-    skip "TLS 1.2 is disabled", 22 if disabled("tls1_2");
+    skip "TLS 1.2 is disabled", 17 if disabled("tls1_2");
     # Run tests with TLS
     run_tests(0);
 }

 SKIP: {
-    skip "DTLS 1.2 is disabled", 22 if disabled("dtls1_2");
-    skip "DTLSProxy does not work on Windows", 22 if $^O =~ /^(MSWin32)$/;
+    skip "DTLS 1.2 is disabled", 17 if disabled("dtls1_2");
+    skip "DTLSProxy does not work on Windows", 17 if $^O =~ /^(MSWin32)$/;
     run_tests(1);
 }

@@ -107,7 +106,7 @@ sub run_tests
        "In context empty records test".($run_test_as_dtls == 1) ? " for DTLS" : " for TLS");

     SKIP: {
-        skip "Record tests not intended for dtls", 7 if $run_test_as_dtls == 1;
+        skip "Record tests not intended for dtls", 2 if $run_test_as_dtls == 1;
         #Test 3: Injecting too many in context empty records should fail
         $fatal_alert = 0;
         $proxy->clear();
@@ -128,76 +127,10 @@ sub run_tests
         $proxy->clientflags("-no_tls1_3");
         $proxy->start();
         ok($fatal_alert, "Fragmented alert records test");
-
-        #Run some SSLv2 ClientHello tests
-
-        use constant {
-            TLSV1_2_IN_SSLV2      => 0,
-            SSLV2_IN_SSLV2        => 1,
-            FRAGMENTED_IN_TLSV1_2 => 2,
-            FRAGMENTED_IN_SSLV2   => 3,
-            ALERT_BEFORE_SSLV2    => 4
-        };
-
-        # The TLSv1.2 in SSLv2 ClientHello need to run at security level 0
-        # because in a SSLv2 ClientHello we can't send extensions to indicate
-        # which signature algorithm we want to use, and the default is SHA1.
-
-        #Test 5: Inject an SSLv2 style record format for a TLSv1.2 ClientHello
-        $sslv2testtype = TLSV1_2_IN_SSLV2;
-        $proxy->clear();
-        $proxy->filter(\&add_sslv2_filter);
-        $proxy->serverflags("-tls1_2");
-        $proxy->clientflags("-no_tls1_3 -legacy_renegotiation");
-        $proxy->ciphers("AES128-SHA:\@SECLEVEL=0");
-        $proxy->start();
-        ok(TLSProxy::Message->success(), "TLSv1.2 in SSLv2 ClientHello test");
-
-        #Test 6: Inject an SSLv2 style record format for an SSLv2 ClientHello. We don't
-        #        support this so it should fail. We actually treat it as an unknown
-        #        protocol so we don't even send an alert in this case.
-        $sslv2testtype = SSLV2_IN_SSLV2;
-        $proxy->clear();
-        $proxy->serverflags("-tls1_2");
-        $proxy->clientflags("-no_tls1_3");
-        $proxy->ciphers("AES128-SHA:\@SECLEVEL=0");
-        $proxy->start();
-        ok(TLSProxy::Message->fail(), "SSLv2 in SSLv2 ClientHello test");
-
-        #Test 7: Sanity check ClientHello fragmentation. This isn't really an SSLv2 test
-        #        at all, but it gives us confidence that Test 8 fails for the right
-        #        reasons
-        $sslv2testtype = FRAGMENTED_IN_TLSV1_2;
-        $proxy->clear();
-        $proxy->serverflags("-tls1_2");
-        $proxy->clientflags("-no_tls1_3");
-        $proxy->ciphers("AES128-SHA:\@SECLEVEL=0");
-        $proxy->start();
-        ok(TLSProxy::Message->success(), "Fragmented ClientHello in TLSv1.2 test");
-
-        #Test 8: Fragment a TLSv1.2 ClientHello across a TLS1.2 record; an SSLv2
-        #        record; and another TLS1.2 record. This isn't allowed so should fail
-        $sslv2testtype = FRAGMENTED_IN_SSLV2;
-        $proxy->clear();
-        $proxy->serverflags("-tls1_2");
-        $proxy->clientflags("-no_tls1_3");
-        $proxy->ciphers("AES128-SHA:\@SECLEVEL=0");
-        $proxy->start();
-        ok(TLSProxy::Message->fail(), "Fragmented ClientHello in TLSv1.2/SSLv2 test");
-
-        #Test 9: Send a TLS warning alert before an SSLv2 ClientHello. This should
-        #        fail because an SSLv2 ClientHello must be the first record.
-        $sslv2testtype = ALERT_BEFORE_SSLV2;
-        $proxy->clear();
-        $proxy->serverflags("-tls1_2");
-        $proxy->clientflags("-no_tls1_3");
-        $proxy->ciphers("AES128-SHA:\@SECLEVEL=0");
-        $proxy->start();
-        ok(TLSProxy::Message->fail(), "Alert before SSLv2 ClientHello test");
    }
     #Unrecognised record type tests

-    #Test 10: Sending an unrecognised record type in TLS1.2 should fail
+    #Test 5: Sending an unrecognised record type in TLS1.2 should fail
     $fatal_alert = 0;
     $proxy->clear();
     if ($run_test_as_dtls == 1) {
@@ -220,7 +153,7 @@ sub run_tests
         skip "TLSv1.1 or DTLSv1 disabled", 1 if ($run_test_as_dtls == 0 && disabled("tls1_1"))
                                                  || ($run_test_as_dtls == 1 && disabled("dtls1"));

-        #Test 11: Sending an unrecognised record type in TLS1.1 should fail
+        #Test 6: Sending an unrecognised record type in TLS1.1 should fail
         $fatal_alert = 0;
         $proxy->clear();
         if ($run_test_as_dtls == 1) {
@@ -239,7 +172,7 @@ sub run_tests

     SKIP: {
         skip "Record tests not intended for dtls", 10 if $run_test_as_dtls == 1;
-        #Test 12: Sending a different record version in TLS1.2 should fail
+        #Test 7: Sending a different record version in TLS1.2 should fail
         $fatal_alert = 0;
         $proxy->clear();
         $proxy->clientflags("-tls1_2");
@@ -252,20 +185,20 @@ sub run_tests
             skip "TLSv1.3 disabled", 9
                 if disabled("tls1_3") || (disabled("ec") && disabled("dh"));

-            #Test 13: Sending a different record version in TLS1.3 should fail
+            #Test 8: Sending a different record version in TLS1.3 should fail
             $proxy->clear();
             $proxy->filter(\&change_version);
             $proxy->start();
             ok(TLSProxy::Message->fail(), "Changed record version in TLS1.3");

-            #Test 14: Sending an unrecognised record type in TLS1.3 should fail
+            #Test 9: Sending an unrecognised record type in TLS1.3 should fail
             $fatal_alert = 0;
             $proxy->clear();
             $proxy->filter(\&add_unknown_record_type);
             $proxy->start();
             ok($fatal_alert, "Unrecognised record type in TLS1.3");

-            #Test 15: Sending an outer record type other than app data once encrypted
+            #Test 10: Sending an outer record type other than app data once encrypted
             #should fail
             $fatal_alert = 0;
             $proxy->clear();
@@ -281,7 +214,7 @@ sub run_tests
                 NO_DATA_BETWEEN_KEY_UPDATE => 4,
             };

-            #Test 16: Sending a ServerHello which doesn't end on a record boundary
+            #Test 11: Sending a ServerHello which doesn't end on a record boundary
             #         should fail
             $fatal_alert = 0;
             $proxy->clear();
@@ -290,7 +223,7 @@ sub run_tests
             $proxy->start();
             ok($fatal_alert, "Record not on boundary in TLS1.3 (ServerHello)");

-            #Test 17: Sending a Finished which doesn't end on a record boundary
+            #Test 12: Sending a Finished which doesn't end on a record boundary
             #         should fail
             $fatal_alert = 0;
             $proxy->clear();
@@ -298,7 +231,7 @@ sub run_tests
             $proxy->start();
             ok($fatal_alert, "Record not on boundary in TLS1.3 (Finished)");

-            #Test 18: Sending a KeyUpdate which doesn't end on a record boundary
+            #Test 13: Sending a KeyUpdate which doesn't end on a record boundary
             #         should fail
             $fatal_alert = 0;
             $proxy->clear();
@@ -306,7 +239,7 @@ sub run_tests
             $proxy->start();
             ok($fatal_alert, "Record not on boundary in TLS1.3 (KeyUpdate)");

-            #Test 19: Sending application data in the middle of a fragmented KeyUpdate
+            #Test 14: Sending application data in the middle of a fragmented KeyUpdate
             #         should fail. Strictly speaking this is not a record boundary test
             #         but we use the same filter.
             $fatal_alert = 0;
@@ -315,7 +248,7 @@ sub run_tests
             $proxy->start();
             ok($fatal_alert, "Data between KeyUpdate");

-            #Test 20: Fragmented KeyUpdate. This should succeed. Strictly speaking this
+            #Test 15: Fragmented KeyUpdate. This should succeed. Strictly speaking this
             #         is not a record boundary test but we use the same filter.
             $proxy->clear();
             $boundary_test_type = NO_DATA_BETWEEN_KEY_UPDATE;
@@ -325,7 +258,7 @@ sub run_tests
             SKIP: {
                 skip "EC disabled", 1 if disabled("ec");

-                #Test 21: Force an HRR and change the "real" ServerHello to have a protocol
+                #Test 16: Force an HRR and change the "real" ServerHello to have a protocol
                 #         record version of 0x0301 (TLSv1.0). At this point we have already
                 #         decided that we are doing TLSv1.3 but are still using plaintext
                 #         records. The server should be sending a record version of 0x303
@@ -342,7 +275,7 @@ sub run_tests

     SKIP: {
         skip "DTLS only record tests", 1 if $run_test_as_dtls != 1;
-        #Test 22: We should ignore empty app data records
+        #Test 17: We should ignore empty app data records
         $proxy->clear();
         $proxy->filter(\&empty_app_data);
         $proxy->start();
@@ -452,153 +385,6 @@ sub add_frag_alert_filter
     push @{$records}, $record;
 }

-sub add_sslv2_filter
-{
-    my $proxy = shift;
-    my $clienthello;
-    my $record;
-
-    # We're only interested in the initial ClientHello
-    if ($proxy->flight != 0) {
-        return;
-    }
-
-    # Ditch the real ClientHello - we're going to replace it with our own
-    shift @{$proxy->record_list};
-
-    if ($sslv2testtype == ALERT_BEFORE_SSLV2) {
-        my $alert = pack('CC', TLSProxy::Message::AL_LEVEL_FATAL,
-                               TLSProxy::Message::AL_DESC_NO_RENEGOTIATION);
-        my $alertlen = length $alert;
-        $record = TLSProxy::Record->new(
-            0,
-            TLSProxy::Record::RT_ALERT,
-            TLSProxy::Record::VERS_TLS_1_2,
-            $alertlen,
-            0,
-            $alertlen,
-            $alertlen,
-            $alert,
-            $alert
-        );
-
-        push @{$proxy->record_list}, $record;
-    }
-
-    if ($sslv2testtype == ALERT_BEFORE_SSLV2
-            || $sslv2testtype == TLSV1_2_IN_SSLV2
-            || $sslv2testtype == SSLV2_IN_SSLV2) {
-        # This is an SSLv2 format ClientHello
-        $clienthello =
-            pack "C44",
-            0x01, # ClientHello
-            0x03, 0x03, #TLSv1.2
-            0x00, 0x03, # Ciphersuites len
-            0x00, 0x00, # Session id len
-            0x00, 0x20, # Challenge len
-            0x00, 0x00, 0x2f, #AES128-SHA
-            0x01, 0x18, 0x9F, 0x76, 0xEC, 0x57, 0xCE, 0xE5, 0xB3, 0xAB, 0x79, 0x90,
-            0xAD, 0xAC, 0x6E, 0xD1, 0x58, 0x35, 0x03, 0x97, 0x16, 0x10, 0x82, 0x56,
-            0xD8, 0x55, 0xFF, 0xE1, 0x8A, 0xA3, 0x2E, 0xF6; # Challenge
-
-        if ($sslv2testtype == SSLV2_IN_SSLV2) {
-            # Set the version to "real" SSLv2
-            vec($clienthello, 1, 8) = 0x00;
-            vec($clienthello, 2, 8) = 0x02;
-        }
-
-        my $chlen = length $clienthello;
-
-        $record = TLSProxy::Record->new(
-            0,
-            TLSProxy::Record::RT_HANDSHAKE,
-            TLSProxy::Record::VERS_TLS_1_2,
-            $chlen,
-            1, #SSLv2
-            $chlen,
-            $chlen,
-            $clienthello,
-            $clienthello
-        );
-
-        push @{$proxy->record_list}, $record;
-    } else {
-        # For this test we're using a real TLS ClientHello
-        $clienthello =
-            pack "C49",
-            0x01, # ClientHello
-            0x00, 0x00, 0x2D, # Message length
-            0x03, 0x03, # TLSv1.2
-            0x01, 0x18, 0x9F, 0x76, 0xEC, 0x57, 0xCE, 0xE5, 0xB3, 0xAB, 0x79, 0x90,
-            0xAD, 0xAC, 0x6E, 0xD1, 0x58, 0x35, 0x03, 0x97, 0x16, 0x10, 0x82, 0x56,
-            0xD8, 0x55, 0xFF, 0xE1, 0x8A, 0xA3, 0x2E, 0xF6, # Random
-            0x00, # Session id len
-            0x00, 0x04, # Ciphersuites len
-            0x00, 0x2f, # AES128-SHA
-            0x00, 0xff, # Empty reneg info SCSV
-            0x01, # Compression methods len
-            0x00, # Null compression
-            0x00, 0x00; # Extensions len
-
-        # Split this into 3: A TLS record; a SSLv2 record and a TLS record.
-        # We deliberately split the second record prior to the Challenge/Random
-        # and set the first byte of the random to 1. This makes the second SSLv2
-        # record look like an SSLv2 ClientHello
-        my $frag1 = substr $clienthello, 0, 6;
-        my $frag2 = substr $clienthello, 6, 32;
-        my $frag3 = substr $clienthello, 38;
-
-        my $fraglen = length $frag1;
-        $record = TLSProxy::Record->new(
-            0,
-            TLSProxy::Record::RT_HANDSHAKE,
-            TLSProxy::Record::VERS_TLS_1_2,
-            $fraglen,
-            0,
-            $fraglen,
-            $fraglen,
-            $frag1,
-            $frag1
-        );
-        push @{$proxy->record_list}, $record;
-
-        $fraglen = length $frag2;
-        my $recvers;
-        if ($sslv2testtype == FRAGMENTED_IN_SSLV2) {
-            $recvers = 1;
-        } else {
-            $recvers = 0;
-        }
-        $record = TLSProxy::Record->new(
-            0,
-            TLSProxy::Record::RT_HANDSHAKE,
-            TLSProxy::Record::VERS_TLS_1_2,
-            $fraglen,
-            $recvers,
-            $fraglen,
-            $fraglen,
-            $frag2,
-            $frag2
-        );
-        push @{$proxy->record_list}, $record;
-
-        $fraglen = length $frag3;
-        $record = TLSProxy::Record->new(
-            0,
-            TLSProxy::Record::RT_HANDSHAKE,
-            TLSProxy::Record::VERS_TLS_1_2,
-            $fraglen,
-            0,
-            $fraglen,
-            $fraglen,
-            $frag3,
-            $frag3
-        );
-        push @{$proxy->record_list}, $record;
-    }
-
-}
-
 sub add_unknown_record_type
 {
     my $proxy = shift;
diff --git a/util/libssl.num b/util/libssl.num
index d43e75f4d5..f8ca36f67d 100644
--- a/util/libssl.num
+++ b/util/libssl.num
@@ -298,7 +298,7 @@ SSL_get_srp_username                    ?	4_0_0	EXIST::FUNCTION:DEPRECATEDIN_3_0
 SSL_get_srp_userinfo                    ?	4_0_0	EXIST::FUNCTION:DEPRECATEDIN_3_0,SRP
 SSL_CTX_set_client_hello_cb             ?	4_0_0	EXIST::FUNCTION:
 SSL_CTX_set_new_pending_conn_cb         ?	4_0_0	EXIST::FUNCTION:
-SSL_client_hello_isv2                   ?	4_0_0	EXIST::FUNCTION:
+SSL_client_hello_isv2                   ?	4_0_0	EXIST::FUNCTION:DEPRECATEDIN_4_0
 SSL_client_hello_get0_legacy_version    ?	4_0_0	EXIST::FUNCTION:
 SSL_client_hello_get0_random            ?	4_0_0	EXIST::FUNCTION:
 SSL_client_hello_get0_session_id        ?	4_0_0	EXIST::FUNCTION: