--- /dev/null
+/*
+ * genKeyPair.cpp - create a key pair, store in specified keychain
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include <string.h>
+#include <unistd.h>
+#include <Security/Security.h>
+#include "cspwrap.h"
+#include "common.h"
+
+static void usage(char **argv)
+{
+ printf("usage: %s keychain [options]\n", argv[0]);
+ printf("Options:\n");
+ printf(" -l label -- no default\n");
+ printf(" -a r|f|d -- algorithm RSA/FEE/DSA, default = RSA\n");
+ printf(" -k bits -- key size in bits, default is 1024/128/512 for RSA/FEE/DSA\n");
+ exit(1);
+}
+
+/*
+ * Generate key pair of arbitrary algorithm.
+ * FEE keys will have random private data.
+ * Like the cspGenKeyPair() in cspwrap.c except this provides a DLDB handle.
+ */
+static CSSM_RETURN genKeyPair(CSSM_CSP_HANDLE cspHand,
+ CSSM_DL_DB_HANDLE dlDbHand,
+ uint32 algorithm,
+ const char *keyLabel,
+ unsigned keyLabelLen,
+ uint32 keySize, // in bits
+ CSSM_KEY_PTR pubKey, // mallocd by caller
+ uint32 pubKeyUsage, // CSSM_KEYUSE_ENCRYPT, etc.
+ CSSM_KEY_PTR privKey, // mallocd by caller
+ uint32 privKeyUsage) // CSSM_KEYUSE_DECRYPT, etc.
+{
+ CSSM_RETURN crtn;
+ CSSM_CC_HANDLE ccHand;
+ CSSM_DATA keyLabelData;
+ uint32 pubAttr;
+ uint32 privAttr;
+ CSSM_RETURN ocrtn = CSSM_OK;
+
+ /* pre-context-create algorithm-specific stuff */
+ switch(algorithm) {
+ case CSSM_ALGID_FEE:
+ if(keySize == CSP_KEY_SIZE_DEFAULT) {
+ keySize = CSP_FEE_KEY_SIZE_DEFAULT;
+ }
+ break;
+ case CSSM_ALGID_RSA:
+ if(keySize == CSP_KEY_SIZE_DEFAULT) {
+ keySize = CSP_RSA_KEY_SIZE_DEFAULT;
+ }
+ break;
+ case CSSM_ALGID_DSA:
+ if(keySize == CSP_KEY_SIZE_DEFAULT) {
+ keySize = CSP_DSA_KEY_SIZE_DEFAULT;
+ }
+ break;
+ default:
+ printf("cspGenKeyPair: Unknown algorithm\n");
+ break;
+ }
+ keyLabelData.Data = (uint8 *)keyLabel,
+ keyLabelData.Length = keyLabelLen;
+ memset(pubKey, 0, sizeof(CSSM_KEY));
+ memset(privKey, 0, sizeof(CSSM_KEY));
+
+ crtn = CSSM_CSP_CreateKeyGenContext(cspHand,
+ algorithm,
+ keySize,
+ NULL, // Seed
+ NULL, // Salt
+ NULL, // StartDate
+ NULL, // EndDate
+ NULL, // Params
+ &ccHand);
+ if(crtn) {
+ printError("CSSM_CSP_CreateKeyGenContext", crtn);
+ ocrtn = crtn;
+ goto abort;
+ }
+ /* cook up attribute bits */
+ pubAttr = CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_PERMANENT;
+ privAttr = CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_PERMANENT;
+
+ /* post-context-create algorithm-specific stuff */
+ switch(algorithm) {
+ case CSSM_ALGID_DSA:
+ /*
+ * extra step - generate params - this just adds some
+ * info to the context
+ */
+ {
+ CSSM_DATA dummy = {0, NULL};
+ crtn = CSSM_GenerateAlgorithmParams(ccHand,
+ keySize, &dummy);
+ if(crtn) {
+ printError("CSSM_GenerateAlgorithmParams", crtn);
+ return crtn;
+ }
+ appFreeCssmData(&dummy, CSSM_FALSE);
+ }
+ break;
+ default:
+ break;
+ }
+
+ /* add in DL/DB to context */
+ crtn = cspAddDlDbToContext(ccHand, dlDbHand.DLHandle, dlDbHand.DBHandle);
+ if(crtn) {
+ ocrtn = crtn;
+ goto abort;
+ }
+
+ crtn = CSSM_GenerateKeyPair(ccHand,
+ pubKeyUsage,
+ pubAttr,
+ &keyLabelData,
+ pubKey,
+ privKeyUsage,
+ privAttr,
+ &keyLabelData, // same labels
+ NULL, // CredAndAclEntry
+ privKey);
+ if(crtn) {
+ printError("CSSM_GenerateKeyPair", crtn);
+ ocrtn = crtn;
+ goto abort;
+ }
+abort:
+ if(ccHand != 0) {
+ crtn = CSSM_DeleteContext(ccHand);
+ if(crtn) {
+ printError("CSSM_DeleteContext", crtn);
+ ocrtn = CSSM_ERRCODE_INTERNAL_ERROR;
+ }
+ }
+ return ocrtn;
+}
+
+int main(int argc, char **argv)
+{
+ char *kcName = NULL;
+ char *label = NULL;
+ CSSM_ALGORITHMS keyAlg = CSSM_ALGID_RSA;
+ unsigned keySizeInBits = CSP_KEY_SIZE_DEFAULT;
+
+ if(argc < 2) {
+ usage(argv);
+ }
+ kcName = argv[1];
+
+ extern char *optarg;
+ extern int optind;
+
+ optind = 2;
+ int arg;
+ while ((arg = getopt(argc, argv, "l:a:k:h")) != -1) {
+ switch (arg) {
+ case 'l':
+ label = optarg;
+ break;
+ case 'a':
+ switch(optarg[0]) {
+ case 'r':
+ keyAlg = CSSM_ALGID_RSA;
+ break;
+ case 'f':
+ keyAlg = CSSM_ALGID_FEE;
+ break;
+ case 'd':
+ keyAlg = CSSM_ALGID_DSA;
+ break;
+ default:
+ usage(argv);
+ }
+ break;
+ case 'k':
+ keySizeInBits = atoi(optarg);
+ break;
+ default:
+ usage(argv);
+ }
+ }
+ if(optind != argc) {
+ usage(argv);
+ }
+
+ SecKeychainRef kcRef = nil;
+ OSStatus ortn;
+
+ ortn = SecKeychainOpen(kcName, &kcRef);
+ if(ortn) {
+ cssmPerror("SecKeychainOpen", ortn);
+ exit(1);
+ }
+
+ CSSM_CSP_HANDLE cspHand = 0;
+ CSSM_DL_DB_HANDLE dlDbHand = {0, 0};
+ ortn = SecKeychainGetCSPHandle(kcRef, &cspHand);
+ if(ortn) {
+ cssmPerror("SecKeychainGetCSPHandle", ortn);
+ exit(1);
+ }
+ ortn = SecKeychainGetDLDBHandle(kcRef, &dlDbHand);
+ if(ortn) {
+ cssmPerror("SecKeychainGetDLDBHandle", ortn);
+ exit(1);
+ }
+
+ CSSM_KEY privKey;
+ CSSM_KEY pubKey;
+ CSSM_RETURN crtn;
+
+ crtn = genKeyPair(cspHand, dlDbHand,
+ keyAlg,
+ label, (label ? strlen(label) : 0),
+ keySizeInBits,
+ &pubKey,
+ CSSM_KEYUSE_ANY, // may want to parameterize
+ &privKey,
+ CSSM_KEYUSE_ANY); // may want to parameterize
+ if(crtn) {
+ printf("**Error creating key pair.\n");
+ }
+ else {
+ printf("...key pair created in keychain %s.\n", kcName);
+ }
+
+ cspFreeKey(cspHand, &privKey);
+ cspFreeKey(cspHand, &pubKey);
+ CFRelease(kcRef);
+ return 0;
+}