1/*
2 * genKeyPair.cpp - create a key pair, store in specified keychain
3 */
4#include <stdlib.h>
5#include <stdio.h>
6#include <time.h>
7#include <string.h>
8#include <unistd.h>
9#include <Security/Security.h>
10#include "cspwrap.h"
11#include "common.h"
12
13static void usage(char **argv)
14{
15	printf("usage: %s keychain [options]\n", argv[0]);
16	printf("Options:\n");
17	printf("   -l label         -- no default\n");
18	printf("   -a r|f|d         -- algorithm RSA/FEE/DSA, default = RSA\n");
19	printf("   -k bits          -- key size in bits, default is 1024/128/512 for RSA/FEE/DSA\n");
20	exit(1);
21}
22
23/*
24 * Generate key pair of arbitrary algorithm.
25 * FEE keys will have random private data.
26 * Like the cspGenKeyPair() in cspwrap.c except this provides a DLDB handle.
27 */
28static CSSM_RETURN genKeyPair(CSSM_CSP_HANDLE cspHand,
29	CSSM_DL_DB_HANDLE dlDbHand,
30	uint32 algorithm,
31	const char *keyLabel,
32	unsigned keyLabelLen,
33	uint32 keySize,					// in bits
34	CSSM_KEY_PTR pubKey,			// mallocd by caller
35	uint32 pubKeyUsage,				// CSSM_KEYUSE_ENCRYPT, etc.
36	CSSM_KEY_PTR privKey,			// mallocd by caller
37	uint32 privKeyUsage)			// CSSM_KEYUSE_DECRYPT, etc.
38{
39	CSSM_RETURN				crtn;
40	CSSM_CC_HANDLE 			ccHand;
41	CSSM_DATA				keyLabelData;
42	uint32					pubAttr;
43	uint32					privAttr;
44	CSSM_RETURN 			ocrtn = CSSM_OK;
45
46	/* pre-context-create algorithm-specific stuff */
47	switch(algorithm) {
48		case CSSM_ALGID_FEE:
49			if(keySize == CSP_KEY_SIZE_DEFAULT) {
50				keySize = CSP_FEE_KEY_SIZE_DEFAULT;
51			}
52			break;
53		case CSSM_ALGID_RSA:
54			if(keySize == CSP_KEY_SIZE_DEFAULT) {
55				keySize = CSP_RSA_KEY_SIZE_DEFAULT;
56			}
57			break;
58		case CSSM_ALGID_DSA:
59			if(keySize == CSP_KEY_SIZE_DEFAULT) {
60				keySize = CSP_DSA_KEY_SIZE_DEFAULT;
61			}
62			break;
63		default:
64			printf("cspGenKeyPair: Unknown algorithm\n");
65			break;
66	}
67	keyLabelData.Data        = (uint8 *)keyLabel,
68	keyLabelData.Length      = keyLabelLen;
69	memset(pubKey, 0, sizeof(CSSM_KEY));
70	memset(privKey, 0, sizeof(CSSM_KEY));
71
72	crtn = CSSM_CSP_CreateKeyGenContext(cspHand,
73		algorithm,
74		keySize,
75		NULL,					// Seed
76		NULL,					// Salt
77		NULL,					// StartDate
78		NULL,					// EndDate
79		NULL,					// Params
80		&ccHand);
81	if(crtn) {
82		printError("CSSM_CSP_CreateKeyGenContext", crtn);
83		ocrtn = crtn;
84		goto abort;
85	}
86	/* cook up attribute bits */
87	pubAttr = CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_PERMANENT;
88	privAttr = CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_PERMANENT;
89
90	/* post-context-create algorithm-specific stuff */
91	switch(algorithm) {
92		 case CSSM_ALGID_DSA:
93			/*
94			 * extra step - generate params - this just adds some
95			 * info to the context
96			 */
97			{
98				CSSM_DATA dummy = {0, NULL};
99				crtn = CSSM_GenerateAlgorithmParams(ccHand,
100					keySize, &dummy);
101				if(crtn) {
102					printError("CSSM_GenerateAlgorithmParams", crtn);
103					return crtn;
104				}
105				appFreeCssmData(&dummy, CSSM_FALSE);
106			}
107			break;
108		default:
109			break;
110	}
111
112	/* add in DL/DB to context */
113	crtn = cspAddDlDbToContext(ccHand, dlDbHand.DLHandle, dlDbHand.DBHandle);
114	if(crtn) {
115		ocrtn = crtn;
116		goto abort;
117	}
118
119	crtn = CSSM_GenerateKeyPair(ccHand,
120		pubKeyUsage,
121		pubAttr,
122		&keyLabelData,
123		pubKey,
124		privKeyUsage,
125		privAttr,
126		&keyLabelData,			// same labels
127		NULL,					// CredAndAclEntry
128		privKey);
129	if(crtn) {
130		printError("CSSM_GenerateKeyPair", crtn);
131		ocrtn = crtn;
132		goto abort;
133	}
134abort:
135	if(ccHand != 0) {
136		crtn = CSSM_DeleteContext(ccHand);
137		if(crtn) {
138			printError("CSSM_DeleteContext", crtn);
139			ocrtn = CSSM_ERRCODE_INTERNAL_ERROR;
140		}
141	}
142	return ocrtn;
143}
144
145int main(int argc, char **argv)
146{
147	char *kcName = NULL;
148	char *label = NULL;
149	CSSM_ALGORITHMS keyAlg = CSSM_ALGID_RSA;
150	unsigned keySizeInBits = CSP_KEY_SIZE_DEFAULT;
151
152	if(argc < 2) {
153		usage(argv);
154	}
155	kcName = argv[1];
156
157	extern char *optarg;
158	extern int optind;
159
160	optind = 2;
161	int arg;
162	while ((arg = getopt(argc, argv, "l:a:k:h")) != -1) {
163		switch (arg) {
164			case 'l':
165				label = optarg;
166				break;
167			case 'a':
168				switch(optarg[0]) {
169					case 'r':
170						keyAlg = CSSM_ALGID_RSA;
171						break;
172					case 'f':
173						keyAlg = CSSM_ALGID_FEE;
174						break;
175					case 'd':
176						keyAlg = CSSM_ALGID_DSA;
177						break;
178					default:
179						usage(argv);
180				}
181				break;
182			case 'k':
183				keySizeInBits = atoi(optarg);
184				break;
185			default:
186				usage(argv);
187		}
188	}
189	if(optind != argc) {
190		usage(argv);
191	}
192
193	SecKeychainRef kcRef = nil;
194	OSStatus ortn;
195
196	ortn = SecKeychainOpen(kcName, &kcRef);
197	if(ortn) {
198		cssmPerror("SecKeychainOpen", ortn);
199		exit(1);
200	}
201
202	CSSM_CSP_HANDLE cspHand = 0;
203	CSSM_DL_DB_HANDLE dlDbHand = {0, 0};
204	ortn = SecKeychainGetCSPHandle(kcRef, &cspHand);
205	if(ortn) {
206		cssmPerror("SecKeychainGetCSPHandle", ortn);
207		exit(1);
208	}
209	ortn = SecKeychainGetDLDBHandle(kcRef, &dlDbHand);
210	if(ortn) {
211		cssmPerror("SecKeychainGetDLDBHandle", ortn);
212		exit(1);
213	}
214
215	CSSM_KEY privKey;
216	CSSM_KEY pubKey;
217	CSSM_RETURN crtn;
218
219	crtn = genKeyPair(cspHand, dlDbHand,
220		keyAlg,
221		label, (label ? strlen(label) : 0),
222		keySizeInBits,
223		&pubKey,
224		CSSM_KEYUSE_ANY,			// may want to parameterize
225		&privKey,
226		CSSM_KEYUSE_ANY);			// may want to parameterize
227	if(crtn) {
228		printf("**Error creating key pair.\n");
229	}
230	else {
231		printf("...key pair created in keychain %s.\n", kcName);
232	}
233
234	cspFreeKey(cspHand, &privKey);
235	cspFreeKey(cspHand, &pubKey);
236	CFRelease(kcRef);
237	return 0;
238}
239