From 1106e5ff0ea339ce26787881e70661fb7470828b Mon Sep 17 00:00:00 2001 From: tmael Date: Fri, 21 Apr 2023 06:46:08 -0700 Subject: [PATCH] TLS v1.3: Support a stateful ticket and test HAVE_EXT_CACHE (#5960) * Add TLSv1.3 stateful support Fix internal and external session cache * session cache fixes * Refactor - implement wolfSSL_CTX_flush_sessions - use wolfSSL_CTX_flush_sessions to make test_wolfSSL_CTX_add_session_ext deterministic - add dtls to test_wolfSSL_CTX_add_session_ext - DoClientTicket_ex does not modify ssl object - only call session remove callback on: - timeout - session is being overwritten/removed from the cache * Session fixes - restore bogus ID on session duplicate - don't evict on overwrite - use memmove instead on memcpy as `ssl->session == session` is possible - ignore ClientSession parameter in AddSessionToCache on NO_SESSION_CACHE_REF - use sessionID when altSessionID not present * Session fixes - DoClientTicketFinalize: always copy in the ID as teh altSessionID - don't overwrite ex_data when overwriting cacheSession and cacheSession owns it * Callback wants to retain a copy * wolfSSL_GetSessionClient: ssl->ctx->get_sess_cb does not apply here * test_wolfSSL_CTX_add_session_ext gate expected results on WOLFSSL_DTLS_NO_HVR_ON_RESUME * TlsSessionIdIsValid: copy return can't be ignored * Silence unused parameter * test_wolfSSL_CTX_add_session_ext: handle async case * Gate wolfSSL_SSL_CTX_remove_session on NO_SESSION_CACHE * ssl.c: style fixes * Add twcase_get_sessionCb_cleanup to free external cache * Remove hard tab * Correct build error in wolfSSL_CTX_flush_sessions * Jenkins fixes: - altSessionID only available with WOLFSSL_TICKET_HAVE_ID - slim out psk_sess_free_cb_ctx * Stateful dtls case has 2 accesses. Stateless just one. * Add version numbering to hostap logs * Import internal.h for test_wolfSSL_SESSION_get_ex_new_index * wolfSSL_SetSession: don't check SslSessionCacheOff for session setting * wolfSSL_SetSession: fully set expired session for OpenSSL compatibility * wolfSSL_SetSession: check if setting same object * AddSession: always populate the session object to allow re-use * Add logging to wolfSSL_NewSession and wolfSSL_FreeSession * Always setup session object * Check if session has been setup before setting it * Print errors in async test * Make SetupSession available outside NO_SESSION_CACHE * Review comments * Fix ticBuf leak and TlsSessionIdIsValid logic * Fix unmatched curly brackets * TlsSessionIdIsValid: always need to check copy var * TlsResumptionIsValid: set resume to FALSE default * wolfSSL_SetSession: remove now variable since only used in one place * Move internalCacheLookupOff into HAVE_EXT_CACHE block --------- Co-authored-by: Juliusz Sosinowicz --- .github/workflows/async.yml | 6 + .github/workflows/hostap.yml | 11 +- .github/workflows/os-check.yml | 4 + src/dtls.c | 59 ++-- src/internal.c | 219 ++++++++++-- src/sniffer.c | 2 + src/ssl.c | 562 ++++++++++++++++-------------- src/tls13.c | 72 ++-- tests/api.c | 601 ++++++++++++++++++++++++++++++++- wolfssl/internal.h | 41 ++- wolfssl/ssl.h | 7 +- 11 files changed, 1241 insertions(+), 343 deletions(-) diff --git a/.github/workflows/async.yml b/.github/workflows/async.yml index cb0407538..5696b2a30 100644 --- a/.github/workflows/async.yml +++ b/.github/workflows/async.yml @@ -23,3 +23,9 @@ jobs: ./configure ${{ matrix.config }} make check + - name: Print errors + if: ${{ failure() }} + run: | + if [ -f test-suite.log ] ; then + cat test-suite.log + fi diff --git a/.github/workflows/hostap.yml b/.github/workflows/hostap.yml index 0fa9b5851..ffa270cb9 100644 --- a/.github/workflows/hostap.yml +++ b/.github/workflows/hostap.yml @@ -99,6 +99,15 @@ jobs: ${{ toJSON(matrix) }} EOF + - name: Print computed job run ID + run: | + SHA_SUM=$(sha256sum << 'END_OF_HEREDOC' | cut -d " " -f 1 + ${{ toJSON(github) }} + END_OF_HEREDOC + ) + echo "our_job_run_id=$SHA_SUM" >> $GITHUB_ENV + echo Our job run ID is $SHA_SUM + - name: Checkout wolfSSL uses: actions/checkout@v3 with: @@ -264,7 +273,7 @@ jobs: if: ${{ failure() && steps.testing.outcome == 'failure' }} uses: actions/upload-artifact@v3 with: - name: hostap-logs + name: hostap-logs-${{ env.our_job_run_id }} path: hostap/tests/hwsim/logs.zip retention-days: 5 diff --git a/.github/workflows/os-check.yml b/.github/workflows/os-check.yml index 218e439f3..6a8c34fd0 100644 --- a/.github/workflows/os-check.yml +++ b/.github/workflows/os-check.yml @@ -15,6 +15,10 @@ jobs: '--enable-all --enable-asn=template', '--enable-all --enable-asn=original', '--enable-harden-tls', + '--enable-tls13 --enable-session-ticket --enable-dtls --enable-dtls13 + --enable-opensslextra --enable-sessioncerts + CPPFLAGS=''-DWOLFSSL_DTLS_NO_HVR_ON_RESUME -DHAVE_EXT_CACHE + -DWOLFSSL_TICKET_HAVE_ID -DHAVE_EX_DATA -DSESSION_CACHE_DYNAMIC_MEM'' ', ] name: make check runs-on: ${{ matrix.os }} diff --git a/src/dtls.c b/src/dtls.c index 513b6991e..11de01541 100644 --- a/src/dtls.c +++ b/src/dtls.c @@ -335,6 +335,8 @@ static int TlsTicketIsValid(const WOLFSSL* ssl, WolfSSL_ConstVector exts, int ret = 0; int tlsxFound; + *resume = FALSE; + ret = FindExtByType(&tlsxSessionTicket, TLSX_SESSION_TICKET, exts, &tlsxFound); if (ret != 0) @@ -359,42 +361,45 @@ static int TlsTicketIsValid(const WOLFSSL* ssl, WolfSSL_ConstVector exts, static int TlsSessionIdIsValid(const WOLFSSL* ssl, WolfSSL_ConstVector sessionID, int* resume) { - WOLFSSL_SESSION* sess; + const WOLFSSL_SESSION* sess; word32 sessRow; int ret; +#ifdef HAVE_EXT_CACHE + int copy; +#endif + *resume = FALSE; + 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((WOLFSSL*)ssl, sessionID.elements, ID_LEN, - &unused); - if (sess != NULL) { +#ifdef HAVE_EXT_CACHE + if (ssl->ctx->get_sess_cb != NULL) { + WOLFSSL_SESSION* extSess = + ssl->ctx->get_sess_cb((WOLFSSL*)ssl, sessionID.elements, ID_LEN, + ©); + if (extSess != NULL) { #if defined(SESSION_CERTS) || (defined(WOLFSSL_TLS13) && \ - defined(HAVE_SESSION_TICKET)) - /* This logic is only for TLS <= 1.2 tickets. Don't accept - * TLS 1.3. */ - if (IsAtLeastTLSv1_3(sess->version)) - wolfSSL_FreeSession(ssl->ctx, sess); - else + defined(HAVE_SESSION_TICKET)) + /* This logic is only for TLS <= 1.2 tickets. Don't accept + * TLS 1.3. */ + if (!IsAtLeastTLSv1_3(extSess->version)) #endif - { - *resume = 1; - wolfSSL_FreeSession(ssl->ctx, sess); - return 0; - } - } + *resume = TRUE; + if (!copy) + wolfSSL_FreeSession(ssl->ctx, extSess); + if (*resume) + return 0; } - if (ssl->ctx->internalCacheLookupOff) - return 0; } + if (ssl->ctx->internalCacheLookupOff) + return 0; #endif - ret = TlsSessionCacheGetAndLock(sessionID.elements, &sess, &sessRow, 1); + + + ret = TlsSessionCacheGetAndRdLock(sessionID.elements, &sess, &sessRow, + ssl->options.side); if (ret == 0 && sess != NULL) { #if defined(SESSION_CERTS) || (defined(WOLFSSL_TLS13) && \ defined(HAVE_SESSION_TICKET)) @@ -402,9 +407,7 @@ static int TlsSessionIdIsValid(const WOLFSSL* ssl, WolfSSL_ConstVector sessionID * TLS 1.3. */ if (!IsAtLeastTLSv1_3(sess->version)) #endif - { - *resume = 1; - } + *resume = TRUE; TlsSessionCacheUnlockRow(sessRow); } @@ -480,7 +483,7 @@ static void FindPskSuiteFromExt(const WOLFSSL* ssl, TLSX* extensions, /* Decode the identity. */ switch (current->decryptRet) { case PSK_DECRYPT_NONE: - ret = DoClientTicket_ex(ssl, current); + ret = DoClientTicket_ex(ssl, current, 0); break; case PSK_DECRYPT_OK: ret = WOLFSSL_TICKET_RET_OK; diff --git a/src/internal.c b/src/internal.c index 4dbf39b4d..dfeb3203b 100644 --- a/src/internal.c +++ b/src/internal.c @@ -21301,8 +21301,9 @@ int SendFinished(WOLFSSL* ssl) return BUILD_MSG_ERROR; if (!ssl->options.resuming) { + SetupSession(ssl); #ifndef NO_SESSION_CACHE - AddSession(ssl); /* just try */ + AddSession(ssl); #endif if (ssl->options.side == WOLFSSL_SERVER_END) { #ifdef OPENSSL_EXTRA @@ -30622,6 +30623,7 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, *inOutIdx += length; if (length > 0) { ssl->timeout = lifetime; + SetupSession(ssl); #ifndef NO_SESSION_CACHE AddSession(ssl); #endif @@ -34833,18 +34835,35 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, } #endif /* WOLFSSL_SLT13 */ - void DoClientTicketFinalize(WOLFSSL* ssl, InternalTicket* it) + void DoClientTicketFinalize(WOLFSSL* ssl, InternalTicket* it, + const WOLFSSL_SESSION* sess) { #ifdef WOLFSSL_TICKET_HAVE_ID ssl->session->haveAltSessionID = 1; XMEMCPY(ssl->session->altSessionID, it->id, ID_LEN); - if (wolfSSL_GetSession(ssl, NULL, 1) != NULL) { - WOLFSSL_MSG("Found session matching the session id" - " found in the ticket"); +#endif + if (sess != NULL) { + byte bogusID[ID_LEN]; + byte bogusIDSz = ssl->session->sessionIDSz; + XMEMCPY(bogusID, ssl->session->sessionID, ID_LEN); + /* Failure here should not interupt the resumption. We already have + * all the cipher material we need in `it` */ + WOLFSSL_MSG("Copying in session from passed in arg"); + (void)wolfSSL_DupSession(sess, ssl->session, 1); + /* Restore the fake ID */ + XMEMCPY(ssl->session->sessionID, bogusID, ID_LEN); + ssl->session->sessionIDSz= bogusIDSz; } +#ifdef WOLFSSL_TICKET_HAVE_ID else { - WOLFSSL_MSG("Can't find session matching the session id" - " found in the ticket"); + if (wolfSSL_GetSession(ssl, NULL, 1) != NULL) { + WOLFSSL_MSG("Found session matching the session id" + " found in the ticket"); + } + else { + WOLFSSL_MSG("Can't find session matching the session id" + " found in the ticket"); + } } #endif @@ -34907,18 +34926,139 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, } #if defined(WOLFSSL_TLS13) + static void PopulateInternalTicketFromSession(const WOLFSSL_SESSION* sess, + InternalTicket* it) + { +#ifdef WOLFSSL_32BIT_MILLI_TIME + word32 milliBornOn = sess->bornOn; +#else + sword64 milliBornOn = (sword64)sess->bornOn; +#endif + /* Convert to milliseconds */ + milliBornOn *= 1000; + it->pv = sess->version; + it->suite[0] = sess->cipherSuite0; + it->suite[1] = sess->cipherSuite; + XMEMCPY(it->msecret, sess->masterSecret, SECRET_LEN); +#ifdef WOLFSSL_32BIT_MILLI_TIME + c32toa(milliBornOn, it->timestamp); +#else + c32toa((word32)(milliBornOn >> 32), it->timestamp); + c32toa((word32)milliBornOn , it->timestamp + OPAQUE32_LEN); +#endif + it->haveEMS = (byte)sess->haveEMS; + c32toa(sess->ticketAdd, it->ageAdd); + c16toa(sess->namedGroup, it->namedGroup); + if (sess->ticketNonce.len <= MAX_TICKET_NONCE_STATIC_SZ) { + it->ticketNonceLen = sess->ticketNonce.len; + XMEMCPY(it->ticketNonce, sess->ticketNonce.data, + sess->ticketNonce.len); + } +#ifdef WOLFSSL_EARLY_DATA + c32toa(sess->maxEarlyDataSz, it->maxEarlyDataSz); +#endif +#ifdef WOLFSSL_TICKET_HAVE_ID + if (sess->haveAltSessionID) + XMEMCPY(it->id, sess->altSessionID, ID_LEN); + else + XMEMCPY(it->id, sess->sessionID, ID_LEN); +#endif + } + + + static const WOLFSSL_SESSION* GetSesionFromCacheOrExt(const WOLFSSL* ssl, + const byte* id, psk_sess_free_cb_ctx* freeCtx) + { + const WOLFSSL_SESSION* sess = NULL; + int ret; + XMEMSET(freeCtx, 0, sizeof(*freeCtx)); +#ifdef HAVE_EXT_CACHE + if (ssl->ctx->get_sess_cb != NULL) { + int copy = 0; + sess = ssl->ctx->get_sess_cb((WOLFSSL*)ssl, + id, ID_LEN, ©); + if (sess != NULL) { + freeCtx->extCache = 1; + /* If copy not set then free immediately */ + if (!copy) + freeCtx->freeSess = 1; + } + } +#endif + if (sess == NULL) { + ret = TlsSessionCacheGetAndRdLock(id, &sess, &freeCtx->row, + ssl->options.side); + if (ret != 0) + sess = NULL; + } + return sess; + } + + static void FreeSessionFromCacheOrExt(const WOLFSSL* ssl, + const WOLFSSL_SESSION* sess, psk_sess_free_cb_ctx* freeCtx) + { + (void)ssl; + (void)sess; +#ifdef HAVE_EXT_CACHE + if (freeCtx->extCache) { + if (freeCtx->freeSess) + /* In this case sess is not longer const and the external cache + * wants us to free it. */ + wolfSSL_FreeSession(ssl->ctx, (WOLFSSL_SESSION*)sess); + } + else +#endif + TlsSessionCacheUnlockRow(freeCtx->row); + } + /* Parse ticket sent by client, returns callback return value. Doesn't * modify ssl and stores the InternalTicket inside psk */ - int DoClientTicket_ex(const WOLFSSL* ssl, PreSharedKey* psk) + int DoClientTicket_ex(const WOLFSSL* ssl, PreSharedKey* psk, int retainSess) { - int decryptRet; int ret; + int decryptRet = WOLFSSL_TICKET_RET_REJECT; WOLFSSL_START(WC_FUNC_TICKET_DO); WOLFSSL_ENTER("DoClientTicket_ex"); - decryptRet = DoDecryptTicket(ssl, psk->identity, psk->identityLen, - &psk->it); + if (psk->identityLen == ID_LEN && IsAtLeastTLSv1_3(ssl->version)) { + /* This is a stateful ticket. We can be sure about this because + * stateless tickets are much longer. */ + const WOLFSSL_SESSION* sess = NULL; + sess = GetSesionFromCacheOrExt(ssl, psk->identity, + &psk->sess_free_cb_ctx); + if (sess != NULL) { + /* Session found in cache. Copy in relevant info to psk */ + byte* tmp; + WOLFSSL_MSG("Found session matching the session id" + " found in the ticket"); + /* Allocate and populate an InternalTicket */ + tmp = (byte*)XREALLOC(psk->identity, sizeof(InternalTicket), + ssl->heap, DYNAMIC_TYPE_TLSX); + if (tmp != NULL) { + XMEMSET(tmp, 0, sizeof(InternalTicket)); + psk->identity = tmp; + psk->identityLen = sizeof(InternalTicket); + psk->it = (InternalTicket*)tmp; + PopulateInternalTicketFromSession(sess, psk->it); + decryptRet = WOLFSSL_TICKET_RET_OK; + if (retainSess) { + psk->sess = sess; + psk->sess_free_cb = FreeSessionFromCacheOrExt; + } + } + if (psk->sess == NULL) { + FreeSessionFromCacheOrExt(ssl, sess, + &psk->sess_free_cb_ctx); + XMEMSET(&psk->sess_free_cb_ctx, 0, + sizeof(psk_sess_free_cb_ctx)); + } + } + } + else { + decryptRet = DoDecryptTicket(ssl, psk->identity, psk->identityLen, + &psk->it); + } switch (decryptRet) { case WOLFSSL_TICKET_RET_OK: psk->decryptRet = PSK_DECRYPT_OK; @@ -34930,11 +35070,11 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, psk->decryptRet = PSK_DECRYPT_FAIL; return decryptRet; } - #ifdef WOLFSSL_CHECK_MEM_ZERO +#ifdef WOLFSSL_CHECK_MEM_ZERO /* Internal ticket successfully decrypted. */ wc_MemZero_Add("Do Client Ticket internal", psk->it, sizeof(InternalTicket)); - #endif +#endif ret = DoClientTicketCheckVersion(ssl, psk->it); if (ret != 0) { @@ -34952,17 +35092,41 @@ 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 decryptRet; + int decryptRet = WOLFSSL_TICKET_RET_REJECT; int ret; - InternalTicket* it + InternalTicket* it; +#ifdef WOLFSSL_TLS13 + InternalTicket staticIt; + const WOLFSSL_SESSION* sess = NULL; + psk_sess_free_cb_ctx freeCtx; + + XMEMSET(&freeCtx, 0, sizeof(psk_sess_free_cb_ctx)); +#endif WOLFSSL_START(WC_FUNC_TICKET_DO); WOLFSSL_ENTER("DoClientTicket"); - decryptRet = DoDecryptTicket(ssl, input, len, &it); +#ifdef WOLFSSL_TLS13 + if (len == ID_LEN && IsAtLeastTLSv1_3(ssl->version)) { + /* This is a stateful ticket. We can be sure about this because + * stateless tickets are much longer. */ + sess = GetSesionFromCacheOrExt(ssl, input, &freeCtx); + if (sess != NULL) { + it = &staticIt; + XMEMSET(it, 0, sizeof(InternalTicket)); + PopulateInternalTicketFromSession(sess, it); + decryptRet = WOLFSSL_TICKET_RET_OK; + } + } + else +#endif + decryptRet = DoDecryptTicket(ssl, input, len, &it); + if (decryptRet != WOLFSSL_TICKET_RET_OK && - decryptRet != WOLFSSL_TICKET_RET_CREATE) - return decryptRet; + decryptRet != WOLFSSL_TICKET_RET_CREATE) { + it = NULL; + goto cleanup; + } #ifdef WOLFSSL_CHECK_MEM_ZERO /* Internal ticket successfully decrypted. */ wc_MemZero_Add("Do Client Ticket internal", it, sizeof(InternalTicket)); @@ -34970,20 +35134,23 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, ret = DoClientTicketCheckVersion(ssl, it); if (ret != 0) { + decryptRet = ret; + goto cleanup; + } + + DoClientTicketFinalize(ssl, it, NULL); + +cleanup: + if (it != NULL) { ForceZero(it, sizeof(*it)); #ifdef WOLFSSL_CHECK_MEM_ZERO wc_MemZero_Check(it, sizeof(InternalTicket)); #endif - return ret; } - - DoClientTicketFinalize(ssl, it); - - ForceZero(it, sizeof(*it)); -#ifdef WOLFSSL_CHECK_MEM_ZERO - wc_MemZero_Check(it, sizeof(InternalTicket)); +#ifdef WOLFSSL_TLS13 + if (sess != NULL) + FreeSessionFromCacheOrExt(ssl, sess, &freeCtx); #endif - return decryptRet; } diff --git a/src/sniffer.c b/src/sniffer.c index 2b6e98889..cbd17ae94 100644 --- a/src/sniffer.c +++ b/src/sniffer.c @@ -3418,6 +3418,7 @@ static int ProcessSessionTicket(const byte* input, int* sslBytes, WOLFSSL_SESSION* sess = wolfSSL_GetSession(session->sslServer, NULL, 0); if (sess == NULL) { + SetupSession(session->sslServer); AddSession(session->sslServer); /* don't re add */ #ifdef WOLFSSL_SNIFFER_STATS INC_STAT(SnifferStats.sslResumptionInserts); @@ -4345,6 +4346,7 @@ static int ProcessFinished(const byte* input, int size, int* sslBytes, #ifndef NO_SESSION_CACHE WOLFSSL_SESSION* sess = wolfSSL_GetSession(session->sslServer, NULL, 0); if (sess == NULL) { + SetupSession(session->sslServer); AddSession(session->sslServer); /* don't re add */ #ifdef WOLFSSL_SNIFFER_STATS INC_STAT(SnifferStats.sslResumptionInserts); diff --git a/src/ssl.c b/src/ssl.c index 60fb21260..d34515744 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -6336,6 +6336,35 @@ int AddCA(WOLFSSL_CERT_MANAGER* cm, DerBuffer** pDer, int type, int verify) static WOLFSSL_GLOBAL int clisession_mutex_valid = 0; #endif /* !NO_CLIENT_CACHE */ + void EvictSessionFromCache(WOLFSSL_SESSION* session) + { +#ifdef HAVE_EX_DATA + int save_ownExData = session->ownExData; + session->ownExData = 1; /* Make sure ex_data access doesn't lead back + * into the cache. */ +#endif +#if defined(HAVE_EXT_CACHE) || defined(HAVE_EX_DATA) + if (session->rem_sess_cb != NULL) { + session->rem_sess_cb(NULL, session); + session->rem_sess_cb = NULL; + } +#endif + ForceZero(session->masterSecret, SECRET_LEN); + XMEMSET(session->sessionID, 0, ID_LEN); + session->sessionIDSz = 0; +#ifdef HAVE_SESSION_TICKET + if (session->ticketLenAlloc > 0) { + XFREE(session->ticket, NULL, DYNAMIC_TYPE_SESSION_TICK); + session->ticket = session->staticTicket; + session->ticketLen = 0; + session->ticketLenAlloc = 0; + } +#endif +#ifdef HAVE_EX_DATA + session->ownExData = save_ownExData; +#endif + } + #endif /* !NO_SESSION_CACHE */ #if defined(OPENSSL_EXTRA) && !defined(WOLFSSL_NO_OPENSSL_RAND_CB) @@ -14446,6 +14475,47 @@ int wolfSSL_Cleanup(void) return ret; } +void SetupSession(WOLFSSL* ssl) +{ + WOLFSSL_SESSION* session = ssl->session; + + WOLFSSL_ENTER("SetupSession"); + + if (!IsAtLeastTLSv1_3(ssl->version) && ssl->arrays != NULL && + !session->haveAltSessionID) { + /* Make sure the session ID is available when the user calls any + * get_session API */ + XMEMCPY(session->sessionID, ssl->arrays->sessionID, ID_LEN); + session->sessionIDSz = ssl->arrays->sessionIDSz; + } + session->side = (byte)ssl->options.side; + if (!IsAtLeastTLSv1_3(ssl->version) && ssl->arrays != NULL) + XMEMCPY(session->masterSecret, ssl->arrays->masterSecret, SECRET_LEN); + session->haveEMS = ssl->options.haveEMS; +#ifdef OPENSSL_EXTRA + /* If using compatibility layer then check for and copy over session context + * id. */ + if (ssl->sessionCtxSz > 0 && ssl->sessionCtxSz < ID_LEN) { + XMEMCPY(ssl->session->sessionCtx, ssl->sessionCtx, ssl->sessionCtxSz); + session->sessionCtxSz = ssl->sessionCtxSz; + } +#endif + session->timeout = ssl->timeout; + session->bornOn = LowResTimer(); +#if defined(SESSION_CERTS) || (defined(WOLFSSL_TLS13) && \ + defined(HAVE_SESSION_TICKET)) + session->version = ssl->version; +#endif +#if defined(SESSION_CERTS) || !defined(NO_RESUME_SUITE_CHECK) || \ + (defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET)) + session->cipherSuite0 = ssl->options.cipherSuite0; + session->cipherSuite = ssl->options.cipherSuite; +#endif +#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) + session->peerVerifyRet = (byte)ssl->peerVerifyRet; +#endif + session->isSetup = 1; +} #ifndef NO_SESSION_CACHE @@ -14457,6 +14527,44 @@ void wolfSSL_flush_sessions(WOLFSSL_CTX* ctx, long tm) (void)tm; } +void wolfSSL_CTX_flush_sessions(WOLFSSL_CTX* ctx, long tm) +{ + int i, j; + byte id[ID_LEN]; + + (void)ctx; + XMEMSET(id, 0, ID_LEN); + WOLFSSL_ENTER("wolfSSL_flush_sessions"); + for (i = 0; i < SESSION_ROWS; ++i) { + if (SESSION_ROW_WR_LOCK(&SessionCache[i]) != 0) { + WOLFSSL_MSG("Session cache mutex lock failed"); + return; + } + for (j = 0; j < SESSIONS_PER_ROW; j++) { +#ifdef SESSION_CACHE_DYNAMIC_MEM + WOLFSSL_SESSION* s = SessionCache[i].Sessions[j]; +#else + WOLFSSL_SESSION* s = &SessionCache[i].Sessions[j]; +#endif + if ( +#ifdef SESSION_CACHE_DYNAMIC_MEM + s != NULL && +#endif + XMEMCMP(s->sessionID, id, ID_LEN) != 0 && + s->bornOn + s->timeout < (word32)tm + ) + { + EvictSessionFromCache(s); +#ifdef SESSION_CACHE_DYNAMIC_MEM + XFREE(s, s->heap, DYNAMIC_TYPE_SESSION); + SessionCache[i].Sessions[j] = NULL; +#endif + } + } + SESSION_ROW_UNLOCK(&SessionCache[i]); + } +} + /* set ssl session timeout in seconds */ WOLFSSL_ABI @@ -14559,23 +14667,8 @@ WOLFSSL_SESSION* wolfSSL_GetSessionClient(WOLFSSL* ssl, const byte* id, int len) len = min(SERVER_ID_LEN, (word32)len); -#ifdef HAVE_EXT_CACHE - if (ssl->ctx->get_sess_cb != NULL) { - int copy = 0; - WOLFSSL_MSG("Calling external session cache"); - ret = ssl->ctx->get_sess_cb(ssl, (byte*)id, len, ©); - if (ret != NULL) { - WOLFSSL_MSG("Session found in external cache"); - return ret; - } - WOLFSSL_MSG("Session not found in external cache"); - } - - if (ssl->ctx->internalCacheLookupOff) { - WOLFSSL_MSG("Internal cache turned off"); - return NULL; - } -#endif + /* Do not access ssl->ctx->get_sess_cb from here. It is using a different + * set of ID's */ row = HashObject(id, len, &error) % CLIENT_SESSION_ROWS; if (error != 0) { @@ -14648,9 +14741,6 @@ static int SslSessionCacheOff(const WOLFSSL* ssl, const WOLFSSL_SESSION* session return ssl->options.sessionCacheOff #if defined(HAVE_SESSION_TICKET) && defined(WOLFSSL_FORCE_CACHE_ON_TICKET) && session->ticketLen == 0 - #endif - #ifdef OPENSSL_EXTRA - && ssl->options.side != WOLFSSL_CLIENT_END #endif ; } @@ -14699,11 +14789,13 @@ void TlsSessionCacheUnlockRow(word32 row) SESSION_ROW_UNLOCK(sessRow); } -int TlsSessionCacheGetAndLock(const byte *id, WOLFSSL_SESSION **sess, - word32 *lockedRow, byte readOnly) +/* Don't use this function directly. Use TlsSessionCacheGetAndRdLock and + * TlsSessionCacheGetAndWrLock to fully utilize compiler const support. */ +static int TlsSessionCacheGetAndLock(const byte *id, + const WOLFSSL_SESSION **sess, word32 *lockedRow, byte readOnly, byte side) { SessionRow *sessRow; - WOLFSSL_SESSION *s; + const WOLFSSL_SESSION *s; word32 row; int count; int error; @@ -14733,7 +14825,7 @@ int TlsSessionCacheGetAndLock(const byte *id, WOLFSSL_SESSION **sess, #else s = &sessRow->Sessions[idx]; #endif - if (s && XMEMCMP(s->sessionID, id, ID_LEN) == 0) { + if (s && XMEMCMP(s->sessionID, id, ID_LEN) == 0 && s->side == side) { *sess = s; break; } @@ -14749,9 +14841,22 @@ int TlsSessionCacheGetAndLock(const byte *id, WOLFSSL_SESSION **sess, return 0; } +int TlsSessionCacheGetAndRdLock(const byte *id, const WOLFSSL_SESSION **sess, + word32 *lockedRow, byte side) +{ + return TlsSessionCacheGetAndLock(id, sess, lockedRow, 1, side); +} + +int TlsSessionCacheGetAndWrLock(const byte *id, WOLFSSL_SESSION **sess, + word32 *lockedRow, byte side) +{ + return TlsSessionCacheGetAndLock(id, (const WOLFSSL_SESSION**)sess, + lockedRow, 0, side); +} + int wolfSSL_GetSessionFromCache(WOLFSSL* ssl, WOLFSSL_SESSION* output) { - WOLFSSL_SESSION* sess = NULL; + const WOLFSSL_SESSION* sess = NULL; const byte* id = NULL; word32 row; int error = 0; @@ -14810,23 +14915,25 @@ int wolfSSL_GetSessionFromCache(WOLFSSL* ssl, WOLFSSL_SESSION* output) #ifdef HAVE_EXT_CACHE if (ssl->ctx->get_sess_cb != NULL) { int copy = 0; + WOLFSSL_SESSION* extSess; /* Attempt to retrieve the session from the external cache. */ WOLFSSL_MSG("Calling external session cache"); - sess = ssl->ctx->get_sess_cb(ssl, (byte*)id, ID_LEN, ©); - if ((sess != NULL) + extSess = ssl->ctx->get_sess_cb(ssl, (byte*)id, ID_LEN, ©); + if ((extSess != NULL) #if defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET) && (IsAtLeastTLSv1_3(ssl->version) == - IsAtLeastTLSv1_3(sess->version)) + IsAtLeastTLSv1_3(extSess->version)) #endif ) { WOLFSSL_MSG("Session found in external cache"); - error = wolfSSL_DupSession(sess, output, 0); + error = wolfSSL_DupSession(extSess, output, 0); #ifdef HAVE_EX_DATA - output->ownExData = 1; + extSess->ownExData = 1; + output->ownExData = 0; #endif /* If copy not set then free immediately */ if (!copy) - wolfSSL_FreeSession(ssl->ctx, sess); + wolfSSL_FreeSession(ssl->ctx, extSess); /* We want to restore the bogus ID for TLS compatibility */ if (ssl->session->haveAltSessionID && output == ssl->session) { @@ -14897,7 +15004,7 @@ int wolfSSL_GetSessionFromCache(WOLFSSL* ssl, WOLFSSL_SESSION* output) /* init to avoid clang static analyzer false positive */ row = 0; - error = TlsSessionCacheGetAndLock(id, &sess, &row, 1); + error = TlsSessionCacheGetAndRdLock(id, &sess, &row, (byte)ssl->options.side); error = (error == 0) ? WOLFSSL_SUCCESS : WOLFSSL_FAILURE; if (error != WOLFSSL_SUCCESS || sess == NULL) { WOLFSSL_MSG("Get Session from cache failed"); @@ -14929,21 +15036,23 @@ int wolfSSL_GetSessionFromCache(WOLFSSL* ssl, WOLFSSL_SESSION* output) error = WOLFSSL_FAILURE; } else if (LowResTimer() >= (sess->bornOn + sess->timeout)) { + WOLFSSL_SESSION* wrSess = NULL; WOLFSSL_MSG("Invalid session: timed out"); + sess = NULL; TlsSessionCacheUnlockRow(row); + /* Attempt to get a write lock */ + error = TlsSessionCacheGetAndWrLock(id, &wrSess, &row, + ssl->options.side); + if (error == 0 && wrSess != NULL) { + EvictSessionFromCache(wrSess); + TlsSessionCacheUnlockRow(row); + } error = WOLFSSL_FAILURE; } #endif /* HAVE_SESSION_TICKET && WOLFSSL_TLS13 */ } 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) { - peer = sess->peer; - sess->peer = NULL; - } -#endif #if defined(HAVE_SESSION_TICKET) && defined(WOLFSSL_TLS13) error = wolfSSL_DupSessionEx(sess, output, 1, preallocNonce, &preallocNonceLen, &preallocNonceUsed); @@ -14951,7 +15060,7 @@ int wolfSSL_GetSessionFromCache(WOLFSSL* ssl, WOLFSSL_SESSION* output) error = wolfSSL_DupSession(sess, output, 1); #endif /* HAVE_SESSION_TICKET && WOLFSSL_TLS13 */ #ifdef HAVE_EX_DATA - output->ownExData = 0; /* Session cache owns external data */ + output->ownExData = !sess->ownExData; /* Session may own ex_data */ #endif TlsSessionCacheUnlockRow(row); } @@ -15071,11 +15180,12 @@ int wolfSSL_SetSession(WOLFSSL* ssl, WOLFSSL_SESSION* session) session = ClientSessionToSession(session); - if (ssl == NULL || session == NULL) { - WOLFSSL_MSG("ssl or session NULL"); + if (ssl == NULL || session == NULL || !session->isSetup) { + WOLFSSL_MSG("ssl or session NULL or not set up"); return WOLFSSL_FAILURE; } + /* We need to lock the session as the first step if its in the cache */ if (session->type == WOLFSSL_SESSION_TYPE_CACHE) { if (session->cacheRow < SESSION_ROWS) { sessRow = &SessionCache[session->cacheRow]; @@ -15086,11 +15196,6 @@ int wolfSSL_SetSession(WOLFSSL* ssl, WOLFSSL_SESSION* session) } } - if (ret == WOLFSSL_SUCCESS && SslSessionCacheOff(ssl, session)) { - WOLFSSL_MSG("Session cache off"); - ret = WOLFSSL_FAILURE; - } - if (ret == WOLFSSL_SUCCESS && ssl->options.side != WOLFSSL_NEITHER_END && (byte)ssl->options.side != session->side) { WOLFSSL_MSG("Setting session for wrong role"); @@ -15098,12 +15203,16 @@ int wolfSSL_SetSession(WOLFSSL* ssl, WOLFSSL_SESSION* session) } if (ret == WOLFSSL_SUCCESS) { + if (ssl->session == session) { + WOLFSSL_MSG("ssl->session and session same"); + } + else #ifdef HAVE_STUNNEL /* stunnel depends on the ex_data not being duplicated. Copy OpenSSL * behaviour for now. */ if (session->type != WOLFSSL_SESSION_TYPE_CACHE) { if (wolfSSL_SESSION_up_ref(session) == WOLFSSL_SUCCESS) { - wolfSSL_SESSION_free(ssl->session); + wolfSSL_FreeSession(ssl->ctx, ssl->session); ssl->session = session; } else @@ -15119,7 +15228,8 @@ int wolfSSL_SetSession(WOLFSSL* ssl, WOLFSSL_SESSION* session) } /* Let's copy over the altSessionID for local cache purposes */ - if (ret == WOLFSSL_SUCCESS && session->haveAltSessionID) { + if (ret == WOLFSSL_SUCCESS && session->haveAltSessionID && + ssl->session != session) { ssl->session->haveAltSessionID = 1; XMEMCPY(ssl->session->altSessionID, session->altSessionID, ID_LEN); } @@ -15146,36 +15256,33 @@ int wolfSSL_SetSession(WOLFSSL* ssl, WOLFSSL_SESSION* session) } #endif /* OPENSSL_EXTRA */ - if (LowResTimer() < (ssl->session->bornOn + ssl->session->timeout)) { - ssl->options.resuming = 1; - ssl->options.haveEMS = ssl->session->haveEMS; - -#if defined(SESSION_CERTS) || (defined(WOLFSSL_TLS13) && \ - defined(HAVE_SESSION_TICKET)) - ssl->version = ssl->session->version; - if (IsAtLeastTLSv1_3(ssl->version)) - ssl->options.tls1_3 = 1; -#endif -#if defined(SESSION_CERTS) || !defined(NO_RESUME_SUITE_CHECK) || \ - (defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET)) - ssl->options.cipherSuite0 = ssl->session->cipherSuite0; - ssl->options.cipherSuite = ssl->session->cipherSuite; -#endif -#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) - ssl->peerVerifyRet = (unsigned long)ssl->session->peerVerifyRet; -#endif - ret = WOLFSSL_SUCCESS; - } - else { -#if defined(OPENSSL_EXTRA) && defined(WOLFSSL_ERROR_CODE_OPENSSL) + if (LowResTimer() >= (ssl->session->bornOn + ssl->session->timeout)) { +#if !defined(OPENSSL_EXTRA) || !defined(WOLFSSL_ERROR_CODE_OPENSSL) + return WOLFSSL_FAILURE; /* session timed out */ +#else /* defined(OPENSSL_EXTRA) && defined(WOLFSSL_ERROR_CODE_OPENSSL) */ WOLFSSL_MSG("Session is expired but return success for " "OpenSSL compatibility"); - ret = WOLFSSL_SUCCESS; -#else - ret = WOLFSSL_FAILURE; /* session timed out */ -#endif /* OPENSSL_EXTRA && WOLFSSL_ERROR_CODE_OPENSSL */ +#endif } - return ret; + ssl->options.resuming = 1; + ssl->options.haveEMS = ssl->session->haveEMS; + +#if defined(SESSION_CERTS) || (defined(WOLFSSL_TLS13) && \ + defined(HAVE_SESSION_TICKET)) + ssl->version = ssl->session->version; + if (IsAtLeastTLSv1_3(ssl->version)) + ssl->options.tls1_3 = 1; +#endif +#if defined(SESSION_CERTS) || !defined(NO_RESUME_SUITE_CHECK) || \ + (defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET)) + ssl->options.cipherSuite0 = ssl->session->cipherSuite0; + ssl->options.cipherSuite = ssl->session->cipherSuite; +#endif +#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) + ssl->peerVerifyRet = (unsigned long)ssl->session->peerVerifyRet; +#endif + + return WOLFSSL_SUCCESS; } @@ -15379,7 +15486,6 @@ int AddSessionToCache(WOLFSSL_CTX* ctx, WOLFSSL_SESSION* addSession, int row; int i; int overwrite = 0; - (void)ctx; (void)sessionIndex; (void)useTicket; @@ -15479,34 +15585,47 @@ int AddSessionToCache(WOLFSSL_CTX* ctx, WOLFSSL_SESSION* addSession, #ifdef SESSION_CACHE_DYNAMIC_MEM cacheSession = sessRow->Sessions[idx]; - if (cacheSession) { - XFREE(cacheSession, sessRow->heap, DYNAMIC_TYPE_SESSION); - cacheSession = NULL; - } - cacheSession = (WOLFSSL_SESSION*) XMALLOC(sizeof(WOLFSSL_SESSION), sessRow->heap, - DYNAMIC_TYPE_SESSION); if (cacheSession == NULL) { - return MEMORY_E; + cacheSession = (WOLFSSL_SESSION*) XMALLOC(sizeof(WOLFSSL_SESSION), + sessRow->heap, DYNAMIC_TYPE_SESSION); + if (cacheSession == NULL) { + #ifdef HAVE_SESSION_TICKET + XFREE(ticBuff, NULL, DYNAMIC_TYPE_SESSION_TICK); + #if defined(WOLFSSL_TLS13) && defined(WOLFSSL_TICKE_NONCE_MALLOC) + if (preallocNonce != NULL) + XFREE(preallocNonce, addSession->heap, DYNAMIC_TYPE_SESSION_TICK); + #endif + #endif + SESSION_ROW_UNLOCK(sessRow); + return MEMORY_E; + } + XMEMSET(cacheSession, 0, sizeof(WOLFSSL_SESSION)); + sessRow->Sessions[idx] = cacheSession; } - XMEMSET(cacheSession, 0, sizeof(WOLFSSL_SESSION)); - sessRow->Sessions[idx] = cacheSession; #else cacheSession = &sessRow->Sessions[idx]; #endif #ifdef HAVE_EX_DATA - if (cacheSession->ownExData) { + if (overwrite) { + /* Figure out who owns the ex_data */ + if (cacheSession->ownExData) { + /* Prioritize cacheSession copy */ + XMEMCPY(&addSession->ex_data, &cacheSession->ex_data, + sizeof(WOLFSSL_CRYPTO_EX_DATA)); + } + /* else will be copied in wolfSSL_DupSession call */ + } + else if (cacheSession->ownExData) { crypto_ex_cb_free_data(cacheSession, crypto_ex_cb_ctx_session, &cacheSession->ex_data); - if (cacheSession->rem_sess_cb) { - cacheSession->rem_sess_cb(NULL, cacheSession); - /* Make sure not to call remove functions again */ - cacheSession->ownExData = 0; - cacheSession->rem_sess_cb = NULL; - } + cacheSession->ownExData = 0; } #endif + if (!overwrite) + EvictSessionFromCache(cacheSession); + cacheSession->type = WOLFSSL_SESSION_TYPE_CACHE; cacheSession->cacheRow = row; @@ -15573,22 +15692,26 @@ int AddSessionToCache(WOLFSSL_CTX* ctx, WOLFSSL_SESSION* addSession, #endif if (ret == 0) { - /* Increment the totalCount and the nextIdx */ - if (sessRow->totalCount < SESSIONS_PER_ROW) - sessRow->totalCount++; - sessRow->nextIdx = (sessRow->nextIdx + 1) % SESSIONS_PER_ROW; + if (!overwrite) { + /* Increment the totalCount and the nextIdx */ + if (sessRow->totalCount < SESSIONS_PER_ROW) + sessRow->totalCount++; + sessRow->nextIdx = (sessRow->nextIdx + 1) % SESSIONS_PER_ROW; + } if (id != addSession->sessionID) { /* ssl->session->sessionID may contain the bogus ID or we want the * ID from the arrays object */ XMEMCPY(cacheSession->sessionID, id, ID_LEN); cacheSession->sessionIDSz = ID_LEN; } -#ifdef HAVE_EX_DATA - if (ctx->rem_sess_cb != NULL) { - addSession->ownExData = 0; - cacheSession->ownExData = 1; +#if defined(HAVE_EXT_CACHE) || defined(HAVE_EX_DATA) + if (ctx->rem_sess_cb != NULL) cacheSession->rem_sess_cb = ctx->rem_sess_cb; - } +#endif +#ifdef HAVE_EX_DATA + /* The session in cache now owns the ex_data */ + addSession->ownExData = 0; + cacheSession->ownExData = 1; #endif #if defined(HAVE_SESSION_TICKET) && defined(WOLFSSL_TLS13) && \ defined(WOLFSSL_TICKET_NONCE_MALLOC) && \ @@ -15610,7 +15733,6 @@ int AddSessionToCache(WOLFSSL_CTX* ctx, WOLFSSL_SESSION* addSession, cacheSession->ticketLen = 0; } #endif - SESSION_ROW_UNLOCK(sessRow); cacheSession = NULL; /* Can't access after unlocked */ @@ -15647,9 +15769,6 @@ int AddSessionToCache(WOLFSSL_CTX* ctx, WOLFSSL_SESSION* addSession, return ret; } -#ifndef NO_CLIENT_CACHE -#endif - void AddSession(WOLFSSL* ssl) { int error = 0; @@ -15666,63 +15785,16 @@ void AddSession(WOLFSSL* ssl) return; } - if (ssl->options.haveSessionId == 0) { - WOLFSSL_MSG("Don't have session id"); - return; - } - -#if defined(HAVE_SESSION_TICKET) && !defined(OPENSSL_EXTRA) - /* For the compat layer generate a session object to use */ - if (ssl->options.side == WOLFSSL_SERVER_END && ssl->options.useTicket == 1) { - WOLFSSL_MSG("Using tickets instead of cache"); - return; - } -#endif - if (session->haveAltSessionID) { id = session->altSessionID; idSz = ID_LEN; } else { - if (!IsAtLeastTLSv1_3(ssl->version) && ssl->arrays != NULL) { - /* Make sure the session ID is available when the user calls any - * get_session API */ - XMEMCPY(session->sessionID, ssl->arrays->sessionID, ID_LEN); - session->sessionIDSz = ssl->arrays->sessionIDSz; - } id = session->sessionID; idSz = session->sessionIDSz; } - session->timeout = ssl->timeout; - session->side = (byte)ssl->options.side; - if (!IsAtLeastTLSv1_3(ssl->version) && ssl->arrays != NULL) - XMEMCPY(session->masterSecret, ssl->arrays->masterSecret, SECRET_LEN); - session->haveEMS = ssl->options.haveEMS; -#ifdef OPENSSL_EXTRA - /* If using compatibility layer then check for and copy over session context - * id. */ - if (ssl->sessionCtxSz > 0 && ssl->sessionCtxSz < ID_LEN) { - XMEMCPY(ssl->session->sessionCtx, ssl->sessionCtx, ssl->sessionCtxSz); - session->sessionCtxSz = ssl->sessionCtxSz; - } -#endif - session->timeout = ssl->timeout; - session->bornOn = LowResTimer(); -#if defined(SESSION_CERTS) || (defined(WOLFSSL_TLS13) && \ - defined(HAVE_SESSION_TICKET)) - session->version = ssl->version; -#endif -#if defined(SESSION_CERTS) || !defined(NO_RESUME_SUITE_CHECK) || \ - (defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET)) - session->cipherSuite0 = ssl->options.cipherSuite0; - session->cipherSuite = ssl->options.cipherSuite; -#endif -#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) - session->peerVerifyRet = (byte)ssl->peerVerifyRet; -#endif - /* Do this last so that if it fails, the rest of the session is setup. Do - * this only for the client because if the server doesn't have an ID at + /* Do this only for the client because if the server doesn't have an ID at * this point, it won't on resumption. */ if (idSz == 0 && ssl->options.side == WOLFSSL_CLIENT_END) { WC_RNG* rng = NULL; @@ -15740,31 +15812,28 @@ void AddSession(WOLFSSL* ssl) id = ssl->session->altSessionID; idSz = ID_LEN; } - /* Setup done */ - if (ssl->options.side == WOLFSSL_SERVER_END /* No point in adding a - * client session */ -#ifdef HAVE_EXT_CACHE - && !ssl->options.internalCacheOff -#endif - ) - { - /* Try to add the session to cache. Its ok if we don't succeed. */ - (void)AddSessionToCache(ssl->ctx, session, id, idSz, + /* Try to add the session to internal cache or external cache + if a new_sess_cb is set. Its ok if we don't succeed. */ + (void)AddSessionToCache(ssl->ctx, session, id, idSz, #ifdef SESSION_INDEX - &ssl->sessionIndex, + &ssl->sessionIndex, #else - NULL, + NULL, #endif - ssl->options.side, + ssl->options.side, #ifdef HAVE_SESSION_TICKET - ssl->options.useTicket, + ssl->options.useTicket, #else - 0, + 0, #endif - NULL - ); - } +#ifdef NO_SESSION_CACHE_REF + NULL +#else + (ssl->options.side == WOLFSSL_CLIENT_END) ? + &ssl->clientSession : NULL +#endif + ); #ifdef HAVE_EXT_CACHE if (error == 0 && ssl->ctx->new_sess_cb != NULL) { @@ -17718,8 +17787,16 @@ cleanup: if ((ctx->mask & WOLFSSL_OP_NO_TICKET) == WOLFSSL_OP_NO_TICKET) { ctx->noTicketTls12 = 1; } + /* This code is here for documentation purpose. You must not turn off + * session tickets with the WOLFSSL_OP_NO_TICKET option for TLSv1.3. + * Because we need to support both stateful and stateless tickets. + #ifdef WOLFSSL_TLS13 + if ((ctx->mask & WOLFSSL_OP_NO_TICKET) == WOLFSSL_OP_NO_TICKET) { + ctx->noTicketTls13 = 1; + } + #endif + */ #endif - return ctx->mask; } @@ -20101,7 +20178,7 @@ size_t wolfSSL_get_client_random(const WOLFSSL* ssl, unsigned char* out, if (!ssl->options.handShakeDone) { /* Only reset the session if we didn't complete a handshake */ - wolfSSL_SESSION_free(ssl->session); + wolfSSL_FreeSession(ssl->ctx, ssl->session); ssl->session = wolfSSL_NewSession(ssl->heap); if (ssl->session == NULL) { return WOLFSSL_FAILURE; @@ -21130,6 +21207,8 @@ WOLFSSL_SESSION* wolfSSL_NewSession(void* heap) { WOLFSSL_SESSION* ret = NULL; + WOLFSSL_ENTER("wolfSSL_NewSession"); + ret = (WOLFSSL_SESSION*)XMALLOC(sizeof(WOLFSSL_SESSION), heap, DYNAMIC_TYPE_SESSION); if (ret != NULL) { @@ -21161,12 +21240,12 @@ WOLFSSL_SESSION* wolfSSL_NewSession(void* heap) ret->ticketNonce.data = ret->ticketNonce.dataStatic; #endif #endif -#ifdef HAVE_EX_DATA - crypto_ex_cb_setup_new_data(ret, crypto_ex_cb_ctx_session, - &ret->ex_data); -#endif #ifdef HAVE_EX_DATA ret->ownExData = 1; + if (crypto_ex_cb_ctx_session != NULL) { + crypto_ex_cb_setup_new_data(ret, crypto_ex_cb_ctx_session, + &ret->ex_data); + } #endif } return ret; @@ -21516,6 +21595,8 @@ void wolfSSL_FreeSession(WOLFSSL_CTX* ctx, WOLFSSL_SESSION* session) (void)ctx; + WOLFSSL_ENTER("wolfSSL_FreeSession"); + if (session->ref.count > 0) { int ret; int isZero; @@ -21527,23 +21608,14 @@ void wolfSSL_FreeSession(WOLFSSL_CTX* ctx, WOLFSSL_SESSION* session) wolfSSL_RefFree(&session->ref); } -#if defined(HAVE_EXT_CACHE) || defined(HAVE_EX_DATA) + WOLFSSL_MSG("wolfSSL_FreeSession full free"); + #ifdef HAVE_EX_DATA if (session->ownExData) { crypto_ex_cb_free_data(session, crypto_ex_cb_ctx_session, &session->ex_data); } #endif - if (ctx != NULL && ctx->rem_sess_cb -#ifdef HAVE_EX_DATA - && session->ownExData /* This will be true if we are not using the - * internal cache so it will get called for - * externally cached sessions as well. */ -#endif - ) { - ctx->rem_sess_cb(ctx, session); - } -#endif #ifdef HAVE_EX_DATA_CLEANUP_HOOKS wolfSSL_CRYPTO_cleanup_ex_data(&session->ex_data); @@ -21583,6 +21655,8 @@ void wolfSSL_FreeSession(WOLFSSL_CTX* ctx, WOLFSSL_SESSION* session) } } +/* DO NOT use this API internally. Use wolfSSL_FreeSession directly instead + * and pass in the ctx parameter if possible (like from ssl->ctx). */ void wolfSSL_SESSION_free(WOLFSSL_SESSION* session) { session = ClientSessionToSession(session); @@ -21605,12 +21679,14 @@ int wolfSSL_CTX_add_session(WOLFSSL_CTX* ctx, WOLFSSL_SESSION* session) /* Session cache is global */ (void)ctx; - id = session->sessionID; - idSz = session->sessionIDSz; if (session->haveAltSessionID) { id = session->altSessionID; idSz = ID_LEN; } + else { + id = session->sessionID; + idSz = session->sessionIDSz; + } error = AddSessionToCache(ctx, session, id, idSz, NULL, session->side, @@ -25800,11 +25876,13 @@ WOLFSSL_SESSION* wolfSSL_d2i_SSL_SESSION(WOLFSSL_SESSION** sess, *sess = s; } + s->isSetup = 1; + *p += idx; end: if (ret != 0 && (sess == NULL || *sess != s)) { - wolfSSL_SESSION_free(s); + wolfSSL_FreeSession(NULL, s); s = NULL; } #endif /* HAVE_EXT_CACHE */ @@ -31340,6 +31418,8 @@ int wolfSSL_version(WOLFSSL* ssl) return DTLS1_VERSION; case DTLSv1_2_MINOR : return DTLS1_2_VERSION; + case DTLSv1_3_MINOR: + return DTLS1_3_VERSION; default: return WOLFSSL_FAILURE; } @@ -32639,10 +32719,13 @@ int wolfSSL_SSL_CTX_set_tmp_ecdh(WOLFSSL_CTX *ctx, WOLFSSL_EC_KEY *ecdh) return WOLFSSL_SUCCESS; } #endif - -/* Assumes that the session passed in is from the cache. */ +#ifndef NO_SESSION_CACHE int wolfSSL_SSL_CTX_remove_session(WOLFSSL_CTX *ctx, WOLFSSL_SESSION *s) { +#if defined(HAVE_EXT_CACHE) || defined(HAVE_EX_DATA) + int rem_called = FALSE; +#endif + WOLFSSL_ENTER("wolfSSL_SSL_CTX_remove_session"); s = ClientSessionToSession(s); @@ -32653,77 +32736,64 @@ int wolfSSL_SSL_CTX_remove_session(WOLFSSL_CTX *ctx, WOLFSSL_SESSION *s) if (!ctx->internalCacheOff) #endif { - /* Don't remove session just timeout session. */ - s->timeout = 0; -#ifndef NO_SESSION_CACHE - /* Clear the timeout in the cache */ - { - int row; - int i; - SessionRow* sessRow = NULL; - WOLFSSL_SESSION *cacheSession; - const byte* id; - int ret = 0; + const byte* id; + WOLFSSL_SESSION *sess = NULL; + word32 row = 0; + int ret; - id = s->sessionID; - if (s->haveAltSessionID) - id = s->altSessionID; + id = s->sessionID; + if (s->haveAltSessionID) + id = s->altSessionID; - row = (int)(HashObject(id, ID_LEN, &ret) % SESSION_ROWS); - if (ret != 0) { - WOLFSSL_MSG("Hash session failed"); - return ret; + ret = TlsSessionCacheGetAndWrLock(id, &sess, &row, ctx->method->side); + if (ret == 0 && sess != NULL) { +#if defined(HAVE_EXT_CACHE) || defined(HAVE_EX_DATA) + if (sess->rem_sess_cb != NULL) { + rem_called = TRUE; } - - sessRow = &SessionCache[row]; - if (SESSION_ROW_WR_LOCK(sessRow) != 0) { - WOLFSSL_MSG("Session row lock failed"); - return BAD_MUTEX_E; - } - - for (i = 0; i < SESSIONS_PER_ROW && i < sessRow->totalCount; i++) { -#ifdef SESSION_CACHE_DYNAMIC_MEM - cacheSession = sessRow->Sessions[i]; -#else - cacheSession = &sessRow->Sessions[i]; #endif - if (cacheSession && - XMEMCMP(id, cacheSession->sessionID, ID_LEN) == 0) { - if (ctx->method->side != cacheSession->side) - continue; - cacheSession->timeout = 0; + /* Call this before changing ownExData so that calls to ex_data + * don't try to access the SessionCache again. */ + EvictSessionFromCache(sess); #ifdef HAVE_EX_DATA - if (cacheSession->ownExData) { - /* Most recent version of ex data is in cache. Copy it - * over so the user can free it. */ - XMEMCPY(&s->ex_data, &cacheSession->ex_data, - sizeof(WOLFSSL_CRYPTO_EX_DATA)); - } - cacheSession->ownExData = 0; /* We clear below */ - s->ownExData = 1; + if (sess->ownExData) { + /* Most recent version of ex data is in cache. Copy it + * over so the user can free it. */ + XMEMCPY(&s->ex_data, &sess->ex_data, + sizeof(WOLFSSL_CRYPTO_EX_DATA)); + s->ownExData = 1; + sess->ownExData = 0; + } #endif - #ifdef SESSION_CACHE_DYNAMIC_MEM - XFREE(cacheSession, sessRow->heap, DYNAMIC_TYPE_SESSION); - sessRow->Sessions[i] = NULL; -#endif - break; + { + /* Find and clear entry. Row is locked so we are good to go. */ + int idx; + for (idx = 0; idx < SESSIONS_PER_ROW; idx++) { + if (sess == SessionCache[row].Sessions[idx]) { + XFREE(sess, sess->heap, DYNAMIC_TYPE_SESSION); + SessionCache[row].Sessions[idx] = NULL; + break; + } } } - SESSION_ROW_UNLOCK(sessRow); - } #endif + TlsSessionCacheUnlockRow(row); + } } #if defined(HAVE_EXT_CACHE) || defined(HAVE_EX_DATA) - if (ctx->rem_sess_cb != NULL) { + if (ctx->rem_sess_cb != NULL && !rem_called) { ctx->rem_sess_cb(ctx, s); } #endif + /* s cannot be resumed at this point */ + s->timeout = 0; + return 0; } - +#endif /* !NO_SESSION_CACHE */ #ifndef NO_BIO BIO *wolfSSL_SSL_get_rbio(const WOLFSSL *s) { diff --git a/src/tls13.c b/src/tls13.c index 882622025..81c032448 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -5667,7 +5667,8 @@ static int DoPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 inputSz, /* Decode the identity. */ switch (current->decryptRet) { case PSK_DECRYPT_NONE: - ret = DoClientTicket_ex(ssl, current); + ret = DoClientTicket_ex(ssl, current, 1); + /* psk->sess may be set. Need to clean up later. */ break; case PSK_DECRYPT_OK: ret = WOLFSSL_TICKET_RET_OK; @@ -5685,12 +5686,27 @@ static int DoPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 inputSz, return ret; #endif + if (ret != WOLFSSL_TICKET_RET_OK && current->sess_free_cb != NULL) { + current->sess_free_cb(ssl, current->sess, + ¤t->sess_free_cb_ctx); + current->sess = NULL; + XMEMSET(¤t->sess_free_cb_ctx, 0, + sizeof(psk_sess_free_cb_ctx)); + } if (ret == WOLFSSL_TICKET_RET_OK) { - if (DoClientTicketCheck(ssl, current, ssl->timeout, suite) != 0) + ret = DoClientTicketCheck(ssl, current, ssl->timeout, suite); + if (ret == 0) + DoClientTicketFinalize(ssl, current->it, current->sess); + if (current->sess_free_cb != NULL) { + current->sess_free_cb(ssl, current->sess, + ¤t->sess_free_cb_ctx); + current->sess = NULL; + XMEMSET(¤t->sess_free_cb_ctx, 0, + sizeof(psk_sess_free_cb_ctx)); + } + if (ret != 0) continue; - DoClientTicketFinalize(ssl, current->it); - /* SERVER: using secret in session ticket for peer auth. */ ssl->options.peerAuthGood = 1; @@ -10023,10 +10039,6 @@ static int DoTls13NewSessionTicket(WOLFSSL* ssl, const byte* input, #endif const byte* nonce; byte nonceLength; -#ifndef NO_SESSION_CACHE - const byte* id; - byte idSz; -#endif WOLFSSL_START(WC_FUNC_NEW_SESSION_TICKET_DO); WOLFSSL_ENTER("DoTls13NewSessionTicket"); @@ -10122,16 +10134,9 @@ static int DoTls13NewSessionTicket(WOLFSSL* ssl, const byte* input, #endif *inOutIdx += length; + SetupSession(ssl); #ifndef NO_SESSION_CACHE - AddSession(ssl); - id = ssl->session->sessionID; - idSz = ssl->session->sessionIDSz; - if (ssl->session->haveAltSessionID) { - id = ssl->session->altSessionID; - idSz = ID_LEN; - } - AddSessionToCache(ssl->ctx, ssl->session, id, idSz, NULL, - ssl->session->side, 1, &ssl->clientSession); + AddSession(ssl); #endif /* Always encrypted. */ @@ -10316,12 +10321,15 @@ static int SendTls13NewSessionTicket(WOLFSSL* ssl) #else extSz = EXTS_SZ; #endif - - /* Lifetime | Age Add | Ticket | Extensions */ - length = SESSION_HINT_SZ + SESSION_ADD_SZ + LENGTH_SZ + - ssl->session->ticketLen + extSz; + /* Lifetime | Age Add | Ticket session ID | Extensions */ + length = SESSION_HINT_SZ + SESSION_ADD_SZ + LENGTH_SZ; + if ((ssl->options.mask & WOLFSSL_OP_NO_TICKET) != 0) + length += ID_LEN + extSz; + else + length += ssl->session->ticketLen + extSz; /* Nonce */ length += TICKET_NONCE_LEN_SZ + DEF_TICKET_NONCE_SZ; + sendSz = idx + length + MAX_MSG_EXTRA; /* Check buffers are big enough and grow if needed. */ @@ -10346,11 +10354,26 @@ static int SendTls13NewSessionTicket(WOLFSSL* ssl) output[idx++] = ssl->session->ticketNonce.data[0]; /* length */ - c16toa(ssl->session->ticketLen, output + idx); + if ((ssl->options.mask & WOLFSSL_OP_NO_TICKET) != 0) { + c16toa(ID_LEN, output + idx); + } + else { + c16toa(ssl->session->ticketLen, output + idx); + } + idx += LENGTH_SZ; /* ticket */ - XMEMCPY(output + idx, ssl->session->ticket, ssl->session->ticketLen); - idx += ssl->session->ticketLen; + if ((ssl->options.mask & WOLFSSL_OP_NO_TICKET) != 0) { + if (ssl->session->haveAltSessionID) + XMEMCPY(output + idx, ssl->session->altSessionID, ID_LEN); + else + XMEMCPY(output + idx, ssl->session->sessionID, ID_LEN); + idx += ID_LEN; + } + else { + XMEMCPY(output + idx, ssl->session->ticket, ssl->session->ticketLen); + idx += ssl->session->ticketLen; + } #ifdef WOLFSSL_EARLY_DATA extSz = 0; @@ -10366,6 +10389,7 @@ static int SendTls13NewSessionTicket(WOLFSSL* ssl) ssl->options.haveSessionId = 1; + SetupSession(ssl); /* Only add to cache when support built in and when the ticket contains * an ID. Otherwise we have no way to actually retrieve the ticket from the * cache. */ diff --git a/tests/api.c b/tests/api.c index a9527d48a..e66dbc551 100644 --- a/tests/api.c +++ b/tests/api.c @@ -342,7 +342,7 @@ defined(HAVE_SESSION_TICKET) || (defined(OPENSSL_EXTRA) && \ defined(WOLFSSL_CERT_EXT) && defined(WOLFSSL_CERT_GEN)) || \ defined(WOLFSSL_TEST_STATIC_BUILD) || defined(WOLFSSL_DTLS) || \ - defined(HAVE_ECH) + defined(HAVE_ECH) || defined(HAVE_EX_DATA) /* for testing SSL_get_peer_cert_chain, or SESSION_TICKET_HINT_DEFAULT, * for setting authKeyIdSrc in WOLFSSL_X509, or testing DTLS sequence * number tracking */ @@ -7447,6 +7447,592 @@ static int test_wolfSSL_CTX_add_session(void) return res; } +#if defined(HAVE_IO_TESTS_DEPENDENCIES) && defined(HAVE_EXT_CACHE) && \ + !defined(SINGLE_THREADED) && defined(WOLFSSL_TLS13) && \ + !defined(NO_SESSION_CACHE) && defined(OPENSSL_EXTRA) && \ + defined(SESSION_CERTS) && defined(HAVE_SESSION_TICKET) && \ + !defined(TITAN_SESSION_CACHE) && \ + !defined(HUGE_SESSION_CACHE) && \ + !defined(BIG_SESSION_CACHE) && \ + !defined(MEDIUM_SESSION_CACHE) + +/* twcase - prefix for test_wolfSSL_CTX_add_session_ext */ +/* Sessions to restore/store */ +static WOLFSSL_SESSION* twcase_server_first_session_ptr; +static WOLFSSL_SESSION* twcase_client_first_session_ptr; +static WOLFSSL_CTX* twcase_server_current_ctx_ptr; +static int twcase_new_session_called = 0; +static int twcase_remove_session_called = 0; +static int twcase_get_session_called = 0; + +/* Test default, SESSIONS_PER_ROW*SESSION_ROWS = 3*11, see ssl.c */ +#define SESSION_CACHE_SIZE 33 + +typedef struct { + const byte* key; /* key, altSessionID, session ID, NULL if empty */ + WOLFSSL_SESSION* value; +} hashTable_entry; + +typedef struct { + hashTable_entry entries[SESSION_CACHE_SIZE]; /* hash slots */ + size_t capacity; /* size of entries */ + size_t length; /* number of items in the hash table */ + wolfSSL_Mutex htLock; /* lock */ +}hashTable; + +static hashTable server_sessionCache; + +static int twcase_new_sessionCb(WOLFSSL *ssl, WOLFSSL_SESSION *sess) +{ + int i; + (void)ssl; + /* + * This example uses a hash table. + * Steps you should take for a non-demo code: + * - acquire a lock for the file named according to the session id + * - open the file + * - encrypt and write the SSL_SESSION object to the file + * - release the lock + * + * Return: + * 0: The callback does not wish to hold a reference of the sess + * 1: The callback wants to hold a reference of the sess. The callback is + * now also responsible for calling wolfSSL_SESSION_free() on sess. + */ + if (sess == NULL) + return 0; + + if (wc_LockMutex(&server_sessionCache.htLock) != 0) { + return 0; + } + for (i = 0; i < SESSION_CACHE_SIZE; i++) { + if (server_sessionCache.entries[i].value == NULL) { + if (sess->haveAltSessionID == 1) + server_sessionCache.entries[i].key = sess->altSessionID; + else + server_sessionCache.entries[i].key = sess->sessionID; + + server_sessionCache.entries[i].value = sess; + server_sessionCache.length++; + break; + } + } + ++twcase_new_session_called; + wc_UnLockMutex(&server_sessionCache.htLock); + fprintf(stderr, "\t\ttwcase_new_session_called %d\n", + twcase_new_session_called); + return 1; +} + +static void twcase_remove_sessionCb(WOLFSSL_CTX *ctx, WOLFSSL_SESSION *sess) +{ + int i; + (void)ctx; + (void)sess; + + if (sess == NULL) + return; + /* + * This example uses a hash table. + * Steps you should take for a non-demo code: + * - acquire a lock for the file named according to the session id + * - remove the file + * - release the lock + */ + if (wc_LockMutex(&server_sessionCache.htLock) != 0) { + return; + } + for (i = 0; i < SESSION_CACHE_SIZE; i++) { + if (server_sessionCache.entries[i].key != NULL && + XMEMCMP(server_sessionCache.entries[i].key, + sess->sessionID, SSL_MAX_SSL_SESSION_ID_LENGTH) == 0) { + wolfSSL_SESSION_free(server_sessionCache.entries[i].value); + server_sessionCache.entries[i].value = NULL; + server_sessionCache.entries[i].key = NULL; + server_sessionCache.length--; + break; + } + } + ++twcase_remove_session_called; + wc_UnLockMutex(&server_sessionCache.htLock); + fprintf(stderr, "\t\ttwcase_remove_session_called %d\n", + twcase_remove_session_called); +} + +static WOLFSSL_SESSION *twcase_get_sessionCb(WOLFSSL *ssl, + const unsigned char *id, int len, int *ref) +{ + int i; + (void)ssl; + (void)id; + (void)len; + + /* + * This example uses a hash table. + * Steps you should take for a non-demo code: + * - acquire a lock for the file named according to the session id in the + * 2nd arg + * - read and decrypt contents of file and create a new SSL_SESSION + * - object release the lock + * - return the new session object + */ + fprintf(stderr, "\t\ttwcase_get_session_called %d\n", + ++twcase_get_session_called); + /* This callback want to retain a copy of the object. If we want wolfSSL to + * be responsible for the pointer then set to 0. */ + *ref = 1; + + for (i = 0; i < SESSION_CACHE_SIZE; i++) { + if (server_sessionCache.entries[i].key != NULL && + XMEMCMP(server_sessionCache.entries[i].key, id, + SSL_MAX_SSL_SESSION_ID_LENGTH) == 0) { + return server_sessionCache.entries[i].value; + } + } + return NULL; +} +static void twcase_get_sessionCb_cleanup(void) +{ + int i; + int cnt = 0; + + /* If twcase_get_sessionCb sets *ref = 1, the application is responsible + * for freeing sessions */ + + for (i = 0; i < SESSION_CACHE_SIZE; i++) { + if (server_sessionCache.entries[i].value != NULL) { + wolfSSL_SESSION_free(server_sessionCache.entries[i].value); + cnt++; + } + } + + fprintf(stderr, "\t\ttwcase_get_sessionCb_cleanup freed %d sessions\n", + cnt); +} + +static void twcase_cache_intOff_extOff(WOLFSSL_CTX* ctx) +{ + /* off - Disable internal cache */ + AssertIntEQ(wolfSSL_CTX_set_session_cache_mode(ctx, + WOLFSSL_SESS_CACHE_NO_INTERNAL_STORE), WOLFSSL_SUCCESS); +#ifdef OPENSSL_EXTRA + AssertIntEQ(wolfSSL_CTX_get_session_cache_mode(ctx) & + WOLFSSL_SESS_CACHE_NO_INTERNAL_STORE, + WOLFSSL_SESS_CACHE_NO_INTERNAL_STORE); +#endif + /* off - Donot setup external cache */ + + /* Require both peers to provide certs */ + wolfSSL_CTX_set_verify(ctx, WOLFSSL_VERIFY_PEER, NULL); +} + +static void twcase_cache_intOn_extOff(WOLFSSL_CTX* ctx) +{ + /* on - internal cache is on by default*/ + /* off - Donot setup external cache */ + /* Require both peers to provide certs */ + wolfSSL_CTX_set_verify(ctx, WOLFSSL_VERIFY_PEER, NULL); +} + +static void twcase_cache_intOff_extOn(WOLFSSL_CTX* ctx) +{ + /* off - Disable internal cache */ + AssertIntEQ(wolfSSL_CTX_set_session_cache_mode(ctx, + WOLFSSL_SESS_CACHE_NO_INTERNAL_STORE), WOLFSSL_SUCCESS); +#ifdef OPENSSL_EXTRA + AssertIntEQ(wolfSSL_CTX_get_session_cache_mode(ctx) & + WOLFSSL_SESS_CACHE_NO_INTERNAL_STORE, + WOLFSSL_SESS_CACHE_NO_INTERNAL_STORE); +#endif + /* on - Enable external cache */ + wolfSSL_CTX_sess_set_new_cb(ctx, twcase_new_sessionCb); + wolfSSL_CTX_sess_set_remove_cb(ctx, twcase_remove_sessionCb); + wolfSSL_CTX_sess_set_get_cb(ctx, twcase_get_sessionCb); + + /* Require both peers to provide certs */ + wolfSSL_CTX_set_verify(ctx, WOLFSSL_VERIFY_PEER, NULL); +} + +static void twcase_cache_intOn_extOn(WOLFSSL_CTX* ctx) +{ + /* on - internal cache is on by default */ + /* on - Enable external cache */ + wolfSSL_CTX_sess_set_new_cb(ctx, twcase_new_sessionCb); + wolfSSL_CTX_sess_set_remove_cb(ctx, twcase_remove_sessionCb); + wolfSSL_CTX_sess_set_get_cb(ctx, twcase_get_sessionCb); + + /* Require both peers to provide certs */ + wolfSSL_CTX_set_verify(ctx, WOLFSSL_VERIFY_PEER, NULL); +} +static void twcase_cache_intOn_extOn_noTicket(WOLFSSL_CTX* ctx) +{ + /* on - internal cache is on by default */ + /* on - Enable external cache */ + wolfSSL_CTX_sess_set_new_cb(ctx, twcase_new_sessionCb); + wolfSSL_CTX_sess_set_remove_cb(ctx, twcase_remove_sessionCb); + wolfSSL_CTX_sess_set_get_cb(ctx, twcase_get_sessionCb); + + wolfSSL_CTX_set_options(ctx, WOLFSSL_OP_NO_TICKET); + /* Require both peers to provide certs */ + wolfSSL_CTX_set_verify(ctx, WOLFSSL_VERIFY_PEER, NULL); +} +static void twcase_server_sess_ctx_pre_shutdown(WOLFSSL* ssl) +{ + WOLFSSL_SESSION** sess; + if (wolfSSL_is_server(ssl)) + sess = &twcase_server_first_session_ptr; + else + return; + + if (*sess == NULL) { + AssertNotNull(*sess = wolfSSL_get1_session(ssl)); + /* Now save the session in the internal store to make it available + * for lookup. For TLS 1.3, we can't save the session without + * WOLFSSL_TICKET_HAVE_ID because there is no way to retrieve the + * session from cache. */ + if (wolfSSL_is_server(ssl) +#ifndef WOLFSSL_TICKET_HAVE_ID + && wolfSSL_version(ssl) != TLS1_3_VERSION + && wolfSSL_version(ssl) != DTLS1_3_VERSION +#endif + ) { + AssertIntEQ(wolfSSL_CTX_add_session(wolfSSL_get_SSL_CTX(ssl), + *sess), WOLFSSL_SUCCESS); + } + } + /* Save CTX to be able to decrypt tickets */ + if (twcase_server_current_ctx_ptr == NULL) { + AssertNotNull(twcase_server_current_ctx_ptr = wolfSSL_get_SSL_CTX(ssl)); + AssertIntEQ(wolfSSL_CTX_up_ref(wolfSSL_get_SSL_CTX(ssl)), + WOLFSSL_SUCCESS); + } +#ifdef SESSION_CERTS +#ifndef WOLFSSL_TICKET_HAVE_ID + if (wolfSSL_version(ssl) != TLS1_3_VERSION && + wolfSSL_session_reused(ssl)) +#endif + { + /* With WOLFSSL_TICKET_HAVE_ID the peer certs should be available + * for all connections. TLS 1.3 only has tickets so if we don't + * include the session id in the ticket then the certificates + * will not be available on resumption. */ + WOLFSSL_X509* peer = wolfSSL_get_peer_certificate(ssl); + AssertNotNull(peer); + wolfSSL_X509_free(peer); + AssertNotNull(wolfSSL_SESSION_get_peer_chain(*sess)); + } +#endif +} + +static void twcase_client_sess_ctx_pre_shutdown(WOLFSSL* ssl) +{ + WOLFSSL_SESSION** sess; + sess = &twcase_client_first_session_ptr; + if (*sess == NULL) { + AssertNotNull(*sess = wolfSSL_get1_session(ssl)); + } + else { + /* If we have a session retrieved then remaining connections should be + * resuming on that session */ + AssertIntEQ(wolfSSL_session_reused(ssl), 1); + } + +#ifdef SESSION_CERTS +#ifndef WOLFSSL_TICKET_HAVE_ID + if (wolfSSL_version(ssl) != TLS1_3_VERSION && + wolfSSL_session_reused(ssl)) +#endif + { + + WOLFSSL_X509* peer = wolfSSL_get_peer_certificate(ssl); + AssertNotNull(peer); + wolfSSL_X509_free(peer); + AssertNotNull(wolfSSL_SESSION_get_peer_chain(*sess)); +#ifdef OPENSSL_EXTRA + AssertNotNull(wolfSSL_SESSION_get0_peer(*sess)); +#endif + } +#endif +} +static void twcase_client_set_sess_ssl_ready(WOLFSSL* ssl) +{ + /* Set the session to reuse for the client */ + AssertNotNull(ssl); + AssertNotNull(twcase_client_first_session_ptr); + AssertIntEQ(wolfSSL_set_session(ssl,twcase_client_first_session_ptr), + WOLFSSL_SUCCESS); +} +#endif + +static int test_wolfSSL_CTX_add_session_ext(void) +{ + int res = TEST_SKIPPED; +#if defined(HAVE_IO_TESTS_DEPENDENCIES) && defined(HAVE_EXT_CACHE) && \ + !defined(SINGLE_THREADED) && defined(WOLFSSL_TLS13) && \ + !defined(NO_SESSION_CACHE) && defined(OPENSSL_EXTRA) && \ + defined(SESSION_CERTS) && defined(HAVE_SESSION_TICKET) && \ + !defined(TITAN_SESSION_CACHE) && \ + !defined(HUGE_SESSION_CACHE) && \ + !defined(BIG_SESSION_CACHE) && \ + !defined(MEDIUM_SESSION_CACHE) + /* Test the default 33 sessions */ + + struct test_params { + method_provider client_meth; + method_provider server_meth; + const char* tls_version; + } params[] = { +#if defined(WOLFSSL_TLS13) && !defined(WOLFSSL_NO_DEF_TICKET_ENC_CB) && \ + defined(HAVE_SESSION_TICKET) && defined(WOLFSSL_TICKET_HAVE_ID) + { wolfTLSv1_3_client_method, wolfTLSv1_3_server_method, "TLSv1_3" }, +#ifdef WOLFSSL_DTLS13 + { wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method, "DTLSv1_3" }, +#endif +#endif +#ifndef WOLFSSL_NO_TLS12 + { wolfTLSv1_2_client_method, wolfTLSv1_2_server_method, "TLSv1_2" }, +#ifdef WOLFSSL_DTLS + { wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method, "DTLSv1_2" }, +#endif +#endif +#if !defined(NO_OLD_TLS) && ((!defined(NO_AES) && !defined(NO_AES_CBC)) || \ + !defined(NO_DES3)) + { wolfTLSv1_1_client_method, wolfTLSv1_1_server_method, "TLSv1_1" }, +#ifdef WOLFSSL_DTLS + { wolfDTLSv1_client_method, wolfDTLSv1_server_method, "DTLSv1_0" }, +#endif +#endif + }; + + const int paramsLen = sizeof(params)/sizeof(*params); + int i, j; + + /* Clear cache before starting */ + wolfSSL_CTX_flush_sessions(NULL, -1); + + XMEMSET(&server_sessionCache, 0, sizeof(hashTable)); + if (wc_InitMutex(&server_sessionCache.htLock) != 0) + return BAD_MUTEX_E; + server_sessionCache.capacity = SESSION_CACHE_SIZE; + + for (i = 0; i < paramsLen; i++) { + fprintf(stderr, "\tBegin %s\n", params[i].tls_version); + for (j = 0; j < 5; j++) { + int tls13 = XSTRSTR(params[i].tls_version, "TLSv1_3") != NULL; + int dtls = XSTRSTR(params[i].tls_version, "DTLS") != NULL; + callback_functions client_cb; + callback_functions server_cb; + + (void)dtls; + + /* Test five cache configurations */ + twcase_client_first_session_ptr = NULL; + twcase_server_first_session_ptr = NULL; + twcase_server_current_ctx_ptr = NULL; + twcase_new_session_called = 0; + twcase_remove_session_called = 0; + twcase_get_session_called = 0; + + /* connection 1 - first connection */ + fprintf(stderr, "\tconnect: %s: j=%d, methodsLen=%d\n", + params[i].tls_version, j, paramsLen); + + XMEMSET(&client_cb, 0, sizeof(callback_functions)); + XMEMSET(&server_cb, 0, sizeof(callback_functions)); + client_cb.method = params[i].client_meth; + server_cb.method = params[i].server_meth; + + if (dtls) + client_cb.doUdp = server_cb.doUdp = 1; + + /* Setup internal and external cache */ + switch (j) { + case 0: + /* SSL_OP_NO_TICKET stateful ticket case */ + server_cb.ctx_ready = twcase_cache_intOn_extOn_noTicket; + break; + case 1: + server_cb.ctx_ready = twcase_cache_intOn_extOn; + break; + case 2: + server_cb.ctx_ready = twcase_cache_intOff_extOn; + break; + case 3: + server_cb.ctx_ready = twcase_cache_intOn_extOff; + break; + case 4: + server_cb.ctx_ready = twcase_cache_intOff_extOff; + break; + } + client_cb.ctx_ready = twcase_cache_intOff_extOff; + + /* Add session to internal cache and save SSL session for testing */ + server_cb.on_result = twcase_server_sess_ctx_pre_shutdown; + /* Save client SSL session for testing */ + client_cb.on_result = twcase_client_sess_ctx_pre_shutdown; + server_cb.ticNoInit = 1; /* Use default builtin */ + /* Don't free/release ctx */ + server_cb.ctx = twcase_server_current_ctx_ptr; + server_cb.isSharedCtx = 1; + + test_wolfSSL_client_server_nofail(&client_cb, &server_cb); + + AssertTrue(client_cb.return_code); + AssertTrue(server_cb.return_code); + AssertIntEQ(twcase_get_session_called, 0); + switch (j) { + case 0: + case 1: + case 2: + /* cache cannot be searched with out a connection */ + /* Add a new session */ + AssertIntEQ(twcase_new_session_called, 1); + /* In twcase_server_sess_ctx_pre_shutdown + * wolfSSL_CTX_add_session which evicts the existing session + * in cache and adds it back in */ + AssertIntLE(twcase_remove_session_called, 1); + break; + case 3: + case 4: + /* no external cache */ + AssertIntEQ(twcase_new_session_called, 0); + AssertIntEQ(twcase_remove_session_called, 0); + break; + } + + /* connection 2 - session resume */ + fprintf(stderr, "\tresume: %s: j=%d, methodsLen=%d\n", + params[i].tls_version, j, paramsLen); + twcase_new_session_called = 0; + twcase_remove_session_called = 0; + twcase_get_session_called = 0; + server_cb.on_result = 0; + client_cb.on_result = 0; + server_cb.ticNoInit = 1; /* Use default builtin */ + + server_cb.ctx = twcase_server_current_ctx_ptr; + + /* try session resumption */ + client_cb.ssl_ready = twcase_client_set_sess_ssl_ready; + + test_wolfSSL_client_server_nofail(&client_cb, &server_cb); + + AssertTrue(client_cb.return_code); + AssertTrue(server_cb.return_code); + + /* Clear cache before checking */ + wolfSSL_CTX_flush_sessions(NULL, -1); + + switch (j) { + case 0: + if (tls13) { + /* (D)TLSv1.3 stateful case */ + /* cache hit */ + /* DTLS accesses cache once for stateless parsing and + * once for stateful parsing */ + AssertIntEQ(twcase_get_session_called, !dtls ? 1 : 2); + + /* (D)TLSv1.3 creates a new ticket, + * updates both internal and external cache */ + AssertIntEQ(twcase_new_session_called, 1); + AssertIntEQ(twcase_remove_session_called, 1); + + } + else { + /* non (D)TLSv1.3 case, no update */ + /* DTLS accesses cache once for stateless parsing and + * once for stateful parsing */ +#ifdef WOLFSSL_DTLS_NO_HVR_ON_RESUME + AssertIntEQ(twcase_get_session_called, !dtls ? 1 : 2); +#else + AssertIntEQ(twcase_get_session_called, 1); +#endif + AssertIntEQ(twcase_new_session_called, 0); + /* Called on session added in + * twcase_server_sess_ctx_pre_shutdown */ + AssertIntEQ(twcase_remove_session_called, 1); + } + break; + case 1: + if (tls13) { + /* (D)TLSv1.3 case */ + /* cache hit */ + AssertIntEQ(twcase_get_session_called, 1); + /* (D)TLSv1.3 creates a new ticket, + * updates both internal and external cache */ + AssertIntEQ(twcase_new_session_called, 1); + /* Called on session added in + * twcase_server_sess_ctx_pre_shutdown and by wolfSSL */ + AssertIntEQ(twcase_remove_session_called, 1); + } + else { + /* non (D)TLSv1.3 case */ + /* cache hit */ + /* DTLS accesses cache once for stateless parsing and + * once for stateful parsing */ +#ifdef WOLFSSL_DTLS_NO_HVR_ON_RESUME + AssertIntEQ(twcase_get_session_called, !dtls ? 1 : 2); +#else + AssertIntEQ(twcase_get_session_called, 1); +#endif + AssertIntEQ(twcase_new_session_called, 0); + /* Called on session added in + * twcase_server_sess_ctx_pre_shutdown */ + AssertIntEQ(twcase_remove_session_called, 1); + } + break; + case 2: + if (tls13) { + /* (D)TLSv1.3 case */ + /* cache hit */ + AssertIntEQ(twcase_get_session_called, 1); + /* (D)TLSv1.3 creates a new ticket, + * updates both internal and external cache */ + AssertIntEQ(twcase_new_session_called, 1); + /* Called on session added in + * twcase_server_sess_ctx_pre_shutdown and by wolfSSL */ + AssertIntEQ(twcase_remove_session_called, 1); + } + else { + /* non (D)TLSv1.3 case */ + /* cache hit */ + /* DTLS accesses cache once for stateless parsing and + * once for stateful parsing */ +#ifdef WOLFSSL_DTLS_NO_HVR_ON_RESUME + AssertIntEQ(twcase_get_session_called, !dtls ? 1 : 2); +#else + AssertIntEQ(twcase_get_session_called, 1); +#endif + AssertIntEQ(twcase_new_session_called, 0); + /* Called on session added in + * twcase_server_sess_ctx_pre_shutdown */ + AssertIntEQ(twcase_remove_session_called, 1); + } + break; + case 3: + case 4: + /* no external cache */ + AssertIntEQ(twcase_get_session_called, 0); + AssertIntEQ(twcase_new_session_called, 0); + AssertIntEQ(twcase_remove_session_called, 0); + break; + } + wolfSSL_SESSION_free(twcase_client_first_session_ptr); + wolfSSL_SESSION_free(twcase_server_first_session_ptr); + wolfSSL_CTX_free(twcase_server_current_ctx_ptr); + } + twcase_get_sessionCb_cleanup(); + XMEMSET(&server_sessionCache.entries, 0, + sizeof(server_sessionCache.entries)); + fprintf(stderr, "\tEnd %s\n", params[i].tls_version); + } + wc_FreeMutex(&server_sessionCache.htLock); + res = TEST_RES_CHECK(1); +#endif + + return res; +} + #if defined(WOLFSSL_DTLS) && defined(WOLFSSL_SESSION_EXPORT) /* canned export of a session using older version 3 */ @@ -44888,14 +45474,10 @@ static int test_wolfSSL_CTX_sess_set_remove_cb(void) /* Both should have been allocated */ AssertIntEQ(clientSessRemCountMalloc, 1); AssertIntEQ(serverSessRemCountMalloc, 1); -#if (!defined(WOLFSSL_TLS13) || !defined(HAVE_SESSION_TICKET)) && \ - defined(NO_SESSION_CACHE_REF) - /* Client session should not be added to cache so this should be free'd when - * the SSL object was being free'd */ - AssertIntEQ(clientSessRemCountFree, 1); -#else - /* Client session is in cache due to requiring a persistent reference */ + /* This should not be called yet. Session wasn't evicted from cache yet. */ AssertIntEQ(clientSessRemCountFree, 0); +#if (defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET)) || \ + !defined(NO_SESSION_CACHE_REF) /* Force a cache lookup */ AssertNotNull(SSL_SESSION_get_ex_data(clientSess, serverSessRemIdx)); /* Force a cache update */ @@ -62297,6 +62879,8 @@ static int test_wolfSSL_SESSION_get_ex_new_index(void) SSL_SESSION_free(d); AssertIntEQ(test_wolfSSL_SESSION_get_ex_new_index_free_cb_called, 2); + crypto_ex_cb_free(crypto_ex_cb_ctx_session); + crypto_ex_cb_ctx_session = NULL; return TEST_RES_CHECK(1); } #else @@ -64972,6 +65556,7 @@ TEST_CASE testCases[] = { #ifdef HAVE_IO_TESTS_DEPENDENCIES TEST_DECL(test_wolfSSL_get_finished), TEST_DECL(test_wolfSSL_CTX_add_session), + TEST_DECL(test_wolfSSL_CTX_add_session_ext), #endif TEST_DECL(test_SSL_CIPHER_get_xxx), TEST_DECL(test_wolfSSL_ERR_strings), diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 89bf9a46f..2ed342449 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -3212,6 +3212,18 @@ enum PskDecryptReturn { PSK_DECRYPT_FAIL, }; +#ifdef HAVE_SESSION_TICKET +typedef struct psk_sess_free_cb_ctx { + word32 row; +#ifdef HAVE_EXT_CACHE + int extCache; + int freeSess; +#endif +} psk_sess_free_cb_ctx; +typedef void (psk_sess_free_cb)(const WOLFSSL* ssl, const WOLFSSL_SESSION* sess, + psk_sess_free_cb_ctx* freeCtx); +#endif + /* The PreSharedKey extension information - entry in a linked list. */ typedef struct PreSharedKey { word16 identityLen; /* Length of identity */ @@ -3224,6 +3236,11 @@ typedef struct PreSharedKey { byte hmac; /* HMAC algorithm */ #ifdef HAVE_SESSION_TICKET InternalTicket* it; /* ptr to ticket */ + const WOLFSSL_SESSION* sess; /* ptr to session either from external cache or + * into SessionCache. Work around so that we + * don't call into the cache more than once */ + psk_sess_free_cb* sess_free_cb; /* callback to free sess */ + psk_sess_free_cb_ctx sess_free_cb_ctx; /* info for sess_free_cb */ #endif byte resumption:1; /* Resumption PSK */ byte chosen:1; /* Server's choice */ @@ -4063,6 +4080,8 @@ struct WOLFSSL_SESSION { byte haveAltSessionID:1; #ifdef HAVE_EX_DATA byte ownExData:1; +#endif +#if defined(HAVE_EXT_CACHE) || defined(HAVE_EX_DATA) Rem_Sess_Cb rem_sess_cb; #endif void* heap; @@ -4138,6 +4157,7 @@ struct WOLFSSL_SESSION { #ifdef HAVE_EX_DATA WOLFSSL_CRYPTO_EX_DATA ex_data; #endif + byte isSetup:1; }; #if defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET) && \ @@ -4152,9 +4172,10 @@ WOLFSSL_LOCAL int wolfSSL_RAND_Init(void); WOLFSSL_LOCAL WOLFSSL_SESSION* wolfSSL_NewSession(void* heap); WOLFSSL_LOCAL WOLFSSL_SESSION* wolfSSL_GetSession( WOLFSSL* ssl, byte* masterSecret, byte restoreSessionCerts); +WOLFSSL_LOCAL void SetupSession(WOLFSSL* ssl); WOLFSSL_LOCAL void AddSession(WOLFSSL* ssl); /* use wolfSSL_API visibility to be able to test in tests/api.c */ -WOLFSSL_API int AddSessionToCache(WOLFSSL_CTX* ssl, +WOLFSSL_API int AddSessionToCache(WOLFSSL_CTX* ctx, WOLFSSL_SESSION* addSession, const byte* id, byte idSz, int* sessionIndex, int side, word16 useTicket, ClientSession** clientCacheEntry); #ifndef NO_CLIENT_CACHE @@ -4165,8 +4186,11 @@ WOLFSSL_LOCAL ClientSession* AddSessionToClientCache(int side, int row, int idx, 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, byte readOnly); +WOLFSSL_LOCAL int TlsSessionCacheGetAndRdLock(const byte *id, + const WOLFSSL_SESSION **sess, word32 *lockedRow, byte side); +WOLFSSL_LOCAL int TlsSessionCacheGetAndWrLock(const byte *id, + WOLFSSL_SESSION **sess, word32 *lockedRow, byte side); +WOLFSSL_LOCAL void EvictSessionFromCache(WOLFSSL_SESSION* session); /* 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); @@ -5767,13 +5791,15 @@ WOLFSSL_LOCAL int SendTicket(WOLFSSL* ssl); WOLFSSL_LOCAL int DoDecryptTicket(const WOLFSSL* ssl, const byte* input, word32 len, InternalTicket **it); /* Return 0 when check successful. <0 on failure. */ -WOLFSSL_LOCAL void DoClientTicketFinalize(WOLFSSL* ssl, InternalTicket* it); +WOLFSSL_LOCAL void DoClientTicketFinalize(WOLFSSL* ssl, InternalTicket* it, + const WOLFSSL_SESSION* sess); #ifdef WOLFSSL_TLS13 WOLFSSL_LOCAL int DoClientTicketCheck(const WOLFSSL* ssl, const PreSharedKey* psk, sword64 timeout, const byte* suite); WOLFSSL_LOCAL void CleanupClientTickets(PreSharedKey* psk); -WOLFSSL_LOCAL int DoClientTicket_ex(const WOLFSSL* ssl, PreSharedKey* psk); +WOLFSSL_LOCAL int DoClientTicket_ex(const WOLFSSL* ssl, PreSharedKey* psk, + int retainSess); #endif WOLFSSL_LOCAL int DoClientTicket(WOLFSSL* ssl, const byte* input, word32 len); @@ -6292,8 +6318,9 @@ typedef struct CRYPTO_EX_cb_ctx { WOLFSSL_CRYPTO_EX_dup* dup_func; struct CRYPTO_EX_cb_ctx* next; } CRYPTO_EX_cb_ctx; -extern CRYPTO_EX_cb_ctx* crypto_ex_cb_ctx_session; -WOLFSSL_LOCAL void crypto_ex_cb_free(CRYPTO_EX_cb_ctx* cb_ctx); +/* use wolfSSL_API visibility to be able to clear in tests/api.c */ +WOLFSSL_API extern CRYPTO_EX_cb_ctx* crypto_ex_cb_ctx_session; +WOLFSSL_API void crypto_ex_cb_free(CRYPTO_EX_cb_ctx* cb_ctx); WOLFSSL_LOCAL void crypto_ex_cb_setup_new_data(void *new_obj, CRYPTO_EX_cb_ctx* cb_ctx, WOLFSSL_CRYPTO_EX_DATA* ex_data); WOLFSSL_LOCAL void crypto_ex_cb_free_data(void *obj, CRYPTO_EX_cb_ctx* cb_ctx, diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index fe74ac944..1085d7c8b 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -1235,6 +1235,7 @@ WOLFSSL_ABI WOLFSSL_API int wolfSSL_set_session(WOLFSSL* ssl, WOLFSSL_SESSION* WOLFSSL_API long wolfSSL_SSL_SESSION_set_timeout(WOLFSSL_SESSION* ses, long t); WOLFSSL_ABI WOLFSSL_API WOLFSSL_SESSION* wolfSSL_get_session(WOLFSSL* ssl); WOLFSSL_ABI WOLFSSL_API void wolfSSL_flush_sessions(WOLFSSL_CTX* ctx, long tm); +WOLFSSL_API void wolfSSL_CTX_flush_sessions(WOLFSSL_CTX* ctx, long tm); WOLFSSL_API int wolfSSL_SetServerID(WOLFSSL* ssl, const unsigned char* id, int len, int newSession); #if defined(OPENSSL_ALL) || defined(WOLFSSL_ASIO) || defined(WOLFSSL_HAPROXY) \ @@ -4881,9 +4882,6 @@ WOLFSSL_API long wolfSSL_SSL_CTX_get_timeout(const WOLFSSL_CTX *ctx); WOLFSSL_API long wolfSSL_get_timeout(WOLFSSL* ssl); WOLFSSL_API int wolfSSL_SSL_CTX_set_tmp_ecdh(WOLFSSL_CTX *ctx, WOLFSSL_EC_KEY *ecdh); -WOLFSSL_API int wolfSSL_SSL_CTX_remove_session(WOLFSSL_CTX* ctx, - WOLFSSL_SESSION *c); - WOLFSSL_API WOLFSSL_BIO *wolfSSL_SSL_get_rbio(const WOLFSSL *s); WOLFSSL_API WOLFSSL_BIO *wolfSSL_SSL_get_wbio(const WOLFSSL *s); WOLFSSL_API int wolfSSL_SSL_do_handshake(WOLFSSL *s); @@ -4899,6 +4897,8 @@ WOLFSSL_API int wolfSSL_SSL_in_init(WOLFSSL* ssl); WOLFSSL_API int wolfSSL_SSL_in_connect_init(WOLFSSL* ssl); #ifndef NO_SESSION_CACHE + WOLFSSL_API int wolfSSL_SSL_CTX_remove_session(WOLFSSL_CTX* ctx, + WOLFSSL_SESSION *c); WOLFSSL_API WOLFSSL_SESSION *wolfSSL_SSL_get0_session(const WOLFSSL *s); #endif @@ -5166,6 +5166,7 @@ WOLFSSL_API int wolfSSL_dtls_cid_get_tx(WOLFSSL* ssl, unsigned char* buffer, #define TLS1_3_VERSION 0x0304 #define DTLS1_VERSION 0xFEFF #define DTLS1_2_VERSION 0xFEFD +#define DTLS1_3_VERSION 0xFEFC #ifdef __cplusplus } /* extern "C" */