Source file src/crypto/tls/quic.go

     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  	"net"
    12  )
    13  
    14  // QUICEncryptionLevel represents a QUIC encryption level used to transmit
    15  // handshake messages.
    16  type QUICEncryptionLevel int
    17  
    18  const (
    19  	QUICEncryptionLevelInitial = QUICEncryptionLevel(iota)
    20  	QUICEncryptionLevelEarly
    21  	QUICEncryptionLevelHandshake
    22  	QUICEncryptionLevelApplication
    23  )
    24  
    25  func (l QUICEncryptionLevel) String() string {
    26  	switch l {
    27  	case QUICEncryptionLevelInitial:
    28  		return "Initial"
    29  	case QUICEncryptionLevelEarly:
    30  		return "Early"
    31  	case QUICEncryptionLevelHandshake:
    32  		return "Handshake"
    33  	case QUICEncryptionLevelApplication:
    34  		return "Application"
    35  	default:
    36  		return fmt.Sprintf("QUICEncryptionLevel(%v)", int(l))
    37  	}
    38  }
    39  
    40  // A QUICConn represents a connection which uses a QUIC implementation as the underlying
    41  // transport as described in RFC 9001.
    42  //
    43  // Methods of QUICConn are not safe for concurrent use.
    44  type QUICConn struct {
    45  	conn *Conn
    46  
    47  	sessionTicketSent bool
    48  }
    49  
    50  // A QUICConfig configures a [QUICConn].
    51  type QUICConfig struct {
    52  	TLSConfig *Config
    53  
    54  	// EnableSessionEvents may be set to true to enable the
    55  	// [QUICStoreSession] and [QUICResumeSession] events for client connections.
    56  	// When this event is enabled, sessions are not automatically
    57  	// stored in the client session cache.
    58  	// The application should use [QUICConn.StoreSession] to store sessions.
    59  	EnableSessionEvents bool
    60  
    61  	// ClientHelloInfoConn is the net.Conn to use for the ClientHelloInfo.Conn field.
    62  	ClientHelloInfoConn net.Conn
    63  }
    64  
    65  // A QUICEventKind is a type of operation on a QUIC connection.
    66  type QUICEventKind int
    67  
    68  const (
    69  	// QUICNoEvent indicates that there are no events available.
    70  	QUICNoEvent QUICEventKind = iota
    71  
    72  	// QUICSetReadSecret and QUICSetWriteSecret provide the read and write
    73  	// secrets for a given encryption level.
    74  	// QUICEvent.Level, QUICEvent.Data, and QUICEvent.Suite are set.
    75  	//
    76  	// Secrets for the Initial encryption level are derived from the initial
    77  	// destination connection ID, and are not provided by the QUICConn.
    78  	QUICSetReadSecret
    79  	QUICSetWriteSecret
    80  
    81  	// QUICWriteData provides data to send to the peer in CRYPTO frames.
    82  	// QUICEvent.Data is set.
    83  	QUICWriteData
    84  
    85  	// QUICTransportParameters provides the peer's QUIC transport parameters.
    86  	// QUICEvent.Data is set.
    87  	QUICTransportParameters
    88  
    89  	// QUICTransportParametersRequired indicates that the caller must provide
    90  	// QUIC transport parameters to send to the peer. The caller should set
    91  	// the transport parameters with QUICConn.SetTransportParameters and call
    92  	// QUICConn.NextEvent again.
    93  	//
    94  	// If transport parameters are set before calling QUICConn.Start, the
    95  	// connection will never generate a QUICTransportParametersRequired event.
    96  	QUICTransportParametersRequired
    97  
    98  	// QUICRejectedEarlyData indicates that the server rejected 0-RTT data even
    99  	// if we offered it. It's returned before QUICEncryptionLevelApplication
   100  	// keys are returned.
   101  	// This event only occurs on client connections.
   102  	QUICRejectedEarlyData
   103  
   104  	// QUICHandshakeDone indicates that the TLS handshake has completed.
   105  	QUICHandshakeDone
   106  
   107  	// QUICResumeSession indicates that a client is attempting to resume a previous session.
   108  	// [QUICEvent.SessionState] is set.
   109  	//
   110  	// For client connections, this event occurs when the session ticket is selected.
   111  	// For server connections, this event occurs when receiving the client's session ticket.
   112  	//
   113  	// The application may set [QUICEvent.SessionState.EarlyData] to false before the
   114  	// next call to [QUICConn.NextEvent] to decline 0-RTT even if the session supports it.
   115  	QUICResumeSession
   116  
   117  	// QUICStoreSession indicates that the server has provided state permitting
   118  	// the client to resume the session.
   119  	// [QUICEvent.SessionState] is set.
   120  	// The application should use [QUICConn.StoreSession] session to store the [SessionState].
   121  	// The application may modify the [SessionState] before storing it.
   122  	// This event only occurs on client connections.
   123  	QUICStoreSession
   124  
   125  	// QUICErrorEvent indicates that a fatal error has occurred.
   126  	// The handshake cannot proceed and the connection must be closed.
   127  	// QUICEvent.Err is set.
   128  	QUICErrorEvent
   129  )
   130  
   131  // A QUICEvent is an event occurring on a QUIC connection.
   132  //
   133  // The type of event is specified by the Kind field.
   134  // The contents of the other fields are kind-specific.
   135  type QUICEvent struct {
   136  	Kind QUICEventKind
   137  
   138  	// Set for QUICSetReadSecret, QUICSetWriteSecret, and QUICWriteData.
   139  	Level QUICEncryptionLevel
   140  
   141  	// Set for QUICTransportParameters, QUICSetReadSecret, QUICSetWriteSecret, and QUICWriteData.
   142  	// The contents are owned by crypto/tls, and are valid until the next NextEvent call.
   143  	Data []byte
   144  
   145  	// Set for QUICSetReadSecret and QUICSetWriteSecret.
   146  	Suite uint16
   147  
   148  	// Set for QUICResumeSession and QUICStoreSession.
   149  	SessionState *SessionState
   150  
   151  	// Set for QUICErrorEvent.
   152  	// The error will wrap AlertError.
   153  	Err error
   154  }
   155  
   156  type quicState struct {
   157  	events    []QUICEvent
   158  	nextEvent int
   159  
   160  	// eventArr is a statically allocated event array, large enough to handle
   161  	// the usual maximum number of events resulting from a single call: transport
   162  	// parameters, Initial data, Early read secret, Handshake write and read
   163  	// secrets, Handshake data, Application write secret, Application data.
   164  	eventArr [8]QUICEvent
   165  
   166  	started  bool
   167  	signalc  chan struct{}   // handshake data is available to be read
   168  	blockedc chan struct{}   // handshake is waiting for data, closed when done
   169  	ctx      context.Context // handshake context
   170  	cancel   context.CancelFunc
   171  
   172  	waitingForDrain bool
   173  	errorReturned   bool
   174  
   175  	// readbuf is shared between HandleData and the handshake goroutine.
   176  	// HandshakeCryptoData passes ownership to the handshake goroutine by
   177  	// reading from signalc, and reclaims ownership by reading from blockedc.
   178  	readbuf []byte
   179  
   180  	transportParams []byte // to send to the peer
   181  
   182  	enableSessionEvents bool
   183  	clientHelloInfoConn net.Conn
   184  }
   185  
   186  // QUICClient returns a new TLS client side connection using QUICTransport as the
   187  // underlying transport. The config cannot be nil.
   188  func QUICClient(config *QUICConfig) *QUICConn {
   189  	return newQUICConn(Client(nil, config.TLSConfig), config)
   190  }
   191  
   192  // QUICServer returns a new TLS server side connection using QUICTransport as the
   193  // underlying transport. The config cannot be nil.
   194  func QUICServer(config *QUICConfig) *QUICConn {
   195  	return newQUICConn(Server(nil, config.TLSConfig), config)
   196  }
   197  
   198  func newQUICConn(conn *Conn, config *QUICConfig) *QUICConn {
   199  	conn.quic = &quicState{
   200  		signalc:             make(chan struct{}),
   201  		blockedc:            make(chan struct{}),
   202  		enableSessionEvents: config.EnableSessionEvents,
   203  		clientHelloInfoConn: config.ClientHelloInfoConn,
   204  	}
   205  	conn.quic.events = conn.quic.eventArr[:0]
   206  	return &QUICConn{
   207  		conn: conn,
   208  	}
   209  }
   210  
   211  // Start starts the client or server handshake protocol.
   212  // It may produce connection events, which may be read with [QUICConn.NextEvent].
   213  //
   214  // Start must be called at most once.
   215  func (q *QUICConn) Start(ctx context.Context) error {
   216  	if q.conn.quic.started {
   217  		return quicError(errors.New("tls: Start called more than once"))
   218  	}
   219  	q.conn.quic.started = true
   220  	go q.conn.HandshakeContext(ctx)
   221  	if _, ok := <-q.conn.quic.blockedc; !ok {
   222  		return q.conn.handshakeErr
   223  	}
   224  	return nil
   225  }
   226  
   227  // NextEvent returns the next event occurring on the connection.
   228  // It returns an event with a Kind of [QUICNoEvent] when no events are available.
   229  func (q *QUICConn) NextEvent() QUICEvent {
   230  	qs := q.conn.quic
   231  	if last := qs.nextEvent - 1; last >= 0 && len(qs.events[last].Data) > 0 {
   232  		// Write over some of the previous event's data,
   233  		// to catch callers erroneously retaining it.
   234  		qs.events[last].Data[0] = 0
   235  	}
   236  	if qs.nextEvent >= len(qs.events) && qs.waitingForDrain {
   237  		qs.waitingForDrain = false
   238  		<-qs.signalc
   239  		<-qs.blockedc
   240  	}
   241  	if err := q.conn.handshakeErr; err != nil {
   242  		if qs.errorReturned {
   243  			return QUICEvent{Kind: QUICNoEvent}
   244  		}
   245  		qs.errorReturned = true
   246  		qs.events = nil
   247  		qs.nextEvent = 0
   248  		return QUICEvent{Kind: QUICErrorEvent, Err: q.conn.handshakeErr}
   249  	}
   250  	if qs.nextEvent >= len(qs.events) {
   251  		qs.events = qs.events[:0]
   252  		qs.nextEvent = 0
   253  		return QUICEvent{Kind: QUICNoEvent}
   254  	}
   255  	e := qs.events[qs.nextEvent]
   256  	qs.events[qs.nextEvent] = QUICEvent{} // zero out references to data
   257  	qs.nextEvent++
   258  	return e
   259  }
   260  
   261  // Close closes the connection and stops any in-progress handshake.
   262  func (q *QUICConn) Close() error {
   263  	if q.conn.quic.ctx == nil {
   264  		return nil // never started
   265  	}
   266  	q.conn.quic.cancel()
   267  	<-q.conn.quic.signalc
   268  	for range q.conn.quic.blockedc {
   269  		// Wait for the handshake goroutine to return.
   270  	}
   271  	return q.conn.handshakeErr
   272  }
   273  
   274  // HandleData handles handshake bytes received from the peer.
   275  // It may produce connection events, which may be read with [QUICConn.NextEvent].
   276  func (q *QUICConn) HandleData(level QUICEncryptionLevel, data []byte) error {
   277  	c := q.conn
   278  	if c.in.level != level {
   279  		return quicError(c.in.setErrorLocked(errors.New("tls: handshake data received at wrong level")))
   280  	}
   281  	c.quic.readbuf = data
   282  	<-c.quic.signalc
   283  	_, ok := <-c.quic.blockedc
   284  	if ok {
   285  		// The handshake goroutine is waiting for more data.
   286  		return nil
   287  	}
   288  	// The handshake goroutine has exited.
   289  	c.handshakeMutex.Lock()
   290  	defer c.handshakeMutex.Unlock()
   291  	c.handBuf().Write(c.quic.readbuf)
   292  	c.quic.readbuf = nil
   293  	for q.conn.handLen() >= 4 && q.conn.handshakeErr == nil {
   294  		b := q.conn.hand.Bytes()
   295  		n := int(b[1])<<16 | int(b[2])<<8 | int(b[3])
   296  		if n > maxHandshake {
   297  			q.conn.handshakeErr = fmt.Errorf("tls: handshake message of length %d bytes exceeds maximum of %d bytes", n, maxHandshake)
   298  			break
   299  		}
   300  		if len(b) < 4+n {
   301  			return nil
   302  		}
   303  		if err := q.conn.handlePostHandshakeMessage(); err != nil {
   304  			q.conn.handshakeErr = err
   305  		}
   306  	}
   307  	q.conn.releaseHand()
   308  	if q.conn.handshakeErr != nil {
   309  		return quicError(q.conn.handshakeErr)
   310  	}
   311  	return nil
   312  }
   313  
   314  type QUICSessionTicketOptions struct {
   315  	// EarlyData specifies whether the ticket may be used for 0-RTT.
   316  	EarlyData bool
   317  	Extra     [][]byte
   318  }
   319  
   320  // SendSessionTicket sends a session ticket to the client.
   321  // It produces connection events, which may be read with [QUICConn.NextEvent].
   322  // Currently, it can only be called once.
   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  // StoreSession stores a session previously received in a QUICStoreSession event
   342  // in the ClientSessionCache.
   343  // The application may process additional events or modify the SessionState
   344  // before storing the session.
   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  // ConnectionState returns basic TLS details about the connection.
   360  func (q *QUICConn) ConnectionState() ConnectionState {
   361  	return q.conn.ConnectionState()
   362  }
   363  
   364  // SetTransportParameters sets the transport parameters to send to the peer.
   365  //
   366  // Server connections may delay setting the transport parameters until after
   367  // receiving the client's transport parameters. See [QUICTransportParametersRequired].
   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  // quicError ensures err is an AlertError.
   380  // If err is not already, quicError wraps it with alertInternalError.
   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  	// Return an error wrapping the original error and an AlertError.
   393  	// Truncate the text of the alert to 0 characters.
   394  	return fmt.Errorf("%w%.0w", err, AlertError(a))
   395  }
   396  
   397  func (c *Conn) quicReadHandshakeBytes(n int) error {
   398  	for c.handLen() < 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  	// Ensure that there are no buffered handshake messages before changing the
   408  	// read keys, since that can cause messages to be parsed that were encrypted
   409  	// using old keys which are no longer appropriate.
   410  	// TODO(roland): we should merge this check with the similar one in setReadTrafficSecret.
   411  	if c.handLen() != 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  // quicWaitForSignal notifies the QUICConn that handshake progress is blocked,
   503  // and waits for a signal that the handshake should proceed.
   504  //
   505  // The handshake may become blocked waiting for handshake bytes
   506  // or for the user to provide transport parameters.
   507  func (c *Conn) quicWaitForSignal() error {
   508  	// Drop the handshake mutex while blocked to allow the user
   509  	// to call ConnectionState before the handshake completes.
   510  	c.handshakeMutex.Unlock()
   511  	defer c.handshakeMutex.Lock()
   512  	// Send on blockedc to notify the QUICConn that the handshake is blocked.
   513  	// Exported methods of QUICConn wait for the handshake to become blocked
   514  	// before returning to the user.
   515  	c.quic.blockedc <- struct{}{}
   516  	// The QUICConn reads from signalc to notify us that the handshake may
   517  	// be able to proceed. (The QUICConn reads, because we close signalc to
   518  	// indicate that the handshake has completed.)
   519  	c.quic.signalc <- struct{}{}
   520  	if c.quic.ctx.Err() != nil {
   521  		// The connection has been canceled.
   522  		return c.sendAlertLocked(alertCloseNotify)
   523  	}
   524  	c.handBuf().Write(c.quic.readbuf)
   525  	c.quic.readbuf = nil
   526  	return nil
   527  }
   528  

View as plain text