Test ECH server with unique and repeated config IDs.

Also shortens ECH variable names in runner.go.

Bug: 275
Change-Id: Iaef520ae09eb94f714fbdaa4383d1456add6f113
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/47744
Commit-Queue: Dan McArdle <dmcardle@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
Reviewed-by: David Benjamin <davidben@google.com>
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go
index 0f7c628..4629a69 100644
--- a/ssl/test/runner/runner.go
+++ b/ssl/test/runner/runner.go
@@ -16167,10 +16167,10 @@
 	},
 }
 
-// generateECHConfigWithSecretKey constructs a valid ECHConfig and corresponding
+// generateECHConfigWithKey constructs a valid ECHConfig and corresponding
 // private key for the server. If the cipher list is empty, all ciphers are
 // included.
-func generateECHConfigWithSecretKey(publicName string, ciphers []HPKECipherSuite) (*ECHConfig, []byte, error) {
+func generateECHConfigWithKey(publicName string, ciphers []HPKECipherSuite, configID uint8) (*ECHConfig, []byte, error) {
 	publicKeyR, secretKeyR, err := hpke.GenerateKeyPair()
 	if err != nil {
 		return nil, nil, err
@@ -16182,7 +16182,7 @@
 		}
 	}
 	result := ECHConfig{
-		ConfigID:     42,
+		ConfigID:     configID,
 		PublicName:   publicName,
 		PublicKey:    publicKeyR,
 		KEM:          hpke.X25519WithHKDFSHA256,
@@ -16196,19 +16196,23 @@
 }
 
 func addEncryptedClientHelloTests() {
-	publicECHConfig, secretKey, err := generateECHConfigWithSecretKey("public.example", nil)
+	echConfig, key, err := generateECHConfigWithKey("public.example", nil, 42)
 	if err != nil {
 		panic(err)
 	}
-	publicECHConfig1, secretKey1, err := generateECHConfigWithSecretKey("public.example", nil)
+	echConfig1, key1, err := generateECHConfigWithKey("public.example", nil, 43)
 	if err != nil {
 		panic(err)
 	}
-	publicECHConfig2, secretKey2, err := generateECHConfigWithSecretKey("public.example", nil)
+	echConfig2, key2, err := generateECHConfigWithKey("public.example", nil, 44)
 	if err != nil {
 		panic(err)
 	}
-	publicECHConfig3, secretKey3, err := generateECHConfigWithSecretKey("public.example", nil)
+	echConfig3, key3, err := generateECHConfigWithKey("public.example", nil, 45)
+	if err != nil {
+		panic(err)
+	}
+	echConfigRepeatID, keyRepeatID, err := generateECHConfigWithKey("public.example", nil, 42)
 	if err != nil {
 		panic(err)
 	}
@@ -16234,13 +16238,13 @@
 				name:     prefix + "ECH-Server" + suffix,
 				config: Config{
 					ServerName:      "secret.example",
-					ClientECHConfig: publicECHConfig,
+					ClientECHConfig: echConfig,
 					DefaultCurves:   defaultCurves,
 				},
 				resumeSession: true,
 				flags: []string{
-					"-ech-server-config", base64.StdEncoding.EncodeToString(MarshalECHConfig(publicECHConfig)),
-					"-ech-server-key", base64.StdEncoding.EncodeToString(secretKey),
+					"-ech-server-config", base64.StdEncoding.EncodeToString(MarshalECHConfig(echConfig)),
+					"-ech-server-key", base64.StdEncoding.EncodeToString(key),
 					"-ech-is-retry-config", "1",
 					"-expect-server-name", "secret.example",
 				},
@@ -16258,7 +16262,7 @@
 				name:     prefix + "ECH-Server-MinimalClientHelloOuter" + suffix,
 				config: Config{
 					ServerName:      "secret.example",
-					ClientECHConfig: publicECHConfig,
+					ClientECHConfig: echConfig,
 					DefaultCurves:   defaultCurves,
 					Bugs: ProtocolBugs{
 						MinimalClientHelloOuter: true,
@@ -16266,8 +16270,8 @@
 				},
 				resumeSession: true,
 				flags: []string{
-					"-ech-server-config", base64.StdEncoding.EncodeToString(MarshalECHConfig(publicECHConfig)),
-					"-ech-server-key", base64.StdEncoding.EncodeToString(secretKey),
+					"-ech-server-config", base64.StdEncoding.EncodeToString(MarshalECHConfig(echConfig)),
+					"-ech-server-key", base64.StdEncoding.EncodeToString(key),
 					"-ech-is-retry-config", "1",
 					"-expect-server-name", "secret.example",
 				},
@@ -16287,24 +16291,24 @@
 					DefaultCurves: defaultCurves,
 					// The client uses an ECHConfig that the server does not understand
 					// so we can observe which retry configs the server sends back.
-					ClientECHConfig: publicECHConfig,
+					ClientECHConfig: echConfig,
 					Bugs: ProtocolBugs{
 						OfferSessionInClientHelloOuter: true,
-						ExpectECHRetryConfigs:          MarshalECHConfigList(publicECHConfig2, publicECHConfig3),
+						ExpectECHRetryConfigs:          MarshalECHConfigList(echConfig2, echConfig3),
 					},
 				},
 				resumeSession: true,
 				flags: []string{
 					// Configure three ECHConfigs on the shim, only two of which
 					// should be sent in retry configs.
-					"-ech-server-config", base64.StdEncoding.EncodeToString(MarshalECHConfig(publicECHConfig1)),
-					"-ech-server-key", base64.StdEncoding.EncodeToString(secretKey1),
+					"-ech-server-config", base64.StdEncoding.EncodeToString(MarshalECHConfig(echConfig1)),
+					"-ech-server-key", base64.StdEncoding.EncodeToString(key1),
 					"-ech-is-retry-config", "0",
-					"-ech-server-config", base64.StdEncoding.EncodeToString(MarshalECHConfig(publicECHConfig2)),
-					"-ech-server-key", base64.StdEncoding.EncodeToString(secretKey2),
+					"-ech-server-config", base64.StdEncoding.EncodeToString(MarshalECHConfig(echConfig2)),
+					"-ech-server-key", base64.StdEncoding.EncodeToString(key2),
 					"-ech-is-retry-config", "1",
-					"-ech-server-config", base64.StdEncoding.EncodeToString(MarshalECHConfig(publicECHConfig3)),
-					"-ech-server-key", base64.StdEncoding.EncodeToString(secretKey3),
+					"-ech-server-config", base64.StdEncoding.EncodeToString(MarshalECHConfig(echConfig3)),
+					"-ech-server-key", base64.StdEncoding.EncodeToString(key3),
 					"-ech-is-retry-config", "1",
 					"-expect-server-name", "public.example",
 				},
@@ -16319,14 +16323,14 @@
 				config: Config{
 					ServerName:      "secret.example",
 					DefaultCurves:   defaultCurves,
-					ClientECHConfig: publicECHConfig,
+					ClientECHConfig: echConfig,
 					Bugs: ProtocolBugs{
 						AllowTLS12InClientHelloInner: true,
 					},
 				},
 				flags: []string{
-					"-ech-server-config", base64.StdEncoding.EncodeToString(MarshalECHConfig(publicECHConfig)),
-					"-ech-server-key", base64.StdEncoding.EncodeToString(secretKey),
+					"-ech-server-config", base64.StdEncoding.EncodeToString(MarshalECHConfig(echConfig)),
+					"-ech-server-key", base64.StdEncoding.EncodeToString(key),
 					"-ech-is-retry-config", "1"},
 				shouldFail:         true,
 				expectedLocalError: "remote error: illegal parameter",
@@ -16342,15 +16346,15 @@
 				config: Config{
 					ServerName:      "secret.example",
 					DefaultCurves:   defaultCurves,
-					ClientECHConfig: publicECHConfig,
+					ClientECHConfig: echConfig,
 					Bugs: ProtocolBugs{
 						OmitECHIsInner:       !hrr,
 						OmitSecondECHIsInner: hrr,
 					},
 				},
 				flags: []string{
-					"-ech-server-config", base64.StdEncoding.EncodeToString(MarshalECHConfig(publicECHConfig)),
-					"-ech-server-key", base64.StdEncoding.EncodeToString(secretKey),
+					"-ech-server-config", base64.StdEncoding.EncodeToString(MarshalECHConfig(echConfig)),
+					"-ech-server-key", base64.StdEncoding.EncodeToString(key),
 					"-ech-is-retry-config", "1",
 				},
 				shouldFail:         true,
@@ -16366,7 +16370,7 @@
 				config: Config{
 					ServerName:      "secret.example",
 					DefaultCurves:   defaultCurves,
-					ClientECHConfig: publicECHConfig,
+					ClientECHConfig: echConfig,
 					ECHOuterExtensions: []uint16{
 						extensionKeyShare,
 						extensionSupportedCurves,
@@ -16384,8 +16388,8 @@
 					},
 				},
 				flags: []string{
-					"-ech-server-config", base64.StdEncoding.EncodeToString(MarshalECHConfig(publicECHConfig)),
-					"-ech-server-key", base64.StdEncoding.EncodeToString(secretKey),
+					"-ech-server-config", base64.StdEncoding.EncodeToString(MarshalECHConfig(echConfig)),
+					"-ech-server-key", base64.StdEncoding.EncodeToString(key),
 					"-ech-is-retry-config", "1",
 					"-expect-server-name", "secret.example",
 				},
@@ -16405,7 +16409,7 @@
 				config: Config{
 					ServerName:      "secret.example",
 					DefaultCurves:   defaultCurves,
-					ClientECHConfig: publicECHConfig,
+					ClientECHConfig: echConfig,
 					ECHOuterExtensions: []uint16{
 						extensionSupportedCurves,
 						extensionSupportedCurves,
@@ -16415,8 +16419,8 @@
 					},
 				},
 				flags: []string{
-					"-ech-server-config", base64.StdEncoding.EncodeToString(MarshalECHConfig(publicECHConfig)),
-					"-ech-server-key", base64.StdEncoding.EncodeToString(secretKey),
+					"-ech-server-config", base64.StdEncoding.EncodeToString(MarshalECHConfig(echConfig)),
+					"-ech-server-key", base64.StdEncoding.EncodeToString(key),
 					"-ech-is-retry-config", "1",
 					"-expect-server-name", "secret.example",
 				},
@@ -16434,7 +16438,7 @@
 				config: Config{
 					ServerName:      "secret.example",
 					DefaultCurves:   defaultCurves,
-					ClientECHConfig: publicECHConfig,
+					ClientECHConfig: echConfig,
 					ECHOuterExtensions: []uint16{
 						extensionCustom,
 					},
@@ -16443,8 +16447,8 @@
 					},
 				},
 				flags: []string{
-					"-ech-server-config", base64.StdEncoding.EncodeToString(MarshalECHConfig(publicECHConfig)),
-					"-ech-server-key", base64.StdEncoding.EncodeToString(secretKey),
+					"-ech-server-config", base64.StdEncoding.EncodeToString(MarshalECHConfig(echConfig)),
+					"-ech-server-key", base64.StdEncoding.EncodeToString(key),
 					"-ech-is-retry-config", "1",
 					"-expect-server-name", "secret.example",
 				},
@@ -16463,7 +16467,7 @@
 				config: Config{
 					ServerName:      "secret.example",
 					DefaultCurves:   defaultCurves,
-					ClientECHConfig: publicECHConfig,
+					ClientECHConfig: echConfig,
 					ECHOuterExtensions: []uint16{
 						extensionEncryptedClientHello,
 					},
@@ -16472,8 +16476,8 @@
 					},
 				},
 				flags: []string{
-					"-ech-server-config", base64.StdEncoding.EncodeToString(MarshalECHConfig(publicECHConfig)),
-					"-ech-server-key", base64.StdEncoding.EncodeToString(secretKey),
+					"-ech-server-config", base64.StdEncoding.EncodeToString(MarshalECHConfig(echConfig)),
+					"-ech-server-key", base64.StdEncoding.EncodeToString(key),
 					"-ech-is-retry-config", "1",
 					"-expect-server-name", "secret.example",
 				},
