diff --git a/src/ssl.c b/src/ssl.c index 6ad5bbdf2..095ee410e 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -33926,20 +33926,34 @@ int wolfSSL_curve_is_disabled(WOLFSSL* ssl, word16 curve_id) defined(HAVE_CURVE25519) || defined(HAVE_CURVE448)) 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; word32 disabled; 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 = (int*)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++) { if (names[idx] != ':' && names[idx] != '\0') continue; len = idx - start; if (len > MAX_CURVE_NAME_SZ - 1) - return WOLFSSL_FAILURE; + goto leave; XMEMCPY(name, names + start, len); name[len] = 0; @@ -33974,25 +33988,25 @@ static int set_curves_list(WOLFSSL* ssl, WOLFSSL_CTX *ctx, const char* names) #endif else { #if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) - int ret; + int nret; const ecc_set_type *eccSet; - ret = wc_ecc_get_curve_idx_from_name(name); - if (ret < 0) { + nret = wc_ecc_get_curve_idx_from_name(name); + if (nret < 0) { WOLFSSL_MSG("Could not find name in set"); - return WOLFSSL_FAILURE; + goto leave; } eccSet = wc_ecc_get_curve_params(ret); if (eccSet == NULL) { WOLFSSL_MSG("NULL set returned"); - return WOLFSSL_FAILURE; + goto leave; } curve = GetCurveByOID(eccSet->oidSum); #else WOLFSSL_MSG("API not present to search farther using name"); - return WOLFSSL_FAILURE; + goto leave; #endif } @@ -34000,32 +34014,71 @@ static int set_curves_list(WOLFSSL* ssl, WOLFSSL_CTX *ctx, const char* names) /* shift left more than size of ctx->disabledCurves causes static * analysis report */ 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); + #ifdef HAVE_SUPPORTED_CURVES + #if defined(WOLFSSL_TLS13) && !defined(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(NO_WOLFSSL_CLIENT) /* set the supported curve so client TLS extension contains only the * desired curves */ - if ((ssl - && wolfSSL_UseSupportedCurve(ssl, curve) != WOLFSSL_SUCCESS) - || (ctx - && wolfSSL_CTX_UseSupportedCurve(ctx, curve) != WOLFSSL_SUCCESS)) { + if ((ssl && wolfSSL_UseSupportedCurve(ssl, curve) != WOLFSSL_SUCCESS) + || (ctx && wolfSSL_CTX_UseSupportedCurve(ctx, curve) + != WOLFSSL_SUCCESS)) { WOLFSSL_MSG("Unable to set supported curve"); - return WOLFSSL_FAILURE; + goto leave; } #endif - - /* Switch the bit to off and therefore is enabled. */ - disabled &= ~(1U << curve); - start = idx + 1; + #endif /* HAVE_SUPPORTED_CURVES */ } if (ssl) ssl->disabledCurves = disabled; else 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) diff --git a/tests/quic.c b/tests/quic.c index 5b1d29aab..28d86d720 100644 --- a/tests/quic.c +++ b/tests/quic.c @@ -949,20 +949,26 @@ static int QuicConversation_start(QuicConversation *conv, const byte *data, return ret; } -static int QuicConversation_step(QuicConversation *conv) +static int QuicConversation_step(QuicConversation *conv, int may_fail) { int n; if (!conv->started) { - AssertTrue(wolfSSL_connect(conv->client->ssl) != WOLFSSL_SUCCESS); - AssertIntEQ(SSL_ERROR_WANT_READ, wolfSSL_get_error(conv->client->ssl, 0)); + n = wolfSSL_connect(conv->client->ssl); + 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; } if (conv->server->output.len > 0) { QuicTestContext_forward(conv->server, conv->client, conv->rec_log, sizeof(conv->rec_log)); n = wolfSSL_quic_read_write(conv->client->ssl); - if (n != WOLFSSL_SUCCESS) { - AssertIntEQ(wolfSSL_get_error(conv->client->ssl, 0), SSL_ERROR_WANT_READ); + 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)); } return 1; } @@ -976,7 +982,10 @@ static int QuicConversation_step(QuicConversation *conv) (int)(sizeof(conv->early_data) - conv->early_data_len), &written); 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) { conv->early_data_len += n; @@ -988,7 +997,9 @@ static int QuicConversation_step(QuicConversation *conv) #endif /* WOLFSSL_EARLY_DATA */ { 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); } } @@ -1004,7 +1015,7 @@ static void QuicConversation_do(QuicConversation *conv) } while (1) { - if (!QuicConversation_step(conv)) { + if (!QuicConversation_step(conv, 0)) { int c_err = wolfSSL_get_error(conv->client->ssl, 0); int s_err = wolfSSL_get_error(conv->server->ssl, 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) { WOLFSSL_CTX *ctx; int ret = 0; @@ -1089,14 +1116,14 @@ static int test_quic_server_hello(int verbose) { /* connect */ QuicConversation_init(&conv, &tclient, &tserver); - QuicConversation_step(&conv); + QuicConversation_step(&conv, 0); /* check established/missing secrets */ check_secrets(&tserver, wolfssl_encryption_initial, 0, 0); check_secrets(&tserver, wolfssl_encryption_handshake, 32, 32); check_secrets(&tserver, wolfssl_encryption_application, 32, 32); check_secrets(&tclient, wolfssl_encryption_handshake, 0, 0); /* feed the server data to the client */ - QuicConversation_step(&conv); + QuicConversation_step(&conv, 0); /* client has generated handshake secret */ check_secrets(&tclient, wolfssl_encryption_handshake, 32, 32); /* continue the handshake till done */ @@ -1166,8 +1193,9 @@ static int test_quic_key_share(int verbose) { QuicTestContext_free(&tclient); QuicTestContext_free(&tserver); - /* setup & handshake, restricted groups, will trigger a - * HelloRetryRequest(ServerHello) and a new ClientHello */ + /* setup & handshake, restricted groups. KEY_SHARE should use + * the first configured group. */ + /*If that is supported by the server, expect a smooth handshake.*/ QuicTestContext_init(&tclient, ctx_c, "client", verbose); QuicTestContext_init(&tserver, ctx_s, "server", verbose); AssertTrue(wolfSSL_set1_curves_list(tclient.ssl, "X25519:P-256") @@ -1176,11 +1204,43 @@ static int test_quic_key_share(int verbose) { == WOLFSSL_SUCCESS); QuicConversation_init(&conv, &tclient, &tserver); 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, "ClientHello:ServerHello:ClientHello:ServerHello:EncryptedExtension:" "Certificate:CertificateVerify:Finished:Finished:SessionTicket"); QuicTestContext_free(&tclient); 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_s); @@ -1476,7 +1536,7 @@ int QuicTest(void) if ((ret = test_quic_key_share(verbose)) != 0) goto leave; if ((ret = test_quic_resumption(verbose)) != 0) goto leave; #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 */ if ((ret = test_quic_session_export(verbose)) != 0) goto leave; #endif /* HAVE_SESSION_TICKET */