#include "SecTrust.h"
#include "SecTrustPriv.h"
#include "Trust.h"
#include <security_keychain/SecTrustSettingsPriv.h>
#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 <security_utilities/cfutilities.h>
#include <security_utilities/cfmunge.h>
#include <CoreFoundation/CoreFoundation.h>
#include <syslog.h>
#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;
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");
#if !SECTRUST_OSX
CFTypeID SecTrustGetTypeID(void)
{
BEGIN_SECAPI
return gTypes().Trust.typeID;
END_SECAPI1(_kCFRuntimeNotATypeID)
}
#endif
#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
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
OSStatus status = errSecSuccess;
#if 1
#warning STU: <rdar://21328005>
#else
CFArrayRef details = SecTrustGetDetails(trustRef); 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) {
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
}
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
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;
}
}
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
OSStatus SecTrustSetKeychains(SecTrustRef trust, CFTypeRef keychainOrArray)
{
#if !SECTRUST_OSX
BEGIN_SECAPI
StorageManager::KeychainList keychains;
if (!( (keychainOrArray != NULL) &&
(CFGetTypeID(keychainOrArray) == CFArrayGetTypeID()) &&
(CFArrayGetCount((CFArrayRef)keychainOrArray) == 0) )) {
globals().storageManager.optionalSearchList(keychainOrArray, keychains);
}
Trust::required(trust)->searchLibs(keychains);
END_SECAPI
#else
#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<CFDateRef> 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;
}
if (trustResult == kSecTrustResultUnspecified) {
if (SecTrustGetExceptionForCertificateAtIndex(trust, 0))
trustResult = kSecTrustResultProceed;
}
else if (trustResult == kSecTrustResultRecoverableTrustFailure && 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);
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
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
#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) {
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) {
static CFMutableArrayRef sTrustArray = NULL;
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);
}
}
}
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);
}
}
}
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);
}
}
CFArrayRef itemImplCertArray = NULL;
trustObj->evaluate();
trustObj->buildEvidence(itemImplCertArray, TPEvidenceInfo::overlayVar(*statusChain));
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
}
#if !SECTRUST_OSX
OSStatus SecTrustGetTrustResult(SecTrustRef trustRef,
SecTrustResultType *result)
{
BEGIN_SECAPI
Trust *trust = Trust::required(trustRef);
if (result) *result = trust->result();
END_SECAPI
}
#endif
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
#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
}
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
#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
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
#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
}
OSStatus SecTrustGetTPHandle(SecTrustRef trust, CSSM_TP_HANDLE *handle)
{
#if !SECTRUST_OSX
BEGIN_SECAPI
Required(handle) = Trust::required(trust)->getTPHandle();
END_SECAPI
#else
#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) {
allowed = trustObj->policySpecified(trustObj->policies(), CSSMOID_APPLE_TP_SSL);
} else {
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
OSStatus SecTrustCopyAnchorCertificates(CFArrayRef *anchorCertificates)
{
BEGIN_SECAPI
return SecTrustSettingsCopyUnrestrictedRoots(
true, true, true,
anchorCertificates);
END_SECAPI
}
#if SECTRUST_OSX
SecKeyRef SecTrustCopyPublicKey(SecTrustRef trust)
{
SecKeyRef pubKey = NULL;
SecCertificateRef certificate = SecTrustGetCertificateAtIndex(trust, 0);
(void) SecCertificateCopyPublicKey(certificate, &pubKey);
return pubKey;
}
#else
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) {
SecCertificateRef cert = SecTrustGetCertificateAtIndex(trust, 0);
__secapiresult = SecCertificateCopyPublicKey(cert, &pubKey);
if (pubKey) {
return pubKey;
}
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);
}
}
return pubKey;
}
#endif
#if !SECTRUST_OSX
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);
return chainLen;
}
#endif
#if !SECTRUST_OSX
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 (ix == 0) {
CFArrayRef certs = trustObj->certificates();
if (certs && (CFArrayGetCount(certs) > 0)) {
certificate = (SecCertificateRef) CFArrayGetValueAtIndex(certs, 0);
if (certificate) {
return certificate;
}
}
}
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);
}
}
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)
{
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;
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);
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;
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
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 {
exception = (CFMutableDictionaryRef)CFDictionaryCreate(kCFAllocatorDefault,
NULL, NULL, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
}
CFArrayAppendValue(exceptions, exception);
CFReleaseNull(exception);
}
CFReleaseSafe(details);
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
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 (SecTrustGetExceptionForCertificateAtIndex(trust, 0))
return true;
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
CFDictionaryRef
SecTrustCopyResult(SecTrustRef trust)
{
CFDictionaryRef result = NULL;
try {
result = Trust::required(trust)->results();
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
CFArrayRef
SecTrustCopyProperties(SecTrustRef trust)
{
CFArrayRef result = NULL;
try {
result = Trust::required(trust)->properties();
}
catch (...) {
if (result) {
CFRelease(result);
result = NULL;
}
}
return result;
}
#endif
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
#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
}
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
#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
}
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:
ortn = SecCertificateIsSelfSigned(certificate, &isRoot);
if(ortn) {
return ortn;
}
if(isRoot) {
tsResult = kSecTrustSettingsResultTrustRoot;
}
else {
tsResult = kSecTrustSettingsResultTrustAsRoot;
}
break;
case kSecTrustResultDeny:
tsResult = kSecTrustSettingsResultDeny;
break;
default:
return errSecUnimplemented;
}
CFRef<CFMutableDictionaryRef> usageDict(CFDictionaryCreateMutable(NULL,
0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
CFDictionaryAddValue(usageDict, kSecTrustSettingsPolicy, policy);
if(tsResult != kSecTrustSettingsResultTrustRoot) {
SInt32 result = tsResult;
CFNumberRef cfNum = CFNumberCreate(NULL, kCFNumberSInt32Type, &result);
CFDictionarySetValue(usageDict, kSecTrustSettingsResult, cfNum);
CFRelease(cfNum);
}
return SecTrustSettingsSetTrustSettings(certificate, kSecTrustSettingsDomainUser,
usageDict);
#else
#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
}
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
#if SECTRUST_DEPRECATION_WARNINGS
syslog(LOG_ERR, "WARNING: SecTrustSetUserTrustLegacy does nothing in 10.11. Please stop using it.");
#endif
return errSecServiceNotAvailable;
#endif
}