[openssl] master update

kaduk at mit.edu kaduk at mit.edu
Sat May 15 22:30:14 UTC 2021


The branch master has been updated
       via  6dc56df26c41666ee5138da6c97bdb400fd03025 (commit)
       via  f89d3d698c570703b7fc0908603faf61f6f68446 (commit)
       via  75d4852090bb898b39be8e7ae2874720bd0a9c5c (commit)
       via  c22ad9b64a9f2cca64400836caee7279a9de8cc1 (commit)
       via  aa6bd216dd2691d1254eabcbd584691eb3b4b9b8 (commit)
      from  a8457b4c3d86a42209eabe90eddb605f59041f9e (commit)


- Log -----------------------------------------------------------------
commit 6dc56df26c41666ee5138da6c97bdb400fd03025
Author: Benjamin Kaduk <bkaduk at akamai.com>
Date:   Tue Mar 16 22:03:36 2021 -0700

    Add extensive test coverage for SSL_get_negotiated_group()
    
    This is nearly comprehensive, but we cannot exercise the functionality
    for PSK-only TLS 1.3 resumption, since openssl talking to openssl will
    always negotiate psk_dhe_ke.
    
    Exercise both the TLS 1.3 and 1.2 cases, for initial handshakes
    and resumptions, and for ECDHE and FFDHE.
    Since RFC 7919 named groups (for FFDHE) are only supported for TLS 1.3,
    the TLS 1.2 versions of those scenarios expect to get NID_undef since
    the key exchange was not performed using a named group.
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/14750)

commit f89d3d698c570703b7fc0908603faf61f6f68446
Author: Benjamin Kaduk <bkaduk at akamai.com>
Date:   Tue Mar 16 20:13:47 2021 -0700

    move group lists out of test_key_exchange() in preparation for reuse
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/14750)

commit 75d4852090bb898b39be8e7ae2874720bd0a9c5c
Author: Benjamin Kaduk <bkaduk at akamai.com>
Date:   Tue Mar 16 16:10:04 2021 -0700

    Extend SSL_get_negotiated_group() tests for TLS 1.2
    
    We don't implement RFC 7919 named groups for TLS 1.2, so we can
    only test the ECDHE case for non-TLS-1.3.
    
    Interestingly, though the test_key_exchange() routine claimed to
    be exercising ffdhe2048 with TLS 1.2, the configured ciphers were
    incompatible with DHE key exchange, so we ended up just using RSA
    key transport and not doing an ephemeral key exchange at all.
    Reconfigure the tests to actually exercise ephemeral key exchange
    for both the EC and FF cases (even though we don't use the named
    group information for the finite-field case).
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/14750)

commit c22ad9b64a9f2cca64400836caee7279a9de8cc1
Author: Benjamin Kaduk <bkaduk at akamai.com>
Date:   Tue Mar 16 13:42:00 2021 -0700

    Regenerate testsid.pem
    
    Convert this file to the new format, that includes the kex_group
    integer value.  This is needed in order for the round-trip conversion
    test to return the same value as the initial input.
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/14750)

commit aa6bd216dd2691d1254eabcbd584691eb3b4b9b8
Author: Benjamin Kaduk <bkaduk at akamai.com>
Date:   Tue Mar 16 07:47:09 2021 -0700

    Promote SSL_get_negotiated_group() for non-TLSv1.3
    
    It can be useful to know what group was used for the handshake's
    key exchange process even on non-TLS 1.3 connections.  Allow this
    API, new in OpenSSL 3.0.0, to be used on other TLS versions as well.
    Since pre-TLS-1.3 key exchange occurs only on full handshakes, this
    necessitates adding a field to the SSL_SESSION object to carry the
    group information across resumptions.  The key exchange group in the
    SSL_SESSION can also be relevant in TLS 1.3 when the resumption handshake
    uses the "psk_ke" key-exchange mode, so also track whether a fresh key
    exchange was done for TLS 1.3.
    
    Since the new field is optional in the ASN.1 sense, there is no need
    to increment SSL_SESSION_ASN1_VERSION (which incurs strong incompatibility
    churn).
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/14750)

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

