1
0
mirror of https://github.com/wolfSSL/wolfssl.git synced 2026-10-24 04:09:07 +03:00

ssl_sess: sanitize session cache save and restore, copy full session row, and add unit tests.

This commit is contained in:
jordan
2026-09-21 15:16:48 -05:00
parent 797790b010
commit 5e8c85b489
10 changed files with 1293 additions and 275 deletions

View File

@@ -59,7 +59,7 @@ else
mapfile -t HEADERS < <(
git ls-files 'wolfssl/*.h' 'wolfssl/wolfcrypt/*.h' \
'wolfssl/wolfcrypt/port/**/*.h' 'wolfssl/openssl/*.h' \
| grep -vE '^wolfssl/(options|internal|certs_test|certs_test_sm|debug-trace-error-codes|debug-untrace-error-codes)\.h$' \
| grep -vE '^wolfssl/(options|internal|ssl_sess|certs_test|certs_test_sm|debug-trace-error-codes|debug-untrace-error-codes)\.h$' \
| grep -vE '^wolfssl/wolfcrypt/(fips_test|selftest|tfm)\.h$' \
| grep -vE '^wolfssl/wolfcrypt/port/aria/aria-crypt(ocb)?\.h$' \
| grep -vE '^wolfssl/wolfcrypt/port/autosar/(CryIf|Crypto)\.h$' \

View File

@@ -4790,6 +4790,7 @@ include(GNUInstallDirs)
set(HEADER_EXCLUDE
"internal.h"
"ssl_sess.h"
"wolfssl/wolfcrypt/port/nrf51.h"
"wolfssl/wolfcrypt/port/arm"
"wolfssl/wolfcrypt/port/cypress"

View File

@@ -30,6 +30,14 @@
--disable-tlsv12` and `--enable-dtls --enable-dtls13 --enable-dtlscid
--enable-session-ticket --disable-tlsv12` now build and test cleanly.
* **Behavioral change (`WOLFSSL_CACHE_VERSION` version bump)**:
The `PERSIST_SESSION_CACHE` feature was fixed to now correctly save the
entire session cache, rather than just the first session member of each row.
This changes the on-disk layout of the session cache, and therefore the
`WOLFSSL_CACHE_VERSION` was bumped from v2 to v3 to reflect this change.
Session caches previously saved with v2 (both file and mem) are no longer
restorable.
* **Behavioral change (`wc_PufReadSram` health tests the raw SRAM readout)**:
the raw readout is now health tested before the context accepts it, and a
readout that cannot be SRAM power-on noise is rejected with `PUF_READ_E`

View File

@@ -171,6 +171,7 @@ INCL_TARGS := wolfssl/callbacks.h \
wolfssl/error-ssl.h \
wolfssl/include.am \
wolfssl/internal.h \
wolfssl/ssl_sess.h \
wolfssl/ocsp.h \
wolfssl/options.h \
wolfssl/options.h.in \

View File

@@ -28,87 +28,7 @@
#else
#ifndef NO_SESSION_CACHE
/* basic config gives a cache with 33 sessions, adequate for clients and
embedded servers
TITAN_SESSION_CACHE allows just over 2 million sessions, for servers
with titanic amounts of memory with long session ID timeouts and high
levels of traffic.
ENABLE_SESSION_CACHE_ROW_LOCK: Allows row level locking for increased
performance with large session caches
HUGE_SESSION_CACHE yields 65,791 sessions, for servers under heavy load,
allows over 13,000 new sessions per minute or over 200 new sessions per
second
BIG_SESSION_CACHE yields 20,027 sessions
MEDIUM_SESSION_CACHE allows 1055 sessions, adequate for servers that
aren't under heavy load, basically allows 200 new sessions per minute
SMALL_SESSION_CACHE only stores 6 sessions, good for embedded clients
or systems where the default of is too much RAM.
SessionCache takes about 2K, ClientCache takes about 3Kbytes
MICRO_SESSION_CACHE only stores 1 session, good for embedded clients
or systems where memory is at a premium.
SessionCache takes about 400 bytes, ClientCache takes 576 bytes
default SESSION_CACHE stores 33 sessions (no XXX_SESSION_CACHE defined)
SessionCache takes about 13K bytes, ClientCache takes 17K bytes
*/
#if defined(TITAN_SESSION_CACHE)
#define SESSIONS_PER_ROW 31
#define SESSION_ROWS 64937
#ifndef ENABLE_SESSION_CACHE_ROW_LOCK
#define ENABLE_SESSION_CACHE_ROW_LOCK
#endif
#elif defined(HUGE_SESSION_CACHE)
#define SESSIONS_PER_ROW 11
#define SESSION_ROWS 5981
#elif defined(BIG_SESSION_CACHE)
#define SESSIONS_PER_ROW 7
#define SESSION_ROWS 2861
#elif defined(MEDIUM_SESSION_CACHE)
#define SESSIONS_PER_ROW 5
#define SESSION_ROWS 211
#elif defined(SMALL_SESSION_CACHE)
#define SESSIONS_PER_ROW 2
#define SESSION_ROWS 3
#elif defined(MICRO_SESSION_CACHE)
#define SESSIONS_PER_ROW 1
#define SESSION_ROWS 1
#else
#define SESSIONS_PER_ROW 3
#define SESSION_ROWS 11
#endif
#define INVALID_SESSION_ROW (-1)
#ifdef NO_SESSION_CACHE_ROW_LOCK
#undef ENABLE_SESSION_CACHE_ROW_LOCK
#endif
typedef struct SessionRow {
int nextIdx; /* where to place next one */
int totalCount; /* sessions ever on this row */
word32 cacheGen; /* next entry generation */
#ifdef SESSION_CACHE_DYNAMIC_MEM
WOLFSSL_SESSION* Sessions[SESSIONS_PER_ROW];
void* heap;
#else
WOLFSSL_SESSION Sessions[SESSIONS_PER_ROW];
#endif
#ifdef ENABLE_SESSION_CACHE_ROW_LOCK
/* not included in import/export */
wolfSSL_RwLock row_lock;
int lock_valid;
#endif
} SessionRow;
#define SIZEOF_SESSION_ROW \
(WC_OFFSETOF(SessionRow, Sessions) + sizeof(WOLFSSL_SESSION))
#include <wolfssl/ssl_sess.h>
static WC_THREADSHARED SessionRow SessionCache[SESSION_ROWS];
@@ -129,55 +49,13 @@
#endif
#if !defined(NO_SESSION_CACHE_REF) && defined(NO_CLIENT_CACHE)
#error ClientCache is required when not using NO_SESSION_CACHE_REF
#error ClientCache is required when not using NO_SESSION_CACHE_REF
#endif
#ifndef NO_CLIENT_CACHE
#ifndef CLIENT_SESSIONS_MULTIPLIER
#ifdef NO_SESSION_CACHE_REF
#define CLIENT_SESSIONS_MULTIPLIER 1
#else
/* ClientSession objects are lightweight (compared to
* WOLFSSL_SESSION) so to decrease chance that user will reuse
* the wrong session, increase the ClientCache size. This will
* make the entire ClientCache about the size of one
* WOLFSSL_SESSION object. */
#define CLIENT_SESSIONS_MULTIPLIER 8
#endif
#endif
#define CLIENT_SESSIONS_PER_ROW \
(SESSIONS_PER_ROW * CLIENT_SESSIONS_MULTIPLIER)
#define CLIENT_SESSION_ROWS (SESSION_ROWS * CLIENT_SESSIONS_MULTIPLIER)
#if CLIENT_SESSIONS_PER_ROW > 65535
#error CLIENT_SESSIONS_PER_ROW too big
#endif
#if CLIENT_SESSION_ROWS > 65535
#error CLIENT_SESSION_ROWS too big
#endif
struct ClientSession {
word16 serverRow; /* SessionCache Row id */
word16 serverIdx; /* SessionCache Idx (column) */
word32 sessionIDHash;
word32 cacheGen; /* SessionCache entry generation */
};
#ifndef WOLFSSL_CLIENT_SESSION_DEFINED
typedef struct ClientSession ClientSession;
#define WOLFSSL_CLIENT_SESSION_DEFINED
#endif
typedef struct ClientRow {
int nextIdx; /* where to place next one */
int totalCount; /* sessions ever on this row */
ClientSession Clients[CLIENT_SESSIONS_PER_ROW];
} ClientRow;
static WC_THREADSHARED ClientRow ClientCache[CLIENT_SESSION_ROWS];
/* Client Cache */
/* uses session mutex */
/* ClientCache mutex */
static WC_THREADSHARED wolfSSL_Mutex clisession_mutex
WOLFSSL_MUTEX_INITIALIZER_CLAUSE(clisession_mutex);
@@ -188,31 +66,31 @@
void EvictSessionFromCache(WOLFSSL_SESSION* session)
{
#ifdef HAVE_EX_DATA
#ifdef HAVE_EX_DATA
byte 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)
#endif /* HAVE_EX_DATA */
#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
#endif /* HAVE_EXT_CACHE || HAVE_EX_DATA */
ForceZero(session->masterSecret, SECRET_LEN);
XMEMSET(session->sessionID, 0, ID_LEN);
session->sessionIDSz = 0;
#ifdef HAVE_SESSION_TICKET
#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
#endif /* HAVE_SESSION_TICKET */
#ifdef HAVE_EX_DATA
session->ownExData = save_ownExData;
#endif
#endif /* HAVE_EX_DATA */
#if defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET) && \
defined(WOLFSSL_TICKET_NONCE_MALLOC) && \
@@ -394,40 +272,16 @@ int wolfSSL_SetServerID(WOLFSSL* ssl, const byte* id, int len, int newSession)
* cache.
*/
#if defined(PERSIST_SESSION_CACHE) && !defined(SESSION_CACHE_DYNAMIC_MEM)
/* for persistence, if changes to layout need to increment and modify
save_session_cache() and restore_session_cache and memory versions too */
#define WOLFSSL_CACHE_VERSION 3
/* Session Cache Header information */
typedef struct {
int version; /* cache layout version id */
int rows; /* session rows */
int columns; /* session columns */
int sessionSz; /* sizeof WOLFSSL_SESSION */
} cache_header_t;
/* current persistence layout is:
1) cache_header_t
2) SessionCache
3) ClientCache
update WOLFSSL_CACHE_VERSION if change layout for the following
PERSISTENT_SESSION_CACHE functions
*/
/* get how big the the session cache save buffer needs to be */
int wolfSSL_get_session_cache_memsize(void)
{
int sz = (int)(sizeof(SessionCache) + sizeof(cache_header_t));
#ifndef NO_CLIENT_CACHE
#ifndef NO_CLIENT_CACHE
sz += (int)(sizeof(ClientCache));
#endif
#endif
return sz;
}
/* Persist session cache to memory */
int wolfSSL_memsave_session_cache(void* mem, int sz)
{
@@ -441,25 +295,26 @@ int wolfSSL_memsave_session_cache(void* mem, int sz)
return BAD_FUNC_ARG;
}
row = (SessionRow*)((byte*)mem + sizeof(cache_header));
if (sz < wolfSSL_get_session_cache_memsize()) {
WOLFSSL_MSG("Memory buffer too small");
return BUFFER_E;
}
XMEMSET(mem, 0, sz);
row = (SessionRow*)((byte*)mem + sizeof(cache_header));
cache_header.version = WOLFSSL_CACHE_VERSION;
cache_header.rows = SESSION_ROWS;
cache_header.columns = SESSIONS_PER_ROW;
cache_header.sessionSz = (int)sizeof(WOLFSSL_SESSION);
XMEMCPY(mem, &cache_header, sizeof(cache_header));
#ifndef ENABLE_SESSION_CACHE_ROW_LOCK
#ifndef ENABLE_SESSION_CACHE_ROW_LOCK
if (SESSION_ROW_RD_LOCK(row) != 0) {
WOLFSSL_MSG("Session cache mutex lock failed");
return BAD_MUTEX_E;
}
#endif
#endif
for (i = 0; i < cache_header.rows; ++i) {
#ifdef ENABLE_SESSION_CACHE_ROW_LOCK
if (SESSION_ROW_RD_LOCK(&SessionCache[i]) != 0) {
@@ -473,62 +328,144 @@ int wolfSSL_memsave_session_cache(void* mem, int sz)
SESSION_ROW_UNLOCK(&SessionCache[i]);
#endif
}
#ifndef ENABLE_SESSION_CACHE_ROW_LOCK
#ifndef ENABLE_SESSION_CACHE_ROW_LOCK
SESSION_ROW_UNLOCK(row);
#endif
#endif
#ifndef NO_CLIENT_CACHE
#ifndef NO_CLIENT_CACHE
if (wc_LockMutex(&clisession_mutex) != 0) {
WOLFSSL_MSG("Client cache mutex lock failed");
return BAD_MUTEX_E;
}
XMEMCPY(row, ClientCache, sizeof(ClientCache));
wc_UnLockMutex(&clisession_mutex);
#endif
#endif
WOLFSSL_LEAVE("wolfSSL_memsave_session_cache", WOLFSSL_SUCCESS);
return WOLFSSL_SUCCESS;
}
#if !defined(SESSION_CACHE_DYNAMIC_MEM) && \
(defined(HAVE_SESSION_TICKET) || \
(defined(SESSION_CERTS) && defined(OPENSSL_EXTRA)))
static void SessionSanityPointerSet(SessionRow* row)
/* attempt to sanitize a restored session row:
* - shallow copy pointers are nulled, and ex_data is zeroed.
* - ticket len is clamped
* - fields that cannot be meaningfully sanitized will error out if invalid.
*
* returns 0 on success
* returns -1 on error
* */
static int SessionSanityPointerSet(int row)
{
int j;
SessionRow * srow = NULL;
int ret = 0;
int j;
/* Reset pointers to safe values after raw copy */
if (row < 0 || row >= SESSION_ROWS) {
WOLFSSL_MSG_EX("session sanity: bad row index: %d", row);
return -1;
}
srow = &SessionCache[row];
if (srow->nextIdx < 0 || srow->nextIdx >= SESSIONS_PER_ROW) {
WOLFSSL_MSG_EX("session sanity: bad row cache index: %d",
srow->nextIdx);
srow->nextIdx = 0;
ret = -1;
}
if (srow->totalCount < 0 || srow->totalCount > SESSIONS_PER_ROW) {
WOLFSSL_MSG_EX("session sanity: bad row cotal count: %d",
srow->totalCount);
srow->totalCount = 0;
ret = -1;
}
/* Reset pointers to safe values after raw copy.
* Don't break early on error, we always sanitize the entire row. */
for (j = 0; j < SESSIONS_PER_ROW; j++) {
WOLFSSL_SESSION* s = &row->Sessions[j];
#ifdef HAVE_SESSION_TICKET
WOLFSSL_SESSION * s = &srow->Sessions[j];
/* set type and cacheRow index */
s->type = WOLFSSL_SESSION_TYPE_CACHE;
s->cacheRow = row;
/* clamp ticketLen */
#ifdef HAVE_SESSION_TICKET
s->ticket = s->staticTicket;
s->ticketLenAlloc = 0;
if (s->ticketLen > SESSION_TICKET_LEN) {
s->ticketLen = SESSION_TICKET_LEN;
}
#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)))
#endif /* HAVE_SESSION_TICKET */
#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)))
s->ticketNonce.data = s->ticketNonce.dataStatic;
if (s->ticketNonce.len > MAX_TICKET_NONCE_STATIC_SZ) {
s->ticketNonce.len = MAX_TICKET_NONCE_STATIC_SZ;
}
#endif
#if defined(SESSION_CERTS) && defined(OPENSSL_EXTRA)
#endif /* WOLFSSL_TLS13 && HAVE_SESSION_TICKET && etc. */
#ifdef SESSION_CERTS
if (s->chain.count < 0 || s->chain.count > MAX_CHAIN_DEPTH) {
WOLFSSL_MSG_EX("session sanity: bad chain count: %d",
s->chain.count);
s->chain.count = 0;
ret = -1;
}
if (s->chain.count) {
int k;
for (k = 0; k < s->chain.count; ++k) {
if (s->chain.certs[k].length < 0 ||
s->chain.certs[k].length > MAX_X509_SIZE) {
WOLFSSL_MSG_EX("session sanity: cert[%d] bad length: %d",
k, s->chain.certs[k].length);
ret = -1;
}
}
}
#endif /* SESSION_CERTS */
#ifdef WOLFSSL_SESSION_ID_CTX
/* sessionCtx is deep copied, but can't exceed ID_LEN. */
if (s->sessionCtxSz > ID_LEN) {
WOLFSSL_MSG_EX("session sanity: sessionCtxSz: %d",
s->sessionCtxSz);
ret = -1;
}
#endif /* WOLFSSL_SESSION_ID_CTX */
/* Sanitize the restored session: none of the following fields are
* meaningful after session restoration.
*
* We could null these instead in wolfSSL_[mem]save_session_cache(),
* but that would require an extra scratch copy (because we save from
* the live session). */
#if defined(SESSION_CERTS) && defined(OPENSSL_EXTRA)
s->peer = NULL;
#endif
#endif /* SESSION_CERTS && OPENSSL_EXTRA */
#if defined(HAVE_EXT_CACHE) || defined(HAVE_EX_DATA)
s->rem_sess_cb = NULL;
#endif /* HAVE_EXT_CACHE || HAVE_EX_DATA */
s->heap = NULL;
#ifdef HAVE_EX_DATA
XMEMSET(&s->ex_data, 0, sizeof(WOLFSSL_CRYPTO_EX_DATA));
s->ownExData = 1;
#endif /* HAVE_EX_DATA */
}
return ret;
}
#endif
/* Restore the persistent session cache from memory */
int wolfSSL_memrestore_session_cache(const void* mem, int sz)
{
int i;
word32 cacheGen;
int ret = 0;
cache_header_t cache_header;
SessionRow* row;
@@ -555,12 +492,12 @@ int wolfSSL_memrestore_session_cache(const void* mem, int sz)
return CACHE_MATCH_ERROR;
}
#ifndef ENABLE_SESSION_CACHE_ROW_LOCK
#ifndef ENABLE_SESSION_CACHE_ROW_LOCK
if (SESSION_ROW_WR_LOCK(&SessionCache[0]) != 0) {
WOLFSSL_MSG("Session cache mutex lock failed");
return BAD_MUTEX_E;
}
#endif
#endif
for (i = 0; i < cache_header.rows; ++i) {
#ifdef ENABLE_SESSION_CACHE_ROW_LOCK
if (SESSION_ROW_WR_LOCK(&SessionCache[i]) != 0) {
@@ -576,31 +513,42 @@ int wolfSSL_memrestore_session_cache(const void* mem, int sz)
* the restored ClientCache entries were issued against. */
if (SessionCache[i].cacheGen < cacheGen)
SessionCache[i].cacheGen = cacheGen;
#if !defined(SESSION_CACHE_DYNAMIC_MEM) && \
(defined(HAVE_SESSION_TICKET) || \
(defined(SESSION_CERTS) && defined(OPENSSL_EXTRA)))
SessionSanityPointerSet(&SessionCache[i]);
#endif
ret = SessionSanityPointerSet(i);
#ifdef ENABLE_SESSION_CACHE_ROW_LOCK
SESSION_ROW_UNLOCK(&SessionCache[i]);
#endif
if (ret) {
/* session data is corrupted
* Wiping the rows must not restart the generation counters. */
int j;
for (j = 0; j < SESSION_ROWS; j++) {
cacheGen = SessionCache[j].cacheGen;
XMEMSET(&SessionCache[j], 0, sizeof(SessionCache[j]));
SessionCache[j].cacheGen = cacheGen;
}
break;
}
}
#ifndef ENABLE_SESSION_CACHE_ROW_LOCK
#ifndef ENABLE_SESSION_CACHE_ROW_LOCK
SESSION_ROW_UNLOCK(&SessionCache[0]);
#endif
#endif
#ifndef NO_CLIENT_CACHE
if (wc_LockMutex(&clisession_mutex) != 0) {
WOLFSSL_MSG("Client cache mutex lock failed");
return BAD_MUTEX_E;
if (ret == 0) {
#ifndef NO_CLIENT_CACHE
if (wc_LockMutex(&clisession_mutex) != 0) {
WOLFSSL_MSG("Client cache mutex lock failed");
return BAD_MUTEX_E;
}
XMEMCPY(ClientCache, row, sizeof(ClientCache));
wc_UnLockMutex(&clisession_mutex);
#endif
}
XMEMCPY(ClientCache, row, sizeof(ClientCache));
wc_UnLockMutex(&clisession_mutex);
#endif
WOLFSSL_LEAVE("wolfSSL_memrestore_session_cache", WOLFSSL_SUCCESS);
WOLFSSL_LEAVE("wolfSSL_memrestore_session_cache",
ret == 0 ? WOLFSSL_SUCCESS : WOLFSSL_FAILURE);
return WOLFSSL_SUCCESS;
return ret == 0 ? WOLFSSL_SUCCESS : WOLFSSL_FAILURE;
}
#if !defined(NO_FILESYSTEM)
@@ -635,13 +583,13 @@ int wolfSSL_save_session_cache(const char *fname)
return FWRITE_ERROR;
}
#ifndef ENABLE_SESSION_CACHE_ROW_LOCK
#ifndef ENABLE_SESSION_CACHE_ROW_LOCK
if (SESSION_ROW_RD_LOCK(&SessionCache[0]) != 0) {
WOLFSSL_MSG("Session cache mutex lock failed");
XFCLOSE(file);
return BAD_MUTEX_E;
}
#endif
#endif
/* session cache */
for (i = 0; i < cache_header.rows; ++i) {
#ifdef ENABLE_SESSION_CACHE_ROW_LOCK
@@ -662,11 +610,11 @@ int wolfSSL_save_session_cache(const char *fname)
break;
}
}
#ifndef ENABLE_SESSION_CACHE_ROW_LOCK
#ifndef ENABLE_SESSION_CACHE_ROW_LOCK
SESSION_ROW_UNLOCK(&SessionCache[0]);
#endif
#endif
#ifndef NO_CLIENT_CACHE
#ifndef NO_CLIENT_CACHE
/* client cache */
if (wc_LockMutex(&clisession_mutex) != 0) {
WOLFSSL_MSG("Client cache mutex lock failed");
@@ -679,7 +627,7 @@ int wolfSSL_save_session_cache(const char *fname)
rc = FWRITE_ERROR;
}
wc_UnLockMutex(&clisession_mutex);
#endif /* !NO_CLIENT_CACHE */
#endif /* !NO_CLIENT_CACHE */
XFCLOSE(file);
WOLFSSL_LEAVE("wolfSSL_save_session_cache", rc);
@@ -687,7 +635,6 @@ int wolfSSL_save_session_cache(const char *fname)
return rc;
}
/* Restore the persistent session cache from file */
/* doesn't use memstore because of additional memory use */
int wolfSSL_restore_session_cache(const char *fname)
@@ -703,13 +650,14 @@ int wolfSSL_restore_session_cache(const char *fname)
file = XFOPEN(fname, "rb");
if (file == XBADFILE) {
WOLFSSL_MSG("Couldn't open session cache save file");
WOLFSSL_MSG_EX("Couldn't open session cache save file: %s", fname);
return WOLFSSL_BAD_FILE;
}
/* cache header */
ret = (int)XFREAD(&cache_header, sizeof(cache_header), 1, file);
if (ret != 1) {
WOLFSSL_MSG("Session cache header file read failed");
WOLFSSL_MSG_EX("Session cache header file read failed: %s: %d", fname,
ret);
XFCLOSE(file);
return FREAD_ERROR;
}
@@ -718,18 +666,18 @@ int wolfSSL_restore_session_cache(const char *fname)
cache_header.columns != SESSIONS_PER_ROW ||
cache_header.sessionSz != (int)sizeof(WOLFSSL_SESSION)) {
WOLFSSL_MSG("Session cache header match failed");
WOLFSSL_MSG_EX("Session cache header match failed: %s", fname);
XFCLOSE(file);
return CACHE_MATCH_ERROR;
}
#ifndef ENABLE_SESSION_CACHE_ROW_LOCK
#ifndef ENABLE_SESSION_CACHE_ROW_LOCK
if (SESSION_ROW_WR_LOCK(&SessionCache[0]) != 0) {
WOLFSSL_MSG("Session cache mutex lock failed");
XFCLOSE(file);
return BAD_MUTEX_E;
}
#endif
#endif
/* session cache */
for (i = 0; i < cache_header.rows; ++i) {
#ifdef ENABLE_SESSION_CACHE_ROW_LOCK
@@ -742,51 +690,61 @@ int wolfSSL_restore_session_cache(const char *fname)
cacheGen = SessionCache[i].cacheGen;
ret = (int)XFREAD(&SessionCache[i], SIZEOF_SESSION_ROW, 1, file);
if (ret != 1) {
WOLFSSL_MSG("Session cache member file read failed");
rc = FREAD_ERROR;
}
/* Generations already handed to live handles must not be reissued.
* The entry keeps the one it was saved with, which is the generation
* the restored ClientCache entries were issued against. */
if (ret != 1 || SessionCache[i].cacheGen < cacheGen)
if (rc != WOLFSSL_SUCCESS || SessionCache[i].cacheGen < cacheGen) {
SessionCache[i].cacheGen = cacheGen;
#if !defined(SESSION_CACHE_DYNAMIC_MEM) && \
(defined(HAVE_SESSION_TICKET) || \
(defined(SESSION_CERTS) && defined(OPENSSL_EXTRA)))
SessionSanityPointerSet(&SessionCache[i]);
#endif
}
if (rc == WOLFSSL_SUCCESS) {
/* file read success. now sanitize the imported session row. */
ret = SessionSanityPointerSet(i);
if (ret) {
/* session data is corrupted */
rc = WOLFSSL_FAILURE;
}
}
#ifdef ENABLE_SESSION_CACHE_ROW_LOCK
SESSION_ROW_UNLOCK(&SessionCache[i]);
#endif
if (ret != 1) {
if (rc != WOLFSSL_SUCCESS) {
int j;
WOLFSSL_MSG("Session cache member file read failed");
/* Wiping the rows must not restart the generation counters. */
for (j = 0; j < SESSION_ROWS; j++) {
cacheGen = SessionCache[j].cacheGen;
XMEMSET(&SessionCache[j], 0, sizeof(SessionCache[j]));
SessionCache[j].cacheGen = cacheGen;
}
rc = FREAD_ERROR;
break;
}
}
#ifndef ENABLE_SESSION_CACHE_ROW_LOCK
#ifndef ENABLE_SESSION_CACHE_ROW_LOCK
SESSION_ROW_UNLOCK(&SessionCache[0]);
#endif
#endif
#ifndef NO_CLIENT_CACHE
/* client cache */
if (wc_LockMutex(&clisession_mutex) != 0) {
WOLFSSL_MSG("Client cache mutex lock failed");
XFCLOSE(file);
return BAD_MUTEX_E;
if (rc == WOLFSSL_SUCCESS) {
#ifndef NO_CLIENT_CACHE
/* client cache */
if (wc_LockMutex(&clisession_mutex) != 0) {
WOLFSSL_MSG("Client cache mutex lock failed");
XFCLOSE(file);
return BAD_MUTEX_E;
}
ret = (int)XFREAD(ClientCache, sizeof(ClientCache), 1, file);
if (ret != 1) {
WOLFSSL_MSG("Client cache member file read failed");
XMEMSET(ClientCache, 0, sizeof ClientCache);
rc = FREAD_ERROR;
}
wc_UnLockMutex(&clisession_mutex);
#endif /* !NO_CLIENT_CACHE */
}
ret = (int)XFREAD(ClientCache, sizeof(ClientCache), 1, file);
if (ret != 1) {
WOLFSSL_MSG("Client cache member file read failed");
XMEMSET(ClientCache, 0, sizeof ClientCache);
rc = FREAD_ERROR;
}
wc_UnLockMutex(&clisession_mutex);
#endif /* !NO_CLIENT_CACHE */
XFCLOSE(file);
WOLFSSL_LEAVE("wolfSSL_restore_session_cache", rc);
@@ -797,7 +755,6 @@ int wolfSSL_restore_session_cache(const char *fname)
#endif /* !NO_FILESYSTEM */
#endif /* PERSIST_SESSION_CACHE && !SESSION_CACHE_DYNAMIC_MEM */
/* on by default if built in but allow user to turn off */
WOLFSSL_ABI
long wolfSSL_CTX_set_session_cache_mode(WOLFSSL_CTX* ctx, long mode)
@@ -1058,8 +1015,9 @@ WOLFSSL_SESSION* wolfSSL_GetSessionClient(WOLFSSL* ssl, const byte* id, int len)
WOLFSSL_SESSION* current;
SessionRow* sessRow;
if (clSess[idx].serverRow >= SESSION_ROWS) {
WOLFSSL_MSG("Client cache serverRow invalid");
if (clSess[idx].serverRow >= SESSION_ROWS ||
clSess[idx].serverIdx >= SESSIONS_PER_ROW ) {
WOLFSSL_MSG("Client cache serverRow or serverIdx invalid");
break;
}
@@ -1070,11 +1028,11 @@ WOLFSSL_SESSION* wolfSSL_GetSessionClient(WOLFSSL* ssl, const byte* id, int len)
break;
}
#ifdef SESSION_CACHE_DYNAMIC_MEM
#ifdef SESSION_CACHE_DYNAMIC_MEM
current = sessRow->Sessions[clSess[idx].serverIdx];
#else
#else
current = &sessRow->Sessions[clSess[idx].serverIdx];
#endif
#endif
/* Require the same length as well as the same bytes. Comparing only
* the requested length lets a short ID alias the prefix of a longer
* cached one, mixing sessions the application meant to keep apart. */
@@ -1556,7 +1514,8 @@ int wolfSSL_SetSession(WOLFSSL* ssl, WOLFSSL_SESSION* session)
/* 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) {
if (session->cacheRow != INVALID_SESSION_ROW &&
session->cacheRow < SESSION_ROWS) {
sessRow = &SessionCache[session->cacheRow];
if (SESSION_ROW_RD_LOCK(sessRow) != 0) {
WOLFSSL_MSG("Session row lock failed");
@@ -1983,11 +1942,11 @@ int AddSessionToCache(WOLFSSL_CTX* ctx, WOLFSSL_SESSION* addSession,
}
for (i = 0; i < SESSIONS_PER_ROW && i < sessRow->totalCount; i++) {
#ifdef SESSION_CACHE_DYNAMIC_MEM
#ifdef SESSION_CACHE_DYNAMIC_MEM
cacheSession = sessRow->Sessions[i];
#else
#else
cacheSession = &sessRow->Sessions[i];
#endif
#endif
if (cacheSession && XMEMCMP(id,
cacheSession->sessionID, ID_LEN) == 0 &&
cacheSession->side == side) {
@@ -2000,6 +1959,22 @@ int AddSessionToCache(WOLFSSL_CTX* ctx, WOLFSSL_SESSION* addSession,
if (!overwrite)
idx = (word32)sessRow->nextIdx;
if (idx >= SESSIONS_PER_ROW) {
/* bad index, possible corrupted session cache memory.
* reset index to a safe value, unlock the row, and return error. */
#ifdef HAVE_SESSION_TICKET
XFREE(ticBuff, 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)))
XFREE(preallocNonce, addSession->heap, DYNAMIC_TYPE_SESSION_TICK);
#endif
#endif
WOLFSSL_MSG_EX("Invalid session cache index: %d", idx);
sessRow->nextIdx = 0;
SESSION_ROW_UNLOCK(sessRow);
return MEMORY_E;
}
#ifdef SESSION_INDEX
if (sessionIndex != NULL)
*sessionIndex = (row << SESSIDX_ROW_SHIFT) | idx;

View File

@@ -1933,3 +1933,840 @@ int test_wolfSSL_client_cache_id_overwrite(void)
#endif
return EXPECT_RESULT();
}
#if defined(PERSIST_SESSION_CACHE) && !defined(NO_SESSION_CACHE) && \
!defined(SESSION_CACHE_DYNAMIC_MEM) && !defined(TITAN_SESSION_CACHE) && \
!defined(HUGE_SESSION_CACHE)
/* Several tests to ensure persistent session cache is saved and restored
* with expected behavior. */
#include <wolfssl/ssl_sess.h>
#if (defined(HAVE_EXT_CACHE) || defined(HAVE_EX_DATA))
static int test_rem_sess_cb_count = 0;
static void test_rem_sess_cb(WOLFSSL_CTX* ctx, WOLFSSL_SESSION* sess)
{
(void)ctx; (void)sess;
WOLFSSL_MSG_EX("info: test test_rem_sess_cb called: %d",
test_rem_sess_cb_count);
test_rem_sess_cb_count++;
}
#endif /* HAVE_EXT_CACHE || HAVE_EX_DATA */
struct sess_cache_t {
cache_header_t hdr;
SessionRow s_rows[SESSION_ROWS];
#ifndef NO_CLIENT_CACHE
ClientRow c_rows[CLIENT_SESSION_ROWS];
#endif /* !NO_CLIENT_CACHE */
};
typedef struct sess_cache_t sess_cache_t;
/* Set the session cache to canary values for testing.
* Will be checked later in test_sanity_sessions(). */
static void test_set_sessions(sess_cache_t * cache_mem)
{
size_t i = 0;
size_t j = 0;
for (i = 0; i < SESSION_ROWS; ++i) {
SessionRow * row = &cache_mem->s_rows[i];
for (j = 0; j < SESSIONS_PER_ROW; ++j) {
WOLFSSL_SESSION * s = &row->Sessions[j];
s->timeout = 1;
s->bornOn = 0;
/* label sessions with something predictable */
s->sessionIDSz = 2;
s->sessionID[0] = (byte)i;
s->sessionID[1] = (byte)j;
/* set type, ticketLen, rem_sess_cb, heap, peer, etc to test
* canary values. These should be sanitized on session restore. */
s->type = WOLFSSL_SESSION_TYPE_UNKNOWN;
#ifdef HAVE_SESSION_TICKET
s->ticketLen = SESSION_TICKET_LEN + 1;
s->ticketLenAlloc = 1;
#endif /* HAVE_SESSION_TICKET */
#if defined(HAVE_EXT_CACHE) || defined(HAVE_EX_DATA)
s->rem_sess_cb = test_rem_sess_cb;
#endif /* HAVE_EXT_CACHE || HAVE_EX_DATA */
s->heap = (void *)0x77;
#if defined(SESSION_CERTS) && defined(OPENSSL_EXTRA)
s->peer = (WOLFSSL_X509 *)0x77;
#endif /* SESSION_CERTS && OPENSSL_EXTRA */
#ifdef HAVE_EX_DATA
XMEMSET(&s->ex_data, 0x77, sizeof(WOLFSSL_CRYPTO_EX_DATA));
s->ownExData = 1;
#endif /* HAVE_EX_DATA */
}
}
}
#define field_null_or_fail(what, s, name, fld) do { \
if ((s)->fld != NULL) { \
WOLFSSL_MSG_EX("error: %s: s = %p, id = 0x%02x%02x, %s = %p", \
(what), (s), (s)->sessionID[0], (s)->sessionID[1], \
(name), (s)->fld); \
ret = -1; \
goto sanity_fail; \
} \
} while (0)
/* sanity check the restored session cache.
* return 0 on success
* return -1 on error */
static int test_sanity_sessions(const sess_cache_t * cache_mem,
const char * what)
{
int ret = -1;
size_t i = 0;
size_t j = 0;
(void)what; /* only used in WOLFSSL_MSG_EX */
/* walk sessions, check for expected values */
for (i = 0; i < SESSION_ROWS; ++i) {
const SessionRow * row = &cache_mem->s_rows[i];
for (j = 0; j < SESSIONS_PER_ROW; ++j) {
const WOLFSSL_SESSION * s = &row->Sessions[j];
#ifdef HAVE_EX_DATA
const WOLFSSL_CRYPTO_EX_DATA * ex_data = &s->ex_data;
size_t k = 0;
#endif /* HAVE_EX_DATA */
#ifdef HAVE_SESSION_TICKET
if (s->ticketLenAlloc != 0 ||
s->ticketLen > SESSION_TICKET_LEN) {
WOLFSSL_MSG_EX("error: %s: s = %p, id = 0x%02x%02x: "
"ticketLenAlloc = %d, ticketLen = %d\n",
what, s,
s->sessionID[0], s->sessionID[1],
s->ticketLenAlloc, s->ticketLen);
ret = -1;
goto sanity_fail;
}
#endif /* HAVE_SESSION_TICKET */
if (s->type != WOLFSSL_SESSION_TYPE_CACHE) {
WOLFSSL_MSG_EX("error: %s: s = %p, id = 0x%02x%02x: "
"type not cache: 0x%02x", what, s,
s->sessionID[0], s->sessionID[1],
s->type);
ret = -1;
goto sanity_fail;
}
if (s->sessionIDSz != 2) {
WOLFSSL_MSG_EX("error: %s: s = %p: got id sz = %d"
", expected id sz = 2", what,
s, s->sessionIDSz);
ret = -1;
goto sanity_fail;
}
if (s->sessionID[0] != (byte)i ||
s->sessionID[1] != (byte)j) {
WOLFSSL_MSG_EX("error: %s: s = %p, got id = 0x%02x%02x:"
", expected id = 0x%02x%02x", what, s,
s->sessionID[0], s->sessionID[1],
(byte)i, (byte)j);
ret = -1;
goto sanity_fail;
}
/* all the remaining fields should have been sanitized as null */
field_null_or_fail(what, s, "heap", heap);
#if defined(SESSION_CERTS) && defined(OPENSSL_EXTRA)
field_null_or_fail(what, s, "peer", peer);
#endif /* SESSION_CERTS && OPENSSL_EXTRA */
#if defined(HAVE_EXT_CACHE) || defined(HAVE_EX_DATA)
field_null_or_fail(what, s, "rem_sess_cb", rem_sess_cb);
#endif /* HAVE_EXT_CACHE || HAVE_EX_DATA */
#ifdef HAVE_EX_DATA
/* The sane default ex_data state is:
* - s->ownExData == 1
* - s->ex_data* zeroed. */
if (s->ownExData != 1) {
WOLFSSL_MSG_EX("error: s = %p, id = 0x%02x%02x, ownExData = %d",
s, s->sessionID[0], s->sessionID[1],
s->ownExData);
ret = -1;
goto sanity_fail;
}
for (k = 0; k < MAX_EX_DATA; ++k) {
if (ex_data->ex_data[k]
#ifdef HAVE_EX_DATA_CLEANUP_HOOKS
|| ex_data->ex_data_cleanup_routines[k]
#endif /* HAVE_EX_DATA_CLEANUP_HOOKS */
) {
WOLFSSL_MSG_EX("error: s = %p, id = 0x%02x%02x:"
"ex_data[%zu] not null", s,
s->sessionID[0], s->sessionID[1], k);
ret = -1;
goto sanity_fail;
}
} /* for k */
#endif /* HAVE_EX_DATA */
} /* for j */
} /* for i */
ret = 0;
sanity_fail:
return ret;
}
/* Tests mem[save, restore]_session_cache.
*
* returns -1 on err
* returns 0 on success
* */
static int test_mem_session_cache(void)
{
int ret = -1;
int mem_sz = 0;
sess_cache_t * cache_mem = NULL;
#ifndef NO_CLIENT_CACHE
ClientRow * c_rows = NULL;
#endif /* !NO_CLIENT_CACHE */
int rst_err = 0;
#if !defined(BIG_SESSION_CACHE) && !defined(MEDIUM_SESSION_CACHE)
int i = 0;
#endif /* !BIG_SESSION_CACHE && !MEDIUM_SESSION_CACHE */
#if (defined(HAVE_EXT_CACHE) || defined(HAVE_EX_DATA))
/* reset callback count */
test_rem_sess_cb_count = 0;
#endif /* HAVE_EXT_CACHE || HAVE_EX_DATA */
/* get session cache size, and allocate scratch copy */
mem_sz = wolfSSL_get_session_cache_memsize();
if (mem_sz != sizeof(sess_cache_t)) {
WOLFSSL_MSG_EX("error: got mem_sz %d, expected %zu\n", mem_sz,
sizeof(sess_cache_t));
return -1;
}
cache_mem = (sess_cache_t *)XMALLOC((size_t)mem_sz, NULL,
DYNAMIC_TYPE_TMP_BUFFER);
if (cache_mem == NULL) {
WOLFSSL_MSG_EX("error: xmalloc(%zu) failed", (size_t) mem_sz);
return -1;
}
XMEMSET(cache_mem, 0, sizeof(sess_cache_t));
#ifndef NO_CLIENT_CACHE
/* allocate scratch ClientCache */
c_rows = (ClientRow *)XMALLOC(sizeof(ClientRow) * CLIENT_SESSION_ROWS,
NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (c_rows == NULL) {
WOLFSSL_MSG_EX("error: xmalloc(%zu) failed",
sizeof(ClientRow) * CLIENT_SESSION_ROWS);
ret = -1;
goto cleanup;
}
#endif /* !NO_CLIENT_CACHE */
/* save session cache to cache_mem struct */
if (wolfSSL_memsave_session_cache(cache_mem, mem_sz) != WOLFSSL_SUCCESS) {
ret = -1;
goto cleanup;
}
/* setup test sessions */
test_set_sessions(cache_mem);
#ifndef NO_CLIENT_CACHE
/* copy current client cache */
XMEMCPY(c_rows, &cache_mem->c_rows, sizeof(cache_mem->c_rows));
#endif /* !NO_CLIENT_CACHE */
/* restore session cache from mem */
if (wolfSSL_memrestore_session_cache(cache_mem, mem_sz) != WOLFSSL_SUCCESS) {
ret = -1;
goto cleanup;
}
/* wipe our session struct in memory */
XMEMSET(cache_mem, 0, sizeof(sess_cache_t));
/* save session cache back to cache_mem struct */
if (wolfSSL_memsave_session_cache(cache_mem, mem_sz) != WOLFSSL_SUCCESS) {
ret = -1;
goto cleanup;
}
/* sanity check values */
ret = test_sanity_sessions(cache_mem, "mem");
if (ret) {
goto cleanup;
}
#ifndef NO_CLIENT_CACHE
/* verify we got back the exact client cache */
ret = XMEMCMP(c_rows, &cache_mem->c_rows, sizeof(cache_mem->c_rows));
if (ret) {
WOLFSSL_MSG_EX("error: mem restore c_rows diff: %d", ret);
ret = -1;
goto cleanup;
}
#endif /* !NO_CLIENT_CACHE */
/* eviction: flush sessions older than time 2 (0 + 1 < 2). */
wolfSSL_CTX_flush_sessions(NULL, 2);
#if (defined(HAVE_EXT_CACHE) || defined(HAVE_EX_DATA))
/* if all else succeeded, finally check the callback count. it should not
* fire for sessions restored from persistent storage. */
if (test_rem_sess_cb_count != 0) {
ret = -1;
}
#endif /* HAVE_EXT_CACHE || HAVE_EX_DATA */
/* verify that invalid cache gives CACHE_MATCH_ERROR */
cache_mem->hdr.version = WOLFSSL_CACHE_VERSION - 1;
rst_err = wolfSSL_memrestore_session_cache(cache_mem, mem_sz);
if (rst_err != WC_NO_ERR_TRACE(CACHE_MATCH_ERROR)) {
WOLFSSL_MSG_EX("error: memrestore: hdr.version: got %d, expected %d",
rst_err, CACHE_MATCH_ERROR);
ret = -1;
goto cleanup;
}
cache_mem->hdr.version = WOLFSSL_CACHE_VERSION;
cache_mem->hdr.rows = SESSION_ROWS - 1;
rst_err = wolfSSL_memrestore_session_cache(cache_mem, mem_sz);
if (rst_err != WC_NO_ERR_TRACE(CACHE_MATCH_ERROR)) {
WOLFSSL_MSG_EX("error: memrestore: hdr.rows: got %d, expected %d",
rst_err, CACHE_MATCH_ERROR);
ret = -1;
goto cleanup;
}
cache_mem->hdr.rows = SESSION_ROWS;
cache_mem->hdr.columns = SESSIONS_PER_ROW - 1;
rst_err = wolfSSL_memrestore_session_cache(cache_mem, mem_sz);
if (rst_err != WC_NO_ERR_TRACE(CACHE_MATCH_ERROR)) {
WOLFSSL_MSG_EX("error: memrestore: hdr.columns: got %d, expected %d",
rst_err, CACHE_MATCH_ERROR);
ret = -1;
goto cleanup;
}
cache_mem->hdr.columns = SESSIONS_PER_ROW;
cache_mem->hdr.sessionSz = (int)(sizeof(WOLFSSL_SESSION) - 1);
rst_err = wolfSSL_memrestore_session_cache(cache_mem, mem_sz);
if (rst_err != WC_NO_ERR_TRACE(CACHE_MATCH_ERROR)) {
WOLFSSL_MSG_EX("error: memrestore: hdr.sessionSz: got %d, expected %d",
rst_err, CACHE_MATCH_ERROR);
ret = -1;
goto cleanup;
}
cache_mem->hdr.sessionSz = (int)(sizeof(WOLFSSL_SESSION));
#if !defined(BIG_SESSION_CACHE) && !defined(MEDIUM_SESSION_CACHE)
/* test rejection of invalid session row */
for (i = 0; i < SESSION_ROWS; ++i) {
/* nextIdx is [0, SESSIONS_PER_ROW - 1] */
int nextIdx = cache_mem->s_rows[i].nextIdx;
cache_mem->s_rows[i].nextIdx = -1;
rst_err = wolfSSL_memrestore_session_cache(cache_mem, mem_sz);
if (rst_err != WC_NO_ERR_TRACE(WOLFSSL_FAILURE)) {
WOLFSSL_MSG_EX("error: restore: nextIdx: got %d, expected %d",
rst_err, WOLFSSL_FAILURE);
ret = -1;
goto cleanup;
}
cache_mem->s_rows[i].nextIdx = SESSIONS_PER_ROW;
rst_err = wolfSSL_memrestore_session_cache(cache_mem, mem_sz);
if (rst_err != WC_NO_ERR_TRACE(WOLFSSL_FAILURE)) {
WOLFSSL_MSG_EX("error: restore: nextIdx: got %d, expected %d",
rst_err, WOLFSSL_FAILURE);
ret = -1;
goto cleanup;
}
/* restore original value */
cache_mem->s_rows[i].nextIdx = nextIdx;
rst_err = wolfSSL_memrestore_session_cache(cache_mem, mem_sz);
if (rst_err != WC_NO_ERR_TRACE(WOLFSSL_SUCCESS)) {
WOLFSSL_MSG_EX("error: restore: nextIdx: got %d, expected %d",
rst_err, WOLFSSL_SUCCESS);
ret = -1;
goto cleanup;
}
}
for (i = 0; i < SESSION_ROWS; ++i) {
/* totalCount is [0, SESSIONS_PER_ROW] */
int totalCount = cache_mem->s_rows[i].totalCount;
cache_mem->s_rows[i].totalCount = -1;
rst_err = wolfSSL_memrestore_session_cache(cache_mem, mem_sz);
if (rst_err != WC_NO_ERR_TRACE(WOLFSSL_FAILURE)) {
WOLFSSL_MSG_EX("error: restore: totalCount: got %d, expected %d",
rst_err, WOLFSSL_FAILURE);
ret = -1;
goto cleanup;
}
cache_mem->s_rows[i].totalCount = SESSIONS_PER_ROW + 1;
rst_err = wolfSSL_memrestore_session_cache(cache_mem, mem_sz);
if (rst_err != WC_NO_ERR_TRACE(WOLFSSL_FAILURE)) {
WOLFSSL_MSG_EX("error: restore: totalCount: got %d, expected %d",
rst_err, WOLFSSL_FAILURE);
ret = -1;
goto cleanup;
}
/* restore original value */
cache_mem->s_rows[i].totalCount = totalCount;
rst_err = wolfSSL_memrestore_session_cache(cache_mem, mem_sz);
if (rst_err != WC_NO_ERR_TRACE(WOLFSSL_SUCCESS)) {
WOLFSSL_MSG_EX("error: restore: totalCount: got %d, expected %d",
rst_err, WOLFSSL_SUCCESS);
ret = -1;
goto cleanup;
}
}
#endif /* !BIG_SESSION_CACHE && !MEDIUM_SESSION_CACHE */
cleanup:
if (cache_mem != NULL) {
XFREE(cache_mem, NULL, DYNAMIC_TYPE_TMP_BUFFER);
cache_mem = NULL;
}
#ifndef NO_CLIENT_CACHE
if (c_rows != NULL) {
XFREE(c_rows, NULL, DYNAMIC_TYPE_TMP_BUFFER);
c_rows = NULL;
}
#endif /* !NO_CLIENT_CACHE */
/* always clean up cache after test */
wolfSSL_CTX_flush_sessions(NULL, -1);
return ret;
}
#if !defined(NO_FILESYSTEM)
/* write cache_mem to file.
*
* returns 0 on success
* returns < 0 on error */
static int test_write_file(const char * fname,
const sess_cache_t * cache_mem)
{
XFILE file = XBADFILE;
size_t n_write = 0;
int ret = -1;
size_t i = 0;
file = XFOPEN(fname, "w+b");
if (file == XBADFILE) {
WOLFSSL_MSG_EX("error: open(%s, w+b)", fname);
goto write_file_cleanup;
}
n_write = (int)XFWRITE(&cache_mem->hdr, sizeof(cache_header_t), 1, file);
if (n_write != 1) {
WOLFSSL_MSG_EX("error: write %s: %zu", fname, n_write);
goto write_file_cleanup;
}
/* we need to write SIZEOF_SESSION_ROW, one row at a time, so the row lock
* fields are skipped. */
for (i = 0; i < SESSION_ROWS; ++i) {
n_write = (int)XFWRITE(&cache_mem->s_rows[i], SIZEOF_SESSION_ROW, 1, file);
if (n_write != 1) {
WOLFSSL_MSG_EX("error: write %s: %zu", fname, n_write);
goto write_file_cleanup;
}
}
#ifndef NO_CLIENT_CACHE
n_write = (int)XFWRITE(&cache_mem->c_rows, sizeof(cache_mem->c_rows), 1, file);
if (n_write != 1) {
WOLFSSL_MSG_EX("error: write %s: %zu", fname, n_write);
goto write_file_cleanup;
}
#endif /* !NO_CLIENT_CACHE */
ret = 0;
write_file_cleanup:
if (file != XBADFILE) {
XFCLOSE(file);
file = XBADFILE;
}
return ret;
}
/* read cache_mem from file.
*
* returns 0 on success
* returns < 0 on error */
static int test_read_file(const char * fname,
sess_cache_t * cache_mem)
{
XFILE file = XBADFILE;
size_t n_read = 0;
int ret = -1;
size_t i = 0;
file = XFOPEN(fname, "rb");
if (file == XBADFILE) {
WOLFSSL_MSG_EX("error: open(%s, rb)", fname);
goto read_file_cleanup;
}
n_read = (int)XFREAD(&cache_mem->hdr, sizeof(cache_header_t), 1, file);
if (n_read != 1) {
WOLFSSL_MSG_EX("error: read %s: %zu", fname, n_read);
goto read_file_cleanup;
}
/* we need to read SIZEOF_SESSION_ROW, one row at a time, so the row lock
* fields are skipped. */
for (i = 0; i < SESSION_ROWS; ++i) {
n_read = (int)XFREAD(&cache_mem->s_rows[i], SIZEOF_SESSION_ROW, 1, file);
if (n_read != 1) {
WOLFSSL_MSG_EX("error: read %s: %zu", fname, n_read);
goto read_file_cleanup;
}
}
#ifndef NO_CLIENT_CACHE
n_read = (int)XFREAD(&cache_mem->c_rows, sizeof(cache_mem->c_rows), 1, file);
if (n_read != 1) {
WOLFSSL_MSG_EX("error: read %s: %zu", fname, n_read);
goto read_file_cleanup;
}
#endif /* !NO_CLIENT_CACHE */
ret = 0;
read_file_cleanup:
if (file != XBADFILE) {
XFCLOSE(file);
file = XBADFILE;
}
return ret;
}
/* Tests file [save, restore]_session_cache.
*
* returns -1 on err
* returns 0 on success
* */
static int test_file_session_cache(void)
{
int ret = -1;
int mem_sz = 0;
sess_cache_t * cache_mem = NULL;
const char * fname = "tmp_test_session_cache.bin";
#ifndef NO_CLIENT_CACHE
ClientRow * c_rows = NULL;
#endif /* !NO_CLIENT_CACHE */
int rst_err = 0;
#if !defined(BIG_SESSION_CACHE) && !defined(MEDIUM_SESSION_CACHE)
int i = 0;
#endif /* !BIG_SESSION_CACHE && !MEDIUM_SESSION_CACHE */
#if (defined(HAVE_EXT_CACHE) || defined(HAVE_EX_DATA))
/* reset callback count */
test_rem_sess_cb_count = 0;
#endif /* HAVE_EXT_CACHE || HAVE_EX_DATA */
/* get session cache size, and allocate scratch copy */
mem_sz = wolfSSL_get_session_cache_memsize();
if (mem_sz != sizeof(sess_cache_t)) {
WOLFSSL_MSG_EX("error: got mem_sz %d, expected %zu\n", mem_sz,
sizeof(sess_cache_t));
return -1;
}
cache_mem = (sess_cache_t *)XMALLOC((size_t)mem_sz, NULL,
DYNAMIC_TYPE_TMP_BUFFER);
if (cache_mem == NULL) {
WOLFSSL_MSG_EX("error: xmalloc(%zu) failed", (size_t) mem_sz);
return -1;
}
#ifndef NO_CLIENT_CACHE
/* allocate scratch ClientCache */
c_rows = (ClientRow *)XMALLOC(sizeof(ClientRow) * CLIENT_SESSION_ROWS,
NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (c_rows == NULL) {
WOLFSSL_MSG_EX("error: xmalloc(%zu) failed",
sizeof(ClientRow) * CLIENT_SESSION_ROWS);
goto file_cleanup;
}
#endif /* !NO_CLIENT_CACHE */
/* save session cache to file fname */
if (wolfSSL_save_session_cache(fname) != WOLFSSL_SUCCESS) {
ret = -1;
goto file_cleanup;
}
/* read it into cache_mem struct */
ret = test_read_file(fname, cache_mem);
if (ret) {
goto file_cleanup;
}
/* setup test sessions */
test_set_sessions(cache_mem);
#ifndef NO_CLIENT_CACHE
/* copy current client cache */
XMEMCPY(c_rows, &cache_mem->c_rows, sizeof(cache_mem->c_rows));
#endif /* !NO_CLIENT_CACHE */
/* write test sessions back to file */
ret = test_write_file(fname, cache_mem);
if (ret) {
goto file_cleanup;
}
/* restore session cache from file */
if (wolfSSL_restore_session_cache(fname) != WOLFSSL_SUCCESS) {
ret = -1;
goto file_cleanup;
}
/* save session cache back to file fname */
if (wolfSSL_save_session_cache(fname) != WOLFSSL_SUCCESS) {
ret = -1;
goto file_cleanup;
}
/* wipe our session struct in memory */
XMEMSET(cache_mem, 0, sizeof(sess_cache_t));
/* read it into cache_mem struct */
ret = test_read_file(fname, cache_mem);
if (ret) {
goto file_cleanup;
}
/* sanity check values */
ret = test_sanity_sessions(cache_mem, "file");
if (ret) {
goto file_cleanup;
}
#ifndef NO_CLIENT_CACHE
/* verify we got back the exact client cache */
ret = XMEMCMP(c_rows, &cache_mem->c_rows, sizeof(cache_mem->c_rows));
if (ret) {
WOLFSSL_MSG_EX("error: file restore c_rows diff: %d", ret);
ret = -1;
goto file_cleanup;
}
#endif /* !NO_CLIENT_CACHE */
/* eviction: flush sessions older than time 2 (0 + 1 < 2). */
wolfSSL_CTX_flush_sessions(NULL, 2);
/* verify that invalid cache gives CACHE_MATCH_ERROR */
cache_mem->hdr.version = WOLFSSL_CACHE_VERSION - 1;
ret = test_write_file(fname, cache_mem);
if (ret) { goto file_cleanup; }
rst_err = wolfSSL_restore_session_cache(fname);
if (rst_err != WC_NO_ERR_TRACE(CACHE_MATCH_ERROR)) {
WOLFSSL_MSG_EX("error: restore: hdr.version: got %d, expected %d",
rst_err, CACHE_MATCH_ERROR);
ret = -1;
goto file_cleanup;
}
cache_mem->hdr.version = WOLFSSL_CACHE_VERSION;
cache_mem->hdr.rows = SESSION_ROWS - 1;
ret = test_write_file(fname, cache_mem);
if (ret) { goto file_cleanup; }
rst_err = wolfSSL_restore_session_cache(fname);
if (rst_err != WC_NO_ERR_TRACE(CACHE_MATCH_ERROR)) {
WOLFSSL_MSG_EX("error: restore: hdr.rows: got %d, expected %d",
rst_err, CACHE_MATCH_ERROR);
ret = -1;
goto file_cleanup;
}
cache_mem->hdr.rows = SESSION_ROWS;
cache_mem->hdr.columns = SESSIONS_PER_ROW - 1;
ret = test_write_file(fname, cache_mem);
if (ret) { goto file_cleanup; }
rst_err = wolfSSL_restore_session_cache(fname);
if (rst_err != WC_NO_ERR_TRACE(CACHE_MATCH_ERROR)) {
WOLFSSL_MSG_EX("error: restore: hdr.columns: got %d, expected %d",
rst_err, CACHE_MATCH_ERROR);
ret = -1;
goto file_cleanup;
}
cache_mem->hdr.columns = SESSIONS_PER_ROW;
cache_mem->hdr.sessionSz = (int)(sizeof(WOLFSSL_SESSION) - 1);
ret = test_write_file(fname, cache_mem);
if (ret) { goto file_cleanup; }
rst_err = wolfSSL_restore_session_cache(fname);
if (rst_err != WC_NO_ERR_TRACE(CACHE_MATCH_ERROR)) {
WOLFSSL_MSG_EX("error: restore: hdr.sessionSz: got %d, expected %d",
rst_err, CACHE_MATCH_ERROR);
ret = -1;
goto file_cleanup;
}
cache_mem->hdr.sessionSz = (int)(sizeof(WOLFSSL_SESSION));
#if !defined(BIG_SESSION_CACHE) && !defined(MEDIUM_SESSION_CACHE)
/* test rejection of invalid session row */
for (i = 0; i < SESSION_ROWS; ++i) {
/* nextIdx is [0, SESSIONS_PER_ROW - 1] */
int nextIdx = cache_mem->s_rows[i].nextIdx;
cache_mem->s_rows[i].nextIdx = -1;
ret = test_write_file(fname, cache_mem);
if (ret) { goto file_cleanup; }
rst_err = wolfSSL_restore_session_cache(fname);
if (rst_err != WC_NO_ERR_TRACE(WOLFSSL_FAILURE)) {
WOLFSSL_MSG_EX("error: restore: nextIdx: got %d, expected %d",
rst_err, WOLFSSL_FAILURE);
ret = -1;
goto file_cleanup;
}
cache_mem->s_rows[i].nextIdx = SESSIONS_PER_ROW;
ret = test_write_file(fname, cache_mem);
if (ret) { goto file_cleanup; }
rst_err = wolfSSL_restore_session_cache(fname);
if (rst_err != WC_NO_ERR_TRACE(WOLFSSL_FAILURE)) {
WOLFSSL_MSG_EX("error: restore: nextIdx: got %d, expected %d",
rst_err, WOLFSSL_FAILURE);
ret = -1;
goto file_cleanup;
}
/* restore original value */
cache_mem->s_rows[i].nextIdx = nextIdx;
ret = test_write_file(fname, cache_mem);
if (ret) { goto file_cleanup; }
rst_err = wolfSSL_restore_session_cache(fname);
if (rst_err != WC_NO_ERR_TRACE(WOLFSSL_SUCCESS)) {
WOLFSSL_MSG_EX("error: restore: nextIdx: got %d, expected %d",
rst_err, WOLFSSL_SUCCESS);
ret = -1;
goto file_cleanup;
}
}
for (i = 0; i < SESSION_ROWS; ++i) {
int totalCount = cache_mem->s_rows[i].totalCount;
/* totalCount is [0, SESSIONS_PER_ROW] */
cache_mem->s_rows[i].totalCount = -1;
ret = test_write_file(fname, cache_mem);
if (ret) { goto file_cleanup; }
rst_err = wolfSSL_restore_session_cache(fname);
if (rst_err != WC_NO_ERR_TRACE(WOLFSSL_FAILURE)) {
WOLFSSL_MSG_EX("error: restore: totalCount: got %d, expected %d",
rst_err, WOLFSSL_FAILURE);
ret = -1;
goto file_cleanup;
}
cache_mem->s_rows[i].totalCount = SESSIONS_PER_ROW + 1;
ret = test_write_file(fname, cache_mem);
if (ret) { goto file_cleanup; }
rst_err = wolfSSL_restore_session_cache(fname);
if (rst_err != WC_NO_ERR_TRACE(WOLFSSL_FAILURE)) {
WOLFSSL_MSG_EX("error: restore: totalCount: got %d, expected %d",
rst_err, WOLFSSL_FAILURE);
ret = -1;
goto file_cleanup;
}
/* restore original value */
cache_mem->s_rows[i].totalCount = totalCount;
ret = test_write_file(fname, cache_mem);
if (ret) { goto file_cleanup; }
rst_err = wolfSSL_restore_session_cache(fname);
if (rst_err != WC_NO_ERR_TRACE(WOLFSSL_SUCCESS)) {
WOLFSSL_MSG_EX("error: restore: totalCount: got %d, expected %d",
rst_err, WOLFSSL_SUCCESS);
ret = -1;
goto file_cleanup;
}
}
#endif /* !BIG_SESSION_CACHE && !MEDIUM_SESSION_CACHE */
file_cleanup:
/* remove session cache file. the file existing and being removed
* is part of the expected result. */
{
int rc = remove(fname);
if (rc) {
fprintf(stderr, "remove(%s) failed: %d\n", fname, rc);
ret = -1;
}
}
#if (defined(HAVE_EXT_CACHE) || defined(HAVE_EX_DATA))
/* if all else succeeded, finally check the callback count. it should not
* fire for sessions restored from persistent storage. */
if (test_rem_sess_cb_count != 0) {
ret = -1;
}
#endif /* HAVE_EXT_CACHE || HAVE_EX_DATA */
if (cache_mem != NULL) {
XFREE(cache_mem, NULL, DYNAMIC_TYPE_TMP_BUFFER);
cache_mem = NULL;
}
#ifndef NO_CLIENT_CACHE
if (c_rows != NULL) {
XFREE(c_rows, NULL, DYNAMIC_TYPE_TMP_BUFFER);
c_rows = NULL;
}
#endif /* !NO_CLIENT_CACHE */
/* always clean up cache after test */
wolfSSL_CTX_flush_sessions(NULL, -1);
return ret;
}
#endif /* !NO_FILESYSTEM */
int test_wolfSSL_session_cache_restore(void)
{
EXPECT_DECLS;
ExpectIntEQ(test_mem_session_cache(), 0);
#if !defined(NO_FILESYSTEM)
ExpectIntEQ(test_file_session_cache(), 0);
#endif /* NO_FILESYSTEM */
return EXPECT_RESULT();
}
#else
int test_wolfSSL_session_cache_restore(void)
{
return TEST_SKIPPED;
}
#endif /* PERSIST_SESSION_CACHE && !NO_SESSION_CACHE &&
* !SESSION_CACHE_DYNAMIC_MEM && !TITAN_SESSION_CACHE &&
* !HUGE_SESSION_CACHE */

View File

@@ -39,6 +39,7 @@ int test_wolfSSL_SESSION_get_ex_new_index(void);
int test_wolfSSL_GetSessionAtIndex(void);
int test_wolfSSL_client_cache_id_prefix(void);
int test_wolfSSL_client_cache_id_overwrite(void);
int test_wolfSSL_session_cache_restore(void);
#define TEST_SESSION_DECLS \
TEST_DECL_GROUP("session", test_wolfSSL_CTX_add_session), \
@@ -55,6 +56,7 @@ int test_wolfSSL_client_cache_id_overwrite(void);
TEST_DECL_GROUP("session", test_wolfSSL_SESSION_get_ex_new_index), \
TEST_DECL_GROUP("session", test_wolfSSL_GetSessionAtIndex), \
TEST_DECL_GROUP("session", test_wolfSSL_client_cache_id_prefix), \
TEST_DECL_GROUP("session", test_wolfSSL_client_cache_id_overwrite)
TEST_DECL_GROUP("session", test_wolfSSL_client_cache_id_overwrite), \
TEST_DECL_GROUP("session", test_wolfSSL_session_cache_restore)
#endif /* WOLFCRYPT_TEST_SESSION_H */

View File

@@ -27,7 +27,8 @@ nobase_include_HEADERS+= \
wolfssl/wolfio.h
noinst_HEADERS+= \
wolfssl/internal.h
wolfssl/internal.h \
wolfssl/ssl_sess.h
# For distro build don't install options.h.
# It depends on the architecture and conflicts with Multi-Arch.

View File

@@ -5057,7 +5057,7 @@ typedef struct TicketNonce {
byte data[MAX_TICKET_NONCE_STATIC_SZ];
#endif /* WOLFSSL_TICKET_NONCE_MALLOC && FIPS_VERSION_GE(5,3) */
} TicketNonce;
#endif
#endif /* WOLFSSL_TLS13 && (HAVE_SESSION_TICKET || !NO_PSK) */
/* wolfSSL session type */
struct WOLFSSL_SESSION {
@@ -5067,16 +5067,16 @@ struct WOLFSSL_SESSION {
#ifndef NO_SESSION_CACHE
int cacheRow; /* row in session cache */
word32 cacheGen; /* writes into this entry */
#endif
#endif /* !NO_SESSION_CACHE */
wolfSSL_Ref ref;
byte altSessionID[ID_LEN];
byte haveAltSessionID:1;
#ifdef HAVE_EX_DATA
byte ownExData:1;
#endif
#endif /* HAVE_EX_DATA */
#if defined(HAVE_EXT_CACHE) || defined(HAVE_EX_DATA)
Rem_Sess_Cb rem_sess_cb;
#endif
#endif /* HAVE_EXT_CACHE || HAVE_EX_DATA */
void* heap;
/* WARNING The above fields (up to and including the heap) are not copied
* in wolfSSL_DupSession. Place new fields after the heap
@@ -5096,41 +5096,41 @@ struct WOLFSSL_SESSION {
word16 haveEMS; /* ext master secret flag */
#if defined(SESSION_CERTS) && defined(OPENSSL_EXTRA)
WOLFSSL_X509* peer; /* peer cert */
#endif
#endif /* SESSION_CERTS && OPENSSL_EXTRA */
ProtocolVersion version; /* which version was used */
#if defined(SESSION_CERTS) || !defined(NO_RESUME_SUITE_CHECK) || \
(defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET))
byte cipherSuite0; /* first byte, normally 0 */
byte cipherSuite; /* 2nd byte, actual suite */
#endif
#endif /* SESSION_CERTS || !NO_RESUME_SUITE_CHECK || ... */
#ifndef NO_CLIENT_CACHE
word16 idLen; /* serverID length */
byte serverID[SERVER_ID_LEN]; /* for easier client lookup */
#endif
#endif /* !NO_CLIENT_CACHE */
#ifdef WOLFSSL_SESSION_ID_CTX
byte sessionCtxSz; /* sessionCtx length */
byte sessionCtx[ID_LEN]; /* app specific context id */
#endif /* WOLFSSL_SESSION_ID_CTX */
#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
byte peerVerifyRet; /* cert verify error */
#endif
#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */
#ifdef WOLFSSL_TLS13
word16 namedGroup;
#endif
#endif /* WOLFSSL_TLS13 */
#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
#ifdef WOLFSSL_TLS13
#ifdef WOLFSSL_32BIT_MILLI_TIME
#ifdef WOLFSSL_TLS13
#ifdef WOLFSSL_32BIT_MILLI_TIME
word32 ticketSeen; /* Time ticket seen (ms) */
#else
#else
sword64 ticketSeen; /* Time ticket seen (ms) */
#endif
#endif /* WOLFSSL_32BIT_MILLI_TIME */
word32 ticketAdd; /* Added by client */
TicketNonce ticketNonce; /* Nonce used to derive PSK */
#endif
#ifdef WOLFSSL_EARLY_DATA
#endif /* WOLFSSL_TLS13 */
#ifdef WOLFSSL_EARLY_DATA
word32 maxEarlyDataSz;
#endif
#endif
#endif /* WOLFSSL_EARLY_DATA */
#endif /* HAVE_SESSION_TICKET || !NO_PSK */
#ifdef HAVE_SESSION_TICKET
byte staticTicket[SESSION_TICKET_LEN];
byte* ticket;
@@ -5138,25 +5138,25 @@ struct WOLFSSL_SESSION {
word16 ticketLenAlloc; /* is dynamic */
#ifdef HAVE_SNI
byte sniHash[TICKET_BINDING_HASH_SZ]; /* SNI at issue */
#endif
#ifdef HAVE_ALPN
#endif /* HAVE_SNI */
#ifdef HAVE_ALPN
byte alpnHash[TICKET_BINDING_HASH_SZ]; /* ALPN at issue */
#endif
#endif
#endif /* HAVE_ALPN */
#endif /* HAVE_SESSION_TICKET */
#ifdef SESSION_CERTS
WOLFSSL_X509_CHAIN chain; /* peer cert chain, static */
#ifdef WOLFSSL_ALT_CERT_CHAINS
WOLFSSL_X509_CHAIN altChain; /* peer alt cert chain, static */
#endif
#endif /* WOLFSSL_ALT_CERT_CHAINS */
#endif
#ifdef HAVE_EX_DATA
WOLFSSL_CRYPTO_EX_DATA ex_data;
#endif
#endif /* HAVE_EX_DATA */
#ifdef HAVE_MAX_FRAGMENT
byte mfl; /* max fragment length negotiated i.e.
* WOLFSSL_MFL_2_8 (6) */
#endif
#endif /* HAVE_MAX_FRAGMENT */
byte isSetup:1;
};

193
wolfssl/ssl_sess.h Normal file
View File

@@ -0,0 +1,193 @@
/* ssl_sess.h
*
* Copyright (C) 2006-2026 wolfSSL Inc.
*
* This file is part of wolfSSL.
*
* wolfSSL is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* wolfSSL is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/
#ifndef WOLFSSL_SSL_SESS_H
#define WOLFSSL_SSL_SESS_H
#ifndef NO_SESSION_CACHE
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* basic config gives a cache with 33 sessions, adequate for clients and
embedded servers
TITAN_SESSION_CACHE allows just over 2 million sessions, for servers
with titanic amounts of memory with long session ID timeouts and high
levels of traffic.
ENABLE_SESSION_CACHE_ROW_LOCK: Allows row level locking for increased
performance with large session caches
HUGE_SESSION_CACHE yields 65,791 sessions, for servers under heavy load,
allows over 13,000 new sessions per minute or over 200 new sessions per
second
BIG_SESSION_CACHE yields 20,027 sessions
MEDIUM_SESSION_CACHE allows 1055 sessions, adequate for servers that
aren't under heavy load, basically allows 200 new sessions per minute
SMALL_SESSION_CACHE only stores 6 sessions, good for embedded clients
or systems where the default is too much RAM.
SessionCache takes about 2K, ClientCache takes about 3Kbytes
MICRO_SESSION_CACHE only stores 1 session, good for embedded clients
or systems where memory is at a premium.
SessionCache takes about 400 bytes, ClientCache takes 576 bytes
default SESSION_CACHE stores 33 sessions (no XXX_SESSION_CACHE defined)
SessionCache takes about 13K bytes, ClientCache takes 17K bytes
*/
#if defined(TITAN_SESSION_CACHE)
#define SESSIONS_PER_ROW 31
#define SESSION_ROWS 64937
#ifndef ENABLE_SESSION_CACHE_ROW_LOCK
#define ENABLE_SESSION_CACHE_ROW_LOCK
#endif
#elif defined(HUGE_SESSION_CACHE)
#define SESSIONS_PER_ROW 11
#define SESSION_ROWS 5981
#elif defined(BIG_SESSION_CACHE)
#define SESSIONS_PER_ROW 7
#define SESSION_ROWS 2861
#elif defined(MEDIUM_SESSION_CACHE)
#define SESSIONS_PER_ROW 5
#define SESSION_ROWS 211
#elif defined(SMALL_SESSION_CACHE)
#define SESSIONS_PER_ROW 2
#define SESSION_ROWS 3
#elif defined(MICRO_SESSION_CACHE)
#define SESSIONS_PER_ROW 1
#define SESSION_ROWS 1
#else
#define SESSIONS_PER_ROW 3
#define SESSION_ROWS 11
#endif
#define INVALID_SESSION_ROW (-1)
#ifdef NO_SESSION_CACHE_ROW_LOCK
#undef ENABLE_SESSION_CACHE_ROW_LOCK
#endif
typedef struct SessionRow {
int nextIdx; /* where to place next one */
int totalCount; /* sessions ever on this row */
word32 cacheGen; /* next entry generation */
#ifdef SESSION_CACHE_DYNAMIC_MEM
WOLFSSL_SESSION* Sessions[SESSIONS_PER_ROW];
void* heap;
#else
WOLFSSL_SESSION Sessions[SESSIONS_PER_ROW];
#endif
#ifdef ENABLE_SESSION_CACHE_ROW_LOCK
/* not included in import/export */
wolfSSL_RwLock row_lock;
int lock_valid;
#endif
} SessionRow;
#if defined(PERSIST_SESSION_CACHE) && !defined(SESSION_CACHE_DYNAMIC_MEM)
/* when writing / restoring from storage, do not read the full struct,
* as this would clobber active row locks. */
#ifdef ENABLE_SESSION_CACHE_ROW_LOCK
#define SIZEOF_SESSION_ROW WC_OFFSETOF(SessionRow, row_lock)
#else
#define SIZEOF_SESSION_ROW (sizeof(SessionRow))
#endif /* ENABLE_SESSION_CACHE_ROW_LOCK */
#endif /* PERSIST_SESSION_CACHE && !SESSION_CACHE_DYNAMIC_MEM */
#ifndef NO_CLIENT_CACHE
#ifndef CLIENT_SESSIONS_MULTIPLIER
#ifdef NO_SESSION_CACHE_REF
#define CLIENT_SESSIONS_MULTIPLIER 1
#else
/* ClientSession objects are lightweight (compared to
* WOLFSSL_SESSION) so to decrease chance that user will reuse
* the wrong session, increase the ClientCache size. This will
* make the entire ClientCache about the size of one
* WOLFSSL_SESSION object. */
#define CLIENT_SESSIONS_MULTIPLIER 8
#endif
#endif
#define CLIENT_SESSIONS_PER_ROW \
(SESSIONS_PER_ROW * CLIENT_SESSIONS_MULTIPLIER)
#define CLIENT_SESSION_ROWS (SESSION_ROWS * CLIENT_SESSIONS_MULTIPLIER)
#if CLIENT_SESSIONS_PER_ROW > 65535
#error CLIENT_SESSIONS_PER_ROW too big
#endif
#if CLIENT_SESSION_ROWS > 65535
#error CLIENT_SESSION_ROWS too big
#endif
struct ClientSession {
word16 serverRow; /* SessionCache Row id */
word16 serverIdx; /* SessionCache Idx (column) */
word32 sessionIDHash;
word32 cacheGen; /* SessionCache entry generation */
};
#ifndef WOLFSSL_CLIENT_SESSION_DEFINED
typedef struct ClientSession ClientSession;
#define WOLFSSL_CLIENT_SESSION_DEFINED
#endif
typedef struct ClientRow {
int nextIdx; /* where to place next one */
int totalCount; /* sessions ever on this row */
ClientSession Clients[CLIENT_SESSIONS_PER_ROW];
} ClientRow;
#endif /* !NO_CLIENT_CACHE */
#if defined(PERSIST_SESSION_CACHE) && !defined(SESSION_CACHE_DYNAMIC_MEM)
/* for persistence, if changes to layout need to increment and modify
save_session_cache() and restore_session_cache and memory versions too */
#define WOLFSSL_CACHE_VERSION 3
/* Session Cache Header information */
typedef struct {
int version; /* cache layout version id */
int rows; /* session rows */
int columns; /* session columns */
int sessionSz; /* sizeof WOLFSSL_SESSION */
} cache_header_t;
/* current persistence layout is:
1) cache_header_t
2) SessionCache
3) ClientCache
update WOLFSSL_CACHE_VERSION if change layout for the following
PERSISTENT_SESSION_CACHE functions
*/
#endif /* PERSIST_SESSION_CACHE && !SESSION_CACHE_DYNAMIC_MEM */
#ifdef __cplusplus
} /* extern "C" */
#endif /* __cplusplus */
#endif /* !NO_SESSION_CACHE */
#endif /* WOLFSSL_SSL_SESS_H */