1
0
mirror of https://github.com/golang/go synced 2024-11-12 03:50:21 -07:00

crypto/x509: use the platform verifier on iOS

Use the same certificate verification APIs on iOS as on macOS (they
share the same APIs, so we should be able to transparently use them
on both.)

Updates #46287
Fixes #38843

Change-Id: If70f99b0823dd5fa747c42ff4f20c3b625605327
Reviewed-on: https://go-review.googlesource.com/c/go/+/353403
Trust: Roland Shoemaker <roland@golang.org>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
Run-TryBot: Roland Shoemaker <roland@golang.org>
This commit is contained in:
Roland Shoemaker 2021-10-01 09:14:10 -07:00
parent 09e8de70c2
commit b74f2efc47
10 changed files with 5 additions and 5115 deletions

11
src/cmd/dist/test.go vendored
View File

@ -499,17 +499,6 @@ func (t *tester) registerTests() {
})
}
if t.iOS() && !t.compileOnly {
t.tests = append(t.tests, distTest{
name: "x509omitbundledroots",
heading: "crypto/x509 without bundled roots",
fn: func(dt *distTest) error {
t.addCmd(dt, "src", t.goTest(), t.timeout(300), "-tags=x509omitbundledroots", "-run=OmitBundledRoots", "crypto/x509")
return nil
},
})
}
// Test ios/amd64 for the iOS simulator.
if goos == "darwin" && goarch == "amd64" && t.cgoEnabled {
t.tests = append(t.tests, distTest{

View File

@ -108,6 +108,8 @@ func SystemCertPool() (*CertPool, error) {
return nil, errors.New("crypto/x509: system root pool is not available on Windows")
} else if runtime.GOOS == "darwin" {
return nil, errors.New("crypto/x509: system root pool is not available on macOS")
} else if runtime.GOOS == "ios" {
return nil, errors.New("crypto/x509: system root pool is not available on iOS")
}
if sysRoots := systemRootsPool(); sysRoots != nil {

View File

@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build !ios
package x509
import (

File diff suppressed because it is too large Load Diff

View File

@ -1,180 +0,0 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build ignore
// Generates root_ios.go.
//
// As of iOS 13, there is no API for querying the system trusted X.509 root
// certificates.
//
// Apple publishes the trusted root certificates for iOS and macOS on
// opensource.apple.com so we embed them into the x509 package.
//
// Note that this ignores distrusted and revoked certificates.
package main
import (
"archive/tar"
"bytes"
"compress/gzip"
"crypto/sha256"
"crypto/tls"
"crypto/x509"
"encoding/pem"
"flag"
"fmt"
"go/format"
"io"
"log"
"net/http"
"os"
"path"
"sort"
"strings"
"time"
)
func main() {
var output = flag.String("output", "root_ios.go", "file name to write")
var version = flag.String("version", "", "security_certificates version")
flag.Parse()
if *version == "" {
log.Fatal("Select the latest security_certificates version from " +
"https://opensource.apple.com/source/security_certificates/")
}
url := "https://opensource.apple.com/tarballs/security_certificates/security_certificates-%s.tar.gz"
hc := &http.Client{Timeout: 1 * time.Minute}
resp, err := hc.Get(fmt.Sprintf(url, *version))
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
log.Fatalf("HTTP status not OK: %s", resp.Status)
}
zr, err := gzip.NewReader(resp.Body)
if err != nil {
log.Fatal(err)
}
defer zr.Close()
var certs []*x509.Certificate
pool := x509.NewCertPool()
tr := tar.NewReader(zr)
for {
hdr, err := tr.Next()
if err == io.EOF {
break
}
if err != nil {
log.Fatal(err)
}
rootsDirectory := fmt.Sprintf("security_certificates-%s/certificates/roots/", *version)
if dir, file := path.Split(hdr.Name); hdr.Typeflag != tar.TypeReg ||
dir != rootsDirectory || strings.HasPrefix(file, ".") {
continue
}
der, err := io.ReadAll(tr)
if err != nil {
log.Fatal(err)
}
c, err := x509.ParseCertificate(der)
if err != nil {
log.Printf("Failed to parse certificate %q: %v", hdr.Name, err)
continue
}
certs = append(certs, c)
pool.AddCert(c)
}
// Quick smoke test to check the pool is well formed, and that we didn't end
// up trusting roots in the removed folder.
for _, c := range certs {
if c.Subject.CommonName == "Symantec Class 2 Public Primary Certification Authority - G4" {
log.Fatal("The pool includes a removed root!")
}
}
conn, err := tls.Dial("tcp", "mail.google.com:443", &tls.Config{
RootCAs: pool,
})
if err != nil {
log.Fatal(err)
}
conn.Close()
certName := func(c *x509.Certificate) string {
if c.Subject.CommonName != "" {
return c.Subject.CommonName
}
if len(c.Subject.OrganizationalUnit) > 0 {
return c.Subject.OrganizationalUnit[0]
}
return c.Subject.Organization[0]
}
sort.Slice(certs, func(i, j int) bool {
if strings.ToLower(certName(certs[i])) != strings.ToLower(certName(certs[j])) {
return strings.ToLower(certName(certs[i])) < strings.ToLower(certName(certs[j]))
}
if !certs[i].NotBefore.Equal(certs[j].NotBefore) {
return certs[i].NotBefore.Before(certs[j].NotBefore)
}
fi, fj := sha256.Sum256(certs[i].Raw), sha256.Sum256(certs[j].Raw)
return bytes.Compare(fi[:], fj[:]) < 0
})
out := new(bytes.Buffer)
fmt.Fprintf(out, header, *version)
fmt.Fprintf(out, "const systemRootsPEM = `\n")
for _, c := range certs {
fmt.Fprintf(out, "# %q\n", certName(c))
h := sha256.Sum256(c.Raw)
fmt.Fprintf(out, "# % X\n", h[:len(h)/2])
fmt.Fprintf(out, "# % X\n", h[len(h)/2:])
b := &pem.Block{
Type: "CERTIFICATE",
Bytes: c.Raw,
}
if err := pem.Encode(out, b); err != nil {
log.Fatal(err)
}
}
fmt.Fprintf(out, "`")
source, err := format.Source(out.Bytes())
if err != nil {
log.Fatal(err)
}
if err := os.WriteFile(*output, source, 0644); err != nil {
log.Fatal(err)
}
}
const header = `// Code generated by root_ios_gen.go -version %s; DO NOT EDIT.
// Update the version in root.go and regenerate with "go generate".
//go:build ios && !x509omitbundledroots
// +build ios,!x509omitbundledroots
package x509
func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) {
return nil, nil
}
func loadSystemRoots() (*CertPool, error) {
p := NewCertPool()
p.AppendCertsFromPEM([]byte(systemRootsPEM))
return p, nil
}
`

View File

@ -1,25 +0,0 @@
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build ((darwin && arm64) || (darwin && amd64 && ios)) && x509omitbundledroots
// This file provides the loadSystemRoots func when the
// "x509omitbundledroots" build tag has disabled bundling a copy,
// which currently on happens on darwin/arm64 (root_darwin_arm64.go).
// This then saves 256 KiB of binary size and another 560 KiB of
// runtime memory size retaining the parsed roots forever. Constrained
// environments can construct minimal x509 root CertPools on the fly
// in the crypto/tls.Config.VerifyPeerCertificate hook.
package x509
import "errors"
func loadSystemRoots() (*CertPool, error) {
return nil, errors.New("x509: system root bundling disabled")
}
func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) {
return nil, nil
}

View File

@ -1,22 +0,0 @@
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build ((darwin && arm64) || (darwin && amd64 && ios)) && x509omitbundledroots
package x509
import (
"strings"
"testing"
)
func TestOmitBundledRoots(t *testing.T) {
cp, err := loadSystemRoots()
if err == nil {
t.Fatalf("loadSystemRoots = (pool %p, error %v); want non-nil error", cp, err)
}
if !strings.Contains(err.Error(), "root bundling disabled") {
t.Errorf("unexpected error doesn't mention bundling: %v", err)
}
}

View File

@ -742,7 +742,7 @@ func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err e
}
// Use platform verifiers, where available
if opts.Roots == nil && (runtime.GOOS == "windows" || runtime.GOOS == "darwin") {
if opts.Roots == nil && (runtime.GOOS == "windows" || runtime.GOOS == "darwin" || runtime.GOOS == "ios") {
return c.systemVerify(&opts)
}

View File

@ -1836,7 +1836,7 @@ func TestLongChain(t *testing.T) {
}
func TestSystemRootsError(t *testing.T) {
if runtime.GOOS == "windows" || runtime.GOOS == "darwin" {
if runtime.GOOS == "windows" || runtime.GOOS == "darwin" || runtime.GOOS == "ios" {
t.Skip("Windows and darwin do not use (or support) systemRoots")
}

View File

@ -1975,7 +1975,7 @@ func TestMultipleRDN(t *testing.T) {
}
func TestSystemCertPool(t *testing.T) {
if runtime.GOOS == "windows" || runtime.GOOS == "darwin" {
if runtime.GOOS == "windows" || runtime.GOOS == "darwin" || runtime.GOOS == "ios" {
t.Skip("not implemented on Windows (Issue 16736, 18609) or darwin (Issue 46287)")
}
a, err := SystemCertPool()