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 "fmt"
18
19func addExportKeyingMaterialTests() {
20	for _, protocol := range []protocol{tls, dtls, quic} {
21		for _, vers := range allVersions(protocol) {
22			suffix := fmt.Sprintf("%s-%s", protocol, vers)
23			testCases = append(testCases, testCase{
24				protocol: protocol,
25				name:     "ExportKeyingMaterial-" + suffix,
26				config: Config{
27					MaxVersion: vers.version,
28				},
29				// Test the exporter in both initial and resumption
30				// handshakes.
31				resumeSession:        true,
32				exportKeyingMaterial: 1024,
33				exportLabel:          "label",
34				exportContext:        "context",
35				useExportContext:     true,
36			})
37			testCases = append(testCases, testCase{
38				protocol: protocol,
39				name:     "ExportKeyingMaterial-NoContext-" + suffix,
40				config: Config{
41					MaxVersion: vers.version,
42				},
43				exportKeyingMaterial: 1024,
44			})
45			testCases = append(testCases, testCase{
46				protocol: protocol,
47				name:     "ExportKeyingMaterial-EmptyContext-" + suffix,
48				config: Config{
49					MaxVersion: vers.version,
50				},
51				exportKeyingMaterial: 1024,
52				useExportContext:     true,
53			})
54			testCases = append(testCases, testCase{
55				protocol: protocol,
56				name:     "ExportKeyingMaterial-Small-" + suffix,
57				config: Config{
58					MaxVersion: vers.version,
59				},
60				exportKeyingMaterial: 1,
61				exportLabel:          "label",
62				exportContext:        "context",
63				useExportContext:     true,
64			})
65
66			// TODO(crbug.com/381113363): Support 0-RTT in DTLS 1.3.
67			if vers.version >= VersionTLS13 && protocol != dtls {
68				// Test the exporters do not work while the client is
69				// sending 0-RTT data.
70				testCases = append(testCases, testCase{
71					protocol: protocol,
72					name:     "NoEarlyKeyingMaterial-Client-InEarlyData-" + suffix,
73					config: Config{
74						MaxVersion: vers.version,
75					},
76					resumeSession: true,
77					earlyData:     true,
78					flags: []string{
79						"-on-resume-export-keying-material", "1024",
80						"-on-resume-export-label", "label",
81						"-on-resume-export-context", "context",
82					},
83					shouldFail:    true,
84					expectedError: ":HANDSHAKE_NOT_COMPLETE:",
85				})
86
87				// Test the normal exporter on the server in half-RTT.
88				testCases = append(testCases, testCase{
89					testType: serverTest,
90					protocol: protocol,
91					name:     "ExportKeyingMaterial-Server-HalfRTT-" + suffix,
92					config: Config{
93						MaxVersion: vers.version,
94						Bugs: ProtocolBugs{
95							// The shim writes exported data immediately after
96							// the handshake returns, so disable the built-in
97							// early data test.
98							SendEarlyData:     [][]byte{},
99							ExpectHalfRTTData: [][]byte{},
100						},
101					},
102					resumeSession:        true,
103					earlyData:            true,
104					exportKeyingMaterial: 1024,
105					exportLabel:          "label",
106					exportContext:        "context",
107					useExportContext:     true,
108				})
109			}
110		}
111	}
112
113	// Exporters work during a False Start.
114	testCases = append(testCases, testCase{
115		name: "ExportKeyingMaterial-FalseStart",
116		config: Config{
117			MaxVersion:   VersionTLS12,
118			CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
119			NextProtos:   []string{"foo"},
120			Bugs: ProtocolBugs{
121				ExpectFalseStart: true,
122			},
123		},
124		flags: []string{
125			"-false-start",
126			"-advertise-alpn", "\x03foo",
127			"-expect-alpn", "foo",
128		},
129		shimWritesFirst:      true,
130		exportKeyingMaterial: 1024,
131		exportLabel:          "label",
132		exportContext:        "context",
133		useExportContext:     true,
134	})
135
136	// Exporters do not work in the middle of a renegotiation. Test this by
137	// triggering the exporter after every SSL_read call and configuring the
138	// shim to run asynchronously.
139	testCases = append(testCases, testCase{
140		name: "ExportKeyingMaterial-Renegotiate",
141		config: Config{
142			MaxVersion: VersionTLS12,
143		},
144		renegotiate: 1,
145		flags: []string{
146			"-async",
147			"-use-exporter-between-reads",
148			"-renegotiate-freely",
149			"-expect-total-renegotiations", "1",
150		},
151		shouldFail:    true,
152		expectedError: "failed to export keying material",
153	})
154}
155
156func addExportTrafficSecretsTests() {
157	for _, cipherSuite := range []testCipherSuite{
158		// Test a SHA-256 and SHA-384 based cipher suite.
159		{"AEAD-AES128-GCM-SHA256", TLS_AES_128_GCM_SHA256},
160		{"AEAD-AES256-GCM-SHA384", TLS_AES_256_GCM_SHA384},
161	} {
162		testCases = append(testCases, testCase{
163			name: "ExportTrafficSecrets-" + cipherSuite.name,
164			config: Config{
165				MinVersion:   VersionTLS13,
166				CipherSuites: []uint16{cipherSuite.id},
167			},
168			exportTrafficSecrets: true,
169		})
170	}
171}
172
173func addTLSUniqueTests() {
174	for _, isClient := range []bool{false, true} {
175		for _, isResumption := range []bool{false, true} {
176			for _, hasEMS := range []bool{false, true} {
177				var suffix string
178				if isResumption {
179					suffix = "Resume-"
180				} else {
181					suffix = "Full-"
182				}
183
184				if hasEMS {
185					suffix += "EMS-"
186				} else {
187					suffix += "NoEMS-"
188				}
189
190				if isClient {
191					suffix += "Client"
192				} else {
193					suffix += "Server"
194				}
195
196				test := testCase{
197					name:          "TLSUnique-" + suffix,
198					testTLSUnique: true,
199					config: Config{
200						MaxVersion: VersionTLS12,
201						Bugs: ProtocolBugs{
202							NoExtendedMasterSecret: !hasEMS,
203						},
204					},
205				}
206
207				if isResumption {
208					test.resumeSession = true
209					test.resumeConfig = &Config{
210						MaxVersion: VersionTLS12,
211						Bugs: ProtocolBugs{
212							NoExtendedMasterSecret: !hasEMS,
213						},
214					}
215				}
216
217				if isResumption && !hasEMS {
218					test.shouldFail = true
219					test.expectedError = "failed to get tls-unique"
220				}
221
222				testCases = append(testCases, test)
223			}
224		}
225	}
226}
227