github.com/zmap/zcrypto@v0.0.0-20240512203510-0fef58d9a9db/ct/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  //go:build ignore
     6  // +build ignore
     7  
     8  // Generates root_darwin_armx.go.
     9  //
    10  // As of iOS 8, there is no API for querying the system trusted X.509 root
    11  // certificates. We could use SecTrustEvaluate to verify that a trust chain
    12  // exists for a certificate, but the x509 API requires returning the entire
    13  // chain.
    14  //
    15  // Apple publishes the list of trusted root certificates for iOS on
    16  // support.apple.com. So we parse the list and extract the certificates from
    17  // an OS X machine and embed them into the x509 package.
    18  package main
    19  
    20  import (
    21  	"bytes"
    22  	"crypto/x509"
    23  	"encoding/pem"
    24  	"flag"
    25  	"fmt"
    26  	"go/format"
    27  	"io/ioutil"
    28  	"log"
    29  	"math/big"
    30  	"net/http"
    31  	"os/exec"
    32  	"strings"
    33  )
    34  
    35  var output = flag.String("output", "root_darwin_armx.go", "file name to write")
    36  
    37  func main() {
    38  	certs, err := selectCerts()
    39  	if err != nil {
    40  		log.Fatal(err)
    41  	}
    42  
    43  	buf := new(bytes.Buffer)
    44  
    45  	fmt.Fprintf(buf, "// Created by root_darwin_arm_gen --output %s; DO NOT EDIT\n", *output)
    46  	fmt.Fprintf(buf, "%s", header)
    47  
    48  	fmt.Fprintf(buf, "const systemRootsPEM = `\n")
    49  	for _, cert := range certs {
    50  		b := &pem.Block{
    51  			Type:  "CERTIFICATE",
    52  			Bytes: cert.Raw,
    53  		}
    54  		if err := pem.Encode(buf, b); err != nil {
    55  			log.Fatal(err)
    56  		}
    57  	}
    58  	fmt.Fprintf(buf, "`")
    59  
    60  	source, err := format.Source(buf.Bytes())
    61  	if err != nil {
    62  		log.Fatal("source format error:", err)
    63  	}
    64  	if err := ioutil.WriteFile(*output, source, 0644); err != nil {
    65  		log.Fatal(err)
    66  	}
    67  }
    68  
    69  func selectCerts() ([]*x509.Certificate, error) {
    70  	ids, err := fetchCertIDs()
    71  	if err != nil {
    72  		return nil, err
    73  	}
    74  
    75  	scerts, err := sysCerts()
    76  	if err != nil {
    77  		return nil, err
    78  	}
    79  
    80  	var certs []*x509.Certificate
    81  	for _, id := range ids {
    82  		sn, ok := big.NewInt(0).SetString(id.serialNumber, 0) // 0x prefix selects hex
    83  		if !ok {
    84  			return nil, fmt.Errorf("invalid serial number: %q", id.serialNumber)
    85  		}
    86  		ski, ok := big.NewInt(0).SetString(id.subjectKeyID, 0)
    87  		if !ok {
    88  			return nil, fmt.Errorf("invalid Subject Key ID: %q", id.subjectKeyID)
    89  		}
    90  
    91  		for _, cert := range scerts {
    92  			if sn.Cmp(cert.SerialNumber) != 0 {
    93  				continue
    94  			}
    95  			cski := big.NewInt(0).SetBytes(cert.SubjectKeyId)
    96  			if ski.Cmp(cski) != 0 {
    97  				continue
    98  			}
    99  			certs = append(certs, cert)
   100  			break
   101  		}
   102  	}
   103  	return certs, nil
   104  }
   105  
   106  func sysCerts() (certs []*x509.Certificate, err error) {
   107  	cmd := exec.Command("/usr/bin/security", "find-certificate", "-a", "-p", "/System/Library/Keychains/SystemRootCertificates.keychain")
   108  	data, err := cmd.Output()
   109  	if err != nil {
   110  		return nil, err
   111  	}
   112  	for len(data) > 0 {
   113  		var block *pem.Block
   114  		block, data = pem.Decode(data)
   115  		if block == nil {
   116  			break
   117  		}
   118  		if block.Type != "CERTIFICATE" || len(block.Headers) != 0 {
   119  			continue
   120  		}
   121  
   122  		cert, err := x509.ParseCertificate(block.Bytes)
   123  		if err != nil {
   124  			continue
   125  		}
   126  		certs = append(certs, cert)
   127  	}
   128  	return certs, nil
   129  }
   130  
   131  type certID struct {
   132  	serialNumber string
   133  	subjectKeyID string
   134  }
   135  
   136  // fetchCertIDs fetches IDs of iOS X509 certificates from apple.com.
   137  func fetchCertIDs() ([]certID, error) {
   138  	resp, err := http.Get("https://support.apple.com/en-us/HT204132")
   139  	if err != nil {
   140  		return nil, err
   141  	}
   142  	defer resp.Body.Close()
   143  	body, err := ioutil.ReadAll(resp.Body)
   144  	if err != nil {
   145  		return nil, err
   146  	}
   147  	text := string(body)
   148  	text = text[strings.Index(text, "<section id=trusted"):]
   149  	text = text[:strings.Index(text, "</section>")]
   150  
   151  	lines := strings.Split(text, "\n")
   152  	var ids []certID
   153  	var id certID
   154  	for i, ln := range lines {
   155  		if i == len(lines)-1 {
   156  			break
   157  		}
   158  		const sn = "Serial Number:"
   159  		if ln == sn {
   160  			id.serialNumber = "0x" + strings.Replace(strings.TrimSpace(lines[i+1]), ":", "", -1)
   161  			continue
   162  		}
   163  		if strings.HasPrefix(ln, sn) {
   164  			// extract hex value from parentheses.
   165  			id.serialNumber = ln[strings.Index(ln, "(")+1 : len(ln)-1]
   166  			continue
   167  		}
   168  		if strings.TrimSpace(ln) == "X509v3 Subject Key Identifier:" {
   169  			id.subjectKeyID = "0x" + strings.Replace(strings.TrimSpace(lines[i+1]), ":", "", -1)
   170  			ids = append(ids, id)
   171  			id = certID{}
   172  		}
   173  	}
   174  	return ids, nil
   175  }
   176  
   177  const header = `
   178  // Copyright 2015 The Go Authors. All rights reserved.
   179  // Use of this source code is governed by a BSD-style
   180  // license that can be found in the LICENSE file.
   181  
   182  // +build cgo
   183  // +build darwin
   184  // +build arm arm64
   185  
   186  package x509
   187  
   188  func loadSystemRoots() (*CertPool, error) {
   189  	p := NewCertPool()
   190  	p.AppendCertsFromPEM([]byte(systemRootsPEM))
   191  	return p, nil
   192  }
   193  `