Commit 8ad70a54 authored by Adam Langley's avatar Adam Langley

crypto/x509: allow a leaf certificate to be specified directly as root.

In other systems, putting a leaf certificate in the root store works to
express that exactly that certificate is acceptable. This change makes
that work in Go too.

Fixes #16763.

Change-Id: I5c0a8dbc47aa631b23dd49061fb217ed8b0c719c
Reviewed-on: https://go-review.googlesource.com/27393
Run-TryBot: Adam Langley <agl@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: 's avatarBrad Fitzpatrick <bradfitz@golang.org>
parent bcd54f6c
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
package x509 package x509
import ( import (
"bytes"
"encoding/pem" "encoding/pem"
"errors" "errors"
"runtime" "runtime"
...@@ -64,6 +65,21 @@ func (s *CertPool) findVerifiedParents(cert *Certificate) (parents []int, errCer ...@@ -64,6 +65,21 @@ func (s *CertPool) findVerifiedParents(cert *Certificate) (parents []int, errCer
return return
} }
func (s *CertPool) contains(cert *Certificate) bool {
if s == nil {
return false
}
candidates := s.byName[string(cert.RawSubject)]
for _, c := range candidates {
if bytes.Equal(cert.Raw, s.certs[c].Raw) {
return true
}
}
return false
}
// AddCert adds a certificate to a pool. // AddCert adds a certificate to a pool.
func (s *CertPool) AddCert(cert *Certificate) { func (s *CertPool) AddCert(cert *Certificate) {
if cert == nil { if cert == nil {
......
...@@ -262,9 +262,13 @@ func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err e ...@@ -262,9 +262,13 @@ func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err e
} }
} }
candidateChains, err := c.buildChains(make(map[int][][]*Certificate), []*Certificate{c}, &opts) var candidateChains [][]*Certificate
if err != nil { if opts.Roots.contains(c) {
return candidateChains = append(candidateChains, []*Certificate{c})
} else {
if candidateChains, err = c.buildChains(make(map[int][][]*Certificate), []*Certificate{c}, &opts); err != nil {
return nil, err
}
} }
keyUsages := opts.KeyUsages keyUsages := opts.KeyUsages
......
...@@ -235,6 +235,30 @@ var verifyTests = []verifyTest{ ...@@ -235,6 +235,30 @@ var verifyTests = []verifyTest{
}, },
}, },
}, },
{
// Putting a certificate as a root directly should work as a
// way of saying “exactly this”.
leaf: selfSigned,
roots: []string{selfSigned},
currentTime: 1471624472,
dnsName: "foo.example",
systemSkip: true,
expectedChains: [][]string{
{"Acme Co"},
},
},
{
// Putting a certificate as a root directly should not skip
// other checks however.
leaf: selfSigned,
roots: []string{selfSigned},
currentTime: 1471624472,
dnsName: "notfoo.example",
systemSkip: true,
errorCallback: expectHostnameError,
},
} }
func expectHostnameError(t *testing.T, i int, err error) (ok bool) { func expectHostnameError(t *testing.T, i int, err error) (ok bool) {
...@@ -1088,3 +1112,22 @@ Nr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX ...@@ -1088,3 +1112,22 @@ Nr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX
c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a
mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ= mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ=
-----END CERTIFICATE-----` -----END CERTIFICATE-----`
const selfSigned = `-----BEGIN CERTIFICATE-----
MIIC/DCCAeSgAwIBAgIRAK0SWRVmi67xU3z0gkgY+PkwDQYJKoZIhvcNAQELBQAw
EjEQMA4GA1UEChMHQWNtZSBDbzAeFw0xNjA4MTkxNjMzNDdaFw0xNzA4MTkxNjMz
NDdaMBIxEDAOBgNVBAoTB0FjbWUgQ28wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
ggEKAoIBAQDWkm1kdCwxyKEt6OTmZitkmLGH8cQu9z7rUdrhW8lWNm4kh2SuaUWP
pscBjda5iqg51aoKuWJR2rw6ElDne+X5eit2FT8zJgAU8v39lMFjbaVZfS9TFOYF
w0Tk0Luo/PyKJpZnwhsP++iiGQiteJbndy8aLKmJ2MpLfpDGIgxEIyNb5dgoDi0D
WReDCpE6K9WDYqvKVGnQ2Jvqqra6Gfx0tFkuqJxQuqA8aUOlPHcCH4KBZdNEoXdY
YL3E4dCAh0YiDs80wNZx4cHqEM3L8gTEFqW2Tn1TSuPZO6gjJ9QPsuUZVjaMZuuO
NVxqLGujZkDzARhC3fBpptMuaAfi20+BAgMBAAGjTTBLMA4GA1UdDwEB/wQEAwIF
oDATBgNVHSUEDDAKBggrBgEFBQcDATAMBgNVHRMBAf8EAjAAMBYGA1UdEQQPMA2C
C2Zvby5leGFtcGxlMA0GCSqGSIb3DQEBCwUAA4IBAQBPvvfnDhsHWt+/cfwdAVim
4EDn+hYOMkTQwU0pouYIvY8QXYkZ8MBxpBtBMK4JhFU+ewSWoBAEH2dCCvx/BDxN
UGTSJHMbsvJHcFvdmsvvRxOqQ/cJz7behx0cfoeHMwcs0/vWv8ms5wHesb5Ek7L0
pl01FCBGTcncVqr6RK1r4fTpeCCfRIERD+YRJz8TtPH6ydesfLL8jIV40H8NiDfG
vRAvOtNiKtPzFeQVdbRPOskC4rcHyPeiDAMAMixeLi63+CFty4da3r5lRezeedCE
cw3ESZzThBwWqvPOtJdpXdm+r57pDW8qD+/0lY8wfImMNkQAyCUCLg/1Lxt/hrBj
-----END 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