[openssl-commits] [openssl] master update

Kurt Roeckx kurt at openssl.org
Sun Mar 27 23:20:26 UTC 2016


The branch master has been updated
       via  c5c7700c9a1c1daae33329fab71d3eed5955d5d8 (commit)
       via  b7dffce017aa045272c42eeb5da40804015a759a (commit)
       via  1ed6587154eaa45c21460177731bd03975af906e (commit)
       via  71ccf961af181fcfceb8d155272b8e8f328a0919 (commit)
       via  ccae4a1582efcad311d095a8e6832b2b67d5ed05 (commit)
      from  ce84456ddf4e57c18a84858755b8b90c183a270e (commit)


- Log -----------------------------------------------------------------
commit c5c7700c9a1c1daae33329fab71d3eed5955d5d8
Author: Kurt Roeckx <kurt at roeckx.be>
Date:   Mon Mar 28 00:31:23 2016 +0200

    When using no-dtls create OPENSSL_NO_DTLS
    
    Reviewed-by: Viktor Dukhovni <viktor at openssl.org>
    
    MR: #2452

commit b7dffce017aa045272c42eeb5da40804015a759a
Author: Kurt Roeckx <kurt at roeckx.be>
Date:   Sun Mar 27 20:53:01 2016 +0200

    Add session reuse tests.
    
    Reviewed-by: Viktor Dukhovni <viktor at openssl.org>
    
    MR: #2452

commit 1ed6587154eaa45c21460177731bd03975af906e
Author: David Benjamin <davidben at google.com>
Date:   Sun Mar 6 00:19:59 2016 -0500

    Resolve DTLS cookie and version before session resumption.
    
    Session resumption involves a version check, so version negotiation must
    happen first. Currently, the DTLS implementation cannot do session
    resumption in DTLS 1.0 because the ssl_version check always checks
    against 1.2.
    
    Switching the order also removes the need to fixup ssl_version in DTLS
    version negotiation.
    
    Signed-off-by: Kurt Roeckx <kurt at roeckx.be>
    Reviewed-by: Viktor Dukhovni <viktor at openssl.org>
    
    RT: #4392, MR: #2452

commit 71ccf961af181fcfceb8d155272b8e8f328a0919
Author: Kurt Roeckx <kurt at roeckx.be>
Date:   Sun Mar 27 20:52:03 2016 +0200

    It's called SSL_session_reused(), not SSL_session_resumed()
    
    Reviewed-by: Viktor Dukhovni <viktor at openssl.org>
    
    MR: #2452

commit ccae4a1582efcad311d095a8e6832b2b67d5ed05
Author: Fedor Indutny <fedor at indutny.com>
Date:   Fri Mar 11 17:44:01 2016 +0300

    Allow different protocol version when trying to reuse a session
    
    We now send the highest supported version by the client, even if the session
    uses an older version.
    
    This fixes 2 problems:
    - When you try to reuse a session but the other side doesn't reuse it and
      uses a different protocol version the connection will fail.
    - When you're trying to reuse a session with an old version you might be
      stuck trying to reuse the old version while both sides support a newer
      version
    
    Signed-off-by: Kurt Roeckx <kurt at roeckx.be>
    Reviewed-by: Viktor Dukhovni <viktor at openssl.org>
    
    GH: #852, MR: #2452

-----------------------------------------------------------------------

Summary of changes:
 Configure                       |   1 +
 doc/ssl/SSL_CTX_dane_enable.pod |   2 +-
 include/openssl/ssl.h           |   1 +
 ssl/methods.c                   | 166 ++++++----------------------------------
 ssl/ssl_err.c                   |   2 +
 ssl/ssl_locl.h                  |  12 ++-
 ssl/ssl_sess.c                  |  19 +----
 ssl/statem/statem_clnt.c        |  13 +++-
 ssl/statem/statem_lib.c         |  41 +++++++++-
 ssl/statem/statem_srvr.c        |  65 ++++++++--------
 test/recipes/80-test_ssl.t      |  48 +++++++++++-
 test/ssltest.c                  | 142 ++++++++++++++++++++++++++++++++++
 12 files changed, 310 insertions(+), 202 deletions(-)

diff --git a/Configure b/Configure
index d303a14..d8064d1 100755
--- a/Configure
+++ b/Configure
@@ -549,6 +549,7 @@ foreach (@argvcopy)
                                 {
                                 $disabled{$proto} = "option(dtls)";
                                 }
