Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions doc/dox_comments/header_files/ssl.h
Original file line number Diff line number Diff line change
Expand Up @@ -6348,6 +6348,59 @@ long wolfSSL_get_options(const WOLFSSL *s);
*/
long wolfSSL_set_tlsext_debug_arg(WOLFSSL *s, void *arg);

/*!
\ingroup Setup

\brief Callback type for the TLS extension debug callback.

Invoked once for every TLS extension received during the handshake,
in wire order, before the extension is processed.

\param ssl The WOLFSSL object receiving the extension.
\param client_server 1 if the WOLFSSL object is a client, 0 if a server.
\param type The extension type, e.g. TLSX_SERVER_NAME.
\param data The raw extension content (data after the 2-byte length).
\param len Length of the extension content in bytes.
\param arg The argument set with wolfSSL_set_tlsext_debug_arg().

Note that, unlike OpenSSL 3.x, the callback also reports unknown
(unregistered) extension types.
*/
typedef void (*WOLFSSL_TLSEXT_DEBUG_CB)(WOLFSSL* ssl, int client_server,
int type, const byte* data, int len, void* arg);

/*!
\ingroup Setup

\brief This is used to set the TLS extension debug callback on the
object.

The callback (type WOLFSSL_TLSEXT_DEBUG_CB) is invoked once for every
TLS extension received during the handshake, in wire order, before the
extension is processed. It reports the side of the connection, the
extension type, the raw extension content and the argument set with
wolfSSL_set_tlsext_debug_arg(). Passing a NULL callback disables it.

\return SSL_SUCCESS On successful setting of the callback.
\return SSL_FAILURE If a NULL ssl is passed in.

\param s WOLFSSL structure to set the callback in.
\param cb Callback to invoke for each received TLS extension, or NULL
to disable it.

_Example_
\code
WOLFSSL* ssl;
long ret;
// create ssl object
ret = wolfSSL_set_tlsext_debug_callback(ssl, my_tlsext_debug_cb);
// check ret value
\endcode

\sa wolfSSL_set_tlsext_debug_arg
*/
long wolfSSL_set_tlsext_debug_callback(WOLFSSL *s, WOLFSSL_TLSEXT_DEBUG_CB cb);

/*!
\ingroup openSSL

Expand Down
23 changes: 23 additions & 0 deletions src/ssl_api_ext.c
Original file line number Diff line number Diff line change
Expand Up @@ -1634,6 +1634,29 @@ long wolfSSL_set_tlsext_debug_arg(WOLFSSL* ssl, void *arg)

return ret;
}

/* Set the callback invoked for each TLS extension received during the
* handshake.
*
* @param [in, out] ssl SSL/TLS object.
* @param [in] cb Debug callback, or NULL to disable.
* @return WOLFSSL_SUCCESS on success.
* @return WOLFSSL_FAILURE when ssl is NULL.
*/
long wolfSSL_set_tlsext_debug_callback(WOLFSSL* ssl,
WOLFSSL_TLSEXT_DEBUG_CB cb)
{
long ret = WOLFSSL_SUCCESS;

if (ssl == NULL) {
ret = WOLFSSL_FAILURE;
}
else {
ssl->tlsextDebugCb = cb;
}

return ret;
}
#endif /* HAVE_PK_CALLBACKS */