@@ -16491,13 +16495,13 @@
 			name:     prefix + "ECH-Server-AsyncEarlyCallback",
 			config: Config{
 				ServerName:      "secret.example",
-				ClientECHConfig: publicECHConfig,
+				ClientECHConfig: echConfig,
 			},
 			flags: []string{
 				"-async",
 				"-use-early-callback",
-				"-ech-server-config", base64.StdEncoding.EncodeToString(MarshalECHConfig(publicECHConfig)),
-				"-ech-server-key", base64.StdEncoding.EncodeToString(secretKey),
+				"-ech-server-config", base64.StdEncoding.EncodeToString(MarshalECHConfig(echConfig)),
+				"-ech-server-key", base64.StdEncoding.EncodeToString(key),
 				"-ech-is-retry-config", "1",
 				"-expect-server-name", "secret.example",
 			},
@@ -16514,14 +16518,38 @@
 			name:     prefix + "ECH-Server-SecondECHConfig",
 			config: Config{
 				ServerName:      "secret.example",
-				ClientECHConfig: publicECHConfig1,
+				ClientECHConfig: echConfig1,
 			},
 			flags: []string{
-				"-ech-server-config", base64.StdEncoding.EncodeToString(MarshalECHConfig(publicECHConfig)),
-				"-ech-server-key", base64.StdEncoding.EncodeToString(secretKey),
+				"-ech-server-config", base64.StdEncoding.EncodeToString(MarshalECHConfig(echConfig)),
+				"-ech-server-key", base64.StdEncoding.EncodeToString(key),
 				"-ech-is-retry-config", "1",
-				"-ech-server-config", base64.StdEncoding.EncodeToString(MarshalECHConfig(publicECHConfig1)),
-				"-ech-server-key", base64.StdEncoding.EncodeToString(secretKey1),
+				"-ech-server-config", base64.StdEncoding.EncodeToString(MarshalECHConfig(echConfig1)),
+				"-ech-server-key", base64.StdEncoding.EncodeToString(key1),
+				"-ech-is-retry-config", "1",
+				"-expect-server-name", "secret.example",
+			},
+			expectations: connectionExpectations{
+				echAccepted: true,
+			},
+		})
+
+		// Test ECH-enabled server with two ECHConfigs that have the same config
+		// ID can decrypt client's ECH when it uses the second ECHConfig.
+		testCases = append(testCases, testCase{
+			testType: serverTest,
+			protocol: protocol,
+			name:     prefix + "ECH-Server-RepeatedConfigID",
+			config: Config{
+				ServerName:      "secret.example",
+				ClientECHConfig: echConfigRepeatID,
+			},
+			flags: []string{
+				"-ech-server-config", base64.StdEncoding.EncodeToString(MarshalECHConfig(echConfig3)),
+				"-ech-server-key", base64.StdEncoding.EncodeToString(key3),
+				"-ech-is-retry-config", "1",
+				"-ech-server-config", base64.StdEncoding.EncodeToString(MarshalECHConfig(echConfigRepeatID)),
+				"-ech-server-key", base64.StdEncoding.EncodeToString(keyRepeatID),
 				"-ech-is-retry-config", "1",
 				"-expect-server-name", "secret.example",
 			},
@@ -16544,12 +16572,12 @@
 				name:     prefix + "ECH-Server-Cipher-" + cipher.name,
 				config: Config{
 					ServerName:      "secret.example",
-					ClientECHConfig: publicECHConfig,
+					ClientECHConfig: echConfig,
 					ECHCipherSuites: []HPKECipherSuite{cipher.cipher},
 				},
 				flags: []string{
-					"-ech-server-config", base64.StdEncoding.EncodeToString(MarshalECHConfig(publicECHConfig)),
-					"-ech-server-key", base64.StdEncoding.EncodeToString(secretKey),
+					"-ech-server-config", base64.StdEncoding.EncodeToString(MarshalECHConfig(echConfig)),
+					"-ech-server-key", base64.StdEncoding.EncodeToString(key),
 					"-ech-is-retry-config", "1",
 					"-expect-server-name", "secret.example",
 				},
@@ -16560,7 +16588,7 @@
 
 			// Test that the ECH server rejects the specified cipher if not
 			// listed in its ECHConfig.
-			config, key, err := generateECHConfigWithSecretKey("public.example", []HPKECipherSuite{otherCipher.cipher})
+			config, key, err := generateECHConfigWithKey("public.example", []HPKECipherSuite{otherCipher.cipher}, 42)
 			if err != nil {
 				panic(err)
 			}
@@ -16570,7 +16598,7 @@
 				name:     prefix + "ECH-Server-DisabledCipher-" + cipher.name,
 				config: Config{
 					ServerName:      "secret.example",
-					ClientECHConfig: publicECHConfig,
+					ClientECHConfig: echConfig,
 					ECHCipherSuites: []HPKECipherSuite{cipher.cipher},
 					Bugs: ProtocolBugs{
 						ExpectECHRetryConfigs: MarshalECHConfigList(config),
@@ -16593,15 +16621,15 @@
 			name:     prefix + "ECH-Server-ShortClientECHEnc",
 			config: Config{
 				ServerName:      "secret.example",
-				ClientECHConfig: publicECHConfig,
+				ClientECHConfig: echConfig,
 				Bugs: ProtocolBugs{
-					ExpectECHRetryConfigs: MarshalECHConfigList(publicECHConfig),
+					ExpectECHRetryConfigs: MarshalECHConfigList(echConfig),
 					TruncateClientECHEnc:  true,
 				},
 			},
 			flags: []string{
-				"-ech-server-config", base64.StdEncoding.EncodeToString(MarshalECHConfig(publicECHConfig)),
-				"-ech-server-key", base64.StdEncoding.EncodeToString(secretKey),
+				"-ech-server-config", base64.StdEncoding.EncodeToString(MarshalECHConfig(echConfig)),
+				"-ech-server-key", base64.StdEncoding.EncodeToString(key),
 				"-ech-is-retry-config", "1",
 				"-expect-server-name", "public.example",
 			},
@@ -16615,15 +16643,15 @@
 			name:     prefix + "ECH-Server-CorruptEncryptedClientHello",
 			config: Config{
 				ServerName:      "secret.example",
-				ClientECHConfig: publicECHConfig,
+				ClientECHConfig: echConfig,
 				Bugs: ProtocolBugs{
-					ExpectECHRetryConfigs:       MarshalECHConfigList(publicECHConfig),
+					ExpectECHRetryConfigs:       MarshalECHConfigList(echConfig),
 					CorruptEncryptedClientHello: true,
 				},
 			},
 			flags: []string{
-				"-ech-server-config", base64.StdEncoding.EncodeToString(MarshalECHConfig(publicECHConfig)),
-				"-ech-server-key", base64.StdEncoding.EncodeToString(secretKey),
+				"-ech-server-config", base64.StdEncoding.EncodeToString(MarshalECHConfig(echConfig)),
+				"-ech-server-key", base64.StdEncoding.EncodeToString(key),
 				"-ech-is-retry-config", "1",
 			},
 		})
@@ -16636,7 +16664,7 @@
 			name:     prefix + "ECH-Server-CorruptSecondEncryptedClientHello",
 			config: Config{
 				ServerName:      "secret.example",
-				ClientECHConfig: publicECHConfig,
+				ClientECHConfig: echConfig,
 				// Force a HelloRetryRequest.
 				DefaultCurves: []CurveID{},
 				Bugs: ProtocolBugs{
@@ -16644,8 +16672,8 @@
 				},
 			},
 			flags: []string{
-				"-ech-server-config", base64.StdEncoding.EncodeToString(MarshalECHConfig(publicECHConfig)),
-				"-ech-server-key", base64.StdEncoding.EncodeToString(secretKey),
+				"-ech-server-config", base64.StdEncoding.EncodeToString(MarshalECHConfig(echConfig)),
+				"-ech-server-key", base64.StdEncoding.EncodeToString(key),
 				"-ech-is-retry-config", "1",
 			},
 			shouldFail:         true,
@@ -16660,7 +16688,7 @@
 			name:     prefix + "ECH-Server-OmitSecondEncryptedClientHello",
 			config: Config{
 				ServerName:      "secret.example",
-				ClientECHConfig: publicECHConfig,
+				ClientECHConfig: echConfig,
 				// Force a HelloRetryRequest.
 				DefaultCurves: []CurveID{},
 				Bugs: ProtocolBugs{
@@ -16668,8 +16696,8 @@
 				},
 			},
 			flags: []string{
-				"-ech-server-config", base64.StdEncoding.EncodeToString(MarshalECHConfig(publicECHConfig)),
-				"-ech-server-key", base64.StdEncoding.EncodeToString(secretKey),
+				"-ech-server-config", base64.StdEncoding.EncodeToString(MarshalECHConfig(echConfig)),
+				"-ech-server-key", base64.StdEncoding.EncodeToString(key),
 				"-ech-is-retry-config", "1",
 			},
 			shouldFail:         true,
@@ -16684,7 +16712,7 @@
 			name:     prefix + "ECH-Server-DifferentConfigIDSecondClientHello",
 			config: Config{
 				ServerName:      "secret.example",
-				ClientECHConfig: publicECHConfig,
+				ClientECHConfig: echConfig,
 				// Force a HelloRetryRequest.
 				DefaultCurves: []CurveID{},
 				Bugs: ProtocolBugs{
@@ -16692,8 +16720,8 @@
 				},
 			},
 			flags: []string{
-				"-ech-server-config", base64.StdEncoding.EncodeToString(MarshalECHConfig(publicECHConfig)),
-				"-ech-server-key", base64.StdEncoding.EncodeToString(secretKey),
+				"-ech-server-config", base64.StdEncoding.EncodeToString(MarshalECHConfig(echConfig)),
+				"-ech-server-key", base64.StdEncoding.EncodeToString(key),
 				"-ech-is-retry-config", "1",
 			},
 			shouldFail:         true,
@@ -16708,13 +16736,13 @@
 			name:     prefix + "ECH-Server-EarlyData",
 			config: Config{
 				ServerName:      "secret.example",
-				ClientECHConfig: publicECHConfig,
+				ClientECHConfig: echConfig,
 			},
 			resumeSession: true,
 			earlyData:     true,
 			flags: []string{
-				"-ech-server-config", base64.StdEncoding.EncodeToString(MarshalECHConfig(publicECHConfig)),
-				"-ech-server-key", base64.StdEncoding.EncodeToString(secretKey),
+				"-ech-server-config", base64.StdEncoding.EncodeToString(MarshalECHConfig(echConfig)),
+				"-ech-server-key", base64.StdEncoding.EncodeToString(key),
 				"-ech-is-retry-config", "1",
 			},
 			expectations: connectionExpectations{
@@ -16727,7 +16755,7 @@
 			name:     prefix + "ECH-Server-EarlyDataRejected",
 			config: Config{
 				ServerName:      "secret.example",
-				ClientECHConfig: publicECHConfig,
+				ClientECHConfig: echConfig,
 				Bugs: ProtocolBugs{
 					// Cause the server to reject 0-RTT with a bad ticket age.
 					SendTicketAge: 1 * time.Hour,
@@ -16737,8 +16765,8 @@
 			earlyData:               true,
 			expectEarlyDataRejected: true,
 			flags: []string{
-				"-ech-server-config", base64.StdEncoding.EncodeToString(MarshalECHConfig(publicECHConfig)),
-				"-ech-server-key", base64.StdEncoding.EncodeToString(secretKey),
+				"-ech-server-config", base64.StdEncoding.EncodeToString(MarshalECHConfig(echConfig)),
+				"-ech-server-key", base64.StdEncoding.EncodeToString(key),
 				"-ech-is-retry-config", "1",
 			},
 			expectations: connectionExpectations{
@@ -16754,7 +16782,7 @@
 			name:     prefix + "ECH-Server-Disabled",
 			config: Config{
 				ServerName:      "secret.example",
-				ClientECHConfig: publicECHConfig,
+				ClientECHConfig: echConfig,
 			},
 			flags: []string{
 				"-expect-server-name", "public.example",
@@ -16953,7 +16981,7 @@
 			config: Config{
 				MinVersion:      VersionTLS13,
 				MaxVersion:      VersionTLS13,
-				ClientECHConfig: publicECHConfig,
+				ClientECHConfig: echConfig,
 				Bugs: ProtocolBugs{
 					AlwaysSendECHIsInner: true,
 				},