diff --git a/src/dtls.c b/src/dtls.c index 79277b152..65a9bcdfd 100644 --- a/src/dtls.c +++ b/src/dtls.c @@ -19,6 +19,15 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA */ +/* + * WOLFSSL_DTLS_NO_HVR_ON_RESUME + * If defined, a DTLS server will not do a cookie exchange on successful + * client resumption: the resumption will be faster (one RTT less) and + * will consume less bandwidth (one ClientHello and one HelloVerifyRequest + * less). On the other hand, if a valid SessionID is collected, forged + * clientHello messages will consume resources on the server. + */ + #ifdef HAVE_CONFIG_H #include #endif @@ -36,7 +45,7 @@ #ifdef WOLFSSL_DTLS -void DtlsResetState(WOLFSSL *ssl) +void DtlsResetState(WOLFSSL* ssl) { /* Reset the state so that we can statelessly await the * ClientHello that contains the cookie. Don't gate on IsAtLeastTLSv1_3 @@ -52,7 +61,7 @@ void DtlsResetState(WOLFSSL *ssl) w64Zero(&ssl->dtls13Epochs[0].nextSeqNumber); w64Zero(&ssl->dtls13Epochs[0].nextPeerSeqNumber); XMEMSET(ssl->dtls13Epochs[0].window, 0, - sizeof(ssl->dtls13Epochs[0].window)); + sizeof(ssl->dtls13Epochs[0].window)); Dtls13FreeFsmResources(ssl); #endif ssl->keys.dtls_expected_peer_handshake_number = 0; @@ -62,14 +71,282 @@ void DtlsResetState(WOLFSSL *ssl) 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->options.acceptState = ACCEPT_BEGIN; + ssl->options.handShakeState = NULL_STATE; ssl->msgsReceived.got_client_hello = 0; ssl->keys.dtls_handshake_number = 0; ssl->keys.dtls_expected_peer_handshake_number = 0; ssl->options.clientState = 0; + XMEMSET(ssl->keys.peerSeq->window, 0, sizeof(ssl->keys.peerSeq->window)); + XMEMSET(ssl->keys.peerSeq->prevWindow, 0, + sizeof(ssl->keys.peerSeq->prevWindow)); } +#if !defined(NO_WOLFSSL_SERVER) + +#if defined(NO_SHA) && defined(NO_SHA256) +#error "DTLS needs either SHA or SHA-256" +#endif /* NO_SHA && NO_SHA256 */ + +#if !defined(NO_SHA) && defined(NO_SHA256) +#define DTLS_COOKIE_TYPE WC_SHA +#define DTLS_COOKIE_SZ WC_SHA_DIGEST_SIZE +#endif /* !NO_SHA && NO_SHA256 */ + +#ifndef NO_SHA256 +#define DTLS_COOKIE_TYPE WC_SHA256 +#define DTLS_COOKIE_SZ WC_SHA256_DIGEST_SIZE +#endif /* !NO_SHA256 */ + +typedef struct WolfSSL_ConstVector { + word32 size; + const byte* elements; +} WolfSSL_ConstVector; + +typedef struct WolfSSL_CH { + ProtocolVersion* pv; + const byte* random; + WolfSSL_ConstVector sessionId; + WolfSSL_ConstVector cookie; + WolfSSL_ConstVector cipherSuite; + WolfSSL_ConstVector compression; + WolfSSL_ConstVector extension; + word32 length; +} WolfSSL_CH; + +static int ReadVector8(const byte* input, WolfSSL_ConstVector* v) +{ + v->size = *input; + v->elements = input + OPAQUE8_LEN; + return v->size + OPAQUE8_LEN; +} + +static int ReadVector16(const byte* input, WolfSSL_ConstVector* v) +{ + word16 size16; + ato16(input, &size16); + v->size = (word32)size16; + v->elements = input + OPAQUE16_LEN; + return v->size + OPAQUE16_LEN; +} + +static int CreateDtlsCookie(WOLFSSL* ssl, const WolfSSL_CH* ch, byte* cookie) +{ + Hmac cookieHmac; + int ret; + + ret = wc_HmacInit(&cookieHmac, ssl->heap, ssl->devId); + if (ret != 0) + return ret; + ret = wc_HmacSetKey(&cookieHmac, DTLS_COOKIE_TYPE, + ssl->buffers.dtlsCookieSecret.buffer, + ssl->buffers.dtlsCookieSecret.length); + if (ret != 0) + goto out; + ret = wc_HmacUpdate(&cookieHmac, (const byte*)ssl->buffers.dtlsCtx.peer.sa, + ssl->buffers.dtlsCtx.peer.sz); + if (ret != 0) + goto out; + ret = wc_HmacUpdate(&cookieHmac, (byte*)ch->pv, OPAQUE16_LEN); + if (ret != 0) + goto out; + ret = wc_HmacUpdate(&cookieHmac, (byte*)ch->random, RAN_LEN); + if (ret != 0) + goto out; + ret = wc_HmacUpdate(&cookieHmac, (byte*)ch->sessionId.elements, + ch->sessionId.size); + if (ret != 0) + goto out; + ret = wc_HmacUpdate(&cookieHmac, (byte*)ch->cipherSuite.elements, + ch->cipherSuite.size); + if (ret != 0) + goto out; + ret = wc_HmacUpdate(&cookieHmac, (byte*)ch->compression.elements, + ch->compression.size); + if (ret != 0) + goto out; + ret = wc_HmacFinal(&cookieHmac, cookie); + +out: + wc_HmacFree(&cookieHmac); + return ret; +} + +static int ParseClientHello(const byte* input, word32 helloSz, WolfSSL_CH* ch) +{ + word32 idx = 0; + + /* protocol version, random and session id length check */ + if (OPAQUE16_LEN + RAN_LEN + OPAQUE8_LEN > helloSz) + return BUFFER_ERROR; + + ch->pv = (ProtocolVersion*)(input + idx); + idx += OPAQUE16_LEN; + ch->random = (byte*)(input + idx); + idx += RAN_LEN; + idx += ReadVector8(input + idx, &ch->sessionId); + if (idx > helloSz - OPAQUE8_LEN) + return BUFFER_ERROR; + idx += ReadVector8(input + idx, &ch->cookie); + if (idx > helloSz - OPAQUE16_LEN) + return BUFFER_ERROR; + idx += ReadVector16(input + idx, &ch->cipherSuite); + if (idx > helloSz - OPAQUE8_LEN) + return BUFFER_ERROR; + idx += ReadVector8(input + idx, &ch->compression); + if (idx > helloSz - OPAQUE16_LEN) + return BUFFER_ERROR; + idx += ReadVector16(input + idx, &ch->extension); + if (idx > helloSz) + return BUFFER_ERROR; + ch->length = idx; + return 0; +} + +#ifdef WOLFSSL_DTLS_NO_HVR_ON_RESUME +#ifdef HAVE_SESSION_TICKET +static int TlsxFindByType(WolfSSL_ConstVector* ret, word16 extType, + WolfSSL_ConstVector exts) +{ + word32 len, idx = 0; + word16 type; + WolfSSL_ConstVector ext; + + XMEMSET(ret, 0, sizeof(*ret)); + len = exts.size; + /* type + len */ + while (len >= OPAQUE16_LEN + OPAQUE16_LEN) { + ato16(exts.elements + idx, &type); + idx += OPAQUE16_LEN; + idx += ReadVector16(exts.elements + idx, &ext); + if (idx > exts.size) + return BUFFER_ERROR; + if (type == extType) { + XMEMCPY(ret, &ext, sizeof(ext)); + return 0; + } + len = exts.size - idx; + } + return 0; +} + +static int TlsTicketIsValid(WOLFSSL* ssl, WolfSSL_ConstVector exts, + byte* isValid) +{ + WolfSSL_ConstVector tlsxSessionTicket; + byte tempTicket[SESSION_TICKET_LEN]; + InternalTicket* it; + int ret; + + *isValid = 0; + ret = TlsxFindByType(&tlsxSessionTicket, TLSX_SESSION_TICKET, exts); + if (ret != 0) + return ret; + if (tlsxSessionTicket.size == 0) + return 0; + if (tlsxSessionTicket.size > SESSION_TICKET_LEN) + return 0; + XMEMCPY(tempTicket, tlsxSessionTicket.elements, tlsxSessionTicket.size); + ret = DoDecryptTicket(ssl, tempTicket, (word32)tlsxSessionTicket.size, &it); + if (ret != WOLFSSL_TICKET_RET_OK && ret != WOLFSSL_TICKET_RET_CREATE) + return 0; + ForceZero(it, sizeof(InternalTicket)); + *isValid = 1; + return 0; +} +#endif /* HAVE_SESSION_TICKET */ + +static int TlsSessionIdIsValid(WOLFSSL* ssl, WolfSSL_ConstVector sessionID, + byte* isValid) +{ + WOLFSSL_SESSION* sess; + word32 sessRow; + int ret; + + *isValid = 0; + if (ssl->options.sessionCacheOff) + return 0; + if (sessionID.size != ID_LEN) + return 0; +#ifdef HAVE_EXT_CACHE + { + + if (ssl->ctx->get_sess_cb != NULL) { + int unused; + sess = + ssl->ctx->get_sess_cb(ssl, sessionID.elements, ID_LEN, &unused); + if (sess != NULL) { + *isValid = 1; + wolfSSL_FreeSession(ssl->ctx, sess); + return 0; + } + } + if (ssl->ctx->internalCacheLookupOff) + return 0; + } +#endif + ret = TlsSessionCacheGetAndLock(sessionID.elements, &sess, &sessRow); + if (ret == 0 && sess != NULL) { + *isValid = 1; + TlsSessionCacheUnlockRow(sessRow); + } + + return 0; +} + +static int TlsResumptionIsValid(WOLFSSL* ssl, WolfSSL_CH* ch, byte* isValid) +{ + int ret; + + *isValid = 0; +#ifdef HAVE_SESSION_TICKET + ret = TlsTicketIsValid(ssl, ch->extension, isValid); + if (ret != 0) + return ret; + if (*isValid) + return 0; +#endif /* HAVE_SESSION_TICKET */ + ret = TlsSessionIdIsValid(ssl, ch->sessionId, isValid); + return ret; +} +#endif /* WOLFSSL_DTLS_NO_HVR_ON_RESUME */ + +int DoClientHelloStateless(WOLFSSL* ssl, const byte* input, word32* inOutIdx, + word32 helloSz, byte* process) +{ + byte cookie[DTLS_COOKIE_SZ]; + int ret; + WolfSSL_CH ch; + + *process = 1; + ret = ParseClientHello(input + *inOutIdx, helloSz, &ch); + if (ret != 0) + return ret; + +#ifdef WOLFSSL_DTLS_NO_HVR_ON_RESUME + { + byte isValid = 0; + ret = TlsResumptionIsValid(ssl, &ch, &isValid); + if (ret != 0) + return ret; + if (isValid) + return 0; + } +#endif /* WOLFSSL_DTLS_NO_HVR_ON_RESUME */ + + ret = CreateDtlsCookie(ssl, &ch, cookie); + if (ret != 0) + return ret; + if (ch.cookie.size != DTLS_COOKIE_SZ || + XMEMCMP(ch.cookie.elements, cookie, DTLS_COOKIE_SZ) != 0) { + *process = 0; + ret = SendHelloVerifyRequest(ssl, cookie, DTLS_COOKIE_SZ); + } + + return ret; +} +#endif /* !defined(NO_WOLFSSL_SERVER) */ + #if defined(WOLFSSL_DTLS_CID) typedef struct ConnectionID { @@ -423,5 +700,4 @@ int wolfSSL_dtls_cid_get_tx(WOLFSSL* ssl, unsigned char* buf, } #endif /* WOLFSSL_DTLS_CID */ - #endif /* WOLFSSL_DTLS */ diff --git a/src/internal.c b/src/internal.c index 67c6ae7d3..44640fbad 100644 --- a/src/internal.c +++ b/src/internal.c @@ -65,13 +65,6 @@ * may be received by a client. To support detecting this, peek will * return WOLFSSL_ERROR_WANT_READ. * This define turns off this behaviour. - * WOLFSSL_DTLS_NO_HVR_ON_RESUME - * If defined, a DTLS server will not do a cookie exchange on successful - * client resumption: the resumption will be faster (one RTT less) and - * will consume less bandwidth (one ClientHello and one HelloVerifyRequest - * less). On the other hand, if a valid SessionID is collected, forged - * clientHello messages will consume resources on the server. - * This define is turned off by default. * WOLFSSL_HOSTNAME_VERIFY_ALT_NAME_ONLY * Verify hostname/ip address using alternate name (SAN) only and do not * use the common name. Forces use of the alternate name, so certificates @@ -178,11 +171,6 @@ WOLFSSL_CALLBACKS needs LARGE_STATIC_BUFFERS, please add LARGE_STATIC_BUFFERS static int DoCertificateVerify(WOLFSSL* ssl, byte* input, word32* inOutIdx, word32 size); #endif - #ifdef WOLFSSL_DTLS - static int SendHelloVerifyRequest(WOLFSSL* ssl, - const byte* cookie, byte cookieSz); - #endif /* WOLFSSL_DTLS */ - #endif /* !NO_WOLFSSL_SERVER */ #endif /* !WOLFSSL_NO_TLS12 */ @@ -9419,6 +9407,10 @@ static void AddRecordHeader(byte* output, word32 length, byte type, WOLFSSL* ssl #ifdef WOLFSSL_TLS13 if (IsAtLeastTLSv1_3(ssl->version)) { rl->pvMinor = TLSv1_2_MINOR; +#ifdef WOLFSSL_DTLS + if (ssl->options.dtls) + rl->pvMinor = DTLSv1_2_MINOR; +#endif /* WOLFSSL_DTLS */ } else #endif @@ -32782,7 +32774,7 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, * was created, timeout value and the current time. If the tickets are * judged expired, falls back to full-handshake. If you want disable this * session ticket validation check in TLS1.2 and below, define - * WOLFSSL_NO_TICKET_EXPRE. + * WOLFSSL_NO_TICKET_EXPIRE. */ int HandleTlsResumption(WOLFSSL* ssl, int bogusID, Suites* clSuites) { @@ -32917,17 +32909,6 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, int ret = 0; byte lesserVersion; -#ifdef WOLFSSL_DTLS - Hmac cookieHmac; - byte newCookie[MAX_COOKIE_LEN]; - byte peerCookie[MAX_COOKIE_LEN]; - byte peerCookieSz = 0; - byte cookieType; - byte cookieSz = 0; - - XMEMSET(&cookieHmac, 0, sizeof(Hmac)); -#endif /* WOLFSSL_DTLS */ - WOLFSSL_START(WC_FUNC_CLIENT_HELLO_DO); WOLFSSL_ENTER("DoClientHello"); @@ -32935,6 +32916,21 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, if (ssl->hsInfoOn) AddPacketName(ssl, "ClientHello"); if (ssl->toInfoOn) AddLateName("ClientHello", &ssl->timeoutInfo); #endif + /* do not change state in the SSL object before the next region of code + * to be able to statelessly compute a DTLS cookie */ +#ifdef WOLFSSL_DTLS + if (IsDtlsNotSctpMode(ssl) && IsDtlsNotSrtpMode(ssl) && !IsSCR(ssl)) { + byte process = 0; + ret = DoClientHelloStateless(ssl, input, inOutIdx, helloSz, + &process); + if (ret != 0 || !process) { + *inOutIdx += helloSz; + DtlsResetState(ssl); + return ret; + } + } +#endif /* WOLFSSL_DTLS */ + /* protocol version, random and session id length check */ if (OPAQUE16_LEN + RAN_LEN + OPAQUE8_LEN > helloSz) return BUFFER_ERROR; @@ -32956,29 +32952,6 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, * Client Hello. */ ssl->keys.dtls_handshake_number = ssl->keys.dtls_peer_handshake_number; - - #if defined(NO_SHA) && defined(NO_SHA256) - #error "DTLS needs either SHA or SHA-256" - #endif /* NO_SHA && NO_SHA256 */ - - #if !defined(NO_SHA) && defined(NO_SHA256) - cookieType = WC_SHA; - cookieSz = WC_SHA_DIGEST_SIZE; - #endif /* NO_SHA */ - #ifndef NO_SHA256 - cookieType = WC_SHA256; - cookieSz = WC_SHA256_DIGEST_SIZE; - #endif /* NO_SHA256 */ - ret = wc_HmacSetKey(&cookieHmac, cookieType, - ssl->buffers.dtlsCookieSecret.buffer, - ssl->buffers.dtlsCookieSecret.length); - if (ret != 0) goto out; - ret = wc_HmacUpdate(&cookieHmac, - (const byte*)ssl->buffers.dtlsCtx.peer.sa, - ssl->buffers.dtlsCtx.peer.sz); - if (ret != 0) goto out; - ret = wc_HmacUpdate(&cookieHmac, input + i, OPAQUE16_LEN); - if (ret != 0) goto out; } #endif /* WOLFSSL_DTLS */ i += OPAQUE16_LEN; @@ -33049,15 +33022,9 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, WOLFSSL_MSG("\tDowngrading to DTLSv1.2"); ssl->options.tls1_3 = 0; ssl->version.minor = DTLSv1_2_MINOR; - - /* reset hashes, DTLSv1.2 will take care of the hashing - later */ - ret = InitHandshakeHashes(ssl); - if (ret != 0) - return ret; } else if (pv.minor == DTLS_MINOR) { - WOLFSSL_MSG("\tDowngrading to DTLSv1.2"); + WOLFSSL_MSG("\tDowngrading to DTLSv1.0"); ssl->options.tls1_3 = 0; ssl->version.minor = DTLS_MINOR; } @@ -33154,12 +33121,6 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, /* random */ XMEMCPY(ssl->arrays->clientRandom, input + i, RAN_LEN); -#ifdef WOLFSSL_DTLS - if (IsDtlsNotSctpMode(ssl) && IsDtlsNotSrtpMode(ssl) && !IsSCR(ssl)) { - ret = wc_HmacUpdate(&cookieHmac, input + i, RAN_LEN); - if (ret != 0) goto out; - } -#endif /* WOLFSSL_DTLS */ i += RAN_LEN; #ifdef SHOW_SECRETS @@ -33189,13 +33150,6 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, } XMEMCPY(ssl->arrays->sessionID, input + i, b); -#ifdef WOLFSSL_DTLS - if (IsDtlsNotSctpMode(ssl) && IsDtlsNotSrtpMode(ssl) && - !IsSCR(ssl)) { - ret = wc_HmacUpdate(&cookieHmac, input + i - 1, b + 1); - if (ret != 0) goto out; - } -#endif /* WOLFSSL_DTLS */ ssl->arrays->sessionIDSz = b; i += b; ssl->options.resuming = 1; /* client wants to resume */ @@ -33207,10 +33161,10 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, goto out; } - #ifdef WOLFSSL_DTLS +#ifdef WOLFSSL_DTLS /* cookie */ if (ssl->options.dtls) { - + word8 peerCookieSz; if ((i - begin) + OPAQUE8_LEN > helloSz) { ret = BUFFER_ERROR; goto out; @@ -33229,12 +33183,10 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, goto out; } - XMEMCPY(peerCookie, input + i, peerCookieSz); - i += peerCookieSz; } } - #endif +#endif /* WOLFSSL_DTLS */ /* suites */ if ((i - begin) + OPAQUE16_LEN > helloSz) { @@ -33304,14 +33256,6 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, } #endif -#ifdef WOLFSSL_DTLS - if (IsDtlsNotSctpMode(ssl) && IsDtlsNotSrtpMode(ssl) && !IsSCR(ssl)) { - ret = wc_HmacUpdate(&cookieHmac, - input + i - OPAQUE16_LEN, - clSuites->suiteSz + OPAQUE16_LEN); - if (ret != 0) goto out; - } -#endif /* WOLFSSL_DTLS */ i += clSuites->suiteSz; clSuites->hashSigAlgoSz = 0; @@ -33332,38 +33276,6 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, goto out; } -#ifdef WOLFSSL_DTLS - if (IsDtlsNotSctpMode(ssl) && IsDtlsNotSrtpMode(ssl) && !IsSCR(ssl)) { - - ret = wc_HmacUpdate(&cookieHmac, input + i - 1, b + 1); - if (ret != 0) goto out; - ret = wc_HmacFinal(&cookieHmac, newCookie); - if (ret != 0) goto out; - - /* If a cookie callback is set, call it to overwrite the cookie. - * This should be deprecated. The code now calculates the cookie - * using an HMAC as expected. */ - if (ssl->ctx->CBIOCookie != NULL && - ssl->ctx->CBIOCookie(ssl, newCookie, cookieSz, - ssl->IOCB_CookieCtx) != cookieSz) { - ret = COOKIE_ERROR; - goto out; - } - - -#ifndef WOLFSSL_DTLS_NO_HVR_ON_RESUME - if (peerCookieSz != cookieSz || - XMEMCMP(peerCookie, newCookie, cookieSz) != 0) { - *inOutIdx += helloSz; - ret = SendHelloVerifyRequest(ssl, newCookie, cookieSz); - goto out; - } -#endif /* !WOLFSSL_DTLS_NO_HVR_ON_RESUME */ - - - } -#endif /* WOLFSSL_DTLS */ - { /* compression match types */ int matchNo = 0; @@ -33548,20 +33460,6 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, } } -#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_DTLS_NO_HVR_ON_RESUME) - if (IsDtlsNotSctpMode(ssl) && IsDtlsNotSrtpMode(ssl) && !IsSCR(ssl)) { - - if (!ssl->options.resuming) { - /* resume failed, check the cookie */ - if (peerCookieSz != cookieSz || - XMEMCMP(peerCookie, newCookie, cookieSz) != 0) { - *inOutIdx = begin + helloSz; - ret = SendHelloVerifyRequest(ssl, newCookie, cookieSz); - goto out; - } - } - } -#endif /* WOLFSSL_DTLS && WOLFSSL_DTLS_NO_HVR_ON_RESUME */ #if defined(HAVE_TLS_EXTENSIONS) && defined(HAVE_DH_DEFAULT_PARAMS) #if defined(HAVE_FFDHE) && defined(HAVE_SUPPORTED_CURVES) @@ -33606,9 +33504,6 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, out: -#ifdef WOLFSSL_DTLS - wc_HmacFree(&cookieHmac); -#endif #ifdef WOLFSSL_SMALL_STACK if (clSuites != NULL) XFREE(clSuites, ssl->heap, DYNAMIC_TYPE_SUITES); @@ -34386,12 +34281,10 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, } - - /* Parse ticket sent by client, returns callback return value */ - int DoClientTicket(WOLFSSL* ssl, const byte* input, word32 len) + int DoDecryptTicket(WOLFSSL* ssl, const byte* input, word32 len, + InternalTicket **it) { ExternalTicket* et; - InternalTicket* it; int ret; int outLen; word16 inLen; @@ -34451,8 +34344,22 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, WOLFSSL_ERROR_VERBOSE(BAD_TICKET_KEY_CB_SZ); return BAD_TICKET_KEY_CB_SZ; } + *it = (InternalTicket*)et->enc_ticket; + return 0; + } - it = (InternalTicket*)et->enc_ticket; + /* Parse ticket sent by client, returns callback return value */ + int DoClientTicket(WOLFSSL* ssl, const byte* input, word32 len) + { + InternalTicket* it; + int ret; + + WOLFSSL_START(WC_FUNC_TICKET_DO); + WOLFSSL_ENTER("DoClientTicket"); + + ret = DoDecryptTicket(ssl, input, len, &it); + if (ret != 0) + return ret; #ifdef WOLFSSL_CHECK_MEM_ZERO /* Internal ticket successfully decrypted. */ wc_MemZero_Add("Do Client Ticket internal", it, sizeof(InternalTicket)); @@ -35212,8 +35119,8 @@ static int DefTicketEncCb(WOLFSSL* ssl, byte key_name[WOLFSSL_TICKET_NAME_SZ], #ifdef WOLFSSL_DTLS /* handle generation of DTLS hello_verify_request (3) */ - static int SendHelloVerifyRequest(WOLFSSL* ssl, - const byte* cookie, byte cookieSz) + int SendHelloVerifyRequest(WOLFSSL* ssl, + const byte* cookie, byte cookieSz) { byte* output; int length = VERSION_SZ + ENUM_LEN + cookieSz; @@ -35251,13 +35158,8 @@ static int DefTicketEncCb(WOLFSSL* ssl, byte key_name[WOLFSSL_TICKET_NAME_SZ], } AddHeaders(output, length, hello_verify_request, ssl); -#ifdef OPENSSL_EXTRA output[idx++] = DTLS_MAJOR; output[idx++] = DTLS_MINOR; -#else - output[idx++] = ssl->version.major; - output[idx++] = ssl->version.minor; -#endif output[idx++] = cookieSz; if (cookie == NULL || cookieSz == 0) diff --git a/src/ssl.c b/src/ssl.c index 880cf92ea..db6c22992 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -12380,7 +12380,7 @@ int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl, ForceZero(ssl->buffers.dtlsCookieSecret.buffer, ssl->buffers.dtlsCookieSecret.length); XFREE(ssl->buffers.dtlsCookieSecret.buffer, - ssl->heap, DYNAMIC_TYPE_NONE); + ssl->heap, DYNAMIC_TYPE_COOKIE_PWD); } newSecret = (byte*)XMALLOC(secretSz, ssl->heap,DYNAMIC_TYPE_COOKIE_PWD); @@ -13839,15 +13839,63 @@ static int wolfSSL_DupSessionEx(const WOLFSSL_SESSION* input, WOLFSSL_SESSION* output, int avoidSysCalls, byte* ticketNonceBuf, byte* ticketNonceLen, byte* preallocUsed); +void TlsSessionCacheUnlockRow(word32 row) +{ + SessionRow* sessRow; + + sessRow = &SessionCache[row]; + (void)sessRow; + SESSION_ROW_UNLOCK(sessRow); +} + +int TlsSessionCacheGetAndLock(const byte *id, WOLFSSL_SESSION **sess, + word32 *lockedRow) +{ + SessionRow *sessRow; + WOLFSSL_SESSION *s; + word32 row; + int count; + int error; + int idx; + + *sess = NULL; + row = HashObject(id, ID_LEN, &error) % SESSION_ROWS; + if (error != 0) + return error; + sessRow = &SessionCache[row]; + if (SESSION_ROW_LOCK(sessRow) != 0) + return FATAL_ERROR; + + /* start from most recently used */ + count = min((word32)sessRow->totalCount, SESSIONS_PER_ROW); + idx = sessRow->nextIdx - 1; + if (idx < 0 || idx >= SESSIONS_PER_ROW) { + idx = SESSIONS_PER_ROW - 1; /* if back to front, the previous was end */ + } + for (; count > 0; --count) { + s = &sessRow->Sessions[idx]; + if (XMEMCMP(s->sessionID, id, ID_LEN) == 0) { + *sess = s; + break; + } + idx = idx > 0 ? idx - 1 : SESSIONS_PER_ROW - 1; + } + if (*sess == NULL) { + SESSION_ROW_UNLOCK(sessRow); + } + else { + *lockedRow = row; + } + + return 0; +} + int wolfSSL_GetSessionFromCache(WOLFSSL* ssl, WOLFSSL_SESSION* output) { WOLFSSL_SESSION* sess = NULL; const byte* id = NULL; word32 row; - int idx; - int count; int error = 0; - SessionRow* sessRow; #ifdef HAVE_SESSION_TICKET #ifndef WOLFSSL_SMALL_STACK byte tmpTicket[PREALLOC_SESSION_TICKET_LEN]; @@ -13937,13 +13985,6 @@ int wolfSSL_GetSessionFromCache(WOLFSSL* ssl, WOLFSSL_SESSION* output) } #endif - row = HashObject(id, ID_LEN, &error) % SESSION_ROWS; - if (error != 0) { - WOLFSSL_MSG("Hash session failed"); - return WOLFSSL_FAILURE; - } - - #ifdef HAVE_SESSION_TICKET if (output->ticket == NULL || output->ticketLenAlloc < PREALLOC_SESSION_TICKET_LEN) { @@ -13995,61 +14036,48 @@ int wolfSSL_GetSessionFromCache(WOLFSSL* ssl, WOLFSSL_SESSION* output) } #endif /* WOLFSSL_TLS13 && HAVE_SESSION_TICKET*/ - /* lock row */ - sessRow = &SessionCache[row]; - if (SESSION_ROW_LOCK(sessRow) != 0) { - WOLFSSL_MSG("Session cache row lock failure"); + /* init to avoid clang static analyzer false positive */ + row = 0; + error = TlsSessionCacheGetAndLock(id, &sess, &row); + error = (error == 0) ? WOLFSSL_SUCCESS : WOLFSSL_FAILURE; + if (error != WOLFSSL_SUCCESS || sess == NULL) { + WOLFSSL_MSG("Get Session from cache failed"); + error = WOLFSSL_FAILURE; #ifdef HAVE_SESSION_TICKET if (tmpBufSet) { output->ticket = output->staticTicket; output->ticketLenAlloc = 0; } #ifdef WOLFSSL_TLS13 - if (preallocNonce != NULL) + if (preallocNonce != NULL) { XFREE(preallocNonce, output->heap, DYNAMIC_TYPE_SESSION_TICK); + preallocNonce = NULL; + } #endif /* WOLFSSL_TLS13 */ #ifdef WOLFSSL_SMALL_STACK - if (tmpTicket != NULL) + if (tmpTicket != NULL) { XFREE(tmpTicket, output->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif -#endif - return WOLFSSL_FAILURE; - } - - /* start from most recently used */ - count = min((word32)sessRow->totalCount, SESSIONS_PER_ROW); - idx = sessRow->nextIdx - 1; - if (idx < 0 || idx >= SESSIONS_PER_ROW) { - idx = SESSIONS_PER_ROW - 1; /* if back to front, the previous was end */ - } - - for (; count > 0; --count) { - WOLFSSL_SESSION* current; - - current = &sessRow->Sessions[idx]; - if (XMEMCMP(current->sessionID, id, ID_LEN) == 0 - && current->side == ssl->options.side - #if defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET) - && (IsAtLeastTLSv1_3(ssl->version) == - IsAtLeastTLSv1_3(current->version)) - #endif - ) { - WOLFSSL_MSG("Found a session match"); - if (LowResTimer() < (current->bornOn + current->timeout)) { - WOLFSSL_MSG("Session valid"); - sess = current; - } else { - WOLFSSL_MSG("Session timed out"); - } - break; /* no more sessionIDs whether valid or not that match */ - } else { - WOLFSSL_MSG("SessionID not a match at this idx"); + tmpTicket = NULL; } - - idx = idx > 0 ? idx - 1 : SESSIONS_PER_ROW - 1; +#endif +#endif + } + else { +#if defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET) + if (IsAtLeastTLSv1_3(ssl->version) != IsAtLeastTLSv1_3(sess->version)) { + WOLFSSL_MSG("Invalid session: different protocol version"); + TlsSessionCacheUnlockRow(row); + error = WOLFSSL_FAILURE; + } + else if (LowResTimer() >= (sess->bornOn + sess->timeout)) { + WOLFSSL_MSG("Invalid session: timed out"); + TlsSessionCacheUnlockRow(row); + error = WOLFSSL_FAILURE; + } +#endif /* HAVE_SESSION_TICKET && WOLFSSL_TLS13 */ } - if (sess != NULL) { + if (error == WOLFSSL_SUCCESS) { #if defined(SESSION_CERTS) && defined(OPENSSL_EXTRA) /* We don't want the peer member. We will free it at the end. */ if (sess->peer != NULL) { @@ -14062,17 +14090,12 @@ int wolfSSL_GetSessionFromCache(WOLFSSL* ssl, WOLFSSL_SESSION* output) preallocNonce, &preallocNonceLen, &preallocNonceUsed); #else error = wolfSSL_DupSession(sess, output, 1); -#endif /* WOLFSSL_TSL */ - +#endif /* HAVE_SESSION_TICKET && WOLFSSL_TLS13 */ #ifdef HAVE_EX_DATA output->ownExData = 0; /* Session cache owns external data */ #endif + TlsSessionCacheUnlockRow(row); } - else { - error = WOLFSSL_FAILURE; - } - - SESSION_ROW_UNLOCK(sessRow); /* We want to restore the bogus ID for TLS compatibility */ if (ssl->session->haveAltSessionID && diff --git a/src/tls13.c b/src/tls13.c index b60626215..a21c7a993 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -5915,6 +5915,7 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, if (wantDowngrade) { #ifndef WOLFSSL_NO_TLS12 + byte realMinor; if (!ssl->options.downgrade) { WOLFSSL_MSG("Client trying to connect with lesser version than " "TLS v1.3"); @@ -5928,7 +5929,10 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, ERROR_OUT(VERSION_ERROR, exit_dch); } + realMinor = ssl->version.minor; + ssl->version.minor = args->pv.minor; ret = HashInput(ssl, input + args->begin, helloSz); + ssl->version.minor = realMinor; if (ret == 0) { ret = DoClientHello(ssl, input, inOutIdx, helloSz); } diff --git a/tests/api.c b/tests/api.c index 92063eab0..ea0df1598 100644 --- a/tests/api.c +++ b/tests/api.c @@ -58699,6 +58699,263 @@ static int test_wolfSSL_DTLS_fragment_buckets(void) } #endif +#if defined(WOLFSSL_DTLS) && !defined(WOLFSSL_NO_TLS12) && \ + !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) + +static int test_wolfSSL_dtls_stateless2(void) +{ + WOLFSSL *ssl_c, *ssl_c2, *ssl_s; + struct test_memio_ctx test_ctx; + WOLFSSL_CTX *ctx_c, *ctx_s; + int ret; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ret = test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method); + if (ret != 0) + return -1; + ssl_c2 = wolfSSL_new(ctx_c); + if (ssl_c2 == NULL) + return -2; + wolfSSL_SetIOWriteCtx(ssl_c2, &test_ctx); + wolfSSL_SetIOReadCtx(ssl_c2, &test_ctx); + /* send CH */ + ret = wolfSSL_connect(ssl_c2); + if (ret == 0 || ssl_c2->error != WANT_READ) + return -3; + ret = wolfSSL_accept(ssl_s); + if (ret == 0 || ssl_s->error != WANT_READ) + return -4; + if (test_ctx.c_len == 0) + return -5; + /* consume HRR */ + test_ctx.c_len = 0; + ret = test_memio_do_handshake(ssl_c, ssl_s, 10, NULL); + if (ret != 0) + return -6; + wolfSSL_free(ssl_c2); + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); + return TEST_SUCCESS; +} + +#ifdef HAVE_MAX_FRAGMENT +static int test_wolfSSL_dtls_stateless_maxfrag(void) +{ + WOLFSSL *ssl_c, *ssl_c2, *ssl_s; + struct test_memio_ctx test_ctx; + WOLFSSL_CTX *ctx_c, *ctx_s; + word16 max_fragment; + int ret; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ret = test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method); + if (ret != 0) + return -1; + ssl_c2 = wolfSSL_new(ctx_c); + if (ssl_c2 == NULL) + return -2; + ret = wolfSSL_UseMaxFragment(ssl_c2, WOLFSSL_MFL_2_8); + if (ret != WOLFSSL_SUCCESS) + return -3; + wolfSSL_SetIOWriteCtx(ssl_c2, &test_ctx); + wolfSSL_SetIOReadCtx(ssl_c2, &test_ctx); + max_fragment = ssl_s->max_fragment; + /* send CH */ + ret = wolfSSL_connect(ssl_c2); + if (ret == 0 || ssl_c2->error != WANT_READ) + return -4; + ret = wolfSSL_accept(ssl_s); + if (ret == 0 || ssl_s->error != WANT_READ) + return -5; + /* CH without cookie shouldn't change state */ + if (ssl_s->max_fragment != max_fragment) + return -6; + if (test_ctx.c_len == 0) + return -7; + /* consume HRR from buffer */ + test_ctx.c_len = 0; + ret = test_memio_do_handshake(ssl_c, ssl_s, 10, NULL); + if (ret != 0) + return -8; + wolfSSL_free(ssl_c2); + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); + return TEST_SUCCESS; +} +#endif /* HAVE_MAX_FRAGMENT */ + +#if defined(WOLFSSL_DTLS_NO_HVR_ON_RESUME) +#define ROUNDS_WITH_HVR 4 +#define ROUNDS_WITHOUT_HVR 2 +#define HANDSHAKE_TYPE_OFFSET DTLS_RECORD_HEADER_SZ +static int buf_is_hvr(const byte *data, int len) +{ + if (len < DTLS_RECORD_HEADER_SZ + DTLS_HANDSHAKE_HEADER_SZ) + return 0; + return data[HANDSHAKE_TYPE_OFFSET] == hello_verify_request; +} + +static int _test_wolfSSL_dtls_stateless_resume(byte useticket, byte bad) +{ + struct test_memio_ctx test_ctx; + WOLFSSL_CTX *ctx_c, *ctx_s; + WOLFSSL *ssl_c, *ssl_s; + WOLFSSL_SESSION *sess; + int ret, round_trips; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ret = test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method); + if (ret != 0) + return -1; +#ifdef HAVE_SESSION_TICKET + if (useticket) { + ret = wolfSSL_UseSessionTicket(ssl_c); + if (ret != WOLFSSL_SUCCESS) + return -2; + } +#endif + round_trips = ROUNDS_WITH_HVR; + ret = test_memio_do_handshake(ssl_c, ssl_s, round_trips, &round_trips); + if (ret != 0) + return -3; + if (round_trips != ROUNDS_WITH_HVR) + return -4; + sess = wolfSSL_get1_session(ssl_c); + if (sess == NULL) + return -5; + wolfSSL_shutdown(ssl_c); + wolfSSL_shutdown(ssl_s); + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + test_ctx.c_len = test_ctx.s_len = 0; + /* make resumption invalid */ + if (bad) { + if (useticket) { +#ifdef HAVE_SESSION_TICKET + sess->ticket[0] = !sess->ticket[0]; +#endif /* HAVE_SESSION_TICKET */ + } + else { + sess->sessionID[0] = !sess->sessionID[0]; + } + } + ssl_c = wolfSSL_new(ctx_c); + ssl_s = wolfSSL_new(ctx_s); + wolfSSL_SetIOWriteCtx(ssl_c, &test_ctx); + wolfSSL_SetIOReadCtx(ssl_c, &test_ctx); + wolfSSL_SetIOWriteCtx(ssl_s, &test_ctx); + wolfSSL_SetIOReadCtx(ssl_s, &test_ctx); + ret = wolfSSL_set_session(ssl_c, sess); + if (ret != WOLFSSL_SUCCESS) + return -6; + ret = wolfSSL_connect(ssl_c); + if (ret == WOLFSSL_SUCCESS || ssl_c->error != WANT_READ) + return -7; + ret = wolfSSL_accept(ssl_s); + if (ret == WOLFSSL_SUCCESS || ssl_s->error != WANT_READ) + return -8; + if (bad && !buf_is_hvr(test_ctx.c_buff, test_ctx.c_len)) + return -9; + if (!bad && buf_is_hvr(test_ctx.c_buff, test_ctx.c_len)) + return -10; + if (!useticket) { + ret = test_memio_do_handshake(ssl_c, ssl_s, 10, &round_trips); + if (ret != 0) + return -11; + if (bad && round_trips != ROUNDS_WITH_HVR - 1) + return -12; + if (!bad && round_trips != ROUNDS_WITHOUT_HVR - 1) + return -13; + } + wolfSSL_SESSION_free(sess); + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); + return TEST_SUCCESS; +} + +static int test_wolfSSL_dtls_stateless_resume(void) +{ + int ret; +#ifdef HAVE_SESSION_TICKET + ret = _test_wolfSSL_dtls_stateless_resume(1, 0); + if (ret != 0) + return ret; + ret = _test_wolfSSL_dtls_stateless_resume(1, 1); + if (ret != 0) + return ret - 100; +#endif /* HAVE_SESION_TICKET */ + ret = _test_wolfSSL_dtls_stateless_resume(0, 0); + if (ret != 0) + return ret - 200; + ret = _test_wolfSSL_dtls_stateless_resume(0, 1); + if (ret != 0) + return ret - 300; + return TEST_SUCCESS; +} +#endif /* WOLFSSL_DTLS_NO_HVR_ON_RESUME */ + +#if !defined(NO_OLD_TLS) +static int test_wolfSSL_dtls_stateless_downgrade(void) +{ + WOLFSSL_CTX *ctx_c, *ctx_c2, *ctx_s; + WOLFSSL *ssl_c, *ssl_c2, *ssl_s; + struct test_memio_ctx test_ctx; + int ret; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ret = test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method); + if (ret != 0) + return -1; + ret = wolfSSL_CTX_SetMinVersion(ctx_s, WOLFSSL_DTLSV1); + if (ret != WOLFSSL_SUCCESS) + return -2; + ctx_c2 = wolfSSL_CTX_new(wolfDTLSv1_client_method()); + if (ctx_c2 == NULL) + return -3; + wolfSSL_SetIORecv(ctx_c2, test_memio_read_cb); + wolfSSL_SetIOSend(ctx_c2, test_memio_write_cb); + ssl_c2 = wolfSSL_new(ctx_c2); + if (ssl_c2 == NULL) + return -4; + wolfSSL_SetIOWriteCtx(ssl_c2, &test_ctx); + wolfSSL_SetIOReadCtx(ssl_c2, &test_ctx); + /* send CH */ + ret = wolfSSL_connect(ssl_c2); + if (ret == 0 || ssl_c2->error != WANT_READ) + return -5; + ret = wolfSSL_accept(ssl_s); + if (ret == 0 || ssl_s->error != WANT_READ) + return -6; + if (test_ctx.c_len == 0) + return -7; + /* consume HRR */ + test_ctx.c_len = 0; + ret = test_memio_do_handshake(ssl_c, ssl_s, 10, NULL); + if (ret != 0) + return -8; + wolfSSL_free(ssl_c2); + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_c2); + wolfSSL_CTX_free(ctx_s); + + return TEST_SUCCESS; +} +#endif /* !defined(NO_OLD_TLS) */ + +#endif /* defined(WOLFSSL_DTLS) && !defined(WOLFSSL_NO_TLS12) && \ + !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)*/ #if defined(WOLFSSL_DTLS) && !defined(WOLFSSL_NO_TLS12) && \ !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) && \ @@ -59882,6 +60139,20 @@ TEST_CASE testCases[] = { TEST_DECL(test_wolfSSL_DtlsUpdateWindow), TEST_DECL(test_wolfSSL_DTLS_fragment_buckets), #endif +#if defined(WOLFSSL_DTLS) && !defined(WOLFSSL_NO_TLS12) && \ + !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) +#ifdef WOLFSSL_DTLS_NO_HVR_ON_RESUME + TEST_DECL(test_wolfSSL_dtls_stateless_resume), +#endif /* WOLFSSL_DTLS_NO_HVR_ON_RESUME */ +#ifdef HAVE_MAX_FRAGMENT + TEST_DECL(test_wolfSSL_dtls_stateless_maxfrag), +#endif /* HAVE_MAX_FRAGMENT */ + TEST_DECL(test_wolfSSL_dtls_stateless2), +#if !defined(NO_OLD_TLS) + TEST_DECL(test_wolfSSL_dtls_stateless_downgrade), +#endif /* !defined(NO_OLD_TLS) */ +#endif /* defined(WOLFSSL_DTLS) && !defined(WOLFSSL_NO_TLS12) && \ + * !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) */ TEST_DECL(test_WOLFSSL_dtls_version_alert), TEST_DECL(test_ForceZero), diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 3ee22f472..0f3abf1b0 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -3922,6 +3922,9 @@ WOLFSSL_LOCAL ClientSession* AddSessionToClientCache(int side, int row, int idx, #endif WOLFSSL_LOCAL WOLFSSL_SESSION* ClientSessionToSession(const WOLFSSL_SESSION* session); +WOLFSSL_LOCAL void TlsSessionCacheUnlockRow(word32 row); +WOLFSSL_LOCAL int TlsSessionCacheGetAndLock(const byte *id, + WOLFSSL_SESSION **sess, word32 *lockedRow); /* WOLFSSL_API to test it in tests/api.c */ WOLFSSL_API int wolfSSL_GetSessionFromCache(WOLFSSL* ssl, WOLFSSL_SESSION* output); WOLFSSL_LOCAL int wolfSSL_SetSession(WOLFSSL* ssl, WOLFSSL_SESSION* session); @@ -5480,6 +5483,10 @@ extern const WOLF_EC_NIST_NAME kNistCurves[]; /* internal functions */ WOLFSSL_LOCAL int SendChangeCipher(WOLFSSL* ssl); WOLFSSL_LOCAL int SendTicket(WOLFSSL* ssl); +#ifdef HAVE_SESSION_TICKET +WOLFSSL_LOCAL int DoDecryptTicket(WOLFSSL* ssl, const byte* input, word32 len, + InternalTicket **it); +#endif /* HAVE_SESSION_TICKET */ WOLFSSL_LOCAL int DoClientTicket(WOLFSSL* ssl, const byte* input, word32 len); WOLFSSL_LOCAL int SendData(WOLFSSL* ssl, const void* data, int sz); #ifdef WOLFSSL_TLS13 @@ -5683,6 +5690,13 @@ WOLFSSL_LOCAL int cipherExtraData(WOLFSSL* ssl); word32 *inOutIdx, byte *type, word32 *size, word32 *fragOffset, word32 *fragSz, word32 totalSz); WOLFSSL_LOCAL int DtlsMsgDrain(WOLFSSL *ssl); + WOLFSSL_LOCAL int SendHelloVerifyRequest(WOLFSSL* ssl, + const byte* cookie, byte cookieSz); + +#if !defined(NO_WOLFSSL_SERVER) + WOLFSSL_LOCAL int DoClientHelloStateless(WOLFSSL* ssl, const byte* input, + word32* inOutIdx, word32 helloSz, byte *process); +#endif /* !defined(NO_WOLFSSL_SERVER) */ #endif /* WOLFSSL_DTLS */ #if defined(HAVE_SECURE_RENEGOTIATION) && defined(WOLFSSL_DTLS) diff --git a/wolfssl/test.h b/wolfssl/test.h index 8697c5866..72105526e 100644 --- a/wolfssl/test.h +++ b/wolfssl/test.h @@ -5136,8 +5136,7 @@ void DEBUG_WRITE_DER(const byte* der, int derSz, const char* fileName); (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3)))\ || \ (defined(WOLFSSL_DTLS) && !defined(WOLFSSL_NO_TLS12) && \ - !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) && \ - !defined(NO_OLD_TLS)) + !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)) #define TEST_MEMIO_BUF_SZ (64 * 1024) struct test_memio_ctx { @@ -5206,6 +5205,51 @@ static WC_INLINE int test_memio_read_cb(WOLFSSL *ssl, char *data, int sz, return read_sz; } +static WC_INLINE int test_memio_do_handshake(WOLFSSL *ssl_c, WOLFSSL *ssl_s, + int max_rounds, int *rounds) +{ + byte handshake_complete = 0, hs_c = 0, hs_s = 0; + int ret, err; + + if (rounds != NULL) + *rounds = 0; + while (!handshake_complete && max_rounds > 0) { + if (!hs_c) { + ret = wolfSSL_connect(ssl_c); + if (ret == WOLFSSL_SUCCESS) { + hs_c = 1; + } + else { + err = wolfSSL_get_error(ssl_c, ret); + if (err != WOLFSSL_ERROR_WANT_READ && + err != WOLFSSL_ERROR_WANT_WRITE) + return -1; + } + } + if (!hs_s) { + ret = wolfSSL_accept(ssl_s); + if (ret == WOLFSSL_SUCCESS) { + hs_s = 1; + } + else { + err = wolfSSL_get_error(ssl_c, ret); + if (err != WOLFSSL_ERROR_WANT_READ && + err != WOLFSSL_ERROR_WANT_WRITE) + return -1; + } + } + handshake_complete = hs_c && hs_s; + max_rounds--; + if (rounds != NULL) + *rounds = *rounds + 1; + } + + if (!handshake_complete) + return -1; + + return 0; +} + static WC_INLINE int test_memio_setup(struct test_memio_ctx *ctx, WOLFSSL_CTX **ctx_c, WOLFSSL_CTX **ctx_s, WOLFSSL **ssl_c, WOLFSSL **ssl_s, method_provider method_c, method_provider method_s) @@ -5224,6 +5268,9 @@ static WC_INLINE int test_memio_setup(struct test_memio_ctx *ctx, ret = wolfSSL_CTX_use_certificate_file(*ctx_s, svrCertFile, WOLFSSL_FILETYPE_PEM); + if (ret != WOLFSSL_SUCCESS) + return -1; + ret = wolfSSL_CTX_load_verify_locations(*ctx_c, caCertFile, 0); if (ret != WOLFSSL_SUCCESS) return -1; wolfSSL_SetIORecv(*ctx_c, test_memio_read_cb);