From: Adam Langley Date: Wed, 18 Dec 2013 15:57:56 +0000 (-0500) Subject: crypto/x509: set default signature hash to SHA256 and allow override. X-Git-Tag: go1.3beta1~1178 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=ca3ff9251dbe34edb539b661a30222d0f3d755bd;p=gostls13.git crypto/x509: set default signature hash to SHA256 and allow override. 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 --- diff --git a/src/pkg/crypto/x509/x509.go b/src/pkg/crypto/x509/x509.go index 4a5e7e86e5..3697db3299 100644 --- a/src/pkg/crypto/x509/x509.go +++ b/src/pkg/crypto/x509/x509.go @@ -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 } diff --git a/src/pkg/crypto/x509/x509_test.go b/src/pkg/crypto/x509/x509_test.go index f1097e992e..5ff6d958db 100644 --- a/src/pkg/crypto/x509/x509_test.go +++ b/src/pkg/crypto/x509/x509_test.go @@ -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) }