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 //}