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.
13 // QUICEncryptionLevel represents a QUIC encryption level used to transmit
14 // handshake messages.
15 type QUICEncryptionLevel int
18 QUICEncryptionLevelInitial = QUICEncryptionLevel(iota)
19 QUICEncryptionLevelHandshake
20 QUICEncryptionLevelApplication
23 func (l QUICEncryptionLevel) String() string {
25 case QUICEncryptionLevelInitial:
27 case QUICEncryptionLevelHandshake:
29 case QUICEncryptionLevelApplication:
32 return fmt.Sprintf("QUICEncryptionLevel(%v)", int(l))
36 // A QUICConn represents a connection which uses a QUIC implementation as the underlying
37 // transport as described in RFC 9001.
39 // Methods of QUICConn are not safe for concurrent use.
40 type QUICConn struct {
44 // A QUICConfig configures a QUICConn.
45 type QUICConfig struct {
49 // A QUICEventKind is a type of operation on a QUIC connection.
50 type QUICEventKind int
53 // QUICNoEvent indicates that there are no events available.
54 QUICNoEvent QUICEventKind = iota
56 // QUICSetReadSecret and QUICSetWriteSecret provide the read and write
57 // secrets for a given encryption level.
58 // QUICEvent.Level, QUICEvent.Data, and QUICEvent.Suite are set.
60 // Secrets for the Initial encryption level are derived from the initial
61 // destination connection ID, and are not provided by the QUICConn.
65 // QUICWriteData provides data to send to the peer in CRYPTO frames.
66 // QUICEvent.Data is set.
69 // QUICTransportParameters provides the peer's QUIC transport parameters.
70 // QUICEvent.Data is set.
71 QUICTransportParameters
73 // QUICTransportParametersRequired indicates that the caller must provide
74 // QUIC transport parameters to send to the peer. The caller should set
75 // the transport parameters with QUICConn.SetTransportParameters and call
76 // QUICConn.NextEvent again.
78 // If transport parameters are set before calling QUICConn.Start, the
79 // connection will never generate a QUICTransportParametersRequired event.
80 QUICTransportParametersRequired
82 // QUICHandshakeDone indicates that the TLS handshake has completed.
86 // A QUICEvent is an event occurring on a QUIC connection.
88 // The type of event is specified by the Kind field.
89 // The contents of the other fields are kind-specific.
90 type QUICEvent struct {
93 // Set for QUICSetReadSecret, QUICSetWriteSecret, and QUICWriteData.
94 Level QUICEncryptionLevel
96 // Set for QUICTransportParameters, QUICSetReadSecret, QUICSetWriteSecret, and QUICWriteData.
97 // The contents are owned by crypto/tls, and are valid until the next NextEvent call.
100 // Set for QUICSetReadSecret and QUICSetWriteSecret.
104 type quicState struct {
108 // eventArr is a statically allocated event array, large enough to handle
109 // the usual maximum number of events resulting from a single call:
110 // transport parameters, Initial data, Handshake write and read secrets,
111 // Handshake data, Application write secret, Application data.
112 eventArr [7]QUICEvent
115 signalc chan struct{} // handshake data is available to be read
116 blockedc chan struct{} // handshake is waiting for data, closed when done
117 cancelc <-chan struct{} // handshake has been canceled
118 cancel context.CancelFunc
120 // readbuf is shared between HandleData and the handshake goroutine.
121 // HandshakeCryptoData passes ownership to the handshake goroutine by
122 // reading from signalc, and reclaims ownership by reading from blockedc.
125 transportParams []byte // to send to the peer
128 // QUICClient returns a new TLS client side connection using QUICTransport as the
129 // underlying transport. The config cannot be nil.
131 // The config's MinVersion must be at least TLS 1.3.
132 func QUICClient(config *QUICConfig) *QUICConn {
133 return newQUICConn(Client(nil, config.TLSConfig))
136 // QUICServer returns a new TLS server side connection using QUICTransport as the
137 // underlying transport. The config cannot be nil.
139 // The config's MinVersion must be at least TLS 1.3.
140 func QUICServer(config *QUICConfig) *QUICConn {
141 return newQUICConn(Server(nil, config.TLSConfig))
144 func newQUICConn(conn *Conn) *QUICConn {
145 conn.quic = &quicState{
146 signalc: make(chan struct{}),
147 blockedc: make(chan struct{}),
149 conn.quic.events = conn.quic.eventArr[:0]
155 // Start starts the client or server handshake protocol.
156 // It may produce connection events, which may be read with NextEvent.
158 // Start must be called at most once.
159 func (q *QUICConn) Start(ctx context.Context) error {
160 if q.conn.quic.started {
161 return quicError(errors.New("tls: Start called more than once"))
163 q.conn.quic.started = true
164 if q.conn.config.MinVersion < VersionTLS13 {
165 return quicError(errors.New("tls: Config MinVersion must be at least TLS 1.13"))
167 go q.conn.HandshakeContext(ctx)
168 if _, ok := <-q.conn.quic.blockedc; !ok {
169 return q.conn.handshakeErr
174 // NextEvent returns the next event occurring on the connection.
175 // It returns an event with a Kind of QUICNoEvent when no events are available.
176 func (q *QUICConn) NextEvent() QUICEvent {
178 if last := qs.nextEvent - 1; last >= 0 && len(qs.events[last].Data) > 0 {
179 // Write over some of the previous event's data,
180 // to catch callers erroniously retaining it.
181 qs.events[last].Data[0] = 0
183 if qs.nextEvent >= len(qs.events) {
184 qs.events = qs.events[:0]
186 return QUICEvent{Kind: QUICNoEvent}
188 e := qs.events[qs.nextEvent]
189 qs.events[qs.nextEvent] = QUICEvent{} // zero out references to data
194 // Close closes the connection and stops any in-progress handshake.
195 func (q *QUICConn) Close() error {
196 if q.conn.quic.cancel == nil {
197 return nil // never started
200 for range q.conn.quic.blockedc {
201 // Wait for the handshake goroutine to return.
203 return q.conn.handshakeErr
206 // HandleData handles handshake bytes received from the peer.
207 // It may produce connection events, which may be read with NextEvent.
208 func (q *QUICConn) HandleData(level QUICEncryptionLevel, data []byte) error {
210 if c.in.level != level {
211 return quicError(c.in.setErrorLocked(errors.New("tls: handshake data received at wrong level")))
213 c.quic.readbuf = data
215 _, ok := <-c.quic.blockedc
217 // The handshake goroutine is waiting for more data.
220 // The handshake goroutine has exited.
221 c.hand.Write(c.quic.readbuf)
223 for q.conn.hand.Len() >= 4 && q.conn.handshakeErr == nil {
224 b := q.conn.hand.Bytes()
225 n := int(b[1])<<16 | int(b[2])<<8 | int(b[3])
229 if err := q.conn.handlePostHandshakeMessage(); err != nil {
230 return quicError(err)
233 if q.conn.handshakeErr != nil {
234 return quicError(q.conn.handshakeErr)
239 // ConnectionState returns basic TLS details about the connection.
240 func (q *QUICConn) ConnectionState() ConnectionState {
241 return q.conn.ConnectionState()
244 // SetTransportParameters sets the transport parameters to send to the peer.
246 // Server connections may delay setting the transport parameters until after
247 // receiving the client's transport parameters. See QUICTransportParametersRequired.
248 func (q *QUICConn) SetTransportParameters(params []byte) {
252 q.conn.quic.transportParams = params
253 if q.conn.quic.started {
254 <-q.conn.quic.signalc
255 <-q.conn.quic.blockedc
259 // quicError ensures err is an AlertError.
260 // If err is not already, quicError wraps it with alertInternalError.
261 func quicError(err error) error {
266 if errors.As(err, &ae) {
270 if !errors.As(err, &a) {
271 a = alertInternalError
273 // Return an error wrapping the original error and an AlertError.
274 // Truncate the text of the alert to 0 characters.
275 return fmt.Errorf("%w%.0w", err, AlertError(a))
278 func (c *Conn) quicReadHandshakeBytes(n int) error {
279 for c.hand.Len() < n {
280 if err := c.quicWaitForSignal(); err != nil {
287 func (c *Conn) quicSetReadSecret(level QUICEncryptionLevel, suite uint16, secret []byte) {
288 c.quic.events = append(c.quic.events, QUICEvent{
289 Kind: QUICSetReadSecret,
296 func (c *Conn) quicSetWriteSecret(level QUICEncryptionLevel, suite uint16, secret []byte) {
297 c.quic.events = append(c.quic.events, QUICEvent{
298 Kind: QUICSetWriteSecret,
305 func (c *Conn) quicWriteCryptoData(level QUICEncryptionLevel, data []byte) {
307 if len(c.quic.events) > 0 {
308 last = &c.quic.events[len(c.quic.events)-1]
310 if last == nil || last.Kind != QUICWriteData || last.Level != level {
311 c.quic.events = append(c.quic.events, QUICEvent{
315 last = &c.quic.events[len(c.quic.events)-1]
317 last.Data = append(last.Data, data...)
320 func (c *Conn) quicSetTransportParameters(params []byte) {
321 c.quic.events = append(c.quic.events, QUICEvent{
322 Kind: QUICTransportParameters,
327 func (c *Conn) quicGetTransportParameters() ([]byte, error) {
328 if c.quic.transportParams == nil {
329 c.quic.events = append(c.quic.events, QUICEvent{
330 Kind: QUICTransportParametersRequired,
333 for c.quic.transportParams == nil {
334 if err := c.quicWaitForSignal(); err != nil {
338 return c.quic.transportParams, nil
341 func (c *Conn) quicHandshakeComplete() {
342 c.quic.events = append(c.quic.events, QUICEvent{
343 Kind: QUICHandshakeDone,
347 // quicWaitForSignal notifies the QUICConn that handshake progress is blocked,
348 // and waits for a signal that the handshake should proceed.
350 // The handshake may become blocked waiting for handshake bytes
351 // or for the user to provide transport parameters.
352 func (c *Conn) quicWaitForSignal() error {
353 // Drop the handshake mutex while blocked to allow the user
354 // to call ConnectionState before the handshake completes.
355 c.handshakeMutex.Unlock()
356 defer c.handshakeMutex.Lock()
357 // Send on blockedc to notify the QUICConn that the handshake is blocked.
358 // Exported methods of QUICConn wait for the handshake to become blocked
359 // before returning to the user.
361 case c.quic.blockedc <- struct{}{}:
362 case <-c.quic.cancelc:
363 return c.sendAlertLocked(alertCloseNotify)
365 // The QUICConn reads from signalc to notify us that the handshake may
366 // be able to proceed. (The QUICConn reads, because we close signalc to
367 // indicate that the handshake has completed.)
369 case c.quic.signalc <- struct{}{}:
370 c.hand.Write(c.quic.readbuf)
372 case <-c.quic.cancelc:
373 return c.sendAlertLocked(alertCloseNotify)