diff --git a/apps/s_server.c b/apps/s_server.c index df2bf02a6e..b0502005cc 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 2b7db637b1..f601794372 100644 --- a/doc/man1/s_server.pod +++ b/doc/man1/s_server.pod @@ -180,6 +180,8 @@ B B [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 4d3e9c2b72..4edd49ca0b 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. +=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. + =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. +B: 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. + =item B The B argument is a comma separated list of flags to set. diff --git a/ssl/ssl_conf.c b/ssl/ssl_conf.c index 758f012938..9c202708d7 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/test/sslapitest.c b/test/sslapitest.c index 91d3bf97cf..6e08795f2d 100644 --- a/test/sslapitest.c +++ b/test/sslapitest.c @@ -2179,8 +2179,10 @@ static int allow_early_data_cb(SSL *s, void *arg) * 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) +static int test_early_data_replay_int(int idx, int usecb, int confopt) { SSL_CTX *cctx = NULL, *sctx = NULL; SSL *clientssl = NULL, *serverssl = NULL; @@ -2197,7 +2199,23 @@ static int test_early_data_replay_int(int idx, int usecb) return 0; if (usecb > 0) { - SSL_CTX_set_options(sctx, SSL_OP_NO_ANTI_REPLAY); + 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); } @@ -2282,11 +2300,12 @@ static int test_early_data_replay_int(int idx, int usecb) static int test_early_data_replay(int idx) { - int ret; + int ret = 1, usecb, confopt; - ret = test_early_data_replay_int(idx, 0); - ret &= test_early_data_replay_int(idx, 1); - ret &= test_early_data_replay_int(idx, 2); + for (usecb = 0; usecb < 3; usecb++) { + for (confopt = 0; confopt < 2; confopt++) + ret &= test_early_data_replay_int(idx, usecb, confopt); + } return ret; }