+                        $disabled{"dtls"} = "option(dtls)";
                         }
                 elsif ($1 eq "ssl")
                         {
diff --git a/doc/ssl/SSL_CTX_dane_enable.pod b/doc/ssl/SSL_CTX_dane_enable.pod
index f2cb99e..8463a3d 100644
--- a/doc/ssl/SSL_CTX_dane_enable.pod
+++ b/doc/ssl/SSL_CTX_dane_enable.pod
@@ -214,7 +214,7 @@ the lifetime of the SSL connection.
 
   /* Perform SSL_connect() handshake and handle errors here */
 
-  if (SSL_session_resumed(ssl)) {
+  if (SSL_session_reused(ssl)) {
       if (SSL_get_verify_result(ssl) == X509_V_OK) {
         /*
          * Resumed session was originally verified, this connection is
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index 87d9e11..fc7dab0 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -2511,6 +2511,7 @@ void ERR_load_SSL_strings(void);
 # define SSL_R_SSL_SESSION_ID_CONFLICT                    302
 # define SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG            273
 # define SSL_R_SSL_SESSION_ID_HAS_BAD_LENGTH              303
+# define SSL_R_SSL_SESSION_VERSION_MISMATCH               210
 # define SSL_R_TLS_CLIENT_CERT_REQ_WITH_ANON_CIPHER       232
 # define SSL_R_TLS_HEARTBEAT_PEER_DOESNT_ACCEPT           365
 # define SSL_R_TLS_HEARTBEAT_PENDING                      366
diff --git a/ssl/methods.c b/ssl/methods.c
index d66edff..e576502 100644
--- a/ssl/methods.c
+++ b/ssl/methods.c
@@ -116,59 +116,34 @@
  * TLS/SSLv3 methods
  */
 
-static const SSL_METHOD *tls1_get_method(int ver)
-{
-    if (ver == TLS_ANY_VERSION)
-        return TLS_method();
-#ifndef OPENSSL_NO_TLS1_2
-    if (ver == TLS1_2_VERSION)
-        return tlsv1_2_method();
-#endif
-#ifndef OPENSSL_NO_TLS1_1
-    if (ver == TLS1_1_VERSION)
-        return tlsv1_1_method();
-#endif
-#ifndef OPENSSL_NO_TLS1
-    if (ver == TLS1_VERSION)
-        return tlsv1_method();
-#endif
-#ifndef OPENSSL_NO_SSL3
-    if (ver == SSL3_VERSION)
-        return (sslv3_method());
-    else
-#endif
-    return NULL;
-}
-
 IMPLEMENT_tls_meth_func(TLS_ANY_VERSION, 0, 0,
                         TLS_method,
                         ossl_statem_accept,
-                        ossl_statem_connect, tls1_get_method, TLSv1_2_enc_data)
+                        ossl_statem_connect, TLSv1_2_enc_data)
 
 #ifndef OPENSSL_NO_TLS1_2_METHOD
 IMPLEMENT_tls_meth_func(TLS1_2_VERSION, 0, SSL_OP_NO_TLSv1_2,
                         tlsv1_2_method,
                         ossl_statem_accept,
-                        ossl_statem_connect, tls1_get_method, TLSv1_2_enc_data)
+                        ossl_statem_connect, TLSv1_2_enc_data)
 #endif
 
 #ifndef OPENSSL_NO_TLS1_1_METHOD
 IMPLEMENT_tls_meth_func(TLS1_1_VERSION, SSL_METHOD_NO_SUITEB, SSL_OP_NO_TLSv1_1,
                         tlsv1_1_method,
                         ossl_statem_accept,
-                        ossl_statem_connect, tls1_get_method, TLSv1_1_enc_data)
+                        ossl_statem_connect, TLSv1_1_enc_data)
 #endif
 
 #ifndef OPENSSL_NO_TLS1_METHOD
 IMPLEMENT_tls_meth_func(TLS1_VERSION, SSL_METHOD_NO_SUITEB, SSL_OP_NO_TLSv1,
                         tlsv1_method,
                         ossl_statem_accept,
-                        ossl_statem_connect, tls1_get_method, TLSv1_enc_data)
+                        ossl_statem_connect, TLSv1_enc_data)
 #endif
 
 #ifndef OPENSSL_NO_SSL3_METHOD
-IMPLEMENT_ssl3_meth_func(sslv3_method, ossl_statem_accept, ossl_statem_connect,
-                         tls1_get_method)
+IMPLEMENT_ssl3_meth_func(sslv3_method, ossl_statem_accept, ossl_statem_connect)
 #endif
 
 
@@ -176,41 +151,18 @@ IMPLEMENT_ssl3_meth_func(sslv3_method, ossl_statem_accept, ossl_statem_connect,
  * TLS/SSLv3 server methods
  */
 
-static const SSL_METHOD *tls1_get_server_method(int ver)
-{
-    if (ver == TLS_ANY_VERSION)
-        return TLS_server_method();
-#ifndef OPENSSL_NO_TLS1_2
-    if (ver == TLS1_2_VERSION)
-        return tlsv1_2_server_method();
-#endif
-#ifndef OPENSSL_NO_TLS1_1
-    if (ver == TLS1_1_VERSION)
-        return tlsv1_1_server_method();
-#endif
-#ifndef OPENSSL_NO_TLS1
-    if (ver == TLS1_VERSION)
-        return tlsv1_server_method();
-#endif
-#ifndef OPENSSL_NO_SSL3
-    if (ver == SSL3_VERSION)
-        return (sslv3_server_method());
-#endif
-    return NULL;
-}
-
 IMPLEMENT_tls_meth_func(TLS_ANY_VERSION, 0, 0,
                         TLS_server_method,
                         ossl_statem_accept,
                         ssl_undefined_function,
-                        tls1_get_server_method, TLSv1_2_enc_data)
+                        TLSv1_2_enc_data)
 
 #ifndef OPENSSL_NO_TLS1_2_METHOD
 IMPLEMENT_tls_meth_func(TLS1_2_VERSION, 0, SSL_OP_NO_TLSv1_2,
                         tlsv1_2_server_method,
                         ossl_statem_accept,
                         ssl_undefined_function,
-                        tls1_get_server_method, TLSv1_2_enc_data)
+                        TLSv1_2_enc_data)
 #endif
 
 #ifndef OPENSSL_NO_TLS1_1_METHOD
@@ -218,7 +170,7 @@ IMPLEMENT_tls_meth_func(TLS1_1_VERSION, SSL_METHOD_NO_SUITEB, SSL_OP_NO_TLSv1_1,
                         tlsv1_1_server_method,
                         ossl_statem_accept,
                         ssl_undefined_function,
-                        tls1_get_server_method, TLSv1_1_enc_data)
+                        TLSv1_1_enc_data)
 #endif
 
 #ifndef OPENSSL_NO_TLS1_METHOD
@@ -226,13 +178,13 @@ IMPLEMENT_tls_meth_func(TLS1_VERSION, SSL_METHOD_NO_SUITEB, SSL_OP_NO_TLSv1,
                         tlsv1_server_method,
                         ossl_statem_accept,
                         ssl_undefined_function,
-                        tls1_get_server_method, TLSv1_enc_data)
+                        TLSv1_enc_data)
 #endif
 
 #ifndef OPENSSL_NO_SSL3_METHOD
 IMPLEMENT_ssl3_meth_func(sslv3_server_method,
                          ossl_statem_accept,
-                         ssl_undefined_function, tls1_get_server_method)
+                         ssl_undefined_function)
 #endif
 
 
