]> Cypherpunks repositories - gostls13.git/commitdiff
crypto/x509: cleanup signature generation
authorFilippo Valsorda <filippo@golang.org>
Thu, 16 May 2024 10:40:31 +0000 (12:40 +0200)
committerGopher Robot <gobot@golang.org>
Wed, 22 May 2024 09:20:15 +0000 (09:20 +0000)
Centralizing some repetitive code, which would have prevented #45990.

This also fixes the deprecated Certificate.CreateCRL for RSA-PSS, not
that anyone cared, probably.

This has two other minor observable behavior changes: MD2 is now treated
as a completely unknown algorithm (why did we even have that!? removing
lets us treat hash == 0 as always meaning no prehash); and we now do the
signature verification self-check for all signing operations.

Change-Id: I3b34fe0c3b6eb6181d2145b0704834225cd45a27
Reviewed-on: https://go-review.googlesource.com/c/go/+/586015
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Reviewed-by: Roland Shoemaker <roland@golang.org>
Auto-Submit: Filippo Valsorda <filippo@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>

doc/next/6-stdlib/99-minor/crypto/x509/45990.md [new file with mode: 0644]
src/crypto/x509/x509.go
src/crypto/x509/x509_test.go

diff --git a/doc/next/6-stdlib/99-minor/crypto/x509/45990.md b/doc/next/6-stdlib/99-minor/crypto/x509/45990.md
new file mode 100644 (file)
index 0000000..2eda847
--- /dev/null
@@ -0,0 +1,3 @@
+[CreateCertificateRequest] now correct supports RSA-PSS signature algorithms.
+
+[CreateCertificateRequest] and [CreateRevocationList] now verify the generated signature using the signer’s public key. If the signature is invalid, an error is returned. This has been the behavior of [CreateCertificate] since Go 1.16.
index 47bb4281102d42d0ed6739a2b2aac3ed70995c2f..50433058f74c3d8b8986b1677442bf1485090582 100644 (file)
@@ -233,12 +233,21 @@ const (
 )
 
 func (algo SignatureAlgorithm) isRSAPSS() bool {
-       switch algo {
-       case SHA256WithRSAPSS, SHA384WithRSAPSS, SHA512WithRSAPSS:
-               return true
-       default:
-               return false
+       for _, details := range signatureAlgorithmDetails {
+               if details.algo == algo {
+                       return details.isRSAPSS
+               }
        }
+       return false
+}
+
+func (algo SignatureAlgorithm) hashFunc() crypto.Hash {
+       for _, details := range signatureAlgorithmDetails {
+               if details.algo == algo {
+                       return details.hash
+               }
+       }
+       return crypto.Hash(0)
 }
 
 func (algo SignatureAlgorithm) String() string {
@@ -281,8 +290,6 @@ func (algo PublicKeyAlgorithm) String() string {
 //
 // RFC 3279 2.2.1 RSA Signature Algorithms
 //
-//     md2WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 2 }
-//
 //     md5WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 4 }
 //
 //     sha-1WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 5 }
@@ -325,7 +332,6 @@ func (algo PublicKeyAlgorithm) String() string {
 //
 //     id-Ed25519   OBJECT IDENTIFIER ::= { 1 3 101 112 }
 var (
-       oidSignatureMD2WithRSA      = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 2}
        oidSignatureMD5WithRSA      = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 4}
        oidSignatureSHA1WithRSA     = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 5}
        oidSignatureSHA256WithRSA   = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 11}
@@ -356,40 +362,43 @@ var signatureAlgorithmDetails = []struct {
        algo       SignatureAlgorithm
        name       string
        oid        asn1.ObjectIdentifier
+       params     asn1.RawValue
        pubKeyAlgo PublicKeyAlgorithm
        hash       crypto.Hash
+       isRSAPSS   bool
 }{
-       {MD2WithRSA, "MD2-RSA", oidSignatureMD2WithRSA, RSA, crypto.Hash(0) /* no value for MD2 */},
-       {MD5WithRSA, "MD5-RSA", oidSignatureMD5WithRSA, RSA, crypto.MD5},
-       {SHA1WithRSA, "SHA1-RSA", oidSignatureSHA1WithRSA, RSA, crypto.SHA1},
-       {SHA1WithRSA, "SHA1-RSA", oidISOSignatureSHA1WithRSA, RSA, crypto.SHA1},
-       {SHA256WithRSA, "SHA256-RSA", oidSignatureSHA256WithRSA, RSA, crypto.SHA256},
-       {SHA384WithRSA, "SHA384-RSA", oidSignatureSHA384WithRSA, RSA, crypto.SHA384},
-       {SHA512WithRSA, "SHA512-RSA", oidSignatureSHA512WithRSA, RSA, crypto.SHA512},
-       {SHA256WithRSAPSS, "SHA256-RSAPSS", oidSignatureRSAPSS, RSA, crypto.SHA256},
-       {SHA384WithRSAPSS, "SHA384-RSAPSS", oidSignatureRSAPSS, RSA, crypto.SHA384},
-       {SHA512WithRSAPSS, "SHA512-RSAPSS", oidSignatureRSAPSS, RSA, crypto.SHA512},
-       {DSAWithSHA1, "DSA-SHA1", oidSignatureDSAWithSHA1, DSA, crypto.SHA1},
-       {DSAWithSHA256, "DSA-SHA256", oidSignatureDSAWithSHA256, DSA, crypto.SHA256},
-       {ECDSAWithSHA1, "ECDSA-SHA1", oidSignatureECDSAWithSHA1, ECDSA, crypto.SHA1},
-       {ECDSAWithSHA256, "ECDSA-SHA256", oidSignatureECDSAWithSHA256, ECDSA, crypto.SHA256},
-       {ECDSAWithSHA384, "ECDSA-SHA384", oidSignatureECDSAWithSHA384, ECDSA, crypto.SHA384},
-       {ECDSAWithSHA512, "ECDSA-SHA512", oidSignatureECDSAWithSHA512, ECDSA, crypto.SHA512},
-       {PureEd25519, "Ed25519", oidSignatureEd25519, Ed25519, crypto.Hash(0) /* no pre-hashing */},
-}
-
-// hashToPSSParameters contains the DER encoded RSA PSS parameters for the
+       {MD5WithRSA, "MD5-RSA", oidSignatureMD5WithRSA, asn1.NullRawValue, RSA, crypto.MD5, false},
+       {SHA1WithRSA, "SHA1-RSA", oidSignatureSHA1WithRSA, asn1.NullRawValue, RSA, crypto.SHA1, false},
+       {SHA1WithRSA, "SHA1-RSA", oidISOSignatureSHA1WithRSA, asn1.NullRawValue, RSA, crypto.SHA1, false},
+       {SHA256WithRSA, "SHA256-RSA", oidSignatureSHA256WithRSA, asn1.NullRawValue, RSA, crypto.SHA256, false},
+       {SHA384WithRSA, "SHA384-RSA", oidSignatureSHA384WithRSA, asn1.NullRawValue, RSA, crypto.SHA384, false},
+       {SHA512WithRSA, "SHA512-RSA", oidSignatureSHA512WithRSA, asn1.NullRawValue, RSA, crypto.SHA512, false},
+       {SHA256WithRSAPSS, "SHA256-RSAPSS", oidSignatureRSAPSS, pssParametersSHA256, RSA, crypto.SHA256, true},
+       {SHA384WithRSAPSS, "SHA384-RSAPSS", oidSignatureRSAPSS, pssParametersSHA384, RSA, crypto.SHA384, true},
+       {SHA512WithRSAPSS, "SHA512-RSAPSS", oidSignatureRSAPSS, pssParametersSHA512, RSA, crypto.SHA512, true},
+       {DSAWithSHA1, "DSA-SHA1", oidSignatureDSAWithSHA1, emptyRawValue, DSA, crypto.SHA1, false},
+       {DSAWithSHA256, "DSA-SHA256", oidSignatureDSAWithSHA256, emptyRawValue, DSA, crypto.SHA256, false},
+       {ECDSAWithSHA1, "ECDSA-SHA1", oidSignatureECDSAWithSHA1, emptyRawValue, ECDSA, crypto.SHA1, false},
+       {ECDSAWithSHA256, "ECDSA-SHA256", oidSignatureECDSAWithSHA256, emptyRawValue, ECDSA, crypto.SHA256, false},
+       {ECDSAWithSHA384, "ECDSA-SHA384", oidSignatureECDSAWithSHA384, emptyRawValue, ECDSA, crypto.SHA384, false},
+       {ECDSAWithSHA512, "ECDSA-SHA512", oidSignatureECDSAWithSHA512, emptyRawValue, ECDSA, crypto.SHA512, false},
+       {PureEd25519, "Ed25519", oidSignatureEd25519, emptyRawValue, Ed25519, crypto.Hash(0) /* no pre-hashing */, false},
+}
+
+var emptyRawValue = asn1.RawValue{}
+
+// DER encoded RSA PSS parameters for the
 // SHA256, SHA384, and SHA512 hashes as defined in RFC 3447, Appendix A.2.3.
 // The parameters contain the following values:
 //   - hashAlgorithm contains the associated hash identifier with NULL parameters
 //   - maskGenAlgorithm always contains the default mgf1SHA1 identifier
 //   - saltLength contains the length of the associated hash
 //   - trailerField always contains the default trailerFieldBC value
