X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/5dd5f9ec28f304ca377c42fd7f711d6cf12b90e1..5c19dc3ae3bd8e40a9c028b0deddd50ff337692c:/OSX/libsecurity_keychain/lib/SecTrust.cpp?ds=sidebyside diff --git a/OSX/libsecurity_keychain/lib/SecTrust.cpp b/OSX/libsecurity_keychain/lib/SecTrust.cpp new file mode 100644 index 00000000..ae0d4c93 --- /dev/null +++ b/OSX/libsecurity_keychain/lib/SecTrust.cpp @@ -0,0 +1,1297 @@ +/* + * Copyright (c) 2002-2015 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#include "SecTrust.h" +#include "SecTrustPriv.h" +#include "Trust.h" +#include +#include "SecBase.h" +#include "SecBridge.h" +#include "SecInternal.h" +#include "SecInternalP.h" +#include "SecTrustSettings.h" +#include "SecCertificatePriv.h" +#include "SecCertificateP.h" +#include "SecCertificatePrivP.h" +#include "SecPolicyPriv.h" +#include +#include +#include +#include + +// forward declarations +#if !SECTRUST_OSX +CFArrayRef SecTrustCopyDetails(SecTrustRef trust); +static CFDictionaryRef SecTrustGetExceptionForCertificateAtIndex(SecTrustRef trust, CFIndex ix); +static void SecTrustCheckException(const void *key, const void *value, void *context); +#endif + +typedef struct SecTrustCheckExceptionContext { + CFDictionaryRef exception; + bool exceptionNotFound; +} SecTrustCheckExceptionContext; + +// public trust result constants +const CFStringRef kSecTrustEvaluationDate = CFSTR("TrustEvaluationDate"); +const CFStringRef kSecTrustExtendedValidation = CFSTR("TrustExtendedValidation"); +const CFStringRef kSecTrustOrganizationName = CFSTR("Organization"); +const CFStringRef kSecTrustResultValue = CFSTR("TrustResultValue"); +const CFStringRef kSecTrustRevocationChecked = CFSTR("TrustRevocationChecked"); +const CFStringRef kSecTrustRevocationReason = CFSTR("TrustRevocationReason"); +const CFStringRef kSecTrustRevocationValidUntilDate = CFSTR("TrustExpirationDate"); +const CFStringRef kSecTrustResultDetails = CFSTR("TrustResultDetails"); + +// +// CF boilerplate +// +#if !SECTRUST_OSX +CFTypeID SecTrustGetTypeID(void) +{ + BEGIN_SECAPI + + return gTypes().Trust.typeID; + + END_SECAPI1(_kCFRuntimeNotATypeID) +} +#endif + +// +// Sec* API bridge functions +// +#if !SECTRUST_OSX +OSStatus SecTrustCreateWithCertificates( + CFTypeRef certificates, + CFTypeRef policies, + SecTrustRef *trustRef) +{ + BEGIN_SECAPI + Required(trustRef); + *trustRef = (new Trust(certificates, policies))->handle(); + END_SECAPI +} +#endif + +#if !SECTRUST_OSX +OSStatus +SecTrustSetPolicies(SecTrustRef trustRef, CFTypeRef policies) +{ + BEGIN_SECAPI + Trust::required(trustRef)->policies(policies); + END_SECAPI +} +#endif + +/* OS X only: __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA) */ +OSStatus +SecTrustSetOptions(SecTrustRef trustRef, SecTrustOptionFlags options) +{ +#if !SECTRUST_OSX + BEGIN_SECAPI + CSSM_APPLE_TP_ACTION_DATA actionData = { + CSSM_APPLE_TP_ACTION_VERSION, + (CSSM_APPLE_TP_ACTION_FLAGS)options + }; + Trust *trust = Trust::required(trustRef); + CFDataRef actionDataRef = CFDataCreate(NULL, + (const UInt8 *)&actionData, + (CFIndex)sizeof(CSSM_APPLE_TP_ACTION_DATA)); + trust->action(CSSM_TP_ACTION_DEFAULT); + trust->actionData(actionDataRef); + if (actionDataRef) CFRelease(actionDataRef); + END_SECAPI +#else + /* bridge to support API functionality for legacy callers */ + OSStatus status = errSecSuccess; +#if 1 +#warning STU: +//%%% need to ensure that the exception covers only the requested options +#else + CFArrayRef details = SecTrustGetDetails(trustRef); // NOTE: performs the evaluation if not done already + CFIndex pathLength = details ? CFArrayGetCount(details) : 0; + CFIndex ix; + for (ix = 0; ix < pathLength; ++ix) { + CFDictionaryRef detail = (CFDictionaryRef)CFArrayGetValueAtIndex(details, ix); + CFIndex detailCount = CFDictionaryGetCount(detail); + if (detailCount > 0) { + // see if we can ignore this error + syslog(LOG_ERR, "SecTrustSetOptions: examining detail dictionary items at ix %ld", (long)ix); + CFShow(detail); + } + } + syslog(LOG_ERR, "SecTrustSetOptions: creating trust exception"); +#endif + CFDataRef exceptions = SecTrustCopyExceptions(trustRef); + if (exceptions) { + SecTrustSetExceptions(trustRef, exceptions); + CFRelease(exceptions); + } + + +#if SECTRUST_DEPRECATION_WARNINGS + bool displayModifyMsg = false; + bool displayNetworkMsg = false; + bool displayPolicyMsg = false; + const char *baseMsg = "WARNING: SecTrustSetOptions called with"; + const char *modifyMsg = "Use SecTrustSetExceptions and SecTrustCopyExceptions to modify default trust results."; + const char *networkMsg = "Use SecTrustSetNetworkFetchAllowed to specify whether missing certificates can be fetched from the network."; + const char *policyMsg = "Use SecPolicyCreateRevocation to specify revocation policy requirements."; + + if (options & kSecTrustOptionAllowExpired) { + syslog(LOG_ERR, "%s %s.", baseMsg, "kSecTrustOptionAllowExpired"); + displayModifyMsg = true; + } + if (options & kSecTrustOptionAllowExpiredRoot) { + syslog(LOG_ERR, "%s %s.", baseMsg, "kSecTrustOptionAllowExpiredRoot"); + displayModifyMsg = true; + } + if (options & kSecTrustOptionFetchIssuerFromNet) { + syslog(LOG_ERR, "%s %s.", baseMsg, "kSecTrustOptionFetchIssuerFromNet"); + displayNetworkMsg = true; + } + if (options & kSecTrustOptionRequireRevPerCert) { + syslog(LOG_ERR, "%s %s.", baseMsg, "kSecTrustOptionRequireRevPerCert"); + displayPolicyMsg = true; + } + if (displayModifyMsg || displayNetworkMsg || displayPolicyMsg) { + syslog(LOG_ERR, "%s %s %s", + (displayModifyMsg) ? modifyMsg : "", + (displayNetworkMsg) ? networkMsg : "", + (displayPolicyMsg) ? policyMsg : ""); + } +#endif + + return status; + +#endif +} + +/* OS X only: __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA) */ +OSStatus SecTrustSetParameters( + SecTrustRef trustRef, + CSSM_TP_ACTION action, + CFDataRef actionData) +{ +#if !SECTRUST_OSX + BEGIN_SECAPI + Trust *trust = Trust::required(trustRef); + trust->action(action); + trust->actionData(actionData); + END_SECAPI +#else + /* bridge to support API functionality for legacy callers */ + OSStatus status; + CSSM_APPLE_TP_ACTION_FLAGS actionFlags = 0; + if (actionData) { + CSSM_APPLE_TP_ACTION_DATA *actionDataPtr = (CSSM_APPLE_TP_ACTION_DATA *) CFDataGetBytePtr(actionData); + if (actionDataPtr) { + actionFlags = actionDataPtr->ActionFlags; + } + } + // note that SecTrustOptionFlags == CSSM_APPLE_TP_ACTION_FLAGS; + // both are sizeof(uint32) and the flag values have identical meanings + status = SecTrustSetOptions(trustRef, (SecTrustOptionFlags)actionFlags); + +#if SECTRUST_DEPRECATION_WARNINGS + syslog(LOG_ERR, "WARNING: SecTrustSetParameters was deprecated in 10.7. Use SecTrustSetOptions instead."); +#endif + + return status; + +#endif +} + +#if !SECTRUST_OSX +OSStatus SecTrustSetAnchorCertificates(SecTrustRef trust, CFArrayRef anchorCertificates) +{ + BEGIN_SECAPI + Trust::required(trust)->anchors(anchorCertificates); + END_SECAPI +} +#endif + +#if !SECTRUST_OSX +OSStatus SecTrustSetAnchorCertificatesOnly(SecTrustRef trust, Boolean anchorCertificatesOnly) +{ + BEGIN_SECAPI + Trust::AnchorPolicy policy = (anchorCertificatesOnly) ? Trust::useAnchorsOnly : Trust::useAnchorsAndBuiltIns; + Trust::required(trust)->anchorPolicy(policy); + END_SECAPI +} +#endif + +/* OS X only: __OSX_AVAILABLE_STARTING(__MAC_10_3, __IPHONE_NA) */ +OSStatus SecTrustSetKeychains(SecTrustRef trust, CFTypeRef keychainOrArray) +{ +#if !SECTRUST_OSX + BEGIN_SECAPI + StorageManager::KeychainList keychains; + // avoid unnecessary global initializations if an empty array is passed in + if (!( (keychainOrArray != NULL) && + (CFGetTypeID(keychainOrArray) == CFArrayGetTypeID()) && + (CFArrayGetCount((CFArrayRef)keychainOrArray) == 0) )) { + globals().storageManager.optionalSearchList(keychainOrArray, keychains); + } + Trust::required(trust)->searchLibs(keychains); + END_SECAPI +#else + /* this function is currently unsupported in unified SecTrust */ + // TODO: pull all certs out of the specified keychains for the evaluation? +#if SECTRUST_DEPRECATION_WARNINGS + syslog(LOG_ERR, "WARNING: SecTrustSetKeychains does nothing in 10.11. Use SecTrustSetAnchorCertificates{Only} to provide anchors."); +#endif + return errSecSuccess; +#endif +} + +#if !SECTRUST_OSX +OSStatus SecTrustSetVerifyDate(SecTrustRef trust, CFDateRef verifyDate) +{ + BEGIN_SECAPI + Trust::required(trust)->time(verifyDate); + END_SECAPI +} +#endif + +#if !SECTRUST_OSX +CFAbsoluteTime SecTrustGetVerifyTime(SecTrustRef trust) +{ + CFAbsoluteTime verifyTime = 0; + OSStatus __secapiresult = errSecSuccess; + try { + CFRef verifyDate = Trust::required(trust)->time(); + verifyTime = CFDateGetAbsoluteTime(verifyDate); + } + catch (const MacOSError &err) { __secapiresult=err.osStatus(); } + catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); } + catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; } + catch (...) { __secapiresult=errSecInternalComponent; } + return verifyTime; +} +#endif + + + +#if !SECTRUST_OSX +OSStatus SecTrustEvaluate(SecTrustRef trust, SecTrustResultType *resultP) +{ + SecTrustResultType trustResult = kSecTrustResultInvalid; + CFArrayRef exceptions = NULL; + OSStatus __secapiresult = errSecSuccess; + try { + Trust *trustObj = Trust::required(trust); + trustObj->evaluate(); + trustResult = trustObj->result(); + exceptions = trustObj->exceptions(); + } + catch (const MacOSError &err) { __secapiresult=err.osStatus(); } + catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); } + catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; } + catch (...) { __secapiresult=errSecInternalComponent; } + + if (__secapiresult) { + return __secapiresult; + } + + /* post-process trust result based on exceptions */ + if (trustResult == kSecTrustResultUnspecified) { + /* If leaf is in exceptions -> proceed, otherwise unspecified. */ + if (SecTrustGetExceptionForCertificateAtIndex(trust, 0)) + trustResult = kSecTrustResultProceed; + } + else if (trustResult == kSecTrustResultRecoverableTrustFailure && exceptions) { + /* If we have exceptions get details and match to exceptions. */ + CFArrayRef details = SecTrustCopyDetails(trust); + if (details) { + CFIndex pathLength = CFArrayGetCount(details); + struct SecTrustCheckExceptionContext context = {}; + CFIndex ix; + for (ix = 0; ix < pathLength; ++ix) { + CFDictionaryRef detail = (CFDictionaryRef)CFArrayGetValueAtIndex(details, ix); + // if ((ix == 0) && CFDictionaryContainsKey(detail, kSecPolicyCheckBlackListedLeaf)) + // trustResult = kSecTrustResultFatalTrustFailure; + context.exception = SecTrustGetExceptionForCertificateAtIndex(trust, ix); + CFDictionaryApplyFunction(detail, SecTrustCheckException, &context); + if (context.exceptionNotFound) { + break; + } + } + if (!context.exceptionNotFound) + trustResult = kSecTrustResultProceed; + } + } + + + secdebug("SecTrustEvaluate", "SecTrustEvaluate trust result = %d", (int)trustResult); + if (resultP) { + *resultP = trustResult; + } + return __secapiresult; +} +#endif + +#if !SECTRUST_OSX +OSStatus SecTrustEvaluateAsync(SecTrustRef trust, + dispatch_queue_t queue, SecTrustCallback result) +{ + BEGIN_SECAPI + dispatch_async(queue, ^{ + try { + Trust *trustObj = Trust::required(trust); + trustObj->evaluate(); + SecTrustResultType trustResult = trustObj->result(); + result(trust, trustResult); + } + catch (...) { + result(trust, kSecTrustResultInvalid); + }; + }); + END_SECAPI +} +#endif + +// +// Construct the "official" result evidence and return it +// +/* OS X only: __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA) */ +OSStatus SecTrustGetResult( + SecTrustRef trustRef, + SecTrustResultType *result, + CFArrayRef *certChain, CSSM_TP_APPLE_EVIDENCE_INFO **statusChain) +{ +#if !SECTRUST_OSX + BEGIN_SECAPI + Trust *trust = Trust::required(trustRef); + if (result) + *result = trust->result(); + if (certChain && statusChain) + trust->buildEvidence(*certChain, TPEvidenceInfo::overlayVar(*statusChain)); + END_SECAPI +#else + /* bridge to support old functionality */ +#if SECTRUST_DEPRECATION_WARNINGS + syslog(LOG_ERR, "WARNING: SecTrustGetResult has been deprecated since 10.7, and may not return a statusChain in 10.11. Please use SecTrustGetTrustResult instead."); +#endif + SecTrustResultType trustResult; + OSStatus status = SecTrustGetTrustResult(trustRef, &trustResult); + if (result) { + *result = trustResult; + } + if (certChain && !statusChain) { + /* This is the easy case; caller only wants cert chain and not status chain. */ + CFMutableArrayRef certArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + CFIndex idx, count = SecTrustGetCertificateCount(trustRef); + for (idx=0; idx < count; idx++) { + SecCertificateRef certificate = SecTrustGetCertificateAtIndex(trustRef, idx); + if (certificate) { + CFArrayAppendValue(certArray, certificate); + } + } + *certChain = certArray; + } + else if (certChain && statusChain) { + /* + * Here is where backward compatibility gets ugly. CSSM_TP_APPLE_EVIDENCE_INFO* is tied to a + * Trust object and does not exist in the new unified world. Unfortunately, some clients are + * still calling this legacy API and grubbing through the info for StatusBits and StatusCodes. + * If they want this info, then we have to do a legacy evaluation to get it. The info struct + * goes away once the old-style object does, so we must keep the old-style object alive after + * returning from the function. + * + * TODO: keep a dictionary and figure out how to expire entries when no longer needed., + * or build the evidence info ourselves: rdar://21005914 + */ + static CFMutableArrayRef sTrustArray = NULL; + + // make array of Certificate instances from unified SecCertificateRefs + CFMutableArrayRef certArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + CFIndex idx, count = SecTrustGetCertificateCount(trustRef); + for (idx=0; idx < count; idx++) { + SecCertificateRef certificate = SecTrustGetCertificateAtIndex(trustRef, idx); + if (certificate) { + SecCertificateRef itemImplRef = SecCertificateCreateItemImplInstance(certificate); + if (itemImplRef) { + CFArrayAppendValue(certArray, itemImplRef); + CFRelease(itemImplRef); + } + } + } + // make array of Policy instances from unified SecPolicyRefs + CFMutableArrayRef policyArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + CFArrayRef policies = NULL; + status = SecTrustCopyPolicies(trustRef, &policies); + count = (!status && policies) ? CFArrayGetCount(policies) : 0; + for (idx=0; idx < count; idx++) { + SecPolicyRef policy = (SecPolicyRef) CFArrayGetValueAtIndex(policies, idx); + if (policy) { + SecPolicyRef itemImplRef = SecPolicyCreateItemImplInstance(policy); + if (itemImplRef) { + CFArrayAppendValue(policyArray, itemImplRef); + CFRelease(itemImplRef); + } + } + } + // now make a Trust instance and evaluate it + try { + Trust *trustObj = new Trust(certArray, policyArray); + SecTrustRef trust = trustObj->handle(); + if (!trust) { + MacOSError::throwMe(errSecTrustNotAvailable); + } + if (!sTrustArray) { + sTrustArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + if (!sTrustArray) { + MacOSError::throwMe(errSecAllocate); + } + } + // fetch the built cert chain and status chain + CFArrayRef itemImplCertArray = NULL; + trustObj->evaluate(); + trustObj->buildEvidence(itemImplCertArray, TPEvidenceInfo::overlayVar(*statusChain)); + + // convert each Certificate in the built chain to a unified SecCertificateRef + CFMutableArrayRef outCertChain = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + CFIndex idx, count = (itemImplCertArray) ? CFArrayGetCount(itemImplCertArray) : 0; + for (idx=0; idx < count; idx++) { + SecCertificateRef inCert = (SecCertificateRef) CFArrayGetValueAtIndex(itemImplCertArray, idx); + SecCertificateRef outCert = SecCertificateCreateFromItemImplInstance(inCert); + if (outCert) { + CFArrayAppendValue(outCertChain, outCert); + CFRelease(outCert); + } + } + *certChain = outCertChain; + if (itemImplCertArray) { + CFRelease(itemImplCertArray); + } + CFArrayAppendValue(sTrustArray, trust); + status = errSecSuccess; + } + catch (const MacOSError &err) { status=err.osStatus(); } + catch (const CommonError &err) { status=SecKeychainErrFromOSStatus(err.osStatus()); } + catch (const std::bad_alloc &) { status=errSecAllocate; } + catch (...) { status=errSecInternalComponent; } + + if (policyArray) + CFRelease(policyArray); + if (certArray) + CFRelease(certArray); + } + return status; +#endif +} + +// +// Retrieve result of trust evaluation only +// +#if !SECTRUST_OSX +OSStatus SecTrustGetTrustResult(SecTrustRef trustRef, + SecTrustResultType *result) +{ + BEGIN_SECAPI + Trust *trust = Trust::required(trustRef); + if (result) *result = trust->result(); + END_SECAPI +} +#endif + +// +// Retrieve extended validation trust results +// +/* OS X only: __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_NA) */ +OSStatus SecTrustCopyExtendedResult(SecTrustRef trust, CFDictionaryRef *result) +{ +#if !SECTRUST_OSX + BEGIN_SECAPI + Trust *trustObj = Trust::required(trust); + if (result == nil) + return errSecParam; + trustObj->extendedResult(*result); + END_SECAPI +#else + /* bridge to support old functionality */ +#if SECTRUST_DEPRECATION_WARNINGS + syslog(LOG_ERR, "WARNING: SecTrustCopyExtendedResult will be deprecated in an upcoming release. Please use SecTrustCopyResult instead."); +#endif + CFDictionaryRef resultDict = SecTrustCopyResult(trust); + if (result == nil) { + return errSecParam; + } + *result = resultDict; + return errSecSuccess; +#endif +} + +// +// Retrieve CSSM-level information for those who want to dig down +// +/* OS X only: __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA) */ +OSStatus SecTrustGetCssmResult(SecTrustRef trust, CSSM_TP_VERIFY_CONTEXT_RESULT_PTR *result) +{ +#if !SECTRUST_OSX + BEGIN_SECAPI + Required(result) = Trust::required(trust)->cssmResult(); + END_SECAPI +#else + /* this function is unsupported in unified SecTrust */ +#if SECTRUST_DEPRECATION_WARNINGS + syslog(LOG_ERR, "WARNING: SecTrustGetCssmResult has been deprecated since 10.7, and has no functional equivalent in 10.11. Please use SecTrustCopyResult instead."); +#endif + if (result) { + *result = NULL; + } + return errSecServiceNotAvailable; +#endif +} + +#if SECTRUST_OSX +static void applyPropertyToCssmResultCode(const void *_key, const void *_value, void *context) { + CFStringRef key = (CFStringRef)_key; + CFStringRef value = (CFStringRef)_value; + OSStatus *result = (OSStatus *)context; + if (CFGetTypeID(_value) != CFStringGetTypeID()) { + return; + } + if (!CFEqual(CFSTR("value"), key)) { + return; + } + if (CFEqual(CFSTR("Invalid certificate chain linkage."), value)) { + *result = CSSMERR_APPLETP_INVALID_ID_LINKAGE; + } else if (CFEqual(CFSTR("One or more unsupported critical extensions found."), value)) { + *result = CSSMERR_APPLETP_UNKNOWN_CRITICAL_EXTEN; + } else if (CFEqual(CFSTR("Root certificate is not trusted."), value)) { + *result = CSSMERR_TP_NOT_TRUSTED; + } else if (CFEqual(CFSTR("Hostname mismatch."), value)) { + *result = CSSMERR_APPLETP_HOSTNAME_MISMATCH; + } else if (CFEqual(CFSTR("One or more certificates have expired or are not valid yet."), value)) { + *result = CSSMERR_TP_CERT_EXPIRED; + } else if (CFEqual(CFSTR("Policy requirements not met."), value)) { + *result = CSSMERR_TP_VERIFY_ACTION_FAILED; + } +} +#endif + +// +// Retrieve CSSM_LEVEL TP return code +// +/* OS X only: __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA) */ +OSStatus SecTrustGetCssmResultCode(SecTrustRef trustRef, OSStatus *result) +{ +#if !SECTRUST_OSX + BEGIN_SECAPI + Trust *trust = Trust::required(trustRef); + if (trust->result() == kSecTrustResultInvalid) + return errSecParam; + else + Required(result) = trust->cssmResultCode(); + END_SECAPI +#else + /* bridge to support old functionality */ +#if SECTRUST_DEPRECATION_WARNINGS + syslog(LOG_ERR, "WARNING: SecTrustGetCssmResultCode has been deprecated since 10.7, and will be removed in a future release. Please use SecTrustCopyProperties instead."); +#endif + if (!trustRef || !result) { + return errSecParam; + } + CFArrayRef properties = SecTrustCopyProperties(trustRef); + if (!properties) { + *result = 0; + return errSecSuccess; + } + OSStatus cssmResultCode = 0; + CFIndex ix, count = CFArrayGetCount(properties); + for (ix = 0; ix < count; ++ix) { + CFDictionaryRef property = (CFDictionaryRef) + CFArrayGetValueAtIndex(properties, ix); + CFDictionaryApplyFunction(property, applyPropertyToCssmResultCode, &cssmResultCode); + } + if (result) { + *result = cssmResultCode; + } + if (properties) { + CFRelease(properties); + } + return errSecSuccess; +#endif +} + +/* OS X only: __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA) */ +OSStatus SecTrustGetTPHandle(SecTrustRef trust, CSSM_TP_HANDLE *handle) +{ +#if !SECTRUST_OSX + BEGIN_SECAPI + Required(handle) = Trust::required(trust)->getTPHandle(); + END_SECAPI +#else + /* this function is unsupported in unified SecTrust */ +#if SECTRUST_DEPRECATION_WARNINGS + syslog(LOG_ERR, "WARNING: SecTrustGetTPHandle has been deprecated since 10.7, and cannot return CSSM objects in 10.11. Please stop using it."); +#endif + if (handle) { + *handle = NULL; + } + return errSecServiceNotAvailable; +#endif +} + +#if !SECTRUST_OSX +OSStatus SecTrustCopyPolicies(SecTrustRef trust, CFArrayRef *policies) +{ + BEGIN_SECAPI + CFArrayRef currentPolicies = Trust::required(trust)->policies(); + if (currentPolicies != NULL) + { + CFRetain(currentPolicies); + } + + Required(policies) = currentPolicies; + END_SECAPI +} +#endif + +#if !SECTRUST_OSX +OSStatus SecTrustSetNetworkFetchAllowed(SecTrustRef trust, Boolean allowFetch) +{ + BEGIN_SECAPI + Trust *trustObj = Trust::required(trust); + Trust::NetworkPolicy netPolicy = (allowFetch) ? + Trust::useNetworkEnabled : Trust::useNetworkDisabled; + trustObj->networkPolicy(netPolicy); + END_SECAPI +} +#endif + +#if !SECTRUST_OSX +OSStatus SecTrustGetNetworkFetchAllowed(SecTrustRef trust, Boolean *allowFetch) +{ + BEGIN_SECAPI + Boolean allowed = false; + Trust *trustObj = Trust::required(trust); + Trust::NetworkPolicy netPolicy = trustObj->networkPolicy(); + if (netPolicy == Trust::useNetworkDefault) { + // network fetch is enabled by default for SSL only + allowed = trustObj->policySpecified(trustObj->policies(), CSSMOID_APPLE_TP_SSL); + } else { + // caller has explicitly set the network policy + allowed = (netPolicy == Trust::useNetworkEnabled); + } + Required(allowFetch) = allowed; + END_SECAPI +} +#endif + +#if !SECTRUST_OSX +OSStatus SecTrustSetOCSPResponse(SecTrustRef trust, CFTypeRef responseData) +{ + BEGIN_SECAPI + Trust::required(trust)->responses(responseData); + END_SECAPI +} +#endif + +#if !SECTRUST_OSX +OSStatus SecTrustCopyCustomAnchorCertificates(SecTrustRef trust, CFArrayRef *anchorCertificates) +{ + BEGIN_SECAPI + CFArrayRef customAnchors = Trust::required(trust)->anchors(); + Required(anchorCertificates) = (customAnchors) ? + (const CFArrayRef)CFRetain(customAnchors) : (const CFArrayRef)NULL; + END_SECAPI +} +#endif + +// +// Get the user's default anchor certificate set +// +/* OS X only */ +OSStatus SecTrustCopyAnchorCertificates(CFArrayRef *anchorCertificates) +{ + BEGIN_SECAPI + + return SecTrustSettingsCopyUnrestrictedRoots( + true, true, true, /* all domains */ + anchorCertificates); + + END_SECAPI +} + +#if SECTRUST_OSX +/* We have an iOS-style SecTrustRef, but we need to return a CDSA-based SecKeyRef. + */ +SecKeyRef SecTrustCopyPublicKey(SecTrustRef trust) +{ + SecKeyRef pubKey = NULL; + SecCertificateRef certificate = SecTrustGetCertificateAtIndex(trust, 0); + (void) SecCertificateCopyPublicKey(certificate, &pubKey); + return pubKey; +} +#else +/* new in 10.6 */ +SecKeyRef SecTrustCopyPublicKey(SecTrustRef trust) +{ + SecKeyRef pubKey = NULL; + CFArrayRef certChain = NULL; + CFArrayRef evidenceChain = NULL; + CSSM_TP_APPLE_EVIDENCE_INFO *statusChain = NULL; + OSStatus __secapiresult = errSecSuccess; + try { + Trust *trustObj = Trust::required(trust); + if (trustObj->result() == kSecTrustResultInvalid) { + // Trust hasn't been evaluated; attempt to retrieve public key from leaf. + SecCertificateRef cert = SecTrustGetCertificateAtIndex(trust, 0); + __secapiresult = SecCertificateCopyPublicKey(cert, &pubKey); + if (pubKey) { + return pubKey; + } + // Otherwise, we must evaluate first. + trustObj->evaluate(); + if (trustObj->result() == kSecTrustResultInvalid) { + MacOSError::throwMe(errSecTrustNotAvailable); + } + } + if (trustObj->evidence() == nil) { + trustObj->buildEvidence(certChain, TPEvidenceInfo::overlayVar(statusChain)); + } + evidenceChain = trustObj->evidence(); + } + catch (const MacOSError &err) { __secapiresult=err.osStatus(); } + catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); } + catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; } + catch (...) { __secapiresult=errSecInternalComponent; } + + if (certChain) + CFRelease(certChain); + + if (evidenceChain) { + if (CFArrayGetCount(evidenceChain) > 0) { + SecCertificateRef cert = (SecCertificateRef) CFArrayGetValueAtIndex(evidenceChain, 0); + __secapiresult = SecCertificateCopyPublicKey(cert, &pubKey); + } + // do not release evidenceChain, as it is owned by the trust object. + } + return pubKey; +} +#endif + +#if !SECTRUST_OSX +/* new in 10.6 */ +CFIndex SecTrustGetCertificateCount(SecTrustRef trust) +{ + CFIndex chainLen = 0; + CFArrayRef certChain = NULL; + CFArrayRef evidenceChain = NULL; + CSSM_TP_APPLE_EVIDENCE_INFO *statusChain = NULL; + OSStatus __secapiresult = errSecSuccess; + try { + Trust *trustObj = Trust::required(trust); + if (trustObj->result() == kSecTrustResultInvalid) { + trustObj->evaluate(); + if (trustObj->result() == kSecTrustResultInvalid) + MacOSError::throwMe(errSecTrustNotAvailable); + } + if (trustObj->evidence() == nil) + trustObj->buildEvidence(certChain, TPEvidenceInfo::overlayVar(statusChain)); + evidenceChain = trustObj->evidence(); + } + catch (const MacOSError &err) { __secapiresult=err.osStatus(); } + catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); } + catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; } + catch (...) { __secapiresult=errSecInternalComponent; } + + if (certChain) + CFRelease(certChain); + + if (evidenceChain) + chainLen = CFArrayGetCount(evidenceChain); // don't release, trust object owns it. + + return chainLen; +} +#endif + +#if !SECTRUST_OSX +/* new in 10.6 */ +SecCertificateRef SecTrustGetCertificateAtIndex(SecTrustRef trust, CFIndex ix) +{ + SecCertificateRef certificate = NULL; + CFArrayRef certChain = NULL; + CFArrayRef evidenceChain = NULL; + CSSM_TP_APPLE_EVIDENCE_INFO *statusChain = NULL; + OSStatus __secapiresult = errSecSuccess; + try { + Trust *trustObj = Trust::required(trust); + if (trustObj->result() == kSecTrustResultInvalid) { + // If caller is asking for the leaf, we can return it without + // having to evaluate the entire chain. Note that we don't retain + // the cert as it's owned by the trust and this is a 'Get' API. + if (ix == 0) { + CFArrayRef certs = trustObj->certificates(); + if (certs && (CFArrayGetCount(certs) > 0)) { + certificate = (SecCertificateRef) CFArrayGetValueAtIndex(certs, 0); + if (certificate) { + return certificate; + } + } + } + // Otherwise, we must evaluate first. + trustObj->evaluate(); + if (trustObj->result() == kSecTrustResultInvalid) { + MacOSError::throwMe(errSecTrustNotAvailable); + } + } + if (trustObj->evidence() == nil) { + trustObj->buildEvidence(certChain, TPEvidenceInfo::overlayVar(statusChain)); + } + evidenceChain = trustObj->evidence(); + } + catch (const MacOSError &err) { __secapiresult=err.osStatus(); } + catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); } + catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; } + catch (...) { __secapiresult=errSecInternalComponent; } + + if (certChain) + CFRelease(certChain); + + if (evidenceChain) { + if (ix < CFArrayGetCount(evidenceChain)) { + certificate = (SecCertificateRef) CFArrayGetValueAtIndex(evidenceChain, ix); + // note: we do not retain this certificate. The assumption here is + // that the certificate is retained by the trust object, so it is + // valid unil the trust is released (or until re-evaluated.) + // also note: we do not release the evidenceChain, as it is owned + // by the trust object. + } + } + return certificate; +} +#endif + + +#if !SECTRUST_OSX +static CFStringRef kSecCertificateDetailSHA1Digest = CFSTR("SHA1Digest"); +static CFStringRef kSecCertificateDetailStatusCodes = CFSTR("StatusCodes"); + +static void +_AppendStatusCode(CFMutableArrayRef array, OSStatus statusCode) +{ + if (!array) + return; + SInt32 num = statusCode; + CFNumberRef numRef = CFNumberCreate(NULL, kCFNumberSInt32Type, &num); + if (!numRef) + return; + CFArrayAppendValue(array, numRef); + CFRelease(numRef); +} +#endif + +#if !SECTRUST_OSX +CFArrayRef SecTrustCopyDetails(SecTrustRef trust) +{ + // This function returns an array of dictionaries, one per certificate, + // holding status info for each certificate in the evaluated chain. + // + CFIndex count, chainLen = 0; + CFArrayRef certChain = NULL; + CFMutableArrayRef details = NULL; + CSSM_TP_APPLE_EVIDENCE_INFO *statusChain = NULL; + OSStatus __secapiresult = errSecSuccess; + try { + Trust *trustObj = Trust::required(trust); + if (trustObj->result() == kSecTrustResultInvalid) { + trustObj->evaluate(); + if (trustObj->result() == kSecTrustResultInvalid) + MacOSError::throwMe(errSecTrustNotAvailable); + } + trustObj->buildEvidence(certChain, TPEvidenceInfo::overlayVar(statusChain)); + } + catch (const MacOSError &err) { __secapiresult=err.osStatus(); } + catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); } + catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; } + catch (...) { __secapiresult=errSecInternalComponent; } + + if (certChain) { + chainLen = CFArrayGetCount(certChain); + CFRelease(certChain); + } + if (statusChain) { + details = CFArrayCreateMutable(NULL, chainLen, &kCFTypeArrayCallBacks); + for (count = 0; count < chainLen; count++) { + CFMutableDictionaryRef certDict = CFDictionaryCreateMutable(kCFAllocatorDefault, + 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + CFMutableArrayRef statusCodes = CFArrayCreateMutable(kCFAllocatorDefault, + 0, &kCFTypeArrayCallBacks); + CSSM_TP_APPLE_EVIDENCE_INFO *evInfo = &statusChain[count]; + CSSM_TP_APPLE_CERT_STATUS statBits = evInfo->StatusBits; + + // translate status bits + if (statBits & CSSM_CERT_STATUS_EXPIRED) + _AppendStatusCode(statusCodes, errSecCertificateExpired); + if (statBits & CSSM_CERT_STATUS_NOT_VALID_YET) + _AppendStatusCode(statusCodes, errSecCertificateNotValidYet); + if (statBits & CSSM_CERT_STATUS_TRUST_SETTINGS_DENY) + _AppendStatusCode(statusCodes, errSecTrustSettingDeny); + + // translate status codes + unsigned int i; + for (i = 0; i < evInfo->NumStatusCodes; i++) { + CSSM_RETURN scode = evInfo->StatusCodes[i]; + _AppendStatusCode(statusCodes, (OSStatus)scode); + } + + CFDictionarySetValue(certDict, kSecCertificateDetailStatusCodes, statusCodes); + CFRelease(statusCodes); + CFArrayAppendValue(details, certDict); + CFRelease(certDict); + } + } + return details; +} +#endif + +#if !SECTRUST_OSX +static CFDictionaryRef SecTrustGetExceptionForCertificateAtIndex(SecTrustRef trust, CFIndex ix) +{ + CFArrayRef exceptions = NULL; + OSStatus __secapiresult = errSecSuccess; + try { + exceptions = Trust::required(trust)->exceptions(); + } + catch (const MacOSError &err) { __secapiresult=err.osStatus(); } + catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); } + catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; } + catch (...) { __secapiresult=errSecInternalComponent; } + + if (!exceptions || ix >= CFArrayGetCount(exceptions)) + return NULL; + CFDictionaryRef exception = (CFDictionaryRef)CFArrayGetValueAtIndex(exceptions, ix); + if (CFGetTypeID(exception) != CFDictionaryGetTypeID()) + return NULL; + + SecCertificateRef certificate = SecTrustGetCertificateAtIndex(trust, ix); + if (!certificate) + return NULL; + + /* If the exception contains the current certificate's sha1Digest in the + kSecCertificateDetailSHA1Digest key then we use it otherwise we ignore it. */ + CFDataRef sha1Digest = SecCertificateGetSHA1Digest(certificate); + CFTypeRef digestValue = CFDictionaryGetValue(exception, kSecCertificateDetailSHA1Digest); + if (!digestValue || !CFEqual(sha1Digest, digestValue)) + exception = NULL; + + return exception; +} +#endif + +#if !SECTRUST_OSX +static void SecTrustCheckException(const void *key, const void *value, void *context) +{ + struct SecTrustCheckExceptionContext *cec = (struct SecTrustCheckExceptionContext *)context; + if (cec->exception) { + CFTypeRef exceptionValue = CFDictionaryGetValue(cec->exception, key); + if (!exceptionValue || !CFEqual(value, exceptionValue)) { + cec->exceptionNotFound = true; + } + } else { + cec->exceptionNotFound = true; + } +} +#endif + +#if !SECTRUST_OSX +/* new in 10.9 */ +CFDataRef SecTrustCopyExceptions(SecTrustRef trust) +{ + CFArrayRef details = SecTrustCopyDetails(trust); + CFIndex pathLength = details ? CFArrayGetCount(details) : 0; + CFMutableArrayRef exceptions = CFArrayCreateMutable(kCFAllocatorDefault, + pathLength, &kCFTypeArrayCallBacks); + CFIndex ix; + for (ix = 0; ix < pathLength; ++ix) { + CFDictionaryRef detail = (CFDictionaryRef)CFArrayGetValueAtIndex(details, ix); + CFIndex detailCount = CFDictionaryGetCount(detail); + CFMutableDictionaryRef exception; + if (ix == 0 || detailCount > 0) { + exception = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, + detailCount + 1, detail); + SecCertificateRef certificate = SecTrustGetCertificateAtIndex(trust, ix); + CFDataRef digest = SecCertificateGetSHA1Digest(certificate); + if (digest) { + CFDictionaryAddValue(exception, kSecCertificateDetailSHA1Digest, digest); + } + } else { + /* Add empty exception dictionaries for non leaf certs which have no exceptions + * to save space. + */ + exception = (CFMutableDictionaryRef)CFDictionaryCreate(kCFAllocatorDefault, + NULL, NULL, 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + } + CFArrayAppendValue(exceptions, exception); + CFReleaseNull(exception); + } + CFReleaseSafe(details); + + /* Remove any trailing empty dictionaries to save even more space (we skip the leaf + since it will never be empty). */ + for (ix = pathLength; ix-- > 1;) { + CFDictionaryRef exception = (CFDictionaryRef)CFArrayGetValueAtIndex(exceptions, ix); + if (CFDictionaryGetCount(exception) == 0) { + CFArrayRemoveValueAtIndex(exceptions, ix); + } else { + break; + } + } + + CFDataRef encodedExceptions = CFPropertyListCreateData(kCFAllocatorDefault, + exceptions, kCFPropertyListBinaryFormat_v1_0, 0, NULL); + CFRelease(exceptions); + + return encodedExceptions; +} +#endif + +#if !SECTRUST_OSX +/* new in 10.9 */ +bool SecTrustSetExceptions(SecTrustRef trust, CFDataRef encodedExceptions) +{ + CFArrayRef exceptions; + exceptions = (CFArrayRef)CFPropertyListCreateWithData(kCFAllocatorDefault, + encodedExceptions, kCFPropertyListImmutable, NULL, NULL); + if (exceptions && CFGetTypeID(exceptions) != CFArrayGetTypeID()) { + CFRelease(exceptions); + exceptions = NULL; + } + + OSStatus __secapiresult = errSecSuccess; + try { + Trust::required(trust)->exceptions(exceptions); + } + catch (const MacOSError &err) { __secapiresult=err.osStatus(); } + catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); } + catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; } + catch (...) { __secapiresult=errSecInternalComponent; } + + /* If there is a valid exception entry for our current leaf we're golden. */ + if (SecTrustGetExceptionForCertificateAtIndex(trust, 0)) + return true; + + /* The passed in exceptions didn't match our current leaf, so we discard it. */ + try { + Trust::required(trust)->exceptions(NULL); + __secapiresult = errSecSuccess; + } + catch (const MacOSError &err) { __secapiresult=err.osStatus(); } + catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); } + catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; } + catch (...) { __secapiresult=errSecInternalComponent; } + + return false; +} +#endif + +#if !SECTRUST_OSX +/* new in 10.9 */ +CFDictionaryRef +SecTrustCopyResult(SecTrustRef trust) +{ + CFDictionaryRef result = NULL; + try { + result = Trust::required(trust)->results(); + // merge details into result + CFArrayRef details = SecTrustCopyDetails(trust); + if (details) { + CFDictionarySetValue((CFMutableDictionaryRef)result, + kSecTrustResultDetails, details); + CFRelease(details); + } + } + catch (...) { + if (result) { + CFRelease(result); + result = NULL; + } + } + return result; +} +#endif + +#if !SECTRUST_OSX +/* new in 10.7 */ +CFArrayRef +SecTrustCopyProperties(SecTrustRef trust) +{ + /* can't use SECAPI macros, since this function does not return OSStatus */ + CFArrayRef result = NULL; + try { + result = Trust::required(trust)->properties(); + } + catch (...) { + if (result) { + CFRelease(result); + result = NULL; + } + } + return result; +} +#endif + +/* deprecated in 10.5 */ +OSStatus SecTrustGetCSSMAnchorCertificates(const CSSM_DATA **cssmAnchors, + uint32 *cssmAnchorCount) +{ +#if !SECTRUST_OSX + BEGIN_SECAPI + CertGroup certs; + Trust::gStore().getCssmRootCertificates(certs); + Required(cssmAnchors) = certs.blobCerts(); + Required(cssmAnchorCount) = certs.count(); + END_SECAPI +#else + /* this function is unsupported in unified SecTrust */ +#if SECTRUST_DEPRECATION_WARNINGS + syslog(LOG_ERR, "WARNING: SecTrustGetCSSMAnchorCertificates has been deprecated since 10.5, and cannot return CSSM objects in 10.11. Please stop using it."); +#endif + if (cssmAnchors) { + *cssmAnchors = NULL; + } + if (cssmAnchorCount) { + *cssmAnchorCount = 0; + } + return errSecServiceNotAvailable; +#endif +} + + +// +// Get and set user trust settings. Deprecated in 10.5. +// User Trust getter, deprecated, works as it always has. +// +OSStatus SecTrustGetUserTrust(SecCertificateRef certificate, + SecPolicyRef policy, SecTrustUserSetting *trustSetting) +{ +#if !SECTRUST_OSX + BEGIN_SECAPI + StorageManager::KeychainList searchList; + globals().storageManager.getSearchList(searchList); + Required(trustSetting) = Trust::gStore().find( + Certificate::required(certificate), + Policy::required(policy), + searchList); + END_SECAPI +#else + /* this function is unsupported in unified SecTrust */ +#if SECTRUST_DEPRECATION_WARNINGS + syslog(LOG_ERR, "WARNING: SecTrustGetUserTrust has been deprecated since 10.5, and does nothing in 10.11. Please stop using it."); +#endif + return errSecServiceNotAvailable; +#endif +} + +// +// The public setter, also deprecated; it maps to the appropriate +// Trust Settings call if possible, else throws errSecUnimplemented. +// +OSStatus SecTrustSetUserTrust(SecCertificateRef certificate, + SecPolicyRef policy, SecTrustUserSetting trustSetting) +{ +#if !SECTRUST_OSX + SecTrustSettingsResult tsResult = kSecTrustSettingsResultInvalid; + OSStatus ortn; + Boolean isRoot; + + Policy::required(policy); + switch(trustSetting) { + case kSecTrustResultProceed: + /* different SecTrustSettingsResult depending in root-ness */ + ortn = SecCertificateIsSelfSigned(certificate, &isRoot); + if(ortn) { + return ortn; + } + if(isRoot) { + tsResult = kSecTrustSettingsResultTrustRoot; + } + else { + tsResult = kSecTrustSettingsResultTrustAsRoot; + } + break; + case kSecTrustResultDeny: + tsResult = kSecTrustSettingsResultDeny; + break; + default: + return errSecUnimplemented; + } + + /* make a usage constraints dictionary */ + CFRef usageDict(CFDictionaryCreateMutable(NULL, + 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); + CFDictionaryAddValue(usageDict, kSecTrustSettingsPolicy, policy); + if(tsResult != kSecTrustSettingsResultTrustRoot) { + /* skip if we're specifying the default */ + SInt32 result = tsResult; + CFNumberRef cfNum = CFNumberCreate(NULL, kCFNumberSInt32Type, &result); + CFDictionarySetValue(usageDict, kSecTrustSettingsResult, cfNum); + CFRelease(cfNum); + } + return SecTrustSettingsSetTrustSettings(certificate, kSecTrustSettingsDomainUser, + usageDict); +#else + /* this function is unsupported in unified SecTrust */ +#if SECTRUST_DEPRECATION_WARNINGS + syslog(LOG_ERR, "WARNING: SecTrustSetUserTrust has been deprecated since 10.5, and does nothing in 10.11. Please stop using it."); +#endif + return errSecServiceNotAvailable; +#endif +} + +// +// This one is the now-private version of what SecTrustSetUserTrust() used to +// be. The public API can no longer manipulate User Trust settings, only +// view them. +// +OSStatus SecTrustSetUserTrustLegacy(SecCertificateRef certificate, + SecPolicyRef policy, SecTrustUserSetting trustSetting) +{ +#if !SECTRUST_OSX + BEGIN_SECAPI + switch (trustSetting) { + case kSecTrustResultProceed: + case kSecTrustResultConfirm: + case kSecTrustResultDeny: + case kSecTrustResultUnspecified: + break; + default: + MacOSError::throwMe(errSecInvalidTrustSetting); + } + Trust::gStore().assign( + Certificate::required(certificate), + Policy::required(policy), + trustSetting); + END_SECAPI +#else + /* this function is unsupported in unified SecTrust */ +#if SECTRUST_DEPRECATION_WARNINGS + syslog(LOG_ERR, "WARNING: SecTrustSetUserTrustLegacy does nothing in 10.11. Please stop using it."); +#endif + return errSecServiceNotAvailable; +#endif +}