Update dummy PQ extension for round two.

In this round, Google servers will echo the extension in order to test
the latency of both parties sending a PQ key-agreement message.

The extension is sent (and echoed) for both full and resumption
handshakes. This is intended to mirror the overhead of TLS 1.3 (even
when using TLS 1.2), as a resumption in TLS 1.3 still does a fresh key
agreement.

Change-Id: I9ad163afac4fd1d916f9c7359ec32994e283abeb
Reviewed-on: https://boringssl-review.googlesource.com/26185
Commit-Queue: David Benjamin <davidben@google.com>
Reviewed-by: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
diff --git a/ssl/internal.h b/ssl/internal.h
index b67637d..a2205c9 100644
--- a/ssl/internal.h
+++ b/ssl/internal.h
@@ -1514,6 +1514,10 @@
   // grease_seed is the entropy for GREASE values. It is valid if
   // |grease_seeded| is true.
   uint8_t grease_seed[ssl_grease_last_index + 1] = {0};
+
+  // dummy_pq_padding_len is the length of the extension that should be echoed
+  // in a ServerHello, or zero if no extension should be echoed.
+  uint16_t dummy_pq_padding_len = 0;
 };
 
 UniquePtr<SSL_HANDSHAKE> ssl_handshake_new(SSL *ssl);
diff --git a/ssl/t1_lib.cc b/ssl/t1_lib.cc
index 5693264..4d3c4c7 100644
--- a/ssl/t1_lib.cc
+++ b/ssl/t1_lib.cc
@@ -2324,12 +2324,7 @@
 // key-exchange and so enable measurement of the latency impact of the
 // additional bandwidth.
 
-static bool ext_dummy_pq_padding_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
-  const size_t len = hs->ssl->dummy_pq_padding_len;
-  if (len == 0) {
-    return true;
-  }
-
+static bool ext_dummy_pq_padding_add(CBB *out, size_t len) {
   CBB contents;
   uint8_t *buffer;
   if (!CBB_add_u16(out, TLSEXT_TYPE_dummy_pq_padding) ||
@@ -2351,6 +2346,33 @@
   return CBB_flush(out);
 }
 
+static bool ext_dummy_pq_padding_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
+  const size_t len = hs->ssl->dummy_pq_padding_len;
+  if (len == 0) {
+    return true;
+  }
+
+  return ext_dummy_pq_padding_add(out, len);
+}
+
+static bool ext_dummy_pq_padding_parse_clienthello(SSL_HANDSHAKE *hs,
+                                                   uint8_t *out_alert,
+                                                   CBS *contents) {
+  if (contents != nullptr &&
+      0 < CBS_len(contents) && CBS_len(contents) < (1 << 12)) {
+    hs->dummy_pq_padding_len = CBS_len(contents);
+  }
+
+  return true;
+}
+
+static bool ext_dummy_pq_padding_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) {
+  if (!hs->dummy_pq_padding_len) {
+    return true;
+  }
+
+  return ext_dummy_pq_padding_add(out, hs->dummy_pq_padding_len);
+}
 
 // Negotiated Groups
 //
@@ -2795,8 +2817,8 @@
     NULL,
     ext_dummy_pq_padding_add_clienthello,
     ignore_parse_serverhello,
-    ignore_parse_clienthello,
-    dont_add_serverhello,
+    ext_dummy_pq_padding_parse_clienthello,
+    ext_dummy_pq_padding_add_serverhello,
   },
   {
     TLSEXT_TYPE_quic_transport_parameters,
diff --git a/ssl/test/runner/common.go b/ssl/test/runner/common.go
index 1192948..16f4dd7 100644
--- a/ssl/test/runner/common.go
+++ b/ssl/test/runner/common.go
@@ -1552,6 +1552,10 @@
 	// length.
 	ExpectDummyPQPaddingLength int
 
+	// SendDummyPQPaddingLength causes a client to send a dummy PQ padding
+	// extension of the given length in the ClientHello.
+	SendDummyPQPaddingLength int
+
 	// SendCompressedCoordinates, if true, causes ECDH key shares over NIST
 	// curves to use compressed coordinates.
 	SendCompressedCoordinates bool
diff --git a/ssl/test/runner/handshake_client.go b/ssl/test/runner/handshake_client.go
index c8b1f37..2ebb5a8 100644
--- a/ssl/test/runner/handshake_client.go
+++ b/ssl/test/runner/handshake_client.go
@@ -100,6 +100,7 @@
 		pskBinderFirst:          c.config.Bugs.PSKBinderFirst,
 		omitExtensions:          c.config.Bugs.OmitExtensions,
 		emptyExtensions:         c.config.Bugs.EmptyExtensions,
+		dummyPQPaddingLen:       c.config.Bugs.SendDummyPQPaddingLength,
 	}
 
 	if maxVersion >= VersionTLS13 {
@@ -1492,6 +1493,11 @@
 		}
 		c.quicTransportParams = serverExtensions.quicTransportParams
 	}
