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  }