aboutsummaryrefslogtreecommitdiff
path: root/src/pkg/crypto
diff options
context:
space:
mode:
authorJosh Bleecher Snyder <josharian@gmail.com>2013-12-18 10:57:07 -0500
committerAdam Langley <agl@golang.org>2013-12-18 10:57:07 -0500
commit4f234814831c48a3bbc2b9a2d00242fad890facf (patch)
tree9c1f56f619b21f263204a755d8c2cd3f00bc9942 /src/pkg/crypto
parent626da8d73741b0cdeaa1acc048fec9ec8286f2b5 (diff)
downloadgo-4f234814831c48a3bbc2b9a2d00242fad890facf.tar.xz
crypto/x509: add non-cgo darwin system anchor certs
The set of certs fetched via exec'ing `security` is not quite identical to the certs fetched via the cgo call. The cgo fetch includes any trusted root certs that the user may have added; exec does not. The exec fetch includes an Apple-specific root cert; the cgo fetch does not. Other than that, they appear to be the same. Unfortunately, os/exec depends on crypto/x509, via net/http. Break the circular dependency by moving the exec tests to their own package. This will not work in iOS; we'll cross that bridge when we get to it. R=golang-dev, minux.ma, agl CC=golang-dev https://golang.org/cl/22020045
Diffstat (limited to 'src/pkg/crypto')
-rw-r--r--src/pkg/crypto/x509/root_cgo_darwin.go79
-rw-r--r--src/pkg/crypto/x509/root_darwin.go78
-rw-r--r--src/pkg/crypto/x509/root_darwin_test.go50
-rw-r--r--src/pkg/crypto/x509/root_nocgo_darwin.go11
-rw-r--r--src/pkg/crypto/x509/root_stub.go14
5 files changed, 150 insertions, 82 deletions
diff --git a/src/pkg/crypto/x509/root_cgo_darwin.go b/src/pkg/crypto/x509/root_cgo_darwin.go
new file mode 100644
index 0000000000..bdcc2c1708
--- /dev/null
+++ b/src/pkg/crypto/x509/root_cgo_darwin.go
@@ -0,0 +1,79 @@
+// Copyright 2011 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.
+
+// +build cgo
+
+package x509
+
+/*
+#cgo CFLAGS: -mmacosx-version-min=10.6 -D__MAC_OS_X_VERSION_MAX_ALLOWED=1060
+#cgo LDFLAGS: -framework CoreFoundation -framework Security
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <Security/Security.h>
+
+// FetchPEMRoots fetches the system's list of trusted X.509 root certificates.
+//
+// On success it returns 0 and fills pemRoots with a CFDataRef that contains the extracted root
+// certificates of the system. On failure, the function returns -1.
+//
+// Note: The CFDataRef returned in pemRoots must be released (using CFRelease) after
+// we've consumed its content.
+int FetchPEMRoots(CFDataRef *pemRoots) {
+ if (pemRoots == NULL) {
+ return -1;
+ }
+
+ CFArrayRef certs = NULL;
+ OSStatus err = SecTrustCopyAnchorCertificates(&certs);
+ if (err != noErr) {
+ return -1;
+ }
+
+ CFMutableDataRef combinedData = CFDataCreateMutable(kCFAllocatorDefault, 0);
+ int i, ncerts = CFArrayGetCount(certs);
+ for (i = 0; i < ncerts; i++) {
+ CFDataRef data = NULL;
+ SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(certs, i);
+ if (cert == NULL) {
+ continue;
+ }
+
+ // Note: SecKeychainItemExport is deprecated as of 10.7 in favor of SecItemExport.
+ // Once we support weak imports via cgo we should prefer that, and fall back to this
+ // for older systems.
+ err = SecKeychainItemExport(cert, kSecFormatX509Cert, kSecItemPemArmour, NULL, &data);
+ if (err != noErr) {
+ continue;
+ }
+
+ if (data != NULL) {
+ CFDataAppendBytes(combinedData, CFDataGetBytePtr(data), CFDataGetLength(data));
+ CFRelease(data);
+ }
+ }
+
+ CFRelease(certs);
+
+ *pemRoots = combinedData;
+ return 0;
+}
+*/
+import "C"
+import "unsafe"
+
+func initSystemRoots() {
+ roots := NewCertPool()
+
+ var data C.CFDataRef = nil
+ err := C.FetchPEMRoots(&data)
+ if err == -1 {
+ return
+ }
+
+ defer C.CFRelease(C.CFTypeRef(data))
+ buf := C.GoBytes(unsafe.Pointer(C.CFDataGetBytePtr(data)), C.int(C.CFDataGetLength(data)))
+ roots.AppendCertsFromPEM(buf)
+ systemRoots = roots
+}
diff --git a/src/pkg/crypto/x509/root_darwin.go b/src/pkg/crypto/x509/root_darwin.go
index ad3bfb4b43..2a61d36eae 100644
--- a/src/pkg/crypto/x509/root_darwin.go
+++ b/src/pkg/crypto/x509/root_darwin.go
@@ -1,81 +1,23 @@
-// Copyright 2011 The Go Authors. All rights reserved.
+// 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 x509
-/*
-#cgo CFLAGS: -mmacosx-version-min=10.6 -D__MAC_OS_X_VERSION_MAX_ALLOWED=1060
-#cgo LDFLAGS: -framework CoreFoundation -framework Security
-
-#include <CoreFoundation/CoreFoundation.h>
-#include <Security/Security.h>
-
-// FetchPEMRoots fetches the system's list of trusted X.509 root certificates.
-//
-// On success it returns 0 and fills pemRoots with a CFDataRef that contains the extracted root
-// certificates of the system. On failure, the function returns -1.
-//
-// Note: The CFDataRef returned in pemRoots must be released (using CFRelease) after
-// we've consumed its content.
-int FetchPEMRoots(CFDataRef *pemRoots) {
- if (pemRoots == NULL) {
- return -1;
- }
-
- CFArrayRef certs = NULL;
- OSStatus err = SecTrustCopyAnchorCertificates(&certs);
- if (err != noErr) {
- return -1;
- }
-
- CFMutableDataRef combinedData = CFDataCreateMutable(kCFAllocatorDefault, 0);
- int i, ncerts = CFArrayGetCount(certs);
- for (i = 0; i < ncerts; i++) {
- CFDataRef data = NULL;
- SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(certs, i);
- if (cert == NULL) {
- continue;
- }
-
- // Note: SecKeychainItemExport is deprecated as of 10.7 in favor of SecItemExport.
- // Once we support weak imports via cgo we should prefer that, and fall back to this
- // for older systems.
- err = SecKeychainItemExport(cert, kSecFormatX509Cert, kSecItemPemArmour, NULL, &data);
- if (err != noErr) {
- continue;
- }
-
- if (data != NULL) {
- CFDataAppendBytes(combinedData, CFDataGetBytePtr(data), CFDataGetLength(data));
- CFRelease(data);
- }
- }
-
- CFRelease(certs);
-
- *pemRoots = combinedData;
- return 0;
-}
-*/
-import "C"
-import "unsafe"
+import "os/exec"
func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) {
return nil, nil
}
-func initSystemRoots() {
- roots := NewCertPool()
-
- var data C.CFDataRef = nil
- err := C.FetchPEMRoots(&data)
- if err == -1 {
- return
+func execSecurityRoots() (*CertPool, error) {
+ cmd := exec.Command("/usr/bin/security", "find-certificate", "-a", "-p", "/System/Library/Keychains/SystemRootCertificates.keychain")
+ data, err := cmd.Output()
+ if err != nil {
+ return nil, err
}
- defer C.CFRelease(C.CFTypeRef(data))
- buf := C.GoBytes(unsafe.Pointer(C.CFDataGetBytePtr(data)), C.int(C.CFDataGetLength(data)))
- roots.AppendCertsFromPEM(buf)
- systemRoots = roots
+ roots := NewCertPool()
+ roots.AppendCertsFromPEM(data)
+ return roots, nil
}
diff --git a/src/pkg/crypto/x509/root_darwin_test.go b/src/pkg/crypto/x509/root_darwin_test.go
new file mode 100644
index 0000000000..87ea4e344f
--- /dev/null
+++ b/src/pkg/crypto/x509/root_darwin_test.go
@@ -0,0 +1,50 @@
+package x509
+
+import "testing"
+
+func TestSystemRoots(t *testing.T) {
+ sysRoots := systemRootsPool() // actual system roots
+ execRoots, err := execSecurityRoots() // non-cgo roots
+
+ if err != nil {
+ t.Fatalf("failed to read system roots: %v", err)
+ }
+
+ for _, tt := range []*CertPool{sysRoots, execRoots} {
+ if tt == nil {
+ t.Fatal("no system roots")
+ }
+ // On Mavericks, there are 212 bundled certs; require only
+ // 150 here, since this is just a sanity check, and the
+ // exact number will vary over time.
+ if want, have := 150, len(tt.certs); have < want {
+ t.Fatalf("want at least %d system roots, have %d", want, have)
+ }
+ }
+
+ // Check that the two cert pools are roughly the same;
+ // |A∩B| > max(|A|, |B|) / 2 should be a reasonably robust check.
+
+ isect := make(map[string]bool, len(sysRoots.certs))
+ for _, c := range sysRoots.certs {
+ isect[string(c.Raw)] = true
+ }
+
+ have := 0
+ for _, c := range execRoots.certs {
+ if isect[string(c.Raw)] {
+ have++
+ }
+ }
+
+ var want int
+ if nsys, nexec := len(sysRoots.certs), len(execRoots.certs); nsys > nexec {
+ want = nsys / 2
+ } else {
+ want = nexec / 2
+ }
+
+ if have < want {
+ t.Errorf("insufficent overlap between cgo and non-cgo roots; want at least %d, have %d", want, have)
+ }
+}
diff --git a/src/pkg/crypto/x509/root_nocgo_darwin.go b/src/pkg/crypto/x509/root_nocgo_darwin.go
new file mode 100644
index 0000000000..d00e257662
--- /dev/null
+++ b/src/pkg/crypto/x509/root_nocgo_darwin.go
@@ -0,0 +1,11 @@
+// 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.
+
+// +build !cgo
+
+package x509
+
+func initSystemRoots() {
+ systemRoots, _ = execSecurityRoots()
+}
diff --git a/src/pkg/crypto/x509/root_stub.go b/src/pkg/crypto/x509/root_stub.go
deleted file mode 100644
index 4c742ccc37..0000000000
--- a/src/pkg/crypto/x509/root_stub.go
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright 2011 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.
-
-// +build darwin,!cgo
-
-package x509
-
-func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) {
- return nil, nil
-}
-
-func initSystemRoots() {
-}