p12ImportExport.cpp [plain text]
#include <security_pkcs12/SecPkcs12.h>
#include <security_cdsa_utils/cuFileIo.h>
#include <Security/Security.h>
#include <stdio.h>
#include <stdlib.h>
#include <security_cdsa_utilities/KeySchema.h>
#include <security_cdsa_utils/cuCdsaUtils.h>
#include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
#include "p12GetPassKey.h"
static void printOsError(
const char *op,
OSStatus ortn)
{
char *errStr = NULL;
switch(ortn) {
case CSSMERR_DL_INVALID_UNIQUE_INDEX_DATA:
errStr = "CSSMERR_DL_INVALID_UNIQUE_INDEX_DATA"; break;
case CSSMERR_DL_DATASTORE_DOESNOT_EXIST:
errStr = "CSSMERR_DL_DATASTORE_DOESNOT_EXIST"; break;
case errSecDuplicateItem:
errStr = "errSecDuplicateItem"; break;
case errSecNotAvailable:
errStr = "errSecNotAvailable"; break;
case errSecAuthFailed:
errStr = "errSecAuthFailed"; break;
case errSecItemNotFound:
errStr = "errSecItemNotFound"; break;
case errSecInvalidItemRef:
errStr = "errSecInvalidItemRef"; break;
default:
break;
}
if(errStr) {
printf("%s returned %s\n", op, errStr);
}
else {
printf("%s returned %d\n", op, (int)ortn);
}
}
int p12Import(
const char *pfxFile,
const char *kcName,
CFStringRef pwd, bool usePassKey, const char *kcPwd) {
OSStatus ortn;
unsigned char *pfx;
unsigned pfxLen;
CSSM_KEY passKey;
if(readFile(pfxFile, &pfx, &pfxLen)) {
printf("***Error reading pfx from %s. Aborting.\n", pfxFile);
return 1;
}
CFDataRef cfd = CFDataCreate(NULL, pfx, pfxLen);
SecKeychainRef kcRef = NULL;
ortn = SecKeychainOpen(kcName, &kcRef);
if(ortn) {
printOsError("SecKeychainOpen", ortn);
return ortn;
}
if(kcPwd) {
ortn = SecKeychainUnlock(kcRef, strlen(kcPwd), (void *)kcPwd, true);
if(ortn) {
printOsError("SecKeychainUnlock", ortn);
}
}
SecPkcs12CoderRef coder;
ortn = SecPkcs12CoderCreate(&coder);
if(ortn) {
printOsError("SecPkcs12CoderCreate", ortn);
return ortn;
}
ortn = SecPkcs12SetKeychain(coder, kcRef);
if(ortn) {
printOsError("SecPkcs12SetKeychain", ortn);
return ortn;
}
if(usePassKey) {
CSSM_CSP_HANDLE cspHand;
ortn = SecKeychainGetCSPHandle(kcRef, &cspHand);
if(ortn) {
printOsError("SecPkcs12SetKeychain", ortn);
return ortn;
}
ortn = p12GetPassKey(cspHand, GPK_Decode, false, &passKey);
if(ortn) {
return ortn;
}
ortn = SecPkcs12SetMACPassKey(coder, &passKey);
if(ortn) {
printOsError("SecPkcs12SetMACPassKey", ortn);
return ortn;
}
}
else {
ortn = SecPkcs12SetMACPassphrase(coder, pwd);
if(ortn) {
printOsError("SecPkcs12SetMACPassphrase", ortn);
return ortn;
}
}
ortn = SecPkcs12SetImportToKeychain(coder,
kSecImportCertificates |
kSecImportCRLs |
kSecImportKeys);
if(ortn) {
printOsError("SecPkcs12SetImportFromKeychain", ortn);
return ortn;
}
ortn = SecPkcs12Decode(coder, cfd);
if(ortn) {
printOsError("SecPkcs12Decode", ortn);
return ortn;
}
CFIndex num;
SecPkcs12CertificateCount(coder, &num);
printf("...%d certs imported\n", (int)num);
SecPkcs12CrlCount(coder, &num);
printf("...%d CRLs imported\n", (int)num);
SecPkcs12PrivateKeyCount(coder, &num);
printf("...%d private keys imported\n", (int)num);
SecPkcs12CoderRelease(coder);
CFRelease(cfd);
free(pfx); return 0;
}
OSStatus attrNameToInt(
const char *name,
uint32 *attrInt)
{
const CSSM_DB_SCHEMA_ATTRIBUTE_INFO *attrList =
KeySchema::KeySchemaAttributeList;
unsigned numAttrs = KeySchema::KeySchemaAttributeCount;
for(unsigned dex=0; dex<numAttrs; dex++) {
const CSSM_DB_SCHEMA_ATTRIBUTE_INFO *info = &attrList[dex];
if(!strcmp(name, info->AttributeName)) {
*attrInt = info->AttributeId;
return noErr;
}
}
return paramErr;
}
static int p12AddExportedItem(
SecKeychainItemRef item,
CFMutableArrayRef itemArray,
bool noPrompt)
{
if(noPrompt) {
CFArrayAppendValue(itemArray, item);
return 1;
}
CFTypeID itemId = CFGetTypeID(item);
OSStatus ortn;
UInt32 nameAttr = 0;
char *itemClass = "";
if(itemId == SecCertificateGetTypeID()) {
itemClass = "Certificate";
nameAttr = kSecLabelItemAttr;
}
else if(itemId == SecKeyGetTypeID()) {
itemClass = "Private Key";
ortn = attrNameToInt("PrintName", &nameAttr);
if(ortn) {
printf("warning: attrNameToInt failure\n");
return 0;
}
}
else {
printf("p12AddExportedItem: internal screwup\n");
return 0;
}
SecKeychainAttributeInfo attrInfo;
attrInfo.count = 1;
attrInfo.tag = &nameAttr;
attrInfo.format = NULL;
SecKeychainAttributeList *attrList = NULL;
ortn = SecKeychainItemCopyAttributesAndData(
item,
&attrInfo,
NULL, &attrList,
NULL, NULL);
if(ortn) {
printOsError("SecKeychainItemCopyAttributesAndData", ortn);
return 0;
}
if(attrList->count != 1) {
printf("***Unexpected attribute count (%u) for %s\n",
(unsigned)attrList->count, itemClass);
return 0;
}
SecKeychainAttribute *attr = attrList->attr;
CFStringRef cfStr = CFStringCreateWithBytes(NULL,
(UInt8 *)attr->data, attr->length,
kCFStringEncodingUTF8, false);
SecKeychainItemFreeAttributesAndData(attrList, NULL);
if(cfStr == NULL) {
printf("***Error converting %s name to UTF CFSTring.\n",
itemClass);
return 0;
}
CFIndex strLen = CFStringGetLength(cfStr);
char *printName = (char *)malloc(strLen + 1);
if(!CFStringGetCString(cfStr, printName, strLen + 1, kCFStringEncodingASCII)) {
printf("***Error converting %s name to ASCII\n", itemClass);
return 0;
}
CFRelease(cfStr);
char *aliasCStr = NULL;
if((itemId == SecCertificateGetTypeID())) {
CFStringRef aliasCFStr = NULL;
nameAttr = kSecAlias;
attrInfo.count = 1;
attrInfo.tag = &nameAttr;
attrInfo.format = NULL; attrList = NULL;
ortn = SecKeychainItemCopyAttributesAndData(
item,
&attrInfo,
NULL, &attrList,
NULL, NULL);
if(ortn) {
printOsError("SecKeychainItemCopyAttributesAndData", ortn);
return 0;
}
if(attrList->count != 1) {
printf("***Unexpected attribute count (%u) for Alias\n",
(unsigned)attrList->count);
return 0;
}
attr = attrList->attr;
aliasCFStr = CFStringCreateWithBytes(NULL,
(UInt8 *)attr->data, attr->length,
kCFStringEncodingUTF8, false);
if(aliasCFStr == NULL) {
printf("***Error converting Alias name to UTF CFSTring.\n");
return 0;
}
strLen = CFStringGetLength(aliasCFStr);
aliasCStr = (char *)malloc(strLen + 1);
if(!CFStringGetCString(aliasCFStr, aliasCStr, strLen + 1,
kCFStringEncodingASCII)) {
printf("***Error converting Alias name to ASCII\n");
return 0;
}
CFRelease(aliasCFStr);
}
int ourRtn = 0;
fpurge(stdin);
printf("Found %s\n", itemClass);
printf(" printable name : %s\n", printName);
if(aliasCStr != NULL) {
printf(" alias : %s\n", aliasCStr);
}
printf("Export (y/anything)? ");
char c = getchar();
if(c == 'y') {
CFArrayAppendValue(itemArray, item);
ourRtn = 1;
}
free(printName);
if(aliasCStr) {
free(aliasCStr);
}
return ourRtn;
}
int p12Export(
const char *pfxFile,
const char *kcName,
CFStringRef pwd, bool usePassKey, const char *kcPwd, bool noPrompt) {
OSStatus ortn;
CSSM_KEY passKey;
SecPkcs12CoderRef coder;
ortn = SecPkcs12CoderCreate(&coder);
if(ortn) {
printOsError("SecPkcs12CoderCreate", ortn);
return ortn;
}
CSSM_CSP_HANDLE cspHand = cuCspStartup(CSSM_FALSE);
if(cspHand == 0) {
printf("***Error attaching to CSPDL. Aborting.\n");
return 1;
}
if(usePassKey) {
ortn = p12GetPassKey(cspHand, GPK_Encode, false, &passKey);
if(ortn) {
return ortn;
}
ortn = SecPkcs12SetMACPassKey(coder, &passKey);
if(ortn) {
printOsError("SecPkcs12SetMACPassKey", ortn);
return ortn;
}
}
else {
ortn = SecPkcs12SetMACPassphrase(coder, pwd);
if(ortn) {
printOsError("SecPkcs12SetMACPassphrase", ortn);
return ortn;
}
}
ortn = SecPkcs12SetCspHandle(coder, cspHand);
if(ortn) {
printOsError("SecPkcs12SetCspHandle", ortn);
return ortn;
}
CFMutableArrayRef items = CFArrayCreateMutable(NULL, 0, NULL);
SecKeychainRef kcRef = NULL;
ortn = SecKeychainOpen(kcName, &kcRef);
if(ortn) {
printOsError("SecKeychainOpen", ortn);
return ortn;
}
if(kcPwd) {
ortn = SecKeychainUnlock(kcRef, strlen(kcPwd), (void *)kcPwd, true);
if(ortn) {
printOsError("SecKeychainUnlock", ortn);
}
}
SecKeychainSearchRef srchRef;
ortn = SecKeychainSearchCreateFromAttributes(kcRef,
kSecCertificateItemClass,
NULL, &srchRef);
if(ortn) {
printOsError("SecKeychainSearchCreateFromAttributes", ortn);
return ortn;
}
int exported = 0;
for(;;) {
SecKeychainItemRef certRef;
ortn = SecKeychainSearchCopyNext(srchRef, &certRef);
if(ortn) {
break;
}
exported += p12AddExportedItem(certRef, items, noPrompt);
}
CFRelease(srchRef);
ortn = SecKeychainSearchCreateFromAttributes(kcRef,
CSSM_DL_DB_RECORD_PRIVATE_KEY, NULL, &srchRef);
if(ortn) {
printOsError("SecKeychainSearchCreateFromAttributes", ortn);
return ortn;
}
for(;;) {
SecKeychainItemRef keyRef;
ortn = SecKeychainSearchCopyNext(srchRef, &keyRef);
if(ortn) {
break;
}
exported += p12AddExportedItem(keyRef, items, noPrompt);
}
if(exported == 0) {
printf("...Hmmm, no items to export. Done.\n");
return 0;
}
ortn = SecPkcs12ExportKeychainItems(coder, items);
if(ortn) {
printOsError("SecPkcs12ExportKeychainItems", ortn);
return ortn;
}
CFDataRef pfx;
ortn = SecPkcs12Encode(coder, &pfx);
if(ortn) {
printOsError("SecPkcs12ExportKeychainItems", ortn);
return ortn;
}
if(writeFile(pfxFile, CFDataGetBytePtr(pfx),
CFDataGetLength(pfx))) {
printf("***Error writing pfx to %s\n", pfxFile);
return 1;
}
printf("...%u items exported; %ld bytes written to %s\n",
exported, CFDataGetLength(pfx), pfxFile);
SecPkcs12CoderRelease(coder);
CFRelease(pfx);
CFRelease(srchRef);
CFRelease(kcRef);
return 0;
}