/*
- * Copyright (c) 2005,2011-2015 Apple Inc. All Rights Reserved.
+ * Copyright (c) 2005,2011-2016 Apple Inc. All Rights Reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
#include "SecTrustSettings.h"
#include "SecTrustSettingsPriv.h"
#include "SecTrustSettingsCertificates.h"
+#include "SecCFRelease.h"
#include "TrustSettingsUtils.h"
#include "TrustSettings.h"
#include "TrustSettingsSchema.h"
#include <vector>
#include <CommonCrypto/CommonDigest.h>
#include <CoreFoundation/CFPreferences.h>
-#include <CoreServices/CoreServicesPriv.h> /* for _CSCheckFix */
+#include <utilities/SecCFRelease.h>
-#define trustSettingsDbg(args...) secdebug("trustSettings", ## args)
+#define trustSettingsDbg(args...) secinfo("trustSettings", ## args)
/*
* Ideally we'd like to implement our own lock to protect the state of the cert stores
StLock<Mutex> _(sutCacheLock());
trustSettingsDbg("tsPurgeCache");
for(domain=0; domain<TRUST_SETTINGS_NUM_DOMAINS; domain++) {
- tsSetGlobalTrustSettings(NULL, domain);
+ tsSetGlobalTrustSettings(NULL, (SecTrustSettingsDomain) domain);
}
}
&kCFTypeArrayCallBacks));
/*
- * Search all keychains - user's, System.keychain, system root store,
- * system intermdiates as appropriate
- */
+ * Search all keychains - user's keychain list, System.keychain,
+ * and system root store
+ */
StorageManager::KeychainList keychains;
Keychain adminKc;
if(user) {
}
Keychain sysRootKc = globals().storageManager.make(SYSTEM_ROOT_STORE_PATH, false);
keychains.push_back(sysRootKc);
- Keychain sysCertKc = globals().storageManager.make(SYSTEM_CERT_STORE_PATH, false);
- keychains.push_back(sysCertKc);
assert(kSecTrustSettingsDomainUser == 0);
for(unsigned domain=0; domain<TRUST_SETTINGS_NUM_DOMAINS; domain++) {
if(!domainEnable[domain]) {
continue;
}
- TrustSettings *ts = tsGetGlobalTrustSettings(domain);
+ TrustSettings *ts = tsGetGlobalTrustSettings((SecTrustSettingsDomain)domain);
if(ts == NULL) {
continue;
}
tsAddConditionalCerts(outArray);
}
*certArray = outArray;
- CFRetain(*certArray);
+ CFRetainSafe(*certArray);
trustSettingsDbg("tsCopyCertsCommon: %ld certs found",
CFArrayGetCount(outArray));
return errSecSuccess;
}
-#if TARGET_OS_MAC && !TARGET_IPHONE_SIMULATOR && !TARGET_OS_IPHONE && !TARGET_OS_NANO
-/*
- * _CSCheckFix is implemented in CarbonCore and exported via CoreServices.
- * To avoid a circular dependency with Security, load this symbol dynamically.
- */
-typedef Boolean (*CSCheckFix_f)(CFStringRef str);
-
-static dispatch_once_t sTSInitializeOnce = 0;
-static void * sCSCheckFixLibrary = NULL;
-static CSCheckFix_f sCSCheckFix_f = NULL;
-
-static OSStatus _tsEnsuredInitialized(void);
-
-static OSStatus _tsEnsuredInitialized(void)
-{
- __block OSStatus status = errSecNotAvailable;
-
- dispatch_once(&sTSInitializeOnce, ^{
- sCSCheckFixLibrary = dlopen("/System/Library/Frameworks/CoreServices.framework/Frameworks/CarbonCore.framework/Versions/A/CarbonCore", RTLD_LAZY | RTLD_LOCAL);
- assert(sCSCheckFixLibrary);
- if (sCSCheckFixLibrary) {
- sCSCheckFix_f = (CSCheckFix_f)(uintptr_t) dlsym(sCSCheckFixLibrary, "_CSCheckFix");
- }
- });
-
- if (sCSCheckFix_f) {
- status = noErr;
- }
- return status;
-}
-#endif
-
static void tsAddConditionalCerts(CFMutableArrayRef certArray)
{
-#if TARGET_OS_MAC && !TARGET_IPHONE_SIMULATOR && !TARGET_OS_IPHONE && !TARGET_OS_NANO
+#if TARGET_OS_OSX
struct certmap_entry_s {
+ CFStringRef bundleId;
const UInt8* data;
const CFIndex length;
};
typedef struct certmap_entry_s certmap_entry_t;
- if (!certArray) { return; }
-
- OSStatus status = _tsEnsuredInitialized();
- if (status == 0 && sCSCheckFix_f(CFSTR("21946795"))) {
- // conditionally include these 1024-bit roots
- const certmap_entry_t certmap[] = {
- { _EquifaxSecureCA, sizeof(_EquifaxSecureCA) },
- { _GTECyberTrustGlobalRootCA, sizeof(_GTECyberTrustGlobalRootCA) },
- { _ThawtePremiumServerCA, sizeof(_ThawtePremiumServerCA) },
- { _ThawteServerCA, sizeof(_ThawteServerCA) },
- { _VeriSignClass3CA, sizeof(_VeriSignClass3CA) },
- };
- unsigned int i, certmaplen = sizeof(certmap) / sizeof(certmap_entry_t);
- for (i=0; i<certmaplen; i++) {
- SecCertificateRef cert = SecCertificateCreateWithBytes(NULL,
- certmap[i].data, certmap[i].length);
- if (cert) {
- CFArrayAppendValue(certArray, cert);
- CFRelease(cert);
- cert = NULL;
- }
+ CFBundleRef bundle = CFBundleGetMainBundle();
+ CFStringRef bundleIdentifier = (bundle) ? CFBundleGetIdentifier(bundle) : NULL;
+ if (!bundleIdentifier || !certArray) { return; }
+
+ // conditionally include 1024-bit compatibility roots for specific apps
+ const certmap_entry_t certmap[] = {
+ { CFSTR("com.autodesk.AdSSO"), _GTECyberTrustGlobalRootCA, sizeof(_GTECyberTrustGlobalRootCA) }, // rdar://25916338
+ { CFSTR("com.clo3d.MD5"), _ThawtePremiumServerCA, sizeof(_ThawtePremiumServerCA) }, // rdar://26281864
+ };
+
+ unsigned int i, certmaplen = sizeof(certmap) / sizeof(certmap_entry_t);
+ for (i=0; i<certmaplen; i++) {
+ if (CFStringCompare(bundleIdentifier, certmap[i].bundleId, 0) == kCFCompareEqualTo) {
+ SecCertificateRef cert = SecCertificateCreateWithBytes(NULL, certmap[i].data, certmap[i].length);
+ if (!cert) { continue; }
+ CFArrayAppendValue(certArray, cert);
+ CFRelease(cert);
+ cert = NULL;
}
}
#else
for(unsigned domain=kSecTrustSettingsDomainUser;
domain<=kSecTrustSettingsDomainSystem;
domain++) {
- TrustSettings *ts = tsGetGlobalTrustSettings(domain);
+ TrustSettings *ts = tsGetGlobalTrustSettings((SecTrustSettingsDomain)domain);
if(ts == NULL) {
continue;
}
* is an Unspecified entry and we find a definitive entry
* later
*/
- *foundDomain = domain;
+ *foundDomain = (SecTrustSettingsDomain)domain;
}
if(found && (*resultType != kSecTrustSettingsResultUnspecified)) {
trustSettingsDbg("SecTrustSettingsEvaluateCert: found in domain %d", domain);
{
BEGIN_RCSAPI
- return tsCopyCertsCommon(NULL, NULL, NULL, /* no constraints */
+ OSStatus status = tsCopyCertsCommon(NULL, NULL, NULL, /* no constraints */
true, /* onlyRoots */
user, admin, system,
certArray);
+ return status;
+
END_RCSAPI
}
if(certRef == kSecTrustSettingsDefaultRootCertSetting) {
/* use this string instead of the cert hash as the dictionary key */
trustSettingsDbg("SecTrustSettingsCertHashStrFromCert: DefaultSetting");
+ secerror("Caller passed kSecTrustSettingsDefaultRootCertSetting. This constant is deprecated and no longer affects the behavior of the system.");
return kSecTrustRecordDefaultRootCert;
}
OSStatus result;
TrustSettings* ts;
- result = TrustSettings::CreateTrustSettings(kSecTrustSettingsDomainMemory, settingsIn, ts);
+ result = TrustSettings::CreateTrustSettings((SecTrustSettingsDomain)kSecTrustSettingsDomainMemory, settingsIn, ts);
if (result != errSecSuccess) {
return result;
}
TS_REQUIRED(certArray)
- OSStatus result;
+ OSStatus status;
TrustSettings* ts;
+ CFMutableArrayRef trustedCertArray = NULL;
+ SecTrustRef trust = NULL;
- result = TrustSettings::CreateTrustSettings(domain, CREATE_NO, TRIM_NO, ts);
- if (result != errSecSuccess) {
- return result;
+ status = TrustSettings::CreateTrustSettings(domain, CREATE_NO, TRIM_NO, ts);
+ if (status != errSecSuccess) {
+ return status;
}
auto_ptr<TrustSettings>_(ts);
CFMutableArrayRef outArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
-
+
/*
- * Keychains to search: user's search list, System.keychain, system root store,
- * system intermediates, as appropriate
+ * Keychains to search: user's search list, System.keychain, system root store
*/
StorageManager::KeychainList keychains;
Keychain adminKc;
- Keychain sysCertKc;
Keychain sysRootKc;
switch(domain) {
case kSecTrustSettingsDomainUser:
/* admin certs in system keychain */
adminKc = globals().storageManager.make(ADMIN_CERT_STORE_PATH, false);
keychains.push_back(adminKc);
- /* system-wide intermediate certs */
- sysCertKc = globals().storageManager.make(SYSTEM_CERT_STORE_PATH, false);
- keychains.push_back(sysCertKc);
/* drop thru to next case */
case kSecTrustSettingsDomainSystem:
/* and, for all cases, immutable system root store */
break;
}
ts->findCerts(keychains, outArray);
- if(CFArrayGetCount(outArray) == 0) {
- CFRelease(outArray);
+ CFIndex count = outArray ? CFArrayGetCount(outArray) : 0;
+ if(count == 0) {
+ CFReleaseSafe(outArray);
return errSecNoTrustSettings;
}
- tsAddConditionalCerts(outArray);
- *certArray = outArray;
+ /* Go through outArray and do a SecTrustEvaluate only for DomainSystem */
+ if (kSecTrustSettingsDomainSystem == domain) {
+ CFIndex i;
+ SecPolicyRef policy = SecPolicyCreateBasicX509();
+ trustedCertArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+ for (i = 0; i < count ; i++) {
+ SecTrustResultType result;
+ SecCertificateRef certificate = (SecCertificateRef) CFArrayGetValueAtIndex(outArray, i);
+ status = SecTrustCreateWithCertificates(certificate, policy, &trust);
+ if (status != errSecSuccess) {
+ CFReleaseSafe(policy);
+ goto out;
+ }
+ status = SecTrustEvaluate(trust, &result);
+ if (status != errSecSuccess) {
+ CFReleaseSafe(policy);
+ goto out;
+ }
+ if (result != kSecTrustResultFatalTrustFailure) {
+ CFArrayAppendValue(trustedCertArray, certificate);
+ }
+ CFReleaseNull(trust);
+ }
+ tsAddConditionalCerts(trustedCertArray);
+ if (CFArrayGetCount(trustedCertArray) == 0) {
+ status = errSecNoTrustSettings;
+ } else {
+ *certArray = trustedCertArray;
+ CFReleaseSafe(outArray);
+ }
+ CFReleaseSafe(policy);
+ } else {
+ *certArray = outArray;
+ }
+out:
+ if (status != errSecSuccess) {
+ CFReleaseSafe(outArray);
+ CFReleaseSafe(trustedCertArray);
+ }
+ CFReleaseNull(trust);
+ return status;
END_RCSAPI
}
+static CFArrayRef gUserAdminCerts = NULL;
+static bool gUserAdminCertsCacheBuilt = false;
+static ModuleNexus<ReadWriteLock> gUserAdminCertsLock;
+
+void SecTrustSettingsPurgeUserAdminCertsCache(void) {
+ StReadWriteLock _(gUserAdminCertsLock(), StReadWriteLock::Write);
+ CFReleaseNull(gUserAdminCerts);
+ gUserAdminCertsCacheBuilt = false;
+}
+
+OSStatus SecTrustSettingsCopyCertificatesForUserAdminDomains(
+ CFArrayRef *certArray)
+{
+ TS_REQUIRED(certArray);
+ OSStatus result = errSecSuccess;
+
+ { /* Hold the read lock for the check */
+ StReadWriteLock _(gUserAdminCertsLock(), StReadWriteLock::Read);
+ if (gUserAdminCertsCacheBuilt) {
+ if (gUserAdminCerts) {
+ *certArray = (CFArrayRef)CFRetain(gUserAdminCerts);
+ return errSecSuccess;
+ } else {
+ return errSecNoTrustSettings;
+ }
+ }
+ }
+
+ /* There were no cached results. We'll have to recreate them. */
+ CFMutableArrayRef outArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+ if (!outArray) {
+ return errSecAllocate;
+ }
+
+ CFArrayRef userTrusted = NULL, adminTrusted = NULL;
+ OSStatus userStatus = SecTrustSettingsCopyCertificates(kSecTrustSettingsDomainUser, &userTrusted);
+ if ((userStatus == errSecSuccess) && (userTrusted != NULL)) {
+ CFArrayAppendArray(outArray, userTrusted, CFRangeMake(0, CFArrayGetCount(userTrusted)));
+ CFRelease(userTrusted);
+ }
+
+ OSStatus adminStatus = SecTrustSettingsCopyCertificates(kSecTrustSettingsDomainAdmin, &adminTrusted);
+ if ((adminStatus == errSecSuccess) && (adminTrusted != NULL)) {
+ CFArrayAppendArray(outArray, adminTrusted, CFRangeMake(0, CFArrayGetCount(adminTrusted)));
+ CFRelease(adminTrusted);
+ }
+
+ /* Lack of trust settings for a domain results in an error above. Only fail
+ * if we weren't able to get trust settings for both domains. */
+ if (userStatus != errSecSuccess && adminStatus != errSecSuccess) {
+ result = userStatus;
+ }
+
+ if (result != errSecSuccess && outArray) {
+ CFRelease(outArray);
+ outArray = NULL;
+ }
+
+ *certArray = outArray;
+
+ /* For valid results, update the global cache */
+ if (result == errSecSuccess || result == errSecNoTrustSettings) {
+ StReadWriteLock _(gUserAdminCertsLock(), StReadWriteLock::Write);
+ CFReleaseNull(gUserAdminCerts);
+ gUserAdminCerts = (CFArrayRef)CFRetainSafe(outArray);
+ gUserAdminCertsCacheBuilt = true;
+ }
+
+ return result;
+}
+
/*
* Obtain an external, portable representation of the specified
* domain's TrustSettings. Caller must CFRelease the returned data.
END_RCSAPI
}
+/*
+ * SecTrustSettingsSetTrustSettings convenience wrapper function.
+ */
+void SecTrustSettingsSetTrustedCertificateForSSLHost(
+ SecCertificateRef certificate,
+ CFStringRef hostname,
+ void (^result)(SecTrustSettingsResult trustResult, CFErrorRef error))
+{
+ __block CFMutableArrayRef trustSettings = NULL;
+ __block CFNumberRef trustSettingsResult = NULL;
+ __block SecTrustSettingsDomain domain = kSecTrustSettingsDomainUser;
+
+ CFDictionaryRef policyProperties = NULL;
+ CFStringRef policyOid = NULL;
+ SecPolicyRef policy = NULL;
+
+ Boolean isSelfSigned = false;
+ Boolean hasPolicyConstraint = false;
+ Boolean hasPolicyValue = false;
+ Boolean policyConstraintChanged = false;
+ CFIndex indexOfEntryWithAllowedErrorForExpiredCert = kCFNotFound;
+ CFIndex indexOfEntryWithAllowedErrorForHostnameMismatch = kCFNotFound;
+ CFIndex i, count;
+ int32_t trustSettingsResultCode = kSecTrustSettingsResultTrustAsRoot;
+ OSStatus status = errSecSuccess;
+
+ CFRetainSafe(certificate);
+ CFRetainSafe(hostname);
+ if (!certificate || !hostname) {
+ status = errSecParam;
+ } else {
+ status = SecCertificateIsSelfSigned(certificate, &isSelfSigned);
+ }
+ if (status != errSecSuccess) {
+ goto reportErr;
+ }
+ if (isSelfSigned) {
+ trustSettingsResultCode = kSecTrustSettingsResultTrustRoot;
+ }
+ trustSettingsResult = CFNumberCreate(NULL, kCFNumberSInt32Type, &trustSettingsResultCode);
+
+ /* start with the existing trust settings for this certificate, if any */
+ {
+ CFArrayRef curTrustSettings = NULL;
+ (void)SecTrustSettingsCopyTrustSettings(certificate, domain, &curTrustSettings);
+ if (curTrustSettings) {
+ trustSettings = CFArrayCreateMutableCopy(NULL, 0, curTrustSettings);
+ CFReleaseNull(curTrustSettings);
+ } else {
+ trustSettings = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+ }
+ }
+ if (!trustSettings || !trustSettingsResult) {
+ status = errSecAllocate;
+ goto reportErr;
+ }
+
+ /* set up policy and value instances to trust the certificate for SSL for a given hostname */
+ policy = SecPolicyCreateSSL(true, hostname);
+ if (!policy) {
+ status = errSecInternal;
+ goto reportErr;
+ }
+ policyProperties = SecPolicyCopyProperties(policy);
+ if (!policyProperties) {
+ status = errSecInternal;
+ goto reportErr;
+ }
+ policyOid = (CFStringRef)CFDictionaryGetValue(policyProperties, kSecPolicyOid);
+ CFRetainSafe(policyOid);
+ if (!policyOid) {
+ status = errSecInternal;
+ goto reportErr;
+ }
+
+ /* look for dictionaries in the trust settings array for this policy and value */
+ count = CFArrayGetCount(trustSettings);
+ for (i=0; i < count; i++) {
+ CFDictionaryRef constraints = (CFDictionaryRef)CFArrayGetValueAtIndex(trustSettings, i);
+ if (!constraints) { continue; }
+ SecPolicyRef aPolicy = (SecPolicyRef)CFDictionaryGetValue(constraints, kSecTrustSettingsPolicy);
+ if (!aPolicy) { continue; }
+ CFDictionaryRef properties = SecPolicyCopyProperties(aPolicy);
+ if (!properties) { continue; }
+ CFStringRef aPolicyOid = (CFStringRef)CFDictionaryGetValue(properties, kSecPolicyOid);
+ if (aPolicyOid && kCFCompareEqualTo == CFStringCompare(aPolicyOid, policyOid, 0)) {
+ CFStringRef aPolicyString = (CFStringRef)CFDictionaryGetValue(constraints, kSecTrustSettingsPolicyString);
+ if (aPolicyString && kCFCompareEqualTo == CFStringCompare(aPolicyString, hostname, kCFCompareCaseInsensitive)) {
+ /* found existing entry */
+ CFNumberRef allowedErr = (CFNumberRef)CFDictionaryGetValue(constraints, kSecTrustSettingsAllowedError);
+ int32_t eOld = 0;
+ if (!allowedErr || !CFNumberGetValue(allowedErr, kCFNumberSInt32Type, &eOld)) {
+ eOld = CSSM_OK;
+ }
+ CFNumberRef tsResult = (CFNumberRef)CFDictionaryGetValue(constraints, kSecTrustSettingsResult);
+ int32_t rOld = 0;
+ if (!tsResult || !CFNumberGetValue(allowedErr, kCFNumberSInt32Type, &rOld)) {
+ rOld = kSecTrustSettingsResultTrustRoot;
+ }
+ if (!hasPolicyValue) { hasPolicyValue = (aPolicyString != NULL); }
+ if (!hasPolicyConstraint) { hasPolicyConstraint = true; }
+ if (eOld == CSSMERR_TP_CERT_EXPIRED) {
+ indexOfEntryWithAllowedErrorForExpiredCert = i;
+ } else if (eOld == CSSMERR_APPLETP_HOSTNAME_MISMATCH) {
+ indexOfEntryWithAllowedErrorForHostnameMismatch = i;
+ }
+ if (trustSettingsResultCode != rOld) {
+ policyConstraintChanged = true; // we are changing existing policy constraint's result
+ }
+ }
+ }
+ CFReleaseSafe(properties);
+ }
+
+ if (!hasPolicyConstraint) {
+ policyConstraintChanged = true; // we are adding a new policy constraint
+ } else if (hostname && !hasPolicyValue) {
+ policyConstraintChanged = true; // we need to add the hostname to an existing policy constraint
+ } else if ((indexOfEntryWithAllowedErrorForExpiredCert == kCFNotFound) ||
+ (indexOfEntryWithAllowedErrorForHostnameMismatch == kCFNotFound)) {
+ policyConstraintChanged = true; // we are missing one of the expected allowed-error entries for this policy
+ }
+
+ if (policyConstraintChanged) {
+ CFMutableDictionaryRef policyDict[2] = { NULL, NULL };
+ policyDict[0] = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+ policyDict[1] = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+ int32_t certExpiredCode = (int32_t)CSSMERR_TP_CERT_EXPIRED;
+ CFNumberRef certExpired = CFNumberCreate(NULL, kCFNumberSInt32Type, &certExpiredCode);
+ int32_t hostnameMismatchCode = (int32_t)CSSMERR_APPLETP_HOSTNAME_MISMATCH;
+ CFNumberRef hostnameMismatch = CFNumberCreate(NULL, kCFNumberSInt32Type, &hostnameMismatchCode);
+ if (!policyDict[0] || !policyDict[1] || !certExpired || !hostnameMismatch) {
+ status = errSecInternal;
+ } else {
+ /* set up entry for policy, hostname, expired cert error, and result */
+ CFDictionarySetValue(policyDict[0], kSecTrustSettingsPolicy, policy);
+ CFDictionarySetValue(policyDict[0], kSecTrustSettingsPolicyString, hostname);
+ CFDictionarySetValue(policyDict[0], kSecTrustSettingsAllowedError, certExpired);
+ CFDictionarySetValue(policyDict[0], kSecTrustSettingsResult, trustSettingsResult);
+ if (indexOfEntryWithAllowedErrorForExpiredCert != kCFNotFound) {
+ /* if we found an existing constraint for this policy, hostname, and allowed error, replace it */
+ CFArraySetValueAtIndex(trustSettings, indexOfEntryWithAllowedErrorForExpiredCert, policyDict[0]);
+ } else if (!(hasPolicyValue)) {
+ /* add a new policy constraint */
+ CFArrayAppendValue(trustSettings, policyDict[0]);
+ }
+ /* set up additional entry for policy, hostname, hostname mismatch error, and result */
+ CFDictionarySetValue(policyDict[1], kSecTrustSettingsPolicy, policy);
+ CFDictionarySetValue(policyDict[1], kSecTrustSettingsPolicyString, hostname);
+ CFDictionarySetValue(policyDict[1], kSecTrustSettingsAllowedError, hostnameMismatch);
+ CFDictionarySetValue(policyDict[1], kSecTrustSettingsResult, trustSettingsResult);
+ if (indexOfEntryWithAllowedErrorForHostnameMismatch != kCFNotFound) {
+ /* if we found an existing constraint for this policy, hostname, and allowed error, replace it */
+ CFArraySetValueAtIndex(trustSettings, indexOfEntryWithAllowedErrorForHostnameMismatch, policyDict[1]);
+ } else if (!(hasPolicyValue)) {
+ /* add a new policy constraint */
+ CFArrayAppendValue(trustSettings, policyDict[1]);
+ }
+ }
+ CFReleaseSafe(policyDict[0]);
+ CFReleaseSafe(policyDict[1]);
+ CFReleaseSafe(certExpired);
+ CFReleaseSafe(hostnameMismatch);
+ }
+
+ if (status != errSecSuccess) {
+ goto reportErr;
+ }
+ CFReleaseSafe(policyOid);
+ CFReleaseSafe(policyProperties);
+ CFReleaseSafe(policy);
+
+ dispatch_async(dispatch_get_main_queue(), ^{
+ /* add certificate to keychain first */
+ OSStatus status = SecCertificateAddToKeychain(certificate, NULL);
+ if (status == errSecSuccess || status == errSecDuplicateItem) {
+ /* this will block on authorization UI... */
+ status = SecTrustSettingsSetTrustSettings(certificate,
+ domain, trustSettings);
+ }
+ if (result) {
+ CFErrorRef error = NULL;
+ if (status) {
+ error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, status, NULL);
+ }
+ int32_t tsrc;
+ if (!CFNumberGetValue(trustSettingsResult, kCFNumberSInt32Type, (int32_t*)&tsrc)) {
+ tsrc = (int32_t)kSecTrustSettingsResultUnspecified;
+ }
+ result((SecTrustSettingsResult)tsrc, error);
+ CFReleaseSafe(error);
+ }
+ CFRelease(trustSettingsResult);
+ CFRelease(trustSettings);
+ CFRelease(certificate);
+ CFRelease(hostname);
+ });
+
+ return;
+
+reportErr:
+ CFReleaseSafe(policyOid);
+ CFReleaseSafe(policyProperties);
+ CFReleaseSafe(policy);
+ CFReleaseSafe(trustSettingsResult);
+ CFReleaseSafe(trustSettings);
+ CFReleaseSafe(certificate);
+ CFReleaseSafe(hostname);
+ if (result) {
+ CFErrorRef error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, status, NULL);
+ result(kSecTrustSettingsResultInvalid, error);
+ CFReleaseSafe(error);
+ }
+}