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  )
    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  
   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.
   126  type 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  
   143  type 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.
   175  func 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.
   183  func QUICServer(config *QUICConfig) *QUICConn {
   184  	return newQUICConn(Server(nil, config.TLSConfig), config)
   185  }
   186  
   187  func 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.
   203  func (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.
   220  func (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.
   244  func (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].
   257  func (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  
   294  type 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.
   303  func (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.
   322  func (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.
   337  func (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].
   345  func (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.
   358  func 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  
   375  func (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  
   384  func (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  
   393  func (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  
   402  func (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  
   417  func (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  
   431  func (c *Conn) quicStoreSession(session *SessionState) {
   432  	c.quic.events = append(c.quic.events, QUICEvent{
   433  		Kind:         QUICStoreSession,
   434  		SessionState: session,
   435  	})
   436  }
   437  
   438  func (c *Conn) quicSetTransportParameters(params []byte) {
   439  	c.quic.events = append(c.quic.events, QUICEvent{
   440  		Kind: QUICTransportParameters,
   441  		Data: params,
   442  	})
   443  }
   444  
   445  func (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  
   459  func (c *Conn) quicHandshakeComplete() {
   460  	c.quic.events = append(c.quic.events, QUICEvent{
   461  		Kind: QUICHandshakeDone,
   462  	})
   463  }
   464  
   465  func (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.
   476  func (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  

View as plain text