Skip to content

Commit 4c0c093

Browse files
Merge pull request #10544 from holtrop-wolfssl/zd21880
Support importing/exporting DTLS sessions with encrypt-then-mac options
2 parents 95158fa + 7f3d589 commit 4c0c093

4 files changed

Lines changed: 138 additions & 15 deletions

File tree

src/internal.c

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1423,7 +1423,9 @@ static int ExportOptions(WOLFSSL* ssl, byte* exp, word32 len, byte ver,
14231423
exp[idx++] = options->acceptState;
14241424
exp[idx++] = options->asyncState;
14251425

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

1507+
case WOLFSSL_EXPORT_VERSION_5:
1508+
if (len < DTLS_EXPORT_OPT_SZ_5) {
1509+
WOLFSSL_MSG("Sanity check on buffer size failed");
1510+
return BAD_FUNC_ARG;
1511+
}
1512+
break;
1513+
15051514
case WOLFSSL_EXPORT_VERSION_4:
15061515
if (len < DTLS_EXPORT_OPT_SZ_4) {
15071516
WOLFSSL_MSG("Sanity check on buffer size failed");
@@ -1628,7 +1637,9 @@ static int ImportOptions(WOLFSSL* ssl, const byte* exp, word32 len, byte ver,
16281637
options->acceptState = exp[idx++];
16291638
options->asyncState = exp[idx++];
16301639

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

1726-
if (ver != WOLFSSL_EXPORT_VERSION && ver != WOLFSSL_EXPORT_VERSION_4 &&
1727-
ver != WOLFSSL_EXPORT_VERSION_3) {
1737+
if (ver != WOLFSSL_EXPORT_VERSION && ver != WOLFSSL_EXPORT_VERSION_5 &&
1738+
ver != WOLFSSL_EXPORT_VERSION_4 && ver != WOLFSSL_EXPORT_VERSION_3) {
17281739
WOLFSSL_MSG("Export version not supported");
17291740
return BAD_FUNC_ARG;
17301741
}
@@ -1982,6 +1993,15 @@ int wolfSSL_session_import_internal(WOLFSSL* ssl, const unsigned char* buf,
19821993
}
19831994
break;
19841995

1996+
case WOLFSSL_EXPORT_VERSION_5:
1997+
if (type == WOLFSSL_EXPORT_DTLS) {
1998+
optSz = DTLS_EXPORT_OPT_SZ_5;
1999+
}
2000+
else {
2001+
optSz = TLS_EXPORT_OPT_SZ_5;
2002+
}
2003+
break;
2004+
19852005
case WOLFSSL_EXPORT_VERSION_4:
19862006
if (type == WOLFSSL_EXPORT_DTLS) {
19872007
optSz = DTLS_EXPORT_OPT_SZ_4;

tests/api/test_dtls.c

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5340,3 +5340,101 @@ int test_dtls12_missing_finished(void)
53405340
#endif
53415341
return EXPECT_RESULT();
53425342
}
5343+
5344+
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS) && \
5345+
defined(WOLFSSL_SESSION_EXPORT) && defined(HAVE_ENCRYPT_THEN_MAC) && \
5346+
!defined(WOLFSSL_AEAD_ONLY) && !defined(WOLFSSL_NO_TLS12) && \
5347+
!defined(NO_RSA) && !defined(NO_AES) && defined(HAVE_AES_CBC) && \
5348+
!defined(NO_SHA256) && defined(HAVE_ECC)
5349+
/* Dummy peer callbacks so the DTLS exporter/importer has peer information to
5350+
* work with (the library requires these unless built with
5351+
* WOLFSSL_SESSION_EXPORT_NOPEER). */
5352+
static int test_dtls_export_etm_get_peer(WOLFSSL* ssl, char* ip, int* ipSz,
5353+
unsigned short* port, int* fam)
5354+
{
5355+
(void)ssl;
5356+
ip[0] = -1;
5357+
*ipSz = 1;
5358+
*port = 1;
5359+
*fam = 2;
5360+
return 1;
5361+
}
5362+
5363+
static int test_dtls_export_etm_set_peer(WOLFSSL* ssl, char* ip, int ipSz,
5364+
unsigned short port, int fam)
5365+
{
5366+
(void)ssl;
5367+
if (ip[0] != -1 || ipSz != 1 || port != 1 || fam != 2)
5368+
return 0;
5369+
return 1;
5370+
}
5371+
#endif
5372+
5373+
/* Regression test for DTLS session export/import dropping the Encrypt-Then-MAC
5374+
* options. Historically the ETM option fields were only serialized for TLS, so
5375+
* a re-imported DTLS session lost the negotiated ETM state and broke the record
5376+
* layer. Establish a DTLS 1.2 connection with a CBC cipher suite (where ETM
5377+
* applies), export the session, re-import it into a fresh WOLFSSL, and confirm
5378+
* the ETM option fields survive the round trip. */
5379+
int test_dtls12_export_import_etm(void)
5380+
{
5381+
EXPECT_DECLS;
5382+
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS) && \
5383+
defined(WOLFSSL_SESSION_EXPORT) && defined(HAVE_ENCRYPT_THEN_MAC) && \
5384+
!defined(WOLFSSL_AEAD_ONLY) && !defined(WOLFSSL_NO_TLS12) && \
5385+
!defined(NO_RSA) && !defined(NO_AES) && defined(HAVE_AES_CBC) && \
5386+
!defined(NO_SHA256) && defined(HAVE_ECC)
5387+
/* TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 - a CBC suite, where ETM applies. */
5388+
const char* cbcSuite = "ECDHE-RSA-AES128-SHA256";
5389+
WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL;
5390+
WOLFSSL *ssl_c = NULL, *ssl_s = NULL;
5391+
WOLFSSL *ssl_imp = NULL;
5392+
struct test_memio_ctx test_ctx;
5393+
unsigned char* session = NULL;
5394+
unsigned int sessionSz = 0;
5395+
5396+
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
5397+
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
5398+
wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method), 0);
5399+
ExpectIntEQ(wolfSSL_set_cipher_list(ssl_c, cbcSuite), WOLFSSL_SUCCESS);
5400+
ExpectIntEQ(wolfSSL_set_cipher_list(ssl_s, cbcSuite), WOLFSSL_SUCCESS);
5401+
5402+
/* The exporter/importer needs peer info callbacks. */
5403+
wolfSSL_CTX_SetIOGetPeer(ctx_s, test_dtls_export_etm_get_peer);
5404+
wolfSSL_CTX_SetIOSetPeer(ctx_s, test_dtls_export_etm_set_peer);
5405+
5406+
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
5407+
5408+
/* Sanity: the handshake itself negotiated ETM on both sides. */
5409+
if (ssl_c != NULL)
5410+
ExpectIntEQ(ssl_c->options.encThenMac, 1);
5411+
if (ssl_s != NULL)
5412+
ExpectIntEQ(ssl_s->options.encThenMac, 1);
5413+
5414+
/* Export the server's DTLS session. */
5415+
ExpectIntGE(wolfSSL_dtls_export(ssl_s, NULL, &sessionSz), 0);
5416+
ExpectIntGT(sessionSz, 0);
5417+
ExpectNotNull(session = (unsigned char*)XMALLOC(sessionSz, NULL,
5418+
DYNAMIC_TYPE_TMP_BUFFER));
5419+
ExpectIntGE(wolfSSL_dtls_export(ssl_s, session, &sessionSz), 0);
5420+
5421+
/* Import into a fresh WOLFSSL and confirm the ETM state survived. */
5422+
ExpectNotNull(ssl_imp = wolfSSL_new(ctx_s));
5423+
ExpectIntGE(wolfSSL_dtls_import(ssl_imp, session, sessionSz), 0);
5424+
if (ssl_imp != NULL) {
5425+
/* Regression check: pre-fix these were all reset to 0 for DTLS. */
5426+
ExpectIntEQ(ssl_imp->options.encThenMac, 1);
5427+
ExpectIntEQ(ssl_imp->options.startedETMRead, 1);
5428+
ExpectIntEQ(ssl_imp->options.startedETMWrite, 1);
5429+
ExpectIntEQ(ssl_imp->options.disallowEncThenMac, 0);
5430+
}
5431+
5432+
XFREE(session, NULL, DYNAMIC_TYPE_TMP_BUFFER);
5433+
wolfSSL_free(ssl_imp);
5434+
wolfSSL_free(ssl_c);
5435+
wolfSSL_free(ssl_s);
5436+
wolfSSL_CTX_free(ctx_c);
5437+
wolfSSL_CTX_free(ctx_s);
5438+
#endif
5439+
return EXPECT_RESULT();
5440+
}

