github.com/ice-blockchain/go/src@v0.0.0-20240403114104-1564d284e521/crypto/tls/quic.go (about) 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 54 // A QUICEventKind is a type of operation on a QUIC connection. 55 type QUICEventKind int 56 57 const ( 58 // QUICNoEvent indicates that there are no events available. 59 QUICNoEvent QUICEventKind = iota 60 61 // QUICSetReadSecret and QUICSetWriteSecret provide the read and write 62 // secrets for a given encryption level. 63 // QUICEvent.Level, QUICEvent.Data, and QUICEvent.Suite are set. 64 // 65 // Secrets for the Initial encryption level are derived from the initial 66 // destination connection ID, and are not provided by the QUICConn. 67 QUICSetReadSecret 68 QUICSetWriteSecret 69 70 // QUICWriteData provides data to send to the peer in CRYPTO frames. 71 // QUICEvent.Data is set. 72 QUICWriteData 73 74 // QUICTransportParameters provides the peer's QUIC transport parameters. 75 // QUICEvent.Data is set. 76 QUICTransportParameters 77 78 // QUICTransportParametersRequired indicates that the caller must provide 79 // QUIC transport parameters to send to the peer. The caller should set 80 // the transport parameters with QUICConn.SetTransportParameters and call 81 // QUICConn.NextEvent again. 82 // 83 // If transport parameters are set before calling QUICConn.Start, the 84 // connection will never generate a QUICTransportParametersRequired event. 85 QUICTransportParametersRequired 86 87 // QUICRejectedEarlyData indicates that the server rejected 0-RTT data even 88 // if we offered it. It's returned before QUICEncryptionLevelApplication 89 // keys are returned. 90 QUICRejectedEarlyData 91 92 // QUICHandshakeDone indicates that the TLS handshake has completed. 93 QUICHandshakeDone 94 ) 95 96 // A QUICEvent is an event occurring on a QUIC connection. 97 // 98 // The type of event is specified by the Kind field. 99 // The contents of the other fields are kind-specific. 100 type QUICEvent struct { 101 Kind QUICEventKind 102 103 // Set for QUICSetReadSecret, QUICSetWriteSecret, and QUICWriteData. 104 Level QUICEncryptionLevel 105 106 // Set for QUICTransportParameters, QUICSetReadSecret, QUICSetWriteSecret, and QUICWriteData. 107 // The contents are owned by crypto/tls, and are valid until the next NextEvent call. 108 Data []byte 109 110 // Set for QUICSetReadSecret and QUICSetWriteSecret. 111 Suite uint16 112 } 113 114 type quicState struct { 115 events []QUICEvent 116 nextEvent int 117 118 // eventArr is a statically allocated event array, large enough to handle 119 // the usual maximum number of events resulting from a single call: transport 120 // parameters, Initial data, Early read secret, Handshake write and read 121 // secrets, Handshake data, Application write secret, Application data. 122 eventArr [8]QUICEvent 123 124 started bool 125 signalc chan struct{} // handshake data is available to be read 126 blockedc chan struct{} // handshake is waiting for data, closed when done 127 cancelc <-chan struct{} // handshake has been canceled 128 cancel context.CancelFunc 129 130 // readbuf is shared between HandleData and the handshake goroutine. 131 // HandshakeCryptoData passes ownership to the handshake goroutine by 132 // reading from signalc, and reclaims ownership by reading from blockedc. 133 readbuf []byte 134 135 transportParams []byte // to send to the peer 136 } 137 138 // QUICClient returns a new TLS client side connection using QUICTransport as the 139 // underlying transport. The config cannot be nil. 140 // 141 // The config's MinVersion must be at least TLS 1.3. 142 func QUICClient(config *QUICConfig) *QUICConn { 143 return newQUICConn(Client(nil, config.TLSConfig)) 144 } 145 146 // QUICServer returns a new TLS server side connection using QUICTransport as the 147 // underlying transport. The config cannot be nil. 148 // 149 // The config's MinVersion must be at least TLS 1.3. 150 func QUICServer(config *QUICConfig) *QUICConn { 151 return newQUICConn(Server(nil, config.TLSConfig)) 152 } 153 154 func newQUICConn(conn *Conn) *QUICConn { 155 conn.quic = &quicState{ 156 signalc: make(chan struct{}), 157 blockedc: make(chan struct{}), 158 } 159 conn.quic.events = conn.quic.eventArr[:0] 160 return &QUICConn{ 161 conn: conn, 162 } 163 } 164 165 // Start starts the client or server handshake protocol. 166 // It may produce connection events, which may be read with [QUICConn.NextEvent]. 167 // 168 // Start must be called at most once. 169 func (q *QUICConn) Start(ctx context.Context) error { 170 if q.conn.quic.started { 171 return quicError(errors.New("tls: Start called more than once")) 172 } 173 q.conn.quic.started = true 174 if q.conn.config.MinVersion < VersionTLS13 { 175 return quicError(errors.New("tls: Config MinVersion must be at least TLS 1.13")) 176 } 177 go q.conn.HandshakeContext(ctx) 178 if _, ok := <-q.conn.quic.blockedc; !ok { 179 return q.conn.handshakeErr 180 } 181 return nil 182 } 183 184 // NextEvent returns the next event occurring on the connection. 185 // It returns an event with a Kind of [QUICNoEvent] when no events are available. 186 func (q *QUICConn) NextEvent() QUICEvent { 187 qs := q.conn.quic 188 if last := qs.nextEvent - 1; last >= 0 && len(qs.events[last].Data) > 0 { 189 // Write over some of the previous event's data, 190 // to catch callers erroniously retaining it. 191 qs.events[last].Data[0] = 0 192 } 193 if qs.nextEvent >= len(qs.events) { 194 qs.events = qs.events[:0] 195 qs.nextEvent = 0 196 return QUICEvent{Kind: QUICNoEvent} 197 } 198 e := qs.events[qs.nextEvent] 199 qs.events[qs.nextEvent] = QUICEvent{} // zero out references to data 200 qs.nextEvent++ 201 return e 202 } 203 204 // Close closes the connection and stops any in-progress handshake. 205 func (q *QUICConn) Close() error { 206 if q.conn.quic.cancel == nil { 207 return nil // never started 208 } 209 q.conn.quic.cancel() 210 for range q.conn.quic.blockedc { 211 // Wait for the handshake goroutine to return. 212 } 213 return q.conn.handshakeErr 214 } 215 216 // HandleData handles handshake bytes received from the peer. 217 // It may produce connection events, which may be read with [QUICConn.NextEvent]. 218 func (q *QUICConn) HandleData(level QUICEncryptionLevel, data []byte) error { 219 c := q.conn 220 if c.in.level != level { 221 return quicError(c.in.setErrorLocked(errors.New("tls: handshake data received at wrong level"))) 222 } 223 c.quic.readbuf = data 224 <-c.quic.signalc 225 _, ok := <-c.quic.blockedc 226 if ok { 227 // The handshake goroutine is waiting for more data. 228 return nil 229 } 230 // The handshake goroutine has exited. 231 c.handshakeMutex.Lock() 232 defer c.handshakeMutex.Unlock() 233 c.hand.Write(c.quic.readbuf) 234 c.quic.readbuf = nil 235 for q.conn.hand.Len() >= 4 && q.conn.handshakeErr == nil { 236 b := q.conn.hand.Bytes() 237 n := int(b[1])<<16 | int(b[2])<<8 | int(b[3]) 238 if n > maxHandshake { 239 q.conn.handshakeErr = fmt.Errorf("tls: handshake message of length %d bytes exceeds maximum of %d bytes", n, maxHandshake) 240 break 241 } 242 if len(b) < 4+n { 243 return nil 244 } 245 if err := q.conn.handlePostHandshakeMessage(); err != nil { 246 q.conn.handshakeErr = err 247 } 248 } 249 if q.conn.handshakeErr != nil { 250 return quicError(q.conn.handshakeErr) 251 } 252 return nil 253 } 254 255 type QUICSessionTicketOptions struct { 256 // EarlyData specifies whether the ticket may be used for 0-RTT. 257 EarlyData bool 258 } 259 260 // SendSessionTicket sends a session ticket to the client. 261 // It produces connection events, which may be read with [QUICConn.NextEvent]. 262 // Currently, it can only be called once. 263 func (q *QUICConn) SendSessionTicket(opts QUICSessionTicketOptions) error { 264 c := q.conn 265 if !c.isHandshakeComplete.Load() { 266 return quicError(errors.New("tls: SendSessionTicket called before handshake completed")) 267 } 268 if c.isClient { 269 return quicError(errors.New("tls: SendSessionTicket called on the client")) 270 } 271 if q.sessionTicketSent { 272 return quicError(errors.New("tls: SendSessionTicket called multiple times")) 273 } 274 q.sessionTicketSent = true 275 return quicError(c.sendSessionTicket(opts.EarlyData)) 276 } 277 278 // ConnectionState returns basic TLS details about the connection. 279 func (q *QUICConn) ConnectionState() ConnectionState { 280 return q.conn.ConnectionState() 281 } 282 283 // SetTransportParameters sets the transport parameters to send to the peer. 284 // 285 // Server connections may delay setting the transport parameters until after 286 // receiving the client's transport parameters. See [QUICTransportParametersRequired]. 287 func (q *QUICConn) SetTransportParameters(params []byte) { 288 if params == nil { 289 params = []byte{} 290 } 291 q.conn.quic.transportParams = params 292 if q.conn.quic.started { 293 <-q.conn.quic.signalc 294 <-q.conn.quic.blockedc 295 } 296 } 297 298 // quicError ensures err is an AlertError. 299 // If err is not already, quicError wraps it with alertInternalError. 300 func quicError(err error) error { 301 if err == nil { 302 return nil 303 } 304 var ae AlertError 305 if errors.As(err, &ae) { 306 return err 307 } 308 var a alert 309 if !errors.As(err, &a) { 310 a = alertInternalError 311 } 312 // Return an error wrapping the original error and an AlertError. 313 // Truncate the text of the alert to 0 characters. 314 return fmt.Errorf("%w%.0w", err, AlertError(a)) 315 } 316 317 func (c *Conn) quicReadHandshakeBytes(n int) error { 318 for c.hand.Len() < n { 319 if err := c.quicWaitForSignal(); err != nil { 320 return err 321 } 322 } 323 return nil 324 } 325 326 func (c *Conn) quicSetReadSecret(level QUICEncryptionLevel, suite uint16, secret []byte) { 327 c.quic.events = append(c.quic.events, QUICEvent{ 328 Kind: QUICSetReadSecret, 329 Level: level, 330 Suite: suite, 331 Data: secret, 332 }) 333 } 334 335 func (c *Conn) quicSetWriteSecret(level QUICEncryptionLevel, suite uint16, secret []byte) { 336 c.quic.events = append(c.quic.events, QUICEvent{ 337 Kind: QUICSetWriteSecret, 338 Level: level, 339 Suite: suite, 340 Data: secret, 341 }) 342 } 343 344 func (c *Conn) quicWriteCryptoData(level QUICEncryptionLevel, data []byte) { 345 var last *QUICEvent 346 if len(c.quic.events) > 0 { 347 last = &c.quic.events[len(c.quic.events)-1] 348 } 349 if last == nil || last.Kind != QUICWriteData || last.Level != level { 350 c.quic.events = append(c.quic.events, QUICEvent{ 351 Kind: QUICWriteData, 352 Level: level, 353 }) 354 last = &c.quic.events[len(c.quic.events)-1] 355 } 356 last.Data = append(last.Data, data...) 357 } 358 359 func (c *Conn) quicSetTransportParameters(params []byte) { 360 c.quic.events = append(c.quic.events, QUICEvent{ 361 Kind: QUICTransportParameters, 362 Data: params, 363 }) 364 } 365 366 func (c *Conn) quicGetTransportParameters() ([]byte, error) { 367 if c.quic.transportParams == nil { 368 c.quic.events = append(c.quic.events, QUICEvent{ 369 Kind: QUICTransportParametersRequired, 370 }) 371 } 372 for c.quic.transportParams == nil { 373 if err := c.quicWaitForSignal(); err != nil { 374 return nil, err 375 } 376 } 377 return c.quic.transportParams, nil 378 } 379 380 func (c *Conn) quicHandshakeComplete() { 381 c.quic.events = append(c.quic.events, QUICEvent{ 382 Kind: QUICHandshakeDone, 383 }) 384 } 385 386 func (c *Conn) quicRejectedEarlyData() { 387 c.quic.events = append(c.quic.events, QUICEvent{ 388 Kind: QUICRejectedEarlyData, 389 }) 390 } 391 392 // quicWaitForSignal notifies the QUICConn that handshake progress is blocked, 393 // and waits for a signal that the handshake should proceed. 394 // 395 // The handshake may become blocked waiting for handshake bytes 396 // or for the user to provide transport parameters. 397 func (c *Conn) quicWaitForSignal() error { 398 // Drop the handshake mutex while blocked to allow the user 399 // to call ConnectionState before the handshake completes. 400 c.handshakeMutex.Unlock() 401 defer c.handshakeMutex.Lock() 402 // Send on blockedc to notify the QUICConn that the handshake is blocked. 403 // Exported methods of QUICConn wait for the handshake to become blocked 404 // before returning to the user. 405 select { 406 case c.quic.blockedc <- struct{}{}: 407 case <-c.quic.cancelc: 408 return c.sendAlertLocked(alertCloseNotify) 409 } 410 // The QUICConn reads from signalc to notify us that the handshake may 411 // be able to proceed. (The QUICConn reads, because we close signalc to 412 // indicate that the handshake has completed.) 413 select { 414 case c.quic.signalc <- struct{}{}: 415 c.hand.Write(c.quic.readbuf) 416 c.quic.readbuf = nil 417 case <-c.quic.cancelc: 418 return c.sendAlertLocked(alertCloseNotify) 419 } 420 return nil 421 }