SecTrustStatusCodes.c [plain text]
#include <Security/Security.h>
#include <Security/SecTrustPriv.h>
#include <Security/SecPolicyPriv.h>
#include <Security/SecCertificatePriv.h>
#include <Security/SecInternal.h>
#include <Security/SecTrustStatusCodes.h>
#include <CoreFoundation/CoreFoundation.h>
#include <libDER/oids.h>
struct resultmap_entry_s {
const CFStringRef checkstr;
const int32_t resultcode;
};
typedef struct resultmap_entry_s resultmap_entry_t;
const resultmap_entry_t resultmap[] = {
#undef POLICYCHECKMACRO
#define POLICYCHECKMACRO(NAME, TRUSTRESULT, SUBTYPE, LEAFCHECK, PATHCHECK, LEAFONLY, CSSMERR, OSSTATUS) \
{ CFSTR(#NAME), CSSMERR },
#include "SecPolicyChecks.list"
};
static bool SecTrustDetailsHaveEKULeafErrorOnly(CFArrayRef details)
{
CFIndex ix, count = (details) ? CFArrayGetCount(details) : 0;
bool hasDisqualifyingError = false;
for (ix = 0; ix < count; ix++) {
CFDictionaryRef detail = (CFDictionaryRef)CFArrayGetValueAtIndex(details, ix);
if (ix == 0) { if (CFDictionaryGetCount(detail) != 1 || CFDictionaryGetValue(detail, kSecPolicyCheckExtendedKeyUsage) != kCFBooleanFalse) {
hasDisqualifyingError = true;
break;
}
} else {
if (CFDictionaryGetCount(detail) > 0) { hasDisqualifyingError = true;
break;
}
}
}
if (hasDisqualifyingError) {
return false;
}
return true;
}
static bool SecTrustIsDevelopmentUpdateSigning(SecTrustRef trust)
{
bool result = false;
CFArrayRef policies = NULL;
SecPolicyRef policy = NULL;
SecCertificateRef cert = NULL;
CFArrayRef ekus = NULL;
CFDataRef eku = NULL;
const DERItem *oid = &oidAppleExtendedKeyUsageCodeSigningDev;
if ((SecTrustCopyPolicies(trust, &policies) != errSecSuccess) ||
((policy = SecPolicyCreateAppleSWUpdateSigning()) == NULL) ||
(!CFArrayContainsValue(policies, CFRangeMake(0, CFArrayGetCount(policies)), policy))) {
goto exit;
}
if (((cert = SecTrustGetCertificateAtIndex(trust, 0)) == NULL) ||
((ekus = SecCertificateCopyExtendedKeyUsage(cert)) == NULL) ||
((eku = CFDataCreate(kCFAllocatorDefault, oid->data, oid->length)) == NULL) ||
(!CFArrayContainsValue(ekus, CFRangeMake(0, CFArrayGetCount(ekus)), eku))) {
goto exit;
}
result = true;
exit:
CFReleaseSafe(eku);
CFReleaseSafe(ekus);
CFReleaseSafe(policies);
CFReleaseSafe(policy);
return result;
}
SInt32 *SecTrustCopyStatusCodes(SecTrustRef trust,
CFIndex index, CFIndex *numStatusCodes)
{
if (!trust || !numStatusCodes) {
return NULL;
}
*numStatusCodes = 0;
CFArrayRef details = SecTrustCopyFilteredDetails(trust);
CFIndex chainLength = (details) ? CFArrayGetCount(details) : 0;
if (!(index < chainLength)) {
CFReleaseSafe(details);
return NULL;
}
CFDictionaryRef detail = (CFDictionaryRef)CFArrayGetValueAtIndex(details, index);
CFIndex ix, detailCount = CFDictionaryGetCount(detail);
*numStatusCodes = (unsigned int)detailCount;
SInt32 *statusCodes = (SInt32*)malloc((detailCount+1) * sizeof(SInt32));
statusCodes[*numStatusCodes] = 0;
const unsigned int resultmaplen = sizeof(resultmap) / sizeof(resultmap_entry_t);
const void *keys[detailCount];
CFDictionaryGetKeysAndValues(detail, &keys[0], NULL);
for (ix = 0; ix < detailCount; ix++) {
CFStringRef key = (CFStringRef)keys[ix];
SInt32 statusCode = 0;
for (unsigned int mapix = 0; mapix < resultmaplen; mapix++) {
CFStringRef str = (CFStringRef) resultmap[mapix].checkstr;
if (CFStringCompare(str, key, 0) == kCFCompareEqualTo) {
statusCode = (SInt32) resultmap[mapix].resultcode;
break;
}
}
if (statusCode == (SInt32)0x80012407) {
if (index == 0 &&
SecTrustIsDevelopmentUpdateSigning(trust) &&
SecTrustDetailsHaveEKULeafErrorOnly(details)) {
statusCode = (SInt32)0x80012433;
}
} else if (statusCode == (SInt32)0x8001210C) {
SInt32 reason;
CFNumberRef number = (CFNumberRef)CFDictionaryGetValue(detail, key);
if (number && CFNumberGetValue(number, kCFNumberSInt32Type, &reason)) {
statusCodes[*numStatusCodes] = (SInt32)reason;
}
}
statusCodes[ix] = statusCode;
}
CFReleaseSafe(details);
return statusCodes;
}