Commit ac53c967 authored by Giovanni Bajo's avatar Giovanni Bajo Committed by Brad Fitzpatrick

crypto/x509: update iOS root certs.

Apple changed the format of its support page, so we need to
restructure the HTML parser. The HTML table is now parsed using
regular expressions, and certificates are then found in macOS
trust store by their fingerprint.

Fixes #22181

Change-Id: I29e7a40d37770bb005d728f1832299c528691f7e
Reviewed-on: https://go-review.googlesource.com/77252
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarAdam Langley <agl@golang.org>
parent 3ea72fb1
...@@ -18,16 +18,18 @@ package main ...@@ -18,16 +18,18 @@ package main
import ( import (
"bytes" "bytes"
"crypto/sha256"
"crypto/x509" "crypto/x509"
"encoding/hex"
"encoding/pem" "encoding/pem"
"flag" "flag"
"fmt" "fmt"
"go/format" "go/format"
"io/ioutil" "io/ioutil"
"log" "log"
"math/big"
"net/http" "net/http"
"os/exec" "os/exec"
"regexp"
"strings" "strings"
) )
...@@ -41,7 +43,7 @@ func main() { ...@@ -41,7 +43,7 @@ func main() {
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
fmt.Fprintf(buf, "// Created by root_darwin_arm_gen --output %s; DO NOT EDIT\n", *output) fmt.Fprintf(buf, "// Code generated by root_darwin_arm_gen --output %s; DO NOT EDIT.\n", *output)
fmt.Fprintf(buf, "%s", header) fmt.Fprintf(buf, "%s", header)
fmt.Fprintf(buf, "const systemRootsPEM = `\n") fmt.Fprintf(buf, "const systemRootsPEM = `\n")
...@@ -78,36 +80,22 @@ func selectCerts() ([]*x509.Certificate, error) { ...@@ -78,36 +80,22 @@ func selectCerts() ([]*x509.Certificate, error) {
var certs []*x509.Certificate var certs []*x509.Certificate
for _, id := range ids { for _, id := range ids {
sn, ok := big.NewInt(0).SetString(id.serialNumber, 0) // 0x prefix selects hex if c, ok := scerts[id.fingerprint]; ok {
if !ok { certs = append(certs, c)
return nil, fmt.Errorf("invalid serial number: %q", id.serialNumber) } else {
} fmt.Printf("WARNING: cannot find certificate: %s (fingerprint: %s)\n", id.name, id.fingerprint)
ski, ok := big.NewInt(0).SetString(id.subjectKeyID, 0)
if !ok {
return nil, fmt.Errorf("invalid Subject Key ID: %q", id.subjectKeyID)
}
for _, cert := range scerts {
if sn.Cmp(cert.SerialNumber) != 0 {
continue
}
cski := big.NewInt(0).SetBytes(cert.SubjectKeyId)
if ski.Cmp(cski) != 0 {
continue
}
certs = append(certs, cert)
break
} }
} }
return certs, nil return certs, nil
} }
func sysCerts() (certs []*x509.Certificate, err error) { func sysCerts() (certs map[string]*x509.Certificate, err error) {
cmd := exec.Command("/usr/bin/security", "find-certificate", "-a", "-p", "/System/Library/Keychains/SystemRootCertificates.keychain") cmd := exec.Command("/usr/bin/security", "find-certificate", "-a", "-p", "/System/Library/Keychains/SystemRootCertificates.keychain")
data, err := cmd.Output() data, err := cmd.Output()
if err != nil { if err != nil {
return nil, err return nil, err
} }
certs = make(map[string]*x509.Certificate)
for len(data) > 0 { for len(data) > 0 {
var block *pem.Block var block *pem.Block
block, data = pem.Decode(data) block, data = pem.Decode(data)
...@@ -122,19 +110,23 @@ func sysCerts() (certs []*x509.Certificate, err error) { ...@@ -122,19 +110,23 @@ func sysCerts() (certs []*x509.Certificate, err error) {
if err != nil { if err != nil {
continue continue
} }
certs = append(certs, cert)
fingerprint := sha256.Sum256(cert.Raw)
certs[hex.EncodeToString(fingerprint[:])] = cert
} }
return certs, nil return certs, nil
} }
type certID struct { type certID struct {
serialNumber string name string
subjectKeyID string fingerprint string
} }
// fetchCertIDs fetches IDs of iOS X509 certificates from apple.com. // fetchCertIDs fetches IDs of iOS X509 certificates from apple.com.
func fetchCertIDs() ([]certID, error) { func fetchCertIDs() ([]certID, error) {
resp, err := http.Get("https://support.apple.com/en-us/HT204132") // Download the iOS 11 support page. The index for all iOS versions is here:
// https://support.apple.com/en-us/HT204132
resp, err := http.Get("https://support.apple.com/en-us/HT208125")
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -144,31 +136,33 @@ func fetchCertIDs() ([]certID, error) { ...@@ -144,31 +136,33 @@ func fetchCertIDs() ([]certID, error) {
return nil, err return nil, err
} }
text := string(body) text := string(body)
text = text[strings.Index(text, "<section id=trusted"):] text = text[strings.Index(text, "<div id=trusted"):]
text = text[:strings.Index(text, "</section>")] text = text[:strings.Index(text, "</div>")]
lines := strings.Split(text, "\n")
var ids []certID var ids []certID
var id certID cols := make(map[string]int)
for i, ln := range lines { for i, rowmatch := range regexp.MustCompile("(?s)<tr>(.*?)</tr>").FindAllStringSubmatch(text, -1) {
if i == len(lines)-1 { row := rowmatch[1]
break if i == 0 {
} // Parse table header row to extract column names
const sn = "Serial Number:" for i, match := range regexp.MustCompile("(?s)<th>(.*?)</th>").FindAllStringSubmatch(row, -1) {
if ln == sn { cols[match[1]] = i
id.serialNumber = "0x" + strings.Replace(strings.TrimSpace(lines[i+1]), ":", "", -1) }
continue
}
if strings.HasPrefix(ln, sn) {
// extract hex value from parentheses.
id.serialNumber = ln[strings.Index(ln, "(")+1 : len(ln)-1]
continue continue
} }
if strings.TrimSpace(ln) == "X509v3 Subject Key Identifier:" {
id.subjectKeyID = "0x" + strings.Replace(strings.TrimSpace(lines[i+1]), ":", "", -1) values := regexp.MustCompile("(?s)<td>(.*?)</td>").FindAllStringSubmatch(row, -1)
ids = append(ids, id) name := values[cols["Certificate name"]][1]
id = certID{} fingerprint := values[cols["Fingerprint (SHA-256)"]][1]
} fingerprint = strings.Replace(fingerprint, "<br>", "", -1)
fingerprint = strings.Replace(fingerprint, "\n", "", -1)
fingerprint = strings.Replace(fingerprint, " ", "", -1)
fingerprint = strings.ToLower(fingerprint)
ids = append(ids, certID{
name: name,
fingerprint: fingerprint,
})
} }
return ids, nil return ids, nil
} }
...@@ -180,7 +174,7 @@ const header = ` ...@@ -180,7 +174,7 @@ const header = `
// +build cgo // +build cgo
// +build darwin // +build darwin
// +build arm arm64 // +build arm arm64 ios
package x509 package x509
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment