#include "SecImportExport.h"
#include "SecExternalRep.h"
#include "SecImportExportPem.h"
#include "SecImportExportUtils.h"
#include <security_cdsa_utils/cuCdsaUtils.h>
#include <security_utilities/globalizer.h>
#include <Security/SecBase.h>
#define SecImpInferDbg(args...) secdebug("SecImpInfer", ## args)
using namespace Security;
using namespace KeychainCore;
static bool impExpInferTypeAndFormat(
SecImportRep *rep,
CFStringRef fileStr,
SecExternalFormat inputFormat,
SecExternalItemType itemType)
{
if((rep->mExternType == kSecItemTypeUnknown) && (itemType != kSecItemTypeUnknown)) {
rep->mExternType = itemType;
}
if((rep->mExternFormat == kSecFormatUnknown) && (inputFormat != kSecFormatUnknown)) {
rep->mExternFormat = inputFormat;
}
if(rep->mExternType == kSecItemTypeUnknown) {
SecExternalFormat format;
if(rep->mExternFormat == kSecFormatUnknown) {
format = inputFormat;
}
else {
format = rep->mExternFormat;
}
switch(format) {
case kSecFormatUnknown:
break;
case kSecFormatPKCS7:
case kSecFormatPKCS12:
case kSecFormatPEMSequence:
case kSecFormatNetscapeCertSequence:
rep->mExternType = kSecItemTypeAggregate;
break;
case kSecFormatRawKey:
rep->mExternType = kSecItemTypeSessionKey;
break;
case kSecFormatX509Cert:
rep->mExternType = kSecItemTypeCertificate;
break;
case kSecFormatWrappedPKCS8:
case kSecFormatWrappedOpenSSL:
case kSecFormatWrappedSSH:
rep->mExternType = kSecItemTypePrivateKey;
break;
case kSecFormatSSHv2:
rep->mExternType = kSecItemTypePublicKey;
break;
case kSecFormatOpenSSL:
case kSecFormatBSAFE:
case kSecFormatWrappedLSH:
default:
break;
}
}
if(rep->mExternFormat == kSecFormatUnknown) {
SecExternalItemType thisType;
if(rep->mExternType == kSecItemTypeUnknown) {
thisType = itemType;
}
else {
thisType = rep->mExternType;
}
switch(thisType) {
case kSecItemTypeCertificate:
rep->mExternFormat = kSecFormatX509Cert;
break;
default:
break;
}
}
bool isWrapped = false;
switch(rep->mExternFormat) {
case kSecFormatWrappedPKCS8:
case kSecFormatWrappedOpenSSL:
case kSecFormatWrappedLSH:
isWrapped = true;
break;
case kSecFormatWrappedSSH:
isWrapped = true;
rep->mKeyAlg = CSSM_ALGID_RSA;
break;
case kSecFormatSSH:
rep->mKeyAlg = CSSM_ALGID_RSA;
break;
default:
break;
}
bool done = true;
if((rep->mExternType == kSecItemTypeUnknown) ||
(rep->mExternFormat == kSecFormatUnknown)) {
done = false;
}
if(done) {
switch(rep->mExternType) {
case kSecItemTypePrivateKey:
case kSecItemTypePublicKey:
if(!isWrapped && (rep->mKeyAlg == CSSM_ALGID_NONE)) {
done = false;
}
break;
default:
break;
}
}
if(!done) {
done = impExpImportParseFileExten(fileStr, &rep->mExternFormat,
&rep->mExternType);
}
if(done) {
return true;
}
return impExpImportGuessByExamination(rep->mExternal, &rep->mExternFormat,
&rep->mExternType, &rep->mKeyAlg);
}
class CSPDLMaker
{
protected:
CSSM_CSP_HANDLE mHandle;
RecursiveMutex mMutex;
public:
CSPDLMaker() : mHandle(cuCspStartup(CSSM_FALSE)) {}
operator CSSM_CSP_HANDLE() {return mHandle;}
};
static ModuleNexus<CSPDLMaker> gCSPHandle;
OSStatus SecKeychainItemImport(
CFDataRef importedData,
CFStringRef fileNameOrExtension, SecExternalFormat *inputFormat, SecExternalItemType *itemType, SecItemImportExportFlags flags,
const SecKeyImportExportParameters *keyParams, SecKeychainRef importKeychain, CFArrayRef *outItems)
{
BEGIN_IMP_EXP_SECAPI
bool isPem;
OSStatus ortn = errSecSuccess;
OSStatus pem_ortn = errSecSuccess;
SecImportRep *rep = NULL;
SecExternalFormat callerInputFormat;
SecExternalItemType callerItemType;
CSSM_CSP_HANDLE cspHand = 0;
CFIndex dex;
CFStringRef ourFileStr = NULL;
if((importedData == NULL) || (CFDataGetLength(importedData) == 0)) {
return errSecParam;
}
if(inputFormat) {
callerInputFormat = *inputFormat;
}
else {
callerInputFormat = kSecFormatUnknown;
}
if(itemType) {
callerItemType = *itemType;
}
else {
callerItemType = kSecItemTypeUnknown;
}
CFIndex numReps = 0;
SecExternalFormat tempFormat = callerInputFormat;
SecExternalItemType tempType = callerItemType;
ImpPrivKeyImportState keyImportState = PIS_NoLimit;
CFMutableArrayRef importReps = CFArrayCreateMutable(NULL, 0, NULL);
CFMutableArrayRef createdKcItems = CFArrayCreateMutable(NULL, 0,
&kCFTypeArrayCallBacks);
pem_ortn = impExpParsePemToImportRefs(importedData, importReps, &isPem);
if(!isPem) {
rep = new SecImportRep(importedData, callerItemType, callerInputFormat,
CSSM_ALGID_NONE);
CFArrayAppendValue(importReps, rep);
if(fileNameOrExtension) {
ourFileStr = fileNameOrExtension;
CFRetain(ourFileStr);
}
}
else {
assert(CFArrayGetCount(importReps) >= 1);
if(fileNameOrExtension) {
if(CFStringHasSuffix(fileNameOrExtension, CFSTR(".pem"))) {
ourFileStr = impExpImportDeleteExtension(fileNameOrExtension);
}
else {
ourFileStr = fileNameOrExtension;
CFRetain(ourFileStr);
}
}
}
numReps = CFArrayGetCount(importReps);
if(numReps > 1) {
if(ourFileStr) {
CFRelease(ourFileStr);
ourFileStr = NULL;
}
tempFormat = kSecFormatUnknown;
tempType = kSecItemTypeUnknown;
}
for(dex=0; dex<numReps; dex++) {
rep = (SecImportRep *)CFArrayGetValueAtIndex(importReps, dex);
bool ok = impExpInferTypeAndFormat(rep, ourFileStr, tempFormat, tempType);
if(!ok) {
ortn = errSecUnknownFormat;
goto errOut;
}
}
if(importKeychain != NULL) {
ortn = SecKeychainGetCSPHandle(importKeychain, &cspHand);
if(ortn) {
goto errOut;
}
}
else {
cspHand = gCSPHandle();
}
if(keyParams && (keyParams->flags & kSecKeyImportOnlyOne)) {
keyImportState = PIS_AllowOne;
}
for(CFIndex dex=0; dex<numReps; dex++) {
rep = (SecImportRep *)CFArrayGetValueAtIndex(importReps, dex);
ortn = rep->importRep(importKeychain, cspHand, flags, keyParams,
keyImportState, createdKcItems);
if(ortn) {
goto errOut;
}
}
if(inputFormat != NULL) {
if(numReps > 1) {
assert(isPem);
*inputFormat = kSecFormatPEMSequence;
}
else {
assert(numReps != 0);
rep = (SecImportRep *)CFArrayGetValueAtIndex(importReps, 0);
*inputFormat = rep->mExternFormat;
}
}
if(itemType != NULL) {
if(numReps > 1) {
assert(isPem);
*itemType = kSecItemTypeAggregate;
}
else {
assert(numReps != 0);
rep = (SecImportRep *)CFArrayGetValueAtIndex(importReps, 0);
*itemType = rep->mExternType;
}
}
if((ortn == errSecSuccess) && (outItems != NULL)) {
*outItems = createdKcItems;
createdKcItems = NULL;
}
errOut:
if(createdKcItems) {
CFRelease(createdKcItems);
}
if(importReps != NULL) {
CFIndex num = CFArrayGetCount(importReps);
for(dex=0; dex<num; dex++) {
rep = (SecImportRep *)CFArrayGetValueAtIndex(importReps, dex);
delete rep;
}
CFRelease(importReps);
}
if(ourFileStr) {
CFRelease(ourFileStr);
}
if(ortn) {
return SecKeychainErrFromOSStatus(ortn);
}
if(pem_ortn == errSecUnsupportedFormat && numReps == 0) {
return SecKeychainErrFromOSStatus(pem_ortn);
}
return errSecSuccess;
END_IMP_EXP_SECAPI
}
OSStatus SecItemImport(
CFDataRef importedData,
CFStringRef fileNameOrExtension,
SecExternalFormat *inputFormat,
SecExternalItemType *itemType,
SecItemImportExportFlags flags,
const SecItemImportExportKeyParameters *keyParams,
SecKeychainRef importKeychain,
CFArrayRef *outItems)
{
SecKeyImportExportParameters* oldStructPtr = NULL;
SecKeyImportExportParameters oldStruct;
memset(&oldStruct, 0, sizeof(oldStruct));
if (NULL != keyParams)
{
if (ConvertSecKeyImportExportParametersToSecImportExportKeyParameters(NULL,
keyParams, &oldStruct))
{
oldStructPtr = &oldStruct;
}
}
return SecKeychainItemImport(importedData, fileNameOrExtension, inputFormat,
itemType, flags, oldStructPtr, importKeychain, outItems);
}