mirror of
https://github.com/wolfSSL/wolfssl.git
synced 2025-07-30 18:57:27 +02:00
Merge pull request #5586 from julek-wolfssl/dtls-misc-security
Add missing minor security checks
This commit is contained in:
98
src/dtls13.c
98
src/dtls13.c
@ -1846,6 +1846,20 @@ struct Dtls13Epoch* Dtls13GetEpoch(WOLFSSL* ssl, w64wrapper epochNumber)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Dtls13SetOlderEpochSide(WOLFSSL* ssl, w64wrapper epochNumber,
|
||||||
|
int side)
|
||||||
|
{
|
||||||
|
Dtls13Epoch* e;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < DTLS13_EPOCH_SIZE; ++i) {
|
||||||
|
e = &ssl->dtls13Epochs[i];
|
||||||
|
if (e->isValid && w64LT(e->epochNumber, epochNumber)) {
|
||||||
|
e->side = (byte)side;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void Dtls13EpochCopyKeys(WOLFSSL* ssl, Dtls13Epoch* e, Keys* k, int side)
|
static void Dtls13EpochCopyKeys(WOLFSSL* ssl, Dtls13Epoch* e, Keys* k, int side)
|
||||||
{
|
{
|
||||||
byte clientWrite, serverWrite;
|
byte clientWrite, serverWrite;
|
||||||
@ -2011,6 +2025,14 @@ int Dtls13NewEpoch(WOLFSSL* ssl, w64wrapper epochNumber, int side)
|
|||||||
e->side = ENCRYPT_AND_DECRYPT_SIDE;
|
e->side = ENCRYPT_AND_DECRYPT_SIDE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Once handshake is done. Mark epochs older than the last one as encrypt
|
||||||
|
* only so that they can't be used for decryption. */
|
||||||
|
if (ssl->options.handShakeDone && (e->side == ENCRYPT_AND_DECRYPT_SIDE ||
|
||||||
|
e->side == DECRYPT_SIDE_ONLY)) {
|
||||||
|
w64Decrement(&epochNumber);
|
||||||
|
Dtls13SetOlderEpochSide(ssl, epochNumber, ENCRYPT_SIDE_ONLY);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2373,6 +2395,13 @@ int Dtls13DoScheduledWork(WOLFSSL* ssl)
|
|||||||
|
|
||||||
ssl->dtls13SendingAckOrRtx = 0;
|
ssl->dtls13SendingAckOrRtx = 0;
|
||||||
|
|
||||||
|
if (ssl->dtls13DoKeyUpdate) {
|
||||||
|
ssl->dtls13DoKeyUpdate = 0;
|
||||||
|
ret = Tls13UpdateKeys(ssl);
|
||||||
|
if (ret != 0)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2610,4 +2639,73 @@ int wolfSSL_dtls13_has_pending_msg(WOLFSSL* ssl)
|
|||||||
return ssl->dtls13Rtx.rtxRecords != NULL;
|
return ssl->dtls13Rtx.rtxRecords != NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef WOLFSSL_TLS13_IGNORE_AEAD_LIMITS
|
||||||
|
/* Limits specified by
|
||||||
|
* https://www.rfc-editor.org/rfc/rfc9147.html#name-aead-limits
|
||||||
|
* We specify the limit by which we need to do a key update as the halfway point
|
||||||
|
* to the hard decryption fail limit. */
|
||||||
|
int Dtls13CheckAEADFailLimit(WOLFSSL* ssl)
|
||||||
|
{
|
||||||
|
w64wrapper keyUpdateLimit;
|
||||||
|
w64wrapper hardLimit;
|
||||||
|
switch (ssl->specs.bulk_cipher_algorithm) {
|
||||||
|
#if defined(BUILD_AESGCM) || (defined(HAVE_CHACHA) && defined(HAVE_POLY1305))
|
||||||
|
case wolfssl_aes_gcm:
|
||||||
|
case wolfssl_chacha:
|
||||||
|
hardLimit = DTLS_AEAD_AES_GCM_CHACHA_FAIL_LIMIT;
|
||||||
|
keyUpdateLimit = DTLS_AEAD_AES_GCM_CHACHA_FAIL_KU_LIMIT;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_AESCCM
|
||||||
|
case wolfssl_aes_ccm:
|
||||||
|
if (ssl->specs.aead_mac_size == AES_CCM_8_AUTH_SZ) {
|
||||||
|
/* Limit is 2^7. The RFC recommends that
|
||||||
|
* "TLS_AES_128_CCM_8_SHA256 is not suitable for general use".
|
||||||
|
* We still should enforce the limit. */
|
||||||
|
hardLimit = DTLS_AEAD_AES_CCM_8_FAIL_LIMIT;
|
||||||
|
keyUpdateLimit = DTLS_AEAD_AES_CCM_8_FAIL_KU_LIMIT;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* Limit is 2^23.5.
|
||||||
|
* Without the fraction is 11863283 (0x00B504F3)
|
||||||
|
* Half of this value is 5931641 (0x005A8279) */
|
||||||
|
hardLimit = DTLS_AEAD_AES_CCM_FAIL_LIMIT;
|
||||||
|
keyUpdateLimit = DTLS_AEAD_AES_CCM_FAIL_KU_LIMIT;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
case wolfssl_cipher_null:
|
||||||
|
/* No encryption being done. The MAC check must have failed. */
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
WOLFSSL_MSG("Unrecognized ciphersuite for AEAD limit check");
|
||||||
|
WOLFSSL_ERROR_VERBOSE(DECRYPT_ERROR);
|
||||||
|
return DECRYPT_ERROR;
|
||||||
|
}
|
||||||
|
if (ssl->dtls13DecryptEpoch == NULL) {
|
||||||
|
WOLFSSL_MSG("Dtls13CheckAEADFailLimit: ssl->dtls13DecryptEpoch should "
|
||||||
|
"not be NULL");
|
||||||
|
WOLFSSL_ERROR_VERBOSE(BAD_STATE_E);
|
||||||
|
return BAD_STATE_E;
|
||||||
|
}
|
||||||
|
w64Increment(&ssl->dtls13DecryptEpoch->dropCount);
|
||||||
|
if (w64GT(ssl->dtls13DecryptEpoch->dropCount, hardLimit)) {
|
||||||
|
/* We have reached the hard limit for failed decryptions. */
|
||||||
|
WOLFSSL_MSG("Connection exceeded hard AEAD limit");
|
||||||
|
WOLFSSL_ERROR_VERBOSE(DECRYPT_ERROR);
|
||||||
|
return DECRYPT_ERROR;
|
||||||
|
}
|
||||||
|
else if (w64GT(ssl->dtls13DecryptEpoch->dropCount, keyUpdateLimit)) {
|
||||||
|
WOLFSSL_MSG("Connection exceeded key update limit. Issuing key update");
|
||||||
|
/* If not waiting for a response then request a key update. */
|
||||||
|
if (!ssl->keys.updateResponseReq) {
|
||||||
|
ssl->dtls13DoKeyUpdate = 1;
|
||||||
|
ssl->dtls13InvalidateBefore = ssl->dtls13PeerEpoch;
|
||||||
|
w64Increment(&ssl->dtls13InvalidateBefore);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* WOLFSSL_DTLS13 */
|
#endif /* WOLFSSL_DTLS13 */
|
||||||
|
137
src/internal.c
137
src/internal.c
@ -80,6 +80,12 @@
|
|||||||
* Verifies the ECC signature after signing in case of faults in the
|
* Verifies the ECC signature after signing in case of faults in the
|
||||||
* calculation of the signature. Useful when signature fault injection is a
|
* calculation of the signature. Useful when signature fault injection is a
|
||||||
* possible attack.
|
* possible attack.
|
||||||
|
* WOLFSSL_TLS13_IGNORE_AEAD_LIMITS
|
||||||
|
* Ignore the AEAD limits for messages specified in the RFC. After
|
||||||
|
* reaching the limit, we initiate a key update. We enforce the AEAD limits
|
||||||
|
* by default.
|
||||||
|
* https://www.rfc-editor.org/rfc/rfc8446#section-5.5
|
||||||
|
* https://www.rfc-editor.org/rfc/rfc9147.html#name-aead-limits
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
@ -18247,6 +18253,23 @@ int DoApplicationData(WOLFSSL* ssl, byte* input, word32* inOutIdx, int sniff)
|
|||||||
return OUT_OF_ORDER_E;
|
return OUT_OF_ORDER_E;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(WOLFSSL_DTLS13) && !defined(WOLFSSL_TLS13_IGNORE_AEAD_LIMITS)
|
||||||
|
/* Check if we want to invalidate old epochs. If
|
||||||
|
* ssl->dtls13InvalidateBefore is set then we want to mark all old
|
||||||
|
* epochs as encrypt only. This is done when we detect too many failed
|
||||||
|
* decryptions. We do this here to confirm that the peer has updated its
|
||||||
|
* keys and we can stop using the old keys. */
|
||||||
|
if (ssl->options.dtls && IsAtLeastTLSv1_3(ssl->version)) {
|
||||||
|
if (!w64IsZero(ssl->dtls13InvalidateBefore) &&
|
||||||
|
w64Equal(ssl->keys.curEpoch64, ssl->dtls13InvalidateBefore)) {
|
||||||
|
Dtls13SetOlderEpochSide(ssl, ssl->dtls13InvalidateBefore,
|
||||||
|
ENCRYPT_SIDE_ONLY);
|
||||||
|
w64Zero(&ssl->dtls13InvalidateBefore);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef WOLFSSL_AEAD_ONLY
|
#ifndef WOLFSSL_AEAD_ONLY
|
||||||
if (ssl->specs.cipher_type == block) {
|
if (ssl->specs.cipher_type == block) {
|
||||||
if (ssl->options.tls1_1)
|
if (ssl->options.tls1_1)
|
||||||
@ -18831,6 +18854,26 @@ static WC_INLINE int VerifyMac(WOLFSSL* ssl, const byte* input, word32 msgSz,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef WOLFSSL_DTLS
|
||||||
|
static int HandleDTLSDecryptFailed(WOLFSSL* ssl)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
#ifdef WOLFSSL_DTLS_DROP_STATS
|
||||||
|
ssl->macDropCount++;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(WOLFSSL_DTLS13) && !defined(WOLFSSL_TLS13_IGNORE_AEAD_LIMITS)
|
||||||
|
/* Handle AEAD limits specified by the RFC for failed decryption */
|
||||||
|
if (IsAtLeastTLSv1_3(ssl->version))
|
||||||
|
ret = Dtls13CheckAEADFailLimit(ssl);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
(void)ssl;
|
||||||
|
WOLFSSL_MSG("DTLS: Ignoring failed decryption");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
int ProcessReply(WOLFSSL* ssl)
|
int ProcessReply(WOLFSSL* ssl)
|
||||||
{
|
{
|
||||||
return ProcessReplyEx(ssl, 0);
|
return ProcessReplyEx(ssl, 0);
|
||||||
@ -19137,17 +19180,14 @@ int ProcessReplyEx(WOLFSSL* ssl, int allowSocketErr)
|
|||||||
#endif
|
#endif
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
WOLFSSL_MSG("VerifyMacEnc failed");
|
WOLFSSL_MSG("VerifyMacEnc failed");
|
||||||
WOLFSSL_ERROR(ret);
|
|
||||||
#ifdef WOLFSSL_DTLS
|
#ifdef WOLFSSL_DTLS
|
||||||
/* If in DTLS mode, if the decrypt fails for any
|
/* If in DTLS mode, if the decrypt fails for any
|
||||||
* reason, pretend the datagram never happened. */
|
* reason, pretend the datagram never happened. */
|
||||||
if (ssl->options.dtls) {
|
if (ssl->options.dtls) {
|
||||||
ssl->options.processReply = doProcessInit;
|
ssl->options.processReply = doProcessInit;
|
||||||
ssl->buffers.inputBuffer.idx =
|
ssl->buffers.inputBuffer.idx =
|
||||||
ssl->buffers.inputBuffer.length;
|
ssl->buffers.inputBuffer.length;
|
||||||
#ifdef WOLFSSL_DTLS_DROP_STATS
|
return HandleDTLSDecryptFailed(ssl);
|
||||||
ssl->macDropCount++;
|
|
||||||
#endif /* WOLFSSL_DTLS_DROP_STATS */
|
|
||||||
}
|
}
|
||||||
#endif /* WOLFSSL_DTLS */
|
#endif /* WOLFSSL_DTLS */
|
||||||
#ifdef WOLFSSL_EXTRA_ALERTS
|
#ifdef WOLFSSL_EXTRA_ALERTS
|
||||||
@ -19304,14 +19344,10 @@ int ProcessReplyEx(WOLFSSL* ssl, int allowSocketErr)
|
|||||||
/* If in DTLS mode, if the decrypt fails for any
|
/* If in DTLS mode, if the decrypt fails for any
|
||||||
* reason, pretend the datagram never happened. */
|
* reason, pretend the datagram never happened. */
|
||||||
if (ssl->options.dtls) {
|
if (ssl->options.dtls) {
|
||||||
WOLFSSL_MSG("DTLS: Ignoring failed decryption");
|
|
||||||
ssl->options.processReply = doProcessInit;
|
ssl->options.processReply = doProcessInit;
|
||||||
ssl->buffers.inputBuffer.idx =
|
ssl->buffers.inputBuffer.idx =
|
||||||
ssl->buffers.inputBuffer.length;
|
ssl->buffers.inputBuffer.length;
|
||||||
#ifdef WOLFSSL_DTLS_DROP_STATS
|
return HandleDTLSDecryptFailed(ssl);
|
||||||
ssl->macDropCount++;
|
|
||||||
#endif /* WOLFSSL_DTLS_DROP_STATS */
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
#endif /* WOLFSSL_DTLS */
|
#endif /* WOLFSSL_DTLS */
|
||||||
#ifdef WOLFSSL_EARLY_DATA
|
#ifdef WOLFSSL_EARLY_DATA
|
||||||
@ -19374,24 +19410,21 @@ int ProcessReplyEx(WOLFSSL* ssl, int allowSocketErr)
|
|||||||
return ret;
|
return ret;
|
||||||
#endif
|
#endif
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
WOLFSSL_MSG("VerifyMac failed");
|
|
||||||
WOLFSSL_ERROR(ret);
|
|
||||||
#ifdef WOLFSSL_DTLS
|
#ifdef WOLFSSL_DTLS
|
||||||
/* If in DTLS mode, if the decrypt fails for any
|
/* If in DTLS mode, if the decrypt fails for any
|
||||||
* reason, pretend the datagram never happened. */
|
* reason, pretend the datagram never happened. */
|
||||||
if (ssl->options.dtls) {
|
if (ssl->options.dtls) {
|
||||||
ssl->options.processReply = doProcessInit;
|
ssl->options.processReply = doProcessInit;
|
||||||
ssl->buffers.inputBuffer.idx =
|
ssl->buffers.inputBuffer.idx =
|
||||||
ssl->buffers.inputBuffer.length;
|
ssl->buffers.inputBuffer.length;
|
||||||
#ifdef WOLFSSL_DTLS_DROP_STATS
|
return HandleDTLSDecryptFailed(ssl);
|
||||||
ssl->macDropCount++;
|
|
||||||
#endif /* WOLFSSL_DTLS_DROP_STATS */
|
|
||||||
}
|
}
|
||||||
#endif /* WOLFSSL_DTLS */
|
#endif /* WOLFSSL_DTLS */
|
||||||
#ifdef WOLFSSL_EXTRA_ALERTS
|
#ifdef WOLFSSL_EXTRA_ALERTS
|
||||||
if (!ssl->options.dtls)
|
if (!ssl->options.dtls)
|
||||||
SendAlert(ssl, alert_fatal, bad_record_mac);
|
SendAlert(ssl, alert_fatal, bad_record_mac);
|
||||||
#endif
|
#endif
|
||||||
|
WOLFSSL_MSG("VerifyMac failed");
|
||||||
WOLFSSL_ERROR_VERBOSE(DECRYPT_ERROR);
|
WOLFSSL_ERROR_VERBOSE(DECRYPT_ERROR);
|
||||||
return DECRYPT_ERROR;
|
return DECRYPT_ERROR;
|
||||||
}
|
}
|
||||||
@ -22021,6 +22054,66 @@ static int ModifyForMTU(WOLFSSL* ssl, int buffSz, int outputSz, int mtuSz)
|
|||||||
}
|
}
|
||||||
#endif /* WOLFSSL_DTLS */
|
#endif /* WOLFSSL_DTLS */
|
||||||
|
|
||||||
|
#if defined(WOLFSSL_TLS13) && !defined(WOLFSSL_TLS13_IGNORE_AEAD_LIMITS)
|
||||||
|
/*
|
||||||
|
* Enforce limits specified in
|
||||||
|
* https://www.rfc-editor.org/rfc/rfc8446#section-5.5
|
||||||
|
*/
|
||||||
|
static int CheckTLS13AEADSendLimit(WOLFSSL* ssl)
|
||||||
|
{
|
||||||
|
w64wrapper seq;
|
||||||
|
w64wrapper limit;
|
||||||
|
|
||||||
|
switch (ssl->specs.bulk_cipher_algorithm) {
|
||||||
|
#ifdef BUILD_AESGCM
|
||||||
|
case wolfssl_aes_gcm:
|
||||||
|
/* Limit is 2^24.5 */
|
||||||
|
limit = AEAD_AES_LIMIT;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#if defined(HAVE_CHACHA) && defined(HAVE_POLY1305)
|
||||||
|
case wolfssl_chacha:
|
||||||
|
/* For ChaCha20/Poly1305, the record sequence number would wrap
|
||||||
|
* before the safety limit is reached. */
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_AESCCM
|
||||||
|
case wolfssl_aes_ccm:
|
||||||
|
/* Use the limits calculated in the DTLS 1.3 spec
|
||||||
|
* https://www.rfc-editor.org/rfc/rfc9147.html#name-analysis-of-limits-on-ccm-u */
|
||||||
|
#ifdef WOLFSSL_DTLS13
|
||||||
|
if (ssl->options.dtls)
|
||||||
|
limit = DTLS_AEAD_AES_CCM_LIMIT; /* Limit is 2^23 */
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
limit = AEAD_AES_LIMIT; /* Limit is 2^24.5 */
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
case wolfssl_cipher_null:
|
||||||
|
/* No encryption being done */
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
WOLFSSL_MSG("Unrecognized ciphersuite for AEAD limit check");
|
||||||
|
return BAD_STATE_E;
|
||||||
|
|
||||||
|
}
|
||||||
|
#ifdef WOLFSSL_DTLS13
|
||||||
|
if (ssl->options.dtls) {
|
||||||
|
seq = ssl->dtls13EncryptEpoch->nextSeqNumber;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
seq = w64From32(ssl->keys.sequence_number_hi,
|
||||||
|
ssl->keys.sequence_number_lo);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (w64GTE(seq, limit))
|
||||||
|
return Tls13UpdateKeys(ssl); /* Need to generate new keys */
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif /* WOLFSSL_TLS13 && !WOLFSSL_TLS13_IGNORE_AEAD_LIMITS */
|
||||||
|
|
||||||
int SendData(WOLFSSL* ssl, const void* data, int sz)
|
int SendData(WOLFSSL* ssl, const void* data, int sz)
|
||||||
{
|
{
|
||||||
@ -22123,6 +22216,16 @@ int SendData(WOLFSSL* ssl, const void* data, int sz)
|
|||||||
byte comp[MAX_RECORD_SIZE + MAX_COMP_EXTRA];
|
byte comp[MAX_RECORD_SIZE + MAX_COMP_EXTRA];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(WOLFSSL_TLS13) && !defined(WOLFSSL_TLS13_IGNORE_AEAD_LIMITS)
|
||||||
|
if (IsAtLeastTLSv1_3(ssl->version)) {
|
||||||
|
ret = CheckTLS13AEADSendLimit(ssl);
|
||||||
|
if (ret != 0) {
|
||||||
|
ssl->error = ret;
|
||||||
|
return WOLFSSL_FATAL_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef WOLFSSL_DTLS13
|
#ifdef WOLFSSL_DTLS13
|
||||||
if (ssl->options.dtls && ssl->options.tls1_3) {
|
if (ssl->options.dtls && ssl->options.tls1_3) {
|
||||||
byte isEarlyData = 0;
|
byte isEarlyData = 0;
|
||||||
|
12
src/ssl.c
12
src/ssl.c
@ -3172,6 +3172,11 @@ static int _Rehandshake(WOLFSSL* ssl)
|
|||||||
if (ssl == NULL)
|
if (ssl == NULL)
|
||||||
return BAD_FUNC_ARG;
|
return BAD_FUNC_ARG;
|
||||||
|
|
||||||
|
if (IsAtLeastTLSv1_3(ssl->version)) {
|
||||||
|
WOLFSSL_MSG("Secure Renegotiation not supported in TLS 1.3");
|
||||||
|
return SECURE_RENEGOTIATION_E;
|
||||||
|
}
|
||||||
|
|
||||||
if (ssl->secure_renegotiation == NULL) {
|
if (ssl->secure_renegotiation == NULL) {
|
||||||
WOLFSSL_MSG("Secure Renegotiation not forced on by user");
|
WOLFSSL_MSG("Secure Renegotiation not forced on by user");
|
||||||
return SECURE_RENEGOTIATION_E;
|
return SECURE_RENEGOTIATION_E;
|
||||||
@ -3182,6 +3187,13 @@ static int _Rehandshake(WOLFSSL* ssl)
|
|||||||
return SECURE_RENEGOTIATION_E;
|
return SECURE_RENEGOTIATION_E;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef WOLFSSL_DTLS
|
||||||
|
if (ssl->options.dtls && ssl->keys.dtls_epoch == 0xFFFF) {
|
||||||
|
WOLFSSL_MSG("Secure Renegotiation not allowed. Epoch would wrap");
|
||||||
|
return SECURE_RENEGOTIATION_E;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* If the client started the renegotiation, the server will already
|
/* If the client started the renegotiation, the server will already
|
||||||
* have processed the client's hello. */
|
* have processed the client's hello. */
|
||||||
if (ssl->options.side != WOLFSSL_SERVER_END ||
|
if (ssl->options.side != WOLFSSL_SERVER_END ||
|
||||||
|
39
src/tls13.c
39
src/tls13.c
@ -2097,7 +2097,7 @@ static WC_INLINE void WriteSEQTls13(WOLFSSL* ssl, int verifyOrder, byte* out)
|
|||||||
Dtls13GetSeq(ssl, verifyOrder, seq, 1);
|
Dtls13GetSeq(ssl, verifyOrder, seq, 1);
|
||||||
#endif /* WOLFSSL_DTLS13 */
|
#endif /* WOLFSSL_DTLS13 */
|
||||||
}
|
}
|
||||||
else if (verifyOrder) {
|
else if (verifyOrder == PEER_ORDER) {
|
||||||
seq[0] = ssl->keys.peer_sequence_number_hi;
|
seq[0] = ssl->keys.peer_sequence_number_hi;
|
||||||
seq[1] = ssl->keys.peer_sequence_number_lo++;
|
seq[1] = ssl->keys.peer_sequence_number_lo++;
|
||||||
/* handle rollover */
|
/* handle rollover */
|
||||||
@ -11130,6 +11130,26 @@ int wolfSSL_no_dhe_psk(WOLFSSL* ssl)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int Tls13UpdateKeys(WOLFSSL* ssl)
|
||||||
|
{
|
||||||
|
if (ssl == NULL || !IsAtLeastTLSv1_3(ssl->version))
|
||||||
|
return BAD_FUNC_ARG;
|
||||||
|
|
||||||
|
#ifdef WOLFSSL_DTLS13
|
||||||
|
/* we are already waiting for the ack of a sent key update message. We can't
|
||||||
|
send another one before receiving its ack. Either wolfSSL_update_keys()
|
||||||
|
was invoked multiple times over a short period of time or we replied to a
|
||||||
|
KeyUpdate with update request. We'll just ignore sending this
|
||||||
|
KeyUpdate. */
|
||||||
|
/* TODO: add WOLFSSL_ERROR_ALREADY_IN_PROGRESS type of error here */
|
||||||
|
if (ssl->options.dtls && ssl->dtls13WaitKeyUpdateAck)
|
||||||
|
return 0;
|
||||||
|
#endif /* WOLFSSL_DTLS13 */
|
||||||
|
|
||||||
|
return SendTls13KeyUpdate(ssl);
|
||||||
|
}
|
||||||
|
|
||||||
/* Update the keys for encryption and decryption.
|
/* Update the keys for encryption and decryption.
|
||||||
* If using non-blocking I/O and WOLFSSL_ERROR_WANT_WRITE is returned then
|
* If using non-blocking I/O and WOLFSSL_ERROR_WANT_WRITE is returned then
|
||||||
* calling wolfSSL_write() will have the message sent when ready.
|
* calling wolfSSL_write() will have the message sent when ready.
|
||||||
@ -11142,22 +11162,7 @@ int wolfSSL_no_dhe_psk(WOLFSSL* ssl)
|
|||||||
int wolfSSL_update_keys(WOLFSSL* ssl)
|
int wolfSSL_update_keys(WOLFSSL* ssl)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
ret = Tls13UpdateKeys(ssl);
|
||||||
if (ssl == NULL || !IsAtLeastTLSv1_3(ssl->version))
|
|
||||||
return BAD_FUNC_ARG;
|
|
||||||
|
|
||||||
#ifdef WOLFSSL_DTLS13
|
|
||||||
/* we are already waiting for the ack of a sent key update message. We can't
|
|
||||||
send another one before receiving its ack. Either wolfSSL_update_keys()
|
|
||||||
was invoked multiple times over a short period of time or we replied to a
|
|
||||||
KeyUpdate with update request. We'll just ignore sending this
|
|
||||||
KeyUpdate. */
|
|
||||||
/* TODO: add WOLFSSL_ERROR_ALREADY_IN_PROGRESS type of error here */
|
|
||||||
if (ssl->options.dtls && ssl->dtls13WaitKeyUpdateAck)
|
|
||||||
return WOLFSSL_SUCCESS;
|
|
||||||
#endif /* WOLFSSL_DTLS13 */
|
|
||||||
|
|
||||||
ret = SendTls13KeyUpdate(ssl);
|
|
||||||
if (ret == WANT_WRITE)
|
if (ret == WANT_WRITE)
|
||||||
ret = WOLFSSL_ERROR_WANT_WRITE;
|
ret = WOLFSSL_ERROR_WANT_WRITE;
|
||||||
else if (ret == 0)
|
else if (ret == 0)
|
||||||
|
322
tests/api.c
322
tests/api.c
@ -5786,6 +5786,49 @@ done:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test_wolfSSL_client_server_nofail(callback_functions* client_cb,
|
||||||
|
callback_functions* server_cb)
|
||||||
|
{
|
||||||
|
func_args client_args;
|
||||||
|
func_args server_args;
|
||||||
|
tcp_ready ready;
|
||||||
|
THREAD_TYPE serverThread;
|
||||||
|
|
||||||
|
XMEMSET(&client_args, 0, sizeof(func_args));
|
||||||
|
XMEMSET(&server_args, 0, sizeof(func_args));
|
||||||
|
|
||||||
|
#ifdef WOLFSSL_TIRTOS
|
||||||
|
fdOpenSession(Task_self());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
StartTCP();
|
||||||
|
InitTcpReady(&ready);
|
||||||
|
|
||||||
|
#if defined(USE_WINDOWS_API)
|
||||||
|
/* use RNG to get random port if using windows */
|
||||||
|
ready.port = GetRandomPort();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
server_args.signal = &ready;
|
||||||
|
server_args.callbacks = server_cb;
|
||||||
|
client_args.signal = &ready;
|
||||||
|
client_args.callbacks = client_cb;
|
||||||
|
|
||||||
|
start_thread(test_server_nofail, &server_args, &serverThread);
|
||||||
|
wait_tcp_ready(&server_args);
|
||||||
|
test_client_nofail(&client_args, NULL);
|
||||||
|
join_thread(serverThread);
|
||||||
|
|
||||||
|
client_cb->return_code = client_args.return_code;
|
||||||
|
server_cb->return_code = server_args.return_code;
|
||||||
|
|
||||||
|
FreeTcpReady(&ready);
|
||||||
|
|
||||||
|
#ifdef WOLFSSL_TIRTOS
|
||||||
|
fdOpenSession(Task_self());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(OPENSSL_EXTRA) && !defined(NO_SESSION_CACHE) && \
|
#if defined(OPENSSL_EXTRA) && !defined(NO_SESSION_CACHE) && \
|
||||||
!defined(WOLFSSL_TLS13) && !defined(NO_WOLFSSL_CLIENT)
|
!defined(WOLFSSL_TLS13) && !defined(NO_WOLFSSL_CLIENT)
|
||||||
static void test_client_reuse_WOLFSSLobj(void* args, void *cb, void* server_args)
|
static void test_client_reuse_WOLFSSLobj(void* args, void *cb, void* server_args)
|
||||||
@ -55575,12 +55618,8 @@ static void test_wolfSSL_dtls_plaintext_client(WOLFSSL* ssl)
|
|||||||
|
|
||||||
static int test_wolfSSL_dtls_plaintext(void)
|
static int test_wolfSSL_dtls_plaintext(void)
|
||||||
{
|
{
|
||||||
tcp_ready ready;
|
|
||||||
func_args client_args;
|
|
||||||
func_args server_args;
|
|
||||||
callback_functions func_cb_client;
|
callback_functions func_cb_client;
|
||||||
callback_functions func_cb_server;
|
callback_functions func_cb_server;
|
||||||
THREAD_TYPE serverThread;
|
|
||||||
size_t i;
|
size_t i;
|
||||||
struct test_params {
|
struct test_params {
|
||||||
method_provider client_meth;
|
method_provider client_meth;
|
||||||
@ -55596,47 +55635,21 @@ static int test_wolfSSL_dtls_plaintext(void)
|
|||||||
printf(testingFmt, "test_wolfSSL_dtls_plaintext");
|
printf(testingFmt, "test_wolfSSL_dtls_plaintext");
|
||||||
|
|
||||||
for (i = 0; i < sizeof(params)/sizeof(*params); i++) {
|
for (i = 0; i < sizeof(params)/sizeof(*params); i++) {
|
||||||
XMEMSET(&client_args, 0, sizeof(func_args));
|
|
||||||
XMEMSET(&server_args, 0, sizeof(func_args));
|
|
||||||
XMEMSET(&func_cb_client, 0, sizeof(callback_functions));
|
XMEMSET(&func_cb_client, 0, sizeof(callback_functions));
|
||||||
XMEMSET(&func_cb_server, 0, sizeof(callback_functions));
|
XMEMSET(&func_cb_server, 0, sizeof(callback_functions));
|
||||||
|
|
||||||
#ifdef WOLFSSL_TIRTOS
|
|
||||||
fdOpenSession(Task_self());
|
|
||||||
#endif
|
|
||||||
|
|
||||||
StartTCP();
|
|
||||||
InitTcpReady(&ready);
|
|
||||||
|
|
||||||
#if defined(USE_WINDOWS_API)
|
|
||||||
/* use RNG to get random port if using windows */
|
|
||||||
ready.port = GetRandomPort();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
server_args.signal = &ready;
|
|
||||||
server_args.callbacks = &func_cb_server;
|
|
||||||
client_args.signal = &ready;
|
|
||||||
client_args.callbacks = &func_cb_client;
|
|
||||||
|
|
||||||
func_cb_client.doUdp = func_cb_server.doUdp = 1;
|
func_cb_client.doUdp = func_cb_server.doUdp = 1;
|
||||||
func_cb_server.method = params[i].server_meth;
|
func_cb_server.method = params[i].server_meth;
|
||||||
func_cb_client.method = params[i].client_meth;
|
func_cb_client.method = params[i].client_meth;
|
||||||
func_cb_client.on_result = params[i].on_result_client;
|
func_cb_client.on_result = params[i].on_result_client;
|
||||||
func_cb_server.on_result = params[i].on_result_server;
|
func_cb_server.on_result = params[i].on_result_server;
|
||||||
|
|
||||||
start_thread(test_server_nofail, &server_args, &serverThread);
|
test_wolfSSL_client_server_nofail(&func_cb_client, &func_cb_server);
|
||||||
wait_tcp_ready(&server_args);
|
|
||||||
test_client_nofail(&client_args, NULL);
|
|
||||||
join_thread(serverThread);
|
|
||||||
|
|
||||||
AssertTrue(client_args.return_code);
|
if (!func_cb_client.return_code)
|
||||||
AssertTrue(server_args.return_code);
|
return -1;
|
||||||
|
if (!func_cb_server.return_code)
|
||||||
FreeTcpReady(&ready);
|
return -2;
|
||||||
|
|
||||||
#ifdef WOLFSSL_TIRTOS
|
|
||||||
fdOpenSession(Task_self());
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
printf(resultFmt, passed);
|
printf(resultFmt, passed);
|
||||||
@ -55761,12 +55774,8 @@ static void test_wolfSSL_dtls13_fragments_spammer(WOLFSSL* ssl)
|
|||||||
|
|
||||||
static int test_wolfSSL_dtls_fragments(void)
|
static int test_wolfSSL_dtls_fragments(void)
|
||||||
{
|
{
|
||||||
tcp_ready ready;
|
|
||||||
func_args client_args;
|
|
||||||
func_args server_args;
|
|
||||||
callback_functions func_cb_client;
|
callback_functions func_cb_client;
|
||||||
callback_functions func_cb_server;
|
callback_functions func_cb_server;
|
||||||
THREAD_TYPE serverThread;
|
|
||||||
size_t i;
|
size_t i;
|
||||||
struct test_params {
|
struct test_params {
|
||||||
method_provider client_meth;
|
method_provider client_meth;
|
||||||
@ -55784,52 +55793,26 @@ static int test_wolfSSL_dtls_fragments(void)
|
|||||||
printf(testingFmt, "test_wolfSSL_dtls_fragments");
|
printf(testingFmt, "test_wolfSSL_dtls_fragments");
|
||||||
|
|
||||||
for (i = 0; i < sizeof(params)/sizeof(*params); i++) {
|
for (i = 0; i < sizeof(params)/sizeof(*params); i++) {
|
||||||
XMEMSET(&client_args, 0, sizeof(func_args));
|
|
||||||
XMEMSET(&server_args, 0, sizeof(func_args));
|
|
||||||
XMEMSET(&func_cb_client, 0, sizeof(callback_functions));
|
XMEMSET(&func_cb_client, 0, sizeof(callback_functions));
|
||||||
XMEMSET(&func_cb_server, 0, sizeof(callback_functions));
|
XMEMSET(&func_cb_server, 0, sizeof(callback_functions));
|
||||||
|
|
||||||
#ifdef WOLFSSL_TIRTOS
|
|
||||||
fdOpenSession(Task_self());
|
|
||||||
#endif
|
|
||||||
|
|
||||||
StartTCP();
|
|
||||||
InitTcpReady(&ready);
|
|
||||||
|
|
||||||
#if defined(USE_WINDOWS_API)
|
|
||||||
/* use RNG to get random port if using windows */
|
|
||||||
ready.port = GetRandomPort();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
server_args.signal = &ready;
|
|
||||||
server_args.callbacks = &func_cb_server;
|
|
||||||
client_args.signal = &ready;
|
|
||||||
client_args.callbacks = &func_cb_client;
|
|
||||||
|
|
||||||
func_cb_client.doUdp = func_cb_server.doUdp = 1;
|
func_cb_client.doUdp = func_cb_server.doUdp = 1;
|
||||||
func_cb_server.method = params[i].server_meth;
|
func_cb_server.method = params[i].server_meth;
|
||||||
func_cb_client.method = params[i].client_meth;
|
func_cb_client.method = params[i].client_meth;
|
||||||
func_cb_client.ssl_ready = params[i].spammer;
|
func_cb_client.ssl_ready = params[i].spammer;
|
||||||
|
|
||||||
start_thread(test_server_nofail, &server_args, &serverThread);
|
test_wolfSSL_client_server_nofail(&func_cb_client, &func_cb_server);
|
||||||
wait_tcp_ready(&server_args);
|
|
||||||
test_client_nofail(&client_args, NULL);
|
AssertFalse(func_cb_client.return_code);
|
||||||
join_thread(serverThread);
|
AssertFalse(func_cb_server.return_code);
|
||||||
|
|
||||||
AssertFalse(client_args.return_code);
|
|
||||||
AssertFalse(server_args.return_code);
|
|
||||||
/* The socket should be closed by the server resulting in a
|
/* The socket should be closed by the server resulting in a
|
||||||
* socket error */
|
* socket error */
|
||||||
AssertIntEQ(func_cb_client.last_err, SOCKET_ERROR_E);
|
AssertIntEQ(func_cb_client.last_err, SOCKET_ERROR_E);
|
||||||
/* Check the server returned an error indicating the msg buffer
|
/* Check the server returned an error indicating the msg buffer
|
||||||
* was full */
|
* was full */
|
||||||
AssertIntEQ(func_cb_server.last_err, DTLS_TOO_MANY_FRAGMENTS_E);
|
AssertIntEQ(func_cb_server.last_err, DTLS_TOO_MANY_FRAGMENTS_E);
|
||||||
|
|
||||||
FreeTcpReady(&ready);
|
|
||||||
|
|
||||||
#ifdef WOLFSSL_TIRTOS
|
|
||||||
fdOpenSession(Task_self());
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
printf(resultFmt, passed);
|
printf(resultFmt, passed);
|
||||||
@ -55842,6 +55825,206 @@ static int test_wolfSSL_dtls_fragments(void) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(WOLFSSL_DTLS13) && !defined(WOLFSSL_TLS13_IGNORE_AEAD_LIMITS)
|
||||||
|
static byte test_AEAD_fail_decryption = 0;
|
||||||
|
static byte test_AEAD_seq_num = 0;
|
||||||
|
static byte test_AEAD_done = 0;
|
||||||
|
|
||||||
|
static int test_AEAD_cbiorecv(WOLFSSL *ssl, char *buf, int sz, void *ctx)
|
||||||
|
{
|
||||||
|
int ret = recv(wolfSSL_get_fd(ssl), buf, sz, 0);
|
||||||
|
if (ret > 0) {
|
||||||
|
if (test_AEAD_fail_decryption) {
|
||||||
|
/* Modify the packet to trigger a decryption failure */
|
||||||
|
buf[ret/2] ^= 0xFF;
|
||||||
|
if (test_AEAD_fail_decryption == 1)
|
||||||
|
test_AEAD_fail_decryption = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(void)ctx;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_AEAD_get_limits(WOLFSSL* ssl, w64wrapper* hardLimit,
|
||||||
|
w64wrapper* keyUpdateLimit, w64wrapper* sendLimit)
|
||||||
|
{
|
||||||
|
if (sendLimit)
|
||||||
|
w64Zero(sendLimit);
|
||||||
|
switch (ssl->specs.bulk_cipher_algorithm) {
|
||||||
|
case wolfssl_aes_gcm:
|
||||||
|
if (sendLimit)
|
||||||
|
*sendLimit = AEAD_AES_LIMIT;
|
||||||
|
FALL_THROUGH;
|
||||||
|
case wolfssl_chacha:
|
||||||
|
if (hardLimit)
|
||||||
|
*hardLimit = DTLS_AEAD_AES_GCM_CHACHA_FAIL_LIMIT;
|
||||||
|
if (keyUpdateLimit)
|
||||||
|
*keyUpdateLimit = DTLS_AEAD_AES_GCM_CHACHA_FAIL_KU_LIMIT;
|
||||||
|
break;
|
||||||
|
case wolfssl_aes_ccm:
|
||||||
|
if (sendLimit)
|
||||||
|
*sendLimit = DTLS_AEAD_AES_CCM_LIMIT;
|
||||||
|
if (ssl->specs.aead_mac_size == AES_CCM_8_AUTH_SZ) {
|
||||||
|
if (hardLimit)
|
||||||
|
*hardLimit = DTLS_AEAD_AES_CCM_8_FAIL_LIMIT;
|
||||||
|
if (keyUpdateLimit)
|
||||||
|
*keyUpdateLimit = DTLS_AEAD_AES_CCM_8_FAIL_KU_LIMIT;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (hardLimit)
|
||||||
|
*hardLimit = DTLS_AEAD_AES_CCM_FAIL_LIMIT;
|
||||||
|
if (keyUpdateLimit)
|
||||||
|
*keyUpdateLimit = DTLS_AEAD_AES_CCM_FAIL_KU_LIMIT;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "Unrecognized bulk cipher");
|
||||||
|
AssertFalse(1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_AEAD_limit_client(WOLFSSL* ssl)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
int i;
|
||||||
|
int didReKey = 0;
|
||||||
|
char msgBuf[20];
|
||||||
|
w64wrapper hardLimit;
|
||||||
|
w64wrapper keyUpdateLimit;
|
||||||
|
w64wrapper counter;
|
||||||
|
w64wrapper sendLimit;
|
||||||
|
|
||||||
|
test_AEAD_get_limits(ssl, &hardLimit, &keyUpdateLimit, &sendLimit);
|
||||||
|
|
||||||
|
w64Zero(&counter);
|
||||||
|
AssertTrue(w64Equal(Dtls13GetEpoch(ssl, ssl->dtls13Epoch)->dropCount, counter));
|
||||||
|
|
||||||
|
wolfSSL_SSLSetIORecv(ssl, test_AEAD_cbiorecv);
|
||||||
|
|
||||||
|
for (i = 0; i < 10; i++) {
|
||||||
|
/* Test some failed decryptions */
|
||||||
|
test_AEAD_fail_decryption = 1;
|
||||||
|
w64Increment(&counter);
|
||||||
|
ret = wolfSSL_read(ssl, msgBuf, sizeof(msgBuf));
|
||||||
|
/* Should succeed since decryption failures are dropped */
|
||||||
|
AssertIntGT(ret, 0);
|
||||||
|
AssertTrue(w64Equal(Dtls13GetEpoch(ssl, ssl->dtls13PeerEpoch)->dropCount, counter));
|
||||||
|
}
|
||||||
|
|
||||||
|
test_AEAD_fail_decryption = 1;
|
||||||
|
Dtls13GetEpoch(ssl, ssl->dtls13PeerEpoch)->dropCount = keyUpdateLimit;
|
||||||
|
w64Increment(&Dtls13GetEpoch(ssl, ssl->dtls13PeerEpoch)->dropCount);
|
||||||
|
/* 100 read calls should be enough to complete the key update */
|
||||||
|
w64Zero(&counter);
|
||||||
|
for (i = 0; i < 100; i++) {
|
||||||
|
/* Key update should be sent and negotiated */
|
||||||
|
ret = wolfSSL_read(ssl, msgBuf, sizeof(msgBuf));
|
||||||
|
AssertIntGT(ret, 0);
|
||||||
|
/* Epoch after one key update is 4 */
|
||||||
|
if (w64Equal(ssl->dtls13PeerEpoch, w64From32(0, 4)) &&
|
||||||
|
w64Equal(Dtls13GetEpoch(ssl, ssl->dtls13PeerEpoch)->dropCount, counter)) {
|
||||||
|
didReKey = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AssertTrue(didReKey);
|
||||||
|
|
||||||
|
if (!w64IsZero(sendLimit)) {
|
||||||
|
/* Test the sending limit for AEAD ciphers */
|
||||||
|
Dtls13GetEpoch(ssl, ssl->dtls13Epoch)->nextSeqNumber = sendLimit;
|
||||||
|
test_AEAD_seq_num = 1;
|
||||||
|
ret = wolfSSL_write(ssl, msgBuf, sizeof(msgBuf));
|
||||||
|
AssertIntGT(ret, 0);
|
||||||
|
didReKey = 0;
|
||||||
|
w64Zero(&counter);
|
||||||
|
/* 100 read calls should be enough to complete the key update */
|
||||||
|
for (i = 0; i < 100; i++) {
|
||||||
|
/* Key update should be sent and negotiated */
|
||||||
|
ret = wolfSSL_read(ssl, msgBuf, sizeof(msgBuf));
|
||||||
|
AssertIntGT(ret, 0);
|
||||||
|
/* Epoch after another key update is 5 */
|
||||||
|
if (w64Equal(ssl->dtls13Epoch, w64From32(0, 5)) &&
|
||||||
|
w64Equal(Dtls13GetEpoch(ssl, ssl->dtls13Epoch)->dropCount, counter)) {
|
||||||
|
didReKey = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AssertTrue(didReKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
test_AEAD_fail_decryption = 2;
|
||||||
|
Dtls13GetEpoch(ssl, ssl->dtls13PeerEpoch)->dropCount = hardLimit;
|
||||||
|
w64Decrement(&Dtls13GetEpoch(ssl, ssl->dtls13PeerEpoch)->dropCount);
|
||||||
|
/* Connection should fail with a DECRYPT_ERROR */
|
||||||
|
ret = wolfSSL_read(ssl, msgBuf, sizeof(msgBuf));
|
||||||
|
AssertIntEQ(ret, WOLFSSL_FATAL_ERROR);
|
||||||
|
AssertIntEQ(wolfSSL_get_error(ssl, ret), DECRYPT_ERROR);
|
||||||
|
|
||||||
|
test_AEAD_done = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int counter = 0;
|
||||||
|
static void test_AEAD_limit_server(WOLFSSL* ssl)
|
||||||
|
{
|
||||||
|
char msgBuf[] = "Sending data";
|
||||||
|
int ret = WOLFSSL_SUCCESS;
|
||||||
|
w64wrapper sendLimit;
|
||||||
|
SOCKET_T fd = wolfSSL_get_fd(ssl);
|
||||||
|
struct timespec delay;
|
||||||
|
XMEMSET(&delay, 0, sizeof(delay));
|
||||||
|
delay.tv_nsec = 100000000; /* wait 0.1 seconds */
|
||||||
|
tcp_set_nonblocking(&fd); /* So that read doesn't block */
|
||||||
|
test_AEAD_get_limits(ssl, NULL, NULL, &sendLimit);
|
||||||
|
while (!test_AEAD_done && ret > 0) {
|
||||||
|
counter++;
|
||||||
|
if (test_AEAD_seq_num) {
|
||||||
|
/* We need to update the seq number so that we can understand the
|
||||||
|
* peer. Otherwise we will incorrectly interpret the seq number. */
|
||||||
|
Dtls13Epoch* e = Dtls13GetEpoch(ssl, ssl->dtls13PeerEpoch);
|
||||||
|
AssertNotNull(e);
|
||||||
|
e->nextPeerSeqNumber = sendLimit;
|
||||||
|
test_AEAD_seq_num = 0;
|
||||||
|
}
|
||||||
|
(void)wolfSSL_read(ssl, msgBuf, sizeof(msgBuf));
|
||||||
|
ret = wolfSSL_write(ssl, msgBuf, sizeof(msgBuf));
|
||||||
|
nanosleep(&delay, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int test_wolfSSL_dtls_AEAD_limit(void)
|
||||||
|
{
|
||||||
|
callback_functions func_cb_client;
|
||||||
|
callback_functions func_cb_server;
|
||||||
|
XMEMSET(&func_cb_client, 0, sizeof(callback_functions));
|
||||||
|
XMEMSET(&func_cb_server, 0, sizeof(callback_functions));
|
||||||
|
|
||||||
|
printf(testingFmt, "test_wolfSSL_dtls_AEAD_limit");
|
||||||
|
|
||||||
|
func_cb_client.doUdp = func_cb_server.doUdp = 1;
|
||||||
|
func_cb_server.method = wolfDTLSv1_3_server_method;
|
||||||
|
func_cb_client.method = wolfDTLSv1_3_client_method;
|
||||||
|
func_cb_server.on_result = test_AEAD_limit_server;
|
||||||
|
func_cb_client.on_result = test_AEAD_limit_client;
|
||||||
|
|
||||||
|
test_wolfSSL_client_server_nofail(&func_cb_client, &func_cb_server);
|
||||||
|
|
||||||
|
if (!func_cb_client.return_code)
|
||||||
|
return -1;
|
||||||
|
if (!func_cb_server.return_code)
|
||||||
|
return -2;
|
||||||
|
|
||||||
|
printf(resultFmt, passed);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static int test_wolfSSL_dtls_AEAD_limit(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#if !defined(NO_RSA) && !defined(NO_SHA) && !defined(NO_FILESYSTEM) && \
|
#if !defined(NO_RSA) && !defined(NO_SHA) && !defined(NO_FILESYSTEM) && \
|
||||||
!defined(NO_CERTS) && (!defined(NO_WOLFSSL_CLIENT) || \
|
!defined(NO_CERTS) && (!defined(NO_WOLFSSL_CLIENT) || \
|
||||||
!defined(WOLFSSL_NO_CLIENT_AUTH))
|
!defined(WOLFSSL_NO_CLIENT_AUTH))
|
||||||
@ -58553,6 +58736,7 @@ TEST_CASE testCases[] = {
|
|||||||
TEST_DECL(test_wolfSSL_either_side),
|
TEST_DECL(test_wolfSSL_either_side),
|
||||||
TEST_DECL(test_wolfSSL_DTLS_either_side),
|
TEST_DECL(test_wolfSSL_DTLS_either_side),
|
||||||
TEST_DECL(test_wolfSSL_dtls_fragments),
|
TEST_DECL(test_wolfSSL_dtls_fragments),
|
||||||
|
TEST_DECL(test_wolfSSL_dtls_AEAD_limit),
|
||||||
TEST_DECL(test_generate_cookie),
|
TEST_DECL(test_generate_cookie),
|
||||||
TEST_DECL(test_wolfSSL_X509_STORE_set_flags),
|
TEST_DECL(test_wolfSSL_X509_STORE_set_flags),
|
||||||
TEST_DECL(test_wolfSSL_X509_LOOKUP_load_file),
|
TEST_DECL(test_wolfSSL_X509_LOOKUP_load_file),
|
||||||
|
@ -1274,6 +1274,30 @@ enum {
|
|||||||
#define TLS13_MAX_TICKET_AGE (7*24*60*60)
|
#define TLS13_MAX_TICKET_AGE (7*24*60*60)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* Limit is 2^24.5
|
||||||
|
* https://www.rfc-editor.org/rfc/rfc8446#section-5.5
|
||||||
|
* Without the fraction is 23726566 (0x016A09E6) */
|
||||||
|
#define AEAD_AES_LIMIT w64From32(0x016A, 0x09E6)
|
||||||
|
/* Limit is 2^23
|
||||||
|
* https://www.rfc-editor.org/rfc/rfc9147.html#name-integrity-limits */
|
||||||
|
#define DTLS_AEAD_AES_CCM_LIMIT w64From32(0, 1 << 22)
|
||||||
|
|
||||||
|
/* Limit is 2^36
|
||||||
|
* https://www.rfc-editor.org/rfc/rfc9147.html#name-aead-limits */
|
||||||
|
#define DTLS_AEAD_AES_GCM_CHACHA_FAIL_LIMIT w64From32(1 << 3, 0)
|
||||||
|
#define DTLS_AEAD_AES_GCM_CHACHA_FAIL_KU_LIMIT w64From32(1 << 2, 0)
|
||||||
|
/* Limit is 2^7
|
||||||
|
* https://www.rfc-editor.org/rfc/rfc9147.html#name-limits-for-aead_aes_128_ccm */
|
||||||
|
#define DTLS_AEAD_AES_CCM_8_FAIL_LIMIT w64From32(0, 1 << 6)
|
||||||
|
#define DTLS_AEAD_AES_CCM_8_FAIL_KU_LIMIT w64From32(0, 1 << 5)
|
||||||
|
/* Limit is 2^23.5.
|
||||||
|
* https://www.rfc-editor.org/rfc/rfc9147.html#name-integrity-limits
|
||||||
|
* Without the fraction is 11863283 (0x00B504F3)
|
||||||
|
* Half of this value is 5931641 (0x005A8279) */
|
||||||
|
#define DTLS_AEAD_AES_CCM_FAIL_LIMIT w64From32(0x00B5, 0x04F3)
|
||||||
|
#define DTLS_AEAD_AES_CCM_FAIL_KU_LIMIT w64From32(0x005A, 0x8279)
|
||||||
|
|
||||||
enum Misc {
|
enum Misc {
|
||||||
CIPHER_BYTE = 0x00, /* Default ciphers */
|
CIPHER_BYTE = 0x00, /* Default ciphers */
|
||||||
ECC_BYTE = 0xC0, /* ECC first cipher suite byte */
|
ECC_BYTE = 0xC0, /* ECC first cipher suite byte */
|
||||||
@ -4035,6 +4059,10 @@ typedef struct Options {
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#ifdef WOLFSSL_DTLS
|
#ifdef WOLFSSL_DTLS
|
||||||
|
#ifdef HAVE_SECURE_RENEGOTIATION
|
||||||
|
word16 dtlsDoSCR:1; /* Enough packets were dropped. We
|
||||||
|
* need to re-key. */
|
||||||
|
#endif
|
||||||
word16 dtlsUseNonblock:1; /* are we using nonblocking socket */
|
word16 dtlsUseNonblock:1; /* are we using nonblocking socket */
|
||||||
word16 dtlsHsRetain:1; /* DTLS retaining HS data */
|
word16 dtlsHsRetain:1; /* DTLS retaining HS data */
|
||||||
word16 haveMcast:1; /* using multicast ? */
|
word16 haveMcast:1; /* using multicast ? */
|
||||||
@ -4632,6 +4660,10 @@ typedef struct Dtls13Epoch {
|
|||||||
w64wrapper nextSeqNumber;
|
w64wrapper nextSeqNumber;
|
||||||
w64wrapper nextPeerSeqNumber;
|
w64wrapper nextPeerSeqNumber;
|
||||||
|
|
||||||
|
#ifndef WOLFSSL_TLS13_IGNORE_AEAD_LIMITS
|
||||||
|
w64wrapper dropCount; /* Amount of records that failed decryption */
|
||||||
|
#endif
|
||||||
|
|
||||||
word32 window[WOLFSSL_DTLS_WINDOW_WORDS];
|
word32 window[WOLFSSL_DTLS_WINDOW_WORDS];
|
||||||
|
|
||||||
/* key material for the epoch */
|
/* key material for the epoch */
|
||||||
@ -4687,10 +4719,10 @@ typedef struct Dtls13Rtx {
|
|||||||
Dtls13RtxRecord *rtxRecords;
|
Dtls13RtxRecord *rtxRecords;
|
||||||
Dtls13RtxRecord **rtxRecordTailPtr;
|
Dtls13RtxRecord **rtxRecordTailPtr;
|
||||||
Dtls13RecordNumber *seenRecords;
|
Dtls13RecordNumber *seenRecords;
|
||||||
|
word32 lastRtx;
|
||||||
byte triggeredRtxs;
|
byte triggeredRtxs;
|
||||||
byte sendAcks:1;
|
byte sendAcks:1;
|
||||||
byte retransmit:1;
|
byte retransmit:1;
|
||||||
word32 lastRtx;
|
|
||||||
} Dtls13Rtx;
|
} Dtls13Rtx;
|
||||||
|
|
||||||
#endif /* WOLFSSL_DTLS13 */
|
#endif /* WOLFSSL_DTLS13 */
|
||||||
@ -4910,6 +4942,7 @@ struct WOLFSSL {
|
|||||||
Dtls13Epoch *dtls13DecryptEpoch;
|
Dtls13Epoch *dtls13DecryptEpoch;
|
||||||
w64wrapper dtls13Epoch;
|
w64wrapper dtls13Epoch;
|
||||||
w64wrapper dtls13PeerEpoch;
|
w64wrapper dtls13PeerEpoch;
|
||||||
|
w64wrapper dtls13InvalidateBefore;
|
||||||
byte dtls13CurRL[DTLS_RECVD_RL_HEADER_MAX_SZ];
|
byte dtls13CurRL[DTLS_RECVD_RL_HEADER_MAX_SZ];
|
||||||
word16 dtls13CurRlLength;
|
word16 dtls13CurRlLength;
|
||||||
|
|
||||||
@ -4919,6 +4952,7 @@ struct WOLFSSL {
|
|||||||
byte dtls13SendingAckOrRtx:1;
|
byte dtls13SendingAckOrRtx:1;
|
||||||
byte dtls13FastTimeout:1;
|
byte dtls13FastTimeout:1;
|
||||||
byte dtls13WaitKeyUpdateAck:1;
|
byte dtls13WaitKeyUpdateAck:1;
|
||||||
|
byte dtls13DoKeyUpdate:1;
|
||||||
word32 dtls13MessageLength;
|
word32 dtls13MessageLength;
|
||||||
word32 dtls13FragOffset;
|
word32 dtls13FragOffset;
|
||||||
byte dtls13FragHandshakeType;
|
byte dtls13FragHandshakeType;
|
||||||
@ -5666,6 +5700,7 @@ WOLFSSL_LOCAL int BuildMessage(WOLFSSL* ssl, byte* output, int outSz,
|
|||||||
/* Use WOLFSSL_API to use this function in tests/api.c */
|
/* Use WOLFSSL_API to use this function in tests/api.c */
|
||||||
WOLFSSL_API int BuildTls13Message(WOLFSSL* ssl, byte* output, int outSz, const byte* input,
|
WOLFSSL_API int BuildTls13Message(WOLFSSL* ssl, byte* output, int outSz, const byte* input,
|
||||||
int inSz, int type, int hashOutput, int sizeOnly, int asyncOkay);
|
int inSz, int type, int hashOutput, int sizeOnly, int asyncOkay);
|
||||||
|
WOLFSSL_LOCAL int Tls13UpdateKeys(WOLFSSL* ssl);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
WOLFSSL_LOCAL int AllocKey(WOLFSSL* ssl, int type, void** pKey);
|
WOLFSSL_LOCAL int AllocKey(WOLFSSL* ssl, int type, void** pKey);
|
||||||
@ -5726,8 +5761,11 @@ WOLFSSL_API int wolfSSL_DtlsUpdateWindow(word16 cur_hi, word32 cur_lo,
|
|||||||
|
|
||||||
#ifdef WOLFSSL_DTLS13
|
#ifdef WOLFSSL_DTLS13
|
||||||
|
|
||||||
WOLFSSL_LOCAL struct Dtls13Epoch* Dtls13GetEpoch(WOLFSSL* ssl,
|
/* Use WOLFSSL_API to use this function in tests/api.c */
|
||||||
|
WOLFSSL_API struct Dtls13Epoch* Dtls13GetEpoch(WOLFSSL* ssl,
|
||||||
w64wrapper epochNumber);
|
w64wrapper epochNumber);
|
||||||
|
WOLFSSL_LOCAL void Dtls13SetOlderEpochSide(WOLFSSL* ssl, w64wrapper epochNumber,
|
||||||
|
int side);
|
||||||
WOLFSSL_LOCAL int Dtls13NewEpoch(WOLFSSL* ssl, w64wrapper epochNumber,
|
WOLFSSL_LOCAL int Dtls13NewEpoch(WOLFSSL* ssl, w64wrapper epochNumber,
|
||||||
int side);
|
int side);
|
||||||
WOLFSSL_LOCAL int Dtls13SetEpochKeys(WOLFSSL* ssl, w64wrapper epochNumber,
|
WOLFSSL_LOCAL int Dtls13SetEpochKeys(WOLFSSL* ssl, w64wrapper epochNumber,
|
||||||
@ -5779,6 +5817,7 @@ WOLFSSL_LOCAL int Dtls13HashHandshake(WOLFSSL* ssl, const byte* output,
|
|||||||
WOLFSSL_LOCAL void Dtls13FreeFsmResources(WOLFSSL* ssl);
|
WOLFSSL_LOCAL void Dtls13FreeFsmResources(WOLFSSL* ssl);
|
||||||
WOLFSSL_LOCAL int Dtls13RtxTimeout(WOLFSSL* ssl);
|
WOLFSSL_LOCAL int Dtls13RtxTimeout(WOLFSSL* ssl);
|
||||||
WOLFSSL_LOCAL int Dtls13ProcessBufferedMessages(WOLFSSL* ssl);
|
WOLFSSL_LOCAL int Dtls13ProcessBufferedMessages(WOLFSSL* ssl);
|
||||||
|
WOLFSSL_LOCAL int Dtls13CheckAEADFailLimit(WOLFSSL* ssl);
|
||||||
#endif /* WOLFSSL_DTLS13 */
|
#endif /* WOLFSSL_DTLS13 */
|
||||||
|
|
||||||
#ifdef WOLFSSL_STATIC_EPHEMERAL
|
#ifdef WOLFSSL_STATIC_EPHEMERAL
|
||||||
|
@ -657,6 +657,9 @@ typedef THREAD_RETURN WOLFSSL_THREAD THREAD_FUNC(void*);
|
|||||||
void start_thread(THREAD_FUNC fun, func_args* args, THREAD_TYPE* thread);
|
void start_thread(THREAD_FUNC fun, func_args* args, THREAD_TYPE* thread);
|
||||||
void join_thread(THREAD_TYPE thread);
|
void join_thread(THREAD_TYPE thread);
|
||||||
|
|
||||||
|
void test_wolfSSL_client_server_nofail(callback_functions* client_cb,
|
||||||
|
callback_functions* server_cb);
|
||||||
|
|
||||||
/* wolfSSL */
|
/* wolfSSL */
|
||||||
#ifndef TEST_IPV6
|
#ifndef TEST_IPV6
|
||||||
static const char* const wolfSSLIP = "127.0.0.1";
|
static const char* const wolfSSLIP = "127.0.0.1";
|
||||||
|
@ -130,6 +130,24 @@ WOLFSSL_LOCAL void ctMaskCopy(byte mask, byte* dst, byte* src, word16 size);
|
|||||||
WOLFSSL_LOCAL word32 MakeWordFromHash(const byte* hashID);
|
WOLFSSL_LOCAL word32 MakeWordFromHash(const byte* hashID);
|
||||||
WOLFSSL_LOCAL word32 HashObject(const byte* o, word32 len, int* error);
|
WOLFSSL_LOCAL word32 HashObject(const byte* o, word32 len, int* error);
|
||||||
|
|
||||||
|
WOLFSSL_LOCAL void w64Increment(w64wrapper *n);
|
||||||
|
WOLFSSL_LOCAL void w64Decrement(w64wrapper *n);
|
||||||
|
WOLFSSL_LOCAL byte w64Equal(w64wrapper a, w64wrapper b);
|
||||||
|
WOLFSSL_LOCAL word32 w64GetLow32(w64wrapper n);
|
||||||
|
WOLFSSL_LOCAL word32 w64GetHigh32(w64wrapper n);
|
||||||
|
WOLFSSL_LOCAL void w64SetLow32(w64wrapper *n, word32 low);
|
||||||
|
WOLFSSL_LOCAL w64wrapper w64Add32(w64wrapper a, word32 b, byte *wrap);
|
||||||
|
WOLFSSL_LOCAL w64wrapper w64Sub32(w64wrapper a, word32 b, byte *wrap);
|
||||||
|
WOLFSSL_LOCAL byte w64GT(w64wrapper a, w64wrapper b);
|
||||||
|
WOLFSSL_LOCAL byte w64IsZero(w64wrapper a);
|
||||||
|
WOLFSSL_LOCAL void c64toa(const w64wrapper *a, byte *out);
|
||||||
|
WOLFSSL_LOCAL void ato64(const byte *in, w64wrapper *w64);
|
||||||
|
WOLFSSL_LOCAL w64wrapper w64From32(word32 hi, word32 lo);
|
||||||
|
WOLFSSL_LOCAL byte w64GTE(w64wrapper a, w64wrapper b);
|
||||||
|
WOLFSSL_LOCAL byte w64LT(w64wrapper a, w64wrapper b);
|
||||||
|
WOLFSSL_LOCAL w64wrapper w64Sub(w64wrapper a, w64wrapper b);
|
||||||
|
WOLFSSL_LOCAL void w64Zero(w64wrapper *a);
|
||||||
|
|
||||||
#endif /* NO_INLINE */
|
#endif /* NO_INLINE */
|
||||||
|
|
||||||
|
|
||||||
|
@ -2771,8 +2771,9 @@ extern void uITRON4_free(void *p) ;
|
|||||||
#define NO_SESSION_CACHE_REF
|
#define NO_SESSION_CACHE_REF
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* DTLS v1.3 requires 64-bit number wrappers */
|
/* (D)TLS v1.3 requires 64-bit number wrappers */
|
||||||
#if defined(WOLFSSL_DTLS13) && !defined(WOLFSSL_W64_WRAPPER)
|
#if defined(WOLFSSL_TLS13) || defined(WOLFSSL_DTLS_DROP_STATS)
|
||||||
|
#undef WOLFSSL_W64_WRAPPER
|
||||||
#define WOLFSSL_W64_WRAPPER
|
#define WOLFSSL_W64_WRAPPER
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user