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