-var hashToPSSParameters = map[crypto.Hash]asn1.RawValue{
-       crypto.SHA256: asn1.RawValue{FullBytes: []byte{48, 52, 160, 15, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 1, 5, 0, 161, 28, 48, 26, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 8, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 1, 5, 0, 162, 3, 2, 1, 32}},
-       crypto.SHA384: asn1.RawValue{FullBytes: []byte{48, 52, 160, 15, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 2, 5, 0, 161, 28, 48, 26, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 8, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 2, 5, 0, 162, 3, 2, 1, 48}},
-       crypto.SHA512: asn1.RawValue{FullBytes: []byte{48, 52, 160, 15, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 3, 5, 0, 161, 28, 48, 26, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 8, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 3, 5, 0, 162, 3, 2, 1, 64}},
-}
+var (
+       pssParametersSHA256 = asn1.RawValue{FullBytes: []byte{48, 52, 160, 15, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 1, 5, 0, 161, 28, 48, 26, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 8, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 1, 5, 0, 162, 3, 2, 1, 32}}
+       pssParametersSHA384 = asn1.RawValue{FullBytes: []byte{48, 52, 160, 15, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 2, 5, 0, 161, 28, 48, 26, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 8, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 2, 5, 0, 162, 3, 2, 1, 48}}
+       pssParametersSHA512 = asn1.RawValue{FullBytes: []byte{48, 52, 160, 15, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 3, 5, 0, 161, 28, 48, 26, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 8, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 3, 5, 0, 162, 3, 2, 1, 64}}
+)
 
 // pssParameters reflects the parameters in an AlgorithmIdentifier that
 // specifies RSA PSS. See RFC 3447, Appendix A.2.3.
