mirror of
https://github.com/tailscale/tailscale.git
synced 2024-11-29 04:55:31 +00:00
tempfork/x509: store certs for iOS compressed in binary, parse lazily
This commit is contained in:
parent
8fd8fc9c7d
commit
28c632c97b
@ -143,12 +143,9 @@ func (s *CertPool) AddCert(cert *Certificate) {
|
|||||||
if cert == nil {
|
if cert == nil {
|
||||||
panic("adding nil Certificate to CertPool")
|
panic("adding nil Certificate to CertPool")
|
||||||
}
|
}
|
||||||
err := s.AddCertFunc(sha256.Sum224(cert.Raw), string(cert.RawSubject), string(cert.SubjectKeyId), func() (*Certificate, error) {
|
s.AddCertFunc(sha256.Sum224(cert.Raw), string(cert.RawSubject), string(cert.SubjectKeyId), func() (*Certificate, error) {
|
||||||
return cert, nil
|
return cert, nil
|
||||||
})
|
})
|
||||||
if err != nil {
|
|
||||||
panic(err.Error())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddCertFunc adds metadata about a certificate to a pool, along with
|
// AddCertFunc adds metadata about a certificate to a pool, along with
|
||||||
@ -157,17 +154,19 @@ func (s *CertPool) AddCert(cert *Certificate) {
|
|||||||
// The rawSubject is Certificate.RawSubject and must be non-empty.
|
// The rawSubject is Certificate.RawSubject and must be non-empty.
|
||||||
// The subjectKeyID is Certificate.SubjectKeyId and may be empty.
|
// The subjectKeyID is Certificate.SubjectKeyId and may be empty.
|
||||||
// The getCert func may be called 0 or more times.
|
// The getCert func may be called 0 or more times.
|
||||||
func (s *CertPool) AddCertFunc(rawSum224 sum224, rawSubject, subjectKeyID string, getCert func() (*Certificate, error)) error {
|
func (s *CertPool) AddCertFunc(rawSum224 sum224, rawSubject, subjectKeyID string, getCert func() (*Certificate, error)) {
|
||||||
|
// Check that the certificate isn't being added twice.
|
||||||
|
if s.haveSum[rawSum224] {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s.haveSum[rawSum224] = true
|
||||||
|
s.addCertFuncNotDup(rawSubject, subjectKeyID, getCert)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *CertPool) addCertFuncNotDup(rawSubject, subjectKeyID string, getCert func() (*Certificate, error)) {
|
||||||
if getCert == nil {
|
if getCert == nil {
|
||||||
panic("getCert can't be nil")
|
panic("getCert can't be nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that the certificate isn't being added twice.
|
|
||||||
if s.haveSum[rawSum224] {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
s.haveSum[rawSum224] = true
|
|
||||||
|
|
||||||
n := len(s.getCert)
|
n := len(s.getCert)
|
||||||
s.getCert = append(s.getCert, getCert)
|
s.getCert = append(s.getCert, getCert)
|
||||||
|
|
||||||
@ -176,7 +175,6 @@ func (s *CertPool) AddCertFunc(rawSum224 sum224, rawSubject, subjectKeyID string
|
|||||||
}
|
}
|
||||||
s.byName[rawSubject] = append(s.byName[rawSubject], n)
|
s.byName[rawSubject] = append(s.byName[rawSubject], n)
|
||||||
s.rawSubjects = append(s.rawSubjects, []byte(rawSubject))
|
s.rawSubjects = append(s.rawSubjects, []byte(rawSubject))
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// AppendCertsFromPEM attempts to parse a series of PEM encoded certificates.
|
// AppendCertsFromPEM attempts to parse a series of PEM encoded certificates.
|
||||||
|
4293
tempfork/x509/certs.pem
Normal file
4293
tempfork/x509/certs.pem
Normal file
File diff suppressed because it is too large
Load Diff
36
tempfork/x509/pool_darwin_arm64.go
Normal file
36
tempfork/x509/pool_darwin_arm64.go
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
// Copyright 2020 Tailscale Inc. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build !x509omitbundledroots
|
||||||
|
|
||||||
|
package x509
|
||||||
|
|
||||||
|
import (
|
||||||
|
"compress/gzip"
|
||||||
|
"io/ioutil"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
func certUncompressor(zcertBytes string) func() (*Certificate, error) {
|
||||||
|
var once sync.Once
|
||||||
|
var c *Certificate
|
||||||
|
var err error
|
||||||
|
return func() (*Certificate, error) {
|
||||||
|
once.Do(func() {
|
||||||
|
var certBytes []byte
|
||||||
|
var zr *gzip.Reader
|
||||||
|
zr, err = gzip.NewReader(strings.NewReader(zcertBytes))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
certBytes, err = ioutil.ReadAll(zr)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c, err = ParseCertificate(certBytes)
|
||||||
|
})
|
||||||
|
return c, err
|
||||||
|
}
|
||||||
|
}
|
@ -306,7 +306,10 @@ func loadSystemRoots() (*CertPool, error) {
|
|||||||
|
|
||||||
trustedRoots := NewCertPool()
|
trustedRoots := NewCertPool()
|
||||||
for i := 0; i < roots.len(); i++ {
|
for i := 0; i < roots.len(); i++ {
|
||||||
c := roots.mustCert(i)
|
c, err := roots.cert(i)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
contains, err := untrustedRoots.contains(c)
|
contains, err := untrustedRoots.contains(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
File diff suppressed because one or more lines are too long
@ -18,19 +18,14 @@
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"crypto/sha256"
|
"compress/gzip"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"encoding/hex"
|
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"go/format"
|
"go/format"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
|
||||||
"os/exec"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var output = flag.String("output", "root_darwin_arm64.go", "file name to write")
|
var output = flag.String("output", "root_darwin_arm64.go", "file name to write")
|
||||||
@ -45,18 +40,24 @@ func main() {
|
|||||||
|
|
||||||
fmt.Fprintf(buf, "// Code generated by root_darwin_arm_gen --output %s; DO NOT EDIT.\n", *output)
|
fmt.Fprintf(buf, "// Code generated by root_darwin_arm_gen --output %s; DO NOT EDIT.\n", *output)
|
||||||
fmt.Fprintf(buf, "%s", header)
|
fmt.Fprintf(buf, "%s", header)
|
||||||
|
|
||||||
fmt.Fprintf(buf, "const systemRootsPEM = `\n")
|
|
||||||
for _, cert := range certs {
|
for _, cert := range certs {
|
||||||
b := &pem.Block{
|
gzbuf := new(bytes.Buffer)
|
||||||
Type: "CERTIFICATE",
|
zw, err := gzip.NewWriterLevel(gzbuf, gzip.BestCompression)
|
||||||
Bytes: cert.Raw,
|
if err != nil {
|
||||||
}
|
|
||||||
if err := pem.Encode(buf, b); err != nil {
|
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
if _, err := zw.Write(cert.Raw); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
fmt.Fprintf(buf, "`")
|
if err := zw.Close(); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
fmt.Fprintf(buf, "p.addCertFuncNotDup(%q, %q, certUncompressor(%q))\n",
|
||||||
|
cert.RawSubject,
|
||||||
|
cert.SubjectKeyId,
|
||||||
|
gzbuf.Bytes())
|
||||||
|
}
|
||||||
|
fmt.Fprintf(buf, "%s", footer)
|
||||||
|
|
||||||
source, err := format.Source(buf.Bytes())
|
source, err := format.Source(buf.Bytes())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -67,38 +68,14 @@ func main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func selectCerts() ([]*x509.Certificate, error) {
|
func selectCerts() (certs []*x509.Certificate, err error) {
|
||||||
ids, err := fetchCertIDs()
|
pemCerts, err := ioutil.ReadFile("certs.pem")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
for len(pemCerts) > 0 {
|
||||||
scerts, err := sysCerts()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var certs []*x509.Certificate
|
|
||||||
for _, id := range ids {
|
|
||||||
if c, ok := scerts[id.fingerprint]; ok {
|
|
||||||
certs = append(certs, c)
|
|
||||||
} else {
|
|
||||||
fmt.Printf("WARNING: cannot find certificate: %s (fingerprint: %s)\n", id.name, id.fingerprint)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return certs, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func sysCerts() (certs map[string]*x509.Certificate, err error) {
|
|
||||||
cmd := exec.Command("/usr/bin/security", "find-certificate", "-a", "-p", "/System/Library/Keychains/SystemRootCertificates.keychain")
|
|
||||||
data, err := cmd.Output()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
certs = make(map[string]*x509.Certificate)
|
|
||||||
for len(data) > 0 {
|
|
||||||
var block *pem.Block
|
var block *pem.Block
|
||||||
block, data = pem.Decode(data)
|
block, pemCerts = pem.Decode(pemCerts)
|
||||||
if block == nil {
|
if block == nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -108,65 +85,13 @@ func sysCerts() (certs map[string]*x509.Certificate, err error) {
|
|||||||
|
|
||||||
cert, err := x509.ParseCertificate(block.Bytes)
|
cert, err := x509.ParseCertificate(block.Bytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
return nil, err
|
||||||
}
|
}
|
||||||
|
certs = append(certs, cert)
|
||||||
fingerprint := sha256.Sum256(cert.Raw)
|
|
||||||
certs[hex.EncodeToString(fingerprint[:])] = cert
|
|
||||||
}
|
}
|
||||||
return certs, nil
|
return certs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type certID struct {
|
|
||||||
name string
|
|
||||||
fingerprint string
|
|
||||||
}
|
|
||||||
|
|
||||||
// fetchCertIDs fetches IDs of iOS X509 certificates from apple.com.
|
|
||||||
func fetchCertIDs() ([]certID, error) {
|
|
||||||
// Download the iOS 11 support page. The index for all iOS versions is here:
|
|
||||||
// https://support.apple.com/en-us/HT204132
|
|
||||||
resp, err := http.Get("https://support.apple.com/en-us/HT208125")
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer resp.Body.Close()
|
|
||||||
body, err := ioutil.ReadAll(resp.Body)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
text := string(body)
|
|
||||||
text = text[strings.Index(text, "<div id=trusted"):]
|
|
||||||
text = text[:strings.Index(text, "</div>")]
|
|
||||||
|
|
||||||
var ids []certID
|
|
||||||
cols := make(map[string]int)
|
|
||||||
for i, rowmatch := range regexp.MustCompile("(?s)<tr>(.*?)</tr>").FindAllStringSubmatch(text, -1) {
|
|
||||||
row := rowmatch[1]
|
|
||||||
if i == 0 {
|
|
||||||
// Parse table header row to extract column names
|
|
||||||
for i, match := range regexp.MustCompile("(?s)<th>(.*?)</th>").FindAllStringSubmatch(row, -1) {
|
|
||||||
cols[match[1]] = i
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
values := regexp.MustCompile("(?s)<td>(.*?)</td>").FindAllStringSubmatch(row, -1)
|
|
||||||
name := values[cols["Certificate name"]][1]
|
|
||||||
fingerprint := values[cols["Fingerprint (SHA-256)"]][1]
|
|
||||||
fingerprint = strings.ReplaceAll(fingerprint, "<br>", "")
|
|
||||||
fingerprint = strings.ReplaceAll(fingerprint, "\n", "")
|
|
||||||
fingerprint = strings.ReplaceAll(fingerprint, " ", "")
|
|
||||||
fingerprint = strings.ToLower(fingerprint)
|
|
||||||
|
|
||||||
ids = append(ids, certID{
|
|
||||||
name: name,
|
|
||||||
fingerprint: fingerprint,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return ids, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
const header = `
|
const header = `
|
||||||
// Copyright 2015 The Go Authors. All rights reserved.
|
// Copyright 2015 The Go Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
@ -178,7 +103,9 @@ func fetchCertIDs() ([]certID, error) {
|
|||||||
|
|
||||||
func loadSystemRoots() (*CertPool, error) {
|
func loadSystemRoots() (*CertPool, error) {
|
||||||
p := NewCertPool()
|
p := NewCertPool()
|
||||||
p.AppendCertsFromPEM([]byte(systemRootsPEM))
|
`
|
||||||
|
|
||||||
|
const footer = `
|
||||||
return p, nil
|
return p, nil
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// +build !cgo
|
// +build !cgo,!arm64
|
||||||
|
|
||||||
package x509
|
package x509
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user