Skip to content

Commit bf6c870

Browse files
authored
Merge pull request #10304 from JeremiahM37/fenrir-2
Zero DH keys, tighten SSL APIs, harden TLS extensions
2 parents fea8d1b + 3d489d1 commit bf6c870

16 files changed

Lines changed: 200 additions & 19 deletions

src/internal.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8669,6 +8669,9 @@ void FreeKeyExchange(WOLFSSL* ssl)
86698669
{
86708670
/* Cleanup signature buffer */
86718671
if (ssl->buffers.sig.buffer) {
8672+
/* May transiently hold the client's DH private exponent in the
8673+
* TLS 1.2 diffie_hellman_kea / dhe_psk_kea paths. */
8674+
ForceZero(ssl->buffers.sig.buffer, ssl->buffers.sig.length);
86728675
XFREE(ssl->buffers.sig.buffer, ssl->heap, DYNAMIC_TYPE_SIGNATURE);
86738676
ssl->buffers.sig.buffer = NULL;
86748677
ssl->buffers.sig.length = 0;

src/pk.c

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4743,6 +4743,7 @@ int wolfSSL_DH_generate_key(WOLFSSL_DH* dh)
47434743
int ret = 1;
47444744
word32 pubSz = 0;
47454745
word32 privSz = 0;
4746+
word32 privAllocSz = 0;
47464747
int localRng = 0;
47474748
WC_RNG* rng = NULL;
47484749
WC_DECLARE_VAR(tmpRng, WC_RNG, 1, 0);
@@ -4792,9 +4793,12 @@ int wolfSSL_DH_generate_key(WOLFSSL_DH* dh)
47924793
else {
47934794
privSz = pubSz;
47944795
}
4795-
/* Allocate public and private key arrays. */
4796+
/* Allocate public and private key arrays. Preserve the allocation
4797+
* size because wc_DhGenerateKeyPair updates privSz in-place. */
4798+
privAllocSz = privSz;
47964799
pub = (unsigned char*)XMALLOC(pubSz, NULL, DYNAMIC_TYPE_PUBLIC_KEY);
4797-
priv = (unsigned char*)XMALLOC(privSz, NULL, DYNAMIC_TYPE_PRIVATE_KEY);
4800+
priv = (unsigned char*)XMALLOC(privAllocSz, NULL,
4801+
DYNAMIC_TYPE_PRIVATE_KEY);
47984802
if (pub == NULL || priv == NULL) {
47994803
WOLFSSL_ERROR_MSG("Unable to malloc memory");
48004804
ret = 0;
@@ -4846,7 +4850,10 @@ int wolfSSL_DH_generate_key(WOLFSSL_DH* dh)
48464850
}
48474851
/* Dispose of allocated data. */
48484852
XFREE(pub, NULL, DYNAMIC_TYPE_PUBLIC_KEY);
4849-
XFREE(priv, NULL, DYNAMIC_TYPE_PRIVATE_KEY);
4853+
if (priv != NULL) {
4854+
ForceZero(priv, privAllocSz);
4855+
XFREE(priv, NULL, DYNAMIC_TYPE_PRIVATE_KEY);
4856+
}
48504857

48514858
return ret;
48524859
}

src/sniffer.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2459,11 +2459,15 @@ static void FreeSetupKeysArgs(WOLFSSL* ssl, void* pArgs)
24592459
args->key->type = WC_PK_TYPE_NONE;
24602460
args->key->initPriv = 0; args->key->initPub = 0;
24612461

2462+
/* Scrub the raw DH private exponent (and any other key material
2463+
* embedded in the union) before release. wc_FreeDhKey above only
2464+
* clears the mp_int DhKey, not the separate privKey byte array.
2465+
* Use ForceZero (rather than XMEMSET) so the wipe cannot be
2466+
* elided by the optimizer. */
2467+
ForceZero(args->key, sizeof(*args->key));
24622468
#ifdef WOLFSSL_ASYNC_CRYPT
24632469
XFREE(args->key, NULL, DYNAMIC_TYPE_SNIFFER_KEY);
24642470
args->key = NULL;
2465-
#else
2466-
XMEMSET(args->key, 0, sizeof(args->key));
24672471
#endif
24682472
}
24692473

src/ssl.c

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10152,11 +10152,21 @@ size_t wolfSSL_get_client_random(const WOLFSSL* ssl, unsigned char* out,
1015210152
#ifdef WOLFSSL_DTLS
1015310153
ssl->options.dtlsStateful = 0;
1015410154
#endif
10155+
#ifdef WOLFSSL_TLS13
1015510156
#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
10156-
ssl->options.noPskDheKe = 0;
10157-
#ifdef HAVE_SUPPORTED_CURVES
10158-
ssl->options.onlyPskDheKe = 0;
10159-
#endif
10157+
if (ssl->ctx != NULL) {
10158+
ssl->options.noPskDheKe = ssl->ctx->noPskDheKe;
10159+
#ifdef HAVE_SUPPORTED_CURVES
10160+
ssl->options.onlyPskDheKe = ssl->ctx->onlyPskDheKe;
10161+
#endif
10162+
}
10163+
else {
10164+
ssl->options.noPskDheKe = 0;
10165+
#ifdef HAVE_SUPPORTED_CURVES
10166+
ssl->options.onlyPskDheKe = 0;
10167+
#endif
10168+
}
10169+
#endif
1016010170
#endif
1016110171
#ifdef HAVE_SESSION_TICKET
1016210172
#ifdef WOLFSSL_TLS13

src/ssl_crypto.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2722,11 +2722,19 @@ void wolfSSL_DES_ncbc_encrypt(const unsigned char* input, unsigned char* output,
27222722
int enc)
27232723
{
27242724
unsigned char tmp[DES_IV_SIZE];
2725-
/* Calculate length to a multiple of block size. */
2726-
size_t offset = (size_t)length;
2725+
size_t offset;
27272726

27282727
WOLFSSL_ENTER("wolfSSL_DES_ncbc_encrypt");
27292728

2729+
/* Zero/negative length: no block to derive an IV from. The offset math
2730+
* below would underflow for length == 0, yielding a wild-pointer read. */
2731+
if (length <= 0) {
2732+
WOLFSSL_LEAVE("wolfSSL_DES_ncbc_encrypt", 0);
2733+
return;
2734+
}
2735+
2736+
/* Calculate length to a multiple of block size. */
2737+
offset = (size_t)length;
27302738
offset = (offset + DES_BLOCK_SIZE - 1) / DES_BLOCK_SIZE;
27312739
offset *= DES_BLOCK_SIZE;
27322740
offset -= DES_BLOCK_SIZE;

src/ssl_load.c

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5513,10 +5513,13 @@ int wolfSSL_CTX_set_default_verify_paths(WOLFSSL_CTX* ctx)
55135513
ret = 1;
55145514
}
55155515
#else
5516-
/* OpenSSL's implementation of this API does not require loading the
5517-
* system CA cert directory. Allow skipping this without erroring out.
5518-
*/
5519-
ret = 1;
5516+
/* No source available: SSL_CERT_DIR/SSL_CERT_FILE not set and
5517+
* WOLFSSL_SYS_CA_CERTS not compiled in. Returning success would be
5518+
* fail-open since no trust anchors were loaded. */
5519+
WOLFSSL_MSG("wolfSSL_CTX_set_default_verify_paths: no CA source "
5520+
"available (build without WOLFSSL_SYS_CA_CERTS and no "
5521+
"SSL_CERT_DIR/SSL_CERT_FILE env)");
5522+
ret = WOLFSSL_FAILURE;
55205523
#endif
55215524
}
55225525

src/ssl_sess.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1598,8 +1598,12 @@ int wolfSSL_SetSession(WOLFSSL* ssl, WOLFSSL_SESSION* session)
15981598
#if !defined(OPENSSL_EXTRA) || !defined(WOLFSSL_ERROR_CODE_OPENSSL)
15991599
return WOLFSSL_FAILURE; /* session timed out */
16001600
#else /* defined(OPENSSL_EXTRA) && defined(WOLFSSL_ERROR_CODE_OPENSSL) */
1601+
/* Return success for OpenSSL compatibility but do not carry the
1602+
* expired session's version/cipher into ssl state, which would
1603+
* otherwise pin the ClientHello to stale values. */
16011604
WOLFSSL_MSG("Session is expired but return success for "
16021605
"OpenSSL compatibility");
1606+
return WOLFSSL_SUCCESS;
16031607
#endif
16041608
}
16051609
ssl->options.resuming = 1;

