Client side version negotiation rewrite
authorMatt Caswell <matt@openssl.org>
Mon, 30 Mar 2015 23:18:31 +0000 (00:18 +0100)
committerMatt Caswell <matt@openssl.org>
Sat, 16 May 2015 08:20:31 +0000 (09:20 +0100)
Continuing from the previous commit this changes the way we do client side
version negotiation. Similarly all of the s23* "up front" state machine code
has been avoided and again things now work much the same way as they already
did for DTLS, i.e. we just do most of the work in the
ssl3_get_server_hello() function.

Reviewed-by: Kurt Roeckx <kurt@openssl.org>
15 files changed:
apps/ocsp.c
apps/s_client.c
apps/s_time.c
demos/bio/client-arg.c
demos/bio/client-conf.c
demos/bio/sconnect.c
demos/easy_tls/easy-tls.c
demos/ssl/cli.cpp
include/openssl/ssl.h
ssl/record/rec_layer_s3.c
ssl/record/ssl3_record.c
ssl/s23_clnt.c
ssl/s3_clnt.c
ssl/t1_clnt.c
util/ssleay.num

index d52da18a5ec7c0e5d815bbc135bfccd9f99446d6..c71b0d6d2cba0f260b1a8d1cf9a26cf462c3fab9 100644 (file)
@@ -1261,7 +1261,7 @@ OCSP_RESPONSE *process_responder(OCSP_REQUEST *req,
         BIO_set_conn_port(cbio, port);
     if (use_ssl == 1) {
         BIO *sbio;
-        ctx = SSL_CTX_new(SSLv23_client_method());
+        ctx = SSL_CTX_new(TLS_client_method());
         if (ctx == NULL) {
             BIO_printf(bio_err, "Error creating SSL context.\n");
             goto end;
index ba411f2e11d6874fc316cb20bda03a5b655a3e80..339e4517db4357947cf1ffeafa48caf96c81f4bb 100644 (file)
@@ -636,7 +636,7 @@ int s_client_main(int argc, char **argv)
     SSL_CONF_CTX *cctx = NULL;
     STACK_OF(OPENSSL_STRING) *ssl_args = NULL;
     STACK_OF(X509_CRL) *crls = NULL;
-    const SSL_METHOD *meth = SSLv23_client_method();
+    const SSL_METHOD *meth = TLS_client_method();
     char *CApath = NULL, *CAfile = NULL, *cbuf = NULL, *sbuf = NULL, *mbuf =
         NULL;
     char *cert_file = NULL, *key_file = NULL, *chain_file = NULL, *prog;
index 5bca72ba72bad4ea2d6857bf8641c970ede78cad..74decd23bcbdc64f1c96d7924f99c8c400fbe318 100644 (file)
@@ -167,7 +167,7 @@ int s_time_main(int argc, char **argv)
     int exitNow = 0;            /* Set when it's time to exit main */
 #endif
 
-    meth = SSLv23_client_method();
+    meth = TLS_client_method();
     verify_depth = 0;
     verify_error = X509_V_OK;
 
index 8507e04f497d8f3480992b29d2a0aa5d878deef6..99ebff1f2a94626e6376fc9205e553806d6288a1 100644 (file)
@@ -17,7 +17,7 @@ int main(int argc, char **argv)
     ERR_load_SSL_strings();
     SSL_library_init();
 
-    ctx = SSL_CTX_new(SSLv23_client_method());
+    ctx = SSL_CTX_new(TLS_client_method());
     cctx = SSL_CONF_CTX_new();
     SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_CLIENT);
     SSL_CONF_CTX_set_ssl_ctx(cctx, ctx);
index b75088a7580f687c7eb00f2314af4c4775b0415b..2a783151659a3b1c026792be81e891cb75448a42 100644 (file)
@@ -37,7 +37,7 @@ int main(int argc, char **argv)
         goto end;
     }
 
-    ctx = SSL_CTX_new(SSLv23_client_method());
+    ctx = SSL_CTX_new(TLS_client_method());
     cctx = SSL_CONF_CTX_new();
     SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_CLIENT);
     SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_FILE);
index 6e4ca6596b6f069d36fcc21f27ec6048cf570246..865d50395692998918b5353649f7b6714e0c4d40 100644 (file)
@@ -43,7 +43,7 @@ char *argv[];
 
     /* Setup all the global SSL stuff */
     OpenSSL_add_ssl_algorithms();
-    ssl_ctx = SSL_CTX_new(SSLv23_client_method());
+    ssl_ctx = SSL_CTX_new(TLS_client_method());
 
     /* Lets make a SSL structure */
     ssl = SSL_new(ssl_ctx);
index 2befb657a0bc2e3c5f859b0fed97581380d193f6..b9512909d14255f83009afa112d3e5f80abdb7b2 100644 (file)
@@ -667,7 +667,7 @@ SSL_CTX *tls_create_ctx(struct tls_create_ctx_args a, void *apparg)
         return NULL;
 
     ret =
-        SSL_CTX_new((a.client_p ? SSLv23_client_method :
+        SSL_CTX_new((a.client_p ? TLS_client_method :
                      TLS_server_method) ());
 
     if (ret == NULL)
index cb5d329ea42da8f55a5c1cbedaa36ca745c71fd7..3459f0f93ac1010b0419b2a02f2170b29fb2d297 100644 (file)
@@ -38,7 +38,7 @@ void main ()
   SSL_METHOD *meth;
 
   SSLeay_add_ssl_algorithms();
-  meth = SSLv23_client_method();
+  meth = TLS_client_method();
   SSL_load_error_strings();
   ctx = SSL_CTX_new (meth);                        CHK_NULL(ctx);
 
index f169fcd2a9c5be8a3706a37c135c90dcde7b9cb7..3f30bc2a8833bc24cbfcd8cda7cac0adf2b9152b 100644 (file)
@@ -1565,14 +1565,13 @@ __owur const SSL_METHOD *SSLv3_client_method(void); /* SSLv3 */
 #ifdef OPENSSL_USE_DEPRECATED
 #define SSLv23_method           TLS_method
 #define SSLv23_server_method    TLS_server_method
+#define SSLv23_client_method    TLS_client_method
 #endif
-/* This next one will be deprecated in a subsequent commit */
-__owur const SSL_METHOD *SSLv23_client_method(void); /* Negotiate highest available
-                                               * SSL/TLS version */
 
 /* Negotiate highest available SSL/TLS version */
 __owur const SSL_METHOD *TLS_method(void);
 __owur const SSL_METHOD *TLS_server_method(void);
+__owur const SSL_METHOD *TLS_client_method(void);
 
 __owur const SSL_METHOD *TLSv1_method(void); /* TLSv1.0 */
 __owur const SSL_METHOD *TLSv1_server_method(void); /* TLSv1.0 */
index 97f6e900c563af79e544486b8f82c7989729edbe..c20af880e31c4e744d5dab1085e58da772f8ed7e 100644 (file)
@@ -1124,6 +1124,20 @@ int ssl3_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek)
         goto f_err;
     }
 
+    if(s->version == TLS_ANY_VERSION
+            && (s->server || rr->type != SSL3_RT_ALERT)) {
+        /*
+         * If we've got this far and still haven't decided on what version
+         * we're using then this must be a client side alert we're dealing with
+         * (we don't allow heartbeats yet). We shouldn't be receiving anything
+         * other than a ClientHello if we are a server.
+         */
+        s->version = rr->rec_version;
+        al = SSL_AD_UNEXPECTED_MESSAGE;
+        SSLerr(SSL_F_SSL3_READ_BYTES, SSL_R_UNEXPECTED_MESSAGE);
+        goto f_err;
+    }
+
     /*
      * In case of record types for which we have 'fragment' storage, fill
      * that so that we can process the data at a fixed place.
index 190abd26e857c95a27b860dbfbe49b0a3f23ae3e..ff09f0b16ae197394ba38b54a7dff0128cef90cf 100644 (file)
@@ -263,7 +263,8 @@ int ssl3_get_record(SSL *s)
 
             /* Lets check version */
             if (!s->first_packet) {
-                if (version != s->version) {
+                if (version != s->version
+                        && s->method->version != TLS_ANY_VERSION) {
                     SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_WRONG_VERSION_NUMBER);
                     if ((s->version & 0xFF00) == (version & 0xFF00)
                         && !s->enc_write_ctx && !s->write_hash)
index 34343402c88fb8abdb71bd30d64169add3580faf..75a0582f95b86ffd5675e5a3ff1ed3c45364dd17 100644 (file)
 #include <openssl/objects.h>
 #include <openssl/evp.h>
 
-static const SSL_METHOD *ssl23_get_client_method(int ver);
+/*static const SSL_METHOD *ssl23_get_client_method(int ver);*/
 static int ssl23_client_hello(SSL *s);
 static int ssl23_get_server_hello(SSL *s);
+
+/*
 static const SSL_METHOD *ssl23_get_client_method(int ver)
 {
 #ifndef OPENSSL_NO_SSL3
@@ -134,10 +136,7 @@ static const SSL_METHOD *ssl23_get_client_method(int ver)
     else
         return (NULL);
 }
-
-IMPLEMENT_ssl23_meth_func(SSLv23_client_method,
-                          ssl_undefined_function,
-                          ssl23_connect, ssl23_get_client_method)
+*/
 
 int ssl23_connect(SSL *s)
 {
index 2228654f8e218276300e9eef70b8e7d16c6c12b8..1bc5bcd9b1ff2c5040bedf3016e7685a1fd91340 100644 (file)
@@ -234,7 +234,8 @@ int ssl3_connect(SSL *s)
             if (cb != NULL)
                 cb(s, SSL_CB_HANDSHAKE_START, 1);
 
-            if ((s->version & 0xff00) != 0x0300) {
+            if ((s->version >> 8) != SSL3_VERSION_MAJOR
+                    && s->version != TLS_ANY_VERSION) {
                 SSLerr(SSL_F_SSL3_CONNECT, ERR_R_INTERNAL_ERROR);
                 s->state = SSL_ST_ERR;
                 ret = -1;
@@ -679,27 +680,46 @@ int ssl3_client_hello(SSL *s)
     int j;
     SSL_COMP *comp;
 #endif
+    unsigned long mask, options = s->options;
 
     buf = (unsigned char *)s->init_buf->data;
     if (s->state == SSL3_ST_CW_CLNT_HELLO_A) {
         SSL_SESSION *sess = s->session;
-        if ((sess == NULL) || (sess->ssl_version != s->version) ||
-#ifdef OPENSSL_NO_TLSEXT
-            !sess->session_id_length ||
-#else
+
+        if (s->method->version == TLS_ANY_VERSION ) {
             /*
-             * In the case of EAP-FAST, we can have a pre-shared
-             * "ticket" without a session ID.
+             * SSL_OP_NO_X disables all protocols above X *if* there are
+             * some protocols below X enabled. This is required in order
+             * to maintain "version capability" vector contiguous. So
+             * that if application wants to disable TLS1.0 in favour of
+             * TLS1>=1, it would be insufficient to pass SSL_NO_TLSv1, the
+             * answer is SSL_OP_NO_TLSv1|SSL_OP_NO_SSLv3.
              */
-            (!sess->session_id_length && !sess->tlsext_tick) ||
+            mask = SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1
+#if !defined(OPENSSL_NO_SSL3)
+                | SSL_OP_NO_SSLv3
 #endif
-            (sess->not_resumable)) {
-            if (!ssl_get_new_session(s, 0))
-                goto err;
-        }
-        if (s->method->version == DTLS_ANY_VERSION) {
+                ;
+#if !defined(OPENSSL_NO_TLS1_2_CLIENT)
+            s->version = TLS1_2_VERSION;
+
+            if ((options & SSL_OP_NO_TLSv1_2) && (options & mask) != mask)
+                s->version = TLS1_1_VERSION;
+#else
+            s->version = TLS1_1_VERSION;
+#endif
+            mask &= ~SSL_OP_NO_TLSv1_1;
+            if ((options & SSL_OP_NO_TLSv1_1) && (options & mask) != mask)
+                s->version = TLS1_VERSION;
+            mask &= ~SSL_OP_NO_TLSv1;
+#if !defined(OPENSSL_NO_SSL3)
+            if ((options & SSL_OP_NO_TLSv1) && (options & mask) != mask)
+                s->version = SSL3_VERSION;
+            mask &= ~SSL_OP_NO_SSLv3;
+#endif
+            s->client_version = s->version;
+        } else if (s->method->version == DTLS_ANY_VERSION) {
             /* Determine which DTLS version to use */
-            int options = s->options;
             /* If DTLS 1.2 disabled correct the version number */
             if (options & SSL_OP_NO_DTLSv1_2) {
                 if (tls1_suiteb(s)) {
@@ -729,6 +749,21 @@ int ssl3_client_hello(SSL *s)
             }
             s->client_version = s->version;
         }
+
+        if ((sess == NULL) || (sess->ssl_version != s->version) ||
+#ifdef OPENSSL_NO_TLSEXT
+            !sess->session_id_length ||
+#else
+            /*
+             * In the case of EAP-FAST, we can have a pre-shared
+             * "ticket" without a session ID.
+             */
+            (!sess->session_id_length && !sess->tlsext_tick) ||
+#endif
+            (sess->not_resumable)) {
+            if (!ssl_get_new_session(s, 0))
+                goto err;
+        }
         /* else use the pre-loaded session */
 
         p = s->s3->client_random;
@@ -934,7 +969,42 @@ int ssl3_get_server_hello(SSL *s)
     }
 
     d = p = (unsigned char *)s->init_msg;
-    if (s->method->version == DTLS_ANY_VERSION) {
+
+    if (s->method->version == TLS_ANY_VERSION) {
+        int sversion = (p[0] << 8) | p[1];
+
+#if TLS_MAX_VERSION != TLS1_2_VERSION
+#error Code needs updating for new TLS version
+#endif
+#ifndef OPENSSL_NO_SSL3
+        if ((sversion == SSL3_VERSION) && !(s->options & SSL_OP_NO_SSLv3)) {
+            if (FIPS_mode()) {
+                SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,
+                       SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE);
+                goto err;
+            }
+            s->method = SSLv3_client_method();
+        } else
+#endif
+        if ((sversion == TLS1_VERSION) && !(s->options & SSL_OP_NO_TLSv1)) {
+            s->method = TLSv1_client_method();
+        } else if ((sversion == TLS1_1_VERSION) &&
+                   !(s->options & SSL_OP_NO_TLSv1_1)) {
+            s->method = TLSv1_1_client_method();
+        } else if ((sversion == TLS1_2_VERSION) &&
+                   !(s->options & SSL_OP_NO_TLSv1_2)) {
+            s->method = TLSv1_2_client_method();
+        } else {
+            SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_UNSUPPORTED_PROTOCOL);
+            goto err;
+        }
+        s->session->ssl_version = s->version = s->method->version;
+
+        if (!ssl_security(s, SSL_SECOP_VERSION, 0, s->version, NULL)) {
+            SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_VERSION_TOO_LOW);
+            goto err;
+        }
+    } else if (s->method->version == DTLS_ANY_VERSION) {
         /* Work out correct protocol version to use */
         int hversion = (p[0] << 8) | p[1];
         int options = s->options;
@@ -955,9 +1025,7 @@ int ssl3_get_server_hello(SSL *s)
             goto f_err;
         }
         s->version = s->method->version;
-    }
-
-    if ((p[0] != (s->version >> 8)) || (p[1] != (s->version & 0xff))) {
+    } else if ((p[0] != (s->version >> 8)) || (p[1] != (s->version & 0xff))) {
         SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_WRONG_SSL_VERSION);
         s->version = (s->version & 0xff00) | p[1];
         al = SSL_AD_PROTOCOL_VERSION;
index 746b4e6b7a4befacde15d3cbd5a9fa2db5bcaaf3..7ead372bc38cfe92c3d0dfa82003f7d25d4eaace 100644 (file)
@@ -66,6 +66,8 @@
 static const SSL_METHOD *tls1_get_client_method(int ver);
 static const SSL_METHOD *tls1_get_client_method(int ver)
 {
+    if (ver == TLS_ANY_VERSION)
+        return TLS_server_method();
     if (ver == TLS1_2_VERSION)
         return TLSv1_2_client_method();
     if (ver == TLS1_1_VERSION)
@@ -75,16 +77,21 @@ static const SSL_METHOD *tls1_get_client_method(int ver)
     return NULL;
 }
 
+IMPLEMENT_tls_meth_func(TLS_ANY_VERSION, TLS_client_method,
+                        ssl_undefined_function,
+                        ssl3_connect,
+                        tls1_get_client_method, TLSv1_2_enc_data)
+
 IMPLEMENT_tls_meth_func(TLS1_2_VERSION, TLSv1_2_client_method,
                         ssl_undefined_function,
                         ssl3_connect,
                         tls1_get_client_method, TLSv1_2_enc_data)
 
-    IMPLEMENT_tls_meth_func(TLS1_1_VERSION, TLSv1_1_client_method,
+IMPLEMENT_tls_meth_func(TLS1_1_VERSION, TLSv1_1_client_method,
                         ssl_undefined_function,
                         ssl3_connect,
                         tls1_get_client_method, TLSv1_1_enc_data)
 
-    IMPLEMENT_tls_meth_func(TLS1_VERSION, TLSv1_client_method,
+IMPLEMENT_tls_meth_func(TLS1_VERSION, TLSv1_client_method,
                         ssl_undefined_function,
                         ssl3_connect, tls1_get_client_method, TLSv1_enc_data)
index d0b41915b375713a18ab402ea942c65a34a2d8d3..d595fe0e3537c276db46468d7006fa9277276284 100755 (executable)
@@ -95,7 +95,7 @@ SSL_use_certificate_ASN1                106   EXIST::FUNCTION:
 SSL_use_certificate_file                107    EXIST::FUNCTION:STDIO
 SSL_write                               108    EXIST::FUNCTION:
 SSLeay_add_ssl_algorithms               109    NOEXIST::FUNCTION:
-SSLv23_client_method                    110    EXIST::FUNCTION:RSA
+SSLv23_client_method                    110    NOEXIST::FUNCTION:
 SSLv23_method                           111    NOEXIST::FUNCTION:
 SSLv23_server_method                    112    NOEXIST::FUNCTION:
 SSLv2_client_method                     113    NOEXIST::FUNCTION:
@@ -398,3 +398,4 @@ SSL_CIPHER_get_cipher_nid               432 EXIST::FUNCTION:
 SSL_use_certificate_chain_file          433    EXIST::FUNCTION:STDIO
 TLS_server_method                       434    EXIST::FUNCTION:
 TLS_method                              435    EXIST::FUNCTION:
+TLS_client_method                       436    EXIST::FUNCTION: