Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions src/dtls13.c
Original file line number Diff line number Diff line change
Expand Up @@ -720,9 +720,14 @@ static Dtls13RecordNumber* Dtls13NewRecordNumber(w64wrapper epoch,
return rn;
}

#ifndef DTLS13_MAX_ACK_RECORDS
#define DTLS13_MAX_ACK_RECORDS 512
#endif

int Dtls13RtxAddAck(WOLFSSL* ssl, w64wrapper epoch, w64wrapper seq)
{
Dtls13RecordNumber* rn;
int count;

WOLFSSL_ENTER("Dtls13RtxAddAck");

Expand All @@ -741,7 +746,9 @@ int Dtls13RtxAddAck(WOLFSSL* ssl, w64wrapper epoch, w64wrapper seq)
return 0; /* list full, silently drop */
}

count = 0;
for (; cur != NULL; prevNext = &cur->next, cur = cur->next) {
count++;
if (w64Equal(cur->epoch, epoch) && w64Equal(cur->seq, seq)) {
/* already in list. no duplicates. */
#ifdef WOLFSSL_RW_THREADED
Expand All @@ -756,6 +763,16 @@ int Dtls13RtxAddAck(WOLFSSL* ssl, w64wrapper epoch, w64wrapper seq)
}
}

/* Cap the ACK list to prevent word16 overflow in
* Dtls13GetAckListLength and bound memory consumption */
if (count >= DTLS13_MAX_ACK_RECORDS) {
WOLFSSL_MSG("DTLS 1.3 ACK list full, dropping record");
#ifdef WOLFSSL_RW_THREADED
wc_UnLockMutex(&ssl->dtls13Rtx.mutex);
#endif
return 0;
}

rn = Dtls13NewRecordNumber(epoch, seq, ssl->heap);
if (rn == NULL) {
#ifdef WOLFSSL_RW_THREADED
Expand Down
253 changes: 253 additions & 0 deletions tests/api.c
Original file line number Diff line number Diff line change
Expand Up @@ -34642,6 +34642,255 @@ static int test_sniffer_chain_input_overflow(void)
}
#endif /* WOLFSSL_SNIFFER && WOLFSSL_SNIFFER_CHAIN_INPUT */

/* Test: wc_DhAgree must reject p-1 as peer public key.
* ffdhe2048 p ends with ...FFFFFFFFFFFFFFFF so p-1 ends ...FFFFFFFFFFFFFFFE */
static int test_DhAgree_rejects_p_minus_1(void)
{
EXPECT_DECLS;
#if !defined(HAVE_SELFTEST) && !defined(NO_DH) && \
defined(HAVE_FFDHE_2048) && !defined(WOLFSSL_NO_MALLOC) && \
(!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0))
DhKey key;
WC_RNG rng;
byte priv[256], pub[256], agree[256];
word32 privSz = sizeof(priv), pubSz = sizeof(pub), agreeSz;

/* ffdhe2048 p - copied from wolfcrypt/src/dh.c dh_ffdhe2048_p.
* p ends with 0xFF*8 so p-1 ends with ...0xFE */
static const byte ffdhe2048_p[256] = {
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xAD,0xF8,0x54,0x58,0xA2,0xBB,0x4A,0x9A,
0xAF,0xDC,0x56,0x20,0x27,0x3D,0x3C,0xF1,
0xD8,0xB9,0xC5,0x83,0xCE,0x2D,0x36,0x95,
0xA9,0xE1,0x36,0x41,0x14,0x64,0x33,0xFB,
0xCC,0x93,0x9D,0xCE,0x24,0x9B,0x3E,0xF9,
0x7D,0x2F,0xE3,0x63,0x63,0x0C,0x75,0xD8,
0xF6,0x81,0xB2,0x02,0xAE,0xC4,0x61,0x7A,
0xD3,0xDF,0x1E,0xD5,0xD5,0xFD,0x65,0x61,
0x24,0x33,0xF5,0x1F,0x5F,0x06,0x6E,0xD0,
0x85,0x63,0x65,0x55,0x3D,0xED,0x1A,0xF3,
0xB5,0x57,0x13,0x5E,0x7F,0x57,0xC9,0x35,
0x98,0x4F,0x0C,0x70,0xE0,0xE6,0x8B,0x77,
0xE2,0xA6,0x89,0xDA,0xF3,0xEF,0xE8,0x72,
0x1D,0xF1,0x58,0xA1,0x36,0xAD,0xE7,0x35,
0x30,0xAC,0xCA,0x4F,0x48,0x3A,0x79,0x7A,
0xBC,0x0A,0xB1,0x82,0xB3,0x24,0xFB,0x61,
0xD1,0x08,0xA9,0x4B,0xB2,0xC8,0xE3,0xFB,
0xB9,0x6A,0xDA,0xB7,0x60,0xD7,0xF4,0x68,
0x1D,0x4F,0x42,0xA3,0xDE,0x39,0x4D,0xF4,
0xAE,0x56,0xED,0xE7,0x63,0x72,0xBB,0x19,
0x0B,0x07,0xA7,0xC8,0xEE,0x0A,0x6D,0x70,
0x9E,0x02,0xFC,0xE1,0xCD,0xF7,0xE2,0xEC,
0xC0,0x34,0x04,0xCD,0x28,0x34,0x2F,0x61,
0x91,0x72,0xFE,0x9C,0xE9,0x85,0x83,0xFF,
0x8E,0x4F,0x12,0x32,0xEE,0xF2,0x81,0x83,
0xC3,0xFE,0x3B,0x1B,0x4C,0x6F,0xAD,0x73,
0x3B,0xB5,0xFC,0xBC,0x2E,0xC2,0x20,0x05,
0xC5,0x8E,0xF1,0x83,0x7D,0x16,0x83,0xB2,
0xC6,0xF3,0x4A,0x26,0xC1,0xB2,0xEF,0xFA,
0x88,0x6B,0x42,0x38,0x61,0x28,0x5C,0x97,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
};
byte pMinus1[256];

ExpectIntEQ(wc_InitRng(&rng), 0);
ExpectIntEQ(wc_InitDhKey(&key), 0);
ExpectIntEQ(wc_DhSetNamedKey(&key, WC_FFDHE_2048), 0);
ExpectIntEQ(wc_DhGenerateKeyPair(&key, &rng, priv, &privSz,
pub, &pubSz), 0);

/* Construct p-1: last byte FF -> FE */
XMEMCPY(pMinus1, ffdhe2048_p, sizeof(ffdhe2048_p));
pMinus1[255] -= 1;

/* wc_DhAgree must reject p-1 */
agreeSz = sizeof(agree);
ExpectIntNE(wc_DhAgree(&key, agree, &agreeSz, priv, privSz,
pMinus1, sizeof(pMinus1)), 0);

wc_FreeDhKey(&key);
wc_FreeRng(&rng);
#endif
return EXPECT_RESULT();
}

/* Test: Ed448 must reject identity public key (0,1) */
static int test_ed448_rejects_identity_key(void)
{
EXPECT_DECLS;
#ifdef HAVE_ED448
ed448_key key;
byte identity[ED448_PUB_KEY_SIZE];
byte forged_sig[ED448_SIG_SIZE];
const byte msg[] = "test message";
int res = 0;

XMEMSET(identity, 0, sizeof(identity));
identity[0] = 0x01; /* identity (0,1) encoding */

XMEMSET(forged_sig, 0, sizeof(forged_sig));
forged_sig[0] = 0x01; /* R = identity, S = 0 */

ExpectIntEQ(wc_ed448_init(&key), 0);

/* The identity public key must be rejected at import time. */
ExpectIntNE(wc_ed448_import_public(identity, sizeof(identity), &key), 0);

/* If import somehow succeeded, verify must also reject the forgery. */
if (EXPECT_SUCCESS() && key.pubKeySet) {
int verifyRet = wc_ed448_verify_msg(forged_sig, sizeof(forged_sig),
msg, sizeof(msg) - 1,
&res, &key, NULL, 0);
ExpectTrue(verifyRet != 0 || res == 0);
}

wc_ed448_free(&key);
#endif
return EXPECT_RESULT();
}