src/tls.c

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9063,6 +9063,9 @@ static void TLSX_KeyShare_FreeAll(KeyShareEntry* list, void* heap)
90639063
if (WOLFSSL_NAMED_GROUP_IS_FFDHE(current->group)) {
90649064
#ifndef NO_DH
90659065
wc_FreeDhKey((DhKey*)current->key);
9066+
if (current->privKey != NULL && current->privKeyLen > 0) {
9067+
ForceZero(current->privKey, current->privKeyLen);
9068+
}
90669069
#endif
90679070
}
90689071
else if (current->group == WOLFSSL_ECC_X25519) {
@@ -17369,8 +17372,8 @@ static word16 TLSX_GetMinSize_Server(const word16 *type)
1736917372

1737017373

1737117374
/** Parses a buffer of TLS extensions. */
17372-
int TLSX_Parse(WOLFSSL* ssl, const byte* input, word16 length, byte msgType,
17373-
Suites *suites)
17375+
WOLFSSL_TEST_VIS int TLSX_Parse(WOLFSSL* ssl, const byte* input, word16 length,
17376+
byte msgType, Suites *suites)
1737417377
{
1737517378
int ret = 0;
1737617379
word16 offset = 0;
@@ -17992,6 +17995,20 @@ int TLSX_Parse(WOLFSSL* ssl, const byte* input, word16 length, byte msgType,
1799217995
#ifdef WOLFSSL_SRTP
1799317996
case TLSX_USE_SRTP:
1799417997
WOLFSSL_MSG("Use SRTP extension received");
17998+
17999+
#if defined(WOLFSSL_TLS13)
18000+
if (IsAtLeastTLSv1_3(ssl->version)) {
18001+
if (msgType != client_hello &&
18002+
msgType != encrypted_extensions)
18003+
return EXT_NOT_ALLOWED;
18004+
}
18005+
else
18006+
#endif
18007+
{
18008+
if (msgType != client_hello &&
18009+
msgType != server_hello)
18010+
return EXT_NOT_ALLOWED;
18011+
}
1799518012
ret = SRTP_PARSE(ssl, input + offset, size, isRequest);
1799618013
break;
1799718014
#endif
@@ -18086,6 +18103,15 @@ int TLSX_Parse(WOLFSSL* ssl, const byte* input, word16 length, byte msgType,
1808618103
#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH)
1808718104
case TLSX_ECH:
1808818105
WOLFSSL_MSG("ECH extension received");
18106+
if (!IsAtLeastTLSv1_3(ssl->version))
18107+
break;
18108+
18109+
if (msgType != client_hello &&
18110+
msgType != encrypted_extensions &&
18111+
msgType != hello_retry_request) {
18112+
return EXT_NOT_ALLOWED;
18113+
}
18114+
1808918115
ret = ECH_PARSE(ssl, input + offset, size, msgType);
1809018116
break;
1809118117
case TLSXT_ECH_OUTER_EXTENSIONS:

tests/api.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39707,6 +39707,8 @@ TEST_CASE testCases[] = {
3970739707
TEST_DECL(test_certificate_authorities_client_hello),
3970839708
TEST_DECL(test_TLSX_TCA_Find),
3970939709
TEST_DECL(test_TLSX_SNI_GetSize_overflow),
39710+
TEST_DECL(test_TLSX_ECH_msg_type_validation),
39711+
TEST_DECL(test_TLSX_SRTP_msg_type_validation),
3971039712
TEST_DECL(test_wolfSSL_wolfSSL_UseSecureRenegotiation),
3971139713
TEST_DECL(test_wolfSSL_clear_secure_renegotiation),
3971239714
TEST_DECL(test_wolfSSL_SCR_Reconnect),

tests/api/test_ossl_cipher.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,34 @@ int test_wolfSSL_DES_ncbc(void)
203203
return EXPECT_RESULT();
204204
}
205205

206+
int test_wolfSSL_DES_ncbc_zero_length(void)
207+
{
208+
EXPECT_DECLS;
209+
#if defined(OPENSSL_EXTRA) && !defined(NO_DES3)
210+
const_DES_cblock myDes;
211+
DES_cblock iv;
212+
DES_cblock ivSaved;
213+
DES_key_schedule key = {0};
214+
unsigned char msg[DES_BLOCK_SIZE] = {0};
215+
unsigned char out[DES_BLOCK_SIZE] = {0};
216+
217+
DES_set_key(&key, &myDes);
218+
219+
/* length == 0 must no-op: the offset math would otherwise underflow
220+
* size_t and read from a wild pointer. */
221+
XMEMSET((byte*)&iv, 0xAB, DES_BLOCK_SIZE);
222+
XMEMCPY(&ivSaved, &iv, DES_BLOCK_SIZE);
223+
DES_ncbc_encrypt(msg, out, 0, &myDes, &iv, DES_ENCRYPT);
224+
ExpectIntEQ(XMEMCMP(&iv, &ivSaved, DES_BLOCK_SIZE), 0);
225+
226+
XMEMSET((byte*)&iv, 0xAB, DES_BLOCK_SIZE);
227+
XMEMCPY(&ivSaved, &iv, DES_BLOCK_SIZE);
228+
DES_ncbc_encrypt(msg, out, 0, &myDes, &iv, DES_DECRYPT);
229+
ExpectIntEQ(XMEMCMP(&iv, &ivSaved, DES_BLOCK_SIZE), 0);
230+
#endif
231+
return EXPECT_RESULT();
232+
}
233+
206234
int test_wolfSSL_DES_ecb_encrypt(void)
207235
{
208236
EXPECT_DECLS;

0 commit comments

Comments
 (0)