Summary of changes:
 doc/man3/SSL_CTX_set1_curves.pod |  18 +--
 ssl/s3_lib.c                     |  11 +-
 ssl/ssl_asn1.c                   |   8 +-
 ssl/ssl_local.h                  |   7 ++
 ssl/statem/extensions_clnt.c     |  23 ++++
 ssl/statem/extensions_srvr.c     |   3 +
 ssl/statem/statem_clnt.c         |   2 +
 ssl/statem/statem_srvr.c         |   4 +-
 test/sslapitest.c                | 252 +++++++++++++++++++++++++++++++++++++--
 test/testsid.pem                 |   4 +-
 10 files changed, 307 insertions(+), 25 deletions(-)

diff --git a/doc/man3/SSL_CTX_set1_curves.pod b/doc/man3/SSL_CTX_set1_curves.pod
index 5eebb2b933..65892e46a5 100644
--- a/doc/man3/SSL_CTX_set1_curves.pod
+++ b/doc/man3/SSL_CTX_set1_curves.pod
@@ -77,10 +77,15 @@ NID_undef is returned. If the NID for the shared group is unknown then the value
 is set to the bitwise OR of TLSEXT_nid_unknown (0x1000000) and the id of the
 group.
 
-SSL_get_negotiated_group() returns the NID of the negotiated group on a TLSv1.3
-connection for key exchange. This can be called by either client or server. If
-the NID for the shared group is unknown then the value is set to the bitwise OR
-of TLSEXT_nid_unknown (0x1000000) and the id of the group.
+SSL_get_negotiated_group() returns the NID of the negotiated group used for
+the handshake key exchange process.  For TLSv1.3 connections this typically
+reflects the state of the current connection, though in the case of PSK-only
+resumption, the returned value will be from a previous connection.  For earlier
+TLS versions, when a session has been resumed, it always reflects the group
+used for key exchange during the initial handshake (otherwise it is from the
+current, non-resumption, connection).  This can be called by either client or
+server. If the NID for the shared group is unknown then the value is set to the
+bitwise OR of TLSEXT_nid_unknown (0x1000000) and the id of the group.
 
 All these functions are implemented as macros.
 
@@ -110,9 +115,8 @@ is -1.
 When called on a client B<ssl>, SSL_get_shared_group() has no meaning and
 returns -1.
 
-SSL_get_negotiated_group() returns the NID of the negotiated group on a
-TLSv1.3 connection for key exchange. Or it returns NID_undef if no negotiated
-group.
+SSL_get_negotiated_group() returns the NID of the negotiated group used for
+key exchange, or NID_undef if there was no negotiated group.
 
 =head1 SEE ALSO
 
diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c
index 1b491e7f92..7839a4d318 100644
--- a/ssl/s3_lib.c
+++ b/ssl/s3_lib.c
@@ -3636,9 +3636,16 @@ long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg)
             return id;
         }
     case SSL_CTRL_GET_NEGOTIATED_GROUP:
-        ret = tls1_group_id2nid(s->s3.group_id, 1);
-        break;
+        {
+            unsigned int id;
 
+            if (SSL_IS_TLS13(s) && s->s3.did_kex)
+                id = s->s3.group_id;
+            else
+                id = s->session->kex_group;
+            ret = tls1_group_id2nid(id, 1);
+            break;
+        }
     case SSL_CTRL_SET_SIGALGS:
         return tls1_set_sigalgs(s->cert, parg, larg, 0);
 
