1/* Copyright (c) 2001,2003-2006,2008 Apple Inc.
2 *
3 * keyStore.c - basic key pair store/lookup routines.
4 *
5 * create key pair, varying pub is permanent, priv is permanent;
6 * sign some data with priv;
7 * lookUpPub = lookup pub by label;
8 * vfy with lookUpPub;
9 * lookUpPriv = lookup priv by label;
10 * if(privIsPerm) {
11 *	 	ensure lookUpPriv == priv;
12 * 		freeKey(lookUpPriv);
13 * 		obtainedPriv = obtainPubFromPriv(lookUpPub);
14 * 		ensure obtainedPriv == priv;
15 * 		freeKey(obtainedPriv);
16 * 		delete priv;		// cspwrap does implicit freeKey here...
17 * }
18 * else {
19 *      free priv;
20 * }
21 * lookUpPriv = lookup priv by label; verify fail;
22 * lookUpPriv = obtainPubFromPriv(pub); verify fail;
23 * freeKey(lookUpPub);
24 * if pub is permament {
25 * 		lookUpPub = lookup pub by label; verify OK;
26 *		deleteKey(lookUpPub);
27 * 		lookUpPub = lookup pub by label; verify fail;
28 * }
29 * lookUpPub = lookup pub by label; verify fail;
30 */
31
32#include <stdlib.h>
33#include <stdio.h>
34#include <time.h>
35#include <string.h>
36#include <unistd.h>
37#include <Security/cssm.h>
38#include "cspwrap.h"
39#include "common.h"
40#include "cspdlTesting.h"
41
42#define LOOPS_DEF			10
43#define MAX_DATA_SIZE		100
44#define DB_NAME				"keyStore.db"
45
46/* can't lookup non-permanent keys! */
47#define FORCE_PUB_PERMANENT		0
48
49static void usage(char **argv)
50{
51	printf("usage: %s [options]\n", argv[0]);
52	printf("   Options:\n");
53	printf("   l=loops (default=%d; 0=forever)\n", LOOPS_DEF);
54	printf("   r(RSA; default = FEE)\n");
55	printf("   p(ermanent keys, implies l=1)\n");
56	printf("   k=keyChainFile\n");
57	printf("   n(o sign/verify)\n");
58	printf("   N(o lookup of nonexistent keys)\n");
59	printf("   x (privKey always extractable)\n");
60	printf("   P(ause for MallocDebug)\n");
61	printf("   v(erbose)\n");
62	printf("   q(uiet)\n");
63	printf("   h(elp)\n");
64	exit(1);
65}
66
67#define FEE_PRIV_DATA_SIZE	20
68
69/*
70 * NULL wrap, error tolerant.
71 */
72CSSM_RETURN cspNullWrapKey(
73	CSSM_CSP_HANDLE cspHand,
74	const CSSM_KEY  *refKey,
75	CSSM_KEY_PTR	rawKey)			// RETURNED on success, caller must FreeKey
76{
77	CSSM_CC_HANDLE			ccHand;
78	CSSM_RETURN				crtn;
79	CSSM_ACCESS_CREDENTIALS	creds;
80	CSSM_DATA descData = {0, 0};
81
82	memset(rawKey, 0, sizeof(CSSM_KEY));
83	memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
84	crtn = CSSM_CSP_CreateSymmetricContext(cspHand,
85			CSSM_ALGID_NONE,
86			CSSM_ALGMODE_NONE,
87			&creds,				// passPhrase,
88			NULL,				// wrappingKey,
89			NULL,				// initVector,
90			CSSM_PADDING_NONE,
91			0,					// Params
92			&ccHand);
93	if(crtn) {
94		printError("cspNullWrapKey/CreateContext", crtn);
95		return crtn;
96	}
97	crtn = CSSM_WrapKey(ccHand,
98		&creds,
99		refKey,
100		&descData,			// DescriptiveData
101		rawKey);
102	if(CSSM_DeleteContext(ccHand)) {
103		printf("CSSM_DeleteContext failure\n");
104	}
105	return crtn;
106}
107
108
109/*
110 * Generate key pair, default size. This is like cspGenKeyPair in cspwrap.c,
111 * tweaked for this test To allow varying permanent attribute.
112 */
113static CSSM_RETURN genKeyPair(CSSM_CSP_HANDLE cspHand,
114	CSSM_DL_HANDLE		dlHand,
115	CSSM_DB_HANDLE		dbHand,
116	const CSSM_DATA_PTR keyLabel,
117	CSSM_KEY_PTR 		pubKey,				// mallocd by caller
118	uint32 				pubKeyUsage,		// CSSM_KEYUSE_ENCRYPT, etc.
119	uint32 				pubKeyAttr,
120	CSSM_KEY_PTR 		privKey,			// mallocd by caller
121	uint32				privKeyUsage,		// CSSM_KEYUSE_DECRYPT, etc.
122	uint32 				privKeyAttr,
123	uint32				keyGenAlg)
124{
125	CSSM_RETURN				crtn;
126	CSSM_CC_HANDLE 			ccHand;
127	CSSM_RETURN 			ocrtn = CSSM_OK;
128	uint32					keySize;
129
130	if(keyGenAlg == CSSM_ALGID_FEE) {
131		keySize = CSP_FEE_KEY_SIZE_DEFAULT;
132	}
133	else {
134		keySize = CSP_RSA_KEY_SIZE_DEFAULT;
135	}
136	memset(pubKey, 0, sizeof(CSSM_KEY));
137	memset(privKey, 0, sizeof(CSSM_KEY));
138
139	crtn = CSSM_CSP_CreateKeyGenContext(cspHand,
140		keyGenAlg,
141		keySize,
142		NULL,					// Seed
143		NULL,					// Salt
144		NULL,					// StartDate
145		NULL,					// EndDate
146		NULL,					// Params
147		&ccHand);
148	if(crtn) {
149		printError("CSSM_CSP_CreateKeyGenContext", crtn);
150		ocrtn = crtn;
151		goto abort;
152	}
153
154	/* add in DL/DB to context */
155	crtn = cspAddDlDbToContext(ccHand, dlHand, dbHand);
156	if(crtn) {
157		ocrtn = crtn;
158		goto abort;
159	}
160	crtn = CSSM_GenerateKeyPair(ccHand,
161		pubKeyUsage,
162		pubKeyAttr,
163		keyLabel,
164		pubKey,
165		privKeyUsage,
166		privKeyAttr,
167		keyLabel,				// same labels
168		NULL,					// cred/acl
169		privKey);
170	if(crtn) {
171		printError("CSSM_GenerateKeyPair", crtn);
172		ocrtn = crtn;
173		goto abort;
174	}
175
176	/* basic checks...*/
177	if(privKey->KeyHeader.BlobType != CSSM_KEYBLOB_REFERENCE) {
178		printf("privKey blob type: exp %u got %u\n",
179			CSSM_KEYBLOB_REFERENCE, (unsigned)privKey->KeyHeader.BlobType);
180	}
181	if(pubKeyAttr & CSSM_KEYATTR_RETURN_REF) {
182		if(pubKey->KeyHeader.BlobType != CSSM_KEYBLOB_REFERENCE) {
183			printf("pubKey blob type: exp %u got %u\n",
184				CSSM_KEYBLOB_REFERENCE, (unsigned)privKey->KeyHeader.BlobType);
185			ocrtn = -1;
186			goto abort;
187		}
188	}
189	else {
190		if(pubKey->KeyHeader.BlobType != CSSM_KEYBLOB_RAW) {
191			printf("pubKey blob type: exp %u got %u\n",
192				CSSM_KEYBLOB_RAW, (unsigned)privKey->KeyHeader.BlobType);
193			ocrtn = -1;
194			goto abort;
195		}
196	}
197
198abort:
199	if(ccHand != 0) {
200		crtn = CSSM_DeleteContext(ccHand);
201		if(crtn) {
202			printError("CSSM_DeleteContext", crtn);
203			ocrtn = crtn;
204		}
205	}
206	return ocrtn;
207}
208
209#define KEY_LABEL "testKey"
210
211/*
212 * when true, keyref in key obtained from DL differs from
213 * keyref in key from CSP
214 */
215#define DL_REF_KEYS_DIFFER		1
216
217/*
218 * ObtainPrivateKeyFromPublicKey doesn't work yet
219 */
220#define DO_OBTAIN_FROM_PUB		CSPDL_OBTAIN_PRIV_FROM_PUB
221
222/* we're assumed to be logged in for access to private objects */
223static int doTest(CSSM_CSP_HANDLE cspHand,
224	CSSM_DL_HANDLE	dlHand,
225	CSSM_DB_HANDLE	dbHand,
226	CSSM_BOOL		pubIsPerm,		// pub is permanent
227	CSSM_BOOL		privIsPerm,		// priv is permanent
228	CSSM_BOOL		privIsExtractable,
229	CSSM_BOOL		permKeys,		// leave them in the KC
230	CSSM_BOOL		doSignVerify,
231	CSSM_BOOL		doFailedLookup,
232	CSSM_DATA_PTR 	ptext,
233	CSSM_BOOL	 	verbose,
234	CSSM_BOOL 		quiet,
235	uint32			keyGenAlg,
236	uint32			sigAlg)
237{
238	CSSM_KEY		pubKey;			// from GenerateKeyPair
239	CSSM_KEY		privKey;
240	CSSM_KEY_PTR	lookUpPub;		// from cspLookUpKeyByLabel, etc.
241	CSSM_KEY_PTR	lookUpPriv;
242	CSSM_RETURN 	crtn;
243	CSSM_DATA		sig;
244	CSSM_DATA		labelData;
245	CSSM_KEY		obtainedPriv;
246	uint32			pubAttr;
247	uint32			privAttr;
248	CSSM_KEY		rawPrivKey;
249	labelData.Data = (uint8 *)KEY_LABEL;
250	labelData.Length = strlen(KEY_LABEL);
251	CSSM_BOOL		doLookup;
252
253 	/* create key pair */
254 	if(verbose) {
255 		printf("   ...generating key pair (pubIsPerm %d privIsPerm %d privIsExtract"
256			" %d)\n", (int)pubIsPerm, (int)privIsPerm, (int)privIsExtractable);
257 	}
258 	pubAttr = CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_RETURN_REF;
259 	if(pubIsPerm) {
260 		pubAttr |= CSSM_KEYATTR_PERMANENT;
261 	}
262
263	/*
264	 * To use a NULL wrap to test detection of !EXTRACTABLE, we're relying on
265	 * being able to create !SENSITIVE private keys. We'll make 'em sensitive
266	 * if we're not trying to null wrap them.
267	 */
268	privAttr =  CSSM_KEYATTR_RETURN_REF;
269 	if(privIsPerm) {
270 		privAttr |= CSSM_KEYATTR_PERMANENT;
271 	}
272	if(privIsExtractable) {
273 		privAttr |= CSSM_KEYATTR_EXTRACTABLE;
274	}
275	else {
276		privAttr |= CSSM_KEYATTR_SENSITIVE;
277	}
278	#if	CSPDL_KEYATTR_PRIVATE
279 		privAttr |= CSSM_KEYATTR_PRIVATE;
280	#endif
281 	crtn = genKeyPair(cspHand,
282		dlHand,
283 		dbHand,
284		&labelData,
285		&pubKey,
286		CSSM_KEYUSE_VERIFY,			// pubKeyUsage
287		pubAttr,
288		&privKey,
289		CSSM_KEYUSE_SIGN,
290		privAttr,
291		keyGenAlg);
292	if(crtn) {
293		return testError(quiet);
294	}
295
296 	/* lookUpPub = lookup pub by label; */
297	doLookup = CSSM_TRUE;
298 	if(verbose) {
299 		if(pubIsPerm) {
300	 		printf("   ...lookup pub by label\n");
301 		}
302 		else {
303			if(doFailedLookup) {
304				printf("   ...lookup (nonexistent) pub by label\n");
305			}
306			else {
307				doLookup = CSSM_FALSE;
308				lookUpPub = NULL;
309			}
310 		}
311 	}
312	if(doLookup) {
313		lookUpPub = cspLookUpKeyByLabel(dlHand, dbHand, &labelData, CKT_Public);
314	}
315	if(pubIsPerm) {
316		if(lookUpPub == NULL) {
317			printf("lookup pub by label failed\n");
318			return testError(quiet);
319		}
320
321		/* sign some data with priv; */
322		sig.Data = NULL;
323		sig.Length = 0;
324		if(doSignVerify) {
325			if(cspSign(cspHand,
326					sigAlg,
327					&privKey,
328					ptext,
329					&sig)) {
330				return testError(quiet);
331			}
332		}
333		/* verify header compare */
334		if(memcmp(&lookUpPub->KeyHeader, &pubKey.KeyHeader,
335				sizeof(CSSM_KEYHEADER))) {
336			printf("**pubKey header miscompare\n");
337			return testError(quiet);
338		}
339
340		/* vfy with lookUpPub; */
341		if(doSignVerify) {
342			if(cspSigVerify(cspHand,
343					sigAlg,
344					lookUpPub,
345					ptext,
346					&sig,
347					CSSM_OK)) {
348				return testError(quiet);
349			}
350
351			CSSM_FREE(sig.Data);
352			sig.Data = NULL;
353			sig.Data = 0;
354		}
355	}
356	else {
357		if(doLookup && (lookUpPub != NULL)) {
358			printf("***Unexpected success on cspLookUpKeyByLabel(pub, not perm)\n");
359			return testError(quiet);
360		}
361	}
362
363	/*
364	 * Ensure proper behavior of extractable bit
365	 */
366	if(verbose) {
367		printf("   ...null wrap %s private key\n",
368			privIsExtractable ? "EXTRACTABLE" : "!EXTRACTABLE");
369	}
370	crtn = cspNullWrapKey(cspHand, &privKey, &rawPrivKey);
371	if(privIsExtractable) {
372		if(crtn) {
373			printError("Null Wrap(extractable private key)", crtn);
374			return testError(quiet);
375		}
376		if(verbose) {
377			printf("   ...free rawPrivKey\n");
378		}
379	 	cspFreeKey(cspHand, &rawPrivKey);
380	}
381	else {
382		if(crtn != CSSMERR_CSP_INVALID_KEYATTR_MASK) {
383			printError("Null Wrap of !extractable private key: expected "
384				"INVALID_KEYATTR_MASK, got", crtn);
385			if(crtn == CSSM_OK) {
386			 	cspFreeKey(cspHand, &rawPrivKey);
387			}
388			return testError(quiet);
389		}
390	}
391	/* lookUpPriv = lookup priv by label; ensure == privKey; */
392	doLookup = CSSM_TRUE;
393 	if(verbose) {
394 		if(privIsPerm) {
395	 		printf("   ...lookup priv by label\n");
396 		}
397 		else {
398			if(doFailedLookup) {
399				printf("   ...lookup (nonexistent) priv by label\n");
400			}
401			else {
402				doLookup = CSSM_FALSE;
403				lookUpPriv = NULL;
404			}
405 		}
406 	}
407	if(doLookup) {
408		lookUpPriv = cspLookUpKeyByLabel(dlHand, dbHand, &labelData, CKT_Private);
409	}
410 	if(privIsPerm) {
411	 	if(lookUpPriv == NULL) {
412	 		printf("lookup priv by label failed\n");
413	 		return testError(quiet);
414	 	}
415
416		/* note we "know" that both keys are ref keys...*/
417		if(lookUpPriv->KeyData.Length != privKey.KeyData.Length) {
418			printf("priv key data length mismatch\n");
419			return testError(quiet);
420		}
421		#if		DL_REF_KEYS_DIFFER
422		if(!memcmp(lookUpPriv->KeyData.Data, privKey.KeyData.Data,
423				privKey.KeyData.Length)) {
424			printf("priv key ref data mismatch\n");
425			return testError(quiet);
426		}
427		#else	/* DL_REF_KEYS_DIFFER */
428		if(memcmp(lookUpPriv->KeyData.Data, privKey.KeyData.Data,
429				privKey.KeyData.Length)) {
430			printf("unexpected priv key ref data match\n");
431			return testError(quiet);
432		}
433		#endif	/* DL_REF_KEYS_DIFFER */
434
435		/* verify header compare in any case */
436		if(memcmp(&lookUpPriv->KeyHeader, &privKey.KeyHeader,
437				sizeof(CSSM_KEYHEADER))) {
438			printf("**privKey header miscompare\n");
439			return testError(quiet);
440		}
441
442		/* sign with lookUpPriv, verify with pubKey */
443		sig.Data = NULL;
444		sig.Length = 0;
445		if(doSignVerify) {
446			if(verbose) {
447				printf("   ...sign with lookup priv\n");
448			}
449			if(cspSign(cspHand,
450					sigAlg,
451					lookUpPriv,
452					ptext,
453					&sig)) {
454				return testError(quiet);
455			}
456			if(verbose) {
457				printf("   ...verify with pub\n");
458			}
459			if(cspSigVerify(cspHand,
460					sigAlg,
461					&pubKey,
462					ptext,
463					&sig,
464					CSSM_OK)) {
465				printf("***sign with lookUpPriv, vfy with pub FAILED\n");
466				return testError(quiet);
467			}
468			CSSM_FREE(sig.Data);
469			sig.Data = NULL;
470			sig.Data = 0;
471		}
472
473	 	/* free lookUpPriv from cache, but it's permanent */
474	 	if(verbose) {
475	 		printf("   ...free lookupPriv\n");
476	 	}
477	 	if(cspFreeKey(cspHand, lookUpPriv)) {
478	 		printf("Error on cspFreeKey(lookUpPriv)\n");
479	 		return testError(quiet);
480	 	}
481	 	CSSM_FREE(lookUpPriv);		// mallocd during lookup
482	 	lookUpPriv = NULL;
483
484		#if	DO_OBTAIN_FROM_PUB
485	 	/* obtainedPriv = obtainPubFromPriv(pub); ensure == priv; */
486	 	if(verbose) {
487	 		printf("   ...ObtainPrivateKeyFromPublicKey\n");
488	 	}
489	 	obtainedPriv.KeyData.Data = NULL;
490	 	obtainedPriv.KeyData.Length = 0;
491	 	crtn = CSSM_CSP_ObtainPrivateKeyFromPublicKey(cspHand,
492	 		lookUpPub,
493	 		&obtainedPriv);
494	 	if(crtn) {
495	 		printError("ObtainPrivateKeyFromPublicKey", crtn);
496	 		return testError(quiet);
497	 	}
498
499	 	/* free obtainedPriv from cache, but it's permanent */
500	 	if(verbose) {
501	 		printf("   ...free obtainedPriv\n");
502	 	}
503	 	if(cspFreeKey(cspHand, &obtainedPriv)) {
504	 		printf("Error on cspFreeKey(obtainedPriv)\n");
505	 		return testError(quiet);
506	 	}
507
508		#endif	/* DO_OBTAIN_FROM_PUB */
509
510		if(!permKeys) {
511			/* delete priv - implies freeKey as well */
512			if(verbose) {
513				printf("   ...delete privKey\n");
514			}
515			crtn = cspDeleteKey(cspHand, dlHand, dbHand, &labelData, &privKey);
516			if(crtn) {
517				printf("Error deleting priv\n");
518				return testError(quiet);
519			}
520
521			/* lookUpPriv = lookup priv by label; verify fail; */
522			if(doFailedLookup) {
523				if(verbose) {
524					printf("   ...lookup (nonexistent) priv by label\n");
525				}
526				lookUpPriv = cspLookUpKeyByLabel(dlHand, dbHand, &labelData, CKT_Private);
527				if(lookUpPriv != NULL) {
528					printf("Unexpected success on cspLookUpKeyByLabel(priv)\n");
529					return testError(quiet);
530				}
531			}
532			else {
533				lookUpPriv = NULL;
534			}
535		}
536	}
537	else if(doLookup) {
538		/* !privIsPerm - just free it and it's all gone */
539		if(lookUpPriv != NULL) {
540			printf("***Unexpected success on cspLookUpKeyByLabel(priv, not perm)\n");
541			return testError(quiet);
542		}
543		if(verbose) {
544			printf("   ...free privKey\n");
545		}
546	 	if(cspFreeKey(cspHand, &privKey)) {
547	 		printf("Error on cspFreeKey(privKey)\n");
548	 		return testError(quiet);
549	 	}
550	}
551	/* CSP, DL have no knowledge of privKey or its variations */
552
553 	/* obtainedPriv = obtainPubFromPriv(pub); verify fail;*/
554 	/* Note this should be safe even if DO_OBTAIN_FROM_PUB == 0 */
555 	obtainedPriv.KeyData.Data = NULL;
556 	obtainedPriv.KeyData.Length = 0;
557 	if(verbose) {
558 		printf("   ...obtain (nonexistent) priv by public\n");
559 	}
560 	crtn = CSSM_CSP_ObtainPrivateKeyFromPublicKey(cspHand,
561 		&pubKey,
562 		&obtainedPriv);
563	switch(crtn) {
564		case CSSM_OK:
565			printf("Unexpected success on ObtainPrivateKeyFromPublicKey\n");
566			return testError(quiet);
567		case CSSMERR_CSP_PRIVATE_KEY_NOT_FOUND:
568			break;
569		#if	!CSPDL_OBTAIN_PRIV_FROM_PUB
570		case CSSMERR_CSP_FUNCTION_NOT_IMPLEMENTED:
571			/* OK */
572			break;
573		#endif
574		default:
575			printf("Unexpected err ObtainPrivateKeyFromPublicKey\n");
576			printError("got this", crtn);
577			return testError(quiet);
578 	}
579
580 	/* free one or both copies of pub as appropriate */
581 	if(verbose) {
582 		printf("   ...free pubKey\n");
583 	}
584 	crtn = cspFreeKey(cspHand, &pubKey);
585	if(crtn) {
586		printf("Error freeing pubKey\n");
587		return testError(quiet);
588	}
589	if(pubIsPerm) {
590	 	if(verbose) {
591	 		printf("   ...free lookUpPub\n");
592	 	}
593	 	crtn = cspFreeKey(cspHand, lookUpPub);
594		if(crtn) {
595			printf("Error freeing lookUpPub\n");
596			return testError(quiet);
597		}
598	}
599	if(lookUpPub) {
600		CSSM_FREE(lookUpPub);			// mallocd by lookup in any case
601	}
602
603	if(pubIsPerm) {
604		/* pub should still be there in DL */
605		/* lookUpPub = lookup pub by label; verify OK; */
606	 	if(verbose) {
607	 		printf("   ...lookup pub by label (2)\n");
608	 	}
609	 	lookUpPub = cspLookUpKeyByLabel(dlHand, dbHand, &labelData, CKT_Public);
610	 	if(lookUpPub == NULL) {
611	 		printf("lookup pub by label (2) failed\n");
612	 		return testError(quiet);
613	 	}
614
615		if(!permKeys) {
616			/* now really delete it */
617			if(verbose) {
618				printf("   ...delete lookUpPub\n");
619			}
620			crtn = cspDeleteKey(cspHand, dlHand, dbHand, &labelData, lookUpPub);
621			if(crtn) {
622				printf("Error deleting lookUpPub\n");
623				return testError(quiet);
624			}
625			CSSM_FREE(lookUpPub);		// mallocd by lookup
626		}
627	}
628	/* else freeKey should have removed all trace */
629
630	if(!permKeys && doFailedLookup) {
631		/* lookUpPub = lookup pub by label; verify fail; */
632		if(verbose) {
633			printf("   ...lookup (nonexistent) pub by label\n");
634		}
635		lookUpPub = cspLookUpKeyByLabel(dlHand, dbHand, &labelData, CKT_Public);
636		if(lookUpPub != NULL) {
637			printf("Unexpected success on cspLookUpKeyByLabel(pub) (2)\n");
638			return testError(quiet);
639		}
640	}
641	return 0;
642}
643
644int main(int argc, char **argv)
645{
646	int					arg;
647	char				*argp;
648	unsigned			loop;
649	CSSM_DATA			ptext;
650	CSSM_CSP_HANDLE 	cspHand;
651	CSSM_DB_HANDLE		dbHand;
652	CSSM_DL_HANDLE		dlHand;
653	CSSM_BOOL			pubIsPerm;
654	CSSM_BOOL			privIsPerm;
655	CSSM_BOOL			privIsExtractable;
656	uint32				keyGenAlg = CSSM_ALGID_FEE;
657	uint32				sigAlg = CSSM_ALGID_FEE_MD5;
658	int					rtn = 0;
659	CSSM_RETURN			crtn;
660
661	/*
662	 * User-spec'd params
663	 */
664	unsigned	loops = LOOPS_DEF;
665	CSSM_BOOL	verbose = CSSM_FALSE;
666	CSSM_BOOL	quiet = CSSM_FALSE;
667	CSSM_BOOL	permKeys = CSSM_FALSE;
668	char		dbName[100];		/* DB_NAME_pid */
669	CSSM_BOOL	useExistDb = CSSM_FALSE;
670	CSSM_BOOL	doPause = CSSM_FALSE;
671	CSSM_BOOL	doSignVerify = CSSM_TRUE;
672	CSSM_BOOL	doFailedLookup = CSSM_TRUE;
673	CSSM_BOOL	privAlwaysExtractable = CSSM_FALSE;
674
675	dbName[0] = '\0';
676
677	for(arg=1; arg<argc; arg++) {
678		argp = argv[arg];
679		switch(argp[0]) {
680		    case 'l':
681				loops = atoi(&argp[2]);
682				break;
683		    case 'v':
684		    	verbose = CSSM_TRUE;
685				break;
686		    case 'q':
687		    	quiet = CSSM_TRUE;
688				break;
689		    case 'p':
690		    	permKeys = CSSM_TRUE;
691				loops = 1;
692				break;
693			case 'r':
694				keyGenAlg = CSSM_ALGID_RSA;
695				sigAlg = CSSM_ALGID_MD5WithRSA;
696				break;
697			case 'k':
698				memmove(dbName, &argp[2], strlen(&argp[2]) + 1);
699				useExistDb = CSSM_TRUE;
700				break;
701			case 'P':
702				doPause = CSSM_TRUE;
703				break;
704			case 'n':
705				doSignVerify = CSSM_FALSE;
706				break;
707			case 'N':
708				doFailedLookup = CSSM_FALSE;
709				break;
710			case 'x':
711				privAlwaysExtractable = CSSM_TRUE;
712				break;
713		    case 'h':
714		    default:
715				usage(argv);
716		}
717	}
718
719	if(dbName[0] == '\0') {
720		sprintf(dbName, "%s_%d", DB_NAME, (int)getpid());
721	}
722
723	ptext.Data = (uint8 *)CSSM_MALLOC(MAX_DATA_SIZE);
724	ptext.Length = MAX_DATA_SIZE;
725	/* data generated in test loop */
726	if(ptext.Data == NULL) {
727		printf("Insufficient heap\n");
728		exit(1);
729	}
730
731	testStartBanner("keyStore", argc, argv);
732
733	/* attach to CSP/DL */
734	cspHand = cspDlDbStartup(CSSM_FALSE, NULL);
735	if(cspHand == 0) {
736		exit(1);
737	}
738	dlHand = dlStartup();
739	if(dlHand == 0) {
740		exit(1);
741	}
742	if(useExistDb) {
743		/* this one may well require SecurityAgent UI */
744		crtn = dbCreateOpen(dlHand, dbName, CSSM_FALSE, CSSM_FALSE, NULL,
745			&dbHand);
746	}
747	else {
748		/* hands-free test */
749		crtn = dbCreateOpen(dlHand, dbName, CSSM_TRUE, CSSM_TRUE, dbName,
750			&dbHand);
751	}
752	if(crtn) {
753		exit(1);
754	}
755	for(loop=1; ; loop++) {
756
757		if(!quiet) {
758			printf("...loop %d\n", loop);
759		}
760		appGetRandomBytes(ptext.Data, ptext.Length);
761
762		if(permKeys) {
763			pubIsPerm = privIsPerm = CSSM_TRUE;
764		}
765		else {
766			#if CSPDL_ALL_KEYS_ARE_PERMANENT
767			pubIsPerm = CSSM_TRUE;
768			privIsPerm = CSSM_TRUE;
769			#else
770
771			/* mix up pubIsPerm, privIsPerm */
772			pubIsPerm  = (loop & 1) ? CSSM_TRUE : CSSM_FALSE;
773			privIsPerm = (loop & 2) ? CSSM_TRUE : CSSM_FALSE;
774			#if FORCE_PUB_PERMANENT
775			pubIsPerm = CSSM_TRUE;
776			#endif
777			#endif	/* CSPDL_ALL_KEYS_ARE_PERMANENT */
778		}
779		privIsExtractable = ((loop & 4) || privAlwaysExtractable) ? CSSM_TRUE : CSSM_FALSE;
780		if(doTest(cspHand,
781				dlHand,
782				dbHand,
783				pubIsPerm,
784				privIsPerm,
785				privIsExtractable,
786				permKeys,
787				doSignVerify, doFailedLookup,
788				&ptext,
789				verbose,
790				quiet,
791				keyGenAlg,
792				sigAlg)) {
793			rtn = 1;
794			break;
795		}
796		if(loops && (loop == loops)) {
797			break;
798		}
799		if(doPause) {
800			fpurge(stdin);
801			printf("CR to continue: ");
802			getchar();
803		}
804	}
805
806	cspShutdown(cspHand, CSSM_FALSE);
807	/* FIXME - DB close? DL shutdown? */
808	if((rtn == 0) && !quiet) {
809		printf("%s test complete\n", argv[0]);
810	}
811	if((rtn == 0) & !permKeys) {
812		/* be nice: if we ran OK delete the cruft DB we created */
813		unlink(dbName);
814	}
815	return rtn;
816}
817