From de0497305130f3c89920df205744d26c59067912 Mon Sep 17 00:00:00 2001 From: Marco Oliverio Date: Fri, 20 May 2022 09:59:29 +0200 Subject: [PATCH] dtls13: record number encryption and decryption --- src/dtls13.c | 189 ++++++++++++++++++++++++++++++++++++++++++++- src/internal.c | 31 ++++++++ src/keys.c | 5 ++ src/tls13.c | 33 +++++++- wolfssl/internal.h | 24 ++++++ 5 files changed, 280 insertions(+), 2 deletions(-) diff --git a/src/dtls13.c b/src/dtls13.c index 3f860723c..66ef38eb2 100644 --- a/src/dtls13.c +++ b/src/dtls13.c @@ -27,8 +27,17 @@ #ifdef WOLFSSL_DTLS13 -#include +#include #include +#include +#include + +#ifdef NO_INLINE +#include +#else +#define WOLFSSL_MISC_INCLUDED +#include +#endif WOLFSSL_METHOD* wolfDTLSv1_3_client_method_ex(void* heap) { @@ -70,4 +79,182 @@ WOLFSSL_METHOD* wolfDTLSv1_3_server_method(void) return wolfDTLSv1_3_server_method_ex(NULL); } +#define SN_LABEL_SZ 2 +static const byte snLabel[SN_LABEL_SZ + 1] = "sn"; + +/** + * Dtls13DeriveSnKeys() - derive the key used to encrypt the record number + * @ssl: ssl object + * @provision: which side (CLIENT or SERVER) to provision + */ +int Dtls13DeriveSnKeys(WOLFSSL* ssl, int provision) +{ + byte key_dig[MAX_PRF_DIG]; + int ret = 0; + + if (provision & PROVISION_CLIENT) { + WOLFSSL_MSG("Derive SN Client key"); + ret = Tls13DeriveKey(ssl, key_dig, ssl->specs.key_size, + ssl->clientSecret, snLabel, SN_LABEL_SZ, ssl->specs.mac_algorithm, + 0); + if (ret != 0) + goto end; + + XMEMCPY(ssl->keys.client_sn_key, key_dig, ssl->specs.key_size); + } + + if (provision & PROVISION_SERVER) { + WOLFSSL_MSG("Derive SN Server key"); + ret = Tls13DeriveKey(ssl, key_dig, ssl->specs.key_size, + ssl->serverSecret, snLabel, SN_LABEL_SZ, ssl->specs.mac_algorithm, + 0); + if (ret != 0) + goto end; + + XMEMCPY(ssl->keys.server_sn_key, key_dig, ssl->specs.key_size); + } + +end: + ForceZero(key_dig, MAX_PRF_DIG); + return ret; +} + +static int Dtls13InitAesCipher(WOLFSSL* ssl, RecordNumberCiphers* cipher, + const byte* key, word16 keySize) +{ + int ret; + if (cipher->aes == NULL) { + cipher->aes = + (Aes*)XMALLOC(sizeof(Aes), ssl->heap, DYNAMIC_TYPE_CIPHER); + if (cipher->aes == NULL) + return MEMORY_E; + } + else { + wc_AesFree(cipher->aes); + } + + XMEMSET(cipher->aes, 0, sizeof(*cipher->aes)); + + ret = wc_AesInit(cipher->aes, ssl->heap, INVALID_DEVID); + if (ret != 0) + return ret; + + return wc_AesSetKey(cipher->aes, key, keySize, NULL, AES_ENCRYPTION); +} + +#ifdef HAVE_CHACHA +static int Dtls13InitChaChaCipher(RecordNumberCiphers* c, byte* key, + word16 keySize, void* heap) +{ + (void)heap; + + if (c->chacha == NULL) { + c->chacha = (ChaCha*)XMALLOC(sizeof(ChaCha), heap, DYNAMIC_TYPE_CIPHER); + + if (c->chacha == NULL) + return MEMORY_E; + } + + return wc_Chacha_SetKey(c->chacha, key, keySize); +} +#endif /* HAVE_CHACHA */ + +int Dtls13SetRecordNumberKeys(WOLFSSL* ssl, enum encrypt_side side) +{ + RecordNumberCiphers* enc = NULL; + RecordNumberCiphers* dec = NULL; + byte *encKey, *decKey; + int ret; + + if (ssl == NULL) { + return BAD_FUNC_ARG; + } + + switch (side) { + case ENCRYPT_SIDE_ONLY: + enc = &ssl->dtlsRecordNumberEncrypt; + break; + case DECRYPT_SIDE_ONLY: + dec = &ssl->dtlsRecordNumberDecrypt; + break; + case ENCRYPT_AND_DECRYPT_SIDE: + enc = &ssl->dtlsRecordNumberEncrypt; + dec = &ssl->dtlsRecordNumberDecrypt; + break; + } + + if (enc) { + if (ssl->options.side == WOLFSSL_CLIENT_END) + encKey = ssl->keys.client_sn_key; + else + encKey = ssl->keys.server_sn_key; + } + + if (dec) { + if (ssl->options.side == WOLFSSL_CLIENT_END) + decKey = ssl->keys.server_sn_key; + else + decKey = ssl->keys.client_sn_key; + } + + /* DTLSv1.3 supports only AEAD algorithm. */ +#if defined(BUILD_AESGCM) || defined(HAVE_AESCCM) + if (ssl->specs.bulk_cipher_algorithm == wolfssl_aes_gcm || + ssl->specs.bulk_cipher_algorithm == wolfssl_aes_ccm) { + + if (enc) { + ret = Dtls13InitAesCipher(ssl, enc, encKey, ssl->specs.key_size); + if (ret != 0) + return ret; +#ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_MSG("Provisioning AES Record Number enc key:"); + WOLFSSL_BUFFER(encKey, ssl->specs.key_size); +#endif /* WOLFSSL_DEBUG_TLS */ + } + + if (dec) { + ret = Dtls13InitAesCipher(ssl, dec, decKey, ssl->specs.key_size); + if (ret != 0) + return ret; +#ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_MSG("Provisioning AES Record Number dec key:"); + WOLFSSL_BUFFER(decKey, ssl->specs.key_size); +#endif /* WOLFSSL_DEBUG_TLS */ + } + + return 0; + } +#endif /* BUILD_AESGCM || HAVE_AESCCM */ + +#ifdef HAVE_CHACHA + if (ssl->specs.bulk_cipher_algorithm == wolfssl_chacha) { + if (enc) { + ret = Dtls13InitChaChaCipher(enc, encKey, ssl->specs.key_size, + ssl->heap); + if (ret != 0) + return ret; +#ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_MSG("Provisioning CHACHA Record Number enc key:"); + WOLFSSL_BUFFER(encKey, ssl->specs.key_size); +#endif /* WOLFSSL_DEBUG_TLS */ + } + + if (dec) { + ret = Dtls13InitChaChaCipher(dec, decKey, ssl->specs.key_size, + ssl->heap); + if (ret != 0) + return ret; +#ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_MSG("Provisioning CHACHA Record Number dec key:"); + WOLFSSL_BUFFER(decKey, ssl->specs.key_size); +#endif /* WOLFSSL_DEBUG_TLS */ + } + + return 0; + } +#endif /* HAVE_CHACHA */ + + return NOT_COMPILED_IN; +} + #endif /* WOLFSSL_DTLS13 */ diff --git a/src/internal.c b/src/internal.c index 4ecd716b4..ad3c099b5 100644 --- a/src/internal.c +++ b/src/internal.c @@ -2589,6 +2589,14 @@ void InitCiphers(WOLFSSL* ssl) #ifdef HAVE_ONE_TIME_AUTH ssl->auth.setup = 0; #endif + +#ifdef WOLFSSL_DTLS13 + XMEMSET(&ssl->dtlsRecordNumberEncrypt, 0, + sizeof(ssl->dtlsRecordNumberEncrypt)); + XMEMSET(&ssl->dtlsRecordNumberDecrypt, 0, + sizeof(ssl->dtlsRecordNumberEncrypt)); +#endif /* WOLFSSL_DTLS13 */ + } @@ -2642,6 +2650,29 @@ void FreeCiphers(WOLFSSL* ssl) XFREE(ssl->encrypt.hmac, ssl->heap, DYNAMIC_TYPE_CIPHER); XFREE(ssl->decrypt.hmac, ssl->heap, DYNAMIC_TYPE_CIPHER); #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; + } +#endif /* BUILD_AES */ +#ifdef HAVE_CHACHA + 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 */ +#endif /* WOLFSSL_DTLS13 */ } diff --git a/src/keys.c b/src/keys.c index b467275d9..e07300628 100644 --- a/src/keys.c +++ b/src/keys.c @@ -2959,6 +2959,11 @@ int SetKeysSide(WOLFSSL* ssl, enum encrypt_side side) ssl->heap, ssl->devId, ssl->rng, ssl->options.tls1_3); } +#ifdef WOLFSSL_DTLS13 + if (ret == 0 && ssl->options.dtls && IsAtLeastTLSv1_3(ssl->version)) + ret = Dtls13SetRecordNumberKeys(ssl, side); +#endif /* WOLFSSL_DTLS13 */ + #ifdef HAVE_SECURE_RENEGOTIATION #ifdef WOLFSSL_DTLS if (ret == 0 && ssl->options.dtls) { diff --git a/src/tls13.c b/src/tls13.c index b929e01ab..b1200b88b 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -153,6 +153,11 @@ /* The protocol label for TLS v1.3. */ static const byte tls13ProtocolLabel[TLS13_PROTOCOL_LABEL_SZ + 1] = "tls13 "; +#ifdef WOLFSSL_DTLS13 +#define DTLS13_PROTOCOL_LABEL_SZ 6 +static const byte dtls13ProtocolLabel[DTLS13_PROTOCOL_LABEL_SZ + 1] = "dtls13"; +#endif /* WOLFSSL_DTLS13 */ + /* Derive a key from a message. * * ssl The SSL/TLS object. @@ -234,7 +239,15 @@ static int DeriveKeyMsg(WOLFSSL* ssl, byte* output, int outputLen, protocol = tls13ProtocolLabel; protocolLen = TLS13_PROTOCOL_LABEL_SZ; break; +#ifdef WOLFSSL_DTLS13 + case DTLSv1_3_MINOR: + if (!ssl->options.dtls) + return VERSION_ERROR; + protocol = dtls13ProtocolLabel; + protocolLen = DTLS13_PROTOCOL_LABEL_SZ; + break; +#endif /* WOLFSSL_DTLS13 */ default: return VERSION_ERROR; } @@ -308,10 +321,16 @@ int Tls13DeriveKey(WOLFSSL* ssl, byte* output, int outputLen, if (ret != 0) return ret; - /* Only one protocol version defined at this time. */ protocol = tls13ProtocolLabel; protocolLen = TLS13_PROTOCOL_LABEL_SZ; +#ifdef WOLFSSL_DTLS13 + if (ssl->options.dtls) { + protocol = dtls13ProtocolLabel; + protocolLen = DTLS13_PROTOCOL_LABEL_SZ; + } +#endif /* WOLFSSL_DTLS13 */ + if (outputLen == -1) outputLen = hashSz; if (includeMsgs) @@ -1263,6 +1282,18 @@ int DeriveTls13Keys(WOLFSSL* ssl, int secret, int side, int store) /* Store keys and IVs but don't activate them. */ ret = StoreKeys(ssl, key_dig, provision); +#ifdef WOLFSSL_DTLS13 + if (ret != 0) + goto end; + + if (ssl->options.dtls) { + ret = Dtls13DeriveSnKeys(ssl, provision); + if (ret != 0) + return ret; + } + +#endif /* WOLFSSL_DTLS13 */ + end: #ifdef WOLFSSL_SMALL_STACK XFREE(key_dig, ssl->heap, DYNAMIC_TYPE_DIGEST); diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 7603ab2a3..c192ae257 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -2242,6 +2242,11 @@ typedef struct Keys { byte aead_dec_imp_IV[AEAD_MAX_IMP_SZ]; #endif +#ifdef WOLFSSL_DTLS13 + byte client_sn_key[MAX_SYM_KEY_SIZE]; + byte server_sn_key[MAX_SYM_KEY_SIZE]; +#endif /* WOLFSSL_DTLS13 */ + word32 peer_sequence_number_hi; word32 peer_sequence_number_lo; word32 sequence_number_hi; @@ -3314,6 +3319,16 @@ typedef struct Ciphers { #endif } Ciphers; +#ifdef WOLFSSL_DTLS13 +typedef struct RecordNumberCiphers { +#if defined(BUILD_AES) || defined(BUILD_AESGCM) + Aes *aes; +#endif /* BUILD_AES || BUILD_AESGCM */ +#ifdef HAVE_CHACHA + ChaCha *chacha; +#endif +} RecordNumberCiphers; +#endif /* WOLFSSL_DTLS13 */ #ifdef HAVE_ONE_TIME_AUTH /* Ciphers for one time authentication such as poly1305 */ @@ -4496,6 +4511,11 @@ struct WOLFSSL { * (selected profiles - up to 16) */ word16 dtlsSrtpId; /* DTLS-with-SRTP profile ID selected */ #endif +#ifdef WOLFSSL_DTLS13 + RecordNumberCiphers dtlsRecordNumberEncrypt; + RecordNumberCiphers dtlsRecordNumberDecrypt; +#endif /* WOLFSSL_DTLS13 */ + #endif /* WOLFSSL_DTLS */ #ifdef WOLFSSL_CALLBACKS TimeoutInfo timeoutInfo; /* info saved during handshake */ @@ -5240,6 +5260,10 @@ WOLFSSL_LOCAL word32 nid2oid(int nid, int grp); #ifdef WOLFSSL_DTLS13 +WOLFSSL_LOCAL int Dtls13DeriveSnKeys(WOLFSSL* ssl, int provision); +WOLFSSL_LOCAL int Dtls13SetRecordNumberKeys(WOLFSSL* ssl, + enum encrypt_side side); + #endif /* WOLFSSL_DTLS13 */ #ifdef WOLFSSL_STATIC_EPHEMERAL WOLFSSL_LOCAL int wolfSSL_StaticEphemeralKeyLoad(WOLFSSL* ssl, int keyAlgo, void* keyPtr);