DTLS 1.3: allow the server to operate without maintaining state

This commit is contained in:
Juliusz Sosinowicz
2022-06-24 10:42:57 +02:00
parent 8fb48464e3
commit c6aa4fc526
5 changed files with 136 additions and 25 deletions

View File

@@ -1388,6 +1388,18 @@ static int _Dtls13HandshakeRecv(WOLFSSL* ssl, byte* input, word32 size,
if (frag_off + frag_length > message_length)
return BUFFER_ERROR;
if (handshake_type == client_hello &&
/* Only when receiving an unverified ClientHello */
ssl->options.serverState < SERVER_HELLO_COMPLETE) {
/* To be able to operate in stateless mode, we assume the ClientHello
* is in order and we use its Handshake Message number and Sequence
* Number for our Tx. */
ssl->keys.dtls_expected_peer_handshake_number =
ssl->keys.dtls_handshake_number =
ssl->keys.dtls_peer_handshake_number;
ssl->dtls13Epochs[0].nextSeqNumber = ssl->keys.curSeq;
}
ret = Dtls13RtxMsgRecvd(ssl, (enum HandShakeType)handshake_type, frag_off);
if (ret != 0)
return ret;

View File

@@ -8788,6 +8788,14 @@ static int EdDSA_Update(WOLFSSL* ssl, const byte* data, int sz)
int HashRaw(WOLFSSL* ssl, const byte* data, int sz)
{
int ret = 0;
#ifdef WOLFSSL_DEBUG_TLS
byte digest[WC_MAX_DIGEST_SIZE];
WOLFSSL_MSG("HashRaw:");
WOLFSSL_MSG("Data:");
WOLFSSL_BUFFER(data, sz);
WOLFSSL_MSG("Hashes:");
#endif
(void)data;
(void)sz;
@@ -8817,16 +8825,31 @@ int HashRaw(WOLFSSL* ssl, const byte* data, int sz)
ret = wc_Sha256Update(&ssl->hsHashes->hashSha256, data, sz);
if (ret != 0)
return ret;
#ifdef WOLFSSL_DEBUG_TLS
WOLFSSL_MSG("Sha256");
wc_Sha256GetHash(&ssl->hsHashes->hashSha256, digest);
WOLFSSL_BUFFER(digest, WC_SHA224_DIGEST_SIZE);
#endif
#endif
#ifdef WOLFSSL_SHA384
ret = wc_Sha384Update(&ssl->hsHashes->hashSha384, data, sz);
if (ret != 0)
return ret;
#ifdef WOLFSSL_DEBUG_TLS
WOLFSSL_MSG("Sha384");
wc_Sha384GetHash(&ssl->hsHashes->hashSha384, digest);
WOLFSSL_BUFFER(digest, WC_SHA384_DIGEST_SIZE);
#endif
#endif
#ifdef WOLFSSL_SHA512
ret = wc_Sha512Update(&ssl->hsHashes->hashSha512, data, sz);
if (ret != 0)
return ret;
#ifdef WOLFSSL_DEBUG_TLS
WOLFSSL_MSG("Sha512");
wc_Sha512GetHash(&ssl->hsHashes->hashSha512, digest);
WOLFSSL_BUFFER(digest, WC_SHA512_DIGEST_SIZE);
#endif
#endif
#if !defined(WOLFSSL_NO_CLIENT_AUTH) && \
((defined(HAVE_ED25519) && !defined(NO_ED25519_CLIENT_AUTH)) || \

View File

@@ -6167,8 +6167,16 @@ static int TLSX_Cookie_Parse(WOLFSSL* ssl, const byte* input, word16 length,
/* client_hello */
extension = TLSX_Find(ssl->extensions, TLSX_COOKIE);
if (extension == NULL)
return HRR_COOKIE_ERROR;
if (extension == NULL) {
#ifdef WOLFSSL_DTLS13
if (ssl->options.dtls)
/* TODO: Should we allow a ClientHello with a valid cookie even if
* the cookie wasn't sent by this WOLFSSL object? */
return TLSX_Cookie_Use(ssl, input + idx, len, NULL, 0, 0);
else
#endif
return HRR_COOKIE_ERROR;
}
cookie = (Cookie*)extension->data;
if (cookie->len != len || XMEMCMP(&cookie->data, input + idx, len) != 0)

View File

@@ -2889,7 +2889,7 @@ int RestartHandshakeHash(WOLFSSL* ssl)
#endif
#if defined(WOLFSSL_SEND_HRR_COOKIE) && !defined(NO_WOLFSSL_SERVER)
if (ssl->options.sendCookie) {
if (ssl->options.sendCookie && ssl->options.side == WOLFSSL_SERVER_END) {
byte cookie[OPAQUE8_LEN + WC_MAX_DIGEST_SIZE + OPAQUE16_LEN * 2];
TLSX* ext;
word32 idx = 0;
@@ -4833,6 +4833,10 @@ static int RestartHandshakeHashWithCookie(WOLFSSL* ssl, Cookie* cookie)
return ret;
if ((ret = HashRaw(ssl, header, sizeof(header))) != 0)
return ret;
#ifdef WOLFSSL_DEBUG_TLS
WOLFSSL_MSG("Restart Hash from Cookie");
WOLFSSL_BUFFER(cookieData + idx, hashSz);
#endif
if ((ret = HashRaw(ssl, cookieData + idx, hashSz)) != 0)
return ret;
@@ -5282,20 +5286,45 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
#if defined(WOLFSSL_SEND_HRR_COOKIE)
if (ssl->options.sendCookie &&
ssl->options.serverState == SERVER_HELLO_RETRY_REQUEST_COMPLETE) {
TLSX* ext;
(ssl->options.serverState == SERVER_HELLO_RETRY_REQUEST_COMPLETE
#ifdef WOLFSSL_DTLS13
/* Always check for a valid cookie since we may have already
* sent a HRR but we reset the state. */
|| ssl->options.dtls
#endif
)) {
TLSX* ext = TLSX_Find(ssl->extensions, TLSX_COOKIE);
if ((ext = TLSX_Find(ssl->extensions, TLSX_COOKIE)) == NULL)
ERROR_OUT(HRR_COOKIE_ERROR, exit_dch);
/* Ensure the cookie came from client and isn't the one in the
* response - HelloRetryRequest.
*/
if (ext->resp == 1)
ERROR_OUT(HRR_COOKIE_ERROR, exit_dch);
ret = RestartHandshakeHashWithCookie(ssl, (Cookie*)ext->data);
if (ret != 0)
goto exit_dch;
if (ext != NULL) {
/* Ensure the cookie came from client and isn't the one in the
* response - HelloRetryRequest.
*/
if (ext->resp == 0) {
ret = RestartHandshakeHashWithCookie(ssl, (Cookie*)ext->data);
#ifdef WOLFSSL_DTLS13
/* Send a new cookie request */
if (ret == HRR_COOKIE_ERROR && ssl->options.dtls)
ssl->options.serverState = NULL_STATE;
else
#endif
if (ret != 0)
goto exit_dch;
ssl->options.serverState = SERVER_HELLO_COMPLETE;
}
else {
#ifdef WOLFSSL_DTLS13
if (ssl->options.dtls)
ssl->options.serverState = NULL_STATE;
else
#endif
ERROR_OUT(HRR_COOKIE_ERROR, exit_dch);
}
}
else
#ifdef WOLFSSL_DTLS13
if (!ssl->options.dtls)
#endif
ERROR_OUT(HRR_COOKIE_ERROR, exit_dch);
}
#endif
@@ -5424,9 +5453,9 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
/* We are using DTLSv13 and set the HRR cookie secret, use the cookie to
perform a return-routability check. */
if (ret == 0 && ssl->options.dtls && ssl->options.sendCookie &&
ssl->options.serverState != SERVER_HELLO_RETRY_REQUEST_COMPLETE) {
ssl->options.serverState < SERVER_HELLO_RETRY_REQUEST_COMPLETE) {
/* ssl->options.serverState != SERVER_HELLO_RETRY_REQUEST_COMPLETE
/* ssl->options.serverState < SERVER_HELLO_RETRY_REQUEST_COMPLETE
so the client already provided a good KeyShareEntry. In this case
we don't add the KEY_SHARE extension to the HelloRetryRequest or
in the Cookie. The RFC8446 forbids to select a supported group
@@ -5556,18 +5585,27 @@ int SendTls13ServerHello(WOLFSSL* ssl, byte extMsgType)
if (ret != 0)
return ret;
#ifdef WOLFSSL_DTLS13
if (ssl->options.dtls) {
ret = Dtls13HashHandshake(ssl,
output + Dtls13GetRlHeaderLength(0) ,
sendSz - Dtls13GetRlHeaderLength(0));
#ifdef WOLFSSL_SEND_HRR_COOKIE
if (ssl->options.sendCookie && extMsgType == hello_retry_request) {
/* Reset the hashes from here. We will be able to restart the hashes
* from the cookie in RestartHandshakeHashWithCookie */
ret = InitHandshakeHashes(ssl);
}
else
#endif
{
#ifdef WOLFSSL_DTLS13
if (ssl->options.dtls) {
ret = Dtls13HashHandshake(ssl,
output + Dtls13GetRlHeaderLength(0) ,
sendSz - Dtls13GetRlHeaderLength(0));
}
else
#endif /* WOLFSSL_DTLS13 */
{
ret = HashOutput(ssl, output, sendSz, 0);
}
}
if (ret != 0)
return ret;
@@ -5598,7 +5636,6 @@ int SendTls13ServerHello(WOLFSSL* ssl, byte extMsgType)
ssl->buffers.outputBuffer.length += sendSz;
if (!ssl->options.groupMessages || extMsgType != server_hello)
ret = SendBuffered(ssl);
WOLFSSL_LEAVE("SendTls13ServerHello", ret);
@@ -10754,6 +10791,36 @@ int wolfSSL_accept_TLSv13(WOLFSSL* ssl)
WOLFSSL_ERROR(ssl->error);
return WOLFSSL_FATAL_ERROR;
}
#ifdef WOLFSSL_DTLS13
if (ssl->options.dtls && wolfSSL_dtls_get_using_nonblock(ssl)) {
/* Reset the state so that we can statelessly await the
* ClientHello that contains the cookie. Return a WANT_READ
* to the user so that we don't drop UDP messages in the
* network callbacks. */
/* Reset DTLS window */
w64Zero(&ssl->dtls13Epochs[0].nextSeqNumber);
w64Zero(&ssl->dtls13Epochs[0].nextPeerSeqNumber);
XMEMSET(ssl->dtls13Epochs[0].window, 0,
sizeof(ssl->dtls13Epochs[0].window));
ssl->keys.dtls_expected_peer_handshake_number = 0;
ssl->keys.dtls_handshake_number = 0;
ssl->msgsReceived.got_client_hello = 0;
/* Reset states */
ssl->options.serverState = NULL_STATE;
ssl->options.clientState = NULL_STATE;
ssl->options.connectState = CONNECT_BEGIN;
ssl->options.acceptState = ACCEPT_BEGIN;
ssl->options.handShakeState = NULL_STATE;
ssl->error = WANT_READ;
WOLFSSL_ERROR(ssl->error);
return WOLFSSL_FATAL_ERROR;
}
#endif /* WOLFSSL_DTLS13 */
}
ssl->options.acceptState = TLS13_ACCEPT_HELLO_RETRY_REQUEST_DONE;

View File

@@ -463,6 +463,7 @@ int wc_PRF_TLS(byte* digest, word32 digLen, const byte* secret, word32 secLen,
WOLFSSL_BUFFER(prk, prkLen);
WOLFSSL_MSG(" Info");
WOLFSSL_BUFFER(data, idx);
WOLFSSL_MSG_EX(" Digest %d", digest);
#endif
ret = wc_HKDF_Expand(digest, prk, prkLen, data, idx, okm, okmLen);