Commit 2f1de159 authored by Adam Langley's avatar Adam Langley

crypto/x509: relax EKU checking in some cases.

CL 71030 enforced EKU nesting at verification time, to go along with the
change in name constraints behaviour. From scanning the Certificate
Transparency logs, it's clear that some CAs are not getting EKU nesting
correct.

This change relaxes the EKU rules in a few ways:
  ∙ EKUs in roots are no longer checked.
  ∙ Any CA certificate may issue OCSP responder certificates.
  ∙ The ServerAuth and SGC EKUs are treated as a single EKU when
    checking nesting.
  ∙ ServerAuth in a CA can now authorise ClientAuth.
  ∙ The generic CodeSigning EKU can now authorise two, Microsoft-specific
    code-signing EKUs.

Change-Id: I7b7ac787709af0dcd177fe419ec2e485b8d85540
Reviewed-on: https://go-review.googlesource.com/77330Reviewed-by: default avatarBrad Fitzpatrick <bradfitz@golang.org>
parent 5a22637c
...@@ -1282,9 +1282,7 @@ var nameConstraintsTests = []nameConstraintsTest{ ...@@ -1282,9 +1282,7 @@ var nameConstraintsTests = []nameConstraintsTest{
}, },
}, },
// #66: trying to add extra permitted key usages in an intermediate // #66: EKUs in roots are ignored.
// (after a limitation in the root) doesn't allow those usages in a
// leaf.
nameConstraintsTest{ nameConstraintsTest{
roots: []constraintsSpec{ roots: []constraintsSpec{
constraintsSpec{ constraintsSpec{
...@@ -1302,7 +1300,6 @@ var nameConstraintsTests = []nameConstraintsTest{ ...@@ -1302,7 +1300,6 @@ var nameConstraintsTests = []nameConstraintsTest{
sans: []string{"dns:example.com"}, sans: []string{"dns:example.com"},
ekus: []string{"serverAuth", "email"}, ekus: []string{"serverAuth", "email"},
}, },
expectedError: "EKU not permitted",
}, },
// #67: in order to support COMODO chains, SGC key usages permit // #67: in order to support COMODO chains, SGC key usages permit
......
...@@ -546,15 +546,32 @@ func (c *Certificate) checkNameConstraints(count *int, ...@@ -546,15 +546,32 @@ func (c *Certificate) checkNameConstraints(count *int,
// ekuPermittedBy returns true iff the given extended key usage is permitted by // ekuPermittedBy returns true iff the given extended key usage is permitted by
// the given EKU from a certificate. Normally, this would be a simple // the given EKU from a certificate. Normally, this would be a simple
// comparison plus a special case for the “any” EKU. But, in order to support // comparison plus a special case for the “any” EKU. But, in order to support
// COMODO chains, SGC EKUs permit generic server and client authentication // existing certificates, some exceptions are made.
// EKUs.
func ekuPermittedBy(eku, certEKU ExtKeyUsage) bool { func ekuPermittedBy(eku, certEKU ExtKeyUsage) bool {
if certEKU == ExtKeyUsageAny || eku == certEKU { if certEKU == ExtKeyUsageAny || eku == certEKU {
return true return true
} }
if (eku == ExtKeyUsageServerAuth || eku == ExtKeyUsageClientAuth) && // Some exceptions are made to support existing certificates. Firstly,
(certEKU == ExtKeyUsageNetscapeServerGatedCrypto || certEKU == ExtKeyUsageMicrosoftServerGatedCrypto) { // the ServerAuth and SGC EKUs are treated as a group.
mapServerAuthEKUs := func(eku ExtKeyUsage) ExtKeyUsage {
if eku == ExtKeyUsageNetscapeServerGatedCrypto || eku == ExtKeyUsageMicrosoftServerGatedCrypto {
return ExtKeyUsageServerAuth
}
return eku
}
eku = mapServerAuthEKUs(eku)
certEKU = mapServerAuthEKUs(certEKU)
if eku == certEKU ||
// ServerAuth in a CA permits ClientAuth in the leaf.
(eku == ExtKeyUsageClientAuth && certEKU == ExtKeyUsageServerAuth) ||
// Any CA may issue an OCSP responder certificate.
eku == ExtKeyUsageOCSPSigning ||
// Code-signing CAs can use Microsoft's commercial and
// kernel-mode EKUs.
((eku == ExtKeyUsageMicrosoftCommercialCodeSigning || eku == ExtKeyUsageMicrosoftKernelCodeSigning) && certEKU == ExtKeyUsageCodeSigning) {
return true return true
} }
...@@ -672,7 +689,7 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V ...@@ -672,7 +689,7 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V
} }
} }
checkEKUs := certType == intermediateCertificate || certType == rootCertificate checkEKUs := certType == intermediateCertificate
// If no extended key usages are specified, then all are acceptable. // If no extended key usages are specified, then all are acceptable.
if checkEKUs && (len(c.ExtKeyUsage) == 0 && len(c.UnknownExtKeyUsage) == 0) { if checkEKUs && (len(c.ExtKeyUsage) == 0 && len(c.UnknownExtKeyUsage) == 0) {
......
...@@ -553,18 +553,20 @@ const ( ...@@ -553,18 +553,20 @@ const (
// id-kp-timeStamping OBJECT IDENTIFIER ::= { id-kp 8 } // id-kp-timeStamping OBJECT IDENTIFIER ::= { id-kp 8 }
// id-kp-OCSPSigning OBJECT IDENTIFIER ::= { id-kp 9 } // id-kp-OCSPSigning OBJECT IDENTIFIER ::= { id-kp 9 }
var ( var (
oidExtKeyUsageAny = asn1.ObjectIdentifier{2, 5, 29, 37, 0} oidExtKeyUsageAny = asn1.ObjectIdentifier{2, 5, 29, 37, 0}
oidExtKeyUsageServerAuth = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 1} oidExtKeyUsageServerAuth = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 1}
oidExtKeyUsageClientAuth = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 2} oidExtKeyUsageClientAuth = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 2}
oidExtKeyUsageCodeSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 3} oidExtKeyUsageCodeSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 3}
oidExtKeyUsageEmailProtection = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 4} oidExtKeyUsageEmailProtection = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 4}
oidExtKeyUsageIPSECEndSystem = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 5} oidExtKeyUsageIPSECEndSystem = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 5}
oidExtKeyUsageIPSECTunnel = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 6} oidExtKeyUsageIPSECTunnel = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 6}
oidExtKeyUsageIPSECUser = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 7} oidExtKeyUsageIPSECUser = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 7}
oidExtKeyUsageTimeStamping = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 8} oidExtKeyUsageTimeStamping = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 8}
oidExtKeyUsageOCSPSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 9} oidExtKeyUsageOCSPSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 9}
oidExtKeyUsageMicrosoftServerGatedCrypto = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 10, 3, 3} oidExtKeyUsageMicrosoftServerGatedCrypto = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 10, 3, 3}
oidExtKeyUsageNetscapeServerGatedCrypto = asn1.ObjectIdentifier{2, 16, 840, 1, 113730, 4, 1} oidExtKeyUsageNetscapeServerGatedCrypto = asn1.ObjectIdentifier{2, 16, 840, 1, 113730, 4, 1}
oidExtKeyUsageMicrosoftCommercialCodeSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 2, 1, 22}
oidExtKeyUsageMicrosoftKernelCodeSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 61, 1, 1}
) )
// ExtKeyUsage represents an extended set of actions that are valid for a given key. // ExtKeyUsage represents an extended set of actions that are valid for a given key.
...@@ -584,6 +586,8 @@ const ( ...@@ -584,6 +586,8 @@ const (
ExtKeyUsageOCSPSigning ExtKeyUsageOCSPSigning
ExtKeyUsageMicrosoftServerGatedCrypto ExtKeyUsageMicrosoftServerGatedCrypto
ExtKeyUsageNetscapeServerGatedCrypto ExtKeyUsageNetscapeServerGatedCrypto
ExtKeyUsageMicrosoftCommercialCodeSigning
ExtKeyUsageMicrosoftKernelCodeSigning
) )
// extKeyUsageOIDs contains the mapping between an ExtKeyUsage and its OID. // extKeyUsageOIDs contains the mapping between an ExtKeyUsage and its OID.
...@@ -603,6 +607,8 @@ var extKeyUsageOIDs = []struct { ...@@ -603,6 +607,8 @@ var extKeyUsageOIDs = []struct {
{ExtKeyUsageOCSPSigning, oidExtKeyUsageOCSPSigning}, {ExtKeyUsageOCSPSigning, oidExtKeyUsageOCSPSigning},
{ExtKeyUsageMicrosoftServerGatedCrypto, oidExtKeyUsageMicrosoftServerGatedCrypto}, {ExtKeyUsageMicrosoftServerGatedCrypto, oidExtKeyUsageMicrosoftServerGatedCrypto},
{ExtKeyUsageNetscapeServerGatedCrypto, oidExtKeyUsageNetscapeServerGatedCrypto}, {ExtKeyUsageNetscapeServerGatedCrypto, oidExtKeyUsageNetscapeServerGatedCrypto},
{ExtKeyUsageMicrosoftCommercialCodeSigning, oidExtKeyUsageMicrosoftCommercialCodeSigning},
{ExtKeyUsageMicrosoftKernelCodeSigning, oidExtKeyUsageMicrosoftKernelCodeSigning},
} }
func extKeyUsageFromOID(oid asn1.ObjectIdentifier) (eku ExtKeyUsage, ok bool) { func extKeyUsageFromOID(oid asn1.ObjectIdentifier) (eku ExtKeyUsage, ok bool) {
......
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