1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package main
19
20 import (
21 "bytes"
22 "crypto/sha256"
23 "encoding/hex"
24 "encoding/pem"
25 "flag"
26 "fmt"
27 "go/format"
28 "io"
29 "log"
30 "net/http"
31 "os"
32 "os/exec"
33 "regexp"
34 "strings"
35
36 "github.com/google/certificate-transparency-go/x509"
37 )
38
39 var output = flag.String("output", "root_darwin_armx.go", "file name to write")
40
41 func main() {
42 certs, err := selectCerts()
43 if err != nil {
44 log.Fatal(err)
45 }
46
47 buf := new(bytes.Buffer)
48
49 fmt.Fprintf(buf, "// Code generated by root_darwin_arm_gen --output %s; DO NOT EDIT.\n", *output)
50 fmt.Fprintf(buf, "%s", header)
51
52 fmt.Fprintf(buf, "const systemRootsPEM = `\n")
53 for _, cert := range certs {
54 b := &pem.Block{
55 Type: "CERTIFICATE",
56 Bytes: cert.Raw,
57 }
58 if err := pem.Encode(buf, b); err != nil {
59 log.Fatal(err)
60 }
61 }
62 fmt.Fprintf(buf, "`")
63
64 source, err := format.Source(buf.Bytes())
65 if err != nil {
66 log.Fatal("source format error:", err)
67 }
68 if err := os.WriteFile(*output, source, 0644); err != nil {
69 log.Fatal(err)
70 }
71 }
72
73 func selectCerts() ([]*x509.Certificate, error) {
74 ids, err := fetchCertIDs()
75 if err != nil {
76 return nil, err
77 }
78
79 scerts, err := sysCerts()
80 if err != nil {
81 return nil, err
82 }
83
84 var certs []*x509.Certificate
85 for _, id := range ids {
86 if c, ok := scerts[id.fingerprint]; ok {
87 certs = append(certs, c)
88 } else {
89 fmt.Printf("WARNING: cannot find certificate: %s (fingerprint: %s)\n", id.name, id.fingerprint)
90 }
91 }
92 return certs, nil
93 }
94
95 func sysCerts() (certs map[string]*x509.Certificate, err error) {
96 cmd := exec.Command("/usr/bin/security", "find-certificate", "-a", "-p", "/System/Library/Keychains/SystemRootCertificates.keychain")
97 data, err := cmd.Output()
98 if err != nil {
99 return nil, err
100 }
101 certs = make(map[string]*x509.Certificate)
102 for len(data) > 0 {
103 var block *pem.Block
104 block, data = pem.Decode(data)
105 if block == nil {
106 break
107 }
108 if block.Type != "CERTIFICATE" || len(block.Headers) != 0 {
109 continue
110 }
111
112 cert, err := x509.ParseCertificate(block.Bytes)
113 if err != nil {
114 continue
115 }
116
117 fingerprint := sha256.Sum256(cert.Raw)
118 certs[hex.EncodeToString(fingerprint[:])] = cert
119 }
120 return certs, nil
121 }
122
123 type certID struct {
124 name string
125 fingerprint string
126 }
127
128
129 func fetchCertIDs() ([]certID, error) {
130
131
132 resp, err := http.Get("https://support.apple.com/en-us/HT208125")
133 if err != nil {
134 return nil, err
135 }
136 defer resp.Body.Close()
137 body, err := io.ReadAll(resp.Body)
138 if err != nil {
139 return nil, err
140 }
141 text := string(body)
142 text = text[strings.Index(text, "<div id=trusted"):]
143 text = text[:strings.Index(text, "</div>")]
144
145 var ids []certID
146 cols := make(map[string]int)
147 for i, rowmatch := range regexp.MustCompile("(?s)<tr>(.*?)</tr>").FindAllStringSubmatch(text, -1) {
148 row := rowmatch[1]
149 if i == 0 {
150
151 for i, match := range regexp.MustCompile("(?s)<th>(.*?)</th>").FindAllStringSubmatch(row, -1) {
152 cols[match[1]] = i
153 }
154 continue
155 }
156
157 values := regexp.MustCompile("(?s)<td>(.*?)</td>").FindAllStringSubmatch(row, -1)
158 name := values[cols["Certificate name"]][1]
159 fingerprint := values[cols["Fingerprint (SHA-256)"]][1]
160 fingerprint = strings.ReplaceAll(fingerprint, "<br>", "")
161 fingerprint = strings.ReplaceAll(fingerprint, "\n", "")
162 fingerprint = strings.ReplaceAll(fingerprint, " ", "")
163 fingerprint = strings.ToLower(fingerprint)
164
165 ids = append(ids, certID{
166 name: name,
167 fingerprint: fingerprint,
168 })
169 }
170 return ids, nil
171 }
172
173 const header = `
174 // Copyright 2015 The Go Authors. All rights reserved.
175 // Use of this source code is governed by a BSD-style
176 // license that can be found in the LICENSE file.
177
178 // +build cgo
179 // +build darwin
180 // +build arm arm64 ios
181
182 package x509
183
184 func loadSystemRoots() (*CertPool, error) {
185 p := NewCertPool()
186 p.AppendCertsFromPEM([]byte(systemRootsPEM))
187 return p, nil
188 }
189 `
190
View as plain text