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@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/14750)
This commit is contained in:
Benjamin Kaduk 2021-03-16 22:03:36 -07:00
parent f89d3d698c
commit 6dc56df26c

View File

@ -4649,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
@ -8994,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);