Skip to content

Commit 5fce802

Browse files
authored
Merge pull request wolfSSL#10386 from JeremiahM37/fenrir-4
Harden TLS handshake validation, OpenSSL-compat defaults, and stale code paths
2 parents 2b04270 + 18c627c commit 5fce802

5 files changed

Lines changed: 118 additions & 12 deletions

File tree

src/internal.c

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1270,7 +1270,8 @@ static int ImportKeyState(WOLFSSL* ssl, const byte* exp, word32 len, byte ver,
12701270
}
12711271

12721272
sz = exp[idx++];
1273-
if (sz > sizeof(keys->client_write_IV) || (sz * 2) + idx > len) {
1273+
if (sz > sizeof(keys->client_write_IV) ||
1274+
(sz * 2) + idx + AEAD_MAX_EXP_SZ + OPAQUE8_LEN > len) {
12741275
WOLFSSL_MSG("Buffer not large enough for write IV import");
12751276
return BUFFER_E;
12761277
}
@@ -16977,10 +16978,15 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx,
1697716978
ret = KEYUSE_ENCIPHER_E;
1697816979
WOLFSSL_ERROR_VERBOSE(ret);
1697916980
}
16980-
if ((ssl->specs.kea != rsa_kea) &&
16981-
(ssl->specs.sig_algo == rsa_sa_algo ||
16982-
(ssl->specs.sig_algo == ecc_dsa_sa_algo &&
16983-
!ssl->specs.static_ecdh)) &&
16981+
/* TLS 1.3 decouples sig algorithm from cipher suite, so
16982+
* specs.sig_algo is any_sa_algo. RFC 8446 4.4.2.4 still
16983+
* requires digital_signature when keyUsage is present on
16984+
* the cert that drives CertificateVerify. */
16985+
if (((ssl->specs.kea != rsa_kea) &&
16986+
(IsAtLeastTLSv1_3(ssl->version) ||
16987+
ssl->specs.sig_algo == rsa_sa_algo ||
16988+
(ssl->specs.sig_algo == ecc_dsa_sa_algo &&
16989+
!ssl->specs.static_ecdh))) &&
1698416990
(args->dCert->extKeyUsage & KEYUSE_DIGITAL_SIG) == 0) {
1698516991
WOLFSSL_MSG("KeyUse Digital Sig not set");
1698616992
ret = KEYUSE_SIGNATURE_E;
@@ -24319,6 +24325,8 @@ static int BuildMD5_CertVerify(const WOLFSSL* ssl, byte* digest)
2431924325
#ifdef WOLFSSL_SMALL_STACK
2432024326
wc_Md5* md5 = (wc_Md5*)XMALLOC(sizeof(wc_Md5), ssl->heap,
2432124327
DYNAMIC_TYPE_HASHCTX);
24328+
if (md5 == NULL)
24329+
return MEMORY_E;
2432224330
#else
2432324331
wc_Md5 md5[1];
2432424332
#endif
@@ -24363,6 +24371,8 @@ static int BuildSHA_CertVerify(const WOLFSSL* ssl, byte* digest)
2436324371
#ifdef WOLFSSL_SMALL_STACK
2436424372
wc_Sha* sha = (wc_Sha*)XMALLOC(sizeof(wc_Sha), ssl->heap,
2436524373
DYNAMIC_TYPE_HASHCTX);
24374+
if (sha == NULL)
24375+
return MEMORY_E;
2436624376
#else
2436724377
wc_Sha sha[1];
2436824378
#endif

src/ocsp.c

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -602,8 +602,9 @@ static int CheckOcspResponderChain(OcspEntry* single, byte* issuerHash,
602602
* in OCSP request
603603
*/
604604

605-
/* End loop if no more issuers found or if we have found a self
606-
* signed cert (ca == prev) */
605+
/* Walk up the issuer chain from the responder's direct issuer toward a
606+
* self-signed root, capturing prev before reassigning ca so the
607+
* (ca == prev) self-signed termination check is meaningful. */
607608
ca = GetCAByName(cm, single->issuerHash);
608609
#if defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)
609610
if (ca == NULL && pendingCAs != NULL) {
@@ -612,21 +613,27 @@ static int CheckOcspResponderChain(OcspEntry* single, byte* issuerHash,
612613
#else
613614
(void)pendingCAs;
614615
#endif
615-
for (; ca != NULL && ca != prev;
616-
prev = ca) {
616+
while (ca != NULL) {
617617
if (XMEMCMP(issuerHash, ca->issuerNameHash, OCSP_DIGEST_SIZE) == 0) {
618618
WOLFSSL_MSG("\tOCSP Response signed by authorized "
619619
"responder delegated by issuer "
620620
"(found in chain)");
621621
passed = 1;
622622
break;
623623
}
624-
ca = GetCAByName(cm, ca->issuerNameHash);
624+
prev = ca;
625+
ca = GetCAByName(cm, prev->issuerNameHash);
625626
#if defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)
627+
/* Look up by the in-flight name (prev's issuer), not by
628+
* single->issuerHash; the latter would re-anchor the pendingCAs
629+
* walk to the bottom of the chain on every iteration. */
626630
if (ca == NULL && pendingCAs != NULL) {
627-
ca = findSignerByName(pendingCAs, single->issuerHash);
631+
ca = findSignerByName(pendingCAs, prev->issuerNameHash);
628632
}
629633
#endif
634+
if (ca == prev) {
635+
break;
636+
}
630637
}
631638
return passed;
632639
}

src/ssl.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17638,7 +17638,10 @@ int wolfSSL_set_alpn_protos(WOLFSSL* ssl,
1763817638
unsigned int ptIdx;
1763917639
unsigned int sz;
1764017640
unsigned int idx = 0;
17641-
int alpn_opt = WOLFSSL_ALPN_CONTINUE_ON_MISMATCH;
17641+
/* RFC 7301: a server that does not select any of the client's offered
17642+
* protocols MUST send no_application_protocol. Match that contract on
17643+
* the OpenSSL-compat surface rather than silently continuing. */
17644+
int alpn_opt = WOLFSSL_ALPN_FAILED_ON_MISMATCH;
1764217645
int ret;
1764317646

1764417647
WOLFSSL_ENTER("wolfSSL_set_alpn_protos");

src/tls.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9294,6 +9294,14 @@ static int TLSX_KeyShare_ProcessDh(WOLFSSL* ssl, KeyShareEntry* keyShareEntry)
92949294
}
92959295
#endif
92969296

9297+
/* RFC 8446 Section 4.2.8.1: FFDHE key_exchange values are left-padded with
9298+
* zeros to the size of the named-group prime. Reject any peer key share
9299+
* whose byte length does not match the expected prime size. */
9300+
if (keyShareEntry->keLen != pSz) {
9301+
WOLFSSL_ERROR_VERBOSE(PEER_KEY_ERROR);
9302+
return PEER_KEY_ERROR;
9303+
}
9304+
92979305
/* if DhKey is not setup, do it now */
92989306
if (keyShareEntry->key == NULL) {
92999307
keyShareEntry->key = (DhKey*)XMALLOC(sizeof(DhKey), ssl->heap,

tests/api.c

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2303,6 +2303,83 @@ static int test_wolfSSL_set_cipher_list_tls13_with_version(void)
23032303
return EXPECT_RESULT();
23042304
}
23052305

2306+
static int test_wolfSSL_set_alpn_protos_default_fails(void)
2307+
{
2308+
EXPECT_DECLS;
2309+
#if defined(HAVE_ALPN) && defined(OPENSSL_EXTRA) && !defined(NO_BIO) && \
2310+
!defined(NO_WOLFSSL_CLIENT)
2311+
{
2312+
WOLFSSL_CTX* ctx = NULL;
2313+
WOLFSSL* ssl = NULL;
2314+
unsigned char p[] = { 6, 's', 'p', 'd', 'y', '/', '3' };
2315+
TLSX* ext = NULL;
2316+
ALPN* alpn = NULL;
2317+
2318+
ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()));
2319+
ExpectNotNull(ssl = wolfSSL_new(ctx));
2320+
#ifdef WOLFSSL_ERROR_CODE_OPENSSL
2321+
ExpectIntEQ(wolfSSL_set_alpn_protos(ssl, p, sizeof(p)), 0);
2322+
#else
2323+
ExpectIntEQ(wolfSSL_set_alpn_protos(ssl, p, sizeof(p)),
2324+
WOLFSSL_SUCCESS);
2325+
#endif
2326+
if (ssl != NULL) {
2327+
ext = TLSX_Find(ssl->extensions,
2328+
TLSX_APPLICATION_LAYER_PROTOCOL);
2329+
ExpectNotNull(ext);
2330+
if (ext != NULL) {
2331+
alpn = (ALPN*)ext->data;
2332+
ExpectNotNull(alpn);
2333+
if (alpn != NULL) {
2334+
ExpectTrue((alpn->options
2335+
& WOLFSSL_ALPN_FAILED_ON_MISMATCH) != 0);
2336+
ExpectIntEQ(alpn->options
2337+
& WOLFSSL_ALPN_CONTINUE_ON_MISMATCH, 0);
2338+
}
2339+
}
2340+
}
2341+
wolfSSL_free(ssl);
2342+
wolfSSL_CTX_free(ctx);
2343+
}
2344+
#if !defined(NO_WOLFSSL_SERVER) && !defined(WOLFSSL_NO_TLS12) && \
2345+
!defined(SINGLE_THREADED) && defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES)
2346+
{
2347+
struct test_memio_ctx test_ctx;
2348+
WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL;
2349+
WOLFSSL *ssl_c = NULL, *ssl_s = NULL;
2350+
unsigned char client_protos[] = { 6, 's', 'p', 'd', 'y', '/', '3' };
2351+
const char* server_protos = "http/2";
2352+
WOLFSSL_ALERT_HISTORY h;
2353+
2354+
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
2355+
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
2356+
wolfTLSv1_2_client_method, wolfTLSv1_2_server_method), 0);
2357+
2358+
#ifdef WOLFSSL_ERROR_CODE_OPENSSL
2359+
ExpectIntEQ(wolfSSL_set_alpn_protos(ssl_c, client_protos,
2360+
sizeof(client_protos)), 0);
2361+
#else
2362+
ExpectIntEQ(wolfSSL_set_alpn_protos(ssl_c, client_protos,
2363+
sizeof(client_protos)), WOLFSSL_SUCCESS);
2364+
#endif
2365+
ExpectIntEQ(wolfSSL_UseALPN(ssl_s, (char*)server_protos,
2366+
(word32)XSTRLEN(server_protos),
2367+
WOLFSSL_ALPN_FAILED_ON_MISMATCH), WOLFSSL_SUCCESS);
2368+
2369+
ExpectIntNE(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
2370+
ExpectIntEQ(wolfSSL_get_alert_history(ssl_s, &h), WOLFSSL_SUCCESS);
2371+
ExpectIntEQ(h.last_tx.code, no_application_protocol);
2372+
ExpectIntEQ(h.last_tx.level, alert_fatal);
2373+
2374+
wolfSSL_free(ssl_c);
2375+
wolfSSL_free(ssl_s);
2376+
wolfSSL_CTX_free(ctx_c);
2377+
wolfSSL_CTX_free(ctx_s);
2378+
}
2379+
#endif
2380+
#endif
2381+
return EXPECT_RESULT();
2382+
}
23062383

23072384
static int test_wolfSSL_CTX_use_certificate(void)
23082385
{
@@ -39581,6 +39658,7 @@ TEST_CASE testCases[] = {
3958139658
TEST_DECL(test_wolfSSL_set_cipher_list_tls13_keeps_tls12),
3958239659
TEST_DECL(test_wolfSSL_set_cipher_list_tls12_with_version),
3958339660
TEST_DECL(test_wolfSSL_set_cipher_list_tls13_with_version),
39661+
TEST_DECL(test_wolfSSL_set_alpn_protos_default_fails),
3958439662
TEST_DECL(test_wolfSSL_CTX_use_certificate),
3958539663
TEST_DECL(test_wolfSSL_CTX_use_certificate_file),
3958639664
TEST_DECL(test_wolfSSL_CTX_use_certificate_buffer),

0 commit comments

Comments
 (0)