 9bdcbe0447
			
		
	
	9bdcbe0447
	
	
	
		
			
			Major integrations and fixes: - Added BACKBEAT SDK integration for P2P operation timing - Implemented beat-aware status tracking for distributed operations - Added Docker secrets support for secure license management - Resolved KACHING license validation via HTTPS/TLS - Updated docker-compose configuration for clean stack deployment - Disabled rollback policies to prevent deployment failures - Added license credential storage (CHORUS-DEV-MULTI-001) Technical improvements: - BACKBEAT P2P operation tracking with phase management - Enhanced configuration system with file-based secrets - Improved error handling for license validation - Clean separation of KACHING and CHORUS deployment stacks 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
		
			
				
	
	
		
			783 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			783 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Copyright 2018 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.
 | |
| 
 | |
| package qtls
 | |
| 
 | |
| import (
 | |
| 	"bytes"
 | |
| 	"context"
 | |
| 	"crypto"
 | |
| 	"crypto/ecdh"
 | |
| 	"crypto/hmac"
 | |
| 	"crypto/rsa"
 | |
| 	"encoding/binary"
 | |
| 	"errors"
 | |
| 	"hash"
 | |
| 	"time"
 | |
| 
 | |
| 	"golang.org/x/crypto/cryptobyte"
 | |
| )
 | |
| 
 | |
| type clientHandshakeStateTLS13 struct {
 | |
| 	c           *Conn
 | |
| 	ctx         context.Context
 | |
| 	serverHello *serverHelloMsg
 | |
| 	hello       *clientHelloMsg
 | |
| 	ecdheKey    *ecdh.PrivateKey
 | |
| 
 | |
| 	session     *clientSessionState
 | |
| 	earlySecret []byte
 | |
| 	binderKey   []byte
 | |
| 
 | |
| 	certReq       *certificateRequestMsgTLS13
 | |
| 	usingPSK      bool
 | |
| 	sentDummyCCS  bool
 | |
| 	suite         *cipherSuiteTLS13
 | |
| 	transcript    hash.Hash
 | |
| 	masterSecret  []byte
 | |
| 	trafficSecret []byte // client_application_traffic_secret_0
 | |
| }
 | |
| 
 | |
| // handshake requires hs.c, hs.hello, hs.serverHello, hs.ecdheKey, and,
 | |
| // optionally, hs.session, hs.earlySecret and hs.binderKey to be set.
 | |
| func (hs *clientHandshakeStateTLS13) handshake() error {
 | |
| 	c := hs.c
 | |
| 
 | |
| 	if needFIPS() {
 | |
| 		return errors.New("tls: internal error: TLS 1.3 reached in FIPS mode")
 | |
| 	}
 | |
| 
 | |
| 	// The server must not select TLS 1.3 in a renegotiation. See RFC 8446,
 | |
| 	// sections 4.1.2 and 4.1.3.
 | |
| 	if c.handshakes > 0 {
 | |
| 		c.sendAlert(alertProtocolVersion)
 | |
| 		return errors.New("tls: server selected TLS 1.3 in a renegotiation")
 | |
| 	}
 | |
| 
 | |
| 	// Consistency check on the presence of a keyShare and its parameters.
 | |
| 	if hs.ecdheKey == nil || len(hs.hello.keyShares) != 1 {
 | |
| 		return c.sendAlert(alertInternalError)
 | |
| 	}
 | |
| 
 | |
| 	if err := hs.checkServerHelloOrHRR(); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	hs.transcript = hs.suite.hash.New()
 | |
| 
 | |
| 	if err := transcriptMsg(hs.hello, hs.transcript); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	if bytes.Equal(hs.serverHello.random, helloRetryRequestRandom) {
 | |
| 		if err := hs.sendDummyChangeCipherSpec(); err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 		if err := hs.processHelloRetryRequest(); err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if err := transcriptMsg(hs.serverHello, hs.transcript); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	c.buffering = true
 | |
| 	if err := hs.processServerHello(); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	if err := hs.sendDummyChangeCipherSpec(); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	if err := hs.establishHandshakeKeys(); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	if err := hs.readServerParameters(); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	if err := hs.readServerCertificate(); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	if err := hs.readServerFinished(); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	if err := hs.sendClientCertificate(); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	if err := hs.sendClientFinished(); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	if _, err := c.flush(); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	c.isHandshakeComplete.Store(true)
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // checkServerHelloOrHRR does validity checks that apply to both ServerHello and
 | |
| // HelloRetryRequest messages. It sets hs.suite.
 | |
| func (hs *clientHandshakeStateTLS13) checkServerHelloOrHRR() error {
 | |
| 	c := hs.c
 | |
| 
 | |
| 	if hs.serverHello.supportedVersion == 0 {
 | |
| 		c.sendAlert(alertMissingExtension)
 | |
| 		return errors.New("tls: server selected TLS 1.3 using the legacy version field")
 | |
| 	}
 | |
| 
 | |
| 	if hs.serverHello.supportedVersion != VersionTLS13 {
 | |
| 		c.sendAlert(alertIllegalParameter)
 | |
| 		return errors.New("tls: server selected an invalid version after a HelloRetryRequest")
 | |
| 	}
 | |
| 
 | |
| 	if hs.serverHello.vers != VersionTLS12 {
 | |
| 		c.sendAlert(alertIllegalParameter)
 | |
| 		return errors.New("tls: server sent an incorrect legacy version")
 | |
| 	}
 | |
| 
 | |
| 	if hs.serverHello.ocspStapling ||
 | |
| 		hs.serverHello.ticketSupported ||
 | |
| 		hs.serverHello.secureRenegotiationSupported ||
 | |
| 		len(hs.serverHello.secureRenegotiation) != 0 ||
 | |
| 		len(hs.serverHello.alpnProtocol) != 0 ||
 | |
| 		len(hs.serverHello.scts) != 0 {
 | |
| 		c.sendAlert(alertUnsupportedExtension)
 | |
| 		return errors.New("tls: server sent a ServerHello extension forbidden in TLS 1.3")
 | |
| 	}
 | |
| 
 | |
| 	if !bytes.Equal(hs.hello.sessionId, hs.serverHello.sessionId) {
 | |
| 		c.sendAlert(alertIllegalParameter)
 | |
| 		return errors.New("tls: server did not echo the legacy session ID")
 | |
| 	}
 | |
| 
 | |
| 	if hs.serverHello.compressionMethod != compressionNone {
 | |
| 		c.sendAlert(alertIllegalParameter)
 | |
| 		return errors.New("tls: server selected unsupported compression format")
 | |
| 	}
 | |
| 
 | |
| 	selectedSuite := mutualCipherSuiteTLS13(hs.hello.cipherSuites, hs.serverHello.cipherSuite)
 | |
| 	if hs.suite != nil && selectedSuite != hs.suite {
 | |
| 		c.sendAlert(alertIllegalParameter)
 | |
| 		return errors.New("tls: server changed cipher suite after a HelloRetryRequest")
 | |
| 	}
 | |
| 	if selectedSuite == nil {
 | |
| 		c.sendAlert(alertIllegalParameter)
 | |
| 		return errors.New("tls: server chose an unconfigured cipher suite")
 | |
| 	}
 | |
| 	hs.suite = selectedSuite
 | |
| 	c.cipherSuite = hs.suite.id
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // sendDummyChangeCipherSpec sends a ChangeCipherSpec record for compatibility
 | |
| // with middleboxes that didn't implement TLS correctly. See RFC 8446, Appendix D.4.
 | |
| func (hs *clientHandshakeStateTLS13) sendDummyChangeCipherSpec() error {
 | |
| 	if hs.c.quic != nil {
 | |
| 		return nil
 | |
| 	}
 | |
| 	if hs.sentDummyCCS {
 | |
| 		return nil
 | |
| 	}
 | |
| 	hs.sentDummyCCS = true
 | |
| 
 | |
| 	return hs.c.writeChangeCipherRecord()
 | |
| }
 | |
| 
 | |
| // processHelloRetryRequest handles the HRR in hs.serverHello, modifies and
 | |
| // resends hs.hello, and reads the new ServerHello into hs.serverHello.
 | |
| func (hs *clientHandshakeStateTLS13) processHelloRetryRequest() error {
 | |
| 	c := hs.c
 | |
| 
 | |
| 	// The first ClientHello gets double-hashed into the transcript upon a
 | |
| 	// HelloRetryRequest. (The idea is that the server might offload transcript
 | |
| 	// storage to the client in the cookie.) See RFC 8446, Section 4.4.1.
 | |
| 	chHash := hs.transcript.Sum(nil)
 | |
| 	hs.transcript.Reset()
 | |
| 	hs.transcript.Write([]byte{typeMessageHash, 0, 0, uint8(len(chHash))})
 | |
| 	hs.transcript.Write(chHash)
 | |
| 	if err := transcriptMsg(hs.serverHello, hs.transcript); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	// The only HelloRetryRequest extensions we support are key_share and
 | |
| 	// cookie, and clients must abort the handshake if the HRR would not result
 | |
| 	// in any change in the ClientHello.
 | |
| 	if hs.serverHello.selectedGroup == 0 && hs.serverHello.cookie == nil {
 | |
| 		c.sendAlert(alertIllegalParameter)
 | |
| 		return errors.New("tls: server sent an unnecessary HelloRetryRequest message")
 | |
| 	}
 | |
| 
 | |
| 	if hs.serverHello.cookie != nil {
 | |
| 		hs.hello.cookie = hs.serverHello.cookie
 | |
| 	}
 | |
| 
 | |
| 	if hs.serverHello.serverShare.group != 0 {
 | |
| 		c.sendAlert(alertDecodeError)
 | |
| 		return errors.New("tls: received malformed key_share extension")
 | |
| 	}
 | |
| 
 | |
| 	// If the server sent a key_share extension selecting a group, ensure it's
 | |
| 	// a group we advertised but did not send a key share for, and send a key
 | |
| 	// share for it this time.
 | |
| 	if curveID := hs.serverHello.selectedGroup; curveID != 0 {
 | |
| 		curveOK := false
 | |
| 		for _, id := range hs.hello.supportedCurves {
 | |
| 			if id == curveID {
 | |
| 				curveOK = true
 | |
| 				break
 | |
| 			}
 | |
| 		}
 | |
| 		if !curveOK {
 | |
| 			c.sendAlert(alertIllegalParameter)
 | |
| 			return errors.New("tls: server selected unsupported group")
 | |
| 		}
 | |
| 		if sentID, _ := curveIDForCurve(hs.ecdheKey.Curve()); sentID == curveID {
 | |
| 			c.sendAlert(alertIllegalParameter)
 | |
| 			return errors.New("tls: server sent an unnecessary HelloRetryRequest key_share")
 | |
| 		}
 | |
| 		if _, ok := curveForCurveID(curveID); !ok {
 | |
| 			c.sendAlert(alertInternalError)
 | |
| 			return errors.New("tls: CurvePreferences includes unsupported curve")
 | |
| 		}
 | |
| 		key, err := generateECDHEKey(c.config.rand(), curveID)
 | |
| 		if err != nil {
 | |
| 			c.sendAlert(alertInternalError)
 | |
| 			return err
 | |
| 		}
 | |
| 		hs.ecdheKey = key
 | |
| 		hs.hello.keyShares = []keyShare{{group: curveID, data: key.PublicKey().Bytes()}}
 | |
| 	}
 | |
| 
 | |
| 	hs.hello.raw = nil
 | |
| 	if len(hs.hello.pskIdentities) > 0 {
 | |
| 		pskSuite := cipherSuiteTLS13ByID(hs.session.cipherSuite)
 | |
| 		if pskSuite == nil {
 | |
| 			return c.sendAlert(alertInternalError)
 | |
| 		}
 | |
| 		if pskSuite.hash == hs.suite.hash {
 | |
| 			// Update binders and obfuscated_ticket_age.
 | |
| 			ticketAge := uint32(c.config.time().Sub(hs.session.receivedAt) / time.Millisecond)
 | |
| 			hs.hello.pskIdentities[0].obfuscatedTicketAge = ticketAge + hs.session.ageAdd
 | |
| 
 | |
| 			transcript := hs.suite.hash.New()
 | |
| 			transcript.Write([]byte{typeMessageHash, 0, 0, uint8(len(chHash))})
 | |
| 			transcript.Write(chHash)
 | |
| 			if err := transcriptMsg(hs.serverHello, transcript); err != nil {
 | |
| 				return err
 | |
| 			}
 | |
| 			helloBytes, err := hs.hello.marshalWithoutBinders()
 | |
| 			if err != nil {
 | |
| 				return err
 | |
| 			}
 | |
| 			transcript.Write(helloBytes)
 | |
| 			pskBinders := [][]byte{hs.suite.finishedHash(hs.binderKey, transcript)}
 | |
| 			if err := hs.hello.updateBinders(pskBinders); err != nil {
 | |
| 				return err
 | |
| 			}
 | |
| 		} else {
 | |
| 			// Server selected a cipher suite incompatible with the PSK.
 | |
| 			hs.hello.pskIdentities = nil
 | |
| 			hs.hello.pskBinders = nil
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if hs.hello.earlyData {
 | |
| 		hs.hello.earlyData = false
 | |
| 		c.quicRejectedEarlyData()
 | |
| 	}
 | |
| 
 | |
| 	if _, err := hs.c.writeHandshakeRecord(hs.hello, hs.transcript); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	// serverHelloMsg is not included in the transcript
 | |
| 	msg, err := c.readHandshake(nil)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	serverHello, ok := msg.(*serverHelloMsg)
 | |
| 	if !ok {
 | |
| 		c.sendAlert(alertUnexpectedMessage)
 | |
| 		return unexpectedMessageError(serverHello, msg)
 | |
| 	}
 | |
| 	hs.serverHello = serverHello
 | |
| 
 | |
| 	if err := hs.checkServerHelloOrHRR(); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func (hs *clientHandshakeStateTLS13) processServerHello() error {
 | |
| 	c := hs.c
 | |
| 
 | |
| 	if bytes.Equal(hs.serverHello.random, helloRetryRequestRandom) {
 | |
| 		c.sendAlert(alertUnexpectedMessage)
 | |
| 		return errors.New("tls: server sent two HelloRetryRequest messages")
 | |
| 	}
 | |
| 
 | |
| 	if len(hs.serverHello.cookie) != 0 {
 | |
| 		c.sendAlert(alertUnsupportedExtension)
 | |
| 		return errors.New("tls: server sent a cookie in a normal ServerHello")
 | |
| 	}
 | |
| 
 | |
| 	if hs.serverHello.selectedGroup != 0 {
 | |
| 		c.sendAlert(alertDecodeError)
 | |
| 		return errors.New("tls: malformed key_share extension")
 | |
| 	}
 | |
| 
 | |
| 	if hs.serverHello.serverShare.group == 0 {
 | |
| 		c.sendAlert(alertIllegalParameter)
 | |
| 		return errors.New("tls: server did not send a key share")
 | |
| 	}
 | |
| 	if sentID, _ := curveIDForCurve(hs.ecdheKey.Curve()); hs.serverHello.serverShare.group != sentID {
 | |
| 		c.sendAlert(alertIllegalParameter)
 | |
| 		return errors.New("tls: server selected unsupported group")
 | |
| 	}
 | |
| 
 | |
| 	if !hs.serverHello.selectedIdentityPresent {
 | |
| 		return nil
 | |
| 	}
 | |
| 
 | |
| 	if int(hs.serverHello.selectedIdentity) >= len(hs.hello.pskIdentities) {
 | |
| 		c.sendAlert(alertIllegalParameter)
 | |
| 		return errors.New("tls: server selected an invalid PSK")
 | |
| 	}
 | |
| 
 | |
| 	if len(hs.hello.pskIdentities) != 1 || hs.session == nil {
 | |
| 		return c.sendAlert(alertInternalError)
 | |
| 	}
 | |
| 	pskSuite := cipherSuiteTLS13ByID(hs.session.cipherSuite)
 | |
| 	if pskSuite == nil {
 | |
| 		return c.sendAlert(alertInternalError)
 | |
| 	}
 | |
| 	if pskSuite.hash != hs.suite.hash {
 | |
| 		c.sendAlert(alertIllegalParameter)
 | |
| 		return errors.New("tls: server selected an invalid PSK and cipher suite pair")
 | |
| 	}
 | |
| 
 | |
| 	hs.usingPSK = true
 | |
| 	c.didResume = true
 | |
| 	c.peerCertificates = hs.session.serverCertificates
 | |
| 	c.verifiedChains = hs.session.verifiedChains
 | |
| 	c.ocspResponse = hs.session.ocspResponse
 | |
| 	c.scts = hs.session.scts
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func (hs *clientHandshakeStateTLS13) establishHandshakeKeys() error {
 | |
| 	c := hs.c
 | |
| 
 | |
| 	peerKey, err := hs.ecdheKey.Curve().NewPublicKey(hs.serverHello.serverShare.data)
 | |
| 	if err != nil {
 | |
| 		c.sendAlert(alertIllegalParameter)
 | |
| 		return errors.New("tls: invalid server key share")
 | |
| 	}
 | |
| 	sharedKey, err := hs.ecdheKey.ECDH(peerKey)
 | |
| 	if err != nil {
 | |
| 		c.sendAlert(alertIllegalParameter)
 | |
| 		return errors.New("tls: invalid server key share")
 | |
| 	}
 | |
| 
 | |
| 	earlySecret := hs.earlySecret
 | |
| 	if !hs.usingPSK {
 | |
| 		earlySecret = hs.suite.extract(nil, nil)
 | |
| 	}
 | |
| 
 | |
| 	handshakeSecret := hs.suite.extract(sharedKey,
 | |
| 		hs.suite.deriveSecret(earlySecret, "derived", nil))
 | |
| 
 | |
| 	clientSecret := hs.suite.deriveSecret(handshakeSecret,
 | |
| 		clientHandshakeTrafficLabel, hs.transcript)
 | |
| 	c.out.setTrafficSecret(hs.suite, QUICEncryptionLevelHandshake, clientSecret)
 | |
| 	serverSecret := hs.suite.deriveSecret(handshakeSecret,
 | |
| 		serverHandshakeTrafficLabel, hs.transcript)
 | |
| 	c.in.setTrafficSecret(hs.suite, QUICEncryptionLevelHandshake, serverSecret)
 | |
| 
 | |
| 	if c.quic != nil {
 | |
| 		if c.hand.Len() != 0 {
 | |
| 			c.sendAlert(alertUnexpectedMessage)
 | |
| 		}
 | |
| 		c.quicSetWriteSecret(QUICEncryptionLevelHandshake, hs.suite.id, clientSecret)
 | |
| 		c.quicSetReadSecret(QUICEncryptionLevelHandshake, hs.suite.id, serverSecret)
 | |
| 	}
 | |
| 
 | |
| 	err = c.config.writeKeyLog(keyLogLabelClientHandshake, hs.hello.random, clientSecret)
 | |
| 	if err != nil {
 | |
| 		c.sendAlert(alertInternalError)
 | |
| 		return err
 | |
| 	}
 | |
| 	err = c.config.writeKeyLog(keyLogLabelServerHandshake, hs.hello.random, serverSecret)
 | |
| 	if err != nil {
 | |
| 		c.sendAlert(alertInternalError)
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	hs.masterSecret = hs.suite.extract(nil,
 | |
| 		hs.suite.deriveSecret(handshakeSecret, "derived", nil))
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func (hs *clientHandshakeStateTLS13) readServerParameters() error {
 | |
| 	c := hs.c
 | |
| 
 | |
| 	msg, err := c.readHandshake(hs.transcript)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	encryptedExtensions, ok := msg.(*encryptedExtensionsMsg)
 | |
| 	if !ok {
 | |
| 		c.sendAlert(alertUnexpectedMessage)
 | |
| 		return unexpectedMessageError(encryptedExtensions, msg)
 | |
| 	}
 | |
| 
 | |
| 	if err := checkALPN(hs.hello.alpnProtocols, encryptedExtensions.alpnProtocol, c.quic != nil); err != nil {
 | |
| 		// RFC 8446 specifies that no_application_protocol is sent by servers, but
 | |
| 		// does not specify how clients handle the selection of an incompatible protocol.
 | |
| 		// RFC 9001 Section 8.1 specifies that QUIC clients send no_application_protocol
 | |
| 		// in this case. Always sending no_application_protocol seems reasonable.
 | |
| 		c.sendAlert(alertNoApplicationProtocol)
 | |
| 		return err
 | |
| 	}
 | |
| 	c.clientProtocol = encryptedExtensions.alpnProtocol
 | |
| 
 | |
| 	if c.quic != nil {
 | |
| 		if encryptedExtensions.quicTransportParameters == nil {
 | |
| 			// RFC 9001 Section 8.2.
 | |
| 			c.sendAlert(alertMissingExtension)
 | |
| 			return errors.New("tls: server did not send a quic_transport_parameters extension")
 | |
| 		}
 | |
| 		c.quicSetTransportParameters(encryptedExtensions.quicTransportParameters)
 | |
| 	} else {
 | |
| 		if encryptedExtensions.quicTransportParameters != nil {
 | |
| 			c.sendAlert(alertUnsupportedExtension)
 | |
| 			return errors.New("tls: server sent an unexpected quic_transport_parameters extension")
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if hs.hello.earlyData && !encryptedExtensions.earlyData {
 | |
| 		c.quicRejectedEarlyData()
 | |
| 	}
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func (hs *clientHandshakeStateTLS13) readServerCertificate() error {
 | |
| 	c := hs.c
 | |
| 
 | |
| 	// Either a PSK or a certificate is always used, but not both.
 | |
| 	// See RFC 8446, Section 4.1.1.
 | |
| 	if hs.usingPSK {
 | |
| 		// Make sure the connection is still being verified whether or not this
 | |
| 		// is a resumption. Resumptions currently don't reverify certificates so
 | |
| 		// they don't call verifyServerCertificate. See Issue 31641.
 | |
| 		if c.config.VerifyConnection != nil {
 | |
| 			if err := c.config.VerifyConnection(c.connectionStateLocked()); err != nil {
 | |
| 				c.sendAlert(alertBadCertificate)
 | |
| 				return err
 | |
| 			}
 | |
| 		}
 | |
| 		return nil
 | |
| 	}
 | |
| 
 | |
| 	msg, err := c.readHandshake(hs.transcript)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	certReq, ok := msg.(*certificateRequestMsgTLS13)
 | |
| 	if ok {
 | |
| 		hs.certReq = certReq
 | |
| 
 | |
| 		msg, err = c.readHandshake(hs.transcript)
 | |
| 		if err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	certMsg, ok := msg.(*certificateMsgTLS13)
 | |
| 	if !ok {
 | |
| 		c.sendAlert(alertUnexpectedMessage)
 | |
| 		return unexpectedMessageError(certMsg, msg)
 | |
| 	}
 | |
| 	if len(certMsg.certificate.Certificate) == 0 {
 | |
| 		c.sendAlert(alertDecodeError)
 | |
| 		return errors.New("tls: received empty certificates message")
 | |
| 	}
 | |
| 
 | |
| 	c.scts = certMsg.certificate.SignedCertificateTimestamps
 | |
| 	c.ocspResponse = certMsg.certificate.OCSPStaple
 | |
| 
 | |
| 	if err := c.verifyServerCertificate(certMsg.certificate.Certificate); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	// certificateVerifyMsg is included in the transcript, but not until
 | |
| 	// after we verify the handshake signature, since the state before
 | |
| 	// this message was sent is used.
 | |
| 	msg, err = c.readHandshake(nil)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	certVerify, ok := msg.(*certificateVerifyMsg)
 | |
| 	if !ok {
 | |
| 		c.sendAlert(alertUnexpectedMessage)
 | |
| 		return unexpectedMessageError(certVerify, msg)
 | |
| 	}
 | |
| 
 | |
| 	// See RFC 8446, Section 4.4.3.
 | |
| 	if !isSupportedSignatureAlgorithm(certVerify.signatureAlgorithm, supportedSignatureAlgorithms()) {
 | |
| 		c.sendAlert(alertIllegalParameter)
 | |
| 		return errors.New("tls: certificate used with invalid signature algorithm")
 | |
| 	}
 | |
| 	sigType, sigHash, err := typeAndHashFromSignatureScheme(certVerify.signatureAlgorithm)
 | |
| 	if err != nil {
 | |
| 		return c.sendAlert(alertInternalError)
 | |
| 	}
 | |
| 	if sigType == signaturePKCS1v15 || sigHash == crypto.SHA1 {
 | |
| 		c.sendAlert(alertIllegalParameter)
 | |
| 		return errors.New("tls: certificate used with invalid signature algorithm")
 | |
| 	}
 | |
| 	signed := signedMessage(sigHash, serverSignatureContext, hs.transcript)
 | |
| 	if err := verifyHandshakeSignature(sigType, c.peerCertificates[0].PublicKey,
 | |
| 		sigHash, signed, certVerify.signature); err != nil {
 | |
| 		c.sendAlert(alertDecryptError)
 | |
| 		return errors.New("tls: invalid signature by the server certificate: " + err.Error())
 | |
| 	}
 | |
| 
 | |
| 	if err := transcriptMsg(certVerify, hs.transcript); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func (hs *clientHandshakeStateTLS13) readServerFinished() error {
 | |
| 	c := hs.c
 | |
| 
 | |
| 	// finishedMsg is included in the transcript, but not until after we
 | |
| 	// check the client version, since the state before this message was
 | |
| 	// sent is used during verification.
 | |
| 	msg, err := c.readHandshake(nil)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	finished, ok := msg.(*finishedMsg)
 | |
| 	if !ok {
 | |
| 		c.sendAlert(alertUnexpectedMessage)
 | |
| 		return unexpectedMessageError(finished, msg)
 | |
| 	}
 | |
| 
 | |
| 	expectedMAC := hs.suite.finishedHash(c.in.trafficSecret, hs.transcript)
 | |
| 	if !hmac.Equal(expectedMAC, finished.verifyData) {
 | |
| 		c.sendAlert(alertDecryptError)
 | |
| 		return errors.New("tls: invalid server finished hash")
 | |
| 	}
 | |
| 
 | |
| 	if err := transcriptMsg(finished, hs.transcript); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	// Derive secrets that take context through the server Finished.
 | |
| 
 | |
| 	hs.trafficSecret = hs.suite.deriveSecret(hs.masterSecret,
 | |
| 		clientApplicationTrafficLabel, hs.transcript)
 | |
| 	serverSecret := hs.suite.deriveSecret(hs.masterSecret,
 | |
| 		serverApplicationTrafficLabel, hs.transcript)
 | |
| 	c.in.setTrafficSecret(hs.suite, QUICEncryptionLevelApplication, serverSecret)
 | |
| 
 | |
| 	err = c.config.writeKeyLog(keyLogLabelClientTraffic, hs.hello.random, hs.trafficSecret)
 | |
| 	if err != nil {
 | |
| 		c.sendAlert(alertInternalError)
 | |
| 		return err
 | |
| 	}
 | |
| 	err = c.config.writeKeyLog(keyLogLabelServerTraffic, hs.hello.random, serverSecret)
 | |
| 	if err != nil {
 | |
| 		c.sendAlert(alertInternalError)
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	c.ekm = hs.suite.exportKeyingMaterial(hs.masterSecret, hs.transcript)
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func (hs *clientHandshakeStateTLS13) sendClientCertificate() error {
 | |
| 	c := hs.c
 | |
| 
 | |
| 	if hs.certReq == nil {
 | |
| 		return nil
 | |
| 	}
 | |
| 
 | |
| 	cert, err := c.getClientCertificate(toCertificateRequestInfo(&certificateRequestInfo{
 | |
| 		AcceptableCAs:    hs.certReq.certificateAuthorities,
 | |
| 		SignatureSchemes: hs.certReq.supportedSignatureAlgorithms,
 | |
| 		Version:          c.vers,
 | |
| 		ctx:              hs.ctx,
 | |
| 	}))
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	certMsg := new(certificateMsgTLS13)
 | |
| 
 | |
| 	certMsg.certificate = *cert
 | |
| 	certMsg.scts = hs.certReq.scts && len(cert.SignedCertificateTimestamps) > 0
 | |
| 	certMsg.ocspStapling = hs.certReq.ocspStapling && len(cert.OCSPStaple) > 0
 | |
| 
 | |
| 	if _, err := hs.c.writeHandshakeRecord(certMsg, hs.transcript); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	// If we sent an empty certificate message, skip the CertificateVerify.
 | |
| 	if len(cert.Certificate) == 0 {
 | |
| 		return nil
 | |
| 	}
 | |
| 
 | |
| 	certVerifyMsg := new(certificateVerifyMsg)
 | |
| 	certVerifyMsg.hasSignatureAlgorithm = true
 | |
| 
 | |
| 	certVerifyMsg.signatureAlgorithm, err = selectSignatureScheme(c.vers, cert, hs.certReq.supportedSignatureAlgorithms)
 | |
| 	if err != nil {
 | |
| 		// getClientCertificate returned a certificate incompatible with the
 | |
| 		// CertificateRequestInfo supported signature algorithms.
 | |
| 		c.sendAlert(alertHandshakeFailure)
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	sigType, sigHash, err := typeAndHashFromSignatureScheme(certVerifyMsg.signatureAlgorithm)
 | |
| 	if err != nil {
 | |
| 		return c.sendAlert(alertInternalError)
 | |
| 	}
 | |
| 
 | |
| 	signed := signedMessage(sigHash, clientSignatureContext, hs.transcript)
 | |
| 	signOpts := crypto.SignerOpts(sigHash)
 | |
| 	if sigType == signatureRSAPSS {
 | |
| 		signOpts = &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash, Hash: sigHash}
 | |
| 	}
 | |
| 	sig, err := cert.PrivateKey.(crypto.Signer).Sign(c.config.rand(), signed, signOpts)
 | |
| 	if err != nil {
 | |
| 		c.sendAlert(alertInternalError)
 | |
| 		return errors.New("tls: failed to sign handshake: " + err.Error())
 | |
| 	}
 | |
| 	certVerifyMsg.signature = sig
 | |
| 
 | |
| 	if _, err := hs.c.writeHandshakeRecord(certVerifyMsg, hs.transcript); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func (hs *clientHandshakeStateTLS13) sendClientFinished() error {
 | |
| 	c := hs.c
 | |
| 
 | |
| 	finished := &finishedMsg{
 | |
| 		verifyData: hs.suite.finishedHash(c.out.trafficSecret, hs.transcript),
 | |
| 	}
 | |
| 
 | |
| 	if _, err := hs.c.writeHandshakeRecord(finished, hs.transcript); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	c.out.setTrafficSecret(hs.suite, QUICEncryptionLevelApplication, hs.trafficSecret)
 | |
| 
 | |
| 	if !c.config.SessionTicketsDisabled && c.config.ClientSessionCache != nil {
 | |
| 		c.resumptionSecret = hs.suite.deriveSecret(hs.masterSecret,
 | |
| 			resumptionLabel, hs.transcript)
 | |
| 	}
 | |
| 
 | |
| 	if c.quic != nil {
 | |
| 		if c.hand.Len() != 0 {
 | |
| 			c.sendAlert(alertUnexpectedMessage)
 | |
| 		}
 | |
| 		c.quicSetWriteSecret(QUICEncryptionLevelApplication, hs.suite.id, hs.trafficSecret)
 | |
| 	}
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func (c *Conn) handleNewSessionTicket(msg *newSessionTicketMsgTLS13) error {
 | |
| 	if !c.isClient {
 | |
| 		c.sendAlert(alertUnexpectedMessage)
 | |
| 		return errors.New("tls: received new session ticket from a client")
 | |
| 	}
 | |
| 
 | |
| 	if c.config.SessionTicketsDisabled || c.config.ClientSessionCache == nil {
 | |
| 		return nil
 | |
| 	}
 | |
| 
 | |
| 	// See RFC 8446, Section 4.6.1.
 | |
| 	if msg.lifetime == 0 {
 | |
| 		return nil
 | |
| 	}
 | |
| 	lifetime := time.Duration(msg.lifetime) * time.Second
 | |
| 	if lifetime > maxSessionTicketLifetime {
 | |
| 		c.sendAlert(alertIllegalParameter)
 | |
| 		return errors.New("tls: received a session ticket with invalid lifetime")
 | |
| 	}
 | |
| 
 | |
| 	cipherSuite := cipherSuiteTLS13ByID(c.cipherSuite)
 | |
| 	if cipherSuite == nil || c.resumptionSecret == nil {
 | |
| 		return c.sendAlert(alertInternalError)
 | |
| 	}
 | |
| 
 | |
| 	// We need to save the max_early_data_size that the server sent us, in order
 | |
| 	// to decide if we're going to try 0-RTT with this ticket.
 | |
| 	// However, at the same time, the qtls.ClientSessionTicket needs to be equal to
 | |
| 	// the tls.ClientSessionTicket, so we can't just add a new field to the struct.
 | |
| 	// We therefore abuse the nonce field (which is a byte slice)
 | |
| 	nonceWithEarlyData := make([]byte, len(msg.nonce)+4)
 | |
| 	binary.BigEndian.PutUint32(nonceWithEarlyData, msg.maxEarlyData)
 | |
| 	copy(nonceWithEarlyData[4:], msg.nonce)
 | |
| 
 | |
| 	var appData []byte
 | |
| 	if c.extraConfig != nil && c.extraConfig.GetAppDataForSessionState != nil {
 | |
| 		appData = c.extraConfig.GetAppDataForSessionState()
 | |
| 	}
 | |
| 	var b cryptobyte.Builder
 | |
| 	b.AddUint16(clientSessionStateVersion) // revision
 | |
| 	b.AddUint32(msg.maxEarlyData)
 | |
| 	b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
 | |
| 		b.AddBytes(appData)
 | |
| 	})
 | |
| 	b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
 | |
| 		b.AddBytes(msg.nonce)
 | |
| 	})
 | |
| 
 | |
| 	// Save the resumption_master_secret and nonce instead of deriving the PSK
 | |
| 	// to do the least amount of work on NewSessionTicket messages before we
 | |
| 	// know if the ticket will be used. Forward secrecy of resumed connections
 | |
| 	// is guaranteed by the requirement for pskModeDHE.
 | |
| 	session := &clientSessionState{
 | |
| 		sessionTicket:      msg.label,
 | |
| 		vers:               c.vers,
 | |
| 		cipherSuite:        c.cipherSuite,
 | |
| 		masterSecret:       c.resumptionSecret,
 | |
| 		serverCertificates: c.peerCertificates,
 | |
| 		verifiedChains:     c.verifiedChains,
 | |
| 		receivedAt:         c.config.time(),
 | |
| 		nonce:              b.BytesOrPanic(),
 | |
| 		useBy:              c.config.time().Add(lifetime),
 | |
| 		ageAdd:             msg.ageAdd,
 | |
| 		ocspResponse:       c.ocspResponse,
 | |
| 		scts:               c.scts,
 | |
| 	}
 | |
| 
 | |
| 	cacheKey := c.clientSessionCacheKey()
 | |
| 	if cacheKey != "" {
 | |
| 		c.config.ClientSessionCache.Put(cacheKey, toClientSessionState(session))
 | |
| 	}
 | |
| 
 | |
| 	return nil
 | |
| }
 |