diff --git a/CMakeLists.txt b/CMakeLists.txt index 4a2c0e9750..217a9e1574 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2942,11 +2942,14 @@ if(WOLFSSL_EXAMPLES) tests/api/test_mldsa_legacy.c tests/api/test_slhdsa.c tests/api/test_signature.c + tests/api/test_lms_xmss.c tests/api/test_dtls.c + tests/api/test_dtls13.c tests/api/test_ocsp.c tests/api/test_evp.c tests/api/test_tls_ext.c tests/api/test_tls.c + tests/api/test_session.c tests/api/test_x509.c tests/api/test_asn.c tests/api/test_pkcs7.c diff --git a/tests/api.c b/tests/api.c index fe92bdee85..a2873fd747 100644 --- a/tests/api.c +++ b/tests/api.c @@ -234,12 +234,15 @@ #include #include #include +#include #include #include #include #include +#include #include #include +#include #include #include #include @@ -6383,7 +6386,7 @@ static void test_client_reuse_WOLFSSLobj(void* args, cbType cb, #if defined(ENABLE_TLS_CALLBACK_TEST) || \ (defined(WOLFSSL_DTLS) && defined(WOLFSSL_SESSION_EXPORT)) /* TLS server for API unit testing - generic */ -static THREAD_RETURN WOLFSSL_THREAD run_wolfssl_server(void* args) +THREAD_RETURN WOLFSSL_THREAD run_wolfssl_server(void* args) { callback_functions* callbacks = ((func_args*)args)->callbacks; @@ -6640,7 +6643,7 @@ static THREAD_RETURN WOLFSSL_THREAD run_wolfssl_server(void* args) } /* TLS Client for API unit testing - generic */ -static void run_wolfssl_client(void* args) +void run_wolfssl_client(void* args) { callback_functions* callbacks = ((func_args*)args)->callbacks; @@ -7196,1152 +7199,6 @@ static int test_wolfSSL_get_finished(void) return EXPECT_RESULT(); } -#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 - -static 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; -}; - -static 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 - -static 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(); -} -static 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(); -} -static 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(); -} -static 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(); -} -static 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(); -} -static 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(); -} - -#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_SESSION_EXPORT) -/* canned export of a session using older version 3 */ -static unsigned char version_3[] = { - 0xA5, 0xA3, 0x01, 0x88, 0x00, 0x3c, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x80, 0x0C, 0x00, 0x00, 0x00, - 0x00, 0x80, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x30, - 0x05, 0x09, 0x0A, 0x01, 0x01, 0x00, 0x0D, 0x05, - 0xFE, 0xFD, 0x01, 0x25, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x06, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x06, 0x00, 0x01, 0x00, 0x07, 0x00, 0x00, - 0x00, 0x30, 0x00, 0x00, 0x00, 0x10, 0x01, 0x01, - 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x3F, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x05, - 0x12, 0xCF, 0x22, 0xA1, 0x9F, 0x1C, 0x39, 0x1D, - 0x31, 0x11, 0x12, 0x1D, 0x11, 0x18, 0x0D, 0x0B, - 0xF3, 0xE1, 0x4D, 0xDC, 0xB1, 0xF1, 0x39, 0x98, - 0x91, 0x6C, 0x48, 0xE5, 0xED, 0x11, 0x12, 0xA0, - 0x00, 0xF2, 0x25, 0x4C, 0x09, 0x26, 0xD1, 0x74, - 0xDF, 0x23, 0x40, 0x15, 0x6A, 0x42, 0x2A, 0x26, - 0xA5, 0xAC, 0x56, 0xD5, 0x4A, 0x20, 0xB7, 0xE9, - 0xEF, 0xEB, 0xAF, 0xA8, 0x1E, 0x23, 0x7C, 0x04, - 0xAA, 0xA1, 0x6D, 0x92, 0x79, 0x7B, 0xFA, 0x80, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0x0C, 0x79, 0x7B, 0xFA, 0x80, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xA1, 0x6D, - 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x10, 0x00, 0x20, 0x00, 0x04, 0x00, - 0x10, 0x00, 0x10, 0x08, 0x02, 0x05, 0x08, 0x01, - 0x30, 0x28, 0x00, 0x00, 0x0F, 0x00, 0x02, 0x00, - 0x09, 0x31, 0x32, 0x37, 0x2E, 0x30, 0x2E, 0x30, - 0x2E, 0x31, 0xED, 0x4F -}; -#endif /* defined(WOLFSSL_DTLS) && defined(WOLFSSL_SESSION_EXPORT) */ - -static int test_wolfSSL_dtls_export(void) -{ - EXPECT_DECLS; -#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_SESSION_EXPORT) - tcp_ready ready; - func_args client_args; - func_args server_args; - THREAD_TYPE serverThread; - callback_functions server_cbf; - callback_functions client_cbf; -#ifdef WOLFSSL_TIRTOS - fdOpenSession(Task_self()); -#endif - - InitTcpReady(&ready); - - /* set using dtls */ - XMEMSET(&client_args, 0, sizeof(func_args)); - XMEMSET(&server_args, 0, sizeof(func_args)); - XMEMSET(&server_cbf, 0, sizeof(callback_functions)); - XMEMSET(&client_cbf, 0, sizeof(callback_functions)); - server_cbf.method = wolfDTLSv1_2_server_method; - client_cbf.method = wolfDTLSv1_2_client_method; - server_args.callbacks = &server_cbf; - client_args.callbacks = &client_cbf; - - server_args.signal = &ready; - client_args.signal = &ready; - - start_thread(run_wolfssl_server, &server_args, &serverThread); - wait_tcp_ready(&server_args); - run_wolfssl_client(&client_args); - join_thread(serverThread); - - ExpectTrue(client_args.return_code); - ExpectTrue(server_args.return_code); - - FreeTcpReady(&ready); - -#ifdef WOLFSSL_TIRTOS - fdOpenSession(Task_self()); -#endif - - if (EXPECT_SUCCESS()) { - SOCKET_T sockfd = 0; - WOLFSSL_CTX* ctx = NULL; - WOLFSSL* ssl = NULL; - char msg[64] = "hello wolfssl!"; - char reply[1024]; - int msgSz = (int)XSTRLEN(msg); - byte *session, *window; - unsigned int sessionSz = 0; - unsigned int windowSz = 0; - -#ifndef TEST_IPV6 - struct sockaddr_in peerAddr; -#else - struct sockaddr_in6 peerAddr; -#endif /* TEST_IPV6 */ - - int i; - - - /* Set ctx to DTLS 1.2 */ - ExpectNotNull(ctx = wolfSSL_CTX_new(wolfDTLSv1_2_server_method())); - ExpectNotNull(ssl = wolfSSL_new(ctx)); - - /* test importing version 3 */ - ExpectIntGE(wolfSSL_dtls_import(ssl, version_3, sizeof(version_3)), 0); - - /* test importing bad length and bad version */ - version_3[2]++; - ExpectIntLT(wolfSSL_dtls_import(ssl, version_3, sizeof(version_3)), 0); - version_3[2]--; version_3[1] = 0XA0; - ExpectIntLT(wolfSSL_dtls_import(ssl, version_3, sizeof(version_3)), 0); - wolfSSL_free(ssl); - wolfSSL_CTX_free(ctx); - - - /* check storing client state after connection and storing window only */ -#ifdef WOLFSSL_TIRTOS - fdOpenSession(Task_self()); -#endif - - InitTcpReady(&ready); - - /* set using dtls */ - XMEMSET(&server_args, 0, sizeof(func_args)); - XMEMSET(&server_cbf, 0, sizeof(callback_functions)); - server_cbf.method = wolfDTLSv1_2_server_method; - server_cbf.doUdp = 1; - server_args.callbacks = &server_cbf; - server_args.argc = 3; /* set loop_count to 3 */ - - - server_args.signal = &ready; - start_thread(test_server_nofail, &server_args, &serverThread); - wait_tcp_ready(&server_args); - - /* create and connect with client */ - ExpectNotNull(ctx = wolfSSL_CTX_new(wolfDTLSv1_2_client_method())); - ExpectIntEQ(WOLFSSL_SUCCESS, - wolfSSL_CTX_load_verify_locations(ctx, caCertFile, 0)); - ExpectIntEQ(WOLFSSL_SUCCESS, - wolfSSL_CTX_use_certificate_file(ctx, cliCertFile, SSL_FILETYPE_PEM)); - ExpectIntEQ(WOLFSSL_SUCCESS, - wolfSSL_CTX_use_PrivateKey_file(ctx, cliKeyFile, SSL_FILETYPE_PEM)); - tcp_connect(&sockfd, wolfSSLIP, server_args.signal->port, 1, 0, NULL); - ExpectNotNull(ssl = wolfSSL_new(ctx)); - ExpectIntEQ(wolfSSL_set_fd(ssl, sockfd), WOLFSSL_SUCCESS); - - /* store server information connected too */ - XMEMSET(&peerAddr, 0, sizeof(peerAddr)); -#ifndef TEST_IPV6 - peerAddr.sin_family = AF_INET; - ExpectIntEQ(XINET_PTON(AF_INET, wolfSSLIP, &peerAddr.sin_addr),1); - peerAddr.sin_port = XHTONS(server_args.signal->port); -#else - peerAddr.sin6_family = AF_INET6; - ExpectIntEQ( - XINET_PTON(AF_INET6, wolfSSLIP, &peerAddr.sin6_addr),1); - peerAddr.sin6_port = XHTONS(server_args.signal->port); -#endif - - ExpectIntEQ(wolfSSL_dtls_set_peer(ssl, &peerAddr, sizeof(peerAddr)), - WOLFSSL_SUCCESS); - - ExpectIntEQ(wolfSSL_connect(ssl), WOLFSSL_SUCCESS); - ExpectIntEQ(wolfSSL_dtls_export(ssl, NULL, &sessionSz), 0); - session = (byte*)XMALLOC(sessionSz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); - ExpectIntGT(wolfSSL_dtls_export(ssl, session, &sessionSz), 0); - ExpectIntEQ(wolfSSL_write(ssl, msg, msgSz), msgSz); - ExpectIntGT(wolfSSL_read(ssl, reply, sizeof(reply)), 0); - ExpectIntEQ(wolfSSL_dtls_export_state_only(ssl, NULL, &windowSz), 0); - window = (byte*)XMALLOC(windowSz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); - ExpectIntGT(wolfSSL_dtls_export_state_only(ssl, window, &windowSz), 0); - wolfSSL_free(ssl); - - for (i = 1; EXPECT_SUCCESS() && i < server_args.argc; i++) { - /* restore state */ - ExpectNotNull(ssl = wolfSSL_new(ctx)); - ExpectIntGT(wolfSSL_dtls_import(ssl, session, sessionSz), 0); - ExpectIntGT(wolfSSL_dtls_import(ssl, window, windowSz), 0); - ExpectIntEQ(wolfSSL_set_fd(ssl, sockfd), WOLFSSL_SUCCESS); - ExpectIntEQ(wolfSSL_dtls_set_peer(ssl, &peerAddr, sizeof(peerAddr)), - WOLFSSL_SUCCESS); - ExpectIntEQ(wolfSSL_write(ssl, msg, msgSz), msgSz); - ExpectIntGE(wolfSSL_read(ssl, reply, sizeof(reply)), 0); - ExpectIntGT(wolfSSL_dtls_export_state_only(ssl, window, &windowSz), 0); - wolfSSL_free(ssl); - } - XFREE(session, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(window, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); - wolfSSL_CTX_free(ctx); - - fprintf(stderr, "done and waiting for server\n"); - join_thread(serverThread); - ExpectIntEQ(server_args.return_code, TEST_SUCCESS); - - FreeTcpReady(&ready); - -#ifdef WOLFSSL_TIRTOS - fdOpenSession(Task_self()); -#endif - } -#endif - - return EXPECT_RESULT(); -} #if defined(WOLFSSL_SESSION_EXPORT) && !defined(WOLFSSL_NO_TLS12) #ifdef WOLFSSL_TLS13 @@ -9270,259 +8127,42 @@ static int test_wolfSSL_SNI_GetFromBuffer(void) #endif /* HAVE_IO_TESTS_DEPENDENCIES */ -#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_SESSION_EXPORT) && \ - defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES) -/* Dummy peer functions to satisfy the exporter/importer */ -static int test_wolfSSL_dtls_export_peers_get_peer(WOLFSSL* ssl, char* ip, - int* ipSz, unsigned short* port, int* fam) -{ - (void)ssl; - ip[0] = -1; - *ipSz = 1; - *port = 1; - *fam = 2; - return 1; -} - -static int test_wolfSSL_dtls_export_peers_set_peer(WOLFSSL* ssl, char* ip, - int ipSz, unsigned short port, int fam) -{ - (void)ssl; - if (ip[0] != -1 || ipSz != 1 || port != 1 || fam != 2) - return 0; - return 1; -} -static int test_wolfSSL_dtls_export_peers_on_handshake(WOLFSSL_CTX **ctx, - WOLFSSL **ssl) +static int test_wolfSSL_UseTrustedCA(void) { EXPECT_DECLS; - unsigned char* sessionBuf = NULL; - unsigned int sessionSz = 0; - void* ioWriteCtx = wolfSSL_GetIOWriteCtx(*ssl); - void* ioReadCtx = wolfSSL_GetIOReadCtx(*ssl); +#if defined(HAVE_TRUSTED_CA) && !defined(NO_CERTS) && !defined(NO_FILESYSTEM) \ + && !defined(NO_RSA) +#if !defined(NO_TLS) && \ + (!defined(NO_WOLFSSL_CLIENT) || !defined(NO_WOLFSSL_SERVER)) + WOLFSSL_CTX *ctx = NULL; + WOLFSSL *ssl = NULL; + byte id[20]; - wolfSSL_CTX_SetIOGetPeer(*ctx, test_wolfSSL_dtls_export_peers_get_peer); - wolfSSL_CTX_SetIOSetPeer(*ctx, test_wolfSSL_dtls_export_peers_set_peer); - ExpectIntGE(wolfSSL_dtls_export(*ssl, NULL, &sessionSz), 0); - ExpectNotNull(sessionBuf = - (unsigned char*)XMALLOC(sessionSz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER)); - ExpectIntGE(wolfSSL_dtls_export(*ssl, sessionBuf, &sessionSz), 0); - wolfSSL_free(*ssl); - *ssl = NULL; - ExpectNotNull(*ssl = wolfSSL_new(*ctx)); - ExpectIntGE(wolfSSL_dtls_import(*ssl, sessionBuf, sessionSz), 0); - wolfSSL_SetIOWriteCtx(*ssl, ioWriteCtx); - wolfSSL_SetIOReadCtx(*ssl, ioReadCtx); +#ifndef NO_WOLFSSL_SERVER + ExpectNotNull((ctx = wolfSSL_CTX_new(wolfSSLv23_server_method()))); + ExpectTrue(wolfSSL_CTX_use_certificate_file(ctx, svrCertFile, WOLFSSL_FILETYPE_PEM)); + ExpectTrue(wolfSSL_CTX_use_PrivateKey_file(ctx, svrKeyFile, WOLFSSL_FILETYPE_PEM)); +#else + ExpectNotNull((ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()))); +#endif + ExpectNotNull((ssl = wolfSSL_new(ctx))); + XMEMSET(id, 0, sizeof(id)); - XFREE(sessionBuf, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); - return EXPECT_RESULT(); -} + /* error cases */ + ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_UseTrustedCA(NULL, 0, NULL, 0)); + ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_UseTrustedCA(ssl, + WOLFSSL_TRUSTED_CA_CERT_SHA1+1, NULL, 0)); + ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_UseTrustedCA(ssl, + WOLFSSL_TRUSTED_CA_CERT_SHA1, NULL, 0)); + ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_UseTrustedCA(ssl, + WOLFSSL_TRUSTED_CA_CERT_SHA1, id, 5)); +#ifdef NO_SHA + ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_UseTrustedCA(ssl, + WOLFSSL_TRUSTED_CA_KEY_SHA1, id, sizeof(id))); #endif - -static int test_wolfSSL_dtls_export_peers(void) -{ - EXPECT_DECLS; -#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_SESSION_EXPORT) && \ - defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES) - test_ssl_cbf client_cbf; - test_ssl_cbf server_cbf; - size_t i, j; - struct test_params { - method_provider client_meth; - method_provider server_meth; - const char* dtls_version; - } params[] = { -#ifndef NO_OLD_TLS - {wolfDTLSv1_client_method, wolfDTLSv1_server_method, "1.0"}, -#endif - {wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method, "1.2"}, - /* TODO DTLS 1.3 exporting not supported -#ifdef WOLFSSL_DTLS13 - {wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method, "1.3"}, -#endif - */ - }; - - for (i = 0; i < sizeof(params)/sizeof(*params); i++) { - for (j = 0; j <= 3; j++) { - XMEMSET(&client_cbf, 0, sizeof(client_cbf)); - XMEMSET(&server_cbf, 0, sizeof(server_cbf)); - - printf("\n\tTesting DTLS %s connection;", params[i].dtls_version); - - client_cbf.method = params[i].client_meth; - server_cbf.method = params[i].server_meth; - - if (j & 0x1) { - client_cbf.on_handshake = - test_wolfSSL_dtls_export_peers_on_handshake; - printf(" With client export;"); - } - if (j & 0x2) { - server_cbf.on_handshake = - test_wolfSSL_dtls_export_peers_on_handshake; - printf(" With server export;"); - } - - printf("\n"); - - ExpectIntEQ(test_wolfSSL_client_server_nofail_memio(&client_cbf, - &server_cbf, NULL), TEST_SUCCESS); - if (!EXPECT_SUCCESS()) - break; - } - } -#endif - return EXPECT_RESULT(); -} - -/* Test that ImportKeyState correctly skips extra window words when importing - * state from a peer compiled with a larger WOLFSSL_DTLS_WINDOW_WORDS. */ -static int test_wolfSSL_dtls_import_state_extra_window_words(void) -{ - EXPECT_DECLS; -#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_SESSION_EXPORT) - WOLFSSL_CTX* ctx = NULL; - WOLFSSL* ssl = NULL; - unsigned int stateSz = 0; - byte* state = NULL; - byte* modified = NULL; - unsigned int modifiedSz; - word16 origKeyLen; - word16 origTotalLen; - /* Offset from start of key state data to the first wordCount field. - * Layout: 4 sequence numbers (16 bytes) + DTLS-specific fields (42 bytes) + - * encryptSz(4) + padSz(4) + encryptionOn(1) + decryptedCur(1) = 68 */ - const int keyStateWindowOffset = 68; - /* Buffer header: 2 proto + 2 total_len + 2 key_len = 6 */ - const int headerSz = 6; - int idx, modIdx; - int extraPerWindow = 2 * (int)sizeof(word32); /* 8 bytes extra per window */ - int totalExtra = extraPerWindow * 2; /* 16 bytes extra total */ - - /* Create DTLS context and SSL object */ - ExpectNotNull(ctx = wolfSSL_CTX_new(wolfDTLSv1_2_server_method())); - ExpectNotNull(ssl = wolfSSL_new(ctx)); - - /* Get required buffer size and export state-only */ - ExpectIntEQ(wolfSSL_dtls_export_state_only(ssl, NULL, &stateSz), 0); - ExpectIntGT((int)stateSz, 0); - state = (byte*)XMALLOC(stateSz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); - ExpectNotNull(state); - ExpectIntGT(wolfSSL_dtls_export_state_only(ssl, state, &stateSz), 0); - - /* Build a modified buffer that simulates a peer with - * WOLFSSL_DTLS_WINDOW_WORDS = WOLFSSL_DTLS_WINDOW_WORDS + 2. - * Each window section gets 2 extra word32 values (8 bytes). - * Two windows => 16 extra bytes total. */ - modifiedSz = stateSz + totalExtra; - modified = (byte*)XMALLOC(modifiedSz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); - ExpectNotNull(modified); - - if (EXPECT_SUCCESS()) { - int windowWords = WOLFSSL_DTLS_WINDOW_WORDS; - int windowDataSz = windowWords * (int)sizeof(word32); - - XMEMSET(modified, 0, modifiedSz); - - /* Copy protocol/version bytes (first 2 bytes) */ - XMEMCPY(modified, state, 2); - - /* Read original total length and key state length */ - ato16(state + 2, &origTotalLen); - ato16(state + 4, &origKeyLen); - - /* Write updated total length and key state length */ - c16toa((word16)(origTotalLen + totalExtra), modified + 2); - c16toa((word16)(origKeyLen + totalExtra), modified + 4); - - /* Copy key state data up to first window section */ - idx = headerSz; - modIdx = headerSz; - XMEMCPY(modified + modIdx, state + idx, keyStateWindowOffset); - idx += keyStateWindowOffset; - modIdx += keyStateWindowOffset; - - /* First window: write increased wordCount */ - c16toa((word16)(windowWords + 2), modified + modIdx); - idx += OPAQUE16_LEN; - modIdx += OPAQUE16_LEN; - - /* Copy original window data */ - XMEMCPY(modified + modIdx, state + idx, windowDataSz); - idx += windowDataSz; - modIdx += windowDataSz; - - /* Insert 2 extra word32 padding values */ - XMEMSET(modified + modIdx, 0, extraPerWindow); - modIdx += extraPerWindow; - - /* Second window (prevWindow): same transformation */ - c16toa((word16)(windowWords + 2), modified + modIdx); - idx += OPAQUE16_LEN; - modIdx += OPAQUE16_LEN; - - XMEMCPY(modified + modIdx, state + idx, windowDataSz); - idx += windowDataSz; - modIdx += windowDataSz; - - XMEMSET(modified + modIdx, 0, extraPerWindow); - modIdx += extraPerWindow; - - /* Copy remainder of key state (after both windows) */ - XMEMCPY(modified + modIdx, state + idx, stateSz - idx); - } - - /* Import the modified state - should succeed with the fix */ - wolfSSL_free(ssl); - ssl = NULL; - ExpectNotNull(ssl = wolfSSL_new(ctx)); - ExpectIntGT(wolfSSL_dtls_import(ssl, modified, modifiedSz), 0); - - XFREE(state, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(modified, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); - wolfSSL_free(ssl); - wolfSSL_CTX_free(ctx); -#endif - return EXPECT_RESULT(); -} - -static int test_wolfSSL_UseTrustedCA(void) -{ - EXPECT_DECLS; -#if defined(HAVE_TRUSTED_CA) && !defined(NO_CERTS) && !defined(NO_FILESYSTEM) \ - && !defined(NO_RSA) -#if !defined(NO_TLS) && \ - (!defined(NO_WOLFSSL_CLIENT) || !defined(NO_WOLFSSL_SERVER)) - WOLFSSL_CTX *ctx = NULL; - WOLFSSL *ssl = NULL; - byte id[20]; - -#ifndef NO_WOLFSSL_SERVER - ExpectNotNull((ctx = wolfSSL_CTX_new(wolfSSLv23_server_method()))); - ExpectTrue(wolfSSL_CTX_use_certificate_file(ctx, svrCertFile, WOLFSSL_FILETYPE_PEM)); - ExpectTrue(wolfSSL_CTX_use_PrivateKey_file(ctx, svrKeyFile, WOLFSSL_FILETYPE_PEM)); -#else - ExpectNotNull((ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()))); -#endif - ExpectNotNull((ssl = wolfSSL_new(ctx))); - XMEMSET(id, 0, sizeof(id)); - - /* error cases */ - ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_UseTrustedCA(NULL, 0, NULL, 0)); - ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_UseTrustedCA(ssl, - WOLFSSL_TRUSTED_CA_CERT_SHA1+1, NULL, 0)); - ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_UseTrustedCA(ssl, - WOLFSSL_TRUSTED_CA_CERT_SHA1, NULL, 0)); - ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_UseTrustedCA(ssl, - WOLFSSL_TRUSTED_CA_CERT_SHA1, id, 5)); -#ifdef NO_SHA - ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_UseTrustedCA(ssl, - WOLFSSL_TRUSTED_CA_KEY_SHA1, id, sizeof(id))); -#endif - ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_UseTrustedCA(ssl, - WOLFSSL_TRUSTED_CA_X509_NAME, id, 0)); + ExpectIntNE(WOLFSSL_SUCCESS, wolfSSL_UseTrustedCA(ssl, + WOLFSSL_TRUSTED_CA_X509_NAME, id, 0)); /* success cases */ ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_UseTrustedCA(ssl, @@ -16967,61 +15607,6 @@ static int test_wolfSSL_either_side(void) return EXPECT_RESULT(); } -static int test_wolfSSL_DTLS_either_side(void) -{ - EXPECT_DECLS; -#if (defined(OPENSSL_EXTRA) || defined(WOLFSSL_EITHER_SIDE)) && \ - defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS) - test_ssl_cbf client_cb; - test_ssl_cbf server_cb; - - XMEMSET(&client_cb, 0, sizeof(client_cb)); - XMEMSET(&server_cb, 0, sizeof(server_cb)); - - /* Use different CTX for client and server */ - client_cb.ctx = wolfSSL_CTX_new(wolfDTLS_method()); - ExpectNotNull(client_cb.ctx); - server_cb.ctx = wolfSSL_CTX_new(wolfDTLS_method()); - ExpectNotNull(server_cb.ctx); - /* we are responsible for free'ing WOLFSSL_CTX */ - server_cb.isSharedCtx = client_cb.isSharedCtx = 1; - - ExpectIntEQ(test_wolfSSL_client_server_nofail_memio(&client_cb, - &server_cb, NULL), TEST_SUCCESS); - - wolfSSL_CTX_free(client_cb.ctx); - wolfSSL_CTX_free(server_cb.ctx); -#endif - return EXPECT_RESULT(); -} - -static int test_generate_cookie(void) -{ - EXPECT_DECLS; -#if defined(WOLFSSL_DTLS) && defined(OPENSSL_EXTRA) && defined(USE_WOLFSSL_IO) - SSL_CTX* ctx = NULL; - SSL* ssl = NULL; - byte buf[FOURK_BUF] = {0}; - - ExpectNotNull(ctx = wolfSSL_CTX_new(wolfDTLS_method())); - ExpectNotNull(ssl = SSL_new(ctx)); - - /* Test unconnected */ - ExpectIntEQ(EmbedGenerateCookie(ssl, buf, FOURK_BUF, NULL), WC_NO_ERR_TRACE(GEN_COOKIE_E)); - - wolfSSL_CTX_SetGenCookie(ctx, EmbedGenerateCookie); - - wolfSSL_SetCookieCtx(ssl, ctx); - - ExpectNotNull(wolfSSL_GetCookieCtx(ssl)); - - ExpectNull(wolfSSL_GetCookieCtx(NULL)); - - SSL_free(ssl); - SSL_CTX_free(ctx); -#endif - return EXPECT_RESULT(); -} static int test_wolfSSL_set_options(void) { @@ -19386,563 +17971,6 @@ static int test_wolfSSL_d2i_SSL_SESSION_bounds_check(void) return EXPECT_RESULT(); } -static 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 - -static 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 - -static 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(); -} - -static 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(); -} - #ifndef NO_BIO #if defined(OPENSSL_EXTRA) && defined(WOLFSSL_HAVE_MLDSA) @@ -27586,1188 +25614,6 @@ static int test_wolfSSL_CTX_get0_privatekey(void) return EXPECT_RESULT(); } -static int test_wolfSSL_dtls_set_mtu(void) -{ - EXPECT_DECLS; -#if (defined(WOLFSSL_DTLS_MTU) || defined(WOLFSSL_SCTP)) && \ - !defined(NO_WOLFSSL_SERVER) && defined(WOLFSSL_DTLS) && \ - !defined(WOLFSSL_NO_TLS12) - WOLFSSL_CTX* ctx = NULL; - WOLFSSL* ssl = NULL; - const char* testCertFile; - const char* testKeyFile; - - ExpectNotNull(ctx = wolfSSL_CTX_new(wolfDTLSv1_2_server_method())); -#ifndef NO_RSA - testCertFile = svrCertFile; - testKeyFile = svrKeyFile; -#elif defined(HAVE_ECC) - testCertFile = eccCertFile; - testKeyFile = eccKeyFile; -#endif - if (testCertFile != NULL && testKeyFile != NULL) { - ExpectTrue(wolfSSL_CTX_use_certificate_file(ctx, testCertFile, - WOLFSSL_FILETYPE_PEM)); - ExpectTrue(wolfSSL_CTX_use_PrivateKey_file(ctx, testKeyFile, - WOLFSSL_FILETYPE_PEM)); - } - ExpectNotNull(ssl = wolfSSL_new(ctx)); - - ExpectIntEQ(wolfSSL_CTX_dtls_set_mtu(NULL, 1488), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); - ExpectIntEQ(wolfSSL_dtls_set_mtu(NULL, 1488), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); - ExpectIntEQ(wolfSSL_CTX_dtls_set_mtu(ctx, 20000), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); - ExpectIntEQ(wolfSSL_dtls_set_mtu(ssl, 20000), WC_NO_ERR_TRACE(WOLFSSL_FAILURE)); - ExpectIntEQ(wolfSSL_get_error(ssl, WC_NO_ERR_TRACE(WOLFSSL_FAILURE)), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); - ExpectIntEQ(wolfSSL_CTX_dtls_set_mtu(ctx, 1488), WOLFSSL_SUCCESS); - ExpectIntEQ(wolfSSL_dtls_set_mtu(ssl, 1488), WOLFSSL_SUCCESS); - -#ifdef OPENSSL_EXTRA - ExpectIntEQ(SSL_set_mtu(ssl, 1488), WOLFSSL_SUCCESS); -#endif - - wolfSSL_free(ssl); - wolfSSL_CTX_free(ctx); -#endif - - return EXPECT_RESULT(); -} - -#if defined(HAVE_IO_TESTS_DEPENDENCIES) && !defined(SINGLE_THREADED) && \ - defined(WOLFSSL_DTLS) && !defined(WOLFSSL_NO_TLS12) - -static WC_INLINE void generateDTLSMsg(byte* out, int outSz, word32 seq, - enum HandShakeType hsType, word16 length) -{ - size_t idx = 0; - byte* l; - - /* record layer */ - /* handshake type */ - out[idx++] = handshake; - /* protocol version */ - out[idx++] = 0xfe; - out[idx++] = 0xfd; /* DTLS 1.2 */ - /* epoch 0 */ - XMEMSET(out + idx, 0, 2); - idx += 2; - /* sequence number */ - XMEMSET(out + idx, 0, 6); - c32toa(seq, out + idx + 2); - idx += 6; - /* length in BE */ - if (length) - c16toa(length, out + idx); - else - c16toa(outSz - idx - 2, out + idx); - idx += 2; - - /* handshake layer */ - /* handshake type */ - out[idx++] = (byte)hsType; - /* length */ - l = out + idx; - idx += 3; - /* message seq */ - c16toa(0, out + idx); - idx += 2; - /* frag offset */ - c32to24(0, out + idx); - idx += 3; - /* frag length */ - c32to24((word32)outSz - (word32)idx - 3, l); - c32to24((word32)outSz - (word32)idx - 3, out + idx); - idx += 3; - XMEMSET(out + idx, 0, outSz - idx); -} - -static void test_wolfSSL_dtls_plaintext_server(WOLFSSL* ssl) -{ - byte msg[] = "This is a msg for the client"; - byte reply[40]; - AssertIntGT(wolfSSL_read(ssl, reply, sizeof(reply)),0); - reply[sizeof(reply) - 1] = '\0'; - fprintf(stderr, "Client message: %s\n", reply); - AssertIntEQ(wolfSSL_write(ssl, msg, sizeof(msg)), sizeof(msg)); -} - -static void test_wolfSSL_dtls_plaintext_client(WOLFSSL* ssl) -{ - byte ch[50]; - int fd = wolfSSL_get_wfd(ssl); - byte msg[] = "This is a msg for the server"; - byte reply[40]; - - AssertIntGE(fd, 0); - generateDTLSMsg(ch, sizeof(ch), 20, client_hello, 0); - /* Server should ignore this datagram */ - AssertIntEQ(send(fd, (MESSAGE_TYPE_CAST)ch, sizeof(ch), 0), sizeof(ch)); - generateDTLSMsg(ch, sizeof(ch), 20, client_hello, 10000); - /* Server should ignore this datagram */ - AssertIntEQ(send(fd, (MESSAGE_TYPE_CAST)ch, sizeof(ch), 0), sizeof(ch)); - - AssertIntEQ(wolfSSL_write(ssl, msg, sizeof(msg)), sizeof(msg)); - AssertIntGT(wolfSSL_read(ssl, reply, sizeof(reply)),0); - reply[sizeof(reply) - 1] = '\0'; - fprintf(stderr, "Server response: %s\n", reply); -} - -static int test_wolfSSL_dtls_plaintext(void) -{ - callback_functions func_cb_client; - callback_functions func_cb_server; - size_t i; - struct test_params { - method_provider client_meth; - method_provider server_meth; - ssl_callback on_result_server; - ssl_callback on_result_client; - } params[] = { - {wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method, - test_wolfSSL_dtls_plaintext_server, - test_wolfSSL_dtls_plaintext_client}, - }; - - for (i = 0; i < sizeof(params)/sizeof(*params); i++) { - XMEMSET(&func_cb_client, 0, sizeof(callback_functions)); - XMEMSET(&func_cb_server, 0, sizeof(callback_functions)); - - func_cb_client.doUdp = func_cb_server.doUdp = 1; - func_cb_server.method = params[i].server_meth; - func_cb_client.method = params[i].client_meth; - func_cb_client.on_result = params[i].on_result_client; - func_cb_server.on_result = params[i].on_result_server; - - test_wolfSSL_client_server_nofail(&func_cb_client, &func_cb_server); - - if (!func_cb_client.return_code) - return TEST_FAIL; - if (!func_cb_server.return_code) - return TEST_FAIL; - } - - return TEST_RES_CHECK(1); -} -#else -static int test_wolfSSL_dtls_plaintext(void) -{ - return TEST_SKIPPED; -} -#endif - -#if defined(HAVE_IO_TESTS_DEPENDENCIES) && !defined(SINGLE_THREADED) && \ - defined(WOLFSSL_DTLS) && !defined(WOLFSSL_NO_TLS12) - -static void test_wolfSSL_dtls12_fragments_spammer(WOLFSSL* ssl) -{ - byte b[1100]; /* buffer for the messages to send */ - size_t idx = 0; - size_t seq_offset = 0; - size_t msg_offset = 0; - int i; - int fd = wolfSSL_get_wfd(ssl); - int ret = wolfSSL_connect_cert(ssl); /* This gets us past the cookie */ - word32 seq_number = 100; /* start high so server definitely reads this */ - word16 msg_number = 50; /* start high so server has to buffer this */ - AssertIntEQ(ret, 1); - /* Now let's start spamming the peer with fragments it needs to store */ - XMEMSET(b, -1, sizeof(b)); - - /* record layer */ - /* handshake type */ - b[idx++] = 22; - /* protocol version */ - b[idx++] = 0xfe; - b[idx++] = 0xfd; /* DTLS 1.2 */ - /* epoch 0 */ - XMEMSET(b + idx, 0, 2); - idx += 2; - /* sequence number */ - XMEMSET(b + idx, 0, 6); - seq_offset = idx + 2; /* increment only the low 32 bits */ - idx += 6; - /* static length in BE */ - c16toa(42, b + idx); - idx += 2; - - /* handshake layer */ - /* cert type */ - b[idx++] = 11; - /* length */ - c32to24(1000, b + idx); - idx += 3; - /* message seq */ - c16toa(0, b + idx); - msg_offset = idx; - idx += 2; - /* frag offset */ - c32to24(500, b + idx); - idx += 3; - /* frag length */ - c32to24(30, b + idx); - idx += 3; - (void)idx; /* inhibit clang-analyzer-deadcode.DeadStores */ - - for (i = 0; i < DTLS_POOL_SZ * 2 && ret > 0; - seq_number++, msg_number++, i++) { - struct timespec delay; - XMEMSET(&delay, 0, sizeof(delay)); - delay.tv_nsec = 10000000; /* wait 0.01 seconds */ - c32toa(seq_number, b + seq_offset); - c16toa(msg_number, b + msg_offset); - ret = (int)send(fd, (MESSAGE_TYPE_CAST)b, 55, 0); - nanosleep(&delay, NULL); - } -} - -#ifdef WOLFSSL_DTLS13 -static void test_wolfSSL_dtls13_fragments_spammer(WOLFSSL* ssl) -{ - const word16 sendCountMax = 100; - byte b[150]; /* buffer for the messages to send */ - size_t idx = 0; - size_t msg_offset = 0; - int fd = wolfSSL_get_wfd(ssl); - word16 msg_number = 10; /* start high so server has to buffer this */ - int ret = wolfSSL_connect_cert(ssl); /* This gets us past the cookie */ - AssertIntEQ(ret, 1); - /* Now let's start spamming the peer with fragments it needs to store */ - XMEMSET(b, -1, sizeof(b)); - - /* handshake type */ - b[idx++] = 11; - /* length */ - c32to24(10000, b + idx); - idx += 3; - /* message_seq */ - msg_offset = idx; - idx += 2; - /* fragment_offset */ - c32to24(5000, b + idx); - idx += 3; - /* fragment_length */ - c32to24(100, b + idx); - idx += 3; - /* fragment contents */ - idx += 100; - - for (; ret > 0 && msg_number < sendCountMax; msg_number++) { - byte sendBuf[150]; - int sendSz = sizeof(sendBuf); - struct timespec delay; - XMEMSET(&delay, 0, sizeof(delay)); - delay.tv_nsec = 10000000; /* wait 0.01 seconds */ - c16toa(msg_number, b + msg_offset); - ret = sendSz = BuildTls13Message(ssl, sendBuf, sendSz, b, - (int)idx, handshake, 0, 0, 0); - if (sendSz > 0) - ret = (int)send(fd, (MESSAGE_TYPE_CAST)sendBuf, (size_t)sendSz, 0); - nanosleep(&delay, NULL); - } -} -#endif - -static int test_wolfSSL_dtls_fragments(void) -{ - EXPECT_DECLS; - callback_functions func_cb_client; - callback_functions func_cb_server; - size_t i; - struct test_params { - method_provider client_meth; - method_provider server_meth; - ssl_callback spammer; - } params[] = { -#if !defined(WOLFSSL_NO_TLS12) - {wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method, - test_wolfSSL_dtls12_fragments_spammer}, -#endif -#ifdef WOLFSSL_DTLS13 - {wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method, - test_wolfSSL_dtls13_fragments_spammer}, -#endif - }; - - for (i = 0; i < sizeof(params)/sizeof(*params); i++) { - XMEMSET(&func_cb_client, 0, sizeof(callback_functions)); - XMEMSET(&func_cb_server, 0, sizeof(callback_functions)); - - func_cb_client.doUdp = func_cb_server.doUdp = 1; - func_cb_server.method = params[i].server_meth; - func_cb_client.method = params[i].client_meth; - func_cb_client.ssl_ready = params[i].spammer; - - test_wolfSSL_client_server_nofail(&func_cb_client, &func_cb_server); - - /* If the client failed, check that the error it encountered was from - * the server aborting, resulting in a socket error, fatal error or - * reading a close notify alert. - * - * Under slow execution (e.g. valgrind + noasm), the server may - * still be processing fragments when the client completes its - * handshake and write, so the client may succeed -- in that - * case return_code is TEST_SUCCESS and these checks don't apply. - */ - if (func_cb_client.return_code == TEST_FAIL) { - if (func_cb_client.last_err != WC_NO_ERR_TRACE(SOCKET_ERROR_E) && - func_cb_client.last_err != WOLFSSL_ERROR_ZERO_RETURN && - func_cb_client.last_err != WC_NO_ERR_TRACE(FATAL_ERROR)) { - ExpectIntEQ(func_cb_client.last_err, WC_NO_ERR_TRACE(SOCKET_ERROR_E)); - } - } - /* Check the server returned an error indicating the msg buffer - * was full. - * - * Under slow execution (e.g. valgrind + noasm), the real handshake - * from wolfSSL_negotiate() may complete before enough spam fragments - * accumulate to trigger DTLS_TOO_MANY_FRAGMENTS_E. Accept both - * outcomes: server hit the fragment limit, or completed normally. - */ - if (func_cb_server.return_code == TEST_FAIL) { - ExpectIntEQ(func_cb_server.last_err, WC_NO_ERR_TRACE(DTLS_TOO_MANY_FRAGMENTS_E)); - } - - if (EXPECT_FAIL()) - break; - } - - return EXPECT_RESULT(); -} - -static void test_wolfSSL_dtls_send_alert(WOLFSSL* ssl) -{ - int fd, ret; - byte alert_msg[] = { - 0x15, /* alert type */ - 0xfe, 0xfd, /* version */ - 0x00, 0x00, /* epoch */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, /* seq number */ - 0x00, 0x02, /* length */ - 0x02, /* level: fatal */ - 0x46 /* protocol version */ - }; - - fd = wolfSSL_get_wfd(ssl); - AssertIntGE(fd, 0); - ret = (int)send(fd, (MESSAGE_TYPE_CAST)alert_msg, sizeof(alert_msg), 0); - AssertIntGT(ret, 0); -} - -static int _test_wolfSSL_ignore_alert_before_cookie(byte version12) -{ - callback_functions client_cbs, server_cbs; - - XMEMSET(&client_cbs, 0, sizeof(client_cbs)); - XMEMSET(&server_cbs, 0, sizeof(server_cbs)); - client_cbs.doUdp = server_cbs.doUdp = 1; - if (version12) { -#if !defined(WOLFSSL_NO_TLS12) - client_cbs.method = wolfDTLSv1_2_client_method; - server_cbs.method = wolfDTLSv1_2_server_method; -#else - return TEST_SKIPPED; -#endif - } - else - { -#ifdef WOLFSSL_DTLS13 - client_cbs.method = wolfDTLSv1_3_client_method; - server_cbs.method = wolfDTLSv1_3_server_method; -#else - return TEST_SKIPPED; -#endif /* WOLFSSL_DTLS13 */ - } - - client_cbs.ssl_ready = test_wolfSSL_dtls_send_alert; - test_wolfSSL_client_server_nofail(&client_cbs, &server_cbs); - - if (!client_cbs.return_code) - return TEST_FAIL; - if (!server_cbs.return_code) - return TEST_FAIL; - - return TEST_SUCCESS; -} - -static int test_wolfSSL_ignore_alert_before_cookie(void) -{ - int ret; - ret =_test_wolfSSL_ignore_alert_before_cookie(0); - if (ret != 0) - return ret; - ret =_test_wolfSSL_ignore_alert_before_cookie(1); - if (ret != 0) - return ret; - return 0; -} - -static void test_wolfSSL_send_bad_record(WOLFSSL* ssl) -{ - int ret; - int fd; - - byte bad_msg[] = { - 0x17, /* app data */ - 0xaa, 0xfd, /* bad version */ - 0x00, 0x01, /* epoch 1 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, /* not seen seq number */ - 0x00, 0x26, /* length: 38 bytes */ - 0xae, 0x30, 0x31, 0xb1, 0xf1, 0xb9, 0x6f, 0xda, 0x17, 0x19, 0xd9, 0x57, - 0xa9, 0x9d, 0x5c, 0x51, 0x9b, 0x53, 0x63, 0xa5, 0x24, 0x70, 0xa1, - 0xae, 0xdf, 0x1c, 0xb9, 0xfc, 0xe3, 0xd7, 0x77, 0x6d, 0xb6, 0x89, 0x0f, - 0x03, 0x18, 0x72 - }; - - fd = wolfSSL_get_wfd(ssl); - AssertIntGE(fd, 0); - ret = (int)send(fd, (MESSAGE_TYPE_CAST)bad_msg, sizeof(bad_msg), 0); - AssertIntEQ(ret, sizeof(bad_msg)); - ret = wolfSSL_write(ssl, "badrecordtest", sizeof("badrecordtest")); - AssertIntEQ(ret, sizeof("badrecordtest")); -} - -static void test_wolfSSL_read_string(WOLFSSL* ssl) -{ - byte buf[100]; - int ret; - - ret = wolfSSL_read(ssl, buf, sizeof(buf)); - AssertIntGT(ret, 0); - AssertIntEQ(strcmp((char*)buf, "badrecordtest"), 0); -} - -static int _test_wolfSSL_dtls_bad_record( - method_provider client_method, method_provider server_method) -{ - callback_functions client_cbs, server_cbs; - - XMEMSET(&client_cbs, 0, sizeof(client_cbs)); - XMEMSET(&server_cbs, 0, sizeof(server_cbs)); - client_cbs.doUdp = server_cbs.doUdp = 1; - client_cbs.method = client_method; - server_cbs.method = server_method; - - client_cbs.on_result = test_wolfSSL_send_bad_record; - server_cbs.on_result = test_wolfSSL_read_string; - - test_wolfSSL_client_server_nofail(&client_cbs, &server_cbs); - - if (!client_cbs.return_code) - return TEST_FAIL; - if (!server_cbs.return_code) - return TEST_FAIL; - - return TEST_SUCCESS; -} - -static int test_wolfSSL_dtls_bad_record(void) -{ - int ret = TEST_SUCCESS; -#if !defined(WOLFSSL_NO_TLS12) - ret = _test_wolfSSL_dtls_bad_record(wolfDTLSv1_2_client_method, - wolfDTLSv1_2_server_method); -#endif -#ifdef WOLFSSL_DTLS13 - if (ret == TEST_SUCCESS) { - ret = _test_wolfSSL_dtls_bad_record(wolfDTLSv1_3_client_method, - wolfDTLSv1_3_server_method); - } -#endif /* WOLFSSL_DTLS13 */ - return ret; - -} - -#else -static int test_wolfSSL_dtls_fragments(void) -{ - return TEST_SKIPPED; -} -static int test_wolfSSL_ignore_alert_before_cookie(void) -{ - return TEST_SKIPPED; -} -static int test_wolfSSL_dtls_bad_record(void) -{ - return TEST_SKIPPED; -} -#endif - -#if defined(WOLFSSL_DTLS13) && !defined(WOLFSSL_TLS13_IGNORE_AEAD_LIMITS) && \ - !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) && \ - defined(HAVE_IO_TESTS_DEPENDENCIES) -static volatile int test_AEAD_seq_num = 0; -#ifdef WOLFSSL_NO_ATOMICS -static volatile int test_AEAD_done = 0; -#else -wolfSSL_Atomic_Int test_AEAD_done = WOLFSSL_ATOMIC_INITIALIZER(0); -#endif -#ifdef WOLFSSL_MUTEX_INITIALIZER -static wolfSSL_Mutex test_AEAD_mutex = WOLFSSL_MUTEX_INITIALIZER(test_AEAD_mutex); -#endif - -static int test_AEAD_fail_decryption = 0; -static int test_AEAD_cbiorecv(WOLFSSL *ssl, char *buf, int sz, void *ctx) -{ - int fd = wolfSSL_get_fd(ssl); - int ret = -1; - if (fd >= 0 && (ret = (int)recv(fd, buf, sz, 0)) > 0) { - if (test_AEAD_fail_decryption) { - /* Modify the packet to trigger a decryption failure */ - buf[ret/2] ^= 0xFF; - if (test_AEAD_fail_decryption == 1) - test_AEAD_fail_decryption = 0; - } - } - (void)ctx; - return ret; -} - -static void test_AEAD_get_limits(WOLFSSL* ssl, w64wrapper* hardLimit, - w64wrapper* keyUpdateLimit, w64wrapper* sendLimit) -{ - if (sendLimit) - w64Zero(sendLimit); - switch (ssl->specs.bulk_cipher_algorithm) { - case wolfssl_aes_gcm: - if (sendLimit) - *sendLimit = AEAD_AES_LIMIT; - FALL_THROUGH; - case wolfssl_chacha: - if (hardLimit) - *hardLimit = DTLS_AEAD_AES_GCM_CHACHA_FAIL_LIMIT; - if (keyUpdateLimit) - *keyUpdateLimit = DTLS_AEAD_AES_GCM_CHACHA_FAIL_KU_LIMIT; - break; - case wolfssl_aes_ccm: - if (sendLimit) - *sendLimit = DTLS_AEAD_AES_CCM_LIMIT; - if (ssl->specs.aead_mac_size == AES_CCM_8_AUTH_SZ) { - if (hardLimit) - *hardLimit = DTLS_AEAD_AES_CCM_8_FAIL_LIMIT; - if (keyUpdateLimit) - *keyUpdateLimit = DTLS_AEAD_AES_CCM_8_FAIL_KU_LIMIT; - } - else { - if (hardLimit) - *hardLimit = DTLS_AEAD_AES_CCM_FAIL_LIMIT; - if (keyUpdateLimit) - *keyUpdateLimit = DTLS_AEAD_AES_CCM_FAIL_KU_LIMIT; - } - break; - default: - fprintf(stderr, "Unrecognized bulk cipher"); - AssertFalse(1); - break; - } -} - -static void test_AEAD_limit_client(WOLFSSL* ssl) -{ - int ret; - int i; - int didReKey = 0; - char msgBuf[20]; - w64wrapper hardLimit; - w64wrapper keyUpdateLimit; - w64wrapper counter; - w64wrapper sendLimit; - - test_AEAD_get_limits(ssl, &hardLimit, &keyUpdateLimit, &sendLimit); - - w64Zero(&counter); - AssertTrue(w64Equal(Dtls13GetEpoch(ssl, ssl->dtls13Epoch)->dropCount, counter)); - - wolfSSL_SSLSetIORecv(ssl, test_AEAD_cbiorecv); - - for (i = 0; i < 10; i++) { - /* Test some failed decryptions */ - test_AEAD_fail_decryption = 1; - w64Increment(&counter); - ret = wolfSSL_read(ssl, msgBuf, sizeof(msgBuf)); - /* Should succeed since decryption failures are dropped */ - AssertIntGT(ret, 0); - AssertTrue(w64Equal(Dtls13GetEpoch(ssl, ssl->dtls13PeerEpoch)->dropCount, counter)); - } - - test_AEAD_fail_decryption = 1; - Dtls13GetEpoch(ssl, ssl->dtls13PeerEpoch)->dropCount = keyUpdateLimit; - w64Increment(&Dtls13GetEpoch(ssl, ssl->dtls13PeerEpoch)->dropCount); - /* 100 read calls should be enough to complete the key update */ - w64Zero(&counter); - for (i = 0; i < 100; i++) { - /* Key update should be sent and negotiated */ - ret = wolfSSL_read(ssl, msgBuf, sizeof(msgBuf)); - AssertIntGT(ret, 0); - /* Epoch after one key update is 4 */ - if (w64Equal(ssl->dtls13PeerEpoch, w64From32(0, 4)) && - w64Equal(Dtls13GetEpoch(ssl, ssl->dtls13PeerEpoch)->dropCount, counter)) { - didReKey = 1; - break; - } - } - AssertTrue(didReKey); - - if (!w64IsZero(sendLimit)) { - /* Test the sending limit for AEAD ciphers */ -#ifdef WOLFSSL_MUTEX_INITIALIZER - (void)wc_LockMutex(&test_AEAD_mutex); -#endif - Dtls13GetEpoch(ssl, ssl->dtls13Epoch)->nextSeqNumber = sendLimit; - test_AEAD_seq_num = 1; - XMEMSET(msgBuf, 0, sizeof(msgBuf)); - ret = wolfSSL_write(ssl, msgBuf, sizeof(msgBuf)); - AssertIntGT(ret, 0); - didReKey = 0; - w64Zero(&counter); -#ifdef WOLFSSL_MUTEX_INITIALIZER - wc_UnLockMutex(&test_AEAD_mutex); -#endif - /* 100 read calls should be enough to complete the key update */ - for (i = 0; i < 100; i++) { - /* Key update should be sent and negotiated */ - ret = wolfSSL_read(ssl, msgBuf, sizeof(msgBuf)); - AssertIntGT(ret, 0); - /* Epoch after another key update is 5 */ - if (w64Equal(ssl->dtls13Epoch, w64From32(0, 5)) && - w64Equal(Dtls13GetEpoch(ssl, ssl->dtls13Epoch)->dropCount, counter)) { - didReKey = 1; - break; - } - } - AssertTrue(didReKey); - } - - test_AEAD_fail_decryption = 2; - Dtls13GetEpoch(ssl, ssl->dtls13PeerEpoch)->dropCount = hardLimit; - w64Decrement(&Dtls13GetEpoch(ssl, ssl->dtls13PeerEpoch)->dropCount); - /* Connection should fail with a DECRYPT_ERROR */ - ret = wolfSSL_read(ssl, msgBuf, sizeof(msgBuf)); - AssertIntEQ(ret, WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)); - AssertIntEQ(wolfSSL_get_error(ssl, ret), WC_NO_ERR_TRACE(DECRYPT_ERROR)); - -#ifdef WOLFSSL_ATOMIC_INITIALIZER - WOLFSSL_ATOMIC_STORE(test_AEAD_done, 1); -#else - test_AEAD_done = 1; -#endif -} - -int counter = 0; -static void test_AEAD_limit_server(WOLFSSL* ssl) -{ - char msgBuf[] = "Sending data"; - int ret = WOLFSSL_SUCCESS; - w64wrapper sendLimit; - SOCKET_T fd = wolfSSL_get_fd(ssl); - struct timespec delay; - XMEMSET(&delay, 0, sizeof(delay)); - delay.tv_nsec = 100000000; /* wait 0.1 seconds */ - tcp_set_nonblocking(&fd); /* So that read doesn't block */ - wolfSSL_dtls_set_using_nonblock(ssl, 1); - test_AEAD_get_limits(ssl, NULL, NULL, &sendLimit); - while (! - #ifdef WOLFSSL_ATOMIC_INITIALIZER - WOLFSSL_ATOMIC_LOAD(test_AEAD_done) - #else - test_AEAD_done - #endif - && ret > 0) - { - counter++; -#ifdef WOLFSSL_MUTEX_INITIALIZER - (void)wc_LockMutex(&test_AEAD_mutex); -#endif - if (test_AEAD_seq_num) { - /* We need to update the seq number so that we can understand the - * peer. Otherwise we will incorrectly interpret the seq number. */ - Dtls13Epoch* e = Dtls13GetEpoch(ssl, ssl->dtls13PeerEpoch); - AssertNotNull(e); - e->nextPeerSeqNumber = sendLimit; - test_AEAD_seq_num = 0; - } -#ifdef WOLFSSL_MUTEX_INITIALIZER - wc_UnLockMutex(&test_AEAD_mutex); -#endif - (void)wolfSSL_read(ssl, msgBuf, sizeof(msgBuf)); - ret = wolfSSL_write(ssl, msgBuf, sizeof(msgBuf)); - nanosleep(&delay, NULL); - } -} - -static int test_wolfSSL_dtls_AEAD_limit(void) -{ - callback_functions func_cb_client; - callback_functions func_cb_server; - XMEMSET(&func_cb_client, 0, sizeof(callback_functions)); - XMEMSET(&func_cb_server, 0, sizeof(callback_functions)); - - func_cb_client.doUdp = func_cb_server.doUdp = 1; - func_cb_server.method = wolfDTLSv1_3_server_method; - func_cb_client.method = wolfDTLSv1_3_client_method; - func_cb_server.on_result = test_AEAD_limit_server; - func_cb_client.on_result = test_AEAD_limit_client; - - test_wolfSSL_client_server_nofail(&func_cb_client, &func_cb_server); - - if (!func_cb_client.return_code) - return TEST_FAIL; - if (!func_cb_server.return_code) - return TEST_FAIL; - - return TEST_SUCCESS; -} -#else -static int test_wolfSSL_dtls_AEAD_limit(void) -{ - return TEST_SKIPPED; -} -#endif - -#if defined(WOLFSSL_DTLS) && \ - defined(HAVE_IO_TESTS_DEPENDENCIES) && !defined(SINGLE_THREADED) && \ - !defined(DEBUG_VECTOR_REGISTER_ACCESS_FUZZING) -static void test_wolfSSL_dtls_send_ch(WOLFSSL* ssl) -{ - int fd, ret; - byte ch_msg[] = { - 0x16, 0xfe, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0xfa, 0x01, 0x00, 0x01, 0xee, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0xee, 0xfe, 0xfd, 0xc0, 0xca, 0xb5, 0x6f, 0x3d, 0x23, 0xcc, 0x53, 0x9a, - 0x67, 0x17, 0x70, 0xd3, 0xfb, 0x23, 0x16, 0x9e, 0x4e, 0xd6, 0x7e, 0x29, - 0xab, 0xfa, 0x4c, 0xa5, 0x84, 0x95, 0xc3, 0xdb, 0x21, 0x9a, 0x52, 0x00, - 0x00, 0x00, 0x36, 0x13, 0x01, 0x13, 0x02, 0x13, 0x03, 0xc0, 0x2c, 0xc0, - 0x2b, 0xc0, 0x30, 0xc0, 0x2f, 0x00, 0x9f, 0x00, 0x9e, 0xcc, 0xa9, 0xcc, - 0xa8, 0xcc, 0xaa, 0xc0, 0x27, 0xc0, 0x23, 0xc0, 0x28, 0xc0, 0x24, 0xc0, - 0x0a, 0xc0, 0x09, 0xc0, 0x14, 0xc0, 0x13, 0x00, 0x6b, 0x00, 0x67, 0x00, - 0x39, 0x00, 0x33, 0xcc, 0x14, 0xcc, 0x13, 0xcc, 0x15, 0x01, 0x00, 0x01, - 0x8e, 0x00, 0x2b, 0x00, 0x03, 0x02, 0xfe, 0xfc, 0x00, 0x0d, 0x00, 0x20, - 0x00, 0x1e, 0x06, 0x03, 0x05, 0x03, 0x04, 0x03, 0x02, 0x03, 0x08, 0x06, - 0x08, 0x0b, 0x08, 0x05, 0x08, 0x0a, 0x08, 0x04, 0x08, 0x09, 0x06, 0x01, - 0x05, 0x01, 0x04, 0x01, 0x03, 0x01, 0x02, 0x01, 0x00, 0x0a, 0x00, 0x0c, - 0x00, 0x0a, 0x00, 0x19, 0x00, 0x18, 0x00, 0x17, 0x00, 0x15, 0x01, 0x00, - 0x00, 0x16, 0x00, 0x00, 0x00, 0x33, 0x01, 0x4b, 0x01, 0x49, 0x00, 0x17, - 0x00, 0x41, 0x04, 0x96, 0xcb, 0x2e, 0x4e, 0xd9, 0x88, 0x71, 0xc7, 0xf3, - 0x1a, 0x16, 0xdd, 0x7a, 0x7c, 0xf7, 0x67, 0x8a, 0x5d, 0x9a, 0x55, 0xa6, - 0x4a, 0x90, 0xd9, 0xfb, 0xc7, 0xfb, 0xbe, 0x09, 0xa9, 0x8a, 0xb5, 0x7a, - 0xd1, 0xde, 0x83, 0x74, 0x27, 0x31, 0x1c, 0xaa, 0xae, 0xef, 0x58, 0x43, - 0x13, 0x7d, 0x15, 0x4d, 0x7f, 0x68, 0xf6, 0x8a, 0x38, 0xef, 0x0e, 0xb3, - 0xcf, 0xb8, 0x4a, 0xa9, 0xb4, 0xd7, 0xcb, 0x01, 0x00, 0x01, 0x00, 0x1d, - 0x0a, 0x22, 0x8a, 0xd1, 0x78, 0x85, 0x1e, 0x5a, 0xe1, 0x1d, 0x1e, 0xb7, - 0x2d, 0xbc, 0x5f, 0x52, 0xbc, 0x97, 0x5d, 0x8b, 0x6a, 0x8b, 0x9d, 0x1e, - 0xb1, 0xfc, 0x8a, 0xb2, 0x56, 0xcd, 0xed, 0x4b, 0xfb, 0x66, 0x3f, 0x59, - 0x3f, 0x15, 0x5d, 0x09, 0x9e, 0x2f, 0x60, 0x5b, 0x31, 0x81, 0x27, 0xf0, - 0x1c, 0xda, 0xcd, 0x48, 0x66, 0xc6, 0xbb, 0x25, 0xf0, 0x5f, 0xda, 0x4c, - 0xcf, 0x1d, 0x88, 0xc8, 0xda, 0x1b, 0x53, 0xea, 0xbd, 0xce, 0x6d, 0xf6, - 0x4a, 0x76, 0xdb, 0x75, 0x99, 0xaf, 0xcf, 0x76, 0x4a, 0xfb, 0xe3, 0xef, - 0xb2, 0xcb, 0xae, 0x4a, 0xc0, 0xe8, 0x63, 0x1f, 0xd6, 0xe8, 0xe6, 0x45, - 0xf9, 0xea, 0x0d, 0x06, 0x19, 0xfc, 0xb1, 0xfd, 0x5d, 0x92, 0x89, 0x7b, - 0xc7, 0x9f, 0x1a, 0xb3, 0x2b, 0xc7, 0xad, 0x0e, 0xfb, 0x13, 0x41, 0x83, - 0x84, 0x58, 0x3a, 0x25, 0xb9, 0x49, 0x35, 0x1c, 0x23, 0xcb, 0xd6, 0xe7, - 0xc2, 0x8c, 0x4b, 0x2a, 0x73, 0xa1, 0xdf, 0x4f, 0x73, 0x9b, 0xb3, 0xd2, - 0xb2, 0x95, 0x00, 0x3c, 0x26, 0x09, 0x89, 0x71, 0x05, 0x39, 0xc8, 0x98, - 0x8f, 0xed, 0x32, 0x15, 0x78, 0xcd, 0xd3, 0x7e, 0xfb, 0x5a, 0x78, 0x2a, - 0xdc, 0xca, 0x20, 0x09, 0xb5, 0x14, 0xf9, 0xd4, 0x58, 0xf6, 0x69, 0xf8, - 0x65, 0x9f, 0xb7, 0xe4, 0x93, 0xf1, 0xa3, 0x84, 0x7e, 0x1b, 0x23, 0x5d, - 0xea, 0x59, 0x3e, 0x4d, 0xca, 0xfd, 0xa5, 0x55, 0xdd, 0x99, 0xb5, 0x02, - 0xf8, 0x0d, 0xe5, 0xf4, 0x06, 0xb0, 0x43, 0x9e, 0x2e, 0xbf, 0x05, 0x33, - 0x65, 0x7b, 0x13, 0x8c, 0xf9, 0x16, 0x4d, 0xc5, 0x15, 0x0b, 0x40, 0x2f, - 0x66, 0x94, 0xf2, 0x43, 0x95, 0xe7, 0xa9, 0xb6, 0x39, 0x99, 0x73, 0xb3, - 0xb0, 0x06, 0xfe, 0x52, 0x9e, 0x57, 0xba, 0x75, 0xfd, 0x76, 0x7b, 0x20, - 0x31, 0x68, 0x4c - }; - - fd = wolfSSL_get_wfd(ssl); - AssertIntGE(fd, 0); - ret = (int)send(fd, (MESSAGE_TYPE_CAST)ch_msg, sizeof(ch_msg), 0); - AssertIntGT(ret, 0); - /* consume the HRR otherwise handshake will fail */ - ret = (int)recv(fd, (MESSAGE_TYPE_CAST)ch_msg, sizeof(ch_msg), 0); - AssertIntGT(ret, 0); -} - -#if defined(WOLFSSL_DTLS13) && defined(WOLFSSL_SEND_HRR_COOKIE) -static void test_wolfSSL_dtls_send_ch_with_invalid_cookie(WOLFSSL* ssl) -{ - int fd, ret; - byte ch_msh_invalid_cookie[] = { - 0x16, 0xfe, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, - 0x4e, 0x01, 0x00, 0x02, 0x42, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, - 0x42, 0xfe, 0xfd, 0x69, 0xca, 0x77, 0x60, 0x6f, 0xfc, 0xd1, 0x5b, 0x60, - 0x5d, 0xf1, 0xa6, 0x5c, 0x44, 0x71, 0xae, 0xca, 0x62, 0x19, 0x0c, 0xb6, - 0xf7, 0x2c, 0xa6, 0xd5, 0xd2, 0x99, 0x9d, 0x18, 0xae, 0xac, 0x11, 0x00, - 0x00, 0x00, 0x36, 0x13, 0x01, 0x13, 0x02, 0x13, 0x03, 0xc0, 0x2c, 0xc0, - 0x2b, 0xc0, 0x30, 0xc0, 0x2f, 0x00, 0x9f, 0x00, 0x9e, 0xcc, 0xa9, 0xcc, - 0xa8, 0xcc, 0xaa, 0xc0, 0x27, 0xc0, 0x23, 0xc0, 0x28, 0xc0, 0x24, 0xc0, - 0x0a, 0xc0, 0x09, 0xc0, 0x14, 0xc0, 0x13, 0x00, 0x6b, 0x00, 0x67, 0x00, - 0x39, 0x00, 0x33, 0xcc, 0x14, 0xcc, 0x13, 0xcc, 0x15, 0x01, 0x00, 0x01, - 0xe2, 0x00, 0x2b, 0x00, 0x03, 0x02, 0xfe, 0xfc, 0x00, 0x0d, 0x00, 0x20, - 0x00, 0x1e, 0x06, 0x03, 0x05, 0x03, 0x04, 0x03, 0x02, 0x03, 0x08, 0x06, - 0x08, 0x0b, 0x08, 0x05, 0x08, 0x0a, 0x08, 0x04, 0x08, 0x09, 0x06, 0x01, - 0x05, 0x01, 0x04, 0x01, 0x03, 0x01, 0x02, 0x01, 0x00, 0x2c, 0x00, 0x45, - 0x00, 0x43, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x2d, 0x00, - 0x03, 0x02, 0x00, 0x01, 0x00, 0x0a, 0x00, 0x0c, 0x00, 0x0a, 0x00, 0x19, - 0x00, 0x18, 0x00, 0x17, 0x00, 0x15, 0x01, 0x00, 0x00, 0x16, 0x00, 0x00, - 0x00, 0x33, 0x01, 0x4b, 0x01, 0x49, 0x00, 0x17, 0x00, 0x41, 0x04, 0x7c, - 0x5a, 0xc2, 0x5a, 0xfd, 0xcd, 0x2b, 0x08, 0xb2, 0xeb, 0x8e, 0xc0, 0x02, - 0x03, 0x9d, 0xb1, 0xc1, 0x0d, 0x7b, 0x7f, 0x46, 0x43, 0xdf, 0xf3, 0xee, - 0x2b, 0x78, 0x0e, 0x29, 0x8c, 0x42, 0x11, 0x2c, 0xde, 0xd7, 0x41, 0x0f, - 0x28, 0x94, 0x80, 0x41, 0x70, 0xc4, 0x17, 0xfd, 0x6d, 0xfa, 0xee, 0x9a, - 0xf2, 0xc4, 0x15, 0x4c, 0x5f, 0x54, 0xb6, 0x78, 0x6e, 0xf9, 0x63, 0x27, - 0x33, 0xb8, 0x7b, 0x01, 0x00, 0x01, 0x00, 0xd4, 0x46, 0x62, 0x9c, 0xbf, - 0x8f, 0x1b, 0x65, 0x9b, 0xf0, 0x29, 0x64, 0xd8, 0x50, 0x0e, 0x74, 0xf1, - 0x58, 0x10, 0xc9, 0xd9, 0x82, 0x5b, 0xd9, 0xbe, 0x14, 0xdf, 0xde, 0x86, - 0xb4, 0x2e, 0x15, 0xee, 0x4f, 0xf6, 0x74, 0x9e, 0x59, 0x11, 0x36, 0x2d, - 0xb9, 0x67, 0xaa, 0x5a, 0x09, 0x9b, 0x45, 0xf1, 0x01, 0x4c, 0x4e, 0xf6, - 0xda, 0x6a, 0xae, 0xa7, 0x73, 0x7b, 0x2e, 0xb6, 0x24, 0x89, 0x99, 0xb7, - 0x52, 0x16, 0x62, 0x0a, 0xab, 0x58, 0xf8, 0x3f, 0x10, 0x5b, 0x83, 0xfd, - 0x7b, 0x81, 0x77, 0x81, 0x8d, 0xef, 0x24, 0x56, 0x6d, 0xba, 0x49, 0xd4, - 0x8b, 0xb5, 0xa0, 0xb1, 0xc9, 0x8c, 0x32, 0x95, 0x1c, 0x5e, 0x0a, 0x4b, - 0xf6, 0x00, 0x50, 0x0a, 0x87, 0x99, 0x59, 0xcf, 0x6f, 0x9d, 0x02, 0xd0, - 0x1b, 0xa1, 0x96, 0x45, 0x28, 0x76, 0x40, 0x33, 0x28, 0xc9, 0xa1, 0xfd, - 0x46, 0xab, 0x2c, 0x9e, 0x5e, 0xc6, 0x74, 0x19, 0x9a, 0xf5, 0x9b, 0x51, - 0x11, 0x4f, 0xc8, 0xb9, 0x99, 0x6b, 0x4e, 0x3e, 0x31, 0x64, 0xb4, 0x92, - 0xf4, 0x0d, 0x41, 0x4b, 0x2c, 0x65, 0x23, 0xf7, 0x47, 0xe3, 0xa5, 0x2e, - 0xe4, 0x9c, 0x2b, 0xc9, 0x41, 0x22, 0x83, 0x8a, 0x23, 0xef, 0x29, 0x7e, - 0x4f, 0x3f, 0xa3, 0xbf, 0x73, 0x2b, 0xd7, 0xcc, 0xc8, 0xc6, 0xe9, 0xbc, - 0x01, 0xb7, 0x32, 0x63, 0xd4, 0x7e, 0x7f, 0x9a, 0xaf, 0x5f, 0x05, 0x31, - 0x53, 0xd6, 0x1f, 0xa2, 0xd0, 0xdf, 0x67, 0x56, 0xf1, 0x9c, 0x4a, 0x9d, - 0x83, 0xb4, 0xef, 0xb3, 0xf2, 0xcc, 0xf1, 0x91, 0x6c, 0x47, 0xc3, 0x8b, - 0xd0, 0x92, 0x79, 0x3d, 0xa0, 0xc0, 0x3a, 0x57, 0x26, 0x6d, 0x0a, 0xad, - 0x5f, 0xad, 0xb4, 0x74, 0x48, 0x4a, 0x51, 0xe1, 0xb5, 0x82, 0x0a, 0x4c, - 0x4f, 0x9d, 0xaf, 0xee, 0x5a, 0xa2, 0x4d, 0x4d, 0x5f, 0xe0, 0x17, 0x00, - 0x23, 0x00, 0x00 - }; - byte alert_reply[50]; - byte expected_alert_reply[] = { - 0x15, 0xfe, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, - 0x02, 0x02, 0x2f - }; - - fd = wolfSSL_get_wfd(ssl); - if (fd >= 0) { - ret = (int)send(fd, (MESSAGE_TYPE_CAST)ch_msh_invalid_cookie, - sizeof(ch_msh_invalid_cookie), 0); - AssertIntGT(ret, 0); - /* should reply with an illegal_parameter reply */ - ret = (int)recv(fd, (MESSAGE_TYPE_CAST)alert_reply, sizeof(alert_reply), 0); - AssertIntEQ(ret, sizeof(expected_alert_reply)); - AssertIntEQ(XMEMCMP(alert_reply, expected_alert_reply, - sizeof(expected_alert_reply)), 0); - } -} -#endif - -static word32 test_wolfSSL_dtls_stateless_HashWOLFSSL(const WOLFSSL* ssl) -{ -#ifndef NO_MD5 - enum wc_HashType hashType = WC_HASH_TYPE_MD5; -#elif !defined(NO_SHA) - enum wc_HashType hashType = WC_HASH_TYPE_SHA; -#elif !defined(NO_SHA256) - enum wc_HashType hashType = WC_HASH_TYPE_SHA256; -#else - #error "We need a digest to hash the WOLFSSL object" -#endif - byte hashBuf[WC_MAX_DIGEST_SIZE]; - wc_HashAlg hash; - const TLSX* exts = ssl->extensions; - WOLFSSL sslCopy; /* Use a copy to omit certain fields */ -#ifndef WOLFSSL_SMALL_STACK_CACHE - HS_Hashes* hsHashes = ssl->hsHashes; /* Is re-allocated in - * InitHandshakeHashes */ -#endif - - XMEMCPY(&sslCopy, ssl, sizeof(*ssl)); - XMEMSET(hashBuf, 0, sizeof(hashBuf)); - - /* Following fields are not important to compare */ - XMEMSET(sslCopy.buffers.inputBuffer.staticBuffer, 0, STATIC_BUFFER_LEN); - sslCopy.buffers.inputBuffer.buffer = NULL; - sslCopy.buffers.inputBuffer.bufferSize = 0; - sslCopy.buffers.inputBuffer.dynamicFlag = 0; - sslCopy.buffers.inputBuffer.offset = 0; - XMEMSET(sslCopy.buffers.outputBuffer.staticBuffer, 0, STATIC_BUFFER_LEN); - sslCopy.buffers.outputBuffer.buffer = NULL; - sslCopy.buffers.outputBuffer.bufferSize = 0; - sslCopy.buffers.outputBuffer.dynamicFlag = 0; - sslCopy.buffers.outputBuffer.offset = 0; - sslCopy.error = 0; - sslCopy.curSize = 0; - sslCopy.curStartIdx = 0; - sslCopy.keys.curSeq_lo = 0; - XMEMSET(&sslCopy.curRL, 0, sizeof(sslCopy.curRL)); -#ifdef WOLFSSL_DTLS13 - XMEMSET(&sslCopy.keys.curSeq, 0, sizeof(sslCopy.keys.curSeq)); - sslCopy.dtls13FastTimeout = 0; -#endif - sslCopy.keys.dtls_peer_handshake_number = 0; - XMEMSET(&sslCopy.alert_history, 0, sizeof(sslCopy.alert_history)); - sslCopy.hsHashes = NULL; -#if !defined(WOLFSSL_NO_CLIENT_AUTH) && \ - ((defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3)) || \ - (defined(HAVE_ED25519) && !defined(NO_ED25519_CLIENT_AUTH)) || \ - (defined(HAVE_ED448) && !defined(NO_ED448_CLIENT_AUTH))) - sslCopy.options.cacheMessages = 0; -#endif -#ifdef WOLFSSL_ASYNC_IO -#ifdef WOLFSSL_ASYNC_CRYPT - sslCopy.asyncDev = NULL; -#endif - sslCopy.async = NULL; -#endif - - AssertIntEQ(wc_HashInit(&hash, hashType), 0); - AssertIntEQ(wc_HashUpdate(&hash, hashType, (byte*)&sslCopy, sizeof(sslCopy)), 0); - /* hash extension list */ - while (exts != NULL) { - AssertIntEQ(wc_HashUpdate(&hash, hashType, (byte*)exts, sizeof(*exts)), 0); - exts = exts->next; - } - /* Hash suites */ - if (sslCopy.suites != NULL) { - AssertIntEQ(wc_HashUpdate(&hash, hashType, (byte*)sslCopy.suites, - sizeof(struct Suites)), 0); - } - -#ifdef WOLFSSL_SMALL_STACK_CACHE - /* with WOLFSSL_SMALL_STACK_CACHE, the SHA-2 objects always differ after - * initialization because of cached W and (for SHA512) X buffers. - */ -#else - /* Hash hsHashes */ - AssertIntEQ(wc_HashUpdate(&hash, hashType, (byte*)hsHashes, - sizeof(*hsHashes)), 0); -#endif - - AssertIntEQ(wc_HashFinal(&hash, hashType, hashBuf), 0); - AssertIntEQ(wc_HashFree(&hash, hashType), 0); - - return MakeWordFromHash(hashBuf); -} - -static CallbackIORecv test_wolfSSL_dtls_compare_stateless_cb; -static int test_wolfSSL_dtls_compare_stateless_cb_call_once; -static int test_wolfSSL_dtls_compare_stateless_read_cb_once(WOLFSSL *ssl, - char *buf, int sz, void *ctx) -{ - if (test_wolfSSL_dtls_compare_stateless_cb_call_once) { - test_wolfSSL_dtls_compare_stateless_cb_call_once = 0; - return test_wolfSSL_dtls_compare_stateless_cb(ssl, buf, sz, ctx); - } - else { - return WOLFSSL_CBIO_ERR_WANT_READ; - } -} - -static void test_wolfSSL_dtls_compare_stateless(WOLFSSL* ssl) -{ - /* Compare the ssl object before and after one ClientHello msg */ - SOCKET_T fd = wolfSSL_get_fd(ssl); - int res; - int err; - word32 initHash; - - test_wolfSSL_dtls_compare_stateless_cb = ssl->CBIORecv; - test_wolfSSL_dtls_compare_stateless_cb_call_once = 1; - wolfSSL_dtls_set_using_nonblock(ssl, 1); - ssl->CBIORecv = test_wolfSSL_dtls_compare_stateless_read_cb_once; - - initHash = test_wolfSSL_dtls_stateless_HashWOLFSSL(ssl); - (void)initHash; - - res = tcp_select(fd, 5); - /* We are expecting a msg. A timeout indicates failure. */ - AssertIntEQ(res, TEST_RECV_READY); - - res = wolfSSL_accept(ssl); - err = wolfSSL_get_error(ssl, res); - AssertIntEQ(res, WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)); - AssertIntEQ(err, WOLFSSL_ERROR_WANT_READ); - - AssertIntEQ(initHash, test_wolfSSL_dtls_stateless_HashWOLFSSL(ssl)); - - wolfSSL_dtls_set_using_nonblock(ssl, 0); - ssl->CBIORecv = test_wolfSSL_dtls_compare_stateless_cb; - -} - -#if defined(WOLFSSL_DTLS13) && defined(WOLFSSL_SEND_HRR_COOKIE) -static void test_wolfSSL_dtls_enable_hrrcookie(WOLFSSL* ssl) -{ - int ret; - ret = wolfSSL_send_hrr_cookie(ssl, NULL, 0); - AssertIntEQ(ret, WOLFSSL_SUCCESS); - test_wolfSSL_dtls_compare_stateless(ssl); -} -#endif - -static int test_wolfSSL_dtls_stateless(void) -{ - callback_functions client_cbs, server_cbs; - size_t i; - struct { - method_provider client_meth; - method_provider server_meth; - ssl_callback client_ssl_ready; - ssl_callback server_ssl_ready; - } test_params[] = { -#if !defined(WOLFSSL_NO_TLS12) - {wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method, - test_wolfSSL_dtls_send_ch, test_wolfSSL_dtls_compare_stateless}, -#endif -#if defined(WOLFSSL_DTLS13) && defined(WOLFSSL_SEND_HRR_COOKIE) - {wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method, - test_wolfSSL_dtls_send_ch, test_wolfSSL_dtls_enable_hrrcookie}, - {wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method, - test_wolfSSL_dtls_send_ch_with_invalid_cookie, test_wolfSSL_dtls_enable_hrrcookie}, -#endif - }; - - if (0 == sizeof(test_params)){ - return TEST_SKIPPED; - } - - for (i = 0; i < sizeof(test_params)/sizeof(*test_params); i++) { - XMEMSET(&client_cbs, 0, sizeof(client_cbs)); - XMEMSET(&server_cbs, 0, sizeof(server_cbs)); - client_cbs.doUdp = server_cbs.doUdp = 1; - client_cbs.method = test_params[i].client_meth; - server_cbs.method = test_params[i].server_meth; - - client_cbs.ssl_ready = test_params[i].client_ssl_ready; - server_cbs.ssl_ready = test_params[i].server_ssl_ready; - test_wolfSSL_client_server_nofail(&client_cbs, &server_cbs); - - if (!client_cbs.return_code) - return TEST_FAIL; - if (!server_cbs.return_code) - return TEST_FAIL; - } - - return TEST_SUCCESS; -} - -/* DTLS stateless API handling multiple CHs with different HRR groups */ -static int test_wolfSSL_dtls_stateless_hrr_group(void) -{ - EXPECT_DECLS; -#if defined(WOLFSSL_SEND_HRR_COOKIE) - size_t i; - word32 initHash; - struct { - method_provider client_meth; - method_provider server_meth; - } params[] = { -#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_DTLS13) - { wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method }, -#endif -#if !defined(WOLFSSL_NO_TLS12) && defined(WOLFSSL_DTLS) - { wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method }, -#endif - }; - for (i = 0; i < XELEM_CNT(params) && !EXPECT_FAIL(); i++) { - WOLFSSL_CTX *ctx_s = NULL, *ctx_c = NULL; - WOLFSSL *ssl_s = NULL, *ssl_c = NULL, *ssl_c2 = NULL; - struct test_memio_ctx test_ctx; - int groups_1[] = { - WOLFSSL_ECC_SECP256R1, - WOLFSSL_ECC_SECP384R1, - WOLFSSL_ECC_SECP521R1 - }; - int groups_2[] = { - WOLFSSL_ECC_SECP384R1, - WOLFSSL_ECC_SECP521R1 - }; - char hrrBuf[1000]; - int hrrSz = sizeof(hrrBuf); - - XMEMSET(&test_ctx, 0, sizeof(test_ctx)); - - ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, - params[i].client_meth, params[i].server_meth), 0); - - ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, NULL, &ssl_c2, NULL, - params[i].client_meth, params[i].server_meth), 0); - - - wolfSSL_SetLoggingPrefix("server"); - wolfSSL_dtls_set_using_nonblock(ssl_s, 1); - - initHash = test_wolfSSL_dtls_stateless_HashWOLFSSL(ssl_s); - - /* Set groups and disable key shares. This ensures that only the given - * groups are in the SupportedGroups extension and that an empty key - * share extension is sent in the initial ClientHello of each session. - * This triggers the server to send a HelloRetryRequest with the first - * group in the SupportedGroups extension selected. */ - wolfSSL_SetLoggingPrefix("client1"); - ExpectIntEQ(wolfSSL_set_groups(ssl_c, groups_1, 3), WOLFSSL_SUCCESS); - ExpectIntEQ(wolfSSL_NoKeyShares(ssl_c), WOLFSSL_SUCCESS); - - wolfSSL_SetLoggingPrefix("client2"); - ExpectIntEQ(wolfSSL_set_groups(ssl_c2, groups_2, 2), WOLFSSL_SUCCESS); - ExpectIntEQ(wolfSSL_NoKeyShares(ssl_c2), WOLFSSL_SUCCESS); - - /* Start handshake, send first ClientHello */ - wolfSSL_SetLoggingPrefix("client1"); - ExpectIntEQ(wolfSSL_connect(ssl_c), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); - - /* Read first ClientHello, send HRR with WOLFSSL_ECC_SECP256R1 */ - wolfSSL_SetLoggingPrefix("server"); - ExpectIntEQ(wolfDTLS_accept_stateless(ssl_s), 0); - ExpectIntEQ(test_memio_copy_message(&test_ctx, 1, hrrBuf, &hrrSz, 0), 0); - ExpectIntGT(hrrSz, 0); - ExpectIntEQ(initHash, test_wolfSSL_dtls_stateless_HashWOLFSSL(ssl_s)); - test_memio_clear_buffer(&test_ctx, 1); - - /* Send second ClientHello */ - wolfSSL_SetLoggingPrefix("client2"); - ExpectIntEQ(wolfSSL_connect(ssl_c2), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_c2, -1), WOLFSSL_ERROR_WANT_READ); - - /* Read second ClientHello, send HRR now with WOLFSSL_ECC_SECP384R1 */ - wolfSSL_SetLoggingPrefix("server"); - ExpectIntEQ(wolfDTLS_accept_stateless(ssl_s), 0); - ExpectIntEQ(initHash, test_wolfSSL_dtls_stateless_HashWOLFSSL(ssl_s)); - test_memio_clear_buffer(&test_ctx, 1); - - /* Complete first handshake with WOLFSSL_ECC_SECP256R1 */ - wolfSSL_SetLoggingPrefix("client1"); - ExpectIntEQ(test_memio_inject_message(&test_ctx, 1, hrrBuf, hrrSz), 0); - ExpectIntEQ(wolfSSL_connect(ssl_c), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); - - wolfSSL_SetLoggingPrefix("server"); - ExpectIntEQ(wolfDTLS_accept_stateless(ssl_s), WOLFSSL_SUCCESS); - - ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); - - wolfSSL_free(ssl_s); - wolfSSL_free(ssl_c); - wolfSSL_free(ssl_c2); - wolfSSL_CTX_free(ctx_s); - wolfSSL_CTX_free(ctx_c); - } -#endif /* WOLFSSL_SEND_HRR_COOKIE */ - return EXPECT_RESULT(); -} -#else -static int test_wolfSSL_dtls_stateless(void) -{ - return TEST_SKIPPED; -} - -static int test_wolfSSL_dtls_stateless_hrr_group(void) -{ - return TEST_SKIPPED; -} -#endif /* WOLFSSL_DTLS13 && WOLFSSL_SEND_HRR_COOKIE && - * HAVE_IO_TESTS_DEPENDENCIES && !SINGLE_THREADED */ #if defined(HAVE_KEYING_MATERIAL) && defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES) static int test_export_keying_material_cb(WOLFSSL_CTX *ctx, WOLFSSL *ssl) @@ -30364,92 +27210,6 @@ static int test_wolfSSL_CRYPTO_get_ex_new_index(void) return EXPECT_RESULT(); } -#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++; - } -} - -static 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 -static int test_wolfSSL_SESSION_get_ex_new_index(void) -{ - return TEST_SKIPPED; -} -#endif - static int test_wolfSSL_set_psk_use_session_callback(void) { EXPECT_DECLS; @@ -32096,560 +28856,6 @@ static int test_wolfSSL_FIPS_mode(void) return EXPECT_RESULT(); } -#ifdef WOLFSSL_DTLS - -/* Prints out the current window */ -static void DUW_TEST_print_window_binary(word32 h, word32 l, word32* w) { -#ifdef WOLFSSL_DEBUG_DTLS_WINDOW - int i; - for (i = WOLFSSL_DTLS_WINDOW_WORDS - 1; i >= 0; i--) { - word32 b = w[i]; - int j; - /* Prints out a 32 bit binary number in big endian order */ - for (j = 0; j < 32; j++, b <<= 1) { - if (b & (((word32)1) << 31)) - fprintf(stderr, "1"); - else - fprintf(stderr, "0"); - } - fprintf(stderr, " "); - } - fprintf(stderr, "cur_hi %u cur_lo %u\n", h, l); -#else - (void)h; - (void)l; - (void)w; -#endif -} - -/* a - cur_hi - * b - cur_lo - * c - next_hi - * d - next_lo - * e - window - * f - expected next_hi - * g - expected next_lo - * h - expected window[1] - * i - expected window[0] - */ -#define DUW_TEST(a,b,c,d,e,f,g,h,i) do { \ - ExpectIntEQ(wolfSSL_DtlsUpdateWindow((a), (b), &(c), &(d), (e)), 1); \ - DUW_TEST_print_window_binary((a), (b), (e)); \ - ExpectIntEQ((c), (f)); \ - ExpectIntEQ((d), (g)); \ - ExpectIntEQ((e)[1], (h)); \ - ExpectIntEQ((e)[0], (i)); \ -} while (0) - -static int test_wolfSSL_DtlsUpdateWindow(void) -{ - EXPECT_DECLS; - word32 window[WOLFSSL_DTLS_WINDOW_WORDS]; - word32 next_lo = 0; - word16 next_hi = 0; - -#ifdef WOLFSSL_DEBUG_DTLS_WINDOW - fprintf(stderr, "\n"); -#endif - - XMEMSET(window, 0, sizeof window); - DUW_TEST(0, 0, next_hi, next_lo, window, 0, 1, 0, 0x01); - DUW_TEST(0, 1, next_hi, next_lo, window, 0, 2, 0, 0x03); - DUW_TEST(0, 5, next_hi, next_lo, window, 0, 6, 0, 0x31); - DUW_TEST(0, 4, next_hi, next_lo, window, 0, 6, 0, 0x33); - DUW_TEST(0, 100, next_hi, next_lo, window, 0, 101, 0, 0x01); - DUW_TEST(0, 101, next_hi, next_lo, window, 0, 102, 0, 0x03); - DUW_TEST(0, 133, next_hi, next_lo, window, 0, 134, 0x03, 0x01); - DUW_TEST(0, 200, next_hi, next_lo, window, 0, 201, 0, 0x01); - DUW_TEST(0, 264, next_hi, next_lo, window, 0, 265, 0, 0x01); - DUW_TEST(0, 0xFFFFFFFF, next_hi, next_lo, window, 1, 0, 0, 0x01); - DUW_TEST(0, 0xFFFFFFFD, next_hi, next_lo, window, 1, 0, 0, 0x05); - DUW_TEST(0, 0xFFFFFFFE, next_hi, next_lo, window, 1, 0, 0, 0x07); - DUW_TEST(1, 3, next_hi, next_lo, window, 1, 4, 0, 0x71); - DUW_TEST(1, 0, next_hi, next_lo, window, 1, 4, 0, 0x79); - DUW_TEST(1, 0xFFFFFFFF, next_hi, next_lo, window, 2, 0, 0, 0x01); - DUW_TEST(2, 3, next_hi, next_lo, window, 2, 4, 0, 0x11); - DUW_TEST(2, 0, next_hi, next_lo, window, 2, 4, 0, 0x19); - DUW_TEST(2, 25, next_hi, next_lo, window, 2, 26, 0, 0x6400001); - DUW_TEST(2, 27, next_hi, next_lo, window, 2, 28, 0, 0x19000005); - DUW_TEST(2, 29, next_hi, next_lo, window, 2, 30, 0, 0x64000015); - DUW_TEST(2, 33, next_hi, next_lo, window, 2, 34, 6, 0x40000151); - DUW_TEST(2, 60, next_hi, next_lo, window, 2, 61, 0x3200000A, 0x88000001); - DUW_TEST(1, 0xFFFFFFF0, next_hi, next_lo, window, 2, 61, 0x3200000A, 0x88000001); - DUW_TEST(2, 0xFFFFFFFD, next_hi, next_lo, window, 2, 0xFFFFFFFE, 0, 0x01); - DUW_TEST(3, 1, next_hi, next_lo, window, 3, 2, 0, 0x11); - DUW_TEST(99, 66, next_hi, next_lo, window, 99, 67, 0, 0x01); - DUW_TEST(50, 66, next_hi, next_lo, window, 99, 67, 0, 0x01); - DUW_TEST(100, 68, next_hi, next_lo, window, 100, 69, 0, 0x01); - DUW_TEST(99, 50, next_hi, next_lo, window, 100, 69, 0, 0x01); - DUW_TEST(99, 0xFFFFFFFF, next_hi, next_lo, window, 100, 69, 0, 0x01); - DUW_TEST(150, 0xFFFFFFFF, next_hi, next_lo, window, 151, 0, 0, 0x01); - DUW_TEST(152, 0xFFFFFFFF, next_hi, next_lo, window, 153, 0, 0, 0x01); - - return EXPECT_RESULT(); -} -#endif /* WOLFSSL_DTLS */ - -#ifdef WOLFSSL_DTLS -static int DFB_TEST(WOLFSSL* ssl, word32 seq, word32 len, word32 f_offset, - word32 f_len, word32 f_count, byte ready, word32 bytesReceived) -{ - EXPECT_DECLS; - DtlsMsg* cur = NULL; - static byte msg[100]; - static byte msgInit = 0; - - if (!msgInit) { - int i; - for (i = 0; i < 100; i++) - msg[i] = i + 1; - msgInit = 1; - } - - /* Sanitize test parameters */ - ExpectIntLE(len, sizeof(msg)); - ExpectIntLE(f_offset + f_len, sizeof(msg)); - - if (EXPECT_SUCCESS()) - DtlsMsgStore(ssl, 0, seq, msg + f_offset, len, certificate, f_offset, f_len, NULL); - - ExpectNotNull(ssl->dtls_rx_msg_list); - - ExpectNotNull(cur = DtlsMsgFind(ssl->dtls_rx_msg_list, 0, seq)); - ExpectIntEQ(cur->fragBucketListCount, f_count); - ExpectIntEQ(cur->ready, ready); - ExpectIntEQ(cur->bytesReceived, bytesReceived); - if (ready) { - ExpectNull(cur->fragBucketList); - ExpectBufEQ(cur->fullMsg, msg, cur->sz); - } - else { - DtlsFragBucket* fb; - ExpectNotNull(cur->fragBucketList); - for (fb = cur != NULL ? cur->fragBucketList : NULL; - EXPECT_SUCCESS() && fb != NULL; fb = fb->m.m.next) - ExpectBufEQ(fb->buf, msg + fb->m.m.offset, fb->m.m.sz); - } - if (EXPECT_FAIL()) { - printf("Test parameters: seq %u len %u f_offset %u f_len %u f_count %u ready %u bytesReceived %u\n", - seq, len, f_offset, f_len, f_count, ready, bytesReceived); - } - return EXPECT_RESULT(); -} - -static int test_wolfSSL_DTLS_fragment_buckets(void) -{ - EXPECT_DECLS; - WOLFSSL ssl[1]; - - XMEMSET(ssl, 0, sizeof(*ssl)); - - EXPECT_TEST(DFB_TEST(ssl, 0, 100, 0, 100, 0, 1, 100)); /* 0-100 */ - - EXPECT_TEST(DFB_TEST(ssl, 1, 100, 0, 20, 1, 0, 20)); /* 0-20 */ - EXPECT_TEST(DFB_TEST(ssl, 1, 100, 20, 20, 1, 0, 40)); /* 20-40 */ - EXPECT_TEST(DFB_TEST(ssl, 1, 100, 40, 20, 1, 0, 60)); /* 40-60 */ - EXPECT_TEST(DFB_TEST(ssl, 1, 100, 60, 20, 1, 0, 80)); /* 60-80 */ - EXPECT_TEST(DFB_TEST(ssl, 1, 100, 80, 20, 0, 1, 100)); /* 80-100 */ - - /* Test all permutations of 3 regions */ - /* 1 2 3 */ - EXPECT_TEST(DFB_TEST(ssl, 2, 100, 0, 30, 1, 0, 30)); /* 0-30 */ - EXPECT_TEST(DFB_TEST(ssl, 2, 100, 30, 30, 1, 0, 60)); /* 30-60 */ - EXPECT_TEST(DFB_TEST(ssl, 2, 100, 60, 40, 0, 1, 100)); /* 60-100 */ - /* 1 3 2 */ - EXPECT_TEST(DFB_TEST(ssl, 3, 100, 0, 30, 1, 0, 30)); /* 0-30 */ - EXPECT_TEST(DFB_TEST(ssl, 3, 100, 60, 40, 2, 0, 70)); /* 60-100 */ - EXPECT_TEST(DFB_TEST(ssl, 3, 100, 30, 30, 0, 1, 100)); /* 30-60 */ - /* 2 1 3 */ - EXPECT_TEST(DFB_TEST(ssl, 4, 100, 30, 30, 1, 0, 30)); /* 30-60 */ - EXPECT_TEST(DFB_TEST(ssl, 4, 100, 0, 30, 1, 0, 60)); /* 0-30 */ - EXPECT_TEST(DFB_TEST(ssl, 4, 100, 60, 40, 0, 1, 100)); /* 60-100 */ - /* 2 3 1 */ - EXPECT_TEST(DFB_TEST(ssl, 5, 100, 30, 30, 1, 0, 30)); /* 30-60 */ - EXPECT_TEST(DFB_TEST(ssl, 5, 100, 60, 40, 1, 0, 70)); /* 60-100 */ - EXPECT_TEST(DFB_TEST(ssl, 5, 100, 0, 30, 0, 1, 100)); /* 0-30 */ - /* 3 1 2 */ - EXPECT_TEST(DFB_TEST(ssl, 6, 100, 60, 40, 1, 0, 40)); /* 60-100 */ - EXPECT_TEST(DFB_TEST(ssl, 6, 100, 0, 30, 2, 0, 70)); /* 0-30 */ - EXPECT_TEST(DFB_TEST(ssl, 6, 100, 30, 30, 0, 1, 100)); /* 30-60 */ - /* 3 2 1 */ - EXPECT_TEST(DFB_TEST(ssl, 7, 100, 60, 40, 1, 0, 40)); /* 60-100 */ - EXPECT_TEST(DFB_TEST(ssl, 7, 100, 30, 30, 1, 0, 70)); /* 30-60 */ - EXPECT_TEST(DFB_TEST(ssl, 7, 100, 0, 30, 0, 1, 100)); /* 0-30 */ - - /* Test overlapping regions */ - EXPECT_TEST(DFB_TEST(ssl, 8, 100, 0, 30, 1, 0, 30)); /* 0-30 */ - EXPECT_TEST(DFB_TEST(ssl, 8, 100, 20, 10, 1, 0, 30)); /* 20-30 */ - EXPECT_TEST(DFB_TEST(ssl, 8, 100, 70, 10, 2, 0, 40)); /* 70-80 */ - EXPECT_TEST(DFB_TEST(ssl, 8, 100, 20, 30, 2, 0, 60)); /* 20-50 */ - EXPECT_TEST(DFB_TEST(ssl, 8, 100, 40, 60, 0, 1, 100)); /* 40-100 */ - - /* Test overlapping multiple regions */ - EXPECT_TEST(DFB_TEST(ssl, 9, 100, 0, 20, 1, 0, 20)); /* 0-20 */ - EXPECT_TEST(DFB_TEST(ssl, 9, 100, 30, 5, 2, 0, 25)); /* 30-35 */ - EXPECT_TEST(DFB_TEST(ssl, 9, 100, 40, 5, 3, 0, 30)); /* 40-45 */ - EXPECT_TEST(DFB_TEST(ssl, 9, 100, 50, 5, 4, 0, 35)); /* 50-55 */ - EXPECT_TEST(DFB_TEST(ssl, 9, 100, 60, 5, 5, 0, 40)); /* 60-65 */ - EXPECT_TEST(DFB_TEST(ssl, 9, 100, 70, 5, 6, 0, 45)); /* 70-75 */ - EXPECT_TEST(DFB_TEST(ssl, 9, 100, 30, 25, 4, 0, 55)); /* 30-55 */ - EXPECT_TEST(DFB_TEST(ssl, 9, 100, 55, 15, 2, 0, 65)); /* 55-70 */ - EXPECT_TEST(DFB_TEST(ssl, 9, 100, 75, 25, 2, 0, 90)); /* 75-100 */ - EXPECT_TEST(DFB_TEST(ssl, 9, 100, 10, 25, 0, 1, 100)); /* 10-35 */ - - EXPECT_TEST(DFB_TEST(ssl,10, 100, 0, 20, 1, 0, 20)); /* 0-20 */ - EXPECT_TEST(DFB_TEST(ssl,10, 100, 30, 20, 2, 0, 40)); /* 30-50 */ - EXPECT_TEST(DFB_TEST(ssl,10, 100, 0, 40, 1, 0, 50)); /* 0-40 */ - EXPECT_TEST(DFB_TEST(ssl,10, 100, 50, 50, 0, 1, 100)); /* 50-100 */ - - /* Test region between other regions */ - EXPECT_TEST(DFB_TEST(ssl,11, 100, 0, 20, 1, 0, 20)); /* 0-20 */ - EXPECT_TEST(DFB_TEST(ssl,11, 100, 80, 20, 2, 0, 40)); /* 80-100 */ - EXPECT_TEST(DFB_TEST(ssl,11, 100, 40, 20, 3, 0, 60)); /* 40-60 */ - EXPECT_TEST(DFB_TEST(ssl,11, 100, 20, 20, 2, 0, 80)); /* 20-40 */ - EXPECT_TEST(DFB_TEST(ssl,11, 100, 60, 20, 0, 1, 100)); /* 60-80 */ - - /* Test gap before first bucket (prev==NULL in gap-before branch) */ - EXPECT_TEST(DFB_TEST(ssl,12, 100, 50, 20, 1, 0, 20)); /* 50-70 */ - EXPECT_TEST(DFB_TEST(ssl,12, 100, 0, 20, 2, 0, 40)); /* 0-20 gap before first */ - EXPECT_TEST(DFB_TEST(ssl,12, 100, 20, 30, 1, 0, 70)); /* 20-50 bridges gap */ - EXPECT_TEST(DFB_TEST(ssl,12, 100, 70, 30, 0, 1, 100)); /* 70-100 */ - - /* Test fragment after message is already complete (ready early return) */ - EXPECT_TEST(DFB_TEST(ssl,13, 100, 0,100, 0, 1, 100)); /* 0-100 complete */ - EXPECT_TEST(DFB_TEST(ssl,13, 100, 0, 50, 0, 1, 100)); /* 0-50 dup on ready */ - - /* Test combine where next bucket is larger than cur (chosenBucket=&next) */ - EXPECT_TEST(DFB_TEST(ssl,14, 100, 0, 10, 1, 0, 10)); /* 0-10 */ - EXPECT_TEST(DFB_TEST(ssl,14, 100, 30, 50, 2, 0, 60)); /* 30-80 */ - EXPECT_TEST(DFB_TEST(ssl,14, 100, 5, 30, 1, 0, 80)); /* 5-35 next>cur */ - EXPECT_TEST(DFB_TEST(ssl,14, 100, 80, 20, 0, 1, 100)); /* 80-100 */ - - /* Test super fragment covering all existing buckets */ - EXPECT_TEST(DFB_TEST(ssl,15, 100, 10, 10, 1, 0, 10)); /* 10-20 */ - EXPECT_TEST(DFB_TEST(ssl,15, 100, 30, 10, 2, 0, 20)); /* 30-40 */ - EXPECT_TEST(DFB_TEST(ssl,15, 100, 60, 10, 3, 0, 30)); /* 60-70 */ - EXPECT_TEST(DFB_TEST(ssl,15, 100, 0,100, 0, 1, 100)); /* 0-100 super frag */ - - /* Test exact duplicate fragment */ - EXPECT_TEST(DFB_TEST(ssl,16, 100, 20, 40, 1, 0, 40)); /* 20-60 */ - EXPECT_TEST(DFB_TEST(ssl,16, 100, 20, 40, 1, 0, 40)); /* 20-60 exact dup */ - EXPECT_TEST(DFB_TEST(ssl,16, 100, 0, 20, 1, 0, 60)); /* 0-20 */ - EXPECT_TEST(DFB_TEST(ssl,16, 100, 60, 40, 0, 1, 100)); /* 60-100 */ - - /* Test combine bridging two buckets (combineNext, cur->data) */ - EXPECT_TEST(DFB_TEST(ssl,17, 100, 0, 30, 1, 0, 30)); /* 0-30 */ - EXPECT_TEST(DFB_TEST(ssl,17, 100, 60, 20, 2, 0, 50)); /* 60-80 */ - EXPECT_TEST(DFB_TEST(ssl,17, 100, 20, 45, 1, 0, 80)); /* 20-65 bridge */ - EXPECT_TEST(DFB_TEST(ssl,17, 100, 80, 20, 0, 1, 100)); /* 80-100 */ - - /* Test progressive left-extension with partial overlaps */ - EXPECT_TEST(DFB_TEST(ssl,18, 100, 70, 30, 1, 0, 30)); /* 70-100 */ - EXPECT_TEST(DFB_TEST(ssl,18, 100, 50, 30, 1, 0, 50)); /* 50-80 extend left */ - EXPECT_TEST(DFB_TEST(ssl,18, 100, 30, 30, 1, 0, 70)); /* 30-60 extend left */ - EXPECT_TEST(DFB_TEST(ssl,18, 100, 0, 40, 0, 1, 100)); /* 0-40 complete left */ - - DtlsMsgListDelete(ssl->dtls_rx_msg_list, ssl->heap); - ssl->dtls_rx_msg_list = NULL; - ssl->dtls_rx_msg_list_sz = 0; - return EXPECT_RESULT(); -} - -#endif - - -#if !defined(NO_FILESYSTEM) && \ - defined(WOLFSSL_DTLS) && !defined(WOLFSSL_NO_TLS12) && \ - defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && !defined(NO_RSA) - -static int test_wolfSSL_dtls_stateless2(void) -{ - EXPECT_DECLS; - WOLFSSL *ssl_c = NULL; - WOLFSSL *ssl_c2 = NULL; - WOLFSSL *ssl_s = NULL; - struct test_memio_ctx test_ctx; - WOLFSSL_CTX *ctx_c = NULL; - WOLFSSL_CTX *ctx_s = NULL; - - XMEMSET(&test_ctx, 0, sizeof(test_ctx)); - ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, - wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method), 0); - ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, NULL, &ssl_c2, NULL, - wolfDTLSv1_2_client_method, NULL), 0); - ExpectFalse(wolfSSL_is_stateful(ssl_s)); - /* send CH */ - ExpectTrue((wolfSSL_connect(ssl_c2) == WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)) && - (ssl_c2->error == WC_NO_ERR_TRACE(WANT_READ))); - ExpectIntEQ(wolfDTLS_accept_stateless(ssl_s), WOLFSSL_FAILURE); - ExpectFalse(wolfSSL_is_stateful(ssl_s)); - ExpectIntNE(test_ctx.c_len, 0); - /* consume HRR */ - test_memio_clear_buffer(&test_ctx, 1); - /* send CH1 */ - ExpectIntEQ(wolfSSL_connect(ssl_c), WOLFSSL_FATAL_ERROR); - ExpectIntEQ(wolfSSL_get_error(ssl_c, WOLFSSL_FATAL_ERROR), - WOLFSSL_ERROR_WANT_READ); - /* send HRR */ - ExpectIntEQ(wolfDTLS_accept_stateless(ssl_s), WOLFSSL_FAILURE); - /* send CH2 */ - ExpectIntEQ(wolfSSL_connect(ssl_c), WOLFSSL_FATAL_ERROR); - ExpectIntEQ(wolfSSL_get_error(ssl_c, WOLFSSL_FATAL_ERROR), - WOLFSSL_ERROR_WANT_READ); - /* send HRR */ - ExpectIntEQ(wolfDTLS_accept_stateless(ssl_s), WOLFSSL_SUCCESS); - ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); - ExpectTrue(wolfSSL_is_stateful(ssl_s)); - - wolfSSL_free(ssl_c2); - wolfSSL_free(ssl_c); - wolfSSL_free(ssl_s); - wolfSSL_CTX_free(ctx_c); - wolfSSL_CTX_free(ctx_s); - return EXPECT_RESULT(); -} - -#ifdef HAVE_MAX_FRAGMENT -static int test_wolfSSL_dtls_stateless_maxfrag(void) -{ - EXPECT_DECLS; - WOLFSSL *ssl_c = NULL; - WOLFSSL *ssl_c2 = NULL; - WOLFSSL *ssl_s = NULL; - struct test_memio_ctx test_ctx; - WOLFSSL_CTX *ctx_c = NULL; - WOLFSSL_CTX *ctx_s = NULL; - word16 max_fragment = 0; - - XMEMSET(&test_ctx, 0, sizeof(test_ctx)); - ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, - wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method), 0); - ExpectNotNull(ssl_s); - ExpectNotNull(ssl_c2 = wolfSSL_new(ctx_c)); - ExpectIntEQ(wolfSSL_UseMaxFragment(ssl_c2, WOLFSSL_MFL_2_8), - WOLFSSL_SUCCESS); - wolfSSL_SetIOWriteCtx(ssl_c2, &test_ctx); - wolfSSL_SetIOReadCtx(ssl_c2, &test_ctx); - if (EXPECT_SUCCESS()) { - max_fragment = ssl_s->max_fragment; - } - /* send CH */ - ExpectTrue((wolfSSL_connect(ssl_c2) == WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)) && - (ssl_c2->error == WC_NO_ERR_TRACE(WANT_READ))); - ExpectTrue((wolfSSL_accept(ssl_s) == WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)) && - (ssl_s->error == WC_NO_ERR_TRACE(WANT_READ))); - /* CH without cookie shouldn't change state */ - ExpectIntEQ(ssl_s->max_fragment, max_fragment); - ExpectIntNE(test_ctx.c_len, 0); - - /* consume HRR from buffer */ - test_memio_clear_buffer(&test_ctx, 1); - ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); - - wolfSSL_free(ssl_c2); - wolfSSL_free(ssl_c); - wolfSSL_free(ssl_s); - wolfSSL_CTX_free(ctx_c); - wolfSSL_CTX_free(ctx_s); - return EXPECT_RESULT(); -} -#endif /* HAVE_MAX_FRAGMENT */ - -#if defined(WOLFSSL_DTLS_NO_HVR_ON_RESUME) -#define ROUNDS_WITH_HVR 4 -#define ROUNDS_WITHOUT_HVR 2 -#define HANDSHAKE_TYPE_OFFSET DTLS_RECORD_HEADER_SZ -static int buf_is_hvr(const byte *data, int len) -{ - if (len < DTLS_RECORD_HEADER_SZ + DTLS_HANDSHAKE_HEADER_SZ) - return 0; - return data[HANDSHAKE_TYPE_OFFSET] == hello_verify_request; -} - -static int _test_wolfSSL_dtls_stateless_resume(byte useticket, byte bad) -{ - EXPECT_DECLS; - struct test_memio_ctx test_ctx; - WOLFSSL_CTX *ctx_c = NULL; - WOLFSSL_CTX *ctx_s = NULL; - WOLFSSL *ssl_c = NULL; - WOLFSSL *ssl_s = NULL; - WOLFSSL_SESSION *sess = NULL; - int round_trips; - - XMEMSET(&test_ctx, 0, sizeof(test_ctx)); - - ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, - &ssl_s, wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method), 0); -#ifdef HAVE_SESSION_TICKET - if (useticket) { - ExpectIntEQ(wolfSSL_UseSessionTicket(ssl_c), WOLFSSL_SUCCESS); - } -#endif - round_trips = ROUNDS_WITH_HVR; - ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, round_trips, - &round_trips), 0); - ExpectIntEQ(round_trips, ROUNDS_WITH_HVR); - ExpectNotNull(sess = wolfSSL_get1_session(ssl_c)); - wolfSSL_shutdown(ssl_c); - wolfSSL_shutdown(ssl_s); - wolfSSL_free(ssl_c); - ssl_c = NULL; - wolfSSL_free(ssl_s); - ssl_s = NULL; - - test_memio_clear_buffer(&test_ctx, 1); - test_memio_clear_buffer(&test_ctx, 0); - /* make resumption invalid */ - if (bad && (sess != NULL)) { - if (useticket) { -#ifdef HAVE_SESSION_TICKET - if (sess->ticket != NULL) { - sess->ticket[0] = !sess->ticket[0]; - } -#endif /* HAVE_SESSION_TICKET */ - } - else { - sess->sessionID[0] = !sess->sessionID[0]; - } - } - ExpectNotNull(ssl_c = wolfSSL_new(ctx_c)); - ExpectNotNull(ssl_s = wolfSSL_new(ctx_s)); - wolfSSL_SetIOWriteCtx(ssl_c, &test_ctx); - wolfSSL_SetIOReadCtx(ssl_c, &test_ctx); - wolfSSL_SetIOWriteCtx(ssl_s, &test_ctx); - wolfSSL_SetIOReadCtx(ssl_s, &test_ctx); - ExpectIntEQ(wolfSSL_set_session(ssl_c, sess), WOLFSSL_SUCCESS); - ExpectTrue((wolfSSL_connect(ssl_c) == WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)) && - (ssl_c->error == WC_NO_ERR_TRACE(WANT_READ))); - ExpectTrue((wolfSSL_accept(ssl_s) == WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)) && - (ssl_s->error == WC_NO_ERR_TRACE(WANT_READ))); - ExpectFalse(bad && !buf_is_hvr(test_ctx.c_buff, test_ctx.c_len)); - ExpectFalse(!bad && buf_is_hvr(test_ctx.c_buff, test_ctx.c_len)); - if (!useticket) { - ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, &round_trips), 0); - ExpectFalse(bad && round_trips != ROUNDS_WITH_HVR - 1); - ExpectFalse(!bad && round_trips != ROUNDS_WITHOUT_HVR - 1); - } - wolfSSL_SESSION_free(sess); - wolfSSL_free(ssl_c); - wolfSSL_free(ssl_s); - wolfSSL_CTX_free(ctx_c); - wolfSSL_CTX_free(ctx_s); - return EXPECT_RESULT(); -} - -static int test_wolfSSL_dtls_stateless_resume(void) -{ - EXPECT_DECLS; -#ifdef HAVE_SESSION_TICKET - ExpectIntEQ(_test_wolfSSL_dtls_stateless_resume(1, 0), TEST_SUCCESS); - ExpectIntEQ(_test_wolfSSL_dtls_stateless_resume(1, 1), TEST_SUCCESS); -#endif /* HAVE_SESION_TICKET */ - ExpectIntEQ(_test_wolfSSL_dtls_stateless_resume(0, 0), TEST_SUCCESS); - ExpectIntEQ(_test_wolfSSL_dtls_stateless_resume(0, 1), TEST_SUCCESS); - return EXPECT_RESULT(); -} -#endif /* WOLFSSL_DTLS_NO_HVR_ON_RESUME */ - -#if !defined(NO_OLD_TLS) -static int test_wolfSSL_dtls_stateless_downgrade(void) -{ - EXPECT_DECLS; - WOLFSSL_CTX *ctx_c = NULL; - WOLFSSL_CTX *ctx_c2 = NULL; - WOLFSSL_CTX *ctx_s = NULL; - WOLFSSL *ssl_c = NULL; - WOLFSSL *ssl_c2 = NULL; - WOLFSSL *ssl_s = NULL; - struct test_memio_ctx test_ctx; - - XMEMSET(&test_ctx, 0, sizeof(test_ctx)); - ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, - wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method), 0); - ExpectIntEQ(wolfSSL_CTX_SetMinVersion(ctx_s, WOLFSSL_DTLSV1), - WOLFSSL_SUCCESS); - ExpectNotNull(ctx_c2 = wolfSSL_CTX_new(wolfDTLSv1_client_method())); - wolfSSL_SetIORecv(ctx_c2, test_memio_read_cb); - wolfSSL_SetIOSend(ctx_c2, test_memio_write_cb); - ExpectNotNull(ssl_c2 = wolfSSL_new(ctx_c2)); - wolfSSL_SetIOWriteCtx(ssl_c2, &test_ctx); - wolfSSL_SetIOReadCtx(ssl_c2, &test_ctx); - /* send CH */ - ExpectTrue((wolfSSL_connect(ssl_c2) == WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)) && - (ssl_c2->error == WC_NO_ERR_TRACE(WANT_READ))); - ExpectTrue((wolfSSL_accept(ssl_s) == WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)) && - (ssl_s->error == WC_NO_ERR_TRACE(WANT_READ))); - ExpectIntNE(test_ctx.c_len, 0); - /* consume HRR */ - test_memio_clear_buffer(&test_ctx, 1); - ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); - - wolfSSL_free(ssl_c2); - wolfSSL_free(ssl_c); - wolfSSL_free(ssl_s); - wolfSSL_CTX_free(ctx_c); - wolfSSL_CTX_free(ctx_c2); - wolfSSL_CTX_free(ctx_s); - - return EXPECT_RESULT(); -} -#endif /* !defined(NO_OLD_TLS) */ - -#endif /* defined(WOLFSSL_DTLS) && !defined(WOLFSSL_NO_TLS12) && \ - !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)*/ - -#if defined(WOLFSSL_DTLS) && !defined(WOLFSSL_NO_TLS12) && \ - !defined(NO_OLD_TLS) && defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) -static int test_WOLFSSL_dtls_version_alert(void) -{ - EXPECT_DECLS; - struct test_memio_ctx test_ctx; - WOLFSSL_CTX *ctx_c = NULL; - WOLFSSL_CTX *ctx_s = NULL; - WOLFSSL *ssl_c = NULL; - WOLFSSL *ssl_s = NULL; - - XMEMSET(&test_ctx, 0, sizeof(test_ctx)); - - ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, - wolfDTLSv1_2_client_method, wolfDTLSv1_server_method), 0); - - /* client hello */ - ExpectTrue((wolfSSL_connect(ssl_c) == WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)) && - (ssl_c->error == WC_NO_ERR_TRACE(WANT_READ))); - /* hrr */ - ExpectTrue((wolfSSL_accept(ssl_s) == WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)) && - (ssl_s->error == WC_NO_ERR_TRACE(WANT_READ))); - /* client hello 1 */ - ExpectTrue((wolfSSL_connect(ssl_c) == WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)) && - (ssl_c->error == WC_NO_ERR_TRACE(WANT_READ))); - /* server hello */ - ExpectTrue((wolfSSL_accept(ssl_s) == WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)) && - (ssl_s->error == WC_NO_ERR_TRACE(WANT_READ))); - /* should fail */ - ExpectTrue((wolfSSL_connect(ssl_c) == WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)) && - (ssl_c->error == WC_NO_ERR_TRACE(VERSION_ERROR))); - /* shuould fail */ - ExpectTrue((wolfSSL_accept(ssl_s) == WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)) && - (ssl_s->error == WC_NO_ERR_TRACE(VERSION_ERROR) || ssl_s->error == WC_NO_ERR_TRACE(FATAL_ERROR))); - - wolfSSL_free(ssl_c); - wolfSSL_free(ssl_s); - wolfSSL_CTX_free(ctx_c); - wolfSSL_CTX_free(ctx_s); - - return EXPECT_RESULT(); -} -#else -static int test_WOLFSSL_dtls_version_alert(void) -{ - return TEST_SKIPPED; -} -#endif /* defined(WOLFSSL_DTLS) && !defined(WOLFSSL_NO_TLS12) && - * !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) && - * !defined(NO_OLD_TLS) && !defined(NO_RSA) - */ #if defined(WOLFSSL_TICKET_NONCE_MALLOC) && defined(HAVE_SESSION_TICKET) \ @@ -34275,71 +30481,6 @@ static int test_rpk_set_xxx_cert_type(void) return EXPECT_RESULT(); } -#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13) - - -static int test_dtls13_bad_epoch_ch(void) -{ - EXPECT_DECLS; - WOLFSSL_CTX *ctx_c = NULL; - WOLFSSL_CTX *ctx_s = NULL; - WOLFSSL *ssl_c = NULL; - WOLFSSL *ssl_s = NULL; - struct test_memio_ctx test_ctx; - const int EPOCH_OFF = 3; - int groups[] = { - WOLFSSL_ECC_SECP256R1, - WOLFSSL_ECC_SECP384R1, - }; - - XMEMSET(&test_ctx, 0, sizeof(test_ctx)); - ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, - wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), 0); - - /* disable hrr cookie so we can later check msgsReceived.got_client_hello - * with just one message */ - ExpectIntEQ(wolfSSL_disable_hrr_cookie(ssl_s), WOLFSSL_SUCCESS); - - /* Set client groups to traditional only to avoid CH fragmentation */ - ExpectIntEQ(wolfSSL_set_groups(ssl_c, groups, 2), WOLFSSL_SUCCESS); - - ExpectIntNE(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS); - ExpectIntEQ(wolfSSL_get_error(ssl_c, WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)), - WOLFSSL_ERROR_WANT_READ); - - ExpectIntGE(test_ctx.s_len, EPOCH_OFF + 2); - - /* first CH should use epoch 0x0 */ - ExpectTrue((test_ctx.s_buff[EPOCH_OFF] == 0x0) && - (test_ctx.s_buff[EPOCH_OFF + 1] == 0x0)); - - /* change epoch to 2 */ - test_ctx.s_buff[EPOCH_OFF + 1] = 0x2; - - ExpectIntNE(wolfSSL_accept(ssl_s), WOLFSSL_SUCCESS); - ExpectIntEQ(wolfSSL_get_error(ssl_s, WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)), - WOLFSSL_ERROR_WANT_READ); - - ExpectIntNE(ssl_s->msgsReceived.got_client_hello, 1); - - /* resend the CH */ - ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl_c), WOLFSSL_SUCCESS); - - ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); - - wolfSSL_free(ssl_c); - wolfSSL_CTX_free(ctx_c); - wolfSSL_free(ssl_s); - wolfSSL_CTX_free(ctx_s); - - return EXPECT_RESULT(); -} -#else -static int test_dtls13_bad_epoch_ch(void) -{ - return TEST_SKIPPED; -} -#endif #if ((defined(WOLFSSL_TLS13) && !defined(WOLFSSL_NO_DEF_TICKET_ENC_CB) && \ defined(HAVE_SESSION_TICKET) && defined(WOLFSSL_TICKET_HAVE_ID) && \ @@ -34428,232 +30569,6 @@ static int test_short_session_id(void) } #endif -#if defined(HAVE_NULL_CIPHER) && defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) \ - && defined(WOLFSSL_DTLS13) -static byte* test_find_string(const char *string, - byte *buf, int buf_size) -{ - int string_size, i; - - string_size = (int)XSTRLEN(string); - for (i = 0; i < buf_size - string_size - 1; i++) { - if (XSTRCMP((char*)&buf[i], string) == 0) - return &buf[i]; - } - return NULL; -} - -static int test_wolfSSL_dtls13_null_cipher(void) -{ - EXPECT_DECLS; - WOLFSSL_CTX *ctx_c = NULL; - WOLFSSL_CTX *ctx_s = NULL; - WOLFSSL *ssl_c = NULL; - WOLFSSL *ssl_s = NULL; - struct test_memio_ctx test_ctx; - const char *test_str = "test"; - int test_str_size; - byte buf[255], *ptr = NULL; - - XMEMSET(&test_ctx, 0, sizeof(test_ctx)); - test_ctx.c_ciphers = test_ctx.s_ciphers = "TLS13-SHA256-SHA256"; - ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, - wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), 0); - ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); - test_str_size = XSTRLEN("test") + 1; - ExpectIntEQ(wolfSSL_write(ssl_c, test_str, test_str_size), test_str_size); - ExpectIntEQ(wolfSSL_read(ssl_s, buf, sizeof(buf)), test_str_size); - ExpectIntEQ(XSTRCMP((char*)buf, test_str), 0); - - ExpectIntEQ(wolfSSL_write(ssl_c, test_str, test_str_size), test_str_size); - - /* check that the packet was sent cleartext */ - ExpectNotNull(ptr = test_find_string(test_str, test_ctx.s_buff, - test_ctx.s_len)); - if (ptr != NULL) { - /* modify the message */ - *ptr = 'H'; - /* bad messages should be ignored in DTLS */ - ExpectIntEQ(wolfSSL_read(ssl_s, buf, sizeof(buf)), -1); - ExpectIntEQ(ssl_s->error, WC_NO_ERR_TRACE(WANT_READ)); - } - - ExpectIntEQ(wolfSSL_shutdown(ssl_c), WOLFSSL_SHUTDOWN_NOT_DONE); - ExpectIntEQ(wolfSSL_shutdown(ssl_s), WOLFSSL_SHUTDOWN_NOT_DONE); - ExpectIntEQ(wolfSSL_shutdown(ssl_c), 1); - ExpectIntEQ(wolfSSL_shutdown(ssl_s), 1); - - wolfSSL_free(ssl_c); - wolfSSL_free(ssl_s); - wolfSSL_CTX_free(ctx_c); - wolfSSL_CTX_free(ctx_s); - return TEST_SUCCESS; -} -#else -static int test_wolfSSL_dtls13_null_cipher(void) -{ - return TEST_SKIPPED; -} -#endif -#if defined(WOLFSSL_DTLS) && !defined(WOLFSSL_NO_TLS12) && \ - !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) && \ - !defined(SINGLE_THREADED) && !defined(NO_RSA) - -static int test_dtls_msg_get_connected_port(int fd, word16 *port) -{ - SOCKADDR_S peer; - XSOCKLENT len; - int ret; - - XMEMSET((byte*)&peer, 0, sizeof(peer)); - len = sizeof(peer); - ret = getpeername(fd, (SOCKADDR*)&peer, &len); - if (ret != 0 || len > (XSOCKLENT)sizeof(peer)) - return -1; - switch (peer.ss_family) { -#ifdef WOLFSSL_IPV6 - case WOLFSSL_IP6: { - *port = ntohs(((SOCKADDR_IN6*)&peer)->sin6_port); - break; - } -#endif /* WOLFSSL_IPV6 */ - case WOLFSSL_IP4: - *port = ntohs(((SOCKADDR_IN*)&peer)->sin_port); - break; - default: - return -1; - } - return 0; -} - -static int test_dtls_msg_from_other_peer_cb(WOLFSSL_CTX *ctx, WOLFSSL *ssl) -{ - char buf[1] = {'t'}; - SOCKADDR_IN_T addr; - int sock_fd; - word16 port; - int err; - - (void)ssl; - (void)ctx; - - if (ssl == NULL) - return -1; - - err = test_dtls_msg_get_connected_port(wolfSSL_get_fd(ssl), &port); - if (err != 0) - return -1; - - sock_fd = socket(AF_INET_V, SOCK_DGRAM, 0); - if (sock_fd == -1) - return -1; - build_addr(&addr, wolfSSLIP, port, 1, 0); - - /* send a packet to the server. Being another socket, the kernel will ensure - * the source port will be different. */ - err = (int)sendto(sock_fd, buf, sizeof(buf), 0, (SOCKADDR*)&addr, - sizeof(addr)); - - close(sock_fd); - if (err == -1) - return -1; - - return 0; -} - -/* setup a SSL session but just after the handshake send a packet to the server - * with a source address different than the one of the connected client. The I/O - * callback EmbedRecvFrom should just ignore the packet. Sending of the packet - * is done in test_dtls_msg_from_other_peer_cb */ -static int test_dtls_msg_from_other_peer(void) -{ - EXPECT_DECLS; - callback_functions client_cbs; - callback_functions server_cbs; - - XMEMSET((byte*)&client_cbs, 0, sizeof(client_cbs)); - XMEMSET((byte*)&server_cbs, 0, sizeof(server_cbs)); - - client_cbs.method = wolfDTLSv1_2_client_method; - server_cbs.method = wolfDTLSv1_2_server_method; - client_cbs.doUdp = 1; - server_cbs.doUdp = 1; - - test_wolfSSL_client_server_nofail_ex(&client_cbs, &server_cbs, - test_dtls_msg_from_other_peer_cb); - - ExpectIntEQ(client_cbs.return_code, WOLFSSL_SUCCESS); - ExpectIntEQ(server_cbs.return_code, WOLFSSL_SUCCESS); - - return EXPECT_RESULT(); -} -#else -static int test_dtls_msg_from_other_peer(void) -{ - return TEST_SKIPPED; -} -#endif /* defined(WOLFSSL_DTLS) && !defined(WOLFSSL_NO_TLS12) && \ - * !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) && \ - * !defined(SINGLE_THREADED) && !defined(NO_RSA) */ -#if defined(WOLFSSL_DTLS) && !defined(WOLFSSL_IPV6) && \ - !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) && \ - defined(HAVE_IO_TESTS_DEPENDENCIES) && !defined(WOLFSSL_NO_TLS12) \ - && !defined(USE_WINDOWS_API) -static int test_dtls_ipv6_check(void) -{ - EXPECT_DECLS; - WOLFSSL_CTX *ctx_c = NULL; - WOLFSSL_CTX *ctx_s = NULL; - WOLFSSL *ssl_c = NULL; - WOLFSSL *ssl_s = NULL; - SOCKADDR_IN fake_addr6; - int sockfd = -1; - - ExpectNotNull(ctx_c = wolfSSL_CTX_new(wolfDTLSv1_2_client_method())); - ExpectNotNull(ssl_c = wolfSSL_new(ctx_c)); - ExpectNotNull(ctx_s = wolfSSL_CTX_new(wolfDTLSv1_2_server_method())); - ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_file(ctx_s, svrKeyFile, - WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS); - ExpectIntEQ(wolfSSL_CTX_use_certificate_file(ctx_s, svrCertFile, - WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS); - ExpectNotNull(ssl_s = wolfSSL_new(ctx_s)); - XMEMSET((byte*)&fake_addr6, 0, sizeof(fake_addr6)); - /* mimic a sockaddr_in6 struct, this way we can't test without - * WOLFSSL_IPV6 */ - fake_addr6.sin_family = WOLFSSL_IP6; - ExpectIntNE(sockfd = socket(AF_INET, SOCK_DGRAM, 0), -1); - ExpectIntEQ(wolfSSL_set_fd(ssl_c, sockfd), WOLFSSL_SUCCESS); - /* can't return error here, as the peer is opaque for wolfssl library at - * this point */ - ExpectIntEQ(wolfSSL_dtls_set_peer(ssl_c, &fake_addr6, sizeof(fake_addr6)), - WOLFSSL_SUCCESS); - ExpectIntNE(fcntl(sockfd, F_SETFL, O_NONBLOCK), -1); - wolfSSL_dtls_set_using_nonblock(ssl_c, 1); - ExpectIntNE(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS); - ExpectIntEQ(ssl_c->error, WC_NO_ERR_TRACE(SOCKET_ERROR_E)); - - ExpectIntEQ(wolfSSL_dtls_set_peer(ssl_s, &fake_addr6, sizeof(fake_addr6)), - WOLFSSL_SUCCESS); - /* reuse the socket */ - ExpectIntEQ(wolfSSL_set_fd(ssl_c, sockfd), WOLFSSL_SUCCESS); - wolfSSL_dtls_set_using_nonblock(ssl_s, 1); - ExpectIntNE(wolfSSL_accept(ssl_s), WOLFSSL_SUCCESS); - ExpectIntEQ(ssl_s->error, WC_NO_ERR_TRACE(SOCKET_ERROR_E)); - if (sockfd != -1) - close(sockfd); - - wolfSSL_free(ssl_c); - wolfSSL_CTX_free(ctx_c); - wolfSSL_free(ssl_s); - wolfSSL_CTX_free(ctx_s); - return EXPECT_RESULT(); -} -#else -static int test_dtls_ipv6_check(void) -{ - return TEST_SKIPPED; -} -#endif #if !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) && \ defined(HAVE_IO_TESTS_DEPENDENCIES) && defined(HAVE_SECURE_RENEGOTIATION) @@ -34747,96 +30662,6 @@ static int test_wolfSSL_configure_args(void) return EXPECT_RESULT(); } -static int test_dtls_no_extensions(void) -{ - EXPECT_DECLS; -#if defined(WOLFSSL_DTLS) && defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \ - !defined(WOLFSSL_NO_TLS12) - WOLFSSL *ssl_s = NULL; - WOLFSSL_CTX *ctx_s = NULL; - struct test_memio_ctx test_ctx; - const byte chNoExtensions[] = { - /* Handshake type */ - 0x16, - /* Version */ - 0xfe, 0xff, - /* Epoch */ - 0x00, 0x00, - /* Seq number */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* Length */ - 0x00, 0x40, - /* CH type */ - 0x01, - /* Length */ - 0x00, 0x00, 0x34, - /* Msg Seq */ - 0x00, 0x00, - /* Frag offset */ - 0x00, 0x00, 0x00, - /* Frag length */ - 0x00, 0x00, 0x34, - /* Version */ - 0xfe, 0xff, - /* Random */ - 0x62, 0xfe, 0xbc, 0xfe, 0x2b, 0xfe, 0x3f, 0xeb, 0x03, 0xc4, 0xea, 0x37, - 0xe7, 0x47, 0x7e, 0x8a, 0xd9, 0xbf, 0x77, 0x0f, 0x6c, 0xb6, 0x77, 0x0b, - 0x03, 0x3f, 0x82, 0x2b, 0x21, 0x64, 0x57, 0x1d, - /* Session Length */ - 0x00, - /* Cookie Length */ - 0x00, - /* CS Length */ - 0x00, 0x0c, - /* CS */ - 0xc0, 0x0a, 0xc0, 0x09, 0xc0, 0x14, 0xc0, 0x13, 0x00, 0x39, 0x00, 0x33, - /* Comp Meths Length */ - 0x01, - /* Comp Meths */ - 0x00 - /* And finally... no extensions */ - }; - int i; -#ifdef OPENSSL_EXTRA - int repeats = 2; -#else - int repeats = 1; -#endif - - for (i = 0; i < repeats; i++) { - XMEMSET(&test_ctx, 0, sizeof(test_ctx)); - ssl_s = NULL; - ctx_s = NULL; - - ExpectIntEQ(test_memio_setup(&test_ctx, NULL, &ctx_s, NULL, &ssl_s, - NULL, wolfDTLS_server_method), 0); - - test_memio_clear_buffer(&test_ctx, 0); - ExpectIntEQ( - test_memio_inject_message(&test_ctx, 1, - (const char *)chNoExtensions, sizeof(chNoExtensions)), 0); - - -#ifdef OPENSSL_EXTRA - if (i > 0) { - ExpectIntEQ(wolfSSL_set_max_proto_version(ssl_s, DTLS1_2_VERSION), - WOLFSSL_SUCCESS); - } -#endif - - ExpectIntEQ(wolfSSL_accept(ssl_s), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); - - /* Expecting a handshake msg. Either HVR or SH. */ - ExpectIntGT(test_ctx.c_len, 0); - ExpectIntEQ(test_ctx.c_buff[0], 0x16); - - wolfSSL_free(ssl_s); - wolfSSL_CTX_free(ctx_s); - } -#endif - return EXPECT_RESULT(); -} static int test_tls_alert_no_server_hello(void) { @@ -34961,42 +30786,6 @@ static int test_TLSX_CA_NAMES_bad_extension(void) return EXPECT_RESULT(); } -#if defined(WOLFSSL_DTLS) && !defined(WOLFSSL_NO_TLS12) && \ - defined(HAVE_IO_TESTS_DEPENDENCIES) -static void test_dtls_1_0_hvr_downgrade_ctx_ready(WOLFSSL_CTX* ctx) -{ - AssertIntEQ(wolfSSL_CTX_SetMinVersion(ctx, WOLFSSL_DTLSV1_2), - WOLFSSL_SUCCESS); -} - -static int test_dtls_1_0_hvr_downgrade(void) -{ - EXPECT_DECLS; - callback_functions func_cb_client; - callback_functions func_cb_server; - - XMEMSET(&func_cb_client, 0, sizeof(callback_functions)); - XMEMSET(&func_cb_server, 0, sizeof(callback_functions)); - - func_cb_client.doUdp = func_cb_server.doUdp = 1; - func_cb_client.method = wolfDTLS_client_method; - func_cb_server.method = wolfDTLSv1_2_server_method; - func_cb_client.ctx_ready = test_dtls_1_0_hvr_downgrade_ctx_ready; - - test_wolfSSL_client_server_nofail(&func_cb_client, &func_cb_server); - - ExpectIntEQ(func_cb_client.return_code, TEST_SUCCESS); - ExpectIntEQ(func_cb_server.return_code, TEST_SUCCESS); - - return EXPECT_RESULT(); -} -#else -static int test_dtls_1_0_hvr_downgrade(void) -{ - EXPECT_DECLS; - return EXPECT_RESULT(); -} -#endif #if defined(HAVE_IO_TESTS_DEPENDENCIES) && !defined(WOLFSSL_NO_TLS12) && \ defined(HAVE_SESSION_TICKET) @@ -35153,499 +30942,12 @@ static int test_session_ticket_hs_update(void) return EXPECT_RESULT(); } -#if defined(WOLFSSL_DTLS) && !defined(WOLFSSL_NO_TLS12) && \ - defined(HAVE_IO_TESTS_DEPENDENCIES) && defined(HAVE_SECURE_RENEGOTIATION) -static void test_dtls_downgrade_scr_server_ctx_ready_server(WOLFSSL_CTX* ctx) -{ - AssertIntEQ(wolfSSL_CTX_SetMinVersion(ctx, WOLFSSL_DTLSV1_2), - WOLFSSL_SUCCESS); - AssertIntEQ(wolfSSL_CTX_UseSecureRenegotiation(ctx), WOLFSSL_SUCCESS); -} - -static void test_dtls_downgrade_scr_server_ctx_ready(WOLFSSL_CTX* ctx) -{ - AssertIntEQ(wolfSSL_CTX_UseSecureRenegotiation(ctx), WOLFSSL_SUCCESS); -} - -static void test_dtls_downgrade_scr_server_on_result(WOLFSSL* ssl) -{ - char testMsg[] = "Message after SCR"; - char msgBuf[sizeof(testMsg)]; - if (wolfSSL_is_server(ssl)) { - AssertIntEQ(wolfSSL_Rehandshake(ssl), WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)); - AssertIntEQ(wolfSSL_get_error(ssl, -1), WC_NO_ERR_TRACE(APP_DATA_READY)); - AssertIntEQ(wolfSSL_read(ssl, msgBuf, sizeof(msgBuf)), sizeof(msgBuf)); - AssertIntEQ(wolfSSL_Rehandshake(ssl), WOLFSSL_SUCCESS); - AssertIntEQ(wolfSSL_write(ssl, testMsg, sizeof(testMsg)), - sizeof(testMsg)); - } - else { - AssertIntEQ(wolfSSL_write(ssl, testMsg, sizeof(testMsg)), - sizeof(testMsg)); - AssertIntEQ(wolfSSL_read(ssl, msgBuf, sizeof(msgBuf)), sizeof(msgBuf)); - } -} - -static int test_dtls_downgrade_scr_server(void) -{ - EXPECT_DECLS; - callback_functions func_cb_client; - callback_functions func_cb_server; - XMEMSET(&func_cb_client, 0, sizeof(callback_functions)); - XMEMSET(&func_cb_server, 0, sizeof(callback_functions)); - - func_cb_client.doUdp = func_cb_server.doUdp = 1; - func_cb_client.method = wolfDTLSv1_2_client_method; - func_cb_server.method = wolfDTLS_server_method; - func_cb_client.ctx_ready = test_dtls_downgrade_scr_server_ctx_ready; - func_cb_server.ctx_ready = test_dtls_downgrade_scr_server_ctx_ready_server; - func_cb_client.on_result = test_dtls_downgrade_scr_server_on_result; - func_cb_server.on_result = test_dtls_downgrade_scr_server_on_result; - - test_wolfSSL_client_server_nofail(&func_cb_client, &func_cb_server); - - ExpectIntEQ(func_cb_client.return_code, TEST_SUCCESS); - ExpectIntEQ(func_cb_server.return_code, TEST_SUCCESS); - - return EXPECT_RESULT(); -} -#else -static int test_dtls_downgrade_scr_server(void) -{ - EXPECT_DECLS; - return EXPECT_RESULT(); -} -#endif - -#if defined(WOLFSSL_DTLS) && !defined(WOLFSSL_NO_TLS12) && \ - defined(HAVE_IO_TESTS_DEPENDENCIES) && defined(HAVE_SECURE_RENEGOTIATION) -static void test_dtls_downgrade_scr_ctx_ready(WOLFSSL_CTX* ctx) -{ - AssertIntEQ(wolfSSL_CTX_SetMinVersion(ctx, WOLFSSL_DTLSV1_2), - WOLFSSL_SUCCESS); - AssertIntEQ(wolfSSL_CTX_UseSecureRenegotiation(ctx), WOLFSSL_SUCCESS); -} -static void test_dtls_downgrade_scr_on_result(WOLFSSL* ssl) -{ - char testMsg[] = "Message after SCR"; - char msgBuf[sizeof(testMsg)]; - if (wolfSSL_is_server(ssl)) { - AssertIntEQ(wolfSSL_Rehandshake(ssl), WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)); - AssertIntEQ(wolfSSL_get_error(ssl, -1), WC_NO_ERR_TRACE(APP_DATA_READY)); - AssertIntEQ(wolfSSL_read(ssl, msgBuf, sizeof(msgBuf)), sizeof(msgBuf)); - AssertIntEQ(wolfSSL_Rehandshake(ssl), WOLFSSL_SUCCESS); - AssertIntEQ(wolfSSL_write(ssl, testMsg, sizeof(testMsg)), - sizeof(testMsg)); - } - else { - AssertIntEQ(wolfSSL_write(ssl, testMsg, sizeof(testMsg)), - sizeof(testMsg)); - AssertIntEQ(wolfSSL_read(ssl, msgBuf, sizeof(msgBuf)), sizeof(msgBuf)); - } -} - -static int test_dtls_downgrade_scr(void) -{ - EXPECT_DECLS; - callback_functions func_cb_client; - callback_functions func_cb_server; - - XMEMSET(&func_cb_client, 0, sizeof(callback_functions)); - XMEMSET(&func_cb_server, 0, sizeof(callback_functions)); - - func_cb_client.doUdp = func_cb_server.doUdp = 1; - func_cb_client.method = wolfDTLS_client_method; - func_cb_server.method = wolfDTLSv1_2_server_method; - func_cb_client.ctx_ready = test_dtls_downgrade_scr_ctx_ready; - func_cb_client.on_result = test_dtls_downgrade_scr_on_result; - func_cb_server.on_result = test_dtls_downgrade_scr_on_result; - - test_wolfSSL_client_server_nofail(&func_cb_client, &func_cb_server); - - ExpectIntEQ(func_cb_client.return_code, TEST_SUCCESS); - ExpectIntEQ(func_cb_server.return_code, TEST_SUCCESS); - - return EXPECT_RESULT(); -} -#else -static int test_dtls_downgrade_scr(void) -{ - EXPECT_DECLS; - return EXPECT_RESULT(); -} -#endif - -#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13) \ - && !defined(WOLFSSL_NO_TLS12) - -static int test_dtls_client_hello_timeout_downgrade_read_cb(WOLFSSL *ssl, - char *data, int sz, void *ctx) -{ - static int call_counter = 0; - call_counter++; - (void)ssl; - (void)data; - (void)sz; - (void)ctx; - switch (call_counter) { - case 1: - case 2: - return WOLFSSL_CBIO_ERR_TIMEOUT; - case 3: - return WOLFSSL_CBIO_ERR_WANT_READ; - default: - AssertIntLE(call_counter, 3); - return -1; - } -} -#endif - -/* Make sure we don't send acks before getting a server hello */ -static int test_dtls_client_hello_timeout_downgrade(void) -{ - EXPECT_DECLS; -#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13) \ - && !defined(WOLFSSL_NO_TLS12) - - WOLFSSL_CTX *ctx_c = NULL; - WOLFSSL_CTX *ctx_s = NULL; - WOLFSSL *ssl_c = NULL; - WOLFSSL *ssl_s = NULL; - struct test_memio_ctx test_ctx; - DtlsRecordLayerHeader* dtlsRH; - size_t len; - byte sequence_number[8]; - int i; - - for (i = 0; i < 2; i++) { - XMEMSET(&test_ctx, 0, sizeof(test_ctx)); - - ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, - wolfDTLS_client_method, wolfDTLSv1_2_server_method), 0); - - if (i == 0) { - /* First time simulate timeout in IO layer */ - /* CH1 */ - ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); - /* HVR */ - ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); - /* CH2 */ - ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); - /* SH flight */ - ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); - /* Drop the SH */ - if (EXPECT_SUCCESS()) { - ExpectIntEQ(test_memio_drop_message(&test_ctx, 1, 0), 0); - } - /* Read the remainder of the flight */ - ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); - wolfSSL_SSLSetIORecv(ssl_c, - test_dtls_client_hello_timeout_downgrade_read_cb); - /* CH3 */ - ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); - wolfSSL_SSLSetIORecv(ssl_c, test_memio_read_cb); - } - else { - /* Second time call wolfSSL_dtls_got_timeout */ - /* CH1 */ - ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); - /* HVR */ - ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); - /* CH2 */ - ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); - /* SH flight */ - ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); - /* Drop the SH */ - if (EXPECT_SUCCESS()) { - ExpectIntEQ(test_memio_drop_message(&test_ctx, 1, 0), 0); - } - /* Read the remainder of the flight */ - ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); - /* Quick timeout should be set as we received at least one msg */ - ExpectIntEQ(wolfSSL_dtls13_use_quick_timeout(ssl_c), 1); - ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl_c), WOLFSSL_SUCCESS); - /* Quick timeout should be cleared after a quick timeout */ - /* CH3 */ - ExpectIntEQ(wolfSSL_dtls13_use_quick_timeout(ssl_c), 0); - ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl_c), WOLFSSL_SUCCESS); - } - - /* Parse out to make sure we got exactly one ClientHello message */ - XMEMSET(&sequence_number, 0, sizeof(sequence_number)); - /* Second ClientHello after HVR */ - sequence_number[7] = 2; - dtlsRH = (DtlsRecordLayerHeader*)test_ctx.s_buff; - ExpectIntEQ(dtlsRH->type, handshake); - ExpectIntEQ(dtlsRH->pvMajor, DTLS_MAJOR); - ExpectIntEQ(dtlsRH->pvMinor, DTLSv1_2_MINOR); - ExpectIntEQ(XMEMCMP(sequence_number, dtlsRH->sequence_number, - sizeof(sequence_number)), 0); - len = (size_t)((dtlsRH->length[0] << 8) | dtlsRH->length[1]); - ExpectIntEQ(sizeof(DtlsRecordLayerHeader) + len, test_ctx.s_len); - - /* Connection should be able to continue */ - ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); - - wolfSSL_free(ssl_c); - wolfSSL_free(ssl_s); - wolfSSL_CTX_free(ctx_c); - wolfSSL_CTX_free(ctx_s); - ssl_c = NULL; - ssl_s = NULL; - ctx_c = NULL; - ctx_s = NULL; - if (!EXPECT_SUCCESS()) - break; - } - -#endif - return EXPECT_RESULT(); -} - -#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13) -static int test_dtls_client_hello_timeout_read_cb(WOLFSSL *ssl, char *data, - int sz, void *ctx) -{ - static int call_counter = 0; - call_counter++; - (void)ssl; - (void)data; - (void)sz; - (void)ctx; - switch (call_counter) { - case 1: - return WOLFSSL_CBIO_ERR_TIMEOUT; - case 2: - return WOLFSSL_CBIO_ERR_WANT_READ; - default: - AssertIntLE(call_counter, 2); - return -1; - } -} -#endif - -/* Make sure we don't send acks before getting a server hello */ -static int test_dtls_client_hello_timeout(void) -{ - EXPECT_DECLS; -#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13) - WOLFSSL *ssl_c = NULL; - WOLFSSL_CTX *ctx_c = NULL; - struct test_memio_ctx test_ctx; - DtlsRecordLayerHeader* dtlsRH; - size_t idx; - size_t len; - byte sequence_number[8]; - int i; - - for (i = 0; i < 2; i++) { - XMEMSET(&test_ctx, 0, sizeof(test_ctx)); - - ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, NULL, &ssl_c, NULL, - wolfDTLSv1_3_client_method, NULL), 0); - - if (i == 0) { - /* First time simulate timeout in IO layer */ - wolfSSL_SSLSetIORecv(ssl_c, test_dtls_client_hello_timeout_read_cb); - ExpectIntEQ(wolfSSL_connect(ssl_c), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); - } - else { - /* Second time call wolfSSL_dtls_got_timeout */ - ExpectIntEQ(wolfSSL_connect(ssl_c), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); - ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl_c), WOLFSSL_SUCCESS); - } - - /* Parse out to make sure we got exactly two ClientHello messages */ - idx = 0; - XMEMSET(&sequence_number, 0, sizeof(sequence_number)); - /* First ClientHello */ - dtlsRH = (DtlsRecordLayerHeader*)(test_ctx.s_buff + idx); - ExpectIntEQ(dtlsRH->type, handshake); - ExpectIntEQ(dtlsRH->pvMajor, DTLS_MAJOR); - ExpectIntEQ(dtlsRH->pvMinor, DTLSv1_2_MINOR); - ExpectIntEQ(XMEMCMP(sequence_number, dtlsRH->sequence_number, - sizeof(sequence_number)), 0); - len = (size_t)((dtlsRH->length[0] << 8) | dtlsRH->length[1]); - ExpectIntLT(idx + sizeof(DtlsRecordLayerHeader) + len, test_ctx.s_len); - idx += sizeof(DtlsRecordLayerHeader) + len; - /* Second ClientHello */ - sequence_number[7] = 1; - dtlsRH = (DtlsRecordLayerHeader*)(test_ctx.s_buff + idx); - ExpectIntEQ(dtlsRH->type, handshake); - ExpectIntEQ(dtlsRH->pvMajor, DTLS_MAJOR); - ExpectIntEQ(dtlsRH->pvMinor, DTLSv1_2_MINOR); - ExpectIntEQ(XMEMCMP(sequence_number, dtlsRH->sequence_number, - sizeof(sequence_number)), 0); - len = (size_t)((dtlsRH->length[0] << 8) | dtlsRH->length[1]); - ExpectIntEQ(idx + sizeof(DtlsRecordLayerHeader) + len, test_ctx.s_len); - - wolfSSL_free(ssl_c); - wolfSSL_CTX_free(ctx_c); - ssl_c = NULL; - ctx_c = NULL; - if (!EXPECT_SUCCESS()) - break; - } -#endif - return EXPECT_RESULT(); -} /* DTLS test when dropping the changed cipher spec message */ -static int test_dtls_dropped_ccs(void) -{ - EXPECT_DECLS; -#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS) \ - && !defined(WOLFSSL_NO_TLS12) - - WOLFSSL_CTX *ctx_c = NULL; - WOLFSSL_CTX *ctx_s = NULL; - WOLFSSL *ssl_c = NULL; - WOLFSSL *ssl_s = NULL; - struct test_memio_ctx test_ctx; - DtlsRecordLayerHeader* dtlsRH; - size_t len; - byte data[1]; - - XMEMSET(&test_ctx, 0, sizeof(test_ctx)); - - ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, - wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method), 0); - - /* CH1 */ - ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); - /* HVR */ - ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); - /* CH2 */ - ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); - /* Server first flight */ - ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); - /* Client flight */ - ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); - /* Server ccs + finished */ - ExpectIntEQ(wolfSSL_negotiate(ssl_s), 1); - - /* Drop the ccs */ - dtlsRH = (DtlsRecordLayerHeader*)test_ctx.c_buff; - len = (size_t)((dtlsRH->length[0] << 8) | dtlsRH->length[1]); - ExpectIntEQ(len, 1); - ExpectIntEQ(dtlsRH->type, change_cipher_spec); - if (EXPECT_SUCCESS()) { - ExpectIntEQ(test_memio_drop_message(&test_ctx, 1, 0), 0); - } - - /* Client rtx flight */ - ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); - ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl_c), WOLFSSL_SUCCESS); - /* Server ccs + finished rtx */ - ExpectIntEQ(wolfSSL_read(ssl_s, data, sizeof(data)), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); - /* Client processes finished */ - ExpectIntEQ(wolfSSL_negotiate(ssl_c), 1); - - wolfSSL_free(ssl_c); - wolfSSL_free(ssl_s); - wolfSSL_CTX_free(ctx_c); - wolfSSL_CTX_free(ctx_s); -#endif - return EXPECT_RESULT(); -} - -#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS) \ - && !defined(WOLFSSL_NO_TLS12) -static int test_dtls_seq_num_downgrade_check_num(byte* ioBuf, int ioBufLen, - byte seq_num) -{ - EXPECT_DECLS; - DtlsRecordLayerHeader* dtlsRH; - byte sequence_number[8]; - - XMEMSET(&sequence_number, 0, sizeof(sequence_number)); - - ExpectIntGE(ioBufLen, sizeof(*dtlsRH)); - dtlsRH = (DtlsRecordLayerHeader*)ioBuf; - ExpectIntEQ(dtlsRH->type, handshake); - ExpectIntEQ(dtlsRH->pvMajor, DTLS_MAJOR); - ExpectIntEQ(dtlsRH->pvMinor, DTLSv1_2_MINOR); - sequence_number[7] = seq_num; - ExpectIntEQ(XMEMCMP(sequence_number, dtlsRH->sequence_number, - sizeof(sequence_number)), 0); - - return EXPECT_RESULT(); -} -#endif - -/* - * Make sure that we send the correct sequence number after a HelloVerifyRequest - * and after a HelloRetryRequest. This is testing the server side as it is - * operating statelessly and should copy the sequence number of the ClientHello. - */ -static int test_dtls_seq_num_downgrade(void) -{ - EXPECT_DECLS; -#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS) \ - && !defined(WOLFSSL_NO_TLS12) - WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; - WOLFSSL *ssl_c = NULL, *ssl_s = NULL; - struct test_memio_ctx test_ctx; - - XMEMSET(&test_ctx, 0, sizeof(test_ctx)); - - ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, - wolfDTLSv1_2_client_method, wolfDTLS_server_method), 0); - - /* CH1 */ - ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); - ExpectIntEQ(test_dtls_seq_num_downgrade_check_num(test_ctx.s_buff, - test_ctx.s_len, 0), TEST_SUCCESS); - /* HVR */ - ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); - ExpectIntEQ(test_dtls_seq_num_downgrade_check_num(test_ctx.c_buff, - test_ctx.c_len, 0), TEST_SUCCESS); - /* CH2 */ - ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); - ExpectIntEQ(test_dtls_seq_num_downgrade_check_num(test_ctx.s_buff, - test_ctx.s_len, 1), TEST_SUCCESS); - /* Server first flight */ - ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); - ExpectIntEQ(test_dtls_seq_num_downgrade_check_num(test_ctx.c_buff, - test_ctx.c_len, 1), TEST_SUCCESS); - - ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); - - wolfSSL_free(ssl_c); - wolfSSL_CTX_free(ctx_c); - wolfSSL_free(ssl_s); - wolfSSL_CTX_free(ctx_s); -#endif - return EXPECT_RESULT(); -} /** * Make sure we don't send RSA Signature Hash Algorithms in the @@ -35873,626 +31175,13 @@ static int test_revoked_loaded_int_cert(void) return EXPECT_RESULT(); } -static int test_dtls13_frag_ch_pq(void) -{ - EXPECT_DECLS; -#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13) \ - && defined(WOLFSSL_DTLS_CH_FRAG) && defined(WOLFSSL_HAVE_MLKEM) - WOLFSSL_CTX *ctx_c = NULL; - WOLFSSL_CTX *ctx_s = NULL; - WOLFSSL *ssl_c = NULL; - WOLFSSL *ssl_s = NULL; - struct test_memio_ctx test_ctx; - const char *test_str = "test"; - int test_str_size; - byte buf[255]; -#if defined(WOLFSSL_MLKEM_KYBER) - #if !defined(WOLFSSL_NO_KYBER1024) - int group = WOLFSSL_KYBER_LEVEL5; - const char *group_name = "KYBER_LEVEL5"; - #elif !defined(WOLFSSL_NO_KYBER768) - int group = WOLFSSL_KYBER_LEVEL3; - const char *group_name = "KYBER_LEVEL3"; - #else - int group = WOLFSSL_KYBER_LEVEL1; - const char *group_name = "KYBER_LEVEL1"; - #endif -#elif !defined(WOLFSSL_NO_ML_KEM) && !defined(WOLFSSL_TLS_NO_MLKEM_STANDALONE) - #if !defined(WOLFSSL_NO_ML_KEM_1024) - int group = WOLFSSL_ML_KEM_1024; - const char *group_name = "ML_KEM_1024"; - #elif !defined(WOLFSSL_NO_ML_KEM_768) - int group = WOLFSSL_ML_KEM_768; - const char *group_name = "ML_KEM_768"; - #else - int group = WOLFSSL_ML_KEM_512; - const char *group_name = "ML_KEM_512"; - #endif -#elif defined(WOLFSSL_PQC_HYBRIDS) - #if defined(HAVE_CURVE25519) && !defined(WOLFSSL_NO_ML_KEM_768) - int group = WOLFSSL_X25519MLKEM768; - const char *group_name = "X25519MLKEM768"; - #elif !defined(WOLFSSL_NO_ML_KEM_768) - int group = WOLFSSL_SECP256R1MLKEM768; - const char *group_name = "SecP256r1MLKEM768"; - #else - int group = WOLFSSL_SECP384R1MLKEM1024; - const char *group_name = "SecP384r1MLKEM1024"; - #endif -#endif - - XMEMSET(&test_ctx, 0, sizeof(test_ctx)); - ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, - wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), 0); - /* Add in a large post-quantum key share to make the CH long. */ - ExpectIntEQ(wolfSSL_set_groups(ssl_c, &group, 1), WOLFSSL_SUCCESS); - ExpectIntEQ(wolfSSL_UseKeyShare(ssl_c, group), WOLFSSL_SUCCESS); - ExpectIntEQ(wolfSSL_dtls13_allow_ch_frag(ssl_s, 1), WOLFSSL_SUCCESS); - ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); - ExpectStrEQ(wolfSSL_get_curve_name(ssl_c), group_name); - ExpectStrEQ(wolfSSL_get_curve_name(ssl_s), group_name); - test_str_size = XSTRLEN("test") + 1; - ExpectIntEQ(wolfSSL_write(ssl_c, test_str, test_str_size), test_str_size); - ExpectIntEQ(wolfSSL_read(ssl_s, buf, sizeof(buf)), test_str_size); - ExpectIntEQ(XSTRCMP((char*)buf, test_str), 0); - ExpectIntEQ(wolfSSL_write(ssl_c, test_str, test_str_size), test_str_size); - wolfSSL_free(ssl_c); - wolfSSL_free(ssl_s); - wolfSSL_CTX_free(ctx_c); - wolfSSL_CTX_free(ctx_s); -#endif - return EXPECT_RESULT(); -} - -#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS) \ - && defined(WOLFSSL_DTLS_MTU) && defined(WOLFSSL_DTLS_CH_FRAG) && \ - defined(WOLFSSL_AES_256) -static int test_dtls_frag_ch_count_records(byte* b, int len) -{ - DtlsRecordLayerHeader* dtlsRH; - int records = 0; - size_t recordLen; - while (len > 0) { - records++; - dtlsRH = (DtlsRecordLayerHeader*)b; - recordLen = (dtlsRH->length[0] << 8) | dtlsRH->length[1]; - if (recordLen > (size_t)len) - break; - b += sizeof(DtlsRecordLayerHeader) + recordLen; - len -= sizeof(DtlsRecordLayerHeader) + recordLen; - } - return records; -} -#endif -static int test_dtls_frag_ch(void) -{ - EXPECT_DECLS; -#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13) \ - && defined(WOLFSSL_DTLS_MTU) && defined(WOLFSSL_DTLS_CH_FRAG) && \ - defined(WOLFSSL_AES_256) - WOLFSSL_CTX *ctx_c = NULL; - WOLFSSL_CTX *ctx_s = NULL; - WOLFSSL *ssl_c = NULL; - WOLFSSL *ssl_s = NULL; - struct test_memio_ctx test_ctx; - static unsigned int DUMMY_MTU = 256; - unsigned int len; - unsigned char four_frag_CH[] = { - 0x16, 0xfe, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xda, 0x01, 0x00, 0x02, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xce, 0xfe, 0xfd, 0xf3, 0x94, 0x01, 0x33, 0x2c, 0xcf, 0x2c, 0x47, 0xb1, - 0xe5, 0xa1, 0x7b, 0x19, 0x3e, 0xac, 0x68, 0xdd, 0xe6, 0x17, 0x6b, 0x85, - 0xad, 0x5f, 0xfc, 0x7f, 0x6e, 0xf0, 0xb9, 0xe0, 0x2e, 0xca, 0x47, 0x00, - 0x00, 0x00, 0x36, 0x13, 0x01, 0x13, 0x02, 0x13, 0x03, 0xc0, 0x2c, 0xc0, - 0x2b, 0xc0, 0x30, 0xc0, 0x2f, 0x00, 0x9f, 0x00, 0x9e, 0xcc, 0xa9, 0xcc, - 0xa8, 0xcc, 0xaa, 0xc0, 0x27, 0xc0, 0x23, 0xc0, 0x28, 0xc0, 0x24, 0xc0, - 0x0a, 0xc0, 0x09, 0xc0, 0x14, 0xc0, 0x13, 0x00, 0x6b, 0x00, 0x67, 0x00, - 0x39, 0x00, 0x33, 0xcc, 0x14, 0xcc, 0x13, 0xcc, 0x15, 0x01, 0x00, 0x02, - 0x7c, 0x00, 0x2b, 0x00, 0x03, 0x02, 0xfe, 0xfc, 0x00, 0x0d, 0x00, 0x20, - 0x00, 0x1e, 0x06, 0x03, 0x05, 0x03, 0x04, 0x03, 0x02, 0x03, 0x08, 0x06, - 0x08, 0x0b, 0x08, 0x05, 0x08, 0x0a, 0x08, 0x04, 0x08, 0x09, 0x06, 0x01, - 0x05, 0x01, 0x04, 0x01, 0x03, 0x01, 0x02, 0x01, 0x00, 0x0a, 0x00, 0x0c, - 0x00, 0x0a, 0x00, 0x19, 0x00, 0x18, 0x00, 0x17, 0x00, 0x15, 0x01, 0x00, - 0x00, 0x16, 0x00, 0x00, 0x00, 0x33, 0x02, 0x39, 0x02, 0x37, 0x00, 0x17, - 0x00, 0x41, 0x04, 0x94, 0xdf, 0x36, 0xd7, 0xb3, 0x90, 0x6d, 0x01, 0xa1, - 0xe6, 0xed, 0x67, 0xf4, 0xd9, 0x9d, 0x2c, 0xac, 0x57, 0x74, 0xff, 0x19, - 0xbe, 0x5a, 0xc9, 0x30, 0x11, 0xb7, 0x2b, 0x59, 0x47, 0x80, 0x7c, 0xa9, - 0xb7, 0x31, 0x8c, 0x16, 0xfe, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x01, 0x00, 0xda, 0x01, 0x00, 0x02, 0xdc, 0x00, 0x00, 0x00, 0x00, - 0xce, 0x00, 0x00, 0xce, 0x9e, 0x13, 0x74, 0x3b, 0x86, 0xba, 0x69, 0x1f, - 0x12, 0xf7, 0xcd, 0x78, 0x53, 0xe8, 0x50, 0x4d, 0x71, 0x3f, 0x4b, 0x4e, - 0xeb, 0x3e, 0xe5, 0x43, 0x54, 0x78, 0x17, 0x6d, 0x00, 0x18, 0x00, 0x61, - 0x04, 0xd1, 0x99, 0x66, 0x4f, 0xda, 0xc7, 0x12, 0x3b, 0xff, 0xb2, 0xd6, - 0x2f, 0x35, 0xb6, 0x17, 0x1f, 0xb3, 0xd0, 0xb6, 0x52, 0xff, 0x97, 0x8b, - 0x01, 0xe8, 0xd9, 0x68, 0x71, 0x40, 0x02, 0xd5, 0x68, 0x3a, 0x58, 0xb2, - 0x5d, 0xee, 0xa4, 0xe9, 0x5f, 0xf4, 0xaf, 0x3e, 0x30, 0x9c, 0x3e, 0x2b, - 0xda, 0x61, 0x43, 0x99, 0x02, 0x35, 0x33, 0x9f, 0xcf, 0xb5, 0xd3, 0x28, - 0x19, 0x9d, 0x1c, 0xbe, 0x69, 0x07, 0x9e, 0xfc, 0xe4, 0x8e, 0xcd, 0x86, - 0x4a, 0x1b, 0xf0, 0xfc, 0x17, 0x94, 0x66, 0x53, 0xda, 0x24, 0x5e, 0xaf, - 0xce, 0xec, 0x62, 0x4c, 0x06, 0xb4, 0x52, 0x94, 0xb1, 0x4a, 0x7a, 0x8c, - 0x4f, 0x00, 0x19, 0x00, 0x85, 0x04, 0x00, 0x27, 0xeb, 0x99, 0x49, 0x7f, - 0xcb, 0x2c, 0x46, 0x54, 0x2d, 0x93, 0x5d, 0x25, 0x92, 0x58, 0x5e, 0x06, - 0xc3, 0x7c, 0xfb, 0x9a, 0xa7, 0xec, 0xcd, 0x9f, 0xe1, 0x6b, 0x2d, 0x78, - 0xf5, 0x16, 0xa9, 0x20, 0x52, 0x48, 0x19, 0x0f, 0x1a, 0xd0, 0xce, 0xd8, - 0x68, 0xb1, 0x4e, 0x7f, 0x33, 0x03, 0x7d, 0x0c, 0x39, 0xdb, 0x9c, 0x4b, - 0xf4, 0xe7, 0xc2, 0xf5, 0xdd, 0x51, 0x9b, 0x03, 0xa8, 0x53, 0x2b, 0xe6, - 0x00, 0x15, 0x4b, 0xff, 0xd2, 0xa0, 0x16, 0xfe, 0xfd, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0xda, 0x01, 0x00, 0x02, 0xdc, 0x00, - 0x00, 0x00, 0x01, 0x9c, 0x00, 0x00, 0xce, 0x58, 0x30, 0x10, 0x3d, 0x46, - 0xcc, 0xca, 0x1a, 0x44, 0xc8, 0x58, 0x9b, 0x27, 0x17, 0x67, 0x31, 0x96, - 0x8a, 0x66, 0x39, 0xf4, 0xcc, 0xc1, 0x9f, 0x12, 0x1f, 0x01, 0x30, 0x50, - 0x16, 0xd6, 0x89, 0x97, 0xa3, 0x66, 0xd7, 0x99, 0x50, 0x09, 0x6e, 0x80, - 0x87, 0xe4, 0xa2, 0x88, 0xae, 0xb4, 0x23, 0x57, 0x2f, 0x12, 0x60, 0xe7, - 0x7d, 0x44, 0x2d, 0xad, 0xbe, 0xe9, 0x0d, 0x01, 0x00, 0x01, 0x00, 0xd5, - 0xdd, 0x62, 0xee, 0xf3, 0x0e, 0xd9, 0x30, 0x0e, 0x38, 0xf3, 0x48, 0xf4, - 0xc9, 0x8f, 0x8c, 0x20, 0xf7, 0xd3, 0xa8, 0xb3, 0x87, 0x3c, 0x98, 0x5d, - 0x70, 0xc5, 0x03, 0x76, 0xb7, 0xd5, 0x0b, 0x7b, 0x23, 0x97, 0x6b, 0xe3, - 0xb5, 0x18, 0xeb, 0x64, 0x55, 0x18, 0xb2, 0x8a, 0x90, 0x1a, 0x8f, 0x0e, - 0x15, 0xda, 0xb1, 0x8e, 0x7f, 0xee, 0x1f, 0xe0, 0x3b, 0xb9, 0xed, 0xfc, - 0x4e, 0x3f, 0x78, 0x16, 0x39, 0x95, 0x5f, 0xb7, 0xcb, 0x65, 0x55, 0x72, - 0x7b, 0x7d, 0x86, 0x2f, 0x8a, 0xe5, 0xee, 0xf7, 0x57, 0x40, 0xf3, 0xc4, - 0x96, 0x4f, 0x11, 0x4d, 0x85, 0xf9, 0x56, 0xfa, 0x3d, 0xf0, 0xc9, 0xa4, - 0xec, 0x1e, 0xaa, 0x47, 0x90, 0x53, 0xdf, 0xe1, 0xb7, 0x78, 0x18, 0xeb, - 0xdd, 0x0d, 0x89, 0xb7, 0xf6, 0x15, 0x0e, 0x55, 0x12, 0xb3, 0x23, 0x17, - 0x0b, 0x59, 0x6f, 0x83, 0x05, 0x6b, 0xa6, 0xf8, 0x6c, 0x3a, 0x9b, 0x1b, - 0x50, 0x93, 0x51, 0xea, 0x95, 0x2d, 0x99, 0x96, 0x38, 0x16, 0xfe, 0xfd, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x7e, 0x01, 0x00, - 0x02, 0xdc, 0x00, 0x00, 0x00, 0x02, 0x6a, 0x00, 0x00, 0x72, 0x2d, 0x66, - 0x3e, 0xf2, 0x36, 0x5a, 0xf2, 0x23, 0x8f, 0x28, 0x09, 0xa9, 0x55, 0x8c, - 0x8f, 0xc0, 0x0d, 0x61, 0x98, 0x33, 0x56, 0x87, 0x7a, 0xfd, 0xa7, 0x50, - 0x71, 0x84, 0x2e, 0x41, 0x58, 0x00, 0x87, 0xd9, 0x27, 0xe5, 0x7b, 0xf4, - 0x6d, 0x84, 0x4e, 0x2e, 0x0c, 0x80, 0x0c, 0xf3, 0x8a, 0x02, 0x4b, 0x99, - 0x3a, 0x1f, 0x9f, 0x18, 0x7d, 0x1c, 0xec, 0xad, 0x60, 0x54, 0xa6, 0xa3, - 0x2c, 0x82, 0x5e, 0xf8, 0x8f, 0xae, 0xe1, 0xc4, 0x82, 0x7e, 0x43, 0x43, - 0xc5, 0x99, 0x49, 0x05, 0xd3, 0xf6, 0xdf, 0xa1, 0xb5, 0x2d, 0x0c, 0x13, - 0x2f, 0x1e, 0xb6, 0x28, 0x7c, 0x5c, 0xa1, 0x02, 0x6b, 0x8d, 0xa3, 0xeb, - 0xd4, 0x58, 0xe6, 0xa0, 0x7e, 0x6b, 0xaa, 0x09, 0x43, 0x67, 0x71, 0x87, - 0xa5, 0xcb, 0x68, 0xf3 - }; - XMEMSET(&test_ctx, 0, sizeof(test_ctx)); - ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, - wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), 0); - /* Fragment msgs */ - ExpectIntEQ(wolfSSL_dtls_set_mtu(ssl_c, DUMMY_MTU), WOLFSSL_SUCCESS); - ExpectIntEQ(wolfSSL_dtls_set_mtu(ssl_s, DUMMY_MTU), WOLFSSL_SUCCESS); - /* Add in some key shares to make the CH long */ - ExpectIntEQ(wolfSSL_UseKeyShare(ssl_c, WOLFSSL_ECC_SECP256R1), - WOLFSSL_SUCCESS); - ExpectIntEQ(wolfSSL_UseKeyShare(ssl_c, WOLFSSL_ECC_SECP384R1), - WOLFSSL_SUCCESS); - ExpectIntEQ(wolfSSL_UseKeyShare(ssl_c, WOLFSSL_ECC_SECP521R1), - WOLFSSL_SUCCESS); -#ifdef HAVE_FFDHE_2048 - ExpectIntEQ(wolfSSL_UseKeyShare(ssl_c, WOLFSSL_FFDHE_2048), - WOLFSSL_SUCCESS); -#endif -#ifdef HAVE_FFDHE_3072 - ExpectIntEQ(wolfSSL_UseKeyShare(ssl_c, WOLFSSL_FFDHE_3072), - WOLFSSL_SUCCESS); -#endif -#ifdef HAVE_FFDHE_4096 - ExpectIntEQ(wolfSSL_UseKeyShare(ssl_c, WOLFSSL_FFDHE_4096), - WOLFSSL_SUCCESS); -#endif - - ExpectIntEQ(wolfSSL_dtls13_allow_ch_frag(ssl_s, 1), WOLFSSL_SUCCESS); - - /* Reject fragmented first CH */ - ExpectIntEQ(test_dtls_frag_ch_count_records(four_frag_CH, - sizeof(four_frag_CH)), 4); - len = sizeof(four_frag_CH); - test_memio_clear_buffer(&test_ctx, 0); - while (len > 0 && EXPECT_SUCCESS()) { - unsigned int inj_len = len > DUMMY_MTU ? DUMMY_MTU : len; - unsigned char *idx = four_frag_CH + sizeof(four_frag_CH) - len; - ExpectIntEQ(test_memio_inject_message(&test_ctx, 0, (const char *)idx, - inj_len), 0); - len -= inj_len; - } - ExpectIntEQ(test_ctx.s_len, sizeof(four_frag_CH)); - while (test_ctx.s_len > 0 && EXPECT_SUCCESS()) { - int s_len = test_ctx.s_len; - ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); - /* Fail if we didn't advance the buffer to avoid infinite loops */ - ExpectIntLT(test_ctx.s_len, s_len); - } - /* Expect all fragments read */ - ExpectIntEQ(test_ctx.s_len, 0); - /* Expect quietly dropping fragmented first CH */ - ExpectIntEQ(test_ctx.c_len, 0); - -#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH) - /* Disable ECH as it pushes it over our MTU */ - wolfSSL_SetEchEnable(ssl_c, 0); -#endif - - /* Limit options to make the CH a fixed length */ - /* See wolfSSL_parse_cipher_list for reason why we provide 1.3 AND 1.2 - * ciphersuite. This is only necessary when building with OPENSSL_EXTRA. */ -#ifdef OPENSSL_EXTRA - ExpectTrue(wolfSSL_set_cipher_list(ssl_c, "TLS13-AES256-GCM-SHA384" - ":DHE-RSA-AES256-GCM-SHA384")); -#else - ExpectTrue(wolfSSL_set_cipher_list(ssl_c, "TLS13-AES256-GCM-SHA384")); -#endif - /* CH1 */ - ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); - /* Count records. Expect 1 unfragmented CH */ - ExpectIntEQ(test_dtls_frag_ch_count_records(test_ctx.s_buff, - test_ctx.s_len), 1); - /* HRR */ - ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); - /* CH2 */ - ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); - /* Count records. Expect fragmented CH */ - ExpectIntGT(test_dtls_frag_ch_count_records(test_ctx.s_buff, - test_ctx.s_len), 1); - ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); - wolfSSL_free(ssl_c); - wolfSSL_free(ssl_s); - wolfSSL_CTX_free(ctx_c); - wolfSSL_CTX_free(ctx_s); - ssl_c = ssl_s = NULL; - ctx_c = ctx_s = NULL; -#endif - return EXPECT_RESULT(); -} - -static int test_dtls_empty_keyshare_with_cookie(void) -{ - EXPECT_DECLS; -#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13) - WOLFSSL_CTX *ctx_s = NULL; - WOLFSSL *ssl_s = NULL; - struct test_memio_ctx test_ctx; - unsigned char ch_empty_keyshare_with_cookie[] = { - 0x16, 0xfe, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, - 0x12, 0x01, 0x00, 0x01, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, - 0x06, 0xfe, 0xfd, 0xfb, 0x8c, 0x9b, 0x28, 0xae, 0x50, 0x1c, 0x4d, 0xf3, - 0xb8, 0xcf, 0x4d, 0xd8, 0x7e, 0x93, 0x13, 0x7b, 0x9e, 0xd9, 0xeb, 0xe9, - 0x13, 0x4b, 0x0d, 0x7f, 0x2e, 0x43, 0x62, 0x8c, 0xe4, 0x57, 0x79, 0x00, - 0x00, 0x00, 0x36, 0x13, 0x01, 0x13, 0x02, 0x13, 0x03, 0xc0, 0x2c, 0xc0, - 0x2b, 0xc0, 0x30, 0xc0, 0x2f, 0x00, 0x9f, 0x00, 0x9e, 0xcc, 0xa9, 0xcc, - 0xa8, 0xcc, 0xaa, 0xc0, 0x27, 0xc0, 0x23, 0xc0, 0x28, 0xc0, 0x24, 0xc0, - 0x0a, 0xc0, 0x09, 0xc0, 0x14, 0xc0, 0x13, 0x00, 0x6b, 0x00, 0x67, 0x00, - 0x39, 0x00, 0x33, 0xcc, 0x14, 0xcc, 0x13, 0xcc, 0x15, 0x01, 0x00, 0x00, - 0xa6, 0x00, 0x2b, 0x00, 0x03, 0x02, 0xfe, 0xfc, 0x00, 0x2c, 0x00, 0x47, - 0x00, 0x45, 0x20, 0xee, 0x4b, 0x17, 0x70, 0x63, 0xa0, 0x4c, 0x82, 0xbf, - 0x43, 0x01, 0x7d, 0x8d, 0xc1, 0x1b, 0x4e, 0x9b, 0xa0, 0x3c, 0x53, 0x1f, - 0xb7, 0xd1, 0x10, 0x81, 0xa8, 0xdf, 0xdf, 0x8c, 0x7f, 0xf3, 0x11, 0x13, - 0x01, 0x02, 0x3d, 0x3b, 0x7d, 0x14, 0x2c, 0x31, 0xb3, 0x60, 0x72, 0x4d, - 0xe5, 0x1a, 0xb2, 0xa3, 0x61, 0x77, 0x73, 0x03, 0x40, 0x0e, 0x5f, 0xc5, - 0x61, 0x38, 0x43, 0x56, 0x21, 0x4a, 0x95, 0xd5, 0x35, 0xa8, 0x0d, 0x00, - 0x0d, 0x00, 0x2a, 0x00, 0x28, 0x06, 0x03, 0x05, 0x03, 0x04, 0x03, 0x02, - 0x03, 0xfe, 0x0b, 0xfe, 0x0e, 0xfe, 0xa0, 0xfe, 0xa3, 0xfe, 0xa5, 0x08, - 0x06, 0x08, 0x0b, 0x08, 0x05, 0x08, 0x0a, 0x08, 0x04, 0x08, 0x09, 0x06, - 0x01, 0x05, 0x01, 0x04, 0x01, 0x03, 0x01, 0x02, 0x01, 0x00, 0x0a, 0x00, - 0x18, 0x00, 0x16, 0x00, 0x19, 0x00, 0x18, 0x00, 0x17, 0x00, 0x15, 0x01, - 0x00, 0x02, 0x3a, 0x02, 0x3c, 0x02, 0x3d, 0x2f, 0x3a, 0x2f, 0x3c, 0x2f, - 0x3d, 0x00, 0x16, 0x00, 0x00, 0x00, 0x33, 0x00, 0x02, 0x00, 0x00 - }; - DtlsRecordLayerHeader* dtlsRH; - byte sequence_number[8]; - - XMEMSET(&sequence_number, 0, sizeof(sequence_number)); - XMEMSET(&test_ctx, 0, sizeof(test_ctx)); - ExpectIntEQ(test_memio_setup(&test_ctx, NULL, &ctx_s, NULL, &ssl_s, - NULL, wolfDTLSv1_3_server_method), 0); - ExpectIntEQ(test_memio_inject_message(&test_ctx, 0, - (const char *)ch_empty_keyshare_with_cookie, - sizeof(ch_empty_keyshare_with_cookie)), 0); - - /* CH1 */ - ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); - /* Expect an alert. A plaintext alert should be exactly 15 bytes. */ - ExpectIntEQ(test_ctx.c_len, 15); - dtlsRH = (DtlsRecordLayerHeader*)test_ctx.c_buff; - ExpectIntEQ(dtlsRH->type, alert); - ExpectIntEQ(dtlsRH->pvMajor, DTLS_MAJOR); - ExpectIntEQ(dtlsRH->pvMinor, DTLSv1_2_MINOR); - sequence_number[7] = 1; - ExpectIntEQ(XMEMCMP(sequence_number, dtlsRH->sequence_number, - sizeof(sequence_number)), 0); - ExpectIntEQ(dtlsRH->length[0], 0); - ExpectIntEQ(dtlsRH->length[1], 2); - ExpectIntEQ(test_ctx.c_buff[13], alert_fatal); - ExpectIntEQ(test_ctx.c_buff[14], illegal_parameter); - - wolfSSL_free(ssl_s); - wolfSSL_CTX_free(ctx_s); -#endif - return EXPECT_RESULT(); -} - -static int test_dtls_old_seq_number(void) -{ - EXPECT_DECLS; -#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS) && \ - !defined(WOLFSSL_NO_TLS12) - WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; - WOLFSSL *ssl_c = NULL, *ssl_s = NULL; - struct test_memio_ctx test_ctx; - - XMEMSET(&test_ctx, 0, sizeof(test_ctx)); - - ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, - wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method), 0); - - /* CH1 */ - ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); - /* HVR */ - ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); - /* CH2 */ - ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); - /* Server first flight */ - ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); - /* Client second flight */ - ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); - /* Modify the sequence number */ - { - DtlsRecordLayerHeader* dtlsRH = (DtlsRecordLayerHeader*)test_ctx.s_buff; - XMEMSET(dtlsRH->sequence_number, 0, sizeof(dtlsRH->sequence_number)); - } - /* Server second flight */ - ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); - /* Server should not do anything as a pkt was dropped */ - ExpectIntEQ(test_ctx.c_len, 0); - ExpectIntEQ(test_ctx.s_len, 0); - /* Trigger rtx */ - ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl_c), WOLFSSL_SUCCESS); - - /* Complete connection */ - ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); - - wolfSSL_free(ssl_c); - wolfSSL_CTX_free(ctx_c); - wolfSSL_free(ssl_s); - wolfSSL_CTX_free(ctx_s); -#endif - return EXPECT_RESULT(); -} - -static int test_dtls12_missing_finished(void) -{ - EXPECT_DECLS; -#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS) && \ - !defined(WOLFSSL_NO_TLS12) - WOLFSSL_CTX *ctx_c = NULL; - WOLFSSL_CTX *ctx_s = NULL; - WOLFSSL *ssl_c = NULL; - WOLFSSL *ssl_s = NULL; - struct test_memio_ctx test_ctx; - const char test_str[] = "test string"; - char test_buf[sizeof(test_str)]; - - XMEMSET(&test_ctx, 0, sizeof(test_ctx)); - - ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, - wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method), 0); - - /* CH1 */ - ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); - /* HVR */ - ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); - /* CH2 */ - ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); - /* Server first flight */ - ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); - /* Client second flight with finished */ - ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); - /* Server second flight with finished */ - ExpectIntEQ(wolfSSL_negotiate(ssl_s), 1); - /* Let's clear the output */ - test_memio_clear_buffer(&test_ctx, 1); - /* Let's send some app data */ - ExpectIntEQ(wolfSSL_write(ssl_s, test_str, sizeof(test_str)), - sizeof(test_str)); - /* Client should not error out on a missing finished */ - ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); - /* Server rtx second flight with finished */ - ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl_s), 1); - /* Client process rest of handshake */ - ExpectIntEQ(wolfSSL_negotiate(ssl_c), 1); - - /* Let's send some app data */ - ExpectIntEQ(wolfSSL_write(ssl_s, test_str, sizeof(test_str)), - sizeof(test_str)); - ExpectIntEQ(wolfSSL_read(ssl_c, test_buf, sizeof(test_buf)), - sizeof(test_str)); - ExpectBufEQ(test_buf, test_str, sizeof(test_str)); - - wolfSSL_free(ssl_c); - wolfSSL_free(ssl_s); - wolfSSL_CTX_free(ctx_c); - wolfSSL_CTX_free(ctx_s); -#endif - return EXPECT_RESULT(); -} - -static int test_dtls13_missing_finished_client(void) -{ - EXPECT_DECLS; -#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13) - WOLFSSL_CTX *ctx_c = NULL; - WOLFSSL_CTX *ctx_s = NULL; - WOLFSSL *ssl_c = NULL; - WOLFSSL *ssl_s = NULL; - struct test_memio_ctx test_ctx; - const char test_str[] = "test string"; - char test_buf[sizeof(test_str)]; - - XMEMSET(&test_ctx, 0, sizeof(test_ctx)); - ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, - wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), 0); - - /* CH1 */ - ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); - /* HRR */ - ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); - /* CH2 */ - ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); - /* Server first flight with finished */ - ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); - /* Let's clear the output */ - test_memio_clear_buffer(&test_ctx, 1); - /* Let's send some app data */ - ExpectIntEQ(wolfSSL_write(ssl_s, test_str, sizeof(test_str)), - sizeof(test_str)); - /* Client second flight with finished */ - ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); - /* Server should not error out on a missing finished */ - ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); - /* Client rtx second flight with finished */ - ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); - /* Server */ - ExpectIntEQ(wolfSSL_negotiate(ssl_s), 1); - /* Client */ - ExpectIntEQ(wolfSSL_negotiate(ssl_c), 1); - /* Let's send some app data */ - ExpectIntEQ(wolfSSL_write(ssl_s, test_str, sizeof(test_str)), - sizeof(test_str)); - ExpectIntEQ(wolfSSL_read(ssl_c, test_buf, sizeof(test_buf)), - sizeof(test_str)); - ExpectBufEQ(test_buf, test_str, sizeof(test_str)); - - wolfSSL_free(ssl_c); - wolfSSL_free(ssl_s); - wolfSSL_CTX_free(ctx_c); - wolfSSL_CTX_free(ctx_s); -#endif - return EXPECT_RESULT(); -} - -static int test_dtls13_missing_finished_server(void) -{ - EXPECT_DECLS; -#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13) - WOLFSSL_CTX *ctx_c = NULL; - WOLFSSL_CTX *ctx_s = NULL; - WOLFSSL *ssl_c = NULL; - WOLFSSL *ssl_s = NULL; - struct test_memio_ctx test_ctx; - const char test_str[] = "test string"; - char test_buf[sizeof(test_str)]; - - XMEMSET(&test_ctx, 0, sizeof(test_ctx)); - ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, - wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), 0); - - /* CH1 */ - ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); - /* HRR */ - ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); - /* CH2 */ - ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); - /* Server first flight with finished */ - ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); - /* Client second flight with finished */ - ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); - /* Let's clear the output */ - test_memio_clear_buffer(&test_ctx, 0); - ExpectFalse(wolfSSL_is_init_finished(ssl_c)); - /* Let's send some app data */ - ExpectIntEQ(wolfSSL_write(ssl_c, test_str, sizeof(test_str)), - sizeof(test_str)); - /* Server should not error out on a missing finished */ - ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); - /* Client rtx second flight with finished */ - ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); - /* Server first flight with finished */ - ExpectIntEQ(wolfSSL_negotiate(ssl_s), 1); - /* Let's send some app data */ - ExpectIntEQ(wolfSSL_write(ssl_c, test_str, sizeof(test_str)), - sizeof(test_str)); - ExpectIntEQ(wolfSSL_read(ssl_s, test_buf, sizeof(test_buf)), - sizeof(test_str)); - ExpectBufEQ(test_buf, test_str, sizeof(test_str)); - - wolfSSL_free(ssl_c); - wolfSSL_free(ssl_s); - wolfSSL_CTX_free(ctx_c); - wolfSSL_CTX_free(ctx_s); -#endif - return EXPECT_RESULT(); -} - -static int test_dtls13_finished_send_error_propagation(void) -{ - EXPECT_DECLS; -#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13) - WOLFSSL_CTX *ctx_c = NULL; - WOLFSSL_CTX *ctx_s = NULL; - WOLFSSL *ssl_c = NULL; - WOLFSSL *ssl_s = NULL; - struct test_memio_ctx test_ctx; - - XMEMSET(&test_ctx, 0, sizeof(test_ctx)); - ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, - wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), 0); - - /* CH1 */ - ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); - /* HRR */ - ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); - /* CH2 */ - ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); - /* Server first flight with finished */ - ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); - /* Client second flight with finished - block sends to force error */ - test_ctx.s_len = TEST_MEMIO_BUF_SZ; - ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); - /* Verify the error is propagated, not silently swallowed as success */ - ExpectIntNE(wolfSSL_get_error(ssl_c, -1), 0); - - wolfSSL_free(ssl_c); - wolfSSL_free(ssl_s); - wolfSSL_CTX_free(ctx_c); - wolfSSL_CTX_free(ctx_s); -#endif - return EXPECT_RESULT(); -} #if !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) @@ -38027,909 +32716,6 @@ static int test_wolfSSL_inject(void) int testAll = 1; int stopOnFail = 0; -/*----------------------------------------------------------------------------*/ -/* LMS tests */ -/*----------------------------------------------------------------------------*/ -int test_wc_LmsKey_sign_verify(void); -int test_wc_LmsKey_reload_cache(void); -int test_rfc9802_lms_x509_verify(void); -int test_rfc9802_xmss_x509_verify(void); - -#if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY) - -#include - -#define LMS_TEST_PRIV_KEY_FILE "/tmp/wolfssl_test_lms.key" - -static int test_lms_write_key(const byte* priv, word32 privSz, void* context) -{ - FILE* f = fopen((const char*)context, "wb"); - int ret = WC_LMS_RC_SAVED_TO_NV_MEMORY; - if (f == NULL) - return -1; - if (fwrite(priv, 1, privSz, f) != privSz) - ret = -1; - fclose(f); - return ret; -} - -static int test_lms_read_key(byte* priv, word32 privSz, void* context) -{ - FILE* f = fopen((const char*)context, "rb"); - if (f == NULL) - return -1; - if (fread(priv, 1, privSz, f) == 0) { - fclose(f); - return -1; - } - fclose(f); - return WC_LMS_RC_READ_TO_MEMORY; -} - -/* Helper: init an LMS key with callbacks and L1-H10-W8 params */ -static int test_lms_init_key(LmsKey* key, WC_RNG* rng) -{ - int ret; - - ret = wc_LmsKey_Init(key, NULL, INVALID_DEVID); - if (ret != 0) return ret; - -#if !defined(WOLFSSL_LMS_MAX_HEIGHT) || (WOLFSSL_LMS_MAX_HEIGHT >= 10) - ret = wc_LmsKey_SetParameters(key, 1, 10, 8); -#else - ret = wc_LmsKey_SetParameters(key, 1, 5, 8); -#endif - if (ret != 0) return ret; - - ret = wc_LmsKey_SetWriteCb(key, test_lms_write_key); - if (ret != 0) return ret; - - ret = wc_LmsKey_SetReadCb(key, test_lms_read_key); - if (ret != 0) return ret; - - ret = wc_LmsKey_SetContext(key, (void*)LMS_TEST_PRIV_KEY_FILE); - if (ret != 0) return ret; - - (void)rng; - return 0; -} - -#endif /* WOLFSSL_HAVE_LMS && !WOLFSSL_LMS_VERIFY_ONLY */ - -/* - * Test basic LMS sign/verify with multiple signings. - * Uses L1-H10-W8 (1024 total signatures, 32-entry leaf cache). - */ -int test_wc_LmsKey_sign_verify(void) -{ - EXPECT_DECLS; -#if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY) - LmsKey key; - WC_RNG rng; - byte msg[] = "test message for LMS signing"; - byte sig[2048]; - word32 sigSz; - int i; - int numSigs = 5; - - ExpectIntEQ(wc_InitRng(&rng), 0); - - remove(LMS_TEST_PRIV_KEY_FILE); - ExpectIntEQ(test_lms_init_key(&key, &rng), 0); - ExpectIntEQ(wc_LmsKey_MakeKey(&key, &rng), 0); - - for (i = 0; i < numSigs; i++) { - sigSz = sizeof(sig); - ExpectIntEQ(wc_LmsKey_Sign(&key, sig, &sigSz, msg, sizeof(msg)), 0); - ExpectIntEQ(wc_LmsKey_Verify(&key, sig, sigSz, msg, sizeof(msg)), 0); - } - - wc_LmsKey_Free(&key); - wc_FreeRng(&rng); - remove(LMS_TEST_PRIV_KEY_FILE); -#endif - return EXPECT_RESULT(); -} - -/* - * Test LMS key reload after advancing past the leaf cache window. - * - * Reproduces a heap-buffer-overflow bug in wc_lms_treehash_init() where the - * leaf cache write uses (i * hash_len) instead of ((i - leaf->idx) * hash_len). - * When q > max_cb (default 32), wc_LmsKey_Reload calls wc_hss_init_auth_path - * which calls wc_lms_treehash_init with q > 0, causing writes past the end of - * the leaf cache buffer. - * - * Reproduction steps: - * 1. Generate L1-H10-W8 key (cacheBits=5, max_cb=32) - * 2. Sign 33 times to advance q past the cache window - * 3. Free the key and reload from persisted state - * 4. Sign and verify after reload - * - * Without the fix: heap-buffer-overflow at wc_lms_impl.c:1965 - * With the fix: all operations succeed, signatures verify - */ -int test_wc_LmsKey_reload_cache(void) -{ - EXPECT_DECLS; -#if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY) && \ - (!defined(WOLFSSL_LMS_MAX_HEIGHT) || (WOLFSSL_LMS_MAX_HEIGHT >= 10)) - LmsKey key; - LmsKey vkey; - WC_RNG rng; - byte msg[] = "test message for LMS signing"; - byte sig[2048]; - word32 sigSz; - byte pub[64]; - word32 pubSz = sizeof(pub); - int i; - /* Sign 33 times to advance q past the 32-entry cache window. */ - int preSigs = 33; - - ExpectIntEQ(wc_InitRng(&rng), 0); - - /* Phase 1: Generate key and sign past cache window */ - remove(LMS_TEST_PRIV_KEY_FILE); - ExpectIntEQ(test_lms_init_key(&key, &rng), 0); - ExpectIntEQ(wc_LmsKey_MakeKey(&key, &rng), 0); - - for (i = 0; i < preSigs; i++) { - sigSz = sizeof(sig); - ExpectIntEQ(wc_LmsKey_Sign(&key, sig, &sigSz, msg, sizeof(msg)), 0); - } - - /* Save public key for verification after reload */ - ExpectIntEQ(wc_LmsKey_ExportPubRaw(&key, pub, &pubSz), 0); - - wc_LmsKey_Free(&key); - - /* Phase 2: Reload key. Triggers wc_lms_treehash_init with q=33 */ - ExpectIntEQ(test_lms_init_key(&key, &rng), 0); - ExpectIntEQ(wc_LmsKey_Reload(&key), 0); - - /* Phase 3: Sign after reload and verify with separate verify-only key */ - sigSz = sizeof(sig); - ExpectIntEQ(wc_LmsKey_Sign(&key, sig, &sigSz, msg, sizeof(msg)), 0); - - ExpectIntEQ(wc_LmsKey_Init(&vkey, NULL, INVALID_DEVID), 0); -#if !defined(WOLFSSL_LMS_MAX_HEIGHT) || (WOLFSSL_LMS_MAX_HEIGHT >= 10) - ExpectIntEQ(wc_LmsKey_SetParameters(&vkey, 1, 10, 8), 0); -#else - ExpectIntEQ(wc_LmsKey_SetParameters(&vkey, 1, 5, 8), 0); -#endif - ExpectIntEQ(wc_LmsKey_ImportPubRaw(&vkey, pub, pubSz), 0); - ExpectIntEQ(wc_LmsKey_Verify(&vkey, sig, sigSz, msg, sizeof(msg)), 0); - - wc_LmsKey_Free(&vkey); - wc_LmsKey_Free(&key); - wc_FreeRng(&rng); - remove(LMS_TEST_PRIV_KEY_FILE); -#endif - return EXPECT_RESULT(); -} - -/*----------------------------------------------------------------------------*/ -/* RFC 9802 (HSS/LMS and XMSS/XMSS^MT in X.509) tests */ -/*----------------------------------------------------------------------------*/ - -/* For every committed self-signed test certificate confirm: - * - wc_ParseCert succeeds on the RFC 9802 AlgorithmIdentifier encoding - * (OID-only SEQUENCE, no NULL parameters) - * - keyOID and signatureOID are set to the expected values - * - loading as a trust anchor and verifying the same bytes through - * wolfSSL_CertManagerVerifyBuffer exercises the ConfirmSignature - * path and succeeds on a valid cert - * - flipping a byte in the signature AND flipping a byte in the - * TBSCertificate both cause verification to fail. - * - * Test vectors are in certs/lms/ and certs/xmss/, generated with Bouncy - * Castle 1.81. BC's default XMSS / XMSS^MT X.509 encoding uses pre- - * standard ISARA OIDs and wraps the raw RFC 8391 pub key in an OCTET - * STRING, so the fixtures were produced with a small generator that - * overrides the AlgorithmIdentifier and SPKI to match RFC 9802. */ -#if (defined(WOLFSSL_HAVE_LMS) || defined(WOLFSSL_HAVE_XMSS)) && \ - !defined(NO_FILESYSTEM) && !defined(NO_CERTS) -/* Sanity bound on a test fixture cert. The largest BC-generated - * fixture we ship (XMSS^MT 40/8) is ~19 KiB; 1 MiB is well above - * any realistic RFC 9802 cert and catches a wild XFTELL. Typed as - * long to match XFTELL's return so the size comparison below isn't - * a mixed long-vs-int compare. */ -#define RFC9802_TEST_MAX_CERT_SIZE ((long)(1L << 20)) - -/* Load a whole file into a freshly-allocated buffer. Caller frees. */ -static int rfc9802_load_file(const char* path, byte** out, int* outLen) -{ - EXPECT_DECLS; - XFILE f = XBADFILE; - long sz = 0; - size_t got = 0; - byte* buf = NULL; - - *out = NULL; - *outLen = 0; - ExpectTrue((f = XFOPEN(path, "rb")) != XBADFILE); - if (f == XBADFILE) - return TEST_FAIL; - if (XFSEEK(f, 0, XSEEK_END) == 0) - sz = XFTELL(f); - (void)XFSEEK(f, 0, XSEEK_SET); - ExpectIntGT(sz, 0); - ExpectIntLT(sz, RFC9802_TEST_MAX_CERT_SIZE); - /* Hard-fail before XMALLOC if XFSEEK / XFTELL produced an unusable - * size: ExpectInt* records the failure but doesn't short-circuit, - * so without this guard a -1 from XFTELL would cast to a multi-GiB - * (size_t) allocation, and a 0 would request a zero-byte malloc. */ - if (sz <= 0 || sz >= RFC9802_TEST_MAX_CERT_SIZE) { - XFCLOSE(f); - return TEST_FAIL; - } - ExpectNotNull(buf = (byte*)XMALLOC((size_t)sz, NULL, - DYNAMIC_TYPE_TMP_BUFFER)); - if (buf != NULL) { - got = XFREAD(buf, 1, (size_t)sz, f); - ExpectIntEQ(got, (size_t)sz); - /* On a short read the caller would otherwise proceed with a - * partially-initialized buffer and produce cascading parse - * failures driven by the uninitialized tail. Free here so the - * caller's `if (buf == NULL) return TEST_FAIL;` short-circuits - * cleanly with a single recorded failure. */ - if (got != (size_t)sz) { - XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); - buf = NULL; - sz = 0; - } - } - XFCLOSE(f); - *out = buf; - *outLen = (int)sz; - return EXPECT_RESULT(); -} - -static int rfc9802_verify_one_cert(const char* path, word32 expectedKeyOID, - word32 expectedSigOID) -{ - EXPECT_DECLS; - byte* buf = NULL; - byte* tampered = NULL; - int bytes = 0; - DecodedCert cert; - WOLFSSL_CERT_MANAGER* cm = NULL; - word32 certBegin = 0; - word32 sigIndex = 0; - - ExpectIntEQ(rfc9802_load_file(path, &buf, &bytes), TEST_SUCCESS); - if (buf == NULL) - return TEST_FAIL; - - /* Parse + check OIDs, capture certBegin and sigIndex for later tamper. */ - wc_InitDecodedCert(&cert, buf, (word32)bytes, NULL); - ExpectIntEQ(wc_ParseCert(&cert, CERT_TYPE, NO_VERIFY, NULL), 0); - ExpectIntEQ((int)cert.keyOID, (int)expectedKeyOID); - ExpectIntEQ((int)cert.signatureOID, (int)expectedSigOID); - certBegin = cert.certBegin; - sigIndex = cert.sigIndex; - wc_FreeDecodedCert(&cert); - - /* Full verify against a self-installed trust anchor. */ - ExpectNotNull(cm = wolfSSL_CertManagerNew()); - ExpectIntEQ(wolfSSL_CertManagerLoadCABuffer(cm, buf, (long)bytes, - WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); - ExpectIntEQ(wolfSSL_CertManagerVerifyBuffer(cm, buf, (long)bytes, - WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); - if (cm != NULL) { - wolfSSL_CertManagerFree(cm); - cm = NULL; - } - - ExpectNotNull(tampered = (byte*)XMALLOC((size_t)bytes, NULL, - DYNAMIC_TYPE_TMP_BUFFER)); - - /* Negative 1: flip a byte inside the signatureValue BIT STRING. - * Everything after sigIndex is the signatureAlgorithm + the BIT - * STRING payload, so flipping the last byte is always inside the - * signature content. */ - if (tampered != NULL) { - XMEMCPY(tampered, buf, (size_t)bytes); - tampered[bytes - 1] ^= 0x01; - ExpectNotNull(cm = wolfSSL_CertManagerNew()); - ExpectIntEQ(wolfSSL_CertManagerLoadCABuffer(cm, buf, (long)bytes, - WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); - ExpectIntNE(wolfSSL_CertManagerVerifyBuffer(cm, tampered, - (long)bytes, WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); - if (cm != NULL) { - wolfSSL_CertManagerFree(cm); - cm = NULL; - } - } - - /* Negative 2: flip a byte at the midpoint of the TBSCertificate. The - * TBS is the first element of the outer Certificate SEQUENCE and - * its bytes lie between (certBegin + outerSeqHeader) and sigIndex. - * Picking the midpoint ensures we're inside TBS regardless of the - * fixture's DN / extensions layout. */ - if (tampered != NULL && sigIndex > certBegin + 8U) { - word32 midTbs = certBegin + 8 + ((sigIndex - (certBegin + 8)) / 2); - XMEMCPY(tampered, buf, (size_t)bytes); - tampered[midTbs] ^= 0x01; - ExpectNotNull(cm = wolfSSL_CertManagerNew()); - ExpectIntEQ(wolfSSL_CertManagerLoadCABuffer(cm, buf, (long)bytes, - WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); - ExpectIntNE(wolfSSL_CertManagerVerifyBuffer(cm, tampered, - (long)bytes, WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); - if (cm != NULL) { - wolfSSL_CertManagerFree(cm); - cm = NULL; - } - } - - /* The fixtures MUST carry a KeyUsage extension with at least one of - * digitalSignature / nonRepudiation / keyCertSign / cRLSign set per - * RFC 9802 sec 3. Re-parse and assert that wolfSSL recorded a non- - * empty set of KeyUsage bits from one of those values. */ - wc_InitDecodedCert(&cert, buf, (word32)bytes, NULL); - ExpectIntEQ(wc_ParseCert(&cert, CERT_TYPE, NO_VERIFY, NULL), 0); - ExpectIntEQ(cert.extKeyUsageSet, 1); - ExpectIntNE(cert.extKeyUsage & (KEYUSE_DIGITAL_SIG | KEYUSE_CONTENT_COMMIT | - KEYUSE_KEY_CERT_SIGN | KEYUSE_CRL_SIGN), 0); - wc_FreeDecodedCert(&cert); - - XFREE(tampered, NULL, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); - return EXPECT_RESULT(); -} -#endif - -/* Direct wolfCrypt-level negative tests for the parameter-derivation - * helpers used by the RFC 9802 parse path. These exercise failure modes - * (unknown algorithm bytes, truncated inputs, mismatches) that a real - * cert body wouldn't easily reach. */ -#if defined(WOLFSSL_HAVE_LMS) -static int rfc9802_lms_import_negative(void) -{ - EXPECT_DECLS; - LmsKey key; - /* 60-byte buffer matches HSS_PUBLIC_KEY_LEN(32), just like a valid - * SHA-256/M32/H5 key; the algorithm-type bytes are junk so param - * derivation must fail cleanly. */ - byte junk[60]; - - XMEMSET(junk, 0, sizeof(junk)); - /* levels=1, lmsType=0xFFFFFFFF, lmOtsType=0xFFFFFFFF. */ - junk[3] = 1; - XMEMSET(junk + 4, 0xFF, 4); - XMEMSET(junk + 8, 0xFF, 4); - - /* Unknown algorithm types must be rejected. */ - ExpectIntEQ(wc_LmsKey_Init(&key, NULL, INVALID_DEVID), 0); - ExpectIntEQ(wc_LmsKey_ImportPubRaw(&key, junk, sizeof(junk)), - WC_NO_ERR_TRACE(NOT_COMPILED_IN)); - wc_LmsKey_Free(&key); - - /* Too-short buffer: only L + lmsType, no lmOtsType. */ - ExpectIntEQ(wc_LmsKey_Init(&key, NULL, INVALID_DEVID), 0); - ExpectIntEQ(wc_LmsKey_ImportPubRaw(&key, junk, 8), - WC_NO_ERR_TRACE(BUFFER_E)); - wc_LmsKey_Free(&key); - -#if !defined(WOLFSSL_NO_LMS_SHA256_256) - /* The two cases below pin specific SHA-256/M32 parameter codes - * (L1_H5_W8, L1_H5_W4, L1_H10_W2). Skip them in builds where the - * SHA-256/M32 family is disabled -- the family-agnostic checks - * above (junk algorithm types, too-short buffer, GetSigLen on - * unconfigured key) still cover the universal invariants. */ - - /* Pre-set params that disagree with the raw key's algorithm bytes: - * configure H=5/W=8 but feed buffer that claims H=10 / W=2. */ - XMEMSET(junk, 0, sizeof(junk)); - junk[3] = 1; /* levels=1 */ - junk[7] = 6; /* lmsType = LMS_SHA256_M32_H10 = 6 */ - junk[11] = 2; /* lmOtsType = LMOTS_SHA256_N32_W2 = 2 */ - ExpectIntEQ(wc_LmsKey_Init(&key, NULL, INVALID_DEVID), 0); - ExpectIntEQ(wc_LmsKey_SetParameters(&key, 1, 5, 8), 0); - ExpectIntEQ(wc_LmsKey_ImportPubRaw(&key, junk, sizeof(junk)), - WC_NO_ERR_TRACE(BAD_FUNC_ARG)); - wc_LmsKey_Free(&key); -#endif /* !WOLFSSL_NO_LMS_SHA256_256 */ - - /* GetSigLen on a key with no params set must not NULL-deref the - * params pointer; it must return BAD_FUNC_ARG instead. */ - { - word32 sigLen = 0; - ExpectIntEQ(wc_LmsKey_Init(&key, NULL, INVALID_DEVID), 0); - ExpectIntEQ(wc_LmsKey_GetSigLen(&key, &sigLen), - WC_NO_ERR_TRACE(BAD_FUNC_ARG)); - wc_LmsKey_Free(&key); - } - -#if !defined(WOLFSSL_NO_LMS_SHA256_256) - /* Partial-write invariant: a length mismatch after a successful - * auto-derive must leave key->params NULL. Build a buffer whose - * leading u32str(L) || lmsType || lmOtsType identifies a known - * parameter set, but truncate to one byte less than the real pub - * key length so the post-derive length check fails. */ - { - byte truncated[59]; /* HSS_PUBLIC_KEY_LEN(32) is 60 */ - XMEMSET(truncated, 0, sizeof(truncated)); - truncated[3] = 1; /* L = 1 */ - truncated[7] = 5; /* lmsType = LMS_SHA256_M32_H5 */ - truncated[11] = 4; /* lmOtsType = LMOTS_SHA256_N32_W4 */ - ExpectIntEQ(wc_LmsKey_Init(&key, NULL, INVALID_DEVID), 0); - ExpectNull(key.params); - ExpectIntEQ(wc_LmsKey_ImportPubRaw(&key, truncated, - sizeof(truncated)), WC_NO_ERR_TRACE(BUFFER_E)); - ExpectNull(key.params); - wc_LmsKey_Free(&key); - } -#endif /* !WOLFSSL_NO_LMS_SHA256_256 */ - - return EXPECT_RESULT(); -} -#endif - -#if defined(WOLFSSL_HAVE_XMSS) -static int rfc9802_xmss_import_negative(void) -{ - EXPECT_DECLS; - XmssKey key; - byte junk[8]; - - XMEMSET(junk, 0, sizeof(junk)); - - /* Too-short buffer. */ - ExpectIntEQ(wc_XmssKey_Init(&key, NULL, INVALID_DEVID), 0); - ExpectIntEQ(wc_XmssKey_ImportPubRaw_ex(&key, junk, 2, 0), - WC_NO_ERR_TRACE(BUFFER_E)); - wc_XmssKey_Free(&key); - - /* Unknown OID (all-zero) for both XMSS and XMSS^MT. */ - ExpectIntEQ(wc_XmssKey_Init(&key, NULL, INVALID_DEVID), 0); - ExpectIntEQ(wc_XmssKey_ImportPubRaw_ex(&key, junk, sizeof(junk), 0), - WC_NO_ERR_TRACE(NOT_COMPILED_IN)); - wc_XmssKey_Free(&key); - ExpectIntEQ(wc_XmssKey_Init(&key, NULL, INVALID_DEVID), 0); - ExpectIntEQ(wc_XmssKey_ImportPubRaw_ex(&key, junk, sizeof(junk), 1), - WC_NO_ERR_TRACE(NOT_COMPILED_IN)); - wc_XmssKey_Free(&key); - - /* NULL key / input. */ - ExpectIntEQ(wc_XmssKey_ImportPubRaw_ex(NULL, junk, sizeof(junk), 0), - WC_NO_ERR_TRACE(BAD_FUNC_ARG)); - ExpectIntEQ(wc_XmssKey_Init(&key, NULL, INVALID_DEVID), 0); - ExpectIntEQ(wc_XmssKey_ImportPubRaw_ex(&key, NULL, 8, 0), - WC_NO_ERR_TRACE(BAD_FUNC_ARG)); - wc_XmssKey_Free(&key); - - /* GetSigLen on a key with no params set must not NULL-deref the - * params pointer; it must return BAD_FUNC_ARG instead. */ - { - word32 sigLen = 0; - ExpectIntEQ(wc_XmssKey_Init(&key, NULL, INVALID_DEVID), 0); - ExpectIntEQ(wc_XmssKey_GetSigLen(&key, &sigLen), - WC_NO_ERR_TRACE(BAD_FUNC_ARG)); - wc_XmssKey_Free(&key); - } - - /* Once params have been configured (state != INITED), the OID - * prefix in the raw key MUST match key->oid and is_xmssmt MUST - * match key->is_xmssmt. Set XMSS-SHA2_10_256 and feed a valid- - * sized buffer whose 4-byte OID prefix is bogus -> BAD_FUNC_ARG. */ - { - byte mismatch[XMSS_SHA256_PUBLEN]; - ExpectIntEQ(wc_XmssKey_Init(&key, NULL, INVALID_DEVID), 0); - ExpectIntEQ(wc_XmssKey_SetParamStr(&key, "XMSS-SHA2_10_256"), 0); - XMEMSET(mismatch, 0, sizeof(mismatch)); - mismatch[3] = 0x77; /* nonsense OID */ - ExpectIntEQ(wc_XmssKey_ImportPubRaw_ex(&key, mismatch, - sizeof(mismatch), 0), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); - /* Same buffer with the correct OID, but is_xmssmt hint - * contradicts the configured family -> BAD_FUNC_ARG. */ - mismatch[3] = 0x01; /* WC_XMSS_OID_SHA2_10_256 */ - ExpectIntEQ(wc_XmssKey_ImportPubRaw_ex(&key, mismatch, - sizeof(mismatch), 1), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); - wc_XmssKey_Free(&key); - } - - /* Partial-write invariant: a length mismatch after a successful - * auto-derive must leave the key in its INITED state, with - * key->params NULL. */ - { - byte truncated[XMSS_SHA256_PUBLEN - 1]; - XMEMSET(truncated, 0, sizeof(truncated)); - truncated[3] = 0x01; - ExpectIntEQ(wc_XmssKey_Init(&key, NULL, INVALID_DEVID), 0); - ExpectNull(key.params); - ExpectIntEQ(wc_XmssKey_ImportPubRaw_ex(&key, truncated, - sizeof(truncated), 0), WC_NO_ERR_TRACE(BUFFER_E)); - ExpectNull(key.params); - wc_XmssKey_Free(&key); - } - - /* is_xmssmt disambiguation: XMSS oid=1 and XMSS^MT oid=1 share - * the wire-numeric value but resolve to different parameter sets. - * Importing the same 68-byte buffer with hint=0 vs hint=1 must - * land in different tables and produce distinct is_xmssmt. */ - { - byte buf[XMSS_SHA256_PUBLEN]; - XMEMSET(buf, 0, sizeof(buf)); - buf[3] = 0x01; - - ExpectIntEQ(wc_XmssKey_Init(&key, NULL, INVALID_DEVID), 0); - ExpectIntEQ(wc_XmssKey_ImportPubRaw_ex(&key, buf, sizeof(buf), 0), 0); - ExpectIntEQ((int)key.is_xmssmt, 0); - wc_XmssKey_Free(&key); - - ExpectIntEQ(wc_XmssKey_Init(&key, NULL, INVALID_DEVID), 0); - ExpectIntEQ(wc_XmssKey_ImportPubRaw_ex(&key, buf, sizeof(buf), 1), 0); - ExpectIntEQ((int)key.is_xmssmt, 1); - wc_XmssKey_Free(&key); - } - - /* Lenient state: re-importing the same pub key into a VERIFYONLY - * key (params set, no private material) succeeds. The second - * call exercises the lenient-state branch. */ - { - byte buf[XMSS_SHA256_PUBLEN]; - XMEMSET(buf, 0, sizeof(buf)); - buf[3] = 0x01; - - ExpectIntEQ(wc_XmssKey_Init(&key, NULL, INVALID_DEVID), 0); - ExpectIntEQ(wc_XmssKey_ImportPubRaw_ex(&key, buf, sizeof(buf), 0), 0); - ExpectIntEQ((int)key.state, (int)WC_XMSS_STATE_VERIFYONLY); - ExpectIntEQ(wc_XmssKey_ImportPubRaw_ex(&key, buf, sizeof(buf), 0), 0); - ExpectIntEQ((int)key.state, (int)WC_XMSS_STATE_VERIFYONLY); - wc_XmssKey_Free(&key); - } - - /* Strict signature-length check: wc_XmssKey_Verify rejects any - * sigLen != key->params->sig_len. This guards every consumer - * (RFC 9802 X.509, PKCS#7, CMS, ...) against a longer wrapper that - * happens to start with a valid signature. Construct a key in - * VERIFYONLY state, then verify with sig_len + 1 and sig_len - 1 - * byte buffers; both must fail with BUFFER_E before any crypto - * runs. The buffer contents are irrelevant since the length check - * fires first. */ - { - byte pub[XMSS_SHA256_PUBLEN]; - byte* sigBuf = NULL; - word32 sigLen = 0; - const byte msg[1] = { 0 }; - - XMEMSET(pub, 0, sizeof(pub)); - pub[3] = 0x01; - ExpectIntEQ(wc_XmssKey_Init(&key, NULL, INVALID_DEVID), 0); - ExpectIntEQ(wc_XmssKey_ImportPubRaw_ex(&key, pub, sizeof(pub), 0), 0); - ExpectIntEQ((int)key.state, (int)WC_XMSS_STATE_VERIFYONLY); - ExpectIntEQ(wc_XmssKey_GetSigLen(&key, &sigLen), 0); - ExpectIntGT(sigLen, 0); - ExpectNotNull(sigBuf = (byte*)XMALLOC((size_t)sigLen + 1, NULL, - DYNAMIC_TYPE_TMP_BUFFER)); - if (sigBuf != NULL) { - XMEMSET(sigBuf, 0, (size_t)sigLen + 1); - ExpectIntEQ(wc_XmssKey_Verify(&key, sigBuf, sigLen + 1, - msg, (int)sizeof(msg)), WC_NO_ERR_TRACE(BUFFER_E)); - ExpectIntEQ(wc_XmssKey_Verify(&key, sigBuf, sigLen - 1, - msg, (int)sizeof(msg)), WC_NO_ERR_TRACE(BUFFER_E)); - XFREE(sigBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); - } - wc_XmssKey_Free(&key); - } - - /* BAD_STATE_E branch: WC_XMSS_STATE_OK must be rejected. Reaching - * OK normally requires a successful private-key Reload / sign, - * which is unavailable in WOLFSSL_XMSS_VERIFY_ONLY builds. Force - * the state directly to exercise the rejection without coupling - * this helper to the signing test fixture; sk stays NULL so Free - * is still safe. */ - { - byte pub[XMSS_SHA256_PUBLEN]; - - XMEMSET(pub, 0, sizeof(pub)); - pub[3] = 0x01; - ExpectIntEQ(wc_XmssKey_Init(&key, NULL, INVALID_DEVID), 0); - ExpectIntEQ(wc_XmssKey_SetParamStr(&key, "XMSS-SHA2_10_256"), 0); - key.state = WC_XMSS_STATE_OK; - ExpectIntEQ(wc_XmssKey_ImportPubRaw_ex(&key, pub, sizeof(pub), 0), - WC_NO_ERR_TRACE(BAD_STATE_E)); - wc_XmssKey_Free(&key); - } - - return EXPECT_RESULT(); -} -#endif - -/* Walk the AlgorithmIdentifier SEQUENCE that begins at sigIndex and - * locate the byte offset of the last byte of its OID content. Handles - * both short-form (length < 128) and long-form DER length encodings, - * so a future fixture-regenerator that emits longer OIDs / SEQUENCEs - * still drives this test rather than tripping the loud-fail branch. - * - * Returns 0 on success with *oidLastByte set; returns -1 on any DER - * shape mismatch. */ -#if defined(WOLFSSL_HAVE_XMSS) && !defined(NO_FILESYSTEM) && !defined(NO_CERTS) -static int rfc9802_find_sig_alg_oid_last_byte(const byte* buf, word32 bufLen, - word32 sigIndex, word32* oidLastByte) -{ - word32 idx = sigIndex; - word32 oidContentLen = 0; - - /* AlgorithmIdentifier ::= SEQUENCE { algorithm OID, ... } */ - if (idx >= bufLen || buf[idx] != 0x30) - return -1; - idx++; - /* Skip SEQUENCE length (short or long form). */ - if (idx >= bufLen) - return -1; - if (buf[idx] < 0x80) { - idx++; - } - else { - word32 nbytes = (word32)(buf[idx] & 0x7F); - if (nbytes == 0 || nbytes > 4 || idx + 1 + nbytes > bufLen) - return -1; - idx += 1 + nbytes; - } - /* algorithm OID tag. */ - if (idx >= bufLen || buf[idx] != 0x06) - return -1; - idx++; - /* OID length (short or long form). */ - if (idx >= bufLen) - return -1; - if (buf[idx] < 0x80) { - oidContentLen = buf[idx]; - idx++; - } - else { - word32 nbytes = (word32)(buf[idx] & 0x7F); - word32 i; - if (nbytes == 0 || nbytes > 4 || idx + 1 + nbytes > bufLen) - return -1; - for (i = 0; i < nbytes; i++) - oidContentLen = (oidContentLen << 8) | buf[idx + 1 + i]; - idx += 1 + nbytes; - } - if (oidContentLen == 0 || idx + oidContentLen > bufLen) - return -1; - *oidLastByte = idx + oidContentLen - 1; - return 0; -} - -/* Helper: load fixture, locate last byte of outer signatureAlgorithm - * OID, patch it from `expected` to `swap`, and assert that verifying - * the patched cert against itself as a trust anchor fails. */ -static int rfc9802_assert_oid_patch_breaks_verify(const char* path, - byte expectedLastByte, byte patchedLastByte) -{ - EXPECT_DECLS; - byte* buf = NULL; - int bytes = 0; - DecodedCert cert; - WOLFSSL_CERT_MANAGER* cm = NULL; - word32 sigIndex = 0; - word32 lastOidByte = 0; - - ExpectIntEQ(rfc9802_load_file(path, &buf, &bytes), TEST_SUCCESS); - if (buf == NULL) - return TEST_FAIL; - - wc_InitDecodedCert(&cert, buf, (word32)bytes, NULL); - ExpectIntEQ(wc_ParseCert(&cert, CERT_TYPE, NO_VERIFY, NULL), 0); - sigIndex = cert.sigIndex; - wc_FreeDecodedCert(&cert); - - ExpectIntEQ(rfc9802_find_sig_alg_oid_last_byte(buf, (word32)bytes, - sigIndex, &lastOidByte), 0); - /* Sanity-check the fixture matches the family the caller asserted, - * so a future regenerator swapping fixtures fails loudly here - * rather than silently testing the wrong direction. */ - ExpectIntEQ((int)buf[lastOidByte], (int)expectedLastByte); - - if (lastOidByte < (word32)bytes && - buf[lastOidByte] == expectedLastByte) { - buf[lastOidByte] = patchedLastByte; - ExpectNotNull(cm = wolfSSL_CertManagerNew()); - /* After the patch the cert's outer signatureAlgorithm and SPKI - * disagree. Verification must fail somewhere (at parse, at - * load, or at ConfirmSignature). The load is best-effort - - * some shape changes get caught there, others only at verify. */ - (void)wolfSSL_CertManagerLoadCABuffer(cm, buf, (long)bytes, - WOLFSSL_FILETYPE_ASN1); - ExpectIntNE(wolfSSL_CertManagerVerifyBuffer(cm, buf, - (long)bytes, WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); - if (cm != NULL) { - wolfSSL_CertManagerFree(cm); - cm = NULL; - } - } - - XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); - return EXPECT_RESULT(); -} - -/* X.509-level negative: swap the outer signatureAlgorithm OID byte so - * the cert declares XMSS where the SPKI is XMSS^MT, and vice versa. - * SigOidMatchesKeyOid must reject both directions before any crypto. */ -static int rfc9802_xmss_sig_oid_mismatch(void) -{ - EXPECT_DECLS; - /* XMSS sigOID ends 0x22; XMSS^MT sigOID ends 0x23. Patch each - * direction so the asymmetric-key path is exercised both ways - - * a regression that only stripped the check from one branch of - * SigOidMatchesKeyOid would otherwise be missed. */ - ExpectIntEQ(rfc9802_assert_oid_patch_breaks_verify( - "./certs/xmss/bc_xmss_sha2_10_256_root.der", - /* expected XMSS */ 0x22, /* patched to XMSS^MT */ 0x23), - TEST_SUCCESS); - ExpectIntEQ(rfc9802_assert_oid_patch_breaks_verify( - "./certs/xmss/bc_xmssmt_sha2_20_2_256_root.der", - /* expected XMSS^MT */ 0x23, /* patched to XMSS */ 0x22), - TEST_SUCCESS); - return EXPECT_RESULT(); -} -#endif - -/* Exercise a real CA -> leaf certificate chain, not just self-signed. - * Loads the CA as a trust anchor and verifies the leaf against it. */ -#if defined(WOLFSSL_HAVE_LMS) && !defined(NO_FILESYSTEM) && !defined(NO_CERTS) -static int rfc9802_lms_chain_verify(void) -{ - EXPECT_DECLS; - byte* caBuf = NULL; - byte* leafBuf = NULL; - int caLen = 0; - int leafLen = 0; - WOLFSSL_CERT_MANAGER* cm = NULL; - - ExpectIntEQ(rfc9802_load_file("./certs/lms/bc_lms_chain_ca.der", - &caBuf, &caLen), TEST_SUCCESS); - ExpectIntEQ(rfc9802_load_file("./certs/lms/bc_lms_chain_leaf.der", - &leafBuf, &leafLen), TEST_SUCCESS); - - ExpectNotNull(cm = wolfSSL_CertManagerNew()); - /* Only the CA is a trust anchor; the leaf is verified against it. */ - ExpectIntEQ(wolfSSL_CertManagerLoadCABuffer(cm, caBuf, (long)caLen, - WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); - ExpectIntEQ(wolfSSL_CertManagerVerifyBuffer(cm, leafBuf, (long)leafLen, - WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); - - /* Without loading the CA the leaf must NOT verify. */ - if (cm != NULL) { - wolfSSL_CertManagerFree(cm); - cm = NULL; - } - ExpectNotNull(cm = wolfSSL_CertManagerNew()); - ExpectIntNE(wolfSSL_CertManagerVerifyBuffer(cm, leafBuf, (long)leafLen, - WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); - if (cm != NULL) { - wolfSSL_CertManagerFree(cm); - cm = NULL; - } - - XFREE(leafBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(caBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); - return EXPECT_RESULT(); -} -#endif - -/* Mirror of rfc9802_lms_chain_verify but for an XMSS CA -> leaf pair. */ -#if defined(WOLFSSL_HAVE_XMSS) && !defined(NO_FILESYSTEM) && !defined(NO_CERTS) -static int rfc9802_xmss_chain_verify(void) -{ - EXPECT_DECLS; - byte* caBuf = NULL; - byte* leafBuf = NULL; - int caLen = 0; - int leafLen = 0; - WOLFSSL_CERT_MANAGER* cm = NULL; - - ExpectIntEQ(rfc9802_load_file("./certs/xmss/bc_xmss_chain_ca.der", - &caBuf, &caLen), TEST_SUCCESS); - ExpectIntEQ(rfc9802_load_file("./certs/xmss/bc_xmss_chain_leaf.der", - &leafBuf, &leafLen), TEST_SUCCESS); - - ExpectNotNull(cm = wolfSSL_CertManagerNew()); - ExpectIntEQ(wolfSSL_CertManagerLoadCABuffer(cm, caBuf, (long)caLen, - WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); - ExpectIntEQ(wolfSSL_CertManagerVerifyBuffer(cm, leafBuf, (long)leafLen, - WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); - - if (cm != NULL) { - wolfSSL_CertManagerFree(cm); - cm = NULL; - } - ExpectNotNull(cm = wolfSSL_CertManagerNew()); - ExpectIntNE(wolfSSL_CertManagerVerifyBuffer(cm, leafBuf, (long)leafLen, - WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); - if (cm != NULL) { - wolfSSL_CertManagerFree(cm); - cm = NULL; - } - - XFREE(leafBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(caBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); - return EXPECT_RESULT(); -} -#endif - -int test_rfc9802_lms_x509_verify(void) -{ - EXPECT_DECLS; -#if defined(WOLFSSL_HAVE_LMS) -#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) && \ - !defined(WOLFSSL_NO_LMS_SHA256_256) - /* Mixed single-level LMS and multi-level HSS fixtures. The HSS - * public key carries only the top-level LMS/LM-OTS types, so - * wc_LmsKey_ImportPubRaw's auto-derive path searches the map - * by (levels, lmsType, lmOtsType). The bc_lms_native_bc_root - * fixture is generated through Bouncy Castle's stock - * JcaContentSignerBuilder("LMS") + JcaX509v3CertificateBuilder - * with no overrides; including it here is the cross-impl interop - * gate (BC's native LMS X.509 path is RFC 9802-compliant for HSS/ - * LMS, so wolfSSL must accept it end-to-end). - * - * All fixtures use the SHA-256/M32 family, so the whole block - * is gated on that family being compiled in. Truncated SHA-256/192 - * or SHAKE-only builds skip this block. */ - static const char* const lmsFiles[] = { - "./certs/lms/bc_lms_sha256_h5_w4_root.der", -#if !defined(WOLFSSL_LMS_MAX_HEIGHT) || (WOLFSSL_LMS_MAX_HEIGHT >= 10) - "./certs/lms/bc_lms_sha256_h10_w8_root.der", -#endif -#if !defined(WOLFSSL_LMS_MAX_LEVELS) || (WOLFSSL_LMS_MAX_LEVELS >= 2) - "./certs/lms/bc_hss_L2_H5_W8_root.der", -#endif -#if !defined(WOLFSSL_LMS_MAX_LEVELS) || (WOLFSSL_LMS_MAX_LEVELS >= 3) - "./certs/lms/bc_hss_L3_H5_W4_root.der", -#endif - "./certs/lms/bc_lms_native_bc_root.der", - }; - size_t i; - for (i = 0; i < sizeof(lmsFiles) / sizeof(lmsFiles[0]); i++) { - ExpectIntEQ(rfc9802_verify_one_cert(lmsFiles[i], - HSS_LMSk, CTC_HSS_LMS), TEST_SUCCESS); - } - ExpectIntEQ(rfc9802_lms_chain_verify(), TEST_SUCCESS); -#endif /* !NO_FILESYSTEM && !NO_CERTS && !WOLFSSL_NO_LMS_SHA256_256 */ - /* Pure wolfCrypt-level negative tests don't need filesystem or cert - * support, so they run for any LMS-enabled build. */ - ExpectIntEQ(rfc9802_lms_import_negative(), TEST_SUCCESS); -#endif - return EXPECT_RESULT(); -} - -int test_rfc9802_xmss_x509_verify(void) -{ - EXPECT_DECLS; -#if defined(WOLFSSL_HAVE_XMSS) -#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) - static const char* const xmssFiles[] = { - "./certs/xmss/bc_xmss_sha2_10_256_root.der", - "./certs/xmss/bc_xmss_sha2_16_256_root.der", - }; - static const char* const xmssmtFiles[] = { - "./certs/xmss/bc_xmssmt_sha2_20_2_256_root.der", - "./certs/xmss/bc_xmssmt_sha2_20_4_256_root.der", - "./certs/xmss/bc_xmssmt_sha2_40_8_256_root.der", - }; - size_t i; - for (i = 0; i < sizeof(xmssFiles) / sizeof(xmssFiles[0]); i++) { - ExpectIntEQ(rfc9802_verify_one_cert(xmssFiles[i], - XMSSk, CTC_XMSS), TEST_SUCCESS); - } - for (i = 0; i < sizeof(xmssmtFiles) / sizeof(xmssmtFiles[0]); i++) { - ExpectIntEQ(rfc9802_verify_one_cert(xmssmtFiles[i], - XMSSMTk, CTC_XMSSMT), TEST_SUCCESS); - } - ExpectIntEQ(rfc9802_xmss_sig_oid_mismatch(), TEST_SUCCESS); - ExpectIntEQ(rfc9802_xmss_chain_verify(), TEST_SUCCESS); -#endif /* !NO_FILESYSTEM && !NO_CERTS */ - /* Pure wolfCrypt-level negative tests don't need filesystem or cert - * support, so they run for any XMSS-enabled build. */ - ExpectIntEQ(rfc9802_xmss_import_negative(), TEST_SUCCESS); -#endif - return EXPECT_RESULT(); -} - #if defined(WOLFSSL_SNIFFER) && defined(WOLFSSL_SNIFFER_CHAIN_INPUT) static int test_sniffer_chain_input_overflow(void) { @@ -39045,47 +32831,6 @@ static int test_DhAgree_rejects_p_minus_1(void) return EXPECT_RESULT(); } - -/* ML-DSA HashML-DSA verify must reject hashLen > WC_MAX_DIGEST_SIZE */ -static int test_mldsa_verify_hash(void) -{ - EXPECT_DECLS; -#if defined(WOLFSSL_HAVE_MLDSA) && \ - !defined(WOLFSSL_MLDSA_NO_MAKE_KEY) && \ - !defined(WOLFSSL_MLDSA_NO_VERIFY) - wc_MlDsaKey key; - WC_RNG rng; - int res = 0; - byte sig[4000]; - byte hash[4096]; /* larger than WC_MAX_DIGEST_SIZE */ - - XMEMSET(&key, 0, sizeof(key)); - XMEMSET(&rng, 0, sizeof(rng)); - XMEMSET(sig, 0x41, sizeof(sig)); - XMEMSET(hash, 'A', sizeof(hash)); - - ExpectIntEQ(wc_InitRng(&rng), 0); - ExpectIntEQ(wc_MlDsaKey_Init(&key, NULL, INVALID_DEVID), 0); -#ifndef WOLFSSL_NO_ML_DSA_65 - ExpectIntEQ(wc_MlDsaKey_SetParams(&key, WC_ML_DSA_65), 0); -#elif !defined(WOLFSSL_NO_ML_DSA_44) - ExpectIntEQ(wc_MlDsaKey_SetParams(&key, WC_ML_DSA_44), 0); -#else - ExpectIntEQ(wc_MlDsaKey_SetParams(&key, WC_ML_DSA_87), 0); -#endif - ExpectIntEQ(wc_MlDsaKey_MakeKey(&key, &rng), 0); - - /* hashLen=4096 must be rejected, not overflow the stack */ - ExpectIntEQ(wc_MlDsaKey_VerifyCtxHash(&key, sig, sizeof(sig), NULL, 0, - hash, sizeof(hash), WC_HASH_TYPE_SHA256, &res), - WC_NO_ERR_TRACE(BAD_LENGTH_E)); - - wc_MlDsaKey_Free(&key); - DoExpectIntEQ(wc_FreeRng(&rng), 0); -#endif - return EXPECT_RESULT(); -} - /* Test: Ed448 must reject identity public key (0,1) */ static int test_ed448_rejects_identity_key(void) { @@ -39964,44 +33709,6 @@ static int test_pkcs7_enveloped_content_size_overflow(void) return EXPECT_RESULT(); } -/* Dilithium verify_ctx_msg must reject absurdly large msgLen */ -static int test_dilithium_hash(void) -{ - EXPECT_DECLS; -#if defined(WOLFSSL_HAVE_MLDSA) && \ - !defined(WOLFSSL_MLDSA_NO_MAKE_KEY) && \ - !defined(WOLFSSL_MLDSA_NO_VERIFY) - wc_MlDsaKey key; - WC_RNG rng; - int res = 0; - byte sig[4000]; - byte msg[64]; - - XMEMSET(&key, 0, sizeof(key)); - XMEMSET(&rng, 0, sizeof(rng)); - XMEMSET(sig, 0, sizeof(sig)); - XMEMSET(msg, 'A', sizeof(msg)); - - ExpectIntEQ(wc_InitRng(&rng), 0); - ExpectIntEQ(wc_MlDsaKey_Init(&key, NULL, INVALID_DEVID), 0); -#ifndef WOLFSSL_NO_ML_DSA_65 - ExpectIntEQ(wc_MlDsaKey_SetParams(&key, WC_ML_DSA_65), 0); -#elif !defined(WOLFSSL_NO_ML_DSA_44) - ExpectIntEQ(wc_MlDsaKey_SetParams(&key, WC_ML_DSA_44), 0); -#else - ExpectIntEQ(wc_MlDsaKey_SetParams(&key, WC_ML_DSA_87), 0); -#endif - ExpectIntEQ(wc_MlDsaKey_MakeKey(&key, &rng), 0); - - ExpectIntEQ(wc_MlDsaKey_VerifyCtx(&key, sig, sizeof(sig), NULL, 0, - msg, 0xFFFFFFC0, &res), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); - - wc_MlDsaKey_Free(&key); - DoExpectIntEQ(wc_FreeRng(&rng), 0); -#endif - return EXPECT_RESULT(); -} - /* PKCS7 CBC must validate all padding bytes */ static int test_pkcs7_padding(void) { @@ -40200,13 +33907,8 @@ TEST_CASE testCases[] = { /* ASN */ TEST_ASN_DECLS, - /* LMS */ - TEST_DECL_GROUP("lms", test_wc_LmsKey_sign_verify), - TEST_DECL_GROUP("lms", test_wc_LmsKey_reload_cache), - - /* RFC 9802 (HSS/LMS and XMSS/XMSS^MT in X.509) */ - TEST_DECL_GROUP("lms", test_rfc9802_lms_x509_verify), - TEST_DECL_GROUP("xmss", test_rfc9802_xmss_x509_verify), + /* LMS, and RFC 9802 (HSS/LMS and XMSS/XMSS^MT in X.509) */ + TEST_LMS_XMSS_DECLS, /* PEM and DER APIs. */ TEST_DECL(test_wc_PemToDer), @@ -40448,10 +34150,6 @@ TEST_CASE testCases[] = { TEST_DECL(test_wolfSSL_sigalg_info), /* Can't memory test as tcp_connect aborts. */ TEST_DECL(test_wolfSSL_d2i_SSL_SESSION_bounds_check), - TEST_DECL(test_wolfSSL_SESSION), - TEST_DECL(test_wolfSSL_SESSION_expire_downgrade), - TEST_DECL(test_wolfSSL_CTX_sess_set_remove_cb), - TEST_DECL(test_wolfSSL_ticket_keys), TEST_DECL(test_wolfSSL_sk_GENERAL_NAME), TEST_DECL(test_wolfSSL_GENERAL_NAME_print), TEST_DECL(test_wolfSSL_sk_DIST_POINT), @@ -40489,7 +34187,6 @@ TEST_CASE testCases[] = { TEST_DECL(test_wolfSSL_CRYPTO_memcmp), TEST_DECL(test_wolfSSL_CRYPTO_get_ex_new_index), - TEST_DECL(test_wolfSSL_SESSION_get_ex_new_index), TEST_DECL(test_CRYPTO_set_dynlock_xxx), TEST_DECL(test_CRYPTO_THREADID_xxx), TEST_DECL(test_ENGINE_cleanup), @@ -40602,20 +34299,6 @@ TEST_CASE testCases[] = { #ifdef HAVE_IO_TESTS_DEPENDENCIES TEST_DECL(test_wolfSSL_get_finished), - /* Uses Assert in handshake callback. */ - TEST_DECL(test_wolfSSL_CTX_add_session), - /* Large number of memory allocations. */ - TEST_DECL(test_wolfSSL_CTX_add_session_ext_tls13), - /* Large number of memory allocations. */ - TEST_DECL(test_wolfSSL_CTX_add_session_ext_dtls13), - /* Large number of memory allocations. */ - TEST_DECL(test_wolfSSL_CTX_add_session_ext_tls12), - /* Large number of memory allocations. */ - TEST_DECL(test_wolfSSL_CTX_add_session_ext_dtls12), - /* Large number of memory allocations. */ - TEST_DECL(test_wolfSSL_CTX_add_session_ext_tls11), - /* Large number of memory allocations. */ - TEST_DECL(test_wolfSSL_CTX_add_session_ext_dtls1), #endif TEST_DECL(test_SSL_CIPHER_get_xxx), TEST_DECL(test_wolfSSL_ERR_strings), @@ -40666,12 +34349,8 @@ TEST_CASE testCases[] = { TEST_DECL(test_SetTmpEC_DHE_Sz), TEST_DECL(test_wolfSSL_CTX_get0_privatekey), #ifdef WOLFSSL_DTLS - TEST_DECL(test_wolfSSL_DtlsUpdateWindow), - TEST_DECL(test_wolfSSL_DTLS_fragment_buckets), #endif - TEST_DECL(test_wolfSSL_dtls_set_mtu), /* Uses Assert in handshake callback. */ - TEST_DECL(test_wolfSSL_dtls_plaintext), #if !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) && \ defined(HAVE_IO_TESTS_DEPENDENCIES) TEST_DECL(test_wolfSSL_read_write), @@ -40684,12 +34363,9 @@ TEST_CASE testCases[] = { TEST_DECL(test_wolfSSL_CTX_verifyDepth_ServerClient_3), TEST_DECL(test_wolfSSL_CTX_set_cipher_list), /* Can't memory test as server hangs. */ - TEST_DECL(test_wolfSSL_dtls_export), /* Uses Assert in handshake callback. */ TEST_DECL(test_wolfSSL_tls_export), #endif - TEST_DECL(test_wolfSSL_dtls_export_peers), - TEST_DECL(test_wolfSSL_dtls_import_state_extra_window_words), TEST_DECL(test_wolfSSL_SetMinVersion), TEST_DECL(test_wolfSSL_CTX_SetMinVersion), @@ -40811,19 +34487,11 @@ TEST_CASE testCases[] = { TEST_DECL(test_wolfSSL_msgCb), TEST_DECL(test_wolfSSL_either_side), - TEST_DECL(test_wolfSSL_DTLS_either_side), /* Uses Assert in handshake callback. */ - TEST_DECL(test_wolfSSL_dtls_fragments), /* Uses Assert in handshake callback. */ - TEST_DECL(test_wolfSSL_dtls_AEAD_limit), /* Uses Assert in handshake callback. */ - TEST_DECL(test_wolfSSL_ignore_alert_before_cookie), /* Uses Assert in handshake callback. */ - TEST_DECL(test_wolfSSL_dtls_bad_record), /* Uses Assert in handshake callback. */ - TEST_DECL(test_wolfSSL_dtls_stateless), - TEST_DECL(test_wolfSSL_dtls_stateless_hrr_group), - TEST_DECL(test_generate_cookie), #ifndef NO_BIO TEST_OSSL_BIO_TLS_DECLS, @@ -40850,15 +34518,11 @@ TEST_CASE testCases[] = { defined(WOLFSSL_DTLS) && !defined(WOLFSSL_NO_TLS12) && \ !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) #ifdef WOLFSSL_DTLS_NO_HVR_ON_RESUME - TEST_DECL(test_wolfSSL_dtls_stateless_resume), #endif /* WOLFSSL_DTLS_NO_HVR_ON_RESUME */ #ifdef HAVE_MAX_FRAGMENT - TEST_DECL(test_wolfSSL_dtls_stateless_maxfrag), #endif /* HAVE_MAX_FRAGMENT */ #ifndef NO_RSA - TEST_DECL(test_wolfSSL_dtls_stateless2), #if !defined(NO_OLD_TLS) - TEST_DECL(test_wolfSSL_dtls_stateless_downgrade), #endif /* !defined(NO_OLD_TLS) */ #endif /* ! NO_RSA */ #endif /* defined(WOLFSSL_DTLS) && !defined(WOLFSSL_NO_TLS12) && \ @@ -40866,7 +34530,6 @@ TEST_CASE testCases[] = { TEST_DECL(test_wolfSSL_CTX_set_ciphersuites), TEST_DECL(test_wolfSSL_CRL_CERT_REVOKED_alert), TEST_DECL(test_TLS_13_ticket_different_ciphers), - TEST_DECL(test_WOLFSSL_dtls_version_alert), #if defined(WOLFSSL_TICKET_NONCE_MALLOC) && defined(HAVE_SESSION_TICKET) \ && defined(WOLFSSL_TLS13) && \ @@ -40885,36 +34548,17 @@ TEST_CASE testCases[] = { TEST_DECL(test_harden_no_secure_renegotiation), TEST_DECL(test_override_alt_cert_chain), TEST_DECL(test_rpk_set_xxx_cert_type), - TEST_DECL(test_dtls13_bad_epoch_ch), TEST_DECL(test_short_session_id), - TEST_DECL(test_wolfSSL_dtls13_null_cipher), /* Can't memory test as client/server hangs. */ - TEST_DECL(test_dtls_msg_from_other_peer), - TEST_DECL(test_dtls_ipv6_check), TEST_DECL(test_wolfSSL_SCR_after_resumption), - TEST_DECL(test_dtls_no_extensions), TEST_DECL(test_tls_alert_no_server_hello), TEST_DECL(test_TLSX_CA_NAMES_bad_extension), - TEST_DECL(test_dtls_1_0_hvr_downgrade), TEST_DECL(test_session_ticket_no_id), TEST_DECL(test_session_ticket_hs_update), - TEST_DECL(test_dtls_downgrade_scr_server), - TEST_DECL(test_dtls_downgrade_scr), - TEST_DECL(test_dtls_client_hello_timeout_downgrade), - TEST_DECL(test_dtls_client_hello_timeout), - TEST_DECL(test_dtls_dropped_ccs), - TEST_DECL(test_dtls_seq_num_downgrade), TEST_DECL(test_certreq_sighash_algos), TEST_DECL(test_revoked_loaded_int_cert), - TEST_DECL(test_dtls_frag_ch), - TEST_DECL(test_dtls13_frag_ch_pq), - TEST_DECL(test_dtls_empty_keyshare_with_cookie), - TEST_DECL(test_dtls_old_seq_number), - TEST_DECL(test_dtls12_missing_finished), - TEST_DECL(test_dtls13_missing_finished_client), - TEST_DECL(test_dtls13_missing_finished_server), - TEST_DECL(test_dtls13_finished_send_error_propagation), TEST_DTLS_DECLS, + TEST_DTLS13_DECLS, TEST_DECL(test_tls_multi_handshakes_one_record), TEST_DECL(test_write_dup), TEST_DECL(test_write_dup_want_write), @@ -40940,6 +34584,7 @@ TEST_CASE testCases[] = { TEST_DECL(test_tls13_nonblock_ocsp_low_mfl), TEST_DECL(test_ocsp_responder), TEST_TLS_DECLS, + TEST_SESSION_DECLS, TEST_DECL(test_wc_DhSetNamedKey), TEST_DECL(test_DhAgree_rejects_p_minus_1), TEST_DECL(test_ed448_rejects_identity_key), @@ -40958,8 +34603,6 @@ TEST_CASE testCases[] = { TEST_DECL(test_sniffer_chain_input_overflow), #endif - TEST_DECL(test_mldsa_verify_hash), - TEST_DECL(test_dilithium_hash), /* This test needs to stay at the end to clean up any caches allocated. */ TEST_DECL(test_wolfSSL_Cleanup) }; diff --git a/tests/api/include.am b/tests/api/include.am index f9d4dfe3f1..7ad64d3e63 100644 --- a/tests/api/include.am +++ b/tests/api/include.am @@ -51,13 +51,16 @@ tests_unit_test_SOURCES += tests/api/test_mldsa.c tests_unit_test_SOURCES += tests/api/test_mldsa_legacy.c tests_unit_test_SOURCES += tests/api/test_slhdsa.c tests_unit_test_SOURCES += tests/api/test_signature.c +tests_unit_test_SOURCES += tests/api/test_lms_xmss.c # TLS Protocol tests_unit_test_SOURCES += tests/api/test_dtls.c +tests_unit_test_SOURCES += tests/api/test_dtls13.c # TLS Feature tests_unit_test_SOURCES += tests/api/test_ocsp.c tests_unit_test_SOURCES += tests/api/test_evp.c tests_unit_test_SOURCES += tests/api/test_tls_ext.c tests_unit_test_SOURCES += tests/api/test_tls.c +tests_unit_test_SOURCES += tests/api/test_session.c # Certs tests_unit_test_SOURCES += tests/api/test_x509.c # ASN @@ -157,13 +160,16 @@ EXTRA_DIST += tests/api/test_mlkem.h EXTRA_DIST += tests/api/test_mldsa.h EXTRA_DIST += tests/api/test_slhdsa.h EXTRA_DIST += tests/api/test_signature.h +EXTRA_DIST += tests/api/test_lms_xmss.h EXTRA_DIST += tests/api/test_dtls.h +EXTRA_DIST += tests/api/test_dtls13.h EXTRA_DIST += tests/api/test_ocsp.h EXTRA_DIST += tests/api/test_ocsp_test_blobs.h EXTRA_DIST += tests/api/create_ocsp_test_blobs.py EXTRA_DIST += tests/api/test_evp.h EXTRA_DIST += tests/api/test_tls_ext.h EXTRA_DIST += tests/api/test_tls.h +EXTRA_DIST += tests/api/test_session.h EXTRA_DIST += tests/api/test_x509.h EXTRA_DIST += tests/api/test_asn.h EXTRA_DIST += tests/api/test_pkcs7.h diff --git a/tests/api/test_dtls.c b/tests/api/test_dtls.c index 336f89257f..ac90f5b7ec 100644 --- a/tests/api/test_dtls.c +++ b/tests/api/test_dtls.c @@ -32,8 +32,19 @@ #include #include +#include #include +/* Cast used to make send()/recv() buffer arguments portable between + * Windows (char*) and POSIX (void*). Mirrors the private macro in + * tests/api.c so the DTLS plaintext/fragments tests moved out of api.c + * still build here. */ +#ifdef USE_WINDOWS_API + #define MESSAGE_TYPE_CAST char* +#else + #define MESSAGE_TYPE_CAST void* +#endif + int test_dtls12_basic_connection_id(void) { EXPECT_DECLS; @@ -408,165 +419,6 @@ int test_dtls12_basic_connection_id(void) return EXPECT_RESULT(); } -int test_dtls13_basic_connection_id(void) -{ - EXPECT_DECLS; -#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13) \ - && defined(WOLFSSL_DTLS_CID) - unsigned char client_cid[] = { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }; - unsigned char server_cid[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; - unsigned char readBuf[50]; - void * cid = NULL; - const char* params[] = { -#ifndef NO_SHA256 -#ifdef WOLFSSL_AES_128 -#ifdef HAVE_AESGCM - "TLS13-AES128-GCM-SHA256", -#endif -#if defined(HAVE_CHACHA) && defined(HAVE_POLY1305) - "TLS13-CHACHA20-POLY1305-SHA256", -#endif -#ifdef HAVE_AESCCM - "TLS13-AES128-CCM-8-SHA256", - "TLS13-AES128-CCM-SHA256", -#endif -#endif -#ifdef HAVE_NULL_CIPHER - "TLS13-SHA256-SHA256", -#endif -#endif - }; - size_t i; - - /* We check if the side included the CID in their output */ -#define CLIENT_CID() mymemmem(test_ctx.s_buff, test_ctx.s_len, \ - client_cid, sizeof(client_cid)) -#define SERVER_CID() mymemmem(test_ctx.c_buff, test_ctx.c_len, \ - server_cid, sizeof(server_cid)) -#define RESET_CID(cid) if ((cid) != NULL) { \ - ((char*)(cid))[0] = -1; \ - } - - - printf("\n"); - for (i = 0; i < XELEM_CNT(params) && EXPECT_SUCCESS(); i++) { - WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; - WOLFSSL *ssl_c = NULL, *ssl_s = NULL; - struct test_memio_ctx test_ctx; - - printf("Testing %s ... ", params[i]); - - XMEMSET(&test_ctx, 0, sizeof(test_ctx)); - - ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, - wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), 0); - - ExpectIntEQ(wolfSSL_set_cipher_list(ssl_c, params[i]), WOLFSSL_SUCCESS); - ExpectIntEQ(wolfSSL_set_cipher_list(ssl_s, params[i]), WOLFSSL_SUCCESS); - - ExpectIntEQ(wolfSSL_dtls_cid_use(ssl_c), 1); - ExpectIntEQ(wolfSSL_dtls_cid_set(ssl_c, server_cid, sizeof(server_cid)), - 1); - ExpectIntEQ(wolfSSL_dtls_cid_use(ssl_s), 1); - ExpectIntEQ(wolfSSL_dtls_cid_set(ssl_s, client_cid, sizeof(client_cid)), - 1); - - /* CH1 */ - ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); - ExpectNull(CLIENT_CID()); - /* HRR */ - ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); - ExpectNull(SERVER_CID()); - /* CH2 */ - ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); - ExpectNull(CLIENT_CID()); - /* Server first flight */ - ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); - ExpectNotNull(SERVER_CID()); - /* Client second flight */ - ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); - ExpectNotNull(CLIENT_CID()); - /* Server process flight */ - ExpectIntEQ(wolfSSL_negotiate(ssl_s), 1); - /* Client process flight */ - ExpectIntEQ(wolfSSL_negotiate(ssl_c), 1); - - /* Write some data */ - ExpectIntEQ(wolfSSL_write(ssl_c, params[i], (int)XSTRLEN(params[i])), - XSTRLEN(params[i])); - ExpectNotNull(CLIENT_CID()); - ExpectIntEQ(wolfSSL_write(ssl_s, params[i], (int)XSTRLEN(params[i])), - XSTRLEN(params[i])); - ExpectNotNull(SERVER_CID()); - /* Read the data */ - XMEMSET(readBuf, 0, sizeof(readBuf)); - ExpectIntEQ(wolfSSL_read(ssl_c, readBuf, sizeof(readBuf)), - XSTRLEN(params[i])); - ExpectStrEQ(readBuf, params[i]); - XMEMSET(readBuf, 0, sizeof(readBuf)); - ExpectIntEQ(wolfSSL_read(ssl_s, readBuf, sizeof(readBuf)), - XSTRLEN(params[i])); - ExpectStrEQ(readBuf, params[i]); - /* Write short data */ - ExpectIntEQ(wolfSSL_write(ssl_c, params[i], 1), 1); - ExpectNotNull(CLIENT_CID()); - ExpectIntEQ(wolfSSL_write(ssl_s, params[i], 1), 1); - ExpectNotNull(SERVER_CID()); - /* Read the short data */ - XMEMSET(readBuf, 0, sizeof(readBuf)); - ExpectIntEQ(wolfSSL_read(ssl_c, readBuf, sizeof(readBuf)), 1); - ExpectIntEQ(readBuf[0], params[i][0]); - XMEMSET(readBuf, 0, sizeof(readBuf)); - ExpectIntEQ(wolfSSL_read(ssl_s, readBuf, sizeof(readBuf)), 1); - ExpectIntEQ(readBuf[0], params[i][0]); - /* Write some data but with wrong CID */ - ExpectIntEQ(wolfSSL_write(ssl_c, params[i], (int)XSTRLEN(params[i])), - XSTRLEN(params[i])); - /* Reset client cid. */ - ExpectNotNull(cid = CLIENT_CID()); - RESET_CID(cid); - ExpectIntEQ(wolfSSL_write(ssl_s, params[i], (int)XSTRLEN(params[i])), - XSTRLEN(params[i])); - /* Reset server cid. */ - ExpectNotNull(cid = SERVER_CID()); - RESET_CID(cid); - /* Try to read the data but it shouldn't be there */ - ExpectIntEQ(wolfSSL_read(ssl_c, readBuf, sizeof(readBuf)), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); - ExpectIntEQ(wolfSSL_read(ssl_s, readBuf, sizeof(readBuf)), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); - - /* Close connection */ - ExpectIntEQ(wolfSSL_shutdown(ssl_c), WOLFSSL_SHUTDOWN_NOT_DONE); - ExpectNotNull(CLIENT_CID()); - ExpectIntEQ(wolfSSL_shutdown(ssl_s), WOLFSSL_SHUTDOWN_NOT_DONE); - ExpectNotNull(SERVER_CID()); - ExpectIntEQ(wolfSSL_shutdown(ssl_c), 1); - ExpectIntEQ(wolfSSL_shutdown(ssl_s), 1); - - if (EXPECT_SUCCESS()) - printf("ok\n"); - else - printf("failed\n"); - - wolfSSL_free(ssl_c); - wolfSSL_CTX_free(ctx_c); - wolfSSL_free(ssl_s); - wolfSSL_CTX_free(ctx_s); - } - -#undef CLIENT_CID -#undef SERVER_CID -#undef RESET_CID - -#endif - return EXPECT_RESULT(); -} /** Test DTLS 1.3 behavior when server hits WANT_WRITE during HRR * The test sets up a DTLS 1.3 connection where the server is forced to @@ -574,74 +426,7 @@ int test_dtls13_basic_connection_id(void) * application data is exchanged in both directions to verify the connection * works as expected. */ -int test_dtls13_hrr_want_write(void) -{ - EXPECT_DECLS; -#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13) - WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; - WOLFSSL *ssl_c = NULL, *ssl_s = NULL; - const char msg[] = "hello"; - const int msgLen = sizeof(msg); - struct test_memio_ctx test_ctx; - char readBuf[sizeof(msg)]; - - XMEMSET(&test_ctx, 0, sizeof(test_ctx)); - - ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, - wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), - 0); - - /* Client sends first ClientHello */ - ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); - - /* Force server to hit WANT_WRITE when producing the HRR */ - test_memio_simulate_want_write(&test_ctx, 0, 1); - ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_WRITE); - /* Allow the server to flush the HRR and proceed */ - test_memio_simulate_want_write(&test_ctx, 0, 0); - ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); - - /* Resume the DTLS 1.3 handshake */ - ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); - - /* Verify post-handshake application data in both directions */ - XMEMSET(readBuf, 0, sizeof(readBuf)); - ExpectIntEQ(wolfSSL_write(ssl_c, msg, msgLen), msgLen); - ExpectIntEQ(wolfSSL_read(ssl_s, readBuf, sizeof(readBuf)), msgLen); - ExpectStrEQ(readBuf, msg); - - XMEMSET(readBuf, 0, sizeof(readBuf)); - ExpectIntEQ(wolfSSL_write(ssl_s, msg, msgLen), msgLen); - ExpectIntEQ(wolfSSL_read(ssl_c, readBuf, sizeof(readBuf)), msgLen); - ExpectStrEQ(readBuf, msg); - - wolfSSL_free(ssl_c); - wolfSSL_CTX_free(ctx_c); - wolfSSL_free(ssl_s); - wolfSSL_CTX_free(ctx_s); -#endif - return EXPECT_RESULT(); -} - -#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13) -struct test_dtls13_wwrite_ctx { - int want_write; - struct test_memio_ctx *text_ctx; -}; -static int test_dtls13_want_write_send_cb(WOLFSSL *ssl, char *data, int sz, void *ctx) -{ - struct test_dtls13_wwrite_ctx *wwctx = (struct test_dtls13_wwrite_ctx *)ctx; - wwctx->want_write = !wwctx->want_write; - if (wwctx->want_write) { - return WOLFSSL_CBIO_ERR_WANT_WRITE; - } - return test_memio_write_cb(ssl, data, sz, wwctx->text_ctx); -} -#endif /** Test DTLS 1.3 behavior when every other write returns WANT_WRITE * The test sets up a DTLS 1.3 connection where both client and server * alternate between WANT_WRITE and successful writes. After the handshake, @@ -651,82 +436,6 @@ static int test_dtls13_want_write_send_cb(WOLFSSL *ssl, char *data, int sz, void * Data exchanged after the handshake is also tested with simulated WANT_WRITE * conditions to ensure the connection remains functional. */ -int test_dtls13_every_write_want_write(void) -{ - EXPECT_DECLS; -#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13) - WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; - WOLFSSL *ssl_c = NULL, *ssl_s = NULL; - struct test_memio_ctx test_ctx; - const char msg[] = "want-write"; - const int msgLen = sizeof(msg); - char readBuf[sizeof(msg)]; - struct test_dtls13_wwrite_ctx wwctx_c; - struct test_dtls13_wwrite_ctx wwctx_s; - - XMEMSET(&test_ctx, 0, sizeof(test_ctx)); - - ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, - wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), - 0); - - wwctx_c.want_write = 0; - wwctx_c.text_ctx = &test_ctx; - wolfSSL_SetIOWriteCtx(ssl_c, &wwctx_c); - wolfSSL_SSLSetIOSend(ssl_c, test_dtls13_want_write_send_cb); - wwctx_s.want_write = 0; - wwctx_s.text_ctx = &test_ctx; - wolfSSL_SetIOWriteCtx(ssl_s, &wwctx_s); - wolfSSL_SSLSetIOSend(ssl_s, test_dtls13_want_write_send_cb); - - ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 20, NULL), 0); - - ExpectTrue(wolfSSL_is_init_finished(ssl_c)); - ExpectTrue(wolfSSL_is_init_finished(ssl_s)); - - test_memio_simulate_want_write(&test_ctx, 0, 0); - test_memio_simulate_want_write(&test_ctx, 1, 0); - - wolfSSL_SetIOWriteCtx(ssl_c, &test_ctx); - wolfSSL_SSLSetIOSend(ssl_c, test_memio_write_cb); - wolfSSL_SetIOWriteCtx(ssl_s, &test_ctx); - wolfSSL_SSLSetIOSend(ssl_s, test_memio_write_cb); - - XMEMSET(readBuf, 0, sizeof(readBuf)); - ExpectIntEQ(wolfSSL_write(ssl_c, msg, msgLen), msgLen); - ExpectIntEQ(wolfSSL_read(ssl_s, readBuf, sizeof(readBuf)), msgLen); - ExpectStrEQ(readBuf, msg); - - XMEMSET(readBuf, 0, sizeof(readBuf)); - ExpectIntEQ(wolfSSL_write(ssl_s, msg, msgLen), msgLen); - ExpectIntEQ(wolfSSL_read(ssl_c, readBuf, sizeof(readBuf)), msgLen); - ExpectStrEQ(readBuf, msg); - - test_memio_simulate_want_write(&test_ctx, 0, 1); - XMEMSET(readBuf, 0, sizeof(readBuf)); - ExpectIntEQ(wolfSSL_write(ssl_s, msg, msgLen), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_WRITE); - test_memio_simulate_want_write(&test_ctx, 0, 0); - ExpectIntEQ(wolfSSL_write(ssl_s, msg, msgLen), msgLen); - ExpectIntEQ(wolfSSL_read(ssl_c, readBuf, sizeof(readBuf)), msgLen); - ExpectStrEQ(readBuf, msg); - - XMEMSET(readBuf, 0, sizeof(readBuf)); - test_memio_simulate_want_write(&test_ctx, 1, 1); - ExpectIntEQ(wolfSSL_write(ssl_c, msg, msgLen), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_WRITE); - test_memio_simulate_want_write(&test_ctx, 1, 0); - ExpectIntEQ(wolfSSL_write(ssl_c, msg, msgLen), msgLen); - ExpectIntEQ(wolfSSL_read(ssl_s, readBuf, sizeof(readBuf)), msgLen); - ExpectStrEQ(readBuf, msg); - - wolfSSL_free(ssl_c); - wolfSSL_CTX_free(ctx_c); - wolfSSL_free(ssl_s); - wolfSSL_CTX_free(ctx_s); -#endif - return EXPECT_RESULT(); -} int test_wolfSSL_dtls_cid_parse(void) { @@ -809,253 +518,9 @@ int test_wolfSSL_dtls_set_pending_peer(void) return EXPECT_RESULT(); } -int test_dtls13_epochs(void) { - EXPECT_DECLS; -#if defined(WOLFSSL_DTLS13) && !defined(NO_WOLFSSL_CLIENT) - WOLFSSL_CTX* ctx = NULL; - WOLFSSL* ssl = NULL; - byte input[20]; - word32 inOutIdx = 0; - - XMEMSET(input, 0, sizeof(input)); - - ExpectNotNull(ctx = wolfSSL_CTX_new(wolfDTLSv1_3_client_method())); - ExpectNotNull(ssl = wolfSSL_new(ctx)); - /* Some manual setup to enter the epoch check */ - ExpectTrue(ssl->options.tls1_3 = 1); - - inOutIdx = 0; - if (ssl != NULL) ssl->keys.curEpoch64 = w64From32(0x0, 0x0); - ExpectIntEQ(DoApplicationData(ssl, input, &inOutIdx, 0), SANITY_MSG_E); - inOutIdx = 0; - if (ssl != NULL) ssl->keys.curEpoch64 = w64From32(0x0, 0x2); - ExpectIntEQ(DoApplicationData(ssl, input, &inOutIdx, 0), SANITY_MSG_E); - - if (ssl != NULL) ssl->keys.curEpoch64 = w64From32(0x0, 0x1); - ExpectIntEQ(Dtls13CheckEpoch(ssl, client_hello), SANITY_MSG_E); - ExpectIntEQ(Dtls13CheckEpoch(ssl, server_hello), SANITY_MSG_E); - ExpectIntEQ(Dtls13CheckEpoch(ssl, hello_verify_request), SANITY_MSG_E); - ExpectIntEQ(Dtls13CheckEpoch(ssl, hello_retry_request), SANITY_MSG_E); - ExpectIntEQ(Dtls13CheckEpoch(ssl, hello_request), SANITY_MSG_E); - ExpectIntEQ(Dtls13CheckEpoch(ssl, encrypted_extensions), SANITY_MSG_E); - ExpectIntEQ(Dtls13CheckEpoch(ssl, server_key_exchange), SANITY_MSG_E); - ExpectIntEQ(Dtls13CheckEpoch(ssl, server_hello_done), SANITY_MSG_E); - ExpectIntEQ(Dtls13CheckEpoch(ssl, client_key_exchange), SANITY_MSG_E); - ExpectIntEQ(Dtls13CheckEpoch(ssl, certificate_request), SANITY_MSG_E); - ExpectIntEQ(Dtls13CheckEpoch(ssl, certificate), SANITY_MSG_E); - ExpectIntEQ(Dtls13CheckEpoch(ssl, certificate_verify), SANITY_MSG_E); - ExpectIntEQ(Dtls13CheckEpoch(ssl, finished), SANITY_MSG_E); - ExpectIntEQ(Dtls13CheckEpoch(ssl, certificate_status), SANITY_MSG_E); - ExpectIntEQ(Dtls13CheckEpoch(ssl, change_cipher_hs), SANITY_MSG_E); - ExpectIntEQ(Dtls13CheckEpoch(ssl, key_update), SANITY_MSG_E); - ExpectIntEQ(Dtls13CheckEpoch(ssl, session_ticket), SANITY_MSG_E); - ExpectIntEQ(Dtls13CheckEpoch(ssl, end_of_early_data), SANITY_MSG_E); - ExpectIntEQ(Dtls13CheckEpoch(ssl, message_hash), SANITY_MSG_E); - ExpectIntEQ(Dtls13CheckEpoch(ssl, no_shake), SANITY_MSG_E); - - wolfSSL_CTX_free(ctx); - wolfSSL_free(ssl); -#endif - return EXPECT_RESULT(); -} - -int test_dtls13_ack_order(void) -{ - EXPECT_DECLS; -#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13) - WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; - WOLFSSL *ssl_c = NULL, *ssl_s = NULL; - struct test_memio_ctx test_ctx; - unsigned char readBuf[50]; - word32 length = 0; - /* struct { - * uint64 epoch; - * uint64 sequence_number; - * } RecordNumber; - * Big endian */ - static const unsigned char expected_output[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, - }; - - XMEMSET(&test_ctx, 0, sizeof(test_ctx)); - - /* Get a populated DTLS object */ - ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, - wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), 0); - ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); - ExpectIntEQ(wolfSSL_read(ssl_c, readBuf, sizeof(readBuf)), -1); - /* Clear the buffer of any extra messages */ - ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); - ExpectIntEQ(wolfSSL_read(ssl_s, readBuf, sizeof(readBuf)), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); - ExpectIntEQ(test_ctx.c_len, 0); - ExpectIntEQ(test_ctx.s_len, 0); - - /* Add seen records */ - ExpectIntEQ(Dtls13RtxAddAck(ssl_c, w64From32(0, 3), w64From32(0, 2)), 0); - ExpectIntEQ(Dtls13RtxAddAck(ssl_c, w64From32(0, 3), w64From32(0, 0)), 0); - ExpectIntEQ(Dtls13RtxAddAck(ssl_c, w64From32(0, 3), w64From32(0, 1)), 0); - ExpectIntEQ(Dtls13RtxAddAck(ssl_c, w64From32(0, 3), w64From32(0, 4)), 0); - ExpectIntEQ(Dtls13RtxAddAck(ssl_c, w64From32(0, 2), w64From32(0, 0)), 0); - ExpectIntEQ(Dtls13RtxAddAck(ssl_c, w64From32(0, 3), w64From32(0, 6)), 0); - ExpectIntEQ(Dtls13RtxAddAck(ssl_c, w64From32(0, 3), w64From32(0, 6)), 0); - ExpectIntEQ(Dtls13RtxAddAck(ssl_c, w64From32(0, 2), w64From32(0, 1)), 0); - ExpectIntEQ(Dtls13RtxAddAck(ssl_c, w64From32(0, 2), w64From32(0, 2)), 0); - ExpectIntEQ(Dtls13RtxAddAck(ssl_c, w64From32(0, 2), w64From32(0, 2)), 0); - ExpectIntEQ(Dtls13WriteAckMessage(ssl_c, ssl_c->dtls13Rtx.seenRecords, - ssl_c->dtls13Rtx.seenRecordsCount, &length), 0); - - /* must zero the span reserved for the header to avoid read of uninited - * data. - */ - XMEMSET(ssl_c->buffers.outputBuffer.buffer, 0, - 5 /* DTLS13_UNIFIED_HEADER_SIZE */); - /* N * RecordNumber + 2 extra bytes for length */ - ExpectIntEQ(length, sizeof(expected_output) + 2); - ExpectNotNull(mymemmem(ssl_c->buffers.outputBuffer.buffer, - ssl_c->buffers.outputBuffer.bufferSize, expected_output, - sizeof(expected_output))); - - wolfSSL_free(ssl_c); - wolfSSL_CTX_free(ctx_c); - wolfSSL_free(ssl_s); - wolfSSL_CTX_free(ctx_s); -#endif - return EXPECT_RESULT(); -} - -int test_dtls13_ack_overflow(void) -{ - EXPECT_DECLS; -#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13) - WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; - WOLFSSL *ssl_c = NULL, *ssl_s = NULL; - struct test_memio_ctx test_ctx; - unsigned char readBuf[50]; - word32 length = 0; - int i; - - XMEMSET(&test_ctx, 0, sizeof(test_ctx)); - - ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, - wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), 0); - ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); - ExpectIntEQ(wolfSSL_read(ssl_c, readBuf, sizeof(readBuf)), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); - ExpectIntEQ(wolfSSL_read(ssl_s, readBuf, sizeof(readBuf)), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); - - /* Edge case 1: one below limit - all inserts must succeed */ - for (i = 0; i < DTLS13_ACK_MAX_RECORDS - 1; i++) { - ExpectIntEQ(Dtls13RtxAddAck(ssl_c, w64From32(0, 0), - w64From32(0, (word32)i)), 0); - } - ExpectIntEQ(ssl_c->dtls13Rtx.seenRecordsCount, DTLS13_ACK_MAX_RECORDS - 1); - - /* Edge case 2: insert the last allowed record - must succeed */ - ExpectIntEQ(Dtls13RtxAddAck(ssl_c, w64From32(0, 0), - w64From32(0, (word32)(DTLS13_ACK_MAX_RECORDS - 1))), 0); - ExpectIntEQ(ssl_c->dtls13Rtx.seenRecordsCount, DTLS13_ACK_MAX_RECORDS); - - /* Writing a full-but-valid list must succeed */ - ExpectIntEQ(Dtls13WriteAckMessage(ssl_c, ssl_c->dtls13Rtx.seenRecords, - ssl_c->dtls13Rtx.seenRecordsCount, &length), 0); - - /* Edge case 3: one over limit - must be silently dropped */ - ExpectIntEQ(Dtls13RtxAddAck(ssl_c, w64From32(0, 0), - w64From32(0, (word32)DTLS13_ACK_MAX_RECORDS)), 0); - ExpectIntEQ(ssl_c->dtls13Rtx.seenRecordsCount, DTLS13_ACK_MAX_RECORDS); - - /* Bypass the insert guard to force the list one element over the limit, - * then verify Dtls13WriteAckMessage errors out instead of overflowing */ - ssl_c->dtls13Rtx.seenRecordsCount = 0; - ExpectIntEQ(Dtls13RtxAddAck(ssl_c, w64From32(0, 1), - w64From32(0, (word32)DTLS13_ACK_MAX_RECORDS)), 0); - ssl_c->dtls13Rtx.seenRecordsCount = (word16)(DTLS13_ACK_MAX_RECORDS + 1); - ExpectIntEQ(Dtls13WriteAckMessage(ssl_c, ssl_c->dtls13Rtx.seenRecords, - ssl_c->dtls13Rtx.seenRecordsCount, &length), BUFFER_E); - - wolfSSL_free(ssl_c); - wolfSSL_CTX_free(ctx_c); - wolfSSL_free(ssl_s); - wolfSSL_CTX_free(ctx_s); -#endif - return EXPECT_RESULT(); -} - -int test_dtls13_ack_dup_write_counter(void) -{ - EXPECT_DECLS; -#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13) \ - && defined(HAVE_WRITE_DUP) - WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; - WOLFSSL *ssl_c = NULL, *ssl_s = NULL; - WOLFSSL *ssl_c2 = NULL; - struct test_memio_ctx test_ctx; - unsigned char readBuf[50]; - int i; - - XMEMSET(&test_ctx, 0, sizeof(test_ctx)); - ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, - wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), 0); - ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); - /* Drain any post-handshake messages */ - ExpectIntEQ(wolfSSL_read(ssl_c, readBuf, sizeof(readBuf)), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); - ExpectIntEQ(wolfSSL_read(ssl_s, readBuf, sizeof(readBuf)), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); - /* Split ssl_c: ssl_c becomes READ_DUP_SIDE, ssl_c2 becomes WRITE_DUP_SIDE */ - ExpectNotNull(ssl_c2 = wolfSSL_write_dup(ssl_c)); - - /* Cycle 1: add records, trigger handoff, verify counter is reset to 0 */ - for (i = 0; i < 5; i++) - ExpectIntEQ(Dtls13RtxAddAck(ssl_c, w64From32(0, 3), - w64From32(0, (word32)i)), 0); - ExpectIntEQ(ssl_c->dtls13Rtx.seenRecordsCount, 5); - ssl_c->dtls13Rtx.sendAcks = 1; - ExpectIntEQ(Dtls13DoScheduledWork(ssl_c), 0); - /* seenRecords ownership was transferred to dupWrite->sendAckList; - * seenRecordsCount must be reset to 0, not left at 5. */ - ExpectNull(ssl_c->dtls13Rtx.seenRecords); - ExpectIntEQ(ssl_c->dtls13Rtx.seenRecordsCount, 0); - - /* Cycle 2 (different epoch to avoid the dup-filter): verify the counter - * did not accumulate across the previous transfer. Without the fix, - * seenRecordsCount would now be 10 after this second batch. */ - for (i = 0; i < 5; i++) - ExpectIntEQ(Dtls13RtxAddAck(ssl_c, w64From32(0, 4), - w64From32(0, (word32)i)), 0); - ExpectIntEQ(ssl_c->dtls13Rtx.seenRecordsCount, 5); - ssl_c->dtls13Rtx.sendAcks = 1; - ExpectIntEQ(Dtls13DoScheduledWork(ssl_c), 0); - ExpectNull(ssl_c->dtls13Rtx.seenRecords); - ExpectIntEQ(ssl_c->dtls13Rtx.seenRecordsCount, 0); - wolfSSL_free(ssl_c); - wolfSSL_free(ssl_c2); - wolfSSL_CTX_free(ctx_c); - wolfSSL_free(ssl_s); - wolfSSL_CTX_free(ctx_s); -#endif - return EXPECT_RESULT(); -} int test_dtls_version_checking(void) { @@ -1836,225 +1301,8 @@ int test_dtls_rtx_across_epoch_change(void) return EXPECT_RESULT(); } -#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \ - defined(WOLFSSL_DTLS13) && defined(WOLFSSL_DTLS) -static int test_dtls13_get_message_seq(const char* msg, int msgSz, - word16* msgSeq) -{ - int hsOff = DTLS_RECORD_HEADER_SZ; - if (msg == NULL || msgSeq == NULL || - msgSz < DTLS_RECORD_HEADER_SZ + DTLS_HANDSHAKE_HEADER_SZ) { - return BAD_FUNC_ARG; - } - *msgSeq = ((word16)(byte)msg[hsOff + 4] << 8) | - (word16)(byte)msg[hsOff + 5]; - - return WOLFSSL_SUCCESS; -} -#endif - -int test_dtls13_ch2_rtx_no_ch1(void) -{ - EXPECT_DECLS; -#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \ - defined(WOLFSSL_DTLS13) && defined(WOLFSSL_DTLS) - WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; - WOLFSSL *ssl_c = NULL, *ssl_s = NULL; - struct test_memio_ctx test_ctx; - const char* msg = NULL; - int msgSz = 0; - word16 ch1Seq = 0; - int i; - int foundCh1Seq = 0; - - XMEMSET(&test_ctx, 0, sizeof(test_ctx)); - - ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, - wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), - 0); - - /* To force HRR */ - ExpectIntEQ(wolfSSL_NoKeyShares(ssl_c), WOLFSSL_SUCCESS); - - /* CH1 */ - ExpectIntEQ(wolfSSL_connect(ssl_c), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); - ExpectIntEQ(test_memio_get_message(&test_ctx, 0, &msg, &msgSz, 0), 0); - ExpectIntGE(msgSz, DTLS_RECORD_HEADER_SZ + DTLS_HANDSHAKE_HEADER_SZ); - ExpectIntEQ(test_dtls13_get_message_seq(msg, msgSz, &ch1Seq), - WOLFSSL_SUCCESS); - - /* HRR */ - ExpectIntEQ(wolfSSL_accept(ssl_s), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); - ExpectIntGT(test_ctx.c_msg_count, 0); - - /* CH2 */ - ExpectIntEQ(wolfSSL_connect(ssl_c), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); - ExpectIntGT(test_ctx.s_msg_count, 0); - - /* Drop CH2 and trigger the client retransmission timeout. */ - test_memio_clear_buffer(&test_ctx, 0); - if (wolfSSL_dtls13_use_quick_timeout(ssl_c)) - ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl_c), WOLFSSL_SUCCESS); - ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl_c), WOLFSSL_SUCCESS); - ExpectIntGT(test_ctx.s_msg_count, 0); - - for (i = 0; i < test_ctx.s_msg_count && EXPECT_SUCCESS(); i++) { - int hsOff = DTLS_RECORD_HEADER_SZ; - word16 msgSeq = 0; - - ExpectIntEQ(test_memio_get_message(&test_ctx, 0, &msg, &msgSz, i), 0); - /* memio stores one DTLS record per message in this handshake path. */ - if (msgSz >= DTLS_RECORD_HEADER_SZ + DTLS_HANDSHAKE_HEADER_SZ && - (byte)msg[0] == handshake && msg[hsOff] == client_hello) { - ExpectIntEQ(test_dtls13_get_message_seq(msg, msgSz, &msgSeq), - WOLFSSL_SUCCESS); - if (msgSeq == ch1Seq) - foundCh1Seq = 1; - } - } - - ExpectIntEQ(foundCh1Seq, 0); - - wolfSSL_free(ssl_c); - wolfSSL_CTX_free(ctx_c); - wolfSSL_free(ssl_s); - wolfSSL_CTX_free(ctx_s); -#endif - return EXPECT_RESULT(); -} - -int test_dtls13_frag_ch2_with_ch1_rtx(void) -{ - EXPECT_DECLS; -#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \ - defined(WOLFSSL_DTLS13) && defined(WOLFSSL_DTLS) && \ - defined(WOLFSSL_DTLS_MTU) && defined(WOLFSSL_DTLS_CH_FRAG) && \ - (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) - WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; - WOLFSSL *ssl_c = NULL, *ssl_s = NULL; - struct test_memio_ctx test_ctx; - char hrr[TEST_MEMIO_BUF_SZ]; - int hrrSz = (int)sizeof(hrr); - char ch1Rtx[TEST_MEMIO_BUF_SZ]; - int ch1RtxSz = (int)sizeof(ch1Rtx); - char ch2[TEST_MEMIO_BUF_SZ]; - int ch2Sz = 0; - int ch2MsgCount = 0; - int ch2MsgSizes[TEST_MEMIO_MAX_MSGS] = {0}; - /* The DTLS record sequence number occupies the last 8 bytes of the - * record header. */ - int recordSeqOff = DTLS_RECORD_HEADER_SZ - 8; - int ch2Seq = 0; - int ch1RtxSeq = 0; - int off; - int i; - - XMEMSET(&test_ctx, 0, sizeof(test_ctx)); - - ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, - wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), - 0); - - /* To force HRR */ - ExpectIntEQ(wolfSSL_NoKeyShares(ssl_c), WOLFSSL_SUCCESS); - ExpectIntEQ(wolfSSL_dtls13_allow_ch_frag(ssl_s, 1), WOLFSSL_SUCCESS); - - /* CH1 */ - ExpectIntEQ(wolfSSL_connect(ssl_c), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); - - /* HRR */ - ExpectIntEQ(wolfSSL_accept(ssl_s), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); - ExpectIntEQ(test_memio_copy_message(&test_ctx, 1, hrr, &hrrSz, 0), 0); - - /* Drop HRR, trigger CH1 retransmission, copy and drop it */ - test_memio_clear_buffer(&test_ctx, 1); - if (wolfSSL_dtls13_use_quick_timeout(ssl_c)) - ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl_c), WOLFSSL_SUCCESS); - ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl_c), WOLFSSL_SUCCESS); - ExpectIntEQ(test_memio_copy_message(&test_ctx, 0, ch1Rtx, &ch1RtxSz, 0), 0); - test_memio_clear_buffer(&test_ctx, 0); - - /* Force CH2 fragmentation. MTU must be small enough to fragment but large - * enough that the cookie extension lands in the first fragment, otherwise - * the server can't validate it statelessly and the test scenario (server - * stateful after frag 1) does not hold. With --enable-all (PQ groups in - * supported_groups), the cookie extension can sit ~400 bytes into CH2; 600 - * gives margin while still producing multiple fragments (CH2 is ~2KB). */ - ExpectIntEQ(wolfSSL_dtls_set_mtu(ssl_c, 600), WOLFSSL_SUCCESS); - - /* Forward HRR and let the client create fragmented CH2 */ - ExpectIntEQ(test_memio_inject_message(&test_ctx, 1, hrr, hrrSz), 0); - ExpectIntEQ(wolfSSL_connect(ssl_c), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); - - ExpectIntGT(test_ctx.s_msg_count, 1); - ExpectIntLE(test_ctx.s_msg_count, TEST_MEMIO_MAX_MSGS); - ExpectIntLE(test_ctx.s_len, (int)sizeof(ch2)); - if (EXPECT_SUCCESS()) { - ch2Sz = test_ctx.s_len; - ch2MsgCount = test_ctx.s_msg_count; - XMEMCPY(ch2, test_ctx.s_buff, ch2Sz); - XMEMCPY(ch2MsgSizes, test_ctx.s_msg_sizes, - sizeof(ch2MsgSizes[0]) * (size_t)ch2MsgCount); - - ch2Seq = ((byte)ch2[recordSeqOff + 4] << 8) | - (byte)ch2[recordSeqOff + 5]; - ch1RtxSeq = ch2Seq + ch2MsgCount; - - /* Synthesize a CH1 retransmission that can pass the replay window after - * the first CH2 fragment makes the server stateful. The handshake - * message_seq remains the original CH1 value; only the DTLS record - * sequence is moved past the fragmented CH2 flight */ - ch1Rtx[recordSeqOff + 0] = 0; - ch1Rtx[recordSeqOff + 1] = 0; - ch1Rtx[recordSeqOff + 2] = 0; - ch1Rtx[recordSeqOff + 3] = 0; - ch1Rtx[recordSeqOff + 4] = (byte)(ch1RtxSeq >> 8); - ch1Rtx[recordSeqOff + 5] = (byte)ch1RtxSeq; - } - - test_memio_clear_buffer(&test_ctx, 0); - - /* Deliver CH2 first fragment only. Now server is stateful */ - ExpectIntEQ(test_memio_inject_message(&test_ctx, 0, ch2, ch2MsgSizes[0]), 0); - ExpectIntEQ(wolfSSL_accept(ssl_s), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); - - /* Deliver the retransmitted CH1 between CH2 fragments, it should be - * discarded as rtx */ - ExpectIntEQ(test_memio_inject_message(&test_ctx, 0, ch1Rtx, ch1RtxSz), 0); - ExpectIntEQ(wolfSSL_accept(ssl_s), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); - test_memio_clear_buffer(&test_ctx, 1); - - /* Deliver the rest of CH2 */ - off = ch2MsgSizes[0]; - for (i = 1; i < ch2MsgCount && EXPECT_SUCCESS(); i++) { - ExpectIntEQ(test_memio_inject_message(&test_ctx, 0, ch2 + off, - ch2MsgSizes[i]), 0); - off += ch2MsgSizes[i]; - } - - /* Restore MTU so the client's input buffer can hold the full server - * flight (e.g. an SH carrying a hybrid PQC key share). */ - ExpectIntEQ(wolfSSL_dtls_set_mtu(ssl_c, 1500), WOLFSSL_SUCCESS); - - ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); - - wolfSSL_free(ssl_c); - wolfSSL_CTX_free(ctx_c); - wolfSSL_free(ssl_s); - wolfSSL_CTX_free(ctx_s); -#endif - return EXPECT_RESULT(); -} int test_dtls_drop_client_ack(void) { @@ -2262,43 +1510,6 @@ int test_dtls_replay(void) return EXPECT_RESULT(); } -#if defined(WOLFSSL_DTLS13) && defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES) && \ - defined(WOLFSSL_SRTP) -static int test_dtls_srtp_ctx_ready(WOLFSSL_CTX* ctx) -{ - EXPECT_DECLS; - ExpectIntEQ(wolfSSL_CTX_set_tlsext_use_srtp(ctx, "SRTP_AEAD_AES_256_GCM:" - "SRTP_AEAD_AES_128_GCM:SRTP_AES128_CM_SHA1_80:SRTP_AES128_CM_SHA1_32"), - 0); - return EXPECT_RESULT(); -} - -int test_dtls_srtp(void) -{ - EXPECT_DECLS; - test_ssl_cbf client_cbf; - test_ssl_cbf server_cbf; - - XMEMSET(&client_cbf, 0, sizeof(client_cbf)); - XMEMSET(&server_cbf, 0, sizeof(server_cbf)); - - client_cbf.method = wolfDTLSv1_3_client_method; - client_cbf.ctx_ready = test_dtls_srtp_ctx_ready; - server_cbf.method = wolfDTLSv1_3_server_method; - server_cbf.ctx_ready = test_dtls_srtp_ctx_ready; - - ExpectIntEQ(test_wolfSSL_client_server_nofail_memio(&client_cbf, - &server_cbf, NULL), TEST_SUCCESS); - - return EXPECT_RESULT(); -} -#else -int test_dtls_srtp(void) -{ - EXPECT_DECLS; - return EXPECT_RESULT(); -} -#endif int test_dtls_timeout(void) { @@ -2876,152 +2087,50 @@ int test_dtls_mtu_split_messages(void) * This tests relies on timing of the retransmission logic so it may be * flaky on very slow systems. */ -int test_dtls13_min_rtx_interval(void) -{ - EXPECT_DECLS; -#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \ - defined(WOLFSSL_DTLS13) && !defined(DTLS13_MIN_RTX_INTERVAL) && \ - !defined(NO_ASN_TIME) - /* We don't want to test when DTLS13_MIN_RTX_INTERVAL is defined because - * it may be too low to trigger reliably in a test. The default value is - * 1 second which is sufficient for testing here. */ - WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; - WOLFSSL *ssl_c = NULL, *ssl_s = NULL; - struct test_memio_ctx test_ctx; - int c_msg_count = 0; - - XMEMSET(&test_ctx, 0, sizeof(test_ctx)); - - /* Setup DTLS 1.3 contexts */ - ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, - wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), 0); - - /* CH0 */ - ExpectIntEQ(wolfSSL_connect(ssl_c), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), SSL_ERROR_WANT_READ); - - /* HRR */ - ExpectIntEQ(wolfSSL_accept(ssl_s), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), SSL_ERROR_WANT_READ); - - /* CH1 */ - ExpectIntEQ(wolfSSL_connect(ssl_c), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), SSL_ERROR_WANT_READ); - - /* SH ... FINISHED */ - ExpectIntEQ(wolfSSL_accept(ssl_s), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), SSL_ERROR_WANT_READ); - - /* We should have SH ... FINISHED messages in the buffer */ - ExpectIntGE(test_ctx.c_msg_count, 2); - - /* Drop everything */ - test_memio_clear_buffer(&test_ctx, 1); - - /* First timeout. This one should trigger a retransmission */ - if (wolfSSL_dtls13_use_quick_timeout(ssl_s)) - ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl_s), WOLFSSL_SUCCESS); - ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl_s), WOLFSSL_SUCCESS); - /* Save the message count to make sure no new messages are sent */ - ExpectIntGE(test_ctx.c_msg_count, 2); - c_msg_count = test_ctx.c_msg_count; - - /* Second timeout. This one should not trigger a retransmission */ - if (wolfSSL_dtls13_use_quick_timeout(ssl_s)) - ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl_s), WOLFSSL_SUCCESS); - ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl_s), WOLFSSL_SUCCESS); - /* This is the critical check. The message count should not increase - * after the second timeout. DTLS13_MIN_RTX_INTERVAL should have blocked - * retransmission here. */ - ExpectIntEQ(c_msg_count, test_ctx.c_msg_count); - - /* Now complete the handshake. We didn't clear the first retransmission - * so the handshake should proceed without issues. */ - ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); - - /* Cleanup */ - wolfSSL_free(ssl_c); - wolfSSL_CTX_free(ctx_c); - wolfSSL_free(ssl_s); - wolfSSL_CTX_free(ctx_s); -#endif - return EXPECT_RESULT(); -} /* RFC 9147 Section 5.3: DTLS 1.3 ServerHello must have empty * legacy_session_id_echo, even if the ClientHello had a non-empty * legacy_session_id. */ -int test_dtls13_no_session_id_echo(void) + +/* Test that a server built with WOLFSSL_DTLS13_ECHO_LEGACY_SESSION_ID echoes the + * client's legacy_session_id in both the direct ServerHello path and the + * stateless HRR path (which also exercises RestartHandshakeHashWithCookie). */ + +/* Test that a DTLS 1.3 handshake with an oversized certificate chain does + * not crash or cause out-of-bounds access in SendTls13Certificate. */ + +/* DTLS counterpart to test_tls_set_session_min_downgrade. Exercises the + * inverted DTLS minor-version comparison (DTLS 1.2 minor 0xFD is "below" + * floor 0xFC = DTLS 1.3). */ +int test_dtls_set_session_min_downgrade(void) { EXPECT_DECLS; -#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13) && \ - defined(HAVE_SESSION_TICKET) && defined(HAVE_ECC) && \ - !defined(WOLFSSL_DTLS13_ECHO_LEGACY_SESSION_ID) - struct test_memio_ctx test_ctx; +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS) && \ + defined(WOLFSSL_DTLS13) && defined(HAVE_SESSION_TICKET) WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; WOLFSSL *ssl_c = NULL, *ssl_s = NULL; WOLFSSL_SESSION *sess = NULL; - char readBuf[1]; - /* Pin to SECP256R1 to avoid a PQ-induced key-share HRR */ - int groups[] = { WOLFSSL_ECC_SECP256R1 }; + struct test_memio_ctx test_ctx; - /* First connection: complete a DTLS 1.3 handshake to get a session */ XMEMSET(&test_ctx, 0, sizeof(test_ctx)); ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, - wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), 0); - ExpectIntEQ(wolfSSL_set_groups(ssl_c, groups, 1), WOLFSSL_SUCCESS); + wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method), 0); ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); - - /* Read to process any NewSessionTicket */ - ExpectIntEQ(wolfSSL_read(ssl_c, readBuf, sizeof(readBuf)), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); - ExpectNotNull(sess = wolfSSL_get1_session(ssl_c)); - /* Ensure the session has a non-empty session ID so the ClientHello - * will have a populated legacy_session_id field (which is legal per - * RFC 9147). */ - if (sess != NULL && sess->sessionIDSz == 0) { - sess->sessionIDSz = ID_LEN; - XMEMSET(sess->sessionID, 0x42, ID_LEN); - } - wolfSSL_free(ssl_c); ssl_c = NULL; wolfSSL_free(ssl_s); ssl_s = NULL; wolfSSL_CTX_free(ctx_c); ctx_c = NULL; wolfSSL_CTX_free(ctx_s); ctx_s = NULL; - /* Second connection: set the session on the client so the ClientHello - * contains a non-empty legacy_session_id. Verify the server does NOT - * echo it in the ServerHello. */ XMEMSET(&test_ctx, 0, sizeof(test_ctx)); ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, - wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), 0); - ExpectIntEQ(wolfSSL_set_session(ssl_c, sess), WOLFSSL_SUCCESS); - ExpectIntEQ(wolfSSL_set_groups(ssl_c, groups, 1), WOLFSSL_SUCCESS); - /* Disable HRR cookie so the server directly sends a ServerHello */ - ExpectIntEQ(wolfSSL_disable_hrr_cookie(ssl_s), WOLFSSL_SUCCESS); - - /* Client sends ClientHello (with non-empty legacy_session_id) */ - ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); - - /* Server processes ClientHello and sends ServerHello + flight */ - ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); - - /* Verify the ServerHello on the wire. - * Layout: DTLS Record Header (13) + DTLS Handshake Header (12) + - * ProtocolVersion (2) + Random (32) = offset 59 for - * legacy_session_id_echo length byte. */ - ExpectIntGE(test_ctx.c_len, 60); - ExpectIntEQ(test_ctx.c_buff[0], handshake); - ExpectIntEQ(test_ctx.c_buff[DTLS_RECORD_HEADER_SZ], server_hello); - ExpectIntEQ(test_ctx.c_buff[DTLS_RECORD_HEADER_SZ + - DTLS_HANDSHAKE_HEADER_SZ + OPAQUE16_LEN + RAN_LEN], 0); - - /* Complete the handshake */ - ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + wolfDTLS_client_method, wolfDTLS_server_method), 0); + ExpectIntEQ(wolfSSL_SetMinVersion(ssl_c, WOLFSSL_DTLSV1_3), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_set_session(ssl_c, sess), WOLFSSL_FAILURE); + if (ssl_c != NULL) + ExpectIntEQ(ssl_c->options.resuming, 0); wolfSSL_SESSION_free(sess); wolfSSL_free(ssl_c); @@ -3032,261 +2141,3198 @@ int test_dtls13_no_session_id_echo(void) return EXPECT_RESULT(); } -/* Test that a server built with WOLFSSL_DTLS13_ECHO_LEGACY_SESSION_ID echoes the - * client's legacy_session_id in both the direct ServerHello path and the - * stateless HRR path (which also exercises RestartHandshakeHashWithCookie). */ -int test_dtls13_5_9_0_compat(void) +/*----------------------------------------------------------------------------*/ +/* DTLS session export / import */ +/*----------------------------------------------------------------------------*/ + +#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_SESSION_EXPORT) +/* canned export of a session using older version 3 */ +static unsigned char version_3[] = { + 0xA5, 0xA3, 0x01, 0x88, 0x00, 0x3c, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x80, 0x0C, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x30, + 0x05, 0x09, 0x0A, 0x01, 0x01, 0x00, 0x0D, 0x05, + 0xFE, 0xFD, 0x01, 0x25, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x06, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x06, 0x00, 0x01, 0x00, 0x07, 0x00, 0x00, + 0x00, 0x30, 0x00, 0x00, 0x00, 0x10, 0x01, 0x01, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x3F, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x05, + 0x12, 0xCF, 0x22, 0xA1, 0x9F, 0x1C, 0x39, 0x1D, + 0x31, 0x11, 0x12, 0x1D, 0x11, 0x18, 0x0D, 0x0B, + 0xF3, 0xE1, 0x4D, 0xDC, 0xB1, 0xF1, 0x39, 0x98, + 0x91, 0x6C, 0x48, 0xE5, 0xED, 0x11, 0x12, 0xA0, + 0x00, 0xF2, 0x25, 0x4C, 0x09, 0x26, 0xD1, 0x74, + 0xDF, 0x23, 0x40, 0x15, 0x6A, 0x42, 0x2A, 0x26, + 0xA5, 0xAC, 0x56, 0xD5, 0x4A, 0x20, 0xB7, 0xE9, + 0xEF, 0xEB, 0xAF, 0xA8, 0x1E, 0x23, 0x7C, 0x04, + 0xAA, 0xA1, 0x6D, 0x92, 0x79, 0x7B, 0xFA, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x0C, 0x79, 0x7B, 0xFA, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xA1, 0x6D, + 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x00, 0x20, 0x00, 0x04, 0x00, + 0x10, 0x00, 0x10, 0x08, 0x02, 0x05, 0x08, 0x01, + 0x30, 0x28, 0x00, 0x00, 0x0F, 0x00, 0x02, 0x00, + 0x09, 0x31, 0x32, 0x37, 0x2E, 0x30, 0x2E, 0x30, + 0x2E, 0x31, 0xED, 0x4F +}; +#endif /* defined(WOLFSSL_DTLS) && defined(WOLFSSL_SESSION_EXPORT) */ + +int test_wolfSSL_dtls_export(void) { EXPECT_DECLS; -#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13) && \ - defined(HAVE_SESSION_TICKET) && defined(WOLFSSL_DTLS13_ECHO_LEGACY_SESSION_ID) && \ - defined(HAVE_ECC) - struct test_memio_ctx test_ctx; - WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; - WOLFSSL *ssl_c = NULL, *ssl_s = NULL; - WOLFSSL_SESSION *sess = NULL; - char readBuf[1]; - /* Pin to SECP256R1 to avoid a PQ-induced key-share HRR */ - int groups[] = { WOLFSSL_ECC_SECP256R1 }; - /* RFC 8446 Section 4.1.3: an HRR is a ServerHello carrying this magic - * random. Used to assert sub-test 1 is a real ServerHello, not an HRR. */ - static const byte hrrRandom[RAN_LEN] = { - 0xCF, 0x21, 0xAD, 0x74, 0xE5, 0x9A, 0x61, 0x11, - 0xBE, 0x1D, 0x8C, 0x02, 0x1E, 0x65, 0xB8, 0x91, - 0xC2, 0xA2, 0x11, 0x16, 0x7A, 0xBB, 0x8C, 0x5E, - 0x07, 0x9E, 0x09, 0xE2, 0xC8, 0xA8, 0x33, 0x9C - }; +#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_SESSION_EXPORT) + tcp_ready ready; + func_args client_args; + func_args server_args; + THREAD_TYPE serverThread; + callback_functions server_cbf; + callback_functions client_cbf; +#ifdef WOLFSSL_TIRTOS + fdOpenSession(Task_self()); +#endif - /* --- initial connection: get a real session to carry the session ID --- */ - XMEMSET(&test_ctx, 0, sizeof(test_ctx)); - ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, - wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), 0); - ExpectIntEQ(wolfSSL_set_groups(ssl_c, groups, 1), WOLFSSL_SUCCESS); - ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + InitTcpReady(&ready); - /* drain any NewSessionTicket before calling get1_session */ - ExpectIntEQ(wolfSSL_read(ssl_c, readBuf, sizeof(readBuf)), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + /* set using dtls */ + XMEMSET(&client_args, 0, sizeof(func_args)); + XMEMSET(&server_args, 0, sizeof(func_args)); + XMEMSET(&server_cbf, 0, sizeof(callback_functions)); + XMEMSET(&client_cbf, 0, sizeof(callback_functions)); + server_cbf.method = wolfDTLSv1_2_server_method; + client_cbf.method = wolfDTLSv1_2_client_method; + server_args.callbacks = &server_cbf; + client_args.callbacks = &client_cbf; - ExpectNotNull(sess = wolfSSL_get1_session(ssl_c)); + server_args.signal = &ready; + client_args.signal = &ready; - /* Force a non-zero session ID - simulates a wolfSSL <=v5.9.0 client that - * mistakenly sends 32 bytes as legacy_session_id in DTLS 1.3. */ - if (sess != NULL && sess->sessionIDSz == 0) { - sess->sessionIDSz = ID_LEN; - XMEMSET(sess->sessionID, 0x42, ID_LEN); - } + start_thread(run_wolfssl_server, &server_args, &serverThread); + wait_tcp_ready(&server_args); + run_wolfssl_client(&client_args); + join_thread(serverThread); - wolfSSL_free(ssl_c); ssl_c = NULL; - wolfSSL_free(ssl_s); ssl_s = NULL; - wolfSSL_CTX_free(ctx_c); ctx_c = NULL; - wolfSSL_CTX_free(ctx_s); ctx_s = NULL; + ExpectTrue(client_args.return_code); + ExpectTrue(server_args.return_code); - /* --- sub-test 1: direct ServerHello (HRR cookie disabled) --- - * Exercises DoTls13ClientHello (change 1) and - * SendTls13ServerHello (change 2). */ - XMEMSET(&test_ctx, 0, sizeof(test_ctx)); - ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, - wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), 0); - ExpectIntEQ(wolfSSL_set_session(ssl_c, sess), WOLFSSL_SUCCESS); - ExpectIntEQ(wolfSSL_set_groups(ssl_c, groups, 1), WOLFSSL_SUCCESS); - ExpectIntEQ(wolfSSL_disable_hrr_cookie(ssl_s), WOLFSSL_SUCCESS); + FreeTcpReady(&ready); - /* Client sends CH1 with non-empty legacy_session_id */ - ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); +#ifdef WOLFSSL_TIRTOS + fdOpenSession(Task_self()); +#endif - /* Server processes CH1 and sends ServerHello */ - ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + if (EXPECT_SUCCESS()) { + SOCKET_T sockfd = 0; + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + char msg[64] = "hello wolfssl!"; + char reply[1024]; + int msgSz = (int)XSTRLEN(msg); + byte *session, *window; + unsigned int sessionSz = 0; + unsigned int windowSz = 0; + +#ifndef TEST_IPV6 + struct sockaddr_in peerAddr; +#else + struct sockaddr_in6 peerAddr; +#endif /* TEST_IPV6 */ - /* Verify that the ServerHello on the wire echoes the session ID. - * Layout: DTLS Record Header (13) + DTLS Handshake Header (12) + - * ProtocolVersion (2) + Random (32) = byte 59 for - * legacy_session_id_echo length. */ - ExpectIntGE(test_ctx.c_len, 60); - ExpectIntEQ(test_ctx.c_buff[0], handshake); - ExpectIntEQ(test_ctx.c_buff[DTLS_RECORD_HEADER_SZ], server_hello); - /* Confirm it is a real ServerHello, not an HRR (also encoded as a - * ServerHello but bearing the HelloRetryRequest magic random). */ - ExpectIntNE(XMEMCMP(&test_ctx.c_buff[DTLS_RECORD_HEADER_SZ + - DTLS_HANDSHAKE_HEADER_SZ + OPAQUE16_LEN], hrrRandom, RAN_LEN), 0); - ExpectIntEQ(test_ctx.c_buff[DTLS_RECORD_HEADER_SZ + - DTLS_HANDSHAKE_HEADER_SZ + OPAQUE16_LEN + RAN_LEN], ID_LEN); - - /* Complete the handshake - Finished MAC validates the transcript */ - ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + int i; - wolfSSL_free(ssl_c); ssl_c = NULL; - wolfSSL_free(ssl_s); ssl_s = NULL; - wolfSSL_CTX_free(ctx_c); ctx_c = NULL; - wolfSSL_CTX_free(ctx_s); ctx_s = NULL; - /* --- sub-test 2: stateless HRR (HRR cookie enabled by default) --- - * Exercises SendStatelessReplyDtls13 (change 4) and - * RestartHandshakeHashWithCookie (change 3). */ - XMEMSET(&test_ctx, 0, sizeof(test_ctx)); - ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, - wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), 0); - ExpectIntEQ(wolfSSL_set_session(ssl_c, sess), WOLFSSL_SUCCESS); - ExpectIntEQ(wolfSSL_set_groups(ssl_c, groups, 1), WOLFSSL_SUCCESS); + /* Set ctx to DTLS 1.2 */ + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfDTLSv1_2_server_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); - /* Client sends CH1 */ - ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + /* test importing version 3 */ + ExpectIntGE(wolfSSL_dtls_import(ssl, version_3, sizeof(version_3)), 0); - /* Server sends stateless HRR (SendStatelessReplyDtls13) */ - ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + /* test importing bad length and bad version */ + version_3[2]++; + ExpectIntLT(wolfSSL_dtls_import(ssl, version_3, sizeof(version_3)), 0); + version_3[2]--; version_3[1] = 0XA0; + ExpectIntLT(wolfSSL_dtls_import(ssl, version_3, sizeof(version_3)), 0); + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); - /* Verify the HRR echoes the session ID at the same wire offset */ - ExpectIntGE(test_ctx.c_len, 60); - ExpectIntEQ(test_ctx.c_buff[0], handshake); - ExpectIntEQ(test_ctx.c_buff[DTLS_RECORD_HEADER_SZ], server_hello); - ExpectIntEQ(test_ctx.c_buff[DTLS_RECORD_HEADER_SZ + - DTLS_HANDSHAKE_HEADER_SZ + OPAQUE16_LEN + RAN_LEN], ID_LEN); - /* Complete the handshake - Finished MAC validates RestartHandshakeHashWithCookie */ - ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + /* check storing client state after connection and storing window only */ +#ifdef WOLFSSL_TIRTOS + fdOpenSession(Task_self()); +#endif - wolfSSL_SESSION_free(sess); - wolfSSL_free(ssl_c); - wolfSSL_free(ssl_s); - wolfSSL_CTX_free(ctx_c); + InitTcpReady(&ready); + + /* set using dtls */ + XMEMSET(&server_args, 0, sizeof(func_args)); + XMEMSET(&server_cbf, 0, sizeof(callback_functions)); + server_cbf.method = wolfDTLSv1_2_server_method; + server_cbf.doUdp = 1; + server_args.callbacks = &server_cbf; + server_args.argc = 3; /* set loop_count to 3 */ + + + server_args.signal = &ready; + start_thread(test_server_nofail, &server_args, &serverThread); + wait_tcp_ready(&server_args); + + /* create and connect with client */ + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfDTLSv1_2_client_method())); + ExpectIntEQ(WOLFSSL_SUCCESS, + wolfSSL_CTX_load_verify_locations(ctx, caCertFile, 0)); + ExpectIntEQ(WOLFSSL_SUCCESS, + wolfSSL_CTX_use_certificate_file(ctx, cliCertFile, SSL_FILETYPE_PEM)); + ExpectIntEQ(WOLFSSL_SUCCESS, + wolfSSL_CTX_use_PrivateKey_file(ctx, cliKeyFile, SSL_FILETYPE_PEM)); + tcp_connect(&sockfd, wolfSSLIP, server_args.signal->port, 1, 0, NULL); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + ExpectIntEQ(wolfSSL_set_fd(ssl, sockfd), WOLFSSL_SUCCESS); + + /* store server information connected too */ + XMEMSET(&peerAddr, 0, sizeof(peerAddr)); +#ifndef TEST_IPV6 + peerAddr.sin_family = AF_INET; + ExpectIntEQ(XINET_PTON(AF_INET, wolfSSLIP, &peerAddr.sin_addr),1); + peerAddr.sin_port = XHTONS(server_args.signal->port); +#else + peerAddr.sin6_family = AF_INET6; + ExpectIntEQ( + XINET_PTON(AF_INET6, wolfSSLIP, &peerAddr.sin6_addr),1); + peerAddr.sin6_port = XHTONS(server_args.signal->port); +#endif + + ExpectIntEQ(wolfSSL_dtls_set_peer(ssl, &peerAddr, sizeof(peerAddr)), + WOLFSSL_SUCCESS); + + ExpectIntEQ(wolfSSL_connect(ssl), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_dtls_export(ssl, NULL, &sessionSz), 0); + session = (byte*)XMALLOC(sessionSz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + ExpectIntGT(wolfSSL_dtls_export(ssl, session, &sessionSz), 0); + ExpectIntEQ(wolfSSL_write(ssl, msg, msgSz), msgSz); + ExpectIntGT(wolfSSL_read(ssl, reply, sizeof(reply)), 0); + ExpectIntEQ(wolfSSL_dtls_export_state_only(ssl, NULL, &windowSz), 0); + window = (byte*)XMALLOC(windowSz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + ExpectIntGT(wolfSSL_dtls_export_state_only(ssl, window, &windowSz), 0); + wolfSSL_free(ssl); + + for (i = 1; EXPECT_SUCCESS() && i < server_args.argc; i++) { + /* restore state */ + ExpectNotNull(ssl = wolfSSL_new(ctx)); + ExpectIntGT(wolfSSL_dtls_import(ssl, session, sessionSz), 0); + ExpectIntGT(wolfSSL_dtls_import(ssl, window, windowSz), 0); + ExpectIntEQ(wolfSSL_set_fd(ssl, sockfd), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_dtls_set_peer(ssl, &peerAddr, sizeof(peerAddr)), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_write(ssl, msg, msgSz), msgSz); + ExpectIntGE(wolfSSL_read(ssl, reply, sizeof(reply)), 0); + ExpectIntGT(wolfSSL_dtls_export_state_only(ssl, window, &windowSz), 0); + wolfSSL_free(ssl); + } + XFREE(session, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(window, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + wolfSSL_CTX_free(ctx); + + fprintf(stderr, "done and waiting for server\n"); + join_thread(serverThread); + ExpectIntEQ(server_args.return_code, TEST_SUCCESS); + + FreeTcpReady(&ready); + +#ifdef WOLFSSL_TIRTOS + fdOpenSession(Task_self()); +#endif + } +#endif + + return EXPECT_RESULT(); +} + +#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_SESSION_EXPORT) && \ + defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES) +/* Dummy peer functions to satisfy the exporter/importer */ +static int test_wolfSSL_dtls_export_peers_get_peer(WOLFSSL* ssl, char* ip, + int* ipSz, unsigned short* port, int* fam) +{ + (void)ssl; + ip[0] = -1; + *ipSz = 1; + *port = 1; + *fam = 2; + return 1; +} + +static int test_wolfSSL_dtls_export_peers_set_peer(WOLFSSL* ssl, char* ip, + int ipSz, unsigned short port, int fam) +{ + (void)ssl; + if (ip[0] != -1 || ipSz != 1 || port != 1 || fam != 2) + return 0; + return 1; +} + +static int test_wolfSSL_dtls_export_peers_on_handshake(WOLFSSL_CTX **ctx, + WOLFSSL **ssl) +{ + EXPECT_DECLS; + unsigned char* sessionBuf = NULL; + unsigned int sessionSz = 0; + void* ioWriteCtx = wolfSSL_GetIOWriteCtx(*ssl); + void* ioReadCtx = wolfSSL_GetIOReadCtx(*ssl); + + wolfSSL_CTX_SetIOGetPeer(*ctx, test_wolfSSL_dtls_export_peers_get_peer); + wolfSSL_CTX_SetIOSetPeer(*ctx, test_wolfSSL_dtls_export_peers_set_peer); + ExpectIntGE(wolfSSL_dtls_export(*ssl, NULL, &sessionSz), 0); + ExpectNotNull(sessionBuf = + (unsigned char*)XMALLOC(sessionSz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER)); + ExpectIntGE(wolfSSL_dtls_export(*ssl, sessionBuf, &sessionSz), 0); + wolfSSL_free(*ssl); + *ssl = NULL; + ExpectNotNull(*ssl = wolfSSL_new(*ctx)); + ExpectIntGE(wolfSSL_dtls_import(*ssl, sessionBuf, sessionSz), 0); + wolfSSL_SetIOWriteCtx(*ssl, ioWriteCtx); + wolfSSL_SetIOReadCtx(*ssl, ioReadCtx); + + XFREE(sessionBuf, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + return EXPECT_RESULT(); +} +#endif + +int test_wolfSSL_dtls_export_peers(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_SESSION_EXPORT) && \ + defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES) + test_ssl_cbf client_cbf; + test_ssl_cbf server_cbf; + size_t i, j; + struct test_params { + method_provider client_meth; + method_provider server_meth; + const char* dtls_version; + } params[] = { +#ifndef NO_OLD_TLS + {wolfDTLSv1_client_method, wolfDTLSv1_server_method, "1.0"}, +#endif + {wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method, "1.2"}, + /* TODO DTLS 1.3 exporting not supported +#ifdef WOLFSSL_DTLS13 + {wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method, "1.3"}, +#endif + */ + }; + + for (i = 0; i < sizeof(params)/sizeof(*params); i++) { + for (j = 0; j <= 3; j++) { + XMEMSET(&client_cbf, 0, sizeof(client_cbf)); + XMEMSET(&server_cbf, 0, sizeof(server_cbf)); + + printf("\n\tTesting DTLS %s connection;", params[i].dtls_version); + + client_cbf.method = params[i].client_meth; + server_cbf.method = params[i].server_meth; + + if (j & 0x1) { + client_cbf.on_handshake = + test_wolfSSL_dtls_export_peers_on_handshake; + printf(" With client export;"); + } + if (j & 0x2) { + server_cbf.on_handshake = + test_wolfSSL_dtls_export_peers_on_handshake; + printf(" With server export;"); + } + + printf("\n"); + + ExpectIntEQ(test_wolfSSL_client_server_nofail_memio(&client_cbf, + &server_cbf, NULL), TEST_SUCCESS); + if (!EXPECT_SUCCESS()) + break; + } + } +#endif + return EXPECT_RESULT(); +} + +/* Test that ImportKeyState correctly skips extra window words when importing + * state from a peer compiled with a larger WOLFSSL_DTLS_WINDOW_WORDS. */ +int test_wolfSSL_dtls_import_state_extra_window_words(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_SESSION_EXPORT) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + unsigned int stateSz = 0; + byte* state = NULL; + byte* modified = NULL; + unsigned int modifiedSz; + word16 origKeyLen; + word16 origTotalLen; + /* Offset from start of key state data to the first wordCount field. + * Layout: 4 sequence numbers (16 bytes) + DTLS-specific fields (42 bytes) + + * encryptSz(4) + padSz(4) + encryptionOn(1) + decryptedCur(1) = 68 */ + const int keyStateWindowOffset = 68; + /* Buffer header: 2 proto + 2 total_len + 2 key_len = 6 */ + const int headerSz = 6; + int idx, modIdx; + int extraPerWindow = 2 * (int)sizeof(word32); /* 8 bytes extra per window */ + int totalExtra = extraPerWindow * 2; /* 16 bytes extra total */ + + /* Create DTLS context and SSL object */ + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfDTLSv1_2_server_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + /* Get required buffer size and export state-only */ + ExpectIntEQ(wolfSSL_dtls_export_state_only(ssl, NULL, &stateSz), 0); + ExpectIntGT((int)stateSz, 0); + state = (byte*)XMALLOC(stateSz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + ExpectNotNull(state); + ExpectIntGT(wolfSSL_dtls_export_state_only(ssl, state, &stateSz), 0); + + /* Build a modified buffer that simulates a peer with + * WOLFSSL_DTLS_WINDOW_WORDS = WOLFSSL_DTLS_WINDOW_WORDS + 2. + * Each window section gets 2 extra word32 values (8 bytes). + * Two windows => 16 extra bytes total. */ + modifiedSz = stateSz + totalExtra; + modified = (byte*)XMALLOC(modifiedSz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + ExpectNotNull(modified); + + if (EXPECT_SUCCESS()) { + int windowWords = WOLFSSL_DTLS_WINDOW_WORDS; + int windowDataSz = windowWords * (int)sizeof(word32); + + XMEMSET(modified, 0, modifiedSz); + + /* Copy protocol/version bytes (first 2 bytes) */ + XMEMCPY(modified, state, 2); + + /* Read original total length and key state length */ + ato16(state + 2, &origTotalLen); + ato16(state + 4, &origKeyLen); + + /* Write updated total length and key state length */ + c16toa((word16)(origTotalLen + totalExtra), modified + 2); + c16toa((word16)(origKeyLen + totalExtra), modified + 4); + + /* Copy key state data up to first window section */ + idx = headerSz; + modIdx = headerSz; + XMEMCPY(modified + modIdx, state + idx, keyStateWindowOffset); + idx += keyStateWindowOffset; + modIdx += keyStateWindowOffset; + + /* First window: write increased wordCount */ + c16toa((word16)(windowWords + 2), modified + modIdx); + idx += OPAQUE16_LEN; + modIdx += OPAQUE16_LEN; + + /* Copy original window data */ + XMEMCPY(modified + modIdx, state + idx, windowDataSz); + idx += windowDataSz; + modIdx += windowDataSz; + + /* Insert 2 extra word32 padding values */ + XMEMSET(modified + modIdx, 0, extraPerWindow); + modIdx += extraPerWindow; + + /* Second window (prevWindow): same transformation */ + c16toa((word16)(windowWords + 2), modified + modIdx); + idx += OPAQUE16_LEN; + modIdx += OPAQUE16_LEN; + + XMEMCPY(modified + modIdx, state + idx, windowDataSz); + idx += windowDataSz; + modIdx += windowDataSz; + + XMEMSET(modified + modIdx, 0, extraPerWindow); + modIdx += extraPerWindow; + + /* Copy remainder of key state (after both windows) */ + XMEMCPY(modified + modIdx, state + idx, stateSz - idx); + } + + /* Import the modified state - should succeed with the fix */ + wolfSSL_free(ssl); + ssl = NULL; + ExpectNotNull(ssl = wolfSSL_new(ctx)); + ExpectIntGT(wolfSSL_dtls_import(ssl, modified, modifiedSz), 0); + + XFREE(state, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(modified, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +/*----------------------------------------------------------------------------*/ +/* DTLS either-side method and cookie generation */ +/*----------------------------------------------------------------------------*/ + +int test_wolfSSL_DTLS_either_side(void) +{ + EXPECT_DECLS; +#if (defined(OPENSSL_EXTRA) || defined(WOLFSSL_EITHER_SIDE)) && \ + defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS) + test_ssl_cbf client_cb; + test_ssl_cbf server_cb; + + XMEMSET(&client_cb, 0, sizeof(client_cb)); + XMEMSET(&server_cb, 0, sizeof(server_cb)); + + /* Use different CTX for client and server */ + client_cb.ctx = wolfSSL_CTX_new(wolfDTLS_method()); + ExpectNotNull(client_cb.ctx); + server_cb.ctx = wolfSSL_CTX_new(wolfDTLS_method()); + ExpectNotNull(server_cb.ctx); + /* we are responsible for free'ing WOLFSSL_CTX */ + server_cb.isSharedCtx = client_cb.isSharedCtx = 1; + + ExpectIntEQ(test_wolfSSL_client_server_nofail_memio(&client_cb, + &server_cb, NULL), TEST_SUCCESS); + + wolfSSL_CTX_free(client_cb.ctx); + wolfSSL_CTX_free(server_cb.ctx); +#endif + return EXPECT_RESULT(); +} + +int test_generate_cookie(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_DTLS) && defined(OPENSSL_EXTRA) && defined(USE_WOLFSSL_IO) + SSL_CTX* ctx = NULL; + SSL* ssl = NULL; + byte buf[FOURK_BUF] = {0}; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfDTLS_method())); + ExpectNotNull(ssl = SSL_new(ctx)); + + /* Test unconnected */ + ExpectIntEQ(EmbedGenerateCookie(ssl, buf, FOURK_BUF, NULL), WC_NO_ERR_TRACE(GEN_COOKIE_E)); + + wolfSSL_CTX_SetGenCookie(ctx, EmbedGenerateCookie); + + wolfSSL_SetCookieCtx(ssl, ctx); + + ExpectNotNull(wolfSSL_GetCookieCtx(ssl)); + + ExpectNull(wolfSSL_GetCookieCtx(NULL)); + + SSL_free(ssl); + SSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +/*----------------------------------------------------------------------------*/ +/* DTLS handshake: MTU, plaintext, fragments, bad records, AEAD, stateless */ +/*----------------------------------------------------------------------------*/ + +int test_wolfSSL_dtls_set_mtu(void) +{ + EXPECT_DECLS; +#if (defined(WOLFSSL_DTLS_MTU) || defined(WOLFSSL_SCTP)) && \ + !defined(NO_WOLFSSL_SERVER) && defined(WOLFSSL_DTLS) && \ + !defined(WOLFSSL_NO_TLS12) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + const char* testCertFile; + const char* testKeyFile; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfDTLSv1_2_server_method())); +#ifndef NO_RSA + testCertFile = svrCertFile; + testKeyFile = svrKeyFile; +#elif defined(HAVE_ECC) + testCertFile = eccCertFile; + testKeyFile = eccKeyFile; +#endif + if (testCertFile != NULL && testKeyFile != NULL) { + ExpectTrue(wolfSSL_CTX_use_certificate_file(ctx, testCertFile, + WOLFSSL_FILETYPE_PEM)); + ExpectTrue(wolfSSL_CTX_use_PrivateKey_file(ctx, testKeyFile, + WOLFSSL_FILETYPE_PEM)); + } + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + ExpectIntEQ(wolfSSL_CTX_dtls_set_mtu(NULL, 1488), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_dtls_set_mtu(NULL, 1488), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_CTX_dtls_set_mtu(ctx, 20000), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_dtls_set_mtu(ssl, 20000), WC_NO_ERR_TRACE(WOLFSSL_FAILURE)); + ExpectIntEQ(wolfSSL_get_error(ssl, WC_NO_ERR_TRACE(WOLFSSL_FAILURE)), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_CTX_dtls_set_mtu(ctx, 1488), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_dtls_set_mtu(ssl, 1488), WOLFSSL_SUCCESS); + +#ifdef OPENSSL_EXTRA + ExpectIntEQ(SSL_set_mtu(ssl, 1488), WOLFSSL_SUCCESS); +#endif + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + + return EXPECT_RESULT(); +} + +#if defined(HAVE_IO_TESTS_DEPENDENCIES) && !defined(SINGLE_THREADED) && \ + defined(WOLFSSL_DTLS) && !defined(WOLFSSL_NO_TLS12) + +static WC_INLINE void generateDTLSMsg(byte* out, int outSz, word32 seq, + enum HandShakeType hsType, word16 length) +{ + size_t idx = 0; + byte* l; + + /* record layer */ + /* handshake type */ + out[idx++] = handshake; + /* protocol version */ + out[idx++] = 0xfe; + out[idx++] = 0xfd; /* DTLS 1.2 */ + /* epoch 0 */ + XMEMSET(out + idx, 0, 2); + idx += 2; + /* sequence number */ + XMEMSET(out + idx, 0, 6); + c32toa(seq, out + idx + 2); + idx += 6; + /* length in BE */ + if (length) + c16toa(length, out + idx); + else + c16toa(outSz - idx - 2, out + idx); + idx += 2; + + /* handshake layer */ + /* handshake type */ + out[idx++] = (byte)hsType; + /* length */ + l = out + idx; + idx += 3; + /* message seq */ + c16toa(0, out + idx); + idx += 2; + /* frag offset */ + c32to24(0, out + idx); + idx += 3; + /* frag length */ + c32to24((word32)outSz - (word32)idx - 3, l); + c32to24((word32)outSz - (word32)idx - 3, out + idx); + idx += 3; + XMEMSET(out + idx, 0, outSz - idx); +} + +static void test_wolfSSL_dtls_plaintext_server(WOLFSSL* ssl) +{ + byte msg[] = "This is a msg for the client"; + byte reply[40]; + AssertIntGT(wolfSSL_read(ssl, reply, sizeof(reply)),0); + reply[sizeof(reply) - 1] = '\0'; + fprintf(stderr, "Client message: %s\n", reply); + AssertIntEQ(wolfSSL_write(ssl, msg, sizeof(msg)), sizeof(msg)); +} + +static void test_wolfSSL_dtls_plaintext_client(WOLFSSL* ssl) +{ + byte ch[50]; + int fd = wolfSSL_get_wfd(ssl); + byte msg[] = "This is a msg for the server"; + byte reply[40]; + + AssertIntGE(fd, 0); + generateDTLSMsg(ch, sizeof(ch), 20, client_hello, 0); + /* Server should ignore this datagram */ + AssertIntEQ(send(fd, (MESSAGE_TYPE_CAST)ch, sizeof(ch), 0), sizeof(ch)); + generateDTLSMsg(ch, sizeof(ch), 20, client_hello, 10000); + /* Server should ignore this datagram */ + AssertIntEQ(send(fd, (MESSAGE_TYPE_CAST)ch, sizeof(ch), 0), sizeof(ch)); + + AssertIntEQ(wolfSSL_write(ssl, msg, sizeof(msg)), sizeof(msg)); + AssertIntGT(wolfSSL_read(ssl, reply, sizeof(reply)),0); + reply[sizeof(reply) - 1] = '\0'; + fprintf(stderr, "Server response: %s\n", reply); +} + +int test_wolfSSL_dtls_plaintext(void) +{ + callback_functions func_cb_client; + callback_functions func_cb_server; + size_t i; + struct test_params { + method_provider client_meth; + method_provider server_meth; + ssl_callback on_result_server; + ssl_callback on_result_client; + } params[] = { + {wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method, + test_wolfSSL_dtls_plaintext_server, + test_wolfSSL_dtls_plaintext_client}, + }; + + for (i = 0; i < sizeof(params)/sizeof(*params); i++) { + XMEMSET(&func_cb_client, 0, sizeof(callback_functions)); + XMEMSET(&func_cb_server, 0, sizeof(callback_functions)); + + func_cb_client.doUdp = func_cb_server.doUdp = 1; + func_cb_server.method = params[i].server_meth; + func_cb_client.method = params[i].client_meth; + func_cb_client.on_result = params[i].on_result_client; + func_cb_server.on_result = params[i].on_result_server; + + test_wolfSSL_client_server_nofail(&func_cb_client, &func_cb_server); + + if (!func_cb_client.return_code) + return TEST_FAIL; + if (!func_cb_server.return_code) + return TEST_FAIL; + } + + return TEST_RES_CHECK(1); +} +#else +int test_wolfSSL_dtls_plaintext(void) +{ + return TEST_SKIPPED; +} +#endif + +#if defined(HAVE_IO_TESTS_DEPENDENCIES) && !defined(SINGLE_THREADED) && \ + defined(WOLFSSL_DTLS) && !defined(WOLFSSL_NO_TLS12) + +static void test_wolfSSL_dtls12_fragments_spammer(WOLFSSL* ssl) +{ + byte b[1100]; /* buffer for the messages to send */ + size_t idx = 0; + size_t seq_offset = 0; + size_t msg_offset = 0; + int i; + int fd = wolfSSL_get_wfd(ssl); + int ret = wolfSSL_connect_cert(ssl); /* This gets us past the cookie */ + word32 seq_number = 100; /* start high so server definitely reads this */ + word16 msg_number = 50; /* start high so server has to buffer this */ + AssertIntEQ(ret, 1); + /* Now let's start spamming the peer with fragments it needs to store */ + XMEMSET(b, -1, sizeof(b)); + + /* record layer */ + /* handshake type */ + b[idx++] = 22; + /* protocol version */ + b[idx++] = 0xfe; + b[idx++] = 0xfd; /* DTLS 1.2 */ + /* epoch 0 */ + XMEMSET(b + idx, 0, 2); + idx += 2; + /* sequence number */ + XMEMSET(b + idx, 0, 6); + seq_offset = idx + 2; /* increment only the low 32 bits */ + idx += 6; + /* static length in BE */ + c16toa(42, b + idx); + idx += 2; + + /* handshake layer */ + /* cert type */ + b[idx++] = 11; + /* length */ + c32to24(1000, b + idx); + idx += 3; + /* message seq */ + c16toa(0, b + idx); + msg_offset = idx; + idx += 2; + /* frag offset */ + c32to24(500, b + idx); + idx += 3; + /* frag length */ + c32to24(30, b + idx); + idx += 3; + (void)idx; /* inhibit clang-analyzer-deadcode.DeadStores */ + + for (i = 0; i < DTLS_POOL_SZ * 2 && ret > 0; + seq_number++, msg_number++, i++) { + struct timespec delay; + XMEMSET(&delay, 0, sizeof(delay)); + delay.tv_nsec = 10000000; /* wait 0.01 seconds */ + c32toa(seq_number, b + seq_offset); + c16toa(msg_number, b + msg_offset); + ret = (int)send(fd, (MESSAGE_TYPE_CAST)b, 55, 0); + nanosleep(&delay, NULL); + } +} + +#ifdef WOLFSSL_DTLS13 +static void test_wolfSSL_dtls13_fragments_spammer(WOLFSSL* ssl) +{ + const word16 sendCountMax = 100; + byte b[150]; /* buffer for the messages to send */ + size_t idx = 0; + size_t msg_offset = 0; + int fd = wolfSSL_get_wfd(ssl); + word16 msg_number = 10; /* start high so server has to buffer this */ + int ret = wolfSSL_connect_cert(ssl); /* This gets us past the cookie */ + AssertIntEQ(ret, 1); + /* Now let's start spamming the peer with fragments it needs to store */ + XMEMSET(b, -1, sizeof(b)); + + /* handshake type */ + b[idx++] = 11; + /* length */ + c32to24(10000, b + idx); + idx += 3; + /* message_seq */ + msg_offset = idx; + idx += 2; + /* fragment_offset */ + c32to24(5000, b + idx); + idx += 3; + /* fragment_length */ + c32to24(100, b + idx); + idx += 3; + /* fragment contents */ + idx += 100; + + for (; ret > 0 && msg_number < sendCountMax; msg_number++) { + byte sendBuf[150]; + int sendSz = sizeof(sendBuf); + struct timespec delay; + XMEMSET(&delay, 0, sizeof(delay)); + delay.tv_nsec = 10000000; /* wait 0.01 seconds */ + c16toa(msg_number, b + msg_offset); + ret = sendSz = BuildTls13Message(ssl, sendBuf, sendSz, b, + (int)idx, handshake, 0, 0, 0); + if (sendSz > 0) + ret = (int)send(fd, (MESSAGE_TYPE_CAST)sendBuf, (size_t)sendSz, 0); + nanosleep(&delay, NULL); + } +} +#endif + +int test_wolfSSL_dtls_fragments(void) +{ + EXPECT_DECLS; + callback_functions func_cb_client; + callback_functions func_cb_server; + size_t i; + struct test_params { + method_provider client_meth; + method_provider server_meth; + ssl_callback spammer; + } params[] = { +#if !defined(WOLFSSL_NO_TLS12) + {wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method, + test_wolfSSL_dtls12_fragments_spammer}, +#endif +#ifdef WOLFSSL_DTLS13 + {wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method, + test_wolfSSL_dtls13_fragments_spammer}, +#endif + }; + + for (i = 0; i < sizeof(params)/sizeof(*params); i++) { + XMEMSET(&func_cb_client, 0, sizeof(callback_functions)); + XMEMSET(&func_cb_server, 0, sizeof(callback_functions)); + + func_cb_client.doUdp = func_cb_server.doUdp = 1; + func_cb_server.method = params[i].server_meth; + func_cb_client.method = params[i].client_meth; + func_cb_client.ssl_ready = params[i].spammer; + + test_wolfSSL_client_server_nofail(&func_cb_client, &func_cb_server); + + /* If the client failed, check that the error it encountered was from + * the server aborting, resulting in a socket error, fatal error or + * reading a close notify alert. + * + * Under slow execution (e.g. valgrind + noasm), the server may + * still be processing fragments when the client completes its + * handshake and write, so the client may succeed -- in that + * case return_code is TEST_SUCCESS and these checks don't apply. + */ + if (func_cb_client.return_code == TEST_FAIL) { + if (func_cb_client.last_err != WC_NO_ERR_TRACE(SOCKET_ERROR_E) && + func_cb_client.last_err != WOLFSSL_ERROR_ZERO_RETURN && + func_cb_client.last_err != WC_NO_ERR_TRACE(FATAL_ERROR)) { + ExpectIntEQ(func_cb_client.last_err, WC_NO_ERR_TRACE(SOCKET_ERROR_E)); + } + } + /* Check the server returned an error indicating the msg buffer + * was full. + * + * Under slow execution (e.g. valgrind + noasm), the real handshake + * from wolfSSL_negotiate() may complete before enough spam fragments + * accumulate to trigger DTLS_TOO_MANY_FRAGMENTS_E. Accept both + * outcomes: server hit the fragment limit, or completed normally. + */ + if (func_cb_server.return_code == TEST_FAIL) { + ExpectIntEQ(func_cb_server.last_err, WC_NO_ERR_TRACE(DTLS_TOO_MANY_FRAGMENTS_E)); + } + + if (EXPECT_FAIL()) + break; + } + + return EXPECT_RESULT(); +} + +static void test_wolfSSL_dtls_send_alert(WOLFSSL* ssl) +{ + int fd, ret; + byte alert_msg[] = { + 0x15, /* alert type */ + 0xfe, 0xfd, /* version */ + 0x00, 0x00, /* epoch */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, /* seq number */ + 0x00, 0x02, /* length */ + 0x02, /* level: fatal */ + 0x46 /* protocol version */ + }; + + fd = wolfSSL_get_wfd(ssl); + AssertIntGE(fd, 0); + ret = (int)send(fd, (MESSAGE_TYPE_CAST)alert_msg, sizeof(alert_msg), 0); + AssertIntGT(ret, 0); +} + +static int _test_wolfSSL_ignore_alert_before_cookie(byte version12) +{ + callback_functions client_cbs, server_cbs; + + XMEMSET(&client_cbs, 0, sizeof(client_cbs)); + XMEMSET(&server_cbs, 0, sizeof(server_cbs)); + client_cbs.doUdp = server_cbs.doUdp = 1; + if (version12) { +#if !defined(WOLFSSL_NO_TLS12) + client_cbs.method = wolfDTLSv1_2_client_method; + server_cbs.method = wolfDTLSv1_2_server_method; +#else + return TEST_SKIPPED; +#endif + } + else + { +#ifdef WOLFSSL_DTLS13 + client_cbs.method = wolfDTLSv1_3_client_method; + server_cbs.method = wolfDTLSv1_3_server_method; +#else + return TEST_SKIPPED; +#endif /* WOLFSSL_DTLS13 */ + } + + client_cbs.ssl_ready = test_wolfSSL_dtls_send_alert; + test_wolfSSL_client_server_nofail(&client_cbs, &server_cbs); + + if (!client_cbs.return_code) + return TEST_FAIL; + if (!server_cbs.return_code) + return TEST_FAIL; + + return TEST_SUCCESS; +} + +int test_wolfSSL_ignore_alert_before_cookie(void) +{ + int ret; + ret =_test_wolfSSL_ignore_alert_before_cookie(0); + if (ret != 0) + return ret; + ret =_test_wolfSSL_ignore_alert_before_cookie(1); + if (ret != 0) + return ret; + return 0; +} + +static void test_wolfSSL_send_bad_record(WOLFSSL* ssl) +{ + int ret; + int fd; + + byte bad_msg[] = { + 0x17, /* app data */ + 0xaa, 0xfd, /* bad version */ + 0x00, 0x01, /* epoch 1 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, /* not seen seq number */ + 0x00, 0x26, /* length: 38 bytes */ + 0xae, 0x30, 0x31, 0xb1, 0xf1, 0xb9, 0x6f, 0xda, 0x17, 0x19, 0xd9, 0x57, + 0xa9, 0x9d, 0x5c, 0x51, 0x9b, 0x53, 0x63, 0xa5, 0x24, 0x70, 0xa1, + 0xae, 0xdf, 0x1c, 0xb9, 0xfc, 0xe3, 0xd7, 0x77, 0x6d, 0xb6, 0x89, 0x0f, + 0x03, 0x18, 0x72 + }; + + fd = wolfSSL_get_wfd(ssl); + AssertIntGE(fd, 0); + ret = (int)send(fd, (MESSAGE_TYPE_CAST)bad_msg, sizeof(bad_msg), 0); + AssertIntEQ(ret, sizeof(bad_msg)); + ret = wolfSSL_write(ssl, "badrecordtest", sizeof("badrecordtest")); + AssertIntEQ(ret, sizeof("badrecordtest")); +} + +static void test_wolfSSL_read_string(WOLFSSL* ssl) +{ + byte buf[100]; + int ret; + + ret = wolfSSL_read(ssl, buf, sizeof(buf)); + AssertIntGT(ret, 0); + AssertIntEQ(strcmp((char*)buf, "badrecordtest"), 0); +} + +static int _test_wolfSSL_dtls_bad_record( + method_provider client_method, method_provider server_method) +{ + callback_functions client_cbs, server_cbs; + + XMEMSET(&client_cbs, 0, sizeof(client_cbs)); + XMEMSET(&server_cbs, 0, sizeof(server_cbs)); + client_cbs.doUdp = server_cbs.doUdp = 1; + client_cbs.method = client_method; + server_cbs.method = server_method; + + client_cbs.on_result = test_wolfSSL_send_bad_record; + server_cbs.on_result = test_wolfSSL_read_string; + + test_wolfSSL_client_server_nofail(&client_cbs, &server_cbs); + + if (!client_cbs.return_code) + return TEST_FAIL; + if (!server_cbs.return_code) + return TEST_FAIL; + + return TEST_SUCCESS; +} + +int test_wolfSSL_dtls_bad_record(void) +{ + int ret = TEST_SUCCESS; +#if !defined(WOLFSSL_NO_TLS12) + ret = _test_wolfSSL_dtls_bad_record(wolfDTLSv1_2_client_method, + wolfDTLSv1_2_server_method); +#endif +#ifdef WOLFSSL_DTLS13 + if (ret == TEST_SUCCESS) { + ret = _test_wolfSSL_dtls_bad_record(wolfDTLSv1_3_client_method, + wolfDTLSv1_3_server_method); + } +#endif /* WOLFSSL_DTLS13 */ + return ret; + +} + +#else +int test_wolfSSL_dtls_fragments(void) +{ + return TEST_SKIPPED; +} +int test_wolfSSL_ignore_alert_before_cookie(void) +{ + return TEST_SKIPPED; +} +int test_wolfSSL_dtls_bad_record(void) +{ + return TEST_SKIPPED; +} +#endif + +#if defined(WOLFSSL_DTLS13) && !defined(WOLFSSL_TLS13_IGNORE_AEAD_LIMITS) && \ + !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) && \ + defined(HAVE_IO_TESTS_DEPENDENCIES) +static volatile int test_AEAD_seq_num = 0; +#ifdef WOLFSSL_NO_ATOMICS +static volatile int test_AEAD_done = 0; +#else +wolfSSL_Atomic_Int test_AEAD_done = WOLFSSL_ATOMIC_INITIALIZER(0); +#endif +#ifdef WOLFSSL_MUTEX_INITIALIZER +static wolfSSL_Mutex test_AEAD_mutex = WOLFSSL_MUTEX_INITIALIZER(test_AEAD_mutex); +#endif + +static int test_AEAD_fail_decryption = 0; +static int test_AEAD_cbiorecv(WOLFSSL *ssl, char *buf, int sz, void *ctx) +{ + int fd = wolfSSL_get_fd(ssl); + int ret = -1; + if (fd >= 0 && (ret = (int)recv(fd, buf, sz, 0)) > 0) { + if (test_AEAD_fail_decryption) { + /* Modify the packet to trigger a decryption failure */ + buf[ret/2] ^= 0xFF; + if (test_AEAD_fail_decryption == 1) + test_AEAD_fail_decryption = 0; + } + } + (void)ctx; + return ret; +} + +static void test_AEAD_get_limits(WOLFSSL* ssl, w64wrapper* hardLimit, + w64wrapper* keyUpdateLimit, w64wrapper* sendLimit) +{ + if (sendLimit) + w64Zero(sendLimit); + switch (ssl->specs.bulk_cipher_algorithm) { + case wolfssl_aes_gcm: + if (sendLimit) + *sendLimit = AEAD_AES_LIMIT; + FALL_THROUGH; + case wolfssl_chacha: + if (hardLimit) + *hardLimit = DTLS_AEAD_AES_GCM_CHACHA_FAIL_LIMIT; + if (keyUpdateLimit) + *keyUpdateLimit = DTLS_AEAD_AES_GCM_CHACHA_FAIL_KU_LIMIT; + break; + case wolfssl_aes_ccm: + if (sendLimit) + *sendLimit = DTLS_AEAD_AES_CCM_LIMIT; + if (ssl->specs.aead_mac_size == AES_CCM_8_AUTH_SZ) { + if (hardLimit) + *hardLimit = DTLS_AEAD_AES_CCM_8_FAIL_LIMIT; + if (keyUpdateLimit) + *keyUpdateLimit = DTLS_AEAD_AES_CCM_8_FAIL_KU_LIMIT; + } + else { + if (hardLimit) + *hardLimit = DTLS_AEAD_AES_CCM_FAIL_LIMIT; + if (keyUpdateLimit) + *keyUpdateLimit = DTLS_AEAD_AES_CCM_FAIL_KU_LIMIT; + } + break; + default: + fprintf(stderr, "Unrecognized bulk cipher"); + AssertFalse(1); + break; + } +} + +static void test_AEAD_limit_client(WOLFSSL* ssl) +{ + int ret; + int i; + int didReKey = 0; + char msgBuf[20]; + w64wrapper hardLimit; + w64wrapper keyUpdateLimit; + w64wrapper counter; + w64wrapper sendLimit; + + test_AEAD_get_limits(ssl, &hardLimit, &keyUpdateLimit, &sendLimit); + + w64Zero(&counter); + AssertTrue(w64Equal(Dtls13GetEpoch(ssl, ssl->dtls13Epoch)->dropCount, counter)); + + wolfSSL_SSLSetIORecv(ssl, test_AEAD_cbiorecv); + + for (i = 0; i < 10; i++) { + /* Test some failed decryptions */ + test_AEAD_fail_decryption = 1; + w64Increment(&counter); + ret = wolfSSL_read(ssl, msgBuf, sizeof(msgBuf)); + /* Should succeed since decryption failures are dropped */ + AssertIntGT(ret, 0); + AssertTrue(w64Equal(Dtls13GetEpoch(ssl, ssl->dtls13PeerEpoch)->dropCount, counter)); + } + + test_AEAD_fail_decryption = 1; + Dtls13GetEpoch(ssl, ssl->dtls13PeerEpoch)->dropCount = keyUpdateLimit; + w64Increment(&Dtls13GetEpoch(ssl, ssl->dtls13PeerEpoch)->dropCount); + /* 100 read calls should be enough to complete the key update */ + w64Zero(&counter); + for (i = 0; i < 100; i++) { + /* Key update should be sent and negotiated */ + ret = wolfSSL_read(ssl, msgBuf, sizeof(msgBuf)); + AssertIntGT(ret, 0); + /* Epoch after one key update is 4 */ + if (w64Equal(ssl->dtls13PeerEpoch, w64From32(0, 4)) && + w64Equal(Dtls13GetEpoch(ssl, ssl->dtls13PeerEpoch)->dropCount, counter)) { + didReKey = 1; + break; + } + } + AssertTrue(didReKey); + + if (!w64IsZero(sendLimit)) { + /* Test the sending limit for AEAD ciphers */ +#ifdef WOLFSSL_MUTEX_INITIALIZER + (void)wc_LockMutex(&test_AEAD_mutex); +#endif + Dtls13GetEpoch(ssl, ssl->dtls13Epoch)->nextSeqNumber = sendLimit; + test_AEAD_seq_num = 1; + XMEMSET(msgBuf, 0, sizeof(msgBuf)); + ret = wolfSSL_write(ssl, msgBuf, sizeof(msgBuf)); + AssertIntGT(ret, 0); + didReKey = 0; + w64Zero(&counter); +#ifdef WOLFSSL_MUTEX_INITIALIZER + wc_UnLockMutex(&test_AEAD_mutex); +#endif + /* 100 read calls should be enough to complete the key update */ + for (i = 0; i < 100; i++) { + /* Key update should be sent and negotiated */ + ret = wolfSSL_read(ssl, msgBuf, sizeof(msgBuf)); + AssertIntGT(ret, 0); + /* Epoch after another key update is 5 */ + if (w64Equal(ssl->dtls13Epoch, w64From32(0, 5)) && + w64Equal(Dtls13GetEpoch(ssl, ssl->dtls13Epoch)->dropCount, counter)) { + didReKey = 1; + break; + } + } + AssertTrue(didReKey); + } + + test_AEAD_fail_decryption = 2; + Dtls13GetEpoch(ssl, ssl->dtls13PeerEpoch)->dropCount = hardLimit; + w64Decrement(&Dtls13GetEpoch(ssl, ssl->dtls13PeerEpoch)->dropCount); + /* Connection should fail with a DECRYPT_ERROR */ + ret = wolfSSL_read(ssl, msgBuf, sizeof(msgBuf)); + AssertIntEQ(ret, WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)); + AssertIntEQ(wolfSSL_get_error(ssl, ret), WC_NO_ERR_TRACE(DECRYPT_ERROR)); + +#ifdef WOLFSSL_ATOMIC_INITIALIZER + WOLFSSL_ATOMIC_STORE(test_AEAD_done, 1); +#else + test_AEAD_done = 1; +#endif +} + +int counter = 0; +static void test_AEAD_limit_server(WOLFSSL* ssl) +{ + char msgBuf[] = "Sending data"; + int ret = WOLFSSL_SUCCESS; + w64wrapper sendLimit; + SOCKET_T fd = wolfSSL_get_fd(ssl); + struct timespec delay; + XMEMSET(&delay, 0, sizeof(delay)); + delay.tv_nsec = 100000000; /* wait 0.1 seconds */ + tcp_set_nonblocking(&fd); /* So that read doesn't block */ + wolfSSL_dtls_set_using_nonblock(ssl, 1); + test_AEAD_get_limits(ssl, NULL, NULL, &sendLimit); + while (! + #ifdef WOLFSSL_ATOMIC_INITIALIZER + WOLFSSL_ATOMIC_LOAD(test_AEAD_done) + #else + test_AEAD_done + #endif + && ret > 0) + { + counter++; +#ifdef WOLFSSL_MUTEX_INITIALIZER + (void)wc_LockMutex(&test_AEAD_mutex); +#endif + if (test_AEAD_seq_num) { + /* We need to update the seq number so that we can understand the + * peer. Otherwise we will incorrectly interpret the seq number. */ + Dtls13Epoch* e = Dtls13GetEpoch(ssl, ssl->dtls13PeerEpoch); + AssertNotNull(e); + e->nextPeerSeqNumber = sendLimit; + test_AEAD_seq_num = 0; + } +#ifdef WOLFSSL_MUTEX_INITIALIZER + wc_UnLockMutex(&test_AEAD_mutex); +#endif + (void)wolfSSL_read(ssl, msgBuf, sizeof(msgBuf)); + ret = wolfSSL_write(ssl, msgBuf, sizeof(msgBuf)); + nanosleep(&delay, NULL); + } +} + +int test_wolfSSL_dtls_AEAD_limit(void) +{ + callback_functions func_cb_client; + callback_functions func_cb_server; + XMEMSET(&func_cb_client, 0, sizeof(callback_functions)); + XMEMSET(&func_cb_server, 0, sizeof(callback_functions)); + + func_cb_client.doUdp = func_cb_server.doUdp = 1; + func_cb_server.method = wolfDTLSv1_3_server_method; + func_cb_client.method = wolfDTLSv1_3_client_method; + func_cb_server.on_result = test_AEAD_limit_server; + func_cb_client.on_result = test_AEAD_limit_client; + + test_wolfSSL_client_server_nofail(&func_cb_client, &func_cb_server); + + if (!func_cb_client.return_code) + return TEST_FAIL; + if (!func_cb_server.return_code) + return TEST_FAIL; + + return TEST_SUCCESS; +} +#else +int test_wolfSSL_dtls_AEAD_limit(void) +{ + return TEST_SKIPPED; +} +#endif + +#if defined(WOLFSSL_DTLS) && \ + defined(HAVE_IO_TESTS_DEPENDENCIES) && !defined(SINGLE_THREADED) && \ + !defined(DEBUG_VECTOR_REGISTER_ACCESS_FUZZING) +static void test_wolfSSL_dtls_send_ch(WOLFSSL* ssl) +{ + int fd, ret; + byte ch_msg[] = { + 0x16, 0xfe, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0xfa, 0x01, 0x00, 0x01, 0xee, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0xee, 0xfe, 0xfd, 0xc0, 0xca, 0xb5, 0x6f, 0x3d, 0x23, 0xcc, 0x53, 0x9a, + 0x67, 0x17, 0x70, 0xd3, 0xfb, 0x23, 0x16, 0x9e, 0x4e, 0xd6, 0x7e, 0x29, + 0xab, 0xfa, 0x4c, 0xa5, 0x84, 0x95, 0xc3, 0xdb, 0x21, 0x9a, 0x52, 0x00, + 0x00, 0x00, 0x36, 0x13, 0x01, 0x13, 0x02, 0x13, 0x03, 0xc0, 0x2c, 0xc0, + 0x2b, 0xc0, 0x30, 0xc0, 0x2f, 0x00, 0x9f, 0x00, 0x9e, 0xcc, 0xa9, 0xcc, + 0xa8, 0xcc, 0xaa, 0xc0, 0x27, 0xc0, 0x23, 0xc0, 0x28, 0xc0, 0x24, 0xc0, + 0x0a, 0xc0, 0x09, 0xc0, 0x14, 0xc0, 0x13, 0x00, 0x6b, 0x00, 0x67, 0x00, + 0x39, 0x00, 0x33, 0xcc, 0x14, 0xcc, 0x13, 0xcc, 0x15, 0x01, 0x00, 0x01, + 0x8e, 0x00, 0x2b, 0x00, 0x03, 0x02, 0xfe, 0xfc, 0x00, 0x0d, 0x00, 0x20, + 0x00, 0x1e, 0x06, 0x03, 0x05, 0x03, 0x04, 0x03, 0x02, 0x03, 0x08, 0x06, + 0x08, 0x0b, 0x08, 0x05, 0x08, 0x0a, 0x08, 0x04, 0x08, 0x09, 0x06, 0x01, + 0x05, 0x01, 0x04, 0x01, 0x03, 0x01, 0x02, 0x01, 0x00, 0x0a, 0x00, 0x0c, + 0x00, 0x0a, 0x00, 0x19, 0x00, 0x18, 0x00, 0x17, 0x00, 0x15, 0x01, 0x00, + 0x00, 0x16, 0x00, 0x00, 0x00, 0x33, 0x01, 0x4b, 0x01, 0x49, 0x00, 0x17, + 0x00, 0x41, 0x04, 0x96, 0xcb, 0x2e, 0x4e, 0xd9, 0x88, 0x71, 0xc7, 0xf3, + 0x1a, 0x16, 0xdd, 0x7a, 0x7c, 0xf7, 0x67, 0x8a, 0x5d, 0x9a, 0x55, 0xa6, + 0x4a, 0x90, 0xd9, 0xfb, 0xc7, 0xfb, 0xbe, 0x09, 0xa9, 0x8a, 0xb5, 0x7a, + 0xd1, 0xde, 0x83, 0x74, 0x27, 0x31, 0x1c, 0xaa, 0xae, 0xef, 0x58, 0x43, + 0x13, 0x7d, 0x15, 0x4d, 0x7f, 0x68, 0xf6, 0x8a, 0x38, 0xef, 0x0e, 0xb3, + 0xcf, 0xb8, 0x4a, 0xa9, 0xb4, 0xd7, 0xcb, 0x01, 0x00, 0x01, 0x00, 0x1d, + 0x0a, 0x22, 0x8a, 0xd1, 0x78, 0x85, 0x1e, 0x5a, 0xe1, 0x1d, 0x1e, 0xb7, + 0x2d, 0xbc, 0x5f, 0x52, 0xbc, 0x97, 0x5d, 0x8b, 0x6a, 0x8b, 0x9d, 0x1e, + 0xb1, 0xfc, 0x8a, 0xb2, 0x56, 0xcd, 0xed, 0x4b, 0xfb, 0x66, 0x3f, 0x59, + 0x3f, 0x15, 0x5d, 0x09, 0x9e, 0x2f, 0x60, 0x5b, 0x31, 0x81, 0x27, 0xf0, + 0x1c, 0xda, 0xcd, 0x48, 0x66, 0xc6, 0xbb, 0x25, 0xf0, 0x5f, 0xda, 0x4c, + 0xcf, 0x1d, 0x88, 0xc8, 0xda, 0x1b, 0x53, 0xea, 0xbd, 0xce, 0x6d, 0xf6, + 0x4a, 0x76, 0xdb, 0x75, 0x99, 0xaf, 0xcf, 0x76, 0x4a, 0xfb, 0xe3, 0xef, + 0xb2, 0xcb, 0xae, 0x4a, 0xc0, 0xe8, 0x63, 0x1f, 0xd6, 0xe8, 0xe6, 0x45, + 0xf9, 0xea, 0x0d, 0x06, 0x19, 0xfc, 0xb1, 0xfd, 0x5d, 0x92, 0x89, 0x7b, + 0xc7, 0x9f, 0x1a, 0xb3, 0x2b, 0xc7, 0xad, 0x0e, 0xfb, 0x13, 0x41, 0x83, + 0x84, 0x58, 0x3a, 0x25, 0xb9, 0x49, 0x35, 0x1c, 0x23, 0xcb, 0xd6, 0xe7, + 0xc2, 0x8c, 0x4b, 0x2a, 0x73, 0xa1, 0xdf, 0x4f, 0x73, 0x9b, 0xb3, 0xd2, + 0xb2, 0x95, 0x00, 0x3c, 0x26, 0x09, 0x89, 0x71, 0x05, 0x39, 0xc8, 0x98, + 0x8f, 0xed, 0x32, 0x15, 0x78, 0xcd, 0xd3, 0x7e, 0xfb, 0x5a, 0x78, 0x2a, + 0xdc, 0xca, 0x20, 0x09, 0xb5, 0x14, 0xf9, 0xd4, 0x58, 0xf6, 0x69, 0xf8, + 0x65, 0x9f, 0xb7, 0xe4, 0x93, 0xf1, 0xa3, 0x84, 0x7e, 0x1b, 0x23, 0x5d, + 0xea, 0x59, 0x3e, 0x4d, 0xca, 0xfd, 0xa5, 0x55, 0xdd, 0x99, 0xb5, 0x02, + 0xf8, 0x0d, 0xe5, 0xf4, 0x06, 0xb0, 0x43, 0x9e, 0x2e, 0xbf, 0x05, 0x33, + 0x65, 0x7b, 0x13, 0x8c, 0xf9, 0x16, 0x4d, 0xc5, 0x15, 0x0b, 0x40, 0x2f, + 0x66, 0x94, 0xf2, 0x43, 0x95, 0xe7, 0xa9, 0xb6, 0x39, 0x99, 0x73, 0xb3, + 0xb0, 0x06, 0xfe, 0x52, 0x9e, 0x57, 0xba, 0x75, 0xfd, 0x76, 0x7b, 0x20, + 0x31, 0x68, 0x4c + }; + + fd = wolfSSL_get_wfd(ssl); + AssertIntGE(fd, 0); + ret = (int)send(fd, (MESSAGE_TYPE_CAST)ch_msg, sizeof(ch_msg), 0); + AssertIntGT(ret, 0); + /* consume the HRR otherwise handshake will fail */ + ret = (int)recv(fd, (MESSAGE_TYPE_CAST)ch_msg, sizeof(ch_msg), 0); + AssertIntGT(ret, 0); +} + +#if defined(WOLFSSL_DTLS13) && defined(WOLFSSL_SEND_HRR_COOKIE) +static void test_wolfSSL_dtls_send_ch_with_invalid_cookie(WOLFSSL* ssl) +{ + int fd, ret; + byte ch_msh_invalid_cookie[] = { + 0x16, 0xfe, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x4e, 0x01, 0x00, 0x02, 0x42, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x42, 0xfe, 0xfd, 0x69, 0xca, 0x77, 0x60, 0x6f, 0xfc, 0xd1, 0x5b, 0x60, + 0x5d, 0xf1, 0xa6, 0x5c, 0x44, 0x71, 0xae, 0xca, 0x62, 0x19, 0x0c, 0xb6, + 0xf7, 0x2c, 0xa6, 0xd5, 0xd2, 0x99, 0x9d, 0x18, 0xae, 0xac, 0x11, 0x00, + 0x00, 0x00, 0x36, 0x13, 0x01, 0x13, 0x02, 0x13, 0x03, 0xc0, 0x2c, 0xc0, + 0x2b, 0xc0, 0x30, 0xc0, 0x2f, 0x00, 0x9f, 0x00, 0x9e, 0xcc, 0xa9, 0xcc, + 0xa8, 0xcc, 0xaa, 0xc0, 0x27, 0xc0, 0x23, 0xc0, 0x28, 0xc0, 0x24, 0xc0, + 0x0a, 0xc0, 0x09, 0xc0, 0x14, 0xc0, 0x13, 0x00, 0x6b, 0x00, 0x67, 0x00, + 0x39, 0x00, 0x33, 0xcc, 0x14, 0xcc, 0x13, 0xcc, 0x15, 0x01, 0x00, 0x01, + 0xe2, 0x00, 0x2b, 0x00, 0x03, 0x02, 0xfe, 0xfc, 0x00, 0x0d, 0x00, 0x20, + 0x00, 0x1e, 0x06, 0x03, 0x05, 0x03, 0x04, 0x03, 0x02, 0x03, 0x08, 0x06, + 0x08, 0x0b, 0x08, 0x05, 0x08, 0x0a, 0x08, 0x04, 0x08, 0x09, 0x06, 0x01, + 0x05, 0x01, 0x04, 0x01, 0x03, 0x01, 0x02, 0x01, 0x00, 0x2c, 0x00, 0x45, + 0x00, 0x43, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x2d, 0x00, + 0x03, 0x02, 0x00, 0x01, 0x00, 0x0a, 0x00, 0x0c, 0x00, 0x0a, 0x00, 0x19, + 0x00, 0x18, 0x00, 0x17, 0x00, 0x15, 0x01, 0x00, 0x00, 0x16, 0x00, 0x00, + 0x00, 0x33, 0x01, 0x4b, 0x01, 0x49, 0x00, 0x17, 0x00, 0x41, 0x04, 0x7c, + 0x5a, 0xc2, 0x5a, 0xfd, 0xcd, 0x2b, 0x08, 0xb2, 0xeb, 0x8e, 0xc0, 0x02, + 0x03, 0x9d, 0xb1, 0xc1, 0x0d, 0x7b, 0x7f, 0x46, 0x43, 0xdf, 0xf3, 0xee, + 0x2b, 0x78, 0x0e, 0x29, 0x8c, 0x42, 0x11, 0x2c, 0xde, 0xd7, 0x41, 0x0f, + 0x28, 0x94, 0x80, 0x41, 0x70, 0xc4, 0x17, 0xfd, 0x6d, 0xfa, 0xee, 0x9a, + 0xf2, 0xc4, 0x15, 0x4c, 0x5f, 0x54, 0xb6, 0x78, 0x6e, 0xf9, 0x63, 0x27, + 0x33, 0xb8, 0x7b, 0x01, 0x00, 0x01, 0x00, 0xd4, 0x46, 0x62, 0x9c, 0xbf, + 0x8f, 0x1b, 0x65, 0x9b, 0xf0, 0x29, 0x64, 0xd8, 0x50, 0x0e, 0x74, 0xf1, + 0x58, 0x10, 0xc9, 0xd9, 0x82, 0x5b, 0xd9, 0xbe, 0x14, 0xdf, 0xde, 0x86, + 0xb4, 0x2e, 0x15, 0xee, 0x4f, 0xf6, 0x74, 0x9e, 0x59, 0x11, 0x36, 0x2d, + 0xb9, 0x67, 0xaa, 0x5a, 0x09, 0x9b, 0x45, 0xf1, 0x01, 0x4c, 0x4e, 0xf6, + 0xda, 0x6a, 0xae, 0xa7, 0x73, 0x7b, 0x2e, 0xb6, 0x24, 0x89, 0x99, 0xb7, + 0x52, 0x16, 0x62, 0x0a, 0xab, 0x58, 0xf8, 0x3f, 0x10, 0x5b, 0x83, 0xfd, + 0x7b, 0x81, 0x77, 0x81, 0x8d, 0xef, 0x24, 0x56, 0x6d, 0xba, 0x49, 0xd4, + 0x8b, 0xb5, 0xa0, 0xb1, 0xc9, 0x8c, 0x32, 0x95, 0x1c, 0x5e, 0x0a, 0x4b, + 0xf6, 0x00, 0x50, 0x0a, 0x87, 0x99, 0x59, 0xcf, 0x6f, 0x9d, 0x02, 0xd0, + 0x1b, 0xa1, 0x96, 0x45, 0x28, 0x76, 0x40, 0x33, 0x28, 0xc9, 0xa1, 0xfd, + 0x46, 0xab, 0x2c, 0x9e, 0x5e, 0xc6, 0x74, 0x19, 0x9a, 0xf5, 0x9b, 0x51, + 0x11, 0x4f, 0xc8, 0xb9, 0x99, 0x6b, 0x4e, 0x3e, 0x31, 0x64, 0xb4, 0x92, + 0xf4, 0x0d, 0x41, 0x4b, 0x2c, 0x65, 0x23, 0xf7, 0x47, 0xe3, 0xa5, 0x2e, + 0xe4, 0x9c, 0x2b, 0xc9, 0x41, 0x22, 0x83, 0x8a, 0x23, 0xef, 0x29, 0x7e, + 0x4f, 0x3f, 0xa3, 0xbf, 0x73, 0x2b, 0xd7, 0xcc, 0xc8, 0xc6, 0xe9, 0xbc, + 0x01, 0xb7, 0x32, 0x63, 0xd4, 0x7e, 0x7f, 0x9a, 0xaf, 0x5f, 0x05, 0x31, + 0x53, 0xd6, 0x1f, 0xa2, 0xd0, 0xdf, 0x67, 0x56, 0xf1, 0x9c, 0x4a, 0x9d, + 0x83, 0xb4, 0xef, 0xb3, 0xf2, 0xcc, 0xf1, 0x91, 0x6c, 0x47, 0xc3, 0x8b, + 0xd0, 0x92, 0x79, 0x3d, 0xa0, 0xc0, 0x3a, 0x57, 0x26, 0x6d, 0x0a, 0xad, + 0x5f, 0xad, 0xb4, 0x74, 0x48, 0x4a, 0x51, 0xe1, 0xb5, 0x82, 0x0a, 0x4c, + 0x4f, 0x9d, 0xaf, 0xee, 0x5a, 0xa2, 0x4d, 0x4d, 0x5f, 0xe0, 0x17, 0x00, + 0x23, 0x00, 0x00 + }; + byte alert_reply[50]; + byte expected_alert_reply[] = { + 0x15, 0xfe, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x02, 0x02, 0x2f + }; + + fd = wolfSSL_get_wfd(ssl); + if (fd >= 0) { + ret = (int)send(fd, (MESSAGE_TYPE_CAST)ch_msh_invalid_cookie, + sizeof(ch_msh_invalid_cookie), 0); + AssertIntGT(ret, 0); + /* should reply with an illegal_parameter reply */ + ret = (int)recv(fd, (MESSAGE_TYPE_CAST)alert_reply, sizeof(alert_reply), 0); + AssertIntEQ(ret, sizeof(expected_alert_reply)); + AssertIntEQ(XMEMCMP(alert_reply, expected_alert_reply, + sizeof(expected_alert_reply)), 0); + } +} +#endif + +static word32 test_wolfSSL_dtls_stateless_HashWOLFSSL(const WOLFSSL* ssl) +{ +#ifndef NO_MD5 + enum wc_HashType hashType = WC_HASH_TYPE_MD5; +#elif !defined(NO_SHA) + enum wc_HashType hashType = WC_HASH_TYPE_SHA; +#elif !defined(NO_SHA256) + enum wc_HashType hashType = WC_HASH_TYPE_SHA256; +#else + #error "We need a digest to hash the WOLFSSL object" +#endif + byte hashBuf[WC_MAX_DIGEST_SIZE]; + wc_HashAlg hash; + const TLSX* exts = ssl->extensions; + WOLFSSL sslCopy; /* Use a copy to omit certain fields */ +#ifndef WOLFSSL_SMALL_STACK_CACHE + HS_Hashes* hsHashes = ssl->hsHashes; /* Is re-allocated in + * InitHandshakeHashes */ +#endif + + XMEMCPY(&sslCopy, ssl, sizeof(*ssl)); + XMEMSET(hashBuf, 0, sizeof(hashBuf)); + + /* Following fields are not important to compare */ + XMEMSET(sslCopy.buffers.inputBuffer.staticBuffer, 0, STATIC_BUFFER_LEN); + sslCopy.buffers.inputBuffer.buffer = NULL; + sslCopy.buffers.inputBuffer.bufferSize = 0; + sslCopy.buffers.inputBuffer.dynamicFlag = 0; + sslCopy.buffers.inputBuffer.offset = 0; + XMEMSET(sslCopy.buffers.outputBuffer.staticBuffer, 0, STATIC_BUFFER_LEN); + sslCopy.buffers.outputBuffer.buffer = NULL; + sslCopy.buffers.outputBuffer.bufferSize = 0; + sslCopy.buffers.outputBuffer.dynamicFlag = 0; + sslCopy.buffers.outputBuffer.offset = 0; + sslCopy.error = 0; + sslCopy.curSize = 0; + sslCopy.curStartIdx = 0; + sslCopy.keys.curSeq_lo = 0; + XMEMSET(&sslCopy.curRL, 0, sizeof(sslCopy.curRL)); +#ifdef WOLFSSL_DTLS13 + XMEMSET(&sslCopy.keys.curSeq, 0, sizeof(sslCopy.keys.curSeq)); + sslCopy.dtls13FastTimeout = 0; +#endif + sslCopy.keys.dtls_peer_handshake_number = 0; + XMEMSET(&sslCopy.alert_history, 0, sizeof(sslCopy.alert_history)); + sslCopy.hsHashes = NULL; +#if !defined(WOLFSSL_NO_CLIENT_AUTH) && \ + ((defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3)) || \ + (defined(HAVE_ED25519) && !defined(NO_ED25519_CLIENT_AUTH)) || \ + (defined(HAVE_ED448) && !defined(NO_ED448_CLIENT_AUTH))) + sslCopy.options.cacheMessages = 0; +#endif +#ifdef WOLFSSL_ASYNC_IO +#ifdef WOLFSSL_ASYNC_CRYPT + sslCopy.asyncDev = NULL; +#endif + sslCopy.async = NULL; +#endif + + AssertIntEQ(wc_HashInit(&hash, hashType), 0); + AssertIntEQ(wc_HashUpdate(&hash, hashType, (byte*)&sslCopy, sizeof(sslCopy)), 0); + /* hash extension list */ + while (exts != NULL) { + AssertIntEQ(wc_HashUpdate(&hash, hashType, (byte*)exts, sizeof(*exts)), 0); + exts = exts->next; + } + /* Hash suites */ + if (sslCopy.suites != NULL) { + AssertIntEQ(wc_HashUpdate(&hash, hashType, (byte*)sslCopy.suites, + sizeof(struct Suites)), 0); + } + +#ifdef WOLFSSL_SMALL_STACK_CACHE + /* with WOLFSSL_SMALL_STACK_CACHE, the SHA-2 objects always differ after + * initialization because of cached W and (for SHA512) X buffers. + */ +#else + /* Hash hsHashes */ + AssertIntEQ(wc_HashUpdate(&hash, hashType, (byte*)hsHashes, + sizeof(*hsHashes)), 0); +#endif + + AssertIntEQ(wc_HashFinal(&hash, hashType, hashBuf), 0); + AssertIntEQ(wc_HashFree(&hash, hashType), 0); + + return MakeWordFromHash(hashBuf); +} + +static CallbackIORecv test_wolfSSL_dtls_compare_stateless_cb; +static int test_wolfSSL_dtls_compare_stateless_cb_call_once; +static int test_wolfSSL_dtls_compare_stateless_read_cb_once(WOLFSSL *ssl, + char *buf, int sz, void *ctx) +{ + if (test_wolfSSL_dtls_compare_stateless_cb_call_once) { + test_wolfSSL_dtls_compare_stateless_cb_call_once = 0; + return test_wolfSSL_dtls_compare_stateless_cb(ssl, buf, sz, ctx); + } + else { + return WOLFSSL_CBIO_ERR_WANT_READ; + } +} + +static void test_wolfSSL_dtls_compare_stateless(WOLFSSL* ssl) +{ + /* Compare the ssl object before and after one ClientHello msg */ + SOCKET_T fd = wolfSSL_get_fd(ssl); + int res; + int err; + word32 initHash; + + test_wolfSSL_dtls_compare_stateless_cb = ssl->CBIORecv; + test_wolfSSL_dtls_compare_stateless_cb_call_once = 1; + wolfSSL_dtls_set_using_nonblock(ssl, 1); + ssl->CBIORecv = test_wolfSSL_dtls_compare_stateless_read_cb_once; + + initHash = test_wolfSSL_dtls_stateless_HashWOLFSSL(ssl); + (void)initHash; + + res = tcp_select(fd, 5); + /* We are expecting a msg. A timeout indicates failure. */ + AssertIntEQ(res, TEST_RECV_READY); + + res = wolfSSL_accept(ssl); + err = wolfSSL_get_error(ssl, res); + AssertIntEQ(res, WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)); + AssertIntEQ(err, WOLFSSL_ERROR_WANT_READ); + + AssertIntEQ(initHash, test_wolfSSL_dtls_stateless_HashWOLFSSL(ssl)); + + wolfSSL_dtls_set_using_nonblock(ssl, 0); + ssl->CBIORecv = test_wolfSSL_dtls_compare_stateless_cb; + +} + +#if defined(WOLFSSL_DTLS13) && defined(WOLFSSL_SEND_HRR_COOKIE) +static void test_wolfSSL_dtls_enable_hrrcookie(WOLFSSL* ssl) +{ + int ret; + ret = wolfSSL_send_hrr_cookie(ssl, NULL, 0); + AssertIntEQ(ret, WOLFSSL_SUCCESS); + test_wolfSSL_dtls_compare_stateless(ssl); +} +#endif + +int test_wolfSSL_dtls_stateless(void) +{ + callback_functions client_cbs, server_cbs; + size_t i; + struct { + method_provider client_meth; + method_provider server_meth; + ssl_callback client_ssl_ready; + ssl_callback server_ssl_ready; + } test_params[] = { +#if !defined(WOLFSSL_NO_TLS12) + {wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method, + test_wolfSSL_dtls_send_ch, test_wolfSSL_dtls_compare_stateless}, +#endif +#if defined(WOLFSSL_DTLS13) && defined(WOLFSSL_SEND_HRR_COOKIE) + {wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method, + test_wolfSSL_dtls_send_ch, test_wolfSSL_dtls_enable_hrrcookie}, + {wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method, + test_wolfSSL_dtls_send_ch_with_invalid_cookie, test_wolfSSL_dtls_enable_hrrcookie}, +#endif + }; + + if (0 == sizeof(test_params)){ + return TEST_SKIPPED; + } + + for (i = 0; i < sizeof(test_params)/sizeof(*test_params); i++) { + XMEMSET(&client_cbs, 0, sizeof(client_cbs)); + XMEMSET(&server_cbs, 0, sizeof(server_cbs)); + client_cbs.doUdp = server_cbs.doUdp = 1; + client_cbs.method = test_params[i].client_meth; + server_cbs.method = test_params[i].server_meth; + + client_cbs.ssl_ready = test_params[i].client_ssl_ready; + server_cbs.ssl_ready = test_params[i].server_ssl_ready; + test_wolfSSL_client_server_nofail(&client_cbs, &server_cbs); + + if (!client_cbs.return_code) + return TEST_FAIL; + if (!server_cbs.return_code) + return TEST_FAIL; + } + + return TEST_SUCCESS; +} + +/* DTLS stateless API handling multiple CHs with different HRR groups */ +int test_wolfSSL_dtls_stateless_hrr_group(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_SEND_HRR_COOKIE) + size_t i; + word32 initHash; + struct { + method_provider client_meth; + method_provider server_meth; + } params[] = { +#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_DTLS13) + { wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method }, +#endif +#if !defined(WOLFSSL_NO_TLS12) && defined(WOLFSSL_DTLS) + { wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method }, +#endif + }; + for (i = 0; i < XELEM_CNT(params) && !EXPECT_FAIL(); i++) { + WOLFSSL_CTX *ctx_s = NULL, *ctx_c = NULL; + WOLFSSL *ssl_s = NULL, *ssl_c = NULL, *ssl_c2 = NULL; + struct test_memio_ctx test_ctx; + int groups_1[] = { + WOLFSSL_ECC_SECP256R1, + WOLFSSL_ECC_SECP384R1, + WOLFSSL_ECC_SECP521R1 + }; + int groups_2[] = { + WOLFSSL_ECC_SECP384R1, + WOLFSSL_ECC_SECP521R1 + }; + char hrrBuf[1000]; + int hrrSz = sizeof(hrrBuf); + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + params[i].client_meth, params[i].server_meth), 0); + + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, NULL, &ssl_c2, NULL, + params[i].client_meth, params[i].server_meth), 0); + + + wolfSSL_SetLoggingPrefix("server"); + wolfSSL_dtls_set_using_nonblock(ssl_s, 1); + + initHash = test_wolfSSL_dtls_stateless_HashWOLFSSL(ssl_s); + + /* Set groups and disable key shares. This ensures that only the given + * groups are in the SupportedGroups extension and that an empty key + * share extension is sent in the initial ClientHello of each session. + * This triggers the server to send a HelloRetryRequest with the first + * group in the SupportedGroups extension selected. */ + wolfSSL_SetLoggingPrefix("client1"); + ExpectIntEQ(wolfSSL_set_groups(ssl_c, groups_1, 3), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_NoKeyShares(ssl_c), WOLFSSL_SUCCESS); + + wolfSSL_SetLoggingPrefix("client2"); + ExpectIntEQ(wolfSSL_set_groups(ssl_c2, groups_2, 2), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_NoKeyShares(ssl_c2), WOLFSSL_SUCCESS); + + /* Start handshake, send first ClientHello */ + wolfSSL_SetLoggingPrefix("client1"); + ExpectIntEQ(wolfSSL_connect(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + + /* Read first ClientHello, send HRR with WOLFSSL_ECC_SECP256R1 */ + wolfSSL_SetLoggingPrefix("server"); + ExpectIntEQ(wolfDTLS_accept_stateless(ssl_s), 0); + ExpectIntEQ(test_memio_copy_message(&test_ctx, 1, hrrBuf, &hrrSz, 0), 0); + ExpectIntGT(hrrSz, 0); + ExpectIntEQ(initHash, test_wolfSSL_dtls_stateless_HashWOLFSSL(ssl_s)); + test_memio_clear_buffer(&test_ctx, 1); + + /* Send second ClientHello */ + wolfSSL_SetLoggingPrefix("client2"); + ExpectIntEQ(wolfSSL_connect(ssl_c2), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c2, -1), WOLFSSL_ERROR_WANT_READ); + + /* Read second ClientHello, send HRR now with WOLFSSL_ECC_SECP384R1 */ + wolfSSL_SetLoggingPrefix("server"); + ExpectIntEQ(wolfDTLS_accept_stateless(ssl_s), 0); + ExpectIntEQ(initHash, test_wolfSSL_dtls_stateless_HashWOLFSSL(ssl_s)); + test_memio_clear_buffer(&test_ctx, 1); + + /* Complete first handshake with WOLFSSL_ECC_SECP256R1 */ + wolfSSL_SetLoggingPrefix("client1"); + ExpectIntEQ(test_memio_inject_message(&test_ctx, 1, hrrBuf, hrrSz), 0); + ExpectIntEQ(wolfSSL_connect(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + + wolfSSL_SetLoggingPrefix("server"); + ExpectIntEQ(wolfDTLS_accept_stateless(ssl_s), WOLFSSL_SUCCESS); + + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + + wolfSSL_free(ssl_s); + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_c2); + wolfSSL_CTX_free(ctx_s); + wolfSSL_CTX_free(ctx_c); + } +#endif /* WOLFSSL_SEND_HRR_COOKIE */ + return EXPECT_RESULT(); +} +#else +int test_wolfSSL_dtls_stateless(void) +{ + return TEST_SKIPPED; +} + +int test_wolfSSL_dtls_stateless_hrr_group(void) +{ + return TEST_SKIPPED; +} +#endif /* WOLFSSL_DTLS13 && WOLFSSL_SEND_HRR_COOKIE && + * HAVE_IO_TESTS_DEPENDENCIES && !SINGLE_THREADED */ + +/*----------------------------------------------------------------------------*/ +/* DTLS window updates, fragment buckets, stateless resume/downgrade, alerts */ +/*----------------------------------------------------------------------------*/ + +#ifdef WOLFSSL_DTLS + +/* Prints out the current window */ +static void DUW_TEST_print_window_binary(word32 h, word32 l, word32* w) { +#ifdef WOLFSSL_DEBUG_DTLS_WINDOW + int i; + for (i = WOLFSSL_DTLS_WINDOW_WORDS - 1; i >= 0; i--) { + word32 b = w[i]; + int j; + /* Prints out a 32 bit binary number in big endian order */ + for (j = 0; j < 32; j++, b <<= 1) { + if (b & (((word32)1) << 31)) + fprintf(stderr, "1"); + else + fprintf(stderr, "0"); + } + fprintf(stderr, " "); + } + fprintf(stderr, "cur_hi %u cur_lo %u\n", h, l); +#else + (void)h; + (void)l; + (void)w; +#endif +} + +/* a - cur_hi + * b - cur_lo + * c - next_hi + * d - next_lo + * e - window + * f - expected next_hi + * g - expected next_lo + * h - expected window[1] + * i - expected window[0] + */ +#define DUW_TEST(a,b,c,d,e,f,g,h,i) do { \ + ExpectIntEQ(wolfSSL_DtlsUpdateWindow((a), (b), &(c), &(d), (e)), 1); \ + DUW_TEST_print_window_binary((a), (b), (e)); \ + ExpectIntEQ((c), (f)); \ + ExpectIntEQ((d), (g)); \ + ExpectIntEQ((e)[1], (h)); \ + ExpectIntEQ((e)[0], (i)); \ +} while (0) + +int test_wolfSSL_DtlsUpdateWindow(void) +{ + EXPECT_DECLS; + word32 window[WOLFSSL_DTLS_WINDOW_WORDS]; + word32 next_lo = 0; + word16 next_hi = 0; + +#ifdef WOLFSSL_DEBUG_DTLS_WINDOW + fprintf(stderr, "\n"); +#endif + + XMEMSET(window, 0, sizeof window); + DUW_TEST(0, 0, next_hi, next_lo, window, 0, 1, 0, 0x01); + DUW_TEST(0, 1, next_hi, next_lo, window, 0, 2, 0, 0x03); + DUW_TEST(0, 5, next_hi, next_lo, window, 0, 6, 0, 0x31); + DUW_TEST(0, 4, next_hi, next_lo, window, 0, 6, 0, 0x33); + DUW_TEST(0, 100, next_hi, next_lo, window, 0, 101, 0, 0x01); + DUW_TEST(0, 101, next_hi, next_lo, window, 0, 102, 0, 0x03); + DUW_TEST(0, 133, next_hi, next_lo, window, 0, 134, 0x03, 0x01); + DUW_TEST(0, 200, next_hi, next_lo, window, 0, 201, 0, 0x01); + DUW_TEST(0, 264, next_hi, next_lo, window, 0, 265, 0, 0x01); + DUW_TEST(0, 0xFFFFFFFF, next_hi, next_lo, window, 1, 0, 0, 0x01); + DUW_TEST(0, 0xFFFFFFFD, next_hi, next_lo, window, 1, 0, 0, 0x05); + DUW_TEST(0, 0xFFFFFFFE, next_hi, next_lo, window, 1, 0, 0, 0x07); + DUW_TEST(1, 3, next_hi, next_lo, window, 1, 4, 0, 0x71); + DUW_TEST(1, 0, next_hi, next_lo, window, 1, 4, 0, 0x79); + DUW_TEST(1, 0xFFFFFFFF, next_hi, next_lo, window, 2, 0, 0, 0x01); + DUW_TEST(2, 3, next_hi, next_lo, window, 2, 4, 0, 0x11); + DUW_TEST(2, 0, next_hi, next_lo, window, 2, 4, 0, 0x19); + DUW_TEST(2, 25, next_hi, next_lo, window, 2, 26, 0, 0x6400001); + DUW_TEST(2, 27, next_hi, next_lo, window, 2, 28, 0, 0x19000005); + DUW_TEST(2, 29, next_hi, next_lo, window, 2, 30, 0, 0x64000015); + DUW_TEST(2, 33, next_hi, next_lo, window, 2, 34, 6, 0x40000151); + DUW_TEST(2, 60, next_hi, next_lo, window, 2, 61, 0x3200000A, 0x88000001); + DUW_TEST(1, 0xFFFFFFF0, next_hi, next_lo, window, 2, 61, 0x3200000A, 0x88000001); + DUW_TEST(2, 0xFFFFFFFD, next_hi, next_lo, window, 2, 0xFFFFFFFE, 0, 0x01); + DUW_TEST(3, 1, next_hi, next_lo, window, 3, 2, 0, 0x11); + DUW_TEST(99, 66, next_hi, next_lo, window, 99, 67, 0, 0x01); + DUW_TEST(50, 66, next_hi, next_lo, window, 99, 67, 0, 0x01); + DUW_TEST(100, 68, next_hi, next_lo, window, 100, 69, 0, 0x01); + DUW_TEST(99, 50, next_hi, next_lo, window, 100, 69, 0, 0x01); + DUW_TEST(99, 0xFFFFFFFF, next_hi, next_lo, window, 100, 69, 0, 0x01); + DUW_TEST(150, 0xFFFFFFFF, next_hi, next_lo, window, 151, 0, 0, 0x01); + DUW_TEST(152, 0xFFFFFFFF, next_hi, next_lo, window, 153, 0, 0, 0x01); + + return EXPECT_RESULT(); +} +#else +int test_wolfSSL_DtlsUpdateWindow(void) +{ + return TEST_SKIPPED; +} +#endif /* WOLFSSL_DTLS */ + +#ifdef WOLFSSL_DTLS +static int DFB_TEST(WOLFSSL* ssl, word32 seq, word32 len, word32 f_offset, + word32 f_len, word32 f_count, byte ready, word32 bytesReceived) +{ + EXPECT_DECLS; + DtlsMsg* cur = NULL; + static byte msg[100]; + static byte msgInit = 0; + + if (!msgInit) { + int i; + for (i = 0; i < 100; i++) + msg[i] = i + 1; + msgInit = 1; + } + + /* Sanitize test parameters */ + ExpectIntLE(len, sizeof(msg)); + ExpectIntLE(f_offset + f_len, sizeof(msg)); + + if (EXPECT_SUCCESS()) + DtlsMsgStore(ssl, 0, seq, msg + f_offset, len, certificate, f_offset, f_len, NULL); + + ExpectNotNull(ssl->dtls_rx_msg_list); + + ExpectNotNull(cur = DtlsMsgFind(ssl->dtls_rx_msg_list, 0, seq)); + ExpectIntEQ(cur->fragBucketListCount, f_count); + ExpectIntEQ(cur->ready, ready); + ExpectIntEQ(cur->bytesReceived, bytesReceived); + if (ready) { + ExpectNull(cur->fragBucketList); + ExpectBufEQ(cur->fullMsg, msg, cur->sz); + } + else { + DtlsFragBucket* fb; + ExpectNotNull(cur->fragBucketList); + for (fb = cur != NULL ? cur->fragBucketList : NULL; + EXPECT_SUCCESS() && fb != NULL; fb = fb->m.m.next) + ExpectBufEQ(fb->buf, msg + fb->m.m.offset, fb->m.m.sz); + } + if (EXPECT_FAIL()) { + printf("Test parameters: seq %u len %u f_offset %u f_len %u f_count %u ready %u bytesReceived %u\n", + seq, len, f_offset, f_len, f_count, ready, bytesReceived); + } + return EXPECT_RESULT(); +} + +int test_wolfSSL_DTLS_fragment_buckets(void) +{ + EXPECT_DECLS; + WOLFSSL ssl[1]; + + XMEMSET(ssl, 0, sizeof(*ssl)); + + EXPECT_TEST(DFB_TEST(ssl, 0, 100, 0, 100, 0, 1, 100)); /* 0-100 */ + + EXPECT_TEST(DFB_TEST(ssl, 1, 100, 0, 20, 1, 0, 20)); /* 0-20 */ + EXPECT_TEST(DFB_TEST(ssl, 1, 100, 20, 20, 1, 0, 40)); /* 20-40 */ + EXPECT_TEST(DFB_TEST(ssl, 1, 100, 40, 20, 1, 0, 60)); /* 40-60 */ + EXPECT_TEST(DFB_TEST(ssl, 1, 100, 60, 20, 1, 0, 80)); /* 60-80 */ + EXPECT_TEST(DFB_TEST(ssl, 1, 100, 80, 20, 0, 1, 100)); /* 80-100 */ + + /* Test all permutations of 3 regions */ + /* 1 2 3 */ + EXPECT_TEST(DFB_TEST(ssl, 2, 100, 0, 30, 1, 0, 30)); /* 0-30 */ + EXPECT_TEST(DFB_TEST(ssl, 2, 100, 30, 30, 1, 0, 60)); /* 30-60 */ + EXPECT_TEST(DFB_TEST(ssl, 2, 100, 60, 40, 0, 1, 100)); /* 60-100 */ + /* 1 3 2 */ + EXPECT_TEST(DFB_TEST(ssl, 3, 100, 0, 30, 1, 0, 30)); /* 0-30 */ + EXPECT_TEST(DFB_TEST(ssl, 3, 100, 60, 40, 2, 0, 70)); /* 60-100 */ + EXPECT_TEST(DFB_TEST(ssl, 3, 100, 30, 30, 0, 1, 100)); /* 30-60 */ + /* 2 1 3 */ + EXPECT_TEST(DFB_TEST(ssl, 4, 100, 30, 30, 1, 0, 30)); /* 30-60 */ + EXPECT_TEST(DFB_TEST(ssl, 4, 100, 0, 30, 1, 0, 60)); /* 0-30 */ + EXPECT_TEST(DFB_TEST(ssl, 4, 100, 60, 40, 0, 1, 100)); /* 60-100 */ + /* 2 3 1 */ + EXPECT_TEST(DFB_TEST(ssl, 5, 100, 30, 30, 1, 0, 30)); /* 30-60 */ + EXPECT_TEST(DFB_TEST(ssl, 5, 100, 60, 40, 1, 0, 70)); /* 60-100 */ + EXPECT_TEST(DFB_TEST(ssl, 5, 100, 0, 30, 0, 1, 100)); /* 0-30 */ + /* 3 1 2 */ + EXPECT_TEST(DFB_TEST(ssl, 6, 100, 60, 40, 1, 0, 40)); /* 60-100 */ + EXPECT_TEST(DFB_TEST(ssl, 6, 100, 0, 30, 2, 0, 70)); /* 0-30 */ + EXPECT_TEST(DFB_TEST(ssl, 6, 100, 30, 30, 0, 1, 100)); /* 30-60 */ + /* 3 2 1 */ + EXPECT_TEST(DFB_TEST(ssl, 7, 100, 60, 40, 1, 0, 40)); /* 60-100 */ + EXPECT_TEST(DFB_TEST(ssl, 7, 100, 30, 30, 1, 0, 70)); /* 30-60 */ + EXPECT_TEST(DFB_TEST(ssl, 7, 100, 0, 30, 0, 1, 100)); /* 0-30 */ + + /* Test overlapping regions */ + EXPECT_TEST(DFB_TEST(ssl, 8, 100, 0, 30, 1, 0, 30)); /* 0-30 */ + EXPECT_TEST(DFB_TEST(ssl, 8, 100, 20, 10, 1, 0, 30)); /* 20-30 */ + EXPECT_TEST(DFB_TEST(ssl, 8, 100, 70, 10, 2, 0, 40)); /* 70-80 */ + EXPECT_TEST(DFB_TEST(ssl, 8, 100, 20, 30, 2, 0, 60)); /* 20-50 */ + EXPECT_TEST(DFB_TEST(ssl, 8, 100, 40, 60, 0, 1, 100)); /* 40-100 */ + + /* Test overlapping multiple regions */ + EXPECT_TEST(DFB_TEST(ssl, 9, 100, 0, 20, 1, 0, 20)); /* 0-20 */ + EXPECT_TEST(DFB_TEST(ssl, 9, 100, 30, 5, 2, 0, 25)); /* 30-35 */ + EXPECT_TEST(DFB_TEST(ssl, 9, 100, 40, 5, 3, 0, 30)); /* 40-45 */ + EXPECT_TEST(DFB_TEST(ssl, 9, 100, 50, 5, 4, 0, 35)); /* 50-55 */ + EXPECT_TEST(DFB_TEST(ssl, 9, 100, 60, 5, 5, 0, 40)); /* 60-65 */ + EXPECT_TEST(DFB_TEST(ssl, 9, 100, 70, 5, 6, 0, 45)); /* 70-75 */ + EXPECT_TEST(DFB_TEST(ssl, 9, 100, 30, 25, 4, 0, 55)); /* 30-55 */ + EXPECT_TEST(DFB_TEST(ssl, 9, 100, 55, 15, 2, 0, 65)); /* 55-70 */ + EXPECT_TEST(DFB_TEST(ssl, 9, 100, 75, 25, 2, 0, 90)); /* 75-100 */ + EXPECT_TEST(DFB_TEST(ssl, 9, 100, 10, 25, 0, 1, 100)); /* 10-35 */ + + EXPECT_TEST(DFB_TEST(ssl,10, 100, 0, 20, 1, 0, 20)); /* 0-20 */ + EXPECT_TEST(DFB_TEST(ssl,10, 100, 30, 20, 2, 0, 40)); /* 30-50 */ + EXPECT_TEST(DFB_TEST(ssl,10, 100, 0, 40, 1, 0, 50)); /* 0-40 */ + EXPECT_TEST(DFB_TEST(ssl,10, 100, 50, 50, 0, 1, 100)); /* 50-100 */ + + /* Test region between other regions */ + EXPECT_TEST(DFB_TEST(ssl,11, 100, 0, 20, 1, 0, 20)); /* 0-20 */ + EXPECT_TEST(DFB_TEST(ssl,11, 100, 80, 20, 2, 0, 40)); /* 80-100 */ + EXPECT_TEST(DFB_TEST(ssl,11, 100, 40, 20, 3, 0, 60)); /* 40-60 */ + EXPECT_TEST(DFB_TEST(ssl,11, 100, 20, 20, 2, 0, 80)); /* 20-40 */ + EXPECT_TEST(DFB_TEST(ssl,11, 100, 60, 20, 0, 1, 100)); /* 60-80 */ + + /* Test gap before first bucket (prev==NULL in gap-before branch) */ + EXPECT_TEST(DFB_TEST(ssl,12, 100, 50, 20, 1, 0, 20)); /* 50-70 */ + EXPECT_TEST(DFB_TEST(ssl,12, 100, 0, 20, 2, 0, 40)); /* 0-20 gap before first */ + EXPECT_TEST(DFB_TEST(ssl,12, 100, 20, 30, 1, 0, 70)); /* 20-50 bridges gap */ + EXPECT_TEST(DFB_TEST(ssl,12, 100, 70, 30, 0, 1, 100)); /* 70-100 */ + + /* Test fragment after message is already complete (ready early return) */ + EXPECT_TEST(DFB_TEST(ssl,13, 100, 0,100, 0, 1, 100)); /* 0-100 complete */ + EXPECT_TEST(DFB_TEST(ssl,13, 100, 0, 50, 0, 1, 100)); /* 0-50 dup on ready */ + + /* Test combine where next bucket is larger than cur (chosenBucket=&next) */ + EXPECT_TEST(DFB_TEST(ssl,14, 100, 0, 10, 1, 0, 10)); /* 0-10 */ + EXPECT_TEST(DFB_TEST(ssl,14, 100, 30, 50, 2, 0, 60)); /* 30-80 */ + EXPECT_TEST(DFB_TEST(ssl,14, 100, 5, 30, 1, 0, 80)); /* 5-35 next>cur */ + EXPECT_TEST(DFB_TEST(ssl,14, 100, 80, 20, 0, 1, 100)); /* 80-100 */ + + /* Test super fragment covering all existing buckets */ + EXPECT_TEST(DFB_TEST(ssl,15, 100, 10, 10, 1, 0, 10)); /* 10-20 */ + EXPECT_TEST(DFB_TEST(ssl,15, 100, 30, 10, 2, 0, 20)); /* 30-40 */ + EXPECT_TEST(DFB_TEST(ssl,15, 100, 60, 10, 3, 0, 30)); /* 60-70 */ + EXPECT_TEST(DFB_TEST(ssl,15, 100, 0,100, 0, 1, 100)); /* 0-100 super frag */ + + /* Test exact duplicate fragment */ + EXPECT_TEST(DFB_TEST(ssl,16, 100, 20, 40, 1, 0, 40)); /* 20-60 */ + EXPECT_TEST(DFB_TEST(ssl,16, 100, 20, 40, 1, 0, 40)); /* 20-60 exact dup */ + EXPECT_TEST(DFB_TEST(ssl,16, 100, 0, 20, 1, 0, 60)); /* 0-20 */ + EXPECT_TEST(DFB_TEST(ssl,16, 100, 60, 40, 0, 1, 100)); /* 60-100 */ + + /* Test combine bridging two buckets (combineNext, cur->data) */ + EXPECT_TEST(DFB_TEST(ssl,17, 100, 0, 30, 1, 0, 30)); /* 0-30 */ + EXPECT_TEST(DFB_TEST(ssl,17, 100, 60, 20, 2, 0, 50)); /* 60-80 */ + EXPECT_TEST(DFB_TEST(ssl,17, 100, 20, 45, 1, 0, 80)); /* 20-65 bridge */ + EXPECT_TEST(DFB_TEST(ssl,17, 100, 80, 20, 0, 1, 100)); /* 80-100 */ + + /* Test progressive left-extension with partial overlaps */ + EXPECT_TEST(DFB_TEST(ssl,18, 100, 70, 30, 1, 0, 30)); /* 70-100 */ + EXPECT_TEST(DFB_TEST(ssl,18, 100, 50, 30, 1, 0, 50)); /* 50-80 extend left */ + EXPECT_TEST(DFB_TEST(ssl,18, 100, 30, 30, 1, 0, 70)); /* 30-60 extend left */ + EXPECT_TEST(DFB_TEST(ssl,18, 100, 0, 40, 0, 1, 100)); /* 0-40 complete left */ + + DtlsMsgListDelete(ssl->dtls_rx_msg_list, ssl->heap); + ssl->dtls_rx_msg_list = NULL; + ssl->dtls_rx_msg_list_sz = 0; + return EXPECT_RESULT(); +} + +#else +int test_wolfSSL_DTLS_fragment_buckets(void) +{ + return TEST_SKIPPED; +} +#endif + + +#if !defined(NO_FILESYSTEM) && \ + defined(WOLFSSL_DTLS) && !defined(WOLFSSL_NO_TLS12) && \ + defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && !defined(NO_RSA) + +int test_wolfSSL_dtls_stateless2(void) +{ + EXPECT_DECLS; + WOLFSSL *ssl_c = NULL; + WOLFSSL *ssl_c2 = NULL; + WOLFSSL *ssl_s = NULL; + struct test_memio_ctx test_ctx; + WOLFSSL_CTX *ctx_c = NULL; + WOLFSSL_CTX *ctx_s = NULL; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method), 0); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, NULL, &ssl_c2, NULL, + wolfDTLSv1_2_client_method, NULL), 0); + ExpectFalse(wolfSSL_is_stateful(ssl_s)); + /* send CH */ + ExpectTrue((wolfSSL_connect(ssl_c2) == WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)) && + (ssl_c2->error == WC_NO_ERR_TRACE(WANT_READ))); + ExpectIntEQ(wolfDTLS_accept_stateless(ssl_s), WOLFSSL_FAILURE); + ExpectFalse(wolfSSL_is_stateful(ssl_s)); + ExpectIntNE(test_ctx.c_len, 0); + /* consume HRR */ + test_memio_clear_buffer(&test_ctx, 1); + /* send CH1 */ + ExpectIntEQ(wolfSSL_connect(ssl_c), WOLFSSL_FATAL_ERROR); + ExpectIntEQ(wolfSSL_get_error(ssl_c, WOLFSSL_FATAL_ERROR), + WOLFSSL_ERROR_WANT_READ); + /* send HRR */ + ExpectIntEQ(wolfDTLS_accept_stateless(ssl_s), WOLFSSL_FAILURE); + /* send CH2 */ + ExpectIntEQ(wolfSSL_connect(ssl_c), WOLFSSL_FATAL_ERROR); + ExpectIntEQ(wolfSSL_get_error(ssl_c, WOLFSSL_FATAL_ERROR), + WOLFSSL_ERROR_WANT_READ); + /* send HRR */ + ExpectIntEQ(wolfDTLS_accept_stateless(ssl_s), WOLFSSL_SUCCESS); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + ExpectTrue(wolfSSL_is_stateful(ssl_s)); + + wolfSSL_free(ssl_c2); + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); + return EXPECT_RESULT(); +} + +int test_wolfSSL_dtls_stateless_maxfrag(void) +{ + EXPECT_DECLS; +#ifdef HAVE_MAX_FRAGMENT + WOLFSSL *ssl_c = NULL; + WOLFSSL *ssl_c2 = NULL; + WOLFSSL *ssl_s = NULL; + struct test_memio_ctx test_ctx; + WOLFSSL_CTX *ctx_c = NULL; + WOLFSSL_CTX *ctx_s = NULL; + word16 max_fragment = 0; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method), 0); + ExpectNotNull(ssl_s); + ExpectNotNull(ssl_c2 = wolfSSL_new(ctx_c)); + ExpectIntEQ(wolfSSL_UseMaxFragment(ssl_c2, WOLFSSL_MFL_2_8), + WOLFSSL_SUCCESS); + wolfSSL_SetIOWriteCtx(ssl_c2, &test_ctx); + wolfSSL_SetIOReadCtx(ssl_c2, &test_ctx); + if (EXPECT_SUCCESS()) { + max_fragment = ssl_s->max_fragment; + } + /* send CH */ + ExpectTrue((wolfSSL_connect(ssl_c2) == WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)) && + (ssl_c2->error == WC_NO_ERR_TRACE(WANT_READ))); + ExpectTrue((wolfSSL_accept(ssl_s) == WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)) && + (ssl_s->error == WC_NO_ERR_TRACE(WANT_READ))); + /* CH without cookie shouldn't change state */ + ExpectIntEQ(ssl_s->max_fragment, max_fragment); + ExpectIntNE(test_ctx.c_len, 0); + + /* consume HRR from buffer */ + test_memio_clear_buffer(&test_ctx, 1); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + + wolfSSL_free(ssl_c2); + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); +#endif /* HAVE_MAX_FRAGMENT */ + return EXPECT_RESULT(); +} + +#if defined(WOLFSSL_DTLS_NO_HVR_ON_RESUME) +#define ROUNDS_WITH_HVR 4 +#define ROUNDS_WITHOUT_HVR 2 +#define HANDSHAKE_TYPE_OFFSET DTLS_RECORD_HEADER_SZ +static int buf_is_hvr(const byte *data, int len) +{ + if (len < DTLS_RECORD_HEADER_SZ + DTLS_HANDSHAKE_HEADER_SZ) + return 0; + return data[HANDSHAKE_TYPE_OFFSET] == hello_verify_request; +} + +static int _test_wolfSSL_dtls_stateless_resume(byte useticket, byte bad) +{ + EXPECT_DECLS; + struct test_memio_ctx test_ctx; + WOLFSSL_CTX *ctx_c = NULL; + WOLFSSL_CTX *ctx_s = NULL; + WOLFSSL *ssl_c = NULL; + WOLFSSL *ssl_s = NULL; + WOLFSSL_SESSION *sess = NULL; + int round_trips; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, + &ssl_s, wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method), 0); +#ifdef HAVE_SESSION_TICKET + if (useticket) { + ExpectIntEQ(wolfSSL_UseSessionTicket(ssl_c), WOLFSSL_SUCCESS); + } +#endif + round_trips = ROUNDS_WITH_HVR; + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, round_trips, + &round_trips), 0); + ExpectIntEQ(round_trips, ROUNDS_WITH_HVR); + ExpectNotNull(sess = wolfSSL_get1_session(ssl_c)); + wolfSSL_shutdown(ssl_c); + wolfSSL_shutdown(ssl_s); + wolfSSL_free(ssl_c); + ssl_c = NULL; + wolfSSL_free(ssl_s); + ssl_s = NULL; + + test_memio_clear_buffer(&test_ctx, 1); + test_memio_clear_buffer(&test_ctx, 0); + /* make resumption invalid */ + if (bad && (sess != NULL)) { + if (useticket) { +#ifdef HAVE_SESSION_TICKET + if (sess->ticket != NULL) { + sess->ticket[0] = !sess->ticket[0]; + } +#endif /* HAVE_SESSION_TICKET */ + } + else { + sess->sessionID[0] = !sess->sessionID[0]; + } + } + ExpectNotNull(ssl_c = wolfSSL_new(ctx_c)); + ExpectNotNull(ssl_s = wolfSSL_new(ctx_s)); + wolfSSL_SetIOWriteCtx(ssl_c, &test_ctx); + wolfSSL_SetIOReadCtx(ssl_c, &test_ctx); + wolfSSL_SetIOWriteCtx(ssl_s, &test_ctx); + wolfSSL_SetIOReadCtx(ssl_s, &test_ctx); + ExpectIntEQ(wolfSSL_set_session(ssl_c, sess), WOLFSSL_SUCCESS); + ExpectTrue((wolfSSL_connect(ssl_c) == WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)) && + (ssl_c->error == WC_NO_ERR_TRACE(WANT_READ))); + ExpectTrue((wolfSSL_accept(ssl_s) == WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)) && + (ssl_s->error == WC_NO_ERR_TRACE(WANT_READ))); + ExpectFalse(bad && !buf_is_hvr(test_ctx.c_buff, test_ctx.c_len)); + ExpectFalse(!bad && buf_is_hvr(test_ctx.c_buff, test_ctx.c_len)); + if (!useticket) { + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, &round_trips), 0); + ExpectFalse(bad && round_trips != ROUNDS_WITH_HVR - 1); + ExpectFalse(!bad && round_trips != ROUNDS_WITHOUT_HVR - 1); + } + wolfSSL_SESSION_free(sess); + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); + return EXPECT_RESULT(); +} + +int test_wolfSSL_dtls_stateless_resume(void) +{ + EXPECT_DECLS; +#ifdef HAVE_SESSION_TICKET + ExpectIntEQ(_test_wolfSSL_dtls_stateless_resume(1, 0), TEST_SUCCESS); + ExpectIntEQ(_test_wolfSSL_dtls_stateless_resume(1, 1), TEST_SUCCESS); +#endif /* HAVE_SESION_TICKET */ + ExpectIntEQ(_test_wolfSSL_dtls_stateless_resume(0, 0), TEST_SUCCESS); + ExpectIntEQ(_test_wolfSSL_dtls_stateless_resume(0, 1), TEST_SUCCESS); + return EXPECT_RESULT(); +} +#else +int test_wolfSSL_dtls_stateless_resume(void) +{ + return TEST_SKIPPED; +} +#endif /* WOLFSSL_DTLS_NO_HVR_ON_RESUME */ + +int test_wolfSSL_dtls_stateless_downgrade(void) +{ + EXPECT_DECLS; +#if !defined(NO_OLD_TLS) + WOLFSSL_CTX *ctx_c = NULL; + WOLFSSL_CTX *ctx_c2 = NULL; + WOLFSSL_CTX *ctx_s = NULL; + WOLFSSL *ssl_c = NULL; + WOLFSSL *ssl_c2 = NULL; + WOLFSSL *ssl_s = NULL; + struct test_memio_ctx test_ctx; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method), 0); + ExpectIntEQ(wolfSSL_CTX_SetMinVersion(ctx_s, WOLFSSL_DTLSV1), + WOLFSSL_SUCCESS); + ExpectNotNull(ctx_c2 = wolfSSL_CTX_new(wolfDTLSv1_client_method())); + wolfSSL_SetIORecv(ctx_c2, test_memio_read_cb); + wolfSSL_SetIOSend(ctx_c2, test_memio_write_cb); + ExpectNotNull(ssl_c2 = wolfSSL_new(ctx_c2)); + wolfSSL_SetIOWriteCtx(ssl_c2, &test_ctx); + wolfSSL_SetIOReadCtx(ssl_c2, &test_ctx); + /* send CH */ + ExpectTrue((wolfSSL_connect(ssl_c2) == WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)) && + (ssl_c2->error == WC_NO_ERR_TRACE(WANT_READ))); + ExpectTrue((wolfSSL_accept(ssl_s) == WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)) && + (ssl_s->error == WC_NO_ERR_TRACE(WANT_READ))); + ExpectIntNE(test_ctx.c_len, 0); + /* consume HRR */ + test_memio_clear_buffer(&test_ctx, 1); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + + wolfSSL_free(ssl_c2); + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_c2); + wolfSSL_CTX_free(ctx_s); +#endif + return EXPECT_RESULT(); +} + +#else /* outer wrap: WOLFSSL_DTLS && !WOLFSSL_NO_TLS12 && client/server && !NO_RSA */ +int test_wolfSSL_dtls_stateless2(void) +{ + return TEST_SKIPPED; +} +int test_wolfSSL_dtls_stateless_maxfrag(void) +{ + return TEST_SKIPPED; +} +int test_wolfSSL_dtls_stateless_resume(void) +{ + return TEST_SKIPPED; +} +int test_wolfSSL_dtls_stateless_downgrade(void) +{ + return TEST_SKIPPED; +} +#endif /* defined(WOLFSSL_DTLS) && !defined(WOLFSSL_NO_TLS12) && \ + !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)*/ + +#if defined(WOLFSSL_DTLS) && !defined(WOLFSSL_NO_TLS12) && \ + !defined(NO_OLD_TLS) && defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) +int test_WOLFSSL_dtls_version_alert(void) +{ + EXPECT_DECLS; + struct test_memio_ctx test_ctx; + WOLFSSL_CTX *ctx_c = NULL; + WOLFSSL_CTX *ctx_s = NULL; + WOLFSSL *ssl_c = NULL; + WOLFSSL *ssl_s = NULL; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLSv1_2_client_method, wolfDTLSv1_server_method), 0); + + /* client hello */ + ExpectTrue((wolfSSL_connect(ssl_c) == WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)) && + (ssl_c->error == WC_NO_ERR_TRACE(WANT_READ))); + /* hrr */ + ExpectTrue((wolfSSL_accept(ssl_s) == WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)) && + (ssl_s->error == WC_NO_ERR_TRACE(WANT_READ))); + /* client hello 1 */ + ExpectTrue((wolfSSL_connect(ssl_c) == WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)) && + (ssl_c->error == WC_NO_ERR_TRACE(WANT_READ))); + /* server hello */ + ExpectTrue((wolfSSL_accept(ssl_s) == WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)) && + (ssl_s->error == WC_NO_ERR_TRACE(WANT_READ))); + /* should fail */ + ExpectTrue((wolfSSL_connect(ssl_c) == WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)) && + (ssl_c->error == WC_NO_ERR_TRACE(VERSION_ERROR))); + /* shuould fail */ + ExpectTrue((wolfSSL_accept(ssl_s) == WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)) && + (ssl_s->error == WC_NO_ERR_TRACE(VERSION_ERROR) || ssl_s->error == WC_NO_ERR_TRACE(FATAL_ERROR))); + + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); + + return EXPECT_RESULT(); +} +#else +int test_WOLFSSL_dtls_version_alert(void) +{ + return TEST_SKIPPED; +} +#endif /* defined(WOLFSSL_DTLS) && !defined(WOLFSSL_NO_TLS12) && + * !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) && + * !defined(NO_OLD_TLS) && !defined(NO_RSA) + */ + +/*----------------------------------------------------------------------------*/ +/* Remaining DTLS tests moved out of api.c (msg, ipv6, downgrade, ccs, etc.) */ +/*----------------------------------------------------------------------------*/ + +/*-- msg_helpers_and_from_other_peer (api.c lines 30572,30671) ---*/ +#if defined(WOLFSSL_DTLS) && !defined(WOLFSSL_NO_TLS12) && \ + !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) && \ + !defined(SINGLE_THREADED) && !defined(NO_RSA) + +static int test_dtls_msg_get_connected_port(int fd, word16 *port) +{ + SOCKADDR_S peer; + XSOCKLENT len; + int ret; + + XMEMSET((byte*)&peer, 0, sizeof(peer)); + len = sizeof(peer); + ret = getpeername(fd, (SOCKADDR*)&peer, &len); + if (ret != 0 || len > (XSOCKLENT)sizeof(peer)) + return -1; + switch (peer.ss_family) { +#ifdef WOLFSSL_IPV6 + case WOLFSSL_IP6: { + *port = ntohs(((SOCKADDR_IN6*)&peer)->sin6_port); + break; + } +#endif /* WOLFSSL_IPV6 */ + case WOLFSSL_IP4: + *port = ntohs(((SOCKADDR_IN*)&peer)->sin_port); + break; + default: + return -1; + } + return 0; +} + +static int test_dtls_msg_from_other_peer_cb(WOLFSSL_CTX *ctx, WOLFSSL *ssl) +{ + char buf[1] = {'t'}; + SOCKADDR_IN_T addr; + int sock_fd; + word16 port; + int err; + + (void)ssl; + (void)ctx; + + if (ssl == NULL) + return -1; + + err = test_dtls_msg_get_connected_port(wolfSSL_get_fd(ssl), &port); + if (err != 0) + return -1; + + sock_fd = socket(AF_INET_V, SOCK_DGRAM, 0); + if (sock_fd == -1) + return -1; + build_addr(&addr, wolfSSLIP, port, 1, 0); + + /* send a packet to the server. Being another socket, the kernel will ensure + * the source port will be different. */ + err = (int)sendto(sock_fd, buf, sizeof(buf), 0, (SOCKADDR*)&addr, + sizeof(addr)); + + close(sock_fd); + if (err == -1) + return -1; + + return 0; +} + +/* setup a SSL session but just after the handshake send a packet to the server + * with a source address different than the one of the connected client. The I/O + * callback EmbedRecvFrom should just ignore the packet. Sending of the packet + * is done in test_dtls_msg_from_other_peer_cb */ +int test_dtls_msg_from_other_peer(void) +{ + EXPECT_DECLS; + callback_functions client_cbs; + callback_functions server_cbs; + + XMEMSET((byte*)&client_cbs, 0, sizeof(client_cbs)); + XMEMSET((byte*)&server_cbs, 0, sizeof(server_cbs)); + + client_cbs.method = wolfDTLSv1_2_client_method; + server_cbs.method = wolfDTLSv1_2_server_method; + client_cbs.doUdp = 1; + server_cbs.doUdp = 1; + + test_wolfSSL_client_server_nofail_ex(&client_cbs, &server_cbs, + test_dtls_msg_from_other_peer_cb); + + ExpectIntEQ(client_cbs.return_code, WOLFSSL_SUCCESS); + ExpectIntEQ(server_cbs.return_code, WOLFSSL_SUCCESS); + + return EXPECT_RESULT(); +} +#else +int test_dtls_msg_from_other_peer(void) +{ + return TEST_SKIPPED; +} +#endif /* defined(WOLFSSL_DTLS) && !defined(WOLFSSL_NO_TLS12) && \ + * !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) && \ + * !defined(SINGLE_THREADED) && !defined(NO_RSA) */ + +/*-- ipv6_check (api.c lines 30672,30730) ---*/ +#if defined(WOLFSSL_DTLS) && !defined(WOLFSSL_IPV6) && \ + !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) && \ + defined(HAVE_IO_TESTS_DEPENDENCIES) && !defined(WOLFSSL_NO_TLS12) \ + && !defined(USE_WINDOWS_API) +int test_dtls_ipv6_check(void) +{ + EXPECT_DECLS; + WOLFSSL_CTX *ctx_c = NULL; + WOLFSSL_CTX *ctx_s = NULL; + WOLFSSL *ssl_c = NULL; + WOLFSSL *ssl_s = NULL; + SOCKADDR_IN fake_addr6; + int sockfd = -1; + + ExpectNotNull(ctx_c = wolfSSL_CTX_new(wolfDTLSv1_2_client_method())); + ExpectNotNull(ssl_c = wolfSSL_new(ctx_c)); + ExpectNotNull(ctx_s = wolfSSL_CTX_new(wolfDTLSv1_2_server_method())); + ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_file(ctx_s, svrKeyFile, + WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_use_certificate_file(ctx_s, svrCertFile, + WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS); + ExpectNotNull(ssl_s = wolfSSL_new(ctx_s)); + XMEMSET((byte*)&fake_addr6, 0, sizeof(fake_addr6)); + /* mimic a sockaddr_in6 struct, this way we can't test without + * WOLFSSL_IPV6 */ + fake_addr6.sin_family = WOLFSSL_IP6; + ExpectIntNE(sockfd = socket(AF_INET, SOCK_DGRAM, 0), -1); + ExpectIntEQ(wolfSSL_set_fd(ssl_c, sockfd), WOLFSSL_SUCCESS); + /* can't return error here, as the peer is opaque for wolfssl library at + * this point */ + ExpectIntEQ(wolfSSL_dtls_set_peer(ssl_c, &fake_addr6, sizeof(fake_addr6)), + WOLFSSL_SUCCESS); + ExpectIntNE(fcntl(sockfd, F_SETFL, O_NONBLOCK), -1); + wolfSSL_dtls_set_using_nonblock(ssl_c, 1); + ExpectIntNE(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS); + ExpectIntEQ(ssl_c->error, WC_NO_ERR_TRACE(SOCKET_ERROR_E)); + + ExpectIntEQ(wolfSSL_dtls_set_peer(ssl_s, &fake_addr6, sizeof(fake_addr6)), + WOLFSSL_SUCCESS); + /* reuse the socket */ + ExpectIntEQ(wolfSSL_set_fd(ssl_c, sockfd), WOLFSSL_SUCCESS); + wolfSSL_dtls_set_using_nonblock(ssl_s, 1); + ExpectIntNE(wolfSSL_accept(ssl_s), WOLFSSL_SUCCESS); + ExpectIntEQ(ssl_s->error, WC_NO_ERR_TRACE(SOCKET_ERROR_E)); + if (sockfd != -1) + close(sockfd); + + wolfSSL_free(ssl_c); + wolfSSL_CTX_free(ctx_c); + wolfSSL_free(ssl_s); wolfSSL_CTX_free(ctx_s); + return EXPECT_RESULT(); +} +#else +int test_dtls_ipv6_check(void) +{ + return TEST_SKIPPED; +} +#endif + +/*-- no_extensions (api.c lines 30824,30913) ---*/ +int test_dtls_no_extensions(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_DTLS) && defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \ + !defined(WOLFSSL_NO_TLS12) + WOLFSSL *ssl_s = NULL; + WOLFSSL_CTX *ctx_s = NULL; + struct test_memio_ctx test_ctx; + const byte chNoExtensions[] = { + /* Handshake type */ + 0x16, + /* Version */ + 0xfe, 0xff, + /* Epoch */ + 0x00, 0x00, + /* Seq number */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* Length */ + 0x00, 0x40, + /* CH type */ + 0x01, + /* Length */ + 0x00, 0x00, 0x34, + /* Msg Seq */ + 0x00, 0x00, + /* Frag offset */ + 0x00, 0x00, 0x00, + /* Frag length */ + 0x00, 0x00, 0x34, + /* Version */ + 0xfe, 0xff, + /* Random */ + 0x62, 0xfe, 0xbc, 0xfe, 0x2b, 0xfe, 0x3f, 0xeb, 0x03, 0xc4, 0xea, 0x37, + 0xe7, 0x47, 0x7e, 0x8a, 0xd9, 0xbf, 0x77, 0x0f, 0x6c, 0xb6, 0x77, 0x0b, + 0x03, 0x3f, 0x82, 0x2b, 0x21, 0x64, 0x57, 0x1d, + /* Session Length */ + 0x00, + /* Cookie Length */ + 0x00, + /* CS Length */ + 0x00, 0x0c, + /* CS */ + 0xc0, 0x0a, 0xc0, 0x09, 0xc0, 0x14, 0xc0, 0x13, 0x00, 0x39, 0x00, 0x33, + /* Comp Meths Length */ + 0x01, + /* Comp Meths */ + 0x00 + /* And finally... no extensions */ + }; + int i; +#ifdef OPENSSL_EXTRA + int repeats = 2; +#else + int repeats = 1; +#endif + + for (i = 0; i < repeats; i++) { + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ssl_s = NULL; + ctx_s = NULL; + + ExpectIntEQ(test_memio_setup(&test_ctx, NULL, &ctx_s, NULL, &ssl_s, + NULL, wolfDTLS_server_method), 0); + + test_memio_clear_buffer(&test_ctx, 0); + ExpectIntEQ( + test_memio_inject_message(&test_ctx, 1, + (const char *)chNoExtensions, sizeof(chNoExtensions)), 0); + + +#ifdef OPENSSL_EXTRA + if (i > 0) { + ExpectIntEQ(wolfSSL_set_max_proto_version(ssl_s, DTLS1_2_VERSION), + WOLFSSL_SUCCESS); + } +#endif + + ExpectIntEQ(wolfSSL_accept(ssl_s), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + + /* Expecting a handshake msg. Either HVR or SH. */ + ExpectIntGT(test_ctx.c_len, 0); + ExpectIntEQ(test_ctx.c_buff[0], 0x16); + + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_s); + } +#endif + return EXPECT_RESULT(); +} + +/*-- dtls_1_0_hvr_downgrade (api.c lines 31038,31073) ---*/ +#if defined(WOLFSSL_DTLS) && !defined(WOLFSSL_NO_TLS12) && \ + defined(HAVE_IO_TESTS_DEPENDENCIES) +static void test_dtls_1_0_hvr_downgrade_ctx_ready(WOLFSSL_CTX* ctx) +{ + AssertIntEQ(wolfSSL_CTX_SetMinVersion(ctx, WOLFSSL_DTLSV1_2), + WOLFSSL_SUCCESS); +} + +int test_dtls_1_0_hvr_downgrade(void) +{ + EXPECT_DECLS; + callback_functions func_cb_client; + callback_functions func_cb_server; + + XMEMSET(&func_cb_client, 0, sizeof(callback_functions)); + XMEMSET(&func_cb_server, 0, sizeof(callback_functions)); + + func_cb_client.doUdp = func_cb_server.doUdp = 1; + func_cb_client.method = wolfDTLS_client_method; + func_cb_server.method = wolfDTLSv1_2_server_method; + func_cb_client.ctx_ready = test_dtls_1_0_hvr_downgrade_ctx_ready; + + test_wolfSSL_client_server_nofail(&func_cb_client, &func_cb_server); + + ExpectIntEQ(func_cb_client.return_code, TEST_SUCCESS); + ExpectIntEQ(func_cb_server.return_code, TEST_SUCCESS); + + return EXPECT_RESULT(); +} +#else +int test_dtls_1_0_hvr_downgrade(void) +{ + EXPECT_DECLS; + return EXPECT_RESULT(); +} +#endif + +/*-- downgrade_scr_server (api.c lines 31230,31293) ---*/ +#if defined(WOLFSSL_DTLS) && !defined(WOLFSSL_NO_TLS12) && \ + defined(HAVE_IO_TESTS_DEPENDENCIES) && defined(HAVE_SECURE_RENEGOTIATION) +static void test_dtls_downgrade_scr_server_ctx_ready_server(WOLFSSL_CTX* ctx) +{ + AssertIntEQ(wolfSSL_CTX_SetMinVersion(ctx, WOLFSSL_DTLSV1_2), + WOLFSSL_SUCCESS); + AssertIntEQ(wolfSSL_CTX_UseSecureRenegotiation(ctx), WOLFSSL_SUCCESS); +} + +static void test_dtls_downgrade_scr_server_ctx_ready(WOLFSSL_CTX* ctx) +{ + AssertIntEQ(wolfSSL_CTX_UseSecureRenegotiation(ctx), WOLFSSL_SUCCESS); +} + +static void test_dtls_downgrade_scr_server_on_result(WOLFSSL* ssl) +{ + char testMsg[] = "Message after SCR"; + char msgBuf[sizeof(testMsg)]; + if (wolfSSL_is_server(ssl)) { + AssertIntEQ(wolfSSL_Rehandshake(ssl), WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)); + AssertIntEQ(wolfSSL_get_error(ssl, -1), WC_NO_ERR_TRACE(APP_DATA_READY)); + AssertIntEQ(wolfSSL_read(ssl, msgBuf, sizeof(msgBuf)), sizeof(msgBuf)); + AssertIntEQ(wolfSSL_Rehandshake(ssl), WOLFSSL_SUCCESS); + AssertIntEQ(wolfSSL_write(ssl, testMsg, sizeof(testMsg)), + sizeof(testMsg)); + } + else { + AssertIntEQ(wolfSSL_write(ssl, testMsg, sizeof(testMsg)), + sizeof(testMsg)); + AssertIntEQ(wolfSSL_read(ssl, msgBuf, sizeof(msgBuf)), sizeof(msgBuf)); + } +} + +int test_dtls_downgrade_scr_server(void) +{ + EXPECT_DECLS; + callback_functions func_cb_client; + callback_functions func_cb_server; + + XMEMSET(&func_cb_client, 0, sizeof(callback_functions)); + XMEMSET(&func_cb_server, 0, sizeof(callback_functions)); + + func_cb_client.doUdp = func_cb_server.doUdp = 1; + func_cb_client.method = wolfDTLSv1_2_client_method; + func_cb_server.method = wolfDTLS_server_method; + func_cb_client.ctx_ready = test_dtls_downgrade_scr_server_ctx_ready; + func_cb_server.ctx_ready = test_dtls_downgrade_scr_server_ctx_ready_server; + func_cb_client.on_result = test_dtls_downgrade_scr_server_on_result; + func_cb_server.on_result = test_dtls_downgrade_scr_server_on_result; + + test_wolfSSL_client_server_nofail(&func_cb_client, &func_cb_server); + + ExpectIntEQ(func_cb_client.return_code, TEST_SUCCESS); + ExpectIntEQ(func_cb_server.return_code, TEST_SUCCESS); + + return EXPECT_RESULT(); +} +#else +int test_dtls_downgrade_scr_server(void) +{ + EXPECT_DECLS; + return EXPECT_RESULT(); +} #endif + +/*-- downgrade_scr (api.c lines 31295,31352) ---*/ +#if defined(WOLFSSL_DTLS) && !defined(WOLFSSL_NO_TLS12) && \ + defined(HAVE_IO_TESTS_DEPENDENCIES) && defined(HAVE_SECURE_RENEGOTIATION) +static void test_dtls_downgrade_scr_ctx_ready(WOLFSSL_CTX* ctx) +{ + AssertIntEQ(wolfSSL_CTX_SetMinVersion(ctx, WOLFSSL_DTLSV1_2), + WOLFSSL_SUCCESS); + AssertIntEQ(wolfSSL_CTX_UseSecureRenegotiation(ctx), WOLFSSL_SUCCESS); +} + +static void test_dtls_downgrade_scr_on_result(WOLFSSL* ssl) +{ + char testMsg[] = "Message after SCR"; + char msgBuf[sizeof(testMsg)]; + if (wolfSSL_is_server(ssl)) { + AssertIntEQ(wolfSSL_Rehandshake(ssl), WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)); + AssertIntEQ(wolfSSL_get_error(ssl, -1), WC_NO_ERR_TRACE(APP_DATA_READY)); + AssertIntEQ(wolfSSL_read(ssl, msgBuf, sizeof(msgBuf)), sizeof(msgBuf)); + AssertIntEQ(wolfSSL_Rehandshake(ssl), WOLFSSL_SUCCESS); + AssertIntEQ(wolfSSL_write(ssl, testMsg, sizeof(testMsg)), + sizeof(testMsg)); + } + else { + AssertIntEQ(wolfSSL_write(ssl, testMsg, sizeof(testMsg)), + sizeof(testMsg)); + AssertIntEQ(wolfSSL_read(ssl, msgBuf, sizeof(msgBuf)), sizeof(msgBuf)); + } +} + +int test_dtls_downgrade_scr(void) +{ + EXPECT_DECLS; + callback_functions func_cb_client; + callback_functions func_cb_server; + + XMEMSET(&func_cb_client, 0, sizeof(callback_functions)); + XMEMSET(&func_cb_server, 0, sizeof(callback_functions)); + + func_cb_client.doUdp = func_cb_server.doUdp = 1; + func_cb_client.method = wolfDTLS_client_method; + func_cb_server.method = wolfDTLSv1_2_server_method; + func_cb_client.ctx_ready = test_dtls_downgrade_scr_ctx_ready; + func_cb_client.on_result = test_dtls_downgrade_scr_on_result; + func_cb_server.on_result = test_dtls_downgrade_scr_on_result; + + test_wolfSSL_client_server_nofail(&func_cb_client, &func_cb_server); + + ExpectIntEQ(func_cb_client.return_code, TEST_SUCCESS); + ExpectIntEQ(func_cb_server.return_code, TEST_SUCCESS); + return EXPECT_RESULT(); } +#else +int test_dtls_downgrade_scr(void) +{ + EXPECT_DECLS; + return EXPECT_RESULT(); +} +#endif -/* Test that a DTLS 1.3 handshake with an oversized certificate chain does - * not crash or cause out-of-bounds access in SendTls13Certificate. */ -int test_dtls13_oversized_cert_chain(void) +/*-- client_hello_timeout_downgrade_with_helper (api.c lines 31354,31490) ---*/ +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13) \ + && !defined(WOLFSSL_NO_TLS12) + +static int test_dtls_client_hello_timeout_downgrade_read_cb(WOLFSSL *ssl, + char *data, int sz, void *ctx) +{ + static int call_counter = 0; + call_counter++; + (void)ssl; + (void)data; + (void)sz; + (void)ctx; + switch (call_counter) { + case 1: + case 2: + return WOLFSSL_CBIO_ERR_TIMEOUT; + case 3: + return WOLFSSL_CBIO_ERR_WANT_READ; + default: + AssertIntLE(call_counter, 3); + return -1; + } +} +#endif + +/* Make sure we don't send acks before getting a server hello */ +int test_dtls_client_hello_timeout_downgrade(void) { EXPECT_DECLS; #if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13) \ - && !defined(NO_FILESYSTEM) && !defined(NO_RSA) - WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; - WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + && !defined(WOLFSSL_NO_TLS12) + + WOLFSSL_CTX *ctx_c = NULL; + WOLFSSL_CTX *ctx_s = NULL; + WOLFSSL *ssl_c = NULL; + WOLFSSL *ssl_s = NULL; struct test_memio_ctx test_ctx; - XFILE f = XBADFILE; - long sz = 0; - byte *cert = NULL; - byte *chain = NULL; - int copies, off, i; + DtlsRecordLayerHeader* dtlsRH; + size_t len; + byte sequence_number[8]; + int i; - XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + for (i = 0; i < 2; i++) { + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); - /* Read server cert */ - f = XFOPEN(svrCertFile, "rb"); - ExpectTrue(f != XBADFILE); - if (EXPECT_SUCCESS()) { - (void)XFSEEK(f, 0, XSEEK_END); - sz = XFTELL(f); - (void)XFSEEK(f, 0, XSEEK_SET); - } - ExpectTrue(sz > 0); - cert = (byte*)XMALLOC((size_t)(sz + 1), NULL, DYNAMIC_TYPE_TMP_BUFFER); - ExpectNotNull(cert); - if (EXPECT_SUCCESS()) - ExpectIntEQ((int)XFREAD(cert, 1, (size_t)sz, f), (int)sz); - if (f != XBADFILE) - XFCLOSE(f); - - /* Build an oversized chain by duplicating the cert */ - copies = EXPECT_SUCCESS() ? (int)(70000 / sz) + 2 : 0; - chain = (byte*)XMALLOC((size_t)(sz * copies + 1), NULL, - DYNAMIC_TYPE_TMP_BUFFER); - ExpectNotNull(chain); - off = 0; - if (EXPECT_SUCCESS()) { - for (i = 0; i < copies; i++) { - XMEMCPY(chain + off, cert, (size_t)sz); - off += (int)sz; + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLS_client_method, wolfDTLSv1_2_server_method), 0); + + if (i == 0) { + /* First time simulate timeout in IO layer */ + /* CH1 */ + ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + /* HVR */ + ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + /* CH2 */ + ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + /* SH flight */ + ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + /* Drop the SH */ + if (EXPECT_SUCCESS()) { + ExpectIntEQ(test_memio_drop_message(&test_ctx, 1, 0), 0); + } + /* Read the remainder of the flight */ + ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + wolfSSL_SSLSetIORecv(ssl_c, + test_dtls_client_hello_timeout_downgrade_read_cb); + /* CH3 */ + ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + wolfSSL_SSLSetIORecv(ssl_c, test_memio_read_cb); + } + else { + /* Second time call wolfSSL_dtls_got_timeout */ + /* CH1 */ + ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + /* HVR */ + ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + /* CH2 */ + ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + /* SH flight */ + ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + /* Drop the SH */ + if (EXPECT_SUCCESS()) { + ExpectIntEQ(test_memio_drop_message(&test_ctx, 1, 0), 0); + } + /* Read the remainder of the flight */ + ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + /* Quick timeout should be set as we received at least one msg */ + ExpectIntEQ(wolfSSL_dtls13_use_quick_timeout(ssl_c), 1); + ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl_c), WOLFSSL_SUCCESS); + /* Quick timeout should be cleared after a quick timeout */ + /* CH3 */ + ExpectIntEQ(wolfSSL_dtls13_use_quick_timeout(ssl_c), 0); + ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl_c), WOLFSSL_SUCCESS); } - } - /* Server context: load the oversized chain */ - ExpectNotNull(ctx_s = wolfSSL_CTX_new(wolfDTLSv1_3_server_method())); - ExpectIntEQ(wolfSSL_CTX_use_certificate_chain_buffer(ctx_s, - chain, (long)off), WOLFSSL_SUCCESS); - ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_file(ctx_s, svrKeyFile, - WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS); - if (EXPECT_SUCCESS()) { - wolfSSL_SetIORecv(ctx_s, test_memio_read_cb); - wolfSSL_SetIOSend(ctx_s, test_memio_write_cb); + /* Parse out to make sure we got exactly one ClientHello message */ + XMEMSET(&sequence_number, 0, sizeof(sequence_number)); + /* Second ClientHello after HVR */ + sequence_number[7] = 2; + dtlsRH = (DtlsRecordLayerHeader*)test_ctx.s_buff; + ExpectIntEQ(dtlsRH->type, handshake); + ExpectIntEQ(dtlsRH->pvMajor, DTLS_MAJOR); + ExpectIntEQ(dtlsRH->pvMinor, DTLSv1_2_MINOR); + ExpectIntEQ(XMEMCMP(sequence_number, dtlsRH->sequence_number, + sizeof(sequence_number)), 0); + len = (size_t)((dtlsRH->length[0] << 8) | dtlsRH->length[1]); + ExpectIntEQ(sizeof(DtlsRecordLayerHeader) + len, test_ctx.s_len); + + /* Connection should be able to continue */ + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); + ssl_c = NULL; + ssl_s = NULL; + ctx_c = NULL; + ctx_s = NULL; + if (!EXPECT_SUCCESS()) + break; } - /* Client context: no verification (chain certs are duplicates) */ - ExpectNotNull(ctx_c = wolfSSL_CTX_new(wolfDTLSv1_3_client_method())); - if (EXPECT_SUCCESS()) { - wolfSSL_CTX_set_verify(ctx_c, WOLFSSL_VERIFY_NONE, NULL); - wolfSSL_SetIORecv(ctx_c, test_memio_read_cb); - wolfSSL_SetIOSend(ctx_c, test_memio_write_cb); +#endif + return EXPECT_RESULT(); +} + +/*-- client_hello_timeout_with_helper (api.c lines 31492,31581) ---*/ +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13) +static int test_dtls_client_hello_timeout_read_cb(WOLFSSL *ssl, char *data, + int sz, void *ctx) +{ + static int call_counter = 0; + call_counter++; + (void)ssl; + (void)data; + (void)sz; + (void)ctx; + switch (call_counter) { + case 1: + return WOLFSSL_CBIO_ERR_TIMEOUT; + case 2: + return WOLFSSL_CBIO_ERR_WANT_READ; + default: + AssertIntLE(call_counter, 2); + return -1; } +} +#endif - ExpectNotNull(ssl_s = wolfSSL_new(ctx_s)); - if (EXPECT_SUCCESS()) { - wolfSSL_SetIOWriteCtx(ssl_s, &test_ctx); - wolfSSL_SetIOReadCtx(ssl_s, &test_ctx); +/* Make sure we don't send acks before getting a server hello */ +int test_dtls_client_hello_timeout(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13) + WOLFSSL *ssl_c = NULL; + WOLFSSL_CTX *ctx_c = NULL; + struct test_memio_ctx test_ctx; + DtlsRecordLayerHeader* dtlsRH; + size_t idx; + size_t len; + byte sequence_number[8]; + int i; + + for (i = 0; i < 2; i++) { + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, NULL, &ssl_c, NULL, + wolfDTLSv1_3_client_method, NULL), 0); + + if (i == 0) { + /* First time simulate timeout in IO layer */ + wolfSSL_SSLSetIORecv(ssl_c, test_dtls_client_hello_timeout_read_cb); + ExpectIntEQ(wolfSSL_connect(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + } + else { + /* Second time call wolfSSL_dtls_got_timeout */ + ExpectIntEQ(wolfSSL_connect(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl_c), WOLFSSL_SUCCESS); + } + + /* Parse out to make sure we got exactly two ClientHello messages */ + idx = 0; + XMEMSET(&sequence_number, 0, sizeof(sequence_number)); + /* First ClientHello */ + dtlsRH = (DtlsRecordLayerHeader*)(test_ctx.s_buff + idx); + ExpectIntEQ(dtlsRH->type, handshake); + ExpectIntEQ(dtlsRH->pvMajor, DTLS_MAJOR); + ExpectIntEQ(dtlsRH->pvMinor, DTLSv1_2_MINOR); + ExpectIntEQ(XMEMCMP(sequence_number, dtlsRH->sequence_number, + sizeof(sequence_number)), 0); + len = (size_t)((dtlsRH->length[0] << 8) | dtlsRH->length[1]); + ExpectIntLT(idx + sizeof(DtlsRecordLayerHeader) + len, test_ctx.s_len); + idx += sizeof(DtlsRecordLayerHeader) + len; + /* Second ClientHello */ + sequence_number[7] = 1; + dtlsRH = (DtlsRecordLayerHeader*)(test_ctx.s_buff + idx); + ExpectIntEQ(dtlsRH->type, handshake); + ExpectIntEQ(dtlsRH->pvMajor, DTLS_MAJOR); + ExpectIntEQ(dtlsRH->pvMinor, DTLSv1_2_MINOR); + ExpectIntEQ(XMEMCMP(sequence_number, dtlsRH->sequence_number, + sizeof(sequence_number)), 0); + len = (size_t)((dtlsRH->length[0] << 8) | dtlsRH->length[1]); + ExpectIntEQ(idx + sizeof(DtlsRecordLayerHeader) + len, test_ctx.s_len); + + wolfSSL_free(ssl_c); + wolfSSL_CTX_free(ctx_c); + ssl_c = NULL; + ctx_c = NULL; + if (!EXPECT_SUCCESS()) + break; } - ExpectNotNull(ssl_c = wolfSSL_new(ctx_c)); +#endif + return EXPECT_RESULT(); +} + +/*-- dropped_ccs (api.c lines 31584,31648) ---*/ +int test_dtls_dropped_ccs(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS) \ + && !defined(WOLFSSL_NO_TLS12) + + WOLFSSL_CTX *ctx_c = NULL; + WOLFSSL_CTX *ctx_s = NULL; + WOLFSSL *ssl_c = NULL; + WOLFSSL *ssl_s = NULL; + struct test_memio_ctx test_ctx; + DtlsRecordLayerHeader* dtlsRH; + size_t len; + byte data[1]; + + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method), 0); + + /* CH1 */ + ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + /* HVR */ + ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + /* CH2 */ + ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + /* Server first flight */ + ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + /* Client flight */ + ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + /* Server ccs + finished */ + ExpectIntEQ(wolfSSL_negotiate(ssl_s), 1); + + /* Drop the ccs */ + dtlsRH = (DtlsRecordLayerHeader*)test_ctx.c_buff; + len = (size_t)((dtlsRH->length[0] << 8) | dtlsRH->length[1]); + ExpectIntEQ(len, 1); + ExpectIntEQ(dtlsRH->type, change_cipher_spec); if (EXPECT_SUCCESS()) { - wolfSSL_SetIOWriteCtx(ssl_c, &test_ctx); - wolfSSL_SetIOReadCtx(ssl_c, &test_ctx); + ExpectIntEQ(test_memio_drop_message(&test_ctx, 1, 0), 0); } - /* Handshake must not crash. If SendTls13Certificate mishandles the - * oversized chain this will trigger a wild pointer dereference or stack - * overflow resulting with the test failing. - * The correct behaviour either returns BUFFER_E or succeeds - * if the build config truncated the chain during loading. */ - (void)test_memio_do_handshake(ssl_c, ssl_s, 10, NULL); + /* Client rtx flight */ + ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl_c), WOLFSSL_SUCCESS); + /* Server ccs + finished rtx */ + ExpectIntEQ(wolfSSL_read(ssl_s, data, sizeof(data)), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + /* Client processes finished */ + ExpectIntEQ(wolfSSL_negotiate(ssl_c), 1); wolfSSL_free(ssl_c); wolfSSL_free(ssl_s); wolfSSL_CTX_free(ctx_c); wolfSSL_CTX_free(ctx_s); - XFREE(cert, NULL, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(chain, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif return EXPECT_RESULT(); } -/* DTLS counterpart to test_tls_set_session_min_downgrade. Exercises the - * inverted DTLS minor-version comparison (DTLS 1.2 minor 0xFD is "below" - * floor 0xFC = DTLS 1.3). */ -int test_dtls_set_session_min_downgrade(void) +/*-- seq_num_downgrade_with_helper (api.c lines 31650,31722) ---*/ +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS) \ + && !defined(WOLFSSL_NO_TLS12) +static int test_dtls_seq_num_downgrade_check_num(byte* ioBuf, int ioBufLen, + byte seq_num) +{ + EXPECT_DECLS; + DtlsRecordLayerHeader* dtlsRH; + byte sequence_number[8]; + + XMEMSET(&sequence_number, 0, sizeof(sequence_number)); + + ExpectIntGE(ioBufLen, sizeof(*dtlsRH)); + dtlsRH = (DtlsRecordLayerHeader*)ioBuf; + ExpectIntEQ(dtlsRH->type, handshake); + ExpectIntEQ(dtlsRH->pvMajor, DTLS_MAJOR); + ExpectIntEQ(dtlsRH->pvMinor, DTLSv1_2_MINOR); + sequence_number[7] = seq_num; + ExpectIntEQ(XMEMCMP(sequence_number, dtlsRH->sequence_number, + sizeof(sequence_number)), 0); + + return EXPECT_RESULT(); +} +#endif + +/* + * Make sure that we send the correct sequence number after a HelloVerifyRequest + * and after a HelloRetryRequest. This is testing the server side as it is + * operating statelessly and should copy the sequence number of the ClientHello. + */ +int test_dtls_seq_num_downgrade(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS) \ + && !defined(WOLFSSL_NO_TLS12) + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLSv1_2_client_method, wolfDTLS_server_method), 0); + + /* CH1 */ + ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + ExpectIntEQ(test_dtls_seq_num_downgrade_check_num(test_ctx.s_buff, + test_ctx.s_len, 0), TEST_SUCCESS); + /* HVR */ + ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + ExpectIntEQ(test_dtls_seq_num_downgrade_check_num(test_ctx.c_buff, + test_ctx.c_len, 0), TEST_SUCCESS); + /* CH2 */ + ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + ExpectIntEQ(test_dtls_seq_num_downgrade_check_num(test_ctx.s_buff, + test_ctx.s_len, 1), TEST_SUCCESS); + /* Server first flight */ + ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + ExpectIntEQ(test_dtls_seq_num_downgrade_check_num(test_ctx.c_buff, + test_ctx.c_len, 1), TEST_SUCCESS); + + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + + wolfSSL_free(ssl_c); + wolfSSL_CTX_free(ctx_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_s); +#endif + return EXPECT_RESULT(); +} + +/*-- old_seq_number (api.c lines 31953,32005) ---*/ +int test_dtls_old_seq_number(void) { EXPECT_DECLS; #if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS) && \ - defined(WOLFSSL_DTLS13) && defined(HAVE_SESSION_TICKET) + !defined(WOLFSSL_NO_TLS12) WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; WOLFSSL *ssl_c = NULL, *ssl_s = NULL; - WOLFSSL_SESSION *sess = NULL; struct test_memio_ctx test_ctx; XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, - wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method), 0); + wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method), 0); + + /* CH1 */ + ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + /* HVR */ + ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + /* CH2 */ + ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + /* Server first flight */ + ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + /* Client second flight */ + ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + /* Modify the sequence number */ + { + DtlsRecordLayerHeader* dtlsRH = (DtlsRecordLayerHeader*)test_ctx.s_buff; + XMEMSET(dtlsRH->sequence_number, 0, sizeof(dtlsRH->sequence_number)); + } + /* Server second flight */ + ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + /* Server should not do anything as a pkt was dropped */ + ExpectIntEQ(test_ctx.c_len, 0); + ExpectIntEQ(test_ctx.s_len, 0); + /* Trigger rtx */ + ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl_c), WOLFSSL_SUCCESS); + + /* Complete connection */ ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); - ExpectNotNull(sess = wolfSSL_get1_session(ssl_c)); - wolfSSL_free(ssl_c); ssl_c = NULL; - wolfSSL_free(ssl_s); ssl_s = NULL; - wolfSSL_CTX_free(ctx_c); ctx_c = NULL; - wolfSSL_CTX_free(ctx_s); ctx_s = NULL; + wolfSSL_free(ssl_c); + wolfSSL_CTX_free(ctx_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_s); +#endif + return EXPECT_RESULT(); +} + +/*-- dtls12_missing_finished (api.c lines 32007,32068) ---*/ +int test_dtls12_missing_finished(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS) && \ + !defined(WOLFSSL_NO_TLS12) + WOLFSSL_CTX *ctx_c = NULL; + WOLFSSL_CTX *ctx_s = NULL; + WOLFSSL *ssl_c = NULL; + WOLFSSL *ssl_s = NULL; + struct test_memio_ctx test_ctx; + const char test_str[] = "test string"; + char test_buf[sizeof(test_str)]; XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, - wolfDTLS_client_method, wolfDTLS_server_method), 0); - ExpectIntEQ(wolfSSL_SetMinVersion(ssl_c, WOLFSSL_DTLSV1_3), - WOLFSSL_SUCCESS); - ExpectIntEQ(wolfSSL_set_session(ssl_c, sess), WOLFSSL_FAILURE); - if (ssl_c != NULL) - ExpectIntEQ(ssl_c->options.resuming, 0); + wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method), 0); + + /* CH1 */ + ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + /* HVR */ + ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + /* CH2 */ + ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + /* Server first flight */ + ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + /* Client second flight with finished */ + ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + /* Server second flight with finished */ + ExpectIntEQ(wolfSSL_negotiate(ssl_s), 1); + /* Let's clear the output */ + test_memio_clear_buffer(&test_ctx, 1); + /* Let's send some app data */ + ExpectIntEQ(wolfSSL_write(ssl_s, test_str, sizeof(test_str)), + sizeof(test_str)); + /* Client should not error out on a missing finished */ + ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + /* Server rtx second flight with finished */ + ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl_s), 1); + /* Client process rest of handshake */ + ExpectIntEQ(wolfSSL_negotiate(ssl_c), 1); + + /* Let's send some app data */ + ExpectIntEQ(wolfSSL_write(ssl_s, test_str, sizeof(test_str)), + sizeof(test_str)); + ExpectIntEQ(wolfSSL_read(ssl_c, test_buf, sizeof(test_buf)), + sizeof(test_str)); + ExpectBufEQ(test_buf, test_str, sizeof(test_str)); - wolfSSL_SESSION_free(sess); wolfSSL_free(ssl_c); wolfSSL_free(ssl_s); wolfSSL_CTX_free(ctx_c); diff --git a/tests/api/test_dtls.h b/tests/api/test_dtls.h index 96e524b537..cb5eb17555 100644 --- a/tests/api/test_dtls.h +++ b/tests/api/test_dtls.h @@ -23,15 +23,8 @@ #define TESTS_API_DTLS_H int test_dtls12_basic_connection_id(void); -int test_dtls13_basic_connection_id(void); -int test_dtls13_hrr_want_write(void); -int test_dtls13_every_write_want_write(void); int test_wolfSSL_dtls_cid_parse(void); int test_wolfSSL_dtls_set_pending_peer(void); -int test_dtls13_epochs(void); -int test_dtls13_ack_order(void); -int test_dtls13_ack_overflow(void); -int test_dtls13_ack_dup_write_counter(void); int test_dtls_version_checking(void); int test_dtls_short_ciphertext(void); int test_dtls12_record_length_mismatch(void); @@ -41,35 +34,55 @@ int test_dtls13_short_read(void); int test_records_span_network_boundaries(void); int test_dtls_record_cross_boundaries(void); int test_dtls_rtx_across_epoch_change(void); -int test_dtls13_ch2_rtx_no_ch1(void); -int test_dtls13_frag_ch2_with_ch1_rtx(void); int test_dtls_drop_client_ack(void); int test_dtls_bogus_finished_epoch_zero(void); int test_dtls_replay(void); -int test_dtls_srtp(void); int test_dtls_timeout(void); int test_dtls_certreq_order(void); int test_dtls_memio_wolfio(void); int test_dtls_memio_wolfio_stateless(void); int test_dtls_mtu_fragment_headroom(void); int test_dtls_mtu_split_messages(void); -int test_dtls13_min_rtx_interval(void); -int test_dtls13_no_session_id_echo(void); -int test_dtls13_5_9_0_compat(void); -int test_dtls13_oversized_cert_chain(void); int test_dtls_set_session_min_downgrade(void); +/* DTLS tests moved out of tests/api.c. */ +int test_dtls_msg_from_other_peer(void); +int test_dtls_ipv6_check(void); +int test_dtls_no_extensions(void); +int test_dtls_1_0_hvr_downgrade(void); +int test_dtls_downgrade_scr_server(void); +int test_dtls_downgrade_scr(void); +int test_dtls_client_hello_timeout_downgrade(void); +int test_dtls_client_hello_timeout(void); +int test_dtls_dropped_ccs(void); +int test_dtls_seq_num_downgrade(void); +int test_dtls_old_seq_number(void); +int test_dtls12_missing_finished(void); +int test_wolfSSL_dtls_export(void); +int test_wolfSSL_dtls_export_peers(void); +int test_wolfSSL_dtls_import_state_extra_window_words(void); +int test_wolfSSL_DTLS_either_side(void); +int test_generate_cookie(void); +int test_wolfSSL_dtls_set_mtu(void); +int test_wolfSSL_dtls_plaintext(void); +int test_wolfSSL_dtls_fragments(void); +int test_wolfSSL_ignore_alert_before_cookie(void); +int test_wolfSSL_dtls_bad_record(void); +int test_wolfSSL_dtls_AEAD_limit(void); +int test_wolfSSL_dtls_stateless(void); +int test_wolfSSL_dtls_stateless_hrr_group(void); +int test_wolfSSL_DtlsUpdateWindow(void); +int test_wolfSSL_DTLS_fragment_buckets(void); +int test_wolfSSL_dtls_stateless2(void); +int test_wolfSSL_dtls_stateless_maxfrag(void); +int test_wolfSSL_dtls_stateless_resume(void); +int test_wolfSSL_dtls_stateless_downgrade(void); +int test_WOLFSSL_dtls_version_alert(void); + #define TEST_DTLS_DECLS \ TEST_DECL_GROUP("dtls", test_dtls12_basic_connection_id), \ - TEST_DECL_GROUP("dtls", test_dtls13_basic_connection_id), \ - TEST_DECL_GROUP("dtls", test_dtls13_hrr_want_write), \ - TEST_DECL_GROUP("dtls", test_dtls13_every_write_want_write), \ TEST_DECL_GROUP("dtls", test_wolfSSL_dtls_cid_parse), \ TEST_DECL_GROUP("dtls", test_wolfSSL_dtls_set_pending_peer), \ - TEST_DECL_GROUP("dtls", test_dtls13_epochs), \ - TEST_DECL_GROUP("dtls", test_dtls13_ack_order), \ - TEST_DECL_GROUP("dtls", test_dtls13_ack_overflow), \ - TEST_DECL_GROUP("dtls", test_dtls13_ack_dup_write_counter), \ TEST_DECL_GROUP("dtls", test_dtls_version_checking), \ TEST_DECL_GROUP("dtls", test_dtls_short_ciphertext), \ TEST_DECL_GROUP("dtls", test_dtls12_record_length_mismatch), \ @@ -79,21 +92,46 @@ int test_dtls_set_session_min_downgrade(void); TEST_DECL_GROUP("dtls", test_records_span_network_boundaries), \ TEST_DECL_GROUP("dtls", test_dtls_record_cross_boundaries), \ TEST_DECL_GROUP("dtls", test_dtls_rtx_across_epoch_change), \ - TEST_DECL_GROUP("dtls", test_dtls13_ch2_rtx_no_ch1), \ - TEST_DECL_GROUP("dtls", test_dtls13_frag_ch2_with_ch1_rtx), \ TEST_DECL_GROUP("dtls", test_dtls_drop_client_ack), \ TEST_DECL_GROUP("dtls", test_dtls_bogus_finished_epoch_zero), \ TEST_DECL_GROUP("dtls", test_dtls_replay), \ - TEST_DECL_GROUP("dtls", test_dtls_srtp), \ TEST_DECL_GROUP("dtls", test_dtls_certreq_order), \ TEST_DECL_GROUP("dtls", test_dtls_timeout), \ TEST_DECL_GROUP("dtls", test_dtls_memio_wolfio), \ TEST_DECL_GROUP("dtls", test_dtls_mtu_fragment_headroom), \ TEST_DECL_GROUP("dtls", test_dtls_mtu_split_messages), \ TEST_DECL_GROUP("dtls", test_dtls_memio_wolfio_stateless), \ - TEST_DECL_GROUP("dtls", test_dtls13_min_rtx_interval), \ - TEST_DECL_GROUP("dtls", test_dtls13_no_session_id_echo), \ - TEST_DECL_GROUP("dtls", test_dtls13_oversized_cert_chain), \ TEST_DECL_GROUP("dtls", test_dtls_set_session_min_downgrade), \ - TEST_DECL_GROUP("dtls", test_dtls13_5_9_0_compat) + TEST_DECL_GROUP("dtls", test_wolfSSL_dtls_export), \ + TEST_DECL_GROUP("dtls", test_wolfSSL_dtls_export_peers), \ + TEST_DECL_GROUP("dtls", test_wolfSSL_dtls_import_state_extra_window_words), \ + TEST_DECL_GROUP("dtls", test_wolfSSL_DTLS_either_side), \ + TEST_DECL_GROUP("dtls", test_generate_cookie), \ + TEST_DECL_GROUP("dtls", test_wolfSSL_dtls_set_mtu), \ + TEST_DECL_GROUP("dtls", test_wolfSSL_dtls_plaintext), \ + TEST_DECL_GROUP("dtls", test_wolfSSL_dtls_fragments), \ + TEST_DECL_GROUP("dtls", test_wolfSSL_ignore_alert_before_cookie), \ + TEST_DECL_GROUP("dtls", test_wolfSSL_dtls_bad_record), \ + TEST_DECL_GROUP("dtls", test_wolfSSL_dtls_AEAD_limit), \ + TEST_DECL_GROUP("dtls", test_wolfSSL_dtls_stateless), \ + TEST_DECL_GROUP("dtls", test_wolfSSL_dtls_stateless_hrr_group), \ + TEST_DECL_GROUP("dtls", test_wolfSSL_DtlsUpdateWindow), \ + TEST_DECL_GROUP("dtls", test_wolfSSL_DTLS_fragment_buckets), \ + TEST_DECL_GROUP("dtls", test_wolfSSL_dtls_stateless2), \ + TEST_DECL_GROUP("dtls", test_wolfSSL_dtls_stateless_maxfrag), \ + TEST_DECL_GROUP("dtls", test_wolfSSL_dtls_stateless_resume), \ + TEST_DECL_GROUP("dtls", test_wolfSSL_dtls_stateless_downgrade), \ + TEST_DECL_GROUP("dtls", test_WOLFSSL_dtls_version_alert), \ + TEST_DECL_GROUP("dtls", test_dtls_msg_from_other_peer), \ + TEST_DECL_GROUP("dtls", test_dtls_ipv6_check), \ + TEST_DECL_GROUP("dtls", test_dtls_no_extensions), \ + TEST_DECL_GROUP("dtls", test_dtls_1_0_hvr_downgrade), \ + TEST_DECL_GROUP("dtls", test_dtls_downgrade_scr_server), \ + TEST_DECL_GROUP("dtls", test_dtls_downgrade_scr), \ + TEST_DECL_GROUP("dtls", test_dtls_client_hello_timeout_downgrade), \ + TEST_DECL_GROUP("dtls", test_dtls_client_hello_timeout), \ + TEST_DECL_GROUP("dtls", test_dtls_dropped_ccs), \ + TEST_DECL_GROUP("dtls", test_dtls_seq_num_downgrade), \ + TEST_DECL_GROUP("dtls", test_dtls_old_seq_number), \ + TEST_DECL_GROUP("dtls", test_dtls12_missing_finished) #endif /* TESTS_API_DTLS_H */ diff --git a/tests/api/test_dtls13.c b/tests/api/test_dtls13.c new file mode 100644 index 0000000000..b74740eb4c --- /dev/null +++ b/tests/api/test_dtls13.c @@ -0,0 +1,1875 @@ +/* test_dtls13.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 + +#ifdef NO_INLINE + #include +#else + #define WOLFSSL_MISC_INCLUDED + #include +#endif + +#include +#include +#include +#include +#include + +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13) + + +int test_dtls13_bad_epoch_ch(void) +{ + EXPECT_DECLS; + WOLFSSL_CTX *ctx_c = NULL; + WOLFSSL_CTX *ctx_s = NULL; + WOLFSSL *ssl_c = NULL; + WOLFSSL *ssl_s = NULL; + struct test_memio_ctx test_ctx; + const int EPOCH_OFF = 3; + int groups[] = { + WOLFSSL_ECC_SECP256R1, + WOLFSSL_ECC_SECP384R1, + }; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), 0); + + /* disable hrr cookie so we can later check msgsReceived.got_client_hello + * with just one message */ + ExpectIntEQ(wolfSSL_disable_hrr_cookie(ssl_s), WOLFSSL_SUCCESS); + + /* Set client groups to traditional only to avoid CH fragmentation */ + ExpectIntEQ(wolfSSL_set_groups(ssl_c, groups, 2), WOLFSSL_SUCCESS); + + ExpectIntNE(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_get_error(ssl_c, WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)), + WOLFSSL_ERROR_WANT_READ); + + ExpectIntGE(test_ctx.s_len, EPOCH_OFF + 2); + + /* first CH should use epoch 0x0 */ + ExpectTrue((test_ctx.s_buff[EPOCH_OFF] == 0x0) && + (test_ctx.s_buff[EPOCH_OFF + 1] == 0x0)); + + /* change epoch to 2 */ + test_ctx.s_buff[EPOCH_OFF + 1] = 0x2; + + ExpectIntNE(wolfSSL_accept(ssl_s), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_get_error(ssl_s, WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)), + WOLFSSL_ERROR_WANT_READ); + + ExpectIntNE(ssl_s->msgsReceived.got_client_hello, 1); + + /* resend the CH */ + ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl_c), WOLFSSL_SUCCESS); + + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + + wolfSSL_free(ssl_c); + wolfSSL_CTX_free(ctx_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_s); + + return EXPECT_RESULT(); +} +#else +int test_dtls13_bad_epoch_ch(void) +{ + return TEST_SKIPPED; +} +#endif + +#if defined(HAVE_NULL_CIPHER) && defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) \ + && defined(WOLFSSL_DTLS13) +static byte* test_find_string(const char *string, + byte *buf, int buf_size) +{ + int string_size, i; + + string_size = (int)XSTRLEN(string); + for (i = 0; i < buf_size - string_size - 1; i++) { + if (XSTRCMP((char*)&buf[i], string) == 0) + return &buf[i]; + } + return NULL; +} + +int test_wolfSSL_dtls13_null_cipher(void) +{ + EXPECT_DECLS; + WOLFSSL_CTX *ctx_c = NULL; + WOLFSSL_CTX *ctx_s = NULL; + WOLFSSL *ssl_c = NULL; + WOLFSSL *ssl_s = NULL; + struct test_memio_ctx test_ctx; + const char *test_str = "test"; + int test_str_size; + byte buf[255], *ptr = NULL; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + test_ctx.c_ciphers = test_ctx.s_ciphers = "TLS13-SHA256-SHA256"; + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), 0); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + test_str_size = XSTRLEN("test") + 1; + ExpectIntEQ(wolfSSL_write(ssl_c, test_str, test_str_size), test_str_size); + ExpectIntEQ(wolfSSL_read(ssl_s, buf, sizeof(buf)), test_str_size); + ExpectIntEQ(XSTRCMP((char*)buf, test_str), 0); + + ExpectIntEQ(wolfSSL_write(ssl_c, test_str, test_str_size), test_str_size); + + /* check that the packet was sent cleartext */ + ExpectNotNull(ptr = test_find_string(test_str, test_ctx.s_buff, + test_ctx.s_len)); + if (ptr != NULL) { + /* modify the message */ + *ptr = 'H'; + /* bad messages should be ignored in DTLS */ + ExpectIntEQ(wolfSSL_read(ssl_s, buf, sizeof(buf)), -1); + ExpectIntEQ(ssl_s->error, WC_NO_ERR_TRACE(WANT_READ)); + } + + ExpectIntEQ(wolfSSL_shutdown(ssl_c), WOLFSSL_SHUTDOWN_NOT_DONE); + ExpectIntEQ(wolfSSL_shutdown(ssl_s), WOLFSSL_SHUTDOWN_NOT_DONE); + ExpectIntEQ(wolfSSL_shutdown(ssl_c), 1); + ExpectIntEQ(wolfSSL_shutdown(ssl_s), 1); + + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); + return TEST_SUCCESS; +} +#else +int test_wolfSSL_dtls13_null_cipher(void) +{ + return TEST_SKIPPED; +} +#endif + +int test_dtls13_frag_ch_pq(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13) \ + && defined(WOLFSSL_DTLS_CH_FRAG) && defined(WOLFSSL_HAVE_MLKEM) + WOLFSSL_CTX *ctx_c = NULL; + WOLFSSL_CTX *ctx_s = NULL; + WOLFSSL *ssl_c = NULL; + WOLFSSL *ssl_s = NULL; + struct test_memio_ctx test_ctx; + const char *test_str = "test"; + int test_str_size; + byte buf[255]; +#if defined(WOLFSSL_MLKEM_KYBER) + #if !defined(WOLFSSL_NO_KYBER1024) + int group = WOLFSSL_KYBER_LEVEL5; + const char *group_name = "KYBER_LEVEL5"; + #elif !defined(WOLFSSL_NO_KYBER768) + int group = WOLFSSL_KYBER_LEVEL3; + const char *group_name = "KYBER_LEVEL3"; + #else + int group = WOLFSSL_KYBER_LEVEL1; + const char *group_name = "KYBER_LEVEL1"; + #endif +#elif !defined(WOLFSSL_NO_ML_KEM) && !defined(WOLFSSL_TLS_NO_MLKEM_STANDALONE) + #if !defined(WOLFSSL_NO_ML_KEM_1024) + int group = WOLFSSL_ML_KEM_1024; + const char *group_name = "ML_KEM_1024"; + #elif !defined(WOLFSSL_NO_ML_KEM_768) + int group = WOLFSSL_ML_KEM_768; + const char *group_name = "ML_KEM_768"; + #else + int group = WOLFSSL_ML_KEM_512; + const char *group_name = "ML_KEM_512"; + #endif +#elif defined(WOLFSSL_PQC_HYBRIDS) + #if defined(HAVE_CURVE25519) && !defined(WOLFSSL_NO_ML_KEM_768) + int group = WOLFSSL_X25519MLKEM768; + const char *group_name = "X25519MLKEM768"; + #elif !defined(WOLFSSL_NO_ML_KEM_768) + int group = WOLFSSL_SECP256R1MLKEM768; + const char *group_name = "SecP256r1MLKEM768"; + #else + int group = WOLFSSL_SECP384R1MLKEM1024; + const char *group_name = "SecP384r1MLKEM1024"; + #endif +#endif + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), 0); + /* Add in a large post-quantum key share to make the CH long. */ + ExpectIntEQ(wolfSSL_set_groups(ssl_c, &group, 1), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_UseKeyShare(ssl_c, group), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_dtls13_allow_ch_frag(ssl_s, 1), WOLFSSL_SUCCESS); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + ExpectStrEQ(wolfSSL_get_curve_name(ssl_c), group_name); + ExpectStrEQ(wolfSSL_get_curve_name(ssl_s), group_name); + test_str_size = XSTRLEN("test") + 1; + ExpectIntEQ(wolfSSL_write(ssl_c, test_str, test_str_size), test_str_size); + ExpectIntEQ(wolfSSL_read(ssl_s, buf, sizeof(buf)), test_str_size); + ExpectIntEQ(XSTRCMP((char*)buf, test_str), 0); + ExpectIntEQ(wolfSSL_write(ssl_c, test_str, test_str_size), test_str_size); + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); +#endif + return EXPECT_RESULT(); +} + +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS) \ + && defined(WOLFSSL_DTLS_MTU) && defined(WOLFSSL_DTLS_CH_FRAG) && \ + defined(WOLFSSL_AES_256) +static int test_dtls_frag_ch_count_records(byte* b, int len) +{ + DtlsRecordLayerHeader* dtlsRH; + int records = 0; + size_t recordLen; + while (len > 0) { + records++; + dtlsRH = (DtlsRecordLayerHeader*)b; + recordLen = (dtlsRH->length[0] << 8) | dtlsRH->length[1]; + if (recordLen > (size_t)len) + break; + b += sizeof(DtlsRecordLayerHeader) + recordLen; + len -= sizeof(DtlsRecordLayerHeader) + recordLen; + } + return records; +} +#endif + +int test_dtls_frag_ch(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13) \ + && defined(WOLFSSL_DTLS_MTU) && defined(WOLFSSL_DTLS_CH_FRAG) && \ + defined(WOLFSSL_AES_256) + WOLFSSL_CTX *ctx_c = NULL; + WOLFSSL_CTX *ctx_s = NULL; + WOLFSSL *ssl_c = NULL; + WOLFSSL *ssl_s = NULL; + struct test_memio_ctx test_ctx; + static unsigned int DUMMY_MTU = 256; + unsigned int len; + unsigned char four_frag_CH[] = { + 0x16, 0xfe, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xda, 0x01, 0x00, 0x02, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xce, 0xfe, 0xfd, 0xf3, 0x94, 0x01, 0x33, 0x2c, 0xcf, 0x2c, 0x47, 0xb1, + 0xe5, 0xa1, 0x7b, 0x19, 0x3e, 0xac, 0x68, 0xdd, 0xe6, 0x17, 0x6b, 0x85, + 0xad, 0x5f, 0xfc, 0x7f, 0x6e, 0xf0, 0xb9, 0xe0, 0x2e, 0xca, 0x47, 0x00, + 0x00, 0x00, 0x36, 0x13, 0x01, 0x13, 0x02, 0x13, 0x03, 0xc0, 0x2c, 0xc0, + 0x2b, 0xc0, 0x30, 0xc0, 0x2f, 0x00, 0x9f, 0x00, 0x9e, 0xcc, 0xa9, 0xcc, + 0xa8, 0xcc, 0xaa, 0xc0, 0x27, 0xc0, 0x23, 0xc0, 0x28, 0xc0, 0x24, 0xc0, + 0x0a, 0xc0, 0x09, 0xc0, 0x14, 0xc0, 0x13, 0x00, 0x6b, 0x00, 0x67, 0x00, + 0x39, 0x00, 0x33, 0xcc, 0x14, 0xcc, 0x13, 0xcc, 0x15, 0x01, 0x00, 0x02, + 0x7c, 0x00, 0x2b, 0x00, 0x03, 0x02, 0xfe, 0xfc, 0x00, 0x0d, 0x00, 0x20, + 0x00, 0x1e, 0x06, 0x03, 0x05, 0x03, 0x04, 0x03, 0x02, 0x03, 0x08, 0x06, + 0x08, 0x0b, 0x08, 0x05, 0x08, 0x0a, 0x08, 0x04, 0x08, 0x09, 0x06, 0x01, + 0x05, 0x01, 0x04, 0x01, 0x03, 0x01, 0x02, 0x01, 0x00, 0x0a, 0x00, 0x0c, + 0x00, 0x0a, 0x00, 0x19, 0x00, 0x18, 0x00, 0x17, 0x00, 0x15, 0x01, 0x00, + 0x00, 0x16, 0x00, 0x00, 0x00, 0x33, 0x02, 0x39, 0x02, 0x37, 0x00, 0x17, + 0x00, 0x41, 0x04, 0x94, 0xdf, 0x36, 0xd7, 0xb3, 0x90, 0x6d, 0x01, 0xa1, + 0xe6, 0xed, 0x67, 0xf4, 0xd9, 0x9d, 0x2c, 0xac, 0x57, 0x74, 0xff, 0x19, + 0xbe, 0x5a, 0xc9, 0x30, 0x11, 0xb7, 0x2b, 0x59, 0x47, 0x80, 0x7c, 0xa9, + 0xb7, 0x31, 0x8c, 0x16, 0xfe, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0xda, 0x01, 0x00, 0x02, 0xdc, 0x00, 0x00, 0x00, 0x00, + 0xce, 0x00, 0x00, 0xce, 0x9e, 0x13, 0x74, 0x3b, 0x86, 0xba, 0x69, 0x1f, + 0x12, 0xf7, 0xcd, 0x78, 0x53, 0xe8, 0x50, 0x4d, 0x71, 0x3f, 0x4b, 0x4e, + 0xeb, 0x3e, 0xe5, 0x43, 0x54, 0x78, 0x17, 0x6d, 0x00, 0x18, 0x00, 0x61, + 0x04, 0xd1, 0x99, 0x66, 0x4f, 0xda, 0xc7, 0x12, 0x3b, 0xff, 0xb2, 0xd6, + 0x2f, 0x35, 0xb6, 0x17, 0x1f, 0xb3, 0xd0, 0xb6, 0x52, 0xff, 0x97, 0x8b, + 0x01, 0xe8, 0xd9, 0x68, 0x71, 0x40, 0x02, 0xd5, 0x68, 0x3a, 0x58, 0xb2, + 0x5d, 0xee, 0xa4, 0xe9, 0x5f, 0xf4, 0xaf, 0x3e, 0x30, 0x9c, 0x3e, 0x2b, + 0xda, 0x61, 0x43, 0x99, 0x02, 0x35, 0x33, 0x9f, 0xcf, 0xb5, 0xd3, 0x28, + 0x19, 0x9d, 0x1c, 0xbe, 0x69, 0x07, 0x9e, 0xfc, 0xe4, 0x8e, 0xcd, 0x86, + 0x4a, 0x1b, 0xf0, 0xfc, 0x17, 0x94, 0x66, 0x53, 0xda, 0x24, 0x5e, 0xaf, + 0xce, 0xec, 0x62, 0x4c, 0x06, 0xb4, 0x52, 0x94, 0xb1, 0x4a, 0x7a, 0x8c, + 0x4f, 0x00, 0x19, 0x00, 0x85, 0x04, 0x00, 0x27, 0xeb, 0x99, 0x49, 0x7f, + 0xcb, 0x2c, 0x46, 0x54, 0x2d, 0x93, 0x5d, 0x25, 0x92, 0x58, 0x5e, 0x06, + 0xc3, 0x7c, 0xfb, 0x9a, 0xa7, 0xec, 0xcd, 0x9f, 0xe1, 0x6b, 0x2d, 0x78, + 0xf5, 0x16, 0xa9, 0x20, 0x52, 0x48, 0x19, 0x0f, 0x1a, 0xd0, 0xce, 0xd8, + 0x68, 0xb1, 0x4e, 0x7f, 0x33, 0x03, 0x7d, 0x0c, 0x39, 0xdb, 0x9c, 0x4b, + 0xf4, 0xe7, 0xc2, 0xf5, 0xdd, 0x51, 0x9b, 0x03, 0xa8, 0x53, 0x2b, 0xe6, + 0x00, 0x15, 0x4b, 0xff, 0xd2, 0xa0, 0x16, 0xfe, 0xfd, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0xda, 0x01, 0x00, 0x02, 0xdc, 0x00, + 0x00, 0x00, 0x01, 0x9c, 0x00, 0x00, 0xce, 0x58, 0x30, 0x10, 0x3d, 0x46, + 0xcc, 0xca, 0x1a, 0x44, 0xc8, 0x58, 0x9b, 0x27, 0x17, 0x67, 0x31, 0x96, + 0x8a, 0x66, 0x39, 0xf4, 0xcc, 0xc1, 0x9f, 0x12, 0x1f, 0x01, 0x30, 0x50, + 0x16, 0xd6, 0x89, 0x97, 0xa3, 0x66, 0xd7, 0x99, 0x50, 0x09, 0x6e, 0x80, + 0x87, 0xe4, 0xa2, 0x88, 0xae, 0xb4, 0x23, 0x57, 0x2f, 0x12, 0x60, 0xe7, + 0x7d, 0x44, 0x2d, 0xad, 0xbe, 0xe9, 0x0d, 0x01, 0x00, 0x01, 0x00, 0xd5, + 0xdd, 0x62, 0xee, 0xf3, 0x0e, 0xd9, 0x30, 0x0e, 0x38, 0xf3, 0x48, 0xf4, + 0xc9, 0x8f, 0x8c, 0x20, 0xf7, 0xd3, 0xa8, 0xb3, 0x87, 0x3c, 0x98, 0x5d, + 0x70, 0xc5, 0x03, 0x76, 0xb7, 0xd5, 0x0b, 0x7b, 0x23, 0x97, 0x6b, 0xe3, + 0xb5, 0x18, 0xeb, 0x64, 0x55, 0x18, 0xb2, 0x8a, 0x90, 0x1a, 0x8f, 0x0e, + 0x15, 0xda, 0xb1, 0x8e, 0x7f, 0xee, 0x1f, 0xe0, 0x3b, 0xb9, 0xed, 0xfc, + 0x4e, 0x3f, 0x78, 0x16, 0x39, 0x95, 0x5f, 0xb7, 0xcb, 0x65, 0x55, 0x72, + 0x7b, 0x7d, 0x86, 0x2f, 0x8a, 0xe5, 0xee, 0xf7, 0x57, 0x40, 0xf3, 0xc4, + 0x96, 0x4f, 0x11, 0x4d, 0x85, 0xf9, 0x56, 0xfa, 0x3d, 0xf0, 0xc9, 0xa4, + 0xec, 0x1e, 0xaa, 0x47, 0x90, 0x53, 0xdf, 0xe1, 0xb7, 0x78, 0x18, 0xeb, + 0xdd, 0x0d, 0x89, 0xb7, 0xf6, 0x15, 0x0e, 0x55, 0x12, 0xb3, 0x23, 0x17, + 0x0b, 0x59, 0x6f, 0x83, 0x05, 0x6b, 0xa6, 0xf8, 0x6c, 0x3a, 0x9b, 0x1b, + 0x50, 0x93, 0x51, 0xea, 0x95, 0x2d, 0x99, 0x96, 0x38, 0x16, 0xfe, 0xfd, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x7e, 0x01, 0x00, + 0x02, 0xdc, 0x00, 0x00, 0x00, 0x02, 0x6a, 0x00, 0x00, 0x72, 0x2d, 0x66, + 0x3e, 0xf2, 0x36, 0x5a, 0xf2, 0x23, 0x8f, 0x28, 0x09, 0xa9, 0x55, 0x8c, + 0x8f, 0xc0, 0x0d, 0x61, 0x98, 0x33, 0x56, 0x87, 0x7a, 0xfd, 0xa7, 0x50, + 0x71, 0x84, 0x2e, 0x41, 0x58, 0x00, 0x87, 0xd9, 0x27, 0xe5, 0x7b, 0xf4, + 0x6d, 0x84, 0x4e, 0x2e, 0x0c, 0x80, 0x0c, 0xf3, 0x8a, 0x02, 0x4b, 0x99, + 0x3a, 0x1f, 0x9f, 0x18, 0x7d, 0x1c, 0xec, 0xad, 0x60, 0x54, 0xa6, 0xa3, + 0x2c, 0x82, 0x5e, 0xf8, 0x8f, 0xae, 0xe1, 0xc4, 0x82, 0x7e, 0x43, 0x43, + 0xc5, 0x99, 0x49, 0x05, 0xd3, 0xf6, 0xdf, 0xa1, 0xb5, 0x2d, 0x0c, 0x13, + 0x2f, 0x1e, 0xb6, 0x28, 0x7c, 0x5c, 0xa1, 0x02, 0x6b, 0x8d, 0xa3, 0xeb, + 0xd4, 0x58, 0xe6, 0xa0, 0x7e, 0x6b, 0xaa, 0x09, 0x43, 0x67, 0x71, 0x87, + 0xa5, 0xcb, 0x68, 0xf3 + }; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), 0); + + /* Fragment msgs */ + ExpectIntEQ(wolfSSL_dtls_set_mtu(ssl_c, DUMMY_MTU), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_dtls_set_mtu(ssl_s, DUMMY_MTU), WOLFSSL_SUCCESS); + + /* Add in some key shares to make the CH long */ + ExpectIntEQ(wolfSSL_UseKeyShare(ssl_c, WOLFSSL_ECC_SECP256R1), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_UseKeyShare(ssl_c, WOLFSSL_ECC_SECP384R1), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_UseKeyShare(ssl_c, WOLFSSL_ECC_SECP521R1), + WOLFSSL_SUCCESS); +#ifdef HAVE_FFDHE_2048 + ExpectIntEQ(wolfSSL_UseKeyShare(ssl_c, WOLFSSL_FFDHE_2048), + WOLFSSL_SUCCESS); +#endif +#ifdef HAVE_FFDHE_3072 + ExpectIntEQ(wolfSSL_UseKeyShare(ssl_c, WOLFSSL_FFDHE_3072), + WOLFSSL_SUCCESS); +#endif +#ifdef HAVE_FFDHE_4096 + ExpectIntEQ(wolfSSL_UseKeyShare(ssl_c, WOLFSSL_FFDHE_4096), + WOLFSSL_SUCCESS); +#endif + + ExpectIntEQ(wolfSSL_dtls13_allow_ch_frag(ssl_s, 1), WOLFSSL_SUCCESS); + + /* Reject fragmented first CH */ + ExpectIntEQ(test_dtls_frag_ch_count_records(four_frag_CH, + sizeof(four_frag_CH)), 4); + len = sizeof(four_frag_CH); + test_memio_clear_buffer(&test_ctx, 0); + while (len > 0 && EXPECT_SUCCESS()) { + unsigned int inj_len = len > DUMMY_MTU ? DUMMY_MTU : len; + unsigned char *idx = four_frag_CH + sizeof(four_frag_CH) - len; + ExpectIntEQ(test_memio_inject_message(&test_ctx, 0, (const char *)idx, + inj_len), 0); + len -= inj_len; + } + ExpectIntEQ(test_ctx.s_len, sizeof(four_frag_CH)); + while (test_ctx.s_len > 0 && EXPECT_SUCCESS()) { + int s_len = test_ctx.s_len; + ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + /* Fail if we didn't advance the buffer to avoid infinite loops */ + ExpectIntLT(test_ctx.s_len, s_len); + } + /* Expect all fragments read */ + ExpectIntEQ(test_ctx.s_len, 0); + /* Expect quietly dropping fragmented first CH */ + ExpectIntEQ(test_ctx.c_len, 0); + +#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH) + /* Disable ECH as it pushes it over our MTU */ + wolfSSL_SetEchEnable(ssl_c, 0); +#endif + + /* Limit options to make the CH a fixed length */ + /* See wolfSSL_parse_cipher_list for reason why we provide 1.3 AND 1.2 + * ciphersuite. This is only necessary when building with OPENSSL_EXTRA. */ +#ifdef OPENSSL_EXTRA + ExpectTrue(wolfSSL_set_cipher_list(ssl_c, "TLS13-AES256-GCM-SHA384" + ":DHE-RSA-AES256-GCM-SHA384")); +#else + ExpectTrue(wolfSSL_set_cipher_list(ssl_c, "TLS13-AES256-GCM-SHA384")); +#endif + + /* CH1 */ + ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + /* Count records. Expect 1 unfragmented CH */ + ExpectIntEQ(test_dtls_frag_ch_count_records(test_ctx.s_buff, + test_ctx.s_len), 1); + /* HRR */ + ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + /* CH2 */ + ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + /* Count records. Expect fragmented CH */ + ExpectIntGT(test_dtls_frag_ch_count_records(test_ctx.s_buff, + test_ctx.s_len), 1); + + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); + ssl_c = ssl_s = NULL; + ctx_c = ctx_s = NULL; +#endif + return EXPECT_RESULT(); +} + +int test_dtls_empty_keyshare_with_cookie(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13) + WOLFSSL_CTX *ctx_s = NULL; + WOLFSSL *ssl_s = NULL; + struct test_memio_ctx test_ctx; + unsigned char ch_empty_keyshare_with_cookie[] = { + 0x16, 0xfe, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, + 0x12, 0x01, 0x00, 0x01, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x06, 0xfe, 0xfd, 0xfb, 0x8c, 0x9b, 0x28, 0xae, 0x50, 0x1c, 0x4d, 0xf3, + 0xb8, 0xcf, 0x4d, 0xd8, 0x7e, 0x93, 0x13, 0x7b, 0x9e, 0xd9, 0xeb, 0xe9, + 0x13, 0x4b, 0x0d, 0x7f, 0x2e, 0x43, 0x62, 0x8c, 0xe4, 0x57, 0x79, 0x00, + 0x00, 0x00, 0x36, 0x13, 0x01, 0x13, 0x02, 0x13, 0x03, 0xc0, 0x2c, 0xc0, + 0x2b, 0xc0, 0x30, 0xc0, 0x2f, 0x00, 0x9f, 0x00, 0x9e, 0xcc, 0xa9, 0xcc, + 0xa8, 0xcc, 0xaa, 0xc0, 0x27, 0xc0, 0x23, 0xc0, 0x28, 0xc0, 0x24, 0xc0, + 0x0a, 0xc0, 0x09, 0xc0, 0x14, 0xc0, 0x13, 0x00, 0x6b, 0x00, 0x67, 0x00, + 0x39, 0x00, 0x33, 0xcc, 0x14, 0xcc, 0x13, 0xcc, 0x15, 0x01, 0x00, 0x00, + 0xa6, 0x00, 0x2b, 0x00, 0x03, 0x02, 0xfe, 0xfc, 0x00, 0x2c, 0x00, 0x47, + 0x00, 0x45, 0x20, 0xee, 0x4b, 0x17, 0x70, 0x63, 0xa0, 0x4c, 0x82, 0xbf, + 0x43, 0x01, 0x7d, 0x8d, 0xc1, 0x1b, 0x4e, 0x9b, 0xa0, 0x3c, 0x53, 0x1f, + 0xb7, 0xd1, 0x10, 0x81, 0xa8, 0xdf, 0xdf, 0x8c, 0x7f, 0xf3, 0x11, 0x13, + 0x01, 0x02, 0x3d, 0x3b, 0x7d, 0x14, 0x2c, 0x31, 0xb3, 0x60, 0x72, 0x4d, + 0xe5, 0x1a, 0xb2, 0xa3, 0x61, 0x77, 0x73, 0x03, 0x40, 0x0e, 0x5f, 0xc5, + 0x61, 0x38, 0x43, 0x56, 0x21, 0x4a, 0x95, 0xd5, 0x35, 0xa8, 0x0d, 0x00, + 0x0d, 0x00, 0x2a, 0x00, 0x28, 0x06, 0x03, 0x05, 0x03, 0x04, 0x03, 0x02, + 0x03, 0xfe, 0x0b, 0xfe, 0x0e, 0xfe, 0xa0, 0xfe, 0xa3, 0xfe, 0xa5, 0x08, + 0x06, 0x08, 0x0b, 0x08, 0x05, 0x08, 0x0a, 0x08, 0x04, 0x08, 0x09, 0x06, + 0x01, 0x05, 0x01, 0x04, 0x01, 0x03, 0x01, 0x02, 0x01, 0x00, 0x0a, 0x00, + 0x18, 0x00, 0x16, 0x00, 0x19, 0x00, 0x18, 0x00, 0x17, 0x00, 0x15, 0x01, + 0x00, 0x02, 0x3a, 0x02, 0x3c, 0x02, 0x3d, 0x2f, 0x3a, 0x2f, 0x3c, 0x2f, + 0x3d, 0x00, 0x16, 0x00, 0x00, 0x00, 0x33, 0x00, 0x02, 0x00, 0x00 + }; + DtlsRecordLayerHeader* dtlsRH; + byte sequence_number[8]; + + XMEMSET(&sequence_number, 0, sizeof(sequence_number)); + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, NULL, &ctx_s, NULL, &ssl_s, + NULL, wolfDTLSv1_3_server_method), 0); + ExpectIntEQ(test_memio_inject_message(&test_ctx, 0, + (const char *)ch_empty_keyshare_with_cookie, + sizeof(ch_empty_keyshare_with_cookie)), 0); + + /* CH1 */ + ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + /* Expect an alert. A plaintext alert should be exactly 15 bytes. */ + ExpectIntEQ(test_ctx.c_len, 15); + dtlsRH = (DtlsRecordLayerHeader*)test_ctx.c_buff; + ExpectIntEQ(dtlsRH->type, alert); + ExpectIntEQ(dtlsRH->pvMajor, DTLS_MAJOR); + ExpectIntEQ(dtlsRH->pvMinor, DTLSv1_2_MINOR); + sequence_number[7] = 1; + ExpectIntEQ(XMEMCMP(sequence_number, dtlsRH->sequence_number, + sizeof(sequence_number)), 0); + ExpectIntEQ(dtlsRH->length[0], 0); + ExpectIntEQ(dtlsRH->length[1], 2); + ExpectIntEQ(test_ctx.c_buff[13], alert_fatal); + ExpectIntEQ(test_ctx.c_buff[14], illegal_parameter); + + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_s); +#endif + return EXPECT_RESULT(); +} + +int test_dtls13_missing_finished_client(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13) + WOLFSSL_CTX *ctx_c = NULL; + WOLFSSL_CTX *ctx_s = NULL; + WOLFSSL *ssl_c = NULL; + WOLFSSL *ssl_s = NULL; + struct test_memio_ctx test_ctx; + const char test_str[] = "test string"; + char test_buf[sizeof(test_str)]; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), 0); + + /* CH1 */ + ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + /* HRR */ + ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + /* CH2 */ + ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + /* Server first flight with finished */ + ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + /* Let's clear the output */ + test_memio_clear_buffer(&test_ctx, 1); + /* Let's send some app data */ + ExpectIntEQ(wolfSSL_write(ssl_s, test_str, sizeof(test_str)), + sizeof(test_str)); + /* Client second flight with finished */ + ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + /* Server should not error out on a missing finished */ + ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + /* Client rtx second flight with finished */ + ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + /* Server */ + ExpectIntEQ(wolfSSL_negotiate(ssl_s), 1); + /* Client */ + ExpectIntEQ(wolfSSL_negotiate(ssl_c), 1); + /* Let's send some app data */ + ExpectIntEQ(wolfSSL_write(ssl_s, test_str, sizeof(test_str)), + sizeof(test_str)); + ExpectIntEQ(wolfSSL_read(ssl_c, test_buf, sizeof(test_buf)), + sizeof(test_str)); + ExpectBufEQ(test_buf, test_str, sizeof(test_str)); + + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); +#endif + return EXPECT_RESULT(); +} + +int test_dtls13_missing_finished_server(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13) + WOLFSSL_CTX *ctx_c = NULL; + WOLFSSL_CTX *ctx_s = NULL; + WOLFSSL *ssl_c = NULL; + WOLFSSL *ssl_s = NULL; + struct test_memio_ctx test_ctx; + const char test_str[] = "test string"; + char test_buf[sizeof(test_str)]; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), 0); + + /* CH1 */ + ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + /* HRR */ + ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + /* CH2 */ + ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + /* Server first flight with finished */ + ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + /* Client second flight with finished */ + ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + /* Let's clear the output */ + test_memio_clear_buffer(&test_ctx, 0); + ExpectFalse(wolfSSL_is_init_finished(ssl_c)); + /* Let's send some app data */ + ExpectIntEQ(wolfSSL_write(ssl_c, test_str, sizeof(test_str)), + sizeof(test_str)); + /* Server should not error out on a missing finished */ + ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + /* Client rtx second flight with finished */ + ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + /* Server first flight with finished */ + ExpectIntEQ(wolfSSL_negotiate(ssl_s), 1); + /* Let's send some app data */ + ExpectIntEQ(wolfSSL_write(ssl_c, test_str, sizeof(test_str)), + sizeof(test_str)); + ExpectIntEQ(wolfSSL_read(ssl_s, test_buf, sizeof(test_buf)), + sizeof(test_str)); + ExpectBufEQ(test_buf, test_str, sizeof(test_str)); + + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); +#endif + return EXPECT_RESULT(); +} + +int test_dtls13_finished_send_error_propagation(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13) + WOLFSSL_CTX *ctx_c = NULL; + WOLFSSL_CTX *ctx_s = NULL; + WOLFSSL *ssl_c = NULL; + WOLFSSL *ssl_s = NULL; + struct test_memio_ctx test_ctx; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), 0); + + /* CH1 */ + ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + /* HRR */ + ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + /* CH2 */ + ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + /* Server first flight with finished */ + ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + /* Client second flight with finished - block sends to force error */ + test_ctx.s_len = TEST_MEMIO_BUF_SZ; + ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); + /* Verify the error is propagated, not silently swallowed as success */ + ExpectIntNE(wolfSSL_get_error(ssl_c, -1), 0); + + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); +#endif + return EXPECT_RESULT(); +} + + +/*----------------------------------------------------------------------------*/ +/* DTLSv1.3-only tests moved from test_dtls.c (isolated from DTLS<=1.2 code) */ +/*----------------------------------------------------------------------------*/ + +/*-- basic_connection_id (test_dtls.c lines 422,580) ---*/ +int test_dtls13_basic_connection_id(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13) \ + && defined(WOLFSSL_DTLS_CID) + unsigned char client_cid[] = { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }; + unsigned char server_cid[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + unsigned char readBuf[50]; + void * cid = NULL; + const char* params[] = { +#ifndef NO_SHA256 +#ifdef WOLFSSL_AES_128 +#ifdef HAVE_AESGCM + "TLS13-AES128-GCM-SHA256", +#endif +#if defined(HAVE_CHACHA) && defined(HAVE_POLY1305) + "TLS13-CHACHA20-POLY1305-SHA256", +#endif +#ifdef HAVE_AESCCM + "TLS13-AES128-CCM-8-SHA256", + "TLS13-AES128-CCM-SHA256", +#endif +#endif +#ifdef HAVE_NULL_CIPHER + "TLS13-SHA256-SHA256", +#endif +#endif + }; + size_t i; + + /* We check if the side included the CID in their output */ +#define CLIENT_CID() mymemmem(test_ctx.s_buff, test_ctx.s_len, \ + client_cid, sizeof(client_cid)) +#define SERVER_CID() mymemmem(test_ctx.c_buff, test_ctx.c_len, \ + server_cid, sizeof(server_cid)) +#define RESET_CID(cid) if ((cid) != NULL) { \ + ((char*)(cid))[0] = -1; \ + } + + + printf("\n"); + for (i = 0; i < XELEM_CNT(params) && EXPECT_SUCCESS(); i++) { + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + + printf("Testing %s ... ", params[i]); + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), 0); + + ExpectIntEQ(wolfSSL_set_cipher_list(ssl_c, params[i]), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_set_cipher_list(ssl_s, params[i]), WOLFSSL_SUCCESS); + + ExpectIntEQ(wolfSSL_dtls_cid_use(ssl_c), 1); + ExpectIntEQ(wolfSSL_dtls_cid_set(ssl_c, server_cid, sizeof(server_cid)), + 1); + ExpectIntEQ(wolfSSL_dtls_cid_use(ssl_s), 1); + ExpectIntEQ(wolfSSL_dtls_cid_set(ssl_s, client_cid, sizeof(client_cid)), + 1); + + /* CH1 */ + ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + ExpectNull(CLIENT_CID()); + /* HRR */ + ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + ExpectNull(SERVER_CID()); + /* CH2 */ + ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + ExpectNull(CLIENT_CID()); + /* Server first flight */ + ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + ExpectNotNull(SERVER_CID()); + /* Client second flight */ + ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + ExpectNotNull(CLIENT_CID()); + /* Server process flight */ + ExpectIntEQ(wolfSSL_negotiate(ssl_s), 1); + /* Client process flight */ + ExpectIntEQ(wolfSSL_negotiate(ssl_c), 1); + + /* Write some data */ + ExpectIntEQ(wolfSSL_write(ssl_c, params[i], (int)XSTRLEN(params[i])), + XSTRLEN(params[i])); + ExpectNotNull(CLIENT_CID()); + ExpectIntEQ(wolfSSL_write(ssl_s, params[i], (int)XSTRLEN(params[i])), + XSTRLEN(params[i])); + ExpectNotNull(SERVER_CID()); + /* Read the data */ + XMEMSET(readBuf, 0, sizeof(readBuf)); + ExpectIntEQ(wolfSSL_read(ssl_c, readBuf, sizeof(readBuf)), + XSTRLEN(params[i])); + ExpectStrEQ(readBuf, params[i]); + XMEMSET(readBuf, 0, sizeof(readBuf)); + ExpectIntEQ(wolfSSL_read(ssl_s, readBuf, sizeof(readBuf)), + XSTRLEN(params[i])); + ExpectStrEQ(readBuf, params[i]); + /* Write short data */ + ExpectIntEQ(wolfSSL_write(ssl_c, params[i], 1), 1); + ExpectNotNull(CLIENT_CID()); + ExpectIntEQ(wolfSSL_write(ssl_s, params[i], 1), 1); + ExpectNotNull(SERVER_CID()); + /* Read the short data */ + XMEMSET(readBuf, 0, sizeof(readBuf)); + ExpectIntEQ(wolfSSL_read(ssl_c, readBuf, sizeof(readBuf)), 1); + ExpectIntEQ(readBuf[0], params[i][0]); + XMEMSET(readBuf, 0, sizeof(readBuf)); + ExpectIntEQ(wolfSSL_read(ssl_s, readBuf, sizeof(readBuf)), 1); + ExpectIntEQ(readBuf[0], params[i][0]); + /* Write some data but with wrong CID */ + ExpectIntEQ(wolfSSL_write(ssl_c, params[i], (int)XSTRLEN(params[i])), + XSTRLEN(params[i])); + /* Reset client cid. */ + ExpectNotNull(cid = CLIENT_CID()); + RESET_CID(cid); + ExpectIntEQ(wolfSSL_write(ssl_s, params[i], (int)XSTRLEN(params[i])), + XSTRLEN(params[i])); + /* Reset server cid. */ + ExpectNotNull(cid = SERVER_CID()); + RESET_CID(cid); + /* Try to read the data but it shouldn't be there */ + ExpectIntEQ(wolfSSL_read(ssl_c, readBuf, sizeof(readBuf)), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + ExpectIntEQ(wolfSSL_read(ssl_s, readBuf, sizeof(readBuf)), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + + /* Close connection */ + ExpectIntEQ(wolfSSL_shutdown(ssl_c), WOLFSSL_SHUTDOWN_NOT_DONE); + ExpectNotNull(CLIENT_CID()); + ExpectIntEQ(wolfSSL_shutdown(ssl_s), WOLFSSL_SHUTDOWN_NOT_DONE); + ExpectNotNull(SERVER_CID()); + ExpectIntEQ(wolfSSL_shutdown(ssl_c), 1); + ExpectIntEQ(wolfSSL_shutdown(ssl_s), 1); + + if (EXPECT_SUCCESS()) + printf("ok\n"); + else + printf("failed\n"); + + wolfSSL_free(ssl_c); + wolfSSL_CTX_free(ctx_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_s); + } + +#undef CLIENT_CID +#undef SERVER_CID +#undef RESET_CID + +#endif + return EXPECT_RESULT(); +} + +/*-- hrr_want_write (test_dtls.c lines 588,639) ---*/ +int test_dtls13_hrr_want_write(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13) + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + const char msg[] = "hello"; + const int msgLen = sizeof(msg); + struct test_memio_ctx test_ctx; + char readBuf[sizeof(msg)]; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), + 0); + + /* Client sends first ClientHello */ + ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + + /* Force server to hit WANT_WRITE when producing the HRR */ + test_memio_simulate_want_write(&test_ctx, 0, 1); + ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_WRITE); + + /* Allow the server to flush the HRR and proceed */ + test_memio_simulate_want_write(&test_ctx, 0, 0); + ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + + /* Resume the DTLS 1.3 handshake */ + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + + /* Verify post-handshake application data in both directions */ + XMEMSET(readBuf, 0, sizeof(readBuf)); + ExpectIntEQ(wolfSSL_write(ssl_c, msg, msgLen), msgLen); + ExpectIntEQ(wolfSSL_read(ssl_s, readBuf, sizeof(readBuf)), msgLen); + ExpectStrEQ(readBuf, msg); + + XMEMSET(readBuf, 0, sizeof(readBuf)); + ExpectIntEQ(wolfSSL_write(ssl_s, msg, msgLen), msgLen); + ExpectIntEQ(wolfSSL_read(ssl_c, readBuf, sizeof(readBuf)), msgLen); + ExpectStrEQ(readBuf, msg); + + wolfSSL_free(ssl_c); + wolfSSL_CTX_free(ctx_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_s); +#endif + return EXPECT_RESULT(); +} + +/*-- want_write_send_cb_helper (test_dtls.c lines 641,655) ---*/ +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13) +struct test_dtls13_wwrite_ctx { + int want_write; + struct test_memio_ctx *text_ctx; +}; +static int test_dtls13_want_write_send_cb(WOLFSSL *ssl, char *data, int sz, void *ctx) +{ + struct test_dtls13_wwrite_ctx *wwctx = (struct test_dtls13_wwrite_ctx *)ctx; + wwctx->want_write = !wwctx->want_write; + if (wwctx->want_write) { + return WOLFSSL_CBIO_ERR_WANT_WRITE; + } + return test_memio_write_cb(ssl, data, sz, wwctx->text_ctx); +} +#endif + +/*-- every_write_want_write (test_dtls.c lines 665,740) ---*/ +int test_dtls13_every_write_want_write(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13) + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + const char msg[] = "want-write"; + const int msgLen = sizeof(msg); + char readBuf[sizeof(msg)]; + struct test_dtls13_wwrite_ctx wwctx_c; + struct test_dtls13_wwrite_ctx wwctx_s; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), + 0); + + wwctx_c.want_write = 0; + wwctx_c.text_ctx = &test_ctx; + wolfSSL_SetIOWriteCtx(ssl_c, &wwctx_c); + wolfSSL_SSLSetIOSend(ssl_c, test_dtls13_want_write_send_cb); + wwctx_s.want_write = 0; + wwctx_s.text_ctx = &test_ctx; + wolfSSL_SetIOWriteCtx(ssl_s, &wwctx_s); + wolfSSL_SSLSetIOSend(ssl_s, test_dtls13_want_write_send_cb); + + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 20, NULL), 0); + + ExpectTrue(wolfSSL_is_init_finished(ssl_c)); + ExpectTrue(wolfSSL_is_init_finished(ssl_s)); + + test_memio_simulate_want_write(&test_ctx, 0, 0); + test_memio_simulate_want_write(&test_ctx, 1, 0); + + wolfSSL_SetIOWriteCtx(ssl_c, &test_ctx); + wolfSSL_SSLSetIOSend(ssl_c, test_memio_write_cb); + wolfSSL_SetIOWriteCtx(ssl_s, &test_ctx); + wolfSSL_SSLSetIOSend(ssl_s, test_memio_write_cb); + + XMEMSET(readBuf, 0, sizeof(readBuf)); + ExpectIntEQ(wolfSSL_write(ssl_c, msg, msgLen), msgLen); + ExpectIntEQ(wolfSSL_read(ssl_s, readBuf, sizeof(readBuf)), msgLen); + ExpectStrEQ(readBuf, msg); + + XMEMSET(readBuf, 0, sizeof(readBuf)); + ExpectIntEQ(wolfSSL_write(ssl_s, msg, msgLen), msgLen); + ExpectIntEQ(wolfSSL_read(ssl_c, readBuf, sizeof(readBuf)), msgLen); + ExpectStrEQ(readBuf, msg); + + test_memio_simulate_want_write(&test_ctx, 0, 1); + XMEMSET(readBuf, 0, sizeof(readBuf)); + ExpectIntEQ(wolfSSL_write(ssl_s, msg, msgLen), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_WRITE); + test_memio_simulate_want_write(&test_ctx, 0, 0); + ExpectIntEQ(wolfSSL_write(ssl_s, msg, msgLen), msgLen); + ExpectIntEQ(wolfSSL_read(ssl_c, readBuf, sizeof(readBuf)), msgLen); + ExpectStrEQ(readBuf, msg); + + XMEMSET(readBuf, 0, sizeof(readBuf)); + test_memio_simulate_want_write(&test_ctx, 1, 1); + ExpectIntEQ(wolfSSL_write(ssl_c, msg, msgLen), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_WRITE); + test_memio_simulate_want_write(&test_ctx, 1, 0); + ExpectIntEQ(wolfSSL_write(ssl_c, msg, msgLen), msgLen); + ExpectIntEQ(wolfSSL_read(ssl_s, readBuf, sizeof(readBuf)), msgLen); + ExpectStrEQ(readBuf, msg); + + wolfSSL_free(ssl_c); + wolfSSL_CTX_free(ctx_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_s); +#endif + return EXPECT_RESULT(); +} + +/*-- epochs (test_dtls.c lines 823,871) ---*/ +int test_dtls13_epochs(void) { + EXPECT_DECLS; +#if defined(WOLFSSL_DTLS13) && !defined(NO_WOLFSSL_CLIENT) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + byte input[20]; + word32 inOutIdx = 0; + + XMEMSET(input, 0, sizeof(input)); + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfDTLSv1_3_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + /* Some manual setup to enter the epoch check */ + ExpectTrue(ssl->options.tls1_3 = 1); + + inOutIdx = 0; + if (ssl != NULL) ssl->keys.curEpoch64 = w64From32(0x0, 0x0); + ExpectIntEQ(DoApplicationData(ssl, input, &inOutIdx, 0), SANITY_MSG_E); + inOutIdx = 0; + if (ssl != NULL) ssl->keys.curEpoch64 = w64From32(0x0, 0x2); + ExpectIntEQ(DoApplicationData(ssl, input, &inOutIdx, 0), SANITY_MSG_E); + + if (ssl != NULL) ssl->keys.curEpoch64 = w64From32(0x0, 0x1); + ExpectIntEQ(Dtls13CheckEpoch(ssl, client_hello), SANITY_MSG_E); + ExpectIntEQ(Dtls13CheckEpoch(ssl, server_hello), SANITY_MSG_E); + ExpectIntEQ(Dtls13CheckEpoch(ssl, hello_verify_request), SANITY_MSG_E); + ExpectIntEQ(Dtls13CheckEpoch(ssl, hello_retry_request), SANITY_MSG_E); + ExpectIntEQ(Dtls13CheckEpoch(ssl, hello_request), SANITY_MSG_E); + ExpectIntEQ(Dtls13CheckEpoch(ssl, encrypted_extensions), SANITY_MSG_E); + ExpectIntEQ(Dtls13CheckEpoch(ssl, server_key_exchange), SANITY_MSG_E); + ExpectIntEQ(Dtls13CheckEpoch(ssl, server_hello_done), SANITY_MSG_E); + ExpectIntEQ(Dtls13CheckEpoch(ssl, client_key_exchange), SANITY_MSG_E); + ExpectIntEQ(Dtls13CheckEpoch(ssl, certificate_request), SANITY_MSG_E); + ExpectIntEQ(Dtls13CheckEpoch(ssl, certificate), SANITY_MSG_E); + ExpectIntEQ(Dtls13CheckEpoch(ssl, certificate_verify), SANITY_MSG_E); + ExpectIntEQ(Dtls13CheckEpoch(ssl, finished), SANITY_MSG_E); + ExpectIntEQ(Dtls13CheckEpoch(ssl, certificate_status), SANITY_MSG_E); + ExpectIntEQ(Dtls13CheckEpoch(ssl, change_cipher_hs), SANITY_MSG_E); + ExpectIntEQ(Dtls13CheckEpoch(ssl, key_update), SANITY_MSG_E); + ExpectIntEQ(Dtls13CheckEpoch(ssl, session_ticket), SANITY_MSG_E); + ExpectIntEQ(Dtls13CheckEpoch(ssl, end_of_early_data), SANITY_MSG_E); + ExpectIntEQ(Dtls13CheckEpoch(ssl, message_hash), SANITY_MSG_E); + ExpectIntEQ(Dtls13CheckEpoch(ssl, no_shake), SANITY_MSG_E); + + wolfSSL_CTX_free(ctx); + wolfSSL_free(ssl); +#endif + return EXPECT_RESULT(); +} + +/*-- ack_order (test_dtls.c lines 873,951) ---*/ +int test_dtls13_ack_order(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13) + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + unsigned char readBuf[50]; + word32 length = 0; + /* struct { + * uint64 epoch; + * uint64 sequence_number; + * } RecordNumber; + * Big endian */ + static const unsigned char expected_output[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, + }; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + + /* Get a populated DTLS object */ + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), 0); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + ExpectIntEQ(wolfSSL_read(ssl_c, readBuf, sizeof(readBuf)), -1); + /* Clear the buffer of any extra messages */ + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + ExpectIntEQ(wolfSSL_read(ssl_s, readBuf, sizeof(readBuf)), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + ExpectIntEQ(test_ctx.c_len, 0); + ExpectIntEQ(test_ctx.s_len, 0); + + /* Add seen records */ + ExpectIntEQ(Dtls13RtxAddAck(ssl_c, w64From32(0, 3), w64From32(0, 2)), 0); + ExpectIntEQ(Dtls13RtxAddAck(ssl_c, w64From32(0, 3), w64From32(0, 0)), 0); + ExpectIntEQ(Dtls13RtxAddAck(ssl_c, w64From32(0, 3), w64From32(0, 1)), 0); + ExpectIntEQ(Dtls13RtxAddAck(ssl_c, w64From32(0, 3), w64From32(0, 4)), 0); + ExpectIntEQ(Dtls13RtxAddAck(ssl_c, w64From32(0, 2), w64From32(0, 0)), 0); + ExpectIntEQ(Dtls13RtxAddAck(ssl_c, w64From32(0, 3), w64From32(0, 6)), 0); + ExpectIntEQ(Dtls13RtxAddAck(ssl_c, w64From32(0, 3), w64From32(0, 6)), 0); + ExpectIntEQ(Dtls13RtxAddAck(ssl_c, w64From32(0, 2), w64From32(0, 1)), 0); + ExpectIntEQ(Dtls13RtxAddAck(ssl_c, w64From32(0, 2), w64From32(0, 2)), 0); + ExpectIntEQ(Dtls13RtxAddAck(ssl_c, w64From32(0, 2), w64From32(0, 2)), 0); + ExpectIntEQ(Dtls13WriteAckMessage(ssl_c, ssl_c->dtls13Rtx.seenRecords, + ssl_c->dtls13Rtx.seenRecordsCount, &length), 0); + + /* must zero the span reserved for the header to avoid read of uninited + * data. + */ + XMEMSET(ssl_c->buffers.outputBuffer.buffer, 0, + 5 /* DTLS13_UNIFIED_HEADER_SIZE */); + /* N * RecordNumber + 2 extra bytes for length */ + ExpectIntEQ(length, sizeof(expected_output) + 2); + ExpectNotNull(mymemmem(ssl_c->buffers.outputBuffer.buffer, + ssl_c->buffers.outputBuffer.bufferSize, expected_output, + sizeof(expected_output))); + + wolfSSL_free(ssl_c); + wolfSSL_CTX_free(ctx_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_s); +#endif + return EXPECT_RESULT(); +} + +/*-- ack_overflow (test_dtls.c lines 953,1010) ---*/ +int test_dtls13_ack_overflow(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13) + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + unsigned char readBuf[50]; + word32 length = 0; + int i; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), 0); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + ExpectIntEQ(wolfSSL_read(ssl_c, readBuf, sizeof(readBuf)), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + ExpectIntEQ(wolfSSL_read(ssl_s, readBuf, sizeof(readBuf)), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + + /* Edge case 1: one below limit - all inserts must succeed */ + for (i = 0; i < DTLS13_ACK_MAX_RECORDS - 1; i++) { + ExpectIntEQ(Dtls13RtxAddAck(ssl_c, w64From32(0, 0), + w64From32(0, (word32)i)), 0); + } + ExpectIntEQ(ssl_c->dtls13Rtx.seenRecordsCount, DTLS13_ACK_MAX_RECORDS - 1); + + /* Edge case 2: insert the last allowed record - must succeed */ + ExpectIntEQ(Dtls13RtxAddAck(ssl_c, w64From32(0, 0), + w64From32(0, (word32)(DTLS13_ACK_MAX_RECORDS - 1))), 0); + ExpectIntEQ(ssl_c->dtls13Rtx.seenRecordsCount, DTLS13_ACK_MAX_RECORDS); + + /* Writing a full-but-valid list must succeed */ + ExpectIntEQ(Dtls13WriteAckMessage(ssl_c, ssl_c->dtls13Rtx.seenRecords, + ssl_c->dtls13Rtx.seenRecordsCount, &length), 0); + + /* Edge case 3: one over limit - must be silently dropped */ + ExpectIntEQ(Dtls13RtxAddAck(ssl_c, w64From32(0, 0), + w64From32(0, (word32)DTLS13_ACK_MAX_RECORDS)), 0); + ExpectIntEQ(ssl_c->dtls13Rtx.seenRecordsCount, DTLS13_ACK_MAX_RECORDS); + + /* Bypass the insert guard to force the list one element over the limit, + * then verify Dtls13WriteAckMessage errors out instead of overflowing */ + ssl_c->dtls13Rtx.seenRecordsCount = 0; + ExpectIntEQ(Dtls13RtxAddAck(ssl_c, w64From32(0, 1), + w64From32(0, (word32)DTLS13_ACK_MAX_RECORDS)), 0); + ssl_c->dtls13Rtx.seenRecordsCount = (word16)(DTLS13_ACK_MAX_RECORDS + 1); + ExpectIntEQ(Dtls13WriteAckMessage(ssl_c, ssl_c->dtls13Rtx.seenRecords, + ssl_c->dtls13Rtx.seenRecordsCount, &length), BUFFER_E); + + wolfSSL_free(ssl_c); + wolfSSL_CTX_free(ctx_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_s); +#endif + return EXPECT_RESULT(); +} + +/*-- ack_dup_write_counter (test_dtls.c lines 1012,1069) ---*/ +int test_dtls13_ack_dup_write_counter(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13) \ + && defined(HAVE_WRITE_DUP) + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + WOLFSSL *ssl_c2 = NULL; + struct test_memio_ctx test_ctx; + unsigned char readBuf[50]; + int i; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), 0); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + /* Drain any post-handshake messages */ + ExpectIntEQ(wolfSSL_read(ssl_c, readBuf, sizeof(readBuf)), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + ExpectIntEQ(wolfSSL_read(ssl_s, readBuf, sizeof(readBuf)), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + + /* Split ssl_c: ssl_c becomes READ_DUP_SIDE, ssl_c2 becomes WRITE_DUP_SIDE */ + ExpectNotNull(ssl_c2 = wolfSSL_write_dup(ssl_c)); + + /* Cycle 1: add records, trigger handoff, verify counter is reset to 0 */ + for (i = 0; i < 5; i++) + ExpectIntEQ(Dtls13RtxAddAck(ssl_c, w64From32(0, 3), + w64From32(0, (word32)i)), 0); + ExpectIntEQ(ssl_c->dtls13Rtx.seenRecordsCount, 5); + ssl_c->dtls13Rtx.sendAcks = 1; + ExpectIntEQ(Dtls13DoScheduledWork(ssl_c), 0); + /* seenRecords ownership was transferred to dupWrite->sendAckList; + * seenRecordsCount must be reset to 0, not left at 5. */ + ExpectNull(ssl_c->dtls13Rtx.seenRecords); + ExpectIntEQ(ssl_c->dtls13Rtx.seenRecordsCount, 0); + + /* Cycle 2 (different epoch to avoid the dup-filter): verify the counter + * did not accumulate across the previous transfer. Without the fix, + * seenRecordsCount would now be 10 after this second batch. */ + for (i = 0; i < 5; i++) + ExpectIntEQ(Dtls13RtxAddAck(ssl_c, w64From32(0, 4), + w64From32(0, (word32)i)), 0); + ExpectIntEQ(ssl_c->dtls13Rtx.seenRecordsCount, 5); + ssl_c->dtls13Rtx.sendAcks = 1; + ExpectIntEQ(Dtls13DoScheduledWork(ssl_c), 0); + ExpectNull(ssl_c->dtls13Rtx.seenRecords); + ExpectIntEQ(ssl_c->dtls13Rtx.seenRecordsCount, 0); + + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_c2); + wolfSSL_CTX_free(ctx_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_s); +#endif + return EXPECT_RESULT(); +} + +/*-- get_message_seq_helper (test_dtls.c lines 1850,1867) ---*/ +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \ + defined(WOLFSSL_DTLS13) && defined(WOLFSSL_DTLS) +static int test_dtls13_get_message_seq(const char* msg, int msgSz, + word16* msgSeq) +{ + int hsOff = DTLS_RECORD_HEADER_SZ; + + if (msg == NULL || msgSeq == NULL || + msgSz < DTLS_RECORD_HEADER_SZ + DTLS_HANDSHAKE_HEADER_SZ) { + return BAD_FUNC_ARG; + } + + *msgSeq = ((word16)(byte)msg[hsOff + 4] << 8) | + (word16)(byte)msg[hsOff + 5]; + + return WOLFSSL_SUCCESS; +} +#endif + +/*-- ch2_rtx_no_ch1 (test_dtls.c lines 1869,1940) ---*/ +int test_dtls13_ch2_rtx_no_ch1(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \ + defined(WOLFSSL_DTLS13) && defined(WOLFSSL_DTLS) + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + const char* msg = NULL; + int msgSz = 0; + word16 ch1Seq = 0; + int i; + int foundCh1Seq = 0; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), + 0); + + /* To force HRR */ + ExpectIntEQ(wolfSSL_NoKeyShares(ssl_c), WOLFSSL_SUCCESS); + + /* CH1 */ + ExpectIntEQ(wolfSSL_connect(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + ExpectIntEQ(test_memio_get_message(&test_ctx, 0, &msg, &msgSz, 0), 0); + ExpectIntGE(msgSz, DTLS_RECORD_HEADER_SZ + DTLS_HANDSHAKE_HEADER_SZ); + ExpectIntEQ(test_dtls13_get_message_seq(msg, msgSz, &ch1Seq), + WOLFSSL_SUCCESS); + + /* HRR */ + ExpectIntEQ(wolfSSL_accept(ssl_s), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + ExpectIntGT(test_ctx.c_msg_count, 0); + + /* CH2 */ + ExpectIntEQ(wolfSSL_connect(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + ExpectIntGT(test_ctx.s_msg_count, 0); + + /* Drop CH2 and trigger the client retransmission timeout. */ + test_memio_clear_buffer(&test_ctx, 0); + if (wolfSSL_dtls13_use_quick_timeout(ssl_c)) + ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl_c), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl_c), WOLFSSL_SUCCESS); + ExpectIntGT(test_ctx.s_msg_count, 0); + + for (i = 0; i < test_ctx.s_msg_count && EXPECT_SUCCESS(); i++) { + int hsOff = DTLS_RECORD_HEADER_SZ; + word16 msgSeq = 0; + + ExpectIntEQ(test_memio_get_message(&test_ctx, 0, &msg, &msgSz, i), 0); + /* memio stores one DTLS record per message in this handshake path. */ + if (msgSz >= DTLS_RECORD_HEADER_SZ + DTLS_HANDSHAKE_HEADER_SZ && + (byte)msg[0] == handshake && msg[hsOff] == client_hello) { + ExpectIntEQ(test_dtls13_get_message_seq(msg, msgSz, &msgSeq), + WOLFSSL_SUCCESS); + if (msgSeq == ch1Seq) + foundCh1Seq = 1; + } + } + + ExpectIntEQ(foundCh1Seq, 0); + + wolfSSL_free(ssl_c); + wolfSSL_CTX_free(ctx_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_s); +#endif + return EXPECT_RESULT(); +} + +/*-- frag_ch2_with_ch1_rtx (test_dtls.c lines 1942,2068) ---*/ +int test_dtls13_frag_ch2_with_ch1_rtx(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \ + defined(WOLFSSL_DTLS13) && defined(WOLFSSL_DTLS) && \ + defined(WOLFSSL_DTLS_MTU) && defined(WOLFSSL_DTLS_CH_FRAG) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + char hrr[TEST_MEMIO_BUF_SZ]; + int hrrSz = (int)sizeof(hrr); + char ch1Rtx[TEST_MEMIO_BUF_SZ]; + int ch1RtxSz = (int)sizeof(ch1Rtx); + char ch2[TEST_MEMIO_BUF_SZ]; + int ch2Sz = 0; + int ch2MsgCount = 0; + int ch2MsgSizes[TEST_MEMIO_MAX_MSGS] = {0}; + /* The DTLS record sequence number occupies the last 8 bytes of the + * record header. */ + int recordSeqOff = DTLS_RECORD_HEADER_SZ - 8; + int ch2Seq = 0; + int ch1RtxSeq = 0; + int off; + int i; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), + 0); + + /* To force HRR */ + ExpectIntEQ(wolfSSL_NoKeyShares(ssl_c), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_dtls13_allow_ch_frag(ssl_s, 1), WOLFSSL_SUCCESS); + + /* CH1 */ + ExpectIntEQ(wolfSSL_connect(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + + /* HRR */ + ExpectIntEQ(wolfSSL_accept(ssl_s), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + ExpectIntEQ(test_memio_copy_message(&test_ctx, 1, hrr, &hrrSz, 0), 0); + + /* Drop HRR, trigger CH1 retransmission, copy and drop it */ + test_memio_clear_buffer(&test_ctx, 1); + if (wolfSSL_dtls13_use_quick_timeout(ssl_c)) + ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl_c), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl_c), WOLFSSL_SUCCESS); + ExpectIntEQ(test_memio_copy_message(&test_ctx, 0, ch1Rtx, &ch1RtxSz, 0), 0); + test_memio_clear_buffer(&test_ctx, 0); + + /* Force CH2 fragmentation. MTU must be small enough to fragment but large + * enough that the cookie extension lands in the first fragment, otherwise + * the server can't validate it statelessly and the test scenario (server + * stateful after frag 1) does not hold. With --enable-all (PQ groups in + * supported_groups), the cookie extension can sit ~400 bytes into CH2; 600 + * gives margin while still producing multiple fragments (CH2 is ~2KB). */ + ExpectIntEQ(wolfSSL_dtls_set_mtu(ssl_c, 600), WOLFSSL_SUCCESS); + + /* Forward HRR and let the client create fragmented CH2 */ + ExpectIntEQ(test_memio_inject_message(&test_ctx, 1, hrr, hrrSz), 0); + ExpectIntEQ(wolfSSL_connect(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + + ExpectIntGT(test_ctx.s_msg_count, 1); + ExpectIntLE(test_ctx.s_msg_count, TEST_MEMIO_MAX_MSGS); + ExpectIntLE(test_ctx.s_len, (int)sizeof(ch2)); + if (EXPECT_SUCCESS()) { + ch2Sz = test_ctx.s_len; + ch2MsgCount = test_ctx.s_msg_count; + XMEMCPY(ch2, test_ctx.s_buff, ch2Sz); + XMEMCPY(ch2MsgSizes, test_ctx.s_msg_sizes, + sizeof(ch2MsgSizes[0]) * (size_t)ch2MsgCount); + + ch2Seq = ((byte)ch2[recordSeqOff + 4] << 8) | + (byte)ch2[recordSeqOff + 5]; + ch1RtxSeq = ch2Seq + ch2MsgCount; + + /* Synthesize a CH1 retransmission that can pass the replay window after + * the first CH2 fragment makes the server stateful. The handshake + * message_seq remains the original CH1 value; only the DTLS record + * sequence is moved past the fragmented CH2 flight */ + ch1Rtx[recordSeqOff + 0] = 0; + ch1Rtx[recordSeqOff + 1] = 0; + ch1Rtx[recordSeqOff + 2] = 0; + ch1Rtx[recordSeqOff + 3] = 0; + ch1Rtx[recordSeqOff + 4] = (byte)(ch1RtxSeq >> 8); + ch1Rtx[recordSeqOff + 5] = (byte)ch1RtxSeq; + } + + test_memio_clear_buffer(&test_ctx, 0); + + /* Deliver CH2 first fragment only. Now server is stateful */ + ExpectIntEQ(test_memio_inject_message(&test_ctx, 0, ch2, ch2MsgSizes[0]), 0); + ExpectIntEQ(wolfSSL_accept(ssl_s), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + + /* Deliver the retransmitted CH1 between CH2 fragments, it should be + * discarded as rtx */ + ExpectIntEQ(test_memio_inject_message(&test_ctx, 0, ch1Rtx, ch1RtxSz), 0); + ExpectIntEQ(wolfSSL_accept(ssl_s), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + test_memio_clear_buffer(&test_ctx, 1); + + /* Deliver the rest of CH2 */ + off = ch2MsgSizes[0]; + for (i = 1; i < ch2MsgCount && EXPECT_SUCCESS(); i++) { + ExpectIntEQ(test_memio_inject_message(&test_ctx, 0, ch2 + off, + ch2MsgSizes[i]), 0); + off += ch2MsgSizes[i]; + } + + /* Restore MTU so the client's input buffer can hold the full server + * flight (e.g. an SH carrying a hybrid PQC key share). */ + ExpectIntEQ(wolfSSL_dtls_set_mtu(ssl_c, 1500), WOLFSSL_SUCCESS); + + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + + wolfSSL_free(ssl_c); + wolfSSL_CTX_free(ctx_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_s); +#endif + return EXPECT_RESULT(); +} + +/*-- srtp_with_helper_and_stub (test_dtls.c lines 2276,2312) ---*/ +#if defined(WOLFSSL_DTLS13) && defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES) && \ + defined(WOLFSSL_SRTP) +static int test_dtls_srtp_ctx_ready(WOLFSSL_CTX* ctx) +{ + EXPECT_DECLS; + ExpectIntEQ(wolfSSL_CTX_set_tlsext_use_srtp(ctx, "SRTP_AEAD_AES_256_GCM:" + "SRTP_AEAD_AES_128_GCM:SRTP_AES128_CM_SHA1_80:SRTP_AES128_CM_SHA1_32"), + 0); + return EXPECT_RESULT(); +} + +int test_dtls_srtp(void) +{ + EXPECT_DECLS; + test_ssl_cbf client_cbf; + test_ssl_cbf server_cbf; + + XMEMSET(&client_cbf, 0, sizeof(client_cbf)); + XMEMSET(&server_cbf, 0, sizeof(server_cbf)); + + client_cbf.method = wolfDTLSv1_3_client_method; + client_cbf.ctx_ready = test_dtls_srtp_ctx_ready; + server_cbf.method = wolfDTLSv1_3_server_method; + server_cbf.ctx_ready = test_dtls_srtp_ctx_ready; + + ExpectIntEQ(test_wolfSSL_client_server_nofail_memio(&client_cbf, + &server_cbf, NULL), TEST_SUCCESS); + + return EXPECT_RESULT(); +} +#else +int test_dtls_srtp(void) +{ + EXPECT_DECLS; + return EXPECT_RESULT(); +} +#endif + +/*-- min_rtx_interval (test_dtls.c lines 2890,2960) ---*/ +int test_dtls13_min_rtx_interval(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \ + defined(WOLFSSL_DTLS13) && !defined(DTLS13_MIN_RTX_INTERVAL) && \ + !defined(NO_ASN_TIME) + /* We don't want to test when DTLS13_MIN_RTX_INTERVAL is defined because + * it may be too low to trigger reliably in a test. The default value is + * 1 second which is sufficient for testing here. */ + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + int c_msg_count = 0; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + + /* Setup DTLS 1.3 contexts */ + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), 0); + + /* CH0 */ + ExpectIntEQ(wolfSSL_connect(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), SSL_ERROR_WANT_READ); + + /* HRR */ + ExpectIntEQ(wolfSSL_accept(ssl_s), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), SSL_ERROR_WANT_READ); + + /* CH1 */ + ExpectIntEQ(wolfSSL_connect(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), SSL_ERROR_WANT_READ); + + /* SH ... FINISHED */ + ExpectIntEQ(wolfSSL_accept(ssl_s), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), SSL_ERROR_WANT_READ); + + /* We should have SH ... FINISHED messages in the buffer */ + ExpectIntGE(test_ctx.c_msg_count, 2); + + /* Drop everything */ + test_memio_clear_buffer(&test_ctx, 1); + + /* First timeout. This one should trigger a retransmission */ + if (wolfSSL_dtls13_use_quick_timeout(ssl_s)) + ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl_s), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl_s), WOLFSSL_SUCCESS); + /* Save the message count to make sure no new messages are sent */ + ExpectIntGE(test_ctx.c_msg_count, 2); + c_msg_count = test_ctx.c_msg_count; + + /* Second timeout. This one should not trigger a retransmission */ + if (wolfSSL_dtls13_use_quick_timeout(ssl_s)) + ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl_s), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl_s), WOLFSSL_SUCCESS); + /* This is the critical check. The message count should not increase + * after the second timeout. DTLS13_MIN_RTX_INTERVAL should have blocked + * retransmission here. */ + ExpectIntEQ(c_msg_count, test_ctx.c_msg_count); + + /* Now complete the handshake. We didn't clear the first retransmission + * so the handshake should proceed without issues. */ + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + + /* Cleanup */ + wolfSSL_free(ssl_c); + wolfSSL_CTX_free(ctx_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_s); +#endif + return EXPECT_RESULT(); +} + +/*-- no_session_id_echo (test_dtls.c lines 2965,3044) ---*/ +int test_dtls13_no_session_id_echo(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13) && \ + defined(HAVE_SESSION_TICKET) && defined(HAVE_ECC) && \ + !defined(WOLFSSL_DTLS13_ECHO_LEGACY_SESSION_ID) + struct test_memio_ctx test_ctx; + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + WOLFSSL_SESSION *sess = NULL; + char readBuf[1]; + /* Pin to SECP256R1 to avoid a PQ-induced key-share HRR */ + int groups[] = { WOLFSSL_ECC_SECP256R1 }; + + /* First connection: complete a DTLS 1.3 handshake to get a session */ + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), 0); + ExpectIntEQ(wolfSSL_set_groups(ssl_c, groups, 1), WOLFSSL_SUCCESS); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + + /* Read to process any NewSessionTicket */ + ExpectIntEQ(wolfSSL_read(ssl_c, readBuf, sizeof(readBuf)), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + + ExpectNotNull(sess = wolfSSL_get1_session(ssl_c)); + + /* Ensure the session has a non-empty session ID so the ClientHello + * will have a populated legacy_session_id field (which is legal per + * RFC 9147). */ + if (sess != NULL && sess->sessionIDSz == 0) { + sess->sessionIDSz = ID_LEN; + XMEMSET(sess->sessionID, 0x42, ID_LEN); + } + + wolfSSL_free(ssl_c); ssl_c = NULL; + wolfSSL_free(ssl_s); ssl_s = NULL; + wolfSSL_CTX_free(ctx_c); ctx_c = NULL; + wolfSSL_CTX_free(ctx_s); ctx_s = NULL; + + /* Second connection: set the session on the client so the ClientHello + * contains a non-empty legacy_session_id. Verify the server does NOT + * echo it in the ServerHello. */ + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), 0); + ExpectIntEQ(wolfSSL_set_session(ssl_c, sess), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_set_groups(ssl_c, groups, 1), WOLFSSL_SUCCESS); + /* Disable HRR cookie so the server directly sends a ServerHello */ + ExpectIntEQ(wolfSSL_disable_hrr_cookie(ssl_s), WOLFSSL_SUCCESS); + + /* Client sends ClientHello (with non-empty legacy_session_id) */ + ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + + /* Server processes ClientHello and sends ServerHello + flight */ + ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + + /* Verify the ServerHello on the wire. + * Layout: DTLS Record Header (13) + DTLS Handshake Header (12) + + * ProtocolVersion (2) + Random (32) = offset 59 for + * legacy_session_id_echo length byte. */ + ExpectIntGE(test_ctx.c_len, 60); + ExpectIntEQ(test_ctx.c_buff[0], handshake); + ExpectIntEQ(test_ctx.c_buff[DTLS_RECORD_HEADER_SZ], server_hello); + ExpectIntEQ(test_ctx.c_buff[DTLS_RECORD_HEADER_SZ + + DTLS_HANDSHAKE_HEADER_SZ + OPAQUE16_LEN + RAN_LEN], 0); + + /* Complete the handshake */ + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + + wolfSSL_SESSION_free(sess); + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); +#endif + return EXPECT_RESULT(); +} + +/*-- 5_9_0_compat (test_dtls.c lines 3049,3170) ---*/ +int test_dtls13_5_9_0_compat(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13) && \ + defined(HAVE_SESSION_TICKET) && defined(WOLFSSL_DTLS13_ECHO_LEGACY_SESSION_ID) && \ + defined(HAVE_ECC) + struct test_memio_ctx test_ctx; + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + WOLFSSL_SESSION *sess = NULL; + char readBuf[1]; + /* Pin to SECP256R1 to avoid a PQ-induced key-share HRR */ + int groups[] = { WOLFSSL_ECC_SECP256R1 }; + /* RFC 8446 Section 4.1.3: an HRR is a ServerHello carrying this magic + * random. Used to assert sub-test 1 is a real ServerHello, not an HRR. */ + static const byte hrrRandom[RAN_LEN] = { + 0xCF, 0x21, 0xAD, 0x74, 0xE5, 0x9A, 0x61, 0x11, + 0xBE, 0x1D, 0x8C, 0x02, 0x1E, 0x65, 0xB8, 0x91, + 0xC2, 0xA2, 0x11, 0x16, 0x7A, 0xBB, 0x8C, 0x5E, + 0x07, 0x9E, 0x09, 0xE2, 0xC8, 0xA8, 0x33, 0x9C + }; + + /* --- initial connection: get a real session to carry the session ID --- */ + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), 0); + ExpectIntEQ(wolfSSL_set_groups(ssl_c, groups, 1), WOLFSSL_SUCCESS); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + + /* drain any NewSessionTicket before calling get1_session */ + ExpectIntEQ(wolfSSL_read(ssl_c, readBuf, sizeof(readBuf)), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + + ExpectNotNull(sess = wolfSSL_get1_session(ssl_c)); + + /* Force a non-zero session ID - simulates a wolfSSL <=v5.9.0 client that + * mistakenly sends 32 bytes as legacy_session_id in DTLS 1.3. */ + if (sess != NULL && sess->sessionIDSz == 0) { + sess->sessionIDSz = ID_LEN; + XMEMSET(sess->sessionID, 0x42, ID_LEN); + } + + wolfSSL_free(ssl_c); ssl_c = NULL; + wolfSSL_free(ssl_s); ssl_s = NULL; + wolfSSL_CTX_free(ctx_c); ctx_c = NULL; + wolfSSL_CTX_free(ctx_s); ctx_s = NULL; + + /* --- sub-test 1: direct ServerHello (HRR cookie disabled) --- + * Exercises DoTls13ClientHello (change 1) and + * SendTls13ServerHello (change 2). */ + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), 0); + ExpectIntEQ(wolfSSL_set_session(ssl_c, sess), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_set_groups(ssl_c, groups, 1), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_disable_hrr_cookie(ssl_s), WOLFSSL_SUCCESS); + + /* Client sends CH1 with non-empty legacy_session_id */ + ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + + /* Server processes CH1 and sends ServerHello */ + ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + + /* Verify that the ServerHello on the wire echoes the session ID. + * Layout: DTLS Record Header (13) + DTLS Handshake Header (12) + + * ProtocolVersion (2) + Random (32) = byte 59 for + * legacy_session_id_echo length. */ + ExpectIntGE(test_ctx.c_len, 60); + ExpectIntEQ(test_ctx.c_buff[0], handshake); + ExpectIntEQ(test_ctx.c_buff[DTLS_RECORD_HEADER_SZ], server_hello); + /* Confirm it is a real ServerHello, not an HRR (also encoded as a + * ServerHello but bearing the HelloRetryRequest magic random). */ + ExpectIntNE(XMEMCMP(&test_ctx.c_buff[DTLS_RECORD_HEADER_SZ + + DTLS_HANDSHAKE_HEADER_SZ + OPAQUE16_LEN], hrrRandom, RAN_LEN), 0); + ExpectIntEQ(test_ctx.c_buff[DTLS_RECORD_HEADER_SZ + + DTLS_HANDSHAKE_HEADER_SZ + OPAQUE16_LEN + RAN_LEN], ID_LEN); + + /* Complete the handshake - Finished MAC validates the transcript */ + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + + wolfSSL_free(ssl_c); ssl_c = NULL; + wolfSSL_free(ssl_s); ssl_s = NULL; + wolfSSL_CTX_free(ctx_c); ctx_c = NULL; + wolfSSL_CTX_free(ctx_s); ctx_s = NULL; + + /* --- sub-test 2: stateless HRR (HRR cookie enabled by default) --- + * Exercises SendStatelessReplyDtls13 (change 4) and + * RestartHandshakeHashWithCookie (change 3). */ + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), 0); + ExpectIntEQ(wolfSSL_set_session(ssl_c, sess), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_set_groups(ssl_c, groups, 1), WOLFSSL_SUCCESS); + + /* Client sends CH1 */ + ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + + /* Server sends stateless HRR (SendStatelessReplyDtls13) */ + ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + + /* Verify the HRR echoes the session ID at the same wire offset */ + ExpectIntGE(test_ctx.c_len, 60); + ExpectIntEQ(test_ctx.c_buff[0], handshake); + ExpectIntEQ(test_ctx.c_buff[DTLS_RECORD_HEADER_SZ], server_hello); + ExpectIntEQ(test_ctx.c_buff[DTLS_RECORD_HEADER_SZ + + DTLS_HANDSHAKE_HEADER_SZ + OPAQUE16_LEN + RAN_LEN], ID_LEN); + + /* Complete the handshake - Finished MAC validates RestartHandshakeHashWithCookie */ + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + + wolfSSL_SESSION_free(sess); + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); +#endif + return EXPECT_RESULT(); +} + +/*-- oversized_cert_chain (test_dtls.c lines 3174,3265) ---*/ +int test_dtls13_oversized_cert_chain(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13) \ + && !defined(NO_FILESYSTEM) && !defined(NO_RSA) + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + XFILE f = XBADFILE; + long sz = 0; + byte *cert = NULL; + byte *chain = NULL; + int copies, off, i; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + + /* Read server cert */ + f = XFOPEN(svrCertFile, "rb"); + ExpectTrue(f != XBADFILE); + if (EXPECT_SUCCESS()) { + (void)XFSEEK(f, 0, XSEEK_END); + sz = XFTELL(f); + (void)XFSEEK(f, 0, XSEEK_SET); + } + ExpectTrue(sz > 0); + cert = (byte*)XMALLOC((size_t)(sz + 1), NULL, DYNAMIC_TYPE_TMP_BUFFER); + ExpectNotNull(cert); + if (EXPECT_SUCCESS()) + ExpectIntEQ((int)XFREAD(cert, 1, (size_t)sz, f), (int)sz); + if (f != XBADFILE) + XFCLOSE(f); + + /* Build an oversized chain by duplicating the cert */ + copies = EXPECT_SUCCESS() ? (int)(70000 / sz) + 2 : 0; + chain = (byte*)XMALLOC((size_t)(sz * copies + 1), NULL, + DYNAMIC_TYPE_TMP_BUFFER); + ExpectNotNull(chain); + off = 0; + if (EXPECT_SUCCESS()) { + for (i = 0; i < copies; i++) { + XMEMCPY(chain + off, cert, (size_t)sz); + off += (int)sz; + } + } + + /* Server context: load the oversized chain */ + ExpectNotNull(ctx_s = wolfSSL_CTX_new(wolfDTLSv1_3_server_method())); + ExpectIntEQ(wolfSSL_CTX_use_certificate_chain_buffer(ctx_s, + chain, (long)off), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_file(ctx_s, svrKeyFile, + WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS); + if (EXPECT_SUCCESS()) { + wolfSSL_SetIORecv(ctx_s, test_memio_read_cb); + wolfSSL_SetIOSend(ctx_s, test_memio_write_cb); + } + + /* Client context: no verification (chain certs are duplicates) */ + ExpectNotNull(ctx_c = wolfSSL_CTX_new(wolfDTLSv1_3_client_method())); + if (EXPECT_SUCCESS()) { + wolfSSL_CTX_set_verify(ctx_c, WOLFSSL_VERIFY_NONE, NULL); + wolfSSL_SetIORecv(ctx_c, test_memio_read_cb); + wolfSSL_SetIOSend(ctx_c, test_memio_write_cb); + } + + ExpectNotNull(ssl_s = wolfSSL_new(ctx_s)); + if (EXPECT_SUCCESS()) { + wolfSSL_SetIOWriteCtx(ssl_s, &test_ctx); + wolfSSL_SetIOReadCtx(ssl_s, &test_ctx); + } + + ExpectNotNull(ssl_c = wolfSSL_new(ctx_c)); + if (EXPECT_SUCCESS()) { + wolfSSL_SetIOWriteCtx(ssl_c, &test_ctx); + wolfSSL_SetIOReadCtx(ssl_c, &test_ctx); + } + + /* Handshake must not crash. If SendTls13Certificate mishandles the + * oversized chain this will trigger a wild pointer dereference or stack + * overflow resulting with the test failing. + * The correct behaviour either returns BUFFER_E or succeeds + * if the build config truncated the chain during loading. */ + (void)test_memio_do_handshake(ssl_c, ssl_s, 10, NULL); + + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); + XFREE(cert, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(chain, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return EXPECT_RESULT(); +} diff --git a/tests/api/test_dtls13.h b/tests/api/test_dtls13.h new file mode 100644 index 0000000000..7b48a35b78 --- /dev/null +++ b/tests/api/test_dtls13.h @@ -0,0 +1,81 @@ +/* test_dtls13.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 TESTS_API_DTLS13_H +#define TESTS_API_DTLS13_H + +#include + +/* DTLSv1.3-only tests. None share helpers with DTLS<=1.2 tests, so they + * live in their own translation unit and register under the "dtls13" + * group. Each function is defined unconditionally with the body (or the + * whole function via #else stub) guarded by WOLFSSL_DTLS13. */ +int test_dtls13_bad_epoch_ch(void); +int test_wolfSSL_dtls13_null_cipher(void); +int test_dtls13_frag_ch_pq(void); +int test_dtls_frag_ch(void); +int test_dtls_empty_keyshare_with_cookie(void); +int test_dtls13_missing_finished_client(void); +int test_dtls13_missing_finished_server(void); +int test_dtls13_finished_send_error_propagation(void); + +/* DTLSv1.3-only tests moved from test_dtls.c (isolated from DTLS<=1.2 code, + * none share helpers with non-DTLS13 tests). */ +int test_dtls13_basic_connection_id(void); +int test_dtls13_hrr_want_write(void); +int test_dtls13_every_write_want_write(void); +int test_dtls13_epochs(void); +int test_dtls13_ack_order(void); +int test_dtls13_ack_overflow(void); +int test_dtls13_ack_dup_write_counter(void); +int test_dtls13_ch2_rtx_no_ch1(void); +int test_dtls13_frag_ch2_with_ch1_rtx(void); +int test_dtls_srtp(void); +int test_dtls13_min_rtx_interval(void); +int test_dtls13_no_session_id_echo(void); +int test_dtls13_5_9_0_compat(void); +int test_dtls13_oversized_cert_chain(void); + +#define TEST_DTLS13_DECLS \ + TEST_DECL_GROUP("dtls13", test_dtls13_bad_epoch_ch), \ + TEST_DECL_GROUP("dtls13", test_wolfSSL_dtls13_null_cipher), \ + TEST_DECL_GROUP("dtls13", test_dtls13_frag_ch_pq), \ + TEST_DECL_GROUP("dtls13", test_dtls_frag_ch), \ + TEST_DECL_GROUP("dtls13", test_dtls_empty_keyshare_with_cookie), \ + TEST_DECL_GROUP("dtls13", test_dtls13_missing_finished_client), \ + TEST_DECL_GROUP("dtls13", test_dtls13_missing_finished_server), \ + TEST_DECL_GROUP("dtls13", test_dtls13_finished_send_error_propagation), \ + TEST_DECL_GROUP("dtls13", test_dtls13_basic_connection_id), \ + TEST_DECL_GROUP("dtls13", test_dtls13_hrr_want_write), \ + TEST_DECL_GROUP("dtls13", test_dtls13_every_write_want_write), \ + TEST_DECL_GROUP("dtls13", test_dtls13_epochs), \ + TEST_DECL_GROUP("dtls13", test_dtls13_ack_order), \ + TEST_DECL_GROUP("dtls13", test_dtls13_ack_overflow), \ + TEST_DECL_GROUP("dtls13", test_dtls13_ack_dup_write_counter), \ + TEST_DECL_GROUP("dtls13", test_dtls13_ch2_rtx_no_ch1), \ + TEST_DECL_GROUP("dtls13", test_dtls13_frag_ch2_with_ch1_rtx), \ + TEST_DECL_GROUP("dtls13", test_dtls_srtp), \ + TEST_DECL_GROUP("dtls13", test_dtls13_min_rtx_interval), \ + TEST_DECL_GROUP("dtls13", test_dtls13_no_session_id_echo), \ + TEST_DECL_GROUP("dtls13", test_dtls13_5_9_0_compat), \ + TEST_DECL_GROUP("dtls13", test_dtls13_oversized_cert_chain) + +#endif /* TESTS_API_DTLS13_H */ diff --git a/tests/api/test_lms_xmss.c b/tests/api/test_lms_xmss.c new file mode 100644 index 0000000000..2dc3ff2158 --- /dev/null +++ b/tests/api/test_lms_xmss.c @@ -0,0 +1,934 @@ +/* test_lms_xmss.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 + +#ifdef NO_INLINE + #include +#else + #define WOLFSSL_MISC_INCLUDED + #include +#endif + +#include +#include +#include +#include +#include + +/*----------------------------------------------------------------------------*/ +/* LMS tests */ +/*----------------------------------------------------------------------------*/ + +#if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY) + +#include + +#define LMS_TEST_PRIV_KEY_FILE "/tmp/wolfssl_test_lms.key" + +static int test_lms_write_key(const byte* priv, word32 privSz, void* context) +{ + FILE* f = fopen((const char*)context, "wb"); + int ret = WC_LMS_RC_SAVED_TO_NV_MEMORY; + if (f == NULL) + return -1; + if (fwrite(priv, 1, privSz, f) != privSz) + ret = -1; + fclose(f); + return ret; +} + +static int test_lms_read_key(byte* priv, word32 privSz, void* context) +{ + FILE* f = fopen((const char*)context, "rb"); + if (f == NULL) + return -1; + if (fread(priv, 1, privSz, f) == 0) { + fclose(f); + return -1; + } + fclose(f); + return WC_LMS_RC_READ_TO_MEMORY; +} + +/* Helper: init an LMS key with callbacks and L1-H10-W8 params */ +static int test_lms_init_key(LmsKey* key, WC_RNG* rng) +{ + int ret; + + ret = wc_LmsKey_Init(key, NULL, INVALID_DEVID); + if (ret != 0) return ret; + +#if !defined(WOLFSSL_LMS_MAX_HEIGHT) || (WOLFSSL_LMS_MAX_HEIGHT >= 10) + ret = wc_LmsKey_SetParameters(key, 1, 10, 8); +#else + ret = wc_LmsKey_SetParameters(key, 1, 5, 8); +#endif + if (ret != 0) return ret; + + ret = wc_LmsKey_SetWriteCb(key, test_lms_write_key); + if (ret != 0) return ret; + + ret = wc_LmsKey_SetReadCb(key, test_lms_read_key); + if (ret != 0) return ret; + + ret = wc_LmsKey_SetContext(key, (void*)LMS_TEST_PRIV_KEY_FILE); + if (ret != 0) return ret; + + (void)rng; + return 0; +} + +#endif /* WOLFSSL_HAVE_LMS && !WOLFSSL_LMS_VERIFY_ONLY */ + +/* + * Test basic LMS sign/verify with multiple signings. + * Uses L1-H10-W8 (1024 total signatures, 32-entry leaf cache). + */ +int test_wc_LmsKey_sign_verify(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY) + LmsKey key; + WC_RNG rng; + byte msg[] = "test message for LMS signing"; + byte sig[2048]; + word32 sigSz; + int i; + int numSigs = 5; + + ExpectIntEQ(wc_InitRng(&rng), 0); + + remove(LMS_TEST_PRIV_KEY_FILE); + ExpectIntEQ(test_lms_init_key(&key, &rng), 0); + ExpectIntEQ(wc_LmsKey_MakeKey(&key, &rng), 0); + + for (i = 0; i < numSigs; i++) { + sigSz = sizeof(sig); + ExpectIntEQ(wc_LmsKey_Sign(&key, sig, &sigSz, msg, sizeof(msg)), 0); + ExpectIntEQ(wc_LmsKey_Verify(&key, sig, sigSz, msg, sizeof(msg)), 0); + } + + wc_LmsKey_Free(&key); + wc_FreeRng(&rng); + remove(LMS_TEST_PRIV_KEY_FILE); +#endif + return EXPECT_RESULT(); +} + +/* + * Test LMS key reload after advancing past the leaf cache window. + * + * Reproduces a heap-buffer-overflow bug in wc_lms_treehash_init() where the + * leaf cache write uses (i * hash_len) instead of ((i - leaf->idx) * hash_len). + * When q > max_cb (default 32), wc_LmsKey_Reload calls wc_hss_init_auth_path + * which calls wc_lms_treehash_init with q > 0, causing writes past the end of + * the leaf cache buffer. + * + * Reproduction steps: + * 1. Generate L1-H10-W8 key (cacheBits=5, max_cb=32) + * 2. Sign 33 times to advance q past the cache window + * 3. Free the key and reload from persisted state + * 4. Sign and verify after reload + * + * Without the fix: heap-buffer-overflow at wc_lms_impl.c:1965 + * With the fix: all operations succeed, signatures verify + */ +int test_wc_LmsKey_reload_cache(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY) && \ + (!defined(WOLFSSL_LMS_MAX_HEIGHT) || (WOLFSSL_LMS_MAX_HEIGHT >= 10)) + LmsKey key; + LmsKey vkey; + WC_RNG rng; + byte msg[] = "test message for LMS signing"; + byte sig[2048]; + word32 sigSz; + byte pub[64]; + word32 pubSz = sizeof(pub); + int i; + /* Sign 33 times to advance q past the 32-entry cache window. */ + int preSigs = 33; + + ExpectIntEQ(wc_InitRng(&rng), 0); + + /* Phase 1: Generate key and sign past cache window */ + remove(LMS_TEST_PRIV_KEY_FILE); + ExpectIntEQ(test_lms_init_key(&key, &rng), 0); + ExpectIntEQ(wc_LmsKey_MakeKey(&key, &rng), 0); + + for (i = 0; i < preSigs; i++) { + sigSz = sizeof(sig); + ExpectIntEQ(wc_LmsKey_Sign(&key, sig, &sigSz, msg, sizeof(msg)), 0); + } + + /* Save public key for verification after reload */ + ExpectIntEQ(wc_LmsKey_ExportPubRaw(&key, pub, &pubSz), 0); + + wc_LmsKey_Free(&key); + + /* Phase 2: Reload key. Triggers wc_lms_treehash_init with q=33 */ + ExpectIntEQ(test_lms_init_key(&key, &rng), 0); + ExpectIntEQ(wc_LmsKey_Reload(&key), 0); + + /* Phase 3: Sign after reload and verify with separate verify-only key */ + sigSz = sizeof(sig); + ExpectIntEQ(wc_LmsKey_Sign(&key, sig, &sigSz, msg, sizeof(msg)), 0); + + ExpectIntEQ(wc_LmsKey_Init(&vkey, NULL, INVALID_DEVID), 0); +#if !defined(WOLFSSL_LMS_MAX_HEIGHT) || (WOLFSSL_LMS_MAX_HEIGHT >= 10) + ExpectIntEQ(wc_LmsKey_SetParameters(&vkey, 1, 10, 8), 0); +#else + ExpectIntEQ(wc_LmsKey_SetParameters(&vkey, 1, 5, 8), 0); +#endif + ExpectIntEQ(wc_LmsKey_ImportPubRaw(&vkey, pub, pubSz), 0); + ExpectIntEQ(wc_LmsKey_Verify(&vkey, sig, sigSz, msg, sizeof(msg)), 0); + + wc_LmsKey_Free(&vkey); + wc_LmsKey_Free(&key); + wc_FreeRng(&rng); + remove(LMS_TEST_PRIV_KEY_FILE); +#endif + return EXPECT_RESULT(); +} + +/*----------------------------------------------------------------------------*/ +/* RFC 9802 (HSS/LMS and XMSS/XMSS^MT in X.509) tests */ +/*----------------------------------------------------------------------------*/ + +/* For every committed self-signed test certificate confirm: + * - wc_ParseCert succeeds on the RFC 9802 AlgorithmIdentifier encoding + * (OID-only SEQUENCE, no NULL parameters) + * - keyOID and signatureOID are set to the expected values + * - loading as a trust anchor and verifying the same bytes through + * wolfSSL_CertManagerVerifyBuffer exercises the ConfirmSignature + * path and succeeds on a valid cert + * - flipping a byte in the signature AND flipping a byte in the + * TBSCertificate both cause verification to fail. + * + * Test vectors are in certs/lms/ and certs/xmss/, generated with Bouncy + * Castle 1.81. BC's default XMSS / XMSS^MT X.509 encoding uses pre- + * standard ISARA OIDs and wraps the raw RFC 8391 pub key in an OCTET + * STRING, so the fixtures were produced with a small generator that + * overrides the AlgorithmIdentifier and SPKI to match RFC 9802. */ +#if (defined(WOLFSSL_HAVE_LMS) || defined(WOLFSSL_HAVE_XMSS)) && \ + !defined(NO_FILESYSTEM) && !defined(NO_CERTS) +/* Sanity bound on a test fixture cert. The largest BC-generated + * fixture we ship (XMSS^MT 40/8) is ~19 KiB; 1 MiB is well above + * any realistic RFC 9802 cert and catches a wild XFTELL. Typed as + * long to match XFTELL's return so the size comparison below isn't + * a mixed long-vs-int compare. */ +#define RFC9802_TEST_MAX_CERT_SIZE ((long)(1L << 20)) + +/* Load a whole file into a freshly-allocated buffer. Caller frees. */ +static int rfc9802_load_file(const char* path, byte** out, int* outLen) +{ + EXPECT_DECLS; + XFILE f = XBADFILE; + long sz = 0; + size_t got = 0; + byte* buf = NULL; + + *out = NULL; + *outLen = 0; + ExpectTrue((f = XFOPEN(path, "rb")) != XBADFILE); + if (f == XBADFILE) + return TEST_FAIL; + if (XFSEEK(f, 0, XSEEK_END) == 0) + sz = XFTELL(f); + (void)XFSEEK(f, 0, XSEEK_SET); + ExpectIntGT(sz, 0); + ExpectIntLT(sz, RFC9802_TEST_MAX_CERT_SIZE); + /* Hard-fail before XMALLOC if XFSEEK / XFTELL produced an unusable + * size: ExpectInt* records the failure but doesn't short-circuit, + * so without this guard a -1 from XFTELL would cast to a multi-GiB + * (size_t) allocation, and a 0 would request a zero-byte malloc. */ + if (sz <= 0 || sz >= RFC9802_TEST_MAX_CERT_SIZE) { + XFCLOSE(f); + return TEST_FAIL; + } + ExpectNotNull(buf = (byte*)XMALLOC((size_t)sz, NULL, + DYNAMIC_TYPE_TMP_BUFFER)); + if (buf != NULL) { + got = XFREAD(buf, 1, (size_t)sz, f); + ExpectIntEQ(got, (size_t)sz); + /* On a short read the caller would otherwise proceed with a + * partially-initialized buffer and produce cascading parse + * failures driven by the uninitialized tail. Free here so the + * caller's `if (buf == NULL) return TEST_FAIL;` short-circuits + * cleanly with a single recorded failure. */ + if (got != (size_t)sz) { + XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + buf = NULL; + sz = 0; + } + } + XFCLOSE(f); + *out = buf; + *outLen = (int)sz; + return EXPECT_RESULT(); +} + +static int rfc9802_verify_one_cert(const char* path, word32 expectedKeyOID, + word32 expectedSigOID) +{ + EXPECT_DECLS; + byte* buf = NULL; + byte* tampered = NULL; + int bytes = 0; + DecodedCert cert; + WOLFSSL_CERT_MANAGER* cm = NULL; + word32 certBegin = 0; + word32 sigIndex = 0; + + ExpectIntEQ(rfc9802_load_file(path, &buf, &bytes), TEST_SUCCESS); + if (buf == NULL) + return TEST_FAIL; + + /* Parse + check OIDs, capture certBegin and sigIndex for later tamper. */ + wc_InitDecodedCert(&cert, buf, (word32)bytes, NULL); + ExpectIntEQ(wc_ParseCert(&cert, CERT_TYPE, NO_VERIFY, NULL), 0); + ExpectIntEQ((int)cert.keyOID, (int)expectedKeyOID); + ExpectIntEQ((int)cert.signatureOID, (int)expectedSigOID); + certBegin = cert.certBegin; + sigIndex = cert.sigIndex; + wc_FreeDecodedCert(&cert); + + /* Full verify against a self-installed trust anchor. */ + ExpectNotNull(cm = wolfSSL_CertManagerNew()); + ExpectIntEQ(wolfSSL_CertManagerLoadCABuffer(cm, buf, (long)bytes, + WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CertManagerVerifyBuffer(cm, buf, (long)bytes, + WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); + if (cm != NULL) { + wolfSSL_CertManagerFree(cm); + cm = NULL; + } + + ExpectNotNull(tampered = (byte*)XMALLOC((size_t)bytes, NULL, + DYNAMIC_TYPE_TMP_BUFFER)); + + /* Negative 1: flip a byte inside the signatureValue BIT STRING. + * Everything after sigIndex is the signatureAlgorithm + the BIT + * STRING payload, so flipping the last byte is always inside the + * signature content. */ + if (tampered != NULL) { + XMEMCPY(tampered, buf, (size_t)bytes); + tampered[bytes - 1] ^= 0x01; + ExpectNotNull(cm = wolfSSL_CertManagerNew()); + ExpectIntEQ(wolfSSL_CertManagerLoadCABuffer(cm, buf, (long)bytes, + WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); + ExpectIntNE(wolfSSL_CertManagerVerifyBuffer(cm, tampered, + (long)bytes, WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); + if (cm != NULL) { + wolfSSL_CertManagerFree(cm); + cm = NULL; + } + } + + /* Negative 2: flip a byte at the midpoint of the TBSCertificate. The + * TBS is the first element of the outer Certificate SEQUENCE and + * its bytes lie between (certBegin + outerSeqHeader) and sigIndex. + * Picking the midpoint ensures we're inside TBS regardless of the + * fixture's DN / extensions layout. */ + if (tampered != NULL && sigIndex > certBegin + 8U) { + word32 midTbs = certBegin + 8 + ((sigIndex - (certBegin + 8)) / 2); + XMEMCPY(tampered, buf, (size_t)bytes); + tampered[midTbs] ^= 0x01; + ExpectNotNull(cm = wolfSSL_CertManagerNew()); + ExpectIntEQ(wolfSSL_CertManagerLoadCABuffer(cm, buf, (long)bytes, + WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); + ExpectIntNE(wolfSSL_CertManagerVerifyBuffer(cm, tampered, + (long)bytes, WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); + if (cm != NULL) { + wolfSSL_CertManagerFree(cm); + cm = NULL; + } + } + + /* The fixtures MUST carry a KeyUsage extension with at least one of + * digitalSignature / nonRepudiation / keyCertSign / cRLSign set per + * RFC 9802 sec 3. Re-parse and assert that wolfSSL recorded a non- + * empty set of KeyUsage bits from one of those values. */ + wc_InitDecodedCert(&cert, buf, (word32)bytes, NULL); + ExpectIntEQ(wc_ParseCert(&cert, CERT_TYPE, NO_VERIFY, NULL), 0); + ExpectIntEQ(cert.extKeyUsageSet, 1); + ExpectIntNE(cert.extKeyUsage & (KEYUSE_DIGITAL_SIG | KEYUSE_CONTENT_COMMIT | + KEYUSE_KEY_CERT_SIGN | KEYUSE_CRL_SIGN), 0); + wc_FreeDecodedCert(&cert); + + XFREE(tampered, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return EXPECT_RESULT(); +} +#endif + +/* Direct wolfCrypt-level negative tests for the parameter-derivation + * helpers used by the RFC 9802 parse path. These exercise failure modes + * (unknown algorithm bytes, truncated inputs, mismatches) that a real + * cert body wouldn't easily reach. */ +#if defined(WOLFSSL_HAVE_LMS) +static int rfc9802_lms_import_negative(void) +{ + EXPECT_DECLS; + LmsKey key; + /* 60-byte buffer matches HSS_PUBLIC_KEY_LEN(32), just like a valid + * SHA-256/M32/H5 key; the algorithm-type bytes are junk so param + * derivation must fail cleanly. */ + byte junk[60]; + + XMEMSET(junk, 0, sizeof(junk)); + /* levels=1, lmsType=0xFFFFFFFF, lmOtsType=0xFFFFFFFF. */ + junk[3] = 1; + XMEMSET(junk + 4, 0xFF, 4); + XMEMSET(junk + 8, 0xFF, 4); + + /* Unknown algorithm types must be rejected. */ + ExpectIntEQ(wc_LmsKey_Init(&key, NULL, INVALID_DEVID), 0); + ExpectIntEQ(wc_LmsKey_ImportPubRaw(&key, junk, sizeof(junk)), + WC_NO_ERR_TRACE(NOT_COMPILED_IN)); + wc_LmsKey_Free(&key); + + /* Too-short buffer: only L + lmsType, no lmOtsType. */ + ExpectIntEQ(wc_LmsKey_Init(&key, NULL, INVALID_DEVID), 0); + ExpectIntEQ(wc_LmsKey_ImportPubRaw(&key, junk, 8), + WC_NO_ERR_TRACE(BUFFER_E)); + wc_LmsKey_Free(&key); + +#if !defined(WOLFSSL_NO_LMS_SHA256_256) + /* The two cases below pin specific SHA-256/M32 parameter codes + * (L1_H5_W8, L1_H5_W4, L1_H10_W2). Skip them in builds where the + * SHA-256/M32 family is disabled -- the family-agnostic checks + * above (junk algorithm types, too-short buffer, GetSigLen on + * unconfigured key) still cover the universal invariants. */ + + /* Pre-set params that disagree with the raw key's algorithm bytes: + * configure H=5/W=8 but feed buffer that claims H=10 / W=2. */ + XMEMSET(junk, 0, sizeof(junk)); + junk[3] = 1; /* levels=1 */ + junk[7] = 6; /* lmsType = LMS_SHA256_M32_H10 = 6 */ + junk[11] = 2; /* lmOtsType = LMOTS_SHA256_N32_W2 = 2 */ + ExpectIntEQ(wc_LmsKey_Init(&key, NULL, INVALID_DEVID), 0); + ExpectIntEQ(wc_LmsKey_SetParameters(&key, 1, 5, 8), 0); + ExpectIntEQ(wc_LmsKey_ImportPubRaw(&key, junk, sizeof(junk)), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + wc_LmsKey_Free(&key); +#endif /* !WOLFSSL_NO_LMS_SHA256_256 */ + + /* GetSigLen on a key with no params set must not NULL-deref the + * params pointer; it must return BAD_FUNC_ARG instead. */ + { + word32 sigLen = 0; + ExpectIntEQ(wc_LmsKey_Init(&key, NULL, INVALID_DEVID), 0); + ExpectIntEQ(wc_LmsKey_GetSigLen(&key, &sigLen), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + wc_LmsKey_Free(&key); + } + +#if !defined(WOLFSSL_NO_LMS_SHA256_256) + /* Partial-write invariant: a length mismatch after a successful + * auto-derive must leave key->params NULL. Build a buffer whose + * leading u32str(L) || lmsType || lmOtsType identifies a known + * parameter set, but truncate to one byte less than the real pub + * key length so the post-derive length check fails. */ + { + byte truncated[59]; /* HSS_PUBLIC_KEY_LEN(32) is 60 */ + XMEMSET(truncated, 0, sizeof(truncated)); + truncated[3] = 1; /* L = 1 */ + truncated[7] = 5; /* lmsType = LMS_SHA256_M32_H5 */ + truncated[11] = 4; /* lmOtsType = LMOTS_SHA256_N32_W4 */ + ExpectIntEQ(wc_LmsKey_Init(&key, NULL, INVALID_DEVID), 0); + ExpectNull(key.params); + ExpectIntEQ(wc_LmsKey_ImportPubRaw(&key, truncated, + sizeof(truncated)), WC_NO_ERR_TRACE(BUFFER_E)); + ExpectNull(key.params); + wc_LmsKey_Free(&key); + } +#endif /* !WOLFSSL_NO_LMS_SHA256_256 */ + + return EXPECT_RESULT(); +} +#endif + +#if defined(WOLFSSL_HAVE_XMSS) +static int rfc9802_xmss_import_negative(void) +{ + EXPECT_DECLS; + XmssKey key; + byte junk[8]; + + XMEMSET(junk, 0, sizeof(junk)); + + /* Too-short buffer. */ + ExpectIntEQ(wc_XmssKey_Init(&key, NULL, INVALID_DEVID), 0); + ExpectIntEQ(wc_XmssKey_ImportPubRaw_ex(&key, junk, 2, 0), + WC_NO_ERR_TRACE(BUFFER_E)); + wc_XmssKey_Free(&key); + + /* Unknown OID (all-zero) for both XMSS and XMSS^MT. */ + ExpectIntEQ(wc_XmssKey_Init(&key, NULL, INVALID_DEVID), 0); + ExpectIntEQ(wc_XmssKey_ImportPubRaw_ex(&key, junk, sizeof(junk), 0), + WC_NO_ERR_TRACE(NOT_COMPILED_IN)); + wc_XmssKey_Free(&key); + ExpectIntEQ(wc_XmssKey_Init(&key, NULL, INVALID_DEVID), 0); + ExpectIntEQ(wc_XmssKey_ImportPubRaw_ex(&key, junk, sizeof(junk), 1), + WC_NO_ERR_TRACE(NOT_COMPILED_IN)); + wc_XmssKey_Free(&key); + + /* NULL key / input. */ + ExpectIntEQ(wc_XmssKey_ImportPubRaw_ex(NULL, junk, sizeof(junk), 0), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wc_XmssKey_Init(&key, NULL, INVALID_DEVID), 0); + ExpectIntEQ(wc_XmssKey_ImportPubRaw_ex(&key, NULL, 8, 0), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + wc_XmssKey_Free(&key); + + /* GetSigLen on a key with no params set must not NULL-deref the + * params pointer; it must return BAD_FUNC_ARG instead. */ + { + word32 sigLen = 0; + ExpectIntEQ(wc_XmssKey_Init(&key, NULL, INVALID_DEVID), 0); + ExpectIntEQ(wc_XmssKey_GetSigLen(&key, &sigLen), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + wc_XmssKey_Free(&key); + } + + /* Once params have been configured (state != INITED), the OID + * prefix in the raw key MUST match key->oid and is_xmssmt MUST + * match key->is_xmssmt. Set XMSS-SHA2_10_256 and feed a valid- + * sized buffer whose 4-byte OID prefix is bogus -> BAD_FUNC_ARG. */ + { + byte mismatch[XMSS_SHA256_PUBLEN]; + ExpectIntEQ(wc_XmssKey_Init(&key, NULL, INVALID_DEVID), 0); + ExpectIntEQ(wc_XmssKey_SetParamStr(&key, "XMSS-SHA2_10_256"), 0); + XMEMSET(mismatch, 0, sizeof(mismatch)); + mismatch[3] = 0x77; /* nonsense OID */ + ExpectIntEQ(wc_XmssKey_ImportPubRaw_ex(&key, mismatch, + sizeof(mismatch), 0), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + /* Same buffer with the correct OID, but is_xmssmt hint + * contradicts the configured family -> BAD_FUNC_ARG. */ + mismatch[3] = 0x01; /* WC_XMSS_OID_SHA2_10_256 */ + ExpectIntEQ(wc_XmssKey_ImportPubRaw_ex(&key, mismatch, + sizeof(mismatch), 1), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + wc_XmssKey_Free(&key); + } + + /* Partial-write invariant: a length mismatch after a successful + * auto-derive must leave the key in its INITED state, with + * key->params NULL. */ + { + byte truncated[XMSS_SHA256_PUBLEN - 1]; + XMEMSET(truncated, 0, sizeof(truncated)); + truncated[3] = 0x01; + ExpectIntEQ(wc_XmssKey_Init(&key, NULL, INVALID_DEVID), 0); + ExpectNull(key.params); + ExpectIntEQ(wc_XmssKey_ImportPubRaw_ex(&key, truncated, + sizeof(truncated), 0), WC_NO_ERR_TRACE(BUFFER_E)); + ExpectNull(key.params); + wc_XmssKey_Free(&key); + } + + /* is_xmssmt disambiguation: XMSS oid=1 and XMSS^MT oid=1 share + * the wire-numeric value but resolve to different parameter sets. + * Importing the same 68-byte buffer with hint=0 vs hint=1 must + * land in different tables and produce distinct is_xmssmt. */ + { + byte buf[XMSS_SHA256_PUBLEN]; + XMEMSET(buf, 0, sizeof(buf)); + buf[3] = 0x01; + + ExpectIntEQ(wc_XmssKey_Init(&key, NULL, INVALID_DEVID), 0); + ExpectIntEQ(wc_XmssKey_ImportPubRaw_ex(&key, buf, sizeof(buf), 0), 0); + ExpectIntEQ((int)key.is_xmssmt, 0); + wc_XmssKey_Free(&key); + + ExpectIntEQ(wc_XmssKey_Init(&key, NULL, INVALID_DEVID), 0); + ExpectIntEQ(wc_XmssKey_ImportPubRaw_ex(&key, buf, sizeof(buf), 1), 0); + ExpectIntEQ((int)key.is_xmssmt, 1); + wc_XmssKey_Free(&key); + } + + /* Lenient state: re-importing the same pub key into a VERIFYONLY + * key (params set, no private material) succeeds. The second + * call exercises the lenient-state branch. */ + { + byte buf[XMSS_SHA256_PUBLEN]; + XMEMSET(buf, 0, sizeof(buf)); + buf[3] = 0x01; + + ExpectIntEQ(wc_XmssKey_Init(&key, NULL, INVALID_DEVID), 0); + ExpectIntEQ(wc_XmssKey_ImportPubRaw_ex(&key, buf, sizeof(buf), 0), 0); + ExpectIntEQ((int)key.state, (int)WC_XMSS_STATE_VERIFYONLY); + ExpectIntEQ(wc_XmssKey_ImportPubRaw_ex(&key, buf, sizeof(buf), 0), 0); + ExpectIntEQ((int)key.state, (int)WC_XMSS_STATE_VERIFYONLY); + wc_XmssKey_Free(&key); + } + + /* Strict signature-length check: wc_XmssKey_Verify rejects any + * sigLen != key->params->sig_len. This guards every consumer + * (RFC 9802 X.509, PKCS#7, CMS, ...) against a longer wrapper that + * happens to start with a valid signature. Construct a key in + * VERIFYONLY state, then verify with sig_len + 1 and sig_len - 1 + * byte buffers; both must fail with BUFFER_E before any crypto + * runs. The buffer contents are irrelevant since the length check + * fires first. */ + { + byte pub[XMSS_SHA256_PUBLEN]; + byte* sigBuf = NULL; + word32 sigLen = 0; + const byte msg[1] = { 0 }; + + XMEMSET(pub, 0, sizeof(pub)); + pub[3] = 0x01; + ExpectIntEQ(wc_XmssKey_Init(&key, NULL, INVALID_DEVID), 0); + ExpectIntEQ(wc_XmssKey_ImportPubRaw_ex(&key, pub, sizeof(pub), 0), 0); + ExpectIntEQ((int)key.state, (int)WC_XMSS_STATE_VERIFYONLY); + ExpectIntEQ(wc_XmssKey_GetSigLen(&key, &sigLen), 0); + ExpectIntGT(sigLen, 0); + ExpectNotNull(sigBuf = (byte*)XMALLOC((size_t)sigLen + 1, NULL, + DYNAMIC_TYPE_TMP_BUFFER)); + if (sigBuf != NULL) { + XMEMSET(sigBuf, 0, (size_t)sigLen + 1); + ExpectIntEQ(wc_XmssKey_Verify(&key, sigBuf, sigLen + 1, + msg, (int)sizeof(msg)), WC_NO_ERR_TRACE(BUFFER_E)); + ExpectIntEQ(wc_XmssKey_Verify(&key, sigBuf, sigLen - 1, + msg, (int)sizeof(msg)), WC_NO_ERR_TRACE(BUFFER_E)); + XFREE(sigBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + } + wc_XmssKey_Free(&key); + } + + /* BAD_STATE_E branch: WC_XMSS_STATE_OK must be rejected. Reaching + * OK normally requires a successful private-key Reload / sign, + * which is unavailable in WOLFSSL_XMSS_VERIFY_ONLY builds. Force + * the state directly to exercise the rejection without coupling + * this helper to the signing test fixture; sk stays NULL so Free + * is still safe. */ + { + byte pub[XMSS_SHA256_PUBLEN]; + + XMEMSET(pub, 0, sizeof(pub)); + pub[3] = 0x01; + ExpectIntEQ(wc_XmssKey_Init(&key, NULL, INVALID_DEVID), 0); + ExpectIntEQ(wc_XmssKey_SetParamStr(&key, "XMSS-SHA2_10_256"), 0); + key.state = WC_XMSS_STATE_OK; + ExpectIntEQ(wc_XmssKey_ImportPubRaw_ex(&key, pub, sizeof(pub), 0), + WC_NO_ERR_TRACE(BAD_STATE_E)); + wc_XmssKey_Free(&key); + } + + return EXPECT_RESULT(); +} +#endif + +/* Walk the AlgorithmIdentifier SEQUENCE that begins at sigIndex and + * locate the byte offset of the last byte of its OID content. Handles + * both short-form (length < 128) and long-form DER length encodings, + * so a future fixture-regenerator that emits longer OIDs / SEQUENCEs + * still drives this test rather than tripping the loud-fail branch. + * + * Returns 0 on success with *oidLastByte set; returns -1 on any DER + * shape mismatch. */ +#if defined(WOLFSSL_HAVE_XMSS) && !defined(NO_FILESYSTEM) && !defined(NO_CERTS) +static int rfc9802_find_sig_alg_oid_last_byte(const byte* buf, word32 bufLen, + word32 sigIndex, word32* oidLastByte) +{ + word32 idx = sigIndex; + word32 oidContentLen = 0; + + /* AlgorithmIdentifier ::= SEQUENCE { algorithm OID, ... } */ + if (idx >= bufLen || buf[idx] != 0x30) + return -1; + idx++; + /* Skip SEQUENCE length (short or long form). */ + if (idx >= bufLen) + return -1; + if (buf[idx] < 0x80) { + idx++; + } + else { + word32 nbytes = (word32)(buf[idx] & 0x7F); + if (nbytes == 0 || nbytes > 4 || idx + 1 + nbytes > bufLen) + return -1; + idx += 1 + nbytes; + } + /* algorithm OID tag. */ + if (idx >= bufLen || buf[idx] != 0x06) + return -1; + idx++; + /* OID length (short or long form). */ + if (idx >= bufLen) + return -1; + if (buf[idx] < 0x80) { + oidContentLen = buf[idx]; + idx++; + } + else { + word32 nbytes = (word32)(buf[idx] & 0x7F); + word32 i; + if (nbytes == 0 || nbytes > 4 || idx + 1 + nbytes > bufLen) + return -1; + for (i = 0; i < nbytes; i++) + oidContentLen = (oidContentLen << 8) | buf[idx + 1 + i]; + idx += 1 + nbytes; + } + if (oidContentLen == 0 || idx + oidContentLen > bufLen) + return -1; + *oidLastByte = idx + oidContentLen - 1; + return 0; +} + +/* Helper: load fixture, locate last byte of outer signatureAlgorithm + * OID, patch it from `expected` to `swap`, and assert that verifying + * the patched cert against itself as a trust anchor fails. */ +static int rfc9802_assert_oid_patch_breaks_verify(const char* path, + byte expectedLastByte, byte patchedLastByte) +{ + EXPECT_DECLS; + byte* buf = NULL; + int bytes = 0; + DecodedCert cert; + WOLFSSL_CERT_MANAGER* cm = NULL; + word32 sigIndex = 0; + word32 lastOidByte = 0; + + ExpectIntEQ(rfc9802_load_file(path, &buf, &bytes), TEST_SUCCESS); + if (buf == NULL) + return TEST_FAIL; + + wc_InitDecodedCert(&cert, buf, (word32)bytes, NULL); + ExpectIntEQ(wc_ParseCert(&cert, CERT_TYPE, NO_VERIFY, NULL), 0); + sigIndex = cert.sigIndex; + wc_FreeDecodedCert(&cert); + + ExpectIntEQ(rfc9802_find_sig_alg_oid_last_byte(buf, (word32)bytes, + sigIndex, &lastOidByte), 0); + /* Sanity-check the fixture matches the family the caller asserted, + * so a future regenerator swapping fixtures fails loudly here + * rather than silently testing the wrong direction. */ + ExpectIntEQ((int)buf[lastOidByte], (int)expectedLastByte); + + if (lastOidByte < (word32)bytes && + buf[lastOidByte] == expectedLastByte) { + buf[lastOidByte] = patchedLastByte; + ExpectNotNull(cm = wolfSSL_CertManagerNew()); + /* After the patch the cert's outer signatureAlgorithm and SPKI + * disagree. Verification must fail somewhere (at parse, at + * load, or at ConfirmSignature). The load is best-effort - + * some shape changes get caught there, others only at verify. */ + (void)wolfSSL_CertManagerLoadCABuffer(cm, buf, (long)bytes, + WOLFSSL_FILETYPE_ASN1); + ExpectIntNE(wolfSSL_CertManagerVerifyBuffer(cm, buf, + (long)bytes, WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); + if (cm != NULL) { + wolfSSL_CertManagerFree(cm); + cm = NULL; + } + } + + XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return EXPECT_RESULT(); +} + +/* X.509-level negative: swap the outer signatureAlgorithm OID byte so + * the cert declares XMSS where the SPKI is XMSS^MT, and vice versa. + * SigOidMatchesKeyOid must reject both directions before any crypto. */ +static int rfc9802_xmss_sig_oid_mismatch(void) +{ + EXPECT_DECLS; + /* XMSS sigOID ends 0x22; XMSS^MT sigOID ends 0x23. Patch each + * direction so the asymmetric-key path is exercised both ways - + * a regression that only stripped the check from one branch of + * SigOidMatchesKeyOid would otherwise be missed. */ + ExpectIntEQ(rfc9802_assert_oid_patch_breaks_verify( + "./certs/xmss/bc_xmss_sha2_10_256_root.der", + /* expected XMSS */ 0x22, /* patched to XMSS^MT */ 0x23), + TEST_SUCCESS); + ExpectIntEQ(rfc9802_assert_oid_patch_breaks_verify( + "./certs/xmss/bc_xmssmt_sha2_20_2_256_root.der", + /* expected XMSS^MT */ 0x23, /* patched to XMSS */ 0x22), + TEST_SUCCESS); + return EXPECT_RESULT(); +} +#endif + +/* Exercise a real CA -> leaf certificate chain, not just self-signed. + * Loads the CA as a trust anchor and verifies the leaf against it. */ +#if defined(WOLFSSL_HAVE_LMS) && !defined(NO_FILESYSTEM) && !defined(NO_CERTS) +static int rfc9802_lms_chain_verify(void) +{ + EXPECT_DECLS; + byte* caBuf = NULL; + byte* leafBuf = NULL; + int caLen = 0; + int leafLen = 0; + WOLFSSL_CERT_MANAGER* cm = NULL; + + ExpectIntEQ(rfc9802_load_file("./certs/lms/bc_lms_chain_ca.der", + &caBuf, &caLen), TEST_SUCCESS); + ExpectIntEQ(rfc9802_load_file("./certs/lms/bc_lms_chain_leaf.der", + &leafBuf, &leafLen), TEST_SUCCESS); + + ExpectNotNull(cm = wolfSSL_CertManagerNew()); + /* Only the CA is a trust anchor; the leaf is verified against it. */ + ExpectIntEQ(wolfSSL_CertManagerLoadCABuffer(cm, caBuf, (long)caLen, + WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CertManagerVerifyBuffer(cm, leafBuf, (long)leafLen, + WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); + + /* Without loading the CA the leaf must NOT verify. */ + if (cm != NULL) { + wolfSSL_CertManagerFree(cm); + cm = NULL; + } + ExpectNotNull(cm = wolfSSL_CertManagerNew()); + ExpectIntNE(wolfSSL_CertManagerVerifyBuffer(cm, leafBuf, (long)leafLen, + WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); + if (cm != NULL) { + wolfSSL_CertManagerFree(cm); + cm = NULL; + } + + XFREE(leafBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(caBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return EXPECT_RESULT(); +} +#endif + +/* Mirror of rfc9802_lms_chain_verify but for an XMSS CA -> leaf pair. */ +#if defined(WOLFSSL_HAVE_XMSS) && !defined(NO_FILESYSTEM) && !defined(NO_CERTS) +static int rfc9802_xmss_chain_verify(void) +{ + EXPECT_DECLS; + byte* caBuf = NULL; + byte* leafBuf = NULL; + int caLen = 0; + int leafLen = 0; + WOLFSSL_CERT_MANAGER* cm = NULL; + + ExpectIntEQ(rfc9802_load_file("./certs/xmss/bc_xmss_chain_ca.der", + &caBuf, &caLen), TEST_SUCCESS); + ExpectIntEQ(rfc9802_load_file("./certs/xmss/bc_xmss_chain_leaf.der", + &leafBuf, &leafLen), TEST_SUCCESS); + + ExpectNotNull(cm = wolfSSL_CertManagerNew()); + ExpectIntEQ(wolfSSL_CertManagerLoadCABuffer(cm, caBuf, (long)caLen, + WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CertManagerVerifyBuffer(cm, leafBuf, (long)leafLen, + WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); + + if (cm != NULL) { + wolfSSL_CertManagerFree(cm); + cm = NULL; + } + ExpectNotNull(cm = wolfSSL_CertManagerNew()); + ExpectIntNE(wolfSSL_CertManagerVerifyBuffer(cm, leafBuf, (long)leafLen, + WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); + if (cm != NULL) { + wolfSSL_CertManagerFree(cm); + cm = NULL; + } + + XFREE(leafBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(caBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return EXPECT_RESULT(); +} +#endif + +int test_rfc9802_lms_x509_verify(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_HAVE_LMS) +#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) && \ + !defined(WOLFSSL_NO_LMS_SHA256_256) + /* Mixed single-level LMS and multi-level HSS fixtures. The HSS + * public key carries only the top-level LMS/LM-OTS types, so + * wc_LmsKey_ImportPubRaw's auto-derive path searches the map + * by (levels, lmsType, lmOtsType). The bc_lms_native_bc_root + * fixture is generated through Bouncy Castle's stock + * JcaContentSignerBuilder("LMS") + JcaX509v3CertificateBuilder + * with no overrides; including it here is the cross-impl interop + * gate (BC's native LMS X.509 path is RFC 9802-compliant for HSS/ + * LMS, so wolfSSL must accept it end-to-end). + * + * All fixtures use the SHA-256/M32 family, so the whole block + * is gated on that family being compiled in. Truncated SHA-256/192 + * or SHAKE-only builds skip this block. */ + static const char* const lmsFiles[] = { + "./certs/lms/bc_lms_sha256_h5_w4_root.der", +#if !defined(WOLFSSL_LMS_MAX_HEIGHT) || (WOLFSSL_LMS_MAX_HEIGHT >= 10) + "./certs/lms/bc_lms_sha256_h10_w8_root.der", +#endif +#if !defined(WOLFSSL_LMS_MAX_LEVELS) || (WOLFSSL_LMS_MAX_LEVELS >= 2) + "./certs/lms/bc_hss_L2_H5_W8_root.der", +#endif +#if !defined(WOLFSSL_LMS_MAX_LEVELS) || (WOLFSSL_LMS_MAX_LEVELS >= 3) + "./certs/lms/bc_hss_L3_H5_W4_root.der", +#endif + "./certs/lms/bc_lms_native_bc_root.der", + }; + size_t i; + for (i = 0; i < sizeof(lmsFiles) / sizeof(lmsFiles[0]); i++) { + ExpectIntEQ(rfc9802_verify_one_cert(lmsFiles[i], + HSS_LMSk, CTC_HSS_LMS), TEST_SUCCESS); + } + ExpectIntEQ(rfc9802_lms_chain_verify(), TEST_SUCCESS); +#endif /* !NO_FILESYSTEM && !NO_CERTS && !WOLFSSL_NO_LMS_SHA256_256 */ + /* Pure wolfCrypt-level negative tests don't need filesystem or cert + * support, so they run for any LMS-enabled build. */ + ExpectIntEQ(rfc9802_lms_import_negative(), TEST_SUCCESS); +#endif + return EXPECT_RESULT(); +} + +int test_rfc9802_xmss_x509_verify(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_HAVE_XMSS) +#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) + static const char* const xmssFiles[] = { + "./certs/xmss/bc_xmss_sha2_10_256_root.der", + "./certs/xmss/bc_xmss_sha2_16_256_root.der", + }; + static const char* const xmssmtFiles[] = { + "./certs/xmss/bc_xmssmt_sha2_20_2_256_root.der", + "./certs/xmss/bc_xmssmt_sha2_20_4_256_root.der", + "./certs/xmss/bc_xmssmt_sha2_40_8_256_root.der", + }; + size_t i; + for (i = 0; i < sizeof(xmssFiles) / sizeof(xmssFiles[0]); i++) { + ExpectIntEQ(rfc9802_verify_one_cert(xmssFiles[i], + XMSSk, CTC_XMSS), TEST_SUCCESS); + } + for (i = 0; i < sizeof(xmssmtFiles) / sizeof(xmssmtFiles[0]); i++) { + ExpectIntEQ(rfc9802_verify_one_cert(xmssmtFiles[i], + XMSSMTk, CTC_XMSSMT), TEST_SUCCESS); + } + ExpectIntEQ(rfc9802_xmss_sig_oid_mismatch(), TEST_SUCCESS); + ExpectIntEQ(rfc9802_xmss_chain_verify(), TEST_SUCCESS); +#endif /* !NO_FILESYSTEM && !NO_CERTS */ + /* Pure wolfCrypt-level negative tests don't need filesystem or cert + * support, so they run for any XMSS-enabled build. */ + ExpectIntEQ(rfc9802_xmss_import_negative(), TEST_SUCCESS); +#endif + return EXPECT_RESULT(); +} diff --git a/tests/api/test_lms_xmss.h b/tests/api/test_lms_xmss.h new file mode 100644 index 0000000000..b2ff579987 --- /dev/null +++ b/tests/api/test_lms_xmss.h @@ -0,0 +1,39 @@ +/* test_lms_xmss.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 WOLFCRYPT_TEST_LMS_XMSS_H +#define WOLFCRYPT_TEST_LMS_XMSS_H + +#include + +int test_wc_LmsKey_sign_verify(void); +int test_wc_LmsKey_reload_cache(void); +int test_rfc9802_lms_x509_verify(void); +int test_rfc9802_xmss_x509_verify(void); + +/* LMS, and RFC 9802 (HSS/LMS and XMSS/XMSS^MT in X.509). */ +#define TEST_LMS_XMSS_DECLS \ + TEST_DECL_GROUP("lms", test_wc_LmsKey_sign_verify), \ + TEST_DECL_GROUP("lms", test_wc_LmsKey_reload_cache), \ + TEST_DECL_GROUP("lms", test_rfc9802_lms_x509_verify), \ + TEST_DECL_GROUP("xmss", test_rfc9802_xmss_x509_verify) + +#endif /* WOLFCRYPT_TEST_LMS_XMSS_H */ diff --git a/tests/api/test_mldsa.c b/tests/api/test_mldsa.c index dc52a54453..5a91f220c3 100644 --- a/tests/api/test_mldsa.c +++ b/tests/api/test_mldsa.c @@ -30508,3 +30508,85 @@ WOLFSSL_MLDSA_API_CHECK_INLINE void wc_mldsa_canonical_api_check(void) PRAGMA_CLANG_DIAG_POP #endif /* WOLFSSL_HAVE_MLDSA */ + +/*----------------------------------------------------------------------------*/ +/* ML-DSA / Dilithium negative length-validation tests */ +/*----------------------------------------------------------------------------*/ + +/* ML-DSA HashML-DSA verify must reject hashLen > WC_MAX_DIGEST_SIZE */ +int test_mldsa_verify_hash(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_HAVE_MLDSA) && \ + !defined(WOLFSSL_MLDSA_NO_MAKE_KEY) && \ + !defined(WOLFSSL_MLDSA_NO_VERIFY) + wc_MlDsaKey key; + WC_RNG rng; + int res = 0; + byte sig[4000]; + byte hash[4096]; /* larger than WC_MAX_DIGEST_SIZE */ + + XMEMSET(&key, 0, sizeof(key)); + XMEMSET(&rng, 0, sizeof(rng)); + XMEMSET(sig, 0x41, sizeof(sig)); + XMEMSET(hash, 'A', sizeof(hash)); + + ExpectIntEQ(wc_InitRng(&rng), 0); + ExpectIntEQ(wc_MlDsaKey_Init(&key, NULL, INVALID_DEVID), 0); +#ifndef WOLFSSL_NO_ML_DSA_65 + ExpectIntEQ(wc_MlDsaKey_SetParams(&key, WC_ML_DSA_65), 0); +#elif !defined(WOLFSSL_NO_ML_DSA_44) + ExpectIntEQ(wc_MlDsaKey_SetParams(&key, WC_ML_DSA_44), 0); +#else + ExpectIntEQ(wc_MlDsaKey_SetParams(&key, WC_ML_DSA_87), 0); +#endif + ExpectIntEQ(wc_MlDsaKey_MakeKey(&key, &rng), 0); + + /* hashLen=4096 must be rejected, not overflow the stack */ + ExpectIntEQ(wc_MlDsaKey_VerifyCtxHash(&key, sig, sizeof(sig), NULL, 0, + hash, sizeof(hash), WC_HASH_TYPE_SHA256, &res), + WC_NO_ERR_TRACE(BAD_LENGTH_E)); + + wc_MlDsaKey_Free(&key); + DoExpectIntEQ(wc_FreeRng(&rng), 0); +#endif + return EXPECT_RESULT(); +} + +/* Dilithium verify_ctx_msg must reject absurdly large msgLen */ +int test_dilithium_hash(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_HAVE_MLDSA) && \ + !defined(WOLFSSL_MLDSA_NO_MAKE_KEY) && \ + !defined(WOLFSSL_MLDSA_NO_VERIFY) + wc_MlDsaKey key; + WC_RNG rng; + int res = 0; + byte sig[4000]; + byte msg[64]; + + XMEMSET(&key, 0, sizeof(key)); + XMEMSET(&rng, 0, sizeof(rng)); + XMEMSET(sig, 0, sizeof(sig)); + XMEMSET(msg, 'A', sizeof(msg)); + + ExpectIntEQ(wc_InitRng(&rng), 0); + ExpectIntEQ(wc_MlDsaKey_Init(&key, NULL, INVALID_DEVID), 0); +#ifndef WOLFSSL_NO_ML_DSA_65 + ExpectIntEQ(wc_MlDsaKey_SetParams(&key, WC_ML_DSA_65), 0); +#elif !defined(WOLFSSL_NO_ML_DSA_44) + ExpectIntEQ(wc_MlDsaKey_SetParams(&key, WC_ML_DSA_44), 0); +#else + ExpectIntEQ(wc_MlDsaKey_SetParams(&key, WC_ML_DSA_87), 0); +#endif + ExpectIntEQ(wc_MlDsaKey_MakeKey(&key, &rng), 0); + + ExpectIntEQ(wc_MlDsaKey_VerifyCtx(&key, sig, sizeof(sig), NULL, 0, + msg, 0xFFFFFFC0, &res), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + wc_MlDsaKey_Free(&key); + DoExpectIntEQ(wc_FreeRng(&rng), 0); +#endif + return EXPECT_RESULT(); +} diff --git a/tests/api/test_mldsa.h b/tests/api/test_mldsa.h index 82c844b54e..631ebabdc1 100644 --- a/tests/api/test_mldsa.h +++ b/tests/api/test_mldsa.h @@ -51,6 +51,11 @@ int test_mldsa_encode_w1_large_values(void); int test_mldsa_pkcs12(void); int test_mldsa_x509_pubkey_sigtype(void); +/* Negative length-validation regression tests, also defined in + * tests/api/test_mldsa.c. */ +int test_mldsa_verify_hash(void); +int test_dilithium_hash(void); + /* Legacy-name shim coverage defined in tests/api/test_mldsa_legacy.c. * Single function -- compile-time wc_static_assert checks for every alias * + one runtime smoke test that drives each arg-reordering macro family. @@ -82,6 +87,8 @@ int test_mldsa_legacy_shim(void); TEST_DECL_GROUP("mldsa", test_mldsa_encode_w1_large_values), \ TEST_DECL_GROUP("mldsa", test_mldsa_pkcs12), \ TEST_DECL_GROUP("mldsa", test_mldsa_x509_pubkey_sigtype), \ + TEST_DECL_GROUP("mldsa", test_mldsa_verify_hash), \ + TEST_DECL_GROUP("mldsa", test_dilithium_hash), \ TEST_DECL_GROUP("mldsa", test_mldsa_legacy_shim) #endif /* WOLFCRYPT_TEST_MLDSA_H */ diff --git a/tests/api/test_session.c b/tests/api/test_session.c new file mode 100644 index 0000000000..e7557ff007 --- /dev/null +++ b/tests/api/test_session.c @@ -0,0 +1,1616 @@ +/* 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 + +#ifdef NO_INLINE + #include +#else + #define WOLFSSL_MISC_INCLUDED + #include +#endif + +#include +#include +#include +#include +#include +#include + +/*----------------------------------------------------------------------------*/ +/* 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 diff --git a/tests/api/test_session.h b/tests/api/test_session.h new file mode 100644 index 0000000000..9dc2e258f1 --- /dev/null +++ b/tests/api/test_session.h @@ -0,0 +1,54 @@ +/* test_session.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 WOLFCRYPT_TEST_SESSION_H +#define WOLFCRYPT_TEST_SESSION_H + +#include + +int test_wolfSSL_CTX_add_session(void); +int test_wolfSSL_CTX_add_session_ext_tls13(void); +int test_wolfSSL_CTX_add_session_ext_dtls13(void); +int test_wolfSSL_CTX_add_session_ext_tls12(void); +int test_wolfSSL_CTX_add_session_ext_dtls12(void); +int test_wolfSSL_CTX_add_session_ext_tls11(void); +int test_wolfSSL_CTX_add_session_ext_dtls1(void); +int test_wolfSSL_SESSION(void); +int test_wolfSSL_SESSION_expire_downgrade(void); +int test_wolfSSL_CTX_sess_set_remove_cb(void); +int test_wolfSSL_ticket_keys(void); +int test_wolfSSL_SESSION_get_ex_new_index(void); + +#define TEST_SESSION_DECLS \ + TEST_DECL_GROUP("session", test_wolfSSL_CTX_add_session), \ + TEST_DECL_GROUP("session", test_wolfSSL_CTX_add_session_ext_tls13), \ + TEST_DECL_GROUP("session", test_wolfSSL_CTX_add_session_ext_dtls13), \ + TEST_DECL_GROUP("session", test_wolfSSL_CTX_add_session_ext_tls12), \ + TEST_DECL_GROUP("session", test_wolfSSL_CTX_add_session_ext_dtls12), \ + TEST_DECL_GROUP("session", test_wolfSSL_CTX_add_session_ext_tls11), \ + TEST_DECL_GROUP("session", test_wolfSSL_CTX_add_session_ext_dtls1), \ + TEST_DECL_GROUP("session", test_wolfSSL_SESSION), \ + TEST_DECL_GROUP("session", test_wolfSSL_SESSION_expire_downgrade), \ + TEST_DECL_GROUP("session", test_wolfSSL_CTX_sess_set_remove_cb), \ + TEST_DECL_GROUP("session", test_wolfSSL_ticket_keys), \ + TEST_DECL_GROUP("session", test_wolfSSL_SESSION_get_ex_new_index) + +#endif /* WOLFCRYPT_TEST_SESSION_H */ diff --git a/tests/utils.h b/tests/utils.h index 8a7942086d..bd9a150e01 100644 --- a/tests/utils.h +++ b/tests/utils.h @@ -87,6 +87,15 @@ int test_memio_modify_message_len(struct test_memio_ctx *ctx, int client, int ms int test_memio_remove_from_buffer(struct test_memio_ctx *ctx, int client, int off, int sz); #endif +/* Shared TLS server/client thread bodies, defined in tests/api.c. The + * definitions are gated on ENABLE_TLS_CALLBACK_TEST (a composite condition + * locally #defined inside api.c) or (WOLFSSL_DTLS && WOLFSSL_SESSION_EXPORT). + * Declared unconditionally here so api.c itself sees the prototype regardless + * of which side of the local #define triggers; absent the definition the + * prototypes are harmless and any caller would get a link error. */ +THREAD_RETURN WOLFSSL_THREAD run_wolfssl_server(void* args); +void run_wolfssl_client(void* args); + #if !defined(NO_FILESYSTEM) && defined(OPENSSL_EXTRA) && \ defined(DEBUG_UNIT_TEST_CERTS) void DEBUG_WRITE_CERT_X509(WOLFSSL_X509* x509, const char* fileName);