1 // Copyright 2015 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
7 // Generates root_darwin_armx.go.
9 // As of iOS 8, there is no API for querying the system trusted X.509 root
10 // certificates. We could use SecTrustEvaluate to verify that a trust chain
11 // exists for a certificate, but the x509 API requires returning the entire
14 // Apple publishes the list of trusted root certificates for iOS on
15 // support.apple.com. So we parse the list and extract the certificates from
16 // an OS X machine and embed them into the x509 package.
36 var output
= flag
.String("output", "root_darwin_armx.go", "file name to write")
39 certs
, err
:= selectCerts()
44 buf
:= new(bytes
.Buffer
)
46 fmt
.Fprintf(buf
, "// Code generated by root_darwin_arm_gen --output %s; DO NOT EDIT.\n", *output
)
47 fmt
.Fprintf(buf
, "%s", header
)
49 fmt
.Fprintf(buf
, "const systemRootsPEM = `\n")
50 for _
, cert
:= range certs
{
55 if err
:= pem
.Encode(buf
, b
); err
!= nil {
61 source
, err
:= format
.Source(buf
.Bytes())
63 log
.Fatal("source format error:", err
)
65 if err
:= ioutil
.WriteFile(*output
, source
, 0644); err
!= nil {
70 func selectCerts() ([]*x509
.Certificate
, error
) {
71 ids
, err
:= fetchCertIDs()
76 scerts
, err
:= sysCerts()
81 var certs
[]*x509
.Certificate
82 for _
, id
:= range ids
{
83 if c
, ok
:= scerts
[id
.fingerprint
]; ok
{
84 certs
= append(certs
, c
)
86 fmt
.Printf("WARNING: cannot find certificate: %s (fingerprint: %s)\n", id
.name
, id
.fingerprint
)
92 func sysCerts() (certs
map[string]*x509
.Certificate
, err error
) {
93 cmd
:= exec
.Command("/usr/bin/security", "find-certificate", "-a", "-p", "/System/Library/Keychains/SystemRootCertificates.keychain")
94 data
, err
:= cmd
.Output()
98 certs
= make(map[string]*x509
.Certificate
)
101 block
, data
= pem
.Decode(data
)
105 if block
.Type
!= "CERTIFICATE" ||
len(block
.Headers
) != 0 {
109 cert
, err
:= x509
.ParseCertificate(block
.Bytes
)
114 fingerprint
:= sha256
.Sum256(cert
.Raw
)
115 certs
[hex
.EncodeToString(fingerprint
[:])] = cert
125 // fetchCertIDs fetches IDs of iOS X509 certificates from apple.com.
126 func fetchCertIDs() ([]certID
, error
) {
127 // Download the iOS 11 support page. The index for all iOS versions is here:
128 // https://support.apple.com/en-us/HT204132
129 resp
, err
:= http
.Get("https://support.apple.com/en-us/HT208125")
133 defer resp
.Body
.Close()
134 body
, err
:= ioutil
.ReadAll(resp
.Body
)
139 text
= text
[strings
.Index(text
, "<div id=trusted"):]
140 text
= text
[:strings
.Index(text
, "</div>")]
143 cols
:= make(map[string]int)
144 for i
, rowmatch
:= range regexp
.MustCompile("(?s)<tr>(.*?)</tr>").FindAllStringSubmatch(text
, -1) {
147 // Parse table header row to extract column names
148 for i
, match
:= range regexp
.MustCompile("(?s)<th>(.*?)</th>").FindAllStringSubmatch(row
, -1) {
154 values
:= regexp
.MustCompile("(?s)<td>(.*?)</td>").FindAllStringSubmatch(row
, -1)
155 name
:= values
[cols
["Certificate name"]][1]
156 fingerprint
:= values
[cols
["Fingerprint (SHA-256)"]][1]
157 fingerprint
= strings
.Replace(fingerprint
, "<br>", "", -1)
158 fingerprint
= strings
.Replace(fingerprint
, "\n", "", -1)
159 fingerprint
= strings
.Replace(fingerprint
, " ", "", -1)
160 fingerprint
= strings
.ToLower(fingerprint
)
162 ids
= append(ids
, certID
{
164 fingerprint
: fingerprint
,
171 // Copyright 2015 The Go Authors. All rights reserved.
172 // Use of this source code is governed by a BSD-style
173 // license that can be found in the LICENSE file.
177 // +build arm arm64 ios
181 func loadSystemRoots() (*CertPool, error) {
183 p.AppendCertsFromPEM([]byte(systemRootsPEM))