summaryrefslogtreecommitdiffstats
path: root/dependencies/pkg/mod/golang.org/x/exp@v0.0.0-20220613132600-b0d781184e0d/cmd/macos-roots-test/root_darwin.go
diff options
context:
space:
mode:
Diffstat (limited to 'dependencies/pkg/mod/golang.org/x/exp@v0.0.0-20220613132600-b0d781184e0d/cmd/macos-roots-test/root_darwin.go')
-rw-r--r--dependencies/pkg/mod/golang.org/x/exp@v0.0.0-20220613132600-b0d781184e0d/cmd/macos-roots-test/root_darwin.go174
1 files changed, 174 insertions, 0 deletions
diff --git a/dependencies/pkg/mod/golang.org/x/exp@v0.0.0-20220613132600-b0d781184e0d/cmd/macos-roots-test/root_darwin.go b/dependencies/pkg/mod/golang.org/x/exp@v0.0.0-20220613132600-b0d781184e0d/cmd/macos-roots-test/root_darwin.go
new file mode 100644
index 0000000..b5bf0f7
--- /dev/null
+++ b/dependencies/pkg/mod/golang.org/x/exp@v0.0.0-20220613132600-b0d781184e0d/cmd/macos-roots-test/root_darwin.go
@@ -0,0 +1,174 @@
+// Copyright 2013 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.
+
+package main
+
+import (
+ "bytes"
+ "crypto/x509"
+ "encoding/pem"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "os/user"
+ "path/filepath"
+ "sync"
+)
+
+var debugDarwinRoots = true
+
+// This code is only used when compiling without cgo.
+// It is here, instead of root_nocgo_darwin.go, so that tests can check it
+// even if the tests are run with cgo enabled.
+// The linker will not include these unused functions in binaries built with cgo enabled.
+
+// execSecurityRoots finds the macOS list of trusted root certificates
+// using only command-line tools. This is our fallback path when cgo isn't available.
+//
+// The strategy is as follows:
+//
+// 1. Run "security find-certificate" to dump the list of system root
+// CAs in PEM format.
+//
+// 2. For each dumped cert, conditionally verify it with "security
+// verify-cert" if that cert was not in the SystemRootCertificates
+// keychain, which can't have custom trust policies.
+//
+// We need to run "verify-cert" for all certificates not in SystemRootCertificates
+// because there might be certificates in the keychains without a corresponding
+// trust entry, in which case the logic is complicated (see root_cgo_darwin.go).
+//
+// TODO: actually parse the "trust-settings-export" output and apply the full
+// logic. See Issue 26830.
+func execSecurityRoots() (*x509.CertPool, error) {
+ keychains := []string{"/Library/Keychains/System.keychain"}
+
+ // Note that this results in trusting roots from $HOME/... (the environment
+ // variable), which might not be expected.
+ u, err := user.Current()
+ if err != nil {
+ if debugDarwinRoots {
+ fmt.Printf("crypto/x509: get current user: %v\n", err)
+ }
+ } else {
+ keychains = append(keychains,
+ filepath.Join(u.HomeDir, "/Library/Keychains/login.keychain"),
+
+ // Fresh installs of Sierra use a slightly different path for the login keychain
+ filepath.Join(u.HomeDir, "/Library/Keychains/login.keychain-db"),
+ )
+ }
+
+ var (
+ mu sync.Mutex
+ roots = x509.NewCertPool()
+ numVerified int // number of execs of 'security verify-cert', for debug stats
+ wg sync.WaitGroup
+ verifyCh = make(chan *x509.Certificate)
+ )
+
+ // Using 4 goroutines to pipe into verify-cert seems to be
+ // about the best we can do. The verify-cert binary seems to
+ // just RPC to another server with coarse locking anyway, so
+ // running 16 at a time for instance doesn't help at all.
+ for i := 0; i < 4; i++ {
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ for cert := range verifyCh {
+ valid := verifyCertWithSystem(cert)
+
+ mu.Lock()
+ numVerified++
+ if valid {
+ roots.AddCert(cert)
+ }
+ mu.Unlock()
+ }
+ }()
+ }
+ err = forEachCertInKeychains(keychains, func(cert *x509.Certificate) {
+ verifyCh <- cert
+ })
+ if err != nil {
+ return nil, err
+ }
+ close(verifyCh)
+ wg.Wait()
+
+ if debugDarwinRoots {
+ fmt.Printf("crypto/x509: ran security verify-cert %d times\n", numVerified)
+ }
+
+ err = forEachCertInKeychains([]string{
+ "/System/Library/Keychains/SystemRootCertificates.keychain",
+ }, roots.AddCert)
+ if err != nil {
+ return nil, err
+ }
+
+ return roots, nil
+}
+
+func forEachCertInKeychains(paths []string, f func(*x509.Certificate)) error {
+ args := append([]string{"find-certificate", "-a", "-p"}, paths...)
+ cmd := exec.Command("/usr/bin/security", args...)
+ data, err := cmd.Output()
+ if err != nil {
+ return err
+ }
+ for len(data) > 0 {
+ var block *pem.Block
+ block, data = pem.Decode(data)
+ if block == nil {
+ break
+ }
+ if block.Type != "CERTIFICATE" || len(block.Headers) != 0 {
+ continue
+ }
+ cert, err := x509.ParseCertificate(block.Bytes)
+ if err != nil {
+ continue
+ }
+ f(cert)
+ }
+ return nil
+}
+
+func verifyCertWithSystem(cert *x509.Certificate) bool {
+ data := pem.EncodeToMemory(&pem.Block{
+ Type: "CERTIFICATE", Bytes: cert.Raw,
+ })
+
+ f, err := ioutil.TempFile("", "cert")
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "can't create temporary file for cert: %v", err)
+ return false
+ }
+ defer os.Remove(f.Name())
+ if _, err := f.Write(data); err != nil {
+ fmt.Fprintf(os.Stderr, "can't write temporary file for cert: %v", err)
+ return false
+ }
+ if err := f.Close(); err != nil {
+ fmt.Fprintf(os.Stderr, "can't write temporary file for cert: %v", err)
+ return false
+ }
+ cmd := exec.Command("/usr/bin/security", "verify-cert", "-p", "ssl", "-c", f.Name(), "-l", "-L")
+ var stderr bytes.Buffer
+ if debugDarwinRoots {
+ cmd.Stderr = &stderr
+ }
+ if err := cmd.Run(); err != nil {
+ if debugDarwinRoots {
+ fmt.Printf("crypto/x509: verify-cert rejected %s: %q\n", cert.Subject, bytes.TrimSpace(stderr.Bytes()))
+ }
+ return false
+ }
+ if debugDarwinRoots {
+ fmt.Printf("crypto/x509: verify-cert approved %s\n", cert.Subject)
+ }
+ return true
+}