Skip to content

Commit cd18da4

Browse files
committed
crypto/tls: improve error messages for invalid certificates and signatures
Also, fix the alert value sent when a signature by a client certificate is invalid in TLS 1.0-1.2. Fixes #35190 Change-Id: I2ae1d5593dfd5ee2b4d979664aec74aab4a8a704 Reviewed-on: https://go-review.googlesource.com/c/go/+/204157 Reviewed-by: Katie Hockman <[email protected]>
1 parent a059346 commit cd18da4

File tree

9 files changed

+96
-90
lines changed

9 files changed

+96
-90
lines changed

src/crypto/tls/auth.go

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,10 @@ func pickSignatureAlgorithm(pubkey crypto.PublicKey, peerSigAlgs, ourSigAlgs []S
5757
if !isSupportedSignatureAlgorithm(sigAlg, ourSigAlgs) {
5858
continue
5959
}
60-
hashAlg, err := hashFromSignatureScheme(sigAlg)
60+
sigType, hashAlg, err := typeAndHashFromSignatureScheme(sigAlg)
6161
if err != nil {
62-
panic("tls: supported signature algorithm has an unknown hash function")
62+
return 0, 0, 0, fmt.Errorf("tls: internal error: %v", err)
6363
}
64-
sigType := signatureFromSignatureScheme(sigAlg)
6564
switch pubkey.(type) {
6665
case *rsa.PublicKey:
6766
if sigType == signaturePKCS1v15 || sigType == signatureRSAPSS {
@@ -89,45 +88,45 @@ func verifyHandshakeSignature(sigType uint8, pubkey crypto.PublicKey, hashFunc c
8988
case signatureECDSA:
9089
pubKey, ok := pubkey.(*ecdsa.PublicKey)
9190
if !ok {
92-
return errors.New("tls: ECDSA signing requires a ECDSA public key")
91+
return fmt.Errorf("expected an ECDSA public key, got %T", pubkey)
9392
}
9493
ecdsaSig := new(ecdsaSignature)
9594
if _, err := asn1.Unmarshal(sig, ecdsaSig); err != nil {
9695
return err
9796
}
9897
if ecdsaSig.R.Sign() <= 0 || ecdsaSig.S.Sign() <= 0 {
99-
return errors.New("tls: ECDSA signature contained zero or negative values")
98+
return errors.New("ECDSA signature contained zero or negative values")
10099
}
101100
if !ecdsa.Verify(pubKey, signed, ecdsaSig.R, ecdsaSig.S) {
102-
return errors.New("tls: ECDSA verification failure")
101+
return errors.New("ECDSA verification failure")
103102
}
104103
case signatureEd25519:
105104
pubKey, ok := pubkey.(ed25519.PublicKey)
106105
if !ok {
107-
return errors.New("tls: Ed25519 signing requires a Ed25519 public key")
106+
return fmt.Errorf("expected an Ed25519 public key, got %T", pubkey)
108107
}
109108
if !ed25519.Verify(pubKey, signed, sig) {
110-
return errors.New("tls: Ed25519 verification failure")
109+
return errors.New("Ed25519 verification failure")
111110
}
112111
case signaturePKCS1v15:
113112
pubKey, ok := pubkey.(*rsa.PublicKey)
114113
if !ok {
115-
return errors.New("tls: RSA signing requires a RSA public key")
114+
return fmt.Errorf("expected an RSA public key, got %T", pubkey)
116115
}
117116
if err := rsa.VerifyPKCS1v15(pubKey, hashFunc, signed, sig); err != nil {
118117
return err
119118
}
120119
case signatureRSAPSS:
121120
pubKey, ok := pubkey.(*rsa.PublicKey)
122121
if !ok {
123-
return errors.New("tls: RSA signing requires a RSA public key")
122+
return fmt.Errorf("expected an RSA public key, got %T", pubkey)
124123
}
125124
signOpts := &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash}
126125
if err := rsa.VerifyPSS(pubKey, hashFunc, signed, sig, signOpts); err != nil {
127126
return err
128127
}
129128
default:
130-
return errors.New("tls: unknown signature algorithm")
129+
return errors.New("internal error: unknown signature type")
131130
}
132131
return nil
133132
}

src/crypto/tls/common.go

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,38 @@ const (
339339
ECDSAWithSHA1 SignatureScheme = 0x0203
340340
)
341341

342+
// typeAndHashFromSignatureScheme returns the corresponding signature type and
343+
// crypto.Hash for a given TLS SignatureScheme.
344+
func typeAndHashFromSignatureScheme(signatureAlgorithm SignatureScheme) (sigType uint8, hash crypto.Hash, err error) {
345+
switch signatureAlgorithm {
346+
case PKCS1WithSHA1, PKCS1WithSHA256, PKCS1WithSHA384, PKCS1WithSHA512:
347+
sigType = signaturePKCS1v15
348+
case PSSWithSHA256, PSSWithSHA384, PSSWithSHA512:
349+
sigType = signatureRSAPSS
350+
case ECDSAWithSHA1, ECDSAWithP256AndSHA256, ECDSAWithP384AndSHA384, ECDSAWithP521AndSHA512:
351+
sigType = signatureECDSA
352+
case Ed25519:
353+
sigType = signatureEd25519
354+
default:
355+
return 0, 0, fmt.Errorf("unsupported signature algorithm: %#04x", signatureAlgorithm)
356+
}
357+
switch signatureAlgorithm {
358+
case PKCS1WithSHA1, ECDSAWithSHA1:
359+
hash = crypto.SHA1
360+
case PKCS1WithSHA256, PSSWithSHA256, ECDSAWithP256AndSHA256:
361+
hash = crypto.SHA256
362+
case PKCS1WithSHA384, PSSWithSHA384, ECDSAWithP384AndSHA384:
363+
hash = crypto.SHA384
364+
case PKCS1WithSHA512, PSSWithSHA512, ECDSAWithP521AndSHA512:
365+
hash = crypto.SHA512
366+
case Ed25519:
367+
hash = directSigning
368+
default:
369+
return 0, 0, fmt.Errorf("unsupported signature algorithm: %#04x", signatureAlgorithm)
370+
}
371+
return sigType, hash, nil
372+
}
373+
342374
// ClientHelloInfo contains information from a ClientHello message in order to
343375
// guide certificate selection in the GetCertificate callback.
344376
type ClientHelloInfo struct {
@@ -1151,20 +1183,3 @@ func isSupportedSignatureAlgorithm(sigAlg SignatureScheme, supportedSignatureAlg
11511183
}
11521184
return false
11531185
}
1154-
1155-
// signatureFromSignatureScheme maps a signature algorithm to the underlying
1156-
// signature method (without hash function).
1157-
func signatureFromSignatureScheme(signatureAlgorithm SignatureScheme) uint8 {
1158-
switch signatureAlgorithm {
1159-
case PKCS1WithSHA1, PKCS1WithSHA256, PKCS1WithSHA384, PKCS1WithSHA512:
1160-
return signaturePKCS1v15
1161-
case PSSWithSHA256, PSSWithSHA384, PSSWithSHA512:
1162-
return signatureRSAPSS
1163-
case ECDSAWithSHA1, ECDSAWithP256AndSHA256, ECDSAWithP384AndSHA384, ECDSAWithP521AndSHA512:
1164-
return signatureECDSA
1165-
case Ed25519:
1166-
return signatureEd25519
1167-
default:
1168-
return 0
1169-
}
1170-
}

src/crypto/tls/handshake_client.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -581,11 +581,7 @@ func (hs *clientHandshakeState) doFullHandshake() error {
581581
if certVerify.hasSignatureAlgorithm {
582582
certVerify.signatureAlgorithm = signatureAlgorithm
583583
}
584-
signed, err := hs.finishedHash.hashForClientCertificate(sigType, hashFunc, hs.masterSecret)
585-
if err != nil {
586-
c.sendAlert(alertInternalError)
587-
return err
588-
}
584+
signed := hs.finishedHash.hashForClientCertificate(sigType, hashFunc, hs.masterSecret)
589585
signOpts := crypto.SignerOpts(hashFunc)
590586
if sigType == signatureRSAPSS {
591587
signOpts = &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash, Hash: hashFunc}
@@ -878,7 +874,11 @@ func certificateRequestInfoFromMsg(certReq *certificateRequestMsg) *CertificateR
878874
// See RFC 5246, Section 7.4.4 (where it calls this "somewhat complicated").
879875
cri.SignatureSchemes = make([]SignatureScheme, 0, len(certReq.supportedSignatureAlgorithms))
880876
for _, sigScheme := range certReq.supportedSignatureAlgorithms {
881-
switch signatureFromSignatureScheme(sigScheme) {
877+
sigType, _, err := typeAndHashFromSignatureScheme(sigScheme)
878+
if err != nil {
879+
continue
880+
}
881+
switch sigType {
882882
case signatureECDSA, signatureEd25519:
883883
if ecAvail {
884884
cri.SignatureSchemes = append(cri.SignatureSchemes, sigScheme)

src/crypto/tls/handshake_client_tls13.go

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -448,23 +448,21 @@ func (hs *clientHandshakeStateTLS13) readServerCertificate() error {
448448
// See RFC 8446, Section 4.4.3.
449449
if !isSupportedSignatureAlgorithm(certVerify.signatureAlgorithm, supportedSignatureAlgorithms) {
450450
c.sendAlert(alertIllegalParameter)
451-
return errors.New("tls: invalid certificate signature algorithm")
451+
return errors.New("tls: certificate used with invalid signature algorithm")
452452
}
453-
sigType := signatureFromSignatureScheme(certVerify.signatureAlgorithm)
454-
sigHash, err := hashFromSignatureScheme(certVerify.signatureAlgorithm)
455-
if sigType == 0 || err != nil {
456-
c.sendAlert(alertInternalError)
457-
return err
453+
sigType, sigHash, err := typeAndHashFromSignatureScheme(certVerify.signatureAlgorithm)
454+
if err != nil {
455+
return c.sendAlert(alertInternalError)
458456
}
459457
if sigType == signaturePKCS1v15 || sigHash == crypto.SHA1 {
460458
c.sendAlert(alertIllegalParameter)
461-
return errors.New("tls: invalid certificate signature algorithm")
459+
return errors.New("tls: certificate used with invalid signature algorithm")
462460
}
463461
signed := signedMessage(sigHash, serverSignatureContext, hs.transcript)
464462
if err := verifyHandshakeSignature(sigType, c.peerCertificates[0].PublicKey,
465463
sigHash, signed, certVerify.signature); err != nil {
466464
c.sendAlert(alertDecryptError)
467-
return errors.New("tls: invalid certificate signature")
465+
return errors.New("tls: invalid signature by the server certificate: " + err.Error())
468466
}
469467

470468
hs.transcript.Write(certVerify.marshal())
@@ -572,9 +570,8 @@ func (hs *clientHandshakeStateTLS13) sendClientCertificate() error {
572570
return errors.New("tls: server doesn't support selected certificate")
573571
}
574572

575-
sigType := signatureFromSignatureScheme(certVerifyMsg.signatureAlgorithm)
576-
sigHash, err := hashFromSignatureScheme(certVerifyMsg.signatureAlgorithm)
577-
if sigType == 0 || err != nil {
573+
sigType, sigHash, err := typeAndHashFromSignatureScheme(certVerifyMsg.signatureAlgorithm)
574+
if err != nil {
578575
return c.sendAlert(alertInternalError)
579576
}
580577

src/crypto/tls/handshake_server.go

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -560,13 +560,10 @@ func (hs *serverHandshakeState) doFullHandshake() error {
560560
return err
561561
}
562562

563-
signed, err := hs.finishedHash.hashForClientCertificate(sigType, hashFunc, hs.masterSecret)
564-
if err == nil {
565-
err = verifyHandshakeSignature(sigType, pub, hashFunc, signed, certVerify.signature)
566-
}
567-
if err != nil {
568-
c.sendAlert(alertBadCertificate)
569-
return errors.New("tls: could not validate signature of connection nonces: " + err.Error())
563+
signed := hs.finishedHash.hashForClientCertificate(sigType, hashFunc, hs.masterSecret)
564+
if err := verifyHandshakeSignature(sigType, pub, hashFunc, signed, certVerify.signature); err != nil {
565+
c.sendAlert(alertDecryptError)
566+
return errors.New("tls: invalid signature by the client certificate: " + err.Error())
570567
}
571568

572569
hs.finishedHash.Write(certVerify.marshal())
@@ -717,7 +714,7 @@ func (c *Conn) processCertsFromClient(certificate Certificate) error {
717714
chains, err := certs[0].Verify(opts)
718715
if err != nil {
719716
c.sendAlert(alertBadCertificate)
720-
return errors.New("tls: failed to verify client's certificate: " + err.Error())
717+
return errors.New("tls: failed to verify client certificate: " + err.Error())
721718
}
722719

723720
c.verifiedChains = chains
@@ -738,7 +735,7 @@ func (c *Conn) processCertsFromClient(certificate Certificate) error {
738735
case *ecdsa.PublicKey, *rsa.PublicKey, ed25519.PublicKey:
739736
default:
740737
c.sendAlert(alertUnsupportedCertificate)
741-
return fmt.Errorf("tls: client's certificate contains an unsupported public key of type %T", certs[0].PublicKey)
738+
return fmt.Errorf("tls: client certificate contains an unsupported public key of type %T", certs[0].PublicKey)
742739
}
743740

744741
c.peerCertificates = certs

src/crypto/tls/handshake_server_tls13.go

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -620,9 +620,8 @@ func (hs *serverHandshakeStateTLS13) sendServerCertificate() error {
620620
certVerifyMsg.hasSignatureAlgorithm = true
621621
certVerifyMsg.signatureAlgorithm = hs.sigAlg
622622

623-
sigType := signatureFromSignatureScheme(hs.sigAlg)
624-
sigHash, err := hashFromSignatureScheme(hs.sigAlg)
625-
if sigType == 0 || err != nil {
623+
sigType, sigHash, err := typeAndHashFromSignatureScheme(hs.sigAlg)
624+
if err != nil {
626625
return c.sendAlert(alertInternalError)
627626
}
628627

@@ -801,23 +800,21 @@ func (hs *serverHandshakeStateTLS13) readClientCertificate() error {
801800
// See RFC 8446, Section 4.4.3.
802801
if !isSupportedSignatureAlgorithm(certVerify.signatureAlgorithm, supportedSignatureAlgorithms) {
803802
c.sendAlert(alertIllegalParameter)
804-
return errors.New("tls: invalid certificate signature algorithm")
803+
return errors.New("tls: client certificate used with invalid signature algorithm")
805804
}
806-
sigType := signatureFromSignatureScheme(certVerify.signatureAlgorithm)
807-
sigHash, err := hashFromSignatureScheme(certVerify.signatureAlgorithm)
808-
if sigType == 0 || err != nil {
809-
c.sendAlert(alertInternalError)
810-
return err
805+
sigType, sigHash, err := typeAndHashFromSignatureScheme(certVerify.signatureAlgorithm)
806+
if err != nil {
807+
return c.sendAlert(alertInternalError)
811808
}
812809
if sigType == signaturePKCS1v15 || sigHash == crypto.SHA1 {
813810
c.sendAlert(alertIllegalParameter)
814-
return errors.New("tls: invalid certificate signature algorithm")
811+
return errors.New("tls: client certificate used with invalid signature algorithm")
815812
}
816813
signed := signedMessage(sigHash, clientSignatureContext, hs.transcript)
817814
if err := verifyHandshakeSignature(sigType, c.peerCertificates[0].PublicKey,
818815
sigHash, signed, certVerify.signature); err != nil {
819816
c.sendAlert(alertDecryptError)
820-
return errors.New("tls: invalid certificate signature")
817+
return errors.New("tls: invalid signature by the client certificate: " + err.Error())
821818
}
822819

823820
hs.transcript.Write(certVerify.marshal())

src/crypto/tls/key_agreement.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,10 @@ func (ka *ecdheKeyAgreement) processServerKeyExchange(config *Config, clientHell
300300
sig = sig[2:]
301301

302302
signed := hashForServerKeyExchange(sigType, hashFunc, ka.version, clientHello.random, serverHello.random, serverECDHParams)
303-
return verifyHandshakeSignature(sigType, cert.PublicKey, hashFunc, signed, sig)
303+
if err := verifyHandshakeSignature(sigType, cert.PublicKey, hashFunc, signed, sig); err != nil {
304+
return errors.New("tls: invalid signature by the server certificate: " + err.Error())
305+
}
306+
return nil
304307
}
305308

306309
func (ka *ecdheKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error) {

src/crypto/tls/prf.go

Lines changed: 5 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -140,25 +140,6 @@ func keysFromMasterSecret(version uint16, suite *cipherSuite, masterSecret, clie
140140
return
141141
}
142142

143-
// hashFromSignatureScheme returns the corresponding crypto.Hash for a given
144-
// hash from a TLS SignatureScheme.
145-
func hashFromSignatureScheme(signatureAlgorithm SignatureScheme) (crypto.Hash, error) {
146-
switch signatureAlgorithm {
147-
case PKCS1WithSHA1, ECDSAWithSHA1:
148-
return crypto.SHA1, nil
149-
case PKCS1WithSHA256, PSSWithSHA256, ECDSAWithP256AndSHA256:
150-
return crypto.SHA256, nil
151-
case PKCS1WithSHA384, PSSWithSHA384, ECDSAWithP384AndSHA384:
152-
return crypto.SHA384, nil
153-
case PKCS1WithSHA512, PSSWithSHA512, ECDSAWithP521AndSHA512:
154-
return crypto.SHA512, nil
155-
case Ed25519:
156-
return directSigning, nil
157-
default:
158-
return 0, fmt.Errorf("tls: unsupported signature algorithm: %#04x", signatureAlgorithm)
159-
}
160-
}
161-
162143
func newFinishedHash(version uint16, cipherSuite *cipherSuite) finishedHash {
163144
var buffer []byte
164145
if version >= VersionTLS12 {
@@ -234,26 +215,26 @@ func (h finishedHash) serverSum(masterSecret []byte) []byte {
234215

235216
// hashForClientCertificate returns the handshake messages so far, pre-hashed if
236217
// necessary, suitable for signing by a TLS client certificate.
237-
func (h finishedHash) hashForClientCertificate(sigType uint8, hashAlg crypto.Hash, masterSecret []byte) ([]byte, error) {
218+
func (h finishedHash) hashForClientCertificate(sigType uint8, hashAlg crypto.Hash, masterSecret []byte) []byte {
238219
if (h.version >= VersionTLS12 || sigType == signatureEd25519) && h.buffer == nil {
239220
panic("tls: handshake hash for a client certificate requested after discarding the handshake buffer")
240221
}
241222

242223
if sigType == signatureEd25519 {
243-
return h.buffer, nil
224+
return h.buffer
244225
}
245226

246227
if h.version >= VersionTLS12 {
247228
hash := hashAlg.New()
248229
hash.Write(h.buffer)
249-
return hash.Sum(nil), nil
230+
return hash.Sum(nil)
250231
}
251232

252233
if sigType == signatureECDSA {
253-
return h.server.Sum(nil), nil
234+
return h.server.Sum(nil)
254235
}
255236

256-
return h.Sum(), nil
237+
return h.Sum()
257238
}
258239

259240
// discardHandshakeBuffer is called when there is no more need to

src/crypto/tls/tls_test.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1045,3 +1045,20 @@ func TestBuildNameToCertificate_doesntModifyCertificates(t *testing.T) {
10451045
}
10461046

10471047
func testingKey(s string) string { return strings.ReplaceAll(s, "TESTING KEY", "PRIVATE KEY") }
1048+
1049+
// TestSupportedSignatureAlgorithms checks that all supportedSignatureAlgorithms
1050+
// have valid type and hash information.
1051+
func TestSupportedSignatureAlgorithms(t *testing.T) {
1052+
for _, sigAlg := range supportedSignatureAlgorithms {
1053+
sigType, hash, err := typeAndHashFromSignatureScheme(sigAlg)
1054+
if err != nil {
1055+
t.Errorf("%#04x: unexpected error: %v", sigAlg, err)
1056+
}
1057+
if sigType == 0 {
1058+
t.Errorf("%#04x: missing signature type", sigAlg)
1059+
}
1060+
if hash == 0 && sigAlg != Ed25519 {
1061+
t.Errorf("%#04x: missing hash", sigAlg)
1062+
}
1063+
}
1064+
}

0 commit comments

Comments
 (0)