Skip to content

Commit fe0d248

Browse files
aglandybons
authored andcommitted
[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 <[email protected]> Reviewed-by: Filippo Valsorda <[email protected]> Run-TryBot: Filippo Valsorda <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-on: https://go-review.googlesource.com/102780 Run-TryBot: Andrew Bonventre <[email protected]> Reviewed-by: Filippo Valsorda <[email protected]>
1 parent b3398f8 commit fe0d248

File tree

2 files changed

+60
-11
lines changed

2 files changed

+60
-11
lines changed

src/crypto/x509/name_constraints_test.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ type nameConstraintsTest struct {
4242
roots []constraintsSpec
4343
intermediates [][]constraintsSpec
4444
leaf leafSpec
45+
requestedEKUs []ExtKeyUsage
4546
expectedError string
4647
noOpenSSL bool
4748
}
@@ -1444,6 +1445,43 @@ var nameConstraintsTests = []nameConstraintsTest{
14441445
},
14451446
expectedError: "\"https://example.com/test\" is excluded",
14461447
},
1448+
1449+
// #75: While serverAuth in a CA certificate permits clientAuth in a leaf,
1450+
// serverAuth in a leaf shouldn't permit clientAuth when requested in
1451+
// VerifyOptions.
1452+
nameConstraintsTest{
1453+
roots: []constraintsSpec{
1454+
constraintsSpec{},
1455+
},
1456+
intermediates: [][]constraintsSpec{
1457+
[]constraintsSpec{
1458+
constraintsSpec{},
1459+
},
1460+
},
1461+
leaf: leafSpec{
1462+
sans: []string{"dns:example.com"},
1463+
ekus: []string{"serverAuth"},
1464+
},
1465+
requestedEKUs: []ExtKeyUsage{ExtKeyUsageClientAuth},
1466+
expectedError: "incompatible key usage",
1467+
},
1468+
1469+
// #76: However, MSSGC in a leaf should match a request for serverAuth.
1470+
nameConstraintsTest{
1471+
roots: []constraintsSpec{
1472+
constraintsSpec{},
1473+
},
1474+
intermediates: [][]constraintsSpec{
1475+
[]constraintsSpec{
1476+
constraintsSpec{},
1477+
},
1478+
},
1479+
leaf: leafSpec{
1480+
sans: []string{"dns:example.com"},
1481+
ekus: []string{"msSGC"},
1482+
},
1483+
requestedEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth},
1484+
},
14471485
}
14481486

14491487
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) {
17811819
Roots: rootPool,
17821820
Intermediates: intermediatePool,
17831821
CurrentTime: time.Unix(1500, 0),
1822+
KeyUsages: test.requestedEKUs,
17841823
}
17851824
_, err = leafCert.Verify(verifyOpts)
17861825

src/crypto/x509/verify.go

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -543,11 +543,16 @@ func (c *Certificate) checkNameConstraints(count *int,
543543
return nil
544544
}
545545

546+
const (
547+
checkingAgainstIssuerCert = iota
548+
checkingAgainstLeafCert
549+
)
550+
546551
// ekuPermittedBy returns true iff the given extended key usage is permitted by
547552
// the given EKU from a certificate. Normally, this would be a simple
548553
// comparison plus a special case for the “any” EKU. But, in order to support
549554
// existing certificates, some exceptions are made.
550-
func ekuPermittedBy(eku, certEKU ExtKeyUsage) bool {
555+
func ekuPermittedBy(eku, certEKU ExtKeyUsage, context int) bool {
551556
if certEKU == ExtKeyUsageAny || eku == certEKU {
552557
return true
553558
}
@@ -564,18 +569,23 @@ func ekuPermittedBy(eku, certEKU ExtKeyUsage) bool {
564569
eku = mapServerAuthEKUs(eku)
565570
certEKU = mapServerAuthEKUs(certEKU)
566571

567-
if eku == certEKU ||
568-
// ServerAuth in a CA permits ClientAuth in the leaf.
569-
(eku == ExtKeyUsageClientAuth && certEKU == ExtKeyUsageServerAuth) ||
572+
if eku == certEKU {
573+
return true
574+
}
575+
576+
// If checking a requested EKU against the list in a leaf certificate there
577+
// are fewer exceptions.
578+
if context == checkingAgainstLeafCert {
579+
return false
580+
}
581+
582+
// ServerAuth in a CA permits ClientAuth in the leaf.
583+
return (eku == ExtKeyUsageClientAuth && certEKU == ExtKeyUsageServerAuth) ||
570584
// Any CA may issue an OCSP responder certificate.
571585
eku == ExtKeyUsageOCSPSigning ||
572586
// Code-signing CAs can use Microsoft's commercial and
573587
// kernel-mode EKUs.
574-
((eku == ExtKeyUsageMicrosoftCommercialCodeSigning || eku == ExtKeyUsageMicrosoftKernelCodeSigning) && certEKU == ExtKeyUsageCodeSigning) {
575-
return true
576-
}
577-
578-
return false
588+
(eku == ExtKeyUsageMicrosoftCommercialCodeSigning || eku == ExtKeyUsageMicrosoftKernelCodeSigning) && certEKU == ExtKeyUsageCodeSigning
579589
}
580590

581591
// 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
716726

717727
for _, caEKU := range c.ExtKeyUsage {
718728
comparisonCount++
719-
if ekuPermittedBy(eku, caEKU) {
729+
if ekuPermittedBy(eku, caEKU, checkingAgainstIssuerCert) {
720730
continue NextEKU
721731
}
722732
}
@@ -850,7 +860,7 @@ func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err e
850860
NextUsage:
851861
for _, eku := range requestedKeyUsages {
852862
for _, leafEKU := range c.ExtKeyUsage {
853-
if ekuPermittedBy(eku, leafEKU) {
863+
if ekuPermittedBy(eku, leafEKU, checkingAgainstLeafCert) {
854864
continue NextUsage
855865
}
856866
}

0 commit comments

Comments
 (0)