github.com/FISCO-BCOS/crypto@v0.0.0-20200202032121-bd8ab0b5d4f1/x509/root_darwin_arm_gen.go (about) 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. 4 5 // +build ignore 6 7 // Generates root_darwin_armx.go. 8 // 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 12 // chain. 13 // 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. 17 package main 18 19 import ( 20 "bytes" 21 "crypto/sha256" 22 "github.com/FISCO-BCOS/crypto/x509" 23 "encoding/hex" 24 "encoding/pem" 25 "flag" 26 "fmt" 27 "go/format" 28 "io/ioutil" 29 "log" 30 "net/http" 31 "os/exec" 32 "regexp" 33 "strings" 34 ) 35 36 var output = flag.String("output", "root_darwin_armx.go", "file name to write") 37 38 func main() { 39 certs, err := selectCerts() 40 if err != nil { 41 log.Fatal(err) 42 } 43 44 buf := new(bytes.Buffer) 45 46 fmt.Fprintf(buf, "// Code generated by root_darwin_arm_gen --output %s; DO NOT EDIT.\n", *output) 47 fmt.Fprintf(buf, "%s", header) 48 49 fmt.Fprintf(buf, "const systemRootsPEM = `\n") 50 for _, cert := range certs { 51 b := &pem.Block{ 52 Type: "CERTIFICATE", 53 Bytes: cert.Raw, 54 } 55 if err := pem.Encode(buf, b); err != nil { 56 log.Fatal(err) 57 } 58 } 59 fmt.Fprintf(buf, "`") 60 61 source, err := format.Source(buf.Bytes()) 62 if err != nil { 63 log.Fatal("source format error:", err) 64 } 65 if err := ioutil.WriteFile(*output, source, 0644); err != nil { 66 log.Fatal(err) 67 } 68 } 69 70 func selectCerts() ([]*x509.Certificate, error) { 71 ids, err := fetchCertIDs() 72 if err != nil { 73 return nil, err 74 } 75 76 scerts, err := sysCerts() 77 if err != nil { 78 return nil, err 79 } 80 81 var certs []*x509.Certificate 82 for _, id := range ids { 83 if c, ok := scerts[id.fingerprint]; ok { 84 certs = append(certs, c) 85 } else { 86 fmt.Printf("WARNING: cannot find certificate: %s (fingerprint: %s)\n", id.name, id.fingerprint) 87 } 88 } 89 return certs, nil 90 } 91 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() 95 if err != nil { 96 return nil, err 97 } 98 certs = make(map[string]*x509.Certificate) 99 for len(data) > 0 { 100 var block *pem.Block 101 block, data = pem.Decode(data) 102 if block == nil { 103 break 104 } 105 if block.Type != "CERTIFICATE" || len(block.Headers) != 0 { 106 continue 107 } 108 109 cert, err := x509.ParseCertificate(block.Bytes) 110 if err != nil { 111 continue 112 } 113 114 fingerprint := sha256.Sum256(cert.Raw) 115 certs[hex.EncodeToString(fingerprint[:])] = cert 116 } 117 return certs, nil 118 } 119 120 type certID struct { 121 name string 122 fingerprint string 123 } 124 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") 130 if err != nil { 131 return nil, err 132 } 133 defer resp.Body.Close() 134 body, err := ioutil.ReadAll(resp.Body) 135 if err != nil { 136 return nil, err 137 } 138 text := string(body) 139 text = text[strings.Index(text, "<div id=trusted"):] 140 text = text[:strings.Index(text, "</div>")] 141 142 var ids []certID 143 cols := make(map[string]int) 144 for i, rowmatch := range regexp.MustCompile("(?s)<tr>(.*?)</tr>").FindAllStringSubmatch(text, -1) { 145 row := rowmatch[1] 146 if i == 0 { 147 // Parse table header row to extract column names 148 for i, match := range regexp.MustCompile("(?s)<th>(.*?)</th>").FindAllStringSubmatch(row, -1) { 149 cols[match[1]] = i 150 } 151 continue 152 } 153 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.ReplaceAll(fingerprint, "<br>", "") 158 fingerprint = strings.ReplaceAll(fingerprint, "\n", "") 159 fingerprint = strings.ReplaceAll(fingerprint, " ", "") 160 fingerprint = strings.ToLower(fingerprint) 161 162 ids = append(ids, certID{ 163 name: name, 164 fingerprint: fingerprint, 165 }) 166 } 167 return ids, nil 168 } 169 170 const header = ` 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. 174 175 // +build cgo 176 // +build darwin 177 // +build arm arm64 ios 178 179 package x509 180 181 func loadSystemRoots() (*CertPool, error) { 182 p := NewCertPool() 183 p.AppendCertsFromPEM([]byte(systemRootsPEM)) 184 return p, nil 185 } 186 `