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