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  `