Refactor alerts into one location

Remove previous stateless code. Now all DTLS 1.3 stateless handling is done in dtls.c
This commit is contained in:
Juliusz Sosinowicz
2023-02-08 14:02:52 +01:00
parent 51a384eba5
commit 5f65752414
7 changed files with 335 additions and 330 deletions

View File

@ -82,6 +82,23 @@ void DtlsResetState(WOLFSSL* ssl)
ssl->options.tls1_3 = 0;
}
int DtlsIgnoreError(int err)
{
/* Whitelist of errors not to ignore */
switch (err) {
case MEMORY_E:
case MEMORY_ERROR:
case ASYNC_INIT_E:
case ASYNC_OP_E:
case SOCKET_ERROR_E:
case WANT_READ:
case WANT_WRITE:
return 0;
default:
return 1;
}
}
#if !defined(NO_WOLFSSL_SERVER)
#if defined(NO_SHA) && defined(NO_SHA256)
@ -482,16 +499,13 @@ static int SendStatelessReplyDtls13(const WOLFSSL* ssl, WolfSSL_CH* ch,
PskInfo* pskInfo)
{
int ret = -1;
(void)pskInfo;
if (ch->cookieExt.size == 0) {
TLSX* parsedExts = NULL;
WolfSSL_ConstVector tlsx;
Suites suites;
word16 len;
#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
byte haveSA = 0;
byte haveKS = 0;
#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
byte usePSK = 0;
byte doKE = 0;
#endif
@ -500,6 +514,8 @@ static int SendStatelessReplyDtls13(const WOLFSSL* ssl, WolfSSL_CH* ch,
byte cookieHash[WC_MAX_DIGEST_SIZE];
int cookieHashSz;
(void)pskInfo;
XMEMSET(&cs, 0, sizeof(cs));
/* We need to echo the session ID sent by the client */
@ -547,6 +563,7 @@ static int SendStatelessReplyDtls13(const WOLFSSL* ssl, WolfSSL_CH* ch,
suites.hashSigAlgoSz = len;
XMEMCPY(suites.hashSigAlgo, tlsx.elements + OPAQUE16_LEN,
len);
haveSA = 1;
}
/* Supported groups */
@ -571,9 +588,7 @@ static int SendStatelessReplyDtls13(const WOLFSSL* ssl, WolfSSL_CH* ch,
(word16)tlsx.size, &parsedExts);
if (ret != 0)
goto dtls13_cleanup;
#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
haveKS = 1;
#endif
}
#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
@ -604,7 +619,7 @@ static int SendStatelessReplyDtls13(const WOLFSSL* ssl, WolfSSL_CH* ch,
if (ret != 0)
goto dtls13_cleanup;
if (tlsx.size == 0)
ERROR_OUT(MISSING_HANDSHAKE_DATA, dtls13_cleanup);
ERROR_OUT(PSK_KEY_ERROR, dtls13_cleanup);
ret = TLSX_PskKeyModes_Parse_Modes(tlsx.elements, tlsx.size,
client_hello, &modes);
if (ret != 0)
@ -612,7 +627,7 @@ static int SendStatelessReplyDtls13(const WOLFSSL* ssl, WolfSSL_CH* ch,
if ((modes & (1 << PSK_DHE_KE)) &&
!ssl->options.noPskDheKe) {
if (!haveKS)
ERROR_OUT(MISSING_HANDSHAKE_DATA, dtls13_cleanup);
ERROR_OUT(PSK_KEY_ERROR, dtls13_cleanup);
doKE = 1;
}
else if ((modes & (1 << PSK_KE)) == 0) {
@ -641,11 +656,14 @@ static int SendStatelessReplyDtls13(const WOLFSSL* ssl, WolfSSL_CH* ch,
else
#endif
{
if (!haveKS || !haveSA) {
WOLFSSL_MSG("Client didn't send KeyShare or SigAlgs");
ERROR_OUT(INCOMPLETE_DATA, dtls13_cleanup);
}
ret = MatchSuite_ex(ssl, &suites, &cs, parsedExts);
if (ret < 0) {
WOLFSSL_MSG("Unsupported cipher suite, ClientHello");
SendAlert((WOLFSSL*)ssl, alert_fatal, handshake_failure);
goto dtls13_cleanup;
ERROR_OUT(INCOMPLETE_DATA, dtls13_cleanup);
}
}
if (cs.doHelloRetry) {
@ -710,9 +728,6 @@ static int SendStatelessReplyDtls13(const WOLFSSL* ssl, WolfSSL_CH* ch,
}
dtls13_cleanup:
TLSX_FreeAll(parsedExts, ssl->heap);
}
else
ret = SendAlert((WOLFSSL*)ssl, alert_fatal, illegal_parameter);
return ret;
}
#endif
@ -742,6 +757,27 @@ static int SendStatelessReply(const WOLFSSL* ssl, WolfSSL_CH* ch, byte isTls13,
return ret;
}
static int ClientHelloSanityCheck(WolfSSL_CH* ch, byte isTls13)
{
/* Do basic checks on the basic fields */
/* Check the protocol version */
if (ch->pv->major != DTLS_MAJOR)
return VERSION_ERROR;
if (ch->pv->minor != DTLSv1_2_MINOR && ch->pv->minor != DTLS_MINOR)
return VERSION_ERROR;
if (isTls13) {
if (ch->cookie.size != 0)
return INVALID_PARAMETER;
if (ch->compression.size != COMP_LEN)
return INVALID_PARAMETER;
if (ch->compression.elements[0] != NO_COMPRESSION)
return INVALID_PARAMETER;
}
return 0;
}
int DoClientHelloStateless(WOLFSSL* ssl, const byte* input,
word32* inOutIdx, word32 helloSz)
{
@ -771,6 +807,10 @@ int DoClientHelloStateless(WOLFSSL* ssl, const byte* input,
}
#endif
ret = ClientHelloSanityCheck(&ch, isTls13);
if (ret != 0)
return ret;
#if defined(WOLFSSL_DTLS13) || defined(WOLFSSL_DTLS_NO_HVR_ON_RESUME)
ret = TlsResumptionIsValid(ssl, &ch, &pskInfo, isTls13);
if (ret != 0)
@ -783,7 +823,7 @@ int DoClientHelloStateless(WOLFSSL* ssl, const byte* input,
}
#endif
#if defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET)
#if defined(WOLFSSL_DTLS13) && defined(HAVE_SESSION_TICKET)
if (pskInfo.isValid) {
if (IsAtLeastTLSv1_3(pskInfo.pv)) {
if (!isTls13)
@ -804,8 +844,16 @@ int DoClientHelloStateless(WOLFSSL* ssl, const byte* input,
ret = CheckDtlsCookie(ssl, &ch, isTls13, &cookieGood);
if (ret != 0)
return ret;
if (!cookieGood)
if (!cookieGood) {
#ifdef WOLFSSL_DTLS13
/* Invalid cookie for DTLS 1.3 results in an alert. Alert to be sent
* in DoTls13ClientHello. */
if (isTls13)
ret = INVALID_PARAMETER;
else
#endif
ret = SendStatelessReply((WOLFSSL*)ssl, &ch, isTls13, &pskInfo);
}
else
ssl->options.dtlsStateful = 1;
}

View File

@ -435,7 +435,7 @@ static int Dtls13SendNow(WOLFSSL* ssl, enum HandShakeType handshakeType)
return 0;
}
/* Handshake header DTLS only fields are not inlcuded in the transcript hash.
/* Handshake header DTLS only fields are not included in the transcript hash.
* body points to the body of the DTLSHandshake message. */
int Dtls13HashClientHello(const WOLFSSL* ssl, byte* hash, int* hashSz,
const byte* body, word32 length, CipherSpecs* specs)

View File

@ -30656,6 +30656,32 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
}
#endif /* HAVE_ECC */
int TranslateErrorToAlert(int err)
{
switch (err) {
case BUFFER_ERROR:
return decode_error;
case EXT_NOT_ALLOWED:
case PEER_KEY_ERROR:
case ECC_PEERKEY_ERROR:
case BAD_KEY_SHARE_DATA:
case PSK_KEY_ERROR:
case INVALID_PARAMETER:
case HRR_COOKIE_ERROR:
return illegal_parameter;
break;
case INCOMPLETE_DATA:
return missing_extension;
case MATCH_SUITE_ERROR:
case MISSING_HANDSHAKE_DATA:
return handshake_failure;
case VERSION_ERROR:
return wolfssl_alert_protocol_version;
default:
return invalid_alert;
}
}
#ifndef NO_WOLFSSL_SERVER
@ -33158,22 +33184,23 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
/* Update the ssl->options.dtlsStateful setting `if` statement in
* wolfSSL_accept when changing this one. */
if (IsDtlsNotSctpMode(ssl) && IsDtlsNotSrtpMode(ssl) && !IsSCR(ssl)) {
if (((ssl->keys.dtls_sequence_number_hi == ssl->keys.curSeq_hi &&
ssl->keys.dtls_sequence_number_lo < ssl->keys.curSeq_lo) ||
(ssl->keys.dtls_sequence_number_hi < ssl->keys.curSeq_hi))) {
/* We should continue with the same sequence number as the
* Client Hello if available. */
* Client Hello. */
ssl->keys.dtls_sequence_number_hi = ssl->keys.curSeq_hi;
ssl->keys.dtls_sequence_number_lo = ssl->keys.curSeq_lo;
}
/* We should continue with the same handshake number as the
* Client Hello. */
ssl->keys.dtls_handshake_number =
ssl->keys.dtls_peer_handshake_number;
ret = DoClientHelloStateless(ssl, input, inOutIdx, helloSz);
if (ret != 0 || !ssl->options.dtlsStateful) {
int alertType = TranslateErrorToAlert(ret);
if (alertType != invalid_alert)
SendAlert(ssl, alert_fatal, alertType);
*inOutIdx += helloSz;
DtlsResetState(ssl);
if (DtlsIgnoreError(ret))
ret = 0;
return ret;
}
}
@ -35440,7 +35467,6 @@ static int DefTicketEncCb(WOLFSSL* ssl, byte key_name[WOLFSSL_TICKET_NAME_SZ],
}
ssl->buffers.outputBuffer.length += sendSz;
DtlsResetState(ssl);
return SendBuffered(ssl);
}

View File

@ -6398,7 +6398,6 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
ret = DoClientHelloStateless(ssl, input, inOutIdx, helloSz);
if (ret != 0 || !ssl->options.dtlsStateful) {
*inOutIdx += helloSz;
DtlsResetState(ssl);
goto exit_dch;
}
}
@ -6422,8 +6421,7 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
/* this check pass for DTLS Major (0xff) */
if (args->pv.major < SSLv3_MAJOR) {
WOLFSSL_MSG("Legacy version field contains unsupported value");
SendAlert(ssl, alert_fatal, wolfssl_alert_protocol_version);
ERROR_OUT(INVALID_PARAMETER, exit_dch);
ERROR_OUT(VERSION_ERROR, exit_dch);
}
#ifdef WOLFSSL_DTLS13
@ -6501,13 +6499,13 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
#endif
sessIdSz = input[args->idx++];
if (sessIdSz != ID_LEN && sessIdSz != 0)
if (sessIdSz != ID_LEN && sessIdSz != 0) {
ERROR_OUT(INVALID_PARAMETER, exit_dch);
if (sessIdSz + args->idx > helloSz) {
ERROR_OUT(BUFFER_ERROR, exit_dch);
}
if (sessIdSz + args->idx > helloSz)
ERROR_OUT(BUFFER_ERROR, exit_dch);
ssl->session->sessionIDSz = sessIdSz;
if (sessIdSz == ID_LEN) {
XMEMCPY(ssl->session->sessionID, input + args->idx, sessIdSz);
@ -6516,8 +6514,13 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
#ifdef WOLFSSL_DTLS13
/* legacy_cookie */
if (ssl->options.dtls)
args->idx += OPAQUE8_LEN;
if (ssl->options.dtls) {
/* https://www.rfc-editor.org/rfc/rfc9147.html#section-5.3 */
byte cookieLen = input[args->idx++];
if (cookieLen != 0) {
ERROR_OUT(INVALID_PARAMETER, exit_dch);
}
}
#endif /* WOLFSSL_DTLS13 */
args->clSuites = (Suites*)XMALLOC(sizeof(Suites), ssl->heap,
@ -6624,12 +6627,6 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
*/
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;
@ -6675,12 +6672,10 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
#ifndef NO_CERTS
if (TLSX_Find(ssl->extensions, TLSX_KEY_SHARE) == NULL) {
WOLFSSL_MSG("Client did not send a KeyShare extension");
SendAlert(ssl, alert_fatal, missing_extension);
ERROR_OUT(INCOMPLETE_DATA, exit_dch);
}
if (TLSX_Find(ssl->extensions, TLSX_SIGNATURE_ALGORITHMS) == NULL) {
WOLFSSL_MSG("Client did not send a SignatureAlgorithms extension");
SendAlert(ssl, alert_fatal, missing_extension);
ERROR_OUT(INCOMPLETE_DATA, exit_dch);
}
#else
@ -6706,11 +6701,9 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
if (!args->usingPSK) {
if ((ret = MatchSuite(ssl, args->clSuites)) < 0) {
#ifdef WOLFSSL_ASYNC_CRYPT
if (ret == WC_PENDING_E)
goto exit_dch;
if (ret != WC_PENDING_E)
#endif
WOLFSSL_MSG("Unsupported cipher suite, ClientHello");
SendAlert(ssl, alert_fatal, handshake_failure);
goto exit_dch;
}
}
@ -6758,8 +6751,7 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
if (ssl->options.cipherSuite0 != TLS13_BYTE) {
WOLFSSL_MSG("Negotiated ciphersuite from lesser version than "
"TLS v1.3");
SendAlert(ssl, alert_fatal, handshake_failure);
ERROR_OUT(VERSION_ERROR, exit_dch);
ERROR_OUT(MATCH_SUITE_ERROR, exit_dch);
}
#ifdef HAVE_SESSION_TICKET
@ -6781,22 +6773,12 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
} /* switch (ssl->options.asyncState) */
#if defined(WOLFSSL_DTLS13) && defined(WOLFSSL_SEND_HRR_COOKIE)
/* 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
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
with KeyShare extension in HelloRetryRequest if the client
already provided a KeyShareEntry for that group. See rfc8446
section 4.1.4 */
TLSX_Remove(&ssl->extensions, TLSX_KEY_SHARE, ssl->heap);
/* send an HRR (see wolfSSL_Accept_TLSv13()) */
ssl->options.serverState = SERVER_HELLO_RETRY_REQUEST_COMPLETE;
ssl->options.serverState <= SERVER_HELLO_RETRY_REQUEST_COMPLETE) {
/* Cookie and key share negotiation should be handled in
* DoClientHelloStateless. If we enter here then something went wrong
* in our logic. */
ERROR_OUT(BAD_HELLO, exit_dch);
}
#endif /* WOLFSSL_DTLS13 */
@ -6820,22 +6802,6 @@ exit_dch:
}
#endif
if (ret == VERSION_ERROR) {
#ifdef WOLFSSL_DTLS
if (ssl->options.dtls) {
if (((ssl->keys.dtls_sequence_number_hi == ssl->keys.curSeq_hi &&
ssl->keys.dtls_sequence_number_lo < ssl->keys.curSeq_lo) ||
(ssl->keys.dtls_sequence_number_hi < ssl->keys.curSeq_hi))) {
/* We should continue with the same sequence number as the
* Client Hello if available. */
ssl->keys.dtls_sequence_number_hi = ssl->keys.curSeq_hi;
ssl->keys.dtls_sequence_number_lo = ssl->keys.curSeq_lo;
}
}
#endif
SendAlert(ssl, alert_fatal, wolfssl_alert_protocol_version);
}
FreeDch13Args(ssl, args);
#ifdef WOLFSSL_ASYNC_CRYPT
FreeAsyncCtx(ssl, 0);
@ -10937,6 +10903,7 @@ int DoTls13HandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx,
{
int ret = 0;
word32 inIdx = *inOutIdx;
int alertType = invalid_alert;
#if defined(HAVE_ECH)
TLSX* echX = NULL;
word32 echInOutIdx;
@ -11143,12 +11110,18 @@ int DoTls13HandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx,
ret = HashInput(ssl, input + inIdx, size);
}
if (ret == BUFFER_ERROR || ret == MISSING_HANDSHAKE_DATA)
SendAlert(ssl, alert_fatal, decode_error);
else if (ret == EXT_NOT_ALLOWED || ret == PEER_KEY_ERROR ||
ret == ECC_PEERKEY_ERROR || ret == BAD_KEY_SHARE_DATA ||
ret == PSK_KEY_ERROR || ret == INVALID_PARAMETER) {
SendAlert(ssl, alert_fatal, illegal_parameter);
alertType = TranslateErrorToAlert(ret);
if (alertType != invalid_alert) {
#ifdef WOLFSSL_DTLS13
if (type == client_hello && ssl->options.dtls) {
/* We should continue with the same sequence number as the
* Client Hello. */
ssl->dtls13EncryptEpoch->nextSeqNumber =
w64From32(ssl->keys.curSeq_hi, ssl->keys.curSeq_lo);
}
#endif
SendAlert(ssl, alert_fatal, alertType);
}
if (ret == 0 && ssl->options.tls1_3) {
@ -11263,7 +11236,15 @@ int DoTls13HandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx,
#endif /* NO_WOLFSSL_SERVER */
}
WOLFSSL_LEAVE("DoTls13HandShakeMsgType", ret);
#ifdef WOLFSSL_DTLS13
if (ssl->options.dtls && !ssl->options.dtlsStateful) {
DtlsResetState(ssl);
if (DtlsIgnoreError(ret))
ret = 0;
}
#endif
WOLFSSL_LEAVE("DoTls13HandShakeMsgType()", ret);
return ret;
}
@ -12524,47 +12505,6 @@ const char* wolfSSL_get_cipher_name_by_hash(WOLFSSL* ssl, const char* hash)
#ifndef NO_WOLFSSL_SERVER
#if defined(WOLFSSL_DTLS13) && defined(WOLFSSL_SEND_HRR_COOKIE)
static int DtlsAcceptStateless(WOLFSSL *ssl)
{
int ret;
if (!ssl->options.dtls)
return 0;
switch (ssl->options.acceptState) {
case TLS13_ACCEPT_BEGIN:
while (ssl->options.clientState < CLIENT_HELLO_COMPLETE) {
ret = ProcessReply(ssl);
if (ret != 0)
return ret;
}
if (!IsAtLeastTLSv1_3(ssl->version))
return wolfSSL_accept(ssl);
ssl->options.acceptState = TLS13_ACCEPT_CLIENT_HELLO_DONE;
WOLFSSL_MSG("accept state ACCEPT_CLIENT_HELLO_DONE");
FALL_THROUGH;
case TLS13_ACCEPT_CLIENT_HELLO_DONE:
if (ssl->options.serverState ==
SERVER_HELLO_RETRY_REQUEST_COMPLETE) {
ret = SendTls13ServerHello(ssl, hello_retry_request);
DtlsResetState(ssl);
return ret;
}
ssl->options.acceptState = TLS13_ACCEPT_HELLO_RETRY_REQUEST_DONE;
WOLFSSL_MSG("accept state ACCEPT_HELLO_RETRY_REQUEST_DONE");
FALL_THROUGH;
default:
return 0;
}
}
#endif /* WOLFSSL_DTLS13 */
/* The server accepting a connection from a client.
* The protocol version is expecting to be TLS v1.3.
@ -12761,19 +12701,6 @@ int wolfSSL_accept_TLSv13(WOLFSSL* ssl)
}
#endif /* WOLFSSL_DTLS13 */
#if defined(WOLFSSL_DTLS13) && defined(WOLFSSL_SEND_HRR_COOKIE)
if (ssl->options.dtls && ssl->options.sendCookie) {
while (ssl->options.serverState < SERVER_HELLO_COMPLETE) {
ret = DtlsAcceptStateless(ssl);
if (ret != 0) {
ssl->error = ret;
WOLFSSL_ERROR(ssl->error);
return WOLFSSL_FATAL_ERROR;
}
}
}
#endif /* defined(WOLFSSL_DTLS13) && defined(WOLFSSL_SEND_HRR_COOKIE) */
switch (ssl->options.acceptState) {
#ifdef HAVE_SECURE_RENEGOTIATION

View File

@ -6071,6 +6071,7 @@ WOLFSSL_LOCAL word32 nid2oid(int nid, int grp);
WOLFSSL_API int wolfSSL_DtlsUpdateWindow(word16 cur_hi, word32 cur_lo,
word16* next_hi, word32* next_lo, word32 *window);
WOLFSSL_LOCAL void DtlsResetState(WOLFSSL *ssl);
WOLFSSL_LOCAL int DtlsIgnoreError(int err);
#endif
#ifdef WOLFSSL_DTLS13
@ -6226,6 +6227,8 @@ WOLFSSL_LOCAL int CreateCookieExt(const WOLFSSL* ssl, byte* hash,
byte cipherSuite0, byte cipherSuite);
#endif
WOLFSSL_LOCAL int TranslateErrorToAlert(int err);
#ifdef __cplusplus
} /* extern "C" */
#endif

View File

@ -729,6 +729,7 @@ typedef struct WOLFSSL_RAND_METHOD {
* Add alert string to the function wolfSSL_alert_type_string_long in src/ssl.c
*/
enum AlertDescription {
invalid_alert = -1,
close_notify = 0,
unexpected_message = 10,
bad_record_mac = 20,

View File

@ -170,7 +170,7 @@ WOLFSSL_API void wolfSSL_Debugging_OFF(void);
WOLFSSL_API void WOLFSSL_MSG_EX(const char* fmt, ...);
#define HAVE_WOLFSSL_MSG_EX
#else
#define WOLFSSL_MSG_EX(...)
#define WOLFSSL_MSG_EX(...) do{} while(0)
#endif
WOLFSSL_API void WOLFSSL_MSG(const char* msg);
WOLFSSL_API void WOLFSSL_BUFFER(const byte* buffer, word32 length);