1// Copyright 2011 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// +build cgo,!arm,!arm64,!ios
6
7package x509
8
9/*
10#cgo CFLAGS: -mmacosx-version-min=10.6 -D__MAC_OS_X_VERSION_MAX_ALLOWED=1060
11#cgo LDFLAGS: -framework CoreFoundation -framework Security
12
13#include <CoreFoundation/CoreFoundation.h>
14#include <Security/Security.h>
15
16// FetchPEMRoots fetches the system's list of trusted X.509 root certificates.
17//
18// On success it returns 0 and fills pemRoots with a CFDataRef that contains the extracted root
19// certificates of the system. On failure, the function returns -1.
20//
21// Note: The CFDataRef returned in pemRoots must be released (using CFRelease) after
22// we've consumed its content.
23int FetchPEMRoots(CFDataRef *pemRoots) {
24	if (pemRoots == NULL) {
25		return -1;
26	}
27
28	CFArrayRef certs = NULL;
29	OSStatus err = SecTrustCopyAnchorCertificates(&certs);
30	if (err != noErr) {
31		return -1;
32	}
33
34	CFMutableDataRef combinedData = CFDataCreateMutable(kCFAllocatorDefault, 0);
35	int i, ncerts = CFArrayGetCount(certs);
36	for (i = 0; i < ncerts; i++) {
37		CFDataRef data = NULL;
38		SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(certs, i);
39		if (cert == NULL) {
40			continue;
41		}
42
43		// Note: SecKeychainItemExport is deprecated as of 10.7 in favor of SecItemExport.
44		// Once we support weak imports via cgo we should prefer that, and fall back to this
45		// for older systems.
46		err = SecKeychainItemExport(cert, kSecFormatX509Cert, kSecItemPemArmour, NULL, &data);
47		if (err != noErr) {
48			continue;
49		}
50
51		if (data != NULL) {
52			CFDataAppendBytes(combinedData, CFDataGetBytePtr(data), CFDataGetLength(data));
53			CFRelease(data);
54		}
55	}
56
57	CFRelease(certs);
58
59	*pemRoots = combinedData;
60	return 0;
61}
62*/
63import "C"
64import "unsafe"
65
66func initSystemRoots() {
67	roots := NewCertPool()
68
69	var data C.CFDataRef = nil
70	err := C.FetchPEMRoots(&data)
71	if err == -1 {
72		return
73	}
74
75	defer C.CFRelease(C.CFTypeRef(data))
76	buf := C.GoBytes(unsafe.Pointer(C.CFDataGetBytePtr(data)), C.int(C.CFDataGetLength(data)))
77	roots.AppendCertsFromPEM(buf)
78	systemRoots = roots
79}
80