Don't mint TLS 1.3 tickets if SSL_OP_NO_TICKETS is set.
Change-Id: I03e05acb024e34beaeaf2f02860da1763e08a093
Reviewed-on: https://boringssl-review.googlesource.com/29844
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/ssl/test/runner/common.go b/ssl/test/runner/common.go
index f77a4cc..aa17350 100644
--- a/ssl/test/runner/common.go
+++ b/ssl/test/runner/common.go
@@ -137,8 +137,8 @@
extensionNextProtoNeg uint16 = 13172 // not IANA assigned
extensionRenegotiationInfo uint16 = 0xff01
extensionQUICTransportParams uint16 = 0xffa5 // draft-ietf-quic-tls-13
- extensionChannelID uint16 = 30032 // not IANA assigned
- extensionDummyPQPadding uint16 = 54537 // not IANA assigned
+ extensionChannelID uint16 = 30032 // not IANA assigned
+ extensionDummyPQPadding uint16 = 54537 // not IANA assigned
)
// TLS signaling cipher suite values
@@ -1168,6 +1168,10 @@
// sessions use session tickets instead of session IDs.
RequireSessionTickets bool
+ // RequireSessionIDs, if true, causes the client to require new sessions use
+ // session IDs instead of session tickets.
+ RequireSessionIDs bool
+
// NullAllCiphers, if true, causes every cipher to behave like the null
// cipher.
NullAllCiphers bool
diff --git a/ssl/test/runner/handshake_client.go b/ssl/test/runner/handshake_client.go
index f367dc4..3e20d87 100644
--- a/ssl/test/runner/handshake_client.go
+++ b/ssl/test/runner/handshake_client.go
@@ -729,6 +729,9 @@
if c.config.Bugs.RequireSessionTickets && len(hs.session.sessionTicket) == 0 {
return errors.New("tls: new session used session IDs instead of tickets")
}
+ if c.config.Bugs.RequireSessionIDs && len(hs.session.sessionId) == 0 {
+ return errors.New("tls: new session used session tickets instead of IDs")
+ }
sessionCache.Put(cacheKey, hs.session)
}
@@ -1672,6 +1675,9 @@
if c.vers == VersionSSL30 {
return errors.New("tls: negotiated session tickets in SSL 3.0")
}
+ if c.config.Bugs.ExpectNoNewSessionTicket {
+ return errors.New("tls: received unexpected NewSessionTicket")
+ }
msg, err := c.readHandshake()
if err != nil {
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go
index f5fac2b..7597764 100644
--- a/ssl/test/runner/runner.go
+++ b/ssl/test/runner/runner.go
@@ -11163,6 +11163,44 @@
resumeSession: true,
expectResumeRejected: true,
})
+
+ for _, ver := range tlsVersions {
+ // Prior to TLS 1.3, disabling session tickets enables session IDs.
+ useStatefulResumption := ver.version < VersionTLS13
+
+ // SSL_OP_NO_TICKET implies the server must not mint any tickets.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: ver.name + "-NoTicket-NoMint",
+ config: Config{
+ MinVersion: ver.version,
+ MaxVersion: ver.version,
+ Bugs: ProtocolBugs{
+ ExpectNoNewSessionTicket: true,
+ RequireSessionIDs: useStatefulResumption,
+ },
+ },
+ resumeSession: useStatefulResumption,
+ tls13Variant: ver.tls13Variant,
+ flags: []string{"-no-ticket"},
+ })
+
+ // SSL_OP_NO_TICKET implies the server must not accept any tickets.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: ver.name + "-NoTicket-NoAccept",
+ config: Config{
+ MinVersion: ver.version,
+ MaxVersion: ver.version,
+ },
+ tls13Variant: ver.tls13Variant,
+ resumeSession: true,
+ expectResumeRejected: true,
+ // Set SSL_OP_NO_TICKET on the second connection, after the first
+ // has established tickets.
+ flags: []string{"-on-resume-no-ticket"},
+ })
+ }
}
func addChangeCipherSpecTests() {
diff --git a/ssl/test/test_config.cc b/ssl/test/test_config.cc
index 1731431..c973fb5 100644
--- a/ssl/test/test_config.cc
+++ b/ssl/test/test_config.cc
@@ -66,6 +66,7 @@
{ "-no-tls12", &TestConfig::no_tls12 },
{ "-no-tls11", &TestConfig::no_tls11 },
{ "-no-tls1", &TestConfig::no_tls1 },
+ { "-no-ticket", &TestConfig::no_ticket },
{ "-enable-channel-id", &TestConfig::enable_channel_id },
{ "-shim-writes-first", &TestConfig::shim_writes_first },
{ "-expect-session-miss", &TestConfig::expect_session_miss },
@@ -1498,6 +1499,9 @@
if (no_tls1) {
SSL_set_options(ssl.get(), SSL_OP_NO_TLSv1);
}
+ if (no_ticket) {
+ SSL_set_options(ssl.get(), SSL_OP_NO_TICKET);
+ }
if (!expected_channel_id.empty() || enable_channel_id) {
SSL_set_tls_channel_id_enabled(ssl.get(), 1);
}
diff --git a/ssl/test/test_config.h b/ssl/test/test_config.h
index fef029f..f6c66e6 100644
--- a/ssl/test/test_config.h
+++ b/ssl/test/test_config.h
@@ -50,6 +50,7 @@
bool no_tls12 = false;
bool no_tls11 = false;
bool no_tls1 = false;
+ bool no_ticket = false;
std::string expected_channel_id;
bool enable_channel_id = false;
std::string send_channel_id;
diff --git a/ssl/tls13_server.cc b/ssl/tls13_server.cc
index 3c2c774..203e704 100644
--- a/ssl/tls13_server.cc
+++ b/ssl/tls13_server.cc
@@ -148,8 +148,18 @@
return best;
}
-static int add_new_session_tickets(SSL_HANDSHAKE *hs) {
+static bool add_new_session_tickets(SSL_HANDSHAKE *hs, bool *out_sent_tickets) {
SSL *const ssl = hs->ssl;
+ if (// If the client doesn't accept resumption with PSK_DHE_KE, don't send a
+ // session ticket.
+ !hs->accept_psk_mode ||
+ // We only implement stateless resumption in TLS 1.3, so skip sending
+ // tickets if disabled.
+ (SSL_get_options(ssl) & SSL_OP_NO_TICKET)) {
+ *out_sent_tickets = false;
+ return true;
+ }
+
// TLS 1.3 recommends single-use tickets, so issue multiple tickets in case
// the client makes several connections before getting a renewal.
static const int kNumTickets = 2;
@@ -162,11 +172,11 @@
UniquePtr<SSL_SESSION> session(
SSL_SESSION_dup(hs->new_session.get(), SSL_SESSION_INCLUDE_NONAUTH));
if (!session) {
- return 0;
+ return false;
}
if (!RAND_bytes((uint8_t *)&session->ticket_age_add, 4)) {
- return 0;
+ return false;
}
session->ticket_age_add_valid = true;
if (ssl->enable_early_data) {
@@ -188,7 +198,7 @@
!tls13_derive_session_psk(session.get(), nonce) ||
!ssl_encrypt_ticket(hs, &ticket, session.get()) ||
!CBB_add_u16_length_prefixed(&body, &extensions)) {
- return 0;
+ return false;
}
if (ssl->enable_early_data) {
@@ -197,7 +207,7 @@
!CBB_add_u16_length_prefixed(&extensions, &early_data_info) ||
!CBB_add_u32(&early_data_info, session->ticket_max_early_data) ||
!CBB_flush(&extensions)) {
- return 0;
+ return false;
}
}
@@ -205,15 +215,16 @@
if (!CBB_add_u16(&extensions,
ssl_get_grease_value(hs, ssl_grease_ticket_extension)) ||
!CBB_add_u16(&extensions, 0 /* empty */)) {
- return 0;
+ return false;
}
if (!ssl_add_message_cbb(ssl, cbb.get())) {
- return 0;
+ return false;
}
}
- return 1;
+ *out_sent_tickets = true;
+ return true;
}
static enum ssl_hs_wait_t do_select_parameters(SSL_HANDSHAKE *hs) {
@@ -723,11 +734,12 @@
assert(hs->hash_len <= 0xff);
uint8_t header[4] = {SSL3_MT_FINISHED, 0, 0,
static_cast<uint8_t>(hs->hash_len)};
+ bool unused_sent_tickets;
if (!hs->transcript.Update(header) ||
!hs->transcript.Update(
MakeConstSpan(hs->expected_client_finished, hs->hash_len)) ||
!tls13_derive_resumption_secret(hs) ||
- !add_new_session_tickets(hs)) {
+ !add_new_session_tickets(hs, &unused_sent_tickets)) {
return ssl_hs_error;
}
}
@@ -904,19 +916,13 @@
}
static enum ssl_hs_wait_t do_send_new_session_ticket(SSL_HANDSHAKE *hs) {
- // If the client doesn't accept resumption with PSK_DHE_KE, don't send a
- // session ticket.
- if (!hs->accept_psk_mode) {
- hs->tls13_state = state_done;
- return ssl_hs_ok;
- }
-
- if (!add_new_session_tickets(hs)) {
+ bool sent_tickets;
+ if (!add_new_session_tickets(hs, &sent_tickets)) {
return ssl_hs_error;
}
hs->tls13_state = state_done;
- return ssl_hs_flush;
+ return sent_tickets ? ssl_hs_flush : ssl_hs_ok;
}
enum ssl_hs_wait_t tls13_server_handshake(SSL_HANDSHAKE *hs) {