Skip to content

Commit c5e2f41

Browse files
Merge pull request #6929 from julek-wolfssl/dtls13-early-data-server-side
dtls 1.3: allow to skip cookie exchange on resumption
2 parents 8ac291b + 8c87920 commit c5e2f41

11 files changed

Lines changed: 185 additions & 72 deletions

File tree

.github/workflows/os-check.yml

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,14 @@ jobs:
1616
'--enable-all --enable-asn=original',
1717
'--enable-harden-tls',
1818
'--enable-tls13 --enable-session-ticket --enable-dtls --enable-dtls13
19-
--enable-opensslextra --enable-sessioncerts
20-
CPPFLAGS=''-DWOLFSSL_DTLS_NO_HVR_ON_RESUME -DHAVE_EXT_CACHE
21-
-DWOLFSSL_TICKET_HAVE_ID -DHAVE_EX_DATA -DSESSION_CACHE_DYNAMIC_MEM'' ',
19+
--enable-opensslextra --enable-sessioncerts
20+
CPPFLAGS=''-DWOLFSSL_DTLS_NO_HVR_ON_RESUME -DHAVE_EXT_CACHE
21+
-DWOLFSSL_TICKET_HAVE_ID -DHAVE_EX_DATA -DSESSION_CACHE_DYNAMIC_MEM'' ',
2222
'--enable-all --enable-secure-renegotiation',
2323
'--enable-all --enable-haproxy --enable-quic',
24+
'--enable-dtls --enable-dtls13 --enable-earlydata
25+
--enable-session-ticket --enable-psk
26+
CPPFLAGS=''-DWOLFSSL_DTLS13_NO_HRR_ON_RESUME'' ',
2427
]
2528
name: make check
2629
runs-on: ${{ matrix.os }}

examples/client/client.c

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -466,26 +466,6 @@ static void EarlyData(WOLFSSL_CTX* ctx, WOLFSSL* ssl, const char* msg,
466466
wolfSSL_CTX_free(ctx); ctx = NULL;
467467
err_sys("SSL_write_early_data failed");
468468
}
469-
do {
470-
err = 0; /* reset error */
471-
ret = wolfSSL_write_early_data(ssl, msg, msgSz, &msgSz);
472-
if (ret <= 0) {
473-
err = wolfSSL_get_error(ssl, 0);
474-
#ifdef WOLFSSL_ASYNC_CRYPT
475-
if (err == WC_PENDING_E) {
476-
ret = wolfSSL_AsyncPoll(ssl, WOLF_POLL_FLAG_CHECK_HW);
477-
if (ret < 0) break;
478-
}
479-
#endif
480-
}
481-
} while (err == WC_PENDING_E);
482-
if (ret != msgSz) {
483-
LOG_ERROR("SSL_write_early_data msg error %d, %s\n", err,
484-
wolfSSL_ERR_error_string(err, buffer));
485-
wolfSSL_free(ssl);
486-
wolfSSL_CTX_free(ctx);
487-
err_sys("SSL_write_early_data failed");
488-
}
489469
}
490470
#endif
491471

