mirror of
https://github.com/wolfSSL/wolfssl.git
synced 2026-08-23 04:33:24 +02:00
Clean up includes single return point from every function, consistent formatting function block comment and tests added. ssl_api_rw.c: Cleanup; 6 helpers extracted from write_dup/shutdown; fixed a SendBuffered corner case that returned 0 instead of an error. ssl_api_ext.c: Cleanup; extracted wolfssl_ticket_key_cb_process, wolfssl_rehandshake_prepare. ssl_api_hs.c: Cleanup + de-indent; 9 helpers extracted, incl. shared wolfssl_handshake_flush/_done between connect and accept (~100 duplicated lines removed). wolfSSL_connect/accept left multi-exit. ssl_api_cert.c: Cleanup of newer functions at end of file; extracted PushPeerCertToChain; fixed a double free in CreatePeerCertChain; fixed 5 wrong @param names. ssl_api_crl_ocsp.c: Full cleanup of all 49 functions; wolfSSL_OCSP_parse_url rewritten; fixed a URL with no host returning success with the rest of the URL as the host; added IPv6 literal support; fixed 4 wrong WOLFSSL_ENTER names. ssl.c: Moved the x509GetIssuerFromCM forward declaration here for clarity.
1948 lines
69 KiB
C
1948 lines
69 KiB
C
/* test_ssl_hs.c
|
|
*
|
|
* Copyright (C) 2006-2026 wolfSSL Inc.
|
|
*
|
|
* This file is part of wolfSSL.
|
|
*
|
|
* wolfSSL is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* wolfSSL is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
|
|
*/
|
|
|
|
#include <tests/unit.h>
|
|
|
|
#ifdef NO_INLINE
|
|
#include <wolfssl/wolfcrypt/misc.h>
|
|
#else
|
|
#define WOLFSSL_MISC_INCLUDED
|
|
#include <wolfcrypt/src/misc.c>
|
|
#endif
|
|
|
|
#include <wolfssl/ssl.h>
|
|
#include <wolfssl/internal.h>
|
|
#include <wolfssl/wolfio.h>
|
|
|
|
#include <tests/utils.h>
|
|
#include <tests/api/test_ssl_hs.h>
|
|
|
|
/* Tests for the handshake APIs in src/ssl_api_hs.c (moved from ssl.c). These
|
|
* cover functions not already exercised elsewhere in api.c. */
|
|
|
|
/* Test wolfSSL_state_string_long() over a live handshake.
|
|
*
|
|
* Covers the NULL case, the unknown-protocol case and sampling the state
|
|
* before, during and after a handshake.
|
|
*
|
|
* @return TEST_SUCCESS on success.
|
|
*/
|
|
int test_wolfSSL_state_string_long(void)
|
|
{
|
|
EXPECT_DECLS;
|
|
#if defined(OPENSSL_EXTRA) && defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) \
|
|
&& !defined(NO_TLS) && !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;
|
|
|
|
/* A NULL object has no state to report. */
|
|
ExpectNull(wolfSSL_state_string_long(NULL));
|
|
|
|
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
|
|
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
|
|
wolfTLSv1_2_client_method, wolfTLSv1_2_server_method), 0);
|
|
|
|
/* Before the handshake both sides report the initial state, named for the
|
|
* method's version rather than a negotiated one. */
|
|
ExpectStrEQ(wolfSSL_state_string_long(ssl_c), "TLSv1_2 Initialization");
|
|
ExpectStrEQ(wolfSSL_state_string_long(ssl_s), "TLSv1_2 Initialization");
|
|
|
|
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
|
|
|
|
/* After the handshake each side reports the last message it handled,
|
|
* prefixed with the negotiated protocol. Both have finished, so neither
|
|
* is still reporting the initial state. */
|
|
ExpectIntEQ(XSTRNCMP(wolfSSL_state_string_long(ssl_c), "TLSv1_2 ", 8), 0);
|
|
ExpectIntEQ(XSTRNCMP(wolfSSL_state_string_long(ssl_s), "TLSv1_2 ", 8), 0);
|
|
ExpectStrNE(wolfSSL_state_string_long(ssl_c), "TLSv1_2 Initialization");
|
|
ExpectStrNE(wolfSSL_state_string_long(ssl_s), "TLSv1_2 Initialization");
|
|
|
|
/* The completed state has one string for both directions, unlike the
|
|
* per-message states which name the direction. */
|
|
if (ssl_c != NULL) {
|
|
ssl_c->cbmode = WOLFSSL_CB_MODE_WRITE;
|
|
ssl_c->options.clientState = HANDSHAKE_DONE;
|
|
ExpectStrEQ(wolfSSL_state_string_long(ssl_c), "TLSv1_2 Handshake Done");
|
|
ssl_c->cbmode = WOLFSSL_CB_MODE_READ;
|
|
ssl_c->cbtype = server_hello;
|
|
ExpectStrEQ(wolfSSL_state_string_long(ssl_c),
|
|
"TLSv1_2 read Server Hello");
|
|
}
|
|
|
|
/* An unrecognized protocol version reports an empty string. */
|
|
if (ssl_c != NULL) {
|
|
ProtocolVersion saved = ssl_c->version;
|
|
|
|
ssl_c->version.major = 0x7f;
|
|
ExpectStrEQ(wolfSSL_state_string_long(ssl_c), "");
|
|
ssl_c->version = saved;
|
|
}
|
|
|
|
wolfSSL_free(ssl_c);
|
|
wolfSSL_free(ssl_s);
|
|
wolfSSL_CTX_free(ctx_c);
|
|
wolfSSL_CTX_free(ctx_s);
|
|
#endif
|
|
return EXPECT_RESULT();
|
|
}
|
|
|
|
/* Test wolfSSL_state_string_long() across the states it can report.
|
|
*
|
|
* The reported string is chosen from the callback mode, the handshake message
|
|
* type when reading, and the connection state when writing. Walk each of those
|
|
* so every arm of the translation is taken.
|
|
*
|
|
* @return TEST_SUCCESS on success.
|
|
*/
|
|
int test_wolfSSL_state_string_long_states(void)
|
|
{
|
|
EXPECT_DECLS;
|
|
#if defined(OPENSSL_EXTRA) && !defined(NO_WOLFSSL_CLIENT) \
|
|
&& !defined(NO_TLS) && !defined(WOLFSSL_NO_TLS12)
|
|
WOLFSSL_CTX* ctx = NULL;
|
|
WOLFSSL* ssl = NULL;
|
|
/* Handshake message types reported while reading, with the string each
|
|
* maps to. Only one side sends these, so the object's own side does not
|
|
* come into it. */
|
|
static const struct {
|
|
int type;
|
|
const char* str;
|
|
} readStates[] = {
|
|
{ hello_request, "TLSv1_2 read Server Hello Request" },
|
|
{ hello_verify_request, "TLSv1_2 read Server Hello Verify Request" },
|
|
{ session_ticket, "TLSv1_2 read Server Session Ticket" },
|
|
{ end_of_early_data, "TLSv1_2 read Client End Of Early Data" },
|
|
{ hello_retry_request, "TLSv1_2 read Server Hello Retry Request" },
|
|
{ client_hello, "TLSv1_2 read Client Hello" },
|
|
{ server_hello, "TLSv1_2 read Server Hello" },
|
|
{ encrypted_extensions, "TLSv1_2 read Server Encrypted Extensions" },
|
|
{ server_key_exchange, "TLSv1_2 read Server Key Exchange" },
|
|
{ certificate_request, "TLSv1_2 read Server Certificate Request" },
|
|
{ server_hello_done, "TLSv1_2 read Server Hello Done" },
|
|
{ certificate_verify, "TLSv1_2 read Client Certificate Verify" },
|
|
{ client_key_exchange, "TLSv1_2 read Client Key Exchange" },
|
|
{ certificate_status, "TLSv1_2 read Server Certificate Status" },
|
|
/* An unrecognized type reports the null state. */
|
|
{ 0x7f, "TLSv1_2 Initialization" }
|
|
};
|
|
/* Message types both sides send. The string names the side that sent the
|
|
* message, which is the peer - the opposite of the object's own side. */
|
|
static const struct {
|
|
int type;
|
|
const char* asClient;
|
|
const char* asServer;
|
|
} sidedStates[] = {
|
|
{ certificate,
|
|
"TLSv1_2 read Server Cert",
|
|
"TLSv1_2 read Client Cert" },
|
|
{ finished,
|
|
"TLSv1_2 read Server Finished",
|
|
"TLSv1_2 read Client Finished" },
|
|
{ key_update,
|
|
"TLSv1_2 read server Key Update",
|
|
"TLSv1_2 read Client Key Update" },
|
|
{ change_cipher_hs,
|
|
"TLSv1_2 read Server Change CipherSpec",
|
|
"TLSv1_2 read Client Change CipherSpec" }
|
|
};
|
|
/* Connection states reported while writing. Every state from the first
|
|
* to HANDSHAKE_DONE is listed, so the walk below covers the range. */
|
|
static const struct {
|
|
int state;
|
|
const char* str;
|
|
} writeStates[] = {
|
|
{ NULL_STATE,
|
|
"TLSv1_2 Initialization" },
|
|
{ SERVER_HELLOVERIFYREQUEST_COMPLETE,
|
|
"TLSv1_2 write Server Hello Verify Request" },
|
|
{ SERVER_HELLO_RETRY_REQUEST_COMPLETE,
|
|
"TLSv1_2 write Server Hello Retry Request" },
|
|
{ SERVER_HELLO_COMPLETE,
|
|
"TLSv1_2 write Server Hello" },
|
|
{ SERVER_ENCRYPTED_EXTENSIONS_COMPLETE,
|
|
"TLSv1_2 write Server Encrypted Extensions" },
|
|
{ SERVER_CERT_COMPLETE,
|
|
"TLSv1_2 write Server Cert" },
|
|
/* Has no string of its own, so reports the null state. */
|
|
{ SERVER_CERT_VERIFY_COMPLETE,
|
|
"TLSv1_2 Initialization" },
|
|
{ SERVER_KEYEXCHANGE_COMPLETE,
|
|
"TLSv1_2 write Server Key Exchange" },
|
|
{ SERVER_HELLODONE_COMPLETE,
|
|
"TLSv1_2 write Server Hello Done" },
|
|
{ SERVER_CHANGECIPHERSPEC_COMPLETE,
|
|
"TLSv1_2 write Server Change CipherSpec" },
|
|
{ SERVER_FINISHED_COMPLETE,
|
|
"TLSv1_2 write Server Finished" },
|
|
{ CLIENT_HELLO_RETRY,
|
|
"TLSv1_2 write Client Hello" },
|
|
{ CLIENT_HELLO_COMPLETE,
|
|
"TLSv1_2 write Client Hello" },
|
|
{ CLIENT_KEYEXCHANGE_COMPLETE,
|
|
"TLSv1_2 write Client Key Exchange" },
|
|
{ CLIENT_CHANGECIPHERSPEC_COMPLETE,
|
|
"TLSv1_2 write Client Change CipherSpec" },
|
|
{ CLIENT_FINISHED_COMPLETE,
|
|
"TLSv1_2 write Client Finished" },
|
|
{ HANDSHAKE_DONE,
|
|
"TLSv1_2 Handshake Done" }
|
|
};
|
|
/* Each protocol version has its own set of strings. */
|
|
static const struct {
|
|
int major;
|
|
int minor;
|
|
const char* str;
|
|
} protocols[] = {
|
|
{ SSLv3_MAJOR, SSLv3_MINOR, "SSLv3 read Server Hello" },
|
|
{ SSLv3_MAJOR, TLSv1_MINOR, "TLSv1 read Server Hello" },
|
|
{ SSLv3_MAJOR, TLSv1_1_MINOR, "TLSv1_1 read Server Hello" },
|
|
{ SSLv3_MAJOR, TLSv1_2_MINOR, "TLSv1_2 read Server Hello" },
|
|
{ SSLv3_MAJOR, TLSv1_3_MINOR, "TLSv1_3 read Server Hello" },
|
|
{ DTLS_MAJOR, DTLS_MINOR, "DTLSv1 read Server Hello" },
|
|
{ DTLS_MAJOR, DTLSv1_2_MINOR, "DTLSv1_2 read Server Hello" },
|
|
{ DTLS_MAJOR, DTLSv1_3_MINOR, "DTLSv1_3 read Server Hello" },
|
|
/* An unrecognized minor version of either major reports no string. */
|
|
{ SSLv3_MAJOR, 0x7f, "" },
|
|
{ DTLS_MAJOR, 0x7f, "" }
|
|
};
|
|
int i;
|
|
|
|
ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_2_client_method()));
|
|
ExpectNotNull(ssl = wolfSSL_new(ctx));
|
|
|
|
if (ssl != NULL) {
|
|
/* Reading: every message type maps to a state string. */
|
|
ssl->cbmode = WOLFSSL_CB_MODE_READ;
|
|
for (i = 0; i < (int)XELEM_CNT(readStates); i++) {
|
|
ssl->cbtype = readStates[i].type;
|
|
ExpectStrEQ(wolfSSL_state_string_long(ssl), readStates[i].str);
|
|
}
|
|
|
|
/* The messages both sides send name their sender, so the string
|
|
* follows the side of the object that read them. */
|
|
for (i = 0; i < (int)XELEM_CNT(sidedStates); i++) {
|
|
ssl->cbtype = sidedStates[i].type;
|
|
ssl->options.side = WOLFSSL_CLIENT_END;
|
|
ExpectStrEQ(wolfSSL_state_string_long(ssl),
|
|
sidedStates[i].asClient);
|
|
ssl->options.side = WOLFSSL_SERVER_END;
|
|
ExpectStrEQ(wolfSSL_state_string_long(ssl),
|
|
sidedStates[i].asServer);
|
|
/* With no side established the sender cannot be named. */
|
|
ssl->options.side = WOLFSSL_NEITHER_END;
|
|
ExpectStrEQ(wolfSSL_state_string_long(ssl),
|
|
"TLSv1_2 Initialization");
|
|
}
|
|
ssl->options.side = WOLFSSL_CLIENT_END;
|
|
|
|
/* Writing: the connection state is reported instead. */
|
|
ssl->cbmode = WOLFSSL_CB_MODE_WRITE;
|
|
for (i = 0; i < (int)XELEM_CNT(writeStates); i++) {
|
|
ssl->options.clientState = (byte)writeStates[i].state;
|
|
ExpectStrEQ(wolfSSL_state_string_long(ssl), writeStates[i].str);
|
|
}
|
|
|
|
/* Which state is reported follows the side: a server reports its own
|
|
* rather than the client's. */
|
|
ssl->options.serverState = SERVER_HELLO_COMPLETE;
|
|
ssl->options.clientState = CLIENT_FINISHED_COMPLETE;
|
|
ssl->options.side = WOLFSSL_SERVER_END;
|
|
ExpectStrEQ(wolfSSL_state_string_long(ssl),
|
|
"TLSv1_2 write Server Hello");
|
|
ssl->options.side = WOLFSSL_CLIENT_END;
|
|
ExpectStrEQ(wolfSSL_state_string_long(ssl),
|
|
"TLSv1_2 write Client Finished");
|
|
|
|
/* Neither reading nor writing: the string carries no direction. */
|
|
ssl->cbmode = 0;
|
|
ssl->options.clientState = SERVER_HELLO_COMPLETE;
|
|
ExpectStrEQ(wolfSSL_state_string_long(ssl), "TLSv1_2 Server Hello");
|
|
|
|
/* Each protocol version has its own set of strings, and one that is
|
|
* not recognized has none. */
|
|
ssl->cbmode = WOLFSSL_CB_MODE_READ;
|
|
ssl->cbtype = server_hello;
|
|
for (i = 0; i < (int)XELEM_CNT(protocols); i++) {
|
|
ssl->version.major = (byte)protocols[i].major;
|
|
ssl->version.minor = (byte)protocols[i].minor;
|
|
ExpectStrEQ(wolfSSL_state_string_long(ssl), protocols[i].str);
|
|
}
|
|
}
|
|
|
|
wolfSSL_free(ssl);
|
|
wolfSSL_CTX_free(ctx);
|
|
#endif
|
|
return EXPECT_RESULT();
|
|
}
|
|
|
|
/* Test wolfSSL_set_connect_state() and wolfSSL_set_accept_state().
|
|
*
|
|
* Each switches the side the object will act as.
|
|
*
|
|
* @return TEST_SUCCESS on success.
|
|
*/
|
|
int test_wolfSSL_set_connect_accept_state(void)
|
|
{
|
|
EXPECT_DECLS;
|
|
#if (defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL)) \
|
|
&& !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) \
|
|
&& !defined(NO_TLS) && !defined(WOLFSSL_NO_TLS12)
|
|
WOLFSSL_CTX* ctx = NULL;
|
|
WOLFSSL* ssl = NULL;
|
|
|
|
/* A NULL object is ignored by both. */
|
|
wolfSSL_set_connect_state(NULL);
|
|
wolfSSL_set_accept_state(NULL);
|
|
|
|
ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_2_client_method()));
|
|
ExpectNotNull(ssl = wolfSSL_new(ctx));
|
|
|
|
/* Created from a client method. */
|
|
ExpectIntEQ(wolfSSL_is_server(ssl), 0);
|
|
|
|
/* Switch to acting as a server, then back. */
|
|
wolfSSL_set_accept_state(ssl);
|
|
ExpectIntEQ(wolfSSL_is_server(ssl), 1);
|
|
wolfSSL_set_connect_state(ssl);
|
|
ExpectIntEQ(wolfSSL_is_server(ssl), 0);
|
|
|
|
/* Setting the same side again is harmless. */
|
|
wolfSSL_set_connect_state(ssl);
|
|
ExpectIntEQ(wolfSSL_is_server(ssl), 0);
|
|
|
|
wolfSSL_free(ssl);
|
|
wolfSSL_CTX_free(ctx);
|
|
#endif
|
|
return EXPECT_RESULT();
|
|
}
|
|
|
|
/* Test wolfSSL_SSL_do_handshake().
|
|
*
|
|
* Drives a handshake through the OpenSSL-compatibility entry point, which
|
|
* dispatches to connect or accept based on the side of the object.
|
|
*
|
|
* @return TEST_SUCCESS on success.
|
|
*/
|
|
int test_wolfSSL_SSL_do_handshake(void)
|
|
{
|
|
EXPECT_DECLS;
|
|
#if (defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA)) \
|
|
&& defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && !defined(NO_TLS) \
|
|
&& !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;
|
|
int i;
|
|
int cRet = WOLFSSL_FATAL_ERROR;
|
|
int sRet = WOLFSSL_FATAL_ERROR;
|
|
|
|
/* A NULL object is rejected. */
|
|
ExpectIntEQ(wolfSSL_SSL_do_handshake(NULL), WOLFSSL_FAILURE);
|
|
|
|
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
|
|
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
|
|
wolfTLSv1_2_client_method, wolfTLSv1_2_server_method), 0);
|
|
|
|
/* Alternate the two sides until both report the handshake is complete. */
|
|
for (i = 0; i < 10; i++) {
|
|
if (cRet != WOLFSSL_SUCCESS) {
|
|
cRet = wolfSSL_SSL_do_handshake(ssl_c);
|
|
}
|
|
if (sRet != WOLFSSL_SUCCESS) {
|
|
sRet = wolfSSL_SSL_do_handshake(ssl_s);
|
|
}
|
|
if ((cRet == WOLFSSL_SUCCESS) && (sRet == WOLFSSL_SUCCESS)) {
|
|
break;
|
|
}
|
|
}
|
|
ExpectIntEQ(cRet, WOLFSSL_SUCCESS);
|
|
ExpectIntEQ(sRet, WOLFSSL_SUCCESS);
|
|
|
|
wolfSSL_free(ssl_c);
|
|
wolfSSL_free(ssl_s);
|
|
wolfSSL_CTX_free(ctx_c);
|
|
wolfSSL_CTX_free(ctx_s);
|
|
#endif
|
|
return EXPECT_RESULT();
|
|
}
|
|
|
|
/* Test wolfSSL_SSL_in_init(), wolfSSL_SSL_in_before() and
|
|
* wolfSSL_SSL_in_connect_init().
|
|
*
|
|
* The three report where in the handshake the object is.
|
|
*
|
|
* @return TEST_SUCCESS on success.
|
|
*/
|
|
int test_wolfSSL_SSL_in_init_hs(void)
|
|
{
|
|
EXPECT_DECLS;
|
|
#if (defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA)) \
|
|
&& defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && !defined(NO_TLS) \
|
|
&& !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;
|
|
|
|
/* NULL objects report no state. */
|
|
ExpectIntEQ(wolfSSL_SSL_in_before(NULL), WOLFSSL_FAILURE);
|
|
ExpectIntEQ(wolfSSL_SSL_in_connect_init(NULL), WOLFSSL_FAILURE);
|
|
|
|
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
|
|
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
|
|
wolfTLSv1_2_client_method, wolfTLSv1_2_server_method), 0);
|
|
|
|
/* Nothing has happened yet. */
|
|
ExpectIntEQ(wolfSSL_SSL_in_before(ssl_c), 1);
|
|
ExpectIntEQ(wolfSSL_SSL_in_init(ssl_c), 1);
|
|
ExpectIntEQ(wolfSSL_SSL_in_connect_init(ssl_c), 0);
|
|
|
|
/* A partial handshake leaves the client mid-connect. */
|
|
ExpectIntNE(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS);
|
|
ExpectIntEQ(wolfSSL_SSL_in_connect_init(ssl_c), 1);
|
|
ExpectIntEQ(wolfSSL_SSL_in_before(ssl_c), 1);
|
|
|
|
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
|
|
|
|
/* Once complete, none of the in-progress states hold. */
|
|
ExpectIntEQ(wolfSSL_SSL_in_init(ssl_c), 0);
|
|
ExpectIntEQ(wolfSSL_SSL_in_before(ssl_c), 0);
|
|
ExpectIntEQ(wolfSSL_SSL_in_connect_init(ssl_c), 0);
|
|
ExpectIntEQ(wolfSSL_SSL_in_init(ssl_s), 0);
|
|
ExpectIntEQ(wolfSSL_SSL_in_connect_init(ssl_s), 0);
|
|
|
|
wolfSSL_free(ssl_c);
|
|
wolfSSL_free(ssl_s);
|
|
wolfSSL_CTX_free(ctx_c);
|
|
wolfSSL_CTX_free(ctx_s);
|
|
#endif
|
|
return EXPECT_RESULT();
|
|
}
|
|
|
|
/* Test wolfSSL_is_init_finished().
|
|
*
|
|
* @return TEST_SUCCESS on success.
|
|
*/
|
|
int test_wolfSSL_is_init_finished(void)
|
|
{
|
|
EXPECT_DECLS;
|
|
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && !defined(NO_TLS) \
|
|
&& !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;
|
|
|
|
/* A NULL object has not finished. */
|
|
ExpectIntEQ(wolfSSL_is_init_finished(NULL), 0);
|
|
|
|
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
|
|
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
|
|
wolfTLSv1_2_client_method, wolfTLSv1_2_server_method), 0);
|
|
|
|
ExpectIntEQ(wolfSSL_is_init_finished(ssl_c), 0);
|
|
ExpectIntEQ(wolfSSL_is_init_finished(ssl_s), 0);
|
|
|
|
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
|
|
|
|
ExpectIntEQ(wolfSSL_is_init_finished(ssl_c), 1);
|
|
ExpectIntEQ(wolfSSL_is_init_finished(ssl_s), 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(NO_HANDSHAKE_DONE_CB) && !defined(NO_TLS) && \
|
|
!defined(WOLFSSL_NO_TLS12)
|
|
/* Count of handshake-done callback invocations. */
|
|
static int test_ssl_hs_done_calls = 0;
|
|
|
|
/* Handshake-done callback recording that it ran.
|
|
*
|
|
* @param [in] ssl SSL/TLS object. Unused.
|
|
* @param [in] user_ctx User context; expected to be &test_ssl_hs_done_calls.
|
|
* @return 0 to let the handshake complete.
|
|
*/
|
|
static int test_ssl_hs_done_cb(WOLFSSL* ssl, void* user_ctx)
|
|
{
|
|
(void)ssl;
|
|
|
|
if (user_ctx == &test_ssl_hs_done_calls) {
|
|
test_ssl_hs_done_calls++;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
/* Test wolfSSL_SetHsDoneCb().
|
|
*
|
|
* The registered callback must run when the handshake completes.
|
|
*
|
|
* @return TEST_SUCCESS on success.
|
|
*/
|
|
int test_wolfSSL_SetHsDoneCb(void)
|
|
{
|
|
EXPECT_DECLS;
|
|
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) \
|
|
&& !defined(NO_HANDSHAKE_DONE_CB) && !defined(NO_TLS) \
|
|
&& !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;
|
|
|
|
/* A NULL object is rejected. */
|
|
ExpectIntEQ(wolfSSL_SetHsDoneCb(NULL, test_ssl_hs_done_cb, NULL),
|
|
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
|
|
|
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
|
|
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
|
|
wolfTLSv1_2_client_method, wolfTLSv1_2_server_method), 0);
|
|
|
|
test_ssl_hs_done_calls = 0;
|
|
ExpectIntEQ(wolfSSL_SetHsDoneCb(ssl_c, test_ssl_hs_done_cb,
|
|
&test_ssl_hs_done_calls), WOLFSSL_SUCCESS);
|
|
|
|
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
|
|
|
|
/* The client's callback ran; the server had none registered. */
|
|
ExpectIntEQ(test_ssl_hs_done_calls, 1);
|
|
|
|
wolfSSL_free(ssl_c);
|
|
wolfSSL_free(ssl_s);
|
|
wolfSSL_CTX_free(ctx_c);
|
|
wolfSSL_CTX_free(ctx_s);
|
|
#endif
|
|
return EXPECT_RESULT();
|
|
}
|
|
|
|
/* Test the public-key callback context accessors.
|
|
*
|
|
* Each Set/Get pair stores and returns an opaque application pointer, and each
|
|
* accessor tolerates a NULL object.
|
|
*
|
|
* @return TEST_SUCCESS on success.
|
|
*/
|
|
int test_wolfSSL_pk_callback_ctx(void)
|
|
{
|
|
EXPECT_DECLS;
|
|
#if defined(HAVE_PK_CALLBACKS) && !defined(NO_CERTS) \
|
|
&& !defined(NO_WOLFSSL_CLIENT) && !defined(NO_TLS) \
|
|
&& !defined(WOLFSSL_NO_TLS12)
|
|
WOLFSSL_CTX* ctx = NULL;
|
|
WOLFSSL* ssl = NULL;
|
|
int marker = 0;
|
|
void* p = ▮
|
|
|
|
/* NULL objects are tolerated by every accessor. */
|
|
ExpectNull(wolfSSL_GetGenPreMasterCtx(NULL));
|
|
ExpectNull(wolfSSL_GetGenMasterSecretCtx(NULL));
|
|
ExpectNull(wolfSSL_GetGenSessionKeyCtx(NULL));
|
|
ExpectNull(wolfSSL_GetEncryptKeysCtx(NULL));
|
|
ExpectNull(wolfSSL_GetTlsFinishedCtx(NULL));
|
|
/* The VerifyMac accessors only exist when a MAC is used, so an AEAD-only
|
|
* build does not have them. */
|
|
#if !defined(WOLFSSL_NO_TLS12) && !defined(WOLFSSL_AEAD_ONLY)
|
|
ExpectNull(wolfSSL_GetVerifyMacCtx(NULL));
|
|
#endif
|
|
wolfSSL_SetGenPreMasterCtx(NULL, p);
|
|
wolfSSL_SetGenMasterSecretCtx(NULL, p);
|
|
wolfSSL_SetGenSessionKeyCtx(NULL, p);
|
|
wolfSSL_SetEncryptKeysCtx(NULL, p);
|
|
wolfSSL_SetTlsFinishedCtx(NULL, p);
|
|
#if !defined(WOLFSSL_NO_TLS12) && !defined(WOLFSSL_AEAD_ONLY)
|
|
wolfSSL_SetVerifyMacCtx(NULL, p);
|
|
#endif
|
|
wolfSSL_CTX_SetGenPreMasterCb(NULL, NULL);
|
|
wolfSSL_CTX_SetGenMasterSecretCb(NULL, NULL);
|
|
wolfSSL_CTX_SetGenSessionKeyCb(NULL, NULL);
|
|
wolfSSL_CTX_SetEncryptKeysCb(NULL, NULL);
|
|
wolfSSL_CTX_SetTlsFinishedCb(NULL, NULL);
|
|
#if !defined(WOLFSSL_NO_TLS12) && !defined(WOLFSSL_AEAD_ONLY)
|
|
wolfSSL_CTX_SetVerifyMacCb(NULL, NULL);
|
|
#endif
|
|
|
|
ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_2_client_method()));
|
|
ExpectNotNull(ssl = wolfSSL_new(ctx));
|
|
|
|
/* Nothing stored yet. */
|
|
ExpectNull(wolfSSL_GetGenPreMasterCtx(ssl));
|
|
ExpectNull(wolfSSL_GetGenMasterSecretCtx(ssl));
|
|
ExpectNull(wolfSSL_GetGenSessionKeyCtx(ssl));
|
|
ExpectNull(wolfSSL_GetEncryptKeysCtx(ssl));
|
|
ExpectNull(wolfSSL_GetTlsFinishedCtx(ssl));
|
|
#if !defined(WOLFSSL_NO_TLS12) && !defined(WOLFSSL_AEAD_ONLY)
|
|
ExpectNull(wolfSSL_GetVerifyMacCtx(ssl));
|
|
#endif
|
|
|
|
/* Each pair round-trips the pointer it was given. */
|
|
wolfSSL_SetGenPreMasterCtx(ssl, p);
|
|
ExpectPtrEq(wolfSSL_GetGenPreMasterCtx(ssl), p);
|
|
wolfSSL_SetGenMasterSecretCtx(ssl, p);
|
|
ExpectPtrEq(wolfSSL_GetGenMasterSecretCtx(ssl), p);
|
|
wolfSSL_SetGenSessionKeyCtx(ssl, p);
|
|
ExpectPtrEq(wolfSSL_GetGenSessionKeyCtx(ssl), p);
|
|
wolfSSL_SetEncryptKeysCtx(ssl, p);
|
|
ExpectPtrEq(wolfSSL_GetEncryptKeysCtx(ssl), p);
|
|
wolfSSL_SetTlsFinishedCtx(ssl, p);
|
|
ExpectPtrEq(wolfSSL_GetTlsFinishedCtx(ssl), p);
|
|
#if !defined(WOLFSSL_NO_TLS12) && !defined(WOLFSSL_AEAD_ONLY)
|
|
wolfSSL_SetVerifyMacCtx(ssl, p);
|
|
ExpectPtrEq(wolfSSL_GetVerifyMacCtx(ssl), p);
|
|
#endif
|
|
|
|
/* The context-level callback setters accept a NULL callback. */
|
|
wolfSSL_CTX_SetGenPreMasterCb(ctx, NULL);
|
|
wolfSSL_CTX_SetGenMasterSecretCb(ctx, NULL);
|
|
wolfSSL_CTX_SetGenSessionKeyCb(ctx, NULL);
|
|
wolfSSL_CTX_SetEncryptKeysCb(ctx, NULL);
|
|
wolfSSL_CTX_SetTlsFinishedCb(ctx, NULL);
|
|
#if !defined(WOLFSSL_NO_TLS12) && !defined(WOLFSSL_AEAD_ONLY)
|
|
wolfSSL_CTX_SetVerifyMacCb(ctx, NULL);
|
|
#endif
|
|
|
|
/* Not guarded on HAVE_EXTENDED_MASTER: these three are defined for the
|
|
* whole of HAVE_PK_CALLBACKS and back onto fields that are unconditional
|
|
* too, so they are reachable whether or not the extended master secret
|
|
* is built in. */
|
|
ExpectNull(wolfSSL_GetGenExtMasterSecretCtx(NULL));
|
|
wolfSSL_SetGenExtMasterSecretCtx(NULL, p);
|
|
wolfSSL_CTX_SetGenExtMasterSecretCb(NULL, NULL);
|
|
ExpectNull(wolfSSL_GetGenExtMasterSecretCtx(ssl));
|
|
wolfSSL_SetGenExtMasterSecretCtx(ssl, p);
|
|
ExpectPtrEq(wolfSSL_GetGenExtMasterSecretCtx(ssl), p);
|
|
wolfSSL_CTX_SetGenExtMasterSecretCb(ctx, NULL);
|
|
|
|
#ifdef WOLFSSL_TLS13
|
|
ExpectNull(wolfSSL_GetHKDFExtractCtx(NULL));
|
|
wolfSSL_SetHKDFExtractCtx(NULL, p);
|
|
wolfSSL_CTX_SetHKDFExtractCb(NULL, NULL);
|
|
ExpectNull(wolfSSL_GetHKDFExtractCtx(ssl));
|
|
wolfSSL_SetHKDFExtractCtx(ssl, p);
|
|
ExpectPtrEq(wolfSSL_GetHKDFExtractCtx(ssl), p);
|
|
wolfSSL_CTX_SetHKDFExtractCb(ctx, NULL);
|
|
wolfSSL_CTX_SetHKDFExpandLabelCb(NULL, NULL);
|
|
wolfSSL_CTX_SetHKDFExpandLabelCb(ctx, NULL);
|
|
#endif
|
|
|
|
#ifdef WOLFSSL_PUBLIC_ASN
|
|
wolfSSL_CTX_SetProcessPeerCertCb(NULL, NULL);
|
|
wolfSSL_CTX_SetProcessPeerCertCb(ctx, NULL);
|
|
#endif
|
|
wolfSSL_CTX_SetProcessServerSigKexCb(NULL, NULL);
|
|
wolfSSL_CTX_SetProcessServerSigKexCb(ctx, NULL);
|
|
wolfSSL_CTX_SetPerformTlsRecordProcessingCb(NULL, NULL);
|
|
wolfSSL_CTX_SetPerformTlsRecordProcessingCb(ctx, NULL);
|
|
|
|
wolfSSL_free(ssl);
|
|
wolfSSL_CTX_free(ctx);
|
|
#endif
|
|
return EXPECT_RESULT();
|
|
}
|
|
|
|
/* Test that a static ECC key survives wolfSSL_set_accept_state().
|
|
*
|
|
* The check that the key is an EC key decodes it, so under
|
|
* WOLFSSL_BLIND_PRIVATE_KEY it has to be unmasked first. Decoding the masked
|
|
* bytes always fails, which silently withdrew the ECC capabilities for a key
|
|
* that was perfectly good.
|
|
*
|
|
* @return TEST_SUCCESS on success.
|
|
*/
|
|
int test_wolfSSL_set_accept_state_static_ecc(void)
|
|
{
|
|
EXPECT_DECLS;
|
|
#if (defined(OPENSSL_EXTRA) || defined(WOLFSSL_EXTRA) || \
|
|
defined(WOLFSSL_WPAS_SMALL)) && \
|
|
defined(HAVE_ECC) && !defined(NO_TLS) && !defined(WOLFSSL_NO_TLS12) && \
|
|
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) && \
|
|
!defined(NO_FILESYSTEM) && !defined(NO_CERTS) && \
|
|
defined(WOLFSSL_PEM_TO_DER)
|
|
WOLFSSL_CTX* ctx = NULL;
|
|
WOLFSSL* ssl = NULL;
|
|
|
|
/* The key is only re-checked when a client object is switched to being a
|
|
* server, so start from a client. */
|
|
ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_2_client_method()));
|
|
ExpectIntEQ(wolfSSL_CTX_use_certificate_file(ctx, eccCertFile,
|
|
WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
|
|
ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_file(ctx, eccKeyFile,
|
|
WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
|
|
ExpectNotNull(ssl = wolfSSL_new(ctx));
|
|
if (ssl != NULL) {
|
|
ssl->options.haveStaticECC = 1;
|
|
ssl->options.haveECC = 1;
|
|
ssl->options.haveECDSAsig = 1;
|
|
|
|
wolfSSL_set_accept_state(ssl);
|
|
|
|
/* The key really is an EC key, so nothing may be withdrawn. Without
|
|
* unmasking, the decode fails and all three are cleared. */
|
|
ExpectIntEQ(ssl->options.haveStaticECC, 1);
|
|
ExpectIntEQ(ssl->options.haveECC, 1);
|
|
ExpectIntEQ(ssl->options.haveECDSAsig, 1);
|
|
}
|
|
|
|
wolfSSL_free(ssl);
|
|
wolfSSL_CTX_free(ctx);
|
|
#endif
|
|
return EXPECT_RESULT();
|
|
}
|
|
|
|
/* Test the client-to-server switch in wolfSSL_set_accept_state().
|
|
*
|
|
* Switching a client object to act as a server re-checks a static ECC key and
|
|
* adopts any DH parameters the context has since acquired. A key that is not
|
|
* an EC key must clear the ECC capability flags rather than be trusted.
|
|
*
|
|
* @return TEST_SUCCESS on success.
|
|
*/
|
|
int test_wolfSSL_set_accept_state_reinit(void)
|
|
{
|
|
EXPECT_DECLS;
|
|
#if (defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL)) \
|
|
&& !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) \
|
|
&& !defined(NO_FILESYSTEM) && !defined(NO_CERTS) && !defined(NO_TLS) \
|
|
&& !defined(WOLFSSL_NO_TLS12) && \
|
|
defined(WOLFSSL_PEM_TO_DER)
|
|
/* Declared only when at least one of the cases below is built. */
|
|
#if defined(HAVE_ECC) || (!defined(NO_DH) && !defined(NO_RSA))
|
|
WOLFSSL_CTX* ctx = NULL;
|
|
WOLFSSL* ssl = NULL;
|
|
#endif
|
|
|
|
#if defined(HAVE_ECC) && !defined(NO_RSA)
|
|
/* An RSA key cannot be decoded as an EC key, so the static ECC
|
|
* capability must be withdrawn. */
|
|
ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_2_client_method()));
|
|
ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_file(ctx, svrKeyFile,
|
|
WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
|
|
ExpectNotNull(ssl = wolfSSL_new(ctx));
|
|
|
|
if (ssl != NULL) {
|
|
ExpectNotNull(ssl->buffers.key);
|
|
ssl->options.haveStaticECC = 1;
|
|
ssl->options.haveECC = 1;
|
|
ssl->options.haveECDSAsig = 1;
|
|
|
|
wolfSSL_set_accept_state(ssl);
|
|
|
|
ExpectIntEQ(ssl->options.haveStaticECC, 0);
|
|
ExpectIntEQ(ssl->options.haveECC, 0);
|
|
ExpectIntEQ(ssl->options.haveECDSAsig, 0);
|
|
ExpectIntEQ(wolfSSL_is_server(ssl), 1);
|
|
}
|
|
|
|
wolfSSL_free(ssl);
|
|
ssl = NULL;
|
|
wolfSSL_CTX_free(ctx);
|
|
ctx = NULL;
|
|
#endif /* HAVE_ECC && !NO_RSA */
|
|
|
|
#ifdef HAVE_ECC
|
|
/* A real EC key decodes, so the flags are left alone. */
|
|
ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_2_client_method()));
|
|
ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_file(ctx, eccKeyFile,
|
|
WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
|
|
ExpectNotNull(ssl = wolfSSL_new(ctx));
|
|
|
|
if (ssl != NULL) {
|
|
ssl->options.haveStaticECC = 1;
|
|
ssl->options.haveECC = 1;
|
|
|
|
wolfSSL_set_accept_state(ssl);
|
|
|
|
ExpectIntEQ(ssl->options.haveStaticECC, 1);
|
|
ExpectIntEQ(ssl->options.haveECC, 1);
|
|
}
|
|
|
|
wolfSSL_free(ssl);
|
|
ssl = NULL;
|
|
wolfSSL_CTX_free(ctx);
|
|
ctx = NULL;
|
|
#endif /* HAVE_ECC */
|
|
|
|
#if !defined(NO_DH) && (!defined(NO_RSA) || defined(HAVE_ECC))
|
|
/* DH parameters added to the context after the object was created are
|
|
* picked up when the object becomes a server. */
|
|
ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_2_client_method()));
|
|
ExpectNotNull(ssl = wolfSSL_new(ctx));
|
|
|
|
/* Not inherited at creation time - the context had none then. */
|
|
if (ssl != NULL) {
|
|
ExpectIntEQ(ssl->options.haveDH, 0);
|
|
}
|
|
|
|
ExpectIntEQ(wolfSSL_CTX_SetTmpDH_file(ctx, dhParamFile,
|
|
WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
|
|
|
|
wolfSSL_set_accept_state(ssl);
|
|
|
|
if ((ssl != NULL) && (ctx != NULL)) {
|
|
ExpectIntEQ(ssl->options.haveDH, 1);
|
|
ExpectPtrEq(ssl->buffers.serverDH_P.buffer, ctx->serverDH_P.buffer);
|
|
ExpectPtrEq(ssl->buffers.serverDH_G.buffer, ctx->serverDH_G.buffer);
|
|
}
|
|
|
|
wolfSSL_free(ssl);
|
|
ssl = NULL;
|
|
wolfSSL_CTX_free(ctx);
|
|
ctx = NULL;
|
|
#endif /* !NO_DH */
|
|
#endif
|
|
return EXPECT_RESULT();
|
|
}
|
|
|
|
/* Test the argument checks of wolfSSL_negotiate() and wolfSSL_connect_cert().
|
|
*
|
|
* Both reject a NULL object, each with its own failure code.
|
|
*
|
|
* @return TEST_SUCCESS on success.
|
|
*/
|
|
int test_wolfSSL_negotiate_bad_args(void)
|
|
{
|
|
EXPECT_DECLS;
|
|
#ifndef NO_TLS
|
|
ExpectIntEQ(wolfSSL_negotiate(NULL), WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR));
|
|
#if !defined(NO_WOLFSSL_CLIENT)
|
|
ExpectIntEQ(wolfSSL_connect_cert(NULL), WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
|
|
#endif
|
|
#endif
|
|
return EXPECT_RESULT();
|
|
}
|
|
|
|
#if defined(WOLFSSL_QUIC) && defined(WOLFSSL_TLS13) && \
|
|
(defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA)) && \
|
|
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_TLS)
|
|
/* QUIC callbacks that do nothing. wolfSSL_SSL_do_handshake() only needs the
|
|
* method to be set so that the object counts as a QUIC one. */
|
|
|
|
/* QUIC callback that takes the traffic secrets and does nothing with them.
|
|
*
|
|
* @param [in] ssl SSL/TLS object. Unused.
|
|
* @param [in] level Encryption level. Unused.
|
|
* @param [in] rx Secret for reading. Unused.
|
|
* @param [in] tx Secret for writing. Unused.
|
|
* @param [in] len Length of each secret. Unused.
|
|
* @return 1 always.
|
|
*/
|
|
static int test_ssl_hs_quic_secrets(WOLFSSL* ssl,
|
|
WOLFSSL_ENCRYPTION_LEVEL level, const uint8_t* rx, const uint8_t* tx,
|
|
size_t len)
|
|
{
|
|
(void)ssl;
|
|
(void)level;
|
|
(void)rx;
|
|
(void)tx;
|
|
(void)len;
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* QUIC callback that accepts handshake data and does nothing with it.
|
|
*
|
|
* @param [in] ssl SSL/TLS object. Unused.
|
|
* @param [in] level Encryption level. Unused.
|
|
* @param [in] data Handshake data. Unused.
|
|
* @param [in] len Length of the data. Unused.
|
|
* @return 1 always.
|
|
*/
|
|
static int test_ssl_hs_quic_add_data(WOLFSSL* ssl,
|
|
WOLFSSL_ENCRYPTION_LEVEL level, const uint8_t* data, size_t len)
|
|
{
|
|
(void)ssl;
|
|
(void)level;
|
|
(void)data;
|
|
(void)len;
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* QUIC callback that reports the data as flushed without doing anything.
|
|
*
|
|
* @param [in] ssl SSL/TLS object. Unused.
|
|
* @return 1 always.
|
|
*/
|
|
static int test_ssl_hs_quic_flush(WOLFSSL* ssl)
|
|
{
|
|
(void)ssl;
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* QUIC callback that accepts an alert and does nothing with it.
|
|
*
|
|
* @param [in] ssl SSL/TLS object. Unused.
|
|
* @param [in] level Encryption level. Unused.
|
|
* @param [in] err Alert to send. Unused.
|
|
* @return 1 always.
|
|
*/
|
|
static int test_ssl_hs_quic_alert(WOLFSSL* ssl,
|
|
WOLFSSL_ENCRYPTION_LEVEL level, uint8_t err)
|
|
{
|
|
(void)ssl;
|
|
(void)level;
|
|
(void)err;
|
|
|
|
return 1;
|
|
}
|
|
|
|
static WOLFSSL_QUIC_METHOD test_ssl_hs_quic_method = {
|
|
test_ssl_hs_quic_secrets,
|
|
test_ssl_hs_quic_add_data,
|
|
test_ssl_hs_quic_flush,
|
|
test_ssl_hs_quic_alert
|
|
};
|
|
#endif
|
|
|
|
/* Test that wolfSSL_SSL_do_handshake() dispatches QUIC objects to the QUIC
|
|
* handshake rather than to connect or accept.
|
|
*
|
|
* @return TEST_SUCCESS on success.
|
|
*/
|
|
int test_wolfSSL_SSL_do_handshake_quic(void)
|
|
{
|
|
EXPECT_DECLS;
|
|
#if defined(WOLFSSL_QUIC) && defined(WOLFSSL_TLS13) && \
|
|
(defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA)) && \
|
|
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_TLS)
|
|
WOLFSSL_CTX* ctx = NULL;
|
|
WOLFSSL* ssl = NULL;
|
|
|
|
ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method()));
|
|
ExpectNotNull(ssl = wolfSSL_new(ctx));
|
|
|
|
/* Not a QUIC object yet. */
|
|
if (ssl != NULL) {
|
|
ExpectNull(ssl->quic.method);
|
|
}
|
|
|
|
ExpectIntEQ(wolfSSL_set_quic_method(ssl, &test_ssl_hs_quic_method),
|
|
WOLFSSL_SUCCESS);
|
|
if (ssl != NULL) {
|
|
ExpectNotNull(ssl->quic.method);
|
|
}
|
|
|
|
/* The QUIC handshake is attempted. With no transport parameters set and
|
|
* nothing to read it cannot complete, so only the dispatch is checked. */
|
|
ExpectIntNE(wolfSSL_SSL_do_handshake(ssl), WOLFSSL_SUCCESS);
|
|
|
|
wolfSSL_free(ssl);
|
|
wolfSSL_CTX_free(ctx);
|
|
#endif
|
|
return EXPECT_RESULT();
|
|
}
|
|
|
|
/* Test that wolfSSL_set_connect_state() discards server DH parameters.
|
|
*
|
|
* A client generates its own DH parameters, so any server ones are dropped.
|
|
* Parameters the object owns are freed; parameters merely borrowed from the
|
|
* context are only unlinked, since the context still owns them.
|
|
*
|
|
* @return TEST_SUCCESS on success.
|
|
*/
|
|
int test_wolfSSL_set_connect_state_dh(void)
|
|
{
|
|
EXPECT_DECLS;
|
|
#if (defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL)) \
|
|
&& !defined(NO_DH) && !defined(NO_WOLFSSL_SERVER) \
|
|
&& !defined(NO_WOLFSSL_CLIENT) && !defined(NO_FILESYSTEM) \
|
|
&& !defined(NO_CERTS) && !defined(NO_TLS) && !defined(NO_RSA) \
|
|
&& !defined(WOLFSSL_NO_TLS12) && \
|
|
defined(WOLFSSL_PEM_TO_DER)
|
|
WOLFSSL_CTX* ctx = NULL;
|
|
WOLFSSL* ssl = NULL;
|
|
WOLFSSL* ssl2 = NULL;
|
|
|
|
/* Parameters owned by the object are freed. */
|
|
ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_2_server_method()));
|
|
ExpectIntEQ(wolfSSL_CTX_use_certificate_file(ctx, svrCertFile,
|
|
WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
|
|
ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_file(ctx, svrKeyFile,
|
|
WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
|
|
ExpectNotNull(ssl = wolfSSL_new(ctx));
|
|
|
|
ExpectIntEQ(wolfSSL_SetTmpDH_file(ssl, dhParamFile,
|
|
WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
|
|
if (ssl != NULL) {
|
|
ExpectNotNull(ssl->buffers.serverDH_P.buffer);
|
|
ExpectNotNull(ssl->buffers.serverDH_G.buffer);
|
|
ExpectIntEQ(ssl->buffers.weOwnDH, 1);
|
|
}
|
|
|
|
wolfSSL_set_connect_state(ssl);
|
|
|
|
/* Freed and unlinked; the object is now a client. */
|
|
if (ssl != NULL) {
|
|
ExpectNull(ssl->buffers.serverDH_P.buffer);
|
|
ExpectNull(ssl->buffers.serverDH_G.buffer);
|
|
}
|
|
ExpectIntEQ(wolfSSL_is_server(ssl), 0);
|
|
|
|
wolfSSL_free(ssl);
|
|
ssl = NULL;
|
|
wolfSSL_CTX_free(ctx);
|
|
ctx = NULL;
|
|
|
|
/* Parameters borrowed from the context are left for the context to free. */
|
|
ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_2_server_method()));
|
|
ExpectIntEQ(wolfSSL_CTX_use_certificate_file(ctx, svrCertFile,
|
|
WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
|
|
ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_file(ctx, svrKeyFile,
|
|
WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
|
|
ExpectIntEQ(wolfSSL_CTX_SetTmpDH_file(ctx, dhParamFile,
|
|
WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
|
|
ExpectNotNull(ssl = wolfSSL_new(ctx));
|
|
|
|
/* Inherited from the context, so not owned here. */
|
|
if (ssl != NULL) {
|
|
ExpectPtrEq(ssl->buffers.serverDH_P.buffer, ctx->serverDH_P.buffer);
|
|
ExpectIntEQ(ssl->buffers.weOwnDH, 0);
|
|
}
|
|
|
|
wolfSSL_set_connect_state(ssl);
|
|
|
|
if (ssl != NULL) {
|
|
ExpectNull(ssl->buffers.serverDH_P.buffer);
|
|
ExpectNull(ssl->buffers.serverDH_G.buffer);
|
|
}
|
|
/* The context kept its own copy, so it can still be used. */
|
|
if (ctx != NULL) {
|
|
ExpectNotNull(ctx->serverDH_P.buffer);
|
|
ExpectNotNull(ctx->serverDH_G.buffer);
|
|
}
|
|
ExpectNotNull(ssl2 = wolfSSL_new(ctx));
|
|
if (ssl2 != NULL) {
|
|
ExpectPtrEq(ssl2->buffers.serverDH_P.buffer, ctx->serverDH_P.buffer);
|
|
}
|
|
|
|
wolfSSL_free(ssl2);
|
|
wolfSSL_free(ssl);
|
|
wolfSSL_CTX_free(ctx);
|
|
#endif
|
|
return EXPECT_RESULT();
|
|
}
|
|
|
|
/* The helpers below only install I/O callbacks, so they need nothing beyond
|
|
* TLS 1.2 itself. The guard is nevertheless the union of their six callers'
|
|
* guards, so the block is neither compiled without a caller nor missing when
|
|
* one is present. The first term covers the five callers that drive a
|
|
* handshake with real credentials; the second covers the memio caller, which
|
|
* runs without RSA when raw public keys are enabled. */
|
|
#if !defined(NO_TLS) && !defined(WOLFSSL_NO_TLS12) && \
|
|
((!defined(NO_CERTS) && !defined(NO_FILESYSTEM) && !defined(NO_RSA) && \
|
|
defined(WOLFSSL_PEM_TO_DER)) || \
|
|
(defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
|
|
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)))
|
|
/* Transport send callback that always fails.
|
|
*
|
|
* Makes every handshake message send fail so that the error handling of each
|
|
* step of wolfSSL_connect()/wolfSSL_accept() can be reached.
|
|
*
|
|
* @param [in] ssl SSL/TLS object. Unused.
|
|
* @param [in] buf Data to send. Unused.
|
|
* @param [in] sz Length of data. Unused.
|
|
* @param [in] ctx I/O context. Unused.
|
|
* @return WOLFSSL_CBIO_ERR_GENERAL always.
|
|
*/
|
|
static int test_ssl_hs_send_fail(WOLFSSL* ssl, char* buf, int sz, void* ctx)
|
|
{
|
|
(void)ssl;
|
|
(void)buf;
|
|
(void)sz;
|
|
(void)ctx;
|
|
|
|
return WOLFSSL_CBIO_ERR_GENERAL;
|
|
}
|
|
|
|
#if !defined(NO_CERTS) && !defined(NO_FILESYSTEM) && !defined(NO_RSA) && \
|
|
defined(WOLFSSL_PEM_TO_DER)
|
|
/* Fail every send, recording the content type of the first record offered.
|
|
*
|
|
* The first byte of a TLS record is its content type, so this reports what
|
|
* the object tried to send first: 'alert' when a pending alert was retried,
|
|
* 'handshake' when it went straight on with the handshake instead. Without
|
|
* this the two are indistinguishable - both fail the send and both record
|
|
* SOCKET_ERROR_E.
|
|
*
|
|
* @param [in] ssl SSL/TLS object. Unused.
|
|
* @param [in] buf Record being sent.
|
|
* @param [in] sz Length of buf in bytes.
|
|
* @param [in, out] ctx int holding the first content type seen. Must be set
|
|
* to a value no content type uses before the call.
|
|
* @return WOLFSSL_CBIO_ERR_GENERAL always.
|
|
*/
|
|
static int test_ssl_hs_send_fail_record(WOLFSSL* ssl, char* buf, int sz,
|
|
void* ctx)
|
|
{
|
|
int* first = (int*)ctx;
|
|
|
|
(void)ssl;
|
|
|
|
if ((first != NULL) && (*first < 0) && (sz > 0)) {
|
|
*first = (int)(unsigned char)buf[0];
|
|
}
|
|
|
|
return WOLFSSL_CBIO_ERR_GENERAL;
|
|
}
|
|
#endif /* !NO_CERTS && !NO_FILESYSTEM && !NO_RSA && WOLFSSL_PEM_TO_DER */
|
|
|
|
/* Transport receive callback that always fails.
|
|
*
|
|
* @param [in] ssl SSL/TLS object. Unused.
|
|
* @param [in] buf Buffer to fill. Unused.
|
|
* @param [in] sz Size of buffer. Unused.
|
|
* @param [in] ctx I/O context. Unused.
|
|
* @return WOLFSSL_CBIO_ERR_GENERAL always.
|
|
*/
|
|
static int test_ssl_hs_recv_fail(WOLFSSL* ssl, char* buf, int sz, void* ctx)
|
|
{
|
|
(void)ssl;
|
|
(void)buf;
|
|
(void)sz;
|
|
(void)ctx;
|
|
|
|
return WOLFSSL_CBIO_ERR_GENERAL;
|
|
}
|
|
|
|
/* Require server credentials so that the checks in wolfSSL_accept() are made.
|
|
*
|
|
* Anonymous cipher suites are available by default in some builds and they let
|
|
* a server run without a certificate, which skips the credential checks.
|
|
*
|
|
* Only used by the tests that need server credentials, so it is guarded to
|
|
* match them rather than the callbacks above.
|
|
*
|
|
* @param [in, out] ssl SSL/TLS object.
|
|
*/
|
|
#if !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) && \
|
|
defined(WOLFSSL_PEM_TO_DER) && !defined(NO_CERTS) && \
|
|
!defined(NO_FILESYSTEM) && !defined(NO_RSA)
|
|
static void test_ssl_hs_need_creds(WOLFSSL* ssl)
|
|
{
|
|
if (ssl != NULL) {
|
|
#ifdef HAVE_ANON
|
|
ssl->options.useAnon = 0;
|
|
#endif
|
|
#ifndef NO_PSK
|
|
ssl->options.havePSK = 0;
|
|
#endif
|
|
#ifdef WOLFSSL_MULTICAST
|
|
ssl->options.haveMcast = 0;
|
|
#endif
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/* Replace the transport of an object with one that always fails.
|
|
*
|
|
* Lets a handshake step be driven to its error handling without a peer and
|
|
* without blocking on a socket.
|
|
*
|
|
* @param [in, out] ssl SSL/TLS object.
|
|
*/
|
|
static void test_ssl_hs_break_io(WOLFSSL* ssl)
|
|
{
|
|
if (ssl != NULL) {
|
|
wolfSSL_SSLSetIOSend(ssl, test_ssl_hs_send_fail);
|
|
wolfSSL_SSLSetIORecv(ssl, test_ssl_hs_recv_fail);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/* Test the argument and side checks of wolfSSL_connect().
|
|
*
|
|
* @return TEST_SUCCESS on success.
|
|
*/
|
|
int test_wolfSSL_connect_bad_args(void)
|
|
{
|
|
EXPECT_DECLS;
|
|
#if !defined(NO_TLS) && !defined(NO_WOLFSSL_CLIENT) && \
|
|
!defined(NO_WOLFSSL_SERVER) && !defined(WOLFSSL_NO_TLS12) && \
|
|
!defined(NO_CERTS) && !defined(NO_FILESYSTEM) && !defined(NO_RSA) && \
|
|
defined(WOLFSSL_PEM_TO_DER)
|
|
WOLFSSL_CTX* ctx = NULL;
|
|
WOLFSSL* ssl = NULL;
|
|
|
|
/* A NULL object is rejected. */
|
|
ExpectIntEQ(wolfSSL_connect(NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
|
|
|
|
/* Connecting with a server object is a side error. Credentials are loaded
|
|
* because a server object cannot be created without them when there are no
|
|
* anonymous cipher suites. */
|
|
ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_2_server_method()));
|
|
ExpectIntEQ(wolfSSL_CTX_use_certificate_file(ctx, svrCertFile,
|
|
WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
|
|
ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_file(ctx, svrKeyFile,
|
|
WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
|
|
ExpectNotNull(ssl = wolfSSL_new(ctx));
|
|
test_ssl_hs_break_io(ssl);
|
|
ExpectIntEQ(wolfSSL_connect(ssl), WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR));
|
|
ExpectIntEQ(wolfSSL_get_error(ssl, 0), WC_NO_ERR_TRACE(SIDE_ERROR));
|
|
wolfSSL_free(ssl);
|
|
ssl = NULL;
|
|
wolfSSL_CTX_free(ctx);
|
|
ctx = NULL;
|
|
|
|
/* An unrecognized connect state is rejected. */
|
|
ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_2_client_method()));
|
|
ExpectNotNull(ssl = wolfSSL_new(ctx));
|
|
test_ssl_hs_break_io(ssl);
|
|
if (ssl != NULL) {
|
|
ssl->options.connectState = 0x7f;
|
|
ExpectIntEQ(wolfSSL_connect(ssl), WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR));
|
|
}
|
|
|
|
wolfSSL_free(ssl);
|
|
wolfSSL_CTX_free(ctx);
|
|
#endif
|
|
return EXPECT_RESULT();
|
|
}
|
|
|
|
/* Test the argument, side and credential checks of wolfSSL_accept().
|
|
*
|
|
* A server needs both a certificate and a private key unless a certificate
|
|
* setup callback is installed to supply them later.
|
|
*
|
|
* @return TEST_SUCCESS on success.
|
|
*/
|
|
int test_wolfSSL_accept_bad_args(void)
|
|
{
|
|
EXPECT_DECLS;
|
|
#if !defined(NO_TLS) && !defined(NO_WOLFSSL_CLIENT) && \
|
|
!defined(NO_WOLFSSL_SERVER) && !defined(NO_CERTS) && \
|
|
!defined(NO_FILESYSTEM) && !defined(NO_RSA) && !defined(WOLFSSL_NO_TLS12) \
|
|
&& defined(WOLFSSL_PEM_TO_DER)
|
|
WOLFSSL_CTX* ctx = NULL;
|
|
WOLFSSL* ssl = NULL;
|
|
|
|
/* A NULL object is rejected. */
|
|
ExpectIntEQ(wolfSSL_accept(NULL), WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR));
|
|
|
|
/* Accepting with a client object is a side error. */
|
|
ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_2_client_method()));
|
|
ExpectNotNull(ssl = wolfSSL_new(ctx));
|
|
test_ssl_hs_break_io(ssl);
|
|
ExpectIntEQ(wolfSSL_accept(ssl), WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR));
|
|
ExpectIntEQ(wolfSSL_get_error(ssl, 0), WC_NO_ERR_TRACE(SIDE_ERROR));
|
|
wolfSSL_free(ssl);
|
|
ssl = NULL;
|
|
wolfSSL_CTX_free(ctx);
|
|
ctx = NULL;
|
|
|
|
/* No certificate. It is hidden from the SSL object rather than left
|
|
* unloaded, because a server object cannot be created without credentials
|
|
* when there are no anonymous cipher suites. The pointer is put back
|
|
* afterwards so that the object still disposes of it: depending on the
|
|
* build the object owns this buffer rather than the context. */
|
|
ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_2_server_method()));
|
|
ExpectIntEQ(wolfSSL_CTX_use_certificate_file(ctx, svrCertFile,
|
|
WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
|
|
ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_file(ctx, svrKeyFile,
|
|
WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
|
|
ExpectNotNull(ssl = wolfSSL_new(ctx));
|
|
test_ssl_hs_break_io(ssl);
|
|
test_ssl_hs_need_creds(ssl);
|
|
if (ssl != NULL) {
|
|
DerBuffer* savedCert = ssl->buffers.certificate;
|
|
|
|
ssl->buffers.certificate = NULL;
|
|
ExpectIntEQ(wolfSSL_accept(ssl), WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR));
|
|
ExpectIntEQ(wolfSSL_get_error(ssl, 0), WC_NO_ERR_TRACE(NO_PRIVATE_KEY));
|
|
ssl->buffers.certificate = savedCert;
|
|
}
|
|
wolfSSL_free(ssl);
|
|
ssl = NULL;
|
|
wolfSSL_CTX_free(ctx);
|
|
ctx = NULL;
|
|
|
|
/* Certificate present but no private key. The key is dropped from the SSL
|
|
* object rather than left unloaded so that the certificate check above is
|
|
* passed first; the context still owns the real key. */
|
|
ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_2_server_method()));
|
|
ExpectIntEQ(wolfSSL_CTX_use_certificate_file(ctx, svrCertFile,
|
|
WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
|
|
ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_file(ctx, svrKeyFile,
|
|
WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
|
|
ExpectNotNull(ssl = wolfSSL_new(ctx));
|
|
test_ssl_hs_break_io(ssl);
|
|
test_ssl_hs_need_creds(ssl);
|
|
if (ssl != NULL) {
|
|
DerBuffer* savedKey = ssl->buffers.key;
|
|
int savedDevId = ssl->devId;
|
|
|
|
ExpectNotNull(ssl->buffers.certificate);
|
|
ssl->buffers.key = NULL;
|
|
ssl->devId = INVALID_DEVID;
|
|
ExpectIntEQ(wolfSSL_accept(ssl), WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR));
|
|
ExpectIntEQ(wolfSSL_get_error(ssl, 0), WC_NO_ERR_TRACE(NO_PRIVATE_KEY));
|
|
/* Put both back so the object disposes of it as it would have. */
|
|
ssl->buffers.key = savedKey;
|
|
ssl->devId = savedDevId;
|
|
}
|
|
wolfSSL_free(ssl);
|
|
ssl = NULL;
|
|
wolfSSL_CTX_free(ctx);
|
|
ctx = NULL;
|
|
|
|
/* An unrecognized accept state is rejected. Credentials are loaded so the
|
|
* checks above are passed. */
|
|
ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_2_server_method()));
|
|
ExpectIntEQ(wolfSSL_CTX_use_certificate_file(ctx, svrCertFile,
|
|
WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
|
|
ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_file(ctx, svrKeyFile,
|
|
WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
|
|
ExpectNotNull(ssl = wolfSSL_new(ctx));
|
|
test_ssl_hs_break_io(ssl);
|
|
if (ssl != NULL) {
|
|
ssl->options.acceptState = 0x7f;
|
|
ExpectIntEQ(wolfSSL_accept(ssl), WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR));
|
|
}
|
|
|
|
wolfSSL_free(ssl);
|
|
wolfSSL_CTX_free(ctx);
|
|
#endif
|
|
return EXPECT_RESULT();
|
|
}
|
|
|
|
/* Test that each step of wolfSSL_connect() copes with a failing transport.
|
|
*
|
|
* The object is placed in each connect state in turn with a transport that
|
|
* always fails, so that every step is entered. The call must reach a
|
|
* definite outcome rather than hang; which error arm ran is not
|
|
* observable from here. The object is
|
|
* discarded after each attempt because a failed handshake is not resumable.
|
|
*
|
|
* @return TEST_SUCCESS on success.
|
|
*/
|
|
int test_wolfSSL_connect_step_failures(void)
|
|
{
|
|
EXPECT_DECLS;
|
|
#if !defined(NO_TLS) && !defined(NO_WOLFSSL_CLIENT) && \
|
|
!defined(WOLFSSL_NO_TLS12) && !defined(NO_CERTS) && \
|
|
!defined(NO_FILESYSTEM) && !defined(NO_RSA) && \
|
|
defined(WOLFSSL_PEM_TO_DER)
|
|
/* Each connect state, paired with whether it still has something to send.
|
|
* One that does must fail on the broken transport; one that does not may
|
|
* report success. Pairing them here rather than splitting the list at an
|
|
* index means adding a state forces its expectation to be written down,
|
|
* instead of silently shifting the boundary for its neighbours. */
|
|
static const struct {
|
|
int state;
|
|
int sends;
|
|
} states[] = {
|
|
{ CONNECT_BEGIN, 1 },
|
|
{ CLIENT_HELLO_SENT, 1 },
|
|
{ HELLO_AGAIN, 1 },
|
|
{ HELLO_AGAIN_REPLY, 1 },
|
|
{ FIRST_REPLY_DONE, 1 },
|
|
{ FIRST_REPLY_FIRST, 1 },
|
|
{ FIRST_REPLY_SECOND, 1 },
|
|
{ FIRST_REPLY_THIRD, 1 },
|
|
{ FIRST_REPLY_FOURTH, 1 },
|
|
{ FINISHED_DONE, 1 },
|
|
{ SECOND_REPLY_DONE, 0 }
|
|
};
|
|
int i;
|
|
|
|
for (i = 0; i < (int)(sizeof(states) / sizeof(states[0])); i++) {
|
|
WOLFSSL_CTX* ctx = NULL;
|
|
WOLFSSL* ssl = NULL;
|
|
int ret = 0;
|
|
|
|
ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_2_client_method()));
|
|
ExpectIntEQ(wolfSSL_CTX_load_verify_locations(ctx, caCertFile, NULL),
|
|
WOLFSSL_SUCCESS);
|
|
ExpectNotNull(ssl = wolfSSL_new(ctx));
|
|
test_ssl_hs_break_io(ssl);
|
|
|
|
if (ssl != NULL) {
|
|
/* Pretend the handshake reached this step, and that the peer was
|
|
* authenticated so the fail-safe check is passed. A client
|
|
* certificate is requested so the certificate steps are taken. */
|
|
ssl->options.connectState = (byte)states[i].state;
|
|
ssl->options.peerAuthGood = 1;
|
|
ssl->options.sendVerify = SEND_CERT;
|
|
ssl->options.resuming = 0;
|
|
|
|
ret = wolfSSL_connect(ssl);
|
|
|
|
/* A step that sends must fail on the broken transport; only a
|
|
* state with nothing left to send may report success. Both arms
|
|
* are cast as they come from different enumerations, which a C++
|
|
* compiler will not mix in a conditional. */
|
|
ExpectIntEQ(ret, states[i].sends ?
|
|
(int)WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR) :
|
|
(int)WOLFSSL_SUCCESS);
|
|
}
|
|
|
|
wolfSSL_free(ssl);
|
|
wolfSSL_CTX_free(ctx);
|
|
}
|
|
#endif
|
|
return EXPECT_RESULT();
|
|
}
|
|
|
|
/* Test that each step of wolfSSL_accept() copes with a failing transport.
|
|
*
|
|
* The object is placed in each accept state in turn with a transport that
|
|
* always fails, so that every step is entered. The call must reach a
|
|
* definite outcome rather than hang; which error arm ran is not
|
|
* observable from here.
|
|
*
|
|
* @return TEST_SUCCESS on success.
|
|
*/
|
|
int test_wolfSSL_accept_step_failures(void)
|
|
{
|
|
EXPECT_DECLS;
|
|
#if !defined(NO_TLS) && !defined(NO_WOLFSSL_SERVER) && \
|
|
!defined(WOLFSSL_NO_TLS12) && !defined(NO_CERTS) && \
|
|
!defined(NO_FILESYSTEM) && !defined(NO_RSA) && \
|
|
defined(WOLFSSL_PEM_TO_DER)
|
|
/* As in test_wolfSSL_connect_step_failures(): each state paired with
|
|
* whether it still has something to send, so that adding one cannot
|
|
* silently change what is expected of another. Only states the TLS 1.2
|
|
* accept switch has a case for are listed - ACCEPT_HELLO_RETRY_REQUEST_DONE
|
|
* and CERT_VERIFY_SENT belong to the TLS 1.3 machine and would exercise
|
|
* the unrecognized-state path, which test_wolfSSL_accept_bad_args covers
|
|
* directly. */
|
|
static const struct {
|
|
int state;
|
|
int sends;
|
|
} states[] = {
|
|
{ ACCEPT_BEGIN, 1 },
|
|
/* These two have a case only when their feature is built in.
|
|
* Without it the state is unrecognized, which returns the same
|
|
* value for a different reason, so they are left out rather than
|
|
* appearing to cover a step that is not there. */
|
|
#ifdef HAVE_SECURE_RENEGOTIATION
|
|
{ ACCEPT_BEGIN_RENEG, 1 },
|
|
#endif
|
|
#ifdef WOLFSSL_TLS13
|
|
{ ACCEPT_CLIENT_HELLO_DONE, 1 },
|
|
#endif
|
|
{ ACCEPT_FIRST_REPLY_DONE, 1 },
|
|
{ SERVER_HELLO_SENT, 1 },
|
|
{ CERT_SENT, 1 },
|
|
{ CERT_STATUS_SENT, 1 },
|
|
{ KEY_EXCHANGE_SENT, 1 },
|
|
{ CERT_REQ_SENT, 1 },
|
|
{ SERVER_HELLO_DONE, 1 },
|
|
{ ACCEPT_SECOND_REPLY_DONE, 1 },
|
|
{ TICKET_SENT, 1 },
|
|
{ CHANGE_CIPHER_SENT, 1 },
|
|
{ ACCEPT_FINISHED_DONE, 0 },
|
|
{ ACCEPT_THIRD_REPLY_DONE, 0 }
|
|
};
|
|
int i;
|
|
|
|
for (i = 0; i < (int)(sizeof(states) / sizeof(states[0])); i++) {
|
|
WOLFSSL_CTX* ctx = NULL;
|
|
WOLFSSL* ssl = NULL;
|
|
int ret = 0;
|
|
|
|
ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_2_server_method()));
|
|
ExpectIntEQ(wolfSSL_CTX_use_certificate_file(ctx, svrCertFile,
|
|
WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
|
|
ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_file(ctx, svrKeyFile,
|
|
WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
|
|
ExpectNotNull(ssl = wolfSSL_new(ctx));
|
|
test_ssl_hs_break_io(ssl);
|
|
|
|
if (ssl != NULL) {
|
|
ssl->options.acceptState = (byte)states[i].state;
|
|
/* Ask for a client certificate so the certificate request and
|
|
* verify steps are taken. */
|
|
ssl->options.verifyPeer = 1;
|
|
ssl->options.sendVerify = SEND_CERT;
|
|
/* Claim the client was authenticated so the fail-safe checks are
|
|
* passed and the steps after them are reached. */
|
|
ssl->options.peerAuthGood = 1;
|
|
#ifdef HAVE_SESSION_TICKET
|
|
/* Ask for a session ticket so that step is taken too. */
|
|
ssl->options.createTicket = 1;
|
|
ssl->options.noTicketTls12 = 0;
|
|
#endif
|
|
|
|
ret = wolfSSL_accept(ssl);
|
|
|
|
/* A step that sends fails on the broken transport. The states at
|
|
* the end of the handshake have nothing left to send and so
|
|
* report success. Both arms are cast as they come from different
|
|
* enumerations, which a C++ compiler will not mix in a
|
|
* conditional. */
|
|
ExpectIntEQ(ret, states[i].sends ?
|
|
(int)WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR) :
|
|
(int)WOLFSSL_SUCCESS);
|
|
}
|
|
|
|
wolfSSL_free(ssl);
|
|
wolfSSL_CTX_free(ctx);
|
|
}
|
|
#endif
|
|
return EXPECT_RESULT();
|
|
}
|
|
|
|
/* Test that a failure to flush the output buffer is reported.
|
|
*
|
|
* A send that reports "want write" leaves the message in the output buffer.
|
|
* Failing the send on the next call makes the flush at the start of
|
|
* wolfSSL_connect() and wolfSSL_accept() fail.
|
|
*
|
|
* @return TEST_SUCCESS on success.
|
|
*/
|
|
int test_wolfSSL_hs_send_buffered_fail(void)
|
|
{
|
|
EXPECT_DECLS;
|
|
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && !defined(NO_TLS) && \
|
|
!defined(WOLFSSL_NO_TLS12) && !defined(NO_WOLFSSL_CLIENT) && \
|
|
!defined(NO_WOLFSSL_SERVER)
|
|
WOLFSSL_CTX* ctx_c = NULL;
|
|
WOLFSSL_CTX* ctx_s = NULL;
|
|
WOLFSSL* ssl_c = NULL;
|
|
WOLFSSL* ssl_s = NULL;
|
|
struct test_memio_ctx test_ctx;
|
|
|
|
/* Client: the ClientHello is left unsent. */
|
|
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
|
|
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
|
|
wolfTLSv1_2_client_method, wolfTLSv1_2_server_method), 0);
|
|
test_memio_simulate_want_write(&test_ctx, 1, 1);
|
|
ExpectIntEQ(wolfSSL_connect(ssl_c), WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR));
|
|
ExpectIntEQ(wolfSSL_get_error(ssl_c, 0), WOLFSSL_ERROR_WANT_WRITE);
|
|
if (ssl_c != NULL) {
|
|
ExpectIntGT(ssl_c->buffers.outputBuffer.length, 0);
|
|
}
|
|
/* The retry now fails outright. */
|
|
test_ssl_hs_break_io(ssl_c);
|
|
ExpectIntEQ(wolfSSL_connect(ssl_c), WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR));
|
|
ExpectIntEQ(wolfSSL_get_error(ssl_c, 0), WC_NO_ERR_TRACE(SOCKET_ERROR_E));
|
|
|
|
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;
|
|
|
|
/* Server: the ClientHello is delivered so the server has a reply to send,
|
|
* and that reply is left unsent. */
|
|
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
|
|
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
|
|
wolfTLSv1_2_client_method, wolfTLSv1_2_server_method), 0);
|
|
ExpectIntEQ(wolfSSL_connect(ssl_c), WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR));
|
|
ExpectIntEQ(wolfSSL_get_error(ssl_c, 0), WOLFSSL_ERROR_WANT_READ);
|
|
test_memio_simulate_want_write(&test_ctx, 0, 1);
|
|
ExpectIntEQ(wolfSSL_accept(ssl_s), WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR));
|
|
ExpectIntEQ(wolfSSL_get_error(ssl_s, 0), WOLFSSL_ERROR_WANT_WRITE);
|
|
if (ssl_s != NULL) {
|
|
ExpectIntGT(ssl_s->buffers.outputBuffer.length, 0);
|
|
}
|
|
test_ssl_hs_break_io(ssl_s);
|
|
ExpectIntEQ(wolfSSL_accept(ssl_s), WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR));
|
|
ExpectIntEQ(wolfSSL_get_error(ssl_s, 0), WC_NO_ERR_TRACE(SOCKET_ERROR_E));
|
|
|
|
wolfSSL_free(ssl_c);
|
|
wolfSSL_free(ssl_s);
|
|
wolfSSL_CTX_free(ctx_c);
|
|
wolfSSL_CTX_free(ctx_s);
|
|
#endif
|
|
return EXPECT_RESULT();
|
|
}
|
|
|
|
/* Test that flushing a buffered message advances the handshake state.
|
|
*
|
|
* A send that reports "want write" leaves the message in the output buffer and
|
|
* the state where it was, before the send. The flush at the start of the next
|
|
* wolfSSL_connect() or wolfSSL_accept() gets the message out and steps the
|
|
* state past that send, so the message is not built and sent a second time.
|
|
* This is the success side of the failures covered by
|
|
* test_wolfSSL_hs_send_buffered_fail().
|
|
*
|
|
* @return TEST_SUCCESS on success.
|
|
*/
|
|
int test_wolfSSL_hs_send_buffered_advance(void)
|
|
{
|
|
EXPECT_DECLS;
|
|
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && !defined(NO_TLS) && \
|
|
!defined(WOLFSSL_NO_TLS12) && !defined(NO_WOLFSSL_CLIENT) && \
|
|
!defined(NO_WOLFSSL_SERVER)
|
|
WOLFSSL_CTX* ctx_c = NULL;
|
|
WOLFSSL_CTX* ctx_s = NULL;
|
|
WOLFSSL* ssl_c = NULL;
|
|
WOLFSSL* ssl_s = NULL;
|
|
struct test_memio_ctx test_ctx;
|
|
int acceptState = -1;
|
|
|
|
/* Client: the ClientHello is left unsent. */
|
|
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
|
|
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
|
|
wolfTLSv1_2_client_method, wolfTLSv1_2_server_method), 0);
|
|
test_memio_simulate_want_write(&test_ctx, 1, 1);
|
|
ExpectIntEQ(wolfSSL_connect(ssl_c), WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR));
|
|
ExpectIntEQ(wolfSSL_get_error(ssl_c, 0), WOLFSSL_ERROR_WANT_WRITE);
|
|
if (ssl_c != NULL) {
|
|
ExpectIntGT(ssl_c->buffers.outputBuffer.length, 0);
|
|
/* The send did not complete, so the state is still before it. */
|
|
ExpectIntEQ(ssl_c->options.connectState, CONNECT_BEGIN);
|
|
}
|
|
/* Nothing reached the peer. */
|
|
ExpectIntEQ(test_ctx.s_msg_count, 0);
|
|
|
|
/* With the transport working again the flush sends what was buffered and
|
|
* steps the state past the send. */
|
|
test_memio_simulate_want_write(&test_ctx, 1, 0);
|
|
ExpectIntEQ(wolfSSL_connect(ssl_c), WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR));
|
|
ExpectIntEQ(wolfSSL_get_error(ssl_c, 0), WOLFSSL_ERROR_WANT_READ);
|
|
if (ssl_c != NULL) {
|
|
ExpectIntEQ(ssl_c->options.connectState, CLIENT_HELLO_SENT);
|
|
ExpectIntEQ(ssl_c->buffers.outputBuffer.length, 0);
|
|
}
|
|
/* Exactly one ClientHello was written: the state moved past the send, so
|
|
* the message was not built again. Without the advance there would be
|
|
* two. */
|
|
ExpectIntEQ(test_ctx.s_msg_count, 1);
|
|
|
|
/* The handshake carries on from there. */
|
|
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;
|
|
|
|
/* Server: the ClientHello is delivered so the server has a reply to send,
|
|
* and that reply is left unsent. The accept side is the one where the
|
|
* state to advance is chosen before the flush rather than after it. */
|
|
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
|
|
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
|
|
wolfTLSv1_2_client_method, wolfTLSv1_2_server_method), 0);
|
|
ExpectIntEQ(wolfSSL_connect(ssl_c), WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR));
|
|
ExpectIntEQ(wolfSSL_get_error(ssl_c, 0), WOLFSSL_ERROR_WANT_READ);
|
|
test_memio_simulate_want_write(&test_ctx, 0, 1);
|
|
ExpectIntEQ(wolfSSL_accept(ssl_s), WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR));
|
|
ExpectIntEQ(wolfSSL_get_error(ssl_s, 0), WOLFSSL_ERROR_WANT_WRITE);
|
|
if (ssl_s != NULL) {
|
|
ExpectIntGT(ssl_s->buffers.outputBuffer.length, 0);
|
|
/* The send did not complete, so the state is still before it. How
|
|
* far into its flight the server got before reaching the transport
|
|
* depends on the build, so the state is recorded rather than
|
|
* named. */
|
|
acceptState = ssl_s->options.acceptState;
|
|
}
|
|
ExpectIntEQ(test_ctx.c_msg_count, 0);
|
|
|
|
/* The flush sends what was buffered and steps the state past that send.
|
|
* The rest of the flight follows, and the server then waits on the
|
|
* client. */
|
|
test_memio_simulate_want_write(&test_ctx, 0, 0);
|
|
ExpectIntEQ(wolfSSL_accept(ssl_s), WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR));
|
|
ExpectIntEQ(wolfSSL_get_error(ssl_s, 0), WOLFSSL_ERROR_WANT_READ);
|
|
if (ssl_s != NULL) {
|
|
ExpectIntGT(ssl_s->options.acceptState, acceptState);
|
|
}
|
|
|
|
/* Not advancing would rebuild and resend the message the flush had
|
|
* already sent, leaving the client with a duplicate - which is what
|
|
* completing the handshake here rules out. */
|
|
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);
|
|
#endif
|
|
return EXPECT_RESULT();
|
|
}
|
|
|
|
#if defined(WOLFSSL_CALLBACKS) && !defined(NO_WOLFSSL_CLIENT) && \
|
|
!defined(NO_TLS) && !defined(WOLFSSL_NO_TLS12)
|
|
/* Timeout callback that does nothing.
|
|
*
|
|
* Supplying one is what makes wolfSSL_ex_wrapper() set up the timer.
|
|
*
|
|
* @param [in] info Timeout information. Unused.
|
|
* @return 0 always.
|
|
*/
|
|
static int test_ssl_hs_to_cb(TimeoutInfo* info)
|
|
{
|
|
(void)info;
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
/* Test that connecting with no side established is reported as a failure.
|
|
*
|
|
* wolfSSL_ex_wrapper() dispatches on the side and leaves its result alone
|
|
* when neither the client nor the server branch runs, so the failure it was
|
|
* seeded with has to survive the timer setup that precedes the dispatch.
|
|
*
|
|
* @return TEST_SUCCESS on success.
|
|
*/
|
|
int test_wolfSSL_connect_ex_no_side(void)
|
|
{
|
|
EXPECT_DECLS;
|
|
#if defined(WOLFSSL_CALLBACKS) && !defined(NO_WOLFSSL_CLIENT) && \
|
|
!defined(NO_TLS) && !defined(WOLFSSL_NO_TLS12)
|
|
WOLFSSL_CTX* ctx = NULL;
|
|
WOLFSSL* ssl = NULL;
|
|
WOLFSSL_TIMEVAL timeout;
|
|
|
|
/* Long enough that it cannot fire while the test runs. */
|
|
timeout.tv_sec = 60;
|
|
timeout.tv_usec = 0;
|
|
|
|
ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_2_client_method()));
|
|
ExpectNotNull(ssl = wolfSSL_new(ctx));
|
|
if (ssl != NULL) {
|
|
/* With a timeout callback the timer is set up first. Its success must
|
|
* not be mistaken for the handshake's. */
|
|
ssl->options.side = WOLFSSL_NEITHER_END;
|
|
ExpectIntEQ(wolfSSL_connect_ex(ssl, NULL, test_ssl_hs_to_cb, timeout),
|
|
WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR));
|
|
/* And without one, where no timer is set up at all. */
|
|
ssl->options.side = WOLFSSL_NEITHER_END;
|
|
ExpectIntEQ(wolfSSL_connect_ex(ssl, NULL, NULL, timeout),
|
|
WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR));
|
|
}
|
|
|
|
wolfSSL_free(ssl);
|
|
wolfSSL_CTX_free(ctx);
|
|
#endif
|
|
return EXPECT_RESULT();
|
|
}
|
|
|
|
/* Test that a failure to send a pending alert is reported.
|
|
*
|
|
* An alert that could not be sent earlier is retried at the start of
|
|
* wolfSSL_connect() and wolfSSL_accept().
|
|
*
|
|
* @return TEST_SUCCESS on success.
|
|
*/
|
|
int test_wolfSSL_hs_retry_alert_fail(void)
|
|
{
|
|
EXPECT_DECLS;
|
|
#if !defined(NO_TLS) && !defined(WOLFSSL_NO_TLS12) && !defined(NO_CERTS) && \
|
|
!defined(NO_FILESYSTEM) && !defined(NO_RSA) && \
|
|
defined(WOLFSSL_PEM_TO_DER)
|
|
WOLFSSL_CTX* ctx = NULL;
|
|
WOLFSSL* ssl = NULL;
|
|
int firstType;
|
|
|
|
#ifndef NO_WOLFSSL_CLIENT
|
|
ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_2_client_method()));
|
|
ExpectIntEQ(wolfSSL_CTX_load_verify_locations(ctx, caCertFile, NULL),
|
|
WOLFSSL_SUCCESS);
|
|
ExpectNotNull(ssl = wolfSSL_new(ctx));
|
|
test_ssl_hs_break_io(ssl);
|
|
firstType = -1;
|
|
wolfSSL_SSLSetIOSend(ssl, test_ssl_hs_send_fail_record);
|
|
wolfSSL_SetIOWriteCtx(ssl, &firstType);
|
|
if (ssl != NULL) {
|
|
ssl->pendingAlert.code = unexpected_message;
|
|
ssl->pendingAlert.level = alert_fatal;
|
|
ExpectIntEQ(wolfSSL_connect(ssl), WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR));
|
|
ExpectIntEQ(wolfSSL_get_error(ssl, 0),
|
|
WC_NO_ERR_TRACE(SOCKET_ERROR_E));
|
|
/* The pending alert is what it tried to send, not a ClientHello.
|
|
* Both fail with SOCKET_ERROR_E, so only this separates them. */
|
|
ExpectIntEQ(firstType, alert);
|
|
}
|
|
wolfSSL_free(ssl);
|
|
ssl = NULL;
|
|
wolfSSL_CTX_free(ctx);
|
|
ctx = NULL;
|
|
#endif
|
|
|
|
#ifndef NO_WOLFSSL_SERVER
|
|
ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_2_server_method()));
|
|
ExpectIntEQ(wolfSSL_CTX_use_certificate_file(ctx, svrCertFile,
|
|
WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
|
|
ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_file(ctx, svrKeyFile,
|
|
WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
|
|
ExpectNotNull(ssl = wolfSSL_new(ctx));
|
|
test_ssl_hs_break_io(ssl);
|
|
firstType = -1;
|
|
wolfSSL_SSLSetIOSend(ssl, test_ssl_hs_send_fail_record);
|
|
wolfSSL_SetIOWriteCtx(ssl, &firstType);
|
|
if (ssl != NULL) {
|
|
ssl->pendingAlert.code = unexpected_message;
|
|
ssl->pendingAlert.level = alert_fatal;
|
|
ExpectIntEQ(wolfSSL_accept(ssl), WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR));
|
|
ExpectIntEQ(wolfSSL_get_error(ssl, 0),
|
|
WC_NO_ERR_TRACE(SOCKET_ERROR_E));
|
|
ExpectIntEQ(firstType, alert);
|
|
}
|
|
wolfSSL_free(ssl);
|
|
wolfSSL_CTX_free(ctx);
|
|
#endif
|
|
#endif
|
|
return EXPECT_RESULT();
|
|
}
|
|
|
|
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
|
|
!defined(NO_HANDSHAKE_DONE_CB) && !defined(NO_TLS) && \
|
|
!defined(WOLFSSL_NO_TLS12)
|
|
/* Handshake done callback that refuses to let the handshake complete.
|
|
*
|
|
* @param [in] ssl SSL object. Unused.
|
|
* @param [in] user_ctx User context. Unused.
|
|
* @return A negative value to stop the handshake.
|
|
*/
|
|
static int test_ssl_hs_done_cb_fail(WOLFSSL* ssl, void* user_ctx)
|
|
{
|
|
(void)ssl;
|
|
(void)user_ctx;
|
|
return -4242;
|
|
}
|
|
#endif
|
|
|
|
/* Test that a handshake done callback reporting an error stops the handshake.
|
|
*
|
|
* @return TEST_SUCCESS on success.
|
|
*/
|
|
int test_wolfSSL_hs_done_cb_error(void)
|
|
{
|
|
EXPECT_DECLS;
|
|
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
|
|
!defined(NO_HANDSHAKE_DONE_CB) && !defined(NO_TLS) && \
|
|
!defined(WOLFSSL_NO_TLS12)
|
|
int i;
|
|
|
|
/* Register the callback on the client and then on the server. */
|
|
for (i = 0; i < 2; i++) {
|
|
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,
|
|
wolfTLSv1_2_client_method, wolfTLSv1_2_server_method), 0);
|
|
ExpectIntEQ(wolfSSL_SetHsDoneCb((i == 0) ? ssl_c : ssl_s,
|
|
test_ssl_hs_done_cb_fail, NULL), WOLFSSL_SUCCESS);
|
|
|
|
/* The handshake cannot complete because the callback fails. */
|
|
ExpectIntNE(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
|
|
ExpectIntEQ(wolfSSL_get_error((i == 0) ? ssl_c : ssl_s, 0), -4242);
|
|
|
|
wolfSSL_free(ssl_c);
|
|
wolfSSL_free(ssl_s);
|
|
wolfSSL_CTX_free(ctx_c);
|
|
wolfSSL_CTX_free(ctx_s);
|
|
}
|
|
#endif
|
|
return EXPECT_RESULT();
|
|
}
|
|
|
|
#if defined(OPENSSL_EXTRA) && defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
|
|
!defined(NO_TLS) && !defined(WOLFSSL_NO_TLS12)
|
|
static int test_ssl_hs_info_calls_c = 0;
|
|
static int test_ssl_hs_info_calls_s = 0;
|
|
|
|
/* Information callback for the client, recording that it was called.
|
|
*
|
|
* @param [in] ssl SSL object. Unused.
|
|
* @param [in] type Type of event. Unused.
|
|
* @param [in] val Value associated with event. Unused.
|
|
*/
|
|
static void test_ssl_hs_info_cb_c(const WOLFSSL* ssl, int type, int val)
|
|
{
|
|
(void)ssl;
|
|
(void)type;
|
|
(void)val;
|
|
test_ssl_hs_info_calls_c++;
|
|
}
|
|
|
|
/* Information callback for the server, recording that it was called.
|
|
*
|
|
* @param [in] ssl SSL object. Unused.
|
|
* @param [in] type Type of event. Unused.
|
|
* @param [in] val Value associated with event. Unused.
|
|
*/
|
|
static void test_ssl_hs_info_cb_s(const WOLFSSL* ssl, int type, int val)
|
|
{
|
|
(void)ssl;
|
|
(void)type;
|
|
(void)val;
|
|
test_ssl_hs_info_calls_s++;
|
|
}
|
|
#endif
|
|
|
|
/* Test that the information callback is called when a handshake starts.
|
|
*
|
|
* @return TEST_SUCCESS on success.
|
|
*/
|
|
int test_wolfSSL_hs_info_cb(void)
|
|
{
|
|
EXPECT_DECLS;
|
|
#if defined(OPENSSL_EXTRA) && defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
|
|
!defined(NO_TLS) && !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;
|
|
|
|
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
|
|
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
|
|
wolfTLSv1_2_client_method, wolfTLSv1_2_server_method), 0);
|
|
|
|
test_ssl_hs_info_calls_c = 0;
|
|
test_ssl_hs_info_calls_s = 0;
|
|
wolfSSL_set_info_callback(ssl_c, test_ssl_hs_info_cb_c);
|
|
wolfSSL_set_info_callback(ssl_s, test_ssl_hs_info_cb_s);
|
|
|
|
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
|
|
|
|
/* Each side reported against its own callback. */
|
|
ExpectIntGT(test_ssl_hs_info_calls_c, 0);
|
|
ExpectIntGT(test_ssl_hs_info_calls_s, 0);
|
|
|
|
wolfSSL_free(ssl_c);
|
|
wolfSSL_free(ssl_s);
|
|
wolfSSL_CTX_free(ctx_c);
|
|
wolfSSL_CTX_free(ctx_s);
|
|
#endif
|
|
return EXPECT_RESULT();
|
|
}
|