diff --git a/ssl/ssl_asn1.c b/ssl/ssl_asn1.c
index de93ccbde6..b27a58df7c 100644
--- a/ssl/ssl_asn1.c
+++ b/ssl/ssl_asn1.c
@@ -43,6 +43,7 @@ typedef struct {
     ASN1_OCTET_STRING *alpn_selected;
     uint32_t tlsext_max_fragment_len_mode;
     ASN1_OCTET_STRING *ticket_appdata;
+    uint32_t kex_group;
 } SSL_SESSION_ASN1;
 
 ASN1_SEQUENCE(SSL_SESSION_ASN1) = {
@@ -73,7 +74,8 @@ ASN1_SEQUENCE(SSL_SESSION_ASN1) = {
     ASN1_EXP_OPT_EMBED(SSL_SESSION_ASN1, max_early_data, ZUINT32, 15),
     ASN1_EXP_OPT(SSL_SESSION_ASN1, alpn_selected, ASN1_OCTET_STRING, 16),
     ASN1_EXP_OPT_EMBED(SSL_SESSION_ASN1, tlsext_max_fragment_len_mode, ZUINT32, 17),
-    ASN1_EXP_OPT(SSL_SESSION_ASN1, ticket_appdata, ASN1_OCTET_STRING, 18)
+    ASN1_EXP_OPT(SSL_SESSION_ASN1, ticket_appdata, ASN1_OCTET_STRING, 18),
+    ASN1_EXP_OPT_EMBED(SSL_SESSION_ASN1, kex_group, UINT32, 19)
 } static_ASN1_SEQUENCE_END(SSL_SESSION_ASN1)
 
 IMPLEMENT_STATIC_ASN1_ENCODE_FUNCTIONS(SSL_SESSION_ASN1)
@@ -134,6 +136,8 @@ int i2d_SSL_SESSION(const SSL_SESSION *in, unsigned char **pp)
     as.version = SSL_SESSION_ASN1_VERSION;
     as.ssl_version = in->ssl_version;
 
+    as.kex_group = in->kex_group;
+
     if (in->cipher == NULL)
         l = in->cipher_id;
     else
@@ -272,6 +276,8 @@ SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const unsigned char **pp,
 
     ret->ssl_version = (int)as->ssl_version;
 
+    ret->kex_group = as->kex_group;
+
     if (as->cipher->length != 2) {
         ERR_raise(ERR_LIB_SSL, SSL_R_CIPHER_CODE_WRONG_LENGTH);
         goto err;
diff --git a/ssl/ssl_local.h b/ssl/ssl_local.h
index 0a6c4bf9ec..8f3a2f93d6 100644
--- a/ssl/ssl_local.h
+++ b/ssl/ssl_local.h
@@ -599,6 +599,7 @@ struct ssl_session_st {
     const SSL_CIPHER *cipher;
     unsigned long cipher_id;    /* when ASN.1 loaded, this needs to be used to
                                  * load the 'cipher' structure */
+    unsigned int kex_group;      /* TLS group from key exchange */
     CRYPTO_EX_DATA ex_data;     /* application specific data */
     /*
      * These are used to make removal of session-ids more efficient and to
@@ -1412,6 +1413,12 @@ struct ssl_st {
          */
         char is_probably_safari;
 
+        /*
+         * Track whether we did a key exchange this handshake or not, so
+         * SSL_get_negotiated_group() knows whether to fall back to the
+         * value in the SSL_SESSION.
+         */
+        char did_kex;
         /* For clients: peer temporary key */
         /* The group_id for the key exchange key */
         uint16_t group_id;
diff --git a/ssl/statem/extensions_clnt.c b/ssl/statem/extensions_clnt.c
index b3ef1bc16a..fe9f8a9de6 100644
--- a/ssl/statem/extensions_clnt.c
+++ b/ssl/statem/extensions_clnt.c
@@ -1793,6 +1793,28 @@ int tls_parse_stoc_key_share(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
         SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_R_BAD_KEY_SHARE);
         return 0;
     }
+    /* Retain this group in the SSL_SESSION */
+    if (!s->hit) {
+        s->session->kex_group = group_id;
+    } else if (group_id != s->session->kex_group) {
+        /*
+         * If this is a resumption but changed what group was used, we need
+         * to record the new group in the session, but the session is not
+         * a new session and could be in use by other threads.  So, make
+         * a copy of the session to record the new information so that it's
+         * useful for any sessions resumed from tickets issued on this
+         * connection.
+         */
+        SSL_SESSION *new_sess;
+
+        if ((new_sess = ssl_session_dup(s->session, 0)) == NULL) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_MALLOC_FAILURE);
+            return 0;
+        }
+        SSL_SESSION_free(s->session);
+        s->session = new_sess;
+        s->session->kex_group = group_id;
+    }
 
     if ((ginf = tls1_group_id_lookup(s->ctx, group_id)) == NULL) {
         SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_R_BAD_KEY_SHARE);
@@ -1836,6 +1858,7 @@ int tls_parse_stoc_key_share(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
             return 0;
         }
     }
+    s->s3.did_kex = 1;
 #endif
 
     return 1;
diff --git a/ssl/statem/extensions_srvr.c b/ssl/statem/extensions_srvr.c
index b2d7ff8f39..6b3b33e239 100644
--- a/ssl/statem/extensions_srvr.c
+++ b/ssl/statem/extensions_srvr.c
@@ -669,6 +669,8 @@ int tls_parse_ctos_key_share(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
         }
 
         s->s3.group_id = group_id;
