github.com/zmap/zcrypto@v0.0.0-20240512203510-0fef58d9a9db/ct/x509/root_cgo_darwin.go (about)

     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  //go:build cgo && !arm && !arm64 && !ios
     6  // +build cgo,!arm,!arm64,!ios
     7  
     8  package x509
     9  
    10  // Use non-cgo on Darwin to prevent duplicate symbols on cgo
    11  
    12  //
    13  ///*
    14  //#cgo CFLAGS: -mmacosx-version-min=10.6 -D__MAC_OS_X_VERSION_MAX_ALLOWED=1080
    15  //#cgo LDFLAGS: -framework CoreFoundation -framework Security
    16  //
    17  //#include <errno.h>
    18  //#include <sys/sysctl.h>
    19  //
    20  //#include <CoreFoundation/CoreFoundation.h>
    21  //#include <Security/Security.h>
    22  //
    23  //// FetchPEMRoots_MountainLion is the version of FetchPEMRoots from Go 1.6
    24  //// which still works on OS X 10.8 (Mountain Lion).
    25  //// It lacks support for admin & user cert domains.
    26  //// See golang.org/issue/16473
    27  //int FetchPEMRoots_MountainLion(CFDataRef *pemRoots) {
    28  //	if (pemRoots == NULL) {
    29  //		return -1;
    30  //	}
    31  //	CFArrayRef certs = NULL;
    32  //	OSStatus err = SecTrustCopyAnchorCertificates(&certs);
    33  //	if (err != noErr) {
    34  //		return -1;
    35  //	}
    36  //	CFMutableDataRef combinedData = CFDataCreateMutable(kCFAllocatorDefault, 0);
    37  //	int i, ncerts = CFArrayGetCount(certs);
    38  //	for (i = 0; i < ncerts; i++) {
    39  //		CFDataRef data = NULL;
    40  //		SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(certs, i);
    41  //		if (cert == NULL) {
    42  //			continue;
    43  //		}
    44  //		// Note: SecKeychainItemExport is deprecated as of 10.7 in favor of SecItemExport.
    45  //		// Once we support weak imports via cgo we should prefer that, and fall back to this
    46  //		// for older systems.
    47  //		err = SecKeychainItemExport(cert, kSecFormatX509Cert, kSecItemPemArmour, NULL, &data);
    48  //		if (err != noErr) {
    49  //			continue;
    50  //		}
    51  //		if (data != NULL) {
    52  //			CFDataAppendBytes(combinedData, CFDataGetBytePtr(data), CFDataGetLength(data));
    53  //			CFRelease(data);
    54  //		}
    55  //	}
    56  //	CFRelease(certs);
    57  //	*pemRoots = combinedData;
    58  //	return 0;
    59  //}
    60  //
    61  //// useOldCode reports whether the running machine is OS X 10.8 Mountain Lion
    62  //// or older. We only support Mountain Lion and higher, but we'll at least try our
    63  //// best on older machines and continue to use the old code path.
    64  ////
    65  //// See golang.org/issue/16473
    66  //int useOldCode() {
    67  //	char str[256];
    68  //	size_t size = sizeof(str);
    69  //	memset(str, 0, size);
    70  //	sysctlbyname("kern.osrelease", str, &size, NULL, 0);
    71  //	// OS X 10.8 is osrelease "12.*", 10.7 is 11.*, 10.6 is 10.*.
    72  //	// We never supported things before that.
    73  //	return memcmp(str, "12.", 3) == 0 || memcmp(str, "11.", 3) == 0 || memcmp(str, "10.", 3) == 0;
    74  //}
    75  //
    76  //// FetchPEMRoots fetches the system's list of trusted X.509 root certificates.
    77  ////
    78  //// On success it returns 0 and fills pemRoots with a CFDataRef that contains the extracted root
    79  //// certificates of the system. On failure, the function returns -1.
    80  //// Additionally, it fills untrustedPemRoots with certs that must be removed from pemRoots.
    81  ////
    82  //// Note: The CFDataRef returned in pemRoots and untrustedPemRoots must
    83  //// be released (using CFRelease) after we've consumed its content.
    84  //int FetchPEMRoots(CFDataRef *pemRoots, CFDataRef *untrustedPemRoots) {
    85  //	if (useOldCode()) {
    86  //		return FetchPEMRoots_MountainLion(pemRoots);
    87  //	}
    88  //
    89  //	// Get certificates from all domains, not just System, this lets
    90  //	// the user add CAs to their "login" keychain, and Admins to add
    91  //	// to the "System" keychain
    92  //	SecTrustSettingsDomain domains[] = { kSecTrustSettingsDomainSystem,
    93  //					     kSecTrustSettingsDomainAdmin,
    94  //					     kSecTrustSettingsDomainUser };
    95  //
    96  //	int numDomains = sizeof(domains)/sizeof(SecTrustSettingsDomain);
    97  //	if (pemRoots == NULL) {
    98  //		return -1;
    99  //	}
   100  //
   101  //	// kSecTrustSettingsResult is defined as CFSTR("kSecTrustSettingsResult"),
   102  //	// but the Go linker's internal linking mode can't handle CFSTR relocations.
   103  //	// Create our own dynamic string instead and release it below.
   104  //	CFStringRef policy = CFStringCreateWithCString(NULL, "kSecTrustSettingsResult", kCFStringEncodingUTF8);
   105  //
   106  //	CFMutableDataRef combinedData = CFDataCreateMutable(kCFAllocatorDefault, 0);
   107  //	CFMutableDataRef combinedUntrustedData = CFDataCreateMutable(kCFAllocatorDefault, 0);
   108  //	for (int i = 0; i < numDomains; i++) {
   109  //		CFArrayRef certs = NULL;
   110  //		OSStatus err = SecTrustSettingsCopyCertificates(domains[i], &certs);
   111  //		if (err != noErr) {
   112  //			continue;
   113  //		}
   114  //
   115  //		CFIndex numCerts = CFArrayGetCount(certs);
   116  //		for (int j = 0; j < numCerts; j++) {
   117  //			CFDataRef data = NULL;
   118  //			CFErrorRef errRef = NULL;
   119  //			CFArrayRef trustSettings = NULL;
   120  //			SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(certs, j);
   121  //			if (cert == NULL) {
   122  //				continue;
   123  //			}
   124  //			// We only want trusted certs.
   125  //			int untrusted = 0;
   126  //			if (i != 0) {
   127  //				// Certs found in the system domain are always trusted. If the user
   128  //				// configures "Never Trust" on such a cert, it will also be found in the
   129  //				// admin or user domain, causing it to be added to untrustedPemRoots. The
   130  //				// Go code will then clean this up.
   131  //
   132  //				// Trust may be stored in any of the domains. According to Apple's
   133  //				// SecTrustServer.c, "user trust settings overrule admin trust settings",
   134  //				// so take the last trust settings array we find.
   135  //				// Skip the system domain since it is always trusted.
   136  //				for (int k = 1; k < numDomains; k++) {
   137  //					CFArrayRef domainTrustSettings = NULL;
   138  //					err = SecTrustSettingsCopyTrustSettings(cert, domains[k], &domainTrustSettings);
   139  //					if (err == errSecSuccess && domainTrustSettings != NULL) {
   140  //						if (trustSettings) {
   141  //							CFRelease(trustSettings);
   142  //						}
   143  //						trustSettings = domainTrustSettings;
   144  //					}
   145  //				}
   146  //				if (trustSettings == NULL) {
   147  //					// "this certificate must be verified to a known trusted certificate"; aka not a root.
   148  //					continue;
   149  //				}
   150  //				for (CFIndex k = 0; k < CFArrayGetCount(trustSettings); k++) {
   151  //					CFNumberRef cfNum;
   152  //					CFDictionaryRef tSetting = (CFDictionaryRef)CFArrayGetValueAtIndex(trustSettings, k);
   153  //					if (CFDictionaryGetValueIfPresent(tSetting, policy, (const void**)&cfNum)){
   154  //						SInt32 result = 0;
   155  //						CFNumberGetValue(cfNum, kCFNumberSInt32Type, &result);
   156  //						// TODO: The rest of the dictionary specifies conditions for evaluation.
   157  //						if (result == kSecTrustSettingsResultDeny) {
   158  //							untrusted = 1;
   159  //						}
   160  //					}
   161  //				}
   162  //				CFRelease(trustSettings);
   163  //			}
   164  //			// We only want to add Root CAs, so make sure Subject and Issuer Name match
   165  //			CFDataRef subjectName = SecCertificateCopyNormalizedSubjectContent(cert, &errRef);
   166  //			if (errRef != NULL) {
   167  //				CFRelease(errRef);
   168  //				continue;
   169  //			}
   170  //			CFDataRef issuerName = SecCertificateCopyNormalizedIssuerContent(cert, &errRef);
   171  //			if (errRef != NULL) {
   172  //				CFRelease(subjectName);
   173  //				CFRelease(errRef);
   174  //				continue;
   175  //			}
   176  //			Boolean equal = CFEqual(subjectName, issuerName);
   177  //			CFRelease(subjectName);
   178  //			CFRelease(issuerName);
   179  //			if (!equal) {
   180  //				continue;
   181  //			}
   182  //
   183  //			// Note: SecKeychainItemExport is deprecated as of 10.7 in favor of SecItemExport.
   184  //			// Once we support weak imports via cgo we should prefer that, and fall back to this
   185  //			// for older systems.
   186  //			err = SecKeychainItemExport(cert, kSecFormatX509Cert, kSecItemPemArmour, NULL, &data);
   187  //			if (err != noErr) {
   188  //				continue;
   189  //			}
   190  //
   191  //			if (data != NULL) {
   192  //				CFMutableDataRef appendTo = untrusted ? combinedUntrustedData : combinedData;
   193  //				CFDataAppendBytes(appendTo, CFDataGetBytePtr(data), CFDataGetLength(data));
   194  //				CFRelease(data);
   195  //			}
   196  //		}
   197  //		CFRelease(certs);
   198  //	}
   199  //	CFRelease(policy);
   200  //	*pemRoots = combinedData;
   201  //	*untrustedPemRoots = combinedUntrustedData;
   202  //	return 0;
   203  //}
   204  //*/
   205  //import "C"
   206  //import (
   207  //	"errors"
   208  //	"unsafe"
   209  //)
   210  //
   211  //func loadSystemRoots() (*CertPool, error) {
   212  //	roots := NewCertPool()
   213  //
   214  //	var data C.CFDataRef = nil
   215  //	var untrustedData C.CFDataRef = nil
   216  //	err := C.FetchPEMRoots(&data, &untrustedData)
   217  //	if err == -1 {
   218  //		// TODO: better error message
   219  //		return nil, errors.New("crypto/x509: failed to load darwin system roots with cgo")
   220  //	}
   221  //
   222  //	defer C.CFRelease(C.CFTypeRef(data))
   223  //	buf := C.GoBytes(unsafe.Pointer(C.CFDataGetBytePtr(data)), C.int(C.CFDataGetLength(data)))
   224  //	roots.AppendCertsFromPEM(buf)
   225  //	if untrustedData == nil {
   226  //		return roots, nil
   227  //	}
   228  //	defer C.CFRelease(C.CFTypeRef(untrustedData))
   229  //	buf = C.GoBytes(unsafe.Pointer(C.CFDataGetBytePtr(untrustedData)), C.int(C.CFDataGetLength(untrustedData)))
   230  //	untrustedRoots := NewCertPool()
   231  //	untrustedRoots.AppendCertsFromPEM(buf)
   232  //
   233  //	trustedRoots := NewCertPool()
   234  //	for _, c := range roots.certs {
   235  //		if !untrustedRoots.contains(c) {
   236  //			trustedRoots.AddCert(c)
   237  //		}
   238  //	}
   239  //	return trustedRoots, nil
   240  //}