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) {