github.com/megatontech/mynoteforgo@v0.0.0-20200507084910-5d0c6ea6e890/源码/crypto/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 // +build cgo,!arm,!arm64,!ios 6 7 package x509 8 9 /* 10 #cgo CFLAGS: -mmacosx-version-min=10.10 -D__MAC_OS_X_VERSION_MAX_ALLOWED=101300 11 #cgo LDFLAGS: -framework CoreFoundation -framework Security 12 13 #include <errno.h> 14 #include <sys/sysctl.h> 15 16 #include <CoreFoundation/CoreFoundation.h> 17 #include <Security/Security.h> 18 19 static bool isSSLPolicy(SecPolicyRef policyRef) { 20 if (!policyRef) { 21 return false; 22 } 23 CFDictionaryRef properties = SecPolicyCopyProperties(policyRef); 24 if (properties == NULL) { 25 return false; 26 } 27 CFTypeRef value = NULL; 28 if (CFDictionaryGetValueIfPresent(properties, kSecPolicyOid, (const void **)&value)) { 29 CFRelease(properties); 30 return CFEqual(value, kSecPolicyAppleSSL); 31 } 32 CFRelease(properties); 33 return false; 34 } 35 36 // sslTrustSettingsResult obtains the final kSecTrustSettingsResult value 37 // for a certificate in the user or admin domain, combining usage constraints 38 // for the SSL SecTrustSettingsPolicy, ignoring SecTrustSettingsKeyUsage and 39 // kSecTrustSettingsAllowedError. 40 // https://developer.apple.com/documentation/security/1400261-sectrustsettingscopytrustsetting 41 static SInt32 sslTrustSettingsResult(SecCertificateRef cert) { 42 CFArrayRef trustSettings = NULL; 43 OSStatus err = SecTrustSettingsCopyTrustSettings(cert, kSecTrustSettingsDomainUser, &trustSettings); 44 45 // According to Apple's SecTrustServer.c, "user trust settings overrule admin trust settings", 46 // but the rules of the override are unclear. Let's assume admin trust settings are applicable 47 // if and only if user trust settings fail to load or are NULL. 48 if (err != errSecSuccess || trustSettings == NULL) { 49 if (trustSettings != NULL) CFRelease(trustSettings); 50 err = SecTrustSettingsCopyTrustSettings(cert, kSecTrustSettingsDomainAdmin, &trustSettings); 51 } 52 53 // > no trust settings [...] means "this certificate must be verified to a known trusted certificate” 54 if (err != errSecSuccess || trustSettings == NULL) { 55 if (trustSettings != NULL) CFRelease(trustSettings); 56 return kSecTrustSettingsResultUnspecified; 57 } 58 59 // > An empty trust settings array means "always trust this certificate” with an 60 // > overall trust setting for the certificate of kSecTrustSettingsResultTrustRoot. 61 if (CFArrayGetCount(trustSettings) == 0) { 62 CFRelease(trustSettings); 63 return kSecTrustSettingsResultTrustRoot; 64 } 65 66 // kSecTrustSettingsResult is defined as CFSTR("kSecTrustSettingsResult"), 67 // but the Go linker's internal linking mode can't handle CFSTR relocations. 68 // Create our own dynamic string instead and release it below. 69 CFStringRef _kSecTrustSettingsResult = CFStringCreateWithCString( 70 NULL, "kSecTrustSettingsResult", kCFStringEncodingUTF8); 71 CFStringRef _kSecTrustSettingsPolicy = CFStringCreateWithCString( 72 NULL, "kSecTrustSettingsPolicy", kCFStringEncodingUTF8); 73 CFStringRef _kSecTrustSettingsPolicyString = CFStringCreateWithCString( 74 NULL, "kSecTrustSettingsPolicyString", kCFStringEncodingUTF8); 75 76 CFIndex m; SInt32 result = 0; 77 for (m = 0; m < CFArrayGetCount(trustSettings); m++) { 78 CFDictionaryRef tSetting = (CFDictionaryRef)CFArrayGetValueAtIndex(trustSettings, m); 79 80 // First, check if this trust setting applies to our policy. We assume 81 // only one will. The docs suggest that there might be multiple applying 82 // but don't explain how to combine them. 83 SecPolicyRef policyRef; 84 if (CFDictionaryGetValueIfPresent(tSetting, _kSecTrustSettingsPolicy, (const void**)&policyRef)) { 85 if (!isSSLPolicy(policyRef)) { 86 continue; 87 } 88 } else { 89 continue; 90 } 91 92 if (CFDictionaryContainsKey(tSetting, _kSecTrustSettingsPolicyString)) { 93 // Restricted to a hostname, not a root. 94 continue; 95 } 96 97 CFNumberRef cfNum; 98 if (CFDictionaryGetValueIfPresent(tSetting, _kSecTrustSettingsResult, (const void**)&cfNum)) { 99 CFNumberGetValue(cfNum, kCFNumberSInt32Type, &result); 100 } else { 101 // > If the value of the kSecTrustSettingsResult component is not 102 // > kSecTrustSettingsResultUnspecified for a usage constraints dictionary that has 103 // > no constraints, the default value kSecTrustSettingsResultTrustRoot is assumed. 104 result = kSecTrustSettingsResultTrustRoot; 105 } 106 107 break; 108 } 109 110 // If trust settings are present, but none of them match the policy... 111 // the docs don't tell us what to do. 112 // 113 // "Trust settings for a given use apply if any of the dictionaries in the 114 // certificate’s trust settings array satisfies the specified use." suggests 115 // that it's as if there were no trust settings at all, so we should probably 116 // fallback to the admin trust settings. TODO. 117 if (result == 0) { 118 result = kSecTrustSettingsResultUnspecified; 119 } 120 121 CFRelease(_kSecTrustSettingsPolicy); 122 CFRelease(_kSecTrustSettingsPolicyString); 123 CFRelease(_kSecTrustSettingsResult); 124 CFRelease(trustSettings); 125 126 return result; 127 } 128 129 // isRootCertificate reports whether Subject and Issuer match. 130 static Boolean isRootCertificate(SecCertificateRef cert, CFErrorRef *errRef) { 131 CFDataRef subjectName = SecCertificateCopyNormalizedSubjectContent(cert, errRef); 132 if (*errRef != NULL) { 133 return false; 134 } 135 CFDataRef issuerName = SecCertificateCopyNormalizedIssuerContent(cert, errRef); 136 if (*errRef != NULL) { 137 CFRelease(subjectName); 138 return false; 139 } 140 Boolean equal = CFEqual(subjectName, issuerName); 141 CFRelease(subjectName); 142 CFRelease(issuerName); 143 return equal; 144 } 145 146 // FetchPEMRoots fetches the system's list of trusted X.509 root certificates 147 // for the kSecTrustSettingsPolicy SSL. 148 // 149 // On success it returns 0 and fills pemRoots with a CFDataRef that contains the extracted root 150 // certificates of the system. On failure, the function returns -1. 151 // Additionally, it fills untrustedPemRoots with certs that must be removed from pemRoots. 152 // 153 // Note: The CFDataRef returned in pemRoots and untrustedPemRoots must 154 // be released (using CFRelease) after we've consumed its content. 155 int FetchPEMRoots(CFDataRef *pemRoots, CFDataRef *untrustedPemRoots, bool debugDarwinRoots) { 156 int i; 157 158 if (debugDarwinRoots) { 159 printf("crypto/x509: kSecTrustSettingsResultInvalid = %d\n", kSecTrustSettingsResultInvalid); 160 printf("crypto/x509: kSecTrustSettingsResultTrustRoot = %d\n", kSecTrustSettingsResultTrustRoot); 161 printf("crypto/x509: kSecTrustSettingsResultTrustAsRoot = %d\n", kSecTrustSettingsResultTrustAsRoot); 162 printf("crypto/x509: kSecTrustSettingsResultDeny = %d\n", kSecTrustSettingsResultDeny); 163 printf("crypto/x509: kSecTrustSettingsResultUnspecified = %d\n", kSecTrustSettingsResultUnspecified); 164 } 165 166 // Get certificates from all domains, not just System, this lets 167 // the user add CAs to their "login" keychain, and Admins to add 168 // to the "System" keychain 169 SecTrustSettingsDomain domains[] = { kSecTrustSettingsDomainSystem, 170 kSecTrustSettingsDomainAdmin, kSecTrustSettingsDomainUser }; 171 172 int numDomains = sizeof(domains)/sizeof(SecTrustSettingsDomain); 173 if (pemRoots == NULL) { 174 return -1; 175 } 176 177 CFMutableDataRef combinedData = CFDataCreateMutable(kCFAllocatorDefault, 0); 178 CFMutableDataRef combinedUntrustedData = CFDataCreateMutable(kCFAllocatorDefault, 0); 179 for (i = 0; i < numDomains; i++) { 180 int j; 181 CFArrayRef certs = NULL; 182 OSStatus err = SecTrustSettingsCopyCertificates(domains[i], &certs); 183 if (err != noErr) { 184 continue; 185 } 186 187 CFIndex numCerts = CFArrayGetCount(certs); 188 for (j = 0; j < numCerts; j++) { 189 CFDataRef data = NULL; 190 CFArrayRef trustSettings = NULL; 191 SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(certs, j); 192 if (cert == NULL) { 193 continue; 194 } 195 196 SInt32 result; 197 if (domains[i] == kSecTrustSettingsDomainSystem) { 198 // Certs found in the system domain are always trusted. If the user 199 // configures "Never Trust" on such a cert, it will also be found in the 200 // admin or user domain, causing it to be added to untrustedPemRoots. The 201 // Go code will then clean this up. 202 result = kSecTrustSettingsResultTrustRoot; 203 } else { 204 result = sslTrustSettingsResult(cert); 205 if (debugDarwinRoots) { 206 CFErrorRef errRef = NULL; 207 CFStringRef summary = SecCertificateCopyShortDescription(NULL, cert, &errRef); 208 if (errRef != NULL) { 209 printf("crypto/x509: SecCertificateCopyShortDescription failed\n"); 210 CFRelease(errRef); 211 continue; 212 } 213 214 CFIndex length = CFStringGetLength(summary); 215 CFIndex maxSize = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8) + 1; 216 char *buffer = malloc(maxSize); 217 if (CFStringGetCString(summary, buffer, maxSize, kCFStringEncodingUTF8)) { 218 printf("crypto/x509: %s returned %d\n", buffer, (int)result); 219 } 220 free(buffer); 221 CFRelease(summary); 222 } 223 } 224 225 CFMutableDataRef appendTo; 226 // > Note the distinction between the results kSecTrustSettingsResultTrustRoot 227 // > and kSecTrustSettingsResultTrustAsRoot: The former can only be applied to 228 // > root (self-signed) certificates; the latter can only be applied to 229 // > non-root certificates. 230 if (result == kSecTrustSettingsResultTrustRoot) { 231 CFErrorRef errRef = NULL; 232 if (!isRootCertificate(cert, &errRef) || errRef != NULL) { 233 if (errRef != NULL) CFRelease(errRef); 234 continue; 235 } 236 237 appendTo = combinedData; 238 } else if (result == kSecTrustSettingsResultTrustAsRoot) { 239 CFErrorRef errRef = NULL; 240 if (isRootCertificate(cert, &errRef) || errRef != NULL) { 241 if (errRef != NULL) CFRelease(errRef); 242 continue; 243 } 244 245 appendTo = combinedData; 246 } else if (result == kSecTrustSettingsResultDeny) { 247 appendTo = combinedUntrustedData; 248 } else if (result == kSecTrustSettingsResultUnspecified) { 249 continue; 250 } else { 251 continue; 252 } 253 254 err = SecItemExport(cert, kSecFormatX509Cert, kSecItemPemArmour, NULL, &data); 255 if (err != noErr) { 256 continue; 257 } 258 if (data != NULL) { 259 CFDataAppendBytes(appendTo, CFDataGetBytePtr(data), CFDataGetLength(data)); 260 CFRelease(data); 261 } 262 } 263 CFRelease(certs); 264 } 265 *pemRoots = combinedData; 266 *untrustedPemRoots = combinedUntrustedData; 267 return 0; 268 } 269 */ 270 import "C" 271 import ( 272 "errors" 273 "unsafe" 274 ) 275 276 func loadSystemRoots() (*CertPool, error) { 277 roots := NewCertPool() 278 279 var data C.CFDataRef = 0 280 var untrustedData C.CFDataRef = 0 281 err := C.FetchPEMRoots(&data, &untrustedData, C.bool(debugDarwinRoots)) 282 if err == -1 { 283 return nil, errors.New("crypto/x509: failed to load darwin system roots with cgo") 284 } 285 286 defer C.CFRelease(C.CFTypeRef(data)) 287 buf := C.GoBytes(unsafe.Pointer(C.CFDataGetBytePtr(data)), C.int(C.CFDataGetLength(data))) 288 roots.AppendCertsFromPEM(buf) 289 if untrustedData == 0 { 290 return roots, nil 291 } 292 defer C.CFRelease(C.CFTypeRef(untrustedData)) 293 buf = C.GoBytes(unsafe.Pointer(C.CFDataGetBytePtr(untrustedData)), C.int(C.CFDataGetLength(untrustedData))) 294 untrustedRoots := NewCertPool() 295 untrustedRoots.AppendCertsFromPEM(buf) 296 297 trustedRoots := NewCertPool() 298 for _, c := range roots.certs { 299 if !untrustedRoots.contains(c) { 300 trustedRoots.AddCert(c) 301 } 302 } 303 return trustedRoots, nil 304 }