+++ /dev/null
-/*
- * 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;
-}