#include <Security/Security.h>
#include <Security/SecImportExport.h>
#include <security_cdsa_utils/cuFileIo.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <utilLib/common.h>
#include <clAppUtils/identPicker.h>
static void usage(char **argv)
{
printf("Usage: %s infile [option ...]\n", argv[0]);
printf("Options:\n");
printf(" -k keychain Keychain to import into\n");
printf(" -z passphrase For PKCS12 and wrapped keys only\n");
printf(" -w Private keys are wrapped\n");
printf(" -d Display Imported Items\n");
printf(" -i Interactive: displays items before possible import\n");
printf(" -v Verbose display\n");
printf(" -l Loop & Pause for MallocDebug\n");
printf(" -q Quiet\n");
printf("Import type/format options:\n");
printf(" -t <type> type = pub|priv|session|cert|agg\n");
printf(" -f <format> format = openssl|openssh1|openssh2|bsafe|\n"
" raw|pkcs7|pkcs8|pkcs12|netscape|pemseq\n");
printf("Private key options:\n");
printf(" -a appPath Add appPath to list of trusted apps in private key's ACL\n");
printf(" -e Allow private keys to be extractable in the clear\n");
printf(" -n Private keys have *NO* ACL\n");
printf(" -s Private keys can sign (only)\n");
printf("Secure passphrase options:\n");
printf(" -Z Get secure passphrase\n");
printf(" -L title\n");
printf(" -p prompt\n");
printf("Verification options:\n");
printf(" -C numCerts Verify number of certificates\n");
printf(" -K numKeys Verify number of keys\n");
printf(" -I numIdents Verify number of identities\n");
printf(" -F rtnFormat Returned format = "
"openssl|openssh1|openssh2|bsafe|raw|pkcs7|pkcs12|netscape|pemseq\n");
printf(" -T <type> Returned type = pub|priv|session|cert|agg\n");
printf(" -m Set ImportOnlyOneKey bit\n");
printf(" -M Set ImportOnlyOneKey bit and expect errSecMultiplePrivKeys\n");
exit(1);
}
const char *secExtFormatStr(
SecExternalFormat format)
{
switch(format) {
case kSecFormatUnknown: return "kSecFormatUnknown";
case kSecFormatOpenSSL: return "kSecFormatOpenSSL";
case kSecFormatSSH: return "kSecFormatSSH";
case kSecFormatBSAFE: return "kSecFormatBSAFE";
case kSecFormatRawKey: return "kSecFormatRawKey";
case kSecFormatWrappedPKCS8: return "kSecFormatWrappedPKCS8";
case kSecFormatWrappedOpenSSL: return "kSecFormatWrappedOpenSSL";
case kSecFormatWrappedSSH: return "kSecFormatWrappedSSH";
case kSecFormatWrappedLSH: return "kSecFormatWrappedLSH";
case kSecFormatX509Cert: return "kSecFormatX509Cert";
case kSecFormatPEMSequence: return "kSecFormatPEMSequence";
case kSecFormatPKCS7: return "kSecFormatPKCS7";
case kSecFormatPKCS12: return "kSecFormatPKCS12";
case kSecFormatNetscapeCertSequence: return "kSecFormatNetscapeCertSequence";
case kSecFormatSSHv2: return "kSecFormatSSHv2";
default: return "UNKNOWN FORMAT ENUM";
}
}
const char *secExtItemTypeStr(
SecExternalItemType itemType)
{
switch(itemType) {
case kSecItemTypeUnknown: return "kSecItemTypeUnknown";
case kSecItemTypePrivateKey: return "kSecItemTypePrivateKey";
case kSecItemTypePublicKey: return "kSecItemTypePublicKey";
case kSecItemTypeSessionKey: return "kSecItemTypeSessionKey";
case kSecItemTypeCertificate: return "kSecItemTypeCertificate";
case kSecItemTypeAggregate: return "kSecItemTypeAggregate";
default: return "UNKNOWN ITEM TYPE ENUM";
}
}
static OSStatus processItem(
SecKeychainRef keychain,
SecKeychainItemRef item,
int *numCerts, int *numKeys,
int *numIds,
bool interactive, bool verbose)
{
char *kcName = NULL;
CFTypeID itemType = CFGetTypeID(item);
if(itemType == SecIdentityGetTypeID()) {
(*numIds)++;
if(verbose) {
SecCertificateRef certRef = NULL;
OSStatus ortn;
ortn = SecIdentityCopyCertificate((SecIdentityRef)item, &certRef);
if(ortn) {
cssmPerror("SecIdentityCopyCertificate", ortn);
return ortn;
}
kcName = kcItemKcFileName((SecKeychainItemRef)certRef);
printf(" identity : cert keychain name %s\n", kcName ? kcName : "<none>");
CFRelease(certRef);
SecKeyRef keyRef = NULL;
ortn = SecIdentityCopyPrivateKey((SecIdentityRef)item, &keyRef);
if(ortn) {
cssmPerror("SecIdentityCopyPrivateKey", ortn);
return ortn;
}
free(kcName);
kcName = kcItemKcFileName((SecKeychainItemRef)keyRef);
printf(" identity : key keychain name %s\n", kcName ? kcName : "<none>");
CFRelease(keyRef);
}
}
else if(itemType == SecCertificateGetTypeID()) {
(*numCerts)++;
if(verbose) {
kcName = kcItemKcFileName(item);
printf(" cert : keychain name %s\n", kcName ? kcName : "<none>");
}
}
else if(itemType == SecKeyGetTypeID()) {
(*numKeys)++;
if(verbose) {
kcName = kcItemKcFileName(item);
printf(" key : keychain name %s\n", kcName ? kcName : "<none>");
}
}
else {
printf("***Unknown type returned from SecKeychainItemImport()\n");
return errSecUnknownFormat;
}
if(kcName) {
free(kcName);
}
return noErr;
}
static OSStatus processItems(
SecKeychainRef keychain,
CFArrayRef outArray,
int expectNumCerts, int expectNumKeys,
int expectNumIds,
bool interactive,
bool displayItems,
bool verbose)
{
int numCerts = 0;
int numKeys = 0;
int numIds = 0;
OSStatus ortn;
CFIndex numItems = CFArrayGetCount(outArray);
for(CFIndex dex=0; dex<numItems; dex++) {
ortn = processItem(keychain,
(SecKeychainItemRef)CFArrayGetValueAtIndex(outArray, dex),
&numCerts, &numKeys, &numIds, interactive, verbose);
if(ortn) {
break;
}
}
if(ortn) {
return ortn;
}
if(displayItems) {
printf("Certs found : %d\n", numCerts);
printf("Keys found : %d\n", numKeys);
printf("Idents found : %d\n", numIds);
}
if(expectNumCerts >= 0) {
if(expectNumCerts != numCerts) {
printf("***Expected %d certs, got %d\n",
expectNumCerts, numCerts);
ortn = -1;
}
}
if(expectNumKeys >= 0) {
if(expectNumKeys != numKeys) {
printf("***Expected %d keys, got %d\n",
expectNumKeys, numKeys);
ortn = -1;
}
}
if(expectNumIds >= 0) {
if(expectNumIds != numIds) {
printf("***Expected %d certs, got %d\n",
expectNumIds, numIds);
ortn = -1;
}
}
return ortn;
}
static bool formatFromString(
const char *formStr,
SecExternalFormat *externFormat)
{
if(!strcmp("openssl", formStr)) {
*externFormat = kSecFormatOpenSSL;
}
else if(!strcmp("openssh1", formStr)) {
*externFormat = kSecFormatSSH;
}
else if(!strcmp("openssh2", formStr)) {
*externFormat = kSecFormatSSHv2;
}
else if(!strcmp("bsafe", formStr)) {
*externFormat = kSecFormatBSAFE;
}
else if(!strcmp("raw", formStr)) {
*externFormat = kSecFormatRawKey;
}
else if(!strcmp("pkcs7", formStr)) {
*externFormat = kSecFormatPKCS7;
}
else if(!strcmp("pkcs8", formStr)) {
*externFormat = kSecFormatWrappedPKCS8;
}
else if(!strcmp("pkcs12", formStr)) {
*externFormat = kSecFormatPKCS12;
}
else if(!strcmp("netscape", formStr)) {
*externFormat = kSecFormatNetscapeCertSequence;
}
else if(!strcmp("pemseq", formStr)) {
*externFormat = kSecFormatPEMSequence;
}
else {
return false;
}
return true;
}
static bool itemTypeFromString(
const char *typeStr,
SecExternalItemType *itemType)
{
if(!strcmp("pub", typeStr)) {
*itemType = kSecItemTypePublicKey;
}
else if(!strcmp("priv", typeStr)) {
*itemType = kSecItemTypePrivateKey;
}
else if(!strcmp("session", typeStr)) {
*itemType = kSecItemTypeSessionKey;
}
else if(!strcmp("cert", typeStr)) {
*itemType = kSecItemTypeCertificate;
}
else if(!strcmp("agg", typeStr)) {
*itemType = kSecItemTypeAggregate;
}
else {
return false;
}
return true;
}
int main(int argc, char **argv)
{
if(argc < 2) {
usage(argv);
}
const char *inFileName = argv[1];
extern int optind;
extern char *optarg;
int arg;
optind = 2;
int ourRtn = 0;
SecAccessRef accessRef = NULL;
OSStatus ortn;
const char *keychainName = NULL;
CFStringRef passphrase = NULL;
bool interactive = false;
bool securePassphrase = false;
SecExternalFormat externFormat = kSecFormatUnknown;
SecExternalItemType itemType = kSecItemTypeUnknown;
bool doWrap = false;
bool allowClearExtract = false;
int expectNumCerts = -1; int expectNumKeys = -1;
int expectNumIds = -1;
bool processOutput = false;
bool displayItems = false;
SecExternalFormat expectFormat = kSecFormatUnknown; SecExternalItemType expectItemType = kSecItemTypeUnknown; bool quiet = false;
bool noACL = false;
char *alertTitle = NULL;
char *alertPrompt = NULL;
bool setAllowOnlyOne = false;
bool expectMultiKeysError = false;
CFMutableArrayRef trustedAppList = NULL;
bool loopPause = false;
bool signOnly = false;
bool verbose = false;
while ((arg = getopt(argc, argv, "k:iZz:wet:f:C:K:I:F:T:qnL:p:mMa:dlsv")) != -1) {
switch (arg) {
case 'k':
keychainName = optarg;
break;
case 'i':
interactive = true;
processOutput = true;
break;
case 'Z':
securePassphrase = true;
break;
case 'z':
passphrase = CFStringCreateWithCString(NULL, optarg,
kCFStringEncodingASCII);
break;
case 'w':
doWrap = true;
break;
case 'e':
allowClearExtract = true;
break;
case 't':
if(!itemTypeFromString(optarg, &itemType)) {
usage(argv);
}
break;
case 'T':
if(!itemTypeFromString(optarg, &expectItemType)) {
usage(argv);
}
break;
case 'f':
if(!formatFromString(optarg, &externFormat)) {
usage(argv);
}
break;
case 'F':
if(!formatFromString(optarg, &expectFormat)) {
usage(argv);
}
break;
case 'C':
expectNumCerts = atoi(optarg);
processOutput = true;
break;
case 'K':
expectNumKeys = atoi(optarg);
processOutput = true;
break;
case 'I':
expectNumIds = atoi(optarg);
processOutput = true;
break;
case 'd':
displayItems = true;
processOutput = true;
break;
case 'q':
quiet = true;
break;
case 'n':
noACL = true;
break;
case 'L':
alertTitle = optarg;
break;
case 'p':
alertPrompt = optarg;
break;
case 'm':
setAllowOnlyOne = true;
break;
case 'M':
setAllowOnlyOne = true;
expectMultiKeysError = true;
break;
case 'a':
{
if(trustedAppList == NULL) {
trustedAppList = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
}
SecTrustedApplicationRef appRef;
ortn = SecTrustedApplicationCreateFromPath(optarg, &appRef);
if(ortn) {
cssmPerror("SecTrustedApplicationCreateFromPath", ortn);
exit(1);
}
CFArrayAppendValue(trustedAppList, appRef);
break;
}
case 's':
signOnly = true;
break;
case 'l':
loopPause = true;
break;
case 'v':
verbose = true;
break;
default:
case '?':
usage(argv);
}
}
if(optind != argc) {
usage(argv);
}
if(doWrap) {
switch(externFormat) {
case kSecFormatOpenSSL:
case kSecFormatUnknown: externFormat = kSecFormatWrappedOpenSSL;
break;
case kSecFormatSSH:
externFormat = kSecFormatWrappedSSH;
break;
case kSecFormatSSHv2:
externFormat = kSecFormatWrappedOpenSSL;
break;
case kSecFormatWrappedPKCS8:
break;
default:
printf("Don't know how to wrap in specified format/type.\n");
exit(1);
}
}
CFArrayRef outArray = NULL;
CFArrayRef *outArrayP = NULL;
if(processOutput) {
outArrayP = &outArray;
}
SecKeychainRef kcRef = NULL;
if(keychainName) {
OSStatus ortn = SecKeychainOpen(keychainName, &kcRef);
if(ortn) {
cssmPerror("SecKeychainOpen", ortn);
exit(1);
}
CSSM_DL_DB_HANDLE dlDbHandle;
ortn = SecKeychainGetDLDBHandle(kcRef, &dlDbHandle);
if(ortn) {
cssmPerror("SecKeychainGetDLDBHandle", ortn);
exit(1);
}
}
unsigned char *inFile = NULL;
unsigned inFileLen = 0;
if(readFile(inFileName, &inFile, &inFileLen)) {
printf("***Error reading input file %s. Aborting.\n", inFileName);
exit(1);
}
CFDataRef inFileRef = CFDataCreate(NULL, inFile, inFileLen);
CFStringRef fileNameStr = CFStringCreateWithCString(NULL, inFileName,
kCFStringEncodingASCII);
loopTop:
SecKeyImportExportParameters keyParams;
SecKeyImportExportParameters *keyParamPtr = NULL;
if(passphrase || securePassphrase || allowClearExtract || noACL ||
setAllowOnlyOne || trustedAppList || signOnly) {
keyParamPtr = &keyParams;
memset(&keyParams, 0, sizeof(keyParams));
if(securePassphrase) {
keyParams.flags |= kSecKeySecurePassphrase;
if(alertTitle) {
keyParams.alertTitle =
CFStringCreateWithCString(NULL, alertTitle, kCFStringEncodingASCII);
}
if(alertPrompt) {
keyParams.alertPrompt =
CFStringCreateWithCString(NULL, alertPrompt, kCFStringEncodingASCII);
}
}
else if(passphrase) {
keyParams.passphrase = passphrase;
}
if(noACL) {
keyParams.flags |= kSecKeyNoAccessControl;
}
if(setAllowOnlyOne) {
keyParams.flags |= kSecKeyImportOnlyOne;
}
keyParams.keyAttributes = ( CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE);
if(!allowClearExtract) {
keyParams.keyAttributes |= CSSM_KEYATTR_SENSITIVE;
}
if(kcRef) {
keyParams.keyAttributes |= CSSM_KEYATTR_PERMANENT;
}
if(signOnly) {
keyParams.keyUsage = CSSM_KEYUSE_SIGN;
}
else {
keyParams.keyUsage = CSSM_KEYUSE_ANY;
}
if(trustedAppList) {
ortn = SecAccessCreate(CFSTR("Imported Private Key"), trustedAppList, &accessRef);
if(ortn) {
cssmPerror("SecAccessCreate", ortn);
exit(1);
}
keyParams.accessRef = accessRef;
}
}
ortn = SecKeychainItemImport(inFileRef,
fileNameStr,
&externFormat,
&itemType,
0, keyParamPtr,
kcRef,
outArrayP);
ourRtn = 0;
if(ortn) {
if(expectMultiKeysError && (ortn == errSecMultiplePrivKeys)) {
if(!quiet) {
printf("...errSecMultiplePrivKeys error seen as expected\n");
}
}
else {
cssmPerror("SecKeychainItemImport", ortn);
ourRtn = -1;
}
}
else if(expectMultiKeysError) {
printf("***errSecMultiplePrivKeys expected but no error seen\n");
ourRtn = -1;
}
if(ortn == noErr) {
if(!quiet) {
printf("...import successful. Returned format %s\n",
secExtFormatStr(externFormat));
}
if(expectFormat != kSecFormatUnknown) {
if(expectFormat != externFormat) {
printf("***Expected format %s, got %s\n",
secExtFormatStr(expectFormat),
secExtFormatStr(externFormat));
ourRtn = -1;
}
}
if(expectItemType != kSecItemTypeUnknown) {
if(expectItemType != itemType) {
printf("***Expected itemType %s, got %s\n",
secExtItemTypeStr(expectItemType),
secExtItemTypeStr(itemType));
ourRtn = -1;
}
}
if(processOutput) {
ourRtn |= processItems(kcRef, outArray, expectNumCerts,
expectNumKeys, expectNumIds, interactive, displayItems, verbose);
}
}
if(loopPause) {
fflush(stdin);
printf("Pausing for MallocDebug; CR to continue: ");
getchar();
goto loopTop;
}
return ourRtn;
}