diff --git a/CMakeLists.txt b/CMakeLists.txt index 7ff3a70ee..91605ca6e 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 2c978f4f2..ab9572e5b 100644 --- a/configure.ac +++ b/configure.ac @@ -4913,6 +4913,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 962bfe842..d79c80fdf 100644 --- a/src/internal.c +++ b/src/internal.c @@ -33982,8 +33982,14 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, #endif /* Resumption master secret. */ XMEMCPY(it->msecret, ssl->session->masterSecret, SECRET_LEN); - XMEMCPY(&it->ticketNonce, &ssl->session->ticketNonce, - sizeof(TicketNonce)); + 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; #endif } @@ -34259,8 +34265,23 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, #endif /* Resumption master secret. */ XMEMCPY(ssl->session->masterSecret, it->msecret, SECRET_LEN); - XMEMCPY(&ssl->session->ticketNonce, &it->ticketNonce, - sizeof(TicketNonce)); + 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; ato16(it->namedGroup, &ssl->session->namedGroup); #endif } diff --git a/src/sniffer.c b/src/sniffer.c index 8afe1b218..83502564f 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 00b156fb6..c9a7d80d1 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) @@ -20026,6 +20209,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" @@ -20088,11 +20275,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; @@ -20102,6 +20294,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); @@ -20116,7 +20311,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) { @@ -20132,6 +20347,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) @@ -20225,10 +20446,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 @@ -20318,6 +20603,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 @@ -25766,7 +26058,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/tests/api.c b/tests/api.c index 10ea1d03e..cf34fb936 100644 --- a/tests/api.c +++ b/tests/api.c @@ -58570,8 +58570,289 @@ static int test_wolfSSL_DTLS_fragment_buckets(void) return 0; } + #endif +#if defined(WOLFSSL_TICKET_NONCE_MALLOC) && defined(HAVE_SESSION_TICKET) \ + && defined(WOLFSSL_TLS13) && \ + (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3))) + +#define TEST_NONCE_BUF_SZ 64 * 1024 +struct test_nonce_ctx +{ + byte c_buff[TEST_NONCE_BUF_SZ]; + int c_len; + byte s_buff[TEST_NONCE_BUF_SZ]; + int s_len; +}; + +static int test_ticket_nonce_write_cb(WOLFSSL *ssl, + char *data, int sz, void *ctx) +{ + struct test_nonce_ctx *test_ctx; + byte *buf; + int *len; + + test_ctx = (struct test_nonce_ctx*)ctx; + + if (ssl->options.side == WOLFSSL_SERVER_END) { + buf = test_ctx->c_buff; + len = &test_ctx->c_len; + } + else { + buf = test_ctx->s_buff; + len = &test_ctx->s_len; + } + + if ((unsigned)(*len + sz) > TEST_NONCE_BUF_SZ) + return WOLFSSL_CBIO_ERR_WANT_READ; + + XMEMCPY(buf + *len, data, sz); + *len += sz; + + return sz; +} + +static int test_ticket_nonce_read_cb(WOLFSSL *ssl, + char *data, int sz, void *ctx) +{ + struct test_nonce_ctx *test_ctx; + int read_sz; + byte *buf; + int *len; + + test_ctx = (struct test_nonce_ctx*)ctx; + + if (ssl->options.side == WOLFSSL_SERVER_END) { + buf = test_ctx->s_buff; + len = &test_ctx->s_len; + } + else { + buf = test_ctx->c_buff; + len = &test_ctx->c_len; + } + + if (*len == 0) + return WOLFSSL_CBIO_ERR_WANT_READ; + + read_sz = sz < *len ? sz : *len; + + XMEMCPY(data, buf, read_sz); + XMEMMOVE(buf, buf + read_sz, *len - read_sz); + + *len -= read_sz; + + return read_sz; +} + +static int send_new_session_ticket(WOLFSSL *ssl, byte nonceLength, byte filler) +{ + struct test_nonce_ctx *test_ctx; + byte buf[2048]; + int idx, sz; + word32 tmp; + int ret; + + idx = 5; /* space for record header */ + + buf[idx] = session_ticket; /* type */ + idx++; + + tmp = OPAQUE32_LEN + + OPAQUE32_LEN + + OPAQUE8_LEN + nonceLength + + OPAQUE16_LEN + OPAQUE8_LEN + OPAQUE16_LEN; + c32to24(tmp, buf + idx); + idx += OPAQUE24_LEN; + + c32toa((word32)12345, buf+idx); /* lifetime */ + idx += OPAQUE32_LEN; + c32toa((word32)12345, buf+idx); /* add */ + idx += OPAQUE32_LEN; + buf[idx] = nonceLength; /* nonce length */ + idx++; + XMEMSET(&buf[idx], filler, nonceLength); /* nonce */ + idx += nonceLength; + tmp = 1; /* ticket len */ + c16toa((word16)tmp, buf+idx); + idx += 2; + buf[idx] = 0xFF; /* ticket */ + idx++; + tmp = 0; /* ext len */ + c16toa((word16)tmp, buf+idx); + idx += 2; + + sz = BuildTls13Message(ssl, buf, 2048, buf+5, idx - 5, + handshake, 0, 0, 0); + test_ctx = (struct test_nonce_ctx*)wolfSSL_GetIOWriteCtx(ssl); + ret = test_ticket_nonce_write_cb(ssl, (char*)buf, sz, test_ctx); + return !(ret == sz); +} + +static int test_ticket_nonce_check(WOLFSSL_SESSION *sess, byte len) +{ + int i; + + if (sess == NULL) + return -1; + + if (sess->ticketNonce.len != len) + return -1; + + for (i = 0; i < len; i++) + if (sess->ticketNonce.data[i] != len) + return -1; + + return 0; +} + +static int test_ticket_nonce_malloc_do(WOLFSSL *ssl_s, WOLFSSL *ssl_c, byte len) +{ + char *buf[1024]; + int ret; + + ret = send_new_session_ticket(ssl_s, len, len); + if (ret != 0) + return -1; + + ret = wolfSSL_recv(ssl_c, buf, 1024, 0); + if (ret != WOLFSSL_SUCCESS && ssl_c->error != WANT_READ) + return -1; + + return test_ticket_nonce_check(ssl_c->session, len); +} + +static int test_ticket_nonce_cache(WOLFSSL *ssl_s, WOLFSSL *ssl_c, byte len) +{ + WOLFSSL_SESSION *sess, *cached; + WOLFSSL_CTX *ctx; + int ret; + + ctx = ssl_c->ctx; + + ret = test_ticket_nonce_malloc_do(ssl_s, ssl_c, len); + if (ret != 0) + return -1; + sess = wolfSSL_get1_session(ssl_c); + if (sess == NULL) + return -1; + + ret = AddSessionToCache(ctx, sess, sess->sessionID, sess->sessionIDSz, + NULL, ssl_c->options.side, 1,NULL); + if (ret != 0) + return -1; + + cached = wolfSSL_SESSION_new(); + if (cached == NULL) + return -1; + + ret = wolfSSL_GetSessionFromCache(ssl_c, cached); + if (ret != WOLFSSL_SUCCESS) + return -1; + + ret = test_ticket_nonce_check(cached, len); + if (ret != 0) + return -1; + + wolfSSL_SESSION_free(cached); + wolfSSL_SESSION_free(sess); + + return 0; +} + +static int test_ticket_nonce_malloc(void) +{ + struct test_nonce_ctx test_ctx = { 0 }; + WOLFSSL_CTX *ctx_c, *ctx_s; + byte small, medium, big; + WOLFSSL *ssl_c, *ssl_s; + int ret; + + ctx_c = wolfSSL_CTX_new(wolfTLSv1_3_client_method()); + ctx_s = wolfSSL_CTX_new(wolfTLSv1_3_server_method()); + if (ctx_c == NULL || ctx_s == NULL) + return -1; + + /* will send ticket manually */ + wolfSSL_CTX_no_ticket_TLSv13(ctx_s); + + wolfSSL_CTX_set_verify(ctx_s, WOLFSSL_VERIFY_NONE, 0); + wolfSSL_CTX_set_verify(ctx_c, WOLFSSL_VERIFY_NONE, 0); + + ret = wolfSSL_CTX_use_PrivateKey_file(ctx_s, svrKeyFile, + WOLFSSL_FILETYPE_PEM); + if (ret != WOLFSSL_SUCCESS) + return- -1; + + ret = wolfSSL_CTX_use_certificate_file(ctx_s, svrCertFile, + WOLFSSL_FILETYPE_PEM); + if (ret != WOLFSSL_SUCCESS) + return -1; + + wolfSSL_SetIORecv(ctx_c, test_ticket_nonce_read_cb); + wolfSSL_SetIOSend(ctx_c, test_ticket_nonce_write_cb); + wolfSSL_SetIORecv(ctx_s, test_ticket_nonce_read_cb); + wolfSSL_SetIOSend(ctx_s, test_ticket_nonce_write_cb); + + ssl_c = wolfSSL_new(ctx_c); + ssl_s = wolfSSL_new(ctx_s); + if (ssl_c == NULL || ssl_s == NULL) + return -1; + + wolfSSL_SetIOWriteCtx(ssl_c, &test_ctx); + wolfSSL_SetIOReadCtx(ssl_c, &test_ctx); + wolfSSL_SetIOWriteCtx(ssl_s, &test_ctx); + wolfSSL_SetIOReadCtx(ssl_s, &test_ctx); + + while (!ssl_c->options.handShakeDone && !ssl_s->options.handShakeDone) { + ret = wolfSSL_connect(ssl_c); + if (ret != WOLFSSL_SUCCESS && ssl_c->error != WANT_READ) + return -2; + + ret = wolfSSL_accept(ssl_s); + if (ret != WOLFSSL_SUCCESS && ssl_s->error != WANT_READ) + return -3; + } + + small = TLS13_TICKET_NONCE_STATIC_SZ; + medium = small + 20 <= 255 ? small + 20 : 255; + big = medium + 20 <= 255 ? small + 20 : 255; + + if (test_ticket_nonce_malloc_do(ssl_s, ssl_c, small)) + return -1; + if (ssl_c->session->ticketNonce.data != + ssl_c->session->ticketNonce.dataStatic) + return -1; + if (test_ticket_nonce_malloc_do(ssl_s, ssl_c, medium)) + return -1; + if (test_ticket_nonce_malloc_do(ssl_s, ssl_c, big)) + return -1; + if (test_ticket_nonce_malloc_do(ssl_s, ssl_c, medium)) + return -5; + if (test_ticket_nonce_malloc_do(ssl_s, ssl_c, small)) + return -6; + + if (test_ticket_nonce_cache(ssl_s, ssl_c, small)) + return -1; + if (test_ticket_nonce_cache(ssl_s, ssl_c, medium)) + return -1; + if (test_ticket_nonce_cache(ssl_s, ssl_c, big)) + return -1; + if (test_ticket_nonce_cache(ssl_s, ssl_c, medium)) + return -1; + if (test_ticket_nonce_cache(ssl_s, ssl_c, small)) + return -1; + + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); + + return 0; +} + +#endif /* WOLFSSL_TICKET_NONCE_MALLOC */ + /*----------------------------------------------------------------------------* | Main *----------------------------------------------------------------------------*/ @@ -59479,7 +59760,11 @@ TEST_CASE testCases[] = { TEST_DECL(test_ForceZero), TEST_DECL(test_wolfSSL_Cleanup), - +#if defined(WOLFSSL_TICKET_NONCE_MALLOC) && defined(HAVE_SESSION_TICKET) \ + && defined(WOLFSSL_TLS13) && \ + (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3))) + TEST_DECL(test_ticket_nonce_malloc), +#endif #if !defined(NO_RSA) && !defined(NO_SHA) && !defined(NO_FILESYSTEM) && \ !defined(NO_CERTS) && (!defined(NO_WOLFSSL_CLIENT) || \ !defined(WOLFSSL_NO_CLIENT_AUTH)) 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 a73676e72..0d6f8de42 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -1298,6 +1298,22 @@ enum { #define DTLS_AEAD_AES_CCM_FAIL_LIMIT w64From32(0x00B5, 0x04F3) #define DTLS_AEAD_AES_CCM_FAIL_KU_LIMIT w64From32(0x005A, 0x8279) +#define TLS13_TICKET_NONCE_MAX_SZ 255 + +#if (defined(HAVE_FIPS) && \ + !(defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3))) && \ + defined(TLS13_TICKET_NONCE_STATIC_SZ) +#error "TLS13_TICKET_NONCE_STATIC_SZ is not supported in this FIPS version" +#endif + +#ifndef TLS13_TICKET_NONCE_STATIC_SZ +#define TLS13_TICKET_NONCE_STATIC_SZ 8 +#endif + +#if TLS13_TICKET_NONCE_STATIC_SZ > TLS13_TICKET_NONCE_MAX_SZ +#error "Max size for ticket nonce is 255 bytes" +#endif + enum Misc { CIPHER_BYTE = 0x00, /* Default ciphers */ ECC_BYTE = 0xC0, /* ECC first cipher suite byte */ @@ -1388,7 +1404,8 @@ 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 = TLS13_TICKET_NONCE_STATIC_SZ, + /* maximum ticket nonce static size */ MAX_LIFETIME = 604800, /* maximum ticket lifetime */ RAN_LEN = 32, /* random length */ @@ -1754,6 +1771,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 @@ -2776,18 +2797,6 @@ WOLFSSL_LOCAL int TLSX_AddEmptyRenegotiationInfo(TLSX** extensions, void* heap); #endif /* HAVE_SECURE_RENEGOTIATION */ -/** Session Ticket - RFC 5077 (session 3.2) */ -#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) -/* Ticket nonce - for deriving PSK. - * Length allowed to be: 1..255. Only support 4 bytes. - * Defined here so that it can be included in InternalTicket. - */ -typedef struct TicketNonce { - byte len; - byte data[MAX_TICKET_NONCE_SZ]; -} TicketNonce; -#endif - #ifdef HAVE_SESSION_TICKET /* Our ticket format. All members need to be a byte or array of byte to * avoid alignment issues */ @@ -2800,7 +2809,8 @@ typedef struct InternalTicket { #ifdef WOLFSSL_TLS13 byte ageAdd[AGEADD_LEN]; /* Obfuscation of age */ byte namedGroup[NAMEDGROUP_LEN]; /* Named group used */ - TicketNonce ticketNonce; /* Ticket nonce */ + byte ticketNonceLen; + byte ticketNonce[MAX_TICKET_NONCE_STATIC_SZ]; #ifdef WOLFSSL_EARLY_DATA byte maxEarlyDataSz[MAXEARLYDATASZ_LEN]; /* Max size of * early data */ @@ -3696,6 +3706,25 @@ WOLFSSL_LOCAL int wolfSSL_quic_add_transport_extensions(WOLFSSL *ssl, int msg_ty #endif /* WOLFSSL_QUIC */ +/** Session Ticket - RFC 5077 (session 3.2) */ +#if defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) +/* Ticket nonce - for deriving PSK. + Length allowed to be: 1..255. Only support + * TLS13_TICKET_NONCE_STATIC_SZ length bytes. + */ +typedef struct TicketNonce { + byte len; +#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 */ struct WOLFSSL_SESSION { /* WARNING Do not add fields here. They will be ignored in @@ -3789,13 +3818,21 @@ 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); WOLFSSL_LOCAL WOLFSSL_SESSION* wolfSSL_GetSession( WOLFSSL* ssl, byte* masterSecret, byte restoreSessionCerts); WOLFSSL_LOCAL void AddSession(WOLFSSL* ssl); -WOLFSSL_LOCAL int AddSessionToCache(WOLFSSL_CTX* ssl, +/* use wolfSSL_API visibility to be able to test in tests/api.c */ +WOLFSSL_API int AddSessionToCache(WOLFSSL_CTX* ssl, WOLFSSL_SESSION* addSession, const byte* id, byte idSz, int* sessionIndex, int side, word16 useTicket, ClientSession** clientCacheEntry); #ifndef NO_CLIENT_CACHE @@ -3805,7 +3842,8 @@ WOLFSSL_LOCAL ClientSession* AddSessionToClientCache(int side, int row, int idx, #endif WOLFSSL_LOCAL WOLFSSL_SESSION* ClientSessionToSession(const WOLFSSL_SESSION* session); -WOLFSSL_LOCAL int wolfSSL_GetSessionFromCache(WOLFSSL* ssl, WOLFSSL_SESSION* output); +/* 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); WOLFSSL_LOCAL void wolfSSL_FreeSession(WOLFSSL_CTX* ctx, WOLFSSL_SESSION* session); 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 */