Commit c2317db2 authored by Adam Langley's avatar Adam Langley

crypto/x509: don't reject certs with critical policy extensions.

There was a missing continue that caused certificates with critical
certificate-policy extensions to be rejected. Additionally, that code
structure in general was prone to exactly that bug so I changed it
around to hopefully be more robust in the future.

Fixes #9964.

Change-Id: I58fc6ef3a84c1bd292a35b8b700f44ef312ec1c1
Reviewed-on: https://go-review.googlesource.com/5670Reviewed-by: 's avatarAndrew Gerrand <adg@golang.org>
parent d9859ad4
...@@ -891,47 +891,47 @@ func parseCertificate(in *certificate) (*Certificate, error) { ...@@ -891,47 +891,47 @@ func parseCertificate(in *certificate) (*Certificate, error) {
for _, e := range in.TBSCertificate.Extensions { for _, e := range in.TBSCertificate.Extensions {
out.Extensions = append(out.Extensions, e) out.Extensions = append(out.Extensions, e)
failIfCritical := false
if len(e.Id) == 4 && e.Id[0] == 2 && e.Id[1] == 5 && e.Id[2] == 29 { if len(e.Id) == 4 && e.Id[0] == 2 && e.Id[1] == 5 && e.Id[2] == 29 {
switch e.Id[3] { switch e.Id[3] {
case 15: case 15:
// RFC 5280, 4.2.1.3 // RFC 5280, 4.2.1.3
var usageBits asn1.BitString var usageBits asn1.BitString
_, err := asn1.Unmarshal(e.Value, &usageBits) if _, err := asn1.Unmarshal(e.Value, &usageBits); err != nil {
return nil, err
}
if err == nil { var usage int
var usage int for i := 0; i < 9; i++ {
for i := 0; i < 9; i++ { if usageBits.At(i) != 0 {
if usageBits.At(i) != 0 { usage |= 1 << uint(i)
usage |= 1 << uint(i)
}
} }
out.KeyUsage = KeyUsage(usage)
continue
} }
out.KeyUsage = KeyUsage(usage)
case 19: case 19:
// RFC 5280, 4.2.1.9 // RFC 5280, 4.2.1.9
var constraints basicConstraints var constraints basicConstraints
_, err := asn1.Unmarshal(e.Value, &constraints) if _, err := asn1.Unmarshal(e.Value, &constraints); err != nil {
return nil, err
if err == nil {
out.BasicConstraintsValid = true
out.IsCA = constraints.IsCA
out.MaxPathLen = constraints.MaxPathLen
out.MaxPathLenZero = out.MaxPathLen == 0
continue
} }
out.BasicConstraintsValid = true
out.IsCA = constraints.IsCA
out.MaxPathLen = constraints.MaxPathLen
out.MaxPathLenZero = out.MaxPathLen == 0
case 17: case 17:
out.DNSNames, out.EmailAddresses, out.IPAddresses, err = parseSANExtension(e.Value) out.DNSNames, out.EmailAddresses, out.IPAddresses, err = parseSANExtension(e.Value)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if len(out.DNSNames) > 0 || len(out.EmailAddresses) > 0 || len(out.IPAddresses) > 0 { if len(out.DNSNames) == 0 && len(out.EmailAddresses) == 0 && len(out.IPAddresses) == 0 {
continue // If we didn't parse anything then we do the critical check, below.
failIfCritical = true
} }
// If we didn't parse any of the names then we
// fall through to the critical check below.
case 30: case 30:
// RFC 5280, 4.2.1.10 // RFC 5280, 4.2.1.10
...@@ -950,8 +950,7 @@ func parseCertificate(in *certificate) (*Certificate, error) { ...@@ -950,8 +950,7 @@ func parseCertificate(in *certificate) (*Certificate, error) {
// BaseDistance ::= INTEGER (0..MAX) // BaseDistance ::= INTEGER (0..MAX)
var constraints nameConstraints var constraints nameConstraints
_, err := asn1.Unmarshal(e.Value, &constraints) if _, err := asn1.Unmarshal(e.Value, &constraints); err != nil {
if err != nil {
return nil, err return nil, err
} }
...@@ -968,7 +967,6 @@ func parseCertificate(in *certificate) (*Certificate, error) { ...@@ -968,7 +967,6 @@ func parseCertificate(in *certificate) (*Certificate, error) {
} }
out.PermittedDNSDomains = append(out.PermittedDNSDomains, subtree.Name) out.PermittedDNSDomains = append(out.PermittedDNSDomains, subtree.Name)
} }
continue
case 31: case 31:
// RFC 5280, 4.2.1.14 // RFC 5280, 4.2.1.14
...@@ -985,15 +983,13 @@ func parseCertificate(in *certificate) (*Certificate, error) { ...@@ -985,15 +983,13 @@ func parseCertificate(in *certificate) (*Certificate, error) {
// nameRelativeToCRLIssuer [1] RelativeDistinguishedName } // nameRelativeToCRLIssuer [1] RelativeDistinguishedName }
var cdp []distributionPoint var cdp []distributionPoint
_, err := asn1.Unmarshal(e.Value, &cdp) if _, err := asn1.Unmarshal(e.Value, &cdp); err != nil {
if err != nil {
return nil, err return nil, err
} }
for _, dp := range cdp { for _, dp := range cdp {
var n asn1.RawValue var n asn1.RawValue
_, err = asn1.Unmarshal(dp.DistributionPoint.FullName.Bytes, &n) if _, err = asn1.Unmarshal(dp.DistributionPoint.FullName.Bytes, &n); err != nil {
if err != nil {
return nil, err return nil, err
} }
...@@ -1001,17 +997,14 @@ func parseCertificate(in *certificate) (*Certificate, error) { ...@@ -1001,17 +997,14 @@ func parseCertificate(in *certificate) (*Certificate, error) {
out.CRLDistributionPoints = append(out.CRLDistributionPoints, string(n.Bytes)) out.CRLDistributionPoints = append(out.CRLDistributionPoints, string(n.Bytes))
} }
} }
continue
case 35: case 35:
// RFC 5280, 4.2.1.1 // RFC 5280, 4.2.1.1
var a authKeyId var a authKeyId
_, err = asn1.Unmarshal(e.Value, &a) if _, err = asn1.Unmarshal(e.Value, &a); err != nil {
if err != nil {
return nil, err return nil, err
} }
out.AuthorityKeyId = a.Id out.AuthorityKeyId = a.Id
continue
case 37: case 37:
// RFC 5280, 4.2.1.12. Extended Key Usage // RFC 5280, 4.2.1.12. Extended Key Usage
...@@ -1023,8 +1016,7 @@ func parseCertificate(in *certificate) (*Certificate, error) { ...@@ -1023,8 +1016,7 @@ func parseCertificate(in *certificate) (*Certificate, error) {
// KeyPurposeId ::= OBJECT IDENTIFIER // KeyPurposeId ::= OBJECT IDENTIFIER
var keyUsage []asn1.ObjectIdentifier var keyUsage []asn1.ObjectIdentifier
_, err = asn1.Unmarshal(e.Value, &keyUsage) if _, err = asn1.Unmarshal(e.Value, &keyUsage); err != nil {
if err != nil {
return nil, err return nil, err
} }
...@@ -1036,17 +1028,13 @@ func parseCertificate(in *certificate) (*Certificate, error) { ...@@ -1036,17 +1028,13 @@ func parseCertificate(in *certificate) (*Certificate, error) {
} }
} }
continue
case 14: case 14:
// RFC 5280, 4.2.1.2 // RFC 5280, 4.2.1.2
var keyid []byte var keyid []byte
_, err = asn1.Unmarshal(e.Value, &keyid) if _, err = asn1.Unmarshal(e.Value, &keyid); err != nil {
if err != nil {
return nil, err return nil, err
} }
out.SubjectKeyId = keyid out.SubjectKeyId = keyid
continue
case 32: case 32:
// RFC 5280 4.2.1.4: Certificate Policies // RFC 5280 4.2.1.4: Certificate Policies
...@@ -1058,6 +1046,10 @@ func parseCertificate(in *certificate) (*Certificate, error) { ...@@ -1058,6 +1046,10 @@ func parseCertificate(in *certificate) (*Certificate, error) {
for i, policy := range policies { for i, policy := range policies {
out.PolicyIdentifiers[i] = policy.Policy out.PolicyIdentifiers[i] = policy.Policy
} }
default:
// Unknown extensions cause an error if marked as critical.
failIfCritical = true
} }
} else if e.Id.Equal(oidExtensionAuthorityInfoAccess) { } else if e.Id.Equal(oidExtensionAuthorityInfoAccess) {
// RFC 5280 4.2.2.1: Authority Information Access // RFC 5280 4.2.2.1: Authority Information Access
...@@ -1077,9 +1069,12 @@ func parseCertificate(in *certificate) (*Certificate, error) { ...@@ -1077,9 +1069,12 @@ func parseCertificate(in *certificate) (*Certificate, error) {
out.IssuingCertificateURL = append(out.IssuingCertificateURL, string(v.Location.Bytes)) out.IssuingCertificateURL = append(out.IssuingCertificateURL, string(v.Location.Bytes))
} }
} }
} else {
// Unknown extensions cause an error if marked as critical.
failIfCritical = true
} }
if e.Critical { if e.Critical && failIfCritical {
return out, UnhandledCriticalExtension{} return out, UnhandledCriticalExtension{}
} }
} }
......
...@@ -480,6 +480,52 @@ func TestCreateSelfSignedCertificate(t *testing.T) { ...@@ -480,6 +480,52 @@ func TestCreateSelfSignedCertificate(t *testing.T) {
} }
} }
func TestUnknownCriticalExtension(t *testing.T) {
priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
t.Fatalf("Failed to generate ECDSA key: %s", err)
}
oids := []asn1.ObjectIdentifier{
// This OID is in the PKIX arc, but unknown.
asn1.ObjectIdentifier{2, 5, 29, 999999},
// This is a nonsense, unassigned OID.
asn1.ObjectIdentifier{1, 2, 3, 4},
}
for _, oid := range oids {
template := Certificate{
SerialNumber: big.NewInt(1),
Subject: pkix.Name{
CommonName: "foo",
},
NotBefore: time.Unix(1000, 0),
NotAfter: time.Unix(100000, 0),
ExtraExtensions: []pkix.Extension{
{
Id: oid,
Critical: true,
Value: nil,
},
},
}
derBytes, err := CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
if err != nil {
t.Fatalf("failed to create certificate: %s", err)
}
_, err = ParseCertificate(derBytes)
if err == nil {
t.Fatalf("Certificate with critical extension was parsed without error.")
}
if _, ok := err.(UnhandledCriticalExtension); !ok {
t.Fatalf("Error was %#v, but wanted one of type UnhandledCriticalExtension", err)
}
}
}
// Self-signed certificate using ECDSA with SHA1 & secp256r1 // Self-signed certificate using ECDSA with SHA1 & secp256r1
var ecdsaSHA1CertPem = ` var ecdsaSHA1CertPem = `
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
......
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