/* Test: wc_PKCS7_DecodeEncryptedData must respect outputSz.
* 588-byte EncryptedData blob: 496 bytes of 'A' encrypted with
* AES-256-CBC under all-zero key/IV. Decrypted content is 496 bytes,
* but we pass a 128-byte output buffer. Must return BUFFER_E. */
static int test_pkcs7_decode_encrypted_outputsz(void)
{
EXPECT_DECLS;
#if defined(HAVE_PKCS7) && !defined(NO_AES) && defined(HAVE_AES_CBC) && \
!defined(WOLFSSL_NO_MALLOC) && defined(WOLFSSL_AES_256)
wc_PKCS7* p7 = NULL;
byte key[32];
byte out[128]; /* smaller than 496-byte decrypted content */

static const byte encBlob[] = {
0x30,0x82,0x02,0x48,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,
0x01,0x07,0x06,0xa0,0x82,0x02,0x39,0x30,0x82,0x02,0x35,0x02,
0x01,0x00,0x30,0x82,0x02,0x2e,0x06,0x09,0x2a,0x86,0x48,0x86,
0xf7,0x0d,0x01,0x07,0x01,0x30,0x1d,0x06,0x09,0x60,0x86,0x48,
0x01,0x65,0x03,0x04,0x01,0x2a,0x04,0x10,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x80,0x82,0x02,0x00,0x7e,0x0e,0x75,0x77,0xef,0x9c,0x30,0xa6,
0xbf,0x0b,0x25,0xe0,0x62,0x1e,0x82,0x7e,0x76,0xf7,0x57,0xef,
0x12,0x71,0xc5,0x74,0x0e,0x60,0xc3,0x3c,0x8e,0xc3,0xce,0x70,
0xbd,0x3c,0xb4,0x60,0x76,0xb1,0xea,0xb5,0x4b,0xc1,0xfe,0x5b,
0x88,0xfa,0x43,0x46,0x03,0x28,0x9d,0xab,0x3d,0xb5,0x88,0x50,
0x07,0xfc,0x3c,0xc9,0x49,0x4d,0x68,0x97,0xb1,0x59,0xb6,0x35,
0xa1,0x68,0x80,0xb0,0x8f,0xb2,0x21,0x9b,0xfc,0xd8,0xf0,0x67,
0xbc,0x4b,0x9b,0x28,0x1c,0x3b,0xa0,0x40,0x76,0x8f,0x1f,0x9f,
0x87,0xe6,0xe4,0xa5,0xdc,0x9a,0x9a,0x84,0x86,0xff,0x43,0x8a,
0x57,0x8d,0x97,0xd2,0x8f,0x67,0x90,0xd8,0x4f,0x0f,0x0d,0xac,
0x56,0x6d,0x51,0x33,0xa3,0x37,0x9e,0xe9,0xbf,0x07,0xab,0x93,
0xbc,0xbe,0xc1,0x64,0x07,0x30,0xf0,0xff,0x89,0x0a,0x36,0x1c,
0xc8,0xe9,0xae,0x24,0x1f,0x95,0x5c,0xa1,0x8a,0x3e,0x15,0x86,
0x49,0x70,0x55,0xc2,0xa5,0x90,0xb9,0xda,0x2b,0x97,0x6f,0x5f,
0x60,0x61,0xc9,0xcf,0x4d,0x3a,0xb1,0xe4,0x9f,0x37,0x0f,0xf3,
0xba,0x85,0x04,0x52,0x68,0x00,0x47,0x3d,0x83,0xc1,0x3f,0xc6,
0x70,0x97,0xc1,0x0c,0xc0,0x0b,0xa2,0xcb,0x8c,0x88,0xb5,0x01,
0x29,0x7f,0x7e,0xd2,0x46,0x24,0x82,0x92,0x28,0xdd,0x49,0x53,
0x0f,0x76,0xad,0x4b,0x81,0x85,0x3a,0x9f,0xda,0x0d,0x69,0xe2,
0x57,0xb9,0xe9,0xfa,0x53,0xed,0x20,0x6f,0x62,0x43,0x1d,0x21,
0xa9,0x53,0x3d,0xd5,0xb9,0x1a,0x4b,0x3e,0xb7,0x05,0x87,0xb6,
0xe3,0xfe,0x03,0x09,0xe1,0x74,0x34,0x42,0x84,0xb1,0x06,0xf9,
0xfe,0x64,0xc1,0xd2,0xce,0x3d,0x29,0xf4,0x94,0xb8,0xfc,0xbe,
0xb1,0x90,0xd6,0x38,0x61,0x4e,0x43,0x36,0x4e,0x27,0x87,0xd3,
0x24,0xdc,0x34,0xf0,0x28,0x2d,0xc8,0xff,0x89,0x9f,0xeb,0xee,
0x0d,0x45,0xfb,0xc5,0x53,0xd3,0xdf,0xcb,0xf8,0xeb,0x7e,0xcb,
0x2a,0xd7,0xa2,0xd6,0x6a,0xf1,0xb8,0x24,0xa1,0x05,0x16,0x56,
0x2e,0x03,0xfe,0x21,0x19,0x36,0x8a,0xeb,0x50,0x8d,0x42,0x31,
0x1d,0xb3,0x0a,0x13,0x1d,0x16,0x09,0x0b,0x40,0x4e,0x90,0x78,
0xbf,0x41,0x5f,0x4d,0xd9,0xce,0x91,0xaa,0xd0,0x38,0x5c,0xfb,
0xc4,0x9f,0x55,0x4e,0x04,0x9d,0xd0,0xca,0x74,0x3c,0x6c,0x01,
0x1b,0x84,0x76,0xfa,0xba,0x5d,0x2d,0x35,0x7e,0xe3,0x37,0x8b,
0x72,0x0a,0xbb,0xa4,0x4d,0x56,0x2b,0x3b,0x9f,0x5a,0xa0,0xe3,
0x60,0x26,0x65,0x09,0xed,0xfc,0x10,0x0c,0xa1,0x4f,0x12,0x76,
0xe2,0x4c,0xbd,0x1b,0x67,0xb4,0xb4,0x54,0x5c,0x38,0x47,0x8b,
0x7e,0x35,0x8e,0x4d,0x4e,0xef,0x91,0x3f,0xff,0x16,0x0a,0x42,
0x0b,0xe5,0x28,0x26,0x24,0x9f,0x6f,0xb4,0x63,0x8a,0xa1,0x52,
0x22,0x3a,0xdb,0xd9,0x8e,0x76,0x6e,0x6a,0xa9,0xa1,0xec,0xf2,
0x9c,0x58,0xf8,0x6b,0xdd,0xf2,0xf8,0x2d,0xcb,0x8c,0x96,0xda,
0xb4,0x9c,0x44,0xdc,0xab,0x43,0x2c,0x22,0xf3,0xfe,0x1a,0xb9,
0x3b,0x82,0x30,0xa2,0xc7,0xef,0x52,0x08,0x7b,0x4f,0x3f,0x7a,
0x7e,0x28,0xd7,0x67,0xb9,0xb1,0x69,0x9b,0x96,0x3e,0xc5,0xe4,
0x45,0xb0,0x23,0x75,0x00,0xda,0xee,0xdb,0x6d,0xa9,0xe7,0x98
};

XMEMSET(key, 0, sizeof(key));

p7 = wc_PKCS7_New(NULL, INVALID_DEVID);
ExpectNotNull(p7);
if (p7 != NULL) {
p7->encryptionKey = key;
p7->encryptionKeySz = sizeof(key);

/* 496-byte content into 128-byte buffer must return BUFFER_E */
ExpectIntLT(wc_PKCS7_DecodeEncryptedData(p7, (byte*)encBlob,
(word32)sizeof(encBlob), out, sizeof(out)), 0);

wc_PKCS7_Free(p7);
}
#endif
return EXPECT_RESULT();
}

