Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
74a1fe3
Update dependencies
yuhan6665 Dec 27, 2025
6eb40df
crypto/tls: enable signature algorithm BoGo tests (and fix two bugs)
yuhan6665 Jul 21, 2025
6fbc22b
crypto/tls: ensure the ECDSA curve matches the signature algorithm
yuhan6665 Jul 21, 2025
12f9576
crypto/tls: empty server_name conf. ext. from server
yuhan6665 Jul 21, 2025
cb7a27b
crypto/tls: use standard chacha20-poly1305 cipher suite names
yuhan6665 Dec 27, 2025
6acf96f
crypto/tls: check if quic conn can send session ticket
yuhan6665 Dec 27, 2025
29b712e
crypto/tls: fix quic comment typo
yuhan6665 Dec 27, 2025
228a68b
crypto/tls: use hash.Cloner
yuhan6665 Dec 27, 2025
2ea89d5
crypto/tls: use context.AfterFunc in handshakeContext
yuhan6665 Dec 27, 2025
40f44da
crypto: use clear built-in
yuhan6665 Dec 27, 2025
4768e21
all: fix typos
yuhan6665 Dec 27, 2025
1781a71
crypto/tls: quote protocols in ALPN error message
yuhan6665 Dec 27, 2025
5e48961
crypto/tls: rm marshalEncryptedClientHelloConfigList dead code
yuhan6665 Dec 27, 2025
6fd4632
all: replace calls to errors.As with errors.AsType
yuhan6665 Apr 13, 2026
7ed05c4
crypto/tls: add QUICErrorEvent
yuhan6665 Apr 13, 2026
f38aed0
crypto/internal/hpke: modularize API and support more ciphersuites
yuhan6665 Apr 17, 2026
41ff4ac
crypto/internal/hpke: separate KEM and PublicKey/PrivateKey interfaces
yuhan6665 Apr 17, 2026
5c9cdde
crypto/tls: use inner hello for earlyData when using QUIC and ECH
yuhan6665 Apr 17, 2026
5293cb2
crypto/tls: expose HelloRetryRequest state
yuhan6665 Apr 17, 2026
bac8a5d
crypto/ecdsa: clean up ECDSA parsing and serialization paths
yuhan6665 Apr 17, 2026
d56ce73
crypto/tls: add SecP256r1/SecP384r1MLKEM1024 hybrid post-quantum key …
yuhan6665 Apr 17, 2026
44de100
crypto/tls: support crypto.MessageSigner private keys
yuhan6665 May 10, 2026
5d1981e
all: fix some comment issues
yuhan6665 May 11, 2026
8d9d990
crypto/tls: reject trailing messages after client/server hello
yuhan6665 May 11, 2026
92d9abd
crypto/tls: add verifiedChains expiration checking during resumption
yuhan6665 May 11, 2026
b390b75
crypto/tls: check verifiedChains roots when resuming sessions
yuhan6665 May 11, 2026
27c0530
crypto/tls: document resumption behavior across Configs
yuhan6665 May 11, 2026
b5bad3e
crypto/tls: revalidate whole chain on resumption on Windows and macOS
yuhan6665 May 11, 2026
2ef7dae
crypto/tls: avoid data race when canceling a QUICConn's Context
yuhan6665 May 11, 2026
19cd0a4
crypto/tls: fix broken link in KeyLogWriter documentation
yuhan6665 May 11, 2026
7fd1dd1
crypto/tls: fix CurvePreferences comment
yuhan6665 May 11, 2026
3d31f9f
crypto/tls: avoid atLeastReader and associated allocations.
yuhan6665 May 11, 2026
d159fe8
crypto/tls: prevent deadlock when client sends multiple key update me…
yuhan6665 May 11, 2026
a8158d1
crypto/tls: fix ECH SNI encoded length
yuhan6665 May 11, 2026
6fcc239
crypto/tls: reject 0xFFFF AEAD ID in pickECHConfig
yuhan6665 May 11, 2026
511e9e8
crypto/tls: increase readFromUntil buffer size
yuhan6665 May 11, 2026
1af176f
crypto/tls: wrap ML-KEM hybrids in fips140.WithoutEnforcement
yuhan6665 May 11, 2026
c59b878
crypto/tls: skip unsupported ECH config versions
yuhan6665 May 11, 2026
a94cf40
src: spelling and grammar fixes
yuhan6665 May 11, 2026
00d4832
crypto/tls: add QUICConfig.ClientHelloInfoConn
yuhan6665 May 11, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
136 changes: 74 additions & 62 deletions auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,13 @@ import (
"slices"
)

