Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / boringssl / src / ssl / s23_srvr.c
index 3a40819..ca8e5d6 100644 (file)
  * (eay@cryptsoft.com).  This product includes software written by Tim
  * Hudson (tjh@cryptsoft.com). */
 
+#include <assert.h>
 #include <stdio.h>
 
 #include <openssl/buf.h>
 #include "ssl_locl.h"
 
 static const SSL_METHOD *ssl23_get_server_method(int ver);
-int ssl23_get_client_hello(SSL *s);
+static int ssl23_get_client_hello(SSL *s);
+static int ssl23_get_v2_client_hello(SSL *s);
+
 static const SSL_METHOD *ssl23_get_server_method(int ver)
        {
        if (ver == SSL3_VERSION)
@@ -190,17 +193,38 @@ int ssl23_accept(SSL *s)
 
                        ssl3_init_finished_mac(s);
 
-                       s->state=SSL23_ST_SR_CLNT_HELLO_A;
+                       s->state=SSL23_ST_SR_CLNT_HELLO;
                        s->ctx->stats.sess_accept++;
                        s->init_num=0;
                        break;
 
-               case SSL23_ST_SR_CLNT_HELLO_A:
-               case SSL23_ST_SR_CLNT_HELLO_B:
+               case SSL23_ST_SR_CLNT_HELLO:
+                       s->shutdown = 0;
+                       ret = ssl23_get_client_hello(s);
+                       if (ret <= 0) goto end;
+                       break;
+
+               case SSL23_ST_SR_V2_CLNT_HELLO:
+                       ret = ssl23_get_v2_client_hello(s);
+                       if (ret <= 0) goto end;
+                       break;
+
+               case SSL23_ST_SR_SWITCH_VERSION:
+                       if (!ssl_init_wbio_buffer(s, 1))
+                               {
+                               ret = -1;
+                               goto end;
+                               }
+
+                       s->state = SSL3_ST_SR_CLNT_HELLO_A;
+                       s->method = ssl23_get_server_method(s->version);
+                       assert(s->method != NULL);
+                       s->handshake_func = s->method->ssl_accept;
+                       s->init_num = 0;
 
-                       s->shutdown=0;
-                       ret=ssl23_get_client_hello(s);
-                       if (ret >= 0) cb=NULL;
+                       /* NULL the callback; SSL_accept will call it instead. */
+                       cb = NULL;
+                       ret = SSL_accept(s);
                        goto end;
                        /* break; */
 
@@ -226,360 +250,275 @@ end:
        return(ret);
        }
 
