1
2
3
4
5 package tls
6
7 import (
8 "context"
9 "errors"
10 "fmt"
11 )
12
13
14
15 type QUICEncryptionLevel int
16
17 const (
18 QUICEncryptionLevelInitial = QUICEncryptionLevel(iota)
19 QUICEncryptionLevelEarly
20 QUICEncryptionLevelHandshake
21 QUICEncryptionLevelApplication
22 )
23
24 func (l QUICEncryptionLevel) String() string {
25 switch l {
26 case QUICEncryptionLevelInitial:
27 return "Initial"
28 case QUICEncryptionLevelEarly:
29 return "Early"
30 case QUICEncryptionLevelHandshake:
31 return "Handshake"
32 case QUICEncryptionLevelApplication:
33 return "Application"
34 default:
35 return fmt.Sprintf("QUICEncryptionLevel(%v)", int(l))
36 }
37 }
38
39
40
41
42
43 type QUICConn struct {
44 conn *Conn
45
46 sessionTicketSent bool
47 }
48
49
50 type QUICConfig struct {
51 TLSConfig *Config
52
53
54
55
56
57
58 EnableSessionEvents bool
59 }
60
61
62 type QUICEventKind int
63
64 const (
65
66 QUICNoEvent QUICEventKind = iota
67
68
69
70
71
72
73
74 QUICSetReadSecret
75 QUICSetWriteSecret
76
77
78
79 QUICWriteData
80
81
82
83 QUICTransportParameters
84
85
86
87
88
89
90
91
92 QUICTransportParametersRequired
93
94
95
96
97
98 QUICRejectedEarlyData
99
100
101 QUICHandshakeDone
102
103
104
105
106
107
108
109
110
111 QUICResumeSession
112
113
114
115
116
117
118
119 QUICStoreSession
120
121
122
123
124 QUICErrorEvent
125 )
126
127
128
129
130
131 type QUICEvent struct {
132 Kind QUICEventKind
133
134
135 Level QUICEncryptionLevel
136
137
138
139 Data []byte
140
141
142 Suite uint16
143
144
145 SessionState *SessionState
146
147
148
149 Err error
150 }
151
152 type quicState struct {
153 events []QUICEvent
154 nextEvent int
155
156
157
158
159
160 eventArr [8]QUICEvent
161
162 started bool
163 signalc chan struct{}
164 blockedc chan struct{}
165 ctx context.Context
166 cancel context.CancelFunc
167
168 waitingForDrain bool
169 errorReturned bool
170
171
172
173
174 readbuf []byte
175
176 transportParams []byte
177
178 enableSessionEvents bool
179 }
180
181
182
183
184
185 func QUICClient(config *QUICConfig) *QUICConn {
186 return newQUICConn(Client(nil, config.TLSConfig), config)
187 }
188
189
190
191
192
193 func QUICServer(config *QUICConfig) *QUICConn {
194 return newQUICConn(Server(nil, config.TLSConfig), config)
195 }
196
197 func newQUICConn(conn *Conn, config *QUICConfig) *QUICConn {
198 conn.quic = &quicState{
199 signalc: make(chan struct{}),
200 blockedc: make(chan struct{}),
201 enableSessionEvents: config.EnableSessionEvents,
202 }
203 conn.quic.events = conn.quic.eventArr[:0]
204 return &QUICConn{
205 conn: conn,
206 }
207 }
208
209
210
211
212
213 func (q *QUICConn) Start(ctx context.Context) error {
214 if q.conn.quic.started {
215 return quicError(errors.New("tls: Start called more than once"))
216 }
217 q.conn.quic.started = true
218 if q.conn.config.MinVersion < VersionTLS13 {
219 return quicError(errors.New("tls: Config MinVersion must be at least TLS 1.3"))
220 }
221 go q.conn.HandshakeContext(ctx)
222 if _, ok := <-q.conn.quic.blockedc; !ok {
223 return q.conn.handshakeErr
224 }
225 return nil
226 }
227
228
229
230 func (q *QUICConn) NextEvent() QUICEvent {
231 qs := q.conn.quic
232 if last := qs.nextEvent - 1; last >= 0 && len(qs.events[last].Data) > 0 {
233
234
235 qs.events[last].Data[0] = 0
236 }
237 if qs.nextEvent >= len(qs.events) && qs.waitingForDrain {
238 qs.waitingForDrain = false
239 <-qs.signalc
240 <-qs.blockedc
241 }
242 if err := q.conn.handshakeErr; err != nil {
243 if qs.errorReturned {
244 return QUICEvent{Kind: QUICNoEvent}
245 }
246 qs.errorReturned = true
247 qs.events = nil
248 qs.nextEvent = 0
249 return QUICEvent{Kind: QUICErrorEvent, Err: q.conn.handshakeErr}
250 }
251 if qs.nextEvent >= len(qs.events) {
252 qs.events = qs.events[:0]
253 qs.nextEvent = 0
254 return QUICEvent{Kind: QUICNoEvent}
255 }
256 e := qs.events[qs.nextEvent]
257 qs.events[qs.nextEvent] = QUICEvent{}
258 qs.nextEvent++
259 return e
260 }
261
262
263 func (q *QUICConn) Close() error {
264 if q.conn.quic.ctx == nil {
265 return nil
266 }
267 q.conn.quic.cancel()
268 <-q.conn.quic.signalc
269 for range q.conn.quic.blockedc {
270
271 }
272 return q.conn.handshakeErr
273 }
274
275
276
277 func (q *QUICConn) HandleData(level QUICEncryptionLevel, data []byte) error {
278 c := q.conn
279 if c.in.level != level {
280 return quicError(c.in.setErrorLocked(errors.New("tls: handshake data received at wrong level")))
281 }
282 c.quic.readbuf = data
283 <-c.quic.signalc
284 _, ok := <-c.quic.blockedc
285 if ok {
286
287 return nil
288 }
289
290 c.handshakeMutex.Lock()
291 defer c.handshakeMutex.Unlock()
292 c.hand.Write(c.quic.readbuf)
293 c.quic.readbuf = nil
294 for q.conn.hand.Len() >= 4 && q.conn.handshakeErr == nil {
295 b := q.conn.hand.Bytes()
296 n := int(b[1])<<16 | int(b[2])<<8 | int(b[3])
297 if n > maxHandshake {
298 q.conn.handshakeErr = fmt.Errorf("tls: handshake message of length %d bytes exceeds maximum of %d bytes", n, maxHandshake)
299 break
300 }
301 if len(b) < 4+n {
302 return nil
303 }
304 if err := q.conn.handlePostHandshakeMessage(); err != nil {
305 q.conn.handshakeErr = err
306 }
307 }
308 if q.conn.handshakeErr != nil {
309 return quicError(q.conn.handshakeErr)
310 }
311 return nil
312 }
313
314 type QUICSessionTicketOptions struct {
315
316 EarlyData bool
317 Extra [][]byte
318 }
319
320
321
322
323 func (q *QUICConn) SendSessionTicket(opts QUICSessionTicketOptions) error {
324 c := q.conn
325 if c.config.SessionTicketsDisabled {
326 return nil
327 }
328 if !c.isHandshakeComplete.Load() {
329 return quicError(errors.New("tls: SendSessionTicket called before handshake completed"))
330 }
331 if c.isClient {
332 return quicError(errors.New("tls: SendSessionTicket called on the client"))
333 }
334 if q.sessionTicketSent {
335 return quicError(errors.New("tls: SendSessionTicket called multiple times"))
336 }
337 q.sessionTicketSent = true
338 return quicError(c.sendSessionTicket(opts.EarlyData, opts.Extra))
339 }
340
341
342
343
344
345 func (q *QUICConn) StoreSession(session *SessionState) error {
346 c := q.conn
347 if !c.isClient {
348 return quicError(errors.New("tls: StoreSessionTicket called on the server"))
349 }
350 cacheKey := c.clientSessionCacheKey()
351 if cacheKey == "" {
352 return nil
353 }
354 cs := &ClientSessionState{session: session}
355 c.config.ClientSessionCache.Put(cacheKey, cs)
356 return nil
357 }
358
359
360 func (q *QUICConn) ConnectionState() ConnectionState {
361 return q.conn.ConnectionState()
362 }
363
364
365
366
367
368 func (q *QUICConn) SetTransportParameters(params []byte) {
369 if params == nil {
370 params = []byte{}
371 }
372 q.conn.quic.transportParams = params
373 if q.conn.quic.started {
374 <-q.conn.quic.signalc
375 <-q.conn.quic.blockedc
376 }
377 }
378
379
380
381 func quicError(err error) error {
382 if err == nil {
383 return nil
384 }
385 if _, ok := errors.AsType[AlertError](err); ok {
386 return err
387 }
388 a, ok := errors.AsType[alert](err)
389 if !ok {
390 a = alertInternalError
391 }
392
393
394 return fmt.Errorf("%w%.0w", err, AlertError(a))
395 }
396
397 func (c *Conn) quicReadHandshakeBytes(n int) error {
398 for c.hand.Len() < n {
399 if err := c.quicWaitForSignal(); err != nil {
400 return err
401 }
402 }
403 return nil
404 }
405
406 func (c *Conn) quicSetReadSecret(level QUICEncryptionLevel, suite uint16, secret []byte) error {
407
408
409
410
411 if c.hand.Len() != 0 {
412 c.sendAlert(alertUnexpectedMessage)
413 return errors.New("tls: handshake buffer not empty before setting read traffic secret")
414 }
415 c.quic.events = append(c.quic.events, QUICEvent{
416 Kind: QUICSetReadSecret,
417 Level: level,
418 Suite: suite,
419 Data: secret,
420 })
421 return nil
422 }
423
424 func (c *Conn) quicSetWriteSecret(level QUICEncryptionLevel, suite uint16, secret []byte) {
425 c.quic.events = append(c.quic.events, QUICEvent{
426 Kind: QUICSetWriteSecret,
427 Level: level,
428 Suite: suite,
429 Data: secret,
430 })
431 }
432
433 func (c *Conn) quicWriteCryptoData(level QUICEncryptionLevel, data []byte) {
434 var last *QUICEvent
435 if len(c.quic.events) > 0 {
436 last = &c.quic.events[len(c.quic.events)-1]
437 }
438 if last == nil || last.Kind != QUICWriteData || last.Level != level {
439 c.quic.events = append(c.quic.events, QUICEvent{
440 Kind: QUICWriteData,
441 Level: level,
442 })
443 last = &c.quic.events[len(c.quic.events)-1]
444 }
445 last.Data = append(last.Data, data...)
446 }
447
448 func (c *Conn) quicResumeSession(session *SessionState) error {
449 c.quic.events = append(c.quic.events, QUICEvent{
450 Kind: QUICResumeSession,
451 SessionState: session,
452 })
453 c.quic.waitingForDrain = true
454 for c.quic.waitingForDrain {
455 if err := c.quicWaitForSignal(); err != nil {
456 return err
457 }
458 }
459 return nil
460 }
461
462 func (c *Conn) quicStoreSession(session *SessionState) {
463 c.quic.events = append(c.quic.events, QUICEvent{
464 Kind: QUICStoreSession,
465 SessionState: session,
466 })
467 }
468
469 func (c *Conn) quicSetTransportParameters(params []byte) {
470 c.quic.events = append(c.quic.events, QUICEvent{
471 Kind: QUICTransportParameters,
472 Data: params,
473 })
474 }
475
476 func (c *Conn) quicGetTransportParameters() ([]byte, error) {
477 if c.quic.transportParams == nil {
478 c.quic.events = append(c.quic.events, QUICEvent{
479 Kind: QUICTransportParametersRequired,
480 })
481 }
482 for c.quic.transportParams == nil {
483 if err := c.quicWaitForSignal(); err != nil {
484 return nil, err
485 }
486 }
487 return c.quic.transportParams, nil
488 }
489
490 func (c *Conn) quicHandshakeComplete() {
491 c.quic.events = append(c.quic.events, QUICEvent{
492 Kind: QUICHandshakeDone,
493 })
494 }
495
496 func (c *Conn) quicRejectedEarlyData() {
497 c.quic.events = append(c.quic.events, QUICEvent{
498 Kind: QUICRejectedEarlyData,
499 })
500 }
501
502
503
504
505
506
507 func (c *Conn) quicWaitForSignal() error {
508
509
510 c.handshakeMutex.Unlock()
511 defer c.handshakeMutex.Lock()
512
513
514
515 c.quic.blockedc <- struct{}{}
516
517
518
519 c.quic.signalc <- struct{}{}
520 if c.quic.ctx.Err() != nil {
521
522 return c.sendAlertLocked(alertCloseNotify)
523 }
524 c.hand.Write(c.quic.readbuf)
525 c.quic.readbuf = nil
526 return nil
527 }
528
View as plain text