diff --git a/.github/workflows/os-check.yml b/.github/workflows/os-check.yml index 8b337c1f0b..154fa04035 100644 --- a/.github/workflows/os-check.yml +++ b/.github/workflows/os-check.yml @@ -38,6 +38,8 @@ jobs: '--enable-all --enable-dtls13 --enable-dtls-frag-ch', '--enable-dtls --enable-dtls13 --enable-dtls-frag-ch --enable-dtls-mtu', + '--enable-dtls --enable-dtlscid --enable-dtls13 --enable-secure-renegotiation + --enable-psk --enable-aesccm --enable-nullcipher CPPFLAGS=-DWOLFSSL_STATIC_RSA', ] name: make check runs-on: ${{ matrix.os }} diff --git a/examples/client/client.c b/examples/client/client.c index b8adcc1924..89c0f975bc 100644 --- a/examples/client/client.c +++ b/examples/client/client.c @@ -4184,10 +4184,7 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) printf("CID extension was negotiated\n"); ret = wolfSSL_dtls_cid_get_tx_size(ssl, &receivedCIDSz); - if (ret != WOLFSSL_SUCCESS) - err_sys("Can't get negotiated DTLS CID size\n"); - - if (receivedCIDSz > 0) { + if (ret == WOLFSSL_SUCCESS && receivedCIDSz > 0) { ret = wolfSSL_dtls_cid_get_tx(ssl, receivedCID, DTLS_CID_BUFFER_SIZE - 1); if (ret != WOLFSSL_SUCCESS) diff --git a/examples/server/server.c b/examples/server/server.c index 2f42a909e3..bc3e1509f7 100644 --- a/examples/server/server.c +++ b/examples/server/server.c @@ -3595,10 +3595,7 @@ THREAD_RETURN WOLFSSL_THREAD server_test(void* args) unsigned int receivedCIDSz; printf("CID extension was negotiated\n"); ret = wolfSSL_dtls_cid_get_tx_size(ssl, &receivedCIDSz); - if (ret != WOLFSSL_SUCCESS) - err_sys("Can't get negotiated DTLS CID size\n"); - - if (receivedCIDSz > 0) { + if (ret == WOLFSSL_SUCCESS && receivedCIDSz > 0) { ret = wolfSSL_dtls_cid_get_tx(ssl, receivedCID, DTLS_CID_BUFFER_SIZE - 1); if (ret != WOLFSSL_SUCCESS) diff --git a/src/dtls.c b/src/dtls.c index 1bdb7ce464..c30066be23 100644 --- a/src/dtls.c +++ b/src/dtls.c @@ -1038,22 +1038,6 @@ int DoClientHelloStateless(WOLFSSL* ssl, const byte* input, word32 helloSz, #if defined(WOLFSSL_DTLS_CID) -typedef struct ConnectionID { - byte length; -/* Ignore "nonstandard extension used : zero-sized array in struct/union" - * MSVC warning */ -#ifdef _MSC_VER -#pragma warning(disable: 4200) -#endif - byte id[]; -} ConnectionID; - -typedef struct CIDInfo { - ConnectionID* tx; - ConnectionID* rx; - byte negotiated : 1; -} CIDInfo; - static ConnectionID* DtlsCidNew(const byte* cid, byte size, void* heap) { ConnectionID* ret; @@ -1079,7 +1063,7 @@ static int DtlsCidGetSize(WOLFSSL* ssl, unsigned int* size, int rx) ConnectionID* id; CIDInfo* info; - if (ssl == NULL || size == NULL) + if (ssl == NULL) return BAD_FUNC_ARG; info = DtlsCidGetInfo(ssl); @@ -1087,12 +1071,14 @@ static int DtlsCidGetSize(WOLFSSL* ssl, unsigned int* size, int rx) return WOLFSSL_FAILURE; id = rx ? info->rx : info->tx; - if (id == NULL) { - *size = 0; - return WOLFSSL_SUCCESS; + if (id == NULL || id->length == 0) { + if (size != NULL) + *size = 0; + return WOLFSSL_FAILURE; } - *size = id->length; + if (size != NULL) + *size = id->length; return WOLFSSL_SUCCESS; } @@ -1231,9 +1217,8 @@ int TLSX_ConnectionID_Use(WOLFSSL* ssl) int TLSX_ConnectionID_Parse(WOLFSSL* ssl, const byte* input, word16 length, byte isRequest) { - ConnectionID* id; CIDInfo* info; - byte cidSize; + byte cidSz; TLSX* ext; ext = TLSX_Find(ssl->extensions, TLSX_CONNECTION_ID); @@ -1254,31 +1239,41 @@ int TLSX_ConnectionID_Parse(WOLFSSL* ssl, const byte* input, word16 length, return BAD_STATE_E; /* it may happen if we process two ClientHello because the server sent an - * HRR request */ + * HRR/HVR request */ if (info->tx != NULL) { if (ssl->options.side != WOLFSSL_SERVER_END && - ssl->options.serverState != SERVER_HELLO_RETRY_REQUEST_COMPLETE) + ssl->options.serverState != SERVER_HELLO_RETRY_REQUEST_COMPLETE && + !IsSCR(ssl)) return BAD_STATE_E; - XFREE(info->tx, ssl->heap, DYNAMIC_TYPE_TLSX); - info->tx = NULL; + if (!info->negotiated) { + XFREE(info->tx, ssl->heap, DYNAMIC_TYPE_TLSX); + info->tx = NULL; + } } if (length < OPAQUE8_LEN) return BUFFER_ERROR; - cidSize = *input; - if (cidSize + OPAQUE8_LEN > length) + cidSz = *input; + if (cidSz + OPAQUE8_LEN > length) return BUFFER_ERROR; - if (cidSize > 0) { - id = (ConnectionID*)XMALLOC(sizeof(*id) + cidSize, ssl->heap, - DYNAMIC_TYPE_TLSX); - if (id == NULL) - return MEMORY_ERROR; - XMEMCPY(id->id, input + OPAQUE8_LEN, cidSize); - id->length = cidSize; - info->tx = id; + if (cidSz > 0) { + if (!info->negotiated) { + ConnectionID* id = (ConnectionID*)XMALLOC(sizeof(*id) + cidSz, + ssl->heap, DYNAMIC_TYPE_TLSX); + if (id == NULL) + return MEMORY_ERROR; + XMEMCPY(id->id, input + OPAQUE8_LEN, cidSz); + id->length = cidSz; + info->tx = id; + } + else { + /* For now we don't support changing the CID on a rehandshake */ + if (XMEMCMP(info->tx->id, input + OPAQUE8_LEN, cidSz) != 0) + return DTLS_CID_ERROR; + } } info->negotiated = 1; @@ -1317,10 +1312,6 @@ int wolfSSL_dtls_cid_use(WOLFSSL* ssl) { int ret; - /* CID is supported on DTLSv1.3 only */ - if (!IsAtLeastTLSv1_3(ssl->version)) - return WOLFSSL_FAILURE; - ssl->options.useDtlsCID = 1; ret = TLSX_ConnectionID_Use(ssl); if (ret != 0) @@ -1345,8 +1336,11 @@ int wolfSSL_dtls_cid_set(WOLFSSL* ssl, unsigned char* cid, unsigned int size) if (cidInfo == NULL) return WOLFSSL_FAILURE; - XFREE(cidInfo->rx, ssl->heap, DYNAMIC_TYPE_TLSX); - cidInfo->rx = NULL; + if (cidInfo->rx != NULL) { + WOLFSSL_MSG("wolfSSL doesn't support changing the CID during a " + "connection"); + return WOLFSSL_FAILURE; + } /* empty CID */ if (size == 0) @@ -1384,6 +1378,11 @@ int wolfSSL_dtls_cid_get_tx(WOLFSSL* ssl, unsigned char* buf, return DtlsCidGet(ssl, buf, bufferSz, 0); } +int wolfSSL_dtls_cid_max_size(void) +{ + return DTLS_CID_MAX_SIZE; +} + #endif /* WOLFSSL_DTLS_CID */ #endif /* WOLFSSL_DTLS */ diff --git a/src/dtls13.c b/src/dtls13.c index c661dc94cc..31b3e53740 100644 --- a/src/dtls13.c +++ b/src/dtls13.c @@ -1076,23 +1076,23 @@ static byte Dtls13GetCidRxSize(WOLFSSL* ssl) static int Dtls13AddCID(WOLFSSL* ssl, byte* flags, byte* out, word16* idx) { - byte cidSize; + byte cidSz; int ret; if (!wolfSSL_dtls_cid_is_enabled(ssl)) return 0; - cidSize = Dtls13GetCidTxSize(ssl); + cidSz = Dtls13GetCidTxSize(ssl); /* no cid */ - if (cidSize == 0) + if (cidSz == 0) return 0; *flags |= DTLS13_CID_BIT; - /* we know that we have at least cidSize of space */ - ret = wolfSSL_dtls_cid_get_tx(ssl, out + *idx, cidSize); + /* we know that we have at least cidSz of space */ + ret = wolfSSL_dtls_cid_get_tx(ssl, out + *idx, cidSz); if (ret != WOLFSSL_SUCCESS) return ret; - *idx += cidSize; + *idx += cidSz; return 0; } diff --git a/src/internal.c b/src/internal.c index 2fc63753f6..d099876578 100644 --- a/src/internal.c +++ b/src/internal.c @@ -210,6 +210,8 @@ WOLFSSL_CALLBACKS needs LARGE_STATIC_BUFFERS, please add LARGE_STATIC_BUFFERS #endif #endif +int writeAeadAuthData(WOLFSSL* ssl, word16 sz, byte type, byte* additional, + byte dec, byte** seq, int verifyOrder); #ifdef WOLFSSL_DTLS static int _DtlsCheckWindow(WOLFSSL* ssl); @@ -2893,12 +2895,16 @@ void FreeCiphers(WOLFSSL* ssl) wc_Arc4Free(ssl->decrypt.arc4); XFREE(ssl->encrypt.arc4, ssl->heap, DYNAMIC_TYPE_CIPHER); XFREE(ssl->decrypt.arc4, ssl->heap, DYNAMIC_TYPE_CIPHER); + ssl->encrypt.arc4 = NULL; + ssl->decrypt.arc4 = NULL; #endif #ifdef BUILD_DES3 wc_Des3Free(ssl->encrypt.des3); wc_Des3Free(ssl->decrypt.des3); XFREE(ssl->encrypt.des3, ssl->heap, DYNAMIC_TYPE_CIPHER); XFREE(ssl->decrypt.des3, ssl->heap, DYNAMIC_TYPE_CIPHER); + ssl->encrypt.des3 = NULL; + ssl->decrypt.des3 = NULL; #endif #if defined(BUILD_AES) || defined(BUILD_AESGCM) || defined(HAVE_ARIA) /* See: InitKeys() in keys.c on addition of BUILD_AESGCM check (enc->aes, dec->aes) */ @@ -2906,31 +2912,43 @@ void FreeCiphers(WOLFSSL* ssl) wc_AesFree(ssl->decrypt.aes); XFREE(ssl->encrypt.aes, ssl->heap, DYNAMIC_TYPE_CIPHER); XFREE(ssl->decrypt.aes, ssl->heap, DYNAMIC_TYPE_CIPHER); + ssl->encrypt.aes = NULL; + ssl->decrypt.aes = NULL; #endif #if defined(WOLFSSL_SM4_GCM) || defined(WOLFSSL_SM4_CCM) wc_Sm4Free(ssl->encrypt.sm4); wc_Sm4Free(ssl->decrypt.sm4); XFREE(ssl->encrypt.sm4, ssl->heap, DYNAMIC_TYPE_CIPHER); XFREE(ssl->decrypt.sm4, ssl->heap, DYNAMIC_TYPE_CIPHER); + ssl->encrypt.sm4 = NULL; + ssl->decrypt.sm4 = NULL; #endif #if (defined(BUILD_AESGCM) || defined(BUILD_AESCCM) || defined(HAVE_ARIA)) && \ !defined(WOLFSSL_NO_TLS12) - XFREE(ssl->decrypt.additional, ssl->heap, DYNAMIC_TYPE_CIPHER); XFREE(ssl->encrypt.additional, ssl->heap, DYNAMIC_TYPE_CIPHER); + XFREE(ssl->decrypt.additional, ssl->heap, DYNAMIC_TYPE_CIPHER); + ssl->encrypt.additional = NULL; + ssl->decrypt.additional = NULL; #endif #ifdef CIPHER_NONCE - XFREE(ssl->decrypt.nonce, ssl->heap, DYNAMIC_TYPE_CIPHER); XFREE(ssl->encrypt.nonce, ssl->heap, DYNAMIC_TYPE_CIPHER); + XFREE(ssl->decrypt.nonce, ssl->heap, DYNAMIC_TYPE_CIPHER); + ssl->encrypt.nonce = NULL; + ssl->decrypt.nonce = NULL; #endif #ifdef HAVE_ARIA wc_AriaFreeCrypt(ssl->encrypt.aria); wc_AriaFreeCrypt(ssl->decrypt.aria); XFREE(ssl->encrypt.aria, ssl->heap, DYNAMIC_TYPE_CIPHER); XFREE(ssl->decrypt.aria, ssl->heap, DYNAMIC_TYPE_CIPHER); + ssl->encrypt.aria = NULL; + ssl->decrypt.aria = NULL; #endif #ifdef HAVE_CAMELLIA XFREE(ssl->encrypt.cam, ssl->heap, DYNAMIC_TYPE_CIPHER); XFREE(ssl->decrypt.cam, ssl->heap, DYNAMIC_TYPE_CIPHER); + ssl->encrypt.cam = NULL; + ssl->decrypt.cam = NULL; #endif #ifdef HAVE_CHACHA if (ssl->encrypt.chacha) @@ -2939,37 +2957,36 @@ void FreeCiphers(WOLFSSL* ssl) ForceZero(ssl->decrypt.chacha, sizeof(ChaCha)); XFREE(ssl->encrypt.chacha, ssl->heap, DYNAMIC_TYPE_CIPHER); XFREE(ssl->decrypt.chacha, ssl->heap, DYNAMIC_TYPE_CIPHER); + ssl->encrypt.chacha = NULL; + ssl->decrypt.chacha = NULL; #endif #if defined(HAVE_POLY1305) && defined(HAVE_ONE_TIME_AUTH) if (ssl->auth.poly1305) ForceZero(ssl->auth.poly1305, sizeof(Poly1305)); XFREE(ssl->auth.poly1305, ssl->heap, DYNAMIC_TYPE_CIPHER); + ssl->auth.poly1305 = NULL; #endif #if defined(WOLFSSL_TLS13) && defined(HAVE_NULL_CIPHER) wc_HmacFree(ssl->encrypt.hmac); wc_HmacFree(ssl->decrypt.hmac); XFREE(ssl->encrypt.hmac, ssl->heap, DYNAMIC_TYPE_CIPHER); XFREE(ssl->decrypt.hmac, ssl->heap, DYNAMIC_TYPE_CIPHER); + ssl->encrypt.hmac = NULL; + ssl->decrypt.hmac = NULL; #endif #ifdef WOLFSSL_DTLS13 #ifdef BUILD_AES - if (ssl->dtlsRecordNumberEncrypt.aes != NULL) { - wc_AesFree(ssl->dtlsRecordNumberEncrypt.aes); - XFREE(ssl->dtlsRecordNumberEncrypt.aes, ssl->heap, DYNAMIC_TYPE_CIPHER); - ssl->dtlsRecordNumberEncrypt.aes = NULL; - } - if (ssl->dtlsRecordNumberDecrypt.aes != NULL) { - wc_AesFree(ssl->dtlsRecordNumberDecrypt.aes); - XFREE(ssl->dtlsRecordNumberDecrypt.aes, ssl->heap, DYNAMIC_TYPE_CIPHER); - ssl->dtlsRecordNumberDecrypt.aes = NULL; - } + wc_AesFree(ssl->dtlsRecordNumberEncrypt.aes); + wc_AesFree(ssl->dtlsRecordNumberDecrypt.aes); + XFREE(ssl->dtlsRecordNumberEncrypt.aes, ssl->heap, DYNAMIC_TYPE_CIPHER); + XFREE(ssl->dtlsRecordNumberDecrypt.aes, ssl->heap, DYNAMIC_TYPE_CIPHER); + ssl->dtlsRecordNumberEncrypt.aes = NULL; + ssl->dtlsRecordNumberDecrypt.aes = NULL; #endif /* BUILD_AES */ #ifdef HAVE_CHACHA - XFREE(ssl->dtlsRecordNumberEncrypt.chacha, - ssl->heap, DYNAMIC_TYPE_CIPHER); - XFREE(ssl->dtlsRecordNumberDecrypt.chacha, - ssl->heap, DYNAMIC_TYPE_CIPHER); + XFREE(ssl->dtlsRecordNumberEncrypt.chacha, ssl->heap, DYNAMIC_TYPE_CIPHER); + XFREE(ssl->dtlsRecordNumberDecrypt.chacha, ssl->heap, DYNAMIC_TYPE_CIPHER); ssl->dtlsRecordNumberEncrypt.chacha = NULL; ssl->dtlsRecordNumberDecrypt.chacha = NULL; #endif /* HAVE_CHACHA */ @@ -4750,8 +4767,7 @@ static void SetDigest(WOLFSSL* ssl, int hashAlgo) #endif /* !NO_WOLFSSL_SERVER || !NO_WOLFSSL_CLIENT */ #endif /* !NO_CERTS */ -#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) -static word32 MacSize(const WOLFSSL* ssl) +word32 MacSize(const WOLFSSL* ssl) { #ifdef HAVE_TRUNCATED_HMAC word32 digestSz = ssl->truncated_hmac ? (byte)TRUNCATED_HMAC_SZ @@ -4762,7 +4778,6 @@ static word32 MacSize(const WOLFSSL* ssl) return digestSz; } -#endif /* HAVE_ENCRYPT_THEN_MAC && !WOLFSSL_AEAD_ONLY */ #ifndef NO_RSA #if !defined(WOLFSSL_NO_TLS12) || \ @@ -10119,6 +10134,14 @@ int HashOutput(WOLFSSL* ssl, const byte* output, int sz, int ivSz) sz -= dtls_record_extra; #endif /* WOLFSSL_DTLS13 */ } else { +#ifdef WOLFSSL_DTLS_CID + unsigned int cidSz = 0; + if (IsEncryptionOn(ssl, 1) && + wolfSSL_dtls_cid_get_tx_size(ssl, &cidSz) == WOLFSSL_SUCCESS) { + adj += cidSz; + sz -= cidSz + 1; /* +1 to not hash the real content type */ + } +#endif adj += DTLS_RECORD_EXTRA; sz -= DTLS_RECORD_EXTRA; } @@ -10159,7 +10182,8 @@ int HashInput(WOLFSSL* ssl, const byte* input, int sz) /* add record layer header for message */ -static void AddRecordHeader(byte* output, word32 length, byte type, WOLFSSL* ssl, int epochOrder) +static void AddRecordHeader(byte* output, word32 length, byte type, + WOLFSSL* ssl, int epochOrder) { RecordLayerHeader* rl; @@ -10198,12 +10222,19 @@ static void AddRecordHeader(byte* output, word32 length, byte type, WOLFSSL* ssl } else { #ifdef WOLFSSL_DTLS - DtlsRecordLayerHeader* dtls; - /* dtls record layer header extensions */ - dtls = (DtlsRecordLayerHeader*)output; + DtlsRecordLayerHeader* dtls = (DtlsRecordLayerHeader*)output; +#ifdef WOLFSSL_DTLS_CID + unsigned int cidSz = 0; + if (type == dtls12_cid && + wolfSSL_dtls_cid_get_tx_size(ssl, &cidSz) == WOLFSSL_SUCCESS) { + wolfSSL_dtls_cid_get_tx(ssl, output + DTLS12_CID_OFFSET, cidSz); + c16toa((word16)length, output + DTLS12_CID_OFFSET + cidSz); + } + else +#endif + c16toa((word16)length, dtls->length); WriteSEQ(ssl, epochOrder, dtls->sequence_number); - c16toa((word16)length, dtls->length); #endif } } @@ -10305,6 +10336,8 @@ static int SendHandshakeMsg(WOLFSSL* ssl, byte* input, word32 inputSz, int maxFrag; int ret = 0; int headerSz; + int rHdrSz = 0; /* record header size */ + int hsHdrSz = 0; /* handshake header size */ WOLFSSL_ENTER("SendHandshakeMsg"); (void)type; @@ -10313,8 +10346,10 @@ static int SendHandshakeMsg(WOLFSSL* ssl, byte* input, word32 inputSz, if (ssl == NULL || input == NULL) return BAD_FUNC_ARG; #ifdef WOLFSSL_DTLS - if (ssl->options.dtls) - headerSz = DTLS_RECORD_HEADER_SZ + DTLS_HANDSHAKE_HEADER_SZ; + if (ssl->options.dtls) { + rHdrSz = DTLS_RECORD_HEADER_SZ; + hsHdrSz = DTLS_HANDSHAKE_HEADER_SZ; + } else #endif { @@ -10322,7 +10357,7 @@ static int SendHandshakeMsg(WOLFSSL* ssl, byte* input, word32 inputSz, * per fragment like in DTLS. The handshake header should * already be in the input buffer. */ inputSz += HANDSHAKE_HEADER_SZ; - headerSz = RECORD_HEADER_SZ; + rHdrSz = RECORD_HEADER_SZ; } maxFrag = wolfSSL_GetMaxFragSize(ssl, (int)inputSz); @@ -10337,7 +10372,7 @@ static int SendHandshakeMsg(WOLFSSL* ssl, byte* input, word32 inputSz, if (!ssl->options.buildingMsg) { /* Hash it before the loop as we modify the input with * encryption on */ - ret = HashOutput(ssl, input, headerSz + (int)inputSz, 0); + ret = HashRaw(ssl, input + rHdrSz, inputSz + hsHdrSz); if (ret != 0) return ret; #ifdef WOLFSSL_DTLS @@ -10347,6 +10382,7 @@ static int SendHandshakeMsg(WOLFSSL* ssl, byte* input, word32 inputSz, ssl->keys.dtls_handshake_number--; #endif } + headerSz = rHdrSz + hsHdrSz; while (ssl->fragOffset < inputSz) { byte* output; int outputSz; @@ -11028,13 +11064,8 @@ int MsgCheckEncryption(WOLFSSL* ssl, byte type, byte encrypted) static WC_INLINE int isLastMsg(const WOLFSSL* ssl, word32 msgSz) { word32 extra = 0; - if (IsEncryptionOn(ssl, 0)) { + if (IsEncryptionOn(ssl, 0)) extra = ssl->keys.padSz; -#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) - if (ssl->options.startedETMRead) - extra += MacSize(ssl); -#endif - } return (ssl->buffers.inputBuffer.idx - ssl->curStartIdx) + msgSz + extra == ssl->curSize; } @@ -11312,6 +11343,9 @@ static int GetDtls13RecordHeader(WOLFSSL* ssl, word32* inOutIdx, static int GetDtlsRecordHeader(WOLFSSL* ssl, word32* inOutIdx, RecordLayerHeader* rh, word16* size) { +#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_DTLS_CID) + unsigned int cidSz = 0; +#endif #ifdef HAVE_FUZZER if (ssl->fuzzerCb) @@ -11365,6 +11399,13 @@ static int GetDtlsRecordHeader(WOLFSSL* ssl, word32* inOutIdx, *inOutIdx += ENUM_LEN + VERSION_SZ; ato16(ssl->buffers.inputBuffer.buffer + *inOutIdx, &ssl->keys.curEpoch); +#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_DTLS_CID) + if (rh->type == dtls12_cid && + (wolfSSL_dtls_cid_get_rx_size(ssl, &cidSz) != WOLFSSL_SUCCESS || + cidSz == 0)) + return DTLS_CID_ERROR; +#endif + #ifdef WOLFSSL_DTLS13 /* only non protected message can use the DTLSPlaintext record header */ if (IsAtLeastTLSv1_3(ssl->version)) { @@ -11396,6 +11437,20 @@ static int GetDtlsRecordHeader(WOLFSSL* ssl, word32* inOutIdx, ssl->keys.curSeq = w64From32(ssl->keys.curSeq_hi, ssl->keys.curSeq_lo); #endif /* WOLFSSL_DTLS13 */ +#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_DTLS_CID) + if (rh->type == dtls12_cid) { + byte cid[DTLS_CID_MAX_SIZE]; + if (ssl->buffers.inputBuffer.length - *inOutIdx < cidSz + LENGTH_SZ) + return LENGTH_ERROR; + if (cidSz > DTLS_CID_MAX_SIZE || + wolfSSL_dtls_cid_get_rx(ssl, cid, cidSz) != WOLFSSL_SUCCESS) + return DTLS_CID_ERROR; + if (XMEMCMP(ssl->buffers.inputBuffer.buffer + *inOutIdx, + cid, cidSz) != 0) + return DTLS_CID_ERROR; + *inOutIdx += cidSz; + } +#endif ato16(ssl->buffers.inputBuffer.buffer + *inOutIdx, size); *inOutIdx += LENGTH_SZ; @@ -11443,8 +11498,12 @@ static int GetRecordHeader(WOLFSSL* ssl, word32* inOutIdx, /* DTLSv1.3 MUST check window after deprotecting to avoid timing channel (RFC9147 Section 4.5.1) */ if (IsDtlsNotSctpMode(ssl) && !IsAtLeastTLSv1_3(ssl->version)) { + byte needsEnc = rh->type == application_data; /* can't be epoch 0 */ +#ifdef WOLFSSL_DTLS_CID + needsEnc = needsEnc || rh->type == dtls12_cid; +#endif if (!_DtlsCheckWindow(ssl) || - (rh->type == application_data && ssl->keys.curEpoch == 0) || + (needsEnc && ssl->keys.curEpoch == 0) || (rh->type == alert && ssl->options.handShakeDone && ssl->keys.curEpoch == 0 && ssl->keys.dtls_epoch != 0)) { WOLFSSL_LEAVE("GetRecordHeader()", SEQUENCE_ERROR); @@ -11535,6 +11594,9 @@ static int GetRecordHeader(WOLFSSL* ssl, word32* inOutIdx, case change_cipher_spec: case application_data: case alert: +#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_DTLS_CID) + case dtls12_cid: +#endif #ifdef WOLFSSL_DTLS13 case ack: #endif /* WOLFSSL_DTLS13 */ @@ -16178,13 +16240,8 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx, ssl->options.serverState = SERVER_CERT_COMPLETE; } - if (IsEncryptionOn(ssl, 0)) { + if (IsEncryptionOn(ssl, 0)) args->idx += ssl->keys.padSz; - #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) - if (ssl->options.startedETMRead) - args->idx += MacSize(ssl); - #endif - } /* Advance state and proceed */ ssl->options.asyncState = TLS_ASYNC_END; @@ -16444,20 +16501,9 @@ static int DoCertificateStatus(WOLFSSL* ssl, byte* input, word32* inOutIdx, } if (IsEncryptionOn(ssl, 0)) { - #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) - if (ssl->options.startedETMRead) { - word32 digestSz = MacSize(ssl); - if (*inOutIdx + ssl->keys.padSz + digestSz > size) - return BUFFER_E; - *inOutIdx += ssl->keys.padSz + digestSz; - } - else - #endif - { - if (*inOutIdx + ssl->keys.padSz > size) - return BUFFER_E; - *inOutIdx += ssl->keys.padSz; - } + if (*inOutIdx + ssl->keys.padSz > size) + return BUFFER_E; + *inOutIdx += ssl->keys.padSz; } WOLFSSL_LEAVE("DoCertificateStatus", ret); @@ -16488,24 +16534,12 @@ static int DoHelloRequest(WOLFSSL* ssl, const byte* input, word32* inOutIdx, if (IsEncryptionOn(ssl, 0)) { /* If size == totalSz then we are in DtlsMsgDrain so no need to worry * about padding */ - #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) - if (ssl->options.startedETMRead) { - word32 digestSz = MacSize(ssl); - if (size != totalSz && - *inOutIdx + ssl->keys.padSz + digestSz > totalSz) - return BUFFER_E; - *inOutIdx += ssl->keys.padSz + digestSz; - } - else - #endif - { - /* access beyond input + size should be checked against totalSz */ - if (size != totalSz && - *inOutIdx + ssl->keys.padSz > totalSz) - return BUFFER_E; + /* access beyond input + size should be checked against totalSz */ + if (size != totalSz && + *inOutIdx + ssl->keys.padSz > totalSz) + return BUFFER_E; - *inOutIdx += ssl->keys.padSz; - } + *inOutIdx += ssl->keys.padSz; } if (ssl->options.side == WOLFSSL_SERVER_END) { @@ -16542,17 +16576,8 @@ int DoFinished(WOLFSSL* ssl, const byte* input, word32* inOutIdx, word32 size, * If size == totalSz then we are in DtlsMsgDrain so no need to worry about * padding */ if (size != totalSz) { - #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) - if (ssl->options.startedETMRead) { - if (*inOutIdx + size + ssl->keys.padSz + MacSize(ssl) > totalSz) - return BUFFER_E; - } - else - #endif - { - if (*inOutIdx + size + ssl->keys.padSz > totalSz) - return BUFFER_E; - } + if (*inOutIdx + size + ssl->keys.padSz > totalSz) + return BUFFER_E; } #ifdef WOLFSSL_CALLBACKS @@ -16595,10 +16620,6 @@ int DoFinished(WOLFSSL* ssl, const byte* input, word32* inOutIdx, word32 size, /* force input exhaustion at ProcessReply consuming padSz */ *inOutIdx += size + ssl->keys.padSz; -#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) - if (ssl->options.startedETMRead) - *inOutIdx += MacSize(ssl); -#endif if (ssl->options.side == WOLFSSL_CLIENT_END) { ssl->options.serverState = SERVER_FINISHED_COMPLETE; @@ -17145,10 +17166,6 @@ int DoHandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx, expectedIdx = *inOutIdx + size + (ssl->keys.encryptionOn ? ssl->keys.padSz : 0); -#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) - if (ssl->options.startedETMRead && ssl->keys.encryptionOn) - expectedIdx += MacSize(ssl); -#endif #if !defined(NO_WOLFSSL_SERVER) && \ defined(HAVE_SECURE_RENEGOTIATION) && \ @@ -17299,23 +17316,12 @@ int DoHandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx, WOLFSSL_MSG("processing hello verify request"); ret = DoHelloVerifyRequest(ssl, input,inOutIdx, size); if (IsEncryptionOn(ssl, 0)) { - #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) - if (ssl->options.startedETMRead) { - word32 digestSz = MacSize(ssl); - if (*inOutIdx + ssl->keys.padSz + digestSz > totalSz) - return BUFFER_E; - *inOutIdx += ssl->keys.padSz + digestSz; - } - else - #endif - { - /* access beyond input + size should be checked against totalSz - */ - if (*inOutIdx + ssl->keys.padSz > totalSz) - return BUFFER_E; + /* access beyond input + size should be checked against totalSz + */ + if (*inOutIdx + ssl->keys.padSz > totalSz) + return BUFFER_E; - *inOutIdx += ssl->keys.padSz; - } + *inOutIdx += ssl->keys.padSz; } break; @@ -17388,13 +17394,8 @@ int DoHandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx, AddLateName("ServerHelloDone", &ssl->timeoutInfo); #endif ssl->options.serverState = SERVER_HELLODONE_COMPLETE; - if (IsEncryptionOn(ssl, 0)) { + if (IsEncryptionOn(ssl, 0)) *inOutIdx += ssl->keys.padSz; - #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) - if (ssl->options.startedETMRead) - *inOutIdx += MacSize(ssl); - #endif - } break; case finished: @@ -17429,24 +17430,12 @@ int DoHandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx, /* If size == totalSz then we are in DtlsMsgDrain so no need to worry * about padding */ if (IsEncryptionOn(ssl, 0)) { - #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) - if (ssl->options.startedETMRead) { - word32 digestSz = MacSize(ssl); - if (size != totalSz && - *inOutIdx + ssl->keys.padSz + digestSz > totalSz) - return BUFFER_E; - *inOutIdx += ssl->keys.padSz + digestSz; - } - else - #endif - { - /* access beyond input + size should be checked against totalSz - */ - if (size != totalSz && - *inOutIdx + ssl->keys.padSz > totalSz) - return BUFFER_E; - *inOutIdx += ssl->keys.padSz; - } + /* access beyond input + size should be checked against totalSz + */ + if (size != totalSz && + *inOutIdx + ssl->keys.padSz > totalSz) + return BUFFER_E; + *inOutIdx += ssl->keys.padSz; } break; @@ -18309,22 +18298,9 @@ static int DoDtlsHandShakeMsg(WOLFSSL* ssl, byte* input, word32* inOutIdx, input + *inOutIdx, size, type, fragOffset, fragSz, ssl->heap); *inOutIdx += fragSz; - #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) - if (ssl->options.startedETMRead && ssl->keys.curEpoch != 0) { - word32 digestSz = MacSize(ssl); - if (*inOutIdx + ssl->keys.padSz + digestSz > totalSz) { - WOLFSSL_ERROR(BUFFER_E); - return BUFFER_E; - } - *inOutIdx += digestSz; - } - else - #endif - { - if (*inOutIdx + ssl->keys.padSz > totalSz) { - WOLFSSL_ERROR(BUFFER_E); - return BUFFER_E; - } + if (*inOutIdx + ssl->keys.padSz > totalSz) { + WOLFSSL_ERROR(BUFFER_E); + return BUFFER_E; } *inOutIdx += ssl->keys.padSz; ret = 0; @@ -18365,22 +18341,9 @@ static int DoDtlsHandShakeMsg(WOLFSSL* ssl, byte* input, word32* inOutIdx, /* Already saw this message and processed it. It can be ignored. */ WOLFSSL_MSG("Already saw this message and processed it"); *inOutIdx += fragSz; - #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) - if (ssl->options.startedETMRead && ssl->keys.curEpoch != 0) { - word32 digestSz = MacSize(ssl); - if (*inOutIdx + ssl->keys.padSz + digestSz > totalSz) { - WOLFSSL_ERROR(BUFFER_E); - return BUFFER_E; - } - *inOutIdx += digestSz; - } - else - #endif - { - if (*inOutIdx + ssl->keys.padSz > totalSz) { - WOLFSSL_ERROR(BUFFER_E); - return BUFFER_E; - } + if (*inOutIdx + ssl->keys.padSz > totalSz) { + WOLFSSL_ERROR(BUFFER_E); + return BUFFER_E; } #ifndef WOLFSSL_DTLS_RESEND_ONLY_TIMEOUT if (IsDtlsNotSctpMode(ssl) && @@ -18413,17 +18376,11 @@ static int DoDtlsHandShakeMsg(WOLFSSL* ssl, byte* input, word32* inOutIdx, input + *inOutIdx, size, type, fragOffset, fragSz, ssl->heap); *inOutIdx += fragSz; - *inOutIdx += ssl->keys.padSz; -#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) - if (ssl->options.startedETMRead && ssl->keys.curEpoch != 0) { - word32 digestSz = MacSize(ssl); - if (*inOutIdx + digestSz > totalSz) { - WOLFSSL_ERROR(BUFFER_E); - return BUFFER_E; - } - *inOutIdx += digestSz; + if (*inOutIdx + ssl->keys.padSz > totalSz) { + WOLFSSL_ERROR(BUFFER_E); + return BUFFER_E; } -#endif + *inOutIdx += ssl->keys.padSz; ret = 0; if (ssl->dtls_rx_msg_list != NULL && ssl->dtls_rx_msg_list->ready) ret = DtlsMsgDrain(ssl); @@ -18443,14 +18400,6 @@ static int DoDtlsHandShakeMsg(WOLFSSL* ssl, byte* input, word32* inOutIdx, if (idx + fragSz + ssl->keys.padSz > totalSz) return BUFFER_E; *inOutIdx = idx + fragSz + ssl->keys.padSz; -#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) - if (ssl->options.startedETMRead && ssl->keys.curEpoch != 0) { - word32 digestSz = MacSize(ssl); - if (*inOutIdx + digestSz > totalSz) - return BUFFER_E; - *inOutIdx += digestSz; - } -#endif /* In async mode always store the message and process it with * DtlsMsgDrain because in case of a WC_PENDING_E it will be * easier this way. */ @@ -18507,8 +18456,8 @@ static WC_INLINE void AeadIncrementExpIV(WOLFSSL* ssl) #if defined(HAVE_CHACHA) && defined(HAVE_POLY1305) && !defined(NO_CHAPOL_AEAD) /* Used for the older version of creating AEAD tags with Poly1305 */ -static int Poly1305TagOld(WOLFSSL* ssl, byte* additional, const byte* out, - byte* cipher, word16 sz, byte* tag) +static int Poly1305TagOld(WOLFSSL* ssl, byte* additional, int additionalSz, + const byte* out, byte* cipher, word16 sz, byte* tag) { int ret = 0; int msglen = (sz - ssl->specs.aead_mac_size); @@ -18526,12 +18475,12 @@ static int Poly1305TagOld(WOLFSSL* ssl, byte* additional, const byte* out, return ret; if ((ret = wc_Poly1305Update(ssl->auth.poly1305, additional, - AEAD_AUTH_DATA_SZ)) != 0) + additionalSz)) != 0) return ret; /* length of additional input plus padding */ XMEMSET(padding, 0, sizeof(padding)); - padding[0] = AEAD_AUTH_DATA_SZ; + padding[0] = additionalSz; if ((ret = wc_Poly1305Update(ssl->auth.poly1305, padding, sizeof(padding))) != 0) return ret; @@ -18574,19 +18523,21 @@ static int Poly1305TagOld(WOLFSSL* ssl, byte* additional, const byte* out, * Return 0 on success negative values in error case */ int ChachaAEADEncrypt(WOLFSSL* ssl, byte* out, const byte* input, - word16 sz) + word16 sz, byte type) { - const byte* additionalSrc = input - RECORD_HEADER_SZ; int ret = 0; word32 msgLen = (sz - ssl->specs.aead_mac_size); byte tag[POLY1305_AUTH_SZ]; byte add[AEAD_AUTH_DATA_SZ]; + int addSz = 0; byte nonce[CHACHA20_NONCE_SZ]; byte poly[CHACHA20_256_KEY_SIZE]; /* generated key for poly1305 */ #ifdef CHACHA_AEAD_TEST int i; #endif Keys* keys = &ssl->keys; + byte* seq = NULL; + int verifyOrder = CUR_ORDER; XMEMSET(tag, 0, sizeof(tag)); XMEMSET(nonce, 0, sizeof(nonce)); @@ -18604,36 +18555,22 @@ int ChachaAEADEncrypt(WOLFSSL* ssl, byte* out, const byte* input, /* opaque SEQ number stored for AD */ if (ssl->options.dtls && DtlsSCRKeysSet(ssl)) { if (ssl->keys.dtls_epoch == - ssl->secure_renegotiation->tmp_keys.dtls_epoch) { + ssl->secure_renegotiation->tmp_keys.dtls_epoch) keys = &ssl->secure_renegotiation->tmp_keys; - WriteSEQ(ssl, CUR_ORDER, add); - } else - WriteSEQ(ssl, PREV_ORDER, add); + verifyOrder = PREV_ORDER; } - else #endif - WriteSEQ(ssl, CUR_ORDER, add); + + addSz = writeAeadAuthData(ssl, msgLen, type, add, 0, &seq, verifyOrder); + if (addSz < 0) + return addSz; if (ssl->options.oldPoly != 0) { /* get nonce. SEQ should not be incremented again here */ - XMEMCPY(nonce + CHACHA20_OLD_OFFSET, add, OPAQUE32_LEN * 2); + XMEMCPY(nonce + CHACHA20_OLD_OFFSET, seq, SEQ_SZ); } - /* Store the type, version. Unfortunately, they are in - * the input buffer ahead of the plaintext. */ - #ifdef WOLFSSL_DTLS - if (ssl->options.dtls) { - additionalSrc -= DTLS_HANDSHAKE_EXTRA; - } - #endif - - /* add TLS message size to additional data */ - add[AEAD_AUTH_DATA_SZ - 2] = (msgLen >> 8) & 0xff; - add[AEAD_AUTH_DATA_SZ - 1] = msgLen & 0xff; - - XMEMCPY(add + AEAD_TYPE_OFFSET, additionalSrc, 3); - #ifdef CHACHA_AEAD_TEST printf("Encrypt Additional : "); for (i = 0; i < AEAD_AUTH_DATA_SZ; i++) { @@ -18652,15 +18589,8 @@ int ChachaAEADEncrypt(WOLFSSL* ssl, byte* out, const byte* input, if (ssl->options.oldPoly == 0) { /* nonce is formed by 4 0x00 byte padded to the left followed by 8 byte * record sequence number XORed with client_write_IV/server_write_IV */ - XMEMCPY(nonce, keys->aead_enc_imp_IV, CHACHA20_IMP_IV_SZ); - nonce[4] ^= add[0]; - nonce[5] ^= add[1]; - nonce[6] ^= add[2]; - nonce[7] ^= add[3]; - nonce[8] ^= add[4]; - nonce[9] ^= add[5]; - nonce[10] ^= add[6]; - nonce[11] ^= add[7]; + XMEMCPY(nonce + CHACHA20_OFFSET, seq, SEQ_SZ); + xorbuf(nonce, keys->aead_enc_imp_IV, CHACHA20_IMP_IV_SZ); } #ifdef WOLFSSL_CHECK_MEM_ZERO wc_MemZero_Add("ChachaAEADEncrypt nonce", nonce, CHACHA20_NONCE_SZ); @@ -18715,7 +18645,7 @@ int ChachaAEADEncrypt(WOLFSSL* ssl, byte* out, const byte* input, /* get the poly1305 tag using either old padding scheme or more recent */ if (ssl->options.oldPoly != 0) { - if ((ret = Poly1305TagOld(ssl, add, (const byte* )out, + if ((ret = Poly1305TagOld(ssl, add, addSz, (const byte* )out, poly, sz, tag)) != 0) { ForceZero(poly, sizeof(poly)); #ifdef WOLFSSL_CHECK_MEM_ZERO @@ -18733,8 +18663,8 @@ int ChachaAEADEncrypt(WOLFSSL* ssl, byte* out, const byte* input, #endif return ret; } - if ((ret = wc_Poly1305_MAC(ssl->auth.poly1305, add, - sizeof(add), out, msgLen, tag, sizeof(tag))) != 0) { + if ((ret = wc_Poly1305_MAC(ssl->auth.poly1305, add, addSz, out, msgLen, + tag, sizeof(tag))) != 0) { ForceZero(poly, sizeof(poly)); #ifdef WOLFSSL_CHECK_MEM_ZERO wc_MemZero_Check(poly, CHACHA20_256_KEY_SIZE); @@ -18790,12 +18720,14 @@ int ChachaAEADDecrypt(WOLFSSL* ssl, byte* plain, const byte* input, word16 sz) { byte add[AEAD_AUTH_DATA_SZ]; + int addSz = 0; byte nonce[CHACHA20_NONCE_SZ]; byte tag[POLY1305_AUTH_SZ]; byte poly[CHACHA20_256_KEY_SIZE]; /* generated key for mac */ int ret = 0; int msgLen = (sz - ssl->specs.aead_mac_size); Keys* keys = &ssl->keys; + byte* seq = NULL; #ifdef CHACHA_AEAD_TEST int i; @@ -18824,24 +18756,16 @@ int ChachaAEADDecrypt(WOLFSSL* ssl, byte* plain, const byte* input, keys = &ssl->secure_renegotiation->tmp_keys; #endif - /* sequence number field is 64-bits */ - WriteSEQ(ssl, PEER_ORDER, add); + + addSz = writeAeadAuthData(ssl, msgLen, no_type, add, 1, &seq, PEER_ORDER); + if (addSz < 0) + return addSz; if (ssl->options.oldPoly != 0) { /* get nonce, SEQ should not be incremented again here */ - XMEMCPY(nonce + CHACHA20_OLD_OFFSET, add, OPAQUE32_LEN * 2); + XMEMCPY(nonce + CHACHA20_OLD_OFFSET, seq, SEQ_SZ); } - /* get AD info */ - /* Store the type, version. */ - add[AEAD_TYPE_OFFSET] = ssl->curRL.type; - add[AEAD_VMAJ_OFFSET] = ssl->curRL.pvMajor; - add[AEAD_VMIN_OFFSET] = ssl->curRL.pvMinor; - - /* add TLS message size to additional data */ - add[AEAD_AUTH_DATA_SZ - 2] = (msgLen >> 8) & 0xff; - add[AEAD_AUTH_DATA_SZ - 1] = msgLen & 0xff; - #ifdef CHACHA_AEAD_TEST printf("Decrypt Additional : "); for (i = 0; i < AEAD_AUTH_DATA_SZ; i++) { @@ -18853,15 +18777,8 @@ int ChachaAEADDecrypt(WOLFSSL* ssl, byte* plain, const byte* input, if (ssl->options.oldPoly == 0) { /* nonce is formed by 4 0x00 byte padded to the left followed by 8 byte * record sequence number XORed with client_write_IV/server_write_IV */ - XMEMCPY(nonce, keys->aead_dec_imp_IV, CHACHA20_IMP_IV_SZ); - nonce[4] ^= add[0]; - nonce[5] ^= add[1]; - nonce[6] ^= add[2]; - nonce[7] ^= add[3]; - nonce[8] ^= add[4]; - nonce[9] ^= add[5]; - nonce[10] ^= add[6]; - nonce[11] ^= add[7]; + XMEMCPY(nonce + CHACHA20_OFFSET, seq, SEQ_SZ); + xorbuf(nonce, keys->aead_dec_imp_IV, CHACHA20_IMP_IV_SZ); } #ifdef WOLFSSL_CHECK_MEM_ZERO wc_MemZero_Add("ChachaAEADEncrypt nonce", nonce, CHACHA20_NONCE_SZ); @@ -18906,7 +18823,8 @@ int ChachaAEADDecrypt(WOLFSSL* ssl, byte* plain, const byte* input, /* get the tag using Poly1305 */ if (ssl->options.oldPoly != 0) { - if ((ret = Poly1305TagOld(ssl, add, input, poly, sz, tag)) != 0) { + if ((ret = Poly1305TagOld(ssl, add, addSz, input, poly, sz, tag)) + != 0) { ForceZero(poly, sizeof(poly)); #ifdef WOLFSSL_CHECK_MEM_ZERO wc_MemZero_Check(poly, CHACHA20_256_KEY_SIZE); @@ -18923,8 +18841,8 @@ int ChachaAEADDecrypt(WOLFSSL* ssl, byte* plain, const byte* input, #endif return ret; } - if ((ret = wc_Poly1305_MAC(ssl->auth.poly1305, add, - sizeof(add), input, (word32)msgLen, tag, sizeof(tag))) != 0) { + if ((ret = wc_Poly1305_MAC(ssl->auth.poly1305, add, addSz, input, + (word32)msgLen, tag, sizeof(tag))) != 0) { ForceZero(poly, sizeof(poly)); #ifdef WOLFSSL_CHECK_MEM_ZERO wc_MemZero_Check(poly, CHACHA20_256_KEY_SIZE); @@ -19008,9 +18926,75 @@ typedef int (*Sm4AuthDecryptFunc)(wc_Sm4* sm4, byte* out, const byte* in, #endif +#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_DTLS_CID) +#define TLS_AEAD_CID_SZ(s, dec, c) \ + ((dec) ? wolfSSL_dtls_cid_get_rx_size((s), (c)) \ + : wolfSSL_dtls_cid_get_tx_size((s), (c))) +#define TLS_AEAD_CID(s, dec, b, c) \ + ((dec) ? wolfSSL_dtls_cid_get_rx((s), (b), (c)) \ + : wolfSSL_dtls_cid_get_tx((s), (b), (c))) +#endif +/** + * + * @param ssl WOLFSSL object + * @param sz Length of fragment + * @param type Record content type + * @param additional AAD output buffer. Assumed AEAD_AUTH_DATA_SZ length. + * @param dec Are we decrypting + * @return > 0 length of auth data + * <=0 error + */ +int writeAeadAuthData(WOLFSSL* ssl, word16 sz, byte type, + byte* additional, byte dec, byte** seq, int verifyOrder) +{ + word32 idx = 0; +#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_DTLS_CID) + unsigned int cidSz = 0; + if (ssl->options.dtls && + TLS_AEAD_CID_SZ(ssl, dec, &cidSz) == WOLFSSL_SUCCESS) { + if (cidSz > DTLS_CID_MAX_SIZE) { + WOLFSSL_MSG("DTLS CID too large"); + return DTLS_CID_ERROR; + } + + XMEMSET(additional + idx, 0xFF, SEQ_SZ); + idx += SEQ_SZ; + additional[idx++] = dtls12_cid; + additional[idx++] = (byte)cidSz; + additional[idx++] = dtls12_cid; + additional[idx++] = dec ? ssl->curRL.pvMajor : ssl->version.major; + additional[idx++] = dec ? ssl->curRL.pvMinor : ssl->version.minor; + WriteSEQ(ssl, verifyOrder, additional + idx); + if (seq != NULL) + *seq = additional + idx; + idx += SEQ_SZ; + if (TLS_AEAD_CID(ssl, dec, additional + idx, cidSz) + == WC_NO_ERR_TRACE(WOLFSSL_FAILURE)) { + WOLFSSL_MSG("DTLS CID write failed"); + return DTLS_CID_ERROR; + } + idx += cidSz; + c16toa(sz, additional + idx); + idx += LENGTH_SZ; + + return (int)idx; + } +#endif + if (seq != NULL) + *seq = additional + idx; + WriteSEQ(ssl, verifyOrder, additional + idx); + idx += SEQ_SZ; + additional[idx++] = dec ? ssl->curRL.type : type; + additional[idx++] = dec ? ssl->curRL.pvMajor : ssl->version.major; + additional[idx++] = dec ? ssl->curRL.pvMinor : ssl->version.minor; + c16toa(sz, additional + idx); + idx += LENGTH_SZ; + + return (int)idx; +} static WC_INLINE int EncryptDo(WOLFSSL* ssl, byte* out, const byte* input, - word16 sz, int asyncOkay) + word16 sz, int asyncOkay, byte type) { int ret = 0; #ifdef WOLFSSL_ASYNC_CRYPT @@ -19077,7 +19061,7 @@ static WC_INLINE int EncryptDo(WOLFSSL* ssl, byte* out, const byte* input, case wolfssl_aes_ccm:/* GCM AEAD macros use same size as CCM */ { AES_AUTH_ENCRYPT_FUNC aes_auth_fn; - const byte* additionalSrc; + int additionalSz; #ifdef WOLFSSL_ASYNC_CRYPT /* initialize event */ @@ -19095,27 +19079,17 @@ static WC_INLINE int EncryptDo(WOLFSSL* ssl, byte* out, const byte* input, #else aes_auth_fn = AES_CCM_ENCRYPT; #endif - additionalSrc = input - 5; - - XMEMSET(ssl->encrypt.additional, 0, AEAD_AUTH_DATA_SZ); - - /* sequence number field is 64-bits */ - WriteSEQ(ssl, CUR_ORDER, ssl->encrypt.additional); - /* Store the type, version. Unfortunately, they are in - * the input buffer ahead of the plaintext. */ - #ifdef WOLFSSL_DTLS - if (ssl->options.dtls) { - additionalSrc -= DTLS_HANDSHAKE_EXTRA; + additionalSz = writeAeadAuthData(ssl, + /* Length of the plain text minus the explicit + * IV length minus the authentication tag size. */ + sz - AESGCM_EXP_IV_SZ - ssl->specs.aead_mac_size, type, + ssl->encrypt.additional, 0, NULL, CUR_ORDER); + if (additionalSz < 0) { + ret = additionalSz; + break; } - #endif - XMEMCPY(ssl->encrypt.additional + AEAD_TYPE_OFFSET, - additionalSrc, 3); - /* Store the length of the plain text minus the explicit - * IV length minus the authentication tag size. */ - c16toa(sz - AESGCM_EXP_IV_SZ - ssl->specs.aead_mac_size, - ssl->encrypt.additional + AEAD_LEN_OFFSET); #if !defined(NO_PUBLIC_GCM_SET_IV) && \ ((defined(HAVE_FIPS) || defined(HAVE_SELFTEST)) && \ (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION < 2))) @@ -19133,7 +19107,7 @@ static WC_INLINE int EncryptDo(WOLFSSL* ssl, byte* out, const byte* input, ssl->encrypt.nonce, AESGCM_NONCE_SZ, out + sz - ssl->specs.aead_mac_size, ssl->specs.aead_mac_size, - ssl->encrypt.additional, AEAD_AUTH_DATA_SZ); + ssl->encrypt.additional, additionalSz); } if (ret == WC_NO_ERR_TRACE(NOT_COMPILED_IN)) @@ -19145,7 +19119,7 @@ static WC_INLINE int EncryptDo(WOLFSSL* ssl, byte* out, const byte* input, ssl->encrypt.nonce, AESGCM_NONCE_SZ, out + sz - ssl->specs.aead_mac_size, ssl->specs.aead_mac_size, - ssl->encrypt.additional, AEAD_AUTH_DATA_SZ); + ssl->encrypt.additional, additionalSz); } #ifdef WOLFSSL_ASYNC_CRYPT @@ -19166,27 +19140,18 @@ static WC_INLINE int EncryptDo(WOLFSSL* ssl, byte* out, const byte* input, #ifdef HAVE_ARIA case wolfssl_aria_gcm: { - const byte* additionalSrc = input - RECORD_HEADER_SZ; + int additionalSz; byte *outBuf = NULL; - XMEMSET(ssl->encrypt.additional, 0, AEAD_AUTH_DATA_SZ); - - /* sequence number field is 64-bits */ - WriteSEQ(ssl, CUR_ORDER, ssl->encrypt.additional); - /* Store the type, version. Unfortunately, they are in - * the input buffer ahead of the plaintext. */ - #ifdef WOLFSSL_DTLS - if (ssl->options.dtls) { - additionalSrc -= DTLS_HANDSHAKE_EXTRA; - } - #endif - XMEMCPY(ssl->encrypt.additional + AEAD_TYPE_OFFSET, - additionalSrc, 3); + additionalSz = ret = writeAeadAuthData(ssl, + /* Length of the plain text minus the explicit + * IV length minus the authentication tag size. */ + sz - AESGCM_EXP_IV_SZ - ssl->specs.aead_mac_size, type, + ssl->encrypt.additional, 0, NULL, CUR_ORDER); + if (ret < 0) + break; + ret = 0; - /* Store the length of the plain text minus the explicit - * IV length minus the authentication tag size. */ - c16toa(sz - AESGCM_EXP_IV_SZ - ssl->specs.aead_mac_size, - ssl->encrypt.additional + AEAD_LEN_OFFSET); XMEMCPY(ssl->encrypt.nonce, ssl->keys.aead_enc_imp_IV, AESGCM_IMP_IV_SZ); XMEMCPY(ssl->encrypt.nonce + AESGCM_IMP_IV_SZ, @@ -19201,7 +19166,7 @@ static WC_INLINE int EncryptDo(WOLFSSL* ssl, byte* out, const byte* input, (byte*) input + AESGCM_EXP_IV_SZ, sz - AESGCM_EXP_IV_SZ - ssl->specs.aead_mac_size, ssl->encrypt.nonce, AESGCM_NONCE_SZ, - ssl->encrypt.additional, AEAD_AUTH_DATA_SZ, + ssl->encrypt.additional, additionalSz, out + sz - ssl->specs.aead_mac_size, ssl->specs.aead_mac_size ); @@ -19224,7 +19189,7 @@ static WC_INLINE int EncryptDo(WOLFSSL* ssl, byte* out, const byte* input, #if defined(HAVE_CHACHA) && defined(HAVE_POLY1305) && \ !defined(NO_CHAPOL_AEAD) case wolfssl_chacha: - ret = ChachaAEADEncrypt(ssl, out, input, sz); + ret = ChachaAEADEncrypt(ssl, out, input, sz, type); break; #endif @@ -19342,7 +19307,7 @@ static WC_INLINE int EncryptDo(WOLFSSL* ssl, byte* out, const byte* input, } static WC_INLINE int Encrypt(WOLFSSL* ssl, byte* out, const byte* input, - word16 sz, int asyncOkay) + word16 sz, int asyncOkay, byte type) { int ret = 0; @@ -19433,7 +19398,7 @@ static WC_INLINE int Encrypt(WOLFSSL* ssl, byte* out, const byte* input, case CIPHER_STATE_DO: { - ret = EncryptDo(ssl, out, input, sz, asyncOkay); + ret = EncryptDo(ssl, out, input, sz, asyncOkay, type); /* Advance state */ ssl->encrypt.state = CIPHER_STATE_END; @@ -19566,6 +19531,7 @@ static WC_INLINE int DecryptDo(WOLFSSL* ssl, byte* plain, const byte* input, case wolfssl_aes_ccm: /* GCM AEAD macros use same size as CCM */ { wc_AesAuthDecryptFunc aes_auth_fn; + int additionalSz; #ifdef WOLFSSL_ASYNC_CRYPT /* initialize event */ @@ -19584,17 +19550,13 @@ static WC_INLINE int DecryptDo(WOLFSSL* ssl, byte* plain, const byte* input, aes_auth_fn = wc_AesCcmDecrypt; #endif - XMEMSET(ssl->decrypt.additional, 0, AEAD_AUTH_DATA_SZ); - - /* sequence number field is 64-bits */ - WriteSEQ(ssl, PEER_ORDER, ssl->decrypt.additional); - - ssl->decrypt.additional[AEAD_TYPE_OFFSET] = ssl->curRL.type; - ssl->decrypt.additional[AEAD_VMAJ_OFFSET] = ssl->curRL.pvMajor; - ssl->decrypt.additional[AEAD_VMIN_OFFSET] = ssl->curRL.pvMinor; - - c16toa(sz - AESGCM_EXP_IV_SZ - ssl->specs.aead_mac_size, - ssl->decrypt.additional + AEAD_LEN_OFFSET); + additionalSz = writeAeadAuthData(ssl, + sz - AESGCM_EXP_IV_SZ - ssl->specs.aead_mac_size, no_type, + ssl->decrypt.additional, 1, NULL, PEER_ORDER); + if (additionalSz < 0) { + ret = additionalSz; + break; + } #if defined(WOLFSSL_DTLS) && defined(HAVE_SECURE_RENEGOTIATION) if (ssl->options.dtls && IsDtlsMsgSCRKeys(ssl)) @@ -19617,7 +19579,7 @@ static WC_INLINE int DecryptDo(WOLFSSL* ssl, byte* plain, const byte* input, ssl->decrypt.nonce, AESGCM_NONCE_SZ, (byte *)(input + sz - ssl->specs.aead_mac_size), ssl->specs.aead_mac_size, - ssl->decrypt.additional, AEAD_AUTH_DATA_SZ); + ssl->decrypt.additional, additionalSz); } if (ret == WC_NO_ERR_TRACE(NOT_COMPILED_IN)) @@ -19630,7 +19592,7 @@ static WC_INLINE int DecryptDo(WOLFSSL* ssl, byte* plain, const byte* input, ssl->decrypt.nonce, AESGCM_NONCE_SZ, input + sz - ssl->specs.aead_mac_size, ssl->specs.aead_mac_size, - ssl->decrypt.additional, AEAD_AUTH_DATA_SZ)) < 0) { + ssl->decrypt.additional, additionalSz)) < 0) { #ifdef WOLFSSL_ASYNC_CRYPT if (ret == WC_NO_ERR_TRACE(WC_PENDING_E)) { ret = wolfSSL_AsyncPush(ssl, @@ -19647,17 +19609,14 @@ static WC_INLINE int DecryptDo(WOLFSSL* ssl, byte* plain, const byte* input, case wolfssl_aria_gcm: { byte *outBuf = NULL; - XMEMSET(ssl->decrypt.additional, 0, AEAD_AUTH_DATA_SZ); - - /* sequence number field is 64-bits */ - WriteSEQ(ssl, PEER_ORDER, ssl->decrypt.additional); - - ssl->decrypt.additional[AEAD_TYPE_OFFSET] = ssl->curRL.type; - ssl->decrypt.additional[AEAD_VMAJ_OFFSET] = ssl->curRL.pvMajor; - ssl->decrypt.additional[AEAD_VMIN_OFFSET] = ssl->curRL.pvMinor; + int additionalSz; - c16toa(sz - AESGCM_EXP_IV_SZ - ssl->specs.aead_mac_size, - ssl->decrypt.additional + AEAD_LEN_OFFSET); + additionalSz = ret = writeAeadAuthData(ssl, + sz - AESGCM_EXP_IV_SZ - ssl->specs.aead_mac_size, no_type, + ssl->decrypt.additional, 1, NULL, PEER_ORDER); + if (ret < 0) + break; + ret = 0; #if defined(WOLFSSL_DTLS) && defined(HAVE_SECURE_RENEGOTIATION) if (ssl->options.dtls && IsDtlsMsgSCRKeys(ssl)) @@ -19680,7 +19639,7 @@ static WC_INLINE int DecryptDo(WOLFSSL* ssl, byte* plain, const byte* input, (byte *)input + AESGCM_EXP_IV_SZ, sz - AESGCM_EXP_IV_SZ - ssl->specs.aead_mac_size, ssl->decrypt.nonce, AESGCM_NONCE_SZ, - ssl->decrypt.additional, AEAD_AUTH_DATA_SZ, + ssl->decrypt.additional, additionalSz, (byte *)input + sz - ssl->specs.aead_mac_size, ssl->specs.aead_mac_size ); @@ -20003,12 +19962,7 @@ static WC_INLINE int CipherHasExpIV(WOLFSSL *ssl) /* check cipher text size for sanity */ static int SanityCheckCipherText(WOLFSSL* ssl, word32 encryptSz) { -#ifdef HAVE_TRUNCATED_HMAC - word32 minLength = ssl->truncated_hmac ? (byte)TRUNCATED_HMAC_SZ - : ssl->specs.hash_size; -#else - word32 minLength = ssl->specs.hash_size; /* covers stream */ -#endif + word32 minLength = MacSize(ssl); #ifndef WOLFSSL_AEAD_ONLY if (ssl->specs.cipher_type == block) { @@ -20466,10 +20420,9 @@ int TimingPadVerify(WOLFSSL* ssl, const byte* input, int padLen, int macSz, int DoApplicationData(WOLFSSL* ssl, byte* input, word32* inOutIdx, int sniff) { - word32 msgSz = WOLFSSL_IS_QUIC(ssl)? ssl->curSize : ssl->keys.encryptSz; + word32 msgSz = ssl->curSize; word32 idx = *inOutIdx; int dataSz; - int ivExtra = 0; byte* rawData = input + idx; /* keep current for hmac */ #ifdef HAVE_LIBZ byte decomp[MAX_RECORD_SIZE + MAX_COMP_EXTRA]; @@ -20530,23 +20483,7 @@ int DoApplicationData(WOLFSSL* ssl, byte* input, word32* inOutIdx, int sniff) } #endif -#ifndef WOLFSSL_AEAD_ONLY - if (ssl->specs.cipher_type == block) { - if (ssl->options.tls1_1) - ivExtra = ssl->specs.block_size; - } - else -#endif - if (ssl->specs.cipher_type == aead) { - if (CipherHasExpIV(ssl)) - ivExtra = AESGCM_EXP_IV_SZ; - } - - dataSz = (int)(msgSz - (word32)ivExtra - ssl->keys.padSz); -#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) - if (ssl->options.startedETMRead) - dataSz -= MacSize(ssl); -#endif + dataSz = msgSz - ssl->keys.padSz; if (dataSz < 0) { WOLFSSL_MSG("App data buffer error, malicious input?"); if (sniff == NO_SNIFF) { @@ -20585,10 +20522,6 @@ int DoApplicationData(WOLFSSL* ssl, byte* input, word32* inOutIdx, int sniff) } idx += ssl->keys.padSz; -#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) - if (ssl->options.startedETMRead) - idx += MacSize(ssl); -#endif #ifdef HAVE_LIBZ /* decompress could be bigger, overwrite after verify */ @@ -20838,26 +20771,8 @@ static int DoAlert(WOLFSSL* ssl, byte* input, word32* inOutIdx, int* type) } #endif - if (IsEncryptionOn(ssl, 0)) { - word32 ivExtra = 0; -#ifndef WOLFSSL_AEAD_ONLY - if (ssl->specs.cipher_type == block) { - if (ssl->options.tls1_1) - ivExtra = ssl->specs.block_size; - } - else -#endif - if (ssl->specs.cipher_type == aead) { - if (CipherHasExpIV(ssl)) - ivExtra = AESGCM_EXP_IV_SZ; - } - dataSz -= ivExtra; + if (IsEncryptionOn(ssl, 0)) dataSz -= ssl->keys.padSz; - #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) - if (ssl->options.startedETMRead) - dataSz -= MacSize(ssl); - #endif - } /* make sure can read the message */ if (dataSz != ALERT_SIZE) { @@ -20900,10 +20815,6 @@ static int DoAlert(WOLFSSL* ssl, byte* input, word32* inOutIdx, int* type) if (IsEncryptionOn(ssl, 0)) { *inOutIdx += ssl->keys.padSz; - #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) - if (ssl->options.startedETMRead) - *inOutIdx += MacSize(ssl); - #endif } return level; @@ -21029,20 +20940,12 @@ static WC_INLINE int VerifyMac(WOLFSSL* ssl, const byte* input, word32 msgSz, int ret; word32 pad = 0; word32 padByte = 0; -#ifdef HAVE_TRUNCATED_HMAC - word32 digestSz = ssl->truncated_hmac ? (byte)TRUNCATED_HMAC_SZ - : ssl->specs.hash_size; -#else - word32 digestSz = ssl->specs.hash_size; -#endif + word32 digestSz = MacSize(ssl); byte verify[WC_MAX_DIGEST_SIZE]; if (ssl->specs.cipher_type == block) { - int ivExtra = 0; - if (ssl->options.tls1_1) - ivExtra = ssl->specs.block_size; - pad = *(input + msgSz - ivExtra - 1); + pad = input[msgSz - 1]; padByte = 1; if (ssl->options.tls) { @@ -21051,8 +20954,8 @@ static WC_INLINE int VerifyMac(WOLFSSL* ssl, const byte* input, word32 msgSz, if(ssl->ctx->VerifyMacCb) { void* ctx = wolfSSL_GetVerifyMacCtx(ssl); ret = ssl->ctx->VerifyMacCb(ssl, input, - (msgSz - ivExtra) - digestSz - pad - 1, - digestSz, (word32)content, ctx); + msgSz - digestSz - pad - 1, + digestSz, (word32)content, ctx); if (ret != 0 && ret != WC_NO_ERR_TRACE(PROTOCOLCB_UNAVAILABLE)) { return ret; @@ -21062,7 +20965,7 @@ static WC_INLINE int VerifyMac(WOLFSSL* ssl, const byte* input, word32 msgSz, ret == WC_NO_ERR_TRACE(PROTOCOLCB_UNAVAILABLE)) #endif ret = TimingPadVerify(ssl, input, (int)pad, (int)digestSz, - (int)(msgSz - (word32)ivExtra), content); + (int)msgSz, content); if (ret != 0) return ret; } @@ -21111,7 +21014,7 @@ static WC_INLINE int VerifyMac(WOLFSSL* ssl, const byte* input, word32 msgSz, } #if !defined(WOLFSSL_NO_TLS12) && !defined(WOLFSSL_AEAD_ONLY) else { - *padSz = digestSz + pad + padByte; + *padSz = pad + padByte; } #endif /* !WOLFSSL_NO_TLS12 && !WOLFSSL_AEAD_ONLY */ @@ -21180,6 +21083,38 @@ static int DtlsShouldDrop(WOLFSSL* ssl, int retcode) } #endif /* WOLFSSL_DTLS */ +#if defined(WOLFSSL_TLS13) || defined(WOLFSSL_DTLS) && defined(WOLFSSL_DTLS_CID) +static int removeMsgInnerPadding(WOLFSSL* ssl) +{ + word32 i = ssl->buffers.inputBuffer.idx + + ssl->curSize; + if (ssl->specs.cipher_type == aead) + i -= ssl->specs.aead_mac_size; + else + i -= ssl->keys.padSz + MacSize(ssl); + + /* check that the end of the logical length doesn't extend + * past the real buffer */ + if (i > ssl->buffers.inputBuffer.length || i == 0) { + WOLFSSL_ERROR(BUFFER_ERROR); + return BUFFER_ERROR; + } + + /* Remove padding from end of plain text. */ + for (--i; i > ssl->buffers.inputBuffer.idx; i--) { + if (ssl->buffers.inputBuffer.buffer[i] != 0) + break; + } + + /* Get the real content type from the end of the data. */ + ssl->curRL.type = ssl->buffers.inputBuffer.buffer[i]; + /* consider both contentType byte and MAC as padding */ + ssl->keys.padSz = ssl->buffers.inputBuffer.idx + + ssl->curSize - i; + return 0; +} +#endif + int ProcessReply(WOLFSSL* ssl) { return ProcessReplyEx(ssl, 0); @@ -21490,8 +21425,6 @@ int ProcessReplyEx(WOLFSSL* ssl, int allowSocketErr) ssl->keys.padSz = 0; ssl->options.processReply = verifyEncryptedMessage; - /* in case > 1 msg per record */ - ssl->curStartIdx = ssl->buffers.inputBuffer.idx; FALL_THROUGH; /* verify digest of encrypted message */ @@ -21659,12 +21592,17 @@ int ProcessReplyEx(WOLFSSL* ssl, int allowSocketErr) #ifndef WOLFSSL_NO_TLS12 /* handle success */ #ifndef WOLFSSL_AEAD_ONLY - if (ssl->options.tls1_1 && ssl->specs.cipher_type == block) + if (ssl->options.tls1_1 && + ssl->specs.cipher_type == block) { ssl->buffers.inputBuffer.idx += ssl->specs.block_size; + ssl->curSize -= ssl->specs.block_size; + } #endif /* go past TLSv1.1 IV */ - if (CipherHasExpIV(ssl)) + if (CipherHasExpIV(ssl)) { ssl->buffers.inputBuffer.idx += AESGCM_EXP_IV_SZ; + ssl->curSize -= AESGCM_EXP_IV_SZ; + } #endif } else { @@ -21761,32 +21699,46 @@ int ProcessReplyEx(WOLFSSL* ssl, int allowSocketErr) ssl->keys.encryptSz = ssl->curSize; ssl->keys.decryptedCur = 1; -#ifdef WOLFSSL_TLS13 - if (ssl->options.tls1_3) { - word32 i = (ssl->buffers.inputBuffer.idx + - ssl->curSize - ssl->specs.aead_mac_size); - /* check that the end of the logical length doesn't extend - * past the real buffer */ - if (i > ssl->buffers.inputBuffer.length || i == 0) { - WOLFSSL_ERROR(BUFFER_ERROR); - return BUFFER_ERROR; - } - - /* Remove padding from end of plain text. */ - for (--i; i > ssl->buffers.inputBuffer.idx; i--) { - if (ssl->buffers.inputBuffer.buffer[i] != 0) - break; - } + } - /* Get the real content type from the end of the data. */ - ssl->curRL.type = ssl->buffers.inputBuffer.buffer[i]; - /* consider both contentType byte and MAC as padding */ - ssl->keys.padSz = ssl->buffers.inputBuffer.idx - + ssl->curSize - i; + if (IsEncryptionOn(ssl, 0) && ssl->keys.decryptedCur == 1) { +#if defined(WOLFSSL_TLS13) || defined(WOLFSSL_DTLS) && defined(WOLFSSL_DTLS_CID) + int removePadding = 0; + if (ssl->options.tls1_3) + removePadding = 1; +#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_DTLS_CID) + if (!ssl->options.tls1_3 && ssl->options.dtls && + ssl->curRL.type == dtls12_cid) + removePadding = 1; +#endif + if (removePadding) { + ret = removeMsgInnerPadding(ssl); + if (ret != 0) + return ret; } + else +#endif + { +#ifdef HAVE_ENCRYPT_THEN_MAC + word16 startedETMRead = ssl->options.startedETMRead; +#else + word16 startedETMRead = 0; #endif + /* With atomicUser the callback should have already included + * the mac in the padding size. The ETM callback doesn't do + * this for some reason. */ + if (ssl->specs.cipher_type != aead && + (!atomicUser || startedETMRead)) { + /* consider MAC as padding */ + ssl->keys.padSz += MacSize(ssl); + } + } + } + /* in case > 1 msg per record */ + ssl->curStartIdx = ssl->buffers.inputBuffer.idx; + ssl->options.processReply = runProcessingOneRecord; FALL_THROUGH; @@ -21835,9 +21787,7 @@ int ProcessReplyEx(WOLFSSL* ssl, int allowSocketErr) if (IsEncryptionOn(ssl, 0) && ssl->options.startedETMRead) { /* For TLS v1.1 the block size and explicit IV are added to idx, * so it needs to be included in this limit check */ - if ((ssl->curSize - ssl->keys.padSz - - (ssl->buffers.inputBuffer.idx - ssl->curStartIdx) - - MacSize(ssl) > MAX_PLAINTEXT_SZ) + if ((ssl->curSize - ssl->keys.padSz > MAX_PLAINTEXT_SZ) #ifdef WOLFSSL_ASYNC_CRYPT && ssl->buffers.inputBuffer.length != ssl->buffers.inputBuffer.idx @@ -21857,9 +21807,7 @@ int ProcessReplyEx(WOLFSSL* ssl, int allowSocketErr) /* For TLS v1.1 the block size and explicit IV are added to idx, * so it needs to be included in this limit check */ if (!IsAtLeastTLSv1_3(ssl->version) - && ssl->curSize - ssl->keys.padSz - - (ssl->buffers.inputBuffer.idx - ssl->curStartIdx) - > MAX_PLAINTEXT_SZ + && ssl->curSize - ssl->keys.padSz > MAX_PLAINTEXT_SZ #ifdef WOLFSSL_ASYNC_CRYPT && ssl->buffers.inputBuffer.length != ssl->buffers.inputBuffer.idx @@ -22047,28 +21995,8 @@ int ProcessReplyEx(WOLFSSL* ssl, int allowSocketErr) } if (IsEncryptionOn(ssl, 0) && ssl->options.handShakeDone) { -#ifdef HAVE_AEAD - if (ssl->specs.cipher_type == aead) { - if (ssl->specs.bulk_cipher_algorithm != wolfssl_chacha) - ssl->curSize -= AESGCM_EXP_IV_SZ; - ssl->buffers.inputBuffer.idx += ssl->specs.aead_mac_size; - ssl->curSize -= ssl->specs.aead_mac_size; - } - else -#endif - { - ssl->buffers.inputBuffer.idx += ssl->keys.padSz; - ssl->curSize -= (word16)ssl->keys.padSz; - ssl->curSize -= ssl->specs.iv_size; - } - - #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) - if (ssl->options.startedETMRead) { - word32 digestSz = MacSize(ssl); - ssl->buffers.inputBuffer.idx += digestSz; - ssl->curSize -= (word16)digestSz; - } - #endif + ssl->buffers.inputBuffer.idx += ssl->keys.padSz; + ssl->curSize -= (word16)ssl->keys.padSz; } if (ssl->curSize != 1) { @@ -22272,32 +22200,17 @@ int ProcessReplyEx(WOLFSSL* ssl, int allowSocketErr) ssl->options.processReply = runProcessingOneMessage; if (IsEncryptionOn(ssl, 0)) { - WOLFSSL_MSG("Bundled encrypted messages, remove middle pad"); - #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) - if (ssl->options.startedETMRead) { - word32 digestSz = MacSize(ssl); - if (ssl->buffers.inputBuffer.idx >= - ssl->keys.padSz + digestSz) { - ssl->buffers.inputBuffer.idx -= - ssl->keys.padSz + digestSz; - } - else { - WOLFSSL_MSG("\tmiddle padding error"); - WOLFSSL_ERROR_VERBOSE(FATAL_ERROR); - return FATAL_ERROR; - } + /* With encryption on, we advance the index by the value + * of ssl->keys.padSz. Since padding only appears once, we + * only can do this at the end of record parsing. We have to + * reset the index to the start of the next message here. */ + if (ssl->buffers.inputBuffer.idx >= ssl->keys.padSz) { + ssl->buffers.inputBuffer.idx -= ssl->keys.padSz; } - else - #endif - { - if (ssl->buffers.inputBuffer.idx >= ssl->keys.padSz) { - ssl->buffers.inputBuffer.idx -= ssl->keys.padSz; - } - else { - WOLFSSL_MSG("\tmiddle padding error"); - WOLFSSL_ERROR_VERBOSE(FATAL_ERROR); - return FATAL_ERROR; - } + else { + WOLFSSL_MSG("\tBuffer advanced not enough error"); + WOLFSSL_ERROR_VERBOSE(FATAL_ERROR); + return FATAL_ERROR; } } } @@ -22835,6 +22748,7 @@ int BuildMessage(WOLFSSL* ssl, byte* output, int outSz, const byte* input, args->sz = RECORD_HEADER_SZ + (word32)inSz; args->idx = RECORD_HEADER_SZ; args->headerSz = RECORD_HEADER_SZ; + args->type = (byte)type; } switch (ssl->options.buildMsgState) { @@ -22900,6 +22814,18 @@ int BuildMessage(WOLFSSL* ssl, byte* output, int outSz, const byte* input, args->sz += DTLS_RECORD_EXTRA; args->idx += DTLS_RECORD_EXTRA; args->headerSz += DTLS_RECORD_EXTRA; + #ifdef WOLFSSL_DTLS_CID + if (ssl->options.dtls) { + unsigned int cidSz = 0; + if (wolfSSL_dtls_cid_get_tx_size(ssl, &cidSz) + == WOLFSSL_SUCCESS) { + args->sz += cidSz; + args->idx += cidSz; + args->headerSz += cidSz; + args->sz++; /* real_type. no padding. */ + } + } + #endif } #endif @@ -22981,7 +22907,13 @@ int BuildMessage(WOLFSSL* ssl, byte* output, int outSz, const byte* input, #endif args->size = (word16)(args->sz - args->headerSz); /* include mac and digest */ - AddRecordHeader(output, args->size, (byte)type, ssl, epochOrder); + +#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_DTLS_CID) + if (ssl->options.dtls && + wolfSSL_dtls_cid_get_tx_size(ssl, NULL) == WOLFSSL_SUCCESS) + args->type = dtls12_cid; +#endif + AddRecordHeader(output, args->size, args->type, ssl, epochOrder); /* write to output */ if (args->ivSz > 0) { @@ -22991,6 +22923,16 @@ int BuildMessage(WOLFSSL* ssl, byte* output, int outSz, const byte* input, } XMEMCPY(output + args->idx, input, inSz); args->idx += (word32)inSz; +#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_DTLS_CID) + if (ssl->options.dtls && + wolfSSL_dtls_cid_get_tx_size(ssl, NULL) == WOLFSSL_SUCCESS) { + output[args->idx++] = (byte)type; /* type goes after input */ + inSz++; + } +#endif + /* Make sure we don't access input anymore as inSz may have been + * incremented */ + input = NULL; ssl->options.buildMsgState = BUILD_MSG_HASH; } @@ -23003,7 +22945,7 @@ int BuildMessage(WOLFSSL* ssl, byte* output, int outSz, const byte* input, if (type == handshake && hashOutput) { ret = HashOutput(ssl, output, - (int)(args->headerSz + (word32)inSz), (int)args->ivSz); + (int)(args->headerSz + (word32)inSz), (int)args->ivSz); if (ret != 0) goto exit_buildmsg; } @@ -23039,7 +22981,7 @@ int BuildMessage(WOLFSSL* ssl, byte* output, int outSz, const byte* input, if (ssl->options.startedETMWrite) { if (ssl->ctx->EncryptMacCb) { ret = ssl->ctx->EncryptMacCb(ssl, output + args->idx + - args->pad + 1, type, 0, + args->pad + 1, args->type, 0, output + args->headerSz, output + args->headerSz, args->size - args->digestSz, @@ -23052,8 +22994,9 @@ int BuildMessage(WOLFSSL* ssl, byte* output, int outSz, const byte* input, { if (ssl->ctx->MacEncryptCb) { ret = ssl->ctx->MacEncryptCb(ssl, output + args->idx, - output + args->headerSz + args->ivSz, (unsigned int)inSz, - type, 0, output + args->headerSz, + output + args->headerSz + args->ivSz, + (unsigned int)inSz, args->type, 0, + output + args->headerSz, output + args->headerSz, args->size, ssl->MacEncryptCtx); goto exit_buildmsg; @@ -23084,8 +23027,9 @@ int BuildMessage(WOLFSSL* ssl, byte* output, int outSz, const byte* input, #endif ret = ssl->hmac(ssl, hmac, - output + args->headerSz + args->ivSz, (word32)inSz, - -1, type, 0, epochOrder); + output + args->headerSz + args->ivSz, + (word32)inSz, -1, args->type, 0, + epochOrder); XMEMCPY(output + args->idx, hmac, args->digestSz); #ifdef WOLFSSL_SMALL_STACK @@ -23096,7 +23040,8 @@ int BuildMessage(WOLFSSL* ssl, byte* output, int outSz, const byte* input, #endif { ret = ssl->hmac(ssl, output + args->idx, output + - args->headerSz + args->ivSz, (word32)inSz, -1, type, 0, epochOrder); + args->headerSz + args->ivSz, (word32)inSz, -1, + args->type, 0, epochOrder); } } #endif /* WOLFSSL_AEAD_ONLY */ @@ -23137,13 +23082,14 @@ int BuildMessage(WOLFSSL* ssl, byte* output, int outSz, const byte* input, ret = Encrypt(ssl, output + args->headerSz, output + args->headerSz, (word16)(args->size - args->digestSz), - asyncOkay); + asyncOkay, args->type); } else #endif { ret = Encrypt(ssl, output + args->headerSz, - output + args->headerSz, args->size, asyncOkay); + output + args->headerSz, args->size, asyncOkay, + args->type); } #if defined(HAVE_SECURE_RENEGOTIATION) && defined(WOLFSSL_DTLS) /* Restore sequence numbers */ @@ -23204,8 +23150,8 @@ int BuildMessage(WOLFSSL* ssl, byte* output, int outSz, const byte* input, #endif ret = ssl->hmac(ssl, hmac, output + args->headerSz, - args->ivSz + inSz + args->pad + 1, -1, type, - 0, epochOrder); + args->ivSz + inSz + args->pad + 1, -1, + args->type, 0, epochOrder); XMEMCPY(output + args->idx + args->pad + 1, hmac, args->digestSz); @@ -23219,8 +23165,7 @@ int BuildMessage(WOLFSSL* ssl, byte* output, int outSz, const byte* input, ret = ssl->hmac(ssl, output + args->idx + args->pad + 1, output + args->headerSz, args->ivSz + (word32)inSz + args->pad + 1, - -1, type, - 0, epochOrder); + -1, args->type, 0, epochOrder); } } #endif /* HAVE_ENCRYPT_THEN_MAC && !WOLFSSL_AEAD_ONLY */ @@ -23291,6 +23236,13 @@ int SendFinished(WOLFSSL* ssl) /* check for available size */ outputSz = sizeof(input) + MAX_MSG_EXTRA; +#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_DTLS_CID) + if (ssl->options.dtls) { + unsigned int cidSz = 0; + if (wolfSSL_dtls_cid_get_tx_size(ssl, &cidSz) == WOLFSSL_SUCCESS) + outputSz += cidSz + 1; /* +1 for inner content type */ + } +#endif /* Set this in case CheckAvailableSize returns a WANT_WRITE so that state * is not advanced yet */ @@ -23355,6 +23307,7 @@ int SendFinished(WOLFSSL* ssl) } #endif + ssl->keys.encryptionOn = 1; sendSz = BuildMessage(ssl, output, outputSz, input, headerSz + finishedSz, handshake, 1, 0, 0, CUR_ORDER); if (sendSz < 0) @@ -23593,6 +23546,14 @@ int cipherExtraData(WOLFSSL* ssl) cipherExtra = ssl->specs.iv_size + ssl->specs.block_size + ssl->specs.hash_size; } + /* Add space needed for the CID */ +#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_DTLS_CID) + if (ssl->options.dtls) { + unsigned int cidSz = 0; + if (wolfSSL_dtls_cid_get_tx_size(ssl, &cidSz) == WOLFSSL_SUCCESS) + cipherExtra += cidSz + 1; /* +1 for inner content type */ + } +#endif /* Sanity check so we don't ever return negative. */ return cipherExtra > 0 ? cipherExtra : 0; } @@ -24798,7 +24759,7 @@ int SendData(WOLFSSL* ssl, const void* data, int sz) if (ssl->options.dtls) { unsigned int cidSz = 0; if (wolfSSL_dtls_cid_get_tx_size(ssl, &cidSz) == WOLFSSL_SUCCESS) - outputSz += cidSz; + outputSz += cidSz + 1; /* +1 for inner content type */ } #endif @@ -29817,13 +29778,8 @@ static int HashSkeData(WOLFSSL* ssl, enum wc_HashType hashType, #endif #ifdef WOLFSSL_DTLS - if (ssl->options.dtls) { + if (ssl->options.dtls) DtlsMsgPoolReset(ssl); -#ifdef WOLFSSL_DTLS_CID - if (ssl->options.useDtlsCID) - DtlsCIDOnExtensionsParsed(ssl); -#endif /* WOLFSSL_DTLS_CID */ - } #endif if (OPAQUE16_LEN + OPAQUE8_LEN > size) @@ -30277,15 +30233,8 @@ static int HashSkeData(WOLFSSL* ssl, enum wc_HashType hashType, ssl->options.serverState = SERVER_HELLO_COMPLETE; - if (IsEncryptionOn(ssl, 0)) { + if (IsEncryptionOn(ssl, 0)) *inOutIdx += ssl->keys.padSz; - #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) - if (ssl->options.startedETMWrite && - ssl->specs.cipher_type == block) { - *inOutIdx += MacSize(ssl); - } - #endif - } #ifdef HAVE_SECRET_CALLBACK if (ssl->sessionSecretCb != NULL @@ -30617,13 +30566,8 @@ static int HashSkeData(WOLFSSL* ssl, enum wc_HashType hashType, ssl->options.sendVerify = SEND_BLANK_CERT; } - if (IsEncryptionOn(ssl, 0)) { + if (IsEncryptionOn(ssl, 0)) *inOutIdx += ssl->keys.padSz; - #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) - if (ssl->options.startedETMRead) - *inOutIdx += MacSize(ssl); - #endif - } WOLFSSL_LEAVE("DoCertificateRequest", 0); WOLFSSL_END(WC_FUNC_CERTIFICATE_REQUEST_DO); @@ -32011,13 +31955,8 @@ static int DoServerKeyExchange(WOLFSSL* ssl, const byte* input, case TLS_ASYNC_FINALIZE: { - if (IsEncryptionOn(ssl, 0)) { + if (IsEncryptionOn(ssl, 0)) args->idx += ssl->keys.padSz; - #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) - if (ssl->options.startedETMRead) - args->idx += MacSize(ssl); - #endif - } /* Advance state and proceed */ ssl->options.asyncState = TLS_ASYNC_END; @@ -33980,13 +33919,8 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, #endif } - if (IsEncryptionOn(ssl, 0)) { + if (IsEncryptionOn(ssl, 0)) *inOutIdx += ssl->keys.padSz; - #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) - if (ssl->options.startedETMRead) - *inOutIdx += MacSize(ssl); - #endif - } ssl->expect_session_ticket = 0; @@ -37792,13 +37726,8 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, case TLS_ASYNC_FINALIZE: { - if (IsEncryptionOn(ssl, 0)) { + if (IsEncryptionOn(ssl, 0)) args->idx += ssl->keys.padSz; - #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) - if (ssl->options.startedETMRead) - args->idx += MacSize(ssl); - #endif - } ssl->options.havePeerVerify = 1; @@ -40877,13 +40806,8 @@ static int DefTicketEncCb(WOLFSSL* ssl, byte key_name[WOLFSSL_TICKET_NAME_SZ], case TLS_ASYNC_FINALIZE: { - if (IsEncryptionOn(ssl, 0)) { + if (IsEncryptionOn(ssl, 0)) args->idx += ssl->keys.padSz; - #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) - if (ssl->options.startedETMRead) - args->idx += MacSize(ssl); - #endif - } ret = MakeMasterSecret(ssl); diff --git a/src/sniffer.c b/src/sniffer.c index 7be98cdef0..1299c2ad0a 100644 --- a/src/sniffer.c +++ b/src/sniffer.c @@ -6495,6 +6495,7 @@ static int ProcessMessage(const byte* sslFrame, SnifferSession* session, case ack: /* TODO */ #endif /* WOLFSSL_DTLS13 */ + case dtls12_cid: case no_type: default: SetError(GOT_UNKNOWN_RECORD_STR, error, session, FATAL_ERROR_STATE); diff --git a/src/ssl.c b/src/ssl.c index 264f2c04ec..98f1b80f2c 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -4850,7 +4850,7 @@ int wolfSSL_GetVersion(const WOLFSSL* ssl) if (ssl == NULL) return BAD_FUNC_ARG; - if (ssl->version.major == SSLv3_MAJOR) { + if (ssl->version.major == SSLv3_MAJOR || ssl->version.major == DTLS_MAJOR) { switch (ssl->version.minor) { case SSLv3_MINOR : return WOLFSSL_SSLV3; @@ -4862,6 +4862,12 @@ int wolfSSL_GetVersion(const WOLFSSL* ssl) return WOLFSSL_TLSV1_2; case TLSv1_3_MINOR : return WOLFSSL_TLSV1_3; + case DTLS_MINOR : + return WOLFSSL_DTLSV1; + case DTLSv1_2_MINOR : + return WOLFSSL_DTLSV1_2; + case DTLSv1_3_MINOR : + return WOLFSSL_DTLSV1_3; default: break; } @@ -8983,11 +8989,11 @@ int wolfSSL_dtls_got_timeout(WOLFSSL* ssl) int result = WOLFSSL_SUCCESS; WOLFSSL_ENTER("wolfSSL_dtls_got_timeout"); - if (ssl == NULL) + if (ssl == NULL || !ssl->options.dtls) return WOLFSSL_FATAL_ERROR; #ifdef WOLFSSL_DTLS13 - if (ssl->options.dtls && IsAtLeastTLSv1_3(ssl->version)) { + if (IsAtLeastTLSv1_3(ssl->version)) { result = Dtls13RtxTimeout(ssl); if (result < 0) { if (result == WC_NO_ERR_TRACE(WANT_WRITE)) @@ -9001,7 +9007,8 @@ int wolfSSL_dtls_got_timeout(WOLFSSL* ssl) } #endif /* WOLFSSL_DTLS13 */ - if ((IsSCR(ssl) || !ssl->options.handShakeDone)) { + /* Do we have any 1.2 messages stored? */ + if (ssl->dtls_tx_msg_list != NULL || ssl->dtls_tx_msg != NULL) { if (DtlsMsgPoolTimeout(ssl) < 0){ ssl->error = SOCKET_ERROR_E; WOLFSSL_ERROR(ssl->error); @@ -13177,6 +13184,10 @@ size_t wolfSSL_get_client_random(const WOLFSSL* ssl, unsigned char* out, ssl->keys.encryptionOn = 0; XMEMSET(&ssl->msgsReceived, 0, sizeof(ssl->msgsReceived)); + FreeCiphers(ssl); + InitCiphers(ssl); + InitCipherSpecs(&ssl->specs); + if (InitSSL_Suites(ssl) != WOLFSSL_SUCCESS) return WOLFSSL_FAILURE; diff --git a/src/tls.c b/src/tls.c index 0aff791697..3c1e0e7fe9 100644 --- a/src/tls.c +++ b/src/tls.c @@ -760,6 +760,16 @@ int wolfSSL_SetTlsHmacInner(WOLFSSL* ssl, byte* inner, word32 sz, int content, if (ssl == NULL || inner == NULL) return BAD_FUNC_ARG; + if (content == dtls12_cid +#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_DTLS_CID) + || (ssl->options.dtls && + wolfSSL_dtls_cid_get_tx_size(ssl, NULL) == WOLFSSL_SUCCESS) +#endif + ) { + WOLFSSL_MSG("wolfSSL_SetTlsHmacInner doesn't support CID"); + return BAD_FUNC_ARG; + } + XMEMSET(inner, 0, WOLFSSL_TLS_HMAC_INNER_SZ); WriteSEQ(ssl, verify, inner); @@ -904,7 +914,6 @@ static int Hmac_OuterHash(Hmac* hmac, unsigned char* mac) (word32)digestSz); if (ret == 0) ret = wc_HashFinal(&hash, hashType, mac); - wc_HashFree(&hash, hashType); } return ret; @@ -918,10 +927,11 @@ static int Hmac_OuterHash(Hmac* hmac, unsigned char* mac) * in Message data. * sz Size of the message data. * header Constructed record header with length of handshake data. + * headerSz Length of header * returns 0 on success, otherwise failure. */ static int Hmac_UpdateFinal_CT(Hmac* hmac, byte* digest, const byte* in, - word32 sz, int macLen, byte* header) + word32 sz, int macLen, byte* header, word32 headerSz) { byte lenBytes[8]; int i, j; @@ -982,7 +992,7 @@ static int Hmac_UpdateFinal_CT(Hmac* hmac, byte* digest, const byte* in, blockMask = blockSz - 1; /* Size of data to HMAC if padding length byte is zero. */ - maxLen = WOLFSSL_TLS_HMAC_INNER_SZ + sz - 1 - macLen; + maxLen = headerSz + sz - 1 - macLen; /* Complete data (including padding) has block for EOC and/or length. */ extraBlock = ctSetLTE((maxLen + padSz) & blockMask, padSz); /* Total number of blocks for data including padding. */ @@ -1016,11 +1026,10 @@ static int Hmac_UpdateFinal_CT(Hmac* hmac, byte* digest, const byte* in, XMEMSET(hmac->innerHash, 0, macLen); if (safeBlocks > 0) { - ret = Hmac_HashUpdate(hmac, header, WOLFSSL_TLS_HMAC_INNER_SZ); + ret = Hmac_HashUpdate(hmac, header, headerSz); if (ret != 0) return ret; - ret = Hmac_HashUpdate(hmac, in, safeBlocks * blockSz - - WOLFSSL_TLS_HMAC_INNER_SZ); + ret = Hmac_HashUpdate(hmac, in, safeBlocks * blockSz - headerSz); if (ret != 0) return ret; } @@ -1039,10 +1048,10 @@ static int Hmac_UpdateFinal_CT(Hmac* hmac, byte* digest, const byte* in, unsigned char pastEoc = ctMaskGT(j, eocIndex) & isEocBlock; unsigned char b = 0; - if (k < WOLFSSL_TLS_HMAC_INNER_SZ) + if (k < headerSz) b = header[k]; else if (k < maxLen) - b = in[k - WOLFSSL_TLS_HMAC_INNER_SZ]; + b = in[k - headerSz]; k++; b = ctMaskSel(atEoc, 0x80, b); @@ -1085,10 +1094,11 @@ static int Hmac_UpdateFinal_CT(Hmac* hmac, byte* digest, const byte* in, * in Message data. * sz Size of the message data. * header Constructed record header with length of handshake data. + * headerSz Length of header * returns 0 on success, otherwise failure. */ static int Hmac_UpdateFinal(Hmac* hmac, byte* digest, const byte* in, - word32 sz, byte* header) + word32 sz, byte* header, word32 headerSz) { byte dummy[WC_MAX_BLOCK_SIZE] = {0}; int ret = 0; @@ -1174,7 +1184,7 @@ static int Hmac_UpdateFinal(Hmac* hmac, byte* digest, const byte* in, /* Calculate whole blocks. */ msgBlocks--; - ret = wc_HmacUpdate(hmac, header, WOLFSSL_TLS_HMAC_INNER_SZ); + ret = wc_HmacUpdate(hmac, header, headerSz); if (ret == 0) { /* Fill the rest of the block with any available data. */ word32 currSz = ctMaskLT((int)msgSz, blockSz) & msgSz; @@ -1210,11 +1220,67 @@ static int Hmac_UpdateFinal(Hmac* hmac, byte* digest, const byte* in, #endif +#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_DTLS_CID) +#define TLS_HMAC_CID_SZ(s, v, c) \ + ((v) ? wolfSSL_dtls_cid_get_rx_size((s), (c)) \ + : wolfSSL_dtls_cid_get_tx_size((s), (c))) +#define TLS_HMAC_CID(s, v, b, c) \ + ((v) ? wolfSSL_dtls_cid_get_rx((s), (b), (c)) \ + : wolfSSL_dtls_cid_get_tx((s), (b), (c))) +#endif + +static int TLS_hmac_SetInner(WOLFSSL* ssl, byte* inner, word32* innerSz, + word32 sz, int content, int verify, int epochOrder) +{ +#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_DTLS_CID) + unsigned int cidSz = 0; + if (ssl->options.dtls && + TLS_HMAC_CID_SZ(ssl, verify, &cidSz) == WOLFSSL_SUCCESS) { + word32 idx = 0; + if (cidSz > DTLS_CID_MAX_SIZE) { + WOLFSSL_MSG("DTLS CID too large"); + return DTLS_CID_ERROR; + } + + XMEMSET(inner + idx, 0xFF, SEQ_SZ); + idx += SEQ_SZ; + inner[idx++] = dtls12_cid; + inner[idx++] = (byte)cidSz; + inner[idx++] = dtls12_cid; + inner[idx++] = ssl->version.major; + inner[idx++] = ssl->version.minor; + WriteSEQ(ssl, epochOrder, inner + idx); + idx += SEQ_SZ; + if (TLS_HMAC_CID(ssl, verify, inner + idx, cidSz) == + WC_NO_ERR_TRACE(WOLFSSL_FAILURE)) { + WOLFSSL_MSG("DTLS CID write failed"); + return DTLS_CID_ERROR; + } + idx += cidSz; + c16toa((word16)sz, inner + idx); + idx += LENGTH_SZ; + + *innerSz = idx; + return 0; + } +#endif + *innerSz = WOLFSSL_TLS_HMAC_INNER_SZ; + return wolfSSL_SetTlsHmacInner(ssl, inner, sz, content, + !ssl->options.dtls ? verify : epochOrder); +} + +#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_DTLS_CID) +#define TLS_HMAC_INNER_SZ WOLFSSL_TLS_HMAC_CID_INNER_SZ +#else +#define TLS_HMAC_INNER_SZ WOLFSSL_TLS_HMAC_INNER_SZ +#endif + int TLS_hmac(WOLFSSL* ssl, byte* digest, const byte* in, word32 sz, int padSz, int content, int verify, int epochOrder) { Hmac hmac; - byte myInner[WOLFSSL_TLS_HMAC_INNER_SZ]; + byte myInner[TLS_HMAC_INNER_SZ]; + word32 innerSz = TLS_HMAC_INNER_SZ; int ret = 0; const byte* macSecret = NULL; word32 hashSz = 0; @@ -1242,10 +1308,10 @@ int TLS_hmac(WOLFSSL* ssl, byte* digest, const byte* in, word32 sz, int padSz, } #endif - if (!ssl->options.dtls) - wolfSSL_SetTlsHmacInner(ssl, myInner, sz, content, verify); - else - wolfSSL_SetTlsHmacInner(ssl, myInner, sz, content, epochOrder); + ret = TLS_hmac_SetInner(ssl, myInner, &innerSz, sz, content, verify, + epochOrder); + if (ret != 0) + return ret; ret = wc_HmacInit(&hmac, ssl->heap, ssl->devId); if (ret != 0) @@ -1256,10 +1322,8 @@ int TLS_hmac(WOLFSSL* ssl, byte* digest, const byte* in, word32 sz, int padSz, if (ssl->options.dtls) macSecret = wolfSSL_GetDtlsMacSecret(ssl, verify, epochOrder); else - macSecret = wolfSSL_GetMacSecret(ssl, verify); -#else - macSecret = wolfSSL_GetMacSecret(ssl, verify); #endif + macSecret = wolfSSL_GetMacSecret(ssl, verify); ret = wc_HmacSetKey(&hmac, wolfSSL_GetHmacType(ssl), macSecret, ssl->specs.hash_size); @@ -1272,21 +1336,21 @@ int TLS_hmac(WOLFSSL* ssl, byte* digest, const byte* in, word32 sz, int padSz, #ifdef HAVE_BLAKE2 if (wolfSSL_GetHmacType(ssl) == WC_HASH_TYPE_BLAKE2B) { ret = Hmac_UpdateFinal(&hmac, digest, in, - sz + hashSz + padSz + 1, myInner); + sz + hashSz + padSz + 1, myInner, innerSz); } else #endif { ret = Hmac_UpdateFinal_CT(&hmac, digest, in, - sz + hashSz + padSz + 1, hashSz, myInner); + sz + hashSz + padSz + 1, hashSz, myInner, innerSz); } #else ret = Hmac_UpdateFinal(&hmac, digest, in, sz + hashSz + padSz + 1, - myInner); + myInner, innerSz); #endif } else { - ret = wc_HmacUpdate(&hmac, myInner, sizeof(myInner)); + ret = wc_HmacUpdate(&hmac, myInner, innerSz); if (ret == 0) ret = wc_HmacUpdate(&hmac, in, sz); /* content */ if (ret == 0) @@ -12387,27 +12451,36 @@ void TLSX_FreeAll(TLSX* list, void* heap) WOLFSSL_MSG("Encrypt-Then-Mac extension free"); break; #endif -#ifdef WOLFSSL_TLS13 - case TLSX_SUPPORTED_VERSIONS: - WOLFSSL_MSG("Supported Versions extension free"); - break; - - #ifdef WOLFSSL_SEND_HRR_COOKIE - case TLSX_COOKIE: - WOLFSSL_MSG("Cookie extension free"); - CKE_FREE_ALL((Cookie*)extension->data, heap); - break; - #endif +#if defined(WOLFSSL_TLS13) || !defined(WOLFSSL_NO_TLS12) || !defined(NO_OLD_TLS) #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) case TLSX_PRE_SHARED_KEY: WOLFSSL_MSG("Pre-Shared Key extension free"); PSK_FREE_ALL((PreSharedKey*)extension->data, heap); break; + #ifdef WOLFSSL_TLS13 case TLSX_PSK_KEY_EXCHANGE_MODES: WOLFSSL_MSG("PSK Key Exchange Modes extension free"); break; + #endif + #endif + + case TLSX_KEY_SHARE: + WOLFSSL_MSG("Key Share extension free"); + KS_FREE_ALL((KeyShareEntry*)extension->data, heap); + break; +#endif +#ifdef WOLFSSL_TLS13 + case TLSX_SUPPORTED_VERSIONS: + WOLFSSL_MSG("Supported Versions extension free"); + break; + + #ifdef WOLFSSL_SEND_HRR_COOKIE + case TLSX_COOKIE: + WOLFSSL_MSG("Cookie extension free"); + CKE_FREE_ALL((Cookie*)extension->data, heap); + break; #endif #ifdef WOLFSSL_EARLY_DATA @@ -12427,11 +12500,6 @@ void TLSX_FreeAll(TLSX* list, void* heap) WOLFSSL_MSG("Signature Algorithms extension free"); break; #endif - - case TLSX_KEY_SHARE: - WOLFSSL_MSG("Key Share extension free"); - KS_FREE_ALL((KeyShareEntry*)extension->data, heap); - break; #if !defined(NO_CERTS) && !defined(WOLFSSL_NO_CA_NAMES) case TLSX_CERTIFICATE_AUTHORITIES: WOLFSSL_MSG("Certificate Authorities extension free"); @@ -12582,26 +12650,33 @@ static int TLSX_GetSize(TLSX* list, byte* semaphore, byte msgType, ret = ETM_GET_SIZE(msgType, &length); break; #endif /* HAVE_ENCRYPT_THEN_MAC */ -#ifdef WOLFSSL_TLS13 - case TLSX_SUPPORTED_VERSIONS: - ret = SV_GET_SIZE(extension->data, msgType, &length); - break; - - #ifdef WOLFSSL_SEND_HRR_COOKIE - case TLSX_COOKIE: - ret = CKE_GET_SIZE((Cookie*)extension->data, msgType, &length); - break; - #endif +#if defined(WOLFSSL_TLS13) || !defined(WOLFSSL_NO_TLS12) || !defined(NO_OLD_TLS) #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) case TLSX_PRE_SHARED_KEY: ret = PSK_GET_SIZE((PreSharedKey*)extension->data, msgType, &length); break; - + #ifdef WOLFSSL_TLS13 case TLSX_PSK_KEY_EXCHANGE_MODES: ret = PKM_GET_SIZE((byte)extension->val, msgType, &length); break; + #endif + #endif + case TLSX_KEY_SHARE: + length += KS_GET_SIZE((KeyShareEntry*)extension->data, msgType); + break; +#endif + +#ifdef WOLFSSL_TLS13 + case TLSX_SUPPORTED_VERSIONS: + ret = SV_GET_SIZE(extension->data, msgType, &length); + break; + + #ifdef WOLFSSL_SEND_HRR_COOKIE + case TLSX_COOKIE: + ret = CKE_GET_SIZE((Cookie*)extension->data, msgType, &length); + break; #endif #ifdef WOLFSSL_EARLY_DATA @@ -12622,9 +12697,6 @@ static int TLSX_GetSize(TLSX* list, byte* semaphore, byte msgType, break; #endif - case TLSX_KEY_SHARE: - length += KS_GET_SIZE((KeyShareEntry*)extension->data, msgType); - break; #if !defined(NO_CERTS) && !defined(WOLFSSL_NO_CA_NAMES) case TLSX_CERTIFICATE_AUTHORITIES: length += CAN_GET_SIZE(extension->data); @@ -12806,20 +12878,8 @@ static int TLSX_Write(TLSX* list, byte* output, byte* semaphore, ret = ETM_WRITE(extension->data, output, msgType, &offset); break; #endif /* HAVE_ENCRYPT_THEN_MAC */ -#ifdef WOLFSSL_TLS13 - case TLSX_SUPPORTED_VERSIONS: - WOLFSSL_MSG("Supported Versions extension to write"); - ret = SV_WRITE(extension->data, output + offset, msgType, &offset); - break; - - #ifdef WOLFSSL_SEND_HRR_COOKIE - case TLSX_COOKIE: - WOLFSSL_MSG("Cookie extension to write"); - ret = CKE_WRITE((Cookie*)extension->data, output + offset, - msgType, &offset); - break; - #endif +#if defined(WOLFSSL_TLS13) || !defined(WOLFSSL_NO_TLS12) || !defined(NO_OLD_TLS) #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) case TLSX_PRE_SHARED_KEY: WOLFSSL_MSG("Pre-Shared Key extension to write"); @@ -12827,11 +12887,33 @@ static int TLSX_Write(TLSX* list, byte* output, byte* semaphore, msgType, &offset); break; + #ifdef WOLFSSL_TLS13 case TLSX_PSK_KEY_EXCHANGE_MODES: WOLFSSL_MSG("PSK Key Exchange Modes extension to write"); ret = PKM_WRITE((byte)extension->val, output + offset, msgType, &offset); break; + #endif + #endif + case TLSX_KEY_SHARE: + WOLFSSL_MSG("Key Share extension to write"); + offset += KS_WRITE((KeyShareEntry*)extension->data, + output + offset, msgType); + break; +#endif +#ifdef WOLFSSL_TLS13 + case TLSX_SUPPORTED_VERSIONS: + WOLFSSL_MSG("Supported Versions extension to write"); + ret = SV_WRITE(extension->data, output + offset, msgType, + &offset); + break; + + #ifdef WOLFSSL_SEND_HRR_COOKIE + case TLSX_COOKIE: + WOLFSSL_MSG("Cookie extension to write"); + ret = CKE_WRITE((Cookie*)extension->data, output + offset, + msgType, &offset); + break; #endif #ifdef WOLFSSL_EARLY_DATA @@ -12856,11 +12938,6 @@ static int TLSX_Write(TLSX* list, byte* output, byte* semaphore, break; #endif - case TLSX_KEY_SHARE: - WOLFSSL_MSG("Key Share extension to write"); - offset += KS_WRITE((KeyShareEntry*)extension->data, - output + offset, msgType); - break; #if !defined(NO_CERTS) && !defined(WOLFSSL_NO_CA_NAMES) case TLSX_CERTIFICATE_AUTHORITIES: WOLFSSL_MSG("Certificate Authorities extension to write"); @@ -14123,9 +14200,6 @@ int TLSX_GetResponseSize(WOLFSSL* ssl, byte msgType, word16* pLength) #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY)); #endif - #ifdef WOLFSSL_DTLS_CID - TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_CONNECTION_ID)); - #endif } #if !defined(WOLFSSL_NO_TLS12) || !defined(NO_OLD_TLS) else { @@ -14137,6 +14211,9 @@ int TLSX_GetResponseSize(WOLFSSL* ssl, byte msgType, word16* pLength) #endif } #endif + #ifdef WOLFSSL_DTLS_CID + TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_CONNECTION_ID)); + #endif #endif /* WOLFSSL_TLS13 */ break; @@ -14250,7 +14327,7 @@ int TLSX_WriteResponse(WOLFSSL *ssl, byte* output, byte msgType, word16* pOffset #ifndef NO_WOLFSSL_SERVER case server_hello: PF_VALIDATE_RESPONSE(ssl, semaphore); - #ifdef WOLFSSL_TLS13 + #ifdef WOLFSSL_TLS13 if (IsAtLeastTLSv1_3(ssl->version)) { XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE); TURN_OFF(semaphore, @@ -14267,21 +14344,23 @@ int TLSX_WriteResponse(WOLFSSL *ssl, byte* output, byte msgType, word16* pOffset #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY)); #endif - #ifdef WOLFSSL_DTLS_CID - TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_CONNECTION_ID)); - #endif /* WOLFSSL_DTLS_CID */ } + else + #endif /* WOLFSSL_TLS13 */ + { #if !defined(WOLFSSL_NO_TLS12) || !defined(NO_OLD_TLS) - else { #ifdef HAVE_SUPPORTED_CURVES TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE)); #endif #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY)); #endif - } #endif - #endif + WC_DO_NOTHING; /* avoid empty brackets */ + } + #ifdef WOLFSSL_DTLS_CID + TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_CONNECTION_ID)); + #endif /* WOLFSSL_DTLS_CID */ break; #ifdef WOLFSSL_TLS13 @@ -15187,10 +15266,6 @@ int TLSX_Parse(WOLFSSL* ssl, const byte* input, word16 length, byte msgType, #endif /* WOLFSSL_QUIC */ #if defined(WOLFSSL_DTLS_CID) case TLSX_CONNECTION_ID: - /* connection ID not supported in DTLSv1.2 */ - if (!IsAtLeastTLSv1_3(ssl->version)) - break; - if (msgType != client_hello && msgType != server_hello) return EXT_NOT_ALLOWED; diff --git a/tests/api.c b/tests/api.c index de041f8f6a..3a28ae3af2 100644 --- a/tests/api.c +++ b/tests/api.c @@ -92419,6 +92419,11 @@ static int test_wolfSSL_dtls13_null_cipher(void) ExpectIntEQ(ssl_s->error, WC_NO_ERR_TRACE(WANT_READ)); } + ExpectIntEQ(wolfSSL_shutdown(ssl_c), WOLFSSL_SHUTDOWN_NOT_DONE); + ExpectIntEQ(wolfSSL_shutdown(ssl_s), WOLFSSL_SHUTDOWN_NOT_DONE); + ExpectIntEQ(wolfSSL_shutdown(ssl_c), 1); + ExpectIntEQ(wolfSSL_shutdown(ssl_s), 1); + wolfSSL_free(ssl_c); wolfSSL_free(ssl_s); wolfSSL_CTX_free(ctx_c); @@ -94134,6 +94139,343 @@ static int test_dtls_old_seq_number(void) return EXPECT_RESULT(); } +static int test_dtls12_basic_connection_id(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS_CID) + unsigned char client_cid[] = { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }; + unsigned char server_cid[] = { 0, 1, 2, 3, 4, 5 }; + unsigned char readBuf[40]; + const char* params[] = { +#ifndef NO_SHA256 +#ifdef WOLFSSL_AES_128 + "AES128-SHA256", +#ifdef HAVE_AESCCM + "AES128-CCM8", +#endif + "DHE-RSA-AES128-SHA256", + "ECDHE-RSA-AES128-SHA256", +#ifdef HAVE_AESGCM + "DHE-RSA-AES128-GCM-SHA256", + "ECDHE-RSA-AES128-GCM-SHA256", +#endif +#endif +#endif +#if defined(HAVE_CHACHA) && defined(HAVE_POLY1305) + "DHE-RSA-CHACHA20-POLY1305", + "DHE-RSA-CHACHA20-POLY1305-OLD", + "ECDHE-RSA-CHACHA20-POLY1305", + "ECDHE-RSA-CHACHA20-POLY1305-OLD", +#endif +#ifndef NO_PSK + "DHE-PSK-AES128-CBC-SHA256", + "DHE-PSK-AES256-GCM-SHA384", +#ifndef HAVE_NULL_CIPHER + "DHE-PSK-NULL-SHA256", +#endif + "DHE-PSK-AES128-CCM", +#endif + }; + size_t i; + struct { + byte drop:1; + byte changeCID:1; + } run_params[] = { + { .drop = 0, .changeCID = 0 }, + { .drop = 1, .changeCID = 0 }, + { .drop = 0, .changeCID = 1 }, + }; + + /* We check if the side included the CID in their output */ +#define CLIENT_CID() mymemmem(test_ctx.s_buff, test_ctx.s_len, \ + client_cid, sizeof(client_cid)) +#define SERVER_CID() mymemmem(test_ctx.c_buff, test_ctx.c_len, \ + server_cid, sizeof(server_cid)) + + printf("\n"); + for (i = 0; i < XELEM_CNT(params) && EXPECT_SUCCESS(); i++) { + size_t j; + for (j = 0; j < XELEM_CNT(run_params); j++) { + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + + printf("Testing %s run #%ld ... ", params[i], j); + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, + &ssl_s, wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method), + 0); + + ExpectIntEQ(wolfSSL_set_cipher_list(ssl_c, params[i]), 1); + ExpectIntEQ(wolfSSL_set_cipher_list(ssl_s, params[i]), 1); + + ExpectIntEQ(wolfSSL_dtls_cid_use(ssl_c), 1); + ExpectIntEQ(wolfSSL_dtls_cid_set(ssl_c, server_cid, + sizeof(server_cid)), 1); + ExpectIntEQ(wolfSSL_dtls_cid_use(ssl_s), 1); + ExpectIntEQ(wolfSSL_dtls_cid_set(ssl_s, client_cid, + sizeof(client_cid)), 1); + +#ifndef NO_PSK + if (XSTRSTR(params[i], "-PSK-") != NULL) { + wolfSSL_set_psk_client_callback(ssl_c, my_psk_client_cb); + wolfSSL_set_psk_server_callback(ssl_s, my_psk_server_cb); + } +#endif + + ExpectIntEQ(wolfSSL_UseSecureRenegotiation(ssl_c), 1); + ExpectIntEQ(wolfSSL_UseSecureRenegotiation(ssl_s), 1); + + /* CH1 */ + wolfSSL_SetLoggingPrefix("client"); + ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + ExpectNull(CLIENT_CID()); + if (run_params[j].drop) { + test_ctx.c_len = test_ctx.s_len = 0; + ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl_c), 1); + ExpectNull(CLIENT_CID()); + } + /* HVR */ + wolfSSL_SetLoggingPrefix("server"); + ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + ExpectNull(SERVER_CID()); + /* No point dropping HVR */ + /* CH2 */ + wolfSSL_SetLoggingPrefix("client"); + ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + ExpectNull(CLIENT_CID()); + if (run_params[j].drop) { + test_ctx.c_len = test_ctx.s_len = 0; + ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl_c), 1); + ExpectNull(CLIENT_CID()); + } + /* Server first flight */ + wolfSSL_SetLoggingPrefix("server"); + ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + ExpectNull(SERVER_CID()); + if (run_params[j].drop) { + test_ctx.c_len = test_ctx.s_len = 0; + ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl_s), 1); + ExpectNull(SERVER_CID()); + } + /* Client second flight */ + wolfSSL_SetLoggingPrefix("client"); + ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + ExpectNotNull(CLIENT_CID()); + if (run_params[j].drop) { + test_ctx.c_len = test_ctx.s_len = 0; + ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl_c), 1); + ExpectNotNull(CLIENT_CID()); + } + /* Server second flight */ + wolfSSL_SetLoggingPrefix("server"); + ExpectIntEQ(wolfSSL_negotiate(ssl_s), 1); + ExpectNotNull(SERVER_CID()); + if (run_params[j].drop) { + test_ctx.c_len = test_ctx.s_len = 0; + ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl_s), 1); + ExpectNotNull(SERVER_CID()); + } + /* Client complete connection */ + wolfSSL_SetLoggingPrefix("client"); + ExpectIntEQ(wolfSSL_negotiate(ssl_c), 1); + ExpectNull(CLIENT_CID()); + + /* Write some data */ + wolfSSL_SetLoggingPrefix("client"); + ExpectIntEQ(wolfSSL_write(ssl_c, params[i], + (int)XSTRLEN(params[i])), XSTRLEN(params[i])); + ExpectNotNull(CLIENT_CID()); + wolfSSL_SetLoggingPrefix("server"); + ExpectIntEQ(wolfSSL_write(ssl_s, params[i], + (int)XSTRLEN(params[i])), XSTRLEN(params[i])); + ExpectNotNull(SERVER_CID()); + /* Read the data */ + wolfSSL_SetLoggingPrefix("client"); + XMEMSET(readBuf, 0, sizeof(readBuf)); + ExpectIntEQ(wolfSSL_read(ssl_c, readBuf, sizeof(readBuf)), + XSTRLEN(params[i])); + ExpectStrEQ(readBuf, params[i]); + XMEMSET(readBuf, 0, sizeof(readBuf)); + wolfSSL_SetLoggingPrefix("server"); + ExpectIntEQ(wolfSSL_read(ssl_s, readBuf, sizeof(readBuf)), + XSTRLEN(params[i])); + ExpectStrEQ(readBuf, params[i]); + /* Write short data */ + wolfSSL_SetLoggingPrefix("client"); + ExpectIntEQ(wolfSSL_write(ssl_c, params[i], 1), 1); + ExpectNotNull(CLIENT_CID()); + wolfSSL_SetLoggingPrefix("server"); + ExpectIntEQ(wolfSSL_write(ssl_s, params[i], 1), 1); + ExpectNotNull(SERVER_CID()); + /* Read the short data */ + XMEMSET(readBuf, 0, sizeof(readBuf)); + wolfSSL_SetLoggingPrefix("client"); + ExpectIntEQ(wolfSSL_read(ssl_c, readBuf, sizeof(readBuf)), 1); + ExpectIntEQ(readBuf[0], params[i][0]); + XMEMSET(readBuf, 0, sizeof(readBuf)); + wolfSSL_SetLoggingPrefix("server"); + ExpectIntEQ(wolfSSL_read(ssl_s, readBuf, sizeof(readBuf)), 1); + ExpectIntEQ(readBuf[0], params[i][0]); + + /* do two SCR's */ + wolfSSL_SetLoggingPrefix("client"); + ExpectIntEQ(wolfSSL_Rehandshake(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + ExpectIntEQ(wolfSSL_read(ssl_s, readBuf, sizeof(readBuf)), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + /* SCR's after the first one have extra internal logic */ + wolfSSL_SetLoggingPrefix("client"); + ExpectIntEQ(wolfSSL_Rehandshake(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + ExpectIntEQ(wolfSSL_read(ssl_s, readBuf, sizeof(readBuf)), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + + if (run_params[j].changeCID) { + ExpectIntEQ(wolfSSL_dtls_cid_set(ssl_c, client_cid, + sizeof(client_cid)), 0); + /* Forcefully change the CID */ + ssl_c->dtlsCidInfo->rx->id[0] = -1; + /* We need to init the rehandshake from the client, otherwise + * we won't be able to test changing the CID. It would be + * rejected by the record CID matching code. */ + wolfSSL_SetLoggingPrefix("client"); + ExpectIntEQ(wolfSSL_Rehandshake(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), + WOLFSSL_ERROR_WANT_READ); + ExpectNotNull(CLIENT_CID()); + ExpectIntEQ(wolfSSL_SSL_renegotiate_pending(ssl_c), 1); + /* Server first flight */ + wolfSSL_SetLoggingPrefix("server"); + ExpectIntEQ(wolfSSL_read(ssl_s, readBuf, sizeof(readBuf)), -1); + /* We expect the server to reject the CID change. */ + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), DTLS_CID_ERROR); + goto loop_exit; + } + /* Server init'd SCR */ + /* Server request */ + wolfSSL_SetLoggingPrefix("server"); + ExpectIntEQ(wolfSSL_Rehandshake(ssl_s), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + ExpectNotNull(SERVER_CID()); + ExpectIntEQ(wolfSSL_SSL_renegotiate_pending(ssl_s), 1); + if (run_params[j].drop) { + test_ctx.c_len = test_ctx.s_len = 0; + ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl_s), 1); + ExpectNotNull(SERVER_CID()); + } + /* Init SCR on client side with the server's request */ + /* CH no HVR on SCR */ + XMEMSET(readBuf, 0, sizeof(readBuf)); + wolfSSL_SetLoggingPrefix("client"); + ExpectIntEQ(wolfSSL_read(ssl_c, readBuf, sizeof(readBuf)), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + ExpectNotNull(CLIENT_CID()); + ExpectIntEQ(wolfSSL_SSL_renegotiate_pending(ssl_c), 1); + if (run_params[j].drop) { + test_ctx.c_len = test_ctx.s_len = 0; + ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl_c), 1); + ExpectNotNull(CLIENT_CID()); + } + /* Server first flight */ + wolfSSL_SetLoggingPrefix("server"); + ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + ExpectNotNull(SERVER_CID()); + if (run_params[j].drop) { + test_ctx.c_len = test_ctx.s_len = 0; + ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl_s), 1); + ExpectNotNull(SERVER_CID()); + } + /* Client second flight */ + wolfSSL_SetLoggingPrefix("client"); + ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + ExpectNotNull(CLIENT_CID()); + if (run_params[j].drop) { + test_ctx.c_len = test_ctx.s_len = 0; + ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl_c), 1); + ExpectNotNull(CLIENT_CID()); + } + ExpectIntEQ(wolfSSL_write(ssl_c, params[i], + (int)XSTRLEN(params[i])), XSTRLEN(params[i])); + /* Server second flight */ + wolfSSL_SetLoggingPrefix("server"); + ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), APP_DATA_READY); + XMEMSET(readBuf, 0, sizeof(readBuf)); + ExpectIntEQ(wolfSSL_read(ssl_s, readBuf, sizeof(readBuf)), + XSTRLEN(params[i])); + ExpectStrEQ(readBuf, params[i]); + if (!run_params[j].drop) { + ExpectIntEQ(wolfSSL_write(ssl_s, params[i], + (int)XSTRLEN(params[i])), XSTRLEN(params[i])); + } + ExpectIntEQ(wolfSSL_negotiate(ssl_s), 1); + ExpectNotNull(SERVER_CID()); + if (run_params[j].drop) { + test_ctx.c_len = test_ctx.s_len = 0; + ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl_s), 1); + ExpectNotNull(SERVER_CID()); + } + /* Test loading old epoch */ + /* Client complete connection */ + wolfSSL_SetLoggingPrefix("client"); + if (!run_params[j].drop) { + ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), APP_DATA_READY); + XMEMSET(readBuf, 0, sizeof(readBuf)); + ExpectIntEQ(wolfSSL_read(ssl_c, readBuf, sizeof(readBuf)), + XSTRLEN(params[i])); + ExpectStrEQ(readBuf, params[i]); + } + ExpectIntEQ(wolfSSL_negotiate(ssl_c), 1); + ExpectNull(CLIENT_CID()); + ExpectIntEQ(wolfSSL_SSL_renegotiate_pending(ssl_c), 0); + ExpectIntEQ(wolfSSL_SSL_renegotiate_pending(ssl_s), 0); + + /* Close connection */ + wolfSSL_SetLoggingPrefix("client"); + ExpectIntEQ(wolfSSL_shutdown(ssl_c), WOLFSSL_SHUTDOWN_NOT_DONE); + ExpectNotNull(CLIENT_CID()); + wolfSSL_SetLoggingPrefix("server"); + ExpectIntEQ(wolfSSL_shutdown(ssl_s), WOLFSSL_SHUTDOWN_NOT_DONE); + ExpectNotNull(SERVER_CID()); + wolfSSL_SetLoggingPrefix("client"); + ExpectIntEQ(wolfSSL_shutdown(ssl_c), 1); + wolfSSL_SetLoggingPrefix("server"); + ExpectIntEQ(wolfSSL_shutdown(ssl_s), 1); + +loop_exit: + wolfSSL_SetLoggingPrefix(NULL); + wolfSSL_free(ssl_c); + wolfSSL_CTX_free(ctx_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_s); + + if (EXPECT_SUCCESS()) + printf("ok\n"); + else + printf("failed\n"); + } + + } + +#undef CLIENT_CID +#undef SERVER_CID +#endif + return EXPECT_RESULT(); +} + static int test_dtls13_basic_connection_id(void) { EXPECT_DECLS; @@ -94218,10 +94560,10 @@ static int test_dtls13_basic_connection_id(void) ExpectIntEQ(wolfSSL_negotiate(ssl_c), 1); /* Write some data */ - ExpectIntEQ(wolfSSL_write(ssl_c, params[i], XSTRLEN(params[i])), + ExpectIntEQ(wolfSSL_write(ssl_c, params[i], (int)XSTRLEN(params[i])), XSTRLEN(params[i])); ExpectNotNull(CLIENT_CID()); - ExpectIntEQ(wolfSSL_write(ssl_s, params[i], XSTRLEN(params[i])), + ExpectIntEQ(wolfSSL_write(ssl_s, params[i], (int)XSTRLEN(params[i])), XSTRLEN(params[i])); ExpectNotNull(SERVER_CID()); /* Read the data */ @@ -96673,6 +97015,7 @@ TEST_CASE testCases[] = { TEST_DECL(test_dtls13_frag_ch_pq), TEST_DECL(test_dtls_empty_keyshare_with_cookie), TEST_DECL(test_dtls_old_seq_number), + TEST_DECL(test_dtls12_basic_connection_id), TEST_DECL(test_dtls13_basic_connection_id), TEST_DECL(test_tls13_pq_groups), TEST_DECL(test_tls13_early_data), diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 7ce0436355..e5e486366f 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -1430,7 +1430,7 @@ enum { #ifdef WOLFSSL_DTLS_CID #ifndef DTLS_CID_MAX_SIZE -/* DTLSv1.3 parsing code copies the record header in a static buffer to decrypt +/* DTLS parsing code copies the record header in a static buffer to decrypt * the record. Increasing the CID max size does increase also this buffer, * impacting on per-session runtime memory footprint. */ #define DTLS_CID_MAX_SIZE 10 @@ -1444,6 +1444,30 @@ enum { #error "Max size for DTLS CID is 255 bytes" #endif +/* Record Payload Protection Section 5 + * https://www.rfc-editor.org/rfc/rfc9146.html#section-5 */ +#define WOLFSSL_TLS_HMAC_CID_INNER_SZ \ + (8 + /* seq_num_placeholder */ \ + 1 + /* tls12_cid */ \ + 1 + /* cid_length */ \ + 1 + /* tls12_cid */ \ + 2 + /* DTLSCiphertext.version */ \ + 2 + /* epoch */ \ + 6 + /* sequence_number */ \ + DTLS_CID_MAX_SIZE + /* cid */ \ + 2) /* length_of_DTLSInnerPlaintext */ + +#define WOLFSSL_TLS_AEAD_CID_AAD_SZ \ + (8 + /* seq_num_placeholder */ \ + 1 + /* tls12_cid */ \ + 1 + /* cid_length */ \ + 1 + /* tls12_cid */ \ + 2 + /* DTLSCiphertext.version */ \ + 2 + /* epoch */ \ + 6 + /* sequence_number */ \ + DTLS_CID_MAX_SIZE + /* cid */ \ + 2) /* length_of_DTLSInnerPlaintext */ + #ifndef MAX_TICKET_AGE_DIFF /* maximum ticket age difference in seconds, 10 seconds */ #define MAX_TICKET_AGE_DIFF 10 @@ -1650,6 +1674,7 @@ enum Misc { DTLS_HANDSHAKE_HEADER_SZ = 12, /* normal + seq(2) + offset(3) + length(3) */ DTLS_RECORD_HEADER_SZ = 13, /* normal + epoch(2) + seq_num(6) */ + DTLS12_CID_OFFSET = 11, DTLS_UNIFIED_HEADER_MIN_SZ = 2, /* flags + seq_number(2) + length(2) + CID */ DTLS_RECVD_RL_HEADER_MAX_SZ = 5 + DTLS_CID_MAX_SIZE, @@ -1750,6 +1775,7 @@ enum Misc { CHACHA20_IMP_IV_SZ = 12, /* Size of ChaCha20 AEAD implicit IV */ CHACHA20_NONCE_SZ = 12, /* Size of ChacCha20 nonce */ CHACHA20_OLD_OFFSET = 4, /* Offset for seq # in old poly1305 */ + CHACHA20_OFFSET = 4, /* Offset for seq # in poly1305 */ /* For any new implicit/explicit IV size adjust AEAD_MAX_***_SZ */ @@ -1859,6 +1885,14 @@ enum Misc { READ_PROTO = 0 /* reading a protocol message */ }; + +/* Size of the data to authenticate */ +#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_DTLS_CID) +#define AEAD_AUTH_DATA_SZ WOLFSSL_TLS_AEAD_CID_AAD_SZ +#else +#define AEAD_AUTH_DATA_SZ 13 +#endif + #define WOLFSSL_NAMED_GROUP_IS_FFHDE(group) \ (MIN_FFHDE_GROUP <= (group) && (group) <= MAX_FFHDE_GROUP) #ifdef WOLFSSL_HAVE_KYBER @@ -2239,7 +2273,7 @@ WOLFSSL_LOCAL int ALPN_Select(WOLFSSL* ssl); #endif WOLFSSL_LOCAL int ChachaAEADEncrypt(WOLFSSL* ssl, byte* out, const byte* input, - word16 sz); /* needed by sniffer */ + word16 sz, byte type); /* needed by sniffer */ WOLFSSL_LOCAL int ChachaAEADDecrypt(WOLFSSL* ssl, byte* plain, const byte* input, word16 sz); /* needed by sniffer */ @@ -2960,9 +2994,6 @@ typedef enum { TLSX_EXTENDED_MASTER_SECRET = TLSXT_EXTENDED_MASTER_SECRET, TLSX_SESSION_TICKET = TLSXT_SESSION_TICKET, #ifdef WOLFSSL_TLS13 - #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) - TLSX_PRE_SHARED_KEY = TLSXT_PRE_SHARED_KEY, - #endif #ifdef WOLFSSL_EARLY_DATA TLSX_EARLY_DATA = TLSXT_EARLY_DATA, #endif @@ -2982,7 +3013,6 @@ typedef enum { #if !defined(NO_CERTS) && !defined(WOLFSSL_NO_SIGALG) TLSX_SIGNATURE_ALGORITHMS_CERT = TLSXT_SIGNATURE_ALGORITHMS_CERT, #endif - TLSX_KEY_SHARE = TLSXT_KEY_SHARE, #if defined(WOLFSSL_DTLS_CID) TLSX_CONNECTION_ID = TLSXT_CONNECTION_ID, #endif /* defined(WOLFSSL_DTLS_CID) */ @@ -2993,6 +3023,12 @@ typedef enum { TLSX_ECH = TLSXT_ECH, #endif #endif +#if defined(WOLFSSL_TLS13) || !defined(WOLFSSL_NO_TLS12) || !defined(NO_OLD_TLS) + #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) + TLSX_PRE_SHARED_KEY = TLSXT_PRE_SHARED_KEY, + #endif + TLSX_KEY_SHARE = TLSXT_KEY_SHARE, +#endif #if defined(WOLFSSL_TLS13) && defined(WOLFSSL_DUAL_ALG_CERTS) TLSX_CKS = TLSXT_CKS, #endif @@ -5480,6 +5516,7 @@ typedef struct BuildMsgArgs { word32 headerSz; word16 size; word32 ivSz; /* TLSv1.1 IV */ + byte type; byte* iv; ALIGN16 byte staticIvBuffer[MAX_IV_SZ]; } BuildMsgArgs; @@ -5626,7 +5663,21 @@ typedef struct Dtls13Rtx { #endif /* WOLFSSL_DTLS13 */ #ifdef WOLFSSL_DTLS_CID -typedef struct CIDInfo CIDInfo; +typedef struct ConnectionID { + byte length; +/* Ignore "nonstandard extension used : zero-sized array in struct/union" + * MSVC warning */ +#ifdef _MSC_VER +#pragma warning(disable: 4200) +#endif + byte id[]; +} ConnectionID; + +typedef struct CIDInfo { + ConnectionID* tx; + ConnectionID* rx; + byte negotiated : 1; +} CIDInfo; #endif /* WOLFSSL_DTLS_CID */ /* The idea is to reuse the context suites object whenever possible to save @@ -6236,6 +6287,7 @@ enum ContentType { alert = 21, handshake = 22, application_data = 23, + dtls12_cid = 25, #ifdef WOLFSSL_DTLS13 ack = 26, #endif /* WOLFSSL_DTLS13 */ @@ -6525,6 +6577,7 @@ WOLFSSL_LOCAL void DoCertFatalAlert(WOLFSSL* ssl, int ret); #endif WOLFSSL_LOCAL int cipherExtraData(WOLFSSL* ssl); +WOLFSSL_LOCAL word32 MacSize(const WOLFSSL* ssl); #ifndef NO_WOLFSSL_CLIENT WOLFSSL_LOCAL int HaveUniqueSessionObj(WOLFSSL* ssl); @@ -6960,7 +7013,7 @@ WOLFSSL_LOCAL int tlsShowSecrets(WOLFSSL* ssl, void* secret, /* Optional Pre-Master-Secret logging for Wireshark */ #if !defined(NO_FILESYSTEM) && defined(WOLFSSL_SSLKEYLOGFILE) #ifndef WOLFSSL_SSLKEYLOGFILE_OUTPUT - #define WOLFSSL_SSLKEYLOGFILE_OUTPUT "sslkeylog.log" + #define WOLFSSL_SSLKEYLOGFILE_OUTPUT "/tmp/secrets" #endif #endif diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index 90f711589e..16e052af73 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -3389,7 +3389,7 @@ enum { WOLFSSL_BLOCK_TYPE = 2, WOLFSSL_STREAM_TYPE = 3, WOLFSSL_AEAD_TYPE = 4, - WOLFSSL_TLS_HMAC_INNER_SZ = 13 /* SEQ_SZ + ENUM + VERSION_SZ + LEN_SZ */ + WOLFSSL_TLS_HMAC_INNER_SZ = 13, /* SEQ_SZ + ENUM + VERSION_SZ + LEN_SZ */ }; /* for GetBulkCipher and internal use @@ -5471,6 +5471,7 @@ WOLFSSL_API int wolfSSL_dtls_cid_get_tx_size(WOLFSSL* ssl, unsigned int* size); WOLFSSL_API int wolfSSL_dtls_cid_get_tx(WOLFSSL* ssl, unsigned char* buffer, unsigned int bufferSz); +WOLFSSL_API int wolfSSL_dtls_cid_max_size(void); #endif /* defined(WOLFSSL_DTLS_CID) */ #ifdef WOLFSSL_DTLS_CH_FRAG diff --git a/wolfssl/test.h b/wolfssl/test.h index 60327d53a6..30f5877229 100644 --- a/wolfssl/test.h +++ b/wolfssl/test.h @@ -1851,7 +1851,8 @@ static WC_INLINE unsigned int my_psk_client_cb(WOLFSSL* ssl, const char* hint, /* see internal.h MAX_PSK_ID_LEN for PSK identity limit */ XSTRNCPY(identity, kIdentityStr, id_max_len); - if (wolfSSL_GetVersion(ssl) < WOLFSSL_TLSV1_3) { + if (wolfSSL_GetVersion(ssl) != WOLFSSL_TLSV1_3 && + wolfSSL_GetVersion(ssl) != WOLFSSL_DTLSV1_3) { /* test key in hex is 0x1a2b3c4d , in decimal 439,041,101 , we're using * unsigned binary */ key[0] = 0x1a; @@ -1895,7 +1896,8 @@ static WC_INLINE unsigned int my_psk_server_cb(WOLFSSL* ssl, const char* identit if (XSTRCMP(identity, kIdentityStr) != 0) return 0; - if (wolfSSL_GetVersion(ssl) < WOLFSSL_TLSV1_3) { + if (wolfSSL_GetVersion(ssl) != WOLFSSL_TLSV1_3 && + wolfSSL_GetVersion(ssl) != WOLFSSL_DTLSV1_3) { /* test key in hex is 0x1a2b3c4d , in decimal 439,041,101 , we're using * unsigned binary */ key[0] = 0x1a;