+
+	if l := c.config.Bugs.ExpectDummyPQPaddingLength; l != 0 && serverExtensions.dummyPQPaddingLen != l {
+		return fmt.Errorf("tls: expected %d-byte dummy PQ padding extension, but got %d bytes", l, serverExtensions.dummyPQPaddingLen)
+	}
+
 	return nil
 }
 
diff --git a/ssl/test/runner/handshake_messages.go b/ssl/test/runner/handshake_messages.go
index b19506d..b9fb89d 100644
--- a/ssl/test/runner/handshake_messages.go
+++ b/ssl/test/runner/handshake_messages.go
@@ -571,6 +571,11 @@
 		customExt := extensions.addU16LengthPrefixed()
 		customExt.addBytes([]byte(m.customExtension))
 	}
+	if l := m.dummyPQPaddingLen; l != 0 {
+		extensions.addU16(extensionDummyPQPadding)
+		body := extensions.addU16LengthPrefixed()
+		body.addBytes(make([]byte, l))
+	}
 	// The PSK extension must be last (draft-ietf-tls-tls13-18 section 4.2.6).
 	if len(m.pskIdentities) > 0 && !m.pskBinderFirst {
 		extensions.addU16(extensionPreSharedKey)
@@ -1144,6 +1149,7 @@
 	supportedCurves         []CurveID
 	quicTransportParams     []byte
 	serverNameAck           bool
+	dummyPQPaddingLen       int
 }
 
 func (m *serverExtensions) marshal(extensions *byteBuilder) {
@@ -1278,6 +1284,11 @@
 		extensions.addU16(extensionServerName)
 		extensions.addU16(0) // zero length
 	}
+	if l := m.dummyPQPaddingLen; l != 0 {
+		extensions.addU16(extensionDummyPQPadding)
+		body := extensions.addU16LengthPrefixed()
+		body.addBytes(make([]byte, l))
+	}
 }
 
 func (m *serverExtensions) unmarshal(data byteReader, version uint16) bool {
@@ -1382,6 +1393,8 @@
 				return false
 			}
 			m.hasEarlyData = true
+		case extensionDummyPQPadding:
+			m.dummyPQPaddingLen = len(body)
 		default:
 			// Unknown extensions are illegal from the server.
 			return false
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go
index 9e4817d..fd30e63 100644
--- a/ssl/test/runner/runner.go
+++ b/ssl/test/runner/runner.go
@@ -7343,23 +7343,39 @@
 			continue
 		}
 
-		for _, paddingLen := range []int{1, 9700} {
-			flags := []string{
-				"-max-version", version.shimFlag(tls),
-				"-dummy-pq-padding-len", strconv.Itoa(paddingLen),
-			}
-
+		for _, paddingLen := range []int{400, 1100} {
 			testCases = append(testCases, testCase{
-				name:         fmt.Sprintf("DummyPQPadding-%d-%s", paddingLen, version.name),
-				testType:     clientTest,
-				tls13Variant: version.tls13Variant,
+				name:          fmt.Sprintf("DummyPQPadding-%d-%s", paddingLen, version.name),
+				testType:      clientTest,
+				tls13Variant:  version.tls13Variant,
+				resumeSession: true,
 				config: Config{
 					MaxVersion: version.version,
 					Bugs: ProtocolBugs{
 						ExpectDummyPQPaddingLength: paddingLen,
 					},
 				},
-				flags: flags,
+				flags: []string{
+					"-max-version", version.shimFlag(tls),
+					"-dummy-pq-padding-len", strconv.Itoa(paddingLen),
+				},
+			})
+
+			testCases = append(testCases, testCase{
+				name:          fmt.Sprintf("DummyPQPadding-Server-%d-%s", paddingLen, version.name),
+				testType:      serverTest,
+				tls13Variant:  version.tls13Variant,
+				resumeSession: true,
+				config: Config{
+					MaxVersion: version.version,
+					Bugs: ProtocolBugs{
+						SendDummyPQPaddingLength:   paddingLen,
+						ExpectDummyPQPaddingLength: paddingLen,
+					},
+				},
+				flags: []string{
+					"-max-version", version.shimFlag(tls),
+				},
 			})
 		}
 	}