@@ -1436,81 +1445,91 @@ func subjectBytes(cert *Certificate) ([]byte, error) {
        return asn1.Marshal(cert.Subject.ToRDNSequence())
 }
 
-// signingParamsForPublicKey returns the parameters to use for signing with
-// priv. If requestedSigAlgo is not zero then it overrides the default
-// signature algorithm.
-func signingParamsForPublicKey(pub any, requestedSigAlgo SignatureAlgorithm) (hashFunc crypto.Hash, sigAlgo pkix.AlgorithmIdentifier, err error) {
+// signingParamsForKey returns the signature algorithm and its Algorithm
+// Identifier to use for signing, based on the key type. If sigAlgo is not zero
+// then it overrides the default.
+func signingParamsForKey(key crypto.Signer, sigAlgo SignatureAlgorithm) (SignatureAlgorithm, pkix.AlgorithmIdentifier, error) {
+       var ai pkix.AlgorithmIdentifier
        var pubType PublicKeyAlgorithm
+       var defaultAlgo SignatureAlgorithm
 
-       switch pub := pub.(type) {
+       switch pub := key.Public().(type) {
        case *rsa.PublicKey:
                pubType = RSA
-               hashFunc = crypto.SHA256
-               sigAlgo.Algorithm = oidSignatureSHA256WithRSA
-               sigAlgo.Parameters = asn1.NullRawValue
+               defaultAlgo = SHA256WithRSA
 
        case *ecdsa.PublicKey:
                pubType = ECDSA
-
                switch pub.Curve {
                case elliptic.P224(), elliptic.P256():
-                       hashFunc = crypto.SHA256
-                       sigAlgo.Algorithm = oidSignatureECDSAWithSHA256
+                       defaultAlgo = ECDSAWithSHA256
                case elliptic.P384():
-                       hashFunc = crypto.SHA384
-                       sigAlgo.Algorithm = oidSignatureECDSAWithSHA384
+                       defaultAlgo = ECDSAWithSHA384
                case elliptic.P521():
-                       hashFunc = crypto.SHA512
-                       sigAlgo.Algorithm = oidSignatureECDSAWithSHA512
+                       defaultAlgo = ECDSAWithSHA512
                default:
-                       err = errors.New("x509: unknown elliptic curve")
+                       return 0, ai, errors.New("x509: unsupported elliptic curve")
                }
 
        case ed25519.PublicKey:
                pubType = Ed25519
-               sigAlgo.Algorithm = oidSignatureEd25519
+               defaultAlgo = PureEd25519
 
        default:
-               err = errors.New("x509: only RSA, ECDSA and Ed25519 keys supported")
+               return 0, ai, errors.New("x509: only RSA, ECDSA and Ed25519 keys supported")
        }
 
-       if err != nil {
-               return
-       }
-
-       if requestedSigAlgo == 0 {
-               return
+       if sigAlgo == 0 {
+               sigAlgo = defaultAlgo
        }
 
-       found := false
        for _, details := range signatureAlgorithmDetails {
-               if details.algo == requestedSigAlgo {
+               if details.algo == sigAlgo {
                        if details.pubKeyAlgo != pubType {
-                               err = errors.New("x509: requested SignatureAlgorithm does not match private key type")
-                               return
-                       }
-                       sigAlgo.Algorithm, hashFunc = details.oid, details.hash
-                       if hashFunc == 0 && pubType != Ed25519 {
-                               err = errors.New("x509: cannot sign with hash function requested")
-                               return
+                               return 0, ai, errors.New("x509: requested SignatureAlgorithm does not match private key type")
                        }
-                       if hashFunc == crypto.MD5 {
-                               err = errors.New("x509: signing with MD5 is not supported")
-                               return
+                       if details.hash == crypto.MD5 {
+                               return 0, ai, errors.New("x509: signing with MD5 is not supported")
                        }
-                       if requestedSigAlgo.isRSAPSS() {
-                               sigAlgo.Parameters = hashToPSSParameters[hashFunc]
-                       }
-                       found = true
-                       break
+
+                       return sigAlgo, pkix.AlgorithmIdentifier{
+                               Algorithm:  details.oid,
+                               Parameters: details.params,
+                       }, nil
                }
        }
 
-       if !found {
-               err = errors.New("x509: unknown SignatureAlgorithm")
+       return 0, ai, errors.New("x509: unknown SignatureAlgorithm")
+}
+
+func signTBS(tbs []byte, key crypto.Signer, sigAlg SignatureAlgorithm, rand io.Reader) ([]byte, error) {
+       signed := tbs
+       hashFunc := sigAlg.hashFunc()
+       if hashFunc != 0 {
+               h := hashFunc.New()
+               h.Write(signed)
+               signed = h.Sum(nil)
        }
 
-       return
+       var signerOpts crypto.SignerOpts = hashFunc
+       if sigAlg.isRSAPSS() {
+               signerOpts = &rsa.PSSOptions{
+                       SaltLength: rsa.PSSSaltLengthEqualsHash,
+                       Hash:       hashFunc,
+               }
+       }
+
+       signature, err := key.Sign(rand, signed, signerOpts)
+       if err != nil {
+               return nil, err
+       }
+
+       // Check the signature to ensure the crypto.Signer behaved correctly.
+       if err := checkSignature(sigAlg, tbs, signature, key.Public(), true); err != nil {
+               return nil, fmt.Errorf("x509: signature returned by signer is invalid: %w", err)
+       }
+
+       return signature, nil
 }
 
 // emptyASN1Subject is the ASN.1 DER encoding of an empty Subject, which is
@@ -1600,7 +1619,7 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv
                return nil, errors.New("x509: only CAs are allowed to specify MaxPathLen")
        }
 
-       hashFunc, signatureAlgorithm, err := signingParamsForPublicKey(key.Public(), template.SignatureAlgorithm)
+       signatureAlgorithm, algorithmIdentifier, err := signingParamsForKey(key, template.SignatureAlgorithm)
        if err != nil {
                return nil, err
        }
@@ -1657,7 +1676,7 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv
        c := tbsCertificate{
                Version:            2,
                SerialNumber:       template.SerialNumber,
-               SignatureAlgorithm: signatureAlgorithm,
+               SignatureAlgorithm: algorithmIdentifier,
                Issuer:             asn1.RawValue{FullBytes: asn1Issuer},
                Validity:           validity{template.NotBefore.UTC(), template.NotAfter.UTC()},
                Subject:            asn1.RawValue{FullBytes: asn1Subject},
@@ -1671,42 +1690,16 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv
        }
        c.Raw = tbsCertContents
 
-       signed := tbsCertContents
-       if hashFunc != 0 {
-               h := hashFunc.New()
-               h.Write(signed)
-               signed = h.Sum(nil)
-       }
-
-       var signerOpts crypto.SignerOpts = hashFunc
-       if template.SignatureAlgorithm != 0 && template.SignatureAlgorithm.isRSAPSS() {
-               signerOpts = &rsa.PSSOptions{
-                       SaltLength: rsa.PSSSaltLengthEqualsHash,
-                       Hash:       hashFunc,
-               }
-       }
-
-       var signature []byte
-       signature, err = key.Sign(rand, signed, signerOpts)
+       signature, err := signTBS(tbsCertContents, key, signatureAlgorithm, rand)
        if err != nil {
                return nil, err
        }
 
-       signedCert, err := asn1.Marshal(certificate{
-               c,
-               signatureAlgorithm,
-               asn1.BitString{Bytes: signature, BitLength: len(signature) * 8},
+       return asn1.Marshal(certificate{
+               TBSCertificate:     c,
+               SignatureAlgorithm: algorithmIdentifier,
+               SignatureValue:     asn1.BitString{Bytes: signature, BitLength: len(signature) * 8},
        })
-       if err != nil {
-               return nil, err
-       }
-
-       // Check the signature to ensure the crypto.Signer behaved correctly.
-       if err := checkSignature(getSignatureAlgorithmFromAI(signatureAlgorithm), c.Raw, signature, key.Public(), true); err != nil {
-               return nil, fmt.Errorf("x509: signature over certificate returned by signer is invalid: %w", err)
-       }
-
-       return signedCert, nil
 }
 
 // pemCRLPrefix is the magic string that indicates that we have a PEM encoded
@@ -1756,7 +1749,7 @@ func (c *Certificate) CreateCRL(rand io.Reader, priv any, revokedCerts []pkix.Re
                return nil, errors.New("x509: certificate private key does not implement crypto.Signer")
        }
 
-       hashFunc, signatureAlgorithm, err := signingParamsForPublicKey(key.Public(), 0)
+       signatureAlgorithm, algorithmIdentifier, err := signingParamsForKey(key, 0)
        if err != nil {
                return nil, err
        }
@@ -1770,7 +1763,7 @@ func (c *Certificate) CreateCRL(rand io.Reader, priv any, revokedCerts []pkix.Re
 
        tbsCertList := pkix.TBSCertificateList{
                Version:             1,
-               Signature:           signatureAlgorithm,
+               Signature:           algorithmIdentifier,
                Issuer:              c.Subject.ToRDNSequence(),
                ThisUpdate:          now.UTC(),
                NextUpdate:          expiry.UTC(),
@@ -1783,32 +1776,25 @@ func (c *Certificate) CreateCRL(rand io.Reader, priv any, revokedCerts []pkix.Re
                aki.Id = oidExtensionAuthorityKeyId
                aki.Value, err = asn1.Marshal(authKeyId{Id: c.SubjectKeyId})
                if err != nil {
-                       return
+                       return nil, err
                }
                tbsCertList.Extensions = append(tbsCertList.Extensions, aki)
        }
 
        tbsCertListContents, err := asn1.Marshal(tbsCertList)
        if err != nil {
-               return
-       }
-
-       signed := tbsCertListContents
-       if hashFunc != 0 {
-               h := hashFunc.New()
-               h.Write(signed)
-               signed = h.Sum(nil)
+               return nil, err
        }
+       tbsCertList.Raw = tbsCertListContents
 
-       var signature []byte
-       signature, err = key.Sign(rand, signed, hashFunc)
+       signature, err := signTBS(tbsCertListContents, key, signatureAlgorithm, rand)
        if err != nil {
-               return
+               return nil, err
        }
 
        return asn1.Marshal(pkix.CertificateList{
                TBSCertList:        tbsCertList,
-               SignatureAlgorithm: signatureAlgorithm,
+               SignatureAlgorithm: algorithmIdentifier,
                SignatureValue:     asn1.BitString{Bytes: signature, BitLength: len(signature) * 8},
        })
 }
@@ -1976,9 +1962,7 @@ func CreateCertificateRequest(rand io.Reader, template *CertificateRequest, priv
                return nil, errors.New("x509: certificate private key does not implement crypto.Signer")
        }
 
-       var hashFunc crypto.Hash
-       var sigAlgo pkix.AlgorithmIdentifier
-       hashFunc, sigAlgo, err = signingParamsForPublicKey(key.Public(), template.SignatureAlgorithm)
+       signatureAlgorithm, algorithmIdentifier, err := signingParamsForKey(key, template.SignatureAlgorithm)
        if err != nil {
                return nil, err
        }
@@ -2050,7 +2034,7 @@ func CreateCertificateRequest(rand io.Reader, template *CertificateRequest, priv
 
        rawAttributes, err := newRawAttributes(attributes)
        if err != nil {
-               return
+               return nil, err
        }
 
        // If not included in attributes, add a new attribute for the
@@ -2100,38 +2084,19 @@ func CreateCertificateRequest(rand io.Reader, template *CertificateRequest, priv
 
        tbsCSRContents, err := asn1.Marshal(tbsCSR)
        if err != nil {
-               return
+               return nil, err
        }
        tbsCSR.Raw = tbsCSRContents
 
-       signed := tbsCSRContents
-       if hashFunc != 0 {
-               h := hashFunc.New()
-               h.Write(signed)
-               signed = h.Sum(nil)
-       }
-
-       var signerOpts crypto.SignerOpts = hashFunc
-       if template.SignatureAlgorithm != 0 && template.SignatureAlgorithm.isRSAPSS() {
-               signerOpts = &rsa.PSSOptions{
-                       SaltLength: rsa.PSSSaltLengthEqualsHash,
-                       Hash:       hashFunc,
-               }
-       }
-
-       var signature []byte
-       signature, err = key.Sign(rand, signed, signerOpts)
+       signature, err := signTBS(tbsCSRContents, key, signatureAlgorithm, rand)
        if err != nil {
-               return
+               return nil, err
        }
 
        return asn1.Marshal(certificateRequest{
                TBSCSR:             tbsCSR,
-               SignatureAlgorithm: sigAlgo,
-               SignatureValue: asn1.BitString{
-                       Bytes:     signature,
-                       BitLength: len(signature) * 8,
-               },
+               SignatureAlgorithm: algorithmIdentifier,
+               SignatureValue:     asn1.BitString{Bytes: signature, BitLength: len(signature) * 8},
        })
 }
 
@@ -2359,7 +2324,7 @@ func CreateRevocationList(rand io.Reader, template *RevocationList, issuer *Cert
                return nil, errors.New("x509: template contains nil Number field")
        }
 
-       hashFunc, signatureAlgorithm, err := signingParamsForPublicKey(priv.Public(), template.SignatureAlgorithm)
+       signatureAlgorithm, algorithmIdentifier, err := signingParamsForKey(priv, template.SignatureAlgorithm)
        if err != nil {
                return nil, err
        }
@@ -2443,7 +2408,7 @@ func CreateRevocationList(rand io.Reader, template *RevocationList, issuer *Cert
 
        tbsCertList := tbsCertificateList{
                Version:    1, // v2
-               Signature:  signatureAlgorithm,
+               Signature:  algorithmIdentifier,
                Issuer:     asn1.RawValue{FullBytes: issuerSubject},
                ThisUpdate: template.ThisUpdate.UTC(),
                NextUpdate: template.NextUpdate.UTC(),
@@ -2475,28 +2440,14 @@ func CreateRevocationList(rand io.Reader, template *RevocationList, issuer *Cert
        // then embedding in certificateList below.
        tbsCertList.Raw = tbsCertListContents
 
-       input := tbsCertListContents
-       if hashFunc != 0 {
-               h := hashFunc.New()
-               h.Write(tbsCertListContents)
-               input = h.Sum(nil)
-       }
-       var signerOpts crypto.SignerOpts = hashFunc
-       if template.SignatureAlgorithm.isRSAPSS() {
-               signerOpts = &rsa.PSSOptions{
-                       SaltLength: rsa.PSSSaltLengthEqualsHash,
-                       Hash:       hashFunc,
-               }
-       }
-
-       signature, err := priv.Sign(rand, input, signerOpts)
+       signature, err := signTBS(tbsCertListContents, priv, signatureAlgorithm, rand)
        if err != nil {
                return nil, err
        }
 
        return asn1.Marshal(certificateList{
                TBSCertList:        tbsCertList,
-               SignatureAlgorithm: signatureAlgorithm,
+               SignatureAlgorithm: algorithmIdentifier,
                SignatureValue:     asn1.BitString{Bytes: signature, BitLength: len(signature) * 8},
        })
 }
index 026367b167624d7aaed0fc50733d5f07e96323e5..90c7ce9076b5a81ab5a5450642ed5345510a0142 100644 (file)
@@ -1301,11 +1301,13 @@ func TestCRLCreation(t *testing.T) {
                crlBytes, err := test.cert.CreateCRL(rand.Reader, test.priv, revokedCerts, now, expiry)
                if err != nil {
                        t.Errorf("%s: error creating CRL: %s", test.name, err)
+                       continue
                }
 
                parsedCRL, err := ParseDERCRL(crlBytes)
                if err != nil {
                        t.Errorf("%s: error reparsing CRL: %s", test.name, err)
+                       continue
                }
                if !reflect.DeepEqual(parsedCRL.TBSCertList.RevokedCertificates, expectedCerts) {
                        t.Errorf("%s: RevokedCertificates mismatch: got %v; want %v.", test.name,
@@ -1815,7 +1817,7 @@ func TestInsecureAlgorithmErrorString(t *testing.T) {
                {MD5WithRSA, "x509: cannot verify signature: insecure algorithm MD5-RSA"},
                {SHA1WithRSA, "x509: cannot verify signature: insecure algorithm SHA1-RSA (temporarily override with GODEBUG=x509sha1=1)"},
                {ECDSAWithSHA1, "x509: cannot verify signature: insecure algorithm ECDSA-SHA1 (temporarily override with GODEBUG=x509sha1=1)"},
-               {MD2WithRSA, "x509: cannot verify signature: insecure algorithm MD2-RSA"},
+               {MD2WithRSA, "x509: cannot verify signature: insecure algorithm 1"},
                {-1, "x509: cannot verify signature: insecure algorithm -1"},
                {0, "x509: cannot verify signature: insecure algorithm 0"},
                {9999, "x509: cannot verify signature: insecure algorithm 9999"},
@@ -2959,10 +2961,13 @@ func TestRSAPSAParameters(t *testing.T) {
                return serialized
        }
 
-       for h, params := range hashToPSSParameters {
-               generated := generateParams(h)
-               if !bytes.Equal(params.FullBytes, generated) {
-                       t.Errorf("hardcoded parameters for %s didn't match generated parameters: got (generated) %x, wanted (hardcoded) %x", h, generated, params.FullBytes)
+       for _, detail := range signatureAlgorithmDetails {
+               if !detail.isRSAPSS {
+                       continue
+               }
+               generated := generateParams(detail.hash)
+               if !bytes.Equal(detail.params.FullBytes, generated) {
+                       t.Errorf("hardcoded parameters for %s didn't match generated parameters: got (generated) %x, wanted (hardcoded) %x", detail.hash, generated, detail.params.FullBytes)
                }
        }
 }
@@ -3138,15 +3143,11 @@ func TestCreateCertificateBrokenSigner(t *testing.T) {
                SerialNumber: big.NewInt(10),
                DNSNames:     []string{"example.com"},
        }
-       k, err := rsa.GenerateKey(rand.Reader, 1024)
-       if err != nil {
-               t.Fatalf("failed to generate test key: %s", err)
-       }
-       expectedErr := "x509: signature over certificate returned by signer is invalid: crypto/rsa: verification error"
-       _, err = CreateCertificate(rand.Reader, template, template, k.Public(), &brokenSigner{k.Public()})
+       expectedErr := "signature returned by signer is invalid"
+       _, err := CreateCertificate(rand.Reader, template, template, testPrivateKey.Public(), &brokenSigner{testPrivateKey.Public()})
        if err == nil {
                t.Fatal("expected CreateCertificate to fail with a broken signer")
-       } else if err.Error() != expectedErr {
+       } else if !strings.Contains(err.Error(), expectedErr) {
                t.Fatalf("CreateCertificate returned an unexpected error: got %q, want %q", err, expectedErr)
        }
 }