Skip to content

Commit bfc2231

Browse files
aglrsc
authored andcommitted
[release-branch.go1.9] crypto/x509: reject intermediates with unknown critical extensions.
In https://golang.org/cl/9390 I messed up and put the critical extension test in the wrong function. Thus it only triggered for leaf certificates and not for intermediates or roots. In practice, this is not expected to have a security impact in the web PKI. Change-Id: I4f2464ef2fb71b5865389901f293062ba1327702 Reviewed-on: https://go-review.googlesource.com/69294 Run-TryBot: Adam Langley <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Russ Cox <[email protected]> Reviewed-on: https://go-review.googlesource.com/70983 Run-TryBot: Russ Cox <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]>
1 parent a1e34ab commit bfc2231

File tree

3 files changed

+100
-72
lines changed

3 files changed

+100
-72
lines changed

src/crypto/x509/verify.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,10 @@ func matchNameConstraint(domain, constraint string) bool {
191191

192192
// isValid performs validity checks on the c.
193193
func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *VerifyOptions) error {
194+
if len(c.UnhandledCriticalExtensions) > 0 {
195+
return UnhandledCriticalExtension{}
196+
}
197+
194198
if len(currentChain) > 0 {
195199
child := currentChain[len(currentChain)-1]
196200
if !bytes.Equal(child.RawIssuer, c.RawSubject) {
@@ -285,10 +289,6 @@ func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err e
285289
return c.systemVerify(&opts)
286290
}
287291

288-
if len(c.UnhandledCriticalExtensions) > 0 {
289-
return nil, UnhandledCriticalExtension{}
290-
}
291-
292292
if opts.Roots == nil {
293293
opts.Roots = systemRootsPool()
294294
if opts.Roots == nil {

src/crypto/x509/verify_test.go

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,30 @@ var verifyTests = []verifyTest{
296296

297297
errorCallback: expectNameConstraintsError,
298298
},
299+
{
300+
// Test that unknown critical extensions in a leaf cause a
301+
// verify error.
302+
leaf: criticalExtLeafWithExt,
303+
dnsName: "example.com",
304+
intermediates: []string{criticalExtIntermediate},
305+
roots: []string{criticalExtRoot},
306+
currentTime: 1486684488,
307+
systemSkip: true,
308+
309+
errorCallback: expectUnhandledCriticalExtension,
310+
},
311+
{
312+
// Test that unknown critical extensions in an intermediate
313+
// cause a verify error.
314+
leaf: criticalExtLeaf,
315+
dnsName: "example.com",
316+
intermediates: []string{criticalExtIntermediateWithExt},
317+
roots: []string{criticalExtRoot},
318+
currentTime: 1486684488,
319+
systemSkip: true,
320+
321+
errorCallback: expectUnhandledCriticalExtension,
322+
},
299323
}
300324

301325
func expectHostnameError(t *testing.T, i int, err error) (ok bool) {
@@ -379,6 +403,14 @@ func expectNotAuthorizedError(t *testing.T, i int, err error) (ok bool) {
379403
return true
380404
}
381405

406+
func expectUnhandledCriticalExtension(t *testing.T, i int, err error) (ok bool) {
407+
if _, ok := err.(UnhandledCriticalExtension); !ok {
408+
t.Errorf("#%d: error was not an UnhandledCriticalExtension: %s", i, err)
409+
return false
410+
}
411+
return true
412+
}
413+
382414
func certificateFromPEM(pemBytes string) (*Certificate, error) {
383415
block, _ := pem.Decode([]byte(pemBytes))
384416
if block == nil {
@@ -1596,3 +1628,67 @@ w67CoNRb81dy+4Q1lGpA8ORoLWh5fIq2t2eNGc4qB8vlTIKiESzAwu7u3sRfuWQi
15961628
4R+gnfLd37FWflMHwztFbVTuNtPOljCX0LN7KcuoXYlr05RhQrmoN7fQHsrZMNLs
15971629
8FVjHdKKu+uPstwd04Uy4BR/H2y1yerN9j/L6ZkMl98iiA==
15981630
-----END CERTIFICATE-----`
1631+
1632+
const criticalExtRoot = `-----BEGIN CERTIFICATE-----
1633+
MIIBqzCCAVGgAwIBAgIJAJ+mI/85cXApMAoGCCqGSM49BAMCMB0xDDAKBgNVBAoT
1634+
A09yZzENMAsGA1UEAxMEUm9vdDAeFw0xNTAxMDEwMDAwMDBaFw0yNTAxMDEwMDAw
1635+
MDBaMB0xDDAKBgNVBAoTA09yZzENMAsGA1UEAxMEUm9vdDBZMBMGByqGSM49AgEG
1636+
CCqGSM49AwEHA0IABJGp9joiG2QSQA+1FczEDAsWo84rFiP3GTL+n+ugcS6TyNib
1637+
gzMsdbJgVi+a33y0SzLZxB+YvU3/4KTk8yKLC+2jejB4MA4GA1UdDwEB/wQEAwIC
1638+
BDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB
1639+
/zAZBgNVHQ4EEgQQQDfXAftAL7gcflQEJ4xZATAbBgNVHSMEFDASgBBAN9cB+0Av
1640+
uBx+VAQnjFkBMAoGCCqGSM49BAMCA0gAMEUCIFeSV00fABFceWR52K+CfIgOHotY
1641+
FizzGiLB47hGwjMuAiEA8e0um2Kr8FPQ4wmFKaTRKHMaZizCGl3m+RG5QsE1KWo=
1642+
-----END CERTIFICATE-----`
1643+
1644+
const criticalExtIntermediate = `-----BEGIN CERTIFICATE-----
1645+
MIIBszCCAVmgAwIBAgIJAL2kcGZKpzVqMAoGCCqGSM49BAMCMB0xDDAKBgNVBAoT
1646+
A09yZzENMAsGA1UEAxMEUm9vdDAeFw0xNTAxMDEwMDAwMDBaFw0yNTAxMDEwMDAw
1647+
MDBaMCUxDDAKBgNVBAoTA09yZzEVMBMGA1UEAxMMSW50ZXJtZWRpYXRlMFkwEwYH
1648+
KoZIzj0CAQYIKoZIzj0DAQcDQgAESqVq92iPEq01cL4o99WiXDc5GZjpjNlzMS1n
1649+
rk8oHcVDp4tQRRQG3F4A6dF1rn/L923ha3b0fhDLlAvXZB+7EKN6MHgwDgYDVR0P
1650+
AQH/BAQDAgIEMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAPBgNVHRMB
1651+
Af8EBTADAQH/MBkGA1UdDgQSBBCMGmiotXbbXVd7H40UsgajMBsGA1UdIwQUMBKA
1652+
EEA31wH7QC+4HH5UBCeMWQEwCgYIKoZIzj0EAwIDSAAwRQIhAOhhNRb6KV7h3wbE
1653+
cdap8bojzvUcPD78fbsQPCNw1jPxAiBOeAJhlTwpKn9KHpeJphYSzydj9NqcS26Y
1654+
xXbdbm27KQ==
1655+
-----END CERTIFICATE-----`
1656+
1657+
const criticalExtLeafWithExt = `-----BEGIN CERTIFICATE-----
1658+
MIIBxTCCAWugAwIBAgIJAJZAUtw5ccb1MAoGCCqGSM49BAMCMCUxDDAKBgNVBAoT
1659+
A09yZzEVMBMGA1UEAxMMSW50ZXJtZWRpYXRlMB4XDTE1MDEwMTAwMDAwMFoXDTI1
1660+
MDEwMTAwMDAwMFowJDEMMAoGA1UEChMDT3JnMRQwEgYDVQQDEwtleGFtcGxlLmNv
1661+
bTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABF3ABa2+B6gUyg6ayCaRQWYY/+No
1662+
6PceLqEavZNUeVNuz7bS74Toy8I7R3bGMkMgbKpLSPlPTroAATvebTXoBaijgYQw
1663+
gYEwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcD
1664+
AjAMBgNVHRMBAf8EAjAAMBkGA1UdDgQSBBBRNtBL2vq8nCV3qVp7ycxMMBsGA1Ud
1665+
IwQUMBKAEIwaaKi1dttdV3sfjRSyBqMwCgYDUQMEAQH/BAAwCgYIKoZIzj0EAwID
1666+
SAAwRQIgVjy8GBgZFiagexEuDLqtGjIRJQtBcf7lYgf6XFPH1h4CIQCT6nHhGo6E
1667+
I+crEm4P5q72AnA/Iy0m24l7OvLuXObAmg==
1668+
-----END CERTIFICATE-----`
1669+
1670+
const criticalExtIntermediateWithExt = `-----BEGIN CERTIFICATE-----
1671+
MIIB2TCCAX6gAwIBAgIIQD3NrSZtcUUwCgYIKoZIzj0EAwIwHTEMMAoGA1UEChMD
1672+
T3JnMQ0wCwYDVQQDEwRSb290MB4XDTE1MDEwMTAwMDAwMFoXDTI1MDEwMTAwMDAw
1673+
MFowPTEMMAoGA1UEChMDT3JnMS0wKwYDVQQDEyRJbnRlcm1lZGlhdGUgd2l0aCBD
1674+
cml0aWNhbCBFeHRlbnNpb24wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQtnmzH
1675+
mcRm10bdDBnJE7xQEJ25cLCL5okuEphRR0Zneo6+nQZikoh+UBbtt5GV3Dms7LeP
1676+
oF5HOplYDCd8wi/wo4GHMIGEMA4GA1UdDwEB/wQEAwICBDAdBgNVHSUEFjAUBggr
1677+
BgEFBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zAZBgNVHQ4EEgQQKxdv
1678+
UuQZ6sO3XvBsxgNZ3zAbBgNVHSMEFDASgBBAN9cB+0AvuBx+VAQnjFkBMAoGA1ED
1679+
BAEB/wQAMAoGCCqGSM49BAMCA0kAMEYCIQCQzTPd6XKex+OAPsKT/1DsoMsg8vcG
1680+
c2qZ4Q0apT/kvgIhAKu2TnNQMIUdcO0BYQIl+Uhxc78dc9h4lO+YJB47pHGx
1681+
-----END CERTIFICATE-----`
1682+
1683+
const criticalExtLeaf = `-----BEGIN CERTIFICATE-----
1684+
MIIBzzCCAXWgAwIBAgIJANoWFIlhCI9MMAoGCCqGSM49BAMCMD0xDDAKBgNVBAoT
1685+
A09yZzEtMCsGA1UEAxMkSW50ZXJtZWRpYXRlIHdpdGggQ3JpdGljYWwgRXh0ZW5z
1686+
aW9uMB4XDTE1MDEwMTAwMDAwMFoXDTI1MDEwMTAwMDAwMFowJDEMMAoGA1UEChMD
1687+
T3JnMRQwEgYDVQQDEwtleGFtcGxlLmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEH
1688+
A0IABG1Lfh8A0Ho2UvZN5H0+ONil9c8jwtC0y0xIZftyQE+Fwr9XwqG3rV2g4M1h
1689+
GnJa9lV9MPHg8+b85Hixm0ZSw7SjdzB1MA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUE
1690+
FjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAZBgNVHQ4EEgQQ
1691+
UNhY4JhezH9gQYqvDMWrWDAbBgNVHSMEFDASgBArF29S5Bnqw7de8GzGA1nfMAoG
1692+
CCqGSM49BAMCA0gAMEUCIQClA3d4tdrDu9Eb5ZBpgyC+fU1xTZB0dKQHz6M5fPZA
1693+
2AIgN96lM+CPGicwhN24uQI6flOsO3H0TJ5lNzBYLtnQtlc=
1694+
-----END CERTIFICATE-----`

src/crypto/x509/x509_test.go

Lines changed: 0 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -523,74 +523,6 @@ func TestCreateSelfSignedCertificate(t *testing.T) {
523523
}
524524
}
525525

526-
func TestUnknownCriticalExtension(t *testing.T) {
527-
priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
528-
if err != nil {
529-
t.Fatalf("Failed to generate ECDSA key: %s", err)
530-
}
531-
532-
oids := []asn1.ObjectIdentifier{
533-
// This OID is in the PKIX arc, but unknown.
534-
{2, 5, 29, 999999},
535-
// This is a nonsense, unassigned OID.
536-
{1, 2, 3, 4},
537-
}
538-
539-
for _, oid := range oids {
540-
template := Certificate{
541-
SerialNumber: big.NewInt(1),
542-
Subject: pkix.Name{
543-
CommonName: "foo",
544-
},
545-
NotBefore: time.Unix(1000, 0),
546-
NotAfter: time.Now().AddDate(1, 0, 0),
547-
548-
BasicConstraintsValid: true,
549-
IsCA: true,
550-
551-
KeyUsage: KeyUsageCertSign,
552-
ExtKeyUsage: []ExtKeyUsage{ExtKeyUsageServerAuth},
553-
554-
ExtraExtensions: []pkix.Extension{
555-
{
556-
Id: oid,
557-
Critical: true,
558-
Value: nil,
559-
},
560-
},
561-
}
562-
563-
derBytes, err := CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
564-
if err != nil {
565-
t.Fatalf("failed to create certificate: %s", err)
566-
}
567-
568-
cert, err := ParseCertificate(derBytes)
569-
if err != nil {
570-
t.Fatalf("Certificate with unknown critical extension was not parsed: %s", err)
571-
}
572-
573-
roots := NewCertPool()
574-
roots.AddCert(cert)
575-
576-
// Setting Roots ensures that Verify won't delegate to the OS
577-
// library and thus the correct error should always be
578-
// returned.
579-
_, err = cert.Verify(VerifyOptions{Roots: roots})
580-
if err == nil {
581-
t.Fatal("Certificate with unknown critical extension was verified without error")
582-
}
583-
if _, ok := err.(UnhandledCriticalExtension); !ok {
584-
t.Fatalf("Error was %#v, but wanted one of type UnhandledCriticalExtension", err)
585-
}
586-
587-
cert.UnhandledCriticalExtensions = nil
588-
if _, err = cert.Verify(VerifyOptions{Roots: roots}); err != nil {
589-
t.Errorf("Certificate failed to verify after unhandled critical extensions were cleared: %s", err)
590-
}
591-
}
592-
}
593-
594526
// Self-signed certificate using ECDSA with SHA1 & secp256r1
595527
var ecdsaSHA1CertPem = `
596528
-----BEGIN CERTIFICATE-----

0 commit comments

Comments
 (0)