+        /* Cache the selected group ID in the SSL_SESSION */
+        s->session->kex_group = group_id;
 
         if (EVP_PKEY_set1_encoded_public_key(s->s3.peer_tmp,
                 PACKET_data(&encoded_pt),
@@ -1705,6 +1707,7 @@ EXT_RETURN tls_construct_stoc_key_share(SSL *s, WPACKET *pkt,
             return EXT_RETURN_FAIL;
         }
     }
+    s->s3.did_kex = 1;
     return EXT_RETURN_SENT;
 #else
     return EXT_RETURN_FAIL;
diff --git a/ssl/statem/statem_clnt.c b/ssl/statem/statem_clnt.c
index dab4d1c4bc..85ed3e4259 100644
--- a/ssl/statem/statem_clnt.c
+++ b/ssl/statem/statem_clnt.c
@@ -2167,6 +2167,8 @@ static int tls_process_ske_ecdhe(SSL *s, PACKET *pkt, EVP_PKEY **pkey)
         *pkey = X509_get0_pubkey(s->session->peer);
     /* else anonymous ECDH, so no certificate or pkey. */
 
+    /* Cache the agreed upon group in the SSL_SESSION */
+    s->session->kex_group = curve_id;
     return 1;
 }
 
diff --git a/ssl/statem/statem_srvr.c b/ssl/statem/statem_srvr.c
index bad3619170..768e1110e6 100644
--- a/ssl/statem/statem_srvr.c
+++ b/ssl/statem/statem_srvr.c
@@ -2519,8 +2519,10 @@ int tls_construct_server_key_exchange(SSL *s, WPACKET *pkt)
                      SSL_R_UNSUPPORTED_ELLIPTIC_CURVE);
             goto err;
         }
-        s->s3.tmp.pkey = ssl_generate_pkey_group(s, curve_id);
+        /* Cache the group used in the SSL_SESSION */
+        s->session->kex_group = curve_id;
         /* Generate a new key for this curve */
+        s->s3.tmp.pkey = ssl_generate_pkey_group(s, curve_id);
         if (s->s3.tmp.pkey == NULL) {
             /* SSLfatal() already called */
             goto err;
diff --git a/test/sslapitest.c b/test/sslapitest.c
index ad83491573..21220d5834 100644
--- a/test/sslapitest.c
+++ b/test/sslapitest.c
@@ -4487,19 +4487,19 @@ static int test_ciphersuite_change(void)
  * Test 12 = Test all ECDHE with TLSv1.2 client and server
  * Test 13 = Test all FFDHE with TLSv1.2 client and server
  */
+# ifndef OPENSSL_NO_EC
+static int ecdhe_kexch_groups[] = {NID_X9_62_prime256v1, NID_secp384r1,
+                                   NID_secp521r1, NID_X25519, NID_X448};
+# endif
+# ifndef OPENSSL_NO_DH
+static int ffdhe_kexch_groups[] = {NID_ffdhe2048, NID_ffdhe3072, NID_ffdhe4096,
+                                   NID_ffdhe6144, NID_ffdhe8192};
+# endif
 static int test_key_exchange(int idx)
 {
     SSL_CTX *sctx = NULL, *cctx = NULL;
     SSL *serverssl = NULL, *clientssl = NULL;
     int testresult = 0;
-# ifndef OPENSSL_NO_EC
-    int ecdhe_kexch_groups[] = {NID_X9_62_prime256v1, NID_secp384r1,
-                                NID_secp521r1, NID_X25519, NID_X448};
-# endif
-# ifndef OPENSSL_NO_DH
-    int ffdhe_kexch_groups[] = {NID_ffdhe2048, NID_ffdhe3072, NID_ffdhe4096,
-                                NID_ffdhe6144, NID_ffdhe8192};
-# endif
     int kexch_alg;
     int *kexch_groups = &kexch_alg;
     int kexch_groups_size = 1;
@@ -4592,7 +4592,9 @@ static int test_key_exchange(int idx)
         goto end;
 
     if (!TEST_true(SSL_CTX_set_cipher_list(sctx,
-                   TLS1_TXT_RSA_WITH_AES_128_SHA)))
+                   TLS1_TXT_ECDHE_RSA_WITH_AES_128_GCM_SHA256 ":"
+                   TLS1_TXT_DHE_RSA_WITH_AES_128_GCM_SHA256))
+            || !TEST_true(SSL_CTX_set_dh_auto(sctx, 1)))
         goto end;
 
     /*
@@ -4601,8 +4603,8 @@ static int test_key_exchange(int idx)
      */
 # ifndef OPENSSL_NO_TLS1_2
     if (!TEST_true(SSL_CTX_set_cipher_list(cctx,
-                   TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_CCM ":"
-                   TLS1_TXT_RSA_WITH_AES_128_SHA)))
+                   TLS1_TXT_ECDHE_RSA_WITH_AES_128_GCM_SHA256 ":"
+                   TLS1_TXT_DHE_RSA_WITH_AES_128_GCM_SHA256)))
         goto end;
 # endif
 
