Commit ca3ff925 authored by Adam Langley's avatar Adam Langley

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
parent 4f234814
......@@ -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
}
......
......@@ -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)
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment