Add secure renegotiation to DTLS 1.2

- Hash of fragmented certificate was not calculated as a single message and instead we were hashing individual fragments which produced the wrong digest, shared secret, etc...
- Reset handshake number after server Finished packet is sent or received (depending on side)
- Reserve space in buffer for cipher stuff
- Take `DTLS_RECORD_EXTRA` and  `DTLS_HANDSHAKE_EXTRA` into size and offset calculations for DTLS path
- Fix renegotiation in DTLS with AES128-SHA
- Fix renegotiation in DTLS with AES-GCM
- Support HelloVerify request during secure renegotiation
- Save renegotiation handshake messages for retransmission in timeout
- Handle cipher parameters from different epochs. DTLS may need to resend and receive messages from previous epochs so handling different sets of encryption and decryption parameters is crucial.
This commit is contained in:
Juliusz Sosinowicz
2020-05-19 14:11:05 +02:00
committed by Unknown
parent 255cc016b3
commit 651a7a97b9
7 changed files with 898 additions and 243 deletions

File diff suppressed because it is too large Load Diff

View File

@ -3066,7 +3066,11 @@ int SetKeysSide(WOLFSSL* ssl, enum encrypt_side side)
#ifdef HAVE_SECURE_RENEGOTIATION
if (ssl->secure_renegotiation && ssl->secure_renegotiation->cache_status) {
keys = &ssl->secure_renegotiation->tmp_keys;
copy = 1;
#ifdef WOLFSSL_DTLS
/* For DTLS, copy is done in StoreKeys */
if (!ssl->options.dtls)
#endif
copy = 1;
}
#endif /* HAVE_SECURE_RENEGOTIATION */
@ -3141,6 +3145,15 @@ int SetKeysSide(WOLFSSL* ssl, enum encrypt_side side)
ssl->heap, ssl->devId, ssl->rng, ssl->options.tls1_3);
#ifdef HAVE_SECURE_RENEGOTIATION
#ifdef WOLFSSL_DTLS
if (ret == 0 && ssl->options.dtls) {
if (wc_encrypt)
wc_encrypt->src = keys == &ssl->keys ? KEYS : SCR;
if (wc_decrypt)
wc_decrypt->src = keys == &ssl->keys ? KEYS : SCR;
}
#endif
if (copy) {
int clientCopy = 0;
@ -3217,11 +3230,25 @@ int StoreKeys(WOLFSSL* ssl, const byte* keyData, int side)
{
int sz, i = 0;
Keys* keys = &ssl->keys;
#ifdef WOLFSSL_DTLS
/* In case of DTLS, ssl->keys is updated here */
int scr_copy = 0;
#endif
#ifdef HAVE_SECURE_RENEGOTIATION
if (ssl->secure_renegotiation && ssl->secure_renegotiation->cache_status ==
SCR_CACHE_NEEDED) {
if (ssl->options.dtls &&
ssl->secure_renegotiation &&
ssl->secure_renegotiation->cache_status == SCR_CACHE_NEEDED) {
keys = &ssl->secure_renegotiation->tmp_keys;
#ifdef WOLFSSL_DTLS
/* epoch is incremented after StoreKeys call */
ssl->secure_renegotiation->tmp_keys.dtls_epoch = ssl->keys.dtls_epoch + 1;
/* we only need to copy keys on second and future renegotiations */
if (ssl->keys.dtls_epoch > 1)
scr_copy = 1;
ssl->encrypt.src = KEYS_NOT_SET;
ssl->decrypt.src = KEYS_NOT_SET;
#endif
CacheStatusPP(ssl->secure_renegotiation);
}
#endif /* HAVE_SECURE_RENEGOTIATION */
@ -3232,23 +3259,54 @@ int StoreKeys(WOLFSSL* ssl, const byte* keyData, int side)
if (ssl->specs.cipher_type != aead) {
sz = ssl->specs.hash_size;
#ifndef WOLFSSL_AEAD_ONLY
#ifdef WOLFSSL_DTLS
if (scr_copy) {
XMEMCPY(ssl->keys.client_write_MAC_secret,
keys->client_write_MAC_secret, sz);
XMEMCPY(ssl->keys.server_write_MAC_secret,
keys->server_write_MAC_secret, sz);
}
#endif
XMEMCPY(keys->client_write_MAC_secret,&keyData[i], sz);
XMEMCPY(keys->server_write_MAC_secret,&keyData[i], sz);
#endif
i += sz;
}
sz = ssl->specs.key_size;
#ifdef WOLFSSL_DTLS
if (scr_copy) {
XMEMCPY(ssl->keys.client_write_key,
keys->client_write_key, sz);
XMEMCPY(ssl->keys.server_write_key,
keys->server_write_key, sz);
}
#endif
XMEMCPY(keys->client_write_key, &keyData[i], sz);
XMEMCPY(keys->server_write_key, &keyData[i], sz);
i += sz;
sz = ssl->specs.iv_size;
#ifdef WOLFSSL_DTLS
if (scr_copy) {
XMEMCPY(ssl->keys.client_write_IV,
keys->client_write_IV, sz);
XMEMCPY(ssl->keys.server_write_IV,
keys->server_write_IV, sz);
}
#endif
XMEMCPY(keys->client_write_IV, &keyData[i], sz);
XMEMCPY(keys->server_write_IV, &keyData[i], sz);
#ifdef HAVE_AEAD
if (ssl->specs.cipher_type == aead) {
/* Initialize the AES-GCM/CCM explicit IV to a zero. */
#ifdef WOLFSSL_DTLS
if (scr_copy) {
XMEMCPY(ssl->keys.aead_exp_IV,
keys->aead_exp_IV, AEAD_MAX_EXP_SZ);
}
#endif
XMEMSET(keys->aead_exp_IV, 0, AEAD_MAX_EXP_SZ);
}
#endif /* HAVE_AEAD */
@ -3261,12 +3319,22 @@ int StoreKeys(WOLFSSL* ssl, const byte* keyData, int side)
sz = ssl->specs.hash_size;
if (side & PROVISION_CLIENT) {
#ifndef WOLFSSL_AEAD_ONLY
#ifdef WOLFSSL_DTLS
if (scr_copy)
XMEMCPY(ssl->keys.client_write_MAC_secret,
keys->client_write_MAC_secret, sz);
#endif
XMEMCPY(keys->client_write_MAC_secret,&keyData[i], sz);
#endif
i += sz;
}
if (side & PROVISION_SERVER) {
#ifndef WOLFSSL_AEAD_ONLY
#ifdef WOLFSSL_DTLS
if (scr_copy)
XMEMCPY(ssl->keys.server_write_MAC_secret,
keys->server_write_MAC_secret, sz);
#endif
XMEMCPY(keys->server_write_MAC_secret,&keyData[i], sz);
#endif
i += sz;
@ -3274,25 +3342,51 @@ int StoreKeys(WOLFSSL* ssl, const byte* keyData, int side)
}
sz = ssl->specs.key_size;
if (side & PROVISION_CLIENT) {
#ifdef WOLFSSL_DTLS
if (scr_copy)
XMEMCPY(ssl->keys.client_write_key,
keys->client_write_key, sz);
#endif
XMEMCPY(keys->client_write_key, &keyData[i], sz);
i += sz;
}
if (side & PROVISION_SERVER) {
#ifdef WOLFSSL_DTLS
if (scr_copy)
XMEMCPY(ssl->keys.server_write_key,
keys->server_write_key, sz);
#endif
XMEMCPY(keys->server_write_key, &keyData[i], sz);
i += sz;
}
sz = ssl->specs.iv_size;
if (side & PROVISION_CLIENT) {
#ifdef WOLFSSL_DTLS
if (scr_copy)
XMEMCPY(ssl->keys.client_write_IV,
keys->client_write_IV, sz);
#endif
XMEMCPY(keys->client_write_IV, &keyData[i], sz);
i += sz;
}
if (side & PROVISION_SERVER)
if (side & PROVISION_SERVER) {
#ifdef WOLFSSL_DTLS
if (scr_copy)
XMEMCPY(ssl->keys.server_write_IV,
keys->server_write_IV, sz);
#endif
XMEMCPY(keys->server_write_IV, &keyData[i], sz);
}
#ifdef HAVE_AEAD
if (ssl->specs.cipher_type == aead) {
/* Initialize the AES-GCM/CCM explicit IV to a zero. */
#ifdef WOLFSSL_DTLS
if (scr_copy)
XMEMCPY(ssl->keys.aead_exp_IV,
keys->aead_exp_IV, AEAD_MAX_EXP_SZ);
#endif
XMEMSET(keys->aead_exp_IV, 0, AEAD_MAX_EXP_SZ);
}
#endif

View File

@ -1647,7 +1647,7 @@ int wolfSSL_GetOutputSize(WOLFSSL* ssl, int inSz)
if (inSz > maxSize)
return INPUT_SIZE_E;
return BuildMessage(ssl, NULL, 0, NULL, inSz, application_data, 0, 1, 0);
return BuildMessage(ssl, NULL, 0, NULL, inSz, application_data, 0, 1, 0, CUR_ORDER);
}
@ -3228,6 +3228,72 @@ int wolfSSL_UseClientSuites(WOLFSSL* ssl)
return 0;
}
#ifdef WOLFSSL_DTLS
const byte* wolfSSL_GetDtlsMacSecret(WOLFSSL* ssl, int verify, int epochOrder)
{
#ifndef WOLFSSL_AEAD_ONLY
Keys* keys = NULL;
(void)epochOrder;
if (ssl == NULL)
return NULL;
#ifdef HAVE_SECURE_RENEGOTIATION
switch (epochOrder) {
case PEER_ORDER:
if (ssl->secure_renegotiation &&
ssl->secure_renegotiation->tmp_keys.dtls_epoch != 0 &&
ssl->keys.curEpoch ==
ssl->secure_renegotiation->tmp_keys.dtls_epoch)
keys = &ssl->secure_renegotiation->tmp_keys;
else
keys = &ssl->keys;
break;
case PREV_ORDER:
if (ssl->keys.dtls_epoch > 1 ||
(ssl->secure_renegotiation &&
ssl->secure_renegotiation->tmp_keys.dtls_epoch != 0))
keys = &ssl->keys;
else {
WOLFSSL_MSG("No previous cipher epoch");
return NULL;
}
break;
case CUR_ORDER:
if (ssl->secure_renegotiation &&
ssl->secure_renegotiation->tmp_keys.dtls_epoch != 0 &&
ssl->secure_renegotiation->tmp_keys.dtls_epoch ==
ssl->keys.dtls_epoch)
/* new keys are in scr and are only current when the
* ssl->keys.dtls_epoch matches */
keys = &ssl->secure_renegotiation->tmp_keys;
else
keys = &ssl->keys;
break;
default:
WOLFSSL_MSG("Unknown epoch order");
return NULL;
}
#else
keys = &ssl->keys;
#endif
if ( (ssl->options.side == WOLFSSL_CLIENT_END && !verify) ||
(ssl->options.side == WOLFSSL_SERVER_END && verify) )
return keys->client_write_MAC_secret;
else
return keys->server_write_MAC_secret;
#else
(void)ssl;
(void)verify;
(void)epochOrder;
return NULL;
#endif
}
#endif /* WOLFSSL_DTLS */
const byte* wolfSSL_GetMacSecret(WOLFSSL* ssl, int verify)
{
#ifndef WOLFSSL_AEAD_ONLY

View File

@ -667,6 +667,14 @@ static WC_INLINE void GetSEQIncrement(WOLFSSL* ssl, int verify, word32 seq[2])
#ifdef WOLFSSL_DTLS
static WC_INLINE void DtlsGetSEQ(WOLFSSL* ssl, int order, word32 seq[2])
{
#ifdef HAVE_SECURE_RENEGOTIATION
/* if ssl->secure_renegotiation->tmp_keys.dtls_epoch > ssl->keys.dtls_epoch then PREV_ORDER
* refers to the current epoch */
if (order == PREV_ORDER && ssl->secure_renegotiation &&
ssl->secure_renegotiation->tmp_keys.dtls_epoch > ssl->keys.dtls_epoch) {
order = CUR_ORDER;
}
#endif
if (order == PREV_ORDER) {
/* Previous epoch case */
seq[0] = (((word32)ssl->keys.dtls_epoch - 1) << 16) |
@ -1169,11 +1177,12 @@ static int Hmac_UpdateFinal(Hmac* hmac, byte* digest, const byte* in,
#endif
int TLS_hmac(WOLFSSL* ssl, byte* digest, const byte* in, word32 sz, int padSz,
int content, int verify)
int content, int verify, int epochOrder)
{
Hmac hmac;
byte myInner[WOLFSSL_TLS_HMAC_INNER_SZ];
int ret = 0;
const byte* macSecret = NULL;
word32 hashSz = 0;
if (ssl == NULL)
@ -1199,7 +1208,7 @@ int TLS_hmac(WOLFSSL* ssl, byte* digest, const byte* in, word32 sz, int padSz,
}
#endif
wolfSSL_SetTlsHmacInner(ssl, myInner, sz, content, verify);
wolfSSL_SetTlsHmacInner(ssl, myInner, sz, content, epochOrder);
#if defined(WOLFSSL_RENESAS_TSIP_TLS) && \
!defined(NO_WOLFSSL_RENESAS_TSIP_TLS_SESSION)
if (tsip_useable(ssl)) {
@ -1219,9 +1228,19 @@ int TLS_hmac(WOLFSSL* ssl, byte* digest, const byte* in, word32 sz, int padSz,
if (ret != 0)
return ret;
#ifdef WOLFSSL_DTLS
if (ssl->options.dtls)
macSecret = wolfSSL_GetDtlsMacSecret(ssl, verify, epochOrder);
else
macSecret = wolfSSL_GetMacSecret(ssl, verify);
#else
macSecret = wolfSSL_GetMacSecret(ssl, verify);
#endif
ret = wc_HmacSetKey(&hmac, wolfSSL_GetHmacType(ssl),
wolfSSL_GetMacSecret(ssl, verify),
macSecret,
ssl->specs.hash_size);
if (ret == 0) {
/* Constant time verification required. */
if (verify && padSz >= 0) {

View File

@ -318,7 +318,9 @@ int EmbedReceiveFrom(WOLFSSL *ssl, char *buf, int sz, void *ctx)
WOLFSSL_ENTER("EmbedReceiveFrom()");
if (ssl->options.handShakeDone)
/* Don't use ssl->options.handShakeDone since it is true even if
* we are in the process of renegotiation */
if (ssl->options.handShakeState == HANDSHAKE_DONE)
dtls_timeout = 0;
if (!wolfSSL_get_using_nonblock(ssl)) {

View File

@ -3003,6 +3003,13 @@ enum CipherType { aead };
#define CIPHER_NONCE
#endif
#if defined(WOLFSSL_DTLS) && defined(HAVE_SECURE_RENEGOTIATION)
enum CipherSrc {
KEYS_NOT_SET = 0,
KEYS, /* keys from ssl->keys are loaded */
SCR /* keys from ssl->secure_renegotiation->tmp_keys are loaded */
};
#endif
/* cipher for now */
typedef struct Ciphers {
@ -3042,6 +3049,9 @@ typedef struct Ciphers {
#endif
byte state;
byte setup; /* have we set it up flag for detection */
#if defined(WOLFSSL_DTLS) && defined(HAVE_SECURE_RENEGOTIATION)
enum CipherSrc src;
#endif
} Ciphers;
@ -3177,7 +3187,7 @@ WOLFSSL_SESSION* GetSession(WOLFSSL*, byte*, byte);
WOLFSSL_LOCAL
int SetSession(WOLFSSL*, WOLFSSL_SESSION*);
typedef int (*hmacfp) (WOLFSSL*, byte*, const byte*, word32, int, int, int);
typedef int (*hmacfp) (WOLFSSL*, byte*, const byte*, word32, int, int, int, int);
#ifndef NO_CLIENT_CACHE
WOLFSSL_SESSION* GetSessionClient(WOLFSSL*, const byte*, int);
@ -3734,6 +3744,7 @@ typedef struct DtlsMsg {
byte* msg;
DtlsFrag* fragList;
word32 fragSz; /* Length of fragments received */
word16 epoch; /* Epoch that this message belongs to */
word32 seq; /* Handshake sequence number */
word32 sz; /* Length of whole message */
byte type;
@ -4355,6 +4366,10 @@ WOLFSSL_LOCAL int IsTLS(const WOLFSSL* ssl);
WOLFSSL_LOCAL int IsAtLeastTLSv1_2(const WOLFSSL* ssl);
WOLFSSL_LOCAL int IsAtLeastTLSv1_3(const ProtocolVersion pv);
#if defined(WOLFSSL_DTLS) || !defined(WOLFSSL_NO_TLS12)
WOLFSSL_LOCAL int IsInitialRenegotiationState(WOLFSSL* ssl);
#endif /* DTLS || !WOLFSSL_NO_TLS12 */
WOLFSSL_LOCAL void FreeHandshakeResources(WOLFSSL* ssl);
WOLFSSL_LOCAL void ShrinkInputBuffer(WOLFSSL* ssl, int forcedFree);
WOLFSSL_LOCAL void ShrinkOutputBuffer(WOLFSSL* ssl);
@ -4451,7 +4466,7 @@ WOLFSSL_LOCAL int GrowInputBuffer(WOLFSSL* ssl, int size, int usedLength);
WOLFSSL_LOCAL int MakeTlsMasterSecret(WOLFSSL*);
#ifndef WOLFSSL_AEAD_ONLY
WOLFSSL_LOCAL int TLS_hmac(WOLFSSL* ssl, byte* digest, const byte* in,
word32 sz, int padSz, int content, int verify);
word32 sz, int padSz, int content, int verify, int epochOrder);
#endif
#endif
@ -4473,16 +4488,18 @@ WOLFSSL_LOCAL int GrowInputBuffer(WOLFSSL* ssl, int size, int usedLength);
WOLFSSL_LOCAL DtlsMsg* DtlsMsgNew(word32, void*);
WOLFSSL_LOCAL void DtlsMsgDelete(DtlsMsg*, void*);
WOLFSSL_LOCAL void DtlsMsgListDelete(DtlsMsg*, void*);
WOLFSSL_LOCAL int DtlsMsgSet(DtlsMsg*, word32, const byte*, byte,
WOLFSSL_LOCAL void DtlsTxMsgListClean(WOLFSSL* ssl);
WOLFSSL_LOCAL int DtlsMsgSet(DtlsMsg*, word32, word16, const byte*, byte,
word32, word32, void*);
WOLFSSL_LOCAL DtlsMsg* DtlsMsgFind(DtlsMsg*, word32);
WOLFSSL_LOCAL void DtlsMsgStore(WOLFSSL*, word32, const byte*, word32,
WOLFSSL_LOCAL DtlsMsg* DtlsMsgFind(DtlsMsg*, word32, word32);
WOLFSSL_LOCAL void DtlsMsgStore(WOLFSSL*, word32, word32, const byte*, word32,
byte, word32, word32, void*);
WOLFSSL_LOCAL DtlsMsg* DtlsMsgInsert(DtlsMsg*, DtlsMsg*);
WOLFSSL_LOCAL int DtlsMsgPoolSave(WOLFSSL*, const byte*, word32);
WOLFSSL_LOCAL int DtlsMsgPoolSave(WOLFSSL*, const byte*, word32, enum HandShakeType);
WOLFSSL_LOCAL int DtlsMsgPoolTimeout(WOLFSSL*);
WOLFSSL_LOCAL int VerifyForDtlsMsgPoolSend(WOLFSSL*, byte, word32);
WOLFSSL_LOCAL int VerifyForTxDtlsMsgDelete(WOLFSSL* ssl, DtlsMsg* head);
WOLFSSL_LOCAL void DtlsMsgPoolReset(WOLFSSL*);
WOLFSSL_LOCAL int DtlsMsgPoolSend(WOLFSSL*, int);
#endif /* WOLFSSL_DTLS */
@ -4587,7 +4604,7 @@ WOLFSSL_LOCAL void FreeHandshakeHashes(WOLFSSL* ssl);
WOLFSSL_LOCAL int BuildMessage(WOLFSSL* ssl, byte* output, int outSz,
const byte* input, int inSz, int type, int hashOutput,
int sizeOnly, int asyncOkay);
int sizeOnly, int asyncOkay, int epochOrder);
#ifdef WOLFSSL_TLS13
int BuildTls13Message(WOLFSSL* ssl, byte* output, int outSz, const byte* input,

View File

@ -2431,6 +2431,7 @@ WOLFSSL_API void wolfSSL_SetVerifyDecryptCtx(WOLFSSL* ssl, void *ctx);
WOLFSSL_API void* wolfSSL_GetVerifyDecryptCtx(WOLFSSL* ssl);
WOLFSSL_API const unsigned char* wolfSSL_GetMacSecret(WOLFSSL*, int);
WOLFSSL_API const unsigned char* wolfSSL_GetDtlsMacSecret(WOLFSSL*, int, int);
WOLFSSL_API const unsigned char* wolfSSL_GetClientWriteKey(WOLFSSL*);
WOLFSSL_API const unsigned char* wolfSSL_GetClientWriteIV(WOLFSSL*);
WOLFSSL_API const unsigned char* wolfSSL_GetServerWriteKey(WOLFSSL*);