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
28 changes: 24 additions & 4 deletions src/internal.c
Original file line number Diff line number Diff line change
Expand Up @@ -1423,7 +1423,9 @@ static int ExportOptions(WOLFSSL* ssl, byte* exp, word32 len, byte ver,
exp[idx++] = options->acceptState;
exp[idx++] = options->asyncState;

if (type == WOLFSSL_EXPORT_TLS) {
/* Encrypt-Then-MAC state. Historically only serialized for TLS; export
* version 6 and later also serialize it for DTLS. */
if (type == WOLFSSL_EXPORT_TLS || ver > WOLFSSL_EXPORT_VERSION_5) {
#ifdef HAVE_ENCRYPT_THEN_MAC
exp[idx++] = options->disallowEncThenMac;
exp[idx++] = options->encThenMac;
Expand Down Expand Up @@ -1502,6 +1504,13 @@ static int ImportOptions(WOLFSSL* ssl, const byte* exp, word32 len, byte ver,
}
break;

case WOLFSSL_EXPORT_VERSION_5:
if (len < DTLS_EXPORT_OPT_SZ_5) {
WOLFSSL_MSG("Sanity check on buffer size failed");
return BAD_FUNC_ARG;
}
break;
Comment thread
JacobBarthelmeh marked this conversation as resolved.

case WOLFSSL_EXPORT_VERSION_4:
if (len < DTLS_EXPORT_OPT_SZ_4) {
WOLFSSL_MSG("Sanity check on buffer size failed");
Expand Down Expand Up @@ -1628,7 +1637,9 @@ static int ImportOptions(WOLFSSL* ssl, const byte* exp, word32 len, byte ver,
options->acceptState = exp[idx++];
options->asyncState = exp[idx++];

if (type == WOLFSSL_EXPORT_TLS) {
/* Encrypt-Then-MAC state. Historically only serialized for TLS; export
* version 6 and later also serialize it for DTLS. */
if (type == WOLFSSL_EXPORT_TLS || ver > WOLFSSL_EXPORT_VERSION_5) {
#ifdef HAVE_ENCRYPT_THEN_MAC
options->disallowEncThenMac = exp[idx++];
options->encThenMac = exp[idx++];
Expand Down Expand Up @@ -1723,8 +1734,8 @@ static int ImportPeerInfo(WOLFSSL* ssl, const byte* buf, word32 len, byte ver)
word16 port;
char ip[MAX_EXPORT_IP];

if (ver != WOLFSSL_EXPORT_VERSION && ver != WOLFSSL_EXPORT_VERSION_4 &&
ver != WOLFSSL_EXPORT_VERSION_3) {
if (ver != WOLFSSL_EXPORT_VERSION && ver != WOLFSSL_EXPORT_VERSION_5 &&
ver != WOLFSSL_EXPORT_VERSION_4 && ver != WOLFSSL_EXPORT_VERSION_3) {
WOLFSSL_MSG("Export version not supported");
return BAD_FUNC_ARG;
}
Expand Down Expand Up @@ -1982,6 +1993,15 @@ int wolfSSL_session_import_internal(WOLFSSL* ssl, const unsigned char* buf,
}
break;

case WOLFSSL_EXPORT_VERSION_5:
if (type == WOLFSSL_EXPORT_DTLS) {
optSz = DTLS_EXPORT_OPT_SZ_5;
}
else {
optSz = TLS_EXPORT_OPT_SZ_5;
}
break;

case WOLFSSL_EXPORT_VERSION_4:
if (type == WOLFSSL_EXPORT_DTLS) {
optSz = DTLS_EXPORT_OPT_SZ_4;
Expand Down
98 changes: 98 additions & 0 deletions tests/api/test_dtls.c
Original file line number Diff line number Diff line change
Expand Up @@ -3294,3 +3294,101 @@ int test_dtls_set_session_min_downgrade(void)
#endif
return EXPECT_RESULT();
}

#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS) && \
defined(WOLFSSL_SESSION_EXPORT) && defined(HAVE_ENCRYPT_THEN_MAC) && \
!defined(WOLFSSL_AEAD_ONLY) && !defined(WOLFSSL_NO_TLS12) && \
!defined(NO_RSA) && !defined(NO_AES) && defined(HAVE_AES_CBC) && \
!defined(NO_SHA256) && defined(HAVE_ECC)
/* Dummy peer callbacks so the DTLS exporter/importer has peer information to
* work with (the library requires these unless built with
* WOLFSSL_SESSION_EXPORT_NOPEER). */
static int test_dtls_export_etm_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;
Comment thread
JacobBarthelmeh marked this conversation as resolved.
}

static int test_dtls_export_etm_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;
Comment thread
JacobBarthelmeh marked this conversation as resolved.
}
#endif

/* Regression test for DTLS session export/import dropping the Encrypt-Then-MAC
* options. Historically the ETM option fields were only serialized for TLS, so
* a re-imported DTLS session lost the negotiated ETM state and broke the record
* layer. Establish a DTLS 1.2 connection with a CBC cipher suite (where ETM
* applies), export the session, re-import it into a fresh WOLFSSL, and confirm
* the ETM option fields survive the round trip. */
int test_dtls12_export_import_etm(void)
{
EXPECT_DECLS;
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS) && \
defined(WOLFSSL_SESSION_EXPORT) && defined(HAVE_ENCRYPT_THEN_MAC) && \
!defined(WOLFSSL_AEAD_ONLY) && !defined(WOLFSSL_NO_TLS12) && \
!defined(NO_RSA) && !defined(NO_AES) && defined(HAVE_AES_CBC) && \
!defined(NO_SHA256) && defined(HAVE_ECC)
/* TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 - a CBC suite, where ETM applies. */
const char* cbcSuite = "ECDHE-RSA-AES128-SHA256";
WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL;
WOLFSSL *ssl_c = NULL, *ssl_s = NULL;
WOLFSSL *ssl_imp = NULL;
struct test_memio_ctx test_ctx;
unsigned char* session = NULL;
unsigned int sessionSz = 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);
ExpectIntEQ(wolfSSL_set_cipher_list(ssl_c, cbcSuite), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_set_cipher_list(ssl_s, cbcSuite), WOLFSSL_SUCCESS);

/* The exporter/importer needs peer info callbacks. */
wolfSSL_CTX_SetIOGetPeer(ctx_s, test_dtls_export_etm_get_peer);
wolfSSL_CTX_SetIOSetPeer(ctx_s, test_dtls_export_etm_set_peer);

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

/* Sanity: the handshake itself negotiated ETM on both sides. */
if (ssl_c != NULL)
ExpectIntEQ(ssl_c->options.encThenMac, 1);
if (ssl_s != NULL)
ExpectIntEQ(ssl_s->options.encThenMac, 1);

/* Export the server's DTLS session. */
ExpectIntGE(wolfSSL_dtls_export(ssl_s, NULL, &sessionSz), 0);
ExpectIntGT(sessionSz, 0);
ExpectNotNull(session = (unsigned char*)XMALLOC(sessionSz, NULL,
DYNAMIC_TYPE_TMP_BUFFER));
ExpectIntGE(wolfSSL_dtls_export(ssl_s, session, &sessionSz), 0);

/* Import into a fresh WOLFSSL and confirm the ETM state survived. */
ExpectNotNull(ssl_imp = wolfSSL_new(ctx_s));
ExpectIntGE(wolfSSL_dtls_import(ssl_imp, session, sessionSz), 0);
if (ssl_imp != NULL) {
/* Regression check: pre-fix these were all reset to 0 for DTLS. */
ExpectIntEQ(ssl_imp->options.encThenMac, 1);
ExpectIntEQ(ssl_imp->options.startedETMRead, 1);
ExpectIntEQ(ssl_imp->options.startedETMWrite, 1);
ExpectIntEQ(ssl_imp->options.disallowEncThenMac, 0);
}

XFREE(session, NULL, DYNAMIC_TYPE_TMP_BUFFER);
wolfSSL_free(ssl_imp);
wolfSSL_free(ssl_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_c);
wolfSSL_CTX_free(ctx_s);
#endif
return EXPECT_RESULT();
}
4 changes: 3 additions & 1 deletion tests/api/test_dtls.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ 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);
int test_dtls12_export_import_etm(void);

#define TEST_DTLS_DECLS \
TEST_DECL_GROUP("dtls", test_dtls12_basic_connection_id), \
Expand Down Expand Up @@ -95,5 +96,6 @@ int test_dtls_set_session_min_downgrade(void);
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_dtls13_5_9_0_compat), \
TEST_DECL_GROUP("dtls", test_dtls12_export_import_etm)
#endif /* TESTS_API_DTLS_H */
23 changes: 13 additions & 10 deletions wolfssl/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -1632,25 +1632,28 @@ enum Misc {
DTLS_EXPORT_PRO = 165,/* wolfSSL protocol for serialized session */
DTLS_EXPORT_STATE_PRO = 166,/* wolfSSL protocol for serialized state */
TLS_EXPORT_PRO = 167,/* wolfSSL protocol for serialized TLS */
DTLS_EXPORT_OPT_SZ = 62, /* amount of bytes used from Options */
DTLS_EXPORT_OPT_SZ_4 = 61, /* amount of bytes used from Options */
TLS_EXPORT_OPT_SZ = 66, /* amount of bytes used from Options */
TLS_EXPORT_OPT_SZ_4 = 65, /* amount of bytes used from Options */
DTLS_EXPORT_OPT_SZ_3 = 60, /* amount of bytes used from Options */
DTLS_EXPORT_OPT_SZ = 66, /* number of bytes used from Options */
DTLS_EXPORT_OPT_SZ_5 = 62, /* number of bytes used from Options */
DTLS_EXPORT_OPT_SZ_4 = 61, /* number of bytes used from Options */
TLS_EXPORT_OPT_SZ = 66, /* number of bytes used from Options */
TLS_EXPORT_OPT_SZ_5 = 66, /* number of bytes used from Options */
TLS_EXPORT_OPT_SZ_4 = 65, /* number of bytes used from Options */
DTLS_EXPORT_OPT_SZ_3 = 60, /* number of bytes used from Options */
DTLS_EXPORT_KEY_SZ = 325 + (DTLS_SEQ_SZ * 2),
/* max amount of bytes used from Keys */
/* max number of bytes used from Keys */
DTLS_EXPORT_MIN_KEY_SZ = 85 + (DTLS_SEQ_SZ * 2),
/* min amount of bytes used from Keys */
/* min number of bytes used from Keys */
WOLFSSL_EXPORT_TLS = 1,
WOLFSSL_EXPORT_DTLS = 0,
#ifndef WOLFSSL_EXPORT_SPC_SZ
WOLFSSL_EXPORT_SPC_SZ = 16, /* amount of bytes used from CipherSpecs */
WOLFSSL_EXPORT_SPC_SZ = 16, /* number of bytes used from CipherSpecs */
#endif
WOLFSSL_EXPORT_LEN = 2, /* 2 bytes for length and protocol */
WOLFSSL_EXPORT_VERSION = 5, /* wolfSSL version for serialized session */
WOLFSSL_EXPORT_VERSION = 6, /* wolfSSL version for serialized session */

WOLFSSL_EXPORT_VERSION_4 = 4, /* 5.6.4 release and before */
/* older export versions supported */
WOLFSSL_EXPORT_VERSION_5 = 5, /* version before DTLS Encrypt-Then-MAC */
WOLFSSL_EXPORT_VERSION_4 = 4, /* 5.6.4 release and before */
WOLFSSL_EXPORT_VERSION_3 = 3, /* wolfSSL version before TLS 1.3 addition */

MAX_EXPORT_IP = 46, /* max ip size IPv4 mapped IPv6 */
Expand Down
Loading