#include "SecImportExport.h"
#include "SecImportExportAgg.h"
#include "SecImportExportPem.h"
#include "SecExternalRep.h"
#include "SecImportExportUtils.h"
#include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
#include <security_utilities/errors.h>
#include <Security/SecIdentity.h>
#include <Security/SecIdentityPriv.h>
#include <Security/SecItem.h>
using namespace Security;
using namespace KeychainCore;
static void impExpAddToExportReps(
CFTypeRef thing, CFMutableArrayRef exportReps,
unsigned &numCerts, unsigned &numKeys) {
if(CFGetTypeID(thing) == SecIdentityGetTypeID()) {
OSStatus ortn;
SecIdentityRef idRef = (SecIdentityRef)thing;
SecCertificateRef certRef;
SecKeyRef keyRef;
SecExportRep *rep;
SecImpExpDbg("impExpAddToExportReps: adding identity cert and key");
ortn = SecIdentityCopyCertificate(idRef, &certRef);
if(ortn) {
Security::MacOSError::throwMe(ortn);
}
rep = SecExportRep::vend(certRef);
CFArrayAppendValue(exportReps, rep);
CFRelease(certRef); numCerts++;
ortn = SecIdentityCopyPrivateKey(idRef, &keyRef);
if(ortn) {
Security::MacOSError::throwMe(ortn);
}
rep = SecExportRep::vend(keyRef);
CFArrayAppendValue(exportReps, rep);
CFRelease(keyRef); numKeys++;
}
else {
SecExportRep *rep = SecExportRep::vend(thing);
SecImpExpDbg("impExpAddToExportReps: adding single type %d",
(int)rep->externType());
CFArrayAppendValue(exportReps, rep);
if(rep->externType() == kSecItemTypeCertificate) {
numCerts++;
}
else {
numKeys++;
}
}
}
#pragma mark --- public export function ---
OSStatus SecKeychainItemExport(
CFTypeRef keychainItemOrArray,
SecExternalFormat outputFormat, SecItemImportExportFlags flags, const SecKeyImportExportParameters *keyParams, CFDataRef *exportedData) {
BEGIN_IMP_EXP_SECAPI
if(keychainItemOrArray == NULL) {
return paramErr;
}
if(keyParams != NULL) {
if( (keyParams->passphrase != NULL) &&
(keyParams->flags & kSecKeySecurePassphrase != 0)) {
return paramErr;
}
}
unsigned numKeys = 0;
unsigned numCerts = 0;
unsigned numTotalExports = 0;
OSStatus ortn = noErr;
SecExportRep *rep = NULL; CFMutableDataRef outputData = NULL;
const char *pemHeader = "UNKNOWN";
CFMutableArrayRef exportReps = CFArrayCreateMutable(NULL, 0, NULL);
try {
if(CFGetTypeID(keychainItemOrArray) == CFArrayGetTypeID()) {
CFArrayRef arr = (CFArrayRef)keychainItemOrArray;
CFIndex arraySize = CFArrayGetCount(arr);
for(CFIndex dex=0; dex<arraySize; dex++) {
impExpAddToExportReps(CFArrayGetValueAtIndex(arr, dex),
exportReps, numCerts, numKeys);
}
}
else {
impExpAddToExportReps(keychainItemOrArray, exportReps, numCerts, numKeys);
}
}
catch(const Security::MacOSError osErr) {
ortn = osErr.error;
goto errOut;
}
catch(...) {
ortn = paramErr;
goto errOut;
}
numTotalExports = CFArrayGetCount(exportReps);
assert((numCerts + numKeys) == numTotalExports);
if((numTotalExports > 1) && (outputFormat == kSecFormatUnknown)) {
outputFormat = kSecFormatPEMSequence;
}
outputData = CFDataCreateMutable(NULL, 0);
switch(outputFormat) {
case kSecFormatPKCS7:
ortn = impExpPkcs7Export(exportReps, flags, keyParams, outputData);
pemHeader = PEM_STRING_PKCS7;
break;
case kSecFormatPKCS12:
ortn = impExpPkcs12Export(exportReps, flags, keyParams, outputData);
pemHeader = PEM_STRING_PKCS12;
break;
case kSecFormatPEMSequence:
{
CFIndex numReps = CFArrayGetCount(exportReps);
for(CFIndex dex=0; dex<numReps; dex++) {
rep = (SecExportRep *)CFArrayGetValueAtIndex(exportReps, dex);
CFMutableDataRef tmpData = CFDataCreateMutable(NULL, 0);
ortn = rep->exportRep(kSecFormatUnknown, flags, keyParams,
tmpData, &pemHeader);
if(ortn) {
SecImpExpDbg("ItemExport: releasing tmpData %p", tmpData);
CFRelease(tmpData);
goto errOut;
}
assert(rep->pemParamLines() == NULL);
ortn = impExpPemEncodeExportRep((CFDataRef)tmpData,
pemHeader, NULL,
outputData);
CFRelease(tmpData);
if(ortn) {
goto errOut;
}
}
break;
}
case kSecFormatOpenSSL:
case kSecFormatSSH:
case kSecFormatSSHv2:
case kSecFormatBSAFE:
case kSecFormatRawKey:
case kSecFormatWrappedPKCS8:
case kSecFormatWrappedOpenSSL:
case kSecFormatWrappedSSH:
case kSecFormatWrappedLSH:
case kSecFormatX509Cert:
case kSecFormatUnknown: {
unsigned foundCount = 0;
if(outputFormat == kSecFormatX509Cert) {
foundCount = numCerts;
}
else if(outputFormat == kSecFormatUnknown) {
foundCount = numTotalExports;
}
else {
foundCount = numKeys;
}
if((numTotalExports != 1) || (foundCount != 1)) {
SecImpExpDbg("Export single item format with other than one item");
ortn = paramErr;
goto errOut;
}
assert(CFArrayGetCount(exportReps) == 1);
rep = (SecExportRep *)CFArrayGetValueAtIndex(exportReps, 0);
ortn = rep->exportRep(outputFormat, flags,
keyParams, outputData, &pemHeader);
break;
}
default:
SecImpExpDbg("SecKeychainItemExport: bad format (%u)",
(unsigned)outputFormat);
ortn = paramErr;
goto errOut;
}
if(ortn == noErr) {
if(outputFormat == kSecFormatPEMSequence) {
*exportedData = outputData;
outputData = NULL;
}
else {
rep = (SecExportRep *)CFArrayGetValueAtIndex(exportReps, 0);
if((flags & kSecItemPemArmour) || (rep->pemParamLines() != NULL)) {
CFMutableDataRef tmpData = CFDataCreateMutable(NULL, 0);
ortn = impExpPemEncodeExportRep((CFDataRef)outputData, pemHeader,
rep->pemParamLines(), tmpData);
CFRelease(outputData); outputData = NULL;
*exportedData = tmpData; }
else {
*exportedData = outputData;
outputData = NULL;
}
}
}
errOut:
if(exportReps != NULL) {
CFIndex num = CFArrayGetCount(exportReps);
for(CFIndex dex=0; dex<num; dex++) {
rep = (SecExportRep *)CFArrayGetValueAtIndex(exportReps, dex);
delete rep;
}
CFRelease(exportReps);
}
if(outputData != NULL) {
CFRelease(outputData);
outputData = NULL;
}
if(ortn) {
return SecKeychainErrFromOSStatus(ortn);
}
else {
return noErr;
}
END_IMP_EXP_SECAPI
}
OSStatus SecItemExport(CFTypeRef secItemOrArray, SecExternalFormat outputFormat,
SecItemImportExportFlags flags,
const SecItemImportExportKeyParameters *keyParams,
CFDataRef *exportedData)
{
SecKeyImportExportParameters* oldStructPtr = NULL;
SecKeyImportExportParameters oldStruct;
memset(&oldStruct, 0, sizeof(oldStruct));
if (NULL != keyParams)
{
SecKeyRef tempKey = NULL;
if (SecKeyGetTypeID() == CFGetTypeID(secItemOrArray))
{
tempKey = (SecKeyRef)secItemOrArray;
}
if (ConvertSecKeyImportExportParametersToSecImportExportKeyParameters(tempKey,
keyParams, &oldStruct))
{
oldStructPtr = &oldStruct;
}
}
return SecKeychainItemExport(secItemOrArray, outputFormat, flags, oldStructPtr, exportedData);
}