Skip to content

Commit 0f8050f

Browse files
Support importing/exporting DTLS sessions with encrypt-then-mac options
1 parent 7cf84dd commit 0f8050f

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
@@ -3171,3 +3171,101 @@ int test_dtls_set_session_min_downgrade(void)
31713171
#endif
31723172
return EXPECT_RESULT();
31733173
}
3174+
3175+
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS) && \
3176+
defined(WOLFSSL_SESSION_EXPORT) && defined(HAVE_ENCRYPT_THEN_MAC) && \
3177+
!defined(WOLFSSL_AEAD_ONLY) && !defined(WOLFSSL_NO_TLS12) && \
3178+
!defined(NO_RSA) && !defined(NO_AES) && defined(HAVE_AES_CBC) && \
3179+
!defined(NO_SHA256) && defined(HAVE_ECC)
3180+
/* Dummy peer callbacks so the DTLS exporter/importer has peer information to
3181+
* work with (the library requires these unless built with
3182+
* WOLFSSL_SESSION_EXPORT_NOPEER). */
3183+
static int test_dtls_export_etm_get_peer(WOLFSSL* ssl, char* ip, int* ipSz,
3184+
unsigned short* port, int* fam)
3185+
{
3186+
(void)ssl;
3187+
ip[0] = -1;
3188+
*ipSz = 1;
3189+
*port = 1;
3190+
*fam = 2;
3191+
return 1;
3192+
}
3193+
3194+
static int test_dtls_export_etm_set_peer(WOLFSSL* ssl, char* ip, int ipSz,
3195+
unsigned short port, int fam)
3196+
{
3197+
(void)ssl;
3198+
if (ip[0] != -1 || ipSz != 1 || port != 1 || fam != 2)
3199+
return 0;
3200+
return 1;
3201+
}
3202+
#endif
3203+
3204+
/* Regression test for DTLS session export/import dropping the Encrypt-Then-MAC
3205+
* options. Historically the ETM option fields were only serialized for TLS, so
3206+
* a re-imported DTLS session lost the negotiated ETM state and broke the record
3207+
* layer. Establish a DTLS 1.2 connection with a CBC cipher suite (where ETM
3208+
* applies), export the session, re-import it into a fresh WOLFSSL, and confirm
3209+
* the ETM option fields survive the round trip. */
3210+
int test_dtls12_export_import_etm(void)
3211+
{
3212+
EXPECT_DECLS;
3213+
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS) && \
3214+
defined(WOLFSSL_SESSION_EXPORT) && defined(HAVE_ENCRYPT_THEN_MAC) && \
3215+
!defined(WOLFSSL_AEAD_ONLY) && !defined(WOLFSSL_NO_TLS12) && \
3216+
!defined(NO_RSA) && !defined(NO_AES) && defined(HAVE_AES_CBC) && \
3217+
!defined(NO_SHA256) && defined(HAVE_ECC)
3218+
/* TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 - a CBC suite, where ETM applies. */
3219+
const char* cbcSuite = "ECDHE-RSA-AES128-SHA256";
3220+
WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL;
3221+
WOLFSSL *ssl_c = NULL, *ssl_s = NULL;
3222+
WOLFSSL *ssl_imp = NULL;
3223+
struct test_memio_ctx test_ctx;
3224+
unsigned char* session = NULL;
3225+
unsigned int sessionSz = 0;
3226+
3227+
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
3228+
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
3229+
wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method), 0);
3230+
ExpectIntEQ(wolfSSL_set_cipher_list(ssl_c, cbcSuite), WOLFSSL_SUCCESS);
3231+
ExpectIntEQ(wolfSSL_set_cipher_list(ssl_s, cbcSuite), WOLFSSL_SUCCESS);
3232+
3233+
/* The exporter/importer needs peer info callbacks. */
3234+
wolfSSL_CTX_SetIOGetPeer(ctx_s, test_dtls_export_etm_get_peer);
3235+
wolfSSL_CTX_SetIOSetPeer(ctx_s, test_dtls_export_etm_set_peer);
3236+
3237+
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
3238+
3239+
/* Sanity: the handshake itself negotiated ETM on both sides. */
3240+
if (ssl_c != NULL)
3241+
ExpectIntEQ(ssl_c->options.encThenMac, 1);
3242+
if (ssl_s != NULL)
3243+
ExpectIntEQ(ssl_s->options.encThenMac, 1);
3244+
3245+
/* Export the server's DTLS session. */
3246+
ExpectIntGE(wolfSSL_dtls_export(ssl_s, NULL, &sessionSz), 0);
3247+
ExpectIntGT(sessionSz, 0);
3248+
ExpectNotNull(session = (unsigned char*)XMALLOC(sessionSz, NULL,
3249+
DYNAMIC_TYPE_TMP_BUFFER));
3250+
ExpectIntGE(wolfSSL_dtls_export(ssl_s, session, &sessionSz), 0);
3251+
3252+
/* Import into a fresh WOLFSSL and confirm the ETM state survived. */
3253+
ExpectNotNull(ssl_imp = wolfSSL_new(ctx_s));
3254+
ExpectIntGE(wolfSSL_dtls_import(ssl_imp, session, sessionSz), 0);
3255+
if (ssl_imp != NULL) {
3256+
/* Regression check: pre-fix these were all reset to 0 for DTLS. */
3257+
ExpectIntEQ(ssl_imp->options.encThenMac, 1);
3258+
ExpectIntEQ(ssl_imp->options.startedETMRead, 1);
3259+
ExpectIntEQ(ssl_imp->options.startedETMWrite, 1);
3260+
ExpectIntEQ(ssl_imp->options.disallowEncThenMac, 0);
3261+
}
3262+
3263+
XFREE(session, NULL, DYNAMIC_TYPE_TMP_BUFFER);
3264+
wolfSSL_free(ssl_imp);
3265+
wolfSSL_free(ssl_c);
3266+
wolfSSL_free(ssl_s);
3267+
wolfSSL_CTX_free(ctx_c);
3268+
wolfSSL_CTX_free(ctx_s);
3269+
#endif
3270+
return EXPECT_RESULT();
3271+
}

tests/api/test_dtls.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ int test_dtls13_min_rtx_interval(void);
5757
int test_dtls13_no_session_id_echo(void);
5858
int test_dtls13_oversized_cert_chain(void);
5959
int test_dtls_set_session_min_downgrade(void);
60+
int test_dtls12_export_import_etm(void);
6061

6162
#define TEST_DTLS_DECLS \
6263
TEST_DECL_GROUP("dtls", test_dtls12_basic_connection_id), \
@@ -93,5 +94,6 @@ int test_dtls_set_session_min_downgrade(void);
9394
TEST_DECL_GROUP("dtls", test_dtls13_min_rtx_interval), \
9495
TEST_DECL_GROUP("dtls", test_dtls13_no_session_id_echo), \
9596
TEST_DECL_GROUP("dtls", test_dtls13_oversized_cert_chain), \
96-
TEST_DECL_GROUP("dtls", test_dtls_set_session_min_downgrade)
97+
TEST_DECL_GROUP("dtls", test_dtls_set_session_min_downgrade), \
98+
TEST_DECL_GROUP("dtls", test_dtls12_export_import_etm)
9799
#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)