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