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 QUICEncryptionLevelEarly
20 QUICEncryptionLevelHandshake
21 QUICEncryptionLevelApplication
24 func (l QUICEncryptionLevel) String() string {
26 case QUICEncryptionLevelInitial:
28 case QUICEncryptionLevelEarly:
30 case QUICEncryptionLevelHandshake:
32 case QUICEncryptionLevelApplication:
35 return fmt.Sprintf("QUICEncryptionLevel(%v)", int(l))
39 // A QUICConn represents a connection which uses a QUIC implementation as the underlying
40 // transport as described in RFC 9001.
42 // Methods of QUICConn are not safe for concurrent use.
43 type QUICConn struct {
46 sessionTicketSent bool
49 // A QUICConfig configures a QUICConn.
50 type QUICConfig struct {
54 // A QUICEventKind is a type of operation on a QUIC connection.
55 type QUICEventKind int
58 // QUICNoEvent indicates that there are no events available.
59 QUICNoEvent QUICEventKind = iota
61 // QUICSetReadSecret and QUICSetWriteSecret provide the read and write
62 // secrets for a given encryption level.
63 // QUICEvent.Level, QUICEvent.Data, and QUICEvent.Suite are set.
65 // Secrets for the Initial encryption level are derived from the initial
66 // destination connection ID, and are not provided by the QUICConn.
70 // QUICWriteData provides data to send to the peer in CRYPTO frames.
71 // QUICEvent.Data is set.
74 // QUICTransportParameters provides the peer's QUIC transport parameters.
75 // QUICEvent.Data is set.
76 QUICTransportParameters
78 // QUICTransportParametersRequired indicates that the caller must provide
79 // QUIC transport parameters to send to the peer. The caller should set
80 // the transport parameters with QUICConn.SetTransportParameters and call
81 // QUICConn.NextEvent again.
83 // If transport parameters are set before calling QUICConn.Start, the
84 // connection will never generate a QUICTransportParametersRequired event.
85 QUICTransportParametersRequired
87 // QUICRejectedEarlyData indicates that the server rejected 0-RTT data even
88 // if we offered it. It's returned before QUICEncryptionLevelApplication
92 // QUICHandshakeDone indicates that the TLS handshake has completed.
96 // A QUICEvent is an event occurring on a QUIC connection.
98 // The type of event is specified by the Kind field.
99 // The contents of the other fields are kind-specific.
100 type QUICEvent struct {
103 // Set for QUICSetReadSecret, QUICSetWriteSecret, and QUICWriteData.
104 Level QUICEncryptionLevel
106 // Set for QUICTransportParameters, QUICSetReadSecret, QUICSetWriteSecret, and QUICWriteData.
107 // The contents are owned by crypto/tls, and are valid until the next NextEvent call.
110 // Set for QUICSetReadSecret and QUICSetWriteSecret.
114 type quicState struct {
118 // eventArr is a statically allocated event array, large enough to handle
119 // the usual maximum number of events resulting from a single call: transport
120 // parameters, Initial data, Early read secret, Handshake write and read
121 // secrets, Handshake data, Application write secret, Application data.
122 eventArr [8]QUICEvent
125 signalc chan struct{} // handshake data is available to be read
126 blockedc chan struct{} // handshake is waiting for data, closed when done
127 cancelc <-chan struct{} // handshake has been canceled
128 cancel context.CancelFunc
130 // readbuf is shared between HandleData and the handshake goroutine.
131 // HandshakeCryptoData passes ownership to the handshake goroutine by
132 // reading from signalc, and reclaims ownership by reading from blockedc.
135 transportParams []byte // to send to the peer
138 // QUICClient returns a new TLS client side connection using QUICTransport as the
139 // underlying transport. The config cannot be nil.
141 // The config's MinVersion must be at least TLS 1.3.
142 func QUICClient(config *QUICConfig) *QUICConn {
143 return newQUICConn(Client(nil, config.TLSConfig))
146 // QUICServer returns a new TLS server side connection using QUICTransport as the
147 // underlying transport. The config cannot be nil.
149 // The config's MinVersion must be at least TLS 1.3.
150 func QUICServer(config *QUICConfig) *QUICConn {
151 return newQUICConn(Server(nil, config.TLSConfig))
154 func newQUICConn(conn *Conn) *QUICConn {
155 conn.quic = &quicState{
156 signalc: make(chan struct{}),
157 blockedc: make(chan struct{}),
159 conn.quic.events = conn.quic.eventArr[:0]
165 // Start starts the client or server handshake protocol.
166 // It may produce connection events, which may be read with NextEvent.
168 // Start must be called at most once.
169 func (q *QUICConn) Start(ctx context.Context) error {
170 if q.conn.quic.started {
171 return quicError(errors.New("tls: Start called more than once"))
173 q.conn.quic.started = true
174 if q.conn.config.MinVersion < VersionTLS13 {
175 return quicError(errors.New("tls: Config MinVersion must be at least TLS 1.13"))
177 go q.conn.HandshakeContext(ctx)
178 if _, ok := <-q.conn.quic.blockedc; !ok {
179 return q.conn.handshakeErr
184 // NextEvent returns the next event occurring on the connection.
185 // It returns an event with a Kind of QUICNoEvent when no events are available.
186 func (q *QUICConn) NextEvent() QUICEvent {
188 if last := qs.nextEvent - 1; last >= 0 && len(qs.events[last].Data) > 0 {
189 // Write over some of the previous event's data,
190 // to catch callers erroniously retaining it.
191 qs.events[last].Data[0] = 0
193 if qs.nextEvent >= len(qs.events) {
194 qs.events = qs.events[:0]
196 return QUICEvent{Kind: QUICNoEvent}
198 e := qs.events[qs.nextEvent]
199 qs.events[qs.nextEvent] = QUICEvent{} // zero out references to data
204 // Close closes the connection and stops any in-progress handshake.
205 func (q *QUICConn) Close() error {
206 if q.conn.quic.cancel == nil {
207 return nil // never started
210 for range q.conn.quic.blockedc {
211 // Wait for the handshake goroutine to return.
213 return q.conn.handshakeErr
216 // HandleData handles handshake bytes received from the peer.
217 // It may produce connection events, which may be read with NextEvent.
218 func (q *QUICConn) HandleData(level QUICEncryptionLevel, data []byte) error {
220 if c.in.level != level {
221 return quicError(c.in.setErrorLocked(errors.New("tls: handshake data received at wrong level")))
223 c.quic.readbuf = data
225 _, ok := <-c.quic.blockedc
227 // The handshake goroutine is waiting for more data.
230 // The handshake goroutine has exited.
231 c.hand.Write(c.quic.readbuf)
233 for q.conn.hand.Len() >= 4 && q.conn.handshakeErr == nil {
234 b := q.conn.hand.Bytes()
235 n := int(b[1])<<16 | int(b[2])<<8 | int(b[3])
239 if err := q.conn.handlePostHandshakeMessage(); err != nil {
240 return quicError(err)
243 if q.conn.handshakeErr != nil {
244 return quicError(q.conn.handshakeErr)
249 // SendSessionTicket sends a session ticket to the client.
250 // It produces connection events, which may be read with NextEvent.
251 // Currently, it can only be called once.
252 func (q *QUICConn) SendSessionTicket(earlyData bool) error {
254 if !c.isHandshakeComplete.Load() {
255 return quicError(errors.New("tls: SendSessionTicket called before handshake completed"))
258 return quicError(errors.New("tls: SendSessionTicket called on the client"))
260 if q.sessionTicketSent {
261 return quicError(errors.New("tls: SendSessionTicket called multiple times"))
263 q.sessionTicketSent = true
264 return quicError(c.sendSessionTicket(earlyData))
267 // ConnectionState returns basic TLS details about the connection.
268 func (q *QUICConn) ConnectionState() ConnectionState {
269 return q.conn.ConnectionState()
272 // SetTransportParameters sets the transport parameters to send to the peer.
274 // Server connections may delay setting the transport parameters until after
275 // receiving the client's transport parameters. See QUICTransportParametersRequired.
276 func (q *QUICConn) SetTransportParameters(params []byte) {
280 q.conn.quic.transportParams = params
281 if q.conn.quic.started {
282 <-q.conn.quic.signalc
283 <-q.conn.quic.blockedc
287 // quicError ensures err is an AlertError.
288 // If err is not already, quicError wraps it with alertInternalError.
289 func quicError(err error) error {
294 if errors.As(err, &ae) {
298 if !errors.As(err, &a) {
299 a = alertInternalError
301 // Return an error wrapping the original error and an AlertError.
302 // Truncate the text of the alert to 0 characters.
303 return fmt.Errorf("%w%.0w", err, AlertError(a))
306 func (c *Conn) quicReadHandshakeBytes(n int) error {
307 for c.hand.Len() < n {
308 if err := c.quicWaitForSignal(); err != nil {
315 func (c *Conn) quicSetReadSecret(level QUICEncryptionLevel, suite uint16, secret []byte) {
316 c.quic.events = append(c.quic.events, QUICEvent{
317 Kind: QUICSetReadSecret,
324 func (c *Conn) quicSetWriteSecret(level QUICEncryptionLevel, suite uint16, secret []byte) {
325 c.quic.events = append(c.quic.events, QUICEvent{
326 Kind: QUICSetWriteSecret,
333 func (c *Conn) quicWriteCryptoData(level QUICEncryptionLevel, data []byte) {
335 if len(c.quic.events) > 0 {
336 last = &c.quic.events[len(c.quic.events)-1]
338 if last == nil || last.Kind != QUICWriteData || last.Level != level {
339 c.quic.events = append(c.quic.events, QUICEvent{
343 last = &c.quic.events[len(c.quic.events)-1]
345 last.Data = append(last.Data, data...)
348 func (c *Conn) quicSetTransportParameters(params []byte) {
349 c.quic.events = append(c.quic.events, QUICEvent{
350 Kind: QUICTransportParameters,
355 func (c *Conn) quicGetTransportParameters() ([]byte, error) {
356 if c.quic.transportParams == nil {
357 c.quic.events = append(c.quic.events, QUICEvent{
358 Kind: QUICTransportParametersRequired,
361 for c.quic.transportParams == nil {
362 if err := c.quicWaitForSignal(); err != nil {
366 return c.quic.transportParams, nil
369 func (c *Conn) quicHandshakeComplete() {
370 c.quic.events = append(c.quic.events, QUICEvent{
371 Kind: QUICHandshakeDone,
375 func (c *Conn) quicRejectedEarlyData() {
376 c.quic.events = append(c.quic.events, QUICEvent{
377 Kind: QUICRejectedEarlyData,
381 // quicWaitForSignal notifies the QUICConn that handshake progress is blocked,
382 // and waits for a signal that the handshake should proceed.
384 // The handshake may become blocked waiting for handshake bytes
385 // or for the user to provide transport parameters.
386 func (c *Conn) quicWaitForSignal() error {
387 // Drop the handshake mutex while blocked to allow the user
388 // to call ConnectionState before the handshake completes.
389 c.handshakeMutex.Unlock()
390 defer c.handshakeMutex.Lock()
391 // Send on blockedc to notify the QUICConn that the handshake is blocked.
392 // Exported methods of QUICConn wait for the handshake to become blocked
393 // before returning to the user.
395 case c.quic.blockedc <- struct{}{}:
396 case <-c.quic.cancelc:
397 return c.sendAlertLocked(alertCloseNotify)
399 // The QUICConn reads from signalc to notify us that the handshake may
400 // be able to proceed. (The QUICConn reads, because we close signalc to
401 // indicate that the handshake has completed.)
403 case c.quic.signalc <- struct{}{}:
404 c.hand.Write(c.quic.readbuf)
406 case <-c.quic.cancelc:
407 return c.sendAlertLocked(alertCloseNotify)