From 56d60877497dee04900c57c4f91339b3ded00537 Mon Sep 17 00:00:00 2001 From: Marco Oliverio Date: Wed, 14 Sep 2022 15:35:12 +0200 Subject: [PATCH] tls13: support ticketNonce bigger than MAX_TICKET_NONCE_SZ to enable it, use WOLFSSL_TICKET_NONCE_MALLOC define --- CMakeLists.txt | 9 ++ configure.ac | 11 ++ src/internal.c | 19 +++ src/sniffer.c | 4 +- src/ssl.c | 316 +++++++++++++++++++++++++++++++++++++++- src/tls13.c | 59 +++++++- wolfcrypt/src/kdf.c | 96 ++++++++++++ wolfssl/internal.h | 24 ++- wolfssl/wolfcrypt/kdf.h | 7 + 9 files changed, 529 insertions(+), 16 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cf48ac0b0..ea2ec8cf6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1340,6 +1340,15 @@ if(WOLFSSL_SESSION_TICKET) "-DHAVE_SESSION_TICKET") endif() +add_option("WOLFSSL_TICKET_NONCE_MALLOC" + "Enable dynamic allocation of ticket nonces (default: disabled)" + "no" "yes;no") + +if(WOLFSSL_TICKET_NONCE_MALLOC) + list(APPEND WOLFSSL_DEFINITIONS + "-DWOLFSSL_TICKET_NONCE_MALLOC") +endif() + # Extended master secret extension add_option("WOLFSSL_EXTENDED_MASTER" "Enable Extended Master Secret (default: enabled)" diff --git a/configure.ac b/configure.ac index 8c205bc1f..614487001 100644 --- a/configure.ac +++ b/configure.ac @@ -4903,6 +4903,17 @@ then AM_CFLAGS="$AM_CFLAGS -DHAVE_TLS_EXTENSIONS -DHAVE_SESSION_TICKET" fi +AC_ARG_ENABLE([ticket-nonce-malloc], + [AS_HELP_STRING([--enable-ticket-nonce-malloc], [Enable dynamic allocation of ticket nonces (default: disabled)])], + [ ENABLED_TICKET_NONCE_MALLOC=$enableval ], + [ ENABLED_TICKET_NONCE_MALLOC=no ] + ) + +if test "$ENABLED_TICKET_NONCE_MALLOC" = "yes" +then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_TICKET_NONCE_MALLOC" +fi + # Extended Master Secret Extension AC_ARG_ENABLE([extended-master], [AS_HELP_STRING([--enable-extended-master],[Enable Extended Master Secret (default: enabled)])], diff --git a/src/internal.c b/src/internal.c index fa90830d5..a01b951fd 100644 --- a/src/internal.c +++ b/src/internal.c @@ -33986,6 +33986,11 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, #endif /* Resumption master secret. */ XMEMCPY(it->msecret, ssl->session->masterSecret, SECRET_LEN); + if (ssl->session->ticketNonce.len > MAX_TICKET_NONCE_STATIC_SZ) { + WOLFSSL_MSG("Bad ticket nonce value"); + ret = BAD_TICKET_MSG_SZ; + goto error; + } XMEMCPY(it->ticketNonce, ssl->session->ticketNonce.data, ssl->session->ticketNonce.len); it->ticketNonceLen = ssl->session->ticketNonce.len; @@ -34264,6 +34269,20 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, #endif /* Resumption master secret. */ XMEMCPY(ssl->session->masterSecret, it->msecret, SECRET_LEN); + if (it->ticketNonceLen > MAX_TICKET_NONCE_STATIC_SZ) { + WOLFSSL_MSG("Unsupported ticketNonce len in ticket"); + return BAD_TICKET_ENCRYPT; + } +#if defined(WOLFSSL_TICKET_NONCE_MALLOC) && \ + (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3))) + if (ssl->session->ticketNonce.data + != ssl->session->ticketNonce.dataStatic) { + XFREE(ssl->session->ticketNonce.data, ssl->heap, + DYNAMIC_TYPE_SESSION_TICK); + ssl->session->ticketNonce.data = + ssl->session->ticketNonce.dataStatic; + } +#endif /* defined(WOLFSSL_TICKET_NONCE_MALLOC) && FIPS_VERSION_GE(5,3) */ XMEMCPY(ssl->session->ticketNonce.data, it->ticketNonce, it->ticketNonceLen); ssl->session->ticketNonce.len = it->ticketNonceLen; diff --git a/src/sniffer.c b/src/sniffer.c index b25f996e0..9f56f4f62 100644 --- a/src/sniffer.c +++ b/src/sniffer.c @@ -3292,7 +3292,7 @@ static int ProcessSessionTicket(const byte* input, int* sslBytes, /* ticket nonce */ len = input[0]; - if (len > MAX_TICKET_NONCE_SZ) { + if (len > MAX_TICKET_NONCE_STATIC_SZ) { SetError(BAD_INPUT_STR, error, session, FATAL_ERROR_STATE); return -1; } @@ -3302,7 +3302,7 @@ static int ProcessSessionTicket(const byte* input, int* sslBytes, /* store nonce in server for DeriveResumptionPSK */ session->sslServer->session->ticketNonce.len = len; if (len > 0) - XMEMCPY(&session->sslServer->session->ticketNonce.data, input, len); + XMEMCPY(session->sslServer->session->ticketNonce.data, input, len); #endif input += len; *sslBytes -= len; diff --git a/src/ssl.c b/src/ssl.c index 33a8544da..263b0f8bb 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -13555,6 +13555,40 @@ static int SslSessionCacheOff(const WOLFSSL* ssl, const WOLFSSL_SESSION* session ; } +#if defined(HAVE_SESSION_TICKET) && defined(WOLFSSL_TLS13) && \ + defined(WOLFSSL_TICKET_NONCE_MALLOC) && \ + (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3))) +/** + * SessionTicketNoncePrealloc() - prealloc a buffer for ticket nonces + * @output: [in] pointer to WOLFSSL_SESSION object that will soon be a + * destination of a session duplication + * @buf: [out] address of the preallocated buf + * @len: [out] len of the preallocated buf + * + * prealloc a buffer that will likely suffice to contain a ticket nonce. It's + * used when copying session under lock, when syscalls need to be avoided. If + * output already has a dynamic buffer, it's reused. + */ +static int SessionTicketNoncePrealloc(byte** buf, byte* len, void *heap) +{ + (void)heap; + + *buf = (byte*)XMALLOC(PREALLOC_SESSION_TICKET_NONCE_LEN, heap, + DYNAMIC_TYPE_SESSION_TICK); + if (*buf == NULL) { + WOLFSSL_MSG("Failed to preallocate ticket nonce buffer"); + *len = 0; + return WOLFSSL_FAILURE; + } + + *len = PREALLOC_SESSION_TICKET_NONCE_LEN; + return 0; +} +#endif /* HAVE_SESSION_TICKET && WOLFSSL_TLS13 */ + +static int wolfSSL_DupSessionEx(const WOLFSSL_SESSION* input, + WOLFSSL_SESSION* output, int avoidSysCalls, byte* ticketNonceBuf, + byte* ticketNonceLen, byte* preallocUsed); int wolfSSL_GetSessionFromCache(WOLFSSL* ssl, WOLFSSL_SESSION* output) { @@ -13571,6 +13605,11 @@ int wolfSSL_GetSessionFromCache(WOLFSSL* ssl, WOLFSSL_SESSION* output) #else byte* tmpTicket = NULL; #endif +#ifdef WOLFSSL_TLS13 + byte *preallocNonce = NULL; + byte preallocNonceLen = 0; + byte preallocNonceUsed = 0; +#endif /* WOLFSSL_TLS13 */ byte tmpBufSet = 0; #endif #if defined(SESSION_CERTS) && defined(OPENSSL_EXTRA) @@ -13678,6 +13717,30 @@ int wolfSSL_GetSessionFromCache(WOLFSSL* ssl, WOLFSSL_SESSION* output) } #endif +#if defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET) && \ + defined(WOLFSSL_TICKET_NONCE_MALLOC) && \ + (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3))) + if (output->ticketNonce.data != output->ticketNonce.dataStatic) { + XFREE(output->ticketNonce.data, output->heap, + DYNAMIC_TYPE_SESSION_TICK); + output->ticketNonce.data = output->ticketNonce.dataStatic; + output->ticketNonce.len = 0; + } + error = SessionTicketNoncePrealloc(&preallocNonce, &preallocNonceLen, + output->heap); + if (error != 0) { + if (tmpBufSet) { + output->ticket = output->staticTicket; + output->ticketLenAlloc = 0; + } +#ifdef WOLFSSL_SMALL_STACK + if (tmpTicket != NULL) + XFREE(tmpTicket, output->heap, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return WOLFSSL_FAILURE; + } +#endif /* WOLFSSL_TLS13 && HAVE_SESSION_TICKET*/ + /* lock row */ sessRow = &SessionCache[row]; if (SESSION_ROW_LOCK(sessRow) != 0) { @@ -13687,6 +13750,10 @@ int wolfSSL_GetSessionFromCache(WOLFSSL* ssl, WOLFSSL_SESSION* output) output->ticket = output->staticTicket; output->ticketLenAlloc = 0; } +#ifdef WOLFSSL_TLS13 + if (preallocNonce != NULL) + XFREE(preallocNonce, output->heap, DYNAMIC_TYPE_SESSION_TICK); +#endif /* WOLFSSL_TLS13 */ #ifdef WOLFSSL_SMALL_STACK if (tmpTicket != NULL) XFREE(tmpTicket, output->heap, DYNAMIC_TYPE_TMP_BUFFER); @@ -13731,7 +13798,13 @@ int wolfSSL_GetSessionFromCache(WOLFSSL* ssl, WOLFSSL_SESSION* output) sess->peer = NULL; } #endif +#if defined(HAVE_SESSION_TICKET) && defined(WOLFSSL_TLS13) + error = wolfSSL_DupSessionEx(sess, output, 1, + preallocNonce, &preallocNonceLen, &preallocNonceUsed); +#else error = wolfSSL_DupSession(sess, output, 1); +#endif /* WOLFSSL_TSL */ + #ifdef HAVE_EX_DATA output->ownExData = 0; /* Session cache owns external data */ #endif @@ -13780,6 +13853,45 @@ int wolfSSL_GetSessionFromCache(WOLFSSL* ssl, WOLFSSL_SESSION* output) if (tmpTicket != NULL) XFREE(tmpTicket, output->heap, DYNAMIC_TYPE_TMP_BUFFER); #endif + +#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_TICKET_NONCE_MALLOC) && \ + (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3))) + if (error == WOLFSSL_SUCCESS && preallocNonceUsed) { + if (preallocNonceLen < PREALLOC_SESSION_TICKET_NONCE_LEN) { + /* buffer bigger than needed */ +#ifndef XREALLOC + output->ticketNonce.data = (byte*)XMALLOC(preallocNonceLen, + output->heap, DYNAMIC_TYPE_SESSION_TICK); + if (output->ticketNonce.data != NULL) + XMEMCPY(output->ticketNonce.data, preallocNonce, + preallocNonceLen); + XFREE(preallocNonce, output->heap, DYNAMIC_TYPE_SESSION_TICK); + preallocNonce = NULL; +#else + output->ticketNonce.data = XREALLOC(preallocNonce, + preallocNonceLen, output->heap, DYNAMIC_TYPE_SESSION_TICK); + if (output->ticketNonce.data != NULL) { + /* don't free the reallocated pointer */ + preallocNonce = NULL; + } +#endif /* !XREALLOC */ + if (output->ticketNonce.data == NULL) { + output->ticketNonce.data = output->ticketNonce.dataStatic; + output->ticketNonce.len = 0; + error = WOLFSSL_FAILURE; + /* preallocNonce will be free'd after the if */ + } + } + else { + output->ticketNonce.data = preallocNonce; + output->ticketNonce.len = preallocNonceLen; + preallocNonce = NULL; + } + } + if (preallocNonce != NULL) + XFREE(preallocNonce, output->heap, DYNAMIC_TYPE_SESSION_TICK); +#endif /* WOLFSSL_TLS13 && WOLFSSL_TICKET_NONCE_MALLOC && FIPS_VERSION_GE(5,3)*/ + #endif #if defined(SESSION_CERTS) && defined(OPENSSL_EXTRA) @@ -14091,7 +14203,14 @@ int AddSessionToCache(WOLFSSL_CTX* ctx, WOLFSSL_SESSION* addSession, byte ticBuffUsed = 0; byte* ticBuff = NULL; int ticLen = 0; -#endif +#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_TICKET_NONCE_MALLOC) && \ + (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3))) + byte *preallocNonce = NULL; + byte preallocNonceLen = 0; + byte preallocNonceUsed = 0; + byte *toFree = NULL; +#endif /* WOLFSSL_TLS13 && WOLFSSL_TICKET_NONCE_MALLOC */ +#endif /* HAVE_SESSION_TICKET */ int ret = 0; int row; int i; @@ -14113,7 +14232,6 @@ int AddSessionToCache(WOLFSSL_CTX* ctx, WOLFSSL_SESSION* addSession, return MEMORY_E; } - /* Find a position for the new session in cache and use that */ #ifdef HAVE_SESSION_TICKET ticLen = addSession->ticketLen; /* Alloc Memory here to avoid syscalls during lock */ @@ -14124,13 +14242,35 @@ int AddSessionToCache(WOLFSSL_CTX* ctx, WOLFSSL_SESSION* addSession, return MEMORY_E; } } -#endif +#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_TICKET_NONCE_MALLOC) && \ + (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3))) + if (addSession->ticketNonce.data != addSession->ticketNonce.dataStatic) { + /* use the AddSession->heap even if the buffer maybe saved in + * CachedSession objects. CachedSession heap and AddSession heap should + * be the same */ + preallocNonce = (byte*)XMALLOC(addSession->ticketNonce.len, + addSession->heap, DYNAMIC_TYPE_SESSION_TICK); + if (preallocNonce == NULL) { + if (ticBuff != NULL) + XFREE(ticBuff, addSession->heap, DYNAMIC_TYPE_SESSION_TICK); + return MEMORY_E; + } + preallocNonceLen = addSession->ticketNonce.len; + } +#endif /* WOLFSSL_TLS13 && WOLFSL_TICKET_NONCE_MALLOC && FIPS_VERSION_GE(5,3) */ +#endif /* HAVE_SESSION_TICKET */ + + /* Find a position for the new session in cache and use that */ /* Use the session object in the cache for external cache if required */ row = (int)(HashObject(id, ID_LEN, &ret) % SESSION_ROWS); if (ret != 0) { WOLFSSL_MSG("Hash session failed"); #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 return ret; } @@ -14139,6 +14279,10 @@ int AddSessionToCache(WOLFSSL_CTX* ctx, WOLFSSL_SESSION* addSession, if (SESSION_ROW_LOCK(sessRow) != 0) { #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 WOLFSSL_MSG("Session row lock failed"); return BAD_MUTEX_E; @@ -14193,6 +14337,19 @@ int AddSessionToCache(WOLFSSL_CTX* ctx, WOLFSSL_SESSION* addSession, cacheSession->ticket = ticBuff; cacheSession->ticketLenAlloc = (word16) ticLen; } +#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_TICKET_NONCE_MALLOC) && \ + (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3))) + /* cache entry never used */ + if (cacheSession->ticketNonce.data == NULL) + cacheSession->ticketNonce.data = cacheSession->ticketNonce.dataStatic; + + if (cacheSession->ticketNonce.data != + cacheSession->ticketNonce.dataStatic) { + toFree = cacheSession->ticketNonce.data; + cacheSession->ticketNonce.data = cacheSession->ticketNonce.dataStatic; + cacheSession->ticketNonce.len = 0; + } +#endif /* WOFLSSL_TLS13 && WOLFSSL_TICKET_NONCE_MALLOC && FIPS_VERSION_GE(5,3)*/ #endif #ifdef SESSION_CERTS if (overwrite && @@ -14206,7 +14363,15 @@ int AddSessionToCache(WOLFSSL_CTX* ctx, WOLFSSL_SESSION* addSession, #endif /* SESSION_CERTS */ cacheSession->heap = NULL; /* Copy data into the cache object */ +#if defined(HAVE_SESSION_TICKET) && defined(WOLFSSL_TLS13) && \ + defined(WOLFSSL_TICKET_NONCE_MALLOC) && \ + (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3))) + ret = wolfSSL_DupSessionEx(addSession, cacheSession, 1, preallocNonce, + &preallocNonceLen, &preallocNonceUsed) == WOLFSSL_FAILURE; +#else ret = wolfSSL_DupSession(addSession, cacheSession, 1) == WOLFSSL_FAILURE; +#endif /* HAVE_SESSION_TICKET && WOLFSSL_TLS13 && WOLFSSL_TICKET_NONCE_MALLOC + && FIPS_VERSION_GE(5,3)*/ if (ret == 0) { /* Increment the totalCount and the nextIdx */ @@ -14226,6 +14391,17 @@ int AddSessionToCache(WOLFSSL_CTX* ctx, WOLFSSL_SESSION* addSession, cacheSession->rem_sess_cb = ctx->rem_sess_cb; } #endif +#if defined(HAVE_SESSION_TICKET) && defined(WOLFSSL_TLS13) && \ + defined(WOLFSSL_TICKET_NONCE_MALLOC) && \ + (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3))) + if (preallocNonce != NULL && preallocNonceUsed) { + cacheSession->ticketNonce.data = preallocNonce; + cacheSession->ticketNonce.len = preallocNonceLen; + preallocNonce = NULL; + preallocNonceLen = 0; + } +#endif /* HAVE_SESSION_TICKET && WOLFSSL_TLS13 && WOLFSSL_TICKET_NONCE_MALLOC + * && FIPS_VERSION_GE(5,3)*/ } #ifdef HAVE_SESSION_TICKET else if (ticBuffUsed) { @@ -14253,6 +14429,13 @@ int AddSessionToCache(WOLFSSL_CTX* ctx, WOLFSSL_SESSION* addSession, XFREE(ticBuff, NULL, DYNAMIC_TYPE_SESSION_TICK); if (cacheTicBuff != NULL) XFREE(cacheTicBuff, NULL, DYNAMIC_TYPE_SESSION_TICK); +#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_TICKET_NONCE_MALLOC) && \ + (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3))) + if (preallocNonce != NULL) + XFREE(preallocNonce, addSession->heap, DYNAMIC_TYPE_SESSION_TICK); + if (toFree != NULL) + XFREE(toFree, addSession->heap, DYNAMIC_TYPE_SESSION_TICK); +#endif /* WOLFSSL_TLS13 && WOLFSSL_TICKET_NONCE_MALLOC && FIPS_VERSION_GE(5,3)*/ #endif #if defined(SESSION_CERTS) && defined(OPENSSL_EXTRA) @@ -20024,6 +20207,10 @@ WOLFSSL_SESSION* wolfSSL_NewSession(void* heap) #endif #ifdef HAVE_SESSION_TICKET ret->ticket = ret->staticTicket; + #if defined(WOLFSSL_TLS13) && defined(WOLFSSL_TICKET_NONCE_MALLOC) && \ + (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3))) + ret->ticketNonce.data = ret->ticketNonce.dataStatic; + #endif #endif #ifdef HAVE_STUNNEL /* stunnel has this funny mechanism of storing the "is_authenticated" @@ -20086,11 +20273,16 @@ int wolfSSL_SESSION_up_ref(WOLFSSL_SESSION* session) * sessions from cache. When a cache row is locked, we * don't want to block other threads with long running * system calls. + * @param ticketNonceBuf If not null and @avoidSysCalls is true, the copy of the + * ticketNonce will happen in this pre allocated buffer + * @param ticketNonceLen @ticketNonceBuf len as input, used length on output + * @param ticketNonceUsed if @ticketNonceBuf was used to copy the ticket noncet * @return WOLFSSL_SUCCESS on success * WOLFSSL_FAILURE on failure */ -int wolfSSL_DupSession(const WOLFSSL_SESSION* input, WOLFSSL_SESSION* output, - int avoidSysCalls) +static int wolfSSL_DupSessionEx(const WOLFSSL_SESSION* input, + WOLFSSL_SESSION* output, int avoidSysCalls, byte* ticketNonceBuf, + byte* ticketNonceLen, byte* preallocUsed) { #ifdef HAVE_SESSION_TICKET int ticLenAlloc = 0; @@ -20100,6 +20292,9 @@ int wolfSSL_DupSession(const WOLFSSL_SESSION* input, WOLFSSL_SESSION* output, int ret = WOLFSSL_SUCCESS; (void)avoidSysCalls; + (void)ticketNonceBuf; + (void)ticketNonceLen; + (void)preallocUsed; input = ClientSessionToSession(input); output = ClientSessionToSession(output); @@ -20114,7 +20309,27 @@ int wolfSSL_DupSession(const WOLFSSL_SESSION* input, WOLFSSL_SESSION* output, ticBuff = output->ticket; ticLenAlloc = output->ticketLenAlloc; } -#endif +#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_TICKET_NONCE_MALLOC) && \ + (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3))) + /* free the data, it would be better to re-use the buffer but this + * maintain the code simpler. A smart allocator should re-use the free'd + * buffer in the next malloc without much performance penalties. */ + if (output->ticketNonce.data != output->ticketNonce.dataStatic) { + + /* Callers that avoid syscall should never calls this with + * output->tickeNonce.data being a dynamic buffer.*/ + if (avoidSysCalls) { + WOLFSSL_MSG("can't avoid syscalls with dynamic TicketNonce buffer"); + return WOLFSSL_FAILURE; + } + + XFREE(output->ticketNonce.data, + output->heap, DYNAMIC_TYPE_SESSION_TICK); + output->ticketNonce.data = output->ticketNonce.dataStatic; + output->ticketNonce.len = 0; + } +#endif /* WOLFSSL_TLS13 && WOLFSSL_TICKET_NONCE_MALLOC && FIPS_VERSION_GE(5,3)*/ +#endif /* HAVE_SESSION_TICKET */ #if defined(SESSION_CERTS) && defined(OPENSSL_EXTRA) if (output->peer != NULL) { @@ -20130,6 +20345,12 @@ int wolfSSL_DupSession(const WOLFSSL_SESSION* input, WOLFSSL_SESSION* output, XMEMCPY((byte*)output + copyOffset, (byte*)input + copyOffset, sizeof(WOLFSSL_SESSION) - copyOffset); +#if defined(HAVE_SESSION_TICKET) && defined(WOLFSSL_TLS13) && \ + defined(WOLFSSL_TICKET_NONCE_MALLOC) && \ + (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3))) + /* fix pointer to static after the copy */ + output->ticketNonce.data = output->ticketNonce.dataStatic; +#endif /* Set sane values for copy */ #ifndef NO_SESSION_CACHE if (output->type != WOLFSSL_SESSION_TYPE_CACHE) @@ -20223,10 +20444,74 @@ int wolfSSL_DupSession(const WOLFSSL_SESSION* input, WOLFSSL_SESSION* output, } } ticBuff = NULL; + +#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_TICKET_NONCE_MALLOC) && \ + (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3))) + if (preallocUsed != NULL) + *preallocUsed = 0; + + if (input->ticketNonce.len > MAX_TICKET_NONCE_STATIC_SZ && + ret == WOLFSSL_SUCCESS) { + /* TicketNonce does not fit in the static buffer */ + if (!avoidSysCalls) { + output->ticketNonce.data = (byte*)XMALLOC(input->ticketNonce.len, + output->heap, DYNAMIC_TYPE_SESSION_TICK); + + if (output->ticketNonce.data == NULL) { + WOLFSSL_MSG("Failed to allocate space for ticket nonce"); + output->ticketNonce.data = output->ticketNonce.dataStatic; + output->ticketNonce.len = 0; + ret = WOLFSSL_FAILURE; + } + else { + output->ticketNonce.len = input->ticketNonce.len; + XMEMCPY(output->ticketNonce.data, input->ticketNonce.data, + input->ticketNonce.len); + ret = WOLFSSL_SUCCESS; + } + } + /* we can't do syscalls. Use prealloc buffers if provided from the + * caller. */ + else if (ticketNonceBuf != NULL && + *ticketNonceLen >= input->ticketNonce.len) { + XMEMCPY(ticketNonceBuf, input->ticketNonce.data, + input->ticketNonce.len); + *ticketNonceLen = input->ticketNonce.len; + if (preallocUsed != NULL) + *preallocUsed = 1; + ret = WOLFSSL_SUCCESS; + } + else { + WOLFSSL_MSG("TicketNonce bigger than static buffer, and we can't " + "do syscalls"); + ret = WOLFSSL_FAILURE; + } + } +#endif /* WOLFSSL_TLS13 && WOLFSSL_TICKET_NONCE_MALLOC && FIPS_VERSION_GE(5,3)*/ + #endif /* HAVE_SESSION_TICKET */ return ret; } +/** + * Deep copy the contents from input to output. + * @param input The source of the copy. + * @param output The destination of the copy. + * @param avoidSysCalls If true, then system calls will be avoided or an error + * will be returned if it is not possible to proceed + * without a system call. This is useful for fetching + * sessions from cache. When a cache row is locked, we + * don't want to block other threads with long running + * system calls. + * @return WOLFSSL_SUCCESS on success + * WOLFSSL_FAILURE on failure + */ +int wolfSSL_DupSession(const WOLFSSL_SESSION* input, WOLFSSL_SESSION* output, + int avoidSysCalls) +{ + return wolfSSL_DupSessionEx(input, output, avoidSysCalls, NULL, NULL, NULL); +} + WOLFSSL_SESSION* wolfSSL_SESSION_dup(WOLFSSL_SESSION* session) { #ifdef HAVE_EXT_CACHE @@ -20316,6 +20601,13 @@ void wolfSSL_FreeSession(WOLFSSL_CTX* ctx, WOLFSSL_SESSION* session) if (session->ticketLenAlloc > 0) { XFREE(session->ticket, session->heap, DYNAMIC_TYPE_SESSION_TICK); } +#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_TICKET_NONCE_MALLOC) && \ + (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3))) + if (session->ticketNonce.data != session->ticketNonce.dataStatic) { + XFREE(session->ticketNonce.data, session->heap, + DYNAMIC_TYPE_SESSION_TICK); + } +#endif /* WOLFSSL_TLS13 && WOLFSSL_TICKET_NONCE_MALLOC && FIPS_VERSION_GE(5,3)*/ #endif #ifdef HAVE_EX_DATA_CLEANUP_HOOKS @@ -25764,7 +26056,19 @@ WOLFSSL_SESSION* wolfSSL_d2i_SSL_SESSION(WOLFSSL_SESSION** sess, ret = BUFFER_ERROR; goto end; } +#if defined(WOLFSSL_TICKET_NONCE_MALLOC) && \ + (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3))) + ret = SessionTicketNoncePopulate(s, data + idx, s->ticketNonce.len); + if (ret != 0) + goto end; +#else + if (s->ticketNonce.len > MAX_TICKET_NONCE_STATIC_SZ) { + ret = BUFFER_ERROR; + goto end; + } XMEMCPY(s->ticketNonce.data, data + idx, s->ticketNonce.len); +#endif /* defined(WOLFSSL_TICKET_NONCE_MALLOC) && FIPS_VERSION_GE(5,3) */ + idx += s->ticketNonce.len; #endif #ifdef WOLFSSL_EARLY_DATA diff --git a/src/tls13.c b/src/tls13.c index 87191db85..f44d37329 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -1036,6 +1036,7 @@ int DeriveMasterSecret(WOLFSSL* ssl) #define RESUMPTION_LABEL_SZ 10 /* Resumption label for generating PSK associated with the ticket. */ static const byte resumptionLabel[RESUMPTION_LABEL_SZ+1] = "resumption"; + /* Derive the PSK associated with the ticket. * * ssl The SSL/TLS object. @@ -1078,10 +1079,17 @@ int DeriveResumptionPSK(WOLFSSL* ssl, byte* nonce, byte nonceLen, byte* secret) } PRIVATE_KEY_UNLOCK(); +#if defined(WOLFSSL_TICKET_NONCE_MALLOC) && \ + (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3))) + ret = wc_Tls13_HKDF_Expand_Label_Alloc(secret, ssl->specs.hash_size, + ssl->session->masterSecret, ssl->specs.hash_size, protocol, protocolLen, + resumptionLabel, RESUMPTION_LABEL_SZ, nonce, nonceLen, digestAlg, + ssl->heap); +#else ret = wc_Tls13_HKDF_Expand_Label(secret, ssl->specs.hash_size, - ssl->session->masterSecret, ssl->specs.hash_size, - protocol, protocolLen, resumptionLabel, - RESUMPTION_LABEL_SZ, nonce, nonceLen, digestAlg); + ssl->session->masterSecret, ssl->specs.hash_size, protocol, protocolLen, + resumptionLabel, RESUMPTION_LABEL_SZ, nonce, nonceLen, digestAlg); +#endif /* !defined(HAVE_FIPS) || FIPS_VERSION_GE(5,3) */ PRIVATE_KEY_LOCK(); return ret; } @@ -9181,6 +9189,31 @@ static int DoTls13EndOfEarlyData(WOLFSSL* ssl, const byte* input, #endif /* !NO_WOLFSSL_SERVER */ #endif /* WOLFSSL_EARLY_DATA */ +#if defined(HAVE_SESSION_TICKET) && defined(WOLFSSL_TICKET_NONCE_MALLOC) && \ + (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3))) +int SessionTicketNoncePopulate(WOLFSSL_SESSION *session, const byte *nonce, + byte len) +{ + if (session->ticketNonce.data + != session->ticketNonce.dataStatic) { + XFREE(session->ticketNonce.data, heap, + DYNAMIC_TYPE_SESSION_TICK); + session->ticketNonce.data = session->ticketNonce.dataStatic; + session->ticketNonce.len = 0; + } + + if (len > MAX_TICKET_NONCE_STATIC_SZ) { + WOLFSSL_MSG("Using dynamic nonce buffer"); + session->ticketNonce.data = (byte*)XMALLOC(len, + session->heap, DYNAMIC_TYPE_SESSION_TICK); + if (session->ticketNonce.data == NULL) + return MEMORY_ERROR; + } + XMEMCPY(session->ticketNonce.data, nonce, len); + session->ticketNonce.len = len; + return 0; +} +#endif #ifndef NO_WOLFSSL_CLIENT /* Handle a New Session Ticket handshake message. * Message contains the information required to perform resumption. @@ -9232,11 +9265,14 @@ static int DoTls13NewSessionTicket(WOLFSSL* ssl, const byte* input, if ((*inOutIdx - begin) + 1 > size) return BUFFER_ERROR; nonceLength = input[*inOutIdx]; - if (nonceLength > MAX_TICKET_NONCE_SZ) { +#if !defined(WOLFSSL_TICKET_NONCE_MALLOC) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION_GE(5,3)) + if (nonceLength > MAX_TICKET_NONCE_STATIC_SZ) { WOLFSSL_MSG("Nonce length not supported"); WOLFSSL_ERROR_VERBOSE(INVALID_PARAMETER); return INVALID_PARAMETER; } +#endif /* WOLFSSL_TICKET_NONCE_MALLOC && FIPS_VERSION_GE(5,3) */ *inOutIdx += 1; if ((*inOutIdx - begin) + nonceLength > size) return BUFFER_ERROR; @@ -9268,9 +9304,22 @@ static int DoTls13NewSessionTicket(WOLFSSL* ssl, const byte* input, #ifdef WOLFSSL_EARLY_DATA ssl->session->maxEarlyDataSz = ssl->options.maxEarlyDataSz; #endif + +#if defined(WOLFSSL_TICKET_NONCE_MALLOC) && \ + (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3))) + ret = SessionTicketNoncePopulate(ssl->session, nonce, nonceLength); + if (ret != 0) + return ret; +#else ssl->session->ticketNonce.len = nonceLength; + if (nonceLength > MAX_TICKET_NONCE_STATIC_SZ) { + ret = BUFFER_ERROR; + return ret; + } if (nonceLength > 0) - XMEMCPY(&ssl->session->ticketNonce.data, nonce, nonceLength); + XMEMCPY(ssl->session->ticketNonce.data, nonce, nonceLength); +#endif /* defined(WOLFSSL_TICKET_NONCE_MALLOC) && FIPS_VERSION_GE(5,3) */ + ssl->session->namedGroup = ssl->namedGroup; if ((*inOutIdx - begin) + EXTS_SZ > size) diff --git a/wolfcrypt/src/kdf.c b/wolfcrypt/src/kdf.c index 6de02ac5b..7c144ab89 100644 --- a/wolfcrypt/src/kdf.c +++ b/wolfcrypt/src/kdf.c @@ -437,6 +437,13 @@ int wc_PRF_TLS(byte* digest, word32 digLen, const byte* secret, word32 secLen, int idx = 0; byte data[MAX_TLS13_HKDF_LABEL_SZ]; + /* okmLen (2) + protocol|label len (1) + info len(1) + protocollen + + * labellen + infolen */ + idx = 4 + protocolLen + labelLen + infoLen; + if (idx > MAX_TLS13_HKDF_LABEL_SZ) + return BUFFER_E; + idx = 0; + /* Output length. */ data[idx++] = (byte)(okmLen >> 8); data[idx++] = (byte)okmLen; @@ -481,6 +488,95 @@ int wc_PRF_TLS(byte* digest, word32 digLen, const byte* secret, word32 secLen, return ret; } +#if defined(WOLFSSL_TICKET_NONCE_MALLOC) && \ + (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3))) + /* Expand data using HMAC, salt and label and info. + * TLS v1.3 defines this function. + * + * okm The generated pseudorandom key - output key material. + * okmLen The length of generated pseudorandom key - + * output key material. + * prk The salt - pseudo-random key. + * prkLen The length of the salt - pseudo-random key. + * protocol The TLS protocol label. + * protocolLen The length of the TLS protocol label. + * info The information to expand. + * infoLen The length of the information. + * digest The type of digest to use. + * + * This functions is very similar to wc_Tls13_HKDF_Expand_Label() but it + * allocate memory if the stack space usually used isn't enough. + * + * returns 0 on success, otherwise failure. + */ + int wc_Tls13_HKDF_Expand_Label_Alloc(byte* okm, word32 okmLen, + const byte* prk, word32 prkLen, const byte* protocol, + word32 protocolLen, const byte* label, word32 labelLen, + const byte* info, word32 infoLen, int digest, void* heap) + { + int ret = 0; + int idx = 0; + int len; + byte *data; + + (void)heap; + /* okmLen (2) + protocol|label len (1) + info len(1) + protocollen + + * labellen + infolen */ + len = 4 + protocolLen + labelLen + infoLen; + + data = (byte*)XMALLOC(len, heap, DYNAMIC_TYPE_TMP_BUFFER); + if (data == NULL) + return BUFFER_E; + + /* Output length. */ + data[idx++] = (byte)(okmLen >> 8); + data[idx++] = (byte)okmLen; + /* Length of protocol | label. */ + data[idx++] = (byte)(protocolLen + labelLen); + /* Protocol */ + XMEMCPY(&data[idx], protocol, protocolLen); + idx += protocolLen; + /* Label */ + XMEMCPY(&data[idx], label, labelLen); + idx += labelLen; + /* Length of hash of messages */ + data[idx++] = (byte)infoLen; + /* Hash of messages */ + XMEMCPY(&data[idx], info, infoLen); + idx += infoLen; + + #ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("wc_Tls13_HKDF_Expand_Label data", data, idx); + #endif + +#ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_MSG(" PRK"); + WOLFSSL_BUFFER(prk, prkLen); + WOLFSSL_MSG(" Info"); + WOLFSSL_BUFFER(data, idx); + WOLFSSL_MSG_EX(" Digest %d", digest); +#endif + + ret = wc_HKDF_Expand(digest, prk, prkLen, data, idx, okm, okmLen); + +#ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_MSG(" OKM"); + WOLFSSL_BUFFER(okm, okmLen); +#endif + + ForceZero(data, idx); + + #ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(data, len); + #endif + XFREE(data, heap, DYNAMIC_TYPE_TMP_BUFFER); + return ret; + } + +#endif +/* defined(WOLFSSL_TICKET_NONCE_MALLOC) && (!defined(HAVE_FIPS) || + * FIPS_VERSION_GE(5,3)) */ + #endif /* HAVE_HKDF && !NO_HMAC */ diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 70a7ec037..da353d2db 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -1388,7 +1388,7 @@ enum Misc { SESSION_ADD_SZ = 4, /* session age add */ TICKET_NONCE_LEN_SZ = 1, /* Ticket nonce length size */ DEF_TICKET_NONCE_SZ = 1, /* Default ticket nonce size */ - MAX_TICKET_NONCE_SZ = 8, /* maximum ticket nonce size */ + MAX_TICKET_NONCE_STATIC_SZ = 8, /* maximum ticket nonce static size */ MAX_LIFETIME = 604800, /* maximum ticket lifetime */ RAN_LEN = 32, /* random length */ @@ -1754,6 +1754,10 @@ enum Misc { #define PREALLOC_SESSION_TICKET_LEN 512 #endif +#ifndef PREALLOC_SESSION_TICKET_NONCE_LEN + #define PREALLOC_SESSION_TICKET_NONCE_LEN 32 +#endif + #ifndef SESSION_TICKET_HINT_DEFAULT #define SESSION_TICKET_HINT_DEFAULT 300 #endif @@ -2789,7 +2793,7 @@ typedef struct InternalTicket { byte ageAdd[AGEADD_LEN]; /* Obfuscation of age */ byte namedGroup[NAMEDGROUP_LEN]; /* Named group used */ byte ticketNonceLen; - byte ticketNonce[MAX_TICKET_NONCE_SZ]; + byte ticketNonce[MAX_TICKET_NONCE_STATIC_SZ]; #ifdef WOLFSSL_EARLY_DATA byte maxEarlyDataSz[MAXEARLYDATASZ_LEN]; /* Max size of * early data */ @@ -3693,8 +3697,15 @@ WOLFSSL_LOCAL int wolfSSL_quic_add_transport_extensions(WOLFSSL *ssl, int msg_ty */ typedef struct TicketNonce { byte len; - byte data[MAX_TICKET_NONCE_SZ]; +#if defined(WOLFSSL_TICKET_NONCE_MALLOC) && \ + (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3))) + byte *data; + byte dataStatic[MAX_TICKET_NONCE_STATIC_SZ]; +#else + byte data[MAX_TICKET_NONCE_STATIC_SZ]; +#endif /* WOLFSSL_TICKET_NONCE_MALLOC && FIPS_VERSION_GE(5,3) */ } TicketNonce; + #endif /* wolfSSL session type */ @@ -3790,6 +3801,13 @@ struct WOLFSSL_SESSION { #endif }; +#if defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET) && \ + defined(WOLFSSL_TICKET_NONCE_MALLOC) && \ + (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3))) +WOLFSSL_LOCAL int SessionTicketNoncePopulate(WOLFSSL_SESSION *session, + const byte* nonce, byte len); +#endif /* WOLFSSL_TLS13 && */ + WOLFSSL_LOCAL int wolfSSL_RAND_Init(void); WOLFSSL_LOCAL WOLFSSL_SESSION* wolfSSL_NewSession(void* heap); diff --git a/wolfssl/wolfcrypt/kdf.h b/wolfssl/wolfcrypt/kdf.h index 986fe298a..1d09b9552 100644 --- a/wolfssl/wolfcrypt/kdf.h +++ b/wolfssl/wolfcrypt/kdf.h @@ -85,6 +85,13 @@ WOLFSSL_API int wc_Tls13_HKDF_Expand_Label(byte* okm, word32 okmLen, const byte* label, word32 labelLen, const byte* info, word32 infoLen, int digest); +#if defined(WOLFSSL_TICKET_NONCE_MALLOC) && \ + (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3))) +WOLFSSL_API int wc_Tls13_HKDF_Expand_Label_Alloc(byte* okm, word32 okmLen, + const byte* prk, word32 prkLen, const byte* protocol, word32 protocolLen, + const byte* label, word32 labelLen, const byte* info, word32 infoLen, + int digest, void* heap); +#endif /* !defined(HAVE_FIPS) || FIPS_VERSION_GE(5,3) */ #endif /* HAVE_HKDF */