Files

1617 lines
58 KiB
C
Raw Permalink Normal View History

2026-05-28 16:59:22 +10:00
/* test_session.c
*
* 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
*/
#include <tests/unit.h>
#ifdef NO_INLINE
#include <wolfssl/wolfcrypt/misc.h>
#else
#define WOLFSSL_MISC_INCLUDED
#include <wolfcrypt/src/misc.c>
#endif
#include <wolfssl/ssl.h>
#include <wolfssl/internal.h>
#include <wolfssl/error-ssl.h>
#include <tests/api/api.h>
#include <tests/utils.h>
#include <tests/api/test_session.h>
/*----------------------------------------------------------------------------*/
/* WOLFSSL_CTX_add_session / session resumption */
/*----------------------------------------------------------------------------*/
#if defined(HAVE_IO_TESTS_DEPENDENCIES) && defined(HAVE_EXT_CACHE) && \
!defined(SINGLE_THREADED) && defined(WOLFSSL_TLS13) && \
!defined(NO_SESSION_CACHE)
/* Sessions to restore/store */
static WOLFSSL_SESSION* test_wolfSSL_CTX_add_session_client_sess;
static WOLFSSL_SESSION* test_wolfSSL_CTX_add_session_server_sess;
static WOLFSSL_CTX* test_wolfSSL_CTX_add_session_server_ctx;
static void test_wolfSSL_CTX_add_session_ctx_ready(WOLFSSL_CTX* ctx)
{
/* Don't store sessions. Lookup is still enabled. */
AssertIntEQ(wolfSSL_CTX_set_session_cache_mode(ctx,
WOLFSSL_SESS_CACHE_NO_INTERNAL_STORE), WOLFSSL_SUCCESS);
#ifdef OPENSSL_EXTRA
AssertIntEQ(wolfSSL_CTX_get_session_cache_mode(ctx) &
WOLFSSL_SESS_CACHE_NO_INTERNAL_STORE,
WOLFSSL_SESS_CACHE_NO_INTERNAL_STORE);
#endif
/* Require both peers to provide certs */
wolfSSL_CTX_set_verify(ctx, WOLFSSL_VERIFY_PEER, NULL);
}
static void test_wolfSSL_CTX_add_session_on_result(WOLFSSL* ssl)
{
WOLFSSL_SESSION** sess;
#ifdef WOLFSSL_MUTEX_INITIALIZER
static wolfSSL_Mutex m = WOLFSSL_MUTEX_INITIALIZER(m);
(void)wc_LockMutex(&m);
#endif
if (wolfSSL_is_server(ssl))
sess = &test_wolfSSL_CTX_add_session_server_sess;
else
sess = &test_wolfSSL_CTX_add_session_client_sess;
if (*sess == NULL) {
#ifdef NO_SESSION_CACHE_REF
*sess = wolfSSL_get1_session(ssl);
AssertNotNull(*sess);
#else
/* Test for backwards compatibility */
if (wolfSSL_is_server(ssl)) {
*sess = wolfSSL_get1_session(ssl);
AssertNotNull(*sess);
}
else {
*sess = wolfSSL_get_session(ssl);
AssertNotNull(*sess);
}
#endif
/* Now save the session in the internal store to make it available
* for lookup. For TLS 1.3, we can't save the session without
* WOLFSSL_TICKET_HAVE_ID because there is no way to retrieve the
* session from cache. */
if (wolfSSL_is_server(ssl)
#ifndef WOLFSSL_TICKET_HAVE_ID
&& wolfSSL_version(ssl) != TLS1_3_VERSION
#endif
)
AssertIntEQ(wolfSSL_CTX_add_session(wolfSSL_get_SSL_CTX(ssl),
*sess), WOLFSSL_SUCCESS);
}
else {
/* If we have a session retrieved then remaining connections should be
* resuming on that session */
AssertIntEQ(wolfSSL_session_reused(ssl), 1);
}
#ifdef WOLFSSL_MUTEX_INITIALIZER
wc_UnLockMutex(&m);
#endif
/* Save CTX to be able to decrypt tickets */
if (wolfSSL_is_server(ssl) &&
test_wolfSSL_CTX_add_session_server_ctx == NULL) {
test_wolfSSL_CTX_add_session_server_ctx = wolfSSL_get_SSL_CTX(ssl);
AssertNotNull(test_wolfSSL_CTX_add_session_server_ctx);
AssertIntEQ(wolfSSL_CTX_up_ref(wolfSSL_get_SSL_CTX(ssl)),
WOLFSSL_SUCCESS);
}
#if defined(SESSION_CERTS) && !defined(WOLFSSL_NO_CLIENT_AUTH)
#ifndef WOLFSSL_TICKET_HAVE_ID
if (wolfSSL_version(ssl) != TLS1_3_VERSION &&
wolfSSL_session_reused(ssl))
#endif
{
/* With WOLFSSL_TICKET_HAVE_ID the peer certs should be available
* for all connections. TLS 1.3 only has tickets so if we don't
* include the session id in the ticket then the certificates
* will not be available on resumption. */
#ifdef KEEP_PEER_CERT
WOLFSSL_X509* peer = wolfSSL_get_peer_certificate(ssl);
AssertNotNull(peer);
wolfSSL_X509_free(peer);
#endif
AssertNotNull(wolfSSL_SESSION_get_peer_chain(*sess));
#ifdef OPENSSL_EXTRA
AssertNotNull(SSL_SESSION_get0_peer(*sess));
#endif
}
#endif /* SESSION_CERTS && !WOLFSSL_NO_CLIENT_AUTH */
}
static void test_wolfSSL_CTX_add_session_ssl_ready(WOLFSSL* ssl)
{
/* Set the session to reuse for the client */
AssertIntEQ(wolfSSL_set_session(ssl,
test_wolfSSL_CTX_add_session_client_sess), WOLFSSL_SUCCESS);
}
#endif
int test_wolfSSL_CTX_add_session(void)
{
EXPECT_DECLS;
#if defined(HAVE_IO_TESTS_DEPENDENCIES) && defined(HAVE_EXT_CACHE) && \
!defined(SINGLE_THREADED) && defined(WOLFSSL_TLS13) && \
!defined(NO_SESSION_CACHE)
tcp_ready ready;
func_args client_args;
func_args server_args;
THREAD_TYPE serverThread;
callback_functions client_cb;
callback_functions server_cb;
method_provider methods[][2] = {
#if !defined(NO_OLD_TLS) && ((!defined(NO_AES) && !defined(NO_AES_CBC)) || \
!defined(NO_DES3))
/* Without AES there are almost no ciphersuites available. This leads
* to no ciphersuites being available and an error. */
{ wolfTLSv1_1_client_method, wolfTLSv1_1_server_method },
#endif
#ifndef WOLFSSL_NO_TLS12
{ wolfTLSv1_2_client_method, wolfTLSv1_2_server_method },
#endif
/* Needs the default ticket callback since it is tied to the
* connection context and this makes it easy to carry over the ticket
* crypto context between connections */
#if defined(WOLFSSL_TLS13) && !defined(WOLFSSL_NO_DEF_TICKET_ENC_CB) && \
defined(HAVE_SESSION_TICKET)
{ wolfTLSv1_3_client_method, wolfTLSv1_3_server_method },
#endif
};
const size_t methodsLen = sizeof(methods)/sizeof(*methods);
size_t i, j;
for (i = 0; i < methodsLen; i++) {
/* First run creates a connection while the second+ run will attempt
* to resume the connection. The trick is that the internal cache
* is turned off. wolfSSL_CTX_add_session should put the session in
* the cache anyway. */
test_wolfSSL_CTX_add_session_client_sess = NULL;
test_wolfSSL_CTX_add_session_server_sess = NULL;
test_wolfSSL_CTX_add_session_server_ctx = NULL;
#ifdef NO_SESSION_CACHE_REF
for (j = 0; j < 4; j++) {
#else
/* The session may be overwritten in this case. Do only one resumption
* to stop this test from failing intermittently. */
for (j = 0; j < 2; j++) {
#endif
#ifdef WOLFSSL_TIRTOS
fdOpenSession(Task_self());
#endif
StartTCP();
InitTcpReady(&ready);
XMEMSET(&client_args, 0, sizeof(func_args));
XMEMSET(&server_args, 0, sizeof(func_args));
XMEMSET(&client_cb, 0, sizeof(callback_functions));
XMEMSET(&server_cb, 0, sizeof(callback_functions));
client_cb.method = methods[i][0];
server_cb.method = methods[i][1];
server_args.signal = &ready;
server_args.callbacks = &server_cb;
client_args.signal = &ready;
client_args.callbacks = &client_cb;
if (test_wolfSSL_CTX_add_session_server_ctx != NULL) {
server_cb.ctx = test_wolfSSL_CTX_add_session_server_ctx;
server_cb.isSharedCtx = 1;
}
server_cb.ctx_ready = test_wolfSSL_CTX_add_session_ctx_ready;
client_cb.ctx_ready = test_wolfSSL_CTX_add_session_ctx_ready;
if (j != 0)
client_cb.ssl_ready = test_wolfSSL_CTX_add_session_ssl_ready;
server_cb.on_result = test_wolfSSL_CTX_add_session_on_result;
client_cb.on_result = test_wolfSSL_CTX_add_session_on_result;
server_cb.ticNoInit = 1; /* Use default builtin */
start_thread(test_server_nofail, &server_args, &serverThread);
wait_tcp_ready(&server_args);
test_client_nofail(&client_args, NULL);
join_thread(serverThread);
ExpectTrue(client_args.return_code);
ExpectTrue(server_args.return_code);
FreeTcpReady(&ready);
if (EXPECT_FAIL())
break;
}
wolfSSL_SESSION_free(test_wolfSSL_CTX_add_session_client_sess);
wolfSSL_SESSION_free(test_wolfSSL_CTX_add_session_server_sess);
wolfSSL_CTX_free(test_wolfSSL_CTX_add_session_server_ctx);
if (EXPECT_FAIL())
break;
}
#endif
return EXPECT_RESULT();
}
#if defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES) && defined(HAVE_EXT_CACHE) && \
defined(WOLFSSL_TLS13) && !defined(NO_SESSION_CACHE) && \
defined(OPENSSL_EXTRA) && defined(SESSION_CERTS) && \
defined(HAVE_SESSION_TICKET) && \
!defined(TITAN_SESSION_CACHE) && \
!defined(HUGE_SESSION_CACHE) && \
!defined(BIG_SESSION_CACHE) && \
!defined(MEDIUM_SESSION_CACHE)
/* twcase - prefix for test_wolfSSL_CTX_add_session_ext */
/* Sessions to restore/store */
static WOLFSSL_SESSION* twcase_server_first_session_ptr;
static WOLFSSL_SESSION* twcase_client_first_session_ptr;
static WOLFSSL_CTX* twcase_server_current_ctx_ptr;
static int twcase_new_session_called = 0;
static int twcase_remove_session_called = 0;
static int twcase_get_session_called = 0;
/* Test default, SESSIONS_PER_ROW*SESSION_ROWS = 3*11, see ssl.c */
#define SESSION_CACHE_SIZE 33
typedef struct {
const byte* key; /* key, altSessionID, session ID, NULL if empty */
WOLFSSL_SESSION* value;
} hashTable_entry;
typedef struct {
hashTable_entry entries[SESSION_CACHE_SIZE]; /* hash slots */
size_t capacity; /* size of entries */
size_t length; /* number of items in the hash table */
wolfSSL_Mutex htLock; /* lock */
}hashTable;
static hashTable server_sessionCache;
static int twcase_new_sessionCb(WOLFSSL *ssl, WOLFSSL_SESSION *sess)
{
int i;
unsigned int len;
(void)ssl;
/*
* This example uses a hash table.
* Steps you should take for a non-demo code:
* - acquire a lock for the file named according to the session id
* - open the file
* - encrypt and write the SSL_SESSION object to the file
* - release the lock
*
* Return:
* 0: The callback does not wish to hold a reference of the sess
* 1: The callback wants to hold a reference of the sess. The callback is
* now also responsible for calling wolfSSL_SESSION_free() on sess.
*/
if (sess == NULL)
return 0;
if (wc_LockMutex(&server_sessionCache.htLock) != 0) {
return 0;
}
for (i = 0; i < SESSION_CACHE_SIZE; i++) {
if (server_sessionCache.entries[i].value == NULL) {
server_sessionCache.entries[i].key = SSL_SESSION_get_id(sess, &len);
server_sessionCache.entries[i].value = sess;
server_sessionCache.length++;
break;
}
}
++twcase_new_session_called;
wc_UnLockMutex(&server_sessionCache.htLock);
fprintf(stderr, "\t\ttwcase_new_session_called %d\n",
twcase_new_session_called);
return 1;
}
static void twcase_remove_sessionCb(WOLFSSL_CTX *ctx, WOLFSSL_SESSION *sess)
{
int i;
(void)ctx;
(void)sess;
if (sess == NULL)
return;
/*
* This example uses a hash table.
* Steps you should take for a non-demo code:
* - acquire a lock for the file named according to the session id
* - remove the file
* - release the lock
*/
if (wc_LockMutex(&server_sessionCache.htLock) != 0) {
return;
}
for (i = 0; i < SESSION_CACHE_SIZE; i++) {
if (server_sessionCache.entries[i].key != NULL &&
XMEMCMP(server_sessionCache.entries[i].key,
sess->sessionID, SSL_MAX_SSL_SESSION_ID_LENGTH) == 0) {
wolfSSL_SESSION_free(server_sessionCache.entries[i].value);
server_sessionCache.entries[i].value = NULL;
server_sessionCache.entries[i].key = NULL;
server_sessionCache.length--;
break;
}
}
++twcase_remove_session_called;
wc_UnLockMutex(&server_sessionCache.htLock);
fprintf(stderr, "\t\ttwcase_remove_session_called %d\n",
twcase_remove_session_called);
}
static WOLFSSL_SESSION *twcase_get_sessionCb(WOLFSSL *ssl,
const unsigned char *id, int len, int *ref)
{
int i;
(void)ssl;
(void)id;
(void)len;
/*
* This example uses a hash table.
* Steps you should take for a non-demo code:
* - acquire a lock for the file named according to the session id in the
* 2nd arg
* - read and decrypt contents of file and create a new SSL_SESSION
* - object release the lock
* - return the new session object
*/
fprintf(stderr, "\t\ttwcase_get_session_called %d\n",
++twcase_get_session_called);
/* This callback want to retain a copy of the object. If we want wolfSSL to
* be responsible for the pointer then set to 0. */
*ref = 1;
for (i = 0; i < SESSION_CACHE_SIZE; i++) {
if (server_sessionCache.entries[i].key != NULL &&
XMEMCMP(server_sessionCache.entries[i].key, id,
SSL_MAX_SSL_SESSION_ID_LENGTH) == 0) {
return server_sessionCache.entries[i].value;
}
}
return NULL;
}
static int twcase_get_sessionCb_cleanup(void)
{
int i;
int cnt = 0;
/* If twcase_get_sessionCb sets *ref = 1, the application is responsible
* for freeing sessions */
for (i = 0; i < SESSION_CACHE_SIZE; i++) {
if (server_sessionCache.entries[i].value != NULL) {
wolfSSL_SESSION_free(server_sessionCache.entries[i].value);
cnt++;
}
}
fprintf(stderr, "\t\ttwcase_get_sessionCb_cleanup freed %d sessions\n",
cnt);
return TEST_SUCCESS;
}
static int twcase_cache_intOff_extOff(WOLFSSL_CTX* ctx)
{
EXPECT_DECLS;
/* off - Disable internal cache */
ExpectIntEQ(wolfSSL_CTX_set_session_cache_mode(ctx,
WOLFSSL_SESS_CACHE_NO_INTERNAL_STORE), WOLFSSL_SUCCESS);
#ifdef OPENSSL_EXTRA
ExpectIntEQ(wolfSSL_CTX_get_session_cache_mode(ctx) &
WOLFSSL_SESS_CACHE_NO_INTERNAL_STORE,
WOLFSSL_SESS_CACHE_NO_INTERNAL_STORE);
#endif
/* off - Do not setup external cache */
/* Require both peers to provide certs */
wolfSSL_CTX_set_verify(ctx, WOLFSSL_VERIFY_PEER, NULL);
return EXPECT_RESULT();
}
static int twcase_cache_intOn_extOff(WOLFSSL_CTX* ctx)
{
/* on - internal cache is on by default */
/* off - Do not setup external cache */
/* Require both peers to provide certs */
wolfSSL_CTX_set_verify(ctx, WOLFSSL_VERIFY_PEER, NULL);
return TEST_SUCCESS;
}
static int twcase_cache_intOff_extOn(WOLFSSL_CTX* ctx)
{
EXPECT_DECLS;
/* off - Disable internal cache */
ExpectIntEQ(wolfSSL_CTX_set_session_cache_mode(ctx,
WOLFSSL_SESS_CACHE_NO_INTERNAL_STORE), WOLFSSL_SUCCESS);
#ifdef OPENSSL_EXTRA
ExpectIntEQ(wolfSSL_CTX_get_session_cache_mode(ctx) &
WOLFSSL_SESS_CACHE_NO_INTERNAL_STORE,
WOLFSSL_SESS_CACHE_NO_INTERNAL_STORE);
#endif
/* on - Enable external cache */
wolfSSL_CTX_sess_set_new_cb(ctx, twcase_new_sessionCb);
wolfSSL_CTX_sess_set_remove_cb(ctx, twcase_remove_sessionCb);
wolfSSL_CTX_sess_set_get_cb(ctx, twcase_get_sessionCb);
/* Require both peers to provide certs */
wolfSSL_CTX_set_verify(ctx, WOLFSSL_VERIFY_PEER, NULL);
return EXPECT_RESULT();
}
static int twcase_cache_intOn_extOn(WOLFSSL_CTX* ctx)
{
/* on - internal cache is on by default */
/* on - Enable external cache */
wolfSSL_CTX_sess_set_new_cb(ctx, twcase_new_sessionCb);
wolfSSL_CTX_sess_set_remove_cb(ctx, twcase_remove_sessionCb);
wolfSSL_CTX_sess_set_get_cb(ctx, twcase_get_sessionCb);
/* Require both peers to provide certs */
wolfSSL_CTX_set_verify(ctx, WOLFSSL_VERIFY_PEER, NULL);
return TEST_SUCCESS;
}
static int twcase_cache_intOn_extOn_noTicket(WOLFSSL_CTX* ctx)
{
/* on - internal cache is on by default */
/* on - Enable external cache */
wolfSSL_CTX_sess_set_new_cb(ctx, twcase_new_sessionCb);
wolfSSL_CTX_sess_set_remove_cb(ctx, twcase_remove_sessionCb);
wolfSSL_CTX_sess_set_get_cb(ctx, twcase_get_sessionCb);
wolfSSL_CTX_set_options(ctx, WOLFSSL_OP_NO_TICKET);
/* Require both peers to provide certs */
wolfSSL_CTX_set_verify(ctx, WOLFSSL_VERIFY_PEER, NULL);
return TEST_SUCCESS;
}
static int twcase_server_sess_ctx_pre_shutdown(WOLFSSL* ssl)
{
EXPECT_DECLS;
WOLFSSL_SESSION** sess;
if (wolfSSL_is_server(ssl))
sess = &twcase_server_first_session_ptr;
else
return TEST_SUCCESS;
if (*sess == NULL) {
ExpectNotNull(*sess = wolfSSL_get1_session(ssl));
/* Now save the session in the internal store to make it available
* for lookup. For TLS 1.3, we can't save the session without
* WOLFSSL_TICKET_HAVE_ID because there is no way to retrieve the
* session from cache. */
if (wolfSSL_is_server(ssl)
#ifndef WOLFSSL_TICKET_HAVE_ID
&& wolfSSL_version(ssl) != TLS1_3_VERSION
&& wolfSSL_version(ssl) != DTLS1_3_VERSION
#endif
) {
ExpectIntEQ(wolfSSL_CTX_add_session(wolfSSL_get_SSL_CTX(ssl),
*sess), WOLFSSL_SUCCESS);
}
}
/* Save CTX to be able to decrypt tickets */
if (twcase_server_current_ctx_ptr == NULL) {
ExpectNotNull(twcase_server_current_ctx_ptr = wolfSSL_get_SSL_CTX(ssl));
ExpectIntEQ(wolfSSL_CTX_up_ref(wolfSSL_get_SSL_CTX(ssl)),
WOLFSSL_SUCCESS);
}
#if defined(SESSION_CERTS) && !defined(WOLFSSL_NO_CLIENT_AUTH)
#ifndef WOLFSSL_TICKET_HAVE_ID
if (wolfSSL_version(ssl) != TLS1_3_VERSION &&
wolfSSL_session_reused(ssl))
#endif
{
/* With WOLFSSL_TICKET_HAVE_ID the peer certs should be available
* for all connections. TLS 1.3 only has tickets so if we don't
* include the session id in the ticket then the certificates
* will not be available on resumption. */
#ifdef KEEP_PEER_CERT
WOLFSSL_X509* peer = NULL;
ExpectNotNull(peer = wolfSSL_get_peer_certificate(ssl));
wolfSSL_X509_free(peer);
#endif
ExpectNotNull(wolfSSL_SESSION_get_peer_chain(*sess));
}
#endif
return EXPECT_RESULT();
}
static int twcase_client_sess_ctx_pre_shutdown(WOLFSSL* ssl)
{
EXPECT_DECLS;
WOLFSSL_SESSION** sess;
sess = &twcase_client_first_session_ptr;
if (*sess == NULL) {
ExpectNotNull(*sess = wolfSSL_get1_session(ssl));
}
else {
/* If we have a session retrieved then remaining connections should be
* resuming on that session */
ExpectIntEQ(wolfSSL_session_reused(ssl), 1);
}
#if defined(SESSION_CERTS) && !defined(WOLFSSL_NO_CLIENT_AUTH)
#ifndef WOLFSSL_TICKET_HAVE_ID
if (wolfSSL_version(ssl) != TLS1_3_VERSION &&
wolfSSL_session_reused(ssl))
#endif
{
#ifdef KEEP_PEER_CERT
WOLFSSL_X509* peer = wolfSSL_get_peer_certificate(ssl);
ExpectNotNull(peer);
wolfSSL_X509_free(peer);
#endif
ExpectNotNull(wolfSSL_SESSION_get_peer_chain(*sess));
#ifdef OPENSSL_EXTRA
ExpectNotNull(wolfSSL_SESSION_get0_peer(*sess));
#endif
}
#endif
return EXPECT_RESULT();
}
static int twcase_client_set_sess_ssl_ready(WOLFSSL* ssl)
{
EXPECT_DECLS;
/* Set the session to reuse for the client */
ExpectNotNull(ssl);
ExpectNotNull(twcase_client_first_session_ptr);
ExpectIntEQ(wolfSSL_set_session(ssl,twcase_client_first_session_ptr),
WOLFSSL_SUCCESS);
return EXPECT_RESULT();
}
struct test_add_session_ext_params {
method_provider client_meth;
method_provider server_meth;
const char* tls_version;
};
/* Marked WC_MAYBE_UNUSED: each registered test_wolfSSL_CTX_add_session_ext_*
* variant below calls this helper, but each variant is gated on a specific
* TLS/DTLS version combination. In builds where no version combination is
* enabled, the helper is defined but unused. */
static WC_MAYBE_UNUSED int test_wolfSSL_CTX_add_session_ext(
struct test_add_session_ext_params* param)
{
EXPECT_DECLS;
/* Test the default 33 sessions */
int j;
/* Clear cache before starting */
wolfSSL_CTX_flush_sessions(NULL, -1);
XMEMSET(&server_sessionCache, 0, sizeof(hashTable));
if (wc_InitMutex(&server_sessionCache.htLock) != 0)
return BAD_MUTEX_E;
server_sessionCache.capacity = SESSION_CACHE_SIZE;
fprintf(stderr, "\tBegin %s\n", param->tls_version);
for (j = 0; j < 5; j++) {
int tls13 = XSTRSTR(param->tls_version, "TLSv1_3") != NULL;
int dtls = XSTRSTR(param->tls_version, "DTLS") != NULL;
test_ssl_cbf client_cb;
test_ssl_cbf server_cb;
(void)dtls;
/* Test five cache configurations */
twcase_client_first_session_ptr = NULL;
twcase_server_first_session_ptr = NULL;
twcase_server_current_ctx_ptr = NULL;
twcase_new_session_called = 0;
twcase_remove_session_called = 0;
twcase_get_session_called = 0;
/* connection 1 - first connection */
fprintf(stderr, "\tconnect: %s: j=%d\n", param->tls_version, j);
XMEMSET(&client_cb, 0, sizeof(client_cb));
XMEMSET(&server_cb, 0, sizeof(server_cb));
client_cb.method = param->client_meth;
server_cb.method = param->server_meth;
if (dtls)
client_cb.doUdp = server_cb.doUdp = 1;
/* Setup internal and external cache */
switch (j) {
case 0:
/* SSL_OP_NO_TICKET stateful ticket case */
server_cb.ctx_ready = twcase_cache_intOn_extOn_noTicket;
break;
case 1:
server_cb.ctx_ready = twcase_cache_intOn_extOn;
break;
case 2:
server_cb.ctx_ready = twcase_cache_intOff_extOn;
break;
case 3:
server_cb.ctx_ready = twcase_cache_intOn_extOff;
break;
case 4:
server_cb.ctx_ready = twcase_cache_intOff_extOff;
break;
}
client_cb.ctx_ready = twcase_cache_intOff_extOff;
/* Add session to internal cache and save SSL session for testing */
server_cb.on_result = twcase_server_sess_ctx_pre_shutdown;
/* Save client SSL session for testing */
client_cb.on_result = twcase_client_sess_ctx_pre_shutdown;
server_cb.ticNoInit = 1; /* Use default builtin */
/* Don't free/release ctx */
server_cb.ctx = twcase_server_current_ctx_ptr;
server_cb.isSharedCtx = 1;
ExpectIntEQ(test_wolfSSL_client_server_nofail_memio(&client_cb,
&server_cb, NULL), TEST_SUCCESS);
ExpectIntEQ(twcase_get_session_called, 0);
if (EXPECT_FAIL()) {
wolfSSL_SESSION_free(twcase_client_first_session_ptr);
wolfSSL_SESSION_free(twcase_server_first_session_ptr);
wolfSSL_CTX_free(twcase_server_current_ctx_ptr);
break;
}
switch (j) {
case 0:
case 1:
case 2:
/* cache cannot be searched with out a connection */
/* Add a new session */
ExpectIntEQ(twcase_new_session_called, 1);
/* In twcase_server_sess_ctx_pre_shutdown
* wolfSSL_CTX_add_session which evicts the existing session
* in cache and adds it back in */
ExpectIntLE(twcase_remove_session_called, 1);
break;
case 3:
case 4:
/* no external cache */
ExpectIntEQ(twcase_new_session_called, 0);
ExpectIntEQ(twcase_remove_session_called, 0);
break;
}
/* connection 2 - session resume */
fprintf(stderr, "\tresume: %s: j=%d\n", param->tls_version, j);
twcase_new_session_called = 0;
twcase_remove_session_called = 0;
twcase_get_session_called = 0;
server_cb.on_result = 0;
client_cb.on_result = 0;
server_cb.ticNoInit = 1; /* Use default builtin */
server_cb.ctx = twcase_server_current_ctx_ptr;
/* try session resumption */
client_cb.ssl_ready = twcase_client_set_sess_ssl_ready;
ExpectIntEQ(test_wolfSSL_client_server_nofail_memio(&client_cb,
&server_cb, NULL), TEST_SUCCESS);
/* Clear cache before checking */
wolfSSL_CTX_flush_sessions(NULL, -1);
switch (j) {
case 0:
if (tls13) {
/* (D)TLSv1.3 stateful case */
/* cache hit */
/* DTLS accesses cache once for stateless parsing and
* once for stateful parsing */
ExpectIntEQ(twcase_get_session_called, !dtls ? 1 : 2);
/* (D)TLSv1.3 creates a new ticket,
* updates both internal and external cache */
ExpectIntEQ(twcase_new_session_called, 1);
/* A new session ID is created for a new ticket */
ExpectIntEQ(twcase_remove_session_called, 2);
}
else {
/* non (D)TLSv1.3 case, no update */
/* DTLS accesses cache once for stateless parsing and
* once for stateful parsing */
#ifdef WOLFSSL_DTLS_NO_HVR_ON_RESUME
ExpectIntEQ(twcase_get_session_called, !dtls ? 1 : 2);
#else
ExpectIntEQ(twcase_get_session_called, 1);
#endif
ExpectIntEQ(twcase_new_session_called, 0);
/* Called on session added in
* twcase_server_sess_ctx_pre_shutdown */
ExpectIntEQ(twcase_remove_session_called, 1);
}
break;
case 1:
if (tls13) {
/* (D)TLSv1.3 case */
/* cache hit */
ExpectIntEQ(twcase_get_session_called, 1);
/* (D)TLSv1.3 creates a new ticket,
* updates both internal and external cache */
ExpectIntEQ(twcase_new_session_called, 1);
/* Called on session added in
* twcase_server_sess_ctx_pre_shutdown and by wolfSSL */
ExpectIntEQ(twcase_remove_session_called, 1);
}
else {
/* non (D)TLSv1.3 case */
/* cache hit */
/* DTLS accesses cache once for stateless parsing and
* once for stateful parsing */
#ifdef WOLFSSL_DTLS_NO_HVR_ON_RESUME
ExpectIntEQ(twcase_get_session_called, !dtls ? 1 : 2);
#else
ExpectIntEQ(twcase_get_session_called, 1);
#endif
ExpectIntEQ(twcase_new_session_called, 0);
/* Called on session added in
* twcase_server_sess_ctx_pre_shutdown */
ExpectIntEQ(twcase_remove_session_called, 1);
}
break;
case 2:
if (tls13) {
/* (D)TLSv1.3 case */
/* cache hit */
ExpectIntEQ(twcase_get_session_called, 1);
/* (D)TLSv1.3 creates a new ticket,
* updates both internal and external cache */
ExpectIntEQ(twcase_new_session_called, 1);
/* Called on session added in
* twcase_server_sess_ctx_pre_shutdown and by wolfSSL */
ExpectIntEQ(twcase_remove_session_called, 1);
}
else {
/* non (D)TLSv1.3 case */
/* cache hit */
/* DTLS accesses cache once for stateless parsing and
* once for stateful parsing */
#ifdef WOLFSSL_DTLS_NO_HVR_ON_RESUME
ExpectIntEQ(twcase_get_session_called, !dtls ? 1 : 2);
#else
ExpectIntEQ(twcase_get_session_called, 1);
#endif
ExpectIntEQ(twcase_new_session_called, 0);
/* Called on session added in
* twcase_server_sess_ctx_pre_shutdown */
ExpectIntEQ(twcase_remove_session_called, 1);
}
break;
case 3:
case 4:
/* no external cache */
ExpectIntEQ(twcase_get_session_called, 0);
ExpectIntEQ(twcase_new_session_called, 0);
ExpectIntEQ(twcase_remove_session_called, 0);
break;
}
wolfSSL_SESSION_free(twcase_client_first_session_ptr);
wolfSSL_SESSION_free(twcase_server_first_session_ptr);
wolfSSL_CTX_free(twcase_server_current_ctx_ptr);
if (EXPECT_FAIL())
break;
}
twcase_get_sessionCb_cleanup();
XMEMSET(&server_sessionCache.entries, 0,
sizeof(server_sessionCache.entries));
fprintf(stderr, "\tEnd %s\n", param->tls_version);
wc_FreeMutex(&server_sessionCache.htLock);
return EXPECT_RESULT();
}
#endif
int test_wolfSSL_CTX_add_session_ext_tls13(void)
{
EXPECT_DECLS;
#if defined(HAVE_IO_TESTS_DEPENDENCIES) && defined(HAVE_EXT_CACHE) && \
defined(WOLFSSL_TLS13) && !defined(NO_SESSION_CACHE) && \
defined(OPENSSL_EXTRA) && defined(SESSION_CERTS) && \
defined(HAVE_SESSION_TICKET) && \
!defined(TITAN_SESSION_CACHE) && \
!defined(HUGE_SESSION_CACHE) && \
!defined(BIG_SESSION_CACHE) && \
!defined(MEDIUM_SESSION_CACHE)
#if defined(WOLFSSL_TLS13) && !defined(WOLFSSL_NO_DEF_TICKET_ENC_CB) && \
defined(HAVE_SESSION_TICKET) && defined(WOLFSSL_TICKET_HAVE_ID)
struct test_add_session_ext_params param[1] = {
{ wolfTLSv1_3_client_method, wolfTLSv1_3_server_method, "TLSv1_3" }
};
ExpectIntEQ(test_wolfSSL_CTX_add_session_ext(param), TEST_SUCCESS);
#endif
#endif
return EXPECT_RESULT();
}
int test_wolfSSL_CTX_add_session_ext_dtls13(void)
{
EXPECT_DECLS;
#if defined(HAVE_IO_TESTS_DEPENDENCIES) && defined(HAVE_EXT_CACHE) && \
defined(WOLFSSL_TLS13) && !defined(NO_SESSION_CACHE) && \
defined(OPENSSL_EXTRA) && defined(SESSION_CERTS) && \
defined(HAVE_SESSION_TICKET) && \
!defined(TITAN_SESSION_CACHE) && \
!defined(HUGE_SESSION_CACHE) && \
!defined(BIG_SESSION_CACHE) && \
!defined(MEDIUM_SESSION_CACHE)
#if defined(WOLFSSL_TLS13) && !defined(WOLFSSL_NO_DEF_TICKET_ENC_CB) && \
defined(HAVE_SESSION_TICKET) && defined(WOLFSSL_TICKET_HAVE_ID)
#ifdef WOLFSSL_DTLS13
struct test_add_session_ext_params param[1] = {
{ wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method, "DTLSv1_3" }
};
ExpectIntEQ(test_wolfSSL_CTX_add_session_ext(param), TEST_SUCCESS);
#endif
#endif
#endif
return EXPECT_RESULT();
}
int test_wolfSSL_CTX_add_session_ext_tls12(void)
{
EXPECT_DECLS;
#if defined(HAVE_IO_TESTS_DEPENDENCIES) && defined(HAVE_EXT_CACHE) && \
defined(WOLFSSL_TLS13) && !defined(NO_SESSION_CACHE) && \
defined(OPENSSL_EXTRA) && defined(SESSION_CERTS) && \
defined(HAVE_SESSION_TICKET) && \
!defined(TITAN_SESSION_CACHE) && \
!defined(HUGE_SESSION_CACHE) && \
!defined(BIG_SESSION_CACHE) && \
!defined(MEDIUM_SESSION_CACHE)
#ifndef WOLFSSL_NO_TLS12
struct test_add_session_ext_params param[1] = {
{ wolfTLSv1_2_client_method, wolfTLSv1_2_server_method, "TLSv1_2" }
};
ExpectIntEQ(test_wolfSSL_CTX_add_session_ext(param), TEST_SUCCESS);
#endif
#endif
return EXPECT_RESULT();
}
int test_wolfSSL_CTX_add_session_ext_dtls12(void)
{
EXPECT_DECLS;
#if defined(HAVE_IO_TESTS_DEPENDENCIES) && defined(HAVE_EXT_CACHE) && \
defined(WOLFSSL_TLS13) && !defined(NO_SESSION_CACHE) && \
defined(OPENSSL_EXTRA) && defined(SESSION_CERTS) && \
defined(HAVE_SESSION_TICKET) && \
!defined(TITAN_SESSION_CACHE) && \
!defined(HUGE_SESSION_CACHE) && \
!defined(BIG_SESSION_CACHE) && \
!defined(MEDIUM_SESSION_CACHE)
#ifndef WOLFSSL_NO_TLS12
#ifdef WOLFSSL_DTLS
struct test_add_session_ext_params param[1] = {
{ wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method, "DTLSv1_2" }
};
ExpectIntEQ(test_wolfSSL_CTX_add_session_ext(param), TEST_SUCCESS);
#endif
#endif
#endif
return EXPECT_RESULT();
}
int test_wolfSSL_CTX_add_session_ext_tls11(void)
{
EXPECT_DECLS;
#if defined(HAVE_IO_TESTS_DEPENDENCIES) && defined(HAVE_EXT_CACHE) && \
defined(WOLFSSL_TLS13) && !defined(NO_SESSION_CACHE) && \
defined(OPENSSL_EXTRA) && defined(SESSION_CERTS) && \
defined(HAVE_SESSION_TICKET) && \
!defined(TITAN_SESSION_CACHE) && \
!defined(HUGE_SESSION_CACHE) && \
!defined(BIG_SESSION_CACHE) && \
!defined(MEDIUM_SESSION_CACHE)
#if !defined(NO_OLD_TLS) && ((!defined(NO_AES) && !defined(NO_AES_CBC)) || \
!defined(NO_DES3))
struct test_add_session_ext_params param[1] = {
{ wolfTLSv1_1_client_method, wolfTLSv1_1_server_method, "TLSv1_1" }
};
ExpectIntEQ(test_wolfSSL_CTX_add_session_ext(param), TEST_SUCCESS);
#endif
#endif
return EXPECT_RESULT();
}
int test_wolfSSL_CTX_add_session_ext_dtls1(void)
{
EXPECT_DECLS;
#if defined(HAVE_IO_TESTS_DEPENDENCIES) && defined(HAVE_EXT_CACHE) && \
defined(WOLFSSL_TLS13) && !defined(NO_SESSION_CACHE) && \
defined(OPENSSL_EXTRA) && defined(SESSION_CERTS) && \
defined(HAVE_SESSION_TICKET) && \
!defined(TITAN_SESSION_CACHE) && \
!defined(HUGE_SESSION_CACHE) && \
!defined(BIG_SESSION_CACHE) && \
!defined(MEDIUM_SESSION_CACHE)
#if !defined(NO_OLD_TLS) && ((!defined(NO_AES) && !defined(NO_AES_CBC)) || \
!defined(NO_DES3))
#ifdef WOLFSSL_DTLS
struct test_add_session_ext_params param[1] = {
{ wolfDTLSv1_client_method, wolfDTLSv1_server_method, "DTLSv1_0" }
};
ExpectIntEQ(test_wolfSSL_CTX_add_session_ext(param), TEST_SUCCESS);
#endif
#endif
#endif
return EXPECT_RESULT();
}
/*----------------------------------------------------------------------------*/
/* WOLFSSL_SESSION, ticket keys and session removal callbacks */
/*----------------------------------------------------------------------------*/
int test_wolfSSL_SESSION(void)
{
EXPECT_DECLS;
#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) && \
!defined(NO_RSA) && !defined(NO_SHA256) && \
defined(HAVE_IO_TESTS_DEPENDENCIES) && !defined(NO_SESSION_CACHE)
WOLFSSL* ssl = NULL;
WOLFSSL_CTX* ctx = NULL;
WOLFSSL_SESSION* sess = NULL;
WOLFSSL_SESSION* sess_copy = NULL;
#ifdef OPENSSL_EXTRA
#ifdef HAVE_EXT_CACHE
unsigned char* sessDer = NULL;
unsigned char* ptr = NULL;
int sz = 0;
#endif
const unsigned char context[] = "user app context";
unsigned int contextSz = (unsigned int)sizeof(context);
#endif
int ret = 0, err = 0;
SOCKET_T sockfd;
tcp_ready ready;
func_args server_args;
THREAD_TYPE serverThread;
char msg[80];
const char* sendGET = "GET";
/* TLS v1.3 requires session tickets */
/* CHACHA and POLY1305 required for myTicketEncCb */
#if !defined(WOLFSSL_NO_TLS12) && (!defined(WOLFSSL_TLS13) || \
!(defined(HAVE_SESSION_TICKET) && ((defined(HAVE_CHACHA) && \
defined(HAVE_POLY1305)) || defined(HAVE_AESGCM))))
ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_2_client_method()));
#else
ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()));
#endif
ExpectTrue(wolfSSL_CTX_use_certificate_file(ctx, cliCertFile,
CERT_FILETYPE));
ExpectTrue(wolfSSL_CTX_use_PrivateKey_file(ctx, cliKeyFile,
CERT_FILETYPE));
ExpectIntEQ(wolfSSL_CTX_load_verify_locations(ctx, caCertFile, 0),
WOLFSSL_SUCCESS);
#ifdef WOLFSSL_ENCRYPTED_KEYS
wolfSSL_CTX_set_default_passwd_cb(ctx, PasswordCallBack);
#endif
#ifdef HAVE_SESSION_TICKET
/* Use session tickets, for ticket tests below */
ExpectIntEQ(wolfSSL_CTX_UseSessionTicket(ctx), WOLFSSL_SUCCESS);
#endif
XMEMSET(&server_args, 0, sizeof(func_args));
#ifdef WOLFSSL_TIRTOS
fdOpenSession(Task_self());
#endif
StartTCP();
InitTcpReady(&ready);
server_args.signal = &ready;
start_thread(test_server_nofail, &server_args, &serverThread);
wait_tcp_ready(&server_args);
/* client connection */
ExpectNotNull(ssl = wolfSSL_new(ctx));
tcp_connect(&sockfd, wolfSSLIP, ready.port, 0, 0, ssl);
ExpectIntEQ(wolfSSL_set_fd(ssl, sockfd), WOLFSSL_SUCCESS);
WOLFSSL_ASYNC_WHILE_PENDING(ret = wolfSSL_connect(ssl),
ret != WOLFSSL_SUCCESS);
ExpectIntEQ(ret, WOLFSSL_SUCCESS);
WOLFSSL_ASYNC_WHILE_PENDING(
ret = wolfSSL_write(ssl, sendGET, (int)XSTRLEN(sendGET)),
ret <= 0);
ExpectIntEQ(ret, (int)XSTRLEN(sendGET));
WOLFSSL_ASYNC_WHILE_PENDING(ret = wolfSSL_read(ssl, msg, sizeof(msg)),
ret != 23);
ExpectIntEQ(ret, 23);
ExpectPtrNE((sess = wolfSSL_get1_session(ssl)), NULL); /* ref count 1 */
ExpectPtrNE((sess_copy = wolfSSL_get1_session(ssl)), NULL); /* ref count 2 */
ExpectIntEQ(wolfSSL_SessionIsSetup(sess), 1);
#ifdef HAVE_EXT_CACHE
ExpectPtrEq(sess, sess_copy); /* they should be the same pointer but without
* HAVE_EXT_CACHE we get new objects each time */
#endif
wolfSSL_SESSION_free(sess_copy); sess_copy = NULL;
wolfSSL_SESSION_free(sess); sess = NULL; /* free session ref */
sess = wolfSSL_get_session(ssl);
#ifdef OPENSSL_EXTRA
ExpectIntEQ(SSL_SESSION_is_resumable(NULL), 0);
ExpectIntEQ(SSL_SESSION_is_resumable(sess), 1);
ExpectIntEQ(wolfSSL_SESSION_has_ticket(NULL), 0);
ExpectIntEQ(wolfSSL_SESSION_get_ticket_lifetime_hint(NULL), 0);
#ifdef HAVE_SESSION_TICKET
ExpectIntEQ(wolfSSL_SESSION_has_ticket(sess), 1);
ExpectIntEQ(wolfSSL_SESSION_get_ticket_lifetime_hint(sess),
SESSION_TICKET_HINT_DEFAULT);
#else
ExpectIntEQ(wolfSSL_SESSION_has_ticket(sess), 0);
#endif
#else
(void)sess;
#endif /* OPENSSL_EXTRA */
/* Retain copy of the session for later testing */
ExpectNotNull(sess = wolfSSL_get1_session(ssl));
wolfSSL_shutdown(ssl);
wolfSSL_free(ssl); ssl = NULL;
CloseSocket(sockfd);
join_thread(serverThread);
FreeTcpReady(&ready);
#ifdef WOLFSSL_TIRTOS
fdOpenSession(Task_self());
#endif
#if defined(SESSION_CERTS) && defined(OPENSSL_EXTRA)
{
X509 *x509 = NULL;
char buf[30];
int bufSz = 0;
ExpectNotNull(x509 = SSL_SESSION_get0_peer(sess));
ExpectIntGT((bufSz = X509_NAME_get_text_by_NID(
X509_get_subject_name(x509), NID_organizationalUnitName, buf,
sizeof(buf))), 0);
ExpectIntNE((bufSz == 7 || bufSz == 16), 0); /* should be one of these*/
if (bufSz == 7) {
ExpectIntEQ(XMEMCMP(buf, "Support", bufSz), 0);
}
if (bufSz == 16) {
ExpectIntEQ(XMEMCMP(buf, "Programming-2048", bufSz), 0);
}
}
#endif
#ifdef HAVE_EXT_CACHE
ExpectNotNull(sess_copy = wolfSSL_SESSION_dup(sess));
wolfSSL_SESSION_free(sess_copy); sess_copy = NULL;
sess_copy = NULL;
#endif
#if defined(OPENSSL_EXTRA) && defined(HAVE_EXT_CACHE)
/* get session from DER and update the timeout */
ExpectIntEQ(wolfSSL_i2d_SSL_SESSION(NULL, &sessDer), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntGT((sz = wolfSSL_i2d_SSL_SESSION(sess, &sessDer)), 0);
wolfSSL_SESSION_free(sess); sess = NULL;
sess = NULL;
ptr = sessDer;
ExpectNull(sess = wolfSSL_d2i_SSL_SESSION(NULL, NULL, sz));
ExpectNotNull(sess = wolfSSL_d2i_SSL_SESSION(NULL,
(const unsigned char**)&ptr, sz));
XFREE(sessDer, NULL, DYNAMIC_TYPE_OPENSSL);
sessDer = NULL;
ExpectIntGT(wolfSSL_SESSION_get_time(sess), 0);
ExpectIntEQ(wolfSSL_SSL_SESSION_set_timeout(sess, 500), SSL_SUCCESS);
#endif
/* successful set session test */
ExpectNotNull(ssl = wolfSSL_new(ctx));
ExpectIntEQ(wolfSSL_set_session(ssl, sess), WOLFSSL_SUCCESS);
#ifdef HAVE_SESSION_TICKET
/* Test set/get session ticket */
{
const char* ticket = "This is a session ticket";
char buf[64] = {0};
word32 bufSz = (word32)sizeof(buf);
word32 retSz = 0;
ExpectIntEQ(WOLFSSL_SUCCESS,
wolfSSL_set_SessionTicket(ssl, (byte *)ticket,
(word32)XSTRLEN(ticket)));
ExpectIntEQ(WOLFSSL_SUCCESS,
wolfSSL_get_SessionTicket(ssl, (byte *)buf, &bufSz));
ExpectStrEQ(ticket, buf);
/* return ticket length if buffer parameter is null */
wolfSSL_get_SessionTicket(ssl, NULL, &retSz);
ExpectIntEQ(bufSz, retSz);
}
#endif
#ifdef OPENSSL_EXTRA
/* session timeout case */
/* make the session to be expired */
ExpectIntEQ(SSL_SESSION_set_timeout(sess,1), SSL_SUCCESS);
XSLEEP_MS(1200);
/* SSL_set_session should reject specified session but return success
* if WOLFSSL_ERROR_CODE_OPENSSL macro is defined for OpenSSL compatibility.
*/
#if defined(WOLFSSL_ERROR_CODE_OPENSSL)
ExpectIntEQ(wolfSSL_set_session(ssl,sess), SSL_SUCCESS);
#else
ExpectIntEQ(wolfSSL_set_session(ssl,sess), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
#endif
ExpectIntEQ(wolfSSL_SSL_SESSION_set_timeout(sess, 500), SSL_SUCCESS);
#ifdef WOLFSSL_SESSION_ID_CTX
/* fail case with miss match session context IDs (use compatibility API) */
ExpectIntEQ(SSL_set_session_id_context(ssl, context, contextSz),
SSL_SUCCESS);
ExpectIntEQ(wolfSSL_set_session(ssl, sess), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
wolfSSL_free(ssl); ssl = NULL;
ExpectIntEQ(SSL_CTX_set_session_id_context(NULL, context, contextSz),
WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
ExpectIntEQ(SSL_CTX_set_session_id_context(ctx, context, contextSz),
SSL_SUCCESS);
ExpectNotNull(ssl = wolfSSL_new(ctx));
ExpectIntEQ(wolfSSL_set_session(ssl, sess), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
#endif
#endif /* OPENSSL_EXTRA */
wolfSSL_free(ssl);
wolfSSL_SESSION_free(sess);
wolfSSL_CTX_free(ctx);
#endif
return EXPECT_RESULT();
}
#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) && \
!defined(NO_RSA) && defined(HAVE_IO_TESTS_DEPENDENCIES) && \
!defined(NO_SESSION_CACHE) && defined(OPENSSL_EXTRA) && \
!defined(WOLFSSL_NO_TLS12)
static WOLFSSL_SESSION* test_wolfSSL_SESSION_expire_sess = NULL;
static void test_wolfSSL_SESSION_expire_downgrade_ctx_ready(WOLFSSL_CTX* ctx)
{
#ifdef WOLFSSL_ERROR_CODE_OPENSSL
/* returns previous timeout value */
AssertIntEQ(wolfSSL_CTX_set_timeout(ctx, 1), 500);
#else
AssertIntEQ(wolfSSL_CTX_set_timeout(ctx, 1), WOLFSSL_SUCCESS);
#endif
}
/* set the session to timeout in a second */
static void test_wolfSSL_SESSION_expire_downgrade_ssl_ready(WOLFSSL* ssl)
{
AssertIntEQ(wolfSSL_set_timeout(ssl, 2), 1);
}
/* store the client side session from the first successful connection */
static void test_wolfSSL_SESSION_expire_downgrade_ssl_result(WOLFSSL* ssl)
{
AssertPtrNE((test_wolfSSL_SESSION_expire_sess = wolfSSL_get1_session(ssl)),
NULL); /* ref count 1 */
}
/* wait till session is expired then set it in the WOLFSSL struct for use */
static void test_wolfSSL_SESSION_expire_downgrade_ssl_ready_wait(WOLFSSL* ssl)
{
AssertIntEQ(wolfSSL_set_timeout(ssl, 1), 1);
AssertIntEQ(wolfSSL_set_session(ssl, test_wolfSSL_SESSION_expire_sess),
WOLFSSL_SUCCESS);
XSLEEP_MS(2000); /* wait 2 seconds for session to expire */
}
/* set expired session in the WOLFSSL struct for use */
static void test_wolfSSL_SESSION_expire_downgrade_ssl_ready_set(WOLFSSL* ssl)
{
XSLEEP_MS(1200); /* wait a second for session to expire */
/* set the expired session, call to set session fails but continuing on
after failure should be handled here */
#if defined(OPENSSL_EXTRA) && defined(WOLFSSL_ERROR_CODE_OPENSSL)
AssertIntEQ(wolfSSL_set_session(ssl, test_wolfSSL_SESSION_expire_sess),
WOLFSSL_SUCCESS);
#else
AssertIntNE(wolfSSL_set_session(ssl, test_wolfSSL_SESSION_expire_sess),
WOLFSSL_SUCCESS);
#endif
}
/* check that the expired session was not reused */
static void test_wolfSSL_SESSION_expire_downgrade_ssl_result_reuse(WOLFSSL* ssl)
{
/* since the session has expired it should not have been reused */
AssertIntEQ(wolfSSL_session_reused(ssl), 0);
}
#endif
int test_wolfSSL_SESSION_expire_downgrade(void)
{
EXPECT_DECLS;
#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) && \
!defined(NO_RSA) && defined(HAVE_IO_TESTS_DEPENDENCIES) && \
!defined(NO_SESSION_CACHE) && defined(OPENSSL_EXTRA) && \
!defined(WOLFSSL_NO_TLS12)
callback_functions server_cbf, client_cbf;
XMEMSET(&server_cbf, 0, sizeof(callback_functions));
XMEMSET(&client_cbf, 0, sizeof(callback_functions));
/* force server side to use TLS 1.2 */
server_cbf.method = wolfTLSv1_2_server_method;
client_cbf.method = wolfSSLv23_client_method;
server_cbf.ctx_ready = test_wolfSSL_SESSION_expire_downgrade_ctx_ready;
client_cbf.ssl_ready = test_wolfSSL_SESSION_expire_downgrade_ssl_ready;
client_cbf.on_result = test_wolfSSL_SESSION_expire_downgrade_ssl_result;
test_wolfSSL_client_server_nofail(&client_cbf, &server_cbf);
ExpectIntEQ(client_cbf.return_code, TEST_SUCCESS);
ExpectIntEQ(server_cbf.return_code, TEST_SUCCESS);
client_cbf.method = wolfSSLv23_client_method;
server_cbf.ctx_ready = test_wolfSSL_SESSION_expire_downgrade_ctx_ready;
client_cbf.ssl_ready = test_wolfSSL_SESSION_expire_downgrade_ssl_ready_wait;
client_cbf.on_result =
test_wolfSSL_SESSION_expire_downgrade_ssl_result_reuse;
test_wolfSSL_client_server_nofail(&client_cbf, &server_cbf);
ExpectIntEQ(client_cbf.return_code, TEST_SUCCESS);
ExpectIntEQ(server_cbf.return_code, TEST_SUCCESS);
client_cbf.method = wolfSSLv23_client_method;
server_cbf.ctx_ready = test_wolfSSL_SESSION_expire_downgrade_ctx_ready;
client_cbf.ssl_ready = test_wolfSSL_SESSION_expire_downgrade_ssl_ready_set;
client_cbf.on_result =
test_wolfSSL_SESSION_expire_downgrade_ssl_result_reuse;
test_wolfSSL_client_server_nofail(&client_cbf, &server_cbf);
ExpectIntEQ(client_cbf.return_code, TEST_SUCCESS);
ExpectIntEQ(server_cbf.return_code, TEST_SUCCESS);
wolfSSL_SESSION_free(test_wolfSSL_SESSION_expire_sess);
#endif
return EXPECT_RESULT();
}
#if defined(OPENSSL_EXTRA) && defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES) && \
defined(HAVE_EX_DATA) && !defined(NO_SESSION_CACHE)
#ifdef WOLFSSL_ATOMIC_OPS
typedef wolfSSL_Atomic_Int SessRemCounter_t;
#else
typedef int SessRemCounter_t;
#endif
static SessRemCounter_t clientSessRemCountMalloc;
static SessRemCounter_t serverSessRemCountMalloc;
static SessRemCounter_t clientSessRemCountFree;
static SessRemCounter_t serverSessRemCountFree;
static WOLFSSL_CTX* serverSessCtx = NULL;
static WOLFSSL_SESSION* serverSess = NULL;
#if (defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET)) || \
!defined(NO_SESSION_CACHE_REF)
static WOLFSSL_CTX* clientSessCtx = NULL;
static WOLFSSL_SESSION* clientSess = NULL;
#endif
static int serverSessRemIdx = 3;
static int sessRemCtx_Server = WOLFSSL_SERVER_END;
static int sessRemCtx_Client = WOLFSSL_CLIENT_END;
static void SessRemCtxCb(WOLFSSL_CTX *ctx, WOLFSSL_SESSION *sess)
{
int* side;
(void)ctx;
side = (int*)SSL_SESSION_get_ex_data(sess, serverSessRemIdx);
if (side != NULL) {
if (*side == WOLFSSL_CLIENT_END)
(void)wolfSSL_Atomic_Int_FetchAdd(&clientSessRemCountFree, 1);
else
(void)wolfSSL_Atomic_Int_FetchAdd(&serverSessRemCountFree, 1);
SSL_SESSION_set_ex_data(sess, serverSessRemIdx, NULL);
}
}
static int SessRemCtxSetupCb(WOLFSSL_CTX* ctx)
{
SSL_CTX_sess_set_remove_cb(ctx, SessRemCtxCb);
#if defined(WOLFSSL_TLS13) && !defined(HAVE_SESSION_TICKET) && \
!defined(NO_SESSION_CACHE_REF)
{
EXPECT_DECLS;
/* Allow downgrade, set min version, and disable TLS 1.3.
* Do this because without NO_SESSION_CACHE_REF we will want to return a
* reference to the session cache. But with WOLFSSL_TLS13 and without
* HAVE_SESSION_TICKET we won't have a session ID to be able to place
* the session in the cache. In this case we need to downgrade to
* previous versions to just use the legacy session ID field. */
ExpectIntEQ(SSL_CTX_set_min_proto_version(ctx, SSL3_VERSION),
SSL_SUCCESS);
ExpectIntEQ(SSL_CTX_set_max_proto_version(ctx, TLS1_2_VERSION),
SSL_SUCCESS);
return EXPECT_RESULT();
}
#else
return TEST_SUCCESS;
#endif
}
static int SessRemSslSetupCb(WOLFSSL* ssl)
{
EXPECT_DECLS;
int* side;
if (SSL_is_server(ssl)) {
side = &sessRemCtx_Server;
(void)wolfSSL_Atomic_Int_FetchAdd(&serverSessRemCountMalloc, 1);
ExpectNotNull(serverSess = SSL_get1_session(ssl));
ExpectIntEQ(SSL_CTX_up_ref(serverSessCtx = SSL_get_SSL_CTX(ssl)),
SSL_SUCCESS);
}
else {
side = &sessRemCtx_Client;
(void)wolfSSL_Atomic_Int_FetchAdd(&clientSessRemCountMalloc, 1);
#if (defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET)) || \
!defined(NO_SESSION_CACHE_REF)
ExpectNotNull(clientSess = SSL_get1_session(ssl));
ExpectIntEQ(SSL_CTX_up_ref(clientSessCtx = SSL_get_SSL_CTX(ssl)),
SSL_SUCCESS);
#endif
}
ExpectIntEQ(SSL_SESSION_set_ex_data(SSL_get_session(ssl),
serverSessRemIdx, side), SSL_SUCCESS);
return EXPECT_RESULT();
}
#endif
int test_wolfSSL_CTX_sess_set_remove_cb(void)
{
EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES) && \
defined(HAVE_EX_DATA) && !defined(NO_SESSION_CACHE)
/* Check that the remove callback gets called for external data in a
* session object */
test_ssl_cbf func_cb;
wolfSSL_Atomic_Int_Init(&clientSessRemCountMalloc, 0);
wolfSSL_Atomic_Int_Init(&serverSessRemCountMalloc, 0);
wolfSSL_Atomic_Int_Init(&clientSessRemCountFree, 0);
wolfSSL_Atomic_Int_Init(&serverSessRemCountFree, 0);
XMEMSET(&func_cb, 0, sizeof(func_cb));
func_cb.ctx_ready = SessRemCtxSetupCb;
func_cb.on_result = SessRemSslSetupCb;
ExpectIntEQ(test_wolfSSL_client_server_nofail_memio(&func_cb, &func_cb,
NULL), TEST_SUCCESS);
/* Both should have been allocated */
ExpectIntEQ(clientSessRemCountMalloc, 1);
ExpectIntEQ(serverSessRemCountMalloc, 1);
/* This should not be called yet. Session wasn't evicted from cache yet. */
ExpectIntEQ(clientSessRemCountFree, 0);
#if (defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET)) || \
!defined(NO_SESSION_CACHE_REF)
/* Force a cache lookup */
ExpectNotNull(SSL_SESSION_get_ex_data(clientSess, serverSessRemIdx));
/* Force a cache update */
ExpectNotNull(SSL_SESSION_set_ex_data(clientSess, serverSessRemIdx - 1, 0));
/* This should set the timeout to 0 and call the remove callback from within
* the session cache. Returns 1 per OpenSSL semantics (session was
* present in the cache and removed). */
ExpectIntEQ(SSL_CTX_remove_session(clientSessCtx, clientSess), 1);
ExpectNull(SSL_SESSION_get_ex_data(clientSess, serverSessRemIdx));
ExpectIntEQ(clientSessRemCountFree, 1);
#endif
/* Server session is in the cache so ex_data isn't free'd with the SSL
* object */
ExpectIntEQ(serverSessRemCountFree, 0);
/* Force a cache lookup */
ExpectNotNull(SSL_SESSION_get_ex_data(serverSess, serverSessRemIdx));
/* Force a cache update */
ExpectNotNull(SSL_SESSION_set_ex_data(serverSess, serverSessRemIdx - 1, 0));
/* This should set the timeout to 0 and call the remove callback from within
* the session cache. Returns 1 per OpenSSL semantics (session was
* present in the cache and removed). */
ExpectIntEQ(SSL_CTX_remove_session(serverSessCtx, serverSess), 1);
ExpectNull(SSL_SESSION_get_ex_data(serverSess, serverSessRemIdx));
ExpectIntEQ(serverSessRemCountFree, 1);
/* Need to free the references that we kept */
SSL_CTX_free(serverSessCtx);
SSL_SESSION_free(serverSess);
#if (defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET)) || \
!defined(NO_SESSION_CACHE_REF)
SSL_CTX_free(clientSessCtx);
SSL_SESSION_free(clientSess);
#endif
#endif
return EXPECT_RESULT();
}
int test_wolfSSL_ticket_keys(void)
{
EXPECT_DECLS;
#if defined(HAVE_SESSION_TICKET) && !defined(WOLFSSL_NO_DEF_TICKET_ENC_CB) && \
!defined(NO_WOLFSSL_SERVER) && !defined(NO_TLS)
WOLFSSL_CTX* ctx = NULL;
byte keys[WOLFSSL_TICKET_KEYS_SZ];
ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method()));
ExpectIntEQ(wolfSSL_CTX_get_tlsext_ticket_keys(NULL, NULL, 0),
WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
ExpectIntEQ(wolfSSL_CTX_get_tlsext_ticket_keys(ctx, NULL, 0),
WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
ExpectIntEQ(wolfSSL_CTX_get_tlsext_ticket_keys(ctx, keys, 0),
WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
ExpectIntEQ(wolfSSL_CTX_get_tlsext_ticket_keys(NULL, keys, 0),
WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
ExpectIntEQ(wolfSSL_CTX_get_tlsext_ticket_keys(NULL, NULL, sizeof(keys)),
WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
ExpectIntEQ(wolfSSL_CTX_get_tlsext_ticket_keys(ctx, NULL, sizeof(keys)),
WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
ExpectIntEQ(wolfSSL_CTX_get_tlsext_ticket_keys(NULL, keys, sizeof(keys)),
WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
ExpectIntEQ(wolfSSL_CTX_set_tlsext_ticket_keys(NULL, NULL, 0),
WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
ExpectIntEQ(wolfSSL_CTX_set_tlsext_ticket_keys(ctx, NULL, 0),
WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
ExpectIntEQ(wolfSSL_CTX_set_tlsext_ticket_keys(ctx, keys, 0),
WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
ExpectIntEQ(wolfSSL_CTX_set_tlsext_ticket_keys(NULL, keys, 0),
WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
ExpectIntEQ(wolfSSL_CTX_set_tlsext_ticket_keys(NULL, NULL, sizeof(keys)),
WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
ExpectIntEQ(wolfSSL_CTX_set_tlsext_ticket_keys(ctx, NULL, sizeof(keys)),
WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
ExpectIntEQ(wolfSSL_CTX_set_tlsext_ticket_keys(NULL, keys, sizeof(keys)),
WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
ExpectIntEQ(wolfSSL_CTX_get_tlsext_ticket_keys(ctx, keys, sizeof(keys)),
WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_CTX_set_tlsext_ticket_keys(ctx, keys, sizeof(keys)),
WOLFSSL_SUCCESS);
wolfSSL_CTX_free(ctx);
#endif
return EXPECT_RESULT();
}
/*----------------------------------------------------------------------------*/
/* SESSION ex_data new index */
/*----------------------------------------------------------------------------*/
#if defined(HAVE_EX_DATA_CRYPTO) && defined(OPENSSL_EXTRA)
#define SESSION_NEW_IDX_LONG 0xDEADBEEF
#define SESSION_NEW_IDX_VAL ((void*)0xAEADAEAD)
#define SESSION_DUP_IDX_VAL ((void*)0xDEDEDEDE)
#define SESSION_NEW_IDX_PTR "Testing"
static void test_wolfSSL_SESSION_get_ex_new_index_new_cb(void* p, void* ptr,
CRYPTO_EX_DATA* a, int idx, long argValue, void* arg)
{
AssertNotNull(p);
AssertNull(ptr);
AssertIntEQ(CRYPTO_set_ex_data(a, idx, SESSION_NEW_IDX_VAL), SSL_SUCCESS);
AssertIntEQ(argValue, SESSION_NEW_IDX_LONG);
AssertStrEQ(arg, SESSION_NEW_IDX_PTR);
}
static int test_wolfSSL_SESSION_get_ex_new_index_dup_cb(CRYPTO_EX_DATA* out,
const CRYPTO_EX_DATA* in, void* inPtr, int idx, long argV,
void* arg)
{
EXPECT_DECLS;
ExpectNotNull(out);
ExpectNotNull(in);
ExpectPtrEq(*(void**)inPtr, SESSION_NEW_IDX_VAL);
ExpectPtrEq(CRYPTO_get_ex_data(in, idx), SESSION_NEW_IDX_VAL);
ExpectPtrEq(CRYPTO_get_ex_data(out, idx), SESSION_NEW_IDX_VAL);
ExpectIntEQ(argV, SESSION_NEW_IDX_LONG);
ExpectStrEQ(arg, SESSION_NEW_IDX_PTR);
*(void**)inPtr = SESSION_DUP_IDX_VAL;
if (EXPECT_SUCCESS()) {
return SSL_SUCCESS;
}
else {
return SSL_FAILURE;
}
}
static int test_wolfSSL_SESSION_get_ex_new_index_free_cb_called = 0;
static void test_wolfSSL_SESSION_get_ex_new_index_free_cb(void* p, void* ptr,
CRYPTO_EX_DATA* a, int idx, long argValue, void* arg)
{
EXPECT_DECLS;
ExpectNotNull(p);
ExpectNull(ptr);
ExpectPtrNE(CRYPTO_get_ex_data(a, idx), 0);
ExpectIntEQ(argValue, SESSION_NEW_IDX_LONG);
ExpectStrEQ(arg, SESSION_NEW_IDX_PTR);
if (EXPECT_SUCCESS()) {
test_wolfSSL_SESSION_get_ex_new_index_free_cb_called++;
}
}
int test_wolfSSL_SESSION_get_ex_new_index(void)
{
EXPECT_DECLS;
int idx = SSL_SESSION_get_ex_new_index(SESSION_NEW_IDX_LONG,
(void*)SESSION_NEW_IDX_PTR,
test_wolfSSL_SESSION_get_ex_new_index_new_cb,
test_wolfSSL_SESSION_get_ex_new_index_dup_cb,
test_wolfSSL_SESSION_get_ex_new_index_free_cb);
SSL_SESSION* s = SSL_SESSION_new();
SSL_SESSION* d = NULL;
ExpectNotNull(s);
ExpectPtrEq(SSL_SESSION_get_ex_data(s, idx), SESSION_NEW_IDX_VAL);
ExpectNotNull(d = SSL_SESSION_dup(s));
ExpectPtrEq(SSL_SESSION_get_ex_data(d, idx), SESSION_DUP_IDX_VAL);
SSL_SESSION_free(s);
ExpectIntEQ(test_wolfSSL_SESSION_get_ex_new_index_free_cb_called, 1);
SSL_SESSION_free(d);
ExpectIntEQ(test_wolfSSL_SESSION_get_ex_new_index_free_cb_called, 2);
crypto_ex_cb_free(crypto_ex_cb_ctx_session);
crypto_ex_cb_ctx_session = NULL;
return EXPECT_RESULT();
}
#else
int test_wolfSSL_SESSION_get_ex_new_index(void)
{
return TEST_SKIPPED;
}
#endif