TrustAdditions.cpp [plain text]
#include "TrustAdditions.h"
#include "SecBridge.h"
#include <security_keychain/SecCFTypes.h>
#include <security_keychain/Globals.h>
#include <security_keychain/Certificate.h>
#include <security_keychain/Item.h>
#include <security_keychain/KCCursor.h>
#include <security_keychain/KCUtilities.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <sys/unistd.h>
#include <string>
#include <AvailabilityMacros.h>
#include <CoreFoundation/CoreFoundation.h>
#include <CommonCrypto/CommonDigest.h>
#include <Security/Security.h>
#include <Security/cssmtype.h>
#include <Security/SecTrustPriv.h> // for kSecEVOrganizationName
#include <Security/cssmapplePriv.h> // for CSSM_APPLE_TP_OCSP_OPTIONS, CSSM_APPLE_TP_OCSP_OPT_FLAGS
#define BEGIN_SECAPI_INTERNAL_CALL \
try {
#define END_SECAPI_INTERNAL_CALL \
} \
catch (const MacOSError &err) { status=err.osStatus(); } \
catch (const CommonError &err) { status=SecKeychainErrFromOSStatus(err.osStatus()); } \
catch (const std::bad_alloc &) { status=memFullErr; } \
catch (...) { status=internalComponentErr; }
static const char *EV_ROOTS_PLIST_SYSTEM_PATH = "/System/Library/Keychains/EVRoots.plist";
static const char *SYSTEM_ROOTS_PLIST_SYSTEM_PATH = "/System/Library/Keychains/SystemRootCertificates.keychain";
static const char *X509ANCHORS_SYSTEM_PATH = "/System/Library/Keychains/X509Anchors";
static CFArrayRef _allowedRootCertificatesForOidString(CFStringRef oidString);
static CSSM_DATA_PTR _copyFieldDataForOid(CSSM_OID_PTR oid, CSSM_DATA_PTR cert, CSSM_CL_HANDLE clHandle);
static CFStringRef _decimalStringForOid(CSSM_OID_PTR oid);
static CFDictionaryRef _evCAOidDict();
static void _freeFieldData(CSSM_DATA_PTR value, CSSM_OID_PTR oid, CSSM_CL_HANDLE clHandle);
static CFStringRef _oidStringForCertificatePolicies(const CE_CertPolicies *certPolicies);
static SecCertificateRef _rootCertificateWithSubjectOfCertificate(SecCertificateRef certificate);
static void SafeCFRelease(void *cfTypeRefPtr)
{
CFTypeRef *obj = (CFTypeRef *)cfTypeRefPtr;
if (obj && *obj) {
CFRelease(*obj);
*obj = NULL;
}
}
static CFDataRef dataWithContentsOfFile(const char *fileName)
{
int rtn;
int fd;
struct stat sb;
off_t fileSize;
UInt8 *fileData = NULL;
CFDataRef outCFData = NULL;
fd = open(fileName, O_RDONLY, 0);
if(fd < 0)
return NULL;
rtn = fstat(fd, &sb);
if(rtn)
goto errOut;
fileSize = sb.st_size;
fileData = (UInt8 *) malloc(fileSize);
if(fileData == NULL)
goto errOut;
rtn = lseek(fd, 0, SEEK_SET);
if(rtn < 0)
goto errOut;
rtn = read(fd, fileData, fileSize);
if(rtn != (int)fileSize) {
rtn = EIO;
} else {
rtn = 0;
outCFData = CFDataCreate(NULL, fileData, fileSize);
}
errOut:
close(fd);
if (fileData) {
free(fileData);
}
return outCFData;
}
static SecKeychainRef systemRootStore()
{
SecKeychainStatus keychainStatus = 0;
SecKeychainRef systemRoots = NULL;
OSStatus status = noErr;
BEGIN_SECAPI_INTERNAL_CALL
systemRoots=globals().storageManager.make(SYSTEM_ROOTS_PLIST_SYSTEM_PATH, false)->handle();
END_SECAPI_INTERNAL_CALL
if (!status && systemRoots) {
BEGIN_SECAPI_INTERNAL_CALL
keychainStatus=(SecKeychainStatus)Keychain::optional(systemRoots)->status();
END_SECAPI_INTERNAL_CALL
}
if (status || !systemRoots) {
SafeCFRelease(&systemRoots);
BEGIN_SECAPI_INTERNAL_CALL
systemRoots=globals().storageManager.make(X509ANCHORS_SYSTEM_PATH, false)->handle();
END_SECAPI_INTERNAL_CALL
if (!status && systemRoots) {
BEGIN_SECAPI_INTERNAL_CALL
keychainStatus=(SecKeychainStatus)Keychain::optional(systemRoots)->status();
END_SECAPI_INTERNAL_CALL
}
}
if (status || !systemRoots) {
SafeCFRelease(&systemRoots);
return NULL;
}
return systemRoots;
}
static CFDictionaryRef dictionaryWithContentsOfPlistFile(const char *fileName)
{
CFDictionaryRef resultDict = NULL;
CFDataRef fileData = dataWithContentsOfFile(fileName);
if (fileData) {
CFPropertyListRef xmlPlist = CFPropertyListCreateFromXMLData(NULL, fileData, kCFPropertyListImmutable, NULL);
if (xmlPlist && CFGetTypeID(xmlPlist) == CFDictionaryGetTypeID()) {
resultDict = (CFDictionaryRef)xmlPlist;
} else {
SafeCFRelease(&xmlPlist);
}
SafeCFRelease(&fileData);
}
return resultDict;
}
static CFStringRef organizationNameForCertificate(SecCertificateRef certificate)
{
CFStringRef organizationName = nil;
OSStatus status = noErr;
#if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_4
CSSM_OID_PTR oidPtr = (CSSM_OID_PTR) &CSSMOID_OrganizationName;
BEGIN_SECAPI_INTERNAL_CALL
organizationName = Certificate::required(certificate)->distinguishedName(&CSSMOID_X509V1SubjectNameCStruct, oidPtr);
END_SECAPI_INTERNAL_CALL
if (status) {
return (CFStringRef)NULL;
}
#else
CSSM_DATA_PTR *fieldValues = NULL;
BEGIN_SECAPI_INTERNAL_CALL
fieldValues = Certificate::required(certificate)->copyFieldValues(&CSSMOID_X509V1SubjectNameCStruct);
END_SECAPI_INTERNAL_CALL
if (*fieldValues == NULL) {
return (CFStringRef)NULL;
}
if (status || (*fieldValues)->Length == 0 || (*fieldValues)->Data == NULL) {
BEGIN_SECAPI_INTERNAL_CALL
Certificate::required(certificate)->releaseFieldValues(&CSSMOID_X509V1SubjectNameCStruct, fieldValues);
END_SECAPI_INTERNAL_CALL
return (CFStringRef)NULL;
}
CSSM_X509_NAME_PTR x509Name = (CSSM_X509_NAME_PTR)(*fieldValues)->Data;
unsigned rdnIndex = 0;
bool foundIt = FALSE;
for (rdnIndex = 0; rdnIndex < x509Name->numberOfRDNs; rdnIndex++) {
CSSM_X509_RDN *rdnPtr = x509Name->RelativeDistinguishedName + rdnIndex;
unsigned pairIndex;
for (pairIndex = 0; pairIndex < rdnPtr->numberOfPairs; pairIndex++) {
CSSM_X509_TYPE_VALUE_PAIR *pair = rdnPtr->AttributeTypeAndValue + pairIndex;
if (!oidsAreEqual(&pair->type, &CSSMOID_OrganizationName))
continue;
switch (pair->valueType) {
case BER_TAG_PKIX_UTF8_STRING:
case BER_TAG_PKIX_UNIVERSAL_STRING:
case BER_TAG_GENERAL_STRING:
organizationName = CFStringCreateWithBytes(NULL, pair->value.Data, pair->value.Length, kCFStringEncodingUTF8, FALSE);
break;
case BER_TAG_PRINTABLE_STRING:
case BER_TAG_IA5_STRING:
organizationName = CFStringCreateWithBytes(NULL, pair->value.Data, pair->value.Length, kCFStringEncodingASCII, FALSE);
break;
case BER_TAG_T61_STRING:
case BER_TAG_VIDEOTEX_STRING:
case BER_TAG_ISO646_STRING:
organizationName = CFStringCreateWithBytes(NULL, pair->value.Data, pair->value.Length, kCFStringEncodingUTF8, FALSE);
if (!organizationName) {
organizationName = CFStringCreateWithBytes(NULL, pair->value.Data, pair->value.Length, kCFStringEncodingISOLatin1, FALSE);
}
break;
case BER_TAG_PKIX_BMP_STRING:
organizationName = CFStringCreateWithBytes(NULL, pair->value.Data, pair->value.Length, kCFStringEncodingUnicode, FALSE);
break;
default:
break;
}
if (organizationName) {
foundIt = TRUE;
break;
}
}
if (foundIt)
break;
}
BEGIN_SECAPI_INTERNAL_CALL
Certificate::required(certificate)->releaseFieldValues(&CSSMOID_X509V1SubjectNameCStruct, fieldValues);
END_SECAPI_INTERNAL_CALL
#endif
return organizationName;
}
CFArrayRef potentialEVChainWithCertificates(CFArrayRef certificates)
{
CFIndex chainIndex, chainLen = (certificates) ? CFArrayGetCount(certificates) : 0;
if (chainLen < 2) {
if (certificates) {
CFRetain(certificates);
}
return certificates;
}
CFMutableArrayRef certArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
for (chainIndex = 0; chainIndex < chainLen; chainIndex++) {
SecCertificateRef aCert = (SecCertificateRef) CFArrayGetValueAtIndex(certificates, chainIndex);
SecCertificateRef replacementCert = NULL;
if (chainIndex > 0) {
replacementCert = _rootCertificateWithSubjectOfCertificate(aCert);
}
CFArrayAppendValue(certArray, (replacementCert) ? replacementCert : aCert);
SafeCFRelease(&replacementCert);
}
return certArray;
}
static SecCertificateRef _rootCertificateWithSubjectOfCertificate(SecCertificateRef certificate)
{
if (!certificate)
return NULL;
CSSM_CL_HANDLE clHandle = 0;
CSSM_DATA certData = { 0, NULL };
OSStatus status = noErr;
BEGIN_SECAPI_INTERNAL_CALL
clHandle = Certificate::required(certificate)->clHandle();
END_SECAPI_INTERNAL_CALL
if (status)
return NULL;
BEGIN_SECAPI_INTERNAL_CALL
certData = Certificate::required(certificate)->data();
END_SECAPI_INTERNAL_CALL
if (status)
return NULL;
SecKeychainRef systemRoots = systemRootStore();
if (!systemRoots)
return NULL;
const CSSM_OID_PTR oidPtr = (const CSSM_OID_PTR) &CSSMOID_X509V1SubjectName;
const CSSM_DATA_PTR subjectDataPtr = _copyFieldDataForOid(oidPtr, &certData, clHandle);
if (!subjectDataPtr)
return NULL;
SecKeyRef keyRef = NULL;
SecCertificateRef resultCert = NULL;
BEGIN_SECAPI_INTERNAL_CALL
keyRef = Certificate::required(certificate)->publicKey()->handle();
END_SECAPI_INTERNAL_CALL
if (!status) {
const CSSM_KEY *cssmKey = NULL;
BEGIN_SECAPI_INTERNAL_CALL
cssmKey = KeyItem::required(keyRef)->key();
END_SECAPI_INTERNAL_CALL
if (!status) {
uint8 buf[CC_SHA1_DIGEST_LENGTH];
CSSM_DATA digest = { sizeof(buf), buf };
if (!cssmKey || !cssmKey->KeyData.Data || !cssmKey->KeyData.Length) {
status = paramErr;
} else {
CC_SHA1(cssmKey->KeyData.Data, cssmKey->KeyData.Length, buf);
}
if (!status) {
SecKeychainAttribute attrs[] = {
{ kSecPublicKeyHashItemAttr, digest.Length, (void *)digest.Data },
{ kSecSubjectItemAttr, subjectDataPtr->Length, (void *)subjectDataPtr->Data }
};
const SecKeychainAttributeList attributes = { sizeof(attrs) / sizeof(attrs[0]), attrs };
SecKeychainSearchRef searchRef = NULL;
BEGIN_SECAPI_INTERNAL_CALL
StorageManager::KeychainList keychains;
globals().storageManager.optionalSearchList(systemRoots, keychains);
KCCursor cursor(keychains, kSecCertificateItemClass, &attributes);
searchRef = cursor->handle();
END_SECAPI_INTERNAL_CALL
if (!status && searchRef) {
SecKeychainItemRef certRef = nil;
BEGIN_SECAPI_INTERNAL_CALL
Item item;
if (!KCCursorImpl::required(searchRef)->next(item)) {
status=errSecItemNotFound;
} else {
certRef=item->handle();
}
END_SECAPI_INTERNAL_CALL
if (!status)
resultCert = (SecCertificateRef)certRef; SafeCFRelease(&searchRef);
}
}
}
}
_freeFieldData(subjectDataPtr, oidPtr, clHandle);
SafeCFRelease(&keyRef);
SafeCFRelease(&systemRoots);
return resultCert;
}
CFArrayRef _allowedRootCertificatesForOidString(CFStringRef oidString)
{
if (!oidString)
return NULL;
CFDictionaryRef evOidDict = _evCAOidDict();
if (!evOidDict)
return NULL;
CFArrayRef possibleCertificateHashes = (CFArrayRef) CFDictionaryGetValue(evOidDict, oidString);
SecKeychainRef systemRoots = systemRootStore();
if (!possibleCertificateHashes || !systemRoots) {
SafeCFRelease(&evOidDict);
return NULL;
}
CFMutableArrayRef possibleRootCertificates = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
CFIndex hashCount = CFArrayGetCount(possibleCertificateHashes);
secdebug("evTrust", "_allowedRootCertificatesForOidString: %d possible hashes", (int)hashCount);
OSStatus status = noErr;
SecKeychainSearchRef searchRef = NULL;
BEGIN_SECAPI_INTERNAL_CALL
StorageManager::KeychainList keychains;
globals().storageManager.optionalSearchList(systemRoots, keychains);
KCCursor cursor(keychains, kSecCertificateItemClass, NULL);
searchRef = cursor->handle();
END_SECAPI_INTERNAL_CALL
if (searchRef) {
while (!status) {
SecKeychainItemRef certRef = NULL;
BEGIN_SECAPI_INTERNAL_CALL
Item item;
if (!KCCursorImpl::required(searchRef)->next(item)) {
certRef=NULL;
status=errSecItemNotFound;
} else {
certRef=item->handle();
}
END_SECAPI_INTERNAL_CALL
if (status || !certRef) {
break;
}
CSSM_DATA certData = { 0, NULL };
BEGIN_SECAPI_INTERNAL_CALL
certData = Certificate::required((SecCertificateRef)certRef)->data();
END_SECAPI_INTERNAL_CALL
if (!status) {
uint8 buf[CC_SHA1_DIGEST_LENGTH];
CSSM_DATA digest = { sizeof(buf), buf };
if (!certData.Data || !certData.Length) {
status = paramErr;
} else {
CC_SHA1(certData.Data, certData.Length, buf);
}
if (!status) {
CFDataRef hashData = CFDataCreateWithBytesNoCopy(NULL, digest.Data, digest.Length, kCFAllocatorNull);
if (hashData && CFArrayContainsValue(possibleCertificateHashes, CFRangeMake(0, hashCount), hashData)) {
CFArrayAppendValue(possibleRootCertificates, certRef);
}
SafeCFRelease(&hashData);
}
}
SafeCFRelease(&certRef);
}
}
SafeCFRelease(&searchRef);
SafeCFRelease(&systemRoots);
SafeCFRelease(&evOidDict);
return possibleRootCertificates;
}
static CSSM_DATA_PTR _copyFieldDataForOid(CSSM_OID_PTR oid, CSSM_DATA_PTR cert, CSSM_CL_HANDLE clHandle)
{
uint32 numFields = 0;
CSSM_HANDLE results = 0;
CSSM_DATA_PTR value = 0;
CSSM_RETURN crtn = CSSM_CL_CertGetFirstFieldValue(clHandle, cert, oid, &results, &numFields, &value);
if (results) {
CSSM_CL_CertAbortQuery(clHandle, results);
}
return (crtn || !numFields) ? NULL : value;
}
static bool _isRevocationServerMetaError(CSSM_RETURN statusCode)
{
switch (statusCode) {
case CSSMERR_APPLETP_CRL_NOT_FOUND: case CSSMERR_APPLETP_CRL_SERVER_DOWN: case CSSMERR_APPLETP_OCSP_UNAVAILABLE: case CSSMERR_APPLETP_OCSP_RESP_MALFORMED_REQ: case CSSMERR_APPLETP_OCSP_RESP_INTERNAL_ERR: case CSSMERR_APPLETP_OCSP_RESP_TRY_LATER: case CSSMERR_APPLETP_OCSP_RESP_SIG_REQUIRED: case CSSMERR_APPLETP_OCSP_RESP_UNAUTHORIZED: return TRUE;
default:
return FALSE;
}
}
CFArrayRef allowedEVRootsForLeafCertificate(CFArrayRef certificates)
{
CFIndex count = (certificates) ? CFArrayGetCount(certificates) : 0;
if (count < 1)
return NULL;
CSSM_CL_HANDLE clHandle = 0;
CSSM_DATA certData = { 0, NULL };
SecCertificateRef certRef = (SecCertificateRef) CFArrayGetValueAtIndex(certificates, 0);
OSStatus status = noErr;
BEGIN_SECAPI_INTERNAL_CALL
clHandle = Certificate::required(certRef)->clHandle();
END_SECAPI_INTERNAL_CALL
if (status)
return NULL;
BEGIN_SECAPI_INTERNAL_CALL
certData = Certificate::required(certRef)->data();
END_SECAPI_INTERNAL_CALL
if (status)
return NULL;
const CSSM_OID_PTR oidPtr = (CSSM_OID_PTR) &CSSMOID_CertificatePolicies;
CSSM_DATA_PTR extensionDataPtr = _copyFieldDataForOid(oidPtr, &certData, clHandle);
if (!extensionDataPtr)
return NULL;
CSSM_X509_EXTENSION *cssmExtension = (CSSM_X509_EXTENSION *)extensionDataPtr->Data;
CE_CertPolicies *certPolicies = (CE_CertPolicies *)cssmExtension->value.parsedValue;
CFStringRef oidString = _oidStringForCertificatePolicies(certPolicies);
_freeFieldData(extensionDataPtr, oidPtr, clHandle);
CFArrayRef allowedRoots = (oidString) ? _allowedRootCertificatesForOidString(oidString) : NULL;
CFIndex rootCount = (allowedRoots) ? CFArrayGetCount(allowedRoots) : 0;
secdebug("evTrust", "allowedEVRootsForLeafCertificate: found %d allowed roots", (int)rootCount);
SafeCFRelease(&oidString);
if (!allowedRoots || !rootCount) {
SafeCFRelease(&allowedRoots);
return NULL;
}
return allowedRoots;
}
CFDictionaryRef extendedValidationResults(CFArrayRef certChain, SecTrustResultType trustResult, OSStatus tpResult)
{
CFIndex chainIndex, chainLen = (certChain) ? CFArrayGetCount(certChain) : 0;
if (chainLen < 2) {
return NULL; }
if (trustResult != kSecTrustResultUnspecified) {
bool recovered = false;
if (trustResult == kSecTrustResultRecoverableTrustFailure) {
recovered = _isRevocationServerMetaError((CSSM_RETURN)tpResult);
}
if (!recovered) {
return NULL;
}
}
bool hasRequiredExtensions = true;
CSSM_CL_HANDLE clHandle = 0;
CSSM_DATA certData = { 0, NULL };
CSSM_OID_PTR oidPtr = (CSSM_OID_PTR) &CSSMOID_CertificatePolicies;
for (chainIndex = 1; hasRequiredExtensions && chainLen > 2 && chainIndex < chainLen - 1; chainIndex++) {
SecCertificateRef intermediateCert = (SecCertificateRef) CFArrayGetValueAtIndex(certChain, chainIndex);
OSStatus status = noErr;
BEGIN_SECAPI_INTERNAL_CALL
clHandle = Certificate::required(intermediateCert)->clHandle();
END_SECAPI_INTERNAL_CALL
if (status)
return NULL;
BEGIN_SECAPI_INTERNAL_CALL
certData = Certificate::required(intermediateCert)->data();
END_SECAPI_INTERNAL_CALL
if (status)
return NULL;
CSSM_DATA_PTR extensionDataPtr = _copyFieldDataForOid(oidPtr, &certData, clHandle);
if (!extensionDataPtr)
return NULL;
CSSM_X509_EXTENSION *cssmExtension = (CSSM_X509_EXTENSION *)extensionDataPtr->Data;
CE_CertPolicies *certPolicies = (CE_CertPolicies *)cssmExtension->value.parsedValue;
CFStringRef oidString = _oidStringForCertificatePolicies(certPolicies);
hasRequiredExtensions = (oidString != NULL);
SafeCFRelease(&oidString);
_freeFieldData(extensionDataPtr, oidPtr, clHandle);
}
if (hasRequiredExtensions) {
SecCertificateRef leafCert = (SecCertificateRef) CFArrayGetValueAtIndex(certChain, 0);
CFStringRef organizationName = organizationNameForCertificate(leafCert);
if (organizationName != NULL) {
CFMutableDictionaryRef resultDict = CFDictionaryCreateMutable(NULL, 0,
&kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFDictionaryAddValue(resultDict, kSecEVOrganizationName, organizationName);
SafeCFRelease(&organizationName);
return resultDict;
}
}
return NULL;
}
static CFDictionaryRef _evCAOidDict()
{
static CFDictionaryRef s_evCAOidDict = NULL;
if (s_evCAOidDict) {
CFRetain(s_evCAOidDict);
secdebug("evTrust", "_evCAOidDict: returning static instance (rc=%d)", (int)CFGetRetainCount(s_evCAOidDict));
return s_evCAOidDict;
}
secdebug("evTrust", "_evCAOidDict: initializing static instance");
s_evCAOidDict = dictionaryWithContentsOfPlistFile(EV_ROOTS_PLIST_SYSTEM_PATH);
if (!s_evCAOidDict)
return NULL;
#if !defined MAC_OS_X_VERSION_10_6 || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
CFStringRef oidString = CFSTR("2.16.840.1.114028.10.1.2");
CFMutableArrayRef hashes = (CFMutableArrayRef) CFDictionaryGetValue(s_evCAOidDict, oidString);
if (hashes) {
uint8 hashBytes[] = {0xB3, 0x1E, 0xB1, 0xB7, 0x40, 0xE3, 0x6C, 0x84, 0x02, 0xDA, 0xDC, 0x37, 0xD4, 0x4D, 0xF5, 0xD4, 0x67, 0x49, 0x52, 0xF9};
CFDataRef hashData = CFDataCreate(NULL, hashBytes, sizeof(hashBytes));
CFIndex hashCount = CFArrayGetCount(hashes);
if (hashData && CFArrayContainsValue(hashes, CFRangeMake(0, hashCount), hashData)) {
secdebug("evTrust", "_evCAOidDict: added hardcoded hash value");
CFArrayAppendValue(hashes, hashData);
}
SafeCFRelease(&hashData);
}
#endif
CFRetain(s_evCAOidDict);
secdebug("evTrust", "_evCAOidDict: returning static instance (rc=%d)", (int)CFGetRetainCount(s_evCAOidDict));
return s_evCAOidDict;
}
static CFStringRef _decimalStringForOid(CSSM_OID_PTR oid)
{
CFMutableStringRef str = CFStringCreateMutable(NULL, 0);
if (!str || oid->Length > 32)
return str;
unsigned long value = 0;
unsigned int x = oid->Data[0] / 40;
unsigned int y = oid->Data[0] % 40;
if (x > 2) {
y += (x - 2) * 40;
x = 2;
}
CFStringAppendFormat(str, NULL, CFSTR("%d.%d"), x, y);
for (x = 1; x < oid->Length; x++) {
value = (value << 7) | (oid->Data[x] & 0x7F);
if(!(oid->Data[x] & 0x80)) {
CFStringAppendFormat(str, NULL, CFSTR(".%ld"), value);
value = 0;
}
}
#if !defined(NDEBUG)
CFIndex nameLen = CFStringGetLength(str);
CFIndex bufLen = 1 + CFStringGetMaximumSizeForEncoding(nameLen, kCFStringEncodingUTF8);
char *nameBuf = (char *)malloc(bufLen);
if (!CFStringGetCString(str, nameBuf, bufLen-1, kCFStringEncodingUTF8))
nameBuf[0]=0;
secdebug("evTrust", "_decimalStringForOid: \"%s\"", nameBuf);
free(nameBuf);
#endif
return str;
}
static void _freeFieldData(CSSM_DATA_PTR value, CSSM_OID_PTR oid, CSSM_CL_HANDLE clHandle)
{
if (value && value->Data) {
CSSM_CL_FreeFieldValue(clHandle, oid, value);
}
return;
}
static ModuleNexus<Mutex> gOidStringForCertificatePoliciesMutex;
static CFStringRef _oidStringForCertificatePolicies(const CE_CertPolicies *certPolicies)
{
StLock<Mutex> _(gOidStringForCertificatePoliciesMutex());
if (!certPolicies) {
secdebug("evTrust", "oidStringForCertificatePolicies: missing certPolicies!");
return NULL;
}
CFDictionaryRef evOidDict = _evCAOidDict();
if (!evOidDict) {
secdebug("evTrust", "oidStringForCertificatePolicies: nil OID dictionary!");
return NULL;
}
CFStringRef foundOidStr = NULL;
uint32 policyIndex, maxIndex = 10; for (policyIndex = 0; policyIndex < certPolicies->numPolicies && policyIndex < maxIndex; policyIndex++) {
CE_PolicyInformation *certPolicyInfo = &certPolicies->policies[policyIndex];
CSSM_OID_PTR oid = &certPolicyInfo->certPolicyId;
CFStringRef oidStr = _decimalStringForOid(oid);
if (!oidStr)
continue;
if (!CFStringCompare(oidStr, CFSTR("2.5.29.32.0"), 0) || CFDictionaryGetValue(evOidDict, oidStr) != NULL) { foundOidStr = CFStringCreateCopy(NULL, oidStr);
}
SafeCFRelease(&oidStr);
if (foundOidStr)
break;
}
SafeCFRelease(&evOidDict);
return foundOidStr;
}