@@ -240,41 +192,18 @@ IMPLEMENT_ssl3_meth_func(sslv3_server_method,
  * TLS/SSLv3 client methods
  */
 
-static const SSL_METHOD *tls1_get_client_method(int ver)
-{
-    if (ver == TLS_ANY_VERSION)
-        return TLS_client_method();
-#ifndef OPENSSL_NO_TLS1_2
-    if (ver == TLS1_2_VERSION)
-        return tlsv1_2_client_method();
-#endif
-#ifndef OPENSSL_NO_TLS1_1
-    if (ver == TLS1_1_VERSION)
-        return tlsv1_1_client_method();
-#endif
-#ifndef OPENSSL_NO_TLS1
-    if (ver == TLS1_VERSION)
-        return tlsv1_client_method();
-#endif
-#ifndef OPENSSL_NO_SSL3
-    if (ver == SSL3_VERSION)
-        return (sslv3_client_method());
-#endif
-    return NULL;
-}
-
 IMPLEMENT_tls_meth_func(TLS_ANY_VERSION, 0, 0,
                         TLS_client_method,
                         ssl_undefined_function,
                         ossl_statem_connect,
-                        tls1_get_client_method, TLSv1_2_enc_data)
+                        TLSv1_2_enc_data)
 
 #ifndef OPENSSL_NO_TLS1_2_METHOD
 IMPLEMENT_tls_meth_func(TLS1_2_VERSION, 0, SSL_OP_NO_TLSv1_2,
                         tlsv1_2_client_method,
                         ssl_undefined_function,
                         ossl_statem_connect,
-                        tls1_get_client_method, TLSv1_2_enc_data)
+                        TLSv1_2_enc_data)
 #endif
 
 #ifndef OPENSSL_NO_TLS1_1_METHOD
@@ -282,7 +211,7 @@ IMPLEMENT_tls_meth_func(TLS1_1_VERSION, SSL_METHOD_NO_SUITEB, SSL_OP_NO_TLSv1_1,
                         tlsv1_1_client_method,
                         ssl_undefined_function,
                         ossl_statem_connect,
-                        tls1_get_client_method, TLSv1_1_enc_data)
+                        TLSv1_1_enc_data)
 #endif
 
 #ifndef OPENSSL_NO_TLS1_METHOD
@@ -290,41 +219,26 @@ IMPLEMENT_tls_meth_func(TLS1_VERSION, SSL_METHOD_NO_SUITEB, SSL_OP_NO_TLSv1,
                         tlsv1_client_method,
                         ssl_undefined_function,
                         ossl_statem_connect,
-                        tls1_get_client_method, TLSv1_enc_data)
+                        TLSv1_enc_data)
 #endif
 
 #ifndef OPENSSL_NO_SSL3_METHOD
 IMPLEMENT_ssl3_meth_func(sslv3_client_method,
                          ssl_undefined_function,
-                         ossl_statem_connect, tls1_get_client_method)
+                         ossl_statem_connect)
 #endif
 
 
 /*
  * DTLS methods
  */
-static const SSL_METHOD *dtls1_get_method(int ver)
-{
-    if (ver == DTLS_ANY_VERSION)
-        return DTLS_method();
-#ifndef OPENSSL_NO_DTLS1
-    else if (ver == DTLS1_VERSION)
-        return dtlsv1_method();
-#endif
-#ifndef OPENSSL_NO_DTLS1_2
-    else if (ver == DTLS1_2_VERSION)
-        return dtlsv1_2_method();
-#endif
-    else
-        return NULL;
-}
 
 #ifndef OPENSSL_NO_DTLS1_METHOD
 IMPLEMENT_dtls1_meth_func(DTLS1_VERSION, SSL_METHOD_NO_SUITEB, SSL_OP_NO_DTLSv1,
                           dtlsv1_method,
                           ossl_statem_accept,
                           ossl_statem_connect,
-                          dtls1_get_method, DTLSv1_enc_data)
+                          DTLSv1_enc_data)
 #endif
 
 #ifndef OPENSSL_NO_DTLS1_2_METHOD
@@ -332,41 +246,25 @@ IMPLEMENT_dtls1_meth_func(DTLS1_2_VERSION, 0, SSL_OP_NO_DTLSv1_2,
                           dtlsv1_2_method,
                           ossl_statem_accept,
                           ossl_statem_connect,
-                          dtls1_get_method, DTLSv1_2_enc_data)
+                          DTLSv1_2_enc_data)
 #endif
 
 IMPLEMENT_dtls1_meth_func(DTLS_ANY_VERSION, 0, 0,
                           DTLS_method,
                           ossl_statem_accept,
                           ossl_statem_connect,
-                          dtls1_get_method, DTLSv1_2_enc_data)
+                          DTLSv1_2_enc_data)
 
 /*
  * DTLS server methods
  */
 
-static const SSL_METHOD *dtls1_get_server_method(int ver)
-{
-    if (ver == DTLS_ANY_VERSION)
-        return DTLS_server_method();
-#ifndef OPENSSL_NO_DTLS1
-    else if (ver == DTLS1_VERSION)
-        return dtlsv1_server_method();
-#endif
-#ifndef OPENSSL_NO_DTLS1_2
-    else if (ver == DTLS1_2_VERSION)
-        return dtlsv1_2_server_method();
-#endif
-    else
-        return NULL;
-}
-
 #ifndef OPENSSL_NO_DTLS1_METHOD
 IMPLEMENT_dtls1_meth_func(DTLS1_VERSION, SSL_METHOD_NO_SUITEB, SSL_OP_NO_DTLSv1,
                           dtlsv1_server_method,
                           ossl_statem_accept,
                           ssl_undefined_function,
-                          dtls1_get_server_method, DTLSv1_enc_data)
+                          DTLSv1_enc_data)
 #endif
 
 #ifndef OPENSSL_NO_DTLS1_2_METHOD
