github.com/mikelsr/quic-go@v0.36.1-0.20230701132136-1d9415b66898/internal/qtls/go121.go (about)

     1  //go:build go1.21
     2  
     3  package qtls
     4  
     5  import (
     6  	"bytes"
     7  	"crypto/tls"
     8  	"fmt"
     9  
    10  	"github.com/mikelsr/quic-go/internal/protocol"
    11  )
    12  
    13  type (
    14  	QUICConn            = tls.QUICConn
    15  	QUICConfig          = tls.QUICConfig
    16  	QUICEvent           = tls.QUICEvent
    17  	QUICEventKind       = tls.QUICEventKind
    18  	QUICEncryptionLevel = tls.QUICEncryptionLevel
    19  	AlertError          = tls.AlertError
    20  )
    21  
    22  const (
    23  	QUICEncryptionLevelInitial     = tls.QUICEncryptionLevelInitial
    24  	QUICEncryptionLevelEarly       = tls.QUICEncryptionLevelEarly
    25  	QUICEncryptionLevelHandshake   = tls.QUICEncryptionLevelHandshake
    26  	QUICEncryptionLevelApplication = tls.QUICEncryptionLevelApplication
    27  )
    28  
    29  const (
    30  	QUICNoEvent                     = tls.QUICNoEvent
    31  	QUICSetReadSecret               = tls.QUICSetReadSecret
    32  	QUICSetWriteSecret              = tls.QUICSetWriteSecret
    33  	QUICWriteData                   = tls.QUICWriteData
    34  	QUICTransportParameters         = tls.QUICTransportParameters
    35  	QUICTransportParametersRequired = tls.QUICTransportParametersRequired
    36  	QUICRejectedEarlyData           = tls.QUICRejectedEarlyData
    37  	QUICHandshakeDone               = tls.QUICHandshakeDone
    38  )
    39  
    40  func QUICServer(config *QUICConfig) *QUICConn { return tls.QUICServer(config) }
    41  func QUICClient(config *QUICConfig) *QUICConn { return tls.QUICClient(config) }
    42  
    43  func SetupConfigForServer(qconf *QUICConfig, _ bool, getData func() []byte, accept0RTT func([]byte) bool) {
    44  	conf := qconf.TLSConfig
    45  
    46  	// Workaround for https://github.com/golang/go/issues/60506.
    47  	// This initializes the session tickets _before_ cloning the config.
    48  	_, _ = conf.DecryptTicket(nil, tls.ConnectionState{})
    49  
    50  	conf = conf.Clone()
    51  	conf.MinVersion = tls.VersionTLS13
    52  	qconf.TLSConfig = conf
    53  
    54  	// add callbacks to save transport parameters into the session ticket
    55  	origWrapSession := conf.WrapSession
    56  	conf.WrapSession = func(cs tls.ConnectionState, state *tls.SessionState) ([]byte, error) {
    57  		// Add QUIC transport parameters if this is a 0-RTT packet.
    58  		// TODO(#3853): also save the RTT for non-0-RTT tickets
    59  		if state.EarlyData {
    60  			state.Extra = append(state.Extra, addExtraPrefix(getData()))
    61  		}
    62  		if origWrapSession != nil {
    63  			return origWrapSession(cs, state)
    64  		}
    65  		b, err := conf.EncryptTicket(cs, state)
    66  		return b, err
    67  	}
    68  	origUnwrapSession := conf.UnwrapSession
    69  	// UnwrapSession might be called multiple times, as the client can use multiple session tickets.
    70  	// However, using 0-RTT is only possible with the first session ticket.
    71  	// crypto/tls guarantees that this callback is called in the same order as the session ticket in the ClientHello.
    72  	var unwrapCount int
    73  	conf.UnwrapSession = func(identity []byte, connState tls.ConnectionState) (*tls.SessionState, error) {
    74  		unwrapCount++
    75  		var state *tls.SessionState
    76  		var err error
    77  		if origUnwrapSession != nil {
    78  			state, err = origUnwrapSession(identity, connState)
    79  		} else {
    80  			state, err = conf.DecryptTicket(identity, connState)
    81  		}
    82  		if err != nil || state == nil {
    83  			return nil, err
    84  		}
    85  		if state.EarlyData {
    86  			extra := findExtraData(state.Extra)
    87  			if unwrapCount == 1 && extra != nil { // first session ticket
    88  				state.EarlyData = accept0RTT(extra)
    89  			} else { // subsequent session ticket, can't be used for 0-RTT
    90  				state.EarlyData = false
    91  			}
    92  		}
    93  		return state, nil
    94  	}
    95  }
    96  
    97  func SetupConfigForClient(qconf *QUICConfig, getData func() []byte, setData func([]byte)) {
    98  	conf := qconf.TLSConfig
    99  	if conf.ClientSessionCache != nil {
   100  		origCache := conf.ClientSessionCache
   101  		conf.ClientSessionCache = &clientSessionCache{
   102  			wrapped: origCache,
   103  			getData: getData,
   104  			setData: setData,
   105  		}
   106  	}
   107  }
   108  
   109  func ToTLSEncryptionLevel(e protocol.EncryptionLevel) tls.QUICEncryptionLevel {
   110  	switch e {
   111  	case protocol.EncryptionInitial:
   112  		return tls.QUICEncryptionLevelInitial
   113  	case protocol.EncryptionHandshake:
   114  		return tls.QUICEncryptionLevelHandshake
   115  	case protocol.Encryption1RTT:
   116  		return tls.QUICEncryptionLevelApplication
   117  	case protocol.Encryption0RTT:
   118  		return tls.QUICEncryptionLevelEarly
   119  	default:
   120  		panic(fmt.Sprintf("unexpected encryption level: %s", e))
   121  	}
   122  }
   123  
   124  func FromTLSEncryptionLevel(e tls.QUICEncryptionLevel) protocol.EncryptionLevel {
   125  	switch e {
   126  	case tls.QUICEncryptionLevelInitial:
   127  		return protocol.EncryptionInitial
   128  	case tls.QUICEncryptionLevelHandshake:
   129  		return protocol.EncryptionHandshake
   130  	case tls.QUICEncryptionLevelApplication:
   131  		return protocol.Encryption1RTT
   132  	case tls.QUICEncryptionLevelEarly:
   133  		return protocol.Encryption0RTT
   134  	default:
   135  		panic(fmt.Sprintf("unexpect encryption level: %s", e))
   136  	}
   137  }
   138  
   139  const extraPrefix = "quic-go1"
   140  
   141  func addExtraPrefix(b []byte) []byte {
   142  	return append([]byte(extraPrefix), b...)
   143  }
   144  
   145  func findExtraData(extras [][]byte) []byte {
   146  	prefix := []byte(extraPrefix)
   147  	for _, extra := range extras {
   148  		if len(extra) < len(prefix) || !bytes.Equal(prefix, extra[:len(prefix)]) {
   149  			continue
   150  		}
   151  		return extra[len(prefix):]
   152  	}
   153  	return nil
   154  }