]> git.saurik.com Git - apple/security.git/blobdiff - SecurityTests/cspxutils/clearPubKeyTest/clearPubKeyTest.cpp
Security-57031.1.35.tar.gz
[apple/security.git] / SecurityTests / cspxutils / clearPubKeyTest / clearPubKeyTest.cpp
diff --git a/SecurityTests/cspxutils/clearPubKeyTest/clearPubKeyTest.cpp b/SecurityTests/cspxutils/clearPubKeyTest/clearPubKeyTest.cpp
new file mode 100644 (file)
index 0000000..81c73e4
--- /dev/null
@@ -0,0 +1,395 @@
+/*
+ * clearPubKeyTest.cpp
+ *
+ * Test CSSM_KEYATTR_PUBLIC_KEY_ENCRYPT. This cannot be run on a handsoff environment; 
+ * it forces Keychain unlock dialogs. 
+ */
+#include <stdlib.h>
+#include <strings.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <Security/Security.h>
+#include "cspwrap.h"
+#include "common.h"
+
+#define KEYCHAIN_NAME  "/tmp/clearPubKey.keychain"
+#define KEYCHAIN_PWD   "pwd"
+#define KEY_ALG                        CSSM_ALGID_RSA
+#define KEYSIZE                        1024
+#define ENCRALG                        CSSM_ALGID_RSA
+
+static void usage(char **argv)
+{
+       printf("usage: %s -v(erbose)\n", argv[0]);
+       exit(1);
+}
+
+static void printNoDialog()
+{
+       printf("*** If you get a keychain unlock dialog here the test is failing ***\n");
+}
+
+static void printExpectDialog()
+{
+       printf("*** You MUST get a keychain unlock dialog here (password = '%s') ***\n",
+               KEYCHAIN_PWD);
+}
+
+static bool didGetDialog()
+{
+       fpurge(stdin);
+       printf("Enter 'y' if you just got a keychain unlock dialog: ");
+       if(getchar() == 'y') {
+               return 1;
+       }
+       printf("***Well, you really should have. Test failed.\n");
+       return 0;
+}
+
+static void verboseDisp(bool verbose, const char *str)
+{
+       if(verbose) {
+               printf("...%s\n", str);
+       }
+}
+
+/* generate key pair, optionally storing the public key in encrypted form */
+static int genKeyPair(
+       bool pubKeyIsEncrypted,
+       SecKeychainRef kcRef,
+       SecKeyRef *pubKeyRef,
+       SecKeyRef *privKeyRef)
+{
+       /* gather keygen args */
+       CSSM_ALGORITHMS keyAlg = KEY_ALG;
+       uint32 keySizeInBits = KEYSIZE;
+       CSSM_KEYUSE pubKeyUsage = CSSM_KEYUSE_ANY;
+       uint32 pubKeyAttr = CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_PERMANENT;
+       if(pubKeyIsEncrypted) {
+               pubKeyAttr |= CSSM_KEYATTR_PUBLIC_KEY_ENCRYPT;
+       }
+       CSSM_KEYUSE privKeyUsage = CSSM_KEYUSE_ANY;
+       uint32 privKeyAttr = CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE |
+                                                CSSM_KEYATTR_PERMANENT | CSSM_KEYATTR_SENSITIVE;
+       
+       OSStatus ortn = SecKeyCreatePair(kcRef, keyAlg, keySizeInBits, 0,
+               pubKeyUsage, pubKeyAttr,
+               privKeyUsage, privKeyAttr,
+               NULL,           // default initial access for now 
+               pubKeyRef, privKeyRef);
+       if(ortn) {
+               cssmPerror("SecKeyCreatePair", ortn);
+               return 1;
+       }
+       return 0;
+}
+
+/* encrypt something with a public key */
+static int pubKeyEncrypt(
+       SecKeyRef pubKeyRef)
+{
+       const CSSM_KEY *cssmKey;
+       OSStatus ortn;
+       CSSM_CSP_HANDLE cspHand;
+       
+       ortn = SecKeyGetCSSMKey(pubKeyRef, &cssmKey);
+       if(ortn) {
+               cssmPerror("SecKeyGetCSSMKey", ortn);
+               return -1;
+       }
+       ortn = SecKeyGetCSPHandle(pubKeyRef, &cspHand);
+       if(ortn) {
+               cssmPerror("SecKeyGetCSPHandle", ortn);
+               return -1;
+       }
+       
+       char *ptext = "something to encrypt";
+       CSSM_DATA ptextData = {strlen(ptext), (uint8 *)ptext};
+       CSSM_DATA ctextData = { 0, NULL };
+       CSSM_RETURN crtn;
+       
+       crtn = cspEncrypt(cspHand, CSSM_ALGID_RSA,
+               0, CSSM_PADDING_PKCS1,  // mode/pad
+               cssmKey, NULL,
+               0, 0,   // effect/rounds
+               NULL,   // IV
+               &ptextData, &ctextData, CSSM_FALSE);
+       if(crtn) {
+               return -1;
+       }
+       /* slighyly hazardous, allocated by CSPDL's allocator */
+       free(ctextData.Data);
+       return 0;
+}
+
+int main(int argc, char **argv)
+{
+       bool verbose = false;
+       
+       int arg;
+       while ((arg = getopt(argc, argv, "vh")) != -1) {
+               switch (arg) {
+                       case 'v':
+                               verbose = true;
+                               break;
+                       case 'h':
+                               usage(argv);
+               }
+       }
+       if(optind != argc) {
+               usage(argv);
+       }
+       
+       printNoDialog();
+       
+       /* initial setup */
+       verboseDisp(verbose, "deleting keychain");
+       unlink(KEYCHAIN_NAME);
+       
+       verboseDisp(verbose, "creating keychain");
+       SecKeychainRef kcRef = NULL;
+       OSStatus ortn = SecKeychainCreate(KEYCHAIN_NAME, 
+               strlen(KEYCHAIN_PWD), KEYCHAIN_PWD,
+               false, NULL, &kcRef);
+       if(ortn) {
+               cssmPerror("SecKeychainCreate", ortn);
+               exit(1);
+       }
+
+       /* 
+        * 1. Generate key pair with cleartext public key.
+        *    Ensure we can use the public key when keychain is locked with no
+        *    user interaction.  
+        */
+        
+       /* generate key pair, cleartext public key */
+       verboseDisp(verbose, "creating key pair, cleartext public key");
+       SecKeyRef pubKeyRef = NULL;
+       SecKeyRef privKeyRef = NULL;
+       if(genKeyPair(false, kcRef, &pubKeyRef, &privKeyRef)) {
+               exit(1);
+       }
+       
+       /* Use generated cleartext public key with locked keychain */
+       verboseDisp(verbose, "locking keychain, exporting public key");
+       SecKeychainLock(kcRef);
+       CFDataRef exportData = NULL;
+       ortn = SecKeychainItemExport(pubKeyRef, kSecFormatOpenSSL, 0, NULL, &exportData);
+       if(ortn) {
+               cssmPerror("SecKeychainCreate", ortn);
+               exit(1);
+       }
+       CFRelease(exportData);
+       
+       verboseDisp(verbose, "locking keychain, encrypting with public key");
+       SecKeychainLock(kcRef);
+       if(pubKeyEncrypt(pubKeyRef)) {
+               exit(1);
+       }
+
+       /* reset */
+       verboseDisp(verbose, "deleting keys");
+       ortn = SecKeychainItemDelete((SecKeychainItemRef)pubKeyRef);
+       if(ortn) {
+               cssmPerror("SecKeychainItemDelete", ortn);
+               exit(1);
+       }
+       ortn = SecKeychainItemDelete((SecKeychainItemRef)privKeyRef);
+       if(ortn) {
+               cssmPerror("SecKeychainItemDelete", ortn);
+               exit(1);
+       }
+       CFRelease(pubKeyRef);
+       CFRelease(privKeyRef);
+
+       /* 
+        * 2. Generate key pair with encrypted public key.
+        *    Ensure that user interaction is required when we use the public key 
+        *    when keychain is locked.
+        */
+
+       verboseDisp(verbose, "programmatically unlocking keychain");
+       ortn = SecKeychainUnlock(kcRef, strlen(KEYCHAIN_PWD), KEYCHAIN_PWD, TRUE);
+       if(ortn) {
+               cssmPerror("SecKeychainItemDelete", ortn);
+               exit(1);
+       }
+       
+       /* generate key pair, encrypted public key */
+       verboseDisp(verbose, "creating key pair, encrypted public key");
+       if(genKeyPair(true, kcRef, &pubKeyRef, &privKeyRef)) {
+               exit(1);
+       }
+
+       /* Use generated encrypted public key with locked keychain */
+       verboseDisp(verbose, "locking keychain, exporting public key");
+       SecKeychainLock(kcRef);
+       printExpectDialog();
+       ortn = SecKeychainItemExport(pubKeyRef, kSecFormatOpenSSL, 0, NULL, &exportData);
+       if(ortn) {
+               cssmPerror("SecKeychainCreate", ortn);
+               exit(1);
+       }
+       /* we'll use that exported blob later to test import */
+       if(!didGetDialog()) {
+               exit(1);
+       }
+       
+       verboseDisp(verbose, "locking keychain, encrypting with public key");
+       SecKeychainLock(kcRef);
+       printExpectDialog();
+       if(pubKeyEncrypt(pubKeyRef)) {
+               exit(1);
+       }
+       if(!didGetDialog()) {
+               exit(1);
+       }
+
+       /* reset */
+       printNoDialog();
+       verboseDisp(verbose, "locking keychain");
+       SecKeychainLock(kcRef);
+       verboseDisp(verbose, "deleting keys");
+       ortn = SecKeychainItemDelete((SecKeychainItemRef)pubKeyRef);
+       if(ortn) {
+               cssmPerror("SecKeychainItemDelete", ortn);
+               exit(1);
+       }
+       ortn = SecKeychainItemDelete((SecKeychainItemRef)privKeyRef);
+       if(ortn) {
+               cssmPerror("SecKeychainItemDelete", ortn);
+               exit(1);
+       }
+       CFRelease(pubKeyRef);
+       CFRelease(privKeyRef);
+
+       /* 
+        * 3. Import public key, storing in cleartext. Ensure that the import
+        *    doesn't require unlock, and ensure we can use the public key 
+        *    when keychain is locked with no user interaction.  
+        */
+
+       printNoDialog();
+       verboseDisp(verbose, "locking keychain");
+       SecKeychainLock(kcRef);
+
+       /* import public key - default is in the clear */
+       verboseDisp(verbose, "importing public key, store in the clear (default)");
+       CFArrayRef outArray = NULL;
+       SecExternalFormat format = kSecFormatOpenSSL;
+       SecExternalItemType type = kSecItemTypePublicKey;
+       ortn = SecKeychainItemImport(exportData, 
+               NULL, &format, &type,
+               0, NULL,
+               kcRef, &outArray);
+       if(ortn) {
+               cssmPerror("SecKeychainItemImport", ortn);
+               exit(1);
+       }
+       CFRelease(exportData);
+       if(CFArrayGetCount(outArray) != 1) {
+               printf("***Unexpected outArray size (%ld) after import\n",
+                       (long)CFArrayGetCount(outArray));
+               exit(1);
+       }
+       pubKeyRef = (SecKeyRef)CFArrayGetValueAtIndex(outArray, 0);
+       if(CFGetTypeID(pubKeyRef) != SecKeyGetTypeID()) {
+               printf("***Unexpected item type after import\n");
+               exit(1);
+       }
+       
+       /* Use imported cleartext public key with locked keychain */
+       verboseDisp(verbose, "locking keychain, exporting public key");
+       SecKeychainLock(kcRef);
+       exportData = NULL;
+       ortn = SecKeychainItemExport(pubKeyRef, kSecFormatOpenSSL, 0, NULL, &exportData);
+       if(ortn) {
+               cssmPerror("SecKeychainItemExport", ortn);
+               exit(1);
+       }
+       /* we'll use exportData again */
+       
+       verboseDisp(verbose, "locking keychain, encrypting with public key");
+       SecKeychainLock(kcRef);
+       if(pubKeyEncrypt(pubKeyRef)) {
+               exit(1);
+       }
+
+       /* reset */
+       verboseDisp(verbose, "deleting key");
+       ortn = SecKeychainItemDelete((SecKeychainItemRef)pubKeyRef);
+       if(ortn) {
+               cssmPerror("SecKeychainItemDelete", ortn);
+               exit(1);
+       }
+       CFRelease(pubKeyRef);
+       
+       /* 
+        * Import public key, storing in encrypted form.
+        * Ensure that user interaction is required when we use the public key 
+        * when keychain is locked.
+        */
+
+       /* import public key, encrypted in the keychain */
+       SecKeyImportExportParameters impExpParams;
+       memset(&impExpParams, 0, sizeof(impExpParams));
+       impExpParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
+       impExpParams.keyAttributes = CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE | 
+                                                                CSSM_KEYATTR_PERMANENT | CSSM_KEYATTR_PUBLIC_KEY_ENCRYPT;
+       verboseDisp(verbose, "importing public key, store encrypted");
+       printExpectDialog();
+       outArray = NULL;
+       format = kSecFormatOpenSSL;
+       type = kSecItemTypePublicKey;
+       ortn = SecKeychainItemImport(exportData, 
+               NULL, &format, &type,
+               0, &impExpParams,
+               kcRef, &outArray);
+       if(ortn) {
+               cssmPerror("SecKeychainItemImport", ortn);
+               exit(1);
+       }
+       if(!didGetDialog()) {
+               exit(1);
+       }
+       CFRelease(exportData);
+       if(CFArrayGetCount(outArray) != 1) {
+               printf("***Unexpected outArray size (%ld) after import\n",
+                       (long)CFArrayGetCount(outArray));
+               exit(1);
+       }
+       pubKeyRef = (SecKeyRef)CFArrayGetValueAtIndex(outArray, 0);
+       if(CFGetTypeID(pubKeyRef) != SecKeyGetTypeID()) {
+               printf("***Unexpected item type after import\n");
+               exit(1);
+       }
+                                       
+       /* Use imported encrypted public key with locked keychain */
+       verboseDisp(verbose, "locking keychain, exporting public key");
+       SecKeychainLock(kcRef);
+       printExpectDialog();
+       ortn = SecKeychainItemExport(pubKeyRef, kSecFormatOpenSSL, 0, NULL, &exportData);
+       if(ortn) {
+               cssmPerror("SecKeychainItemExport", ortn);
+               exit(1);
+       }
+       if(!didGetDialog()) {
+               exit(1);
+       }
+       CFRelease(exportData);
+       
+       verboseDisp(verbose, "locking keychain, encrypting with public key");
+       SecKeychainLock(kcRef);
+       printExpectDialog();
+       if(pubKeyEncrypt(pubKeyRef)) {
+               exit(1);
+       }
+       if(!didGetDialog()) {
+               exit(1);
+       }
+
+       SecKeychainDelete(kcRef);
+       printf("...test succeeded.\n");
+       return 0;
+}