@@ -374,42 +272,26 @@ IMPLEMENT_dtls1_meth_func(DTLS1_2_VERSION, 0, SSL_OP_NO_DTLSv1_2,
                           dtlsv1_2_server_method,
                           ossl_statem_accept,
                           ssl_undefined_function,
-                          dtls1_get_server_method, DTLSv1_2_enc_data)
+                          DTLSv1_2_enc_data)
 #endif
 
 IMPLEMENT_dtls1_meth_func(DTLS_ANY_VERSION, 0, 0,
                           DTLS_server_method,
                           ossl_statem_accept,
                           ssl_undefined_function,
-                          dtls1_get_server_method, DTLSv1_2_enc_data)
+                          DTLSv1_2_enc_data)
 
 
 /*
  * DTLS client methods
  */
 
-static const SSL_METHOD *dtls1_get_client_method(int ver)
-{
-    if (ver == DTLS_ANY_VERSION)
-        return DTLS_client_method();
-#ifndef OPENSSL_NO_DTLS1
-    else if (ver == DTLS1_VERSION || ver == DTLS1_BAD_VER)
-        return dtlsv1_client_method();
-#endif
-#ifndef OPENSSL_NO_DTLS1_2
-    else if (ver == DTLS1_2_VERSION)
-        return dtlsv1_2_client_method();
-#endif
-    else
-        return NULL;
-}
-
 #ifndef OPENSSL_NO_DTLS1_METHOD
 IMPLEMENT_dtls1_meth_func(DTLS1_VERSION, SSL_METHOD_NO_SUITEB, SSL_OP_NO_DTLSv1,
                           dtlsv1_client_method,
                           ssl_undefined_function,
                           ossl_statem_connect,
-                          dtls1_get_client_method, DTLSv1_enc_data)
+                          DTLSv1_enc_data)
 #endif
 
 #ifndef OPENSSL_NO_DTLS1_2_METHOD
@@ -417,14 +299,14 @@ IMPLEMENT_dtls1_meth_func(DTLS1_2_VERSION, 0, SSL_OP_NO_DTLSv1_2,
                           dtlsv1_2_client_method,
                           ssl_undefined_function,
                           ossl_statem_connect,
-                          dtls1_get_client_method, DTLSv1_2_enc_data)
+                          DTLSv1_2_enc_data)
 #endif
 
 IMPLEMENT_dtls1_meth_func(DTLS_ANY_VERSION, 0, 0,
                           DTLS_client_method,
                           ssl_undefined_function,
                           ossl_statem_connect,
-                          dtls1_get_client_method, DTLSv1_2_enc_data)
+                          DTLSv1_2_enc_data)
 
 #if OPENSSL_API_COMPAT < 0x10100000L
 
diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c
index 88f6c73..d0cadc6 100644
--- a/ssl/ssl_err.c
+++ b/ssl/ssl_err.c
@@ -634,6 +634,8 @@ static ERR_STRING_DATA SSL_str_reasons[] = {
      "ssl session id context too long"},
     {ERR_REASON(SSL_R_SSL_SESSION_ID_HAS_BAD_LENGTH),
      "ssl session id has bad length"},
+    {ERR_REASON(SSL_R_SSL_SESSION_VERSION_MISMATCH),
+     "ssl session version mismatch"},
     {ERR_REASON(SSL_R_TLS_CLIENT_CERT_REQ_WITH_ANON_CIPHER),
      "tls client cert req with anon cipher"},
     {ERR_REASON(SSL_R_TLS_HEARTBEAT_PEER_DOESNT_ACCEPT),
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index 64f4ae9..4a2b52d 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -542,7 +542,6 @@ struct ssl_method_st {
     int (*ssl_pending) (const SSL *s);
     int (*num_ciphers) (void);
     const SSL_CIPHER *(*get_cipher) (unsigned ncipher);
-    const struct ssl_method_st *(*get_ssl_method) (int version);
     long (*get_timeout) (void);
     const struct ssl3_enc_method *ssl3_enc; /* Extra SSLv3/TLS stuff */
     int (*ssl_version) (void);
@@ -1761,7 +1760,7 @@ extern const SSL3_ENC_METHOD DTLSv1_2_enc_data;
 #define SSL_METHOD_NO_SUITEB    (1U<<1)
 
 # define IMPLEMENT_tls_meth_func(version, flags, mask, func_name, s_accept, \
-                                 s_connect, s_get_meth, enc_data) \
+                                 s_connect, enc_data) \
 const SSL_METHOD *func_name(void)  \
         { \
         static const SSL_METHOD func_name##_data= { \
@@ -1789,7 +1788,6 @@ const SSL_METHOD *func_name(void)  \
                 ssl3_pending, \
                 ssl3_num_ciphers, \
                 ssl3_get_cipher, \
-                s_get_meth, \
                 tls1_default_timeout, \
                 &enc_data, \
                 ssl_undefined_void_function, \
@@ -1799,7 +1797,7 @@ const SSL_METHOD *func_name(void)  \
         return &func_name##_data; \
         }
 
-# define IMPLEMENT_ssl3_meth_func(func_name, s_accept, s_connect, s_get_meth) \
+# define IMPLEMENT_ssl3_meth_func(func_name, s_accept, s_connect) \
 const SSL_METHOD *func_name(void)  \
         { \
         static const SSL_METHOD func_name##_data= { \
@@ -1827,7 +1825,6 @@ const SSL_METHOD *func_name(void)  \
                 ssl3_pending, \
                 ssl3_num_ciphers, \
                 ssl3_get_cipher, \
-                s_get_meth, \
                 ssl3_default_timeout, \
                 &SSLv3_enc_data, \
                 ssl_undefined_void_function, \
@@ -1838,7 +1835,7 @@ const SSL_METHOD *func_name(void)  \
         }
 
 # define IMPLEMENT_dtls1_meth_func(version, flags, mask, func_name, s_accept, \
