#include <Security/SecBase.h>
#include <Security/SecBasePriv.h>
#include <Security/SecItem.h>
#include <Security/SecCertificate.h>
#include <Security/SecCertificatePriv.h>
#include <Security/SecIdentity.h>
#include <Security/SecIdentityPriv.h>
#include <Security/SecPolicy.h>
#include <Security/SecTrust.h>
#include <Security/SecKeyPriv.h>
#include <Security/SecInternal.h>
#include <CommonCrypto/CommonDigest.h>
#include <Security/SecImportExportPriv.h>
#include <CoreFoundation/CFPriv.h>
const CFStringRef __nonnull kSecImportExportPassphrase = CFSTR("passphrase");
const CFStringRef __nonnull kSecImportExportKeychain = CFSTR("keychain");
const CFStringRef __nonnull kSecImportExportAccess = CFSTR("access");
const CFStringRef __nonnull kSecImportItemLabel = CFSTR("label");
const CFStringRef __nonnull kSecImportItemKeyID = CFSTR("keyid");
const CFStringRef __nonnull kSecImportItemTrust = CFSTR("trust");
const CFStringRef __nonnull kSecImportItemCertChain = CFSTR("chain");
const CFStringRef __nonnull kSecImportItemIdentity = CFSTR("identity");
#if 0
static void collect_certs(const void *key, const void *value, void *context)
{
if (!CFDictionaryContainsKey(value, CFSTR("key"))) {
CFDataRef cert_bytes = CFDictionaryGetValue(value, CFSTR("cert"));
if (!cert_bytes)
return;
SecCertificateRef cert =
SecCertificateCreateWithData(kCFAllocatorDefault, cert_bytes);
if (!cert)
return;
CFMutableArrayRef cert_array = (CFMutableArrayRef)context;
CFArrayAppendValue(cert_array, cert);
CFRelease(cert);
}
}
typedef struct {
CFMutableArrayRef identities;
CFArrayRef certs;
} build_trust_chains_context;
static void build_trust_chains(const void *key, const void *value,
void *context)
{
CFMutableDictionaryRef identity_dict = CFDictionaryCreateMutable(kCFAllocatorDefault,
0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
SecKeyRef private_key = NULL;
SecCertificateRef cert = NULL;
SecIdentityRef identity = NULL;
SecPolicyRef policy = NULL;
CFMutableArrayRef cert_chain = NULL, eval_chain = NULL;
SecTrustRef trust = NULL;
build_trust_chains_context * a_build_trust_chains_context = (build_trust_chains_context*)context;
CFDataRef key_bytes = CFDictionaryGetValue(value, CFSTR("key"));
if(!key_bytes) goto out; CFDataRef cert_bytes = CFDictionaryGetValue(value, CFSTR("cert"));
if(!cert_bytes) goto out;
if(!private_key) goto out; cert = SecCertificateCreateWithData(kCFAllocatorDefault, cert_bytes);
if(!cert) goto out; identity = SecIdentityCreate(kCFAllocatorDefault, cert, private_key);
if(!identity) goto out; CFDictionarySetValue(identity_dict, kSecImportItemIdentity, identity);
eval_chain = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
if(!eval_chain) goto out; CFArrayAppendValue(eval_chain, cert);
CFRange all_certs = { 0, CFArrayGetCount(a_build_trust_chains_context->certs) };
CFArrayAppendArray(eval_chain, a_build_trust_chains_context->certs, all_certs);
policy = SecPolicyCreateBasicX509();
if(!policy) goto out; SecTrustResultType result;
SecTrustCreateWithCertificates(eval_chain, policy, &trust);
if(!trust) goto out; SecTrustEvaluate(trust, &result);
CFDictionarySetValue(identity_dict, kSecImportItemTrust, trust);
cert_chain = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
if(!cert_chain) goto out; CFIndex cert_chain_length = SecTrustGetCertificateCount(trust);
int i;
for (i = 0; i < cert_chain_length; i++)
CFArrayAppendValue(cert_chain, SecTrustGetCertificateAtIndex(trust, i));
CFDictionarySetValue(identity_dict, kSecImportItemCertChain, cert_chain);
CFArrayAppendValue(a_build_trust_chains_context->identities, identity_dict);
out:
CFReleaseSafe(identity_dict);
CFReleaseSafe(identity);
CFReleaseSafe(private_key);
CFReleaseSafe(cert);
CFReleaseSafe(policy);
CFReleaseSafe(cert_chain);
CFReleaseSafe(eval_chain);
CFReleaseSafe(trust);
}
#endif // if 0
OSStatus SecPKCS12Import(CFDataRef pkcs12_data, CFDictionaryRef options, CFArrayRef *items)
{
if (_CFMZEnabled()) {
return SecPKCS12Import_ios(pkcs12_data, options, items);
}
OSStatus status = errSecSuccess;
SecExternalFormat inputFormat = kSecFormatPKCS12;
SecExternalItemType itemType = kSecItemTypeAggregate;
SecItemImportExportFlags flags = 0;
SecKeyImportExportParameters keyParams;
SecKeychainRef importKeychain = NULL;
SecAccessRef importAccess = NULL;
CFStringRef importPassword = NULL;
CFArrayRef tmpItems = NULL;
CFMutableArrayRef certs = NULL;
CFMutableArrayRef identities = NULL;
if (options) {
importKeychain = (SecKeychainRef) CFDictionaryGetValue(options, kSecImportExportKeychain);
if (importKeychain)
CFRetain(importKeychain);
importAccess = (SecAccessRef) CFDictionaryGetValue(options, kSecImportExportAccess);
if (importAccess)
CFRetain(importAccess);
importPassword = (CFStringRef) CFDictionaryGetValue(options, kSecImportExportPassphrase);
if (importPassword)
CFRetain(importPassword);
}
if (!importKeychain) {
status = SecKeychainCopyDefault(&importKeychain);
}
memset(&keyParams, 0, sizeof(SecKeyImportExportParameters));
keyParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
keyParams.passphrase = importPassword;
keyParams.accessRef = importAccess;
status = SecKeychainItemImport(pkcs12_data,
NULL,
&inputFormat,
&itemType,
flags,
&keyParams,
importKeychain,
&tmpItems);
if (!status) {
certs = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
CFIndex i, count = CFArrayGetCount(tmpItems);
for (i=0; i<count; i++) {
CFTypeRef anItem = (CFTypeRef)CFArrayGetValueAtIndex(tmpItems, i);
CFTypeID itemID = CFGetTypeID(anItem);
if (itemID == SecCertificateGetTypeID()) {
CFArrayAppendValue(certs, anItem);
}
}
}
if (!status) {
identities = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
CFIndex i, count = CFArrayGetCount(tmpItems);
for (i=0; i<count; i++) {
CFTypeRef anItem = (CFTypeRef)CFArrayGetValueAtIndex(tmpItems, i);
CFTypeID itemID = CFGetTypeID(anItem);
if (itemID == SecIdentityGetTypeID()) {
CFMutableDictionaryRef itemDict;
itemDict = CFDictionaryCreateMutable(kCFAllocatorDefault,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
SecCertificateRef itemCert = NULL;
status = SecIdentityCopyCertificate((SecIdentityRef)anItem, &itemCert);
if (!status) {
CFStringRef label = SecCertificateCopySubjectSummary(itemCert);
if (label) {
CFDictionaryAddValue(itemDict, kSecImportItemLabel, label);
CFRelease(label);
}
}
if (!status) {
CFDataRef digest = SecCertificateCopyPublicKeySHA1Digest(itemCert);
if (digest) {
CFDictionaryAddValue(itemDict, kSecImportItemKeyID, digest);
CFRelease(digest);
}
}
SecTrustRef trust = NULL;
SecPolicyRef policy = SecPolicyCreateBasicX509();
CFMutableArrayRef certArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
CFArrayAppendValue(certArray, itemCert);
if (certs) {
CFArrayAppendArray(certArray, certs, CFRangeMake(0, CFArrayGetCount(certs)));
}
status = SecTrustCreateWithCertificates(certArray, policy, &trust);
if (policy) {
CFRelease(policy);
}
if (trust) {
CFDictionaryAddValue(itemDict, kSecImportItemTrust, trust);
CFRelease(trust);
}
if (certArray) {
CFDictionaryAddValue(itemDict, kSecImportItemCertChain, certArray);
CFRelease(certArray);
}
CFDictionaryAddValue(itemDict, kSecImportItemIdentity, anItem);
if (itemCert)
CFRelease(itemCert);
CFArrayAppendValue(identities, itemDict);
CFRelease(itemDict);
}
}
}
if (items)
*items = identities;
else if (identities)
CFRelease(identities);
if (certs)
CFRelease(certs);
if (tmpItems)
CFRelease(tmpItems);
if (importKeychain)
CFRelease(importKeychain);
if (importAccess)
CFRelease(importAccess);
if (importPassword)
CFRelease(importPassword);
return status;
#if 0
pkcs12_context context = {};
SecAsn1CoderCreate(&context.coder);
if (options)
context.passphrase = CFDictionaryGetValue(options, kSecImportExportPassphrase);
context.items = CFDictionaryCreateMutable(kCFAllocatorDefault,
0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
int status = p12decode(&context, pkcs12_data);
if (!status) {
CFMutableArrayRef certs = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
CFDictionaryApplyFunction(context.items, collect_certs, certs);
CFMutableArrayRef identities = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
build_trust_chains_context a_build_trust_chains_context = { identities, certs };
CFDictionaryApplyFunction(context.items, build_trust_chains, &a_build_trust_chains_context);
CFReleaseSafe(certs);
*items = identities;
}
CFReleaseSafe(context.items);
SecAsn1CoderRelease(context.coder);
switch (status) {
case p12_noErr: return errSecSuccess;
case p12_passwordErr: return errSecAuthFailed;
case p12_decodeErr: return errSecDecode;
default: return errSecInternal;
};
return errSecSuccess;
#endif
}