Enforce compression_method in TLS 1.3 draft 22.

Change-Id: Ic99a949258e62cad168c2c39507ca63100a8ffe5
Reviewed-on: https://boringssl-review.googlesource.com/23264
Reviewed-by: David Benjamin <davidben@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
diff --git a/ssl/handshake_client.cc b/ssl/handshake_client.cc
index 583aceb..7b1c097 100644
--- a/ssl/handshake_client.cc
+++ b/ssl/handshake_client.cc
@@ -295,33 +295,14 @@
     return 0;
   }
 
-  // Renegotiations do not participate in session resumption.
-  int has_session_id = ssl->session != NULL &&
-                       !ssl->s3->initial_handshake_complete &&
-                       ssl->session->session_id_length > 0;
-
   CBB child;
   if (!CBB_add_u16(&body, hs->client_version) ||
       !CBB_add_bytes(&body, ssl->s3->client_random, SSL3_RANDOM_SIZE) ||
-      !CBB_add_u8_length_prefixed(&body, &child)) {
+      !CBB_add_u8_length_prefixed(&body, &child) ||
+      !CBB_add_bytes(&child, hs->session_id, hs->session_id_len)) {
     return 0;
   }
 
-  if (has_session_id) {
-    if (!CBB_add_bytes(&child, ssl->session->session_id,
-                       ssl->session->session_id_length)) {
-      return 0;
-    }
-  } else {
-    // In TLS 1.3 experimental encodings, send a fake placeholder session ID
-    // when we do not otherwise have one to send.
-    if (hs->max_version >= TLS1_3_VERSION &&
-        ssl_is_resumption_variant(ssl->tls13_variant) &&
-        !CBB_add_bytes(&child, hs->session_id, hs->session_id_len)) {
-      return 0;
-    }
-  }
-
   if (SSL_is_dtls(ssl)) {
     if (!CBB_add_u8_length_prefixed(&body, &child) ||
         !CBB_add_bytes(&child, ssl->d1->cookie, ssl->d1->cookie_len)) {
@@ -472,7 +453,13 @@
 
   // Initialize a random session ID for the experimental TLS 1.3 variant
   // requiring a session id.
-  if (ssl_is_resumption_variant(ssl->tls13_variant)) {
+  if (ssl->session != nullptr &&
+      !ssl->s3->initial_handshake_complete &&
+      ssl->session->session_id_length > 0) {
+    hs->session_id_len = ssl->session->session_id_length;
+    OPENSSL_memcpy(hs->session_id, ssl->session->session_id,
+                   hs->session_id_len);
+  } else if (ssl_is_resumption_variant(ssl->tls13_variant)) {
     hs->session_id_len = sizeof(hs->session_id);
     if (!RAND_bytes(hs->session_id, hs->session_id_len)) {
       return ssl_hs_error;
diff --git a/ssl/test/runner/handshake_messages.go b/ssl/test/runner/handshake_messages.go
index 22eb013..1fd84cb 100644
--- a/ssl/test/runner/handshake_messages.go
+++ b/ssl/test/runner/handshake_messages.go
@@ -1356,6 +1356,7 @@
 	isServerHello       bool
 	sessionId           []byte
 	cipherSuite         uint16
+	compressionMethod   uint8
 	hasSelectedGroup    bool
 	selectedGroup       CurveID
 	cookie              []byte
@@ -1382,7 +1383,7 @@
 		sessionId := retryRequest.addU8LengthPrefixed()
 		sessionId.addBytes(m.sessionId)
 		retryRequest.addU16(m.cipherSuite)
-		retryRequest.addU8(0)
+		retryRequest.addU8(m.compressionMethod)
 	} else {
 		retryRequest.addU16(m.vers)
 		if isDraft21(m.vers) {
diff --git a/ssl/test/runner/handshake_server.go b/ssl/test/runner/handshake_server.go
index 4286911..595f8da 100644
--- a/ssl/test/runner/handshake_server.go
+++ b/ssl/test/runner/handshake_server.go
@@ -368,6 +368,7 @@
 		isDTLS:                c.isDTLS,
 		vers:                  c.wireVersion,
 		sessionId:             hs.clientHello.sessionId,
+		compressionMethod:     config.Bugs.SendCompressionMethod,
 		versOverride:          config.Bugs.SendServerHelloVersion,
 		supportedVersOverride: config.Bugs.SendServerSupportedExtensionVersion,
 		customExtension:       config.Bugs.CustomUnencryptedExtension,
@@ -534,6 +535,7 @@
 		vers:                c.wireVersion,
 		sessionId:           hs.clientHello.sessionId,
 		cipherSuite:         cipherSuite,
+		compressionMethod:   config.Bugs.SendCompressionMethod,
 		duplicateExtensions: config.Bugs.DuplicateHelloRetryRequestExtensions,
 	}
 
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go
index 8700af2..4f6fd13 100644
--- a/ssl/test/runner/runner.go
+++ b/ssl/test/runner/runner.go
@@ -2785,6 +2785,34 @@
 			expectedLocalError: "remote error: illegal parameter",
 		},
 		{
+			testType: clientTest,
+			name:     "TLS13Draft22-InvalidCompressionMethod",
+			config: Config{
+				MaxVersion: VersionTLS13,
+				Bugs: ProtocolBugs{
+					SendCompressionMethod: 1,
+				},
+			},
+			tls13Variant:  TLS13Draft22,
+			shouldFail:    true,
+			expectedError: ":DECODE_ERROR:",
+		},
+		{
+			testType: clientTest,
+			name:     "TLS13Draft22-HRR-InvalidCompressionMethod",
+			config: Config{
+				MaxVersion:       VersionTLS13,
+				CurvePreferences: []CurveID{CurveP384},
+				Bugs: ProtocolBugs{
+					SendCompressionMethod: 1,
+				},
+			},
+			tls13Variant:       TLS13Draft22,
+			shouldFail:         true,
+			expectedError:      ":DECODE_ERROR:",
+			expectedLocalError: "remote error: error decoding message",
+		},
+		{
 			name: "GREASE-Client-TLS12",
 			config: Config{
 				MaxVersion: VersionTLS12,
@@ -11017,6 +11045,23 @@
 			resumeSession: true,
 		})
 
+		// Test that the client correctly handles a TLS 1.3 ServerHello which echoes
+		// a TLS 1.2 session ID.
+		testCases = append(testCases, testCase{
+			testType: clientTest,
+			name:     "TLS12SessionID-" + name,
+			config: Config{
+				MaxVersion:             VersionTLS12,
+				SessionTicketsDisabled: true,
+			},
+			resumeConfig: &Config{
+				MaxVersion: VersionTLS13,
+			},
+			tls13Variant:         variant,
+			resumeSession:        true,
+			expectResumeRejected: true,
+		})
+
 		// Test that the server correctly echoes back session IDs of
 		// various lengths.
 		testCases = append(testCases, testCase{
diff --git a/ssl/tls13_client.cc b/ssl/tls13_client.cc
index 688fa06..f471a4e 100644
--- a/ssl/tls13_client.cc
+++ b/ssl/tls13_client.cc
@@ -75,11 +75,14 @@
 
     CBS body = msg.body, server_random, session_id;
     uint16_t server_version;
+    uint8_t compression_method;
     if (!CBS_get_u16(&body, &server_version) ||
         !CBS_get_bytes(&body, &server_random, SSL3_RANDOM_SIZE) ||
         !CBS_get_u8_length_prefixed(&body, &session_id) ||
+        !CBS_mem_equal(&session_id, hs->session_id, hs->session_id_len) ||
         !CBS_get_u16(&body, &cipher_suite) ||
-        !CBS_skip(&body, 1) ||
+        !CBS_get_u8(&body, &compression_method) ||
+        compression_method != 0 ||
         !CBS_get_u16_length_prefixed(&body, &extensions) ||
         CBS_len(&extensions) == 0 ||
         CBS_len(&body) != 0) {
@@ -251,7 +254,8 @@
   if (!CBS_get_u16(&body, &server_version) ||
       !CBS_get_bytes(&body, &server_random, SSL3_RANDOM_SIZE) ||
       (ssl_is_resumption_experiment(ssl->version) &&
-       !CBS_get_u8_length_prefixed(&body, &session_id)) ||
+       (!CBS_get_u8_length_prefixed(&body, &session_id) ||
+        !CBS_mem_equal(&session_id, hs->session_id, hs->session_id_len))) ||
       !CBS_get_u16(&body, &cipher_suite) ||
       (ssl_is_resumption_experiment(ssl->version) &&
        (!CBS_get_u8(&body, &compression_method) || compression_method != 0)) ||