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 "fmt"
11 )
12 13 // QUICEncryptionLevel represents a QUIC encryption level used to transmit
14 // handshake messages.
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 // A QUICConn represents a connection which uses a QUIC implementation as the underlying
40 // transport as described in RFC 9001.
41 //
42 // Methods of QUICConn are not safe for concurrent use.
43 type QUICConn struct {
44 conn *Conn
45 46 sessionTicketSent bool
47 }
48 49 // A QUICConfig configures a [QUICConn].
50 type QUICConfig struct {
51 TLSConfig *Config
52 53 // EnableSessionEvents may be set to true to enable the
54 // [QUICStoreSession] and [QUICResumeSession] events for client connections.
55 // When this event is enabled, sessions are not automatically
56 // stored in the client session cache.
57 // The application should use [QUICConn.StoreSession] to store sessions.
58 EnableSessionEvents bool
59 }
60 61 // A QUICEventKind is a type of operation on a QUIC connection.
62 type QUICEventKind int
63 64 const (
65 // QUICNoEvent indicates that there are no events available.
66 QUICNoEvent QUICEventKind = iota
67 68 // QUICSetReadSecret and QUICSetWriteSecret provide the read and write
69 // secrets for a given encryption level.
70 // QUICEvent.Level, QUICEvent.Data, and QUICEvent.Suite are set.
71 //
72 // Secrets for the Initial encryption level are derived from the initial
73 // destination connection ID, and are not provided by the QUICConn.
74 QUICSetReadSecret
75 QUICSetWriteSecret
76 77 // QUICWriteData provides data to send to the peer in CRYPTO frames.
78 // QUICEvent.Data is set.
79 QUICWriteData
80 81 // QUICTransportParameters provides the peer's QUIC transport parameters.
82 // QUICEvent.Data is set.
83 QUICTransportParameters
84 85 // QUICTransportParametersRequired indicates that the caller must provide
86 // QUIC transport parameters to send to the peer. The caller should set
87 // the transport parameters with QUICConn.SetTransportParameters and call
88 // QUICConn.NextEvent again.
89 //
90 // If transport parameters are set before calling QUICConn.Start, the
91 // connection will never generate a QUICTransportParametersRequired event.
92 QUICTransportParametersRequired
93 94 // QUICRejectedEarlyData indicates that the server rejected 0-RTT data even
95 // if we offered it. It's returned before QUICEncryptionLevelApplication
96 // keys are returned.
97 // This event only occurs on client connections.
98 QUICRejectedEarlyData
99 100 // QUICHandshakeDone indicates that the TLS handshake has completed.
101 QUICHandshakeDone
102 103 // QUICResumeSession indicates that a client is attempting to resume a previous session.
104 // [QUICEvent.SessionState] is set.
105 //
106 // For client connections, this event occurs when the session ticket is selected.
107 // For server connections, this event occurs when receiving the client's session ticket.
108 //
109 // The application may set [QUICEvent.SessionState.EarlyData] to false before the
110 // next call to [QUICConn.NextEvent] to decline 0-RTT even if the session supports it.
111 QUICResumeSession
112 113 // QUICStoreSession indicates that the server has provided state permitting
114 // the client to resume the session.
115 // [QUICEvent.SessionState] is set.
116 // The application should use [QUICConn.StoreSession] session to store the [SessionState].
117 // The application may modify the [SessionState] before storing it.
118 // This event only occurs on client connections.
119 QUICStoreSession
120 121 // QUICErrorEvent indicates that a fatal error has occurred.
122 // The handshake cannot proceed and the connection must be closed.
123 // QUICEvent.Err is set.
124 QUICErrorEvent
125 )
126 127 // A QUICEvent is an event occurring on a QUIC connection.
128 //
129 // The type of event is specified by the Kind field.
130 // The contents of the other fields are kind-specific.
131 type QUICEvent struct {
132 Kind QUICEventKind
133 134 // Set for QUICSetReadSecret, QUICSetWriteSecret, and QUICWriteData.
135 Level QUICEncryptionLevel
136 137 // Set for QUICTransportParameters, QUICSetReadSecret, QUICSetWriteSecret, and QUICWriteData.
138 // The contents are owned by crypto/tls, and are valid until the next NextEvent call.
139 Data []byte
140 141 // Set for QUICSetReadSecret and QUICSetWriteSecret.
142 Suite uint16
143 144 // Set for QUICResumeSession and QUICStoreSession.
145 SessionState *SessionState
146 147 // Set for QUICErrorEvent.
148 // The error will wrap AlertError.
149 Err error
150 }
151 152 type quicState struct {
153 events []QUICEvent
154 nextEvent int
155 156 // eventArr is a statically allocated event array, large enough to handle
157 // the usual maximum number of events resulting from a single call: transport
158 // parameters, Initial data, Early read secret, Handshake write and read
159 // secrets, Handshake data, Application write secret, Application data.
160 eventArr [8]QUICEvent
161 162 started bool
163 signalc chan struct{} // handshake data is available to be read
164 blockedc chan struct{} // handshake is waiting for data, closed when done
165 ctx context.Context // handshake context
166 cancel context.CancelFunc
167 168 waitingForDrain bool
169 errorReturned bool
170 171 // readbuf is shared between HandleData and the handshake goroutine.
172 // HandshakeCryptoData passes ownership to the handshake goroutine by
173 // reading from signalc, and reclaims ownership by reading from blockedc.
174 readbuf []byte
175 176 transportParams []byte // to send to the peer
177 178 enableSessionEvents bool
179 }
180 181 // QUICClient returns a new TLS client side connection using QUICTransport as the
182 // underlying transport. The config cannot be nil.
183 //
184 // The config's MinVersion must be at least TLS 1.3.
185 func QUICClient(config *QUICConfig) *QUICConn {
186 return newQUICConn(Client(nil, config.TLSConfig), config)
187 }
188 189 // QUICServer returns a new TLS server side connection using QUICTransport as the
190 // underlying transport. The config cannot be nil.
191 //
192 // The config's MinVersion must be at least TLS 1.3.
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: chan struct{}{},
200 blockedc: 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 // Start starts the client or server handshake protocol.
210 // It may produce connection events, which may be read with [QUICConn.NextEvent].
211 //
212 // Start must be called at most once.
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 // moxie: no goroutines, run synchronously.
222 // QUIC is not used in moxie; this is a stub.
223 q.conn.HandshakeContext(ctx)
224 if _, ok := <-q.conn.quic.blockedc; !ok {
225 return q.conn.handshakeErr
226 }
227 return nil
228 }
229 230 // NextEvent returns the next event occurring on the connection.
231 // It returns an event with a Kind of [QUICNoEvent] when no events are available.
232 func (q *QUICConn) NextEvent() QUICEvent {
233 qs := q.conn.quic
234 if last := qs.nextEvent - 1; last >= 0 && len(qs.events[last].Data) > 0 {
235 // Write over some of the previous event's data,
236 // to catch callers erroneously retaining it.
237 qs.events[last].Data[0] = 0
238 }
239 if qs.nextEvent >= len(qs.events) && qs.waitingForDrain {
240 qs.waitingForDrain = false
241 <-qs.signalc
242 <-qs.blockedc
243 }
244 if err := q.conn.handshakeErr; err != nil {
245 if qs.errorReturned {
246 return QUICEvent{Kind: QUICNoEvent}
247 }
248 qs.errorReturned = true
249 qs.events = nil
250 qs.nextEvent = 0
251 return QUICEvent{Kind: QUICErrorEvent, Err: q.conn.handshakeErr}
252 }
253 if qs.nextEvent >= len(qs.events) {
254 qs.events = qs.events[:0]
255 qs.nextEvent = 0
256 return QUICEvent{Kind: QUICNoEvent}
257 }
258 e := qs.events[qs.nextEvent]
259 qs.events[qs.nextEvent] = QUICEvent{} // zero out references to data
260 qs.nextEvent++
261 return e
262 }
263 264 // Close closes the connection and stops any in-progress handshake.
265 func (q *QUICConn) Close() error {
266 if q.conn.quic.ctx == nil {
267 return nil // never started
268 }
269 q.conn.quic.cancel()
270 <-q.conn.quic.signalc
271 for range q.conn.quic.blockedc {
272 // Wait for the handshake goroutine to return.
273 }
274 return q.conn.handshakeErr
275 }
276 277 // HandleData handles handshake bytes received from the peer.
278 // It may produce connection events, which may be read with [QUICConn.NextEvent].
279 func (q *QUICConn) HandleData(level QUICEncryptionLevel, data []byte) error {
280 c := q.conn
281 if c.in.level != level {
282 return quicError(c.in.setErrorLocked(errors.New("tls: handshake data received at wrong level")))
283 }
284 c.quic.readbuf = data
285 <-c.quic.signalc
286 _, ok := <-c.quic.blockedc
287 if ok {
288 // The handshake goroutine is waiting for more data.
289 return nil
290 }
291 // The handshake goroutine has exited.
292 c.handshakeMutex.Lock()
293 defer c.handshakeMutex.Unlock()
294 c.hand.Write(c.quic.readbuf)
295 c.quic.readbuf = nil
296 for q.conn.hand.Len() >= 4 && q.conn.handshakeErr == nil {
297 b := q.conn.hand.Bytes()
298 n := int(b[1])<<16 | int(b[2])<<8 | int(b[3])
299 if n > maxHandshake {
300 q.conn.handshakeErr = fmt.Errorf("tls: handshake message of length %d bytes exceeds maximum of %d bytes", n, maxHandshake)
301 break
302 }
303 if len(b) < 4+n {
304 return nil
305 }
306 if err := q.conn.handlePostHandshakeMessage(); err != nil {
307 q.conn.handshakeErr = err
308 }
309 }
310 if q.conn.handshakeErr != nil {
311 return quicError(q.conn.handshakeErr)
312 }
313 return nil
314 }
315 316 type QUICSessionTicketOptions struct {
317 // EarlyData specifies whether the ticket may be used for 0-RTT.
318 EarlyData bool
319 Extra [][]byte
320 }
321 322 // SendSessionTicket sends a session ticket to the client.
323 // It produces connection events, which may be read with [QUICConn.NextEvent].
324 // Currently, it can only be called once.
325 func (q *QUICConn) SendSessionTicket(opts QUICSessionTicketOptions) error {
326 c := q.conn
327 if c.config.SessionTicketsDisabled {
328 return nil
329 }
330 if !c.isHandshakeComplete.Load() {
331 return quicError(errors.New("tls: SendSessionTicket called before handshake completed"))
332 }
333 if c.isClient {
334 return quicError(errors.New("tls: SendSessionTicket called on the client"))
335 }
336 if q.sessionTicketSent {
337 return quicError(errors.New("tls: SendSessionTicket called multiple times"))
338 }
339 q.sessionTicketSent = true
340 return quicError(c.sendSessionTicket(opts.EarlyData, opts.Extra))
341 }
342 343 // StoreSession stores a session previously received in a QUICStoreSession event
344 // in the ClientSessionCache.
345 // The application may process additional events or modify the SessionState
346 // before storing the session.
347 func (q *QUICConn) StoreSession(session *SessionState) error {
348 c := q.conn
349 if !c.isClient {
350 return quicError(errors.New("tls: StoreSessionTicket called on the server"))
351 }
352 cacheKey := c.clientSessionCacheKey()
353 if cacheKey == "" {
354 return nil
355 }
356 cs := &ClientSessionState{session: session}
357 c.config.ClientSessionCache.Put(cacheKey, cs)
358 return nil
359 }
360 361 // ConnectionState returns basic TLS details about the connection.
362 func (q *QUICConn) ConnectionState() ConnectionState {
363 return q.conn.ConnectionState()
364 }
365 366 // SetTransportParameters sets the transport parameters to send to the peer.
367 //
368 // Server connections may delay setting the transport parameters until after
369 // receiving the client's transport parameters. See [QUICTransportParametersRequired].
370 func (q *QUICConn) SetTransportParameters(params []byte) {
371 if params == nil {
372 params = []byte{}
373 }
374 q.conn.quic.transportParams = params
375 if q.conn.quic.started {
376 <-q.conn.quic.signalc
377 <-q.conn.quic.blockedc
378 }
379 }
380 381 // quicError ensures err is an AlertError.
382 // If err is not already, quicError wraps it with alertInternalError.
383 func quicError(err error) error {
384 if err == nil {
385 return nil
386 }
387 if _, ok := err.(AlertError); ok {
388 return err
389 }
390 a, ok := err.(alert)
391 if !ok {
392 a = alertInternalError
393 }
394 // Return an error wrapping the original error and an AlertError.
395 // Truncate the text of the alert to 0 characters.
396 return fmt.Errorf("%w%.0w", err, AlertError(a))
397 }
398 399 func (c *Conn) quicReadHandshakeBytes(n int) error {
400 for c.hand.Len() < n {
401 if err := c.quicWaitForSignal(); err != nil {
402 return err
403 }
404 }
405 return nil
406 }
407 408 func (c *Conn) quicSetReadSecret(level QUICEncryptionLevel, suite uint16, secret []byte) error {
409 // Ensure that there are no buffered handshake messages before changing the
410 // read keys, since that can cause messages to be parsed that were encrypted
411 // using old keys which are no longer appropriate.
412 // TODO(roland): we should merge this check with the similar one in setReadTrafficSecret.
413 if c.hand.Len() != 0 {
414 c.sendAlert(alertUnexpectedMessage)
415 return errors.New("tls: handshake buffer not empty before setting read traffic secret")
416 }
417 c.quic.events = append(c.quic.events, QUICEvent{
418 Kind: QUICSetReadSecret,
419 Level: level,
420 Suite: suite,
421 Data: secret,
422 })
423 return nil
424 }
425 426 func (c *Conn) quicSetWriteSecret(level QUICEncryptionLevel, suite uint16, secret []byte) {
427 c.quic.events = append(c.quic.events, QUICEvent{
428 Kind: QUICSetWriteSecret,
429 Level: level,
430 Suite: suite,
431 Data: secret,
432 })
433 }
434 435 func (c *Conn) quicWriteCryptoData(level QUICEncryptionLevel, data []byte) {
436 var last *QUICEvent
437 if len(c.quic.events) > 0 {
438 last = &c.quic.events[len(c.quic.events)-1]
439 }
440 if last == nil || last.Kind != QUICWriteData || last.Level != level {
441 c.quic.events = append(c.quic.events, QUICEvent{
442 Kind: QUICWriteData,
443 Level: level,
444 })
445 last = &c.quic.events[len(c.quic.events)-1]
446 }
447 last.Data = append(last.Data, data...)
448 }
449 450 func (c *Conn) quicResumeSession(session *SessionState) error {
451 c.quic.events = append(c.quic.events, QUICEvent{
452 Kind: QUICResumeSession,
453 SessionState: session,
454 })
455 c.quic.waitingForDrain = true
456 for c.quic.waitingForDrain {
457 if err := c.quicWaitForSignal(); err != nil {
458 return err
459 }
460 }
461 return nil
462 }
463 464 func (c *Conn) quicStoreSession(session *SessionState) {
465 c.quic.events = append(c.quic.events, QUICEvent{
466 Kind: QUICStoreSession,
467 SessionState: session,
468 })
469 }
470 471 func (c *Conn) quicSetTransportParameters(params []byte) {
472 c.quic.events = append(c.quic.events, QUICEvent{
473 Kind: QUICTransportParameters,
474 Data: params,
475 })
476 }
477 478 func (c *Conn) quicGetTransportParameters() ([]byte, error) {
479 if c.quic.transportParams == nil {
480 c.quic.events = append(c.quic.events, QUICEvent{
481 Kind: QUICTransportParametersRequired,
482 })
483 }
484 for c.quic.transportParams == nil {
485 if err := c.quicWaitForSignal(); err != nil {
486 return nil, err
487 }
488 }
489 return c.quic.transportParams, nil
490 }
491 492 func (c *Conn) quicHandshakeComplete() {
493 c.quic.events = append(c.quic.events, QUICEvent{
494 Kind: QUICHandshakeDone,
495 })
496 }
497 498 func (c *Conn) quicRejectedEarlyData() {
499 c.quic.events = append(c.quic.events, QUICEvent{
500 Kind: QUICRejectedEarlyData,
501 })
502 }
503 504 // quicWaitForSignal notifies the QUICConn that handshake progress is blocked,
505 // and waits for a signal that the handshake should proceed.
506 //
507 // The handshake may become blocked waiting for handshake bytes
508 // or for the user to provide transport parameters.
509 func (c *Conn) quicWaitForSignal() error {
510 // Drop the handshake mutex while blocked to allow the user
511 // to call ConnectionState before the handshake completes.
512 c.handshakeMutex.Unlock()
513 defer c.handshakeMutex.Lock()
514 // Send on blockedc to notify the QUICConn that the handshake is blocked.
515 // Exported methods of QUICConn wait for the handshake to become blocked
516 // before returning to the user.
517 c.quic.blockedc <- struct{}{}
518 // The QUICConn reads from signalc to notify us that the handshake may
519 // be able to proceed. (The QUICConn reads, because we close signalc to
520 // indicate that the handshake has completed.)
521 c.quic.signalc <- struct{}{}
522 if c.quic.ctx.Err() != nil {
523 // The connection has been canceled.
524 return c.sendAlertLocked(alertCloseNotify)
525 }
526 c.hand.Write(c.quic.readbuf)
527 c.quic.readbuf = nil
528 return nil
529 }
530