[openssl-commits] [openssl] master update

Matt Caswell matt at openssl.org
Fri Jun 16 10:42:30 UTC 2017


The branch master has been updated
       via  abeb2a639b7030aeac08aab4fd9d6b52a3be8b04 (commit)
       via  3b0e88d3bd79d01c2da519e405849b78646aab8f (commit)
       via  8acc27998bf253f0fd7c59d0e6aa515e5793ad01 (commit)
       via  0de6d66d36dc5f6d46247c63da71b73d7e8e018c (commit)
       via  ca0413ae14f8fc9cc840b8acaadd150ea290285f (commit)
       via  a055a8815587f402d700093dea0dec6bf34631a3 (commit)
      from  9b03b91b84b64c086081b87bd0a2c7d3612af6c0 (commit)


- Log -----------------------------------------------------------------
commit abeb2a639b7030aeac08aab4fd9d6b52a3be8b04
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Jun 16 10:56:40 2017 +0100

    Tweak the check that a ciphersuite has not changed since the HRR
    
    Reviewed-by: Ben Kaduk <kaduk at mit.edu>
    (Merged from https://github.com/openssl/openssl/pull/3623)

commit 3b0e88d3bd79d01c2da519e405849b78646aab8f
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Jun 15 13:44:24 2017 +0100

    Add comments to test_ciphersuite_change()
    
    Make it clear that we are pausing one of the connections and then
    restarting it again.
    
    Reviewed-by: Ben Kaduk <kaduk at mit.edu>
    (Merged from https://github.com/openssl/openssl/pull/3623)

commit 8acc27998bf253f0fd7c59d0e6aa515e5793ad01
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Jun 12 13:57:13 2017 +0100

    Fix an uninitialised variable warning
    
    Reviewed-by: Ben Kaduk <kaduk at mit.edu>
    (Merged from https://github.com/openssl/openssl/pull/3623)

commit 0de6d66d36dc5f6d46247c63da71b73d7e8e018c
Author: Matt Caswell <matt at openssl.org>
Date:   Tue Jun 6 17:19:32 2017 +0100

    Move ciphersuite selection before session resumption in TLSv1.3
    
    This does things as per the recommendation in the TLSv1.3 spec. It also
    means that the server will always choose its preferred ciphersuite.
    Previously the server would only select ciphersuites compatible with the
    session.
    
    Reviewed-by: Ben Kaduk <kaduk at mit.edu>
    (Merged from https://github.com/openssl/openssl/pull/3623)

commit ca0413ae14f8fc9cc840b8acaadd150ea290285f
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Jun 2 13:10:50 2017 +0100

    Add a test for a server changing the ciphersuite
    
    Test that if a server selects a differenct ciphersuite with the same hash
    in TLSv1.3 then this is accepted by the client.
    
    Reviewed-by: Ben Kaduk <kaduk at mit.edu>
    (Merged from https://github.com/openssl/openssl/pull/3623)

commit a055a8815587f402d700093dea0dec6bf34631a3
Author: Matt Caswell <matt at openssl.org>
Date:   Fri May 26 17:59:34 2017 +0100

    Allow the server to change the ciphersuite on resume
    
    Reviewed-by: Ben Kaduk <kaduk at mit.edu>
    (Merged from https://github.com/openssl/openssl/pull/3623)

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

Summary of changes:
 crypto/err/openssl.txt       |   1 +
 include/openssl/sslerr.h     |   1 +
 ssl/s3_lib.c                 |   9 ++-
 ssl/ssl_err.c                |   2 +
 ssl/statem/extensions_srvr.c |   7 +-
 ssl/statem/statem_clnt.c     |  23 ++++++-
 ssl/statem/statem_srvr.c     | 154 +++++++++++++++++++++++++------------------
 test/sslapitest.c            | 134 ++++++++++++++++++++++++++++++++++++-
 8 files changed, 254 insertions(+), 77 deletions(-)

diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt
index e85c9a0..37e3166 100644
--- a/crypto/err/openssl.txt
+++ b/crypto/err/openssl.txt
@@ -2158,6 +2158,7 @@ SSL_R_CCS_RECEIVED_EARLY:133:ccs received early
 SSL_R_CERTIFICATE_VERIFY_FAILED:134:certificate verify failed
 SSL_R_CERT_CB_ERROR:377:cert cb error
 SSL_R_CERT_LENGTH_MISMATCH:135:cert length mismatch
+SSL_R_CIPHERSUITE_DIGEST_HAS_CHANGED:218:ciphersuite digest has changed
 SSL_R_CIPHER_CODE_WRONG_LENGTH:137:cipher code wrong length
 SSL_R_CIPHER_OR_HASH_UNAVAILABLE:138:cipher or hash unavailable
 SSL_R_CLIENTHELLO_TLSEXT:226:clienthello tlsext
diff --git a/include/openssl/sslerr.h b/include/openssl/sslerr.h
index fdb59f4..8dfc974 100644
--- a/include/openssl/sslerr.h
+++ b/include/openssl/sslerr.h
@@ -403,6 +403,7 @@ int ERR_load_SSL_strings(void);
 # define SSL_R_CERTIFICATE_VERIFY_FAILED                  134
 # define SSL_R_CERT_CB_ERROR                              377
 # define SSL_R_CERT_LENGTH_MISMATCH                       135
+# define SSL_R_CIPHERSUITE_DIGEST_HAS_CHANGED             218
 # define SSL_R_CIPHER_CODE_WRONG_LENGTH                   137
 # define SSL_R_CIPHER_OR_HASH_UNAVAILABLE                 138
 # define SSL_R_CLIENTHELLO_TLSEXT                         226
diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c
index ffbe663..41c44ce 100644
--- a/ssl/s3_lib.c
+++ b/ssl/s3_lib.c
@@ -3680,7 +3680,7 @@ const SSL_CIPHER *ssl3_choose_cipher(SSL *s, STACK_OF(SSL_CIPHER) *clnt,
     const SSL_CIPHER *c, *ret = NULL;
     STACK_OF(SSL_CIPHER) *prio, *allow;
     int i, ii, ok;
-    unsigned long alg_k = 0, alg_a = 0, mask_k, mask_a;
+    unsigned long alg_k = 0, alg_a = 0, mask_k = 0, mask_a = 0;
 
     /* Let's see which ciphers we can support */
 
@@ -3714,8 +3714,10 @@ const SSL_CIPHER *ssl3_choose_cipher(SSL *s, STACK_OF(SSL_CIPHER) *clnt,
         allow = srvr;
     }
 
-    tls1_set_cert_validity(s);
-    ssl_set_masks(s);
+    if (!SSL_IS_TLS13(s)) {
+        tls1_set_cert_validity(s);
+        ssl_set_masks(s);
+    }
 
     for (i = 0; i < sk_SSL_CIPHER_num(prio); i++) {
         c = sk_SSL_CIPHER_value(prio, i);
@@ -3728,6 +3730,7 @@ const SSL_CIPHER *ssl3_choose_cipher(SSL *s, STACK_OF(SSL_CIPHER) *clnt,
             (DTLS_VERSION_LT(s->version, c->min_dtls) ||
              DTLS_VERSION_GT(s->version, c->max_dtls)))
             continue;
+
         /*
          * Since TLS 1.3 ciphersuites can be used with any auth or
          * key exchange scheme skip tests.
diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c
index 29e6648..eccc5af 100644
--- a/ssl/ssl_err.c
+++ b/ssl/ssl_err.c
@@ -622,6 +622,8 @@ static const ERR_STRING_DATA SSL_str_reasons[] = {
     {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_CERT_CB_ERROR), "cert cb error"},
     {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_CERT_LENGTH_MISMATCH),
     "cert length mismatch"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_CIPHERSUITE_DIGEST_HAS_CHANGED),
+    "ciphersuite digest has changed"},
     {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_CIPHER_CODE_WRONG_LENGTH),
     "cipher code wrong length"},
     {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_CIPHER_OR_HASH_UNAVAILABLE),
diff --git a/ssl/statem/extensions_srvr.c b/ssl/statem/extensions_srvr.c
index fe181ab..39e6c07 100644
--- a/ssl/statem/extensions_srvr.c
+++ b/ssl/statem/extensions_srvr.c
@@ -726,11 +726,8 @@ int tls_parse_ctos_psk(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
             continue;
 
         md = ssl_md(sess->cipher->algorithm2);
-        if (md == NULL) {
-            /*
-             * Don't recognise this cipher so we can't use the session.
-             * Ignore it
-             */
+        if (md != ssl_md(s->s3->tmp.new_cipher->algorithm2)) {
+            /* The ciphersuite is not compatible with this session. */
             SSL_SESSION_free(sess);
             sess = NULL;
             continue;
diff --git a/ssl/statem/statem_clnt.c b/ssl/statem/statem_clnt.c
index 020589f..7dd921e 100644
--- a/ssl/statem/statem_clnt.c
+++ b/ssl/statem/statem_clnt.c
@@ -1268,9 +1268,26 @@ static int set_client_ciphersuite(SSL *s, const unsigned char *cipherchars)
     if (s->session->cipher != NULL)
         s->session->cipher_id = s->session->cipher->id;
     if (s->hit && (s->session->cipher_id != c->id)) {
-        SSLerr(SSL_F_SET_CLIENT_CIPHERSUITE,
-               SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED);
-        return 0;
+        if (SSL_IS_TLS13(s)) {
+            /*
+             * In TLSv1.3 it is valid for the server to select a different
+             * ciphersuite as long as the hash is the same.
+             */
+            if (ssl_md(c->algorithm2)
+                    != ssl_md(s->session->cipher->algorithm2)) {
+                SSLerr(SSL_F_SET_CLIENT_CIPHERSUITE,
+                       SSL_R_CIPHERSUITE_DIGEST_HAS_CHANGED);
+                return 0;
+            }
+        } else {
+            /*
+             * Prior to TLSv1.3 resuming a session always meant using the same
+             * ciphersuite.
+             */
+            SSLerr(SSL_F_SET_CLIENT_CIPHERSUITE,
+                   SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED);
+            return 0;
+        }
     }
     s->s3->tmp.new_cipher = c;
 
diff --git a/ssl/statem/statem_srvr.c b/ssl/statem/statem_srvr.c
index e2d618c..6f57816 100644
--- a/ssl/statem/statem_srvr.c
+++ b/ssl/statem/statem_srvr.c
@@ -1566,6 +1566,69 @@ static int tls_early_post_process_client_hello(SSL *s, int *pal)
 
     s->hit = 0;
 
+    if (!ssl_cache_cipherlist(s, &clienthello->ciphersuites,
+                              clienthello->isv2, &al) ||
+        !bytes_to_cipher_list(s, &clienthello->ciphersuites, &ciphers, &scsvs,
+                             clienthello->isv2, &al)) {
+        goto err;
+    }
+
+    s->s3->send_connection_binding = 0;
+    /* Check what signalling cipher-suite values were received. */
+    if (scsvs != NULL) {
+        for(i = 0; i < sk_SSL_CIPHER_num(scsvs); i++) {
+            c = sk_SSL_CIPHER_value(scsvs, i);
+            if (SSL_CIPHER_get_id(c) == SSL3_CK_SCSV) {
+                if (s->renegotiate) {
+                    /* SCSV is fatal if renegotiating */
+                    SSLerr(SSL_F_TLS_EARLY_POST_PROCESS_CLIENT_HELLO,
+                           SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING);
+                    al = SSL_AD_HANDSHAKE_FAILURE;
+                    goto err;
+                }
+                s->s3->send_connection_binding = 1;
+            } else if (SSL_CIPHER_get_id(c) == SSL3_CK_FALLBACK_SCSV &&
+                       !ssl_check_version_downgrade(s)) {
+                /*
+                 * This SCSV indicates that the client previously tried
+                 * a higher version.  We should fail if the current version
+                 * is an unexpected downgrade, as that indicates that the first
+                 * connection may have been tampered with in order to trigger
+                 * an insecure downgrade.
+                 */
+                SSLerr(SSL_F_TLS_EARLY_POST_PROCESS_CLIENT_HELLO,
+                       SSL_R_INAPPROPRIATE_FALLBACK);
+                al = SSL_AD_INAPPROPRIATE_FALLBACK;
+                goto err;
+            }
+        }
+    }
+
+    /* For TLSv1.3 we must select the ciphersuite *before* session resumption */
+    if (SSL_IS_TLS13(s)) {
+        const SSL_CIPHER *cipher =
+            ssl3_choose_cipher(s, ciphers, SSL_get_ciphers(s));
+
+        if (cipher == NULL) {
+            SSLerr(SSL_F_TLS_EARLY_POST_PROCESS_CLIENT_HELLO,
+                   SSL_R_NO_SHARED_CIPHER);
+            al = SSL_AD_HANDSHAKE_FAILURE;
+            goto err;
+        }
+        if (s->hello_retry_request
+                && (s->s3->tmp.new_cipher == NULL
+                    || s->s3->tmp.new_cipher->id != cipher->id)) {
+            /*
+             * A previous HRR picked a different ciphersuite to the one we
+             * just selected. Something must have changed.
+             */
+            al = SSL_AD_ILLEGAL_PARAMETER;
+            SSLerr(SSL_F_TLS_EARLY_POST_PROCESS_CLIENT_HELLO, SSL_R_BAD_CIPHER);
+            goto err;
+        }
+        s->s3->tmp.new_cipher = cipher;
+    }
+
     /* We need to do this before getting the session */
     if (!tls_parse_extension(s, TLSEXT_IDX_extended_master_secret,
                              SSL_EXT_CLIENT_HELLO,
@@ -1609,46 +1672,11 @@ static int tls_early_post_process_client_hello(SSL *s, int *pal)
         }
     }
 
-    if (!ssl_cache_cipherlist(s, &clienthello->ciphersuites,
-                              clienthello->isv2, &al) ||
-        !bytes_to_cipher_list(s, &clienthello->ciphersuites, &ciphers, &scsvs,
-                             clienthello->isv2, &al)) {
-        goto err;
-    }
-
-    s->s3->send_connection_binding = 0;
-    /* Check what signalling cipher-suite values were received. */
-    if (scsvs != NULL) {
-        for(i = 0; i < sk_SSL_CIPHER_num(scsvs); i++) {
-            c = sk_SSL_CIPHER_value(scsvs, i);
-            if (SSL_CIPHER_get_id(c) == SSL3_CK_SCSV) {
-                if (s->renegotiate) {
-                    /* SCSV is fatal if renegotiating */
-                    SSLerr(SSL_F_TLS_EARLY_POST_PROCESS_CLIENT_HELLO,
-                           SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING);
-                    al = SSL_AD_HANDSHAKE_FAILURE;
-                    goto err;
-                }
-                s->s3->send_connection_binding = 1;
-            } else if (SSL_CIPHER_get_id(c) == SSL3_CK_FALLBACK_SCSV &&
-                       !ssl_check_version_downgrade(s)) {
-                /*
-                 * This SCSV indicates that the client previously tried
-                 * a higher version.  We should fail if the current version
-                 * is an unexpected downgrade, as that indicates that the first
-                 * connection may have been tampered with in order to trigger
-                 * an insecure downgrade.
-                 */
-                SSLerr(SSL_F_TLS_EARLY_POST_PROCESS_CLIENT_HELLO,
-                       SSL_R_INAPPROPRIATE_FALLBACK);
-                al = SSL_AD_INAPPROPRIATE_FALLBACK;
-                goto err;
-            }
-        }
-    }
-
-    /* If it is a hit, check that the cipher is in the list */
-    if (s->hit) {
+    /*
+     * If it is a hit, check that the cipher is in the list. In TLSv1.3 we check
+     * ciphersuite compatibility with the session as part of resumption.
+     */
+    if (!SSL_IS_TLS13(s) && s->hit) {
         j = 0;
         id = s->session->cipher->id;
 
@@ -1716,7 +1744,11 @@ static int tls_early_post_process_client_hello(SSL *s, int *pal)
         }
     }
 
-    if (!s->hit && s->version >= TLS1_VERSION && s->ext.session_secret_cb) {
+    if (!s->hit
+            && s->version >= TLS1_VERSION
+            && !SSL_IS_TLS13(s)
+            && !SSL_IS_DTLS(s)
+            && s->ext.session_secret_cb) {
         const SSL_CIPHER *pref_cipher = NULL;
         /*
          * s->session->master_key_length is a size_t, but this is an int for
@@ -1850,7 +1882,7 @@ static int tls_early_post_process_client_hello(SSL *s, int *pal)
      * Given s->session->ciphers and SSL_get_ciphers, we must pick a cipher
      */
 
-    if (!s->hit || s->hello_retry_request) {
+    if (!s->hit || SSL_IS_TLS13(s)) {
         sk_SSL_CIPHER_free(s->session->ciphers);
         s->session->ciphers = ciphers;
         if (ciphers == NULL) {
@@ -1956,9 +1988,9 @@ WORK_STATE tls_post_process_client_hello(SSL *s, WORK_STATE wst)
         wst = WORK_MORE_B;
     }
     if (wst == WORK_MORE_B) {
-        if (!s->hit || s->hello_retry_request) {
+        if (!s->hit || SSL_IS_TLS13(s)) {
             /* Let cert callback update server certificates if required */
-            if (s->cert->cert_cb) {
+            if (!s->hit && s->cert->cert_cb != NULL) {
                 int rv = s->cert->cert_cb(s, s->cert->cert_cb_arg);
                 if (rv == 0) {
                     al = SSL_AD_INTERNAL_ERROR;
@@ -1972,34 +2004,28 @@ WORK_STATE tls_post_process_client_hello(SSL *s, WORK_STATE wst)
                 }
                 s->rwstate = SSL_NOTHING;
             }
-            cipher =
-                ssl3_choose_cipher(s, s->session->ciphers, SSL_get_ciphers(s));
 
-            if (cipher == NULL) {
-                SSLerr(SSL_F_TLS_POST_PROCESS_CLIENT_HELLO,
-                       SSL_R_NO_SHARED_CIPHER);
-                goto f_err;
-            }
-            if (SSL_IS_TLS13(s) && s->s3->tmp.new_cipher != NULL
-                    && s->s3->tmp.new_cipher->id != cipher->id) {
-                /*
-                 * A previous HRR picked a different ciphersuite to the one we
-                 * just selected. Something must have changed.
-                 */
-                al = SSL_AD_ILLEGAL_PARAMETER;
-                SSLerr(SSL_F_TLS_POST_PROCESS_CLIENT_HELLO, SSL_R_BAD_CIPHER);
-                goto f_err;
+            /* In TLSv1.3 we selected the ciphersuite before resumption */
+            if (!SSL_IS_TLS13(s)) {
+                cipher =
+                    ssl3_choose_cipher(s, s->session->ciphers, SSL_get_ciphers(s));
+
+                if (cipher == NULL) {
+                    SSLerr(SSL_F_TLS_POST_PROCESS_CLIENT_HELLO,
+                           SSL_R_NO_SHARED_CIPHER);
+                    goto f_err;
+                }
+                s->s3->tmp.new_cipher = cipher;
             }
-            s->s3->tmp.new_cipher = cipher;
             if (!s->hit) {
                 if (!tls_choose_sigalg(s, &al))
                     goto f_err;
                 /* check whether we should disable session resumption */
                 if (s->not_resumable_session_cb != NULL)
                     s->session->not_resumable =
-                        s->not_resumable_session_cb(s, ((cipher->algorithm_mkey
-                                                        & (SSL_kDHE | SSL_kECDHE))
-                                                       != 0));
+                        s->not_resumable_session_cb(s,
+                            ((s->s3->tmp.new_cipher->algorithm_mkey
+                              & (SSL_kDHE | SSL_kECDHE)) != 0));
                 if (s->session->not_resumable)
                     /* do not send a session ticket */
                     s->ext.ticket_expected = 0;
diff --git a/test/sslapitest.c b/test/sslapitest.c
index ecbb8b7..a161989 100644
--- a/test/sslapitest.c
+++ b/test/sslapitest.c
@@ -18,6 +18,7 @@
 #include "ssltestlib.h"
 #include "testutil.h"
 #include "e_os.h"
+#include "../ssl/ssl_locl.h"
 
 static char *cert = NULL;
 static char *privkey = NULL;
@@ -1797,8 +1798,136 @@ static int test_early_data_tls1_2(int idx)
 
     return testresult;
 }
-# endif
-#endif
+# endif /* OPENSSL_NO_TLS1_2 */
+
+static int test_ciphersuite_change(void)
+{
+    SSL_CTX *cctx = NULL, *sctx = NULL;
+    SSL *clientssl = NULL, *serverssl = NULL;
+    SSL_SESSION *clntsess = NULL;
+    int testresult = 0;
+    const SSL_CIPHER *aes_128_gcm_sha256 = NULL;
+
+    /* Create a session based on SHA-256 */
+    if (!TEST_true(create_ssl_ctx_pair(TLS_server_method(),
+                                       TLS_client_method(), &sctx,
+                                       &cctx, cert, privkey))
+            || !TEST_true(SSL_CTX_set_cipher_list(cctx,
+                                                  "TLS13-AES-128-GCM-SHA256"))
+            || !TEST_true(create_ssl_objects(sctx, cctx, &serverssl,
+                                          &clientssl, NULL, NULL))
+            || !TEST_true(create_ssl_connection(serverssl, clientssl,
+                                                SSL_ERROR_NONE)))
+        goto end;
+
+    clntsess = SSL_get1_session(clientssl);
+    /* Save for later */
+    aes_128_gcm_sha256 = SSL_SESSION_get0_cipher(clntsess);
+    SSL_shutdown(clientssl);
+    SSL_shutdown(serverssl);
+    SSL_free(serverssl);
+    SSL_free(clientssl);
+    serverssl = clientssl = NULL;
+
+    /* Check we can resume a session with a different SHA-256 ciphersuite */
+    if (!TEST_true(SSL_CTX_set_cipher_list(cctx,
+                                           "TLS13-CHACHA20-POLY1305-SHA256"))
+            || !TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl,
+                                             NULL, NULL))
+            || !TEST_true(SSL_set_session(clientssl, clntsess))
+            || !TEST_true(create_ssl_connection(serverssl, clientssl,
+                                                SSL_ERROR_NONE))
+            || !TEST_true(SSL_session_reused(clientssl)))
+        goto end;
+
+    SSL_SESSION_free(clntsess);
+    clntsess = SSL_get1_session(clientssl);
+    SSL_shutdown(clientssl);
+    SSL_shutdown(serverssl);
+    SSL_free(serverssl);
+    SSL_free(clientssl);
+    serverssl = clientssl = NULL;
+
+    /*
+     * Check attempting to resume a SHA-256 session with no SHA-256 ciphersuites
+     * succeeds but does not resume.
+     */
+    if (!TEST_true(SSL_CTX_set_cipher_list(cctx, "TLS13-AES-256-GCM-SHA384"))
+            || !TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl,
+                                             NULL, NULL))
+            || !TEST_true(SSL_set_session(clientssl, clntsess))
+            || !TEST_true(create_ssl_connection(serverssl, clientssl,
+                                                SSL_ERROR_SSL))
+            || !TEST_false(SSL_session_reused(clientssl)))
+        goto end;
+
+    SSL_SESSION_free(clntsess);
+    clntsess = NULL;
+    SSL_shutdown(clientssl);
+    SSL_shutdown(serverssl);
+    SSL_free(serverssl);
+    SSL_free(clientssl);
+    serverssl = clientssl = NULL;
+
+    /* Create a session based on SHA384 */
+    if (!TEST_true(SSL_CTX_set_cipher_list(cctx, "TLS13-AES-256-GCM-SHA384"))
+            || !TEST_true(create_ssl_objects(sctx, cctx, &serverssl,
+                                          &clientssl, NULL, NULL))
+            || !TEST_true(create_ssl_connection(serverssl, clientssl,
+                                                SSL_ERROR_NONE)))
+        goto end;
+
+    clntsess = SSL_get1_session(clientssl);
+    SSL_shutdown(clientssl);
+    SSL_shutdown(serverssl);
+    SSL_free(serverssl);
+    SSL_free(clientssl);
+    serverssl = clientssl = NULL;
+
+    if (!TEST_true(SSL_CTX_set_cipher_list(cctx,
+                   "TLS13-AES-128-GCM-SHA256:TLS13-AES-256-GCM-SHA384"))
+            || !TEST_true(SSL_CTX_set_cipher_list(sctx,
+                                                  "TLS13-AES-256-GCM-SHA384"))
+            || !TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl,
+                                             NULL, NULL))
+            || !TEST_true(SSL_set_session(clientssl, clntsess))
+               /*
+                * We use SSL_ERROR_WANT_READ below so that we can pause the
+                * connection after the initial ClientHello has been sent to
+                * enable us to make some session changes.
+                */
+            || !TEST_false(create_ssl_connection(serverssl, clientssl,
+                                                SSL_ERROR_WANT_READ)))
+        goto end;
+
+    /* Trick the client into thinking this session is for a different digest */
+    clntsess->cipher = aes_128_gcm_sha256;
+    clntsess->cipher_id = clntsess->cipher->id;
+
+    /*
+     * Continue the previously started connection. Server has selected a SHA-384
+     * ciphersuite, but client thinks the session is for SHA-256, so it should
+     * bail out.
+     */
+    if (!TEST_false(create_ssl_connection(serverssl, clientssl,
+                                                SSL_ERROR_SSL))
+            || !TEST_int_eq(ERR_GET_REASON(ERR_get_error()),
+                            SSL_R_CIPHERSUITE_DIGEST_HAS_CHANGED))
+        goto end;
+
+    testresult = 1;
+
+ end:
+    SSL_SESSION_free(clntsess);
+    SSL_free(serverssl);
+    SSL_free(clientssl);
+    SSL_CTX_free(sctx);
+    SSL_CTX_free(cctx);
+
+    return testresult;
+}
+
+#endif /* OPENSSL_NO_TLS1_3 */
 
 static int clntaddoldcb = 0;
 static int clntparseoldcb = 0;
@@ -2222,6 +2351,7 @@ int test_main(int argc, char *argv[])
 # endif
 #endif
 #ifndef OPENSSL_NO_TLS1_3
+    ADD_TEST(test_ciphersuite_change);
     ADD_ALL_TESTS(test_custom_exts, 5);
 #else
     ADD_ALL_TESTS(test_custom_exts, 3);


More information about the openssl-commits mailing list