github.com/FISCO-BCOS/crypto@v0.0.0-20200202032121-bd8ab0b5d4f1/x509/root_darwin_test.go (about) 1 // Copyright 2013 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 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() // actual system roots 25 sysRootsDuration := time.Since(t0) 26 27 t1 := time.Now() 28 execRoots, err := execSecurityRoots() // non-cgo roots 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 // On Mavericks, there are 212 bundled certs, at least there was at 39 // one point in time on one machine. (Maybe it was a corp laptop 40 // with extra certs?) Other OS X users report 135, 142, 145... 41 // Let's try requiring at least 100, since this is just a sanity 42 // check. 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 // Fetch any intermediate certificate that verify-cert might be aware of. 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 // Check that the two cert pools are the same. 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 // verify-cert lets in certificates that are not trusted roots, but 68 // are signed by trusted roots. This is not great, but unavoidable 69 // until we parse real policies without cgo, so confirm that's the 70 // case and skip them. 71 if _, err := c.Verify(VerifyOptions{ 72 Roots: sysRoots, 73 Intermediates: allCerts, 74 KeyUsages: []ExtKeyUsage{ExtKeyUsageAny}, 75 CurrentTime: c.NotBefore, // verify-cert does not check expiration 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 // The nocgo codepath uses verify-cert with the ssl policy, which also 85 // happens to check EKUs, so some certificates will appear only in the 86 // cgo pool. We can't easily make them consistent because the EKU check 87 // is only applied to the certificates passed to verify-cert. 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 // Same for expired certificates. We don't chain to them anyway. 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 // On 10.11 there are five unexplained roots that only show up from the 111 // C API. They have in common the fact that they are old, 1024-bit 112 // certificates. It's arguably better to ignore them anyway. 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 }