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
5package tls
6
7import (
8	"context"
9	"errors"
10	"fmt"
11)
12
13// QUICEncryptionLevel represents a QUIC encryption level used to transmit
14// handshake messages.
15type QUICEncryptionLevel int
16
17const (
18	QUICEncryptionLevelInitial = QUICEncryptionLevel(iota)
19	QUICEncryptionLevelEarly
20	QUICEncryptionLevelHandshake
21	QUICEncryptionLevelApplication
22)
23
24func (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.
43type QUICConn struct {
44	conn *Conn
45
46	sessionTicketSent bool
47}
48
49// A QUICConfig configures a [QUICConn].
50type 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.
62type QUICEventKind int
63
64const (
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
122// A QUICEvent is an event occurring on a QUIC connection.
123//
124// The type of event is specified by the Kind field.
125// The contents of the other fields are kind-specific.
126type QUICEvent struct {
127	Kind QUICEventKind
128
129	// Set for QUICSetReadSecret, QUICSetWriteSecret, and QUICWriteData.
130	Level QUICEncryptionLevel
131
132	// Set for QUICTransportParameters, QUICSetReadSecret, QUICSetWriteSecret, and QUICWriteData.
133	// The contents are owned by crypto/tls, and are valid until the next NextEvent call.
134	Data []byte
135
136	// Set for QUICSetReadSecret and QUICSetWriteSecret.
137	Suite uint16
138
139	// Set for QUICResumeSession and QUICStoreSession.
140	SessionState *SessionState
141}
142
143type quicState struct {
144	events    []QUICEvent
145	nextEvent int
146
147	// eventArr is a statically allocated event array, large enough to handle
148	// the usual maximum number of events resulting from a single call: transport
149	// parameters, Initial data, Early read secret, Handshake write and read
150	// secrets, Handshake data, Application write secret, Application data.
151	eventArr [8]QUICEvent
152
153	started  bool
154	signalc  chan struct{}   // handshake data is available to be read
155	blockedc chan struct{}   // handshake is waiting for data, closed when done
156	cancelc  <-chan struct{} // handshake has been canceled
157	cancel   context.CancelFunc
158
159	waitingForDrain bool
160
161	// readbuf is shared between HandleData and the handshake goroutine.
162	// HandshakeCryptoData passes ownership to the handshake goroutine by
163	// reading from signalc, and reclaims ownership by reading from blockedc.
164	readbuf []byte
165
166	transportParams []byte // to send to the peer
167
168	enableSessionEvents bool
169}
170
171// QUICClient returns a new TLS client side connection using QUICTransport as the
172// underlying transport. The config cannot be nil.
173//
174// The config's MinVersion must be at least TLS 1.3.
175func QUICClient(config *QUICConfig) *QUICConn {
176	return newQUICConn(Client(nil, config.TLSConfig), config)
177}
178
179// QUICServer returns a new TLS server side connection using QUICTransport as the
180// underlying transport. The config cannot be nil.
181//
182// The config's MinVersion must be at least TLS 1.3.
183func QUICServer(config *QUICConfig) *QUICConn {
184	return newQUICConn(Server(nil, config.TLSConfig), config)
185}
186
187func newQUICConn(conn *Conn, config *QUICConfig) *QUICConn {
188	conn.quic = &quicState{
189		signalc:             make(chan struct{}),
190		blockedc:            make(chan struct{}),
191		enableSessionEvents: config.EnableSessionEvents,
192	}
193	conn.quic.events = conn.quic.eventArr[:0]
194	return &QUICConn{
195		conn: conn,
196	}
197}
198
199// Start starts the client or server handshake protocol.
200// It may produce connection events, which may be read with [QUICConn.NextEvent].
201//
202// Start must be called at most once.
203func (q *QUICConn) Start(ctx context.Context) error {
204	if q.conn.quic.started {
205		return quicError(errors.New("tls: Start called more than once"))
206	}
207	q.conn.quic.started = true
208	if q.conn.config.MinVersion < VersionTLS13 {
209		return quicError(errors.New("tls: Config MinVersion must be at least TLS 1.13"))
210	}
211	go q.conn.HandshakeContext(ctx)
212	if _, ok := <-q.conn.quic.blockedc; !ok {
213		return q.conn.handshakeErr
214	}
215	return nil
216}
217
218// NextEvent returns the next event occurring on the connection.
219// It returns an event with a Kind of [QUICNoEvent] when no events are available.
220func (q *QUICConn) NextEvent() QUICEvent {
221	qs := q.conn.quic
222	if last := qs.nextEvent - 1; last >= 0 && len(qs.events[last].Data) > 0 {
223		// Write over some of the previous event's data,
224		// to catch callers erroniously retaining it.
225		qs.events[last].Data[0] = 0
226	}
227	if qs.nextEvent >= len(qs.events) && qs.waitingForDrain {
228		qs.waitingForDrain = false
229		<-qs.signalc
230		<-qs.blockedc
231	}
232	if qs.nextEvent >= len(qs.events) {
233		qs.events = qs.events[:0]
234		qs.nextEvent = 0
235		return QUICEvent{Kind: QUICNoEvent}
236	}
237	e := qs.events[qs.nextEvent]
238	qs.events[qs.nextEvent] = QUICEvent{} // zero out references to data
239	qs.nextEvent++
240	return e
241}
242
243// Close closes the connection and stops any in-progress handshake.
244func (q *QUICConn) Close() error {
245	if q.conn.quic.cancel == nil {
246		return nil // never started
247	}
248	q.conn.quic.cancel()
249	for range q.conn.quic.blockedc {
250		// Wait for the handshake goroutine to return.
251	}
252	return q.conn.handshakeErr
253}
254
255// HandleData handles handshake bytes received from the peer.
256// It may produce connection events, which may be read with [QUICConn.NextEvent].
257func (q *QUICConn) HandleData(level QUICEncryptionLevel, data []byte) error {
258	c := q.conn
259	if c.in.level != level {
260		return quicError(c.in.setErrorLocked(errors.New("tls: handshake data received at wrong level")))
261	}
262	c.quic.readbuf = data
263	<-c.quic.signalc
264	_, ok := <-c.quic.blockedc
265	if ok {
266		// The handshake goroutine is waiting for more data.
267		return nil
268	}
269	// The handshake goroutine has exited.
270	c.handshakeMutex.Lock()
271	defer c.handshakeMutex.Unlock()
272	c.hand.Write(c.quic.readbuf)
273	c.quic.readbuf = nil
274	for q.conn.hand.Len() >= 4 && q.conn.handshakeErr == nil {
275		b := q.conn.hand.Bytes()
276		n := int(b[1])<<16 | int(b[2])<<8 | int(b[3])
277		if n > maxHandshake {
278			q.conn.handshakeErr = fmt.Errorf("tls: handshake message of length %d bytes exceeds maximum of %d bytes", n, maxHandshake)
279			break
280		}
281		if len(b) < 4+n {
282			return nil
283		}
284		if err := q.conn.handlePostHandshakeMessage(); err != nil {
285			q.conn.handshakeErr = err
286		}
287	}
288	if q.conn.handshakeErr != nil {
289		return quicError(q.conn.handshakeErr)
290	}
291	return nil
292}
293
294type QUICSessionTicketOptions struct {
295	// EarlyData specifies whether the ticket may be used for 0-RTT.
296	EarlyData bool
297	Extra     [][]byte
298}
299
300// SendSessionTicket sends a session ticket to the client.
301// It produces connection events, which may be read with [QUICConn.NextEvent].
302// Currently, it can only be called once.
303func (q *QUICConn) SendSessionTicket(opts QUICSessionTicketOptions) error {
304	c := q.conn
305	if !c.isHandshakeComplete.Load() {
306		return quicError(errors.New("tls: SendSessionTicket called before handshake completed"))
307	}
308	if c.isClient {
309		return quicError(errors.New("tls: SendSessionTicket called on the client"))
310	}
311	if q.sessionTicketSent {
312		return quicError(errors.New("tls: SendSessionTicket called multiple times"))
313	}
314	q.sessionTicketSent = true
315	return quicError(c.sendSessionTicket(opts.EarlyData, opts.Extra))
316}
317
318// StoreSession stores a session previously received in a QUICStoreSession event
319// in the ClientSessionCache.
320// The application may process additional events or modify the SessionState
321// before storing the session.
322func (q *QUICConn) StoreSession(session *SessionState) error {
323	c := q.conn
324	if !c.isClient {
325		return quicError(errors.New("tls: StoreSessionTicket called on the server"))
326	}
327	cacheKey := c.clientSessionCacheKey()
328	if cacheKey == "" {
329		return nil
330	}
331	cs := &ClientSessionState{session: session}
332	c.config.ClientSessionCache.Put(cacheKey, cs)
333	return nil
334}
335
336// ConnectionState returns basic TLS details about the connection.
337func (q *QUICConn) ConnectionState() ConnectionState {
338	return q.conn.ConnectionState()
339}
340
341// SetTransportParameters sets the transport parameters to send to the peer.
342//
343// Server connections may delay setting the transport parameters until after
344// receiving the client's transport parameters. See [QUICTransportParametersRequired].
345func (q *QUICConn) SetTransportParameters(params []byte) {
346	if params == nil {
347		params = []byte{}
348	}
349	q.conn.quic.transportParams = params
350	if q.conn.quic.started {
351		<-q.conn.quic.signalc
352		<-q.conn.quic.blockedc
353	}
354}
355
356// quicError ensures err is an AlertError.
357// If err is not already, quicError wraps it with alertInternalError.
358func quicError(err error) error {
359	if err == nil {
360		return nil
361	}
362	var ae AlertError
363	if errors.As(err, &ae) {
364		return err
365	}
366	var a alert
367	if !errors.As(err, &a) {
368		a = alertInternalError
369	}
370	// Return an error wrapping the original error and an AlertError.
371	// Truncate the text of the alert to 0 characters.
372	return fmt.Errorf("%w%.0w", err, AlertError(a))
373}
374
375func (c *Conn) quicReadHandshakeBytes(n int) error {
376	for c.hand.Len() < n {
377		if err := c.quicWaitForSignal(); err != nil {
378			return err
379		}
380	}
381	return nil
382}
383
384func (c *Conn) quicSetReadSecret(level QUICEncryptionLevel, suite uint16, secret []byte) {
385	c.quic.events = append(c.quic.events, QUICEvent{
386		Kind:  QUICSetReadSecret,
387		Level: level,
388		Suite: suite,
389		Data:  secret,
390	})
391}
392
393func (c *Conn) quicSetWriteSecret(level QUICEncryptionLevel, suite uint16, secret []byte) {
394	c.quic.events = append(c.quic.events, QUICEvent{
395		Kind:  QUICSetWriteSecret,
396		Level: level,
397		Suite: suite,
398		Data:  secret,
399	})
400}
401
402func (c *Conn) quicWriteCryptoData(level QUICEncryptionLevel, data []byte) {
403	var last *QUICEvent
404	if len(c.quic.events) > 0 {
405		last = &c.quic.events[len(c.quic.events)-1]
406	}
407	if last == nil || last.Kind != QUICWriteData || last.Level != level {
408		c.quic.events = append(c.quic.events, QUICEvent{
409			Kind:  QUICWriteData,
410			Level: level,
411		})
412		last = &c.quic.events[len(c.quic.events)-1]
413	}
414	last.Data = append(last.Data, data...)
415}
416
417func (c *Conn) quicResumeSession(session *SessionState) error {
418	c.quic.events = append(c.quic.events, QUICEvent{
419		Kind:         QUICResumeSession,
420		SessionState: session,
421	})
422	c.quic.waitingForDrain = true
423	for c.quic.waitingForDrain {
424		if err := c.quicWaitForSignal(); err != nil {
425			return err
426		}
427	}
428	return nil
429}
430
431func (c *Conn) quicStoreSession(session *SessionState) {
432	c.quic.events = append(c.quic.events, QUICEvent{
433		Kind:         QUICStoreSession,
434		SessionState: session,
435	})
436}
437
438func (c *Conn) quicSetTransportParameters(params []byte) {
439	c.quic.events = append(c.quic.events, QUICEvent{
440		Kind: QUICTransportParameters,
441		Data: params,
442	})
443}
444
445func (c *Conn) quicGetTransportParameters() ([]byte, error) {
446	if c.quic.transportParams == nil {
447		c.quic.events = append(c.quic.events, QUICEvent{
448			Kind: QUICTransportParametersRequired,
449		})
450	}
451	for c.quic.transportParams == nil {
452		if err := c.quicWaitForSignal(); err != nil {
453			return nil, err
454		}
455	}
456	return c.quic.transportParams, nil
457}
458
459func (c *Conn) quicHandshakeComplete() {
460	c.quic.events = append(c.quic.events, QUICEvent{
461		Kind: QUICHandshakeDone,
462	})
463}
464
465func (c *Conn) quicRejectedEarlyData() {
466	c.quic.events = append(c.quic.events, QUICEvent{
467		Kind: QUICRejectedEarlyData,
468	})
469}
470
471// quicWaitForSignal notifies the QUICConn that handshake progress is blocked,
472// and waits for a signal that the handshake should proceed.
473//
474// The handshake may become blocked waiting for handshake bytes
475// or for the user to provide transport parameters.
476func (c *Conn) quicWaitForSignal() error {
477	// Drop the handshake mutex while blocked to allow the user
478	// to call ConnectionState before the handshake completes.
479	c.handshakeMutex.Unlock()
480	defer c.handshakeMutex.Lock()
481	// Send on blockedc to notify the QUICConn that the handshake is blocked.
482	// Exported methods of QUICConn wait for the handshake to become blocked
483	// before returning to the user.
484	select {
485	case c.quic.blockedc <- struct{}{}:
486	case <-c.quic.cancelc:
487		return c.sendAlertLocked(alertCloseNotify)
488	}
489	// The QUICConn reads from signalc to notify us that the handshake may
490	// be able to proceed. (The QUICConn reads, because we close signalc to
491	// indicate that the handshake has completed.)
492	select {
493	case c.quic.signalc <- struct{}{}:
494		c.hand.Write(c.quic.readbuf)
495		c.quic.readbuf = nil
496	case <-c.quic.cancelc:
497		return c.sendAlertLocked(alertCloseNotify)
498	}
499	return nil
500}
501