1 // Copyright 2023 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
14 type testQUICConn struct {
17 readSecret map[QUICEncryptionLevel]suiteSecret
18 writeSecret map[QUICEncryptionLevel]suiteSecret
23 func newTestQUICClient(t *testing.T, config *Config) *testQUICConn {
24 q := &testQUICConn{t: t}
25 q.conn = QUICClient(&QUICConfig{
34 func newTestQUICServer(t *testing.T, config *Config) *testQUICConn {
35 q := &testQUICConn{t: t}
36 q.conn = QUICServer(&QUICConfig{
45 type suiteSecret struct {
50 func (q *testQUICConn) setReadSecret(level QUICEncryptionLevel, suite uint16, secret []byte) {
51 if _, ok := q.writeSecret[level]; !ok {
52 q.t.Errorf("SetReadSecret for level %v called before SetWriteSecret", level)
54 if level == QUICEncryptionLevelApplication && !q.complete {
55 q.t.Errorf("SetReadSecret for level %v called before HandshakeComplete", level)
57 if _, ok := q.readSecret[level]; ok {
58 q.t.Errorf("SetReadSecret for level %v called twice", level)
60 if q.readSecret == nil {
61 q.readSecret = map[QUICEncryptionLevel]suiteSecret{}
64 case QUICEncryptionLevelHandshake, QUICEncryptionLevelApplication:
65 q.readSecret[level] = suiteSecret{suite, secret}
67 q.t.Errorf("SetReadSecret for unexpected level %v", level)
71 func (q *testQUICConn) setWriteSecret(level QUICEncryptionLevel, suite uint16, secret []byte) {
72 if _, ok := q.writeSecret[level]; ok {
73 q.t.Errorf("SetWriteSecret for level %v called twice", level)
75 if q.writeSecret == nil {
76 q.writeSecret = map[QUICEncryptionLevel]suiteSecret{}
79 case QUICEncryptionLevelHandshake, QUICEncryptionLevelApplication:
80 q.writeSecret[level] = suiteSecret{suite, secret}
82 q.t.Errorf("SetWriteSecret for unexpected level %v", level)
86 var errTransportParametersRequired = errors.New("transport parameters required")
88 func runTestQUICConnection(ctx context.Context, cli, srv *testQUICConn, onHandleCryptoData func()) error {
90 for _, c := range []*testQUICConn{a, b} {
91 if !c.conn.conn.quic.started {
92 if err := c.conn.Start(ctx); err != nil {
99 e := a.conn.NextEvent()
104 if !a.complete || !b.complete {
105 return errors.New("handshake incomplete")
110 case QUICSetReadSecret:
111 a.setReadSecret(e.Level, e.Suite, e.Data)
112 case QUICSetWriteSecret:
113 a.setWriteSecret(e.Level, e.Suite, e.Data)
115 if err := b.conn.HandleData(e.Level, e.Data); err != nil {
118 case QUICTransportParameters:
120 if a.gotParams == nil {
121 a.gotParams = []byte{}
123 case QUICTransportParametersRequired:
124 return errTransportParametersRequired
125 case QUICHandshakeDone:
128 opts := QUICSessionTicketOptions{}
129 if err := srv.conn.SendSessionTicket(opts); err != nil {
134 if e.Kind != QUICNoEvent {
140 func TestQUICConnection(t *testing.T) {
141 config := testConfig.Clone()
142 config.MinVersion = VersionTLS13
144 cli := newTestQUICClient(t, config)
145 cli.conn.SetTransportParameters(nil)
147 srv := newTestQUICServer(t, config)
148 srv.conn.SetTransportParameters(nil)
150 if err := runTestQUICConnection(context.Background(), cli, srv, nil); err != nil {
151 t.Fatalf("error during connection handshake: %v", err)
154 if _, ok := cli.readSecret[QUICEncryptionLevelHandshake]; !ok {
155 t.Errorf("client has no Handshake secret")
157 if _, ok := cli.readSecret[QUICEncryptionLevelApplication]; !ok {
158 t.Errorf("client has no Application secret")
160 if _, ok := srv.readSecret[QUICEncryptionLevelHandshake]; !ok {
161 t.Errorf("server has no Handshake secret")
163 if _, ok := srv.readSecret[QUICEncryptionLevelApplication]; !ok {
164 t.Errorf("server has no Application secret")
166 for _, level := range []QUICEncryptionLevel{QUICEncryptionLevelHandshake, QUICEncryptionLevelApplication} {
167 if _, ok := cli.readSecret[level]; !ok {
168 t.Errorf("client has no %v read secret", level)
170 if _, ok := srv.readSecret[level]; !ok {
171 t.Errorf("server has no %v read secret", level)
173 if !reflect.DeepEqual(cli.readSecret[level], srv.writeSecret[level]) {
174 t.Errorf("client read secret does not match server write secret for level %v", level)
176 if !reflect.DeepEqual(cli.writeSecret[level], srv.readSecret[level]) {
177 t.Errorf("client write secret does not match server read secret for level %v", level)
182 func TestQUICSessionResumption(t *testing.T) {
183 clientConfig := testConfig.Clone()
184 clientConfig.MinVersion = VersionTLS13
185 clientConfig.ClientSessionCache = NewLRUClientSessionCache(1)
186 clientConfig.ServerName = "example.go.dev"
188 serverConfig := testConfig.Clone()
189 serverConfig.MinVersion = VersionTLS13
191 cli := newTestQUICClient(t, clientConfig)
192 cli.conn.SetTransportParameters(nil)
193 srv := newTestQUICServer(t, serverConfig)
194 srv.conn.SetTransportParameters(nil)
195 if err := runTestQUICConnection(context.Background(), cli, srv, nil); err != nil {
196 t.Fatalf("error during first connection handshake: %v", err)
198 if cli.conn.ConnectionState().DidResume {
199 t.Errorf("first connection unexpectedly used session resumption")
202 cli2 := newTestQUICClient(t, clientConfig)
203 cli2.conn.SetTransportParameters(nil)
204 srv2 := newTestQUICServer(t, serverConfig)
205 srv2.conn.SetTransportParameters(nil)
206 if err := runTestQUICConnection(context.Background(), cli2, srv2, nil); err != nil {
207 t.Fatalf("error during second connection handshake: %v", err)
209 if !cli2.conn.ConnectionState().DidResume {
210 t.Errorf("second connection did not use session resumption")
214 func TestQUICPostHandshakeClientAuthentication(t *testing.T) {
215 // RFC 9001, Section 4.4.
216 config := testConfig.Clone()
217 config.MinVersion = VersionTLS13
218 cli := newTestQUICClient(t, config)
219 cli.conn.SetTransportParameters(nil)
220 srv := newTestQUICServer(t, config)
221 srv.conn.SetTransportParameters(nil)
222 if err := runTestQUICConnection(context.Background(), cli, srv, nil); err != nil {
223 t.Fatalf("error during connection handshake: %v", err)
226 certReq := new(certificateRequestMsgTLS13)
227 certReq.ocspStapling = true
229 certReq.supportedSignatureAlgorithms = supportedSignatureAlgorithms()
230 certReqBytes, err := certReq.marshal()
234 if err := cli.conn.HandleData(QUICEncryptionLevelApplication, append([]byte{
235 byte(typeCertificateRequest),
236 byte(0), byte(0), byte(len(certReqBytes)),
237 }, certReqBytes...)); err == nil {
238 t.Fatalf("post-handshake authentication request: got no error, want one")
242 func TestQUICPostHandshakeKeyUpdate(t *testing.T) {
243 // RFC 9001, Section 6.
244 config := testConfig.Clone()
245 config.MinVersion = VersionTLS13
246 cli := newTestQUICClient(t, config)
247 cli.conn.SetTransportParameters(nil)
248 srv := newTestQUICServer(t, config)
249 srv.conn.SetTransportParameters(nil)
250 if err := runTestQUICConnection(context.Background(), cli, srv, nil); err != nil {
251 t.Fatalf("error during connection handshake: %v", err)
254 keyUpdate := new(keyUpdateMsg)
255 keyUpdateBytes, err := keyUpdate.marshal()
259 if err := cli.conn.HandleData(QUICEncryptionLevelApplication, append([]byte{
261 byte(0), byte(0), byte(len(keyUpdateBytes)),
262 }, keyUpdateBytes...)); !errors.Is(err, alertUnexpectedMessage) {
263 t.Fatalf("key update request: got error %v, want alertUnexpectedMessage", err)
267 func TestQUICHandshakeError(t *testing.T) {
268 clientConfig := testConfig.Clone()
269 clientConfig.MinVersion = VersionTLS13
270 clientConfig.InsecureSkipVerify = false
271 clientConfig.ServerName = "name"
273 serverConfig := testConfig.Clone()
274 serverConfig.MinVersion = VersionTLS13
276 cli := newTestQUICClient(t, clientConfig)
277 cli.conn.SetTransportParameters(nil)
278 srv := newTestQUICServer(t, serverConfig)
279 srv.conn.SetTransportParameters(nil)
280 err := runTestQUICConnection(context.Background(), cli, srv, nil)
281 if !errors.Is(err, AlertError(alertBadCertificate)) {
282 t.Errorf("connection handshake terminated with error %q, want alertBadCertificate", err)
284 var e *CertificateVerificationError
285 if !errors.As(err, &e) {
286 t.Errorf("connection handshake terminated with error %q, want CertificateVerificationError", err)
290 // Test that QUICConn.ConnectionState can be used during the handshake,
291 // and that it reports the application protocol as soon as it has been
293 func TestQUICConnectionState(t *testing.T) {
294 config := testConfig.Clone()
295 config.MinVersion = VersionTLS13
296 config.NextProtos = []string{"h3"}
297 cli := newTestQUICClient(t, config)
298 cli.conn.SetTransportParameters(nil)
299 srv := newTestQUICServer(t, config)
300 srv.conn.SetTransportParameters(nil)
301 onHandleCryptoData := func() {
302 cliCS := cli.conn.ConnectionState()
304 if _, ok := cli.readSecret[QUICEncryptionLevelApplication]; ok {
307 if want, got := cliCS.NegotiatedProtocol, cliWantALPN; want != got {
308 t.Errorf("cli.ConnectionState().NegotiatedProtocol = %q, want %q", want, got)
311 srvCS := srv.conn.ConnectionState()
313 if _, ok := srv.readSecret[QUICEncryptionLevelHandshake]; ok {
316 if want, got := srvCS.NegotiatedProtocol, srvWantALPN; want != got {
317 t.Errorf("srv.ConnectionState().NegotiatedProtocol = %q, want %q", want, got)
320 if err := runTestQUICConnection(context.Background(), cli, srv, onHandleCryptoData); err != nil {
321 t.Fatalf("error during connection handshake: %v", err)
325 func TestQUICStartContextPropagation(t *testing.T) {
327 const value = "value"
328 ctx := context.WithValue(context.Background(), key, value)
329 config := testConfig.Clone()
330 config.MinVersion = VersionTLS13
332 config.GetConfigForClient = func(info *ClientHelloInfo) (*Config, error) {
334 got, _ := info.Context().Value(key).(string)
336 t.Errorf("GetConfigForClient context key %q has value %q, want %q", key, got, value)
340 cli := newTestQUICClient(t, config)
341 cli.conn.SetTransportParameters(nil)
342 srv := newTestQUICServer(t, config)
343 srv.conn.SetTransportParameters(nil)
344 if err := runTestQUICConnection(ctx, cli, srv, nil); err != nil {
345 t.Fatalf("error during connection handshake: %v", err)
348 t.Errorf("GetConfigForClient called %v times, want 1", calls)
352 func TestQUICDelayedTransportParameters(t *testing.T) {
353 clientConfig := testConfig.Clone()
354 clientConfig.MinVersion = VersionTLS13
355 clientConfig.ClientSessionCache = NewLRUClientSessionCache(1)
356 clientConfig.ServerName = "example.go.dev"
358 serverConfig := testConfig.Clone()
359 serverConfig.MinVersion = VersionTLS13
361 cliParams := "client params"
362 srvParams := "server params"
364 cli := newTestQUICClient(t, clientConfig)
365 srv := newTestQUICServer(t, serverConfig)
366 if err := runTestQUICConnection(context.Background(), cli, srv, nil); err != errTransportParametersRequired {
367 t.Fatalf("handshake with no client parameters: %v; want errTransportParametersRequired", err)
369 cli.conn.SetTransportParameters([]byte(cliParams))
370 if err := runTestQUICConnection(context.Background(), cli, srv, nil); err != errTransportParametersRequired {
371 t.Fatalf("handshake with no server parameters: %v; want errTransportParametersRequired", err)
373 srv.conn.SetTransportParameters([]byte(srvParams))
374 if err := runTestQUICConnection(context.Background(), cli, srv, nil); err != nil {
375 t.Fatalf("error during connection handshake: %v", err)
378 if got, want := string(cli.gotParams), srvParams; got != want {
379 t.Errorf("client got transport params: %q, want %q", got, want)
381 if got, want := string(srv.gotParams), cliParams; got != want {
382 t.Errorf("server got transport params: %q, want %q", got, want)
386 func TestQUICEmptyTransportParameters(t *testing.T) {
387 config := testConfig.Clone()
388 config.MinVersion = VersionTLS13
390 cli := newTestQUICClient(t, config)
391 cli.conn.SetTransportParameters(nil)
392 srv := newTestQUICServer(t, config)
393 srv.conn.SetTransportParameters(nil)
394 if err := runTestQUICConnection(context.Background(), cli, srv, nil); err != nil {
395 t.Fatalf("error during connection handshake: %v", err)
398 if cli.gotParams == nil {
399 t.Errorf("client did not get transport params")
401 if srv.gotParams == nil {
402 t.Errorf("server did not get transport params")
404 if len(cli.gotParams) != 0 {
405 t.Errorf("client got transport params: %v, want empty", cli.gotParams)
407 if len(srv.gotParams) != 0 {
408 t.Errorf("server got transport params: %v, want empty", srv.gotParams)
412 func TestQUICCanceledWaitingForData(t *testing.T) {
413 config := testConfig.Clone()
414 config.MinVersion = VersionTLS13
415 cli := newTestQUICClient(t, config)
416 cli.conn.SetTransportParameters(nil)
417 cli.conn.Start(context.Background())
418 for cli.conn.NextEvent().Kind != QUICNoEvent {
420 err := cli.conn.Close()
421 if !errors.Is(err, alertCloseNotify) {
422 t.Errorf("conn.Close() = %v, want alertCloseNotify", err)
426 func TestQUICCanceledWaitingForTransportParams(t *testing.T) {
427 config := testConfig.Clone()
428 config.MinVersion = VersionTLS13
429 cli := newTestQUICClient(t, config)
430 cli.conn.Start(context.Background())
431 for cli.conn.NextEvent().Kind != QUICTransportParametersRequired {
433 err := cli.conn.Close()
434 if !errors.Is(err, alertCloseNotify) {
435 t.Errorf("conn.Close() = %v, want alertCloseNotify", err)