#ifndef NO_WOLFSSL_STUB
Expand Down
11 changes: 11 additions & 0 deletions src/tls.c
Original file line number Diff line number Diff line change
Expand Up @@ -18612,6 +18612,17 @@ WOLFSSL_TEST_VIS int TLSX_Parse(WOLFSSL* ssl, const byte* input, word16 length,
if (length - offset < size)
return BUFFER_ERROR;

#if defined(OPENSSL_EXTRA) && defined(HAVE_PK_CALLBACKS)
/* Report the extension to the debug callback, like OpenSSL does in
* tls1_handle_extensions(). client_server is 1 when this SSL object
* is a client. */
if (ssl->tlsextDebugCb != NULL) {
ssl->tlsextDebugCb(ssl,
(int)(ssl->options.side == WOLFSSL_CLIENT_END), (int)type,
input + offset, (int)size, ssl->loggingCtx);
}
#endif

/* Check minimum size required for TLSX, even if disabled */
switch (msgType) {
#ifndef NO_WOLFSSL_SERVER
Expand Down
143 changes: 143 additions & 0 deletions tests/api/test_ssl_ext.c
Original file line number Diff line number Diff line change
Expand Up @@ -528,6 +528,149 @@ int test_wolfSSL_set_tlsext_debug_arg_ext(void)
return EXPECT_RESULT();
}

#if defined(OPENSSL_EXTRA) && defined(HAVE_PK_CALLBACKS) && \
!defined(NO_TLS) && \
(!defined(NO_WOLFSSL_CLIENT) || \
(defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
defined(HAVE_TLS_EXTENSIONS)))
/* State recorded by test_tlsext_debug_cb(). */
struct test_tlsext_debug_data {
int count; /* number of extensions reported */
int client_server; /* client_server value reported */
int types[32]; /* extension types reported, in order */
int lens[32]; /* lengths of the reported extensions */
};

static void test_tlsext_debug_cb(WOLFSSL *ssl, int client_server, int type,
const byte *data, int len, void *arg)
{
struct test_tlsext_debug_data *d = (struct test_tlsext_debug_data *)arg;
(void)ssl;
(void)data;

d->count++;
d->client_server = client_server;
if (d->count - 1 < (int)(sizeof(d->types) / sizeof(d->types[0]))) {
d->types[d->count - 1] = type;
d->lens[d->count - 1] = len;
}
}

/* Find an extension type in the recorded list; returns its length, -1 if
* not reported. */
static int test_tlsext_debug_find_len(const struct test_tlsext_debug_data *d,
int type)
{
int i;

for (i = 0; i < d->count &&
i < (int)(sizeof(d->types) / sizeof(d->types[0])); i++) {
if (d->types[i] == type)
return d->lens[i];
}
return -1;
}
#endif /* helpers for the TLS ext debug callback tests */

/* Test installing the TLS extension debug callback.
*
* @return TEST_SUCCESS on success.
*/
int test_wolfSSL_set_tlsext_debug_callback_ext(void)
{
EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && defined(HAVE_PK_CALLBACKS) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_TLS)
WOLFSSL_CTX* ctx = NULL;
WOLFSSL* ssl = NULL;

/* NULL object is rejected. */
ExpectIntEQ(wolfSSL_set_tlsext_debug_callback(NULL,
test_tlsext_debug_cb), WOLFSSL_FAILURE);

ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()));
ExpectNotNull(ssl = wolfSSL_new(ctx));
ExpectIntEQ(wolfSSL_set_tlsext_debug_callback(ssl, test_tlsext_debug_cb),
WOLFSSL_SUCCESS);
/* Setting NULL disables the callback. */
ExpectIntEQ(wolfSSL_set_tlsext_debug_callback(ssl, NULL),
WOLFSSL_SUCCESS);

wolfSSL_free(ssl);
wolfSSL_CTX_free(ctx);
#endif
return EXPECT_RESULT();
}

/* Test that the TLS extension debug callback reports the extensions
* received during a handshake on both sides.
*
* client_server identifies the side of the connection and the argument set
* with wolfSSL_set_tlsext_debug_arg() is passed through to the callback.
*
* @return TEST_SUCCESS on success.
*/
int test_wolfSSL_set_tlsext_debug_callback_handshake_ext(void)
{
EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && defined(HAVE_PK_CALLBACKS) && \
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
defined(HAVE_TLS_EXTENSIONS) && !defined(NO_TLS)
WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL;
WOLFSSL *ssl_c = NULL, *ssl_s = NULL;
struct test_memio_ctx test_ctx;
struct test_tlsext_debug_data cData, sData;

XMEMSET(&test_ctx, 0, sizeof(test_ctx));
XMEMSET(&cData, 0, sizeof(cData));
XMEMSET(&sData, 0, sizeof(sData));

ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
wolfSSLv23_client_method, wolfSSLv23_server_method), 0);

ExpectIntEQ(wolfSSL_set_tlsext_debug_callback(ssl_c, test_tlsext_debug_cb),
WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_set_tlsext_debug_arg(ssl_c, &cData), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_set_tlsext_debug_callback(ssl_s, test_tlsext_debug_cb),
WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_set_tlsext_debug_arg(ssl_s, &sData), WOLFSSL_SUCCESS);

ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);

/* Each side saw extensions from the peer, tagged with its own side.
* The server always sees the client hello's core extensions (e.g.
* supported groups); the client sees the server hello's, which carries
* supported versions in TLS 1.3 or the echoed extended master secret in
* TLS 1.2. */
ExpectTrue(sData.count > 0);
#if defined(HAVE_EXTENDED_MASTER) || defined(WOLFSSL_TLS13)
ExpectTrue(cData.count > 0);
#endif
ExpectIntEQ(cData.client_server, 1);
ExpectIntEQ(sData.client_server, 0);

/* Known extensions are reported with the expected content. */
#if defined(WOLFSSL_TLS13)
/* TLS 1.3: both sides see supported versions (a list of 2-byte
* versions, so at least 2 bytes). */
ExpectTrue(test_tlsext_debug_find_len(&cData,
TLSX_SUPPORTED_VERSIONS) >= 2);
ExpectTrue(test_tlsext_debug_find_len(&sData,
TLSX_SUPPORTED_VERSIONS) >= 2);
#elif defined(HAVE_EXTENDED_MASTER)
/* TLS 1.2: the client offers extended master secret (empty content). */
ExpectIntEQ(test_tlsext_debug_find_len(&sData,
TLSX_EXTENDED_MASTER_SECRET), 0);
#endif

