mirror of
https://github.com/autc04/Retro68.git
synced 2024-09-08 20:55:01 +00:00
674 lines
19 KiB
Go
674 lines
19 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 tls
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"crypto"
|
||
|
"crypto/hmac"
|
||
|
"crypto/rsa"
|
||
|
"errors"
|
||
|
"hash"
|
||
|
"sync/atomic"
|
||
|
"time"
|
||
|
)
|
||
|
|
||
|
type clientHandshakeStateTLS13 struct {
|
||
|
c *Conn
|
||
|
serverHello *serverHelloMsg
|
||
|
hello *clientHelloMsg
|
||
|
ecdheParams ecdheParameters
|
||
|
|
||
|
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.ecdheParams, and,
|
||
|
// optionally, hs.session, hs.earlySecret and hs.binderKey to be set.
|
||
|
func (hs *clientHandshakeStateTLS13) handshake() error {
|
||
|
c := hs.c
|
||
|
|
||
|
// 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.ecdheParams == nil || len(hs.hello.keyShares) != 1 {
|
||
|
return c.sendAlert(alertInternalError)
|
||
|
}
|
||
|
|
||
|
if err := hs.checkServerHelloOrHRR(); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
hs.transcript = hs.suite.hash.New()
|
||
|
hs.transcript.Write(hs.hello.marshal())
|
||
|
|
||
|
if bytes.Equal(hs.serverHello.random, helloRetryRequestRandom) {
|
||
|
if err := hs.sendDummyChangeCipherSpec(); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
if err := hs.processHelloRetryRequest(); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
}
|
||
|
|
||
|
hs.transcript.Write(hs.serverHello.marshal())
|
||
|
|
||
|
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
|
||
|
}
|
||
|
|
||
|
atomic.StoreUint32(&c.handshakeStatus, 1)
|
||
|
|
||
|
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.nextProtoNeg ||
|
||
|
len(hs.serverHello.nextProtos) != 0 ||
|
||
|
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.sentDummyCCS {
|
||
|
return nil
|
||
|
}
|
||
|
hs.sentDummyCCS = true
|
||
|
|
||
|
_, err := hs.c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
// 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. 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)
|
||
|
hs.transcript.Write(hs.serverHello.marshal())
|
||
|
|
||
|
if hs.serverHello.serverShare.group != 0 {
|
||
|
c.sendAlert(alertDecodeError)
|
||
|
return errors.New("tls: received malformed key_share extension")
|
||
|
}
|
||
|
|
||
|
curveID := hs.serverHello.selectedGroup
|
||
|
if curveID == 0 {
|
||
|
c.sendAlert(alertMissingExtension)
|
||
|
return errors.New("tls: received HelloRetryRequest without selected group")
|
||
|
}
|
||
|
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 hs.ecdheParams.CurveID() == curveID {
|
||
|
c.sendAlert(alertIllegalParameter)
|
||
|
return errors.New("tls: server sent an unnecessary HelloRetryRequest message")
|
||
|
}
|
||
|
if _, ok := curveForCurveID(curveID); curveID != X25519 && !ok {
|
||
|
c.sendAlert(alertInternalError)
|
||
|
return errors.New("tls: CurvePreferences includes unsupported curve")
|
||
|
}
|
||
|
params, err := generateECDHEParameters(c.config.rand(), curveID)
|
||
|
if err != nil {
|
||
|
c.sendAlert(alertInternalError)
|
||
|
return err
|
||
|
}
|
||
|
hs.ecdheParams = params
|
||
|
hs.hello.keyShares = []keyShare{{group: curveID, data: params.PublicKey()}}
|
||
|
|
||
|
hs.hello.cookie = hs.serverHello.cookie
|
||
|
|
||
|
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)
|
||
|
transcript.Write(hs.serverHello.marshal())
|
||
|
transcript.Write(hs.hello.marshalWithoutBinders())
|
||
|
pskBinders := [][]byte{hs.suite.finishedHash(hs.binderKey, transcript)}
|
||
|
hs.hello.updateBinders(pskBinders)
|
||
|
} else {
|
||
|
// Server selected a cipher suite incompatible with the PSK.
|
||
|
hs.hello.pskIdentities = nil
|
||
|
hs.hello.pskBinders = nil
|
||
|
}
|
||
|
}
|
||
|
|
||
|
hs.transcript.Write(hs.hello.marshal())
|
||
|
if _, err := c.writeRecord(recordTypeHandshake, hs.hello.marshal()); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
msg, err := c.readHandshake()
|
||
|
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 hs.serverHello.serverShare.group != hs.ecdheParams.CurveID() {
|
||
|
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
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (hs *clientHandshakeStateTLS13) establishHandshakeKeys() error {
|
||
|
c := hs.c
|
||
|
|
||
|
sharedKey := hs.ecdheParams.SharedKey(hs.serverHello.serverShare.data)
|
||
|
if sharedKey == 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, clientSecret)
|
||
|
serverSecret := hs.suite.deriveSecret(handshakeSecret,
|
||
|
serverHandshakeTrafficLabel, hs.transcript)
|
||
|
c.in.setTrafficSecret(hs.suite, 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()
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
encryptedExtensions, ok := msg.(*encryptedExtensionsMsg)
|
||
|
if !ok {
|
||
|
c.sendAlert(alertUnexpectedMessage)
|
||
|
return unexpectedMessageError(encryptedExtensions, msg)
|
||
|
}
|
||
|
hs.transcript.Write(encryptedExtensions.marshal())
|
||
|
|
||
|
if len(encryptedExtensions.alpnProtocol) != 0 && len(hs.hello.alpnProtocols) == 0 {
|
||
|
c.sendAlert(alertUnsupportedExtension)
|
||
|
return errors.New("tls: server advertised unrequested ALPN extension")
|
||
|
}
|
||
|
c.clientProtocol = encryptedExtensions.alpnProtocol
|
||
|
|
||
|
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 {
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
msg, err := c.readHandshake()
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
certReq, ok := msg.(*certificateRequestMsgTLS13)
|
||
|
if ok {
|
||
|
hs.transcript.Write(certReq.marshal())
|
||
|
|
||
|
hs.certReq = certReq
|
||
|
|
||
|
msg, err = c.readHandshake()
|
||
|
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")
|
||
|
}
|
||
|
hs.transcript.Write(certMsg.marshal())
|
||
|
|
||
|
c.scts = certMsg.certificate.SignedCertificateTimestamps
|
||
|
c.ocspResponse = certMsg.certificate.OCSPStaple
|
||
|
|
||
|
if err := c.verifyServerCertificate(certMsg.certificate.Certificate); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
msg, err = c.readHandshake()
|
||
|
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: invalid certificate signature algorithm")
|
||
|
}
|
||
|
sigType := signatureFromSignatureScheme(certVerify.signatureAlgorithm)
|
||
|
sigHash, err := hashFromSignatureScheme(certVerify.signatureAlgorithm)
|
||
|
if sigType == 0 || err != nil {
|
||
|
c.sendAlert(alertInternalError)
|
||
|
return err
|
||
|
}
|
||
|
if sigType == signaturePKCS1v15 || sigHash == crypto.SHA1 {
|
||
|
c.sendAlert(alertIllegalParameter)
|
||
|
return errors.New("tls: invalid certificate signature algorithm")
|
||
|
}
|
||
|
h := sigHash.New()
|
||
|
writeSignedMessage(h, serverSignatureContext, hs.transcript)
|
||
|
if err := verifyHandshakeSignature(sigType, c.peerCertificates[0].PublicKey,
|
||
|
sigHash, h.Sum(nil), certVerify.signature); err != nil {
|
||
|
c.sendAlert(alertDecryptError)
|
||
|
return errors.New("tls: invalid certificate signature")
|
||
|
}
|
||
|
|
||
|
hs.transcript.Write(certVerify.marshal())
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (hs *clientHandshakeStateTLS13) readServerFinished() error {
|
||
|
c := hs.c
|
||
|
|
||
|
msg, err := c.readHandshake()
|
||
|
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")
|
||
|
}
|
||
|
|
||
|
hs.transcript.Write(finished.marshal())
|
||
|
|
||
|
// 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, 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(&CertificateRequestInfo{
|
||
|
AcceptableCAs: hs.certReq.certificateAuthorities,
|
||
|
SignatureSchemes: hs.certReq.supportedSignatureAlgorithms,
|
||
|
})
|
||
|
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
|
||
|
|
||
|
hs.transcript.Write(certMsg.marshal())
|
||
|
if _, err := c.writeRecord(recordTypeHandshake, certMsg.marshal()); 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
|
||
|
|
||
|
supportedAlgs := signatureSchemesForCertificate(c.vers, cert)
|
||
|
if supportedAlgs == nil {
|
||
|
c.sendAlert(alertInternalError)
|
||
|
return unsupportedCertificateError(cert)
|
||
|
}
|
||
|
// Pick signature scheme in server preference order, as the client
|
||
|
// preference order is not configurable.
|
||
|
for _, preferredAlg := range hs.certReq.supportedSignatureAlgorithms {
|
||
|
if isSupportedSignatureAlgorithm(preferredAlg, supportedAlgs) {
|
||
|
certVerifyMsg.signatureAlgorithm = preferredAlg
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
if certVerifyMsg.signatureAlgorithm == 0 {
|
||
|
// getClientCertificate returned a certificate incompatible with the
|
||
|
// CertificateRequestInfo supported signature algorithms.
|
||
|
c.sendAlert(alertHandshakeFailure)
|
||
|
return errors.New("tls: server doesn't support selected certificate")
|
||
|
}
|
||
|
|
||
|
sigType := signatureFromSignatureScheme(certVerifyMsg.signatureAlgorithm)
|
||
|
sigHash, err := hashFromSignatureScheme(certVerifyMsg.signatureAlgorithm)
|
||
|
if sigType == 0 || err != nil {
|
||
|
return c.sendAlert(alertInternalError)
|
||
|
}
|
||
|
h := sigHash.New()
|
||
|
writeSignedMessage(h, 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(), h.Sum(nil), signOpts)
|
||
|
if err != nil {
|
||
|
c.sendAlert(alertInternalError)
|
||
|
return errors.New("tls: failed to sign handshake: " + err.Error())
|
||
|
}
|
||
|
certVerifyMsg.signature = sig
|
||
|
|
||
|
hs.transcript.Write(certVerifyMsg.marshal())
|
||
|
if _, err := c.writeRecord(recordTypeHandshake, certVerifyMsg.marshal()); 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),
|
||
|
}
|
||
|
|
||
|
hs.transcript.Write(finished.marshal())
|
||
|
if _, err := c.writeRecord(recordTypeHandshake, finished.marshal()); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
c.out.setTrafficSecret(hs.suite, hs.trafficSecret)
|
||
|
|
||
|
if !c.config.SessionTicketsDisabled && c.config.ClientSessionCache != nil {
|
||
|
c.resumptionSecret = hs.suite.deriveSecret(hs.masterSecret,
|
||
|
resumptionLabel, hs.transcript)
|
||
|
}
|
||
|
|
||
|
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)
|
||
|
}
|
||
|
|
||
|
// 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: msg.nonce,
|
||
|
useBy: c.config.time().Add(lifetime),
|
||
|
ageAdd: msg.ageAdd,
|
||
|
}
|
||
|
|
||
|
cacheKey := clientSessionCacheKey(c.conn.RemoteAddr(), c.config)
|
||
|
c.config.ClientSessionCache.Put(cacheKey, session)
|
||
|
|
||
|
return nil
|
||
|
}
|