summaryrefslogtreecommitdiffstats
path: root/dependencies/pkg/mod/golang.org/x/exp@v0.0.0-20220613132600-b0d781184e0d/cmd/macos-roots-test/main.go
blob: db2bfe62375a96b9fe20dc7a997f9bd7f0ef07fb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
// Copyright 2018 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
// +build darwin

// Command macOS-roots-test runs crypto/x509.TestSystemRoots as a
// stand-alone binary for crowdsourced testing.
package main

import (
	"crypto/x509"
	"fmt"
	"log"
	"os"
	"os/exec"
	"time"
	"unsafe"
)

type CertPool struct {
	bySubjectKeyId map[string][]int
	byName         map[string][]int
	certs          []*x509.Certificate
}

func (s *CertPool) contains(cert *x509.Certificate) bool {
	if s == nil {
		return false
	}

	candidates := s.byName[string(cert.RawSubject)]
	for _, c := range candidates {
		if s.certs[c].Equal(cert) {
			return true
		}
	}

	return false
}

func main() {
	var failed bool

	t0 := time.Now()
	sysRootsExt, err := loadSystemRoots() // actual system roots
	sysRootsDuration := time.Since(t0)

	if err != nil {
		log.Fatalf("failed to read system roots (cgo): %v", err)
	}
	sysRoots := (*CertPool)(unsafe.Pointer(sysRootsExt))

	t1 := time.Now()
	execRootsExt, err := execSecurityRoots() // non-cgo roots
	execSysRootsDuration := time.Since(t1)

	if err != nil {
		log.Fatalf("failed to read system roots (nocgo): %v", err)
	}
	execRoots := (*CertPool)(unsafe.Pointer(execRootsExt))

	fmt.Printf("    cgo sys roots: %v\n", sysRootsDuration)
	fmt.Printf("non-cgo sys roots: %v\n", execSysRootsDuration)

	// On Mavericks, there are 212 bundled certs, at least there was at
	// one point in time on one machine. (Maybe it was a corp laptop
	// with extra certs?) Other OS X users report 135, 142, 145...
	// Let's try requiring at least 100, since this is just a sanity
	// check.
	if want, have := 100, len(sysRoots.certs); have < want {
		failed = true
		fmt.Printf("want at least %d system roots, have %d\n", want, have)
	}

	// Check that the two cert pools are the same.
	sysPool := make(map[string]*x509.Certificate, len(sysRoots.certs))
	for _, c := range sysRoots.certs {
		sysPool[string(c.Raw)] = c
	}
	for _, c := range execRoots.certs {
		if _, ok := sysPool[string(c.Raw)]; ok {
			delete(sysPool, string(c.Raw))
		} else {
			// verify-cert lets in certificates that are not trusted roots, but are
			// signed by trusted roots. This should not be a problem, so confirm that's
			// the case and skip them.
			if _, err := c.Verify(x509.VerifyOptions{
				Roots:         sysRootsExt,
				Intermediates: execRootsExt, // the intermediates for EAP certs are stored in the keychain
				KeyUsages:     []x509.ExtKeyUsage{x509.ExtKeyUsageAny},
			}); err != nil {
				failed = true
				fmt.Printf("certificate only present in non-cgo pool: %v (verify error: %v)\n", c.Subject, err)
			} else {
				fmt.Printf("signed certificate only present in non-cgo pool (acceptable): %v\n", c.Subject)
			}
		}
	}
	for _, c := range sysPool {
		failed = true
		fmt.Printf("certificate only present in cgo pool: %v\n", c.Subject)
	}

	if failed && debugDarwinRoots {
		cmd := exec.Command("security", "dump-trust-settings")
		cmd.Stdout = os.Stdout
		cmd.Stderr = os.Stderr
		cmd.Run()
		cmd = exec.Command("security", "dump-trust-settings", "-d")
		cmd.Stdout = os.Stdout
		cmd.Stderr = os.Stderr
		cmd.Run()
	}

	if failed {
		fmt.Printf("\n\n!!! The test failed!\n\nPlease report *the whole output* at https://github.com/golang/go/issues/24652 wrapping it in ``` a code block ```\nThank you!\n")
	} else {
		fmt.Printf("\n\nThe test passed, no need to report the output. Thank you.\n")
	}
}