tests/api/test_dtls.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ int test_dtls_memio_wolfio_stateless(void);
4444
int test_dtls_mtu_fragment_headroom(void);
4545
int test_dtls_mtu_split_messages(void);
4646
int test_dtls_set_session_min_downgrade(void);
47+
int test_dtls12_export_import_etm(void);
4748

4849
/* DTLS tests moved out of tests/api.c. */
4950
int test_dtls_msg_from_other_peer(void);
@@ -133,5 +134,6 @@ int test_WOLFSSL_dtls_version_alert(void);
133134
TEST_DECL_GROUP("dtls", test_dtls_dropped_ccs), \
134135
TEST_DECL_GROUP("dtls", test_dtls_seq_num_downgrade), \
135136
TEST_DECL_GROUP("dtls", test_dtls_old_seq_number), \
136-
TEST_DECL_GROUP("dtls", test_dtls12_missing_finished)
137+
TEST_DECL_GROUP("dtls", test_dtls12_missing_finished), \
138+
TEST_DECL_GROUP("dtls", test_dtls12_export_import_etm)
137139
#endif /* TESTS_API_DTLS_H */

wolfssl/internal.h

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1632,25 +1632,28 @@ enum Misc {
16321632
DTLS_EXPORT_PRO = 165,/* wolfSSL protocol for serialized session */
16331633
DTLS_EXPORT_STATE_PRO = 166,/* wolfSSL protocol for serialized state */
16341634
TLS_EXPORT_PRO = 167,/* wolfSSL protocol for serialized TLS */
1635-
DTLS_EXPORT_OPT_SZ = 62, /* amount of bytes used from Options */
1636-
DTLS_EXPORT_OPT_SZ_4 = 61, /* amount of bytes used from Options */
1637-
TLS_EXPORT_OPT_SZ = 66, /* amount of bytes used from Options */
1638-
TLS_EXPORT_OPT_SZ_4 = 65, /* amount of bytes used from Options */
1639-
DTLS_EXPORT_OPT_SZ_3 = 60, /* amount of bytes used from Options */
1635+
DTLS_EXPORT_OPT_SZ = 66, /* number of bytes used from Options */
1636+
DTLS_EXPORT_OPT_SZ_5 = 62, /* number of bytes used from Options */
1637+
DTLS_EXPORT_OPT_SZ_4 = 61, /* number of bytes used from Options */
1638+
TLS_EXPORT_OPT_SZ = 66, /* number of bytes used from Options */
1639+
TLS_EXPORT_OPT_SZ_5 = 66, /* number of bytes used from Options */
1640+
TLS_EXPORT_OPT_SZ_4 = 65, /* number of bytes used from Options */
1641+
DTLS_EXPORT_OPT_SZ_3 = 60, /* number of bytes used from Options */
16401642
DTLS_EXPORT_KEY_SZ = 325 + (DTLS_SEQ_SZ * 2),
1641-
/* max amount of bytes used from Keys */
1643+
/* max number of bytes used from Keys */
16421644
DTLS_EXPORT_MIN_KEY_SZ = 85 + (DTLS_SEQ_SZ * 2),
1643-
/* min amount of bytes used from Keys */
1645+
/* min number of bytes used from Keys */
16441646
WOLFSSL_EXPORT_TLS = 1,
16451647
WOLFSSL_EXPORT_DTLS = 0,
16461648
#ifndef WOLFSSL_EXPORT_SPC_SZ
1647-
WOLFSSL_EXPORT_SPC_SZ = 16, /* amount of bytes used from CipherSpecs */
1649+
WOLFSSL_EXPORT_SPC_SZ = 16, /* number of bytes used from CipherSpecs */
16481650
#endif
16491651
WOLFSSL_EXPORT_LEN = 2, /* 2 bytes for length and protocol */
1650-
WOLFSSL_EXPORT_VERSION = 5, /* wolfSSL version for serialized session */
1652+
WOLFSSL_EXPORT_VERSION = 6, /* wolfSSL version for serialized session */
16511653

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

16561659
MAX_EXPORT_IP = 46, /* max ip size IPv4 mapped IPv6 */

0 commit comments

Comments
 (0)