aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdam Langley <agl@golang.org>2018-02-22 12:30:44 -0800
committerAndrew Bonventre <andybons@golang.org>2018-03-29 06:07:20 +0000
commitfe0d248f29e5f0c95fd90be8c457586230809ce4 (patch)
treece8c3e1eae077387baaf87afcd1403e002885c90
parentb3398f8fa8233279eb343f4c478eb9ea6524ecdd (diff)
downloadgo-fe0d248f29e5f0c95fd90be8c457586230809ce4.tar.gz
go-fe0d248f29e5f0c95fd90be8c457586230809ce4.zip
[release-branch.go1.10] crypto/x509: tighten EKU checking for requested EKUs.
There are, sadly, many exceptions to EKU checking to reflect mistakes that CAs have made in practice. However, the requirements for checking requested EKUs against the leaf should be tighter than for checking leaf EKUs against a CA. Fixes #23884 Change-Id: I05ea874c4ada0696d8bb18cac4377c0b398fcb5e Reviewed-on: https://go-review.googlesource.com/96379 Reviewed-by: Jonathan Rudenberg <jonathan@titanous.com> Reviewed-by: Filippo Valsorda <hi@filippo.io> Run-TryBot: Filippo Valsorda <hi@filippo.io> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-on: https://go-review.googlesource.com/102780 Run-TryBot: Andrew Bonventre <andybons@golang.org> Reviewed-by: Filippo Valsorda <filippo@golang.org>
-rw-r--r--src/crypto/x509/name_constraints_test.go39
-rw-r--r--src/crypto/x509/verify.go32
2 files changed, 60 insertions, 11 deletions
diff --git a/src/crypto/x509/name_constraints_test.go b/src/crypto/x509/name_constraints_test.go
index 10cc348357..1474159203 100644
--- a/src/crypto/x509/name_constraints_test.go
+++ b/src/crypto/x509/name_constraints_test.go
@@ -42,6 +42,7 @@ type nameConstraintsTest struct {
roots []constraintsSpec
intermediates [][]constraintsSpec
leaf leafSpec
+ requestedEKUs []ExtKeyUsage
expectedError string
noOpenSSL bool
}
@@ -1444,6 +1445,43 @@ var nameConstraintsTests = []nameConstraintsTest{
},
expectedError: "\"https://example.com/test\" is excluded",
},
+
+ // #75: While serverAuth in a CA certificate permits clientAuth in a leaf,
+ // serverAuth in a leaf shouldn't permit clientAuth when requested in
+ // VerifyOptions.
+ nameConstraintsTest{
+ roots: []constraintsSpec{
+ constraintsSpec{},
+ },
+ intermediates: [][]constraintsSpec{
+ []constraintsSpec{
+ constraintsSpec{},
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"dns:example.com"},
+ ekus: []string{"serverAuth"},
+ },
+ requestedEKUs: []ExtKeyUsage{ExtKeyUsageClientAuth},
+ expectedError: "incompatible key usage",
+ },
+
+ // #76: However, MSSGC in a leaf should match a request for serverAuth.
+ nameConstraintsTest{
+ roots: []constraintsSpec{
+ constraintsSpec{},
+ },
+ intermediates: [][]constraintsSpec{
+ []constraintsSpec{
+ constraintsSpec{},
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"dns:example.com"},
+ ekus: []string{"msSGC"},
+ },
+ requestedEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth},
+ },
}
func makeConstraintsCACert(constraints constraintsSpec, name string, key *ecdsa.PrivateKey, parent *Certificate, parentKey *ecdsa.PrivateKey) (*Certificate, error) {
@@ -1781,6 +1819,7 @@ func TestConstraintCases(t *testing.T) {
Roots: rootPool,
Intermediates: intermediatePool,
CurrentTime: time.Unix(1500, 0),
+ KeyUsages: test.requestedEKUs,
}
_, err = leafCert.Verify(verifyOpts)
diff --git a/src/crypto/x509/verify.go b/src/crypto/x509/verify.go
index 9477e85b95..cd6156c69f 100644
--- a/src/crypto/x509/verify.go
+++ b/src/crypto/x509/verify.go
@@ -543,11 +543,16 @@ func (c *Certificate) checkNameConstraints(count *int,
return nil
}
+const (
+ checkingAgainstIssuerCert = iota
+ checkingAgainstLeafCert
+)
+
// ekuPermittedBy returns true iff the given extended key usage is permitted by
// 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
// existing certificates, some exceptions are made.
-func ekuPermittedBy(eku, certEKU ExtKeyUsage) bool {
+func ekuPermittedBy(eku, certEKU ExtKeyUsage, context int) bool {
if certEKU == ExtKeyUsageAny || eku == certEKU {
return true
}
@@ -564,18 +569,23 @@ func ekuPermittedBy(eku, certEKU ExtKeyUsage) bool {
eku = mapServerAuthEKUs(eku)
certEKU = mapServerAuthEKUs(certEKU)
- if eku == certEKU ||
- // ServerAuth in a CA permits ClientAuth in the leaf.
- (eku == ExtKeyUsageClientAuth && certEKU == ExtKeyUsageServerAuth) ||
+ if eku == certEKU {
+ return true
+ }
+
+ // If checking a requested EKU against the list in a leaf certificate there
+ // are fewer exceptions.
+ if context == checkingAgainstLeafCert {
+ return false
+ }
+
+ // ServerAuth in a CA permits ClientAuth in the leaf.
+ return (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 false
+ (eku == ExtKeyUsageMicrosoftCommercialCodeSigning || eku == ExtKeyUsageMicrosoftKernelCodeSigning) && certEKU == ExtKeyUsageCodeSigning
}
// isValid performs validity checks on c given that it is a candidate to append
@@ -716,7 +726,7 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V
for _, caEKU := range c.ExtKeyUsage {
comparisonCount++
- if ekuPermittedBy(eku, caEKU) {
+ if ekuPermittedBy(eku, caEKU, checkingAgainstIssuerCert) {
continue NextEKU
}
}
@@ -850,7 +860,7 @@ func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err e
NextUsage:
for _, eku := range requestedKeyUsages {
for _, leafEKU := range c.ExtKeyUsage {
- if ekuPermittedBy(eku, leafEKU) {
+ if ekuPermittedBy(eku, leafEKU, checkingAgainstLeafCert) {
continue NextUsage
}
}