...

Source file src/github.com/google/certificate-transparency-go/x509/root_darwin_arm_gen.go

Documentation: github.com/google/certificate-transparency-go/x509

     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/sha256"
    23  	"encoding/hex"
    24  	"encoding/pem"
    25  	"flag"
    26  	"fmt"
    27  	"go/format"
    28  	"io"
    29  	"log"
    30  	"net/http"
    31  	"os"
    32  	"os/exec"
    33  	"regexp"
    34  	"strings"
    35  
    36  	"github.com/google/certificate-transparency-go/x509"
    37  )
    38  
    39  var output = flag.String("output", "root_darwin_armx.go", "file name to write")
    40  
    41  func main() {
    42  	certs, err := selectCerts()
    43  	if err != nil {
    44  		log.Fatal(err)
    45  	}
    46  
    47  	buf := new(bytes.Buffer)
    48  
    49  	fmt.Fprintf(buf, "// Code generated by root_darwin_arm_gen --output %s; DO NOT EDIT.\n", *output)
    50  	fmt.Fprintf(buf, "%s", header)
    51  
    52  	fmt.Fprintf(buf, "const systemRootsPEM = `\n")
    53  	for _, cert := range certs {
    54  		b := &pem.Block{
    55  			Type:  "CERTIFICATE",
    56  			Bytes: cert.Raw,
    57  		}
    58  		if err := pem.Encode(buf, b); err != nil {
    59  			log.Fatal(err)
    60  		}
    61  	}
    62  	fmt.Fprintf(buf, "`")
    63  
    64  	source, err := format.Source(buf.Bytes())
    65  	if err != nil {
    66  		log.Fatal("source format error:", err)
    67  	}
    68  	if err := os.WriteFile(*output, source, 0644); err != nil {
    69  		log.Fatal(err)
    70  	}
    71  }
    72  
    73  func selectCerts() ([]*x509.Certificate, error) {
    74  	ids, err := fetchCertIDs()
    75  	if err != nil {
    76  		return nil, err
    77  	}
    78  
    79  	scerts, err := sysCerts()
    80  	if err != nil {
    81  		return nil, err
    82  	}
    83  
    84  	var certs []*x509.Certificate
    85  	for _, id := range ids {
    86  		if c, ok := scerts[id.fingerprint]; ok {
    87  			certs = append(certs, c)
    88  		} else {
    89  			fmt.Printf("WARNING: cannot find certificate: %s (fingerprint: %s)\n", id.name, id.fingerprint)
    90  		}
    91  	}
    92  	return certs, nil
    93  }
    94  
    95  func sysCerts() (certs map[string]*x509.Certificate, err error) {
    96  	cmd := exec.Command("/usr/bin/security", "find-certificate", "-a", "-p", "/System/Library/Keychains/SystemRootCertificates.keychain")
    97  	data, err := cmd.Output()
    98  	if err != nil {
    99  		return nil, err
   100  	}
   101  	certs = make(map[string]*x509.Certificate)
   102  	for len(data) > 0 {
   103  		var block *pem.Block
   104  		block, data = pem.Decode(data)
   105  		if block == nil {
   106  			break
   107  		}
   108  		if block.Type != "CERTIFICATE" || len(block.Headers) != 0 {
   109  			continue
   110  		}
   111  
   112  		cert, err := x509.ParseCertificate(block.Bytes)
   113  		if err != nil {
   114  			continue
   115  		}
   116  
   117  		fingerprint := sha256.Sum256(cert.Raw)
   118  		certs[hex.EncodeToString(fingerprint[:])] = cert
   119  	}
   120  	return certs, nil
   121  }
   122  
   123  type certID struct {
   124  	name        string
   125  	fingerprint string
   126  }
   127  
   128  // fetchCertIDs fetches IDs of iOS X509 certificates from apple.com.
   129  func fetchCertIDs() ([]certID, error) {
   130  	// Download the iOS 11 support page. The index for all iOS versions is here:
   131  	// https://support.apple.com/en-us/HT204132
   132  	resp, err := http.Get("https://support.apple.com/en-us/HT208125")
   133  	if err != nil {
   134  		return nil, err
   135  	}
   136  	defer resp.Body.Close()
   137  	body, err := io.ReadAll(resp.Body)
   138  	if err != nil {
   139  		return nil, err
   140  	}
   141  	text := string(body)
   142  	text = text[strings.Index(text, "<div id=trusted"):]
   143  	text = text[:strings.Index(text, "</div>")]
   144  
   145  	var ids []certID
   146  	cols := make(map[string]int)
   147  	for i, rowmatch := range regexp.MustCompile("(?s)<tr>(.*?)</tr>").FindAllStringSubmatch(text, -1) {
   148  		row := rowmatch[1]
   149  		if i == 0 {
   150  			// Parse table header row to extract column names
   151  			for i, match := range regexp.MustCompile("(?s)<th>(.*?)</th>").FindAllStringSubmatch(row, -1) {
   152  				cols[match[1]] = i
   153  			}
   154  			continue
   155  		}
   156  
   157  		values := regexp.MustCompile("(?s)<td>(.*?)</td>").FindAllStringSubmatch(row, -1)
   158  		name := values[cols["Certificate name"]][1]
   159  		fingerprint := values[cols["Fingerprint (SHA-256)"]][1]
   160  		fingerprint = strings.ReplaceAll(fingerprint, "<br>", "")
   161  		fingerprint = strings.ReplaceAll(fingerprint, "\n", "")
   162  		fingerprint = strings.ReplaceAll(fingerprint, " ", "")
   163  		fingerprint = strings.ToLower(fingerprint)
   164  
   165  		ids = append(ids, certID{
   166  			name:        name,
   167  			fingerprint: fingerprint,
   168  		})
   169  	}
   170  	return ids, nil
   171  }
   172  
   173  const header = `
   174  // Copyright 2015 The Go Authors. All rights reserved.
   175  // Use of this source code is governed by a BSD-style
   176  // license that can be found in the LICENSE file.
   177  
   178  // +build cgo
   179  // +build darwin
   180  // +build arm arm64 ios
   181  
   182  package x509
   183  
   184  func loadSystemRoots() (*CertPool, error) {
   185  	p := NewCertPool()
   186  	p.AppendCertsFromPEM([]byte(systemRootsPEM))
   187  	return p, nil
   188  }
   189  `
   190  

View as plain text