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:
parent
09e8de70c2
commit
b74f2efc47
11
src/cmd/dist/test.go
vendored
11
src/cmd/dist/test.go
vendored
@ -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{
|
||||
|
@ -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 {
|
||||
|
@ -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
@ -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
|
||||
}
|
||||
`
|
@ -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
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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")
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
|
Loading…
Reference in New Issue
Block a user