-
-int ssl23_get_client_hello(SSL *s)
+/* ssl23_get_mutual_version determines the highest supported version for a
+ * client which reports a highest version of |client_version|. On success, it
+ * returns 1 and sets |*out_version| to the negotiated version. Otherwise, it
+ * returns 0. */
+static int ssl23_get_mutual_version(SSL *s, int *out_version, uint16_t client_version)
        {
-       char buf_space[11]; /* Request this many bytes in initial read.
-                            * We can detect SSL 3.0/TLS 1.0 Client Hellos
-                            * ('type == 3') correctly only when the following
-                            * is in a single record, which is not guaranteed by
-                            * the protocol specification:
-                            * Byte  Content
-                            *  0     type            \
-                            *  1/2   version          > record header
-                            *  3/4   length          /
-                            *  5     msg_type        \
-                            *  6-8   length           > Client Hello message
-                            *  9/10  client_version  /
-                            */
-       char *buf= &(buf_space[0]);
-       unsigned char *p,*d,*d_len,*dd;
-       unsigned int i;
-       unsigned int csl,sil,cl;
-       int n=0,j;
-       int type=0;
-       int v[2];
-
-       if (s->state == SSL23_ST_SR_CLNT_HELLO_A)
+       if (client_version >= TLS1_2_VERSION && !(s->options & SSL_OP_NO_TLSv1_2))
                {
-               /* read the initial header */
-               v[0]=v[1]=0;
-
-               if (!ssl3_setup_buffers(s)) goto err;
-
-               n=ssl23_read_bytes(s, sizeof buf_space);
-               if (n != sizeof buf_space) return(n); /* n == -1 || n == 0 */
-
-               p=s->packet;
-
-               memcpy(buf,p,n);
-
-               if ((p[0] & 0x80) && (p[2] == SSL2_MT_CLIENT_HELLO))
-                       {
-                       /*
-                        * SSLv2 header
-                        */
-                       if ((p[3] == 0x00) && (p[4] == 0x02))
-                               {
-                               v[0]=p[3]; v[1]=p[4];
-                               /* SSLv2 */
-                               if (!(s->options & SSL_OP_NO_SSLv2))
-                                       type=1;
-                               }
-                       else if (p[3] == SSL3_VERSION_MAJOR)
-                               {
-                               v[0]=p[3]; v[1]=p[4];
-                               /* SSLv3/TLSv1 */
-                               if (p[4] >= TLS1_VERSION_MINOR)
-                                       {
-                                       if (p[4] >= TLS1_2_VERSION_MINOR &&
-                                          !(s->options & SSL_OP_NO_TLSv1_2))
-                                               {
-                                               s->version=TLS1_2_VERSION;
-                                               s->state=SSL23_ST_SR_CLNT_HELLO_B;
-                                               }
-                                       else if (p[4] >= TLS1_1_VERSION_MINOR &&
-                                          !(s->options & SSL_OP_NO_TLSv1_1))
-                                               {
-                                               s->version=TLS1_1_VERSION;
-                                               /* type=2; */ /* done later to survive restarts */
-                                               s->state=SSL23_ST_SR_CLNT_HELLO_B;
-                                               }
-                                       else if (!(s->options & SSL_OP_NO_TLSv1))
-                                               {
-                                               s->version=TLS1_VERSION;
-                                               /* type=2; */ /* done later to survive restarts */
-                                               s->state=SSL23_ST_SR_CLNT_HELLO_B;
-                                               }
-                                       else if (!(s->options & SSL_OP_NO_SSLv3))
-                                               {
-                                               s->version=SSL3_VERSION;
-                                               /* type=2; */
-                                               s->state=SSL23_ST_SR_CLNT_HELLO_B;
-                                               }
-                                       else if (!(s->options & SSL_OP_NO_SSLv2))
-                                               {
-                                               type=1;
-                                               }
-                                       }
-                               else if (!(s->options & SSL_OP_NO_SSLv3))
-                                       {
-                                       s->version=SSL3_VERSION;
-                                       /* type=2; */
-                                       s->state=SSL23_ST_SR_CLNT_HELLO_B;
-                                       }
-                               else if (!(s->options & SSL_OP_NO_SSLv2))
-                                       type=1;
-
-                               }
-                       }
-               else if ((p[0] == SSL3_RT_HANDSHAKE) &&
-                        (p[1] == SSL3_VERSION_MAJOR) &&
-                        (p[5] == SSL3_MT_CLIENT_HELLO) &&
-                        ((p[3] == 0 && p[4] < 5 /* silly record length? */)
-                               || (p[9] >= p[1])))
-                       {
-                       /*
-                        * SSLv3 or tls1 header
-                        */
-                       
-                       v[0]=p[1]; /* major version (= SSL3_VERSION_MAJOR) */
-                       /* We must look at client_version inside the Client Hello message
-                        * to get the correct minor version.
-                        * However if we have only a pathologically small fragment of the
-                        * Client Hello message, this would be difficult, and we'd have
-                        * to read more records to find out.
-                        * No known SSL 3.0 client fragments ClientHello like this,
-                        * so we simply assume TLS 1.0 to avoid protocol version downgrade
-                        * attacks. */
-                       if (p[3] == 0 && p[4] < 6)
-                               {
-#if 0
-                               OPENSSL_PUT_ERROR(SSL, XXX, SSL_R_RECORD_TOO_SMALL);
-                               goto err;
-#else
-                               v[1] = TLS1_VERSION_MINOR;
-#endif
-                               }
-                       /* if major version number > 3 set minor to a value
-                        * which will use the highest version 3 we support.
-                        * If TLS 2.0 ever appears we will need to revise
-                        * this....
-                        */
-                       else if (p[9] > SSL3_VERSION_MAJOR)
-                               v[1]=0xff;
-                       else
-                               v[1]=p[10]; /* minor version according to client_version */
-                       if (v[1] >= TLS1_VERSION_MINOR)
-                               {
-                               if (v[1] >= TLS1_2_VERSION_MINOR &&
-                                       !(s->options & SSL_OP_NO_TLSv1_2))
-                                       {
-                                       s->version=TLS1_2_VERSION;
-                                       type=3;
-                                       }
-                               else if (v[1] >= TLS1_1_VERSION_MINOR &&
-                                       !(s->options & SSL_OP_NO_TLSv1_1))
-                                       {
-                                       s->version=TLS1_1_VERSION;
-                                       type=3;
-                                       }
-                               else if (!(s->options & SSL_OP_NO_TLSv1))
-                                       {
-                                       s->version=TLS1_VERSION;
-                                       type=3;
-                                       }
-                               else if (!(s->options & SSL_OP_NO_SSLv3))
-                                       {
-                                       s->version=SSL3_VERSION;
-                                       type=3;
-                                       }
-                               }
-                       else
-                               {
-                               /* client requests SSL 3.0 */
-                               if (!(s->options & SSL_OP_NO_SSLv3))
-                                       {
-                                       s->version=SSL3_VERSION;
-                                       type=3;
-                                       }
-                               else if (!(s->options & SSL_OP_NO_TLSv1))
-                                       {
-                                       /* we won't be able to use TLS of course,
-                                        * but this will send an appropriate alert */
-                                       s->version=TLS1_VERSION;
-                                       type=3;
-                                       }
-                               }
-                       }
-               else if ((strncmp("GET ", (char *)p,4) == 0) ||
-                        (strncmp("POST ",(char *)p,5) == 0) ||
-                        (strncmp("HEAD ",(char *)p,5) == 0) ||
-                        (strncmp("PUT ", (char *)p,4) == 0))
-                       {
-                       OPENSSL_PUT_ERROR(SSL, ssl23_get_client_hello, SSL_R_HTTP_REQUEST);
-                       goto err;
-                       }
-               else if (strncmp("CONNECT",(char *)p,7) == 0)
-                       {
-                       OPENSSL_PUT_ERROR(SSL, ssl23_get_client_hello, SSL_R_HTTPS_PROXY_REQUEST);
-                       goto err;
-                       }
+               *out_version = TLS1_2_VERSION;
+               return 1;
+               }
+       if (client_version >= TLS1_1_VERSION && !(s->options & SSL_OP_NO_TLSv1_1))
+               {
+               *out_version = TLS1_1_VERSION;
+               return 1;
+               }
+       if (client_version >= TLS1_VERSION && !(s->options & SSL_OP_NO_TLSv1))
+               {
+               *out_version = TLS1_VERSION;
+               return 1;
                }
+       if (client_version >= SSL3_VERSION && !(s->options & SSL_OP_NO_SSLv3))
+               {
+               *out_version = SSL3_VERSION;
+               return 1;
+               }
+       return 0;
+       }
 
