forked from wolfSSL/wolfssl
wolfSSL_set1_curves_list(), wolfSSL_CTX_set1_curves_list() improvements.
- Use wolfSSL API wolfSSL_set_groups() and wolfSSL_CTX_set_groups() to configure curves list - This sets ssl->groups and ctx->groups accordingly and makes TLSX_KEY_SHARE generation respect the selection and precedence. - Add tests in quic to assert the order of selections.
This commit is contained in:
96
src/ssl.c
96
src/ssl.c
@ -33926,20 +33926,34 @@ int wolfSSL_curve_is_disabled(WOLFSSL* ssl, word16 curve_id)
|
|||||||
defined(HAVE_CURVE25519) || defined(HAVE_CURVE448))
|
defined(HAVE_CURVE25519) || defined(HAVE_CURVE448))
|
||||||
static int set_curves_list(WOLFSSL* ssl, WOLFSSL_CTX *ctx, const char* names)
|
static int set_curves_list(WOLFSSL* ssl, WOLFSSL_CTX *ctx, const char* names)
|
||||||
{
|
{
|
||||||
int idx, start = 0, len;
|
int idx, start = 0, len, i, ret = WOLFSSL_FAILURE;
|
||||||
word16 curve;
|
word16 curve;
|
||||||
word32 disabled;
|
word32 disabled;
|
||||||
char name[MAX_CURVE_NAME_SZ];
|
char name[MAX_CURVE_NAME_SZ];
|
||||||
|
byte groups_len = 0;
|
||||||
|
#ifdef WOLFSSL_SMALL_STACK
|
||||||
|
void *heap = ssl? ssl->heap : ctx->heap;
|
||||||
|
int *groups;
|
||||||
|
#else
|
||||||
|
int groups[WOLFSSL_MAX_GROUP_COUNT];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef WOLFSSL_SMALL_STACK
|
||||||
|
groups = (byte*)XMALLOC(sizeof(int)*WOLFSSL_MAX_GROUP_COUNT,
|
||||||
|
heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||||
|
if (groups == NULL) {
|
||||||
|
ret = MEMORY_E;
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Disable all curves so that only the ones the user wants are enabled. */
|
|
||||||
disabled = 0xFFFFFFFFUL;
|
|
||||||
for (idx = 1; names[idx-1] != '\0'; idx++) {
|
for (idx = 1; names[idx-1] != '\0'; idx++) {
|
||||||
if (names[idx] != ':' && names[idx] != '\0')
|
if (names[idx] != ':' && names[idx] != '\0')
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
len = idx - start;
|
len = idx - start;
|
||||||
if (len > MAX_CURVE_NAME_SZ - 1)
|
if (len > MAX_CURVE_NAME_SZ - 1)
|
||||||
return WOLFSSL_FAILURE;
|
goto leave;
|
||||||
|
|
||||||
XMEMCPY(name, names + start, len);
|
XMEMCPY(name, names + start, len);
|
||||||
name[len] = 0;
|
name[len] = 0;
|
||||||
@ -33974,25 +33988,25 @@ static int set_curves_list(WOLFSSL* ssl, WOLFSSL_CTX *ctx, const char* names)
|
|||||||
#endif
|
#endif
|
||||||
else {
|
else {
|
||||||
#if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST)
|
#if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST)
|
||||||
int ret;
|
int nret;
|
||||||
const ecc_set_type *eccSet;
|
const ecc_set_type *eccSet;
|
||||||
|
|
||||||
ret = wc_ecc_get_curve_idx_from_name(name);
|
nret = wc_ecc_get_curve_idx_from_name(name);
|
||||||
if (ret < 0) {
|
if (nret < 0) {
|
||||||
WOLFSSL_MSG("Could not find name in set");
|
WOLFSSL_MSG("Could not find name in set");
|
||||||
return WOLFSSL_FAILURE;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
eccSet = wc_ecc_get_curve_params(ret);
|
eccSet = wc_ecc_get_curve_params(ret);
|
||||||
if (eccSet == NULL) {
|
if (eccSet == NULL) {
|
||||||
WOLFSSL_MSG("NULL set returned");
|
WOLFSSL_MSG("NULL set returned");
|
||||||
return WOLFSSL_FAILURE;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
curve = GetCurveByOID(eccSet->oidSum);
|
curve = GetCurveByOID(eccSet->oidSum);
|
||||||
#else
|
#else
|
||||||
WOLFSSL_MSG("API not present to search farther using name");
|
WOLFSSL_MSG("API not present to search farther using name");
|
||||||
return WOLFSSL_FAILURE;
|
goto leave;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34000,32 +34014,70 @@ static int set_curves_list(WOLFSSL* ssl, WOLFSSL_CTX *ctx, const char* names)
|
|||||||
/* shift left more than size of ctx->disabledCurves causes static
|
/* shift left more than size of ctx->disabledCurves causes static
|
||||||
* analysis report */
|
* analysis report */
|
||||||
WOLFSSL_MSG("curve value is too large for upcoming shift");
|
WOLFSSL_MSG("curve value is too large for upcoming shift");
|
||||||
return WOLFSSL_FAILURE;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(HAVE_SUPPORTED_CURVES) && !defined(NO_WOLFSSL_CLIENT)
|
for (i = 0; i < groups_len; ++i) {
|
||||||
|
if (groups[i] == curve) {
|
||||||
|
/* silently drop duplicates */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (i >= groups_len) {
|
||||||
|
if (groups_len >= WOLFSSL_MAX_GROUP_COUNT) {
|
||||||
|
WOLFSSL_MSG_EX("setting %d or more supported "
|
||||||
|
"curves is not permitted", groups_len);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
groups[groups_len++] = (int)curve;
|
||||||
|
}
|
||||||
|
|
||||||
|
start = idx + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Disable all curves so that only the ones the user wants are enabled. */
|
||||||
|
disabled = 0xFFFFFFFFUL;
|
||||||
|
for (i = 0; i < groups_len; ++i) {
|
||||||
|
/* Switch the bit to off and therefore is enabled. */
|
||||||
|
curve = (word16)groups[i];
|
||||||
|
disabled &= ~(1U << curve);
|
||||||
|
|
||||||
|
#ifndef WOLFSSL_OLD_SET_CURVES_LIST
|
||||||
|
/* using the wolfSSL API to set the groups, this will populate
|
||||||
|
* (ssl|ctx)->groups and reset any TLSX_SUPPORTED_GROUPS.
|
||||||
|
* The order in (ssl|ctx)->groups will then be respected
|
||||||
|
* when TLSX_KEY_SHARE needs to be established */
|
||||||
|
if ((ssl && wolfSSL_set_groups(ssl, groups, groups_len)
|
||||||
|
!= WOLFSSL_SUCCESS)
|
||||||
|
|| (ctx && wolfSSL_CTX_set_groups(ctx, groups, groups_len)
|
||||||
|
!= WOLFSSL_SUCCESS)) {
|
||||||
|
WOLFSSL_MSG("Unable to set supported curve");
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
#elif defined(HAVE_SUPPORTED_CURVES) && !defined(NO_WOLFSSL_CLIENT)
|
||||||
/* set the supported curve so client TLS extension contains only the
|
/* set the supported curve so client TLS extension contains only the
|
||||||
* desired curves */
|
* desired curves */
|
||||||
if ((ssl
|
if ((ssl && wolfSSL_UseSupportedCurve(ssl, curve) != WOLFSSL_SUCCESS)
|
||||||
&& wolfSSL_UseSupportedCurve(ssl, curve) != WOLFSSL_SUCCESS)
|
|| (ctx && wolfSSL_CTX_UseSupportedCurve(ctx, curve)
|
||||||
|| (ctx
|
!= WOLFSSL_SUCCESS)) {
|
||||||
&& wolfSSL_CTX_UseSupportedCurve(ctx, curve) != WOLFSSL_SUCCESS)) {
|
|
||||||
WOLFSSL_MSG("Unable to set supported curve");
|
WOLFSSL_MSG("Unable to set supported curve");
|
||||||
return WOLFSSL_FAILURE;
|
goto leave;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Switch the bit to off and therefore is enabled. */
|
|
||||||
disabled &= ~(1U << curve);
|
|
||||||
start = idx + 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ssl)
|
if (ssl)
|
||||||
ssl->disabledCurves = disabled;
|
ssl->disabledCurves = disabled;
|
||||||
else
|
else
|
||||||
ctx->disabledCurves = disabled;
|
ctx->disabledCurves = disabled;
|
||||||
|
ret = WOLFSSL_SUCCESS;
|
||||||
|
|
||||||
return WOLFSSL_SUCCESS;
|
leave:
|
||||||
|
#ifdef WOLFSSL_SMALL_STACK
|
||||||
|
if (groups)
|
||||||
|
XFREE((void*)groups, heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||||
|
#endif
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int wolfSSL_CTX_set1_curves_list(WOLFSSL_CTX* ctx, const char* names)
|
int wolfSSL_CTX_set1_curves_list(WOLFSSL_CTX* ctx, const char* names)
|
||||||
|
86
tests/quic.c
86
tests/quic.c
@ -949,20 +949,26 @@ static int QuicConversation_start(QuicConversation *conv, const byte *data,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int QuicConversation_step(QuicConversation *conv)
|
static int QuicConversation_step(QuicConversation *conv, int may_fail)
|
||||||
{
|
{
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
if (!conv->started) {
|
if (!conv->started) {
|
||||||
AssertTrue(wolfSSL_connect(conv->client->ssl) != WOLFSSL_SUCCESS);
|
n = wolfSSL_connect(conv->client->ssl);
|
||||||
AssertIntEQ(SSL_ERROR_WANT_READ, wolfSSL_get_error(conv->client->ssl, 0));
|
if (n != WOLFSSL_SUCCESS
|
||||||
|
&& wolfSSL_get_error(conv->client->ssl, 0) != SSL_ERROR_WANT_READ) {
|
||||||
|
if (may_fail) return 0;
|
||||||
|
AssertIntEQ(SSL_ERROR_WANT_READ, wolfSSL_get_error(conv->client->ssl, 0));
|
||||||
|
}
|
||||||
conv->started = 1;
|
conv->started = 1;
|
||||||
}
|
}
|
||||||
if (conv->server->output.len > 0) {
|
if (conv->server->output.len > 0) {
|
||||||
QuicTestContext_forward(conv->server, conv->client, conv->rec_log, sizeof(conv->rec_log));
|
QuicTestContext_forward(conv->server, conv->client, conv->rec_log, sizeof(conv->rec_log));
|
||||||
n = wolfSSL_quic_read_write(conv->client->ssl);
|
n = wolfSSL_quic_read_write(conv->client->ssl);
|
||||||
if (n != WOLFSSL_SUCCESS) {
|
if (n != WOLFSSL_SUCCESS
|
||||||
AssertIntEQ(wolfSSL_get_error(conv->client->ssl, 0), SSL_ERROR_WANT_READ);
|
&& wolfSSL_get_error(conv->client->ssl, 0) != SSL_ERROR_WANT_READ) {
|
||||||
|
if (may_fail) return 0;
|
||||||
|
AssertIntEQ(SSL_ERROR_WANT_READ, wolfSSL_get_error(conv->client->ssl, 0));
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -976,7 +982,10 @@ static int QuicConversation_step(QuicConversation *conv)
|
|||||||
(int)(sizeof(conv->early_data) - conv->early_data_len),
|
(int)(sizeof(conv->early_data) - conv->early_data_len),
|
||||||
&written);
|
&written);
|
||||||
if (n < 0) {
|
if (n < 0) {
|
||||||
AssertIntEQ(wolfSSL_get_error(conv->server->ssl, 0), SSL_ERROR_WANT_READ);
|
if (wolfSSL_get_error(conv->server->ssl, 0) != SSL_ERROR_WANT_READ) {
|
||||||
|
if (may_fail) return 0;
|
||||||
|
AssertIntEQ(wolfSSL_get_error(conv->server->ssl, 0), SSL_ERROR_WANT_READ);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (n > 0) {
|
else if (n > 0) {
|
||||||
conv->early_data_len += n;
|
conv->early_data_len += n;
|
||||||
@ -988,7 +997,9 @@ static int QuicConversation_step(QuicConversation *conv)
|
|||||||
#endif /* WOLFSSL_EARLY_DATA */
|
#endif /* WOLFSSL_EARLY_DATA */
|
||||||
{
|
{
|
||||||
n = wolfSSL_quic_read_write(conv->server->ssl);
|
n = wolfSSL_quic_read_write(conv->server->ssl);
|
||||||
if (n != WOLFSSL_SUCCESS) {
|
if (n != WOLFSSL_SUCCESS
|
||||||
|
&& wolfSSL_get_error(conv->server->ssl, 0) != SSL_ERROR_WANT_READ) {
|
||||||
|
if (may_fail) return 0;
|
||||||
AssertIntEQ(wolfSSL_get_error(conv->server->ssl, 0), SSL_ERROR_WANT_READ);
|
AssertIntEQ(wolfSSL_get_error(conv->server->ssl, 0), SSL_ERROR_WANT_READ);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1004,7 +1015,7 @@ static void QuicConversation_do(QuicConversation *conv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
if (!QuicConversation_step(conv)) {
|
if (!QuicConversation_step(conv, 0)) {
|
||||||
int c_err = wolfSSL_get_error(conv->client->ssl, 0);
|
int c_err = wolfSSL_get_error(conv->client->ssl, 0);
|
||||||
int s_err = wolfSSL_get_error(conv->server->ssl, 0);
|
int s_err = wolfSSL_get_error(conv->server->ssl, 0);
|
||||||
if (c_err == 0 && s_err == 0) {
|
if (c_err == 0 && s_err == 0) {
|
||||||
@ -1018,6 +1029,22 @@ static void QuicConversation_do(QuicConversation *conv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void QuicConversation_fail(QuicConversation *conv)
|
||||||
|
{
|
||||||
|
if (!conv->started) {
|
||||||
|
QuicConversation_start(conv, NULL, 0, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
if (!QuicConversation_step(conv, 1)) {
|
||||||
|
int c_err = wolfSSL_get_error(conv->client->ssl, 0);
|
||||||
|
int s_err = wolfSSL_get_error(conv->server->ssl, 0);
|
||||||
|
AssertTrue(c_err != 0 || s_err != 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int test_quic_client_hello(int verbose) {
|
static int test_quic_client_hello(int verbose) {
|
||||||
WOLFSSL_CTX *ctx;
|
WOLFSSL_CTX *ctx;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
@ -1089,14 +1116,14 @@ static int test_quic_server_hello(int verbose) {
|
|||||||
|
|
||||||
/* connect */
|
/* connect */
|
||||||
QuicConversation_init(&conv, &tclient, &tserver);
|
QuicConversation_init(&conv, &tclient, &tserver);
|
||||||
QuicConversation_step(&conv);
|
QuicConversation_step(&conv, 0);
|
||||||
/* check established/missing secrets */
|
/* check established/missing secrets */
|
||||||
check_secrets(&tserver, wolfssl_encryption_initial, 0, 0);
|
check_secrets(&tserver, wolfssl_encryption_initial, 0, 0);
|
||||||
check_secrets(&tserver, wolfssl_encryption_handshake, 32, 32);
|
check_secrets(&tserver, wolfssl_encryption_handshake, 32, 32);
|
||||||
check_secrets(&tserver, wolfssl_encryption_application, 32, 32);
|
check_secrets(&tserver, wolfssl_encryption_application, 32, 32);
|
||||||
check_secrets(&tclient, wolfssl_encryption_handshake, 0, 0);
|
check_secrets(&tclient, wolfssl_encryption_handshake, 0, 0);
|
||||||
/* feed the server data to the client */
|
/* feed the server data to the client */
|
||||||
QuicConversation_step(&conv);
|
QuicConversation_step(&conv, 0);
|
||||||
/* client has generated handshake secret */
|
/* client has generated handshake secret */
|
||||||
check_secrets(&tclient, wolfssl_encryption_handshake, 32, 32);
|
check_secrets(&tclient, wolfssl_encryption_handshake, 32, 32);
|
||||||
/* continue the handshake till done */
|
/* continue the handshake till done */
|
||||||
@ -1166,8 +1193,9 @@ static int test_quic_key_share(int verbose) {
|
|||||||
QuicTestContext_free(&tclient);
|
QuicTestContext_free(&tclient);
|
||||||
QuicTestContext_free(&tserver);
|
QuicTestContext_free(&tserver);
|
||||||
|
|
||||||
/* setup & handshake, restricted groups, will trigger a
|
/* setup & handshake, restricted groups. KEY_SHARE should use
|
||||||
* HelloRetryRequest(ServerHello) and a new ClientHello */
|
* the first configured group. */
|
||||||
|
/*If that is supported by the server, expect a smooth handshake.*/
|
||||||
QuicTestContext_init(&tclient, ctx_c, "client", verbose);
|
QuicTestContext_init(&tclient, ctx_c, "client", verbose);
|
||||||
QuicTestContext_init(&tserver, ctx_s, "server", verbose);
|
QuicTestContext_init(&tserver, ctx_s, "server", verbose);
|
||||||
AssertTrue(wolfSSL_set1_curves_list(tclient.ssl, "X25519:P-256")
|
AssertTrue(wolfSSL_set1_curves_list(tclient.ssl, "X25519:P-256")
|
||||||
@ -1176,11 +1204,43 @@ static int test_quic_key_share(int verbose) {
|
|||||||
== WOLFSSL_SUCCESS);
|
== WOLFSSL_SUCCESS);
|
||||||
QuicConversation_init(&conv, &tclient, &tserver);
|
QuicConversation_init(&conv, &tclient, &tserver);
|
||||||
QuicConversation_do(&conv);
|
QuicConversation_do(&conv);
|
||||||
|
AssertStrEQ(conv.rec_log,
|
||||||
|
"ClientHello:ServerHello:EncryptedExtension:"
|
||||||
|
"Certificate:CertificateVerify:Finished:Finished:SessionTicket");
|
||||||
|
QuicTestContext_free(&tclient);
|
||||||
|
QuicTestContext_free(&tserver);
|
||||||
|
printf(" test_quic_key_share: priority ok\n");
|
||||||
|
|
||||||
|
/* If group is not supported by server, expect HelloRetry */
|
||||||
|
QuicTestContext_init(&tclient, ctx_c, "client", verbose);
|
||||||
|
QuicTestContext_init(&tserver, ctx_s, "server", verbose);
|
||||||
|
AssertTrue(wolfSSL_set1_curves_list(tclient.ssl, "X25519:P-256")
|
||||||
|
== WOLFSSL_SUCCESS);
|
||||||
|
AssertTrue(wolfSSL_set1_curves_list(tserver.ssl, "P-256")
|
||||||
|
== WOLFSSL_SUCCESS);
|
||||||
|
QuicConversation_init(&conv, &tclient, &tserver);
|
||||||
|
QuicConversation_do(&conv);
|
||||||
AssertStrEQ(conv.rec_log,
|
AssertStrEQ(conv.rec_log,
|
||||||
"ClientHello:ServerHello:ClientHello:ServerHello:EncryptedExtension:"
|
"ClientHello:ServerHello:ClientHello:ServerHello:EncryptedExtension:"
|
||||||
"Certificate:CertificateVerify:Finished:Finished:SessionTicket");
|
"Certificate:CertificateVerify:Finished:Finished:SessionTicket");
|
||||||
QuicTestContext_free(&tclient);
|
QuicTestContext_free(&tclient);
|
||||||
QuicTestContext_free(&tserver);
|
QuicTestContext_free(&tserver);
|
||||||
|
printf(" test_quic_key_share: retry ok\n");
|
||||||
|
|
||||||
|
/* If no group overlap, expect failure */
|
||||||
|
QuicTestContext_init(&tclient, ctx_c, "client", verbose);
|
||||||
|
QuicTestContext_init(&tserver, ctx_s, "server", verbose);
|
||||||
|
AssertTrue(wolfSSL_set1_curves_list(tclient.ssl, "P-256")
|
||||||
|
== WOLFSSL_SUCCESS);
|
||||||
|
AssertTrue(wolfSSL_set1_curves_list(tserver.ssl, "X25519")
|
||||||
|
== WOLFSSL_SUCCESS);
|
||||||
|
QuicConversation_init(&conv, &tclient, &tserver);
|
||||||
|
QuicConversation_fail(&conv);
|
||||||
|
AssertIntEQ(wolfSSL_get_error(tserver.ssl, 0), SSL_ERROR_WANT_READ);
|
||||||
|
AssertIntEQ(wolfSSL_get_error(tclient.ssl, 0), BAD_KEY_SHARE_DATA);
|
||||||
|
QuicTestContext_free(&tclient);
|
||||||
|
QuicTestContext_free(&tserver);
|
||||||
|
printf(" test_quic_key_share: no match ok\n");
|
||||||
|
|
||||||
wolfSSL_CTX_free(ctx_c);
|
wolfSSL_CTX_free(ctx_c);
|
||||||
wolfSSL_CTX_free(ctx_s);
|
wolfSSL_CTX_free(ctx_s);
|
||||||
@ -1476,7 +1536,7 @@ int QuicTest(void)
|
|||||||
if ((ret = test_quic_key_share(verbose)) != 0) goto leave;
|
if ((ret = test_quic_key_share(verbose)) != 0) goto leave;
|
||||||
if ((ret = test_quic_resumption(verbose)) != 0) goto leave;
|
if ((ret = test_quic_resumption(verbose)) != 0) goto leave;
|
||||||
#ifdef WOLFSSL_EARLY_DATA
|
#ifdef WOLFSSL_EARLY_DATA
|
||||||
if ((ret = test_quic_early_data(verbose || 1)) != 0) goto leave;
|
if ((ret = test_quic_early_data(verbose)) != 0) goto leave;
|
||||||
#endif /* WOLFSSL_EARLY_DATA */
|
#endif /* WOLFSSL_EARLY_DATA */
|
||||||
if ((ret = test_quic_session_export(verbose)) != 0) goto leave;
|
if ((ret = test_quic_session_export(verbose)) != 0) goto leave;
|
||||||
#endif /* HAVE_SESSION_TICKET */
|
#endif /* HAVE_SESSION_TICKET */
|
||||||
|
Reference in New Issue
Block a user