[openssl-commits] [openssl] master update
Matt Caswell
matt at openssl.org
Mon Jul 2 14:11:23 UTC 2018
The branch master has been updated
via 3bb5e5b09e32defefda2b61087c113203005ffa0 (commit)
via 5a42141565a4074167b006e7a28a822176b40f86 (commit)
via dc7a3543e0244bfdb9cbca1408fb7a6aa5da34b5 (commit)
via c9598459b6c797bd316e44834f5129bdf28add2b (commit)
via 5d263fb78b51f96753056f21abc4d992d0219df2 (commit)
from b6ff436fcb597663ffcfe6d724d207cf120e7250 (commit)
- Log -----------------------------------------------------------------
commit 3bb5e5b09e32defefda2b61087c113203005ffa0
Author: Matt Caswell <matt at openssl.org>
Date: Fri Jun 15 14:55:06 2018 +0100
Add the ability to configure anti-replay via SSL_CONF
This also adds the ability to control this through s_server
Reviewed-by: Viktor Dukhovni <viktor at openssl.org>
Reviewed-by: Rich Salz <rsalz at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/6469)
commit 5a42141565a4074167b006e7a28a822176b40f86
Author: Matt Caswell <matt at openssl.org>
Date: Fri Jun 8 10:03:19 2018 +0100
Add a test for the new early data callback
Reviewed-by: Viktor Dukhovni <viktor at openssl.org>
Reviewed-by: Rich Salz <rsalz at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/6469)
commit dc7a3543e0244bfdb9cbca1408fb7a6aa5da34b5
Author: Matt Caswell <matt at openssl.org>
Date: Thu Jun 7 16:32:19 2018 +0100
Document the new early data callback and option
Document SSL_OP_NO_ANTI_REPLAY and SSL_CTX_set_allow_early_data_cb()
Reviewed-by: Viktor Dukhovni <viktor at openssl.org>
Reviewed-by: Rich Salz <rsalz at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/6469)
commit c9598459b6c797bd316e44834f5129bdf28add2b
Author: Matt Caswell <matt at openssl.org>
Date: Thu Jun 7 15:14:36 2018 +0100
Add setters to set the early_data callback
Reviewed-by: Viktor Dukhovni <viktor at openssl.org>
Reviewed-by: Rich Salz <rsalz at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/6469)
commit 5d263fb78b51f96753056f21abc4d992d0219df2
Author: Matt Caswell <matt at openssl.org>
Date: Thu Jun 7 09:11:05 2018 +0100
Make the anti-replay feature optional
Fixes #6389
Reviewed-by: Viktor Dukhovni <viktor at openssl.org>
Reviewed-by: Rich Salz <rsalz at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/6469)
-----------------------------------------------------------------------
Summary of changes:
apps/s_server.c | 5 ++
doc/man1/s_server.pod | 11 ++++
doc/man3/SSL_CONF_cmd.pod | 21 +++++++
doc/man3/SSL_CTX_set_options.pod | 11 ++++
doc/man3/SSL_read_early_data.pod | 35 ++++++++++-
include/openssl/ssl.h | 16 ++++-
ssl/ssl_conf.c | 11 +++-
ssl/ssl_lib.c | 22 ++++++-
ssl/ssl_locl.h | 9 +++
ssl/statem/extensions.c | 5 +-
ssl/statem/extensions_srvr.c | 4 +-
ssl/statem/statem_srvr.c | 6 +-
test/sslapitest.c | 131 ++++++++++++++++++++++++++++++++++-----
util/libssl.num | 2 +
util/private.num | 2 +
15 files changed, 267 insertions(+), 24 deletions(-)
diff --git a/apps/s_server.c b/apps/s_server.c
index df2bf02..b050200 100644
--- a/apps/s_server.c
+++ b/apps/s_server.c
@@ -749,6 +749,7 @@ typedef enum OPTION_choice {
OPT_CERT2, OPT_KEY2, OPT_NEXTPROTONEG, OPT_ALPN,
OPT_SRTP_PROFILES, OPT_KEYMATEXPORT, OPT_KEYMATEXPORTLEN,
OPT_KEYLOG_FILE, OPT_MAX_EARLY, OPT_EARLY_DATA, OPT_S_NUM_TICKETS,
+ OPT_ANTI_REPLAY, OPT_NO_ANTI_REPLAY,
OPT_R_ENUM,
OPT_S_ENUM,
OPT_V_ENUM,
@@ -958,6 +959,8 @@ const OPTIONS s_server_options[] = {
{"early_data", OPT_EARLY_DATA, '-', "Attempt to read early data"},
{"num_tickets", OPT_S_NUM_TICKETS, 'n',
"The number of TLSv1.3 session tickets that a server will automatically issue" },
+ {"anti_replay", OPT_ANTI_REPLAY, '-', "Switch on anti-replay protection (default)"},
+ {"no_anti_replay", OPT_NO_ANTI_REPLAY, '-', "Switch off anti-replay protection"},
{NULL, OPT_EOF, 0, NULL}
};
@@ -1258,6 +1261,8 @@ int s_server_main(int argc, char *argv[])
break;
case OPT_S_CASES:
case OPT_S_NUM_TICKETS:
+ case OPT_ANTI_REPLAY:
+ case OPT_NO_ANTI_REPLAY:
if (ssl_args == NULL)
ssl_args = sk_OPENSSL_STRING_new_null();
if (ssl_args == NULL
diff --git a/doc/man1/s_server.pod b/doc/man1/s_server.pod
index 2b7db63..f601794 100644
--- a/doc/man1/s_server.pod
+++ b/doc/man1/s_server.pod
@@ -180,6 +180,8 @@ B<openssl> B<s_server>
[B<-keylogfile outfile>]
[B<-max_early_data int>]
[B<-early_data>]
+[B<-anti_replay>]
+[B<-no_anti_replay>]
=head1 DESCRIPTION
@@ -709,6 +711,15 @@ greater than or equal to 0.
Accept early data where possible.
+=item B<-anti_replay>, B<-no_anti_replay>
+
+Switches replay protection on or off, respectively. Replay protection is on by
+default unless overridden by a configuration file. When it is on, OpenSSL will
+automatically detect if a session ticket has been used more than once, TLSv1.3
+has been negotiated, and early data is enabled on the server. A full handshake
+is forced if a session ticket is used a second or subsequent time. Any early
+data that was sent will be rejected.
+
=back
=head1 CONNECTED COMMANDS
diff --git a/doc/man3/SSL_CONF_cmd.pod b/doc/man3/SSL_CONF_cmd.pod
index 4d3e9c2..4edd49c 100644
--- a/doc/man3/SSL_CONF_cmd.pod
+++ b/doc/man3/SSL_CONF_cmd.pod
@@ -211,6 +211,18 @@ that there will be no forward secrecy for the resumed session.
enables strict mode protocol handling. Equivalent to setting
B<SSL_CERT_FLAG_TLS_STRICT>.
+=item B<-anti_replay>, B<-no_anti_replay>
+
+Switches replay protection, on or off respectively. With replay protection on,
+OpenSSL will automatically detect if a session ticket has been used more than
+once, TLSv1.3 has been negotiated, and early data is enabled on the server. A
+full handshake is forced if a session ticket is used a second or subsequent
+time. Anti-Replay is on by default unless overridden by a configuration file and
+is only used by servers. Anti-replay measures are required for compliance with
+the TLSv1.3 specification. Some applications may be able to mitigate the replay
+risks in other ways and in such cases the built-in OpenSSL functionality is not
+required. Switching off anti-replay is equivalent to B<SSL_OP_NO_ANTI_REPLAY>.
+
=back
=head1 SUPPORTED CONFIGURATION FILE COMMANDS
@@ -441,6 +453,15 @@ middleboxes that do not understand TLSv1.3 will not drop the connection. This
option is set by default. A future version of OpenSSL may not set this by
default. Equivalent to B<SSL_OP_ENABLE_MIDDLEBOX_COMPAT>.
+B<AntiReplay>: If set then OpenSSL will automatically detect if a session ticket
+has been used more than once, TLSv1.3 has been negotiated, and early data is
+enabled on the server. A full handshake is forced if a session ticket is used a
+second or subsequent time. This option is set by default and is only used by
+servers. Anti-replay measures are required to comply with the TLSv1.3
+specification. Some applications may be able to mitigate the replay risks in
+other ways and in such cases the built-in OpenSSL functionality is not required.
+Disabling anti-replay is equivalent to setting B<SSL_OP_NO_ANTI_REPLAY>.
+
=item B<VerifyMode>
The B<value> argument is a comma separated list of flags to set.
diff --git a/doc/man3/SSL_CTX_set_options.pod b/doc/man3/SSL_CTX_set_options.pod
index f04de32..ae5ca1b 100644
--- a/doc/man3/SSL_CTX_set_options.pod
+++ b/doc/man3/SSL_CTX_set_options.pod
@@ -226,6 +226,17 @@ this option is set or not CCS messages received from the peer will always be
ignored in TLSv1.3. This option is set by default. To switch it off use
SSL_clear_options(). A future version of OpenSSL may not set this by default.
+=item SSL_OP_NO_ANTI_REPLAY
+
+By default, when a server is configured for early data (i.e., max_early_data > 0),
+OpenSSL will switch on replay protection. See L<SSL_read_early_data(3)> for a
+description of the replay protection feature. Anti-replay measures are required
+to comply with the TLSv1.3 specification. Some applications may be able to
+mitigate the replay risks in other ways and in such cases the built in OpenSSL
+functionality is not required. Those applications can turn this feature off by
+setting this option. This is a server-side opton only. It is ignored by
+clients.
+
=back
The following options no longer have any effect but their identifiers are
diff --git a/doc/man3/SSL_read_early_data.pod b/doc/man3/SSL_read_early_data.pod
index 6a76ec2..cf6f757 100644
--- a/doc/man3/SSL_read_early_data.pod
+++ b/doc/man3/SSL_read_early_data.pod
@@ -10,7 +10,10 @@ SSL_SESSION_get_max_early_data,
SSL_SESSION_set_max_early_data,
SSL_write_early_data,
SSL_read_early_data,
-SSL_get_early_data_status
+SSL_get_early_data_status,
+SSL_allow_early_data_cb_fn,
+SSL_CTX_set_allow_early_data_cb,
+SSL_set_allow_early_data_cb
- functions for sending and receiving early data
=head1 SYNOPSIS
@@ -30,6 +33,16 @@ SSL_get_early_data_status
int SSL_get_early_data_status(const SSL *s);
+
+ typedef int (*SSL_allow_early_data_cb_fn)(SSL *s, void *arg);
+
+ void SSL_CTX_set_allow_early_data_cb(SSL_CTX *ctx,
+ SSL_allow_early_data_cb_fn cb,
+ void *arg);
+ void SSL_set_allow_early_data_cb(SSL *s,
+ SSL_allow_early_data_cb_fn cb,
+ void *arg);
+
=head1 DESCRIPTION
These functions are used to send and receive early data where TLSv1.3 has been
@@ -186,6 +199,20 @@ In the event that the current maximum early data setting for the server is
different to that originally specified in a session that a client is resuming
with then the lower of the two values will apply.
+Some server applications may wish to have more control over whether early data
+is accepted or not, for example to mitigate replay risks (see L</REPLAY PROTECTION>
+below) or to decline early_data when the server is heavily loaded. The functions
+SSL_CTX_set_allow_early_data_cb() and SSL_set_allow_early_data_cb() set a
+callback which is called at a point in the handshake immediately before a
+decision is made to accept or reject early data. The callback is provided with a
+pointer to the user data argument that was provided when the callback was first
+set. Returning 1 from the callback will allow early data and returning 0 will
+reject it. Note that the OpenSSL library may reject early data for other reasons
+in which case this callback will not get called. Notably, the built-in replay
+protection feature will still be used even if a callback is present unless it
+has been explicitly disabled using the SSL_OP_NO_ANTI_REPLAY option. See
+L</REPLAY PROTECTION> below.
+
=head1 NOTES
The whole purpose of early data is to enable a client to start sending data to
@@ -252,6 +279,12 @@ The OpenSSL replay protection does not apply to external Pre Shared Keys (PSKs)
(e.g. see SSL_CTX_set_psk_find_session_callback(3)). Therefore extreme caution
should be applied when combining external PSKs with early data.
+Some applications may mitigate the replay risks in other ways. For those
+applications it is possible to turn off the built-in replay protection feature
+using the B<SSL_OP_NO_ANTI_REPLAY> option. See L<SSL_CTX_set_options(3)> for
+details. Applications can also set a callback to make decisions about accepting
+early data or not. See SSL_CTX_set_allow_early_data_cb() above for details.
+
=head1 RETURN VALUES
SSL_write_early_data() returns 1 for success or 0 for failure. In the event of a
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index 943a8d6..bbcfb3c 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -368,6 +368,12 @@ typedef int (*SSL_verify_cb)(int preverify_ok, X509_STORE_CTX *x509_ctx);
*/
# define SSL_OP_TLS_ROLLBACK_BUG 0x00800000U
+/*
+ * Switches off automatic TLSv1.3 anti-replay protection for early data. This
+ * is a server-side option only (no effect on the client).
+ */
+# define SSL_OP_NO_ANTI_REPLAY 0x01000000U
+
# define SSL_OP_NO_SSLv3 0x02000000U
# define SSL_OP_NO_TLSv1 0x04000000U
# define SSL_OP_NO_TLSv1_2 0x08000000U
@@ -2383,13 +2389,19 @@ int SSL_SESSION_get0_ticket_appdata(SSL_SESSION *ss, void **data, size_t *len);
extern const char SSL_version_str[];
-
-
typedef unsigned int (*DTLS_timer_cb)(SSL *s, unsigned int timer_us);
void DTLS_set_timer_cb(SSL *s, DTLS_timer_cb cb);
+typedef int (*SSL_allow_early_data_cb_fn)(SSL *s, void *arg);
+void SSL_CTX_set_allow_early_data_cb(SSL_CTX *ctx,
+ SSL_allow_early_data_cb_fn cb,
+ void *arg);
+void SSL_set_allow_early_data_cb(SSL *s,
+ SSL_allow_early_data_cb_fn cb,
+ void *arg);
+
# ifdef __cplusplus
}
# endif
diff --git a/ssl/ssl_conf.c b/ssl/ssl_conf.c
index 758f012..9c20270 100644
--- a/ssl/ssl_conf.c
+++ b/ssl/ssl_conf.c
@@ -383,7 +383,8 @@ static int cmd_Options(SSL_CONF_CTX *cctx, const char *value)
SSL_FLAG_TBL("NoRenegotiation", SSL_OP_NO_RENEGOTIATION),
SSL_FLAG_TBL("AllowNoDHEKEX", SSL_OP_ALLOW_NO_DHE_KEX),
SSL_FLAG_TBL("PrioritizeChaCha", SSL_OP_PRIORITIZE_CHACHA),
- SSL_FLAG_TBL("MiddleboxCompat", SSL_OP_ENABLE_MIDDLEBOX_COMPAT)
+ SSL_FLAG_TBL("MiddleboxCompat", SSL_OP_ENABLE_MIDDLEBOX_COMPAT),
+ SSL_FLAG_TBL_INV("AntiReplay", SSL_OP_NO_ANTI_REPLAY)
};
if (value == NULL)
return -3;
@@ -626,6 +627,8 @@ static const ssl_conf_cmd_tbl ssl_conf_cmds[] = {
SSL_CONF_CMD_SWITCH("prioritize_chacha", SSL_CONF_FLAG_SERVER),
SSL_CONF_CMD_SWITCH("strict", 0),
SSL_CONF_CMD_SWITCH("no_middlebox", 0),
+ SSL_CONF_CMD_SWITCH("anti_replay", SSL_CONF_FLAG_SERVER),
+ SSL_CONF_CMD_SWITCH("no_anti_replay", SSL_CONF_FLAG_SERVER),
SSL_CONF_CMD_STRING(SignatureAlgorithms, "sigalgs", 0),
SSL_CONF_CMD_STRING(ClientSignatureAlgorithms, "client_sigalgs", 0),
SSL_CONF_CMD_STRING(Curves, "curves", 0),
@@ -671,7 +674,7 @@ static const ssl_conf_cmd_tbl ssl_conf_cmds[] = {
SSL_CONF_TYPE_FILE),
#endif
SSL_CONF_CMD_STRING(RecordPadding, "record_padding", 0),
- SSL_CONF_CMD_STRING(NumTickets, "num_tickets", SSL_CONF_FLAG_SERVER)
+ SSL_CONF_CMD_STRING(NumTickets, "num_tickets", SSL_CONF_FLAG_SERVER),
};
/* Supported switches: must match order of switches in ssl_conf_cmds */
@@ -704,6 +707,10 @@ static const ssl_switch_tbl ssl_cmd_switches[] = {
{SSL_CERT_FLAG_TLS_STRICT, SSL_TFLAG_CERT}, /* strict */
/* no_middlebox */
{SSL_OP_ENABLE_MIDDLEBOX_COMPAT, SSL_TFLAG_INV},
+ /* anti_replay */
+ {SSL_OP_NO_ANTI_REPLAY, SSL_TFLAG_INV},
+ /* no_anti_replay */
+ {SSL_OP_NO_ANTI_REPLAY, 0},
};
static int ssl_conf_cmd_skip_prefix(SSL_CONF_CTX *cctx, const char **pcmd)
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index 6ced147..1387067 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -805,6 +805,9 @@ SSL *SSL_new(SSL_CTX *ctx)
s->key_update = SSL_KEY_UPDATE_NONE;
+ s->allow_early_data_cb = ctx->allow_early_data_cb;
+ s->allow_early_data_cb_data = ctx->allow_early_data_cb_data;
+
if (!s->method->ssl_new(s))
goto err;
@@ -3381,7 +3384,8 @@ void ssl_update_cache(SSL *s, int mode)
if ((i & SSL_SESS_CACHE_NO_INTERNAL_STORE) == 0
&& (!SSL_IS_TLS13(s)
|| !s->server
- || s->max_early_data > 0
+ || (s->max_early_data > 0
+ && (s->options & SSL_OP_NO_ANTI_REPLAY) == 0)
|| s->session_ctx->remove_session_cb != NULL
|| (s->options & SSL_OP_NO_TICKET) != 0))
SSL_CTX_add_session(s->session_ctx, s->session);
@@ -5482,3 +5486,19 @@ int SSL_CTX_set_session_ticket_cb(SSL_CTX *ctx,
ctx->ticket_cb_data = arg;
return 1;
}
+
+void SSL_CTX_set_allow_early_data_cb(SSL_CTX *ctx,
+ SSL_allow_early_data_cb_fn cb,
+ void *arg)
+{
+ ctx->allow_early_data_cb = cb;
+ ctx->allow_early_data_cb_data = arg;
+}
+
+void SSL_set_allow_early_data_cb(SSL *s,
+ SSL_allow_early_data_cb_fn cb,
+ void *arg)
+{
+ s->allow_early_data_cb = cb;
+ s->allow_early_data_cb_data = arg;
+}
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index a4d1376..6a2edeb 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -1047,6 +1047,10 @@ struct ssl_ctx_st {
/* The number of TLS1.3 tickets to automatically send */
size_t num_tickets;
+
+ /* Callback to determine if early_data is acceptable or not */
+ SSL_allow_early_data_cb_fn allow_early_data_cb;
+ void *allow_early_data_cb_data;
};
struct ssl_st {
@@ -1205,6 +1209,7 @@ struct ssl_st {
# endif
SSL_psk_find_session_cb_func psk_find_session_cb;
SSL_psk_use_session_cb_func psk_use_session_cb;
+
SSL_CTX *ctx;
/* Verified chain of peer */
STACK_OF(X509) *verified_chain;
@@ -1424,6 +1429,10 @@ struct ssl_st {
size_t sent_tickets;
/* The next nonce value to use when we send a ticket on this connection */
uint64_t next_ticket_nonce;
+
+ /* Callback to determine if early_data is acceptable or not */
+ SSL_allow_early_data_cb_fn allow_early_data_cb;
+ void *allow_early_data_cb_data;
};
/*
diff --git a/ssl/statem/extensions.c b/ssl/statem/extensions.c
index 496039e..5309b12 100644
--- a/ssl/statem/extensions.c
+++ b/ssl/statem/extensions.c
@@ -1622,7 +1622,10 @@ static int final_early_data(SSL *s, unsigned int context, int sent)
|| s->session->ext.tick_identity != 0
|| s->early_data_state != SSL_EARLY_DATA_ACCEPTING
|| !s->ext.early_data_ok
- || s->hello_retry_request != SSL_HRR_NONE) {
+ || s->hello_retry_request != SSL_HRR_NONE
+ || (s->ctx->allow_early_data_cb != NULL
+ && !s->ctx->allow_early_data_cb(s,
+ s->ctx->allow_early_data_cb_data))) {
s->ext.early_data = SSL_EARLY_DATA_REJECTED;
} else {
s->ext.early_data = SSL_EARLY_DATA_ACCEPTED;
diff --git a/ssl/statem/extensions_srvr.c b/ssl/statem/extensions_srvr.c
index f58ed0b..ab38a4f 100644
--- a/ssl/statem/extensions_srvr.c
+++ b/ssl/statem/extensions_srvr.c
@@ -1165,7 +1165,8 @@ int tls_parse_ctos_psk(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
* is no point in using full stateless tickets.
*/
if ((s->options & SSL_OP_NO_TICKET) != 0
- || s->max_early_data > 0)
+ || (s->max_early_data > 0
+ && (s->options & SSL_OP_NO_ANTI_REPLAY) == 0))
ret = tls_get_stateful_ticket(s, &identity, &sess);
else
ret = tls_decrypt_ticket(s, PACKET_data(&identity),
@@ -1189,6 +1190,7 @@ int tls_parse_ctos_psk(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
/* Check for replay */
if (s->max_early_data > 0
+ && (s->options & SSL_OP_NO_ANTI_REPLAY) == 0
&& !SSL_CTX_remove_session(s->session_ctx, sess)) {
SSL_SESSION_free(sess);
sess = NULL;
diff --git a/ssl/statem/statem_srvr.c b/ssl/statem/statem_srvr.c
index 26cd850..5c59eb8 100644
--- a/ssl/statem/statem_srvr.c
+++ b/ssl/statem/statem_srvr.c
@@ -4086,8 +4086,10 @@ int tls_construct_new_session_ticket(SSL *s, WPACKET *pkt)
* SSL_OP_NO_TICKET is set - we are caching tickets anyway so there
* is no point in using full stateless tickets.
*/
- if (((s->options & SSL_OP_NO_TICKET) != 0 || s->max_early_data > 0)
- && SSL_IS_TLS13(s)) {
+ if (SSL_IS_TLS13(s)
+ && ((s->options & SSL_OP_NO_TICKET) != 0
+ || (s->max_early_data > 0
+ && (s->options & SSL_OP_NO_ANTI_REPLAY) == 0))) {
if (!construct_stateful_ticket(s, pkt, age_add_u.age_add, tick_nonce)) {
/* SSLfatal() already called */
goto err;
diff --git a/test/sslapitest.c b/test/sslapitest.c
index baf0881..6e08795 100644
--- a/test/sslapitest.c
+++ b/test/sslapitest.c
@@ -1847,11 +1847,14 @@ static unsigned int psk_server_cb(SSL *ssl, const char *identity,
static int setupearly_data_test(SSL_CTX **cctx, SSL_CTX **sctx, SSL **clientssl,
SSL **serverssl, SSL_SESSION **sess, int idx)
{
- if (!TEST_true(create_ssl_ctx_pair(TLS_server_method(), TLS_client_method(),
- TLS1_VERSION, TLS_MAX_VERSION,
- sctx, cctx, cert, privkey))
- || !TEST_true(SSL_CTX_set_max_early_data(*sctx,
- SSL3_RT_MAX_PLAIN_LENGTH)))
+ if (*sctx == NULL
+ && !TEST_true(create_ssl_ctx_pair(TLS_server_method(),
+ TLS_client_method(),
+ TLS1_VERSION, TLS_MAX_VERSION,
+ sctx, cctx, cert, privkey)))
+ return 0;
+
+ if (!TEST_true(SSL_CTX_set_max_early_data(*sctx, SSL3_RT_MAX_PLAIN_LENGTH)))
return 0;
if (idx == 1) {
@@ -2156,12 +2159,65 @@ static int test_early_data_read_write(int idx)
return testresult;
}
-static int test_early_data_replay(int idx)
+static int allow_ed_cb_called = 0;
+
+static int allow_early_data_cb(SSL *s, void *arg)
+{
+ int *usecb = (int *)arg;
+
+ allow_ed_cb_called++;
+
+ if (*usecb == 1)
+ return 0;
+
+ return 1;
+}
+
+/*
+ * idx == 0: Standard early_data setup
+ * idx == 1: early_data setup using read_ahead
+ * usecb == 0: Don't use a custom early data callback
+ * usecb == 1: Use a custom early data callback and reject the early data
+ * usecb == 2: Use a custom early data callback and accept the early data
+ * confopt == 0: Configure anti-replay directly
+ * confopt == 1: Configure anti-replay using SSL_CONF
+ */
+static int test_early_data_replay_int(int idx, int usecb, int confopt)
{
SSL_CTX *cctx = NULL, *sctx = NULL;
SSL *clientssl = NULL, *serverssl = NULL;
int testresult = 0;
SSL_SESSION *sess = NULL;
+ size_t readbytes, written;
+ unsigned char buf[20];
+
+ allow_ed_cb_called = 0;
+
+ if (!TEST_true(create_ssl_ctx_pair(TLS_server_method(), TLS_client_method(),
+ TLS1_VERSION, TLS_MAX_VERSION, &sctx,
+ &cctx, cert, privkey)))
+ return 0;
+
+ if (usecb > 0) {
+ if (confopt == 0) {
+ SSL_CTX_set_options(sctx, SSL_OP_NO_ANTI_REPLAY);
+ } else {
+ SSL_CONF_CTX *confctx = SSL_CONF_CTX_new();
+
+ if (!TEST_ptr(confctx))
+ goto end;
+ SSL_CONF_CTX_set_flags(confctx, SSL_CONF_FLAG_FILE
+ | SSL_CONF_FLAG_SERVER);
+ SSL_CONF_CTX_set_ssl_ctx(confctx, sctx);
+ if (!TEST_int_eq(SSL_CONF_cmd(confctx, "Options", "-AntiReplay"),
+ 2)) {
+ SSL_CONF_CTX_free(confctx);
+ goto end;
+ }
+ SSL_CONF_CTX_free(confctx);
+ }
+ SSL_CTX_set_allow_early_data_cb(sctx, allow_early_data_cb, &usecb);
+ }
if (!TEST_true(setupearly_data_test(&cctx, &sctx, &clientssl,
&serverssl, &sess, idx)))
@@ -2183,14 +2239,49 @@ static int test_early_data_replay(int idx)
if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl,
&clientssl, NULL, NULL))
- || !TEST_true(SSL_set_session(clientssl, sess))
- || !TEST_true(create_ssl_connection(serverssl, clientssl,
- SSL_ERROR_NONE))
- /*
- * This time we should not have resumed the session because we
- * already used it once.
- */
- || !TEST_false(SSL_session_reused(clientssl)))
+ || !TEST_true(SSL_set_session(clientssl, sess)))
+ goto end;
+
+ /* Write and read some early data */
+ if (!TEST_true(SSL_write_early_data(clientssl, MSG1, strlen(MSG1),
+ &written))
+ || !TEST_size_t_eq(written, strlen(MSG1)))
+ goto end;
+
+ if (usecb <= 1) {
+ if (!TEST_int_eq(SSL_read_early_data(serverssl, buf, sizeof(buf),
+ &readbytes),
+ SSL_READ_EARLY_DATA_FINISH)
+ /*
+ * The ticket was reused, so the we should have rejected the
+ * early data
+ */
+ || !TEST_int_eq(SSL_get_early_data_status(serverssl),
+ SSL_EARLY_DATA_REJECTED))
+ goto end;
+ } else {
+ /* In this case the callback decides to accept the early data */
+ if (!TEST_int_eq(SSL_read_early_data(serverssl, buf, sizeof(buf),
+ &readbytes),
+ SSL_READ_EARLY_DATA_SUCCESS)
+ || !TEST_mem_eq(MSG1, strlen(MSG1), buf, readbytes)
+ /*
+ * Server will have sent its flight so client can now send
+ * end of early data and complete its half of the handshake
+ */
+ || !TEST_int_gt(SSL_connect(clientssl), 0)
+ || !TEST_int_eq(SSL_read_early_data(serverssl, buf, sizeof(buf),
+ &readbytes),
+ SSL_READ_EARLY_DATA_FINISH)
+ || !TEST_int_eq(SSL_get_early_data_status(serverssl),
+ SSL_EARLY_DATA_ACCEPTED))
+ goto end;
+ }
+
+ /* Complete the connection */
+ if (!TEST_true(create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE))
+ || !TEST_int_eq(SSL_session_reused(clientssl), (usecb > 0) ? 1 : 0)
+ || !TEST_int_eq(allow_ed_cb_called, usecb > 0 ? 1 : 0))
goto end;
testresult = 1;
@@ -2207,6 +2298,18 @@ static int test_early_data_replay(int idx)
return testresult;
}
+static int test_early_data_replay(int idx)
+{
+ int ret = 1, usecb, confopt;
+
+ for (usecb = 0; usecb < 3; usecb++) {
+ for (confopt = 0; confopt < 2; confopt++)
+ ret &= test_early_data_replay_int(idx, usecb, confopt);
+ }
+
+ return ret;
+}
+
/*
* Helper function to test that a server attempting to read early data can
* handle a connection from a client where the early data should be skipped.
diff --git a/util/libssl.num b/util/libssl.num
index 3495903..df6a71e 100644
--- a/util/libssl.num
+++ b/util/libssl.num
@@ -490,3 +490,5 @@ SSL_set_num_tickets 490 1_1_1 EXIST::FUNCTION:
SSL_CTX_get_num_tickets 491 1_1_1 EXIST::FUNCTION:
SSL_get_num_tickets 492 1_1_1 EXIST::FUNCTION:
SSL_CTX_set_num_tickets 493 1_1_1 EXIST::FUNCTION:
+SSL_CTX_set_allow_early_data_cb 494 1_1_1 EXIST::FUNCTION:
+SSL_set_allow_early_data_cb 495 1_1_1 EXIST::FUNCTION:
diff --git a/util/private.num b/util/private.num
index ac536a5..b90e33d 100644
--- a/util/private.num
+++ b/util/private.num
@@ -48,7 +48,9 @@ RAND_DRBG_cleanup_nonce_fn datatype
RAND_DRBG_get_entropy_fn datatype
RAND_DRBG_get_nonce_fn datatype
RAND_poll_cb datatype
+SSL_CTX_allow_early_data_cb_fn datatype
SSL_CTX_keylog_cb_func datatype
+SSL_allow_early_data_cb_fn datatype
SSL_client_hello_cb_fn datatype
SSL_psk_client_cb_func datatype
SSL_psk_find_session_cb_func datatype
More information about the openssl-commits
mailing list