/* Dummy ORI callback for PKCS#7 ORI overflow test */
#if defined(HAVE_PKCS7) && !defined(WOLFSSL_NO_MALLOC)
static int test_dummy_ori_cb(wc_PKCS7* pkcs7, byte* oriType, word32 oriTypeSz,
byte* oriValue, word32 oriValueSz,
byte* decryptedKey, word32* decryptedKeySz,
void* ctx)
{
(void)pkcs7; (void)oriType; (void)oriTypeSz;
(void)oriValue; (void)oriValueSz;
(void)decryptedKey; (void)decryptedKeySz; (void)ctx;
return -1;
}
#endif

/* Test: PKCS#7 ORI must reject OID larger than MAX_OID_SZ (32) */
static int test_pkcs7_ori_oversized_oid(void)
{
EXPECT_DECLS;
#if defined(HAVE_PKCS7) && !defined(WOLFSSL_NO_MALLOC)
wc_PKCS7* p7 = NULL;
byte out[256];

/* EnvelopedData with [4] IMPLICIT ORI containing an 80-byte OID */
static const byte poc[] = {
0x30, 0x6b,
0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x03,
0xa0, 0x5e,
0x30, 0x5c,
0x02, 0x01, 0x00,
0x31, 0x57,
0xa4, 0x55,
0x06, 0x50,
0x2a,
0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
0x04, 0x01, 0x00
};

p7 = wc_PKCS7_New(NULL, INVALID_DEVID);
ExpectNotNull(p7);
if (p7 != NULL) {
wc_PKCS7_SetOriDecryptCb(p7, test_dummy_ori_cb);

/* Must return error (ASN_PARSE_E), not overflow the stack */
ExpectIntLT(wc_PKCS7_DecodeEnvelopedData(p7, (byte*)poc, sizeof(poc),
out, sizeof(out)), 0);

wc_PKCS7_Free(p7);
}
#endif
return EXPECT_RESULT();
}

TEST_CASE testCases[] = {
TEST_DECL(test_fileAccess),

Expand Down Expand Up @@ -35455,6 +35704,10 @@ TEST_CASE testCases[] = {
TEST_DECL(test_ocsp_responder),
TEST_TLS_DECLS,
TEST_DECL(test_wc_DhSetNamedKey),
TEST_DECL(test_DhAgree_rejects_p_minus_1),
TEST_DECL(test_ed448_rejects_identity_key),
TEST_DECL(test_pkcs7_decode_encrypted_outputsz),
TEST_DECL(test_pkcs7_ori_oversized_oid),

#if defined(WOLFSSL_SNIFFER) && defined(WOLFSSL_SNIFFER_CHAIN_INPUT)
TEST_DECL(test_sniffer_chain_input_overflow),
Expand Down
3 changes: 2 additions & 1 deletion wolfcrypt/src/dh.c
Original file line number Diff line number Diff line change
Expand Up @@ -2030,12 +2030,13 @@ static int wc_DhAgree_Sync(DhKey* key, byte* agree, word32* agreeSz,
WOLFSSL_MSG("wc_DhAgree wc_DhCheckPrivKey failed");
return DH_CHECK_PRIV_E;
}
#endif

/* Always validate peer public key (2 <= y <= p-2) per SP 800-56A */
if (wc_DhCheckPubKey(key, otherPub, pubSz) != 0) {
WOLFSSL_MSG("wc_DhAgree wc_DhCheckPubKey failed");
return DH_CHECK_PUB_E;
}
#endif

#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
y = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, DYNAMIC_TYPE_DH);
Expand Down
32 changes: 29 additions & 3 deletions wolfcrypt/src/ed448.c
Original file line number Diff line number Diff line change
Expand Up @@ -711,6 +711,18 @@ static int ed448_verify_msg_final_with_sha(const byte* sig, word32 sigLen,
if (i == -1)
return BAD_FUNC_ARG;

/* Reject identity public key (0,1): 0x01 followed by 56 zero bytes. */
{
int isIdentity = (key->p[0] == 0x01);
int j;
for (j = 1; j < ED448_PUB_KEY_SIZE && isIdentity; j++) {
if (key->p[j] != 0x00)
isIdentity = 0;
}
if (isIdentity)
return BAD_FUNC_ARG;
}

/* uncompress A (public key), test if valid, and negate it */
if (ge448_from_bytes_negate_vartime(&A, key->p) != 0)
return BAD_FUNC_ARG;
Expand Down Expand Up @@ -1335,14 +1347,28 @@ int wc_ed448_check_key(ed448_key* key)
}
/* No private key, check Y is valid. */
else if ((ret == 0) && (!key->privKeySet)) {
/* Verify that Q is not identity element 0.
* 0 has no representation for Ed448. */
/* Reject the identity element (0, 1).
* Encoding: 0x01 followed by 56 zero bytes. */
{
int isIdentity = 1;
int i;
if (key->p[0] != 0x01)
isIdentity = 0;
for (i = 1; i < ED448_PUB_KEY_SIZE && isIdentity; i++) {
if (key->p[i] != 0x00)
isIdentity = 0;
}
if (isIdentity) {
WOLFSSL_MSG("Ed448 public key is the identity element");
ret = PUBLIC_KEY_E;
}
}

/* Verify that xQ and yQ are integers in the interval [0, p - 1].
* Only have yQ so check that ordinate.
* p = 2^448-2^224-1 = 0xff..fe..ff
*/
{
if (ret == 0) {
int i;
ret = PUBLIC_KEY_E;

Expand Down
Loading
Loading