@@ -4630,7 +4632,8 @@ static int test_key_exchange(int idx)
                      kexch_name0))
         goto end;
 
-    if (max_version == TLS1_3_VERSION) {
+    /* We don't implement RFC 7919 named groups for TLS 1.2. */
+    if (idx != 13) {
         if (!TEST_int_eq(SSL_get_negotiated_group(serverssl), kexch_groups[0]))
             goto end;
         if (!TEST_int_eq(SSL_get_negotiated_group(clientssl), kexch_groups[0]))
@@ -4646,6 +4649,226 @@ static int test_key_exchange(int idx)
     return testresult;
 }
 
+# if !defined(OPENSSL_NO_EC) && !defined(OPENSSL_NO_DH)
+static int set_ssl_groups(SSL *serverssl, SSL *clientssl, int clientmulti,
+                          int isecdhe, int idx)
+{
+    int kexch_alg;
+    int *kexch_groups = &kexch_alg;
+    int numec, numff;
+
+    numec = OSSL_NELEM(ecdhe_kexch_groups);
+    numff = OSSL_NELEM(ffdhe_kexch_groups);
+    if (isecdhe)
+        kexch_alg = ecdhe_kexch_groups[idx];
+    else
+        kexch_alg = ffdhe_kexch_groups[idx];
+
+    if (clientmulti) {
+        if (!TEST_true(SSL_set1_groups(serverssl, kexch_groups, 1)))
+            return 0;
+        if (isecdhe) {
+            if (!TEST_true(SSL_set1_groups(clientssl, ecdhe_kexch_groups,
+                                           numec)))
+                return 0;
+        } else {
+            if (!TEST_true(SSL_set1_groups(clientssl, ffdhe_kexch_groups,
+                                           numff)))
+                return 0;
+        }
+    } else {
+        if (!TEST_true(SSL_set1_groups(clientssl, kexch_groups, 1)))
+            return 0;
+        if (isecdhe) {
+            if (!TEST_true(SSL_set1_groups(serverssl, ecdhe_kexch_groups,
+                                           numec)))
+                return 0;
+        } else {
+            if (!TEST_true(SSL_set1_groups(serverssl, ffdhe_kexch_groups,
+                                           numff)))
+                return 0;
+        }
+    }
+    return 1;
+}
+
+/*-
+ * Test the SSL_get_negotiated_group() API across a battery of scenarios.
+ * Run through both the ECDHE and FFDHE group lists used in the previous
+ * test, for both TLS 1.2 and TLS 1.3, negotiating each group in turn,
+ * confirming the expected result; then perform a resumption handshake
+ * while offering the same group list, and another resumption handshake
+ * offering a different group list.  The returned value should be the
+ * negotiated group for the initial handshake; for TLS 1.3 resumption
+ * handshakes the returned value will be negotiated on the resumption
+ * handshake itself, but for TLS 1.2 resumption handshakes the value will
+ * be cached in the session from the original handshake, regardless of what
+ * was offered in the resumption ClientHello.
+ *
+ * Using E for the number of EC groups and F for the number of FF groups:
+ * E tests of ECDHE with TLS 1.3, client sends only one group
+ * F tests of FFDHE with TLS 1.3, client sends only one group
+ * E tests of ECDHE with TLS 1.2, client sends only one group
+ * F tests of FFDHE with TLS 1.2, client sends only one group
+ * E tests of ECDHE with TLS 1.3, server only has one group
+ * F tests of FFDHE with TLS 1.3, server only has one group
+ * E tests of ECDHE with TLS 1.2, server only has one group
+ * F tests of FFDHE with TLS 1.2, server only has one group
+ */
+static int test_negotiated_group(int idx)
+{
+    int clientmulti, istls13, isecdhe, numec, numff, numgroups;
+    int expectednid;
+    SSL_CTX *sctx = NULL, *cctx = NULL;
+    SSL *serverssl = NULL, *clientssl = NULL;
+    SSL_SESSION *origsess = NULL;
+    int testresult = 0;
+    int kexch_alg;
+    int max_version = TLS1_3_VERSION;
+
+    numec = OSSL_NELEM(ecdhe_kexch_groups);
+    numff = OSSL_NELEM(ffdhe_kexch_groups);
+    numgroups = numec + numff;
+    clientmulti = (idx < 2 * numgroups);
+    idx = idx % (2 * numgroups);
+    istls13 = (idx < numgroups);
+    idx = idx % numgroups;
+    isecdhe = (idx < numec);
+    if (!isecdhe)
+        idx -= numec;
+    /* Now 'idx' is an index into ecdhe_kexch_groups or ffdhe_kexch_groups */
+    if (isecdhe)
+        kexch_alg = ecdhe_kexch_groups[idx];
+    else
+        kexch_alg = ffdhe_kexch_groups[idx];
+    /* We expect nothing for the unimplemented TLS 1.2 FFDHE named groups */
+    if (!istls13 && !isecdhe)
+        expectednid = NID_undef;
+    else
+        expectednid = kexch_alg;
+
+    if (!istls13)
+        max_version = TLS1_2_VERSION;
+
+    if (!TEST_true(create_ssl_ctx_pair(libctx, TLS_server_method(),
+                                       TLS_client_method(), TLS1_VERSION,
+                                       max_version, &sctx, &cctx, cert,
+                                       privkey)))
+        goto end;
+
+    /*
+     * Force (EC)DHE ciphers for TLS 1.2.
+     * Be sure to enable auto tmp DH so that FFDHE can succeed.
+     */
+    if (!TEST_true(SSL_CTX_set_cipher_list(sctx,
+                   TLS1_TXT_ECDHE_RSA_WITH_AES_128_GCM_SHA256 ":"
+                   TLS1_TXT_DHE_RSA_WITH_AES_128_GCM_SHA256))
+            || !TEST_true(SSL_CTX_set_dh_auto(sctx, 1)))
+        goto end;
+    if (!TEST_true(SSL_CTX_set_cipher_list(cctx,
+                   TLS1_TXT_ECDHE_RSA_WITH_AES_128_GCM_SHA256 ":"
+                   TLS1_TXT_DHE_RSA_WITH_AES_128_GCM_SHA256)))
+        goto end;
+
+    if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl,
+                                             NULL, NULL)))
+        goto end;
+
+    if (!TEST_true(set_ssl_groups(serverssl, clientssl, clientmulti, isecdhe,
+                                  idx)))
+        goto end;
+
+    if (!TEST_true(create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE)))
+        goto end;
+
+    /* Initial handshake; always the configured one */
+    if (!TEST_uint_eq(SSL_get_negotiated_group(clientssl), expectednid)
+            || !TEST_uint_eq(SSL_get_negotiated_group(serverssl), expectednid))
+        goto end;
+
+    if (!TEST_ptr((origsess = SSL_get1_session(clientssl))))
+        goto end;
+
+    SSL_shutdown(clientssl);
+    SSL_shutdown(serverssl);
+    SSL_free(serverssl);
+    SSL_free(clientssl);
+    serverssl = clientssl = NULL;
+
+    /* First resumption attempt; use the same config as initial handshake */
+    if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl,
+                                             NULL, NULL))
+            || !TEST_true(SSL_set_session(clientssl, origsess))
+            || !TEST_true(set_ssl_groups(serverssl, clientssl, clientmulti,
+                                         isecdhe, idx)))
+        goto end;
+
+    if (!TEST_true(create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE))
+            || !TEST_true(SSL_session_reused(clientssl)))
+        goto end;
+
+    /* Still had better agree, since nothing changed... */
+    if (!TEST_uint_eq(SSL_get_negotiated_group(clientssl), expectednid)
+            || !TEST_uint_eq(SSL_get_negotiated_group(serverssl), expectednid))
+        goto end;
+
+    SSL_shutdown(clientssl);
+    SSL_shutdown(serverssl);
+    SSL_free(serverssl);
+    SSL_free(clientssl);
+    serverssl = clientssl = NULL;
+
+    /*-
+     * Second resumption attempt
+     * The party that picks one group changes it, which we effectuate by
+     * changing 'idx' and updating what we expect.
+     */
+    if (idx == 0)
+        idx = 1;
+    else
+        idx--;
+    if (istls13) {
+        if (isecdhe)
+            expectednid = ecdhe_kexch_groups[idx];
+        else
+            expectednid = ffdhe_kexch_groups[idx];
+        /* Verify that we are changing what we expect. */
+        if (!TEST_int_ne(expectednid, kexch_alg))
+            goto end;
+    } else {
+        /* TLS 1.2 only supports named groups for ECDHE. */
+        if (isecdhe)
+            expectednid = kexch_alg;
+        else
+            expectednid = 0;
+    }
+    if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl,
+                                             NULL, NULL))
+            || !TEST_true(SSL_set_session(clientssl, origsess))
+            || !TEST_true(set_ssl_groups(serverssl, clientssl, clientmulti,
+                                         isecdhe, idx)))
+        goto end;
+
+    if (!TEST_true(create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE))
+            || !TEST_true(SSL_session_reused(clientssl)))
+        goto end;
+
+    /* Check that we get what we expected */
+    if (!TEST_uint_eq(SSL_get_negotiated_group(clientssl), expectednid)
+            || !TEST_uint_eq(SSL_get_negotiated_group(serverssl), expectednid))
+        goto end;
+
+    testresult = 1;
+ end:
+    SSL_free(serverssl);
+    SSL_free(clientssl);
+    SSL_CTX_free(sctx);
+    SSL_CTX_free(cctx);
+    SSL_SESSION_free(origsess);
+    return testresult;
+}
+# endif /* !defined(OPENSSL_NO_EC) && !defined(OPENSSL_NO_DH) */
+
 /*
  * Test TLSv1.3 Cipher Suite
  * Test 0 = Set TLS1.3 cipher on context
@@ -8991,6 +9214,11 @@ int setup_tests(void)
 # ifndef OPENSSL_NO_TLS1_2
     /* Test with both TLSv1.3 and 1.2 versions */
     ADD_ALL_TESTS(test_key_exchange, 14);