wolfSSL_free(ssl_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_c);
wolfSSL_CTX_free(ctx_s);
#endif
return EXPECT_RESULT();
}

/* Test installing the session ticket callback and its context.
*
* @return TEST_SUCCESS on success.
Expand Down
5 changes: 5 additions & 0 deletions tests/api/test_ssl_ext.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ int test_wolfSSL_DisableExtendedMasterSecret_ext(void);
int test_wolfSSL_set_tlsext_host_name_ext(void);
int test_wolfSSL_CTX_set_tlsext_servername_callback_ext(void);
int test_wolfSSL_set_tlsext_debug_arg_ext(void);
int test_wolfSSL_set_tlsext_debug_callback_ext(void);
int test_wolfSSL_set_tlsext_debug_callback_handshake_ext(void);
int test_wolfSSL_set_SessionTicket_cb_ext(void);
int test_wolfSSL_set1_curves_list_ext(void);
int test_wolfSSL_SecureResume_ext(void);
Expand Down Expand Up @@ -74,6 +76,9 @@ int test_wolfSSL_ticket_key_cb_renew_ext(void);
TEST_DECL_GROUP("ssl_ext", \
test_wolfSSL_CTX_set_tlsext_servername_callback_ext), \
TEST_DECL_GROUP("ssl_ext", test_wolfSSL_set_tlsext_debug_arg_ext), \
TEST_DECL_GROUP("ssl_ext", test_wolfSSL_set_tlsext_debug_callback_ext), \
TEST_DECL_GROUP("ssl_ext", \
test_wolfSSL_set_tlsext_debug_callback_handshake_ext), \
TEST_DECL_GROUP("ssl_ext", test_wolfSSL_set_SessionTicket_cb_ext), \
TEST_DECL_GROUP("ssl_ext", test_wolfSSL_set1_curves_list_ext), \
TEST_DECL_GROUP("ssl_ext", test_wolfSSL_SecureResume_ext), \
Expand Down
1 change: 1 addition & 0 deletions wolfssl/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -6572,6 +6572,7 @@ struct WOLFSSL {
#ifdef OPENSSL_EXTRA
#ifdef HAVE_PK_CALLBACKS
void* loggingCtx; /* logging callback argument */
WOLFSSL_TLSEXT_DEBUG_CB tlsextDebugCb; /* TLS ext debug callback */
#endif
#endif /* OPENSSL_EXTRA */
#ifndef NO_RSA
Expand Down
2 changes: 2 additions & 0 deletions wolfssl/openssl/ssl.h
Original file line number Diff line number Diff line change
Expand Up @@ -1449,6 +1449,8 @@ typedef WOLFSSL_SRTP_PROTECTION_PROFILE SRTP_PROTECTION_PROFILE;
#define SSL_get_secure_renegotiation_support wolfSSL_SSL_get_secure_renegotiation_support
#define SSL_renegotiate_pending wolfSSL_SSL_renegotiate_pending
#define SSL_set_tlsext_debug_arg wolfSSL_set_tlsext_debug_arg
#define SSL_set_tlsext_debug_callback(ssl, cb) \
wolfSSL_set_tlsext_debug_callback((ssl), (WOLFSSL_TLSEXT_DEBUG_CB)(cb))
#define SSL_set_tlsext_status_type wolfSSL_set_tlsext_status_type
#define SSL_get_tlsext_status_type wolfSSL_get_tlsext_status_type
#define SSL_set_tlsext_status_exts wolfSSL_set_tlsext_status_exts
Expand Down
4 changes: 4 additions & 0 deletions wolfssl/ssl.h
Original file line number Diff line number Diff line change
Expand Up @@ -2775,7 +2775,11 @@ WOLFSSL_API char* wolfSSL_get_srp_username(WOLFSSL *ssl);

WOLFSSL_API long wolfSSL_clear_options(WOLFSSL *s, long op);
WOLFSSL_API long wolfSSL_set_tmp_dh(WOLFSSL *s, WOLFSSL_DH *dh);
typedef void (*WOLFSSL_TLSEXT_DEBUG_CB)(WOLFSSL* ssl, int client_server,
int type, const byte* data, int len, void* arg);
WOLFSSL_API long wolfSSL_set_tlsext_debug_arg(WOLFSSL *s, void *arg);
WOLFSSL_API long wolfSSL_set_tlsext_debug_callback(WOLFSSL *s,
WOLFSSL_TLSEXT_DEBUG_CB cb);
WOLFSSL_API long wolfSSL_set_tlsext_status_type(WOLFSSL *s, int type);
WOLFSSL_API long wolfSSL_get_tlsext_status_type(WOLFSSL *s);
WOLFSSL_API long wolfSSL_set_tlsext_status_exts(WOLFSSL *s, void *arg);
Expand Down
Loading