Fix TLS 1.3 NewSessionTicket processing.
08b65f4e31f7eb63bad0e903e9f191bcc699eaca introduced a memory leak and
also got enums confused. Also fix a codepath that was missing an error
code.
Thanks to OSS-Fuzz which appears to have found it in a matter of hours.
Change-Id: Ia9e926c28a01daab3e6154d363d0acda91209a22
Reviewed-on: https://boringssl-review.googlesource.com/13104
Commit-Queue: David Benjamin <davidben@google.com>
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/ssl/test/runner/common.go b/ssl/test/runner/common.go
index 029fd4a..96bc39a 100644
--- a/ssl/test/runner/common.go
+++ b/ssl/test/runner/common.go
@@ -960,6 +960,10 @@
// extension of the NewSessionTicket message.
SendTicketEarlyDataInfo uint32
+ // DuplicateTicketEarlyDataInfo causes an extra empty extension of
+ // ticket_early_data_info to be sent in NewSessionTicket.
+ DuplicateTicketEarlyDataInfo bool
+
// ExpectTicketEarlyDataInfo, if true, means that the client will fail upon
// absence of the ticket_early_data_info extension.
ExpectTicketEarlyDataInfo bool
diff --git a/ssl/test/runner/conn.go b/ssl/test/runner/conn.go
index 62a46bf..ee342fa 100644
--- a/ssl/test/runner/conn.go
+++ b/ssl/test/runner/conn.go
@@ -1767,11 +1767,12 @@
// TODO(davidben): Allow configuring these values.
m := &newSessionTicketMsg{
- version: c.vers,
- ticketLifetime: uint32(24 * time.Hour / time.Second),
- earlyDataInfo: c.config.Bugs.SendTicketEarlyDataInfo,
- customExtension: c.config.Bugs.CustomTicketExtension,
- ticketAgeAdd: ticketAgeAdd,
+ version: c.vers,
+ ticketLifetime: uint32(24 * time.Hour / time.Second),
+ earlyDataInfo: c.config.Bugs.SendTicketEarlyDataInfo,
+ duplicateEarlyDataInfo: c.config.Bugs.DuplicateTicketEarlyDataInfo,
+ customExtension: c.config.Bugs.CustomTicketExtension,
+ ticketAgeAdd: ticketAgeAdd,
}
state := sessionState{
diff --git a/ssl/test/runner/handshake_messages.go b/ssl/test/runner/handshake_messages.go
index a431cb5..62309b8 100644
--- a/ssl/test/runner/handshake_messages.go
+++ b/ssl/test/runner/handshake_messages.go
@@ -2003,14 +2003,15 @@
}
type newSessionTicketMsg struct {
- raw []byte
- version uint16
- ticketLifetime uint32
- ticketAgeAdd uint32
- ticket []byte
- earlyDataInfo uint32
- customExtension string
- hasGREASEExtension bool
+ raw []byte
+ version uint16
+ ticketLifetime uint32
+ ticketAgeAdd uint32
+ ticket []byte
+ earlyDataInfo uint32
+ customExtension string
+ duplicateEarlyDataInfo bool
+ hasGREASEExtension bool
}
func (m *newSessionTicketMsg) marshal() []byte {
@@ -2035,6 +2036,10 @@
if m.earlyDataInfo > 0 {
extensions.addU16(extensionTicketEarlyDataInfo)
extensions.addU16LengthPrefixed().addU32(m.earlyDataInfo)
+ if m.duplicateEarlyDataInfo {
+ extensions.addU16(extensionTicketEarlyDataInfo)
+ extensions.addU16LengthPrefixed().addU32(m.earlyDataInfo)
+ }
}
if len(m.customExtension) > 0 {
extensions.addU16(extensionCustom)
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go
index 5c3d914..ba78fce 100644
--- a/ssl/test/runner/runner.go
+++ b/ssl/test/runner/runner.go
@@ -8394,6 +8394,21 @@
})
testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: "TLS13-DuplicateTicketEarlyDataInfo",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ SendTicketEarlyDataInfo: 16384,
+ DuplicateTicketEarlyDataInfo: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":DUPLICATE_EXTENSION:",
+ expectedLocalError: "remote error: illegal parameter",
+ })
+
+ testCases = append(testCases, testCase{
testType: serverTest,
name: "TLS13-ExpectTicketEarlyDataInfo",
config: Config{
diff --git a/ssl/tls13_client.c b/ssl/tls13_client.c
index 1d8bc54..6f2bb21 100644
--- a/ssl/tls13_client.c
+++ b/ssl/tls13_client.c
@@ -638,6 +638,7 @@
}
int tls13_process_new_session_ticket(SSL *ssl) {
+ int ret = 0;
SSL_SESSION *session =
SSL_SESSION_dup(ssl->s3->established_session,
SSL_SESSION_INCLUDE_NONAUTH);
@@ -655,10 +656,9 @@
!CBS_stow(&ticket, &session->tlsext_tick, &session->tlsext_ticklen) ||
!CBS_get_u16_length_prefixed(&cbs, &extensions) ||
CBS_len(&cbs) != 0) {
- SSL_SESSION_free(session);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
- return 0;
+ goto err;
}
/* Parse out the extensions. */
@@ -674,14 +674,15 @@
OPENSSL_ARRAY_SIZE(ext_types),
1 /* ignore unknown */)) {
ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
- return ssl_hs_error;
+ goto err;
}
if (have_early_data_info) {
if (!CBS_get_u32(&early_data_info, &session->ticket_max_early_data) ||
CBS_len(&early_data_info) != 0) {
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
- return ssl_hs_error;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ goto err;
}
}
@@ -691,11 +692,14 @@
if (ssl->ctx->new_session_cb != NULL &&
ssl->ctx->new_session_cb(ssl, session)) {
/* |new_session_cb|'s return value signals that it took ownership. */
- return 1;
+ session = NULL;
}
+ ret = 1;
+
+err:
SSL_SESSION_free(session);
- return 1;
+ return ret;
}
void ssl_clear_tls13_state(SSL_HANDSHAKE *hs) {