+#  if !defined(OPENSSL_NO_EC) && !defined(OPENSSL_NO_DH)
+    ADD_ALL_TESTS(test_negotiated_group,
+                  4 * (OSSL_NELEM(ecdhe_kexch_groups)
+                       + OSSL_NELEM(ffdhe_kexch_groups)));
+#  endif
 # else
     /* Test with only TLSv1.3 versions */
     ADD_ALL_TESTS(test_key_exchange, 12);
diff --git a/test/testsid.pem b/test/testsid.pem
index a90fb6ef12..36fc4dbe48 100644
--- a/test/testsid.pem
+++ b/test/testsid.pem
@@ -1,5 +1,5 @@
 -----BEGIN SSL SESSION PARAMETERS-----
-MIIGpAIBAQICAwMEAsAwBCABkpk0q01VEnPtcNWLtYg1xZJLreP0C1r4wPOakiLu
+MIIGqQIBAQICAwMEAsAwBCABkpk0q01VEnPtcNWLtYg1xZJLreP0C1r4wPOakiLu
 8AQwi0opOLa+Omt26PqbLUcmI1H7F/n7qRy6TaL9Lxf2/ZBUDgRG3aSuSejO+gki
 F2U9oQYCBFR6XVaiBAICASyjggVjMIIFXzCCBEegAwIBAgIQNdDRF5hINFi7kAeK
 0fP5FjANBgkqhkiG9w0BAQUFADBBMQswCQYDVQQGEwJGUjESMBAGA1UEChMJR0FO
@@ -34,5 +34,5 @@ d/xgQ6J+/Z2kAgQAqQQCAgEsqoHDBIHAPGxCacLRMYb3hbL3lRqQIfH3xoufIwKn
 zOAIyjxH7GPZpI87/e93AF1uw6eyy+aWJM6G/71E8Ln1iQtZjrGkGQCjEcIrUhEk
 Bgg93A28zly2zu2aBwi2yT4bUcyHxE3P3Q4R8xkQxrdWSMfCjCy9HKUViOENKET6
 avKXF7lDT1iG/x8RtTHtFGYX4YcFVhdEqcqnZ7tw5sqkHG2D0gLzO2SETF9KPHCq
-zAHQtw5r4Dgl+a+BGLczh6as4yIH+xH+
+zAHQtw5r4Dgl+a+BGLczh6as4yIH+xH+swMCAQA=
 -----END SSL SESSION PARAMETERS-----


More information about the openssl-commits mailing list