]> Cypherpunks repositories - gostls13.git/commitdiff
crypto/x509: set default signature hash to SHA256 and allow override.
authorAdam Langley <agl@golang.org>
Wed, 18 Dec 2013 15:57:56 +0000 (10:57 -0500)
committerAdam Langley <agl@golang.org>
Wed, 18 Dec 2013 15:57:56 +0000 (10:57 -0500)
Previously the hash used when signing an X.509 certificate was fixed
and, for RSA, it was fixed to SHA1. Since Microsoft have announced the
deprecation of SHA1 in X.509 certificates, this change switches the
default to SHA256.

It also allows the hash function to be controlled by the caller by
setting the SignatureAlgorithm field of the template.

[1] http://blogs.technet.com/b/pki/archive/2013/11/12/sha1-deprecation-policy.aspx

Fixes #5302.

R=golang-dev, bradfitz
CC=golang-dev
https://golang.org/cl/40720047

src/pkg/crypto/x509/x509.go
src/pkg/crypto/x509/x509_test.go

index 4a5e7e86e5d4090bf1a9a251871202fd334368f3..3697db32991e0f87487531dc98506fba1ced3ede 100644 (file)
@@ -241,32 +241,31 @@ var (
        oidSignatureECDSAWithSHA512 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 4}
 )
 
