dnscrypt-proxy/vendor/github.com/quic-go/quic-go/internal/handshake/crypto_setup.go

664 lines
20 KiB
Go
Raw Normal View History

2022-07-21 18:50:10 +02:00
package handshake
import (
"bytes"
2023-05-01 16:05:02 +02:00
"context"
2022-07-21 18:50:10 +02:00
"crypto/tls"
"errors"
"fmt"
2023-08-01 00:06:22 +02:00
"net"
2023-08-25 16:15:45 +02:00
"strings"
2023-07-22 00:41:27 +02:00
"sync/atomic"
2022-07-21 18:50:10 +02:00
"time"
"github.com/quic-go/quic-go/internal/protocol"
"github.com/quic-go/quic-go/internal/qerr"
"github.com/quic-go/quic-go/internal/qtls"
"github.com/quic-go/quic-go/internal/utils"
"github.com/quic-go/quic-go/internal/wire"
"github.com/quic-go/quic-go/logging"
"github.com/quic-go/quic-go/quicvarint"
2022-07-21 18:50:10 +02:00
)
2023-05-01 16:05:02 +02:00
type quicVersionContextKey struct{}
var QUICVersionContextKey = &quicVersionContextKey{}
2024-01-18 23:47:00 +01:00
const clientSessionStateRevision = 4
2022-07-21 18:50:10 +02:00
type cryptoSetup struct {
2023-07-22 00:41:27 +02:00
tlsConf *tls.Config
2024-01-18 23:47:00 +01:00
conn *tls.QUICConn
2022-07-21 18:50:10 +02:00
2023-07-22 00:41:27 +02:00
events []Event
2022-07-21 18:50:10 +02:00
2024-03-26 19:56:06 +01:00
version protocol.Version
2022-07-21 18:50:10 +02:00
ourParams *wire.TransportParameters
peerParams *wire.TransportParameters
2023-07-22 00:41:27 +02:00
zeroRTTParameters *wire.TransportParameters
allow0RTT bool
2022-07-21 18:50:10 +02:00
rttStats *utils.RTTStats
2023-10-12 15:53:53 +02:00
tracer *logging.ConnectionTracer
2022-07-21 18:50:10 +02:00
logger utils.Logger
perspective protocol.Perspective
handshakeCompleteTime time.Time
zeroRTTOpener LongHeaderOpener // only set for the server
zeroRTTSealer LongHeaderSealer // only set for the client
initialOpener LongHeaderOpener
initialSealer LongHeaderSealer
handshakeOpener LongHeaderOpener
handshakeSealer LongHeaderSealer
2023-07-22 00:41:27 +02:00
used0RTT atomic.Bool
2022-07-21 18:50:10 +02:00
aead *updatableAEAD
has1RTTSealer bool
has1RTTOpener bool
}
2023-07-22 00:41:27 +02:00
var _ CryptoSetup = &cryptoSetup{}
2022-07-21 18:50:10 +02:00
// NewCryptoSetupClient creates a new crypto setup for the client
func NewCryptoSetupClient(
connID protocol.ConnectionID,
tp *wire.TransportParameters,
tlsConf *tls.Config,
enable0RTT bool,
rttStats *utils.RTTStats,
2023-10-12 15:53:53 +02:00
tracer *logging.ConnectionTracer,
2022-07-21 18:50:10 +02:00
logger utils.Logger,
2024-03-26 19:56:06 +01:00
version protocol.Version,
2023-07-22 00:41:27 +02:00
) CryptoSetup {
cs := newCryptoSetup(
2022-07-21 18:50:10 +02:00
connID,
tp,
rttStats,
tracer,
logger,
protocol.PerspectiveClient,
version,
)
2023-07-22 00:41:27 +02:00
tlsConf = tlsConf.Clone()
tlsConf.MinVersion = tls.VersionTLS13
2024-01-18 23:47:00 +01:00
quicConf := &tls.QUICConfig{TLSConfig: tlsConf}
2023-07-22 00:41:27 +02:00
qtls.SetupConfigForClient(quicConf, cs.marshalDataForSessionState, cs.handleDataFromSessionState)
cs.tlsConf = tlsConf
2023-11-16 00:51:48 +01:00
cs.allow0RTT = enable0RTT
2023-07-22 00:41:27 +02:00
2024-01-18 23:47:00 +01:00
cs.conn = tls.QUICClient(quicConf)
2023-07-22 00:41:27 +02:00
cs.conn.SetTransportParameters(cs.ourParams.Marshal(protocol.PerspectiveClient))
return cs
2022-07-21 18:50:10 +02:00
}
// NewCryptoSetupServer creates a new crypto setup for the server
func NewCryptoSetupServer(
connID protocol.ConnectionID,
2023-08-01 00:06:22 +02:00
localAddr, remoteAddr net.Addr,
2022-07-21 18:50:10 +02:00
tp *wire.TransportParameters,
tlsConf *tls.Config,
allow0RTT bool,
2022-07-21 18:50:10 +02:00
rttStats *utils.RTTStats,
2023-10-12 15:53:53 +02:00
tracer *logging.ConnectionTracer,
2022-07-21 18:50:10 +02:00
logger utils.Logger,
2024-03-26 19:56:06 +01:00
version protocol.Version,
2022-07-21 18:50:10 +02:00
) CryptoSetup {
2023-07-22 00:41:27 +02:00
cs := newCryptoSetup(
2022-07-21 18:50:10 +02:00
connID,
tp,
rttStats,
tracer,
logger,
protocol.PerspectiveServer,
version,
)
2023-07-22 00:41:27 +02:00
cs.allow0RTT = allow0RTT
2024-01-18 23:47:00 +01:00
quicConf := &tls.QUICConfig{TLSConfig: tlsConf}
2023-10-12 15:53:53 +02:00
qtls.SetupConfigForServer(quicConf, cs.allow0RTT, cs.getDataForSessionTicket, cs.handleSessionTicket)
2023-08-07 17:32:25 +02:00
addConnToClientHelloInfo(quicConf.TLSConfig, localAddr, remoteAddr)
2023-07-22 00:41:27 +02:00
cs.tlsConf = quicConf.TLSConfig
2024-01-18 23:47:00 +01:00
cs.conn = tls.QUICServer(quicConf)
2023-07-22 00:41:27 +02:00
2022-07-21 18:50:10 +02:00
return cs
}
2023-08-07 17:32:25 +02:00
// The tls.Config contains two callbacks that pass in a tls.ClientHelloInfo.
// Since crypto/tls doesn't do it, we need to make sure to set the Conn field with a fake net.Conn
// that allows the caller to get the local and the remote address.
func addConnToClientHelloInfo(conf *tls.Config, localAddr, remoteAddr net.Addr) {
if conf.GetConfigForClient != nil {
gcfc := conf.GetConfigForClient
conf.GetConfigForClient = func(info *tls.ClientHelloInfo) (*tls.Config, error) {
info.Conn = &conn{localAddr: localAddr, remoteAddr: remoteAddr}
c, err := gcfc(info)
if c != nil {
2023-11-16 00:51:48 +01:00
c = c.Clone()
// This won't be necessary anymore once https://github.com/golang/go/issues/63722 is accepted.
c.MinVersion = tls.VersionTLS13
2023-08-07 17:32:25 +02:00
// We're returning a tls.Config here, so we need to apply this recursively.
addConnToClientHelloInfo(c, localAddr, remoteAddr)
}
return c, err
}
}
if conf.GetCertificate != nil {
gc := conf.GetCertificate
conf.GetCertificate = func(info *tls.ClientHelloInfo) (*tls.Certificate, error) {
info.Conn = &conn{localAddr: localAddr, remoteAddr: remoteAddr}
return gc(info)
}
}
}
2022-07-21 18:50:10 +02:00
func newCryptoSetup(
connID protocol.ConnectionID,
tp *wire.TransportParameters,
rttStats *utils.RTTStats,
2023-10-12 15:53:53 +02:00
tracer *logging.ConnectionTracer,
2022-07-21 18:50:10 +02:00
logger utils.Logger,
perspective protocol.Perspective,
2024-03-26 19:56:06 +01:00
version protocol.Version,
2023-07-22 00:41:27 +02:00
) *cryptoSetup {
2022-07-21 18:50:10 +02:00
initialSealer, initialOpener := NewInitialAEAD(connID, perspective, version)
2023-10-12 15:53:53 +02:00
if tracer != nil && tracer.UpdatedKeyFromTLS != nil {
2022-07-21 18:50:10 +02:00
tracer.UpdatedKeyFromTLS(protocol.EncryptionInitial, protocol.PerspectiveClient)
tracer.UpdatedKeyFromTLS(protocol.EncryptionInitial, protocol.PerspectiveServer)
}
2023-07-22 00:41:27 +02:00
return &cryptoSetup{
initialSealer: initialSealer,
initialOpener: initialOpener,
aead: newUpdatableAEAD(rttStats, tracer, logger, version),
events: make([]Event, 0, 16),
ourParams: tp,
rttStats: rttStats,
tracer: tracer,
logger: logger,
perspective: perspective,
version: version,
}
2022-07-21 18:50:10 +02:00
}
func (h *cryptoSetup) ChangeConnectionID(id protocol.ConnectionID) {
initialSealer, initialOpener := NewInitialAEAD(id, h.perspective, h.version)
h.initialSealer = initialSealer
h.initialOpener = initialOpener
2023-10-12 15:53:53 +02:00
if h.tracer != nil && h.tracer.UpdatedKeyFromTLS != nil {
2022-07-21 18:50:10 +02:00
h.tracer.UpdatedKeyFromTLS(protocol.EncryptionInitial, protocol.PerspectiveClient)
h.tracer.UpdatedKeyFromTLS(protocol.EncryptionInitial, protocol.PerspectiveServer)
}
}
func (h *cryptoSetup) SetLargest1RTTAcked(pn protocol.PacketNumber) error {
return h.aead.SetLargestAcked(pn)
}
2023-07-22 00:41:27 +02:00
func (h *cryptoSetup) StartHandshake() error {
err := h.conn.Start(context.WithValue(context.Background(), QUICVersionContextKey, h.version))
if err != nil {
return wrapError(err)
}
for {
ev := h.conn.NextEvent()
done, err := h.handleEvent(ev)
if err != nil {
return wrapError(err)
2022-07-21 18:50:10 +02:00
}
2023-07-22 00:41:27 +02:00
if done {
break
2022-07-21 18:50:10 +02:00
}
}
2023-07-22 00:41:27 +02:00
if h.perspective == protocol.PerspectiveClient {
if h.zeroRTTSealer != nil && h.zeroRTTParameters != nil {
h.logger.Debugf("Doing 0-RTT.")
h.events = append(h.events, Event{Kind: EventRestoredTransportParameters, TransportParameters: h.zeroRTTParameters})
} else {
h.logger.Debugf("Not doing 0-RTT. Has sealer: %t, has params: %t", h.zeroRTTSealer != nil, h.zeroRTTParameters != nil)
}
2022-07-21 18:50:10 +02:00
}
2023-07-22 00:41:27 +02:00
return nil
2022-07-21 18:50:10 +02:00
}
// Close closes the crypto setup.
// It aborts the handshake, if it is still running.
func (h *cryptoSetup) Close() error {
2023-07-22 00:41:27 +02:00
return h.conn.Close()
2022-07-21 18:50:10 +02:00
}
2023-07-22 00:41:27 +02:00
// HandleMessage handles a TLS handshake message.
2022-07-21 18:50:10 +02:00
// It is called by the crypto streams when a new message is available.
2023-07-22 00:41:27 +02:00
func (h *cryptoSetup) HandleMessage(data []byte, encLevel protocol.EncryptionLevel) error {
if err := h.handleMessage(data, encLevel); err != nil {
return wrapError(err)
2023-02-25 23:45:38 +01:00
}
2023-07-22 00:41:27 +02:00
return nil
}
func (h *cryptoSetup) handleMessage(data []byte, encLevel protocol.EncryptionLevel) error {
if err := h.conn.HandleData(qtls.ToTLSEncryptionLevel(encLevel), data); err != nil {
return err
2022-07-21 18:50:10 +02:00
}
for {
2023-07-22 00:41:27 +02:00
ev := h.conn.NextEvent()
done, err := h.handleEvent(ev)
if err != nil {
return err
}
if done {
return nil
2022-07-21 18:50:10 +02:00
}
}
2023-07-22 00:41:27 +02:00
}
2024-01-18 23:47:00 +01:00
func (h *cryptoSetup) handleEvent(ev tls.QUICEvent) (done bool, err error) {
2023-07-22 00:41:27 +02:00
switch ev.Kind {
2024-01-18 23:47:00 +01:00
case tls.QUICNoEvent:
2023-07-22 00:41:27 +02:00
return true, nil
2024-01-18 23:47:00 +01:00
case tls.QUICSetReadSecret:
2024-03-26 19:56:06 +01:00
h.setReadKey(ev.Level, ev.Suite, ev.Data)
2023-07-22 00:41:27 +02:00
return false, nil
2024-01-18 23:47:00 +01:00
case tls.QUICSetWriteSecret:
2024-03-26 19:56:06 +01:00
h.setWriteKey(ev.Level, ev.Suite, ev.Data)
2023-07-22 00:41:27 +02:00
return false, nil
2024-01-18 23:47:00 +01:00
case tls.QUICTransportParameters:
2023-07-22 00:41:27 +02:00
return false, h.handleTransportParameters(ev.Data)
2024-01-18 23:47:00 +01:00
case tls.QUICTransportParametersRequired:
2023-07-22 00:41:27 +02:00
h.conn.SetTransportParameters(h.ourParams.Marshal(h.perspective))
return false, nil
2024-01-18 23:47:00 +01:00
case tls.QUICRejectedEarlyData:
2023-07-22 00:41:27 +02:00
h.rejected0RTT()
return false, nil
2024-01-18 23:47:00 +01:00
case tls.QUICWriteData:
h.writeRecord(ev.Level, ev.Data)
2023-07-22 00:41:27 +02:00
return false, nil
2024-01-18 23:47:00 +01:00
case tls.QUICHandshakeDone:
2023-07-22 00:41:27 +02:00
h.handshakeComplete()
return false, nil
2022-07-21 18:50:10 +02:00
default:
2023-07-22 00:41:27 +02:00
return false, fmt.Errorf("unexpected event: %d", ev.Kind)
2022-07-21 18:50:10 +02:00
}
2023-07-22 00:41:27 +02:00
}
func (h *cryptoSetup) NextEvent() Event {
if len(h.events) == 0 {
return Event{Kind: EventNoEvent}
2022-07-21 18:50:10 +02:00
}
2023-07-22 00:41:27 +02:00
ev := h.events[0]
h.events = h.events[1:]
return ev
2022-07-21 18:50:10 +02:00
}
2023-07-22 00:41:27 +02:00
func (h *cryptoSetup) handleTransportParameters(data []byte) error {
2022-07-21 18:50:10 +02:00
var tp wire.TransportParameters
if err := tp.Unmarshal(data, h.perspective.Opposite()); err != nil {
2023-07-22 00:41:27 +02:00
return err
2022-07-21 18:50:10 +02:00
}
h.peerParams = &tp
2023-07-22 00:41:27 +02:00
h.events = append(h.events, Event{Kind: EventReceivedTransportParameters, TransportParameters: h.peerParams})
return nil
2022-07-21 18:50:10 +02:00
}
// must be called after receiving the transport parameters
2024-01-18 23:47:00 +01:00
func (h *cryptoSetup) marshalDataForSessionState(earlyData bool) []byte {
2022-10-24 10:20:25 +02:00
b := make([]byte, 0, 256)
b = quicvarint.Append(b, clientSessionStateRevision)
b = quicvarint.Append(b, uint64(h.rttStats.SmoothedRTT().Microseconds()))
2024-01-18 23:47:00 +01:00
if earlyData {
// only save the transport parameters for 0-RTT enabled session tickets
return h.peerParams.MarshalForSessionTicket(b)
}
return b
2022-07-21 18:50:10 +02:00
}
2024-01-18 23:47:00 +01:00
func (h *cryptoSetup) handleDataFromSessionState(data []byte, earlyData bool) (allowEarlyData bool) {
rtt, tp, err := decodeDataFromSessionState(data, earlyData)
2022-07-21 18:50:10 +02:00
if err != nil {
h.logger.Debugf("Restoring of transport parameters from session ticket failed: %s", err.Error())
return
}
2024-01-18 23:47:00 +01:00
h.rttStats.SetInitialRTT(rtt)
2023-11-16 00:51:48 +01:00
// The session ticket might have been saved from a connection that allowed 0-RTT,
// and therefore contain transport parameters.
// Only use them if 0-RTT is actually used on the new connection.
if tp != nil && h.allow0RTT {
h.zeroRTTParameters = tp
return true
}
return false
2022-07-21 18:50:10 +02:00
}
2024-01-18 23:47:00 +01:00
func decodeDataFromSessionState(data []byte, earlyData bool) (time.Duration, *wire.TransportParameters, error) {
2022-07-21 18:50:10 +02:00
r := bytes.NewReader(data)
ver, err := quicvarint.Read(r)
if err != nil {
2024-01-18 23:47:00 +01:00
return 0, nil, err
2022-07-21 18:50:10 +02:00
}
if ver != clientSessionStateRevision {
2024-01-18 23:47:00 +01:00
return 0, nil, fmt.Errorf("mismatching version. Got %d, expected %d", ver, clientSessionStateRevision)
2022-07-21 18:50:10 +02:00
}
2024-01-18 23:47:00 +01:00
rttEncoded, err := quicvarint.Read(r)
2022-07-21 18:50:10 +02:00
if err != nil {
2024-01-18 23:47:00 +01:00
return 0, nil, err
}
rtt := time.Duration(rttEncoded) * time.Microsecond
if !earlyData {
return rtt, nil, nil
2022-07-21 18:50:10 +02:00
}
var tp wire.TransportParameters
if err := tp.UnmarshalFromSessionTicket(r); err != nil {
2024-01-18 23:47:00 +01:00
return 0, nil, err
2022-07-21 18:50:10 +02:00
}
2024-01-18 23:47:00 +01:00
return rtt, &tp, nil
2022-07-21 18:50:10 +02:00
}
2023-07-22 00:41:27 +02:00
func (h *cryptoSetup) getDataForSessionTicket() []byte {
2023-10-12 15:53:53 +02:00
ticket := &sessionTicket{
RTT: h.rttStats.SmoothedRTT(),
}
if h.allow0RTT {
ticket.Parameters = h.ourParams
}
return ticket.Marshal()
2023-07-22 00:41:27 +02:00
}
// GetSessionTicket generates a new session ticket.
// Due to limitations in crypto/tls, it's only possible to generate a single session ticket per connection.
// It is only valid for the server.
2022-07-21 18:50:10 +02:00
func (h *cryptoSetup) GetSessionTicket() ([]byte, error) {
2024-01-18 23:47:00 +01:00
if err := h.conn.SendSessionTicket(tls.QUICSessionTicketOptions{
EarlyData: h.allow0RTT,
}); err != nil {
2023-08-25 16:15:45 +02:00
// Session tickets might be disabled by tls.Config.SessionTicketsDisabled.
// We can't check h.tlsConfig here, since the actual config might have been obtained from
// the GetConfigForClient callback.
// See https://github.com/golang/go/issues/62032.
// Once that issue is resolved, this error assertion can be removed.
if strings.Contains(err.Error(), "session ticket keys unavailable") {
return nil, nil
}
2023-07-22 00:41:27 +02:00
return nil, err
2022-07-21 18:50:10 +02:00
}
2023-07-22 00:41:27 +02:00
ev := h.conn.NextEvent()
2024-01-18 23:47:00 +01:00
if ev.Kind != tls.QUICWriteData || ev.Level != tls.QUICEncryptionLevelApplication {
2023-07-22 00:41:27 +02:00
panic("crypto/tls bug: where's my session ticket?")
}
ticket := ev.Data
2024-01-18 23:47:00 +01:00
if ev := h.conn.NextEvent(); ev.Kind != tls.QUICNoEvent {
2023-07-22 00:41:27 +02:00
panic("crypto/tls bug: why more than one ticket?")
}
return ticket, nil
2022-07-21 18:50:10 +02:00
}
2023-10-12 15:53:53 +02:00
// handleSessionTicket is called for the server when receiving the client's session ticket.
2023-11-16 00:51:48 +01:00
// It reads parameters from the session ticket and checks whether to accept 0-RTT if the session ticket enabled 0-RTT.
// Note that the fact that the session ticket allows 0-RTT doesn't mean that the actual TLS handshake enables 0-RTT:
// A client may use a 0-RTT enabled session to resume a TLS session without using 0-RTT.
2023-10-12 15:53:53 +02:00
func (h *cryptoSetup) handleSessionTicket(sessionTicketData []byte, using0RTT bool) bool {
2022-07-21 18:50:10 +02:00
var t sessionTicket
2023-10-12 15:53:53 +02:00
if err := t.Unmarshal(sessionTicketData, using0RTT); err != nil {
h.logger.Debugf("Unmarshalling session ticket failed: %s", err.Error())
return false
}
h.rttStats.SetInitialRTT(t.RTT)
if !using0RTT {
2022-07-21 18:50:10 +02:00
return false
}
valid := h.ourParams.ValidFor0RTT(t.Parameters)
if !valid {
2022-07-21 18:50:10 +02:00
h.logger.Debugf("Transport parameters changed. Rejecting 0-RTT.")
return false
}
if !h.allow0RTT {
h.logger.Debugf("0-RTT not allowed. Rejecting 0-RTT.")
return false
2022-07-21 18:50:10 +02:00
}
h.logger.Debugf("Accepting 0-RTT. Restoring RTT from session ticket: %s", t.RTT)
return true
2022-07-21 18:50:10 +02:00
}
// rejected0RTT is called for the client when the server rejects 0-RTT.
func (h *cryptoSetup) rejected0RTT() {
h.logger.Debugf("0-RTT was rejected. Dropping 0-RTT keys.")
had0RTTKeys := h.zeroRTTSealer != nil
h.zeroRTTSealer = nil
if had0RTTKeys {
2023-07-22 00:41:27 +02:00
h.events = append(h.events, Event{Kind: EventDiscard0RTTKeys})
2022-07-21 18:50:10 +02:00
}
}
2024-03-26 19:56:06 +01:00
func (h *cryptoSetup) setReadKey(el tls.QUICEncryptionLevel, suiteID uint16, trafficSecret []byte) {
2023-07-22 00:41:27 +02:00
suite := getCipherSuite(suiteID)
//nolint:exhaustive // The TLS stack doesn't export Initial keys.
switch el {
2024-01-18 23:47:00 +01:00
case tls.QUICEncryptionLevelEarly:
2022-07-21 18:50:10 +02:00
if h.perspective == protocol.PerspectiveClient {
panic("Received 0-RTT read key for the client")
}
h.zeroRTTOpener = newLongHeaderOpener(
createAEAD(suite, trafficSecret, h.version),
newHeaderProtector(suite, trafficSecret, true, h.version),
)
2023-07-22 00:41:27 +02:00
h.used0RTT.Store(true)
if h.logger.Debug() {
h.logger.Debugf("Installed 0-RTT Read keys (using %s)", tls.CipherSuiteName(suite.ID))
}
2024-01-18 23:47:00 +01:00
case tls.QUICEncryptionLevelHandshake:
2023-07-22 00:41:27 +02:00
h.handshakeOpener = newLongHeaderOpener(
2022-07-21 18:50:10 +02:00
createAEAD(suite, trafficSecret, h.version),
newHeaderProtector(suite, trafficSecret, true, h.version),
)
if h.logger.Debug() {
h.logger.Debugf("Installed Handshake Read keys (using %s)", tls.CipherSuiteName(suite.ID))
}
2024-01-18 23:47:00 +01:00
case tls.QUICEncryptionLevelApplication:
2022-07-21 18:50:10 +02:00
h.aead.SetReadKey(suite, trafficSecret)
h.has1RTTOpener = true
if h.logger.Debug() {
h.logger.Debugf("Installed 1-RTT Read keys (using %s)", tls.CipherSuiteName(suite.ID))
}
2022-07-21 18:50:10 +02:00
default:
panic("unexpected read encryption level")
}
2023-07-22 00:41:27 +02:00
h.events = append(h.events, Event{Kind: EventReceivedReadKeys})
2023-10-12 15:53:53 +02:00
if h.tracer != nil && h.tracer.UpdatedKeyFromTLS != nil {
2023-07-22 00:41:27 +02:00
h.tracer.UpdatedKeyFromTLS(qtls.FromTLSEncryptionLevel(el), h.perspective.Opposite())
2022-07-21 18:50:10 +02:00
}
}
2024-03-26 19:56:06 +01:00
func (h *cryptoSetup) setWriteKey(el tls.QUICEncryptionLevel, suiteID uint16, trafficSecret []byte) {
2023-07-22 00:41:27 +02:00
suite := getCipherSuite(suiteID)
//nolint:exhaustive // The TLS stack doesn't export Initial keys.
switch el {
2024-01-18 23:47:00 +01:00
case tls.QUICEncryptionLevelEarly:
2022-07-21 18:50:10 +02:00
if h.perspective == protocol.PerspectiveServer {
panic("Received 0-RTT write key for the server")
}
h.zeroRTTSealer = newLongHeaderSealer(
createAEAD(suite, trafficSecret, h.version),
newHeaderProtector(suite, trafficSecret, true, h.version),
)
if h.logger.Debug() {
h.logger.Debugf("Installed 0-RTT Write keys (using %s)", tls.CipherSuiteName(suite.ID))
}
2023-10-12 15:53:53 +02:00
if h.tracer != nil && h.tracer.UpdatedKeyFromTLS != nil {
2022-07-21 18:50:10 +02:00
h.tracer.UpdatedKeyFromTLS(protocol.Encryption0RTT, h.perspective)
}
2023-07-22 00:41:27 +02:00
// don't set used0RTT here. 0-RTT might still get rejected.
2022-07-21 18:50:10 +02:00
return
2024-01-18 23:47:00 +01:00
case tls.QUICEncryptionLevelHandshake:
2023-07-22 00:41:27 +02:00
h.handshakeSealer = newLongHeaderSealer(
2022-07-21 18:50:10 +02:00
createAEAD(suite, trafficSecret, h.version),
newHeaderProtector(suite, trafficSecret, true, h.version),
)
if h.logger.Debug() {
h.logger.Debugf("Installed Handshake Write keys (using %s)", tls.CipherSuiteName(suite.ID))
}
2024-01-18 23:47:00 +01:00
case tls.QUICEncryptionLevelApplication:
2022-07-21 18:50:10 +02:00
h.aead.SetWriteKey(suite, trafficSecret)
h.has1RTTSealer = true
if h.logger.Debug() {
h.logger.Debugf("Installed 1-RTT Write keys (using %s)", tls.CipherSuiteName(suite.ID))
}
2022-07-21 18:50:10 +02:00
if h.zeroRTTSealer != nil {
2023-07-22 00:41:27 +02:00
// Once we receive handshake keys, we know that 0-RTT was not rejected.
h.used0RTT.Store(true)
2022-07-21 18:50:10 +02:00
h.zeroRTTSealer = nil
h.logger.Debugf("Dropping 0-RTT keys.")
2023-10-12 15:53:53 +02:00
if h.tracer != nil && h.tracer.DroppedEncryptionLevel != nil {
2022-07-21 18:50:10 +02:00
h.tracer.DroppedEncryptionLevel(protocol.Encryption0RTT)
}
}
default:
panic("unexpected write encryption level")
}
2023-10-12 15:53:53 +02:00
if h.tracer != nil && h.tracer.UpdatedKeyFromTLS != nil {
2023-07-22 00:41:27 +02:00
h.tracer.UpdatedKeyFromTLS(qtls.FromTLSEncryptionLevel(el), h.perspective)
2022-07-21 18:50:10 +02:00
}
}
2024-01-18 23:47:00 +01:00
// writeRecord is called when TLS writes data
func (h *cryptoSetup) writeRecord(encLevel tls.QUICEncryptionLevel, p []byte) {
2023-07-22 00:41:27 +02:00
//nolint:exhaustive // handshake records can only be written for Initial and Handshake.
switch encLevel {
2024-01-18 23:47:00 +01:00
case tls.QUICEncryptionLevelInitial:
2023-07-22 00:41:27 +02:00
h.events = append(h.events, Event{Kind: EventWriteInitialData, Data: p})
2024-01-18 23:47:00 +01:00
case tls.QUICEncryptionLevelHandshake:
2023-07-22 00:41:27 +02:00
h.events = append(h.events, Event{Kind: EventWriteHandshakeData, Data: p})
2024-01-18 23:47:00 +01:00
case tls.QUICEncryptionLevelApplication:
2023-07-22 00:41:27 +02:00
panic("unexpected write")
2022-07-21 18:50:10 +02:00
default:
2023-07-22 00:41:27 +02:00
panic(fmt.Sprintf("unexpected write encryption level: %s", encLevel))
2022-07-21 18:50:10 +02:00
}
}
2023-07-22 00:41:27 +02:00
func (h *cryptoSetup) DiscardInitialKeys() {
dropped := h.initialOpener != nil
2022-07-21 18:50:10 +02:00
h.initialOpener = nil
h.initialSealer = nil
2023-07-22 00:41:27 +02:00
if dropped {
h.logger.Debugf("Dropping Initial keys.")
}
}
func (h *cryptoSetup) handshakeComplete() {
h.handshakeCompleteTime = time.Now()
h.events = append(h.events, Event{Kind: EventHandshakeComplete})
2022-07-21 18:50:10 +02:00
}
func (h *cryptoSetup) SetHandshakeConfirmed() {
h.aead.SetHandshakeConfirmed()
// drop Handshake keys
var dropped bool
if h.handshakeOpener != nil {
h.handshakeOpener = nil
h.handshakeSealer = nil
dropped = true
}
if dropped {
h.logger.Debugf("Dropping Handshake keys.")
}
}
func (h *cryptoSetup) GetInitialSealer() (LongHeaderSealer, error) {
if h.initialSealer == nil {
return nil, ErrKeysDropped
}
return h.initialSealer, nil
}
func (h *cryptoSetup) Get0RTTSealer() (LongHeaderSealer, error) {
if h.zeroRTTSealer == nil {
return nil, ErrKeysDropped
}
return h.zeroRTTSealer, nil
}
func (h *cryptoSetup) GetHandshakeSealer() (LongHeaderSealer, error) {
if h.handshakeSealer == nil {
if h.initialSealer == nil {
return nil, ErrKeysDropped
}
return nil, ErrKeysNotYetAvailable
}
return h.handshakeSealer, nil
}
func (h *cryptoSetup) Get1RTTSealer() (ShortHeaderSealer, error) {
if !h.has1RTTSealer {
return nil, ErrKeysNotYetAvailable
}
return h.aead, nil
}
func (h *cryptoSetup) GetInitialOpener() (LongHeaderOpener, error) {
if h.initialOpener == nil {
return nil, ErrKeysDropped
}
return h.initialOpener, nil
}
func (h *cryptoSetup) Get0RTTOpener() (LongHeaderOpener, error) {
if h.zeroRTTOpener == nil {
if h.initialOpener != nil {
return nil, ErrKeysNotYetAvailable
}
// if the initial opener is also not available, the keys were already dropped
return nil, ErrKeysDropped
}
return h.zeroRTTOpener, nil
}
func (h *cryptoSetup) GetHandshakeOpener() (LongHeaderOpener, error) {
if h.handshakeOpener == nil {
if h.initialOpener != nil {
return nil, ErrKeysNotYetAvailable
}
// if the initial opener is also not available, the keys were already dropped
return nil, ErrKeysDropped
}
return h.handshakeOpener, nil
}
func (h *cryptoSetup) Get1RTTOpener() (ShortHeaderOpener, error) {
if h.zeroRTTOpener != nil && time.Since(h.handshakeCompleteTime) > 3*h.rttStats.PTO(true) {
h.zeroRTTOpener = nil
h.logger.Debugf("Dropping 0-RTT keys.")
2023-10-12 15:53:53 +02:00
if h.tracer != nil && h.tracer.DroppedEncryptionLevel != nil {
2022-07-21 18:50:10 +02:00
h.tracer.DroppedEncryptionLevel(protocol.Encryption0RTT)
}
}
if !h.has1RTTOpener {
return nil, ErrKeysNotYetAvailable
}
return h.aead, nil
}
func (h *cryptoSetup) ConnectionState() ConnectionState {
2023-07-22 00:41:27 +02:00
return ConnectionState{
ConnectionState: h.conn.ConnectionState(),
Used0RTT: h.used0RTT.Load(),
}
}
func wrapError(err error) error {
2023-08-25 16:15:45 +02:00
// alert 80 is an internal error
2024-01-18 23:47:00 +01:00
if alertErr := tls.AlertError(0); errors.As(err, &alertErr) && alertErr != 80 {
2023-08-25 16:15:45 +02:00
return qerr.NewLocalCryptoError(uint8(alertErr), err)
2023-07-22 00:41:27 +02:00
}
return &qerr.TransportError{ErrorCode: qerr.InternalError, ErrorMessage: err.Error()}
2022-07-21 18:50:10 +02:00
}