|
|
|
|
@ -18,19 +18,14 @@ package main |
|
|
|
|
|
|
|
|
|
import ( |
|
|
|
|
"bytes" |
|
|
|
|
"crypto/sha256" |
|
|
|
|
"compress/gzip" |
|
|
|
|
"crypto/x509" |
|
|
|
|
"encoding/hex" |
|
|
|
|
"encoding/pem" |
|
|
|
|
"flag" |
|
|
|
|
"fmt" |
|
|
|
|
"go/format" |
|
|
|
|
"io/ioutil" |
|
|
|
|
"log" |
|
|
|
|
"net/http" |
|
|
|
|
"os/exec" |
|
|
|
|
"regexp" |
|
|
|
|
"strings" |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
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, "%s", header) |
|
|
|
|
|
|
|
|
|
fmt.Fprintf(buf, "const systemRootsPEM = `\n") |
|
|
|
|
for _, cert := range certs { |
|
|
|
|
b := &pem.Block{ |
|
|
|
|
Type: "CERTIFICATE", |
|
|
|
|
Bytes: cert.Raw, |
|
|
|
|
gzbuf := new(bytes.Buffer) |
|
|
|
|
zw, err := gzip.NewWriterLevel(gzbuf, gzip.BestCompression) |
|
|
|
|
if err != nil { |
|
|
|
|
log.Fatal(err) |
|
|
|
|
} |
|
|
|
|
if _, err := zw.Write(cert.Raw); err != nil { |
|
|
|
|
log.Fatal(err) |
|
|
|
|
} |
|
|
|
|
if err := pem.Encode(buf, b); err != nil { |
|
|
|
|
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, "`") |
|
|
|
|
fmt.Fprintf(buf, "%s", footer) |
|
|
|
|
|
|
|
|
|
source, err := format.Source(buf.Bytes()) |
|
|
|
|
if err != nil { |
|
|
|
|
@ -67,38 +68,14 @@ func main() { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func selectCerts() ([]*x509.Certificate, error) { |
|
|
|
|
ids, err := fetchCertIDs() |
|
|
|
|
func selectCerts() (certs []*x509.Certificate, err error) { |
|
|
|
|
pemCerts, err := ioutil.ReadFile("certs.pem") |
|
|
|
|
if err != nil { |
|
|
|
|
return nil, err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
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 { |
|
|
|
|
for len(pemCerts) > 0 { |
|
|
|
|
var block *pem.Block |
|
|
|
|
block, data = pem.Decode(data) |
|
|
|
|
block, pemCerts = pem.Decode(pemCerts) |
|
|
|
|
if block == nil { |
|
|
|
|
break |
|
|
|
|
} |
|
|
|
|
@ -108,65 +85,13 @@ func sysCerts() (certs map[string]*x509.Certificate, err error) { |
|
|
|
|
|
|
|
|
|
cert, err := x509.ParseCertificate(block.Bytes) |
|
|
|
|
if err != nil { |
|
|
|
|
continue |
|
|
|
|
return nil, err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fingerprint := sha256.Sum256(cert.Raw) |
|
|
|
|
certs[hex.EncodeToString(fingerprint[:])] = cert |
|
|
|
|
certs = append(certs, cert) |
|
|
|
|
} |
|
|
|
|
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 = ` |
|
|
|
|
// Copyright 2015 The Go Authors. All rights reserved.
|
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
|
@ -178,7 +103,9 @@ package x509 |
|
|
|
|
|
|
|
|
|
func loadSystemRoots() (*CertPool, error) { |
|
|
|
|
p := NewCertPool() |
|
|
|
|
p.AppendCertsFromPEM([]byte(systemRootsPEM)) |
|
|
|
|
` |
|
|
|
|
|
|
|
|
|
const footer = ` |
|
|
|
|
return p, nil |
|
|
|
|
} |
|
|
|
|
` |
|
|
|
|
|