-                                        s_connect, s_get_meth, enc_data) \
+                                        s_connect, enc_data) \
 const SSL_METHOD *func_name(void)  \
         { \
         static const SSL_METHOD func_name##_data= { \
@@ -1866,7 +1863,6 @@ const SSL_METHOD *func_name(void)  \
                 ssl3_pending, \
                 ssl3_num_ciphers, \
                 ssl3_get_cipher, \
-                s_get_meth, \
                 dtls1_default_timeout, \
                 &enc_data, \
                 ssl_undefined_void_function, \
@@ -1996,6 +1992,8 @@ __owur int ssl3_handshake_write(SSL *s);
 
 __owur int ssl_allow_compression(SSL *s);
 
+__owur int ssl_version_supported(const SSL *s, int version);
+
 __owur int ssl_set_client_hello_version(SSL *s);
 __owur int ssl_check_version_downgrade(SSL *s);
 __owur int ssl_set_version_bound(int method_version, int version, int *bound);
diff --git a/ssl/ssl_sess.c b/ssl/ssl_sess.c
index 3f030a7..70e2683 100644
--- a/ssl/ssl_sess.c
+++ b/ssl/ssl_sess.c
@@ -872,19 +872,9 @@ int SSL_SESSION_up_ref(SSL_SESSION *ss)
 int SSL_set_session(SSL *s, SSL_SESSION *session)
 {
     int ret = 0;
-    const SSL_METHOD *meth;
-
     if (session != NULL) {
-        meth = s->ctx->method->get_ssl_method(session->ssl_version);
-        if (meth == NULL)
-            meth = s->method->get_ssl_method(session->ssl_version);
-        if (meth == NULL) {
-            SSLerr(SSL_F_SSL_SET_SESSION, SSL_R_UNABLE_TO_FIND_SSL_METHOD);
-            return (0);
-        }
-
-        if (meth != s->method) {
-            if (!SSL_set_ssl_method(s, meth))
+        if (s->ctx->method != s->method) {
+            if (!SSL_set_ssl_method(s, s->ctx->method))
                 return (0);
         }
 
@@ -896,9 +886,8 @@ int SSL_set_session(SSL *s, SSL_SESSION *session)
     } else {
         SSL_SESSION_free(s->session);
         s->session = NULL;
-        meth = s->ctx->method;
-        if (meth != s->method) {
-            if (!SSL_set_ssl_method(s, meth))
+        if (s->ctx->method != s->method) {
+            if (!SSL_set_ssl_method(s, s->ctx->method))
                 return (0);
         }
         ret = 1;
diff --git a/ssl/statem/statem_clnt.c b/ssl/statem/statem_clnt.c
index bafb90a..73f54bc 100644
--- a/ssl/statem/statem_clnt.c
+++ b/ssl/statem/statem_clnt.c
@@ -817,7 +817,8 @@ int tls_construct_client_hello(SSL *s)
         goto err;
     }
 
-    if ((sess == NULL) || (sess->ssl_version != s->version) ||
+    if ((sess == NULL) ||
+        !ssl_version_supported(s, sess->ssl_version) ||
         /*
          * In the case of EAP-FAST, we can have a pre-shared
          * "ticket" without a session ID.
@@ -1126,12 +1127,22 @@ MSG_PROCESS_RETURN tls_process_server_hello(SSL *s, PACKET *pkt)
             }
         }
 
+        s->session->ssl_version = s->version;
         s->session->session_id_length = session_id_len;
         /* session_id_len could be 0 */
         memcpy(s->session->session_id, PACKET_data(&session_id),
                session_id_len);
     }
 
+    /* Session version and negotiated protocol version should match */
+    if (s->version != s->session->ssl_version) {
+        al = SSL_AD_PROTOCOL_VERSION;
+
+        SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO,
+               SSL_R_SSL_SESSION_VERSION_MISMATCH);
+        goto f_err;
+    }
+
     c = ssl_get_cipher_by_char(s, cipherchars);
     if (c == NULL) {
         /* unknown cipher */
diff --git a/ssl/statem/statem_lib.c b/ssl/statem/statem_lib.c
index a24060e..8fcc232 100644
--- a/ssl/statem/statem_lib.c
+++ b/ssl/statem/statem_lib.c
@@ -788,6 +788,44 @@ static int ssl_method_error(const SSL *s, const SSL_METHOD *method)
 }
 
 /*
+ * ssl_version_supported - Check that the specified `version` is supported by
+ * `SSL *` instance
+ *
+ * @s: The SSL handle for the candidate method
+ * @version: Protocol version to test against
+ *
+ * Returns 1 when supported, otherwise 0
+ */
+int ssl_version_supported(const SSL *s, int version)
+{
+    const version_info *vent;
+    const version_info *table;
+
+    switch (s->method->version) {
+    default:
+        /* Version should match method version for non-ANY method */
+        return version_cmp(s, version, s->version) == 0;
+    case TLS_ANY_VERSION:
+        table = tls_version_table;
+        break;
+    case DTLS_ANY_VERSION:
+        table = dtls_version_table;
+        break;
+    }
+
+    for (vent = table;
+         vent->version != 0 && version_cmp(s, version, vent->version) <= 0;
+         ++vent) {
+        if (vent->cmeth != NULL &&
+            version_cmp(s, version, vent->version) == 0 &&
+            ssl_method_error(s, vent->cmeth()) == 0) {
+            return 1;
+        }
+    }
+    return 0;
+}
+
+/*
  * ssl_check_version_downgrade - In response to RFC7507 SCSV version
  * fallback indication from a client check whether we're using the highest
  * supported protocol version.
@@ -976,7 +1014,6 @@ int ssl_choose_client_version(SSL *s, int version)
          * versions they don't want.  If not, then easy to fix, just return
          * ssl_method_error(s, s->method)
          */
-        s->session->ssl_version = s->version;
         return 0;
     case TLS_ANY_VERSION:
         table = tls_version_table;
@@ -999,7 +1036,7 @@ int ssl_choose_client_version(SSL *s, int version)
         if (err != 0)
             return err;
         s->method = method;
-        s->session->ssl_version = s->version = version;
+        s->version = version;
         return 0;
     }
 
diff --git a/ssl/statem/statem_srvr.c b/ssl/statem/statem_srvr.c
index 983b821..23e7903 100644
--- a/ssl/statem/statem_srvr.c
+++ b/ssl/statem/statem_srvr.c
@@ -1152,6 +1152,38 @@ MSG_PROCESS_RETURN tls_process_client_hello(SSL *s, PACKET *pkt)
         extensions = *pkt;
     }
 
+    if (SSL_IS_DTLS(s)) {
+        /* Empty cookie was already handled above by returning early. */
+        if (SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE) {
+            if (s->ctx->app_verify_cookie_cb != NULL) {
+                if (s->ctx->app_verify_cookie_cb(s, PACKET_data(&cookie),
+                                                 PACKET_remaining(&cookie)) == 0) {
+                    al = SSL_AD_HANDSHAKE_FAILURE;
+                    SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO,
+                           SSL_R_COOKIE_MISMATCH);
+                    goto f_err;
+                    /* else cookie verification succeeded */
+                }
+            /* default verification */
+            } else if (!PACKET_equal(&cookie, s->d1->cookie,
+                                     s->d1->cookie_len)) {
+                al = SSL_AD_HANDSHAKE_FAILURE;
+                SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_COOKIE_MISMATCH);
+                goto f_err;
+            }
+            s->d1->cookie_verified = 1;
+        }
+        if (s->method->version == DTLS_ANY_VERSION) {
+            protverr = ssl_choose_server_version(s);
+            if (protverr != 0) {
+                SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, protverr);
+                s->version = s->client_version;
+                al = SSL_AD_PROTOCOL_VERSION;
+                goto f_err;
+            }
+        }
+    }
+
     s->hit = 0;
 
     /*
@@ -1198,39 +1230,6 @@ MSG_PROCESS_RETURN tls_process_client_hello(SSL *s, PACKET *pkt)
         }
     }
 
-    if (SSL_IS_DTLS(s)) {
-        /* Empty cookie was already handled above by returning early. */
-        if (SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE) {
-            if (s->ctx->app_verify_cookie_cb != NULL) {
-                if (s->ctx->app_verify_cookie_cb(s, PACKET_data(&cookie),
-                                                 PACKET_remaining(&cookie)) == 0) {
-                    al = SSL_AD_HANDSHAKE_FAILURE;
-                    SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO,
-                           SSL_R_COOKIE_MISMATCH);
-                    goto f_err;
-                    /* else cookie verification succeeded */
-                }
-            /* default verification */
-            } else if (!PACKET_equal(&cookie, s->d1->cookie,
-                                     s->d1->cookie_len)) {
-                al = SSL_AD_HANDSHAKE_FAILURE;
-                SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_COOKIE_MISMATCH);
-                goto f_err;
-            }
-            s->d1->cookie_verified = 1;
-        }
-        if (s->method->version == DTLS_ANY_VERSION) {
-            protverr = ssl_choose_server_version(s);
-            if (protverr != 0) {
-                SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, protverr);
-                s->version = s->client_version;
-                al = SSL_AD_PROTOCOL_VERSION;
-                goto f_err;
-            }
-            s->session->ssl_version = s->version;
-        }
-    }
-
     if (ssl_bytes_to_cipher_list(s, &cipher_suites, &(ciphers),
                                  is_v2_record, &al) == NULL) {
         goto f_err;
diff --git a/test/recipes/80-test_ssl.t b/test/recipes/80-test_ssl.t
index f1ffe9a..45750b4 100644
--- a/test/recipes/80-test_ssl.t
+++ b/test/recipes/80-test_ssl.t
@@ -63,10 +63,13 @@ my $P2req="reqP2.ss";
 my $P2cert="certP2.ss";
 my $P2intermediate="tmp_intP2.ss";
 
+my $server_sess="server.ss";
+my $client_sess="client.ss";
+
 plan tests =>
     1				# For testss
     + 1				# For ssltest -test_cipherlist
-    + 13			# For the first testssl
+    + 15			# For the first testssl
     + 16			# For the first testsslproxy
     + 16			# For the second testsslproxy
     ;
@@ -805,6 +808,49 @@ sub testssl {
         }}}}}
     };
 