examples/server/server.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3358,7 +3358,7 @@ THREAD_RETURN WOLFSSL_THREAD server_test(void* args)
33583358
err = 0; /* reset error */
33593359
ret = wolfSSL_read_early_data(ssl, input, sizeof(input)-1,
33603360
&len);
3361-
if (ret != WOLFSSL_SUCCESS) {
3361+
if (ret <= 0) {
33623362
err = SSL_get_error(ssl, 0);
33633363
#ifdef WOLFSSL_ASYNC_CRYPT
33643364
if (err == WC_PENDING_E) {

src/dtls.c

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,13 @@
2121

2222
/*
2323
* WOLFSSL_DTLS_NO_HVR_ON_RESUME
24+
* WOLFSSL_DTLS13_NO_HRR_ON_RESUME
2425
* If defined, a DTLS server will not do a cookie exchange on successful
2526
* client resumption: the resumption will be faster (one RTT less) and
26-
* will consume less bandwidth (one ClientHello and one HelloVerifyRequest
27-
* less). On the other hand, if a valid SessionID is collected, forged
28-
* clientHello messages will consume resources on the server.
27+
* will consume less bandwidth (one ClientHello and one
28+
* HelloVerifyRequest/HelloRetryRequest less). On the other hand, if a valid
29+
* SessionID/ticket/psk is collected, forged clientHello messages will
30+
* consume resources on the server.
2931
* WOLFSSL_DTLS_CH_FRAG
3032
* Allow a server to process a fragmented second/verified (one containing a
3133
* valid cookie response) ClientHello message. The first/unverified (one
@@ -769,6 +771,15 @@ static int SendStatelessReplyDtls13(const WOLFSSL* ssl, WolfSSL_CH* ch)
769771
}
770772
}
771773

774+
#ifdef WOLFSSL_DTLS13_NO_HRR_ON_RESUME
775+
if (ssl->options.dtls13NoHrrOnResume && usePSK && pskInfo.isValid &&
776+
!cs.doHelloRetry) {
777+
/* Skip HRR on resumption */
778+
((WOLFSSL*)ssl)->options.dtlsStateful = 1;
779+
goto dtls13_cleanup;
780+
}
781+
#endif
782+
772783
#ifdef HAVE_SUPPORTED_CURVES
773784
if (cs.doHelloRetry) {
774785
ret = TLSX_KeyShare_SetSupported(ssl, &parsedExts);
@@ -949,7 +960,7 @@ int DoClientHelloStateless(WOLFSSL* ssl, const byte* input, word32 helloSz,
949960
ret = COOKIE_ERROR;
950961
else
951962
#endif
952-
ret = SendStatelessReply((WOLFSSL*)ssl, &ch, isTls13);
963+
ret = SendStatelessReply(ssl, &ch, isTls13);
953964
}
954965
else {
955966
byte cookieGood;
@@ -970,7 +981,7 @@ int DoClientHelloStateless(WOLFSSL* ssl, const byte* input, word32 helloSz,
970981
ret = COOKIE_ERROR;
971982
else
972983
#endif
973-
ret = SendStatelessReply((WOLFSSL*)ssl, &ch, isTls13);
984+
ret = SendStatelessReply(ssl, &ch, isTls13);
974985
}
975986
else {
976987
ssl->options.dtlsStateful = 1;

src/dtls13.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2844,5 +2844,15 @@ int wolfSSL_dtls13_allow_ch_frag(WOLFSSL *ssl, int enabled)
28442844
}
28452845
#endif
28462846

2847+
#ifdef WOLFSSL_DTLS13_NO_HRR_ON_RESUME
2848+
int wolfSSL_dtls13_no_hrr_on_resume(WOLFSSL *ssl, int enabled)
2849+
{
2850+
if (ssl->options.side == WOLFSSL_CLIENT_END) {
2851+
return WOLFSSL_FAILURE;
2852+
}
2853+
ssl->options.dtls13NoHrrOnResume = !!enabled;
2854+
return WOLFSSL_SUCCESS;
2855+
}
2856+
#endif
28472857

28482858
#endif /* WOLFSSL_DTLS13 */

src/internal.c

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20185,20 +20185,8 @@ static int DtlsShouldDrop(WOLFSSL* ssl, int retcode)
2018520185
#ifndef NO_WOLFSSL_SERVER
2018620186
if (ssl->options.side == WOLFSSL_SERVER_END
2018720187
&& ssl->curRL.type != handshake && !IsSCR(ssl)) {
20188-
int beforeCookieVerified = 0;
20189-
if (!IsAtLeastTLSv1_3(ssl->version)) {
20190-
beforeCookieVerified =
20191-
ssl->options.acceptState < ACCEPT_FIRST_REPLY_DONE;
20192-
}
20193-
#ifdef WOLFSSL_DTLS13
20194-
else {
20195-
beforeCookieVerified =
20196-
ssl->options.acceptState < TLS13_ACCEPT_SECOND_REPLY_DONE;
20197-
}
20198-
#endif /* WOLFSSL_DTLS13 */
20199-
20200-
if (beforeCookieVerified) {
20201-
WOLFSSL_MSG("Drop non-handshake record before handshake");
20188+
if (!ssl->options.dtlsStateful) {
20189+
WOLFSSL_MSG("Drop non-handshake record when not stateful");
2020220190
return 1;
2020320191
}
2020420192
}
@@ -34441,6 +34429,9 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
3444134429

3444234430
#if defined(WOLFSSL_TLS13) && defined(HAVE_SUPPORTED_CURVES)
3444334431
if (cs.doHelloRetry) {
34432+
/* Make sure we don't send HRR twice */
34433+
if (ssl->options.serverState == SERVER_HELLO_RETRY_REQUEST_COMPLETE)
34434+
return INVALID_PARAMETER;
3444434435
ssl->options.serverState = SERVER_HELLO_RETRY_REQUEST_COMPLETE;
3444534436
return TLSX_KeyShare_SetSupported(ssl, &ssl->extensions);
3444634437
}

src/ssl.c

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16793,11 +16793,13 @@ int wolfSSL_set_compression(WOLFSSL* ssl)
1679316793
#endif /* OPENSSL_EXTRA || WOLFSSL_EXTRA || WOLFSSL_WPAS_SMALL */
1679416794

1679516795
/* return true if connection established */
16796-
int wolfSSL_is_init_finished(WOLFSSL* ssl)
16796+
int wolfSSL_is_init_finished(const WOLFSSL* ssl)
1679716797
{
1679816798
if (ssl == NULL)
1679916799
return 0;
1680016800

16801+
/* Can't use ssl->options.connectState and ssl->options.acceptState because
16802+
* they differ in meaning for TLS <=1.2 and 1.3 */
1680116803
if (ssl->options.handShakeState == HANDSHAKE_DONE)
1680216804
return 1;
1680316805

@@ -31970,12 +31972,7 @@ int wolfSSL_SSL_in_init(WOLFSSL *ssl)
3197031972
{
3197131973
WOLFSSL_ENTER("wolfSSL_SSL_in_init");
3197231974

31973-
if (ssl == NULL)
31974-
return WOLFSSL_FAILURE;
31975-
31976-
/* Can't use ssl->options.connectState and ssl->options.acceptState because
31977-
* they differ in meaning for TLS <=1.2 and 1.3 */
31978-
return ssl->options.handShakeState != HANDSHAKE_DONE;
31975+
return !wolfSSL_is_init_finished(ssl);
3197931976
}
3198031977

3198131978
int wolfSSL_SSL_in_connect_init(WOLFSSL* ssl)

src/tls13.c

Lines changed: 53 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6204,6 +6204,8 @@ static int CheckPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 helloSz,
62046204
if ((ret = SetKeysSide(ssl, DECRYPT_SIDE_ONLY)) != 0)
62056205
return ret;
62066206

6207+
ssl->keys.encryptionOn = 1;
6208+
62076209
#ifdef WOLFSSL_DTLS13
62086210
if (ssl->options.dtls) {
62096211
ret = Dtls13NewEpoch(ssl,
@@ -6916,7 +6918,11 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
69166918
}
69176919
}
69186920
else {
6919-
ERROR_OUT(HRR_COOKIE_ERROR, exit_dch);
6921+
#if defined(WOLFSSL_DTLS13) && defined(WOLFSSL_DTLS13_NO_HRR_ON_RESUME)
6922+
/* Don't error out as we may be resuming. We confirm this later. */
6923+
if (!ssl->options.dtls)
6924+
#endif
6925+
ERROR_OUT(HRR_COOKIE_ERROR, exit_dch);
69206926
}
69216927
}
69226928
#endif
@@ -6982,14 +6988,16 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
69826988
goto exit_dch;
69836989
}
69846990
}
6985-
else
69866991
#endif
69876992
#ifdef HAVE_SUPPORTED_CURVES
69886993
if (args->usingPSK == 2) {
69896994
/* Pick key share and Generate a new key if not present. */
69906995
int doHelloRetry = 0;
69916996
ret = TLSX_KeyShare_Establish(ssl, &doHelloRetry);
69926997
if (doHelloRetry) {
6998+
/* Make sure we don't send HRR twice */
6999+
if (ssl->options.serverState == SERVER_HELLO_RETRY_REQUEST_COMPLETE)
7000+
ERROR_OUT(INVALID_PARAMETER, exit_dch);
69937001
ssl->options.serverState = SERVER_HELLO_RETRY_REQUEST_COMPLETE;
69947002
if (ret != WC_PENDING_E)
69957003
ret = 0; /* for hello_retry return 0 */
@@ -7082,32 +7090,58 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
70827090
ret = INPUT_CASE_ERROR;
70837091
} /* switch (ssl->options.asyncState) */
70847092

7085-
#if defined(WOLFSSL_SEND_HRR_COOKIE)
7086-
if (ret == 0 && ssl->options.sendCookie && ssl->options.cookieGood &&
7087-
(ssl->options.serverState == SERVER_HELLO_RETRY_REQUEST_COMPLETE
7093+
#ifdef WOLFSSL_SEND_HRR_COOKIE
7094+
if (ret == 0 && ssl->options.sendCookie) {
7095+
if (ssl->options.cookieGood &&
7096+
ssl->options.acceptState == TLS13_ACCEPT_FIRST_REPLY_DONE) {
7097+
/* Processing second ClientHello. Clear HRR state. */
7098+
ssl->options.serverState = NULL_STATE;
7099+
}
7100+
7101+
if (ssl->options.cookieGood &&
7102+
ssl->options.serverState == SERVER_HELLO_RETRY_REQUEST_COMPLETE) {
7103+
/* If we already verified the peer with a cookie then we can't
7104+
* do another HRR for cipher negotiation. Send alert and restart
7105+
* the entire handshake. */
7106+
ERROR_OUT(INVALID_PARAMETER, exit_dch);
7107+
}
70887108
#ifdef WOLFSSL_DTLS13
7089-
/* DTLS cookie exchange should be done in stateless code in
7090-
* DoClientHelloStateless. If we verified the cookie then
7091-
* always advance the state. */
7092-
|| ssl->options.dtls
7109+
if (ssl->options.dtls &&
7110+
ssl->options.serverState == SERVER_HELLO_RETRY_REQUEST_COMPLETE) {
7111+
/* Cookie and key share negotiation should be handled in
7112+
* DoClientHelloStateless. If we enter here then something went
7113+
* wrong in our logic. */
7114+
ERROR_OUT(BAD_HELLO, exit_dch);
7115+
}
70937116
#endif
7094-
))
7095-
ssl->options.serverState = SERVER_HELLO_COMPLETE;
7117+
/* Send a cookie */
7118+
if (!ssl->options.cookieGood &&
7119+
ssl->options.serverState != SERVER_HELLO_RETRY_REQUEST_COMPLETE) {
7120+
#ifdef WOLFSSL_DTLS13
7121+
if (ssl->options.dtls) {
7122+
#ifdef WOLFSSL_DTLS13_NO_HRR_ON_RESUME
7123+
/* We can skip cookie on resumption */
7124+
if (!ssl->options.dtls || !ssl->options.dtls13NoHrrOnResume ||
7125+
!args->usingPSK)
7126+
#endif
7127+
ERROR_OUT(BAD_HELLO, exit_dch);
7128+
}
7129+
else
70967130
#endif
7131+
{
7132+
/* Need to remove the keyshare ext if we found a common group
7133+
* and are not doing curve negotiation. */
7134+
TLSX_Remove(&ssl->extensions, TLSX_KEY_SHARE, ssl->heap);
7135+
ssl->options.serverState = SERVER_HELLO_RETRY_REQUEST_COMPLETE;
7136+
}
70977137

7098-
#if defined(WOLFSSL_DTLS13) && defined(WOLFSSL_SEND_HRR_COOKIE)
7099-
if (ret == 0 && ssl->options.dtls && ssl->options.sendCookie &&
7100-
ssl->options.serverState <= SERVER_HELLO_RETRY_REQUEST_COMPLETE) {
7101-
/* Cookie and key share negotiation should be handled in
7102-
* DoClientHelloStateless. If we enter here then something went wrong
7103-
* in our logic. */
7104-
ERROR_OUT(BAD_HELLO, exit_dch);
7138+
}
71057139
}
71067140
#endif /* WOLFSSL_DTLS13 */
71077141

71087142
#ifdef WOLFSSL_DTLS_CID
71097143
/* do not modify CID state if we are sending an HRR */
7110-
if (ssl->options.useDtlsCID &&
7144+
if (ret == 0 && ssl->options.dtls && ssl->options.useDtlsCID &&
71117145
ssl->options.serverState != SERVER_HELLO_RETRY_REQUEST_COMPLETE)
71127146
DtlsCIDOnExtensionsParsed(ssl);
71137147
#endif /* WOLFSSL_DTLS_CID */

0 commit comments

Comments
 (0)