1// Copyright 2025 The BoringSSL Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package runner
16
17import (
18	"bytes"
19	"fmt"
20	"strconv"
21)
22
23type stateMachineTestConfig struct {
24	protocol          protocol
25	async             bool
26	splitHandshake    bool
27	packHandshake     bool
28	implicitHandshake bool
29}
30
31// Adds tests that try to cover the range of the handshake state machine, under
32// various conditions. Some of these are redundant with other tests, but they
33// only cover the synchronous case.
34func addAllStateMachineCoverageTests() {
35	for _, async := range []bool{false, true} {
36		for _, protocol := range []protocol{tls, dtls, quic} {
37			addStateMachineCoverageTests(stateMachineTestConfig{
38				protocol: protocol,
39				async:    async,
40			})
41			// QUIC doesn't work with the implicit handshake API. Additionally,
42			// splitting or packing handshake records is meaningless in QUIC.
43			if protocol != quic {
44				addStateMachineCoverageTests(stateMachineTestConfig{
45					protocol:          protocol,
46					async:             async,
47					implicitHandshake: true,
48				})
49				addStateMachineCoverageTests(stateMachineTestConfig{
50					protocol:       protocol,
51					async:          async,
52					splitHandshake: true,
53				})
54				addStateMachineCoverageTests(stateMachineTestConfig{
55					protocol:      protocol,
56					async:         async,
57					packHandshake: true,
58				})
59			}
60		}
61	}
62}
63
64func addStateMachineCoverageTests(config stateMachineTestConfig) {
65	var tests []testCase
66
67	// Basic handshake, with resumption. Client and server,
68	// session ID and session ticket.
69	// The following tests have a max version of 1.2, so they are not suitable
70	// for use with QUIC.
71	if config.protocol != quic {
72		tests = append(tests, testCase{
73			name: "Basic-Client",
74			config: Config{
75				MaxVersion: VersionTLS12,
76			},
77			resumeSession: true,
78			// Ensure session tickets are used, not session IDs.
79			noSessionCache: true,
80			flags:          []string{"-expect-no-hrr"},
81		})
82		tests = append(tests, testCase{
83			name: "Basic-Client-RenewTicket",
84			config: Config{
85				MaxVersion: VersionTLS12,
86				Bugs: ProtocolBugs{
87					RenewTicketOnResume: true,
88				},
89			},
90			flags:                []string{"-expect-ticket-renewal"},
91			resumeSession:        true,
92			resumeRenewedSession: true,
93		})
94		tests = append(tests, testCase{
95			name: "Basic-Client-NoTicket",
96			config: Config{
97				MaxVersion:             VersionTLS12,
98				SessionTicketsDisabled: true,
99			},
100			resumeSession: true,
101		})
102		tests = append(tests, testCase{
103			testType: serverTest,
104			name:     "Basic-Server",
105			config: Config{
106				MaxVersion: VersionTLS12,
107				Bugs: ProtocolBugs{
108					RequireSessionTickets: true,
109				},
110			},
111			resumeSession: true,
112			flags: []string{
113				"-expect-no-session-id",
114				"-expect-no-hrr",
115			},
116		})
117		tests = append(tests, testCase{
118			testType: serverTest,
119			name:     "Basic-Server-NoTickets",
120			config: Config{
121				MaxVersion:             VersionTLS12,
122				SessionTicketsDisabled: true,
123			},
124			resumeSession: true,
125			flags:         []string{"-expect-session-id"},
126		})
127		tests = append(tests, testCase{
128			testType: serverTest,
129			name:     "Basic-Server-EarlyCallback",
130			config: Config{
131				MaxVersion: VersionTLS12,
132			},
133			flags:         []string{"-use-early-callback"},
134			resumeSession: true,
135		})
136	}
137
138	// TLS 1.3 basic handshake shapes.
139	tests = append(tests, testCase{
140		name: "TLS13-1RTT-Client",
141		config: Config{
142			MaxVersion: VersionTLS13,
143			MinVersion: VersionTLS13,
144		},
145		resumeSession:        true,
146		resumeRenewedSession: true,
147		// 0-RTT being disabled overrides all other 0-RTT reasons.
148		flags: []string{"-expect-early-data-reason", "disabled"},
149	})
150
151	tests = append(tests, testCase{
152		testType: serverTest,
153		name:     "TLS13-1RTT-Server",
154		config: Config{
155			MaxVersion: VersionTLS13,
156			MinVersion: VersionTLS13,
157		},
158		resumeSession:        true,
159		resumeRenewedSession: true,
160		flags: []string{
161			// TLS 1.3 uses tickets, so the session should not be
162			// cached statefully.
163			"-expect-no-session-id",
164			// 0-RTT being disabled overrides all other 0-RTT reasons.
165			"-expect-early-data-reason", "disabled",
166		},
167	})
168
169	tests = append(tests, testCase{
170		name: "TLS13-HelloRetryRequest-Client",
171		config: Config{
172			MaxVersion: VersionTLS13,
173			MinVersion: VersionTLS13,
174			// P-384 requires a HelloRetryRequest against BoringSSL's default
175			// configuration. Assert this with ExpectMissingKeyShare.
176			CurvePreferences: []CurveID{CurveP384},
177			Bugs: ProtocolBugs{
178				ExpectMissingKeyShare: true,
179			},
180		},
181		// Cover HelloRetryRequest during an ECDHE-PSK resumption.
182		resumeSession: true,
183		flags:         []string{"-expect-hrr"},
184	})
185
186	tests = append(tests, testCase{
187		testType: serverTest,
188		name:     "TLS13-HelloRetryRequest-Server",
189		config: Config{
190			MaxVersion: VersionTLS13,
191			MinVersion: VersionTLS13,
192			// Require a HelloRetryRequest for every curve.
193			DefaultCurves: []CurveID{},
194		},
195		// Cover HelloRetryRequest during an ECDHE-PSK resumption.
196		resumeSession: true,
197		flags:         []string{"-expect-hrr"},
198	})
199
200	// TLS 1.3 early data tests. DTLS 1.3 doesn't support early data yet.
201	// These tests are disabled for QUIC as well because they test features
202	// that do not apply to QUIC's use of TLS 1.3.
203	//
204	// TODO(crbug.com/381113363): Enable these tests for DTLS once we
205	// support early data in DTLS 1.3.
206	if config.protocol != dtls && config.protocol != quic {
207		tests = append(tests, testCase{
208			testType: clientTest,
209			name:     "TLS13-EarlyData-TooMuchData-Client",
210			config: Config{
211				MaxVersion:       VersionTLS13,
212				MinVersion:       VersionTLS13,
213				MaxEarlyDataSize: 2,
214			},
215			resumeConfig: &Config{
216				MaxVersion:       VersionTLS13,
217				MinVersion:       VersionTLS13,
218				MaxEarlyDataSize: 2,
219				Bugs: ProtocolBugs{
220					ExpectEarlyData: [][]byte{[]byte(shimInitialWrite[:2])},
221				},
222			},
223			resumeShimPrefix: shimInitialWrite[2:],
224			resumeSession:    true,
225			earlyData:        true,
226		})
227
228		// Unfinished writes can only be tested when operations are async. EarlyData
229		// can't be tested as part of an ImplicitHandshake in this case since
230		// otherwise the early data will be sent as normal data.
231		if config.async && !config.implicitHandshake {
232			tests = append(tests, testCase{
233				testType: clientTest,
234				name:     "TLS13-EarlyData-UnfinishedWrite-Client",
235				config: Config{
236					MaxVersion: VersionTLS13,
237					MinVersion: VersionTLS13,
238					Bugs: ProtocolBugs{
239						// Write the server response before expecting early data.
240						ExpectEarlyData:     [][]byte{},
241						ExpectLateEarlyData: [][]byte{[]byte(shimInitialWrite)},
242					},
243				},
244				resumeSession: true,
245				earlyData:     true,
246				flags:         []string{"-on-resume-read-with-unfinished-write"},
247			})
248
249			// Rejected unfinished writes are discarded (from the
250			// perspective of the calling application) on 0-RTT
251			// reject.
252			tests = append(tests, testCase{
253				testType: clientTest,
254				name:     "TLS13-EarlyData-RejectUnfinishedWrite-Client",
255				config: Config{
256					MaxVersion: VersionTLS13,
257					MinVersion: VersionTLS13,
258					Bugs: ProtocolBugs{
259						AlwaysRejectEarlyData: true,
260					},
261				},
262				resumeSession:           true,
263				earlyData:               true,
264				expectEarlyDataRejected: true,
265				flags:                   []string{"-on-resume-read-with-unfinished-write"},
266			})
267		}
268
269		// Early data has no size limit in QUIC.
270		tests = append(tests, testCase{
271			testType: serverTest,
272			name:     "TLS13-MaxEarlyData-Server",
273			config: Config{
274				MaxVersion: VersionTLS13,
275				MinVersion: VersionTLS13,
276				Bugs: ProtocolBugs{
277					SendEarlyData:           [][]byte{bytes.Repeat([]byte{1}, 14336+1)},
278					ExpectEarlyDataAccepted: true,
279				},
280			},
281			messageCount:  2,
282			resumeSession: true,
283			earlyData:     true,
284			shouldFail:    true,
285			expectedError: ":TOO_MUCH_READ_EARLY_DATA:",
286		})
287	}
288
289	// Test that early data is disabled for DTLS 1.3.
290	if config.protocol == dtls {
291		tests = append(tests, testCase{
292			testType: clientTest,
293			protocol: dtls,
294			name:     "DTLS13-EarlyData",
295			config: Config{
296				MaxVersion: VersionTLS13,
297				MinVersion: VersionTLS13,
298			},
299			resumeSession: true,
300			earlyData:     true,
301		})
302	}
303
304	// TLS client auth.
305	// The following tests have a max version of 1.2, so they are not suitable
306	// for use with QUIC.
307	if config.protocol != quic {
308		tests = append(tests, testCase{
309			testType: clientTest,
310			name:     "ClientAuth-NoCertificate-Client",
311			config: Config{
312				MaxVersion: VersionTLS12,
313				ClientAuth: RequestClientCert,
314			},
315		})
316		tests = append(tests, testCase{
317			testType: serverTest,
318			name:     "ClientAuth-NoCertificate-Server",
319			config: Config{
320				MaxVersion: VersionTLS12,
321			},
322			// Setting SSL_VERIFY_PEER allows anonymous clients.
323			flags: []string{"-verify-peer"},
324		})
325	}
326	if config.protocol != dtls {
327		tests = append(tests, testCase{
328			testType: clientTest,
329			name:     "ClientAuth-NoCertificate-Client-TLS13",
330			config: Config{
331				MaxVersion: VersionTLS13,
332				ClientAuth: RequestClientCert,
333			},
334		})
335		tests = append(tests, testCase{
336			testType: serverTest,
337			name:     "ClientAuth-NoCertificate-Server-TLS13",
338			config: Config{
339				MaxVersion: VersionTLS13,
340			},
341			// Setting SSL_VERIFY_PEER allows anonymous clients.
342			flags: []string{"-verify-peer"},
343		})
344	}
345	if config.protocol != quic {
346		tests = append(tests, testCase{
347			testType: clientTest,
348			name:     "ClientAuth-RSA-Client",
349			config: Config{
350				MaxVersion: VersionTLS12,
351				ClientAuth: RequireAnyClientCert,
352			},
353			shimCertificate: &rsaCertificate,
354		})
355	}
356	tests = append(tests, testCase{
357		testType: clientTest,
358		name:     "ClientAuth-RSA-Client-TLS13",
359		config: Config{
360			MaxVersion: VersionTLS13,
361			ClientAuth: RequireAnyClientCert,
362		},
363		shimCertificate: &rsaCertificate,
364	})
365	if config.protocol != quic {
366		tests = append(tests, testCase{
367			testType: clientTest,
368			name:     "ClientAuth-ECDSA-Client",
369			config: Config{
370				MaxVersion: VersionTLS12,
371				ClientAuth: RequireAnyClientCert,
372			},
373			shimCertificate: &ecdsaP256Certificate,
374		})
375	}
376	tests = append(tests, testCase{
377		testType: clientTest,
378		name:     "ClientAuth-ECDSA-Client-TLS13",
379		config: Config{
380			MaxVersion: VersionTLS13,
381			ClientAuth: RequireAnyClientCert,
382		},
383		shimCertificate: &ecdsaP256Certificate,
384	})
385	if config.protocol != quic {
386		tests = append(tests, testCase{
387			testType: clientTest,
388			name:     "ClientAuth-NoCertificate-OldCallback",
389			config: Config{
390				MaxVersion: VersionTLS12,
391				ClientAuth: RequestClientCert,
392			},
393			flags: []string{"-use-old-client-cert-callback"},
394		})
395	}
396	tests = append(tests, testCase{
397		testType: clientTest,
398		name:     "ClientAuth-NoCertificate-OldCallback-TLS13",
399		config: Config{
400			MaxVersion: VersionTLS13,
401			ClientAuth: RequestClientCert,
402		},
403		flags: []string{"-use-old-client-cert-callback"},
404	})
405	if config.protocol != quic {
406		tests = append(tests, testCase{
407			testType: clientTest,
408			name:     "ClientAuth-OldCallback",
409			config: Config{
410				MaxVersion: VersionTLS12,
411				ClientAuth: RequireAnyClientCert,
412			},
413			shimCertificate: &rsaCertificate,
414			flags: []string{
415				"-use-old-client-cert-callback",
416			},
417		})
418	}
419	tests = append(tests, testCase{
420		testType: clientTest,
421		name:     "ClientAuth-OldCallback-TLS13",
422		config: Config{
423			MaxVersion: VersionTLS13,
424			ClientAuth: RequireAnyClientCert,
425		},
426		shimCertificate: &rsaCertificate,
427		flags: []string{
428			"-use-old-client-cert-callback",
429		},
430	})
431	if config.protocol != quic {
432		tests = append(tests, testCase{
433			testType: serverTest,
434			name:     "ClientAuth-Server",
435			config: Config{
436				MaxVersion: VersionTLS12,
437				Credential: &rsaCertificate,
438			},
439			flags: []string{"-require-any-client-certificate"},
440		})
441	}
442	tests = append(tests, testCase{
443		testType: serverTest,
444		name:     "ClientAuth-Server-TLS13",
445		config: Config{
446			MaxVersion: VersionTLS13,
447			Credential: &rsaCertificate,
448		},
449		flags: []string{"-require-any-client-certificate"},
450	})
451
452	// Test each key exchange on the server side for async keys.
453	if config.protocol != quic {
454		tests = append(tests, testCase{
455			testType: serverTest,
456			name:     "Basic-Server-RSA",
457			config: Config{
458				MaxVersion:   VersionTLS12,
459				CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256},
460			},
461			shimCertificate: &rsaCertificate,
462		})
463		tests = append(tests, testCase{
464			testType: serverTest,
465			name:     "Basic-Server-ECDHE-RSA",
466			config: Config{
467				MaxVersion:   VersionTLS12,
468				CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
469			},
470			shimCertificate: &rsaCertificate,
471		})
472		tests = append(tests, testCase{
473			testType: serverTest,
474			name:     "Basic-Server-ECDHE-ECDSA",
475			config: Config{
476				MaxVersion:   VersionTLS12,
477				CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
478			},
479			shimCertificate: &ecdsaP256Certificate,
480		})
481		tests = append(tests, testCase{
482			testType: serverTest,
483			name:     "Basic-Server-Ed25519",
484			config: Config{
485				MaxVersion:   VersionTLS12,
486				CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
487			},
488			shimCertificate: &ed25519Certificate,
489			flags: []string{
490				"-verify-prefs", strconv.Itoa(int(signatureEd25519)),
491			},
492		})
493
494		// No session ticket support; server doesn't send NewSessionTicket.
495		tests = append(tests, testCase{
496			name: "SessionTicketsDisabled-Client",
497			config: Config{
498				MaxVersion:             VersionTLS12,
499				SessionTicketsDisabled: true,
500			},
501		})
502		tests = append(tests, testCase{
503			testType: serverTest,
504			name:     "SessionTicketsDisabled-Server",
505			config: Config{
506				MaxVersion:             VersionTLS12,
507				SessionTicketsDisabled: true,
508			},
509		})
510
511		// Skip ServerKeyExchange in PSK key exchange if there's no
512		// identity hint.
513		tests = append(tests, testCase{
514			name: "EmptyPSKHint-Client",
515			config: Config{
516				MaxVersion:   VersionTLS12,
517				CipherSuites: []uint16{TLS_PSK_WITH_AES_128_CBC_SHA},
518				PreSharedKey: []byte("secret"),
519			},
520			flags: []string{"-psk", "secret"},
521		})
522		tests = append(tests, testCase{
523			testType: serverTest,
524			name:     "EmptyPSKHint-Server",
525			config: Config{
526				MaxVersion:   VersionTLS12,
527				CipherSuites: []uint16{TLS_PSK_WITH_AES_128_CBC_SHA},
528				PreSharedKey: []byte("secret"),
529			},
530			flags: []string{"-psk", "secret"},
531		})
532	}
533
534	// OCSP stapling tests.
535	for _, vers := range allVersions(config.protocol) {
536		tests = append(tests, testCase{
537			testType: clientTest,
538			name:     "OCSPStapling-Client-" + vers.name,
539			config: Config{
540				MaxVersion: vers.version,
541				Credential: rsaCertificate.WithOCSP(testOCSPResponse),
542			},
543			flags: []string{
544				"-enable-ocsp-stapling",
545				"-expect-ocsp-response",
546				base64FlagValue(testOCSPResponse),
547				"-verify-peer",
548			},
549			resumeSession: true,
550		})
551		tests = append(tests, testCase{
552			testType: serverTest,
553			name:     "OCSPStapling-Server-" + vers.name,
554			config: Config{
555				MaxVersion: vers.version,
556			},
557			expectations: connectionExpectations{
558				peerCertificate: rsaCertificate.WithOCSP(testOCSPResponse),
559			},
560			shimCertificate: rsaCertificate.WithOCSP(testOCSPResponse),
561			resumeSession:   true,
562		})
563
564		// The client OCSP callback is an alternate certificate
565		// verification callback.
566		tests = append(tests, testCase{
567			testType: clientTest,
568			name:     "ClientOCSPCallback-Pass-" + vers.name,
569			config: Config{
570				MaxVersion: vers.version,
571				Credential: rsaCertificate.WithOCSP(testOCSPResponse),
572			},
573			flags: []string{
574				"-enable-ocsp-stapling",
575				"-use-ocsp-callback",
576			},
577		})
578		var expectedLocalError string
579		if !config.async {
580			// TODO(davidben): Asynchronous fatal alerts are never
581			// sent. https://crbug.com/boringssl/130.
582			expectedLocalError = "remote error: bad certificate status response"
583		}
584		tests = append(tests, testCase{
585			testType: clientTest,
586			name:     "ClientOCSPCallback-Fail-" + vers.name,
587			config: Config{
588				MaxVersion: vers.version,
589				Credential: rsaCertificate.WithOCSP(testOCSPResponse),
590			},
591			flags: []string{
592				"-enable-ocsp-stapling",
593				"-use-ocsp-callback",
594				"-fail-ocsp-callback",
595			},
596			shouldFail:         true,
597			expectedLocalError: expectedLocalError,
598			expectedError:      ":OCSP_CB_ERROR:",
599		})
600		// The callback still runs if the server does not send an OCSP
601		// response.
602		tests = append(tests, testCase{
603			testType: clientTest,
604			name:     "ClientOCSPCallback-FailNoStaple-" + vers.name,
605			config: Config{
606				MaxVersion: vers.version,
607				Credential: &rsaCertificate,
608			},
609			flags: []string{
610				"-enable-ocsp-stapling",
611				"-use-ocsp-callback",
612				"-fail-ocsp-callback",
613			},
614			shouldFail:         true,
615			expectedLocalError: expectedLocalError,
616			expectedError:      ":OCSP_CB_ERROR:",
617		})
618
619		// The server OCSP callback is a legacy mechanism for
620		// configuring OCSP, used by unreliable server software.
621		tests = append(tests, testCase{
622			testType: serverTest,
623			name:     "ServerOCSPCallback-SetInCallback-" + vers.name,
624			config: Config{
625				MaxVersion: vers.version,
626			},
627			shimCertificate: rsaCertificate.WithOCSP(testOCSPResponse),
628			expectations: connectionExpectations{
629				peerCertificate: rsaCertificate.WithOCSP(testOCSPResponse),
630			},
631			flags: []string{
632				"-use-ocsp-callback",
633				"-set-ocsp-in-callback",
634			},
635			resumeSession: true,
636		})
637
638		// The callback may decline OCSP, in which case  we act as if
639		// the client did not support it, even if a response was
640		// configured.
641		tests = append(tests, testCase{
642			testType: serverTest,
643			name:     "ServerOCSPCallback-Decline-" + vers.name,
644			config: Config{
645				MaxVersion: vers.version,
646			},
647			shimCertificate: rsaCertificate.WithOCSP(testOCSPResponse),
648			expectations: connectionExpectations{
649				// There should be no OCSP response from the peer.
650				peerCertificate: &rsaCertificate,
651			},
652			flags: []string{
653				"-use-ocsp-callback",
654				"-decline-ocsp-callback",
655			},
656			resumeSession: true,
657		})
658
659		// The callback may also signal an internal error.
660		tests = append(tests, testCase{
661			testType: serverTest,
662			name:     "ServerOCSPCallback-Fail-" + vers.name,
663			config: Config{
664				MaxVersion: vers.version,
665			},
666			shimCertificate: rsaCertificate.WithOCSP(testOCSPResponse),
667			flags: []string{
668				"-use-ocsp-callback",
669				"-fail-ocsp-callback",
670			},
671			shouldFail:    true,
672			expectedError: ":OCSP_CB_ERROR:",
673		})
674	}
675
676	// Certificate verification tests.
677	for _, vers := range allVersions(config.protocol) {
678		for _, useCustomCallback := range []bool{false, true} {
679			for _, testType := range []testType{clientTest, serverTest} {
680				suffix := "-Client"
681				if testType == serverTest {
682					suffix = "-Server"
683				}
684				suffix += "-" + vers.name
685				if useCustomCallback {
686					suffix += "-CustomCallback"
687				}
688
689				// The custom callback and legacy callback have different default
690				// alerts.
691				verifyFailLocalError := "remote error: handshake failure"
692				if useCustomCallback {
693					verifyFailLocalError = "remote error: unknown certificate"
694				}
695
696				// We do not reliably send asynchronous fatal alerts. See
697				// https://crbug.com/boringssl/130.
698				if config.async {
699					verifyFailLocalError = ""
700				}
701
702				flags := []string{"-verify-peer"}
703				if testType == serverTest {
704					flags = append(flags, "-require-any-client-certificate")
705				}
706				if useCustomCallback {
707					flags = append(flags, "-use-custom-verify-callback")
708				}
709
710				tests = append(tests, testCase{
711					testType: testType,
712					name:     "CertificateVerificationSucceed" + suffix,
713					config: Config{
714						MaxVersion: vers.version,
715						Credential: &rsaCertificate,
716					},
717					flags:         append([]string{"-expect-verify-result"}, flags...),
718					resumeSession: true,
719				})
720				tests = append(tests, testCase{
721					testType: testType,
722					name:     "CertificateVerificationFail" + suffix,
723					config: Config{
724						MaxVersion: vers.version,
725						Credential: &rsaCertificate,
726					},
727					flags:              append([]string{"-verify-fail"}, flags...),
728					shouldFail:         true,
729					expectedError:      ":CERTIFICATE_VERIFY_FAILED:",
730					expectedLocalError: verifyFailLocalError,
731				})
732				// Tests that although the verify callback fails on resumption, by default we don't call it.
733				tests = append(tests, testCase{
734					testType: testType,
735					name:     "CertificateVerificationDoesNotFailOnResume" + suffix,
736					config: Config{
737						MaxVersion: vers.version,
738						Credential: &rsaCertificate,
739					},
740					flags:         append([]string{"-on-resume-verify-fail"}, flags...),
741					resumeSession: true,
742				})
743				if testType == clientTest && useCustomCallback {
744					tests = append(tests, testCase{
745						testType: testType,
746						name:     "CertificateVerificationFailsOnResume" + suffix,
747						config: Config{
748							MaxVersion: vers.version,
749							Credential: &rsaCertificate,
750						},
751						flags: append([]string{
752							"-on-resume-verify-fail",
753							"-reverify-on-resume",
754						}, flags...),
755						resumeSession:      true,
756						shouldFail:         true,
757						expectedError:      ":CERTIFICATE_VERIFY_FAILED:",
758						expectedLocalError: verifyFailLocalError,
759					})
760					tests = append(tests, testCase{
761						testType: testType,
762						name:     "CertificateVerificationPassesOnResume" + suffix,
763						config: Config{
764							MaxVersion: vers.version,
765							Credential: &rsaCertificate,
766						},
767						flags: append([]string{
768							"-reverify-on-resume",
769						}, flags...),
770						resumeSession: true,
771					})
772					// TODO(crbug.com/381113363): Support 0-RTT in DTLS 1.3.
773					if vers.version >= VersionTLS13 && config.protocol != dtls {
774						tests = append(tests, testCase{
775							testType: testType,
776							name:     "EarlyData-RejectTicket-Client-Reverify" + suffix,
777							config: Config{
778								MaxVersion: vers.version,
779							},
780							resumeConfig: &Config{
781								MaxVersion:             vers.version,
782								SessionTicketsDisabled: true,
783							},
784							resumeSession:           true,
785							expectResumeRejected:    true,
786							earlyData:               true,
787							expectEarlyDataRejected: true,
788							flags: append([]string{
789								"-reverify-on-resume",
790								// Session tickets are disabled, so the runner will not send a ticket.
791								"-on-retry-expect-no-session",
792							}, flags...),
793						})
794						tests = append(tests, testCase{
795							testType: testType,
796							name:     "EarlyData-Reject0RTT-Client-Reverify" + suffix,
797							config: Config{
798								MaxVersion: vers.version,
799								Bugs: ProtocolBugs{
800									AlwaysRejectEarlyData: true,
801								},
802							},
803							resumeSession:           true,
804							expectResumeRejected:    false,
805							earlyData:               true,
806							expectEarlyDataRejected: true,
807							flags: append([]string{
808								"-reverify-on-resume",
809							}, flags...),
810						})
811						tests = append(tests, testCase{
812							testType: testType,
813							name:     "EarlyData-RejectTicket-Client-ReverifyFails" + suffix,
814							config: Config{
815								MaxVersion: vers.version,
816							},
817							resumeConfig: &Config{
818								MaxVersion:             vers.version,
819								SessionTicketsDisabled: true,
820							},
821							resumeSession:           true,
822							expectResumeRejected:    true,
823							earlyData:               true,
824							expectEarlyDataRejected: true,
825							shouldFail:              true,
826							expectedError:           ":CERTIFICATE_VERIFY_FAILED:",
827							flags: append([]string{
828								"-reverify-on-resume",
829								// Session tickets are disabled, so the runner will not send a ticket.
830								"-on-retry-expect-no-session",
831								"-on-retry-verify-fail",
832							}, flags...),
833						})
834						tests = append(tests, testCase{
835							testType: testType,
836							name:     "EarlyData-Reject0RTT-Client-ReverifyFails" + suffix,
837							config: Config{
838								MaxVersion: vers.version,
839								Bugs: ProtocolBugs{
840									AlwaysRejectEarlyData: true,
841								},
842							},
843							resumeSession:           true,
844							expectResumeRejected:    false,
845							earlyData:               true,
846							expectEarlyDataRejected: true,
847							shouldFail:              true,
848							expectedError:           ":CERTIFICATE_VERIFY_FAILED:",
849							expectedLocalError:      verifyFailLocalError,
850							flags: append([]string{
851								"-reverify-on-resume",
852								"-on-retry-verify-fail",
853							}, flags...),
854						})
855						// This tests that we only call the verify callback once.
856						tests = append(tests, testCase{
857							testType: testType,
858							name:     "EarlyData-Accept0RTT-Client-Reverify" + suffix,
859							config: Config{
860								MaxVersion: vers.version,
861							},
862							resumeSession: true,
863							earlyData:     true,
864							flags: append([]string{
865								"-reverify-on-resume",
866							}, flags...),
867						})
868						tests = append(tests, testCase{
869							testType: testType,
870							name:     "EarlyData-Accept0RTT-Client-ReverifyFails" + suffix,
871							config: Config{
872								MaxVersion: vers.version,
873							},
874							resumeSession: true,
875							earlyData:     true,
876							shouldFail:    true,
877							expectedError: ":CERTIFICATE_VERIFY_FAILED:",
878							// We do not set expectedLocalError here because the shim rejects
879							// the connection without an alert.
880							flags: append([]string{
881								"-reverify-on-resume",
882								"-on-resume-verify-fail",
883							}, flags...),
884						})
885					}
886				}
887			}
888		}
889
890		// By default, the client is in a soft fail mode where the peer
891		// certificate is verified but failures are non-fatal.
892		tests = append(tests, testCase{
893			testType: clientTest,
894			name:     "CertificateVerificationSoftFail-" + vers.name,
895			config: Config{
896				MaxVersion: vers.version,
897				Credential: &rsaCertificate,
898			},
899			flags: []string{
900				"-verify-fail",
901				"-expect-verify-result",
902			},
903			resumeSession: true,
904		})
905	}
906
907	tests = append(tests, testCase{
908		name:               "ShimSendAlert",
909		flags:              []string{"-send-alert"},
910		shimWritesFirst:    true,
911		shouldFail:         true,
912		expectedLocalError: "remote error: decompression failure",
913	})
914
915	if config.protocol == tls {
916		tests = append(tests, testCase{
917			name: "Renegotiate-Client",
918			config: Config{
919				MaxVersion: VersionTLS12,
920			},
921			renegotiate: 1,
922			flags: []string{
923				"-renegotiate-freely",
924				"-expect-total-renegotiations", "1",
925			},
926		})
927
928		tests = append(tests, testCase{
929			name: "Renegotiate-Client-Explicit",
930			config: Config{
931				MaxVersion: VersionTLS12,
932			},
933			renegotiate: 1,
934			flags: []string{
935				"-renegotiate-explicit",
936				"-expect-total-renegotiations", "1",
937			},
938		})
939
940		halfHelloRequestError := ":UNEXPECTED_RECORD:"
941		if config.packHandshake {
942			// If the HelloRequest is sent in the same record as the server Finished,
943			// BoringSSL rejects it before the handshake completes.
944			halfHelloRequestError = ":EXCESS_HANDSHAKE_DATA:"
945		}
946		tests = append(tests, testCase{
947			name: "SendHalfHelloRequest",
948			config: Config{
949				MaxVersion: VersionTLS12,
950				Bugs: ProtocolBugs{
951					PackHelloRequestWithFinished: config.packHandshake,
952				},
953			},
954			sendHalfHelloRequest: true,
955			flags:                []string{"-renegotiate-ignore"},
956			shouldFail:           true,
957			expectedError:        halfHelloRequestError,
958		})
959
960		// NPN on client and server; results in post-ChangeCipherSpec message.
961		tests = append(tests, testCase{
962			name: "NPN-Client",
963			config: Config{
964				MaxVersion: VersionTLS12,
965				NextProtos: []string{"foo"},
966			},
967			flags:         []string{"-select-next-proto", "foo"},
968			resumeSession: true,
969			expectations: connectionExpectations{
970				nextProto:     "foo",
971				nextProtoType: npn,
972			},
973		})
974		tests = append(tests, testCase{
975			testType: serverTest,
976			name:     "NPN-Server",
977			config: Config{
978				MaxVersion: VersionTLS12,
979				NextProtos: []string{"bar"},
980			},
981			flags: []string{
982				"-advertise-npn", "\x03foo\x03bar\x03baz",
983				"-expect-next-proto", "bar",
984			},
985			resumeSession: true,
986			expectations: connectionExpectations{
987				nextProto:     "bar",
988				nextProtoType: npn,
989			},
990		})
991
992		// The client may select no protocol after seeing the server list.
993		tests = append(tests, testCase{
994			name: "NPN-Client-ClientSelectEmpty",
995			config: Config{
996				MaxVersion: VersionTLS12,
997				NextProtos: []string{"foo"},
998			},
999			flags:         []string{"-select-empty-next-proto"},
1000			resumeSession: true,
1001			expectations: connectionExpectations{
1002				noNextProto:   true,
1003				nextProtoType: npn,
1004			},
1005		})
1006		tests = append(tests, testCase{
1007			testType: serverTest,
1008			name:     "NPN-Server-ClientSelectEmpty",
1009			config: Config{
1010				MaxVersion:          VersionTLS12,
1011				NextProtos:          []string{"no-match"},
1012				NoFallbackNextProto: true,
1013			},
1014			flags: []string{
1015				"-advertise-npn", "\x03foo\x03bar\x03baz",
1016				"-expect-no-next-proto",
1017			},
1018			resumeSession: true,
1019			expectations: connectionExpectations{
1020				noNextProto:   true,
1021				nextProtoType: npn,
1022			},
1023		})
1024
1025		// The server may negotiate NPN, despite offering no protocols. In this
1026		// case, the server must still be prepared for the client to select a
1027		// fallback protocol.
1028		tests = append(tests, testCase{
1029			name: "NPN-Client-ServerAdvertiseEmpty",
1030			config: Config{
1031				MaxVersion:               VersionTLS12,
1032				NegotiateNPNWithNoProtos: true,
1033			},
1034			flags:         []string{"-select-next-proto", "foo"},
1035			resumeSession: true,
1036			expectations: connectionExpectations{
1037				nextProto:     "foo",
1038				nextProtoType: npn,
1039			},
1040		})
1041		tests = append(tests, testCase{
1042			testType: serverTest,
1043			name:     "NPN-Server-ServerAdvertiseEmpty",
1044			config: Config{
1045				MaxVersion: VersionTLS12,
1046				NextProtos: []string{"foo"},
1047			},
1048			flags: []string{
1049				"-advertise-empty-npn",
1050				"-expect-next-proto", "foo",
1051			},
1052			resumeSession: true,
1053			expectations: connectionExpectations{
1054				nextProto:     "foo",
1055				nextProtoType: npn,
1056			},
1057		})
1058
1059		// Client does False Start and negotiates NPN.
1060		tests = append(tests, testCase{
1061			name: "FalseStart",
1062			config: Config{
1063				MaxVersion:   VersionTLS12,
1064				CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
1065				NextProtos:   []string{"foo"},
1066				Bugs: ProtocolBugs{
1067					ExpectFalseStart: true,
1068				},
1069			},
1070			flags: []string{
1071				"-false-start",
1072				"-select-next-proto", "foo",
1073			},
1074			shimWritesFirst: true,
1075			resumeSession:   true,
1076		})
1077
1078		// Client does False Start and negotiates ALPN.
1079		tests = append(tests, testCase{
1080			name: "FalseStart-ALPN",
1081			config: Config{
1082				MaxVersion:   VersionTLS12,
1083				CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
1084				NextProtos:   []string{"foo"},
1085				Bugs: ProtocolBugs{
1086					ExpectFalseStart: true,
1087				},
1088			},
1089			flags: []string{
1090				"-false-start",
1091				"-advertise-alpn", "\x03foo",
1092				"-expect-alpn", "foo",
1093			},
1094			shimWritesFirst: true,
1095			resumeSession:   true,
1096		})
1097
1098		// False Start without session tickets.
1099		tests = append(tests, testCase{
1100			name: "FalseStart-SessionTicketsDisabled",
1101			config: Config{
1102				MaxVersion:             VersionTLS12,
1103				CipherSuites:           []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
1104				NextProtos:             []string{"foo"},
1105				SessionTicketsDisabled: true,
1106				Bugs: ProtocolBugs{
1107					ExpectFalseStart: true,
1108				},
1109			},
1110			flags: []string{
1111				"-false-start",
1112				"-select-next-proto", "foo",
1113			},
1114			shimWritesFirst: true,
1115		})
1116
1117		// Server parses a V2ClientHello. Test different lengths for the
1118		// challenge field.
1119		for _, challengeLength := range []int{16, 31, 32, 33, 48} {
1120			tests = append(tests, testCase{
1121				testType: serverTest,
1122				name:     fmt.Sprintf("SendV2ClientHello-%d", challengeLength),
1123				config: Config{
1124					// Choose a cipher suite that does not involve
1125					// elliptic curves, so no extensions are
1126					// involved.
1127					MaxVersion:   VersionTLS12,
1128					CipherSuites: []uint16{TLS_RSA_WITH_AES_128_CBC_SHA},
1129					Bugs: ProtocolBugs{
1130						SendV2ClientHello:            true,
1131						V2ClientHelloChallengeLength: challengeLength,
1132					},
1133				},
1134				flags: []string{
1135					"-expect-msg-callback",
1136					`read v2clienthello
1137write hs 2
1138write hs 11
1139write hs 14
1140read hs 16
1141read ccs
1142read hs 20
1143write ccs
1144write hs 20
1145read alert 1 0
1146`,
1147				},
1148			})
1149		}
1150
1151		// Channel ID and NPN at the same time, to ensure their relative
1152		// ordering is correct.
1153		tests = append(tests, testCase{
1154			name: "ChannelID-NPN-Client",
1155			config: Config{
1156				MaxVersion:       VersionTLS12,
1157				RequestChannelID: true,
1158				NextProtos:       []string{"foo"},
1159			},
1160			flags: []string{
1161				"-send-channel-id", channelIDKeyPath,
1162				"-select-next-proto", "foo",
1163			},
1164			resumeSession: true,
1165			expectations: connectionExpectations{
1166				channelID:     true,
1167				nextProto:     "foo",
1168				nextProtoType: npn,
1169			},
1170		})
1171		tests = append(tests, testCase{
1172			testType: serverTest,
1173			name:     "ChannelID-NPN-Server",
1174			config: Config{
1175				MaxVersion: VersionTLS12,
1176				ChannelID:  &channelIDKey,
1177				NextProtos: []string{"bar"},
1178			},
1179			flags: []string{
1180				"-expect-channel-id",
1181				base64FlagValue(channelIDBytes),
1182				"-advertise-npn", "\x03foo\x03bar\x03baz",
1183				"-expect-next-proto", "bar",
1184			},
1185			resumeSession: true,
1186			expectations: connectionExpectations{
1187				channelID:     true,
1188				nextProto:     "bar",
1189				nextProtoType: npn,
1190			},
1191		})
1192
1193		// Bidirectional shutdown with the runner initiating.
1194		tests = append(tests, testCase{
1195			name: "Shutdown-Runner",
1196			config: Config{
1197				Bugs: ProtocolBugs{
1198					ExpectCloseNotify: true,
1199				},
1200			},
1201			flags: []string{"-check-close-notify"},
1202		})
1203	}
1204	if config.protocol != dtls {
1205		// Test Channel ID
1206		for _, ver := range allVersions(config.protocol) {
1207			if ver.version < VersionTLS10 {
1208				continue
1209			}
1210			// Client sends a Channel ID.
1211			tests = append(tests, testCase{
1212				name: "ChannelID-Client-" + ver.name,
1213				config: Config{
1214					MaxVersion:       ver.version,
1215					RequestChannelID: true,
1216				},
1217				flags:         []string{"-send-channel-id", channelIDKeyPath},
1218				resumeSession: true,
1219				expectations: connectionExpectations{
1220					channelID: true,
1221				},
1222			})
1223
1224			// Server accepts a Channel ID.
1225			tests = append(tests, testCase{
1226				testType: serverTest,
1227				name:     "ChannelID-Server-" + ver.name,
1228				config: Config{
1229					MaxVersion: ver.version,
1230					ChannelID:  &channelIDKey,
1231				},
1232				flags: []string{
1233					"-expect-channel-id",
1234					base64FlagValue(channelIDBytes),
1235				},
1236				resumeSession: true,
1237				expectations: connectionExpectations{
1238					channelID: true,
1239				},
1240			})
1241
1242			tests = append(tests, testCase{
1243				testType: serverTest,
1244				name:     "InvalidChannelIDSignature-" + ver.name,
1245				config: Config{
1246					MaxVersion: ver.version,
1247					ChannelID:  &channelIDKey,
1248					Bugs: ProtocolBugs{
1249						InvalidChannelIDSignature: true,
1250					},
1251				},
1252				flags:         []string{"-enable-channel-id"},
1253				shouldFail:    true,
1254				expectedError: ":CHANNEL_ID_SIGNATURE_INVALID:",
1255			})
1256
1257			if ver.version < VersionTLS13 {
1258				// Channel ID requires ECDHE ciphers.
1259				tests = append(tests, testCase{
1260					testType: serverTest,
1261					name:     "ChannelID-NoECDHE-" + ver.name,
1262					config: Config{
1263						MaxVersion:   ver.version,
1264						CipherSuites: []uint16{TLS_RSA_WITH_AES_128_CBC_SHA},
1265						ChannelID:    &channelIDKey,
1266					},
1267					expectations: connectionExpectations{
1268						channelID: false,
1269					},
1270					flags: []string{"-enable-channel-id"},
1271				})
1272
1273				// Sanity-check setting expectations.channelID false works.
1274				tests = append(tests, testCase{
1275					testType: serverTest,
1276					name:     "ChannelID-ECDHE-" + ver.name,
1277					config: Config{
1278						MaxVersion:   ver.version,
1279						CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
1280						ChannelID:    &channelIDKey,
1281					},
1282					expectations: connectionExpectations{
1283						channelID: false,
1284					},
1285					flags:              []string{"-enable-channel-id"},
1286					shouldFail:         true,
1287					expectedLocalError: "channel ID unexpectedly negotiated",
1288				})
1289			}
1290		}
1291
1292		if !config.implicitHandshake {
1293			// Bidirectional shutdown with the shim initiating. The runner,
1294			// in the meantime, sends garbage before the close_notify which
1295			// the shim must ignore. This test is disabled under implicit
1296			// handshake tests because the shim never reads or writes.
1297
1298			// Tests that require checking for a close notify alert don't work with
1299			// QUIC because alerts are handled outside of the TLS stack in QUIC.
1300			if config.protocol != quic {
1301				tests = append(tests, testCase{
1302					name: "Shutdown-Shim",
1303					config: Config{
1304						MaxVersion: VersionTLS12,
1305						Bugs: ProtocolBugs{
1306							ExpectCloseNotify: true,
1307						},
1308					},
1309					shimShutsDown:     true,
1310					sendEmptyRecords:  1,
1311					sendWarningAlerts: 1,
1312					flags:             []string{"-check-close-notify"},
1313				})
1314
1315				// The shim should reject unexpected application data
1316				// when shutting down.
1317				tests = append(tests, testCase{
1318					name: "Shutdown-Shim-ApplicationData",
1319					config: Config{
1320						MaxVersion: VersionTLS12,
1321						Bugs: ProtocolBugs{
1322							ExpectCloseNotify: true,
1323						},
1324					},
1325					shimShutsDown:     true,
1326					messageCount:      1,
1327					sendEmptyRecords:  1,
1328					sendWarningAlerts: 1,
1329					flags:             []string{"-check-close-notify"},
1330					shouldFail:        true,
1331					expectedError:     ":APPLICATION_DATA_ON_SHUTDOWN:",
1332				})
1333
1334				// Test that SSL_shutdown still processes KeyUpdate.
1335				tests = append(tests, testCase{
1336					name: "Shutdown-Shim-KeyUpdate",
1337					config: Config{
1338						MinVersion: VersionTLS13,
1339						MaxVersion: VersionTLS13,
1340						Bugs: ProtocolBugs{
1341							ExpectCloseNotify: true,
1342						},
1343					},
1344					shimShutsDown:    true,
1345					sendKeyUpdates:   1,
1346					keyUpdateRequest: keyUpdateRequested,
1347					flags:            []string{"-check-close-notify"},
1348				})
1349
1350				// Test that SSL_shutdown processes HelloRequest
1351				// correctly.
1352				tests = append(tests, testCase{
1353					name: "Shutdown-Shim-HelloRequest-Ignore",
1354					config: Config{
1355						MinVersion: VersionTLS12,
1356						MaxVersion: VersionTLS12,
1357						Bugs: ProtocolBugs{
1358							SendHelloRequestBeforeEveryAppDataRecord: true,
1359							ExpectCloseNotify:                        true,
1360						},
1361					},
1362					shimShutsDown: true,
1363					flags: []string{
1364						"-renegotiate-ignore",
1365						"-check-close-notify",
1366					},
1367				})
1368				tests = append(tests, testCase{
1369					name: "Shutdown-Shim-HelloRequest-Reject",
1370					config: Config{
1371						MinVersion: VersionTLS12,
1372						MaxVersion: VersionTLS12,
1373						Bugs: ProtocolBugs{
1374							ExpectCloseNotify: true,
1375						},
1376					},
1377					shimShutsDown: true,
1378					renegotiate:   1,
1379					shouldFail:    true,
1380					expectedError: ":NO_RENEGOTIATION:",
1381					flags:         []string{"-check-close-notify"},
1382				})
1383				tests = append(tests, testCase{
1384					name: "Shutdown-Shim-HelloRequest-CannotHandshake",
1385					config: Config{
1386						MinVersion: VersionTLS12,
1387						MaxVersion: VersionTLS12,
1388						Bugs: ProtocolBugs{
1389							ExpectCloseNotify: true,
1390						},
1391					},
1392					shimShutsDown: true,
1393					renegotiate:   1,
1394					shouldFail:    true,
1395					expectedError: ":NO_RENEGOTIATION:",
1396					flags: []string{
1397						"-check-close-notify",
1398						"-renegotiate-freely",
1399					},
1400				})
1401
1402				tests = append(tests, testCase{
1403					testType: serverTest,
1404					name:     "Shutdown-Shim-Renegotiate-Server-Forbidden",
1405					config: Config{
1406						MaxVersion: VersionTLS12,
1407						Bugs: ProtocolBugs{
1408							ExpectCloseNotify: true,
1409						},
1410					},
1411					shimShutsDown: true,
1412					renegotiate:   1,
1413					shouldFail:    true,
1414					expectedError: ":NO_RENEGOTIATION:",
1415					flags: []string{
1416						"-check-close-notify",
1417					},
1418				})
1419			}
1420		}
1421	}
1422	if config.protocol == dtls {
1423		tests = append(tests, testCase{
1424			name: "SkipHelloVerifyRequest",
1425			config: Config{
1426				MaxVersion: VersionTLS12,
1427				Bugs: ProtocolBugs{
1428					SkipHelloVerifyRequest: true,
1429				},
1430			},
1431		})
1432		tests = append(tests, testCase{
1433			name: "DTLS13-HelloVerifyRequest",
1434			config: Config{
1435				MinVersion: VersionTLS13,
1436				Bugs: ProtocolBugs{
1437					ForceHelloVerifyRequest: true,
1438				},
1439			},
1440			shouldFail:    true,
1441			expectedError: ":INVALID_MESSAGE:",
1442		})
1443		tests = append(tests, testCase{
1444			name: "DTLS13-HelloVerifyRequestEmptyCookie",
1445			config: Config{
1446				MinVersion: VersionTLS13,
1447				Bugs: ProtocolBugs{
1448					ForceHelloVerifyRequest:       true,
1449					EmptyHelloVerifyRequestCookie: true,
1450				},
1451			},
1452			shouldFail:    true,
1453			expectedError: ":INVALID_MESSAGE:",
1454		})
1455	}
1456
1457	for _, test := range tests {
1458		test.protocol = config.protocol
1459		test.name += "-" + config.protocol.String()
1460		if config.async {
1461			test.name += "-Async"
1462			test.flags = append(test.flags, "-async")
1463		} else {
1464			test.name += "-Sync"
1465		}
1466		if config.splitHandshake {
1467			test.name += "-SplitHandshakeRecords"
1468			test.config.Bugs.MaxHandshakeRecordLength = 1
1469			if config.protocol == dtls {
1470				test.config.Bugs.MaxPacketLength = 256
1471				test.flags = append(test.flags, "-mtu", "256")
1472			}
1473		}
1474		if config.packHandshake {
1475			test.name += "-PackHandshake"
1476			if config.protocol == dtls {
1477				test.config.Bugs.MaxHandshakeRecordLength = 2
1478				test.config.Bugs.PackHandshakeFragments = 20
1479				test.config.Bugs.PackHandshakeRecords = 1500
1480				test.config.Bugs.PackAppDataWithHandshake = true
1481			} else {
1482				test.config.Bugs.PackHandshakeFlight = true
1483			}
1484		}
1485		if config.implicitHandshake {
1486			test.name += "-ImplicitHandshake"
1487			test.flags = append(test.flags, "-implicit-handshake")
1488		}
1489		testCases = append(testCases, test)
1490	}
1491}
1492