// verifyHandshakeSignature verifies a signature against pre-hashed
// (if required) handshake contents.
// verifyHandshakeSignature verifies a signature against unhashed handshake contents.
func verifyHandshakeSignature(sigType uint8, pubkey crypto.PublicKey, hashFunc crypto.Hash, signed, sig []byte) error {
if hashFunc != directSigning {
h := hashFunc.New()
h.Write(signed)
signed = h.Sum(nil)
}
switch sigType {
case signatureECDSA:
pubKey, ok := pubkey.(*ecdsa.PublicKey)
Expand Down Expand Up @@ -61,6 +65,32 @@ func verifyHandshakeSignature(sigType uint8, pubkey crypto.PublicKey, hashFunc c
return nil
}

// verifyLegacyHandshakeSignature verifies a TLS 1.0 and 1.1 signature against
// pre-hashed handshake contents.
func verifyLegacyHandshakeSignature(sigType uint8, pubkey crypto.PublicKey, hashFunc crypto.Hash, hashed, sig []byte) error {
switch sigType {
case signatureECDSA:
pubKey, ok := pubkey.(*ecdsa.PublicKey)
if !ok {
return fmt.Errorf("expected an ECDSA public key, got %T", pubkey)
}
if !ecdsa.VerifyASN1(pubKey, hashed, sig) {
return errors.New("ECDSA verification failure")
}
case signaturePKCS1v15:
pubKey, ok := pubkey.(*rsa.PublicKey)
if !ok {
return fmt.Errorf("expected an RSA public key, got %T", pubkey)
}
if err := rsa.VerifyPKCS1v15(pubKey, hashFunc, hashed, sig); err != nil {
return err
}
default:
return errors.New("internal error: unknown signature type")
}
return nil
}

const (
serverSignatureContext = "TLS 1.3, server CertificateVerify\x00"
clientSignatureContext = "TLS 1.3, client CertificateVerify\x00"
Expand All @@ -77,21 +107,15 @@ var signaturePadding = []byte{
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
}

// signedMessage returns the pre-hashed (if necessary) message to be signed by
// certificate keys in TLS 1.3. See RFC 8446, Section 4.4.3.
func signedMessage(sigHash crypto.Hash, context string, transcript hash.Hash) []byte {
if sigHash == directSigning {
b := &bytes.Buffer{}
b.Write(signaturePadding)
io.WriteString(b, context)
b.Write(transcript.Sum(nil))
return b.Bytes()
}
h := sigHash.New()
h.Write(signaturePadding)
io.WriteString(h, context)
h.Write(transcript.Sum(nil))
return h.Sum(nil)
// signedMessage returns the (unhashed) message to be signed by certificate keys
// in TLS 1.3. See RFC 8446, Section 4.4.3.
func signedMessage(context string, transcript hash.Hash) []byte {
const maxSize = 64 /* signaturePadding */ + len(serverSignatureContext) + 512/8 /* SHA-512 */
b := bytes.NewBuffer(make([]byte, 0, maxSize))
b.Write(signaturePadding)
io.WriteString(b, context)
b.Write(transcript.Sum(nil))
return b.Bytes()
}

// typeAndHashFromSignatureScheme returns the corresponding signature type and
Expand Down Expand Up @@ -149,90 +173,78 @@ func legacyTypeAndHashFromPublicKey(pub crypto.PublicKey) (sigType uint8, hash c
var rsaSignatureSchemes = []struct {
scheme SignatureScheme
minModulusBytes int
maxVersion uint16
}{
// RSA-PSS is used with PSSSaltLengthEqualsHash, and requires
// emLen >= hLen + sLen + 2
{PSSWithSHA256, crypto.SHA256.Size()*2 + 2, VersionTLS13},
{PSSWithSHA384, crypto.SHA384.Size()*2 + 2, VersionTLS13},
{PSSWithSHA512, crypto.SHA512.Size()*2 + 2, VersionTLS13},
{PSSWithSHA256, crypto.SHA256.Size()*2 + 2},
{PSSWithSHA384, crypto.SHA384.Size()*2 + 2},
{PSSWithSHA512, crypto.SHA512.Size()*2 + 2},
// PKCS #1 v1.5 uses prefixes from hashPrefixes in crypto/rsa, and requires
// emLen >= len(prefix) + hLen + 11
// TLS 1.3 dropped support for PKCS #1 v1.5 in favor of RSA-PSS.
{PKCS1WithSHA256, 19 + crypto.SHA256.Size() + 11, VersionTLS12},
{PKCS1WithSHA384, 19 + crypto.SHA384.Size() + 11, VersionTLS12},
{PKCS1WithSHA512, 19 + crypto.SHA512.Size() + 11, VersionTLS12},
{PKCS1WithSHA1, 15 + crypto.SHA1.Size() + 11, VersionTLS12},
{PKCS1WithSHA256, 19 + crypto.SHA256.Size() + 11},
{PKCS1WithSHA384, 19 + crypto.SHA384.Size() + 11},
{PKCS1WithSHA512, 19 + crypto.SHA512.Size() + 11},
{PKCS1WithSHA1, 15 + crypto.SHA1.Size() + 11},
}

// signatureSchemesForCertificate returns the list of supported SignatureSchemes
// for a given certificate, based on the public key and the protocol version,
// and optionally filtered by its explicit SupportedSignatureAlgorithms.
func signatureSchemesForCertificate(version uint16, cert *Certificate) []SignatureScheme {
priv, ok := cert.PrivateKey.(crypto.Signer)
if !ok {
return nil
}

var sigAlgs []SignatureScheme
switch pub := priv.Public().(type) {
func signatureSchemesForPublicKey(version uint16, pub crypto.PublicKey) []SignatureScheme {
switch pub := pub.(type) {
case *ecdsa.PublicKey:
if version != VersionTLS13 {
if version < VersionTLS13 {
// In TLS 1.2 and earlier, ECDSA algorithms are not
// constrained to a single curve.
sigAlgs = []SignatureScheme{
return []SignatureScheme{
ECDSAWithP256AndSHA256,
ECDSAWithP384AndSHA384,
ECDSAWithP521AndSHA512,
ECDSAWithSHA1,
}
break
}
switch pub.Curve {
case elliptic.P256():
sigAlgs = []SignatureScheme{ECDSAWithP256AndSHA256}
return []SignatureScheme{ECDSAWithP256AndSHA256}
case elliptic.P384():
sigAlgs = []SignatureScheme{ECDSAWithP384AndSHA384}
return []SignatureScheme{ECDSAWithP384AndSHA384}
case elliptic.P521():
sigAlgs = []SignatureScheme{ECDSAWithP521AndSHA512}
return []SignatureScheme{ECDSAWithP521AndSHA512}
default:
return nil
}
case *rsa.PublicKey:
size := pub.Size()
sigAlgs = make([]SignatureScheme, 0, len(rsaSignatureSchemes))
sigAlgs := make([]SignatureScheme, 0, len(rsaSignatureSchemes))
for _, candidate := range rsaSignatureSchemes {
if size >= candidate.minModulusBytes && version <= candidate.maxVersion {
if size >= candidate.minModulusBytes {
sigAlgs = append(sigAlgs, candidate.scheme)
}
}
return sigAlgs
case ed25519.PublicKey:
sigAlgs = []SignatureScheme{Ed25519}
return []SignatureScheme{Ed25519}
default:
return nil
}

if cert.SupportedSignatureAlgorithms != nil {
sigAlgs = slices.DeleteFunc(sigAlgs, func(sigAlg SignatureScheme) bool {
return !isSupportedSignatureAlgorithm(sigAlg, cert.SupportedSignatureAlgorithms)
})
}

// Filter out any unsupported signature algorithms, for example due to
// FIPS 140-3 policy, tlssha1=0, or any downstream changes to defaults.go.
supportedAlgs := supportedSignatureAlgorithms(version)
sigAlgs = slices.DeleteFunc(sigAlgs, func(sigAlg SignatureScheme) bool {
return !isSupportedSignatureAlgorithm(sigAlg, supportedAlgs)
})

return sigAlgs
}

// selectSignatureScheme picks a SignatureScheme from the peer's preference list
// that works with the selected certificate. It's only called for protocol
// versions that support signature algorithms, so TLS 1.2 and 1.3.
func selectSignatureScheme(vers uint16, c *Certificate, peerAlgs []SignatureScheme) (SignatureScheme, error) {
supportedAlgs := signatureSchemesForCertificate(vers, c)
priv, ok := c.PrivateKey.(crypto.Signer)
if !ok {
return 0, unsupportedCertificateError(c)
}
supportedAlgs := signatureSchemesForPublicKey(vers, priv.Public())
if c.SupportedSignatureAlgorithms != nil {
supportedAlgs = slices.DeleteFunc(supportedAlgs, func(sigAlg SignatureScheme) bool {
return !isSupportedSignatureAlgorithm(sigAlg, c.SupportedSignatureAlgorithms)
})
}
// Filter out any unsupported signature algorithms, for example due to
// FIPS 140-3 policy, tlssha1=0, or protocol version.
supportedAlgs = slices.DeleteFunc(supportedAlgs, func(sigAlg SignatureScheme) bool {
return isDisabledSignatureAlgorithm(vers, sigAlg, false)
})
if len(supportedAlgs) == 0 {
return 0, unsupportedCertificateError(c)
}
Expand Down
8 changes: 4 additions & 4 deletions cipher_suites.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,8 @@ type cipherSuite struct {
}

var cipherSuites = []*cipherSuite{ // TODO: replace with a map, since the order doesn't matter.
{TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, 32, 0, 12, ecdheRSAKA, suiteECDHE | suiteTLS12, nil, nil, aeadChaCha20Poly1305},
{TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, 32, 0, 12, ecdheECDSAKA, suiteECDHE | suiteECSign | suiteTLS12, nil, nil, aeadChaCha20Poly1305},
{TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, 32, 0, 12, ecdheRSAKA, suiteECDHE | suiteTLS12, nil, nil, aeadChaCha20Poly1305},
{TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, 32, 0, 12, ecdheECDSAKA, suiteECDHE | suiteECSign | suiteTLS12, nil, nil, aeadChaCha20Poly1305},
{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, ecdheRSAKA, suiteECDHE | suiteTLS12, nil, nil, aeadAESGCM},
{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, ecdheECDSAKA, suiteECDHE | suiteECSign | suiteTLS12, nil, nil, aeadAESGCM},
{TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, ecdheRSAKA, suiteECDHE | suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM},
Expand Down Expand Up @@ -281,7 +281,7 @@ var cipherSuitesPreferenceOrder = []uint16{
// AEADs w/ ECDHE
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,

// CBC w/ ECDHE
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
Expand Down Expand Up @@ -310,7 +310,7 @@ var cipherSuitesPreferenceOrder = []uint16{

var cipherSuitesPreferenceOrderNoAES = []uint16{
// ChaCha20Poly1305
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,

// AES-GCM w/ ECDHE
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
Expand Down
Loading