+    subtest 'TLS session reuse' => sub {
+        plan tests => 12;
+
+        ok(run(test([@ssltest, "-server_sess_out", $server_sess, "-client_sess_out", $client_sess])));
+        ok(run(test([@ssltest, "-server_sess_in", $server_sess, "-client_sess_in", $client_sess, "-should_reuse", "1", "-should_negotiate", "tls1.2"])));
+        ok(run(test([@ssltest, "-server_max_proto", "tls1.1", "-server_sess_in", $server_sess, "-client_sess_in", $client_sess, "-should_reuse", "0", "-should_negotiate", "tls1.1"])));
+
+        ok(run(test([@ssltest, "-server_max_proto", "tls1.1", "-server_sess_out", $server_sess, "-client_sess_out", $client_sess])));
+        ok(run(test([@ssltest, "-server_max_proto", "tls1.1", "-server_sess_in", $server_sess, "-client_sess_in", $client_sess, "-should_reuse", "1", "-should_negotiate", "tls1.1"])));
+        ok(run(test([@ssltest, "-server_sess_in", $server_sess, "-client_sess_in", $client_sess, "-should_reuse", "0", "-should_negotiate", "tls1.2"])));
+
+        ok(run(test([@ssltest, "-no_ticket", "-server_sess_out", $server_sess, "-client_sess_out", $client_sess])));
+        ok(run(test([@ssltest, "-no_ticket", "-server_sess_in", $server_sess, "-client_sess_in", $client_sess, "-should_reuse", "1", "-should_negotiate", "tls1.2"])));
+        ok(run(test([@ssltest, "-no_ticket", "-server_max_proto", "tls1.1", "-server_sess_in", $server_sess, "-client_sess_in", $client_sess, "-should_reuse", "0", "-should_negotiate", "tls1.1"])));
+
+        ok(run(test([@ssltest, "-no_ticket", "-server_max_proto", "tls1.1", "-server_sess_out", $server_sess, "-client_sess_out", $client_sess])));
+        ok(run(test([@ssltest, "-no_ticket", "-server_max_proto", "tls1.1", "-server_sess_in", $server_sess, "-client_sess_in", $client_sess, "-should_reuse", "1", "-should_negotiate", "tls1.1"])));
+        ok(run(test([@ssltest, "-no_ticket", "-server_sess_in", $server_sess, "-client_sess_in", $client_sess, "-should_reuse", "0", "-should_negotiate", "tls1.2"])));
+    };
+
+    subtest 'DTLS session reuse' => sub {
+        plan tests => 12;
+      SKIP: {
+        skip "DTLS disabled", 12 if $no_dtls;
+
+        ok(run(test([@ssltest, "-dtls", "-server_sess_out", $server_sess, "-client_sess_out", $client_sess])));
+        ok(run(test([@ssltest, "-dtls", "-server_sess_in", $server_sess, "-client_sess_in", $client_sess, "-should_reuse", "1", "-should_negotiate", "dtls1.2"])));
+        ok(run(test([@ssltest, "-dtls", "-server_max_proto", "dtls1", "-server_sess_in", $server_sess, "-client_sess_in", $client_sess, "-should_reuse", "0", "-should_negotiate", "dtls1"])));
+
+        ok(run(test([@ssltest, "-dtls", "-server_max_proto", "dtls1", "-server_sess_out", $server_sess, "-client_sess_out", $client_sess])));
+        ok(run(test([@ssltest, "-dtls", "-server_max_proto", "dtls1", "-server_sess_in", $server_sess, "-client_sess_in", $client_sess, "-should_reuse", "1", "-should_negotiate", "dtls1"])));
+        ok(run(test([@ssltest, "-dtls", "-server_sess_in", $server_sess, "-client_sess_in", $client_sess, "-should_reuse", "0", "-should_negotiate", "dtls1.2"])));
+
+        ok(run(test([@ssltest, "-dtls", "-no_ticket", "-server_sess_out", $server_sess, "-client_sess_out", $client_sess])));
+        ok(run(test([@ssltest, "-dtls", "-no_ticket", "-server_sess_in", $server_sess, "-client_sess_in", $client_sess, "-should_reuse", "1", "-should_negotiate", "dtls1.2"])));
+        ok(run(test([@ssltest, "-dtls", "-no_ticket", "-server_max_proto", "dtls1", "-server_sess_in", $server_sess, "-client_sess_in", $client_sess, "-should_reuse", "0", "-should_negotiate", "dtls1"])));
+
+        ok(run(test([@ssltest, "-dtls", "-no_ticket", "-server_max_proto", "dtls1", "-server_sess_out", $server_sess, "-client_sess_out", $client_sess])));
+        ok(run(test([@ssltest, "-dtls", "-no_ticket", "-server_max_proto", "dtls1", "-server_sess_in", $server_sess, "-client_sess_in", $client_sess, "-should_reuse", "1", "-should_negotiate", "dtls1"])));
+        ok(run(test([@ssltest, "-dtls", "-no_ticket", "-server_sess_in", $server_sess, "-client_sess_in", $client_sess, "-should_reuse", "0", "-should_negotiate", "dtls1.2"])));
+	}
+    };
+
     subtest 'Certificate Transparency tests' => sub {
 	######################################################################
 
diff --git a/test/ssltest.c b/test/ssltest.c
index a2dd445..8018b3b 100644
--- a/test/ssltest.c
+++ b/test/ssltest.c
@@ -383,6 +383,12 @@ static const char *sn_client;
 static const char *sn_server1;
 static const char *sn_server2;
 static int sn_expect = 0;
+static const char *server_sess_out;
+static const char *server_sess_in;
+static const char *client_sess_out;
+static const char *client_sess_in;
+static SSL_SESSION *server_sess;
+static SSL_SESSION *client_sess;
 
 static int servername_cb(SSL *s, int *ad, void *arg)
 {
@@ -900,6 +906,12 @@ static void sv_usage(void)
     fprintf(stderr, " -sn_server2 <string> - have server context 2 respond to this servername\n");
     fprintf(stderr, " -sn_expect1          - expected server 1\n");
     fprintf(stderr, " -sn_expect2          - expected server 2\n");
+    fprintf(stderr, " -server_sess_out <file>    - Save the server session to a file\n");
+    fprintf(stderr, " -server_sess_in <file>     - Read the server session from a file\n");
+    fprintf(stderr, " -client_sess_out <file>    - Save the client session to a file\n");
+    fprintf(stderr, " -client_sess_in <file>     - Read the client session from a file\n");
+    fprintf(stderr, " -should_reuse <number>     - The expected state of reusing the session\n");
+    fprintf(stderr, " -no_ticket    - do not issue TLS session ticket\n");
 }
 
 static void print_key_details(BIO *out, EVP_PKEY *key)
@@ -997,6 +1009,43 @@ static int protocol_from_string(const char *value)
     return -1;
 }
 