+var signatureAlgorithmDetails = []struct {
+       algo       SignatureAlgorithm
+       oid        asn1.ObjectIdentifier
+       pubKeyAlgo PublicKeyAlgorithm
+       hash       crypto.Hash
+}{
+       {MD2WithRSA, oidSignatureMD2WithRSA, RSA, crypto.Hash(0) /* no value for MD2 */},
+       {MD5WithRSA, oidSignatureMD5WithRSA, RSA, crypto.MD5},
+       {SHA1WithRSA, oidSignatureSHA1WithRSA, RSA, crypto.SHA1},
+       {SHA256WithRSA, oidSignatureSHA256WithRSA, RSA, crypto.SHA256},
+       {SHA384WithRSA, oidSignatureSHA384WithRSA, RSA, crypto.SHA384},
+       {SHA512WithRSA, oidSignatureSHA512WithRSA, RSA, crypto.SHA512},
+       {DSAWithSHA1, oidSignatureDSAWithSHA1, DSA, crypto.SHA1},
+       {DSAWithSHA256, oidSignatureDSAWithSHA256, DSA, crypto.SHA256},
+       {ECDSAWithSHA1, oidSignatureECDSAWithSHA1, ECDSA, crypto.SHA1},
+       {ECDSAWithSHA256, oidSignatureECDSAWithSHA256, ECDSA, crypto.SHA256},
+       {ECDSAWithSHA384, oidSignatureECDSAWithSHA384, ECDSA, crypto.SHA384},
+       {ECDSAWithSHA512, oidSignatureECDSAWithSHA512, ECDSA, crypto.SHA512},
+}
+
 func getSignatureAlgorithmFromOID(oid asn1.ObjectIdentifier) SignatureAlgorithm {
-       switch {
-       case oid.Equal(oidSignatureMD2WithRSA):
-               return MD2WithRSA
-       case oid.Equal(oidSignatureMD5WithRSA):
-               return MD5WithRSA
-       case oid.Equal(oidSignatureSHA1WithRSA):
-               return SHA1WithRSA
-       case oid.Equal(oidSignatureSHA256WithRSA):
-               return SHA256WithRSA
-       case oid.Equal(oidSignatureSHA384WithRSA):
-               return SHA384WithRSA
-       case oid.Equal(oidSignatureSHA512WithRSA):
-               return SHA512WithRSA
-       case oid.Equal(oidSignatureDSAWithSHA1):
-               return DSAWithSHA1
-       case oid.Equal(oidSignatureDSAWithSHA256):
-               return DSAWithSHA256
-       case oid.Equal(oidSignatureECDSAWithSHA1):
-               return ECDSAWithSHA1
-       case oid.Equal(oidSignatureECDSAWithSHA256):
-               return ECDSAWithSHA256
-       case oid.Equal(oidSignatureECDSAWithSHA384):
-               return ECDSAWithSHA384
-       case oid.Equal(oidSignatureECDSAWithSHA512):
-               return ECDSAWithSHA512
+       for _, details := range signatureAlgorithmDetails {
+               if oid.Equal(details.oid) {
+                       return details.algo
+               }
        }
        return UnknownSignatureAlgorithm
 }
@@ -1346,7 +1345,7 @@ func subjectBytes(cert *Certificate) ([]byte, error) {
 // following members of template are used: SerialNumber, Subject, NotBefore,
 // NotAfter, KeyUsage, ExtKeyUsage, UnknownExtKeyUsage, BasicConstraintsValid,
 // IsCA, MaxPathLen, SubjectKeyId, DNSNames, PermittedDNSDomainsCritical,
-// PermittedDNSDomains.
+// PermittedDNSDomains, SignatureAlgorithm.
 //
 // The certificate is signed by parent. If parent is equal to template then the
 // certificate is self-signed. The parameter pub is the public key of the
@@ -1366,12 +1365,16 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub interf
 
        var signatureAlgorithm pkix.AlgorithmIdentifier
        var hashFunc crypto.Hash
+       var privType PublicKeyAlgorithm
 
        switch priv := priv.(type) {
        case *rsa.PrivateKey:
-               signatureAlgorithm.Algorithm = oidSignatureSHA1WithRSA
-               hashFunc = crypto.SHA1
+               privType = RSA
+               signatureAlgorithm.Algorithm = oidSignatureSHA256WithRSA
+               hashFunc = crypto.SHA256
        case *ecdsa.PrivateKey:
+               privType = ECDSA
+
                switch priv.Curve {
                case elliptic.P224(), elliptic.P256():
                        hashFunc = crypto.SHA256
@@ -1389,6 +1392,26 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub interf
                return nil, errors.New("x509: only RSA and ECDSA private keys supported")
        }
 
+       if template.SignatureAlgorithm != 0 {
+               found := false
+               for _, details := range signatureAlgorithmDetails {
+                       if details.algo == template.SignatureAlgorithm {
+                               if details.pubKeyAlgo != privType {
+                                       return nil, errors.New("x509: requested SignatureAlgorithm does not match private key type")
+                               }
+                               signatureAlgorithm.Algorithm, hashFunc = details.oid, details.hash
+                               if hashFunc == 0 {
+                                       return nil, errors.New("x509: cannot sign with hash function requested")
+                               }
+                               found = true
+                               break
+                       }
+               }
+               if !found {
+                       return nil, errors.New("x509: unknown SignatureAlgorithm")
+               }
+       }
+
        if err != nil {
                return
        }
index f1097e992e706dab810404c8c38aabf87f917957..5ff6d958dbaf5566fe5d0c21e0a8d7d4da6f1c6c 100644 (file)
@@ -305,11 +305,12 @@ func TestCreateSelfSignedCertificate(t *testing.T) {
                name      string
                pub, priv interface{}
                checkSig  bool
+               sigAlgo   SignatureAlgorithm
        }{
-               {"RSA/RSA", &rsaPriv.PublicKey, rsaPriv, true},
-               {"RSA/ECDSA", &rsaPriv.PublicKey, ecdsaPriv, false},
-               {"ECDSA/RSA", &ecdsaPriv.PublicKey, rsaPriv, false},
-               {"ECDSA/ECDSA", &ecdsaPriv.PublicKey, ecdsaPriv, true},
+               {"RSA/RSA", &rsaPriv.PublicKey, rsaPriv, true, SHA1WithRSA},
+               {"RSA/ECDSA", &rsaPriv.PublicKey, ecdsaPriv, false, ECDSAWithSHA384},
+               {"ECDSA/RSA", &ecdsaPriv.PublicKey, rsaPriv, false, SHA256WithRSA},
+               {"ECDSA/ECDSA", &ecdsaPriv.PublicKey, ecdsaPriv, true, ECDSAWithSHA1},
        }
 
        testExtKeyUsage := []ExtKeyUsage{ExtKeyUsageClientAuth, ExtKeyUsageServerAuth}
@@ -327,6 +328,8 @@ func TestCreateSelfSignedCertificate(t *testing.T) {
                        NotBefore: time.Unix(1000, 0),
                        NotAfter:  time.Unix(100000, 0),
 
+                       SignatureAlgorithm: test.sigAlgo,
+
                        SubjectKeyId: []byte{1, 2, 3, 4},
                        KeyUsage:     KeyUsageCertSign,
 
@@ -390,6 +393,10 @@ func TestCreateSelfSignedCertificate(t *testing.T) {
                        t.Errorf("%s: issuer wasn't correctly copied from the template. Got %s, want %s", test.name, cert.Issuer.CommonName, commonName)
                }
 
+               if cert.SignatureAlgorithm != test.sigAlgo {
+                       t.Errorf("%s: SignatureAlgorithm wasn't copied from template. Got %s, want %s", test.name, cert.SignatureAlgorithm, test.sigAlgo)
+               }
+
                if !reflect.DeepEqual(cert.ExtKeyUsage, testExtKeyUsage) {
                        t.Errorf("%s: extkeyusage wasn't correctly copied from the template. Got %v, want %v", test.name, cert.ExtKeyUsage, testExtKeyUsage)
                }