]> git.saurik.com Git - apple/security.git/blobdiff - SecurityTests/clxutils/p12/p12ImportExport.cpp
Security-57031.1.35.tar.gz
[apple/security.git] / SecurityTests / clxutils / p12 / p12ImportExport.cpp
diff --git a/SecurityTests/clxutils/p12/p12ImportExport.cpp b/SecurityTests/clxutils/p12/p12ImportExport.cpp
new file mode 100644 (file)
index 0000000..13c52af
--- /dev/null
@@ -0,0 +1,472 @@
+/*
+ * p12ImportExport.cpp - high-level libnsspkcs12 exerciser
+ */
+#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);
+       }
+}
+
+/*
+ * For now we assume "import everything"
+ */
+int p12Import(
+       const char *pfxFile,
+       const char *kcName,
+       CFStringRef pwd,                        // explicit passphrase, mutually exclusive with...
+       bool usePassKey,                        // use SECURE_PASSPHRASE key
+       const char *kcPwd)                      // optional
+{
+       OSStatus                ortn;
+       unsigned char   *pfx;
+       unsigned                pfxLen;
+       CSSM_KEY                passKey;
+       
+       /* get the PFX */
+       if(readFile(pfxFile, &pfx, &pfxLen)) {
+               printf("***Error reading pfx from %s. Aborting.\n", pfxFile);
+               return 1;
+       }
+       CFDataRef cfd = CFDataCreate(NULL, pfx, pfxLen);
+       
+       /* import to keychain specified by kcName */
+       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);
+               }
+       }
+
+       /* set up a pkcs12 coder for import */
+       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;
+               }
+       }
+       
+       /*
+        * For now we assume "import everything"
+        */
+       ortn = SecPkcs12SetImportToKeychain(coder,
+               kSecImportCertificates | 
+               kSecImportCRLs |
+               kSecImportKeys);
+       if(ortn) {
+               printOsError("SecPkcs12SetImportFromKeychain", ortn);
+               return ortn;
+       }
+       
+       /* Go! */
+       ortn = SecPkcs12Decode(coder, cfd);
+       if(ortn) {
+               printOsError("SecPkcs12Decode", ortn);
+               return ortn;
+       }
+       
+       /* report how many of each item got imported */
+       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);                      // mallocd by readFile()
+       return 0;
+}
+
+/* 
+ * Use the kludge from hell to get the name-as-int form of a specified
+ * "known" name-as-string for the Key Schema.
+ */
+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;
+       
+       /* the printable name attr */
+       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) {
+                       /* out of sync with Sec layer? With KeySchema? */
+                       printf("warning: attrNameToInt failure\n");
+                       return 0;
+               }
+       }
+       else {
+               /* we don't know how to deal with this */
+               printf("p12AddExportedItem: internal screwup\n");
+               return 0;
+       }
+       
+       /* get the printable name attr */
+       SecKeychainAttributeInfo attrInfo;
+       attrInfo.count = 1;
+       attrInfo.tag = &nameAttr;
+       attrInfo.format = NULL; // ???
+       
+       /* FIXME header says this is an IN/OUT param, but it's not */
+       SecKeychainAttributeList *attrList = NULL;
+       
+       ortn = SecKeychainItemCopyAttributesAndData(
+               item, 
+               &attrInfo,
+               NULL,                   // itemClass
+               &attrList, 
+               NULL,                   // don't need the data
+               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;
+       
+       /* it's a UTF8 string: use CFString to convert to C ASCII string */
+       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())) {
+               /* the alias attr, for cert email */
+               CFStringRef aliasCFStr = NULL;
+               nameAttr = kSecAlias;
+               attrInfo.count = 1;
+               attrInfo.tag = &nameAttr;
+               attrInfo.format = NULL; // ???
+               attrList = NULL;
+               
+               ortn = SecKeychainItemCopyAttributesAndData(
+                       item, 
+                       &attrInfo,
+                       NULL,                   // itemClass
+                       &attrList, 
+                       NULL,                   // don't need the data
+                       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;
+               
+               /* it's a UTF8 string: use CFString to convert to C ASCII string */
+               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,                        // explicit passphrase, mutually exclusive with...
+       bool usePassKey,                        // use SECURE_PASSPHRASE key
+       const char *kcPwd,                      // optional
+       bool noPrompt)                          // true --> export all 
+{
+       OSStatus ortn;
+       CSSM_KEY                passKey;
+
+       /* set up a pkcs12 coder for export */
+       SecPkcs12CoderRef coder;
+       ortn = SecPkcs12CoderCreate(&coder);
+       if(ortn) {
+               printOsError("SecPkcs12CoderCreate", ortn);
+               return ortn;
+       }
+
+       /* 
+       Ê* Since we're not providing the SecPkcs12CoderRef with a
+        * keychain, we have to provide the CSPDL handle 
+        */
+       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;
+       }
+       
+       /* the array of things we want to export */
+       CFMutableArrayRef items = CFArrayCreateMutable(NULL, 0, NULL);
+       
+       /* export from keychain specified by kcName */
+       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);
+               }
+       }
+
+       /* 
+        * Prompt user for each known item - it would be nice if we 
+        * could search for anything, eh? 
+        * Certs first...
+        */
+       SecKeychainSearchRef srchRef;
+       ortn = SecKeychainSearchCreateFromAttributes(kcRef,
+               kSecCertificateItemClass,
+               NULL,           // no attrs
+               &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);
+
+       /* now private keys */
+       ortn = SecKeychainSearchCreateFromAttributes(kcRef,
+               CSSM_DL_DB_RECORD_PRIVATE_KEY,  // undocumented
+               NULL,                                                   // no attrs
+               &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;
+       }
+       
+       /* go */
+       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);
+               
+       /* cleanup */
+       SecPkcs12CoderRelease(coder);
+       CFRelease(pfx);
+       CFRelease(srchRef);
+       CFRelease(kcRef);
+       return 0;
+}