+static SSL_SESSION *read_session(const char *filename)
+{
+    SSL_SESSION *sess;
+    BIO *f = BIO_new_file(filename, "r");
+
+    if (f == NULL) {
+        BIO_printf(bio_err, "Can't open session file %s\n", filename);
+        ERR_print_errors(bio_err);
+        return NULL;
+    }
+    sess = PEM_read_bio_SSL_SESSION(f, NULL, 0, NULL);
+    if (sess == NULL) {
+        BIO_printf(bio_err, "Can't parse session file %s\n", filename);
+        ERR_print_errors(bio_err);
+    }
+    BIO_free(f);
+    return sess;
+}
+
+static int write_session(const char *filename, SSL_SESSION *sess)
+{
+    BIO *f = BIO_new_file(filename, "w");
+
+    if (sess == NULL) {
+        BIO_printf(bio_err, "No session information\n");
+        return 0;
+    }
+    if (f == NULL) {
+        BIO_printf(bio_err, "Can't open session file %s\n", filename);
+        ERR_print_errors(bio_err);
+        return 0;
+    }
+    PEM_write_bio_SSL_SESSION(f, sess);
+    BIO_free(f);
+    return 1;
+}
+
 /*
  * set_protocol_version - Sets protocol version minimum or maximum
  *
@@ -1031,6 +1080,8 @@ int main(int argc, char *argv[])
     const SSL_METHOD *meth = NULL;
     SSL *c_ssl, *s_ssl;
     int number = 1, reuse = 0;
+    int should_reuse = -1;
+    int no_ticket = 0;
     long bytes = 256L;
 #ifndef OPENSSL_NO_DH
     DH *dh;
@@ -1342,6 +1393,28 @@ int main(int argc, char *argv[])
             sn_expect = 1;
         } else if (strcmp(*argv, "-sn_expect2") == 0) {
             sn_expect = 2;
+        } else if (strcmp(*argv, "-server_sess_out") == 0) {
+            if (--argc < 1)
+                goto bad;
+            server_sess_out = *(++argv);
+        } else if (strcmp(*argv, "-server_sess_in") == 0) {
+            if (--argc < 1)
+                goto bad;
+            server_sess_in = *(++argv);
+        } else if (strcmp(*argv, "-client_sess_out") == 0) {
+            if (--argc < 1)
+                goto bad;
+            client_sess_out = *(++argv);
+        } else if (strcmp(*argv, "-client_sess_in") == 0) {
+            if (--argc < 1)
+                goto bad;
+            client_sess_in = *(++argv);
+        } else if (strcmp(*argv, "-should_reuse") == 0) {
+            if (--argc < 1)
+                goto bad;
+            should_reuse = !!atoi(*(++argv));
+        } else if (strcmp(*argv, "-no_ticket") == 0) {
+            no_ticket = 1;
         } else {
             int rv;
             arg = argv[0];
@@ -1536,6 +1609,11 @@ int main(int argc, char *argv[])
     SSL_CTX_set_security_level(s_ctx, 0);
     SSL_CTX_set_security_level(s_ctx2, 0);
 
+    if (no_ticket) {
+        SSL_CTX_set_options(c_ctx, SSL_OP_NO_TICKET);
+        SSL_CTX_set_options(s_ctx, SSL_OP_NO_TICKET);
+    }
+
     if (SSL_CTX_set_min_proto_version(c_ctx, min_version) == 0)
         goto end;
     if (SSL_CTX_set_max_proto_version(c_ctx, max_version) == 0)
@@ -1828,6 +1906,28 @@ int main(int argc, char *argv[])
         OPENSSL_free(alpn);
     }
 
+    if (server_sess_in != NULL) {
+        server_sess = read_session(server_sess_in);
+        if (server_sess == NULL)
+            goto end;
+    }
+    if (client_sess_in != NULL) {
+        client_sess = read_session(client_sess_in);
+        if (client_sess == NULL)
+            goto end;
+    }
+
+    if (server_sess_out != NULL || server_sess_in != NULL) {
+        char *keys;
+        long size;
+
+        /* Use a fixed key so that we can decrypt the ticket. */
+        size = SSL_CTX_set_tlsext_ticket_keys(s_ctx, NULL, 0);
+        keys = OPENSSL_zalloc(size);
+        SSL_CTX_set_tlsext_ticket_keys(s_ctx, keys, size);
+        OPENSSL_free(keys);
+    }
+
     if (sn_server1 != NULL || sn_server2 != NULL)
         SSL_CTX_set_tlsext_servername_callback(s_ctx, servername_cb);
 
