github.com/comwrg/go/src@v0.0.0-20220319063731-c238d0440370/crypto/x509/root_ios_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 //go:build ignore 6 // +build ignore 7 8 // Generates root_ios.go. 9 // 10 // As of iOS 13, there is no API for querying the system trusted X.509 root 11 // certificates. 12 // 13 // Apple publishes the trusted root certificates for iOS and macOS on 14 // opensource.apple.com so we embed them into the x509 package. 15 // 16 // Note that this ignores distrusted and revoked certificates. 17 package main 18 19 import ( 20 "archive/tar" 21 "bytes" 22 "compress/gzip" 23 "crypto/sha256" 24 "crypto/tls" 25 "crypto/x509" 26 "encoding/pem" 27 "flag" 28 "fmt" 29 "go/format" 30 "io" 31 "log" 32 "net/http" 33 "os" 34 "path" 35 "sort" 36 "strings" 37 "time" 38 ) 39 40 func main() { 41 var output = flag.String("output", "root_ios.go", "file name to write") 42 var version = flag.String("version", "", "security_certificates version") 43 flag.Parse() 44 if *version == "" { 45 log.Fatal("Select the latest security_certificates version from " + 46 "https://opensource.apple.com/source/security_certificates/") 47 } 48 49 url := "https://opensource.apple.com/tarballs/security_certificates/security_certificates-%s.tar.gz" 50 hc := &http.Client{Timeout: 1 * time.Minute} 51 resp, err := hc.Get(fmt.Sprintf(url, *version)) 52 if err != nil { 53 log.Fatal(err) 54 } 55 defer resp.Body.Close() 56 if resp.StatusCode != http.StatusOK { 57 log.Fatalf("HTTP status not OK: %s", resp.Status) 58 } 59 60 zr, err := gzip.NewReader(resp.Body) 61 if err != nil { 62 log.Fatal(err) 63 } 64 defer zr.Close() 65 66 var certs []*x509.Certificate 67 pool := x509.NewCertPool() 68 69 tr := tar.NewReader(zr) 70 for { 71 hdr, err := tr.Next() 72 if err == io.EOF { 73 break 74 } 75 if err != nil { 76 log.Fatal(err) 77 } 78 79 rootsDirectory := fmt.Sprintf("security_certificates-%s/certificates/roots/", *version) 80 if dir, file := path.Split(hdr.Name); hdr.Typeflag != tar.TypeReg || 81 dir != rootsDirectory || strings.HasPrefix(file, ".") { 82 continue 83 } 84 85 der, err := io.ReadAll(tr) 86 if err != nil { 87 log.Fatal(err) 88 } 89 90 c, err := x509.ParseCertificate(der) 91 if err != nil { 92 log.Printf("Failed to parse certificate %q: %v", hdr.Name, err) 93 continue 94 } 95 96 certs = append(certs, c) 97 pool.AddCert(c) 98 } 99 100 // Quick smoke test to check the pool is well formed, and that we didn't end 101 // up trusting roots in the removed folder. 102 for _, c := range certs { 103 if c.Subject.CommonName == "Symantec Class 2 Public Primary Certification Authority - G4" { 104 log.Fatal("The pool includes a removed root!") 105 } 106 } 107 conn, err := tls.Dial("tcp", "mail.google.com:443", &tls.Config{ 108 RootCAs: pool, 109 }) 110 if err != nil { 111 log.Fatal(err) 112 } 113 conn.Close() 114 115 certName := func(c *x509.Certificate) string { 116 if c.Subject.CommonName != "" { 117 return c.Subject.CommonName 118 } 119 if len(c.Subject.OrganizationalUnit) > 0 { 120 return c.Subject.OrganizationalUnit[0] 121 } 122 return c.Subject.Organization[0] 123 } 124 sort.Slice(certs, func(i, j int) bool { 125 if strings.ToLower(certName(certs[i])) != strings.ToLower(certName(certs[j])) { 126 return strings.ToLower(certName(certs[i])) < strings.ToLower(certName(certs[j])) 127 } 128 if !certs[i].NotBefore.Equal(certs[j].NotBefore) { 129 return certs[i].NotBefore.Before(certs[j].NotBefore) 130 } 131 fi, fj := sha256.Sum256(certs[i].Raw), sha256.Sum256(certs[j].Raw) 132 return bytes.Compare(fi[:], fj[:]) < 0 133 }) 134 135 out := new(bytes.Buffer) 136 fmt.Fprintf(out, header, *version) 137 fmt.Fprintf(out, "const systemRootsPEM = `\n") 138 139 for _, c := range certs { 140 fmt.Fprintf(out, "# %q\n", certName(c)) 141 h := sha256.Sum256(c.Raw) 142 fmt.Fprintf(out, "# % X\n", h[:len(h)/2]) 143 fmt.Fprintf(out, "# % X\n", h[len(h)/2:]) 144 b := &pem.Block{ 145 Type: "CERTIFICATE", 146 Bytes: c.Raw, 147 } 148 if err := pem.Encode(out, b); err != nil { 149 log.Fatal(err) 150 } 151 } 152 153 fmt.Fprintf(out, "`") 154 155 source, err := format.Source(out.Bytes()) 156 if err != nil { 157 log.Fatal(err) 158 } 159 if err := os.WriteFile(*output, source, 0644); err != nil { 160 log.Fatal(err) 161 } 162 } 163 164 const header = `// Code generated by root_ios_gen.go -version %s; DO NOT EDIT. 165 // Update the version in root.go and regenerate with "go generate". 166 167 // +build ios 168 // +build !x509omitbundledroots 169 170 package x509 171 172 func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) { 173 return nil, nil 174 } 175 176 func loadSystemRoots() (*CertPool, error) { 177 p := NewCertPool() 178 p.AppendCertsFromPEM([]byte(systemRootsPEM)) 179 return p, nil 180 } 181 `