]> Cypherpunks.ru repositories - gostls13.git/blob - src/crypto/tls/quic_test.go
crypto/tls: change SendSessionTicket to take an options struct
[gostls13.git] / src / crypto / tls / quic_test.go
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.
4
5 package tls
6
7 import (
8         "context"
9         "errors"
10         "reflect"
11         "testing"
12 )
13
14 type testQUICConn struct {
15         t           *testing.T
16         conn        *QUICConn
17         readSecret  map[QUICEncryptionLevel]suiteSecret
18         writeSecret map[QUICEncryptionLevel]suiteSecret
19         gotParams   []byte
20         complete    bool
21 }
22
23 func newTestQUICClient(t *testing.T, config *Config) *testQUICConn {
24         q := &testQUICConn{t: t}
25         q.conn = QUICClient(&QUICConfig{
26                 TLSConfig: config,
27         })
28         t.Cleanup(func() {
29                 q.conn.Close()
30         })
31         return q
32 }
33
34 func newTestQUICServer(t *testing.T, config *Config) *testQUICConn {
35         q := &testQUICConn{t: t}
36         q.conn = QUICServer(&QUICConfig{
37                 TLSConfig: config,
38         })
39         t.Cleanup(func() {
40                 q.conn.Close()
41         })
42         return q
43 }
44
45 type suiteSecret struct {
46         suite  uint16
47         secret []byte
48 }
49
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)
53         }
54         if level == QUICEncryptionLevelApplication && !q.complete {
55                 q.t.Errorf("SetReadSecret for level %v called before HandshakeComplete", level)
56         }
57         if _, ok := q.readSecret[level]; ok {
58                 q.t.Errorf("SetReadSecret for level %v called twice", level)
59         }
60         if q.readSecret == nil {
61                 q.readSecret = map[QUICEncryptionLevel]suiteSecret{}
62         }
63         switch level {
64         case QUICEncryptionLevelHandshake, QUICEncryptionLevelApplication:
65                 q.readSecret[level] = suiteSecret{suite, secret}
66         default:
67                 q.t.Errorf("SetReadSecret for unexpected level %v", level)
68         }
69 }
70
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)
74         }
75         if q.writeSecret == nil {
76                 q.writeSecret = map[QUICEncryptionLevel]suiteSecret{}
77         }
78         switch level {
79         case QUICEncryptionLevelHandshake, QUICEncryptionLevelApplication:
80                 q.writeSecret[level] = suiteSecret{suite, secret}
81         default:
82                 q.t.Errorf("SetWriteSecret for unexpected level %v", level)
83         }
84 }
85
86 var errTransportParametersRequired = errors.New("transport parameters required")
87
88 func runTestQUICConnection(ctx context.Context, cli, srv *testQUICConn, onHandleCryptoData func()) error {
89         a, b := cli, srv
90         for _, c := range []*testQUICConn{a, b} {
91                 if !c.conn.conn.quic.started {
92                         if err := c.conn.Start(ctx); err != nil {
93                                 return err
94                         }
95                 }
96         }
97         idleCount := 0
98         for {
99                 e := a.conn.NextEvent()
100                 switch e.Kind {
101                 case QUICNoEvent:
102                         idleCount++
103                         if idleCount == 2 {
104                                 if !a.complete || !b.complete {
105                                         return errors.New("handshake incomplete")
106                                 }
107                                 return nil
108                         }
109                         a, b = b, a
110                 case QUICSetReadSecret:
111                         a.setReadSecret(e.Level, e.Suite, e.Data)
112                 case QUICSetWriteSecret:
113                         a.setWriteSecret(e.Level, e.Suite, e.Data)
114                 case QUICWriteData:
115                         if err := b.conn.HandleData(e.Level, e.Data); err != nil {
116                                 return err
117                         }
118                 case QUICTransportParameters:
119                         a.gotParams = e.Data
120                         if a.gotParams == nil {
121                                 a.gotParams = []byte{}
122                         }
123                 case QUICTransportParametersRequired:
124                         return errTransportParametersRequired
125                 case QUICHandshakeDone:
126                         a.complete = true
127                         if a == srv {
128                                 opts := QUICSessionTicketOptions{}
129                                 if err := srv.conn.SendSessionTicket(opts); err != nil {
130                                         return err
131                                 }
132                         }
133                 }
134                 if e.Kind != QUICNoEvent {
135                         idleCount = 0
136                 }
137         }
138 }
139
140 func TestQUICConnection(t *testing.T) {
141         config := testConfig.Clone()
142         config.MinVersion = VersionTLS13
143
144         cli := newTestQUICClient(t, config)
145         cli.conn.SetTransportParameters(nil)
146
147         srv := newTestQUICServer(t, config)
148         srv.conn.SetTransportParameters(nil)
149
150         if err := runTestQUICConnection(context.Background(), cli, srv, nil); err != nil {
151                 t.Fatalf("error during connection handshake: %v", err)
152         }
153
154         if _, ok := cli.readSecret[QUICEncryptionLevelHandshake]; !ok {
155                 t.Errorf("client has no Handshake secret")
156         }
157         if _, ok := cli.readSecret[QUICEncryptionLevelApplication]; !ok {
158                 t.Errorf("client has no Application secret")
159         }
160         if _, ok := srv.readSecret[QUICEncryptionLevelHandshake]; !ok {
161                 t.Errorf("server has no Handshake secret")
162         }
163         if _, ok := srv.readSecret[QUICEncryptionLevelApplication]; !ok {
164                 t.Errorf("server has no Application secret")
165         }
166         for _, level := range []QUICEncryptionLevel{QUICEncryptionLevelHandshake, QUICEncryptionLevelApplication} {
167                 if _, ok := cli.readSecret[level]; !ok {
168                         t.Errorf("client has no %v read secret", level)
169                 }
170                 if _, ok := srv.readSecret[level]; !ok {
171                         t.Errorf("server has no %v read secret", level)
172                 }
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)
175                 }
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)
178                 }
179         }
180 }
181
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"
187
188         serverConfig := testConfig.Clone()
189         serverConfig.MinVersion = VersionTLS13
190
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)
197         }
198         if cli.conn.ConnectionState().DidResume {
199                 t.Errorf("first connection unexpectedly used session resumption")
200         }
201
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)
208         }
209         if !cli2.conn.ConnectionState().DidResume {
210                 t.Errorf("second connection did not use session resumption")
211         }
212 }
213
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)
224         }
225
226         certReq := new(certificateRequestMsgTLS13)
227         certReq.ocspStapling = true
228         certReq.scts = true
229         certReq.supportedSignatureAlgorithms = supportedSignatureAlgorithms()
230         certReqBytes, err := certReq.marshal()
231         if err != nil {
232                 t.Fatal(err)
233         }
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")
239         }
240 }
241
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)
252         }
253
254         keyUpdate := new(keyUpdateMsg)
255         keyUpdateBytes, err := keyUpdate.marshal()
256         if err != nil {
257                 t.Fatal(err)
258         }
259         if err := cli.conn.HandleData(QUICEncryptionLevelApplication, append([]byte{
260                 byte(typeKeyUpdate),
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)
264         }
265 }
266
267 func TestQUICHandshakeError(t *testing.T) {
268         clientConfig := testConfig.Clone()
269         clientConfig.MinVersion = VersionTLS13
270         clientConfig.InsecureSkipVerify = false
271         clientConfig.ServerName = "name"
272
273         serverConfig := testConfig.Clone()
274         serverConfig.MinVersion = VersionTLS13
275
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)
283         }
284         var e *CertificateVerificationError
285         if !errors.As(err, &e) {
286                 t.Errorf("connection handshake terminated with error %q, want CertificateVerificationError", err)
287         }
288 }
289
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
292 // negotiated.
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()
303                 cliWantALPN := ""
304                 if _, ok := cli.readSecret[QUICEncryptionLevelApplication]; ok {
305                         cliWantALPN = "h3"
306                 }
307                 if want, got := cliCS.NegotiatedProtocol, cliWantALPN; want != got {
308                         t.Errorf("cli.ConnectionState().NegotiatedProtocol = %q, want %q", want, got)
309                 }
310
311                 srvCS := srv.conn.ConnectionState()
312                 srvWantALPN := ""
313                 if _, ok := srv.readSecret[QUICEncryptionLevelHandshake]; ok {
314                         srvWantALPN = "h3"
315                 }
316                 if want, got := srvCS.NegotiatedProtocol, srvWantALPN; want != got {
317                         t.Errorf("srv.ConnectionState().NegotiatedProtocol = %q, want %q", want, got)
318                 }
319         }
320         if err := runTestQUICConnection(context.Background(), cli, srv, onHandleCryptoData); err != nil {
321                 t.Fatalf("error during connection handshake: %v", err)
322         }
323 }
324
325 func TestQUICStartContextPropagation(t *testing.T) {
326         const key = "key"
327         const value = "value"
328         ctx := context.WithValue(context.Background(), key, value)
329         config := testConfig.Clone()
330         config.MinVersion = VersionTLS13
331         calls := 0
332         config.GetConfigForClient = func(info *ClientHelloInfo) (*Config, error) {
333                 calls++
334                 got, _ := info.Context().Value(key).(string)
335                 if got != value {
336                         t.Errorf("GetConfigForClient context key %q has value %q, want %q", key, got, value)
337                 }
338                 return nil, nil
339         }
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)
346         }
347         if calls != 1 {
348                 t.Errorf("GetConfigForClient called %v times, want 1", calls)
349         }
350 }
351
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"
357
358         serverConfig := testConfig.Clone()
359         serverConfig.MinVersion = VersionTLS13
360
361         cliParams := "client params"
362         srvParams := "server params"
363
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)
368         }
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)
372         }
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)
376         }
377
378         if got, want := string(cli.gotParams), srvParams; got != want {
379                 t.Errorf("client got transport params: %q, want %q", got, want)
380         }
381         if got, want := string(srv.gotParams), cliParams; got != want {
382                 t.Errorf("server got transport params: %q, want %q", got, want)
383         }
384 }
385
386 func TestQUICEmptyTransportParameters(t *testing.T) {
387         config := testConfig.Clone()
388         config.MinVersion = VersionTLS13
389
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)
396         }
397
398         if cli.gotParams == nil {
399                 t.Errorf("client did not get transport params")
400         }
401         if srv.gotParams == nil {
402                 t.Errorf("server did not get transport params")
403         }
404         if len(cli.gotParams) != 0 {
405                 t.Errorf("client got transport params: %v, want empty", cli.gotParams)
406         }
407         if len(srv.gotParams) != 0 {
408                 t.Errorf("server got transport params: %v, want empty", srv.gotParams)
409         }
410 }
411
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 {
419         }
420         err := cli.conn.Close()
421         if !errors.Is(err, alertCloseNotify) {
422                 t.Errorf("conn.Close() = %v, want alertCloseNotify", err)
423         }
424 }
425
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 {
432         }
433         err := cli.conn.Close()
434         if !errors.Is(err, alertCloseNotify) {
435                 t.Errorf("conn.Close() = %v, want alertCloseNotify", err)
436         }
437 }