#include "SecTrust.h"
#include "SecTrustPriv.h"
#include "Trust.h"
#include "SecBase.h"
#include "SecBridge.h"
#include "SecInternal.h"
#include "SecInternalP.h"
#include "SecTrustSettings.h"
#include "SecTrustSettingsPriv.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);
#else
CFArrayRef SecTrustCopyInputCertificates(SecTrustRef trust);
CFArrayRef SecTrustCopyInputAnchors(SecTrustRef trust);
CFArrayRef SecTrustCopyConstructedChain(SecTrustRef trust);
static CSSM_TP_APPLE_EVIDENCE_INFO * SecTrustGetEvidenceInfo(SecTrustRef trust);
#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");
struct resultmap_entry_s {
const CFStringRef checkstr;
const CSSM_RETURN resultcode;
};
typedef struct resultmap_entry_s resultmap_entry_t;
#if SECTRUST_OSX
const resultmap_entry_t cssmresultmap[] = {
{ CFSTR("SSLHostname"), CSSMERR_APPLETP_HOSTNAME_MISMATCH },
{ CFSTR("email"), CSSMERR_APPLETP_SMIME_EMAIL_ADDRS_NOT_FOUND },
{ CFSTR("IssuerCommonName"), CSSMERR_APPLETP_IDENTIFIER_MISSING },
{ CFSTR("SubjectCommonName"), CSSMERR_APPLETP_IDENTIFIER_MISSING },
{ CFSTR("SubjectCommonNamePrefix"), CSSMERR_APPLETP_IDENTIFIER_MISSING },
{ CFSTR("SubjectCommonNameTEST"), CSSMERR_APPLETP_IDENTIFIER_MISSING },
{ CFSTR("SubjectOrganization"), CSSMERR_APPLETP_IDENTIFIER_MISSING },
{ CFSTR("SubjectOrganizationalUnit"), CSSMERR_APPLETP_IDENTIFIER_MISSING },
{ CFSTR("EAPTrustedServerNames"), CSSMERR_APPLETP_HOSTNAME_MISMATCH },
{ CFSTR("CertificatePolicy"), CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION },
{ CFSTR("KeyUsage"), CSSMERR_APPLETP_INVALID_KEY_USAGE },
{ CFSTR("ExtendedKeyUsage"), CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE },
{ CFSTR("BasicConstraints"), CSSMERR_APPLETP_NO_BASIC_CONSTRAINTS },
{ CFSTR("QualifiedCertStatements"), CSSMERR_APPLETP_UNKNOWN_QUAL_CERT_STATEMENT },
{ CFSTR("IntermediateSPKISHA256"), CSSMERR_APPLETP_IDENTIFIER_MISSING },
{ CFSTR("IntermediateEKU"), CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE },
{ CFSTR("AnchorSHA1"), CSSMERR_TP_NOT_TRUSTED },
{ CFSTR("AnchorSHA256"), CSSMERR_TP_NOT_TRUSTED },
{ CFSTR("AnchorTrusted"), CSSMERR_TP_NOT_TRUSTED },
{ CFSTR("AnchorApple"), CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH },
{ CFSTR("NonEmptySubject"), CSSMERR_APPLETP_INVALID_EMPTY_SUBJECT },
{ CFSTR("IdLinkage"), CSSMERR_APPLETP_INVALID_AUTHORITY_ID },
{ CFSTR("WeakIntermediates"), CSSMERR_TP_INVALID_CERTIFICATE },
{ CFSTR("WeakLeaf"), CSSMERR_TP_INVALID_CERTIFICATE },
{ CFSTR("WeakRoot"), CSSMERR_TP_INVALID_CERTIFICATE },
{ CFSTR("KeySize"), CSSMERR_CSP_UNSUPPORTED_KEY_SIZE },
{ CFSTR("SignatureHashAlgorithms"), CSSMERR_CSP_ALGID_MISMATCH },
{ CFSTR("CriticalExtensions"), CSSMERR_APPLETP_UNKNOWN_CRITICAL_EXTEN },
{ CFSTR("ChainLength"), CSSMERR_APPLETP_PATH_LEN_CONSTRAINT },
{ CFSTR("BasicCertificateProcessing"), CSSMERR_TP_INVALID_CERTIFICATE },
{ CFSTR("ExtendedValidation"), CSSMERR_TP_NOT_TRUSTED },
{ CFSTR("Revocation"), CSSMERR_TP_CERT_REVOKED },
{ CFSTR("RevocationResponseRequired"), CSSMERR_TP_VERIFY_ACTION_FAILED },
{ CFSTR("CertificateTransparency"), CSSMERR_TP_NOT_TRUSTED },
{ CFSTR("BlackListedLeaf"), CSSMERR_TP_CERT_REVOKED },
{ CFSTR("GrayListedLeaf"), CSSMERR_TP_NOT_TRUSTED },
{ CFSTR("GrayListedKey"), CSSMERR_TP_NOT_TRUSTED },
{ CFSTR("BlackListedKey"), CSSMERR_TP_CERT_REVOKED },
{ CFSTR("CheckLeafMarkerOid"), CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION },
{ CFSTR("CheckLeafMarkerOidNoValueCheck"), CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION },
{ CFSTR("CheckIntermediateMarkerOid"), CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION },
{ CFSTR("UsageConstraints"), CSSMERR_APPLETP_TRUST_SETTING_DENY },
{ CFSTR("NotValidBefore"), CSSMERR_TP_CERT_NOT_VALID_YET },
{ CFSTR("ValidIntermediates"), CSSMERR_TP_CERT_EXPIRED },
{ CFSTR("ValidLeaf"), CSSMERR_TP_CERT_EXPIRED },
{ CFSTR("ValidRoot"), CSSMERR_TP_CERT_EXPIRED },
};
#endif
#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
#if SECTRUST_OSX
typedef struct {
SecTrustOptionFlags flags;
CFIndex certIX;
SecTrustRef trustRef;
CFMutableDictionaryRef filteredException;
CFDictionaryRef oldException;
} SecExceptionFilterContext;
#if 0
#include <utilities/SecCFWrappers.h>
#else
static inline char *CFStringToCString(CFStringRef inStr)
{
if (!inStr)
return (char *)strdup("");
CFRetain(inStr);
CFIndex length = CFStringGetLength(inStr); size_t len = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8);
char *buffer = (char *)malloc(len); if (!CFStringGetCString(inStr, buffer, len, kCFStringEncodingUTF8))
buffer[0] = 0;
CFRelease(inStr);
return buffer;
}
#endif
static void
filter_exception(const void *key, const void *value, void *context)
{
SecExceptionFilterContext *ctx = (SecExceptionFilterContext *)context;
if (!ctx) { return; }
SecTrustOptionFlags options = ctx->flags;
CFMutableDictionaryRef filteredException = ctx->filteredException;
CFStringRef keystr = (CFStringRef)key;
if (ctx->oldException && CFDictionaryContainsKey(ctx->oldException, key)) {
CFDictionaryAddValue(filteredException, key, CFDictionaryGetValue(ctx->oldException, key));
return;
}
bool allowed = false;
if (CFEqual(keystr, CFSTR("SHA1Digest"))) {
allowed = true; }
else if (CFEqual(keystr, CFSTR("NotValidBefore"))) {
allowed = ((options & kSecTrustOptionAllowExpired) != 0);
}
else if (CFEqual(keystr, CFSTR("ValidLeaf"))) {
allowed = ((options & kSecTrustOptionAllowExpired) != 0);
}
else if (CFEqual(keystr, CFSTR("ValidIntermediates"))) {
allowed = ((options & kSecTrustOptionAllowExpired) != 0);
}
else if (CFEqual(keystr, CFSTR("ValidRoot"))) {
if (((options & kSecTrustOptionAllowExpired) != 0) ||
((options & kSecTrustOptionAllowExpiredRoot) != 0)) {
allowed = true;
}
}
else if (CFEqual(keystr, CFSTR("AnchorTrusted"))) {
bool implicitAnchors = ((options & kSecTrustOptionImplicitAnchors) != 0);
if (implicitAnchors && ctx->trustRef &&
(ctx->certIX < SecTrustGetCertificateCount(ctx->trustRef))) {
Boolean isSelfSigned = false;
SecCertificateRef cert = SecTrustGetCertificateAtIndex(ctx->trustRef, ctx->certIX);
if (cert && (errSecSuccess == SecCertificateIsSelfSigned(cert, &isSelfSigned)) &&
isSelfSigned) {
allowed = true;
}
}
}
else if (CFEqual(keystr, CFSTR("KeyUsage")) ||
CFEqual(keystr, CFSTR("ExtendedKeyUsage")) ||
CFEqual(keystr, CFSTR("BasicConstraints")) ||
CFEqual(keystr, CFSTR("NonEmptySubject")) ||
CFEqual(keystr, CFSTR("IdLinkage"))) {
allowed = false;
}
else {
char *cstr = CFStringToCString(keystr);
syslog(LOG_ERR, "Unfiltered exception: %s", (cstr) ? cstr : "<NULL>");
if (cstr) { free(cstr); }
allowed = false;
}
if (allowed) {
CFDictionaryAddValue(filteredException, key, value);
}
}
#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;
CFDataRef encodedExceptions = SecTrustCopyExceptions(trustRef);
CFArrayRef exceptions = NULL,
oldExceptions = SecTrustGetTrustExceptionsArray(trustRef);
if (encodedExceptions) {
exceptions = (CFArrayRef)CFPropertyListCreateWithData(kCFAllocatorDefault,
encodedExceptions, kCFPropertyListImmutable, NULL, NULL);
CFRelease(encodedExceptions);
encodedExceptions = NULL;
}
if (exceptions && CFGetTypeID(exceptions) != CFArrayGetTypeID()) {
CFRelease(exceptions);
exceptions = NULL;
}
if (oldExceptions && exceptions &&
CFArrayGetCount(oldExceptions) > CFArrayGetCount(exceptions)) {
oldExceptions = NULL;
}
if (oldExceptions && exceptions && CFArrayGetCount(oldExceptions) > 0) {
CFDictionaryRef oldLeafExceptions = (CFDictionaryRef)CFArrayGetValueAtIndex(oldExceptions, 0);
CFDictionaryRef leafExceptions = (CFDictionaryRef)CFArrayGetValueAtIndex(exceptions, 0);
CFDataRef oldDigest = (CFDataRef)CFDictionaryGetValue(oldLeafExceptions, CFSTR("SHA1Digest"));
CFDataRef digest = (CFDataRef)CFDictionaryGetValue(leafExceptions, CFSTR("SHA1Digest"));
if (!oldDigest || !digest || !CFEqual(oldDigest, digest)) {
oldExceptions = NULL;
}
}
if (exceptions) {
CFMutableArrayRef filteredExceptions = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
CFIndex i, exceptionCount = (filteredExceptions) ? CFArrayGetCount(exceptions) : 0;
for (i = 0; i < exceptionCount; ++i) {
CFDictionaryRef exception = (CFDictionaryRef)CFArrayGetValueAtIndex(exceptions, i);
CFDictionaryRef oldException = NULL;
if (oldExceptions && i < CFArrayGetCount(oldExceptions)) {
oldException = (CFDictionaryRef)CFArrayGetValueAtIndex(oldExceptions, i);
}
CFMutableDictionaryRef filteredException = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
if (exception && filteredException) {
SecExceptionFilterContext filterContext = { options, i, trustRef, filteredException, oldException };
CFDictionaryApplyFunction(exception, filter_exception, &filterContext);
CFArrayAppendValue(filteredExceptions, filteredException);
CFRelease(filteredException);
}
}
if (filteredExceptions) {
CFIndex filteredCount = CFArrayGetCount(filteredExceptions);
for (i = filteredCount; i-- > 1;) {
CFDictionaryRef exception = (CFDictionaryRef)CFArrayGetValueAtIndex(filteredExceptions, i);
if (CFDictionaryGetCount(exception) == 0) {
CFArrayRemoveValueAtIndex(filteredExceptions, i);
} else {
break;
}
}
encodedExceptions = CFPropertyListCreateData(kCFAllocatorDefault,
filteredExceptions, kCFPropertyListBinaryFormat_v1_0, 0, NULL);
CFRelease(filteredExceptions);
SecTrustSetExceptions(trustRef, encodedExceptions);
CFRelease(encodedExceptions);
}
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;
}
}
secnotice("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. Please use SecTrustGetTrustResult instead.");
#endif
SecTrustResultType trustResult;
OSStatus status = SecTrustGetTrustResult(trustRef, &trustResult);
if (status != errSecSuccess) {
return status;
}
if (result) {
*result = trustResult;
}
if (certChain) {
*certChain = SecTrustCopyConstructedChain(trustRef);
}
if (statusChain) {
*statusChain = SecTrustGetEvidenceInfo(trustRef);
}
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 CSSM_RETURN *copyCssmStatusCodes(SecTrustRef trust,
unsigned int index, unsigned int *numStatusCodes)
{
if (!trust || !numStatusCodes) {
return NULL;
}
*numStatusCodes = 0;
CFArrayRef details = SecTrustGetDetails(trust);
CFIndex chainLength = (details) ? CFArrayGetCount(details) : 0;
if (!(index < chainLength)) {
return NULL;
}
CFDictionaryRef detail = (CFDictionaryRef)CFArrayGetValueAtIndex(details, index);
CFIndex ix, detailCount = CFDictionaryGetCount(detail);
*numStatusCodes = (unsigned int)detailCount;
CSSM_RETURN *statusCodes = (CSSM_RETURN*)malloc((detailCount+1) * sizeof(CSSM_RETURN));
statusCodes[*numStatusCodes] = 0;
const unsigned int resultmaplen = sizeof(cssmresultmap) / sizeof(resultmap_entry_t);
const void *keys[detailCount];
CFDictionaryGetKeysAndValues(detail, &keys[0], NULL);
for (ix = 0; ix < detailCount; ix++) {
CFStringRef key = (CFStringRef)keys[ix];
CSSM_RETURN statusCode = CSSM_OK;
for (unsigned int mapix = 0; mapix < resultmaplen; mapix++) {
CFStringRef str = (CFStringRef) cssmresultmap[mapix].checkstr;
if (CFStringCompare(str, key, 0) == kCFCompareEqualTo) {
statusCode = (CSSM_RETURN) cssmresultmap[mapix].resultcode;
break;
}
}
if (statusCode == CSSMERR_TP_CERT_REVOKED) {
SInt32 reason;
CFNumberRef number = (CFNumberRef)CFDictionaryGetValue(detail, key);
if (number && CFNumberGetValue(number, kCFNumberSInt32Type, &reason)) {
statusCodes[*numStatusCodes] = (CSSM_RETURN)reason;
}
}
statusCodes[ix] = statusCode;
}
return statusCodes;
}
static uint8_t convertCssmResultToPriority(CSSM_RETURN resultCode) {
switch (resultCode) {
case CSSMERR_TP_CERT_REVOKED:
case CSSMERR_APPLETP_TRUST_SETTING_DENY:
return 1;
case CSSMERR_APPLETP_NO_BASIC_CONSTRAINTS:
case CSSMERR_APPLETP_UNKNOWN_QUAL_CERT_STATEMENT:
case CSSMERR_APPLETP_INVALID_EMPTY_SUBJECT:
case CSSMERR_APPLETP_INVALID_AUTHORITY_ID:
case CSSMERR_TP_INVALID_CERTIFICATE:
case CSSMERR_APPLETP_UNKNOWN_CRITICAL_EXTEN:
return 2;
case CSSMERR_TP_CERT_EXPIRED:
return 3;
case CSSMERR_TP_NOT_TRUSTED:
case CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH:
return 4;
default:
return 5;
}
}
#include <libDER/oidsPriv.h>
#include <Security/oidscert.h>
static bool isSoftwareUpdateDevelopment(SecTrustRef trust) {
bool isPolicy = false, isEKU = false;
CFArrayRef policies = NULL;
SecTrustCopyPolicies(trust, &policies);
if (policies) {
SecPolicyRef swUpdatePolicy = SecPolicyCreateAppleSWUpdateSigning();
if (swUpdatePolicy && CFArrayContainsValue(policies, CFRangeMake(0, CFArrayGetCount(policies)),
swUpdatePolicy)) {
isPolicy = true;
}
if (swUpdatePolicy) { CFRelease(swUpdatePolicy); }
CFRelease(policies);
}
if (!isPolicy) {
return false;
}
CFArrayRef details = SecTrustGetDetails(trust);
CFIndex ix, count = CFArrayGetCount(details);
for (ix = 0; ix < count; ix++) {
CFDictionaryRef detail = (CFDictionaryRef)CFArrayGetValueAtIndex(details, ix);
if (ix == 0) { if (CFDictionaryGetCount(detail) != 1 || CFDictionaryGetValue(detail, CFSTR("ExtendedKeyUsage")) != kCFBooleanFalse) return false;
} else {
if (CFDictionaryGetCount(detail) > 0) { return false;
}
}
}
SecCertificateRef leaf = SecTrustGetCertificateAtIndex(trust, 0);
CSSM_DATA *fieldValue = NULL;
if (errSecSuccess != SecCertificateCopyFirstFieldValue(leaf, &CSSMOID_ExtendedKeyUsage, &fieldValue)) {
return false;
}
if (fieldValue && fieldValue->Data && fieldValue->Length == sizeof(CSSM_X509_EXTENSION)) {
const CSSM_X509_EXTENSION *ext = (const CSSM_X509_EXTENSION *)fieldValue->Data;
if (ext->format == CSSM_X509_DATAFORMAT_PARSED) {
const CE_ExtendedKeyUsage *ekus = (const CE_ExtendedKeyUsage *)ext->value.parsedValue;
if (ekus && (ekus->numPurposes == 1) && ekus->purposes[0].Data &&
(ekus->purposes[0].Length == CSSMOID_APPLE_EKU_CODE_SIGNING_DEV.Length) &&
(memcmp(ekus->purposes[0].Data, CSSMOID_APPLE_EKU_CODE_SIGNING_DEV.Data,
ekus->purposes[0].Length) == 0)) {
isEKU = true;
}
}
}
SecCertificateReleaseFirstFieldValue(leaf, &CSSMOID_ExtendedKeyUsage, fieldValue);
return isEKU;
}
#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;
}
SecTrustResultType trustResult = kSecTrustResultInvalid;
(void) SecTrustGetTrustResult(trustRef, &trustResult);
if (trustResult == kSecTrustResultProceed || trustResult == kSecTrustResultUnspecified) {
if (result) { *result = 0; }
return errSecSuccess;
}
if (isSoftwareUpdateDevelopment(trustRef)) {
if (result) {
*result = CSSMERR_APPLETP_CODE_SIGN_DEVELOPMENT;
}
return errSecSuccess;
}
OSStatus cssmResultCode = errSecSuccess;
uint8_t resultCodePriority = 0xFF;
CFIndex ix, count = SecTrustGetCertificateCount(trustRef);
for (ix = 0; ix < count; ix++) {
unsigned int numStatusCodes;
CSSM_RETURN *statusCodes = NULL;
statusCodes = copyCssmStatusCodes(trustRef, (uint32_t)ix, &numStatusCodes);
if (statusCodes && numStatusCodes > 0) {
unsigned int statusIX;
for (statusIX = 0; statusIX < numStatusCodes; statusIX++) {
CSSM_RETURN currStatus = statusCodes[statusIX];
uint8_t currPriotiy = convertCssmResultToPriority(currStatus);
if (resultCodePriority > currPriotiy) {
cssmResultCode = currStatus;
resultCodePriority = currPriotiy;
}
}
}
if (statusCodes) { free(statusCodes); }
if (resultCodePriority == 1) { break; }
}
if (result) {
*result = cssmResultCode;
}
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
typedef struct __TSecTrust {
CFRuntimeBase _base;
CFArrayRef _certificates;
CFArrayRef _anchors;
CFTypeRef _policies;
CFArrayRef _responses;
CFArrayRef _SCTs;
CFArrayRef _trustedLogs;
CFDateRef _verifyDate;
CFTypeRef _chain;
SecKeyRef _publicKey;
CFArrayRef _details;
CFDictionaryRef _info;
CFArrayRef _exceptions;
SecTrustResultType _trustResult;
bool _anchorsOnly;
bool _keychainsAllowed;
void* _legacy_info_array;
void* _legacy_status_array;
SecTrustResultType _trustResultBeforeExceptions;
} TSecTrust;
#if SECTRUST_OSX
CFArrayRef SecTrustCopyInputCertificates(SecTrustRef trust)
{
if (!trust) { return NULL; };
TSecTrust *secTrust = (TSecTrust *)trust;
if (secTrust->_certificates) {
CFRetain(secTrust->_certificates);
}
return secTrust->_certificates;
}
#endif
#if SECTRUST_OSX
CFArrayRef SecTrustCopyInputAnchors(SecTrustRef trust)
{
if (!trust) { return NULL; };
TSecTrust *secTrust = (TSecTrust *)trust;
if (secTrust->_anchors) {
CFRetain(secTrust->_anchors);
}
return secTrust->_anchors;
}
#endif
#if SECTRUST_OSX
CFArrayRef SecTrustCopyConstructedChain(SecTrustRef trust)
{
CFMutableArrayRef certChain = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
CFIndex idx, count = SecTrustGetCertificateCount(trust);
for (idx=0; idx < count; idx++) {
SecCertificateRef certificate = SecTrustGetCertificateAtIndex(trust, idx);
if (certificate) {
CFArrayAppendValue(certChain, certificate);
}
}
CFArrayRef inputCertArray = SecTrustCopyInputCertificates(trust);
CFArrayRef inputAnchorArray = SecTrustCopyInputAnchors(trust);
CFIndex inputCertIdx, inputCertCount = (inputCertArray) ? CFArrayGetCount(inputCertArray) : 0;
CFIndex inputAnchorIdx, inputAnchorCount = (inputAnchorArray) ? CFArrayGetCount(inputAnchorArray) : 0;
for (idx=0; idx < count; idx++) {
SecCertificateRef tmpCert = (SecCertificateRef) CFArrayGetValueAtIndex(certChain, idx);
if (tmpCert) {
SecCertificateRef matchCert = NULL;
for (inputCertIdx=0; inputCertIdx < inputCertCount && !matchCert; inputCertIdx++) {
SecCertificateRef inputCert = (SecCertificateRef) CFArrayGetValueAtIndex(inputCertArray, inputCertIdx);
if (inputCert && CFEqual(inputCert, tmpCert)) {
matchCert = inputCert;
}
}
for (inputAnchorIdx=0; inputAnchorIdx < inputAnchorCount && !matchCert; inputAnchorIdx++) {
SecCertificateRef inputAnchor = (SecCertificateRef) CFArrayGetValueAtIndex(inputAnchorArray, inputAnchorIdx);
if (inputAnchor && CFEqual(inputAnchor, tmpCert)) {
matchCert = inputAnchor;
}
}
if (matchCert) {
CFArraySetValueAtIndex(certChain, idx, matchCert);
}
}
}
if (inputCertArray) {
CFRelease(inputCertArray);
}
if (inputAnchorArray) {
CFRelease(inputAnchorArray);
}
return certChain;
}
#endif
#if SECTRUST_OSX
static CSSM_TP_APPLE_EVIDENCE_INFO *
SecTrustGetEvidenceInfo(SecTrustRef trust)
{
TSecTrust *secTrust = (TSecTrust *)trust;
if (!secTrust) {
return NULL;
}
if (secTrust->_trustResult != kSecTrustSettingsResultInvalid &&
secTrust->_legacy_info_array) {
return (CSSM_TP_APPLE_EVIDENCE_INFO *)secTrust->_legacy_info_array;
}
CFIndex idx, count = SecTrustGetCertificateCount(trust);
CFArrayRef inputCertArray = SecTrustCopyInputCertificates(trust);
CFArrayRef inputAnchorArray = SecTrustCopyInputAnchors(trust);
CFIndex inputCertIdx, inputCertCount = (inputCertArray) ? CFArrayGetCount(inputCertArray) : 0;
CFIndex inputAnchorIdx, inputAnchorCount = (inputAnchorArray) ? CFArrayGetCount(inputAnchorArray) : 0;
CSSM_TP_APPLE_EVIDENCE_INFO *infoArray = (CSSM_TP_APPLE_EVIDENCE_INFO *)calloc(count, sizeof(CSSM_TP_APPLE_EVIDENCE_INFO));
CSSM_RETURN *statusArray = NULL;
unsigned int numStatusCodes = 0;
for (idx=0; idx < count; idx++) {
SecCertificateRef cert = SecTrustGetCertificateAtIndex(trust, idx);
if (!cert) {
continue;
}
CSSM_TP_APPLE_EVIDENCE_INFO *evInfo = &infoArray[idx];
CFAbsoluteTime now = CFAbsoluteTimeGetCurrent();
if (secTrust->_verifyDate) {
now = CFDateGetAbsoluteTime(secTrust->_verifyDate);
}
CFAbsoluteTime na = SecCertificateNotValidAfter(cert);
if (na < now) {
evInfo->StatusBits |= CSSM_CERT_STATUS_EXPIRED;
}
CFAbsoluteTime nb = SecCertificateNotValidBefore(cert);
if (nb > now) {
evInfo->StatusBits |= CSSM_CERT_STATUS_NOT_VALID_YET;
}
for (inputAnchorIdx=0; inputAnchorIdx < inputAnchorCount; inputAnchorIdx++) {
SecCertificateRef inputAnchor = (SecCertificateRef) CFArrayGetValueAtIndex(inputAnchorArray, inputAnchorIdx);
if (inputAnchor && CFEqual(inputAnchor, cert)) {
evInfo->StatusBits |= CSSM_CERT_STATUS_IS_IN_ANCHORS;
break;
}
}
for (inputCertIdx=0; inputCertIdx < inputCertCount; inputCertIdx++) {
SecCertificateRef inputCert = (SecCertificateRef) CFArrayGetValueAtIndex(inputCertArray, inputCertIdx);
if (inputCert && CFEqual(inputCert, cert)) {
evInfo->StatusBits |= CSSM_CERT_STATUS_IS_IN_INPUT_CERTS;
break;
}
}
CFStringRef hashStr = SecTrustSettingsCertHashStrFromCert(cert);
bool foundMatch = false;
bool foundAny = false;
CSSM_RETURN *errors = NULL;
uint32 errorCount = 0;
OSStatus status = 0;
SecTrustSettingsDomain foundDomain = 0;
SecTrustSettingsResult foundResult = kSecTrustSettingsResultInvalid;
bool isSelfSigned = false;
if ((count - 1) == idx) {
Boolean selfSigned;
status = SecCertificateIsSelfSigned(cert, &selfSigned);
isSelfSigned = (status) ? false : ((selfSigned) ? true : false);
if (isSelfSigned) {
evInfo->StatusBits |= CSSM_CERT_STATUS_IS_ROOT;
}
}
status = SecTrustSettingsEvaluateCert(
hashStr,
NULL,
NULL,
0,
0,
isSelfSigned,
&foundDomain,
&errors,
&errorCount,
&foundResult,
&foundMatch,
&foundAny);
if (status == errSecSuccess) {
if (foundMatch) {
switch (foundResult) {
case kSecTrustSettingsResultTrustRoot:
case kSecTrustSettingsResultTrustAsRoot:
evInfo->StatusBits |= CSSM_CERT_STATUS_TRUST_SETTINGS_TRUST;
break;
case kSecTrustSettingsResultDeny:
evInfo->StatusBits |= CSSM_CERT_STATUS_TRUST_SETTINGS_DENY;
break;
case kSecTrustSettingsResultUnspecified:
case kSecTrustSettingsResultInvalid:
default:
break;
}
}
}
if (errors) {
free(errors);
}
if (hashStr) {
CFRelease(hashStr);
}
unsigned int numCodes=0;
CSSM_RETURN *statusCodes = copyCssmStatusCodes(trust, (unsigned int)idx, &numCodes);
if (statusCodes) {
unsigned int totalStatusCodes = numStatusCodes + numCodes + 1;
statusArray = (CSSM_RETURN *)realloc(statusArray, totalStatusCodes * sizeof(CSSM_RETURN));
evInfo->StatusCodes = &statusArray[numStatusCodes];
evInfo->NumStatusCodes = numCodes;
for (unsigned int cpix = 0; cpix <= numCodes; cpix++) {
evInfo->StatusCodes[cpix] = statusCodes[cpix];
}
numStatusCodes = totalStatusCodes;
free(statusCodes);
}
if(evInfo->StatusBits & (CSSM_CERT_STATUS_TRUST_SETTINGS_TRUST |
CSSM_CERT_STATUS_TRUST_SETTINGS_DENY |
CSSM_CERT_STATUS_TRUST_SETTINGS_IGNORED_ERROR)) {
uint32 whichDomain = 0;
switch(foundDomain) {
case kSecTrustSettingsDomainUser:
whichDomain = CSSM_CERT_STATUS_TRUST_SETTINGS_FOUND_USER;
break;
case kSecTrustSettingsDomainAdmin:
whichDomain = CSSM_CERT_STATUS_TRUST_SETTINGS_FOUND_ADMIN;
break;
case kSecTrustSettingsDomainSystem:
whichDomain = CSSM_CERT_STATUS_TRUST_SETTINGS_FOUND_SYSTEM;
break;
}
evInfo->StatusBits |= whichDomain;
}
}
numStatusCodes = 0;
for (idx=0; idx < count; idx++) {
CSSM_TP_APPLE_EVIDENCE_INFO *evInfo = &infoArray[idx];
evInfo->StatusCodes = &statusArray[numStatusCodes];
numStatusCodes += evInfo->NumStatusCodes + 1;
}
secTrust->_legacy_info_array = infoArray;
secTrust->_legacy_status_array = statusArray;
if (inputCertArray) {
CFRelease(inputCertArray);
}
if (inputAnchorArray) {
CFRelease(inputAnchorArray);
}
return (CSSM_TP_APPLE_EVIDENCE_INFO *)secTrust->_legacy_info_array;
}
#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 = NULL;
if (NULL != encodedExceptions) {
exceptions = (CFArrayRef)CFPropertyListCreateWithData(kCFAllocatorDefault,
encodedExceptions, kCFPropertyListImmutable, NULL, NULL);
}
if (exceptions && CFGetTypeID(exceptions) != CFArrayGetTypeID()) {
CFRelease(exceptions);
exceptions = NULL;
}
OSStatus __secapiresult = errSecSuccess;
try {
Trust::required(trust)->setResult(kSecTrustResultInvalid);
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;
}
#else
CFArrayRef SecTrustCopyProperties(SecTrustRef trust) {
CFIndex ix, count = SecTrustGetCertificateCount(trust);
CFMutableArrayRef properties = CFArrayCreateMutable(kCFAllocatorDefault, count,
&kCFTypeArrayCallBacks);
for (ix = 0; ix < count; ix++) {
CFMutableDictionaryRef certDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
SecCertificateRef cert = SecTrustGetCertificateAtIndex(trust, ix);
if (cert) {
CFStringRef subjectSummary = SecCertificateCopySubjectSummary(cert);
if (subjectSummary) {
CFDictionaryAddValue(certDict, kSecPropertyTypeTitle, subjectSummary);
CFRelease(subjectSummary);
}
}
unsigned int numStatusCodes;
CSSM_RETURN *statusCodes = NULL;
statusCodes = copyCssmStatusCodes(trust, (uint32_t)ix, &numStatusCodes);
if (statusCodes) {
int32_t reason = statusCodes[numStatusCodes]; if (reason > 0) {
CFNumberRef cfreason = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &reason);
if (cfreason) {
CFDictionarySetValue(certDict, kSecTrustRevocationReason, cfreason);
CFRelease(cfreason);
}
}
free(statusCodes);
}
if (ix == 0) {
OSStatus error = errSecSuccess;
(void)SecTrustGetCssmResultCode(trust, &error);
CFStringRef errorStr = SecCopyErrorMessageString(error, NULL);
if (errorStr) {
CFDictionarySetValue(certDict, kSecPropertyTypeError, errorStr);
CFRelease(errorStr);
}
}
CFArrayAppendValue(properties, certDict);
}
return properties;
}
#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
}