1
2
3
4
5 package x509
6
7 import (
8 "crypto/rsa"
9 "os"
10 "os/exec"
11 "path/filepath"
12 "runtime"
13 "testing"
14 "time"
15 )
16
17 func TestSystemRoots(t *testing.T) {
18 switch runtime.GOARCH {
19 case "arm", "arm64":
20 t.Skipf("skipping on %s/%s, no system root", runtime.GOOS, runtime.GOARCH)
21 }
22
23 t0 := time.Now()
24 sysRoots := systemRootsPool()
25 sysRootsDuration := time.Since(t0)
26
27 t1 := time.Now()
28 execRoots, err := execSecurityRoots()
29 execSysRootsDuration := time.Since(t1)
30
31 if err != nil {
32 t.Fatalf("failed to read system roots: %v", err)
33 }
34
35 t.Logf(" cgo sys roots: %v", sysRootsDuration)
36 t.Logf("non-cgo sys roots: %v", execSysRootsDuration)
37
38
39
40
41
42
43 if want, have := 100, len(sysRoots.certs); have < want {
44 t.Errorf("want at least %d system roots, have %d", want, have)
45 }
46
47
48 out, err := exec.Command("/usr/bin/security", "find-certificate", "-a", "-p",
49 "/Library/Keychains/System.keychain",
50 filepath.Join(os.Getenv("HOME"), "/Library/Keychains/login.keychain"),
51 filepath.Join(os.Getenv("HOME"), "/Library/Keychains/login.keychain-db")).Output()
52 if err != nil {
53 t.Fatal(err)
54 }
55 allCerts := NewCertPool()
56 allCerts.AppendCertsFromPEM(out)
57
58
59 sysPool := make(map[string]*Certificate, len(sysRoots.certs))
60 for _, c := range sysRoots.certs {
61 sysPool[string(c.Raw)] = c
62 }
63 for _, c := range execRoots.certs {
64 if _, ok := sysPool[string(c.Raw)]; ok {
65 delete(sysPool, string(c.Raw))
66 } else {
67
68
69
70
71 if _, err := c.Verify(VerifyOptions{
72 Roots: sysRoots,
73 Intermediates: allCerts,
74 KeyUsages: []ExtKeyUsage{ExtKeyUsageAny},
75 CurrentTime: c.NotBefore,
76 }); err != nil {
77 t.Errorf("certificate only present in non-cgo pool: %v (verify error: %v)", c.Subject, err)
78 } else {
79 t.Logf("signed certificate only present in non-cgo pool (acceptable): %v", c.Subject)
80 }
81 }
82 }
83 for _, c := range sysPool {
84
85
86
87
88 var ekuOk bool
89 for _, eku := range c.ExtKeyUsage {
90 if eku == ExtKeyUsageServerAuth || eku == ExtKeyUsageNetscapeServerGatedCrypto ||
91 eku == ExtKeyUsageMicrosoftServerGatedCrypto || eku == ExtKeyUsageAny {
92 ekuOk = true
93 }
94 }
95 if len(c.ExtKeyUsage) == 0 && len(c.UnknownExtKeyUsage) == 0 {
96 ekuOk = true
97 }
98 if !ekuOk {
99 t.Logf("off-EKU certificate only present in cgo pool (acceptable): %v", c.Subject)
100 continue
101 }
102
103
104 now := time.Now()
105 if now.Before(c.NotBefore) || now.After(c.NotAfter) {
106 t.Logf("expired certificate only present in cgo pool (acceptable): %v", c.Subject)
107 continue
108 }
109
110
111
112
113 if key, ok := c.PublicKey.(*rsa.PublicKey); ok && key.N.BitLen() == 1024 {
114 t.Logf("1024-bit certificate only present in cgo pool (acceptable): %v", c.Subject)
115 continue
116 }
117
118 t.Errorf("certificate only present in cgo pool: %v", c.Subject)
119 }
120
121 if t.Failed() && debugDarwinRoots {
122 cmd := exec.Command("security", "dump-trust-settings")
123 cmd.Stdout, cmd.Stderr = os.Stderr, os.Stderr
124 cmd.Run()
125 cmd = exec.Command("security", "dump-trust-settings", "-d")
126 cmd.Stdout, cmd.Stderr = os.Stderr, os.Stderr
127 cmd.Run()
128 }
129 }
130
View as plain text