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; }
static int do_keychain_import( SecKeychainRef kcRef, CFDataRef inData, SecExternalFormat externFormat, SecExternalItemType itemType, SecAccessRef access, Boolean nonExtractable, const char *passphrase, const char *fileName, char **attrNames, char **attrValues, unsigned numExtendedAttributes) { SecKeyImportExportParameters keyParams; OSStatus ortn; CFStringRef fileStr; CFArrayRef outArray = NULL; int result = 0; int numCerts = 0; int numKeys = 0; int numIdentities = 0; int tryCount = 0; CFIndex dex; CFIndex numItems = 0; CFStringRef passStr = NULL; CFStringRef promptStr = NULL; CFStringRef retryStr = NULL; /* * Specify some kind of passphrase in case caller doesn't know this * is a wrapped object */ memset(&keyParams, 0, sizeof(SecKeyImportExportParameters)); keyParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION; if(passphrase != NULL) { passStr = CFStringCreateWithCString(NULL, passphrase, kCFStringEncodingASCII); keyParams.passphrase = passStr; } else { keyParams.flags = kSecKeySecurePassphrase; } if(nonExtractable) { // explicitly set the key attributes, omitting the CSSM_KEYATTR_EXTRACTABLE bit keyParams.keyAttributes = CSSM_KEYATTR_PERMANENT | CSSM_KEYATTR_SENSITIVE; } keyParams.accessRef = access; fileStr = CFStringCreateWithCString(NULL, fileName, kCFStringEncodingUTF8); if (fileStr) { CFURLRef fileURL = CFURLCreateWithFileSystemPath(NULL, fileStr, kCFURLPOSIXPathStyle, FALSE); if (fileURL) { CFStringRef nameStr = CFURLCopyLastPathComponent(fileURL); if (nameStr) { safe_CFRelease(&fileStr); fileStr = nameStr; } safe_CFRelease(&fileURL); } } promptStr = CFStringCreateWithFormat(NULL, NULL, KC_IMPORT_KEY_PASSWORD_MESSAGE, fileStr); retryStr = CFStringCreateWithFormat(NULL, NULL, KC_IMPORT_KEY_PASSWORD_RETRYMESSAGE, fileStr); while (TRUE) { keyParams.alertPrompt = (tryCount == 0) ? promptStr : retryStr; ortn = SecKeychainItemImport(inData, fileStr, &externFormat, &itemType, 0, /* flags not used (yet) */ &keyParams, kcRef, &outArray); if(ortn) { if (ortn == errSecPkcs12VerifyFailure && ++tryCount < 3) { continue; } sec_perror("SecKeychainItemImport", ortn); result = 1; goto cleanup; } break; } /* * Parse returned items & report to user */ if(outArray == NULL) { sec_error("No keychain items found"); result = 1; goto cleanup; } numItems = CFArrayGetCount(outArray); for(dex=0; dex<numItems; dex++) { CFTypeRef item = CFArrayGetValueAtIndex(outArray, dex); CFTypeID itemType = CFGetTypeID(item); if(itemType == SecIdentityGetTypeID()) { numIdentities++; } else if(itemType == SecCertificateGetTypeID()) { numCerts++; } else if(itemType == SecKeyGetTypeID()) { numKeys++; } else { sec_error("Unexpected item type returned from SecKeychainItemImport"); result = 1; goto cleanup; } } if(numIdentities) { char *str; if(numIdentities > 1) { str = "identities"; } else { str = "identity"; } fprintf(stdout, "%d %s imported.\n", numIdentities, str); } if(numKeys) { char *str; if(numKeys > 1) { str = "keys"; } else { str = "key"; } fprintf(stdout, "%d %s imported.\n", numKeys, str); } if(numCerts) { char *str; if(numCerts > 1) { str = "certificates"; } else { str = "certificate"; } fprintf(stdout, "%d %s imported.\n", numCerts, str); } /* optionally apply extended attributes */ if(numExtendedAttributes) { unsigned attrDex; for(attrDex=0; attrDex<numExtendedAttributes; attrDex++) { CFStringRef attrNameStr = CFStringCreateWithCString(NULL, attrNames[attrDex], kCFStringEncodingASCII); CFDataRef attrValueData = CFDataCreate(NULL, (const UInt8 *)attrValues[attrDex], strlen(attrValues[attrDex])); for(dex=0; dex<numItems; dex++) { SecKeychainItemRef itemRef = (SecKeychainItemRef)CFArrayGetValueAtIndex(outArray, dex); ortn = SecKeychainItemSetExtendedAttribute(itemRef, attrNameStr, attrValueData); if(ortn) { cssmPerror("SecKeychainItemSetExtendedAttribute", ortn); result = 1; break; } } /* for each imported item */ CFRelease(attrNameStr); CFRelease(attrValueData); if(result) { break; } } /* for each extended attribute */ } cleanup: safe_CFRelease(&fileStr); safe_CFRelease(&outArray); safe_CFRelease(&passStr); safe_CFRelease(&promptStr); safe_CFRelease(&retryStr); return result; }
OSStatus SecCertificateRequestGetResult( SecCertificateRequestRef certRequestRef, SecKeychainRef keychain, sint32 *estimatedTime, SecCertificateRef *certificateRef) { BEGIN_SECAPI CssmData certData; *certificateRef = NULL; CertificateRequest::required(certRequestRef)->getResult(estimatedTime, certData); if(certData.data() != NULL) { /* * Convert to SecCertifcateRef, optionally import. */ CFDataRef cfCert = CFDataCreate(NULL, (UInt8 *)certData.data(), certData.Length); SecExternalItemType itemType = kSecItemTypeCertificate; CFArrayRef outItems = NULL; bool freeKcRef = false; OSStatus ortn; if(keychain == NULL) { /* * Unlike most Sec* calls, if the keychain argument to SecKeychainItemImport() * is NULL, the item is not imported to the default keychain. At our * interface, however, a NULL keychain means "import to the default * keychain". */ ortn = SecKeychainCopyDefault(&keychain); if(ortn) { certReqDbg("GetResult: SecKeychainCopyDefault failure"); /* oh well, there's nothing we can do about this */ } else { freeKcRef = true; } } ortn = SecKeychainItemImport(cfCert, NULL, NULL, // format, don't care &itemType, 0, // flags NULL, // keyParams keychain, // optional, like ours &outItems); CFRelease(cfCert); if(freeKcRef) { CFRelease(keychain); } if(ortn) { certReqDbg("SecCertificateRequestGetResult: SecKeychainItemImport failure"); MacOSError::throwMe(ortn); } CFIndex numItems = CFArrayGetCount(outItems); switch(numItems) { case 0: certReqDbg("SecCertificateRequestGetResult: import zero items"); MacOSError::throwMe(errSecInternalComponent); default: certReqDbg("SecCertificateRequestGetResult: import %d items", (int)numItems); /* but drop thru anyway, take the first one */ case 1: SecCertificateRef certRef = (SecCertificateRef)(CFArrayGetValueAtIndex(outItems, 0)); if(CFGetTypeID(certRef) != SecCertificateGetTypeID()) { certReqDbg("SecCertificateRequestGetResult: bad type"); } else { CFRetain(certRef); *certificateRef = certRef; } } CFRelease(outItems); } END_SECAPI }