// Copyright 2023 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. //go:build go1.21 package quic import ( "context" "crypto/tls" "errors" "fmt" "time" ) // startTLS starts the TLS handshake. func (c *Conn) startTLS(now time.Time, initialConnID []byte, params transportParameters) error { c.keysInitial = initialKeys(initialConnID, c.side) qconfig := &tls.QUICConfig{TLSConfig: c.config.TLSConfig} if c.side == clientSide { c.tls = tls.QUICClient(qconfig) } else { c.tls = tls.QUICServer(qconfig) } c.tls.SetTransportParameters(marshalTransportParameters(params)) // TODO: We don't need or want a context for cancelation here, // but users can use a context to plumb values through to hooks defined // in the tls.Config. Pass through a context. if err := c.tls.Start(context.TODO()); err != nil { return err } return c.handleTLSEvents(now) } func (c *Conn) handleTLSEvents(now time.Time) error { for { e := c.tls.NextEvent() if c.testHooks != nil { c.testHooks.handleTLSEvent(e) } switch e.Kind { case tls.QUICNoEvent: return nil case tls.QUICSetReadSecret: if err := checkCipherSuite(e.Suite); err != nil { return err } switch e.Level { case tls.QUICEncryptionLevelHandshake: c.keysHandshake.r.init(e.Suite, e.Data) case tls.QUICEncryptionLevelApplication: c.keysAppData.r.init(e.Suite, e.Data) } case tls.QUICSetWriteSecret: if err := checkCipherSuite(e.Suite); err != nil { return err } switch e.Level { case tls.QUICEncryptionLevelHandshake: c.keysHandshake.w.init(e.Suite, e.Data) case tls.QUICEncryptionLevelApplication: c.keysAppData.w.init(e.Suite, e.Data) } case tls.QUICWriteData: var space numberSpace switch e.Level { case tls.QUICEncryptionLevelInitial: space = initialSpace case tls.QUICEncryptionLevelHandshake: space = handshakeSpace case tls.QUICEncryptionLevelApplication: space = appDataSpace default: return fmt.Errorf("quic: internal error: write handshake data at level %v", e.Level) } c.crypto[space].write(e.Data) case tls.QUICHandshakeDone: if c.side == serverSide { // "[...] the TLS handshake is considered confirmed // at the server when the handshake completes." // https://www.rfc-editor.org/rfc/rfc9001#section-4.1.2-1 c.confirmHandshake(now) } c.handshakeDone() case tls.QUICTransportParameters: params, err := unmarshalTransportParams(e.Data) if err != nil { return err } if err := c.receiveTransportParameters(params); err != nil { return err } } } } // handleCrypto processes data received in a CRYPTO frame. func (c *Conn) handleCrypto(now time.Time, space numberSpace, off int64, data []byte) error { var level tls.QUICEncryptionLevel switch space { case initialSpace: level = tls.QUICEncryptionLevelInitial case handshakeSpace: level = tls.QUICEncryptionLevelHandshake case appDataSpace: level = tls.QUICEncryptionLevelApplication default: return errors.New("quic: internal error: received CRYPTO frame in unexpected number space") } err := c.crypto[space].handleCrypto(off, data, func(b []byte) error { return c.tls.HandleData(level, b) }) if err != nil { return err } return c.handleTLSEvents(now) }