-       if (s->version < TLS1_2_VERSION && tls1_suiteb(s))
+static int ssl23_get_client_hello(SSL *s)
+       {
+       uint8_t *p;
+       int n = 0;
+
+       /* Sniff enough of the input to determine ClientHello type and the
+        * client version. */
+       if (!ssl3_setup_buffers(s)) goto err;
+
+       /* Read the initial 11 bytes of the input. This is sufficient to
+        * determine the client version for a ClientHello or a
+        * V2ClientHello.
+        *
+        * ClientHello (assuming client_version is unfragmented):
+        * Byte  Content
+        *  0     type            \
+        *  1-2   version          > record header
+        *  3-4   length          /
+        *  5     msg_type        \
+        *  6-8   length           > Client Hello message
+        *  9-10  client_version  /
+        *
+        * V2ClientHello:
+        * Byte  Content
+        *  0-1   msg_length
+        *  2     msg_type
+        *  3-4   version
+        *  5-6   cipher_spec_length
+        *  7-8   session_id_length
+        *  9-10  challenge_length
+        */
+       n = ssl23_read_bytes(s, 11);
+       if (n <= 0)
+               return n;
+       assert(n == 11);
+
+       p = s->packet;
+
+       /* Some dedicated error codes for protocol mixups should the application
+        * wish to interpret them differently. (These do not overlap with
+        * ClientHello or V2ClientHello.) */
+       if ((strncmp("GET ", (char *)p, 4) == 0) ||
+               (strncmp("POST ",(char *)p, 5) == 0) ||
+               (strncmp("HEAD ",(char *)p, 5) == 0) ||
+               (strncmp("PUT ", (char *)p, 4) == 0))
                {
-               OPENSSL_PUT_ERROR(SSL, ssl23_get_client_hello, SSL_R_ONLY_TLS_1_2_ALLOWED_IN_SUITEB_MODE);
+               OPENSSL_PUT_ERROR(SSL, ssl23_get_client_hello, SSL_R_HTTP_REQUEST);
                goto err;
                }
-
-       if (s->state == SSL23_ST_SR_CLNT_HELLO_B)
+       if (strncmp("CONNECT",(char *)p, 7) == 0)
                {
-               /* we have SSLv3/TLSv1 in an SSLv2 header
-                * (other cases skip this state) */
-
-               type=2;
-               p=s->packet;
-               v[0] = p[3]; /* == SSL3_VERSION_MAJOR */
-               v[1] = p[4];
+               OPENSSL_PUT_ERROR(SSL, ssl23_get_client_hello, SSL_R_HTTPS_PROXY_REQUEST);
+               goto err;
+               }
 
-               n=((p[0]&0x7f)<<8)|p[1];
-               if (n > (1024*4))
+       /* Determine if this is a ClientHello or V2ClientHello. */
+       if ((p[0] & 0x80) && (p[2] == SSL2_MT_CLIENT_HELLO))
+               {
+               /* This is a V2ClientHello. Determine the version to
+                * use. */
+               uint16_t client_version = (p[3] << 8) | p[4];
+               if (!ssl23_get_mutual_version(s, &s->version, client_version))
                        {
-                       OPENSSL_PUT_ERROR(SSL, ssl23_get_client_hello, SSL_R_RECORD_TOO_LARGE);
+                       OPENSSL_PUT_ERROR(SSL, ssl23_get_client_hello, SSL_R_UNSUPPORTED_PROTOCOL);
                        goto err;
                        }
-
-               j=ssl23_read_bytes(s,n+2);
-               if (j <= 0) return(j);
-
-               ssl3_finish_mac(s, s->packet+2, s->packet_length-2);
-               if (s->msg_callback)
-                       s->msg_callback(0, SSL2_VERSION, 0, s->packet+2, s->packet_length-2, s, s->msg_callback_arg); /* CLIENT-HELLO */
-
-               p=s->packet;
-               p+=5;
-               n2s(p,csl);
-               n2s(p,sil);
-               n2s(p,cl);
-               d=(unsigned char *)s->init_buf->data;
-               if ((csl+sil+cl+11) != s->packet_length) /* We can't have TLS extensions in SSL 2.0 format
-                                                         * Client Hello, can we? Error condition should be
-                                                         * '>' otherweise */
+               /* Parse the entire V2ClientHello. */
+               s->state = SSL23_ST_SR_V2_CLNT_HELLO;
+               }
+       else if ((p[0] == SSL3_RT_HANDSHAKE) &&
+                (p[1] >= SSL3_VERSION_MAJOR) &&
+                (p[5] == SSL3_MT_CLIENT_HELLO))
+               {
+               /* This is a fragment of a ClientHello. We look at the
+                * client_hello to negotiate the version. However, this
+                * is difficult if we have only a pathologically small
+                * fragment. No known client fragments ClientHello like
+                * this, so we simply reject such connections to avoid
+                * protocol version downgrade attacks. */
+               uint16_t record_length = (p[3] << 8) | p[4];
+               uint16_t client_version;
+               if (record_length < 6)
                        {
-                       OPENSSL_PUT_ERROR(SSL, ssl23_get_client_hello, SSL_R_RECORD_LENGTH_MISMATCH);
+                       OPENSSL_PUT_ERROR(SSL, ssl23_get_client_hello, SSL_R_RECORD_TOO_SMALL);
                        goto err;
                        }
 
-               /* record header: msg_type ... */
-               *(d++) = SSL3_MT_CLIENT_HELLO;
-               /* ... and length (actual value will be written later) */
-               d_len = d;
-               d += 3;
-
-               /* client_version */
-               *(d++) = SSL3_VERSION_MAJOR; /* == v[0] */
-               *(d++) = v[1];
-
-               /* lets populate the random area */
-               /* get the challenge_length */
-               i=(cl > SSL3_RANDOM_SIZE)?SSL3_RANDOM_SIZE:cl;
-               memset(d,0,SSL3_RANDOM_SIZE);
-               memcpy(&(d[SSL3_RANDOM_SIZE-i]),&(p[csl+sil]),i);
-               d+=SSL3_RANDOM_SIZE;
-
-               /* no session-id reuse */
-               *(d++)=0;
-
-               /* ciphers */
-               j=0;
-               dd=d;
-               d+=2;
-               for (i=0; i<csl; i+=3)
-                       {
-                       if (p[i] != 0) continue;
-                       *(d++)=p[i+1];
-                       *(d++)=p[i+2];
-                       j+=2;
-                       }
-               s2n(j,dd);
-
-               /* COMPRESSION */
-               *(d++)=1;
-               *(d++)=0;
-               
-#if 0
-                /* copy any remaining data with may be extensions */
-               p = p+csl+sil+cl;
-               while (p <  s->packet+s->packet_length)
+               client_version = (p[9] << 8) | p[10];
+               if (!ssl23_get_mutual_version(s, &s->version, client_version))
                        {
-                       *(d++)=*(p++);
+                       OPENSSL_PUT_ERROR(SSL, ssl23_get_client_hello, SSL_R_UNSUPPORTED_PROTOCOL);
+                       goto err;
                        }
-#endif
 
-               i = (d-(unsigned char *)s->init_buf->data) - 4;
-               l2n3((long)i, d_len);
+                /* Reset the record-layer state for SSL3. */
+                assert(s->rstate == SSL_ST_READ_HEADER);
+                s->s3->rbuf.left = s->packet_length;
+                s->s3->rbuf.offset = 0;
+                s->packet_length = 0;
 
-               /* get the data reused from the init_buf */
-               s->s3->tmp.reuse_message=1;
-               s->s3->tmp.message_type=SSL3_MT_CLIENT_HELLO;
-               s->s3->tmp.message_size=i;
+               /* Ready to switch versions. */
+               s->state = SSL23_ST_SR_SWITCH_VERSION;
                }
 
-       /* imaginary new state (for program structure): */
-       /* s->state = SSL23_SR_CLNT_HELLO_C */
+       return 1;
+err:
+       return -1;
+       }
 
-       if (type == 1)
+static int ssl23_get_v2_client_hello(SSL *s)
+       {
+       uint8_t *p;
+       size_t i;
+       int n = 0;
+
+       CBS v2_client_hello, cipher_specs, session_id, challenge;
+       size_t msg_length, len;
+       uint8_t msg_type;
+       uint16_t version, cipher_spec_length, session_id_length, challenge_length;
+       CBB client_hello, hello_body, cipher_suites;
+       uint8_t random[SSL3_RANDOM_SIZE];
+
+       /* Read the remainder of the V2ClientHello. We have previously read 11
+        * bytes in ssl23_get_client_hello. */
+       p = s->packet;
+       msg_length = ((p[0] & 0x7f) << 8) | p[1];
+       if (msg_length > (1024 * 4))
                {
-               OPENSSL_PUT_ERROR(SSL, ssl23_get_client_hello, SSL_R_UNSUPPORTED_PROTOCOL);
+               OPENSSL_PUT_ERROR(SSL, ssl23_get_v2_client_hello, SSL_R_RECORD_TOO_LARGE);
                goto err;
                }
-
-       if ((type == 2) || (type == 3))
+       if (msg_length < 11 - 2)
+               {
+               /* Reject lengths that are too short early. We have already read
+                * 11 bytes, so we should not attempt to process an (invalid)
+                * V2ClientHello which would be shorter than that. */
+               OPENSSL_PUT_ERROR(SSL, ssl23_get_v2_client_hello, SSL_R_RECORD_LENGTH_MISMATCH);
+               goto err;
+               }
+       n = ssl23_read_bytes(s, msg_length + 2);
+       if (n <= 0)
+               return n;
+       assert(n == s->packet_length);
+
+       /* The V2ClientHello without the length is incorporated into the
+        * Finished hash. */
+       ssl3_finish_mac(s, s->packet + 2, s->packet_length - 2);
+       if (s->msg_callback)
+               s->msg_callback(0, SSL2_VERSION, 0, s->packet+2, s->packet_length-2, s, s->msg_callback_arg); /* CLIENT-HELLO */
+
+       CBS_init(&v2_client_hello, s->packet + 2, s->packet_length - 2);
+       if (!CBS_get_u8(&v2_client_hello, &msg_type) ||
+               !CBS_get_u16(&v2_client_hello, &version) ||
+               !CBS_get_u16(&v2_client_hello, &cipher_spec_length) ||
+               !CBS_get_u16(&v2_client_hello, &session_id_length) ||
+               !CBS_get_u16(&v2_client_hello, &challenge_length) ||
+               !CBS_get_bytes(&v2_client_hello, &cipher_specs, cipher_spec_length) ||
+               !CBS_get_bytes(&v2_client_hello, &session_id, session_id_length) ||
+               !CBS_get_bytes(&v2_client_hello, &challenge, challenge_length) ||
+               CBS_len(&v2_client_hello) != 0)
                {
-               /* we have SSLv3/TLSv1 (type 2: SSL2 style, type 3: SSL3/TLS style) */
+               OPENSSL_PUT_ERROR(SSL, ssl23_get_v2_client_hello, SSL_R_DECODE_ERROR);
+               goto err;
+               }
 
-               if (!ssl_init_wbio_buffer(s,1)) goto err;
+       /* msg_type has already been checked. */
+       assert(msg_type == SSL2_MT_CLIENT_HELLO);
 
-               /* we are in this state */
-               s->state=SSL3_ST_SR_CLNT_HELLO_A;
+       /* The client_random is the V2ClientHello challenge. Truncate or
+        * left-pad with zeros as needed. */
+       memset(random, 0, SSL3_RANDOM_SIZE);
+       i = (CBS_len(&challenge) > SSL3_RANDOM_SIZE) ? SSL3_RANDOM_SIZE : CBS_len(&challenge);
+       memcpy(random, CBS_data(&challenge), i);
 
-               if (type == 3)
+       /* Write out an equivalent SSLv3 ClientHello. */
+       if (!CBB_init_fixed(&client_hello, (uint8_t *)s->init_buf->data, s->init_buf->max))
+               {
+               OPENSSL_PUT_ERROR(SSL, ssl23_get_v2_client_hello, ERR_R_MALLOC_FAILURE);
+               goto err;
+               }
+       if (!CBB_add_u8(&client_hello, SSL3_MT_CLIENT_HELLO) ||
+               !CBB_add_u24_length_prefixed(&client_hello, &hello_body) ||
+               !CBB_add_u16(&hello_body, version) ||
+               !CBB_add_bytes(&hello_body, random, SSL3_RANDOM_SIZE) ||
+               /* No session id. */
+               !CBB_add_u8(&hello_body, 0) ||
+               !CBB_add_u16_length_prefixed(&hello_body, &cipher_suites))
+               {
+               CBB_cleanup(&client_hello);
+               OPENSSL_PUT_ERROR(SSL, ssl23_get_v2_client_hello, ERR_R_INTERNAL_ERROR);
+               goto err;
+               }
+
+       /* Copy the cipher suites. */
+       while (CBS_len(&cipher_specs) > 0)
+               {
+               uint32_t cipher_spec;
+               if (!CBS_get_u24(&cipher_specs, &cipher_spec))
                        {
-                       /* put the 'n' bytes we have read into the input buffer
-                        * for SSLv3 */
-                       s->rstate=SSL_ST_READ_HEADER;
-                       s->packet_length=n;
-                       if (s->s3->rbuf.buf == NULL)
-                               if (!ssl3_setup_read_buffer(s))
-                                       goto err;
-
-                       s->packet= &(s->s3->rbuf.buf[0]);
-                       memcpy(s->packet,buf,n);
-                       s->s3->rbuf.left=n;
-                       s->s3->rbuf.offset=0;
+                       CBB_cleanup(&client_hello);
+                       OPENSSL_PUT_ERROR(SSL, ssl23_get_v2_client_hello, SSL_R_DECODE_ERROR);
+                       goto err;
                        }
-               else
+
+               /* Skip SSLv2 ciphers. */
+               if ((cipher_spec & 0xff0000) != 0)
+                       continue;
+               if (!CBB_add_u16(&cipher_suites, cipher_spec))
                        {
-                       s->packet_length=0;
-                       s->s3->rbuf.left=0;
-                       s->s3->rbuf.offset=0;
+                       CBB_cleanup(&client_hello);
+                       OPENSSL_PUT_ERROR(SSL, ssl23_get_v2_client_hello, ERR_R_INTERNAL_ERROR);
+                       goto err;
                        }
-               if (s->version == TLS1_2_VERSION)
-                       s->method = TLSv1_2_server_method();
-               else if (s->version == TLS1_1_VERSION)
-                       s->method = TLSv1_1_server_method();
-               else if (s->version == TLS1_VERSION)
-                       s->method = TLSv1_server_method();
-               else
-                       s->method = SSLv3_server_method();
-#if 0 /* ssl3_get_client_hello does this */
-               s->client_version=(v[0]<<8)|v[1];
-#endif
-               s->handshake_func=s->method->ssl_accept;
                }
-       
-       if ((type < 1) || (type > 3))
+
+       /* Add the null compression scheme and finish. */
+       if (!CBB_add_u8(&hello_body, 1) ||
+               !CBB_add_u8(&hello_body, 0) ||
+               !CBB_finish(&client_hello, NULL, &len))
                {
-               /* bad, very bad */
-               OPENSSL_PUT_ERROR(SSL, ssl23_get_client_hello, SSL_R_UNKNOWN_PROTOCOL);
+               CBB_cleanup(&client_hello);
+               OPENSSL_PUT_ERROR(SSL, ssl23_get_v2_client_hello, ERR_R_INTERNAL_ERROR);
                goto err;
                }
-       s->init_num=0;
 
-       if (buf != buf_space) OPENSSL_free(buf);
-       return(SSL_accept(s));
+       /* Mark the message for "re"-use by the version-specific
+        * method. */
+       s->s3->tmp.reuse_message = 1;
+       s->s3->tmp.message_type = SSL3_MT_CLIENT_HELLO;
+       /* The handshake message header is 4 bytes. */
+       s->s3->tmp.message_size = len - 4;
+
+       /* Reset the record layer for SSL3. */
+       assert(s->rstate == SSL_ST_READ_HEADER);
+       s->packet_length = 0;
+       s->s3->rbuf.left = 0;
+       s->s3->rbuf.offset = 0;
+
+       s->state = SSL23_ST_SR_SWITCH_VERSION;
+       return 1;
 err:
-       if (buf != buf_space) OPENSSL_free(buf);
-       return(-1);
+       return -1;
        }