SecCertificatePath.c [plain text]
#include "SecCertificatePath.h"
#include <Security/SecTrust.h>
#include <Security/SecTrustStore.h>
#include <Security/SecItem.h>
#include <Security/SecCertificateInternal.h>
#include <Security/SecFramework.h>
#include <utilities/SecIOFormat.h>
#include <CoreFoundation/CFRuntime.h>
#include <CoreFoundation/CFSet.h>
#include <CoreFoundation/CFString.h>
#include <CoreFoundation/CFNumber.h>
#include <CoreFoundation/CFArray.h>
#include <CoreFoundation/CFPropertyList.h>
#include <AssertMacros.h>
#include <stdbool.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
#include <Security/SecBase.h>
#include "SecRSAKey.h"
#include <libDER/oids.h>
#include <utilities/debugging.h>
#include <Security/SecInternal.h>
#include <utilities/SecCFError.h>
#include <utilities/SecCFWrappers.h>
struct SecCertificatePath {
CFRuntimeBase _base;
CFIndex count;
SecCertificateRef certificates[];
};
CFGiblisWithHashFor(SecCertificatePath)
static void SecCertificatePathDestroy(CFTypeRef cf) {
SecCertificatePathRef certificatePath = (SecCertificatePathRef) cf;
CFIndex ix;
for (ix = 0; ix < certificatePath->count; ++ix) {
CFRelease(certificatePath->certificates[ix]);
}
}
static Boolean SecCertificatePathCompare(CFTypeRef cf1, CFTypeRef cf2) {
SecCertificatePathRef cp1 = (SecCertificatePathRef) cf1;
SecCertificatePathRef cp2 = (SecCertificatePathRef) cf2;
if (cp1->count != cp2->count)
return false;
CFIndex ix;
for (ix = 0; ix < cp1->count; ++ix) {
if (!CFEqual(cp1->certificates[ix], cp2->certificates[ix]))
return false;
}
return true;
}
static CFHashCode SecCertificatePathHash(CFTypeRef cf) {
SecCertificatePathRef certificatePath = (SecCertificatePathRef) cf;
CFHashCode hashCode = 0;
CFIndex ix;
for (ix = 0; ix < certificatePath->count; ++ix) {
hashCode += CFHash(certificatePath->certificates[ix]);
}
return hashCode;
}
static CFStringRef SecCertificatePathCopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions) {
SecCertificatePathRef certificatePath = (SecCertificatePathRef) cf;
CFMutableStringRef desc = CFStringCreateMutable(kCFAllocatorDefault, 0);
CFStringRef typeStr = CFCopyTypeIDDescription(CFGetTypeID(cf));
CFStringAppendFormat(desc, NULL,
CFSTR("<%@ certs: "), typeStr);
CFRelease(typeStr);
CFIndex ix;
for (ix = 0; ix < certificatePath->count; ++ix) {
if (ix > 0) {
CFStringAppend(desc, CFSTR(", "));
}
CFStringRef str = CFCopyDescription(certificatePath->certificates[ix]);
CFStringAppend(desc, str);
CFRelease(str);
}
CFStringAppend(desc, CFSTR(" >"));
return desc;
}
SecCertificatePathRef SecCertificatePathCreateWithXPCArray(xpc_object_t xpc_path, CFErrorRef *error) {
SecCertificatePathRef result = NULL;
require_action_quiet(xpc_path, exit, SecError(errSecParam, error, CFSTR("xpc_path is NULL")));
require_action_quiet(xpc_get_type(xpc_path) == XPC_TYPE_ARRAY, exit, SecError(errSecDecode, error, CFSTR("xpc_path value is not an array")));
size_t count;
require_action_quiet(count = xpc_array_get_count(xpc_path), exit, SecError(errSecDecode, error, CFSTR("xpc_path array count == 0")));
size_t size = sizeof(struct SecCertificatePath) + count * sizeof(SecCertificateRef);
require_action_quiet(result = (SecCertificatePathRef)_CFRuntimeCreateInstance(kCFAllocatorDefault, SecCertificatePathGetTypeID(), size - sizeof(CFRuntimeBase), 0), exit, SecError(errSecDecode, error, CFSTR("_CFRuntimeCreateInstance returned NULL")));
result->count = count;
size_t ix;
for (ix = 0; ix < count; ++ix) {
SecCertificateRef certificate = SecCertificateCreateWithXPCArrayAtIndex(xpc_path, ix, error);
if (certificate) {
result->certificates[ix] = certificate;
} else {
result->count = ix; CFReleaseNull(result);
break;
}
}
exit:
return result;
}
SecCertificatePathRef SecCertificatePathCreateDeserialized(CFArrayRef certificates, CFErrorRef *error) {
SecCertificatePathRef result = NULL;
require_action_quiet(isArray(certificates), exit,
SecError(errSecParam, error, CFSTR("certificates is not an array")));
size_t count = 0;
require_action_quiet(count = CFArrayGetCount(certificates), exit,
SecError(errSecDecode, error, CFSTR("certificates array count == 0")));
size_t size = sizeof(struct SecCertificatePath) + count * sizeof(SecCertificateRef);
require_action_quiet(result = (SecCertificatePathRef)_CFRuntimeCreateInstance(kCFAllocatorDefault, SecCertificatePathGetTypeID(), size - sizeof(CFRuntimeBase), 0), exit,
SecError(errSecDecode, error, CFSTR("_CFRuntimeCreateInstance returned NULL")));
result->count = count;
size_t ix;
for (ix = 0; ix < count; ++ix) {
SecCertificateRef certificate = SecCertificateCreateWithData(NULL, CFArrayGetValueAtIndex(certificates, ix));
if (certificate) {
result->certificates[ix] = certificate;
} else {
result->count = ix; CFReleaseNull(result);
break;
}
}
exit:
return result;
}
xpc_object_t SecCertificatePathCopyXPCArray(SecCertificatePathRef path, CFErrorRef *error) {
xpc_object_t xpc_chain = NULL;
size_t ix, count = path->count;
require_action_quiet(xpc_chain = xpc_array_create(NULL, 0), exit, SecError(errSecParam, error, CFSTR("xpc_array_create failed")));
for (ix = 0; ix < count; ++ix) {
SecCertificateRef cert = SecCertificatePathGetCertificateAtIndex(path, ix);
if (!SecCertificateAppendToXPCArray(cert, xpc_chain, error)) {
xpc_release(xpc_chain);
return NULL;
}
}
exit:
return xpc_chain;
}
CFArrayRef SecCertificatePathCopyCertificates(SecCertificatePathRef path, CFErrorRef *error) {
CFMutableArrayRef outCerts = NULL;
size_t ix, count = path->count;
require_action_quiet(outCerts = CFArrayCreateMutable(NULL, count, &kCFTypeArrayCallBacks), exit,
SecError(errSecParam, error, CFSTR("CFArray failed to create")));
for (ix = 0; ix < count; ++ix) {
SecCertificateRef cert = SecCertificatePathGetCertificateAtIndex(path, ix);
if (cert) {
CFArrayAppendValue(outCerts, cert);
}
}
exit:
return outCerts;
}
SecCertificatePathRef SecCertificatePathCreateWithCertificates(CFArrayRef certificates, CFErrorRef *error) {
SecCertificatePathRef result = NULL;
require_action_quiet(isArray(certificates), exit,
SecError(errSecParam, error, CFSTR("certificates is not an array")));
size_t count = 0;
require_action_quiet(count = CFArrayGetCount(certificates), exit,
SecError(errSecDecode, error, CFSTR("certificates array count == 0")));
size_t size = sizeof(struct SecCertificatePath) + count * sizeof(SecCertificateRef);
require_action_quiet(result = (SecCertificatePathRef)_CFRuntimeCreateInstance(kCFAllocatorDefault, SecCertificatePathGetTypeID(), size - sizeof(CFRuntimeBase), 0), exit,
SecError(errSecDecode, error, CFSTR("_CFRuntimeCreateInstance returned NULL")));
result->count = count;
size_t ix;
for (ix = 0; ix < count; ++ix) {
SecCertificateRef certificate = (SecCertificateRef)CFArrayGetValueAtIndex(certificates, ix);
if (certificate) {
result->certificates[ix] = CFRetainSafe(certificate);
} else {
result->count = ix; CFReleaseNull(result);
break;
}
}
exit:
return result;
}
CFArrayRef SecCertificatePathCreateSerialized(SecCertificatePathRef path, CFErrorRef *error) {
CFMutableArrayRef serializedCerts = NULL;
require_quiet(path, exit);
size_t ix, count = path->count;
require_action_quiet(serializedCerts = CFArrayCreateMutable(NULL, count, &kCFTypeArrayCallBacks), exit,
SecError(errSecParam, error, CFSTR("CFArray failed to create")));
for (ix = 0; ix < count; ++ix) {
SecCertificateRef cert = SecCertificatePathGetCertificateAtIndex(path, ix);
CFDataRef certData = SecCertificateCopyData(cert);
if (certData) {
CFArrayAppendValue(serializedCerts, certData);
CFRelease(certData);
}
}
exit:
return serializedCerts;
}
CFIndex SecCertificatePathGetCount(
SecCertificatePathRef certificatePath) {
check(certificatePath);
return certificatePath ? certificatePath->count : 0;
}
SecCertificateRef SecCertificatePathGetCertificateAtIndex(
SecCertificatePathRef certificatePath, CFIndex ix) {
check(certificatePath && ix >= 0 && ix < certificatePath->count);
return certificatePath->certificates[ix];
}
CFIndex SecCertificatePathGetIndexOfCertificate(SecCertificatePathRef path,
SecCertificateRef certificate) {
CFIndex ix, count = path->count;
for (ix = 0; ix < count; ++ix) {
if (CFEqual(path->certificates[ix], certificate))
return ix;
}
return kCFNotFound;
}
SecKeyRef SecCertificatePathCopyPublicKeyAtIndex(
SecCertificatePathRef certificatePath, CFIndex ix) {
SecCertificateRef certificate =
SecCertificatePathGetCertificateAtIndex(certificatePath, ix);
#if TARGET_OS_OSX
return SecCertificateCopyPublicKey_ios(certificate);
#else
return SecCertificateCopyPublicKey(certificate);
#endif
}