Apply GREASE to TLS 1.3 tickets. Change-Id: I5d4fc0d3204744e93d71a36923469035c19a5b10 Reviewed-on: https://boringssl-review.googlesource.com/11560 CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org> Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> Commit-Queue: David Benjamin <davidben@google.com>
diff --git a/ssl/internal.h b/ssl/internal.h index 3e7c053..720b822 100644 --- a/ssl/internal.h +++ b/ssl/internal.h
@@ -1024,6 +1024,7 @@ ssl_grease_extension1, ssl_grease_extension2, ssl_grease_version, + ssl_grease_ticket_extension, }; /* ssl_get_grease_value returns a GREASE value for |ssl|. For a given
diff --git a/ssl/test/runner/common.go b/ssl/test/runner/common.go index 309cd82..1449550 100644 --- a/ssl/test/runner/common.go +++ b/ssl/test/runner/common.go
@@ -1127,8 +1127,8 @@ // invalid Channel ID signature. InvalidChannelIDSignature bool - // ExpectGREASE, if true, causes the server to reject a ClientHello - // unless it contains GREASE values. See draft-davidben-tls-grease-01. + // ExpectGREASE, if true, causes messages without GREASE values to be + // rejected. See draft-davidben-tls-grease-01. ExpectGREASE bool }
diff --git a/ssl/test/runner/conn.go b/ssl/test/runner/conn.go index 84e1eb8..7f395d5 100644 --- a/ssl/test/runner/conn.go +++ b/ssl/test/runner/conn.go
@@ -1398,6 +1398,10 @@ if c.isClient { if newSessionTicket, ok := msg.(*newSessionTicketMsg); ok { + if c.config.Bugs.ExpectGREASE && !newSessionTicket.hasGREASEExtension { + return errors.New("tls: no GREASE ticket extension found") + } + if c.config.ClientSessionCache == nil || newSessionTicket.ticketLifetime == 0 { return nil }
diff --git a/ssl/test/runner/handshake_messages.go b/ssl/test/runner/handshake_messages.go index 19578e8..9864b0a 100644 --- a/ssl/test/runner/handshake_messages.go +++ b/ssl/test/runner/handshake_messages.go
@@ -1819,12 +1819,13 @@ } type newSessionTicketMsg struct { - raw []byte - version uint16 - ticketLifetime uint32 - keModes []byte - authModes []byte - ticket []byte + raw []byte + version uint16 + ticketLifetime uint32 + keModes []byte + authModes []byte + ticket []byte + hasGREASEExtension bool } func (m *newSessionTicketMsg) marshal() []byte { @@ -1913,7 +1914,24 @@ if len(data) < extsLength { return false } + extensions := data[:extsLength] data = data[extsLength:] + + for len(extensions) > 0 { + if len(extensions) < 4 { + return false + } + extValue := uint16(extensions[0])<<8 | uint16(extensions[1]) + extLength := int(extensions[2])<<8 | int(extensions[3]) + if len(extensions) < 4+extLength { + return false + } + extensions = extensions[4+extLength:] + + if isGREASEValue(extValue) { + m.hasGREASEExtension = true + } + } } if len(data) > 0 {
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go index 248c6eb..a7fd154 100644 --- a/ssl/test/runner/runner.go +++ b/ssl/test/runner/runner.go
@@ -2263,7 +2263,7 @@ expectedLocalError: "remote error: illegal parameter", }, { - name: "GREASE-TLS12", + name: "GREASE-Client-TLS12", config: Config{ MaxVersion: VersionTLS12, Bugs: ProtocolBugs{ @@ -2273,7 +2273,18 @@ flags: []string{"-enable-grease"}, }, { - name: "GREASE-TLS13", + name: "GREASE-Client-TLS13", + config: Config{ + MaxVersion: VersionTLS13, + Bugs: ProtocolBugs{ + ExpectGREASE: true, + }, + }, + flags: []string{"-enable-grease"}, + }, + { + testType: serverTest, + name: "GREASE-Server-TLS13", config: Config{ MaxVersion: VersionTLS13, Bugs: ProtocolBugs{
diff --git a/ssl/tls13_server.c b/ssl/tls13_server.c index 984cc5c..7332347 100644 --- a/ssl/tls13_server.c +++ b/ssl/tls13_server.c
@@ -541,7 +541,7 @@ /* TODO(svaldez): Add support for sending 0RTT through TicketEarlyDataInfo * extension. */ - CBB cbb, body, ke_modes, auth_modes, ticket; + CBB cbb, body, ke_modes, auth_modes, ticket, extensions; if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_NEW_SESSION_TICKET) || !CBB_add_u32(&body, session->tlsext_tick_lifetime_hint) || @@ -551,16 +551,31 @@ !CBB_add_u8(&auth_modes, SSL_PSK_AUTH) || !CBB_add_u16_length_prefixed(&body, &ticket) || !ssl_encrypt_ticket(ssl, &ticket, session) || - !CBB_add_u16(&body, 0 /* no ticket extensions */) || - !ssl->method->finish_message(ssl, &cbb)) { - CBB_cleanup(&cbb); - return ssl_hs_error; + !CBB_add_u16_length_prefixed(&body, &extensions)) { + goto err; + } + + /* Add a fake extension. See draft-davidben-tls-grease-01. */ + if (ssl->ctx->grease_enabled) { + if (!CBB_add_u16(&extensions, + ssl_get_grease_value(ssl, ssl_grease_ticket_extension)) || + !CBB_add_u16(&extensions, 0 /* empty */)) { + goto err; + } + } + + if (!ssl->method->finish_message(ssl, &cbb)) { + goto err; } hs->session_tickets_sent++; hs->state = state_flush_new_session_ticket; return ssl_hs_write_message; + +err: + CBB_cleanup(&cbb); + return ssl_hs_error; } /* TLS 1.3 recommends single-use tickets, so issue multiple tickets in case the