github.com/4ad/go@v0.0.0-20161219182952-69a12818b605/src/crypto/x509/root_darwin.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 //go:generate go run root_darwin_arm_gen.go -output root_darwin_armx.go 6 7 package x509 8 9 import ( 10 "bytes" 11 "encoding/pem" 12 "fmt" 13 "io/ioutil" 14 "os" 15 "os/exec" 16 "strconv" 17 "sync" 18 "syscall" 19 ) 20 21 func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) { 22 return nil, nil 23 } 24 25 // This code is only used when compiling without cgo. 26 // It is here, instead of root_nocgo_darwin.go, so that tests can check it 27 // even if the tests are run with cgo enabled. 28 // The linker will not include these unused functions in binaries built with cgo enabled. 29 30 func execSecurityRoots() (*CertPool, error) { 31 cmd := exec.Command("/usr/bin/security", "find-certificate", "-a", "-p", "/System/Library/Keychains/SystemRootCertificates.keychain") 32 data, err := cmd.Output() 33 if err != nil { 34 return nil, err 35 } 36 37 var ( 38 mu sync.Mutex 39 roots = NewCertPool() 40 ) 41 add := func(cert *Certificate) { 42 mu.Lock() 43 defer mu.Unlock() 44 roots.AddCert(cert) 45 } 46 blockCh := make(chan *pem.Block) 47 var wg sync.WaitGroup 48 for i := 0; i < 4; i++ { 49 wg.Add(1) 50 go func() { 51 defer wg.Done() 52 for block := range blockCh { 53 verifyCertWithSystem(block, add) 54 } 55 }() 56 } 57 for len(data) > 0 { 58 var block *pem.Block 59 block, data = pem.Decode(data) 60 if block == nil { 61 break 62 } 63 if block.Type != "CERTIFICATE" || len(block.Headers) != 0 { 64 continue 65 } 66 blockCh <- block 67 } 68 close(blockCh) 69 wg.Wait() 70 return roots, nil 71 } 72 73 func verifyCertWithSystem(block *pem.Block, add func(*Certificate)) { 74 data := pem.EncodeToMemory(block) 75 var cmd *exec.Cmd 76 if needsTmpFiles() { 77 f, err := ioutil.TempFile("", "cert") 78 if err != nil { 79 fmt.Fprintf(os.Stderr, "can't create temporary file for cert: %v", err) 80 return 81 } 82 defer os.Remove(f.Name()) 83 if _, err := f.Write(data); err != nil { 84 fmt.Fprintf(os.Stderr, "can't write temporary file for cert: %v", err) 85 return 86 } 87 if err := f.Close(); err != nil { 88 fmt.Fprintf(os.Stderr, "can't write temporary file for cert: %v", err) 89 return 90 } 91 cmd = exec.Command("/usr/bin/security", "verify-cert", "-c", f.Name(), "-l") 92 } else { 93 cmd = exec.Command("/usr/bin/security", "verify-cert", "-c", "/dev/stdin", "-l") 94 cmd.Stdin = bytes.NewReader(data) 95 } 96 if cmd.Run() == nil { 97 // Non-zero exit means untrusted 98 cert, err := ParseCertificate(block.Bytes) 99 if err != nil { 100 return 101 } 102 103 add(cert) 104 } 105 } 106 107 var versionCache struct { 108 sync.Once 109 major int 110 } 111 112 // needsTmpFiles reports whether the OS is <= 10.11 (which requires real 113 // files as arguments to the security command). 114 func needsTmpFiles() bool { 115 versionCache.Do(func() { 116 release, err := syscall.Sysctl("kern.osrelease") 117 if err != nil { 118 return 119 } 120 for i, c := range release { 121 if c == '.' { 122 release = release[:i] 123 break 124 } 125 } 126 major, err := strconv.Atoi(release) 127 if err != nil { 128 return 129 } 130 versionCache.major = major 131 }) 132 return versionCache.major <= 15 133 }