@@ -1846,6 +1946,14 @@ int main(int argc, char *argv[])
     if (!set_protocol_version(client_max_proto, c_ssl, SSL_CTRL_SET_MAX_PROTO_VERSION))
         goto end;
 
+    if (server_sess) {
+        if (SSL_CTX_add_session(s_ctx, server_sess) == 0) {
+            BIO_printf(bio_err, "Can't add server session\n");
+            ERR_print_errors(bio_err);
+            goto end;
+        }
+    }
+
     BIO_printf(bio_stdout, "Doing handshakes=%d bytes=%ld\n", number, bytes);
     for (i = 0; i < number; i++) {
         if (!reuse) {
@@ -1854,6 +1962,13 @@ int main(int argc, char *argv[])
                 goto end;
             }
         }
+        if (client_sess_in != NULL) {
+            if (SSL_set_session(c_ssl, client_sess) == 0) {
+                BIO_printf(bio_err, "Can't set client session\n");
+                ERR_print_errors(bio_err);
+                goto end;
+            }
+        }
         switch (bio_type) {
         case BIO_MEM:
             ret = doit(s_ssl, c_ssl, bytes);
@@ -1897,6 +2012,30 @@ int main(int argc, char *argv[])
         }
     }
 
+    if (should_reuse != -1) {
+        if (SSL_session_reused(s_ssl) != should_reuse ||
+            SSL_session_reused(c_ssl) != should_reuse) {
+            BIO_printf(bio_err, "Unexpected session reuse state. "
+                "Expected: %d, server: %d, client: %d\n", should_reuse,
+                SSL_session_reused(s_ssl), SSL_session_reused(c_ssl));
+            ret = 1;
+            goto err;
+        }
+    }
+
+    if (server_sess_out != NULL) {
+        if (write_session(server_sess_out, SSL_get_session(s_ssl)) == 0) {
+            ret = 1;
+            goto err;
+        }
+    }
+    if (client_sess_out != NULL) {
+        if (write_session(client_sess_out, SSL_get_session(c_ssl)) == 0) {
+            ret = 1;
+            goto err;
+        }
+    }
+
     if (!verbose) {
         print_details(c_ssl, "");
     }
@@ -1934,6 +2073,9 @@ int main(int argc, char *argv[])
 
     BIO_free(bio_stdout);
 
+    SSL_SESSION_free(server_sess);
+    SSL_SESSION_free(client_sess);
+
 #ifndef OPENSSL_NO_CRYPTO_MDEBUG
     if (CRYPTO_mem_leaks(bio_err) <= 0)
         ret = 1;


More information about the openssl-commits mailing list