yuhan6665
2026-09-20 21:57:26 +00:00
committed by RPRX
parent 8cdf7bf9c7
commit 9124ee149d
25 changed files with 1491 additions and 1118 deletions
+63 -18
View File
@@ -9,10 +9,10 @@ import (
"crypto"
"crypto/ecdsa"
"crypto/ed25519"
"crypto/mldsa"
"crypto/rsa"
"crypto/subtle"
"crypto/x509"
"encoding/binary"
"errors"
"fmt"
"hash"
@@ -189,7 +189,7 @@ func (c *Conn) readClientHello(ctx context.Context) (*clientHelloMsg, *echServer
} else if len(clientVersions) == 0 {
clientVersions = supportedVersionsFromMax(clientHello.vers)
}
c.vers, ok = c.config.mutualVersion(roleServer, clientVersions)
c.vers, ok = c.config.mutualVersion(roleServer, c.quic != nil, clientVersions)
if !ok {
c.sendAlert(alertProtocolVersion)
return nil, nil, fmt.Errorf("tls: client offered only unsupported versions: %x", clientVersions)
@@ -236,7 +236,7 @@ func (hs *serverHandshakeState) processClientHello() error {
hs.hello.random = make([]byte, 32)
serverRandom := hs.hello.random
// Downgrade protection canaries. See RFC 8446, Section 4.1.3.
maxVers := c.config.maxSupportedVersion(roleServer)
maxVers := c.config.maxSupportedVersion(roleServer, c.quic != nil)
if maxVers >= VersionTLS12 && c.vers < maxVers || testingOnlyForceDowngradeCanary {
if c.vers == VersionTLS12 {
copy(serverRandom[24:], downgradeCanaryTLS12)
@@ -280,6 +280,7 @@ func (hs *serverHandshakeState) processClientHello() error {
}
return err
}
if hs.clientHello.scts {
hs.hello.scts = hs.cert.SignedCertificateTimestamps
}
@@ -307,6 +308,11 @@ func (hs *serverHandshakeState) processClientHello() error {
hs.ecSignOk = true
case *rsa.PublicKey:
hs.rsaSignOk = true
case *mldsa.PublicKey:
// ML-DSA can only be used with TLS 1.3.
c.sendAlert(alertInternalError)
return fmt.Errorf("tls: ML-DSA certificates require TLS 1.3, but client negotiated %s",
VersionName(c.vers))
default:
c.sendAlert(alertInternalError)
return fmt.Errorf("tls: unsupported signing key type (%T)", priv.Public())
@@ -354,7 +360,7 @@ func negotiateALPN(serverProtos, clientProtos []string, quic bool) (string, erro
if http11fallback {
return "", nil
}
return "", fmt.Errorf("tls: client requested unsupported application protocols (%s)", clientProtos)
return "", fmt.Errorf("tls: client requested unsupported application protocols (%q)", clientProtos)
}
// supportsECDHE returns whether ECDHE key exchanges can be used with this
@@ -406,7 +412,7 @@ func (hs *serverHandshakeState) pickCipherSuite() error {
for _, id := range hs.clientHello.cipherSuites {
if id == TLS_FALLBACK_SCSV {
// The client is doing a fallback connection. See RFC 7507.
if hs.clientHello.vers < c.config.maxSupportedVersion(roleServer) {
if hs.clientHello.vers < c.config.maxSupportedVersion(roleServer, c.quic != nil) {
c.sendAlert(alertInappropriateFallback)
return errors.New("tls: client using inappropriate protocol fallback")
}
@@ -511,8 +517,13 @@ func (hs *serverHandshakeState) checkForResumption() error {
if sessionHasClientCerts && c.config.time().After(sessionState.peerCertificates[0].NotAfter) {
return nil
}
opts := x509.VerifyOptions{
CurrentTime: c.config.time(),
Roots: c.config.ClientCAs,
KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
}
if sessionHasClientCerts && c.config.ClientAuth >= VerifyClientCertIfGiven &&
len(sessionState.verifiedChains) == 0 {
!anyValidVerifiedChain(sessionState.verifiedChains, opts) {
return nil
}
@@ -582,6 +593,10 @@ func (hs *serverHandshakeState) doFullHandshake() error {
hs.hello.ocspStapling = true
}
if hs.clientHello.serverName != "" {
hs.hello.serverNameAck = true
}
hs.hello.ticketSupported = hs.clientHello.ticketSupported && !c.config.SessionTicketsDisabled
hs.hello.cipherSuite = hs.suite.id
@@ -600,6 +615,10 @@ func (hs *serverHandshakeState) doFullHandshake() error {
certMsg := new(certificateMsg)
certMsg.certificates = hs.cert.Certificate
// Set localCertificate here, rather than at certificate selection time, so
// that it is only populated when a certificate is actually presented to the
// peer, and not on resumed connections.
c.localCertificate = hs.cert.Certificate
if _, err := hs.c.writeHandshakeRecord(certMsg, &hs.finishedHash); err != nil {
return err
}
@@ -619,8 +638,9 @@ func (hs *serverHandshakeState) doFullHandshake() error {
return err
}
if skx != nil {
if len(skx.key) >= 3 && skx.key[0] == 3 /* named curve */ {
c.curveID = CurveID(binary.BigEndian.Uint16(skx.key[1:]))
if keyAgreement, ok := keyAgreement.(*ecdheKeyAgreement); ok {
c.curveID = keyAgreement.curveID
c.peerSigAlg = keyAgreement.signatureAlgorithm
}
if _, err := hs.c.writeHandshakeRecord(skx, &hs.finishedHash); err != nil {
return err
@@ -637,7 +657,7 @@ func (hs *serverHandshakeState) doFullHandshake() error {
}
if c.vers >= VersionTLS12 {
certReq.hasSignatureAlgorithm = true
certReq.supportedSignatureAlgorithms = supportedSignatureAlgorithms(c.vers)
certReq.supportedSignatureAlgorithms = supportedSignatureAlgorithms(c.vers, c.vers)
}
// An empty list of certificateAuthorities signals to
@@ -759,19 +779,28 @@ func (hs *serverHandshakeState) doFullHandshake() error {
if err != nil {
return c.sendAlert(alertInternalError)
}
if hs.finishedHash.buffer == nil {
c.sendAlert(alertInternalError)
return errors.New("tls: internal error: did not keep handshake transcript for TLS 1.2")
}
if err := verifyHandshakeSignature(sigType, pub, sigHash, hs.finishedHash.buffer, certVerify.signature); err != nil {
c.sendAlert(alertDecryptError)
return errors.New("tls: invalid signature by the client certificate: " + err.Error())
}
} else {
sigType, sigHash, err = legacyTypeAndHashFromPublicKey(pub)
if err != nil {
c.sendAlert(alertIllegalParameter)
return err
}
signed := hs.finishedHash.hashForClientCertificate(sigType)
if err := verifyLegacyHandshakeSignature(sigType, pub, sigHash, signed, certVerify.signature); err != nil {
c.sendAlert(alertDecryptError)
return errors.New("tls: invalid signature by the client certificate: " + err.Error())
}
}
signed := hs.finishedHash.hashForClientCertificate(sigType, sigHash)
if err := verifyHandshakeSignature(sigType, pub, sigHash, signed, certVerify.signature); err != nil {
c.sendAlert(alertDecryptError)
return errors.New("tls: invalid signature by the client certificate: " + err.Error())
}
c.peerSigAlg = certVerify.signatureAlgorithm
if err := transcriptMsg(certVerify, &hs.finishedHash); err != nil {
return err
@@ -943,10 +972,9 @@ func (c *Conn) processCertsFromClient(certificate Certificate) error {
chains, err := certs[0].Verify(opts)
if err != nil {
var errCertificateInvalid x509.CertificateInvalidError
if errors.As(err, &x509.UnknownAuthorityError{}) {
if _, ok := errors.AsType[x509.UnknownAuthorityError](err); ok {
c.sendAlert(alertUnknownCA)
} else if errors.As(err, &errCertificateInvalid) && errCertificateInvalid.Reason == x509.Expired {
} else if errCertificateInvalid, ok := errors.AsType[x509.CertificateInvalidError](err); ok && errCertificateInvalid.Reason == x509.Expired {
c.sendAlert(alertCertificateExpired)
} else {
c.sendAlert(alertBadCertificate)
@@ -966,8 +994,19 @@ func (c *Conn) processCertsFromClient(certificate Certificate) error {
c.scts = certificate.SignedCertificateTimestamps
if len(certs) > 0 {
if fips140tls.Required() && !isCertificateAllowedFIPS(certs[0]) {
c.sendAlert(alertBadCertificate)
err := errors.New("client's certificate is not allowed in FIPS 140-3 mode")
return &CertificateVerificationError{UnverifiedCertificates: certs, Err: err}
}
switch certs[0].PublicKey.(type) {
case *ecdsa.PublicKey, *rsa.PublicKey, ed25519.PublicKey:
case *mldsa.PublicKey:
if c.vers < VersionTLS13 {
c.sendAlert(alertIllegalParameter)
return errors.New("tls: client certificate uses ML-DSA, which requires TLS 1.3")
}
default:
c.sendAlert(alertUnsupportedCertificate)
return fmt.Errorf("tls: client certificate contains an unsupported public key of type %T", certs[0].PublicKey)
@@ -990,6 +1029,10 @@ func clientHelloInfo(ctx context.Context, c *Conn, clientHello *clientHelloMsg)
supportedVersions = supportedVersionsFromMax(clientHello.vers)
}
conn := c.conn
if c.quic != nil {
conn = c.quic.clientHelloInfoConn
}
return &ClientHelloInfo{
CipherSuites: clientHello.cipherSuites,
ServerName: clientHello.serverName,
@@ -999,8 +1042,10 @@ func clientHelloInfo(ctx context.Context, c *Conn, clientHello *clientHelloMsg)
SupportedProtos: clientHello.alpnProtocols,
SupportedVersions: supportedVersions,
Extensions: clientHello.extensions,
Conn: c.conn,
Conn: conn,
HelloRetryRequest: c.didHRR,
config: c.config,
isQUIC: c.quic != nil,
ctx: ctx,
}
}