]> Cypherpunks repositories - gostls13.git/commitdiff
crypto/x509: allow a leaf certificate to be specified directly as root.
authorAdam Langley <agl@golang.org>
Thu, 18 Aug 2016 23:44:08 +0000 (16:44 -0700)
committerAdam Langley <agl@golang.org>
Fri, 19 Aug 2016 16:56:23 +0000 (16:56 +0000)
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: Brad Fitzpatrick <bradfitz@golang.org>
src/crypto/x509/cert_pool.go
src/crypto/x509/verify.go
src/crypto/x509/verify_test.go

index 59ab8871054aef95e176c376409989b625ad7883..7650494824e66a66da4f093bfbab7dbba975b7f3 100644 (file)
@@ -5,6 +5,7 @@
 package x509
 
 import (
+       "bytes"
        "encoding/pem"
        "errors"
        "runtime"
@@ -64,6 +65,21 @@ func (s *CertPool) findVerifiedParents(cert *Certificate) (parents []int, errCer
        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.
 func (s *CertPool) AddCert(cert *Certificate) {
        if cert == nil {
index 85c083fbb2c9c40481c48cb84936cb2c1bf8d4de..825a8f849f01876ac87ad507eaa1d5208b0f1c33 100644 (file)
@@ -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)
-       if err != nil {
-               return
+       var candidateChains [][]*Certificate
+       if opts.Roots.contains(c) {
+               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
index bacf7ded29f532d1daba76e2a0c8f20710e9cde6..0bd1a2c7902b515af63107cef37bd8493fd2b13c 100644 (file)
@@ -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) {
@@ -1088,3 +1112,22 @@ Nr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX
 c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a
 mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ=
 -----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-----`