1/* Copyright (c) 1998,2003-2005 Apple Computer, Inc.
2 *
3 * miniWrap.c - simple key wrap/unwrap exerciser.
4 *
5 * Revision History
6 * ----------------
7 *   4 May 2000  Doug Mitchell
8 *		Ported to X/CDSA2.
9 *  22 May 1998 Doug Mitchell at Apple
10 *		Created.
11 */
12
13#include <stdlib.h>
14#include <stdio.h>
15#include <time.h>
16#include <string.h>
17#include <Security/cssm.h>
18#include "cspwrap.h"
19#include "common.h"
20#include "cspdlTesting.h"
21
22/*
23 * Temporary hack to use CSSM_KEYBLOB_WRAPPED_FORMAT_{PKCS7,PKCS8}, which
24 * are no longer supported as of 7/28/00
25 */
26#define PKCS8_FORMAT_ENABLE		1
27#define PKCS7_FORMAT_ENABLE		0
28
29#define ENCR_USAGE_NAME		"noLabel"
30#define ENCR_USAGE_NAME_LEN	(strlen(ENCR_USAGE_NAME))
31#define WRAP_USAGE_NAME		"noWrapLabel"
32#define WRAP_USAGE_NAME_LEN	(strlen(WRAP_USAGE_NAME))
33#define LOOPS_DEF		10
34#define MAX_PTEXT_SIZE	1000
35#define LOOP_PAUSE		10
36
37/*
38 * A new restriction for X: when wrapping using an RSA key, you can't
39 * wrap a key which is  bigger than the RSA key itself because the
40 * wrap (Encrypt) is a one-shot deal, unlike the OS9 CSP which
41 * handled multiple chunks. This only effectively restricts the
42 * use of an RSA key to wrap symmetric keys, which doesn't seem like
43 * an unreasonable restriction.
44 */
45#define RSA_WRAP_RESTRICTION		1
46
47/*
48 * Currently the CSP can use wrapping keys flagged exclusively for wrapping
49 * (CSSM_KEYUSE_{WRAP,UNWRAP} for the actual wrap since�the wrap/unwrap op is
50 * done with an encrypt/decrypt op. The WrapKey op doesn't even see the
51 * wrapping key - it's in the context we pass it. Thus for now wrap/unwrap
52 * keys have to be marked with CSSM_KEYUSE_ANY.
53 */
54#define WRAP_USAGE_ANY			0
55
56static void usage(char **argv)
57{
58	printf("usage: %s [options]\n", argv[0]);
59	printf("   Options:\n");
60	printf("   f (only wrap RSA private key)\n");
61	printf("   d (only wrap DES key)\n");
62	printf("   S (do symmetric wrap only)\n");
63	printf("   a (do asymmetric wrap only)\n");
64	printf("   n (do null wrap only)\n");
65	printf("   m (dump malloc info)\n");
66	printf("   r (ref keys only)\n");
67	printf("   w (wrap only)\n");
68	printf("   e (export)\n");
69	printf("   q (quiet)\n");
70	printf("   k (force PKCS7/8)\n");
71	#if		PKCS7_FORMAT_ENABLE || PKCS8_FORMAT_ENABLE
72	printf("   K (skip PKCS7/8) (pkcs normally enable)\n");
73	#else
74	printf("   K (allow PKCS7/8) (pkcs normally disabled)\n");
75	#endif	/* PKCS_FORMAT_ENABLE */
76	printf("   D (CSP/DL; default = bare CSP)\n");
77	printf("   l=loops (default=%d; 0=forever)\n", LOOPS_DEF);
78	printf("   p(ause every %d loops)\n", LOOP_PAUSE);
79	printf("   h(elp)\n");
80	exit(1);
81}
82
83/* not all algs need this, pass it in anyway */
84CSSM_DATA initVector = {8, (uint8 *)"someVect"};
85
86/*
87 * local verbose wrap/unwrap functions.
88 */
89/* wrap key function. */
90static CSSM_RETURN wrapKey(CSSM_CSP_HANDLE cspHand,
91	const CSSM_KEY_PTR		unwrappedKey,		// must be ref
92	const CSSM_KEY_PTR		wrappingKey,
93	CSSM_ALGORITHMS			wrapAlg,
94	CSSM_ENCRYPT_MODE		wrapMode,
95	CSSM_KEYBLOB_FORMAT		wrapFormat,			// NONE, PKCS7, PKCS8
96	CSSM_PADDING 			wrapPad,
97	CSSM_KEY_PTR			wrappedKey)			// RETURNED
98{
99	CSSM_CC_HANDLE		ccHand;
100	CSSM_RETURN			crtn;
101	CSSM_RETURN			crtn2;
102	#if	WRAP_KEY_REQUIRES_CREDS
103	CSSM_ACCESS_CREDENTIALS	creds;
104	#endif
105
106	#if 0
107	if(unwrappedKey->KeyHeader.BlobType != CSSM_KEYBLOB_REFERENCE) {
108		printf("Hey! you can only wrap a reference key!\n");
109		return CSSM_ERRCODE_INTERNAL_ERROR;
110	}
111	#endif
112	memset(wrappedKey, 0, sizeof(CSSM_KEY));
113	memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
114	/* special case for NULL wrap - no wrapping key */
115	if((wrappingKey == NULL) ||
116	   (wrappingKey->KeyHeader.KeyClass == CSSM_KEYCLASS_SESSION_KEY)) {
117		crtn = CSSM_CSP_CreateSymmetricContext(cspHand,
118				wrapAlg,
119				wrapMode,
120				&creds,					// accessCred
121				wrappingKey,
122				&initVector,
123				wrapPad,				// Padding
124				NULL,					// Reserved
125				&ccHand);
126		if(crtn) {
127			printError("cspWrapKey/CreateContext", crtn);
128			return CSSM_ERRCODE_INTERNAL_ERROR;
129		}
130	}
131	else {
132		crtn = CSSM_CSP_CreateAsymmetricContext(cspHand,
133				wrapAlg,
134				&creds,			// passPhrase
135				wrappingKey,
136				wrapPad,		// Padding
137				&ccHand);
138		if(crtn) {
139			printError("cspWrapKey/CreateContext", crtn);
140			return CSSM_ERRCODE_INTERNAL_ERROR;
141		}
142		/* CMS requires 8-byte IV */
143		crtn = AddContextAttribute(ccHand,
144			CSSM_ATTRIBUTE_INIT_VECTOR,
145			sizeof(CSSM_DATA),
146			CAT_Ptr,
147			&initVector,
148			0);
149		if(crtn) {
150			printError("CSSM_UpdateContextAttributes", crtn);
151			return crtn;
152		}
153	}
154	if(wrapFormat != CSSM_KEYBLOB_WRAPPED_FORMAT_NONE) {
155		/* only add this attribute if it's not the default */
156		CSSM_CONTEXT_ATTRIBUTE attr;
157		attr.AttributeType = CSSM_ATTRIBUTE_WRAPPED_KEY_FORMAT;
158		attr.AttributeLength = sizeof(uint32);
159		attr.Attribute.Uint32 = wrapFormat;
160		crtn = CSSM_UpdateContextAttributes(
161			ccHand,
162			1,
163			&attr);
164		if(crtn) {
165			printError("CSSM_UpdateContextAttributes", crtn);
166			return crtn;
167		}
168	}
169	crtn = CSSM_WrapKey(ccHand,
170		#if	WRAP_KEY_REQUIRES_CREDS
171		&creds,
172		#else
173		NULL,			// AccessCred
174		#endif
175		unwrappedKey,
176		NULL,			// DescriptiveData
177		wrappedKey);
178	if(crtn != CSSM_OK) {
179		printError("CSSM_WrapKey", crtn);
180	}
181	if((crtn2 = CSSM_DeleteContext(ccHand))) {
182		printError("CSSM_DeleteContext", crtn2);
183	}
184	return crtn;
185}
186
187/* unwrap key function. */
188static CSSM_RETURN unwrapKey(CSSM_CSP_HANDLE cspHand,
189	const CSSM_KEY_PTR		wrappedKey,
190	const CSSM_KEY_PTR		unwrappingKey,
191	CSSM_ALGORITHMS			unwrapAlg,
192	CSSM_ENCRYPT_MODE		unwrapMode,
193	CSSM_PADDING 			unwrapPad,
194	CSSM_KEY_PTR			unwrappedKey,		// RETURNED
195	const unsigned char 	*keyLabel,
196	unsigned 				keyLabelLen)
197{
198	CSSM_CC_HANDLE		ccHand;
199	CSSM_RETURN			crtn;
200	CSSM_RETURN			crtn2;
201	CSSM_DATA			labelData;
202	uint32				keyAttr;
203	CSSM_DATA			descData = { 0, NULL };
204	CSSM_ACCESS_CREDENTIALS	creds;
205
206	memset(unwrappedKey, 0, sizeof(CSSM_KEY));
207	memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
208	if((unwrappingKey == NULL) ||
209	   (unwrappingKey->KeyHeader.KeyClass == CSSM_KEYCLASS_SESSION_KEY)) {
210		crtn = CSSM_CSP_CreateSymmetricContext(cspHand,
211				unwrapAlg,
212				unwrapMode,
213				&creds,				// accessCreds
214				unwrappingKey,
215				&initVector,
216				unwrapPad,			// Padding
217				0,					// Reserved
218				&ccHand);
219		if(crtn) {
220			printError("cspUnwrapKey/CreateContext", crtn);
221			return CSSM_ERRCODE_INTERNAL_ERROR;
222		}
223	}
224	else {
225		crtn = CSSM_CSP_CreateAsymmetricContext(cspHand,
226				unwrapAlg,
227				&creds,			// passPhrase,
228				unwrappingKey,
229				unwrapPad,		// Padding
230				&ccHand);
231		if(crtn) {
232			printError("cspUnwrapKey/CreateContext", crtn);
233			return CSSM_ERRCODE_INTERNAL_ERROR;
234		}
235		/* CMS requires 8-byte IV */
236		crtn = AddContextAttribute(ccHand,
237			CSSM_ATTRIBUTE_INIT_VECTOR,
238			sizeof(CSSM_DATA),
239			CAT_Ptr,
240			&initVector,
241			0);
242		if(crtn) {
243			printError("CSSM_UpdateContextAttributes", crtn);
244			return crtn;
245		}
246	}
247	labelData.Data = (uint8 *)keyLabel;
248	labelData.Length = keyLabelLen;
249
250	/*
251	 * New keyAttr - clear some old bits, make sure we ask for ref key
252	 */
253	keyAttr = wrappedKey->KeyHeader.KeyAttr;
254	keyAttr &= ~(CSSM_KEYATTR_ALWAYS_SENSITIVE | CSSM_KEYATTR_NEVER_EXTRACTABLE);
255	keyAttr |= CSSM_KEYATTR_RETURN_REF;
256	crtn = CSSM_UnwrapKey(ccHand,
257		NULL,		// PublicKey
258		wrappedKey,
259		CSSM_KEYUSE_ANY,		// FIXME
260		keyAttr,
261		&labelData,
262		NULL,					// CredAndAclEntry
263		unwrappedKey,
264		&descData);				// required
265	if(crtn != CSSM_OK) {
266		printError("CSSM_UnwrapKey", crtn);
267	}
268	if((crtn2 = CSSM_DeleteContext(ccHand))) {
269		printError("CSSM_DeleteContext", crtn2);
270	}
271	return crtn;
272}
273
274#define UNWRAPPED_LABEL	"unwrapped thing"
275#define NULL_TEST	0
276#if		NULL_TEST
277
278static int doTest(CSSM_CSP_HANDLE cspHand,
279	CSSM_KEY_PTR encrKey,
280	CSSM_KEY_PTR decrKey,		// we wrap this one
281	CSSM_KEY_PTR wrappingKey,	// ...using this key, NULL for null wrap
282	CSSM_KEY_PTR unwrappingKey,
283	CSSM_ALGORITHMS wrapAlg,
284	CSSM_ENCRYPT_MODE wrapMode,
285	CSSM_PADDING wrapPad,
286	CSSM_ALGORITHMS encrAlg,
287	CSSM_ENCRYPT_MODE encrMode,
288	CSSM_PADDING encrPad,
289	CSSM_BOOL wrapOnly,
290	uint32 maxPtextSize,		// max size to encrypt
291	CSSM_BOOL quiet)
292{
293	return 0;
294}
295#else	/* NULL_TEST */
296/*
297 * NULL Wrapping decrKey - a private key - only works for DEBUG CSPs.
298 * We'll always wrap decrKey, except for NULL wrap when
299 * NULL_WRAP_DECR_KEY is false.
300 */
301#define NULL_WRAP_DECR_KEY	1
302
303static int doTest(CSSM_CSP_HANDLE cspHand,
304	CSSM_KEY_PTR encrKey,		// we wrap this one
305	CSSM_KEY_PTR decrKey,		// ...or this one, depending on WRAP_DECR_KEY
306	CSSM_KEY_PTR wrappingKey,	// ...using this key, NULL for null wrap
307	CSSM_KEY_PTR unwrappingKey,
308	CSSM_ALGORITHMS wrapAlg,
309	CSSM_ENCRYPT_MODE wrapMode,
310	CSSM_KEYBLOB_FORMAT	wrapFormat,	// NONE, PKCS7, PKCS8
311	CSSM_PADDING wrapPad,
312	CSSM_ALGORITHMS encrAlg,
313	CSSM_ENCRYPT_MODE encrMode,
314	CSSM_PADDING encrPad,
315	CSSM_BOOL wrapOnly,
316	uint32 maxPtextSize,		// max size to encrypt
317	CSSM_BOOL quiet)
318{
319	CSSM_DATA	ptext;
320	CSSM_DATA	ctext;
321	CSSM_DATA	rptext;
322	CSSM_KEY	wrappedKey;
323	CSSM_KEY	unwrappedKey;
324	CSSM_RETURN	crtn;
325	CSSM_KEY_PTR	realEncrKey;	// encrKey or &unwrappedKey
326	CSSM_KEY_PTR	realDecrKey;	// decrKey or &unwrappedKey
327
328	/* wrap decrKey or encrKey using wrappingKey ==> wrappedKey */
329	if((wrappingKey == NULL) && !NULL_WRAP_DECR_KEY) {
330		/* NULL wrap of pub key */
331		crtn = wrapKey(cspHand,
332			encrKey,
333			wrappingKey,
334			wrapAlg,
335			wrapMode,
336			wrapFormat,
337			wrapPad,
338			&wrappedKey);
339		realEncrKey = &unwrappedKey;
340		realDecrKey = decrKey;
341	}
342	else {
343		/* normal case, wrap priv key (may be NULL if NULL_WRAP_DECR_KEY) */
344		crtn = wrapKey(cspHand,
345			decrKey,
346			wrappingKey,
347			wrapAlg,
348			wrapMode,
349			wrapFormat,
350			wrapPad,
351			&wrappedKey);
352		realEncrKey = encrKey;
353		realDecrKey = &unwrappedKey;
354	}
355
356	if(crtn) {
357		return testError(quiet);
358	}
359	if((wrappingKey != NULL) &&	// skip for NULL wrap
360	   (wrapFormat != CSSM_KEYBLOB_WRAPPED_FORMAT_NONE)) {
361		/* don't want default, verify we got what we want */
362		if(wrappedKey.KeyHeader.Format != wrapFormat) {
363			printf("wrapped key format mismatch: expect %u; got %u\n",
364				(unsigned)wrapFormat, (unsigned)wrappedKey.KeyHeader.Format);
365			if(testError(quiet)) {
366				return 1;
367			}
368		}
369	}
370	if(wrapOnly) {
371		cspFreeKey(cspHand, &wrappedKey);
372		goto done;
373	}
374	/* unwrap wrappedKey using unwrappingKey ==> unwrappedKey; */
375	crtn = unwrapKey(cspHand,
376		&wrappedKey,
377		unwrappingKey,
378		wrapAlg,
379		wrapMode,
380		wrapPad,
381		&unwrappedKey,
382		(uint8 *)UNWRAPPED_LABEL,
383		15);
384	if(crtn) {
385		return testError(quiet);
386	}
387
388	/* cook up ptext */
389	ptext.Data = (uint8 *)CSSM_MALLOC(maxPtextSize);
390	simpleGenData(&ptext, 1, maxPtextSize);
391	/* encrypt using realEncrKey ==> ctext */
392	ctext.Data = NULL;
393	ctext.Length = 0;
394	crtn = cspEncrypt(cspHand,
395		encrAlg,
396		encrMode,
397		encrPad,
398		realEncrKey,
399		NULL,		// no 2nd key
400		0,			// effectiveKeySize
401		0,			// rounds
402		&initVector,
403		&ptext,
404		&ctext,
405		CSSM_TRUE);	// mallocCtext
406	if(crtn) {
407		return testError(quiet);
408	}
409
410	/* decrypt ctext with realDecrKey ==> rptext; */
411	rptext.Data = NULL;
412	rptext.Length = 0;
413	crtn = cspDecrypt(cspHand,
414		encrAlg,
415		encrMode,
416		encrPad,
417		realDecrKey,
418		NULL,			// no 2nd key
419		0,				// effectiveKeySize
420		0,				// rounds
421		&initVector,
422		&ctext,
423		&rptext,
424		CSSM_TRUE);
425	if(crtn) {
426		return testError(quiet);
427	}
428
429	/* compare ptext vs. rptext; */
430	if(ptext.Length != rptext.Length) {
431		printf("ptext length mismatch\n");
432		return testError(quiet);
433	}
434	if(memcmp(ptext.Data, rptext.Data, ptext.Length)) {
435		printf("***data miscompare\n");
436		return testError(quiet);
437	}
438	/* free resources */
439	cspFreeKey(cspHand, &wrappedKey);
440	cspFreeKey(cspHand, &unwrappedKey);
441	CSSM_FREE(ptext.Data);
442	CSSM_FREE(ctext.Data);
443	CSSM_FREE(rptext.Data);
444done:
445	return 0;
446}
447#endif	/* NULL_TEST */
448
449int main(int argc, char **argv)
450{
451	int						arg;
452	char					*argp;
453	int 					i;
454	CSSM_CSP_HANDLE 		cspHand;
455	CSSM_RETURN				crtn;
456	CSSM_KEY				origPub;		// we generate if !desSubj
457	CSSM_KEY				origPriv;
458	CSSM_KEY_PTR			origSess;		// we generate if desSubj
459	CSSM_KEY_PTR			origEncrKey;	// pts to origPub or origSess
460	CSSM_KEY_PTR			origDecrKey;	// pts to origPriv or origSess
461	CSSM_ALGORITHMS			encrAlg;
462	CSSM_ENCRYPT_MODE		encrMode;
463	CSSM_PADDING			encrPad;
464	int						rtn = 0;
465	CSSM_BOOL				genRsaKey;
466	uint32					maxPtextSize;
467	CSSM_BOOL				encrIsRef = CSSM_TRUE;
468	CSSM_BOOL				decrIsRef = CSSM_TRUE;
469	CSSM_KEYBLOB_FORMAT		wrapFormat = CSSM_KEYBLOB_WRAPPED_FORMAT_NONE;
470	unsigned				loop;
471
472	/* user-specified vars */
473	unsigned				loops = LOOPS_DEF;
474	CSSM_BOOL				pause = CSSM_FALSE;
475	CSSM_BOOL				doSymmWrap = CSSM_TRUE;
476	CSSM_BOOL				doAsymmWrap = CSSM_TRUE;
477	CSSM_BOOL				doNullWrap = CSSM_TRUE;
478	CSSM_BOOL				doSymmEncrOnly = CSSM_FALSE;
479	CSSM_BOOL				doAsymmEncrOnly = CSSM_FALSE;
480	CSSM_BOOL				wrapOnly = CSSM_FALSE;
481	CSSM_BOOL				quiet = CSSM_FALSE;
482	CSSM_BOOL				bareCsp = CSSM_TRUE;
483	CSSM_BOOL				forcePkcs = CSSM_FALSE;
484	CSSM_BOOL				refKeysOnly = CSSM_FALSE;
485	#if	PKCS_FORMAT_ENABLE
486	CSSM_BOOL				skipPkcs = CSSM_FALSE;
487	#else
488	CSSM_BOOL				skipPkcs = CSSM_TRUE;
489	#endif
490
491	for(arg=1; arg<argc; arg++) {
492		argp = argv[arg];
493		switch(argp[0]) {
494			case 'S':
495				doAsymmWrap = CSSM_FALSE;
496				doNullWrap = CSSM_FALSE;
497				break;
498			case 'a':
499				doSymmWrap = CSSM_FALSE;
500				doNullWrap = CSSM_FALSE;
501				break;
502			case 'n':
503				doSymmWrap = CSSM_FALSE;
504				doAsymmWrap = CSSM_FALSE;
505				break;
506			case 'f':
507				doAsymmEncrOnly = CSSM_TRUE;
508				break;
509			case 'd':		// symmetric encrypt only option
510			case 'e':		// export option - avoids asymetric encrypt/decrypt
511				doSymmEncrOnly = CSSM_TRUE;
512				break;
513		    case 'l':
514				loops = atoi(&argp[2]);
515				break;
516			case 'w':
517				wrapOnly = CSSM_TRUE;
518				break;
519			case 'p':
520				pause = CSSM_TRUE;
521				break;
522			case 'D':
523				bareCsp = CSSM_FALSE;
524				#if CSPDL_ALL_KEYS_ARE_REF
525		    	refKeysOnly = CSSM_TRUE;
526				#endif
527				break;
528			case 'k':
529				forcePkcs = CSSM_TRUE;
530				break;
531			case 'K':
532				#if		PKCS7_FORMAT_ENABLE || PKCS8_FORMAT_ENABLE
533				skipPkcs = CSSM_TRUE;
534				#else
535				skipPkcs = CSSM_FALSE;
536				#endif
537				break;
538			case 'r':
539				refKeysOnly = CSSM_TRUE;
540				break;
541			case 'q':
542				quiet = CSSM_TRUE;
543				break;
544			default:
545				usage(argv);
546		}
547	}
548
549	#if 0
550	#if	!PKCS_FORMAT_ENABLE
551	if(skipPkcs) {
552		if(doAsymmEncrOnly) {
553			printf("Asymmetric keys can only be wrapped via PKCS; aborting\n");
554			usage(argv);
555		}
556		else if(!doSymmWrap) {
557			printf("AsymmetricWrapping can only be done via PKCS; aborting\n");
558			usage(argv);
559		}
560		doSymmEncrOnly = CSSM_TRUE;
561		doSymmWrap = CSSM_TRUE;
562		doAsymmWrap = CSSM_FALSE;
563	}
564	#endif	/* !PKCS_FORMAT_ENABLE */
565	#endif
566
567	cspHand = cspDlDbStartup(bareCsp, NULL);
568	if(cspHand == 0) {
569		exit(1);
570	}
571
572	printf("Starting miniWrap; args: ");
573	for(i=1; i<argc; i++) {
574		printf("%s ", argv[i]);
575	}
576	printf("\n");
577
578	for(loop=1; ; loop++) {
579		if((loop % LOOP_PAUSE) == 0) {
580			if(!quiet) {
581				printf("...loop %d\n", loop);
582			}
583			if(pause) {
584				fpurge(stdin);
585				printf("Hit CR to proceed: ");
586				getchar();
587			}
588		}
589
590		/* mix up ref and raw keys - with X, we can wrap a raw key */
591		if(!refKeysOnly) {
592			encrIsRef   = (loop & 2) ? CSSM_TRUE : CSSM_FALSE;
593			decrIsRef   = (loop & 4) ? CSSM_TRUE : CSSM_FALSE;
594		}
595
596		/* first generate key to be wrapped */
597		if(!doAsymmEncrOnly && (doSymmEncrOnly || ((loop & 1) == 0))) {
598			if(!quiet) {
599				printf("...wrapping DES key (%s)\n",
600					encrIsRef ? "ref" : "raw");
601			}
602			origSess = cspGenSymKey(cspHand,
603				CSSM_ALGID_DES,
604				ENCR_USAGE_NAME,
605				ENCR_USAGE_NAME_LEN,
606				CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_DECRYPT,
607				CSP_KEY_SIZE_DEFAULT,
608				encrIsRef);
609			if(origSess == NULL) {
610				rtn = 1;
611				goto testDone;
612			}
613			origDecrKey = origEncrKey = origSess;
614			encrAlg = CSSM_ALGID_DES;
615			encrMode = CSSM_ALGMODE_CBCPadIV8;
616			encrPad = CSSM_PADDING_PKCS5;
617			maxPtextSize = MAX_PTEXT_SIZE;	// i.e., unlimited
618		}
619		else {
620			origSess = NULL;
621		}
622		if(!doSymmEncrOnly && (doAsymmEncrOnly || ((loop & 1) == 1))) {
623			if(!quiet) {
624				printf("...wrapping RSA key (pub %s priv %s)\n",
625					(encrIsRef ? "ref" : "raw"),
626					(decrIsRef ? "ref" : "raw"));
627			}
628			crtn = cspGenKeyPair(cspHand,
629				CSSM_ALGID_RSA,
630				ENCR_USAGE_NAME,
631				ENCR_USAGE_NAME_LEN,
632				CSP_KEY_SIZE_DEFAULT,
633				&origPub,
634				encrIsRef,			// pubIsRef
635				CSSM_KEYUSE_ENCRYPT,
636				CSSM_KEYBLOB_RAW_FORMAT_NONE,
637				&origPriv,
638				decrIsRef,			// privIsRef
639				CSSM_KEYUSE_DECRYPT,
640				CSSM_KEYBLOB_RAW_FORMAT_NONE,
641				CSSM_FALSE);		// genSeed
642			if(crtn) {
643				rtn = 1;
644				goto testDone;
645			}
646			origDecrKey = &origPriv;
647			origEncrKey = &origPub;
648			encrAlg = CSSM_ALGID_RSA;
649			encrMode = CSSM_ALGMODE_NONE;
650			encrPad = CSSM_PADDING_PKCS1;
651			genRsaKey = CSSM_TRUE;
652			maxPtextSize = origPriv.KeyHeader.LogicalKeySizeInBits / 8;
653			// a weird BSAFE requirement which is not documented
654			maxPtextSize -= 11;
655		}
656		else {
657			genRsaKey = CSSM_FALSE;
658		}
659
660		/* now the tests, symmetric and/or asymmetric wrapping */
661		if(doSymmWrap) {
662			CSSM_KEY_PTR wrapKey;
663			if(!quiet) {
664				printf("   ...Doing symmetric wrap\n");
665			}
666			wrapKey = cspGenSymKey(cspHand,
667				CSSM_ALGID_DES,
668				WRAP_USAGE_NAME,
669				WRAP_USAGE_NAME_LEN,
670				/* for now, wrapping keys have to have keyuse_any */
671				/* CSSM_KEYUSE_WRAP | CSSM_KEYUSE_UNWRAP, */
672				WRAP_USAGE_ANY ? CSSM_KEYUSE_ANY :
673						CSSM_KEYUSE_WRAP | CSSM_KEYUSE_UNWRAP,
674				CSP_KEY_SIZE_DEFAULT,
675				CSSM_TRUE);		// FIXME - try both
676			if(wrapKey == NULL) {
677				rtn = 1;
678				goto testDone;
679			}
680			if(forcePkcs) {
681				/* symmetric wrapping key ==> PKCS7 */
682				wrapFormat = CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS7;
683			}
684			else {
685				/* default */
686				wrapFormat = CSSM_KEYBLOB_WRAPPED_FORMAT_NONE;
687			}
688			if(doTest(cspHand,
689					origEncrKey,
690					origDecrKey,
691					wrapKey,
692					wrapKey,
693					CSSM_ALGID_DES,				// wrapAlg
694					CSSM_ALGMODE_CBCPadIV8,		// wrapMode
695					wrapFormat,
696					CSSM_PADDING_PKCS5,			// wrapPad
697					encrAlg,
698					encrMode,
699					encrPad,
700					wrapOnly,
701					maxPtextSize,
702					quiet)) {
703				rtn = 1;
704				goto testDone;
705			}
706			cspFreeKey(cspHand, wrapKey);
707			CSSM_FREE(wrapKey);					// mallocd by cspGenSymKey
708			wrapKey = NULL;
709		}
710		if(doAsymmWrap &&
711		   !(RSA_WRAP_RESTRICTION && (origEncrKey != origDecrKey))) {
712			/* skip wrapping asymmetric key with asymmetric key */
713			CSSM_KEY wrapPrivKey;
714			CSSM_KEY wrapPubKey;
715
716			if(!quiet) {
717				printf("   ...Doing asymmetric wrap\n");
718			}
719			crtn = cspGenKeyPair(cspHand,
720				CSSM_ALGID_RSA,
721				WRAP_USAGE_NAME,
722				WRAP_USAGE_NAME_LEN,
723				CSP_RSA_KEY_SIZE_DEFAULT,
724				&wrapPubKey,
725				CSSM_TRUE,				// both are ref
726				WRAP_USAGE_ANY ? CSSM_KEYUSE_ANY : CSSM_KEYUSE_WRAP,
727				CSSM_KEYBLOB_RAW_FORMAT_NONE,
728				&wrapPrivKey,
729				CSSM_TRUE,				// FIXME privIsRef
730				WRAP_USAGE_ANY ? CSSM_KEYUSE_ANY : CSSM_KEYUSE_UNWRAP,
731				CSSM_KEYBLOB_RAW_FORMAT_NONE,
732				CSSM_FALSE);			// genSeed
733			if(crtn) {
734				rtn = 1;
735				goto testDone;
736			}
737			if(forcePkcs) {
738				/* asymmetric wrapping key ==> PKCS8 */
739				wrapFormat = CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS8;
740			}
741			else {
742				wrapFormat = CSSM_KEYBLOB_WRAPPED_FORMAT_NONE;
743			}
744			if(doTest(cspHand,
745					origEncrKey,
746					origDecrKey,
747					&wrapPubKey,
748					&wrapPrivKey,
749					CSSM_ALGID_RSA,			// wrapAlg
750					CSSM_ALGMODE_NONE,		// wrapMode
751					wrapFormat,
752					CSSM_PADDING_PKCS1,		// wrapPad
753					encrAlg,
754					encrMode,
755					encrPad,
756					wrapOnly,
757					maxPtextSize,
758					quiet)) {
759				rtn = 1;
760				goto testDone;
761			}
762			cspFreeKey(cspHand, &wrapPubKey);
763			cspFreeKey(cspHand, &wrapPrivKey);
764		}
765		//if(doNullWrap && (origDecrKey != origEncrKey)) {
766		if(doNullWrap) {
767			/* with X, we can do NULL wrap/unwrap of any key */
768			if(!quiet) {
769				printf("   ...Doing NULL wrap\n");
770			}
771			if(doTest(cspHand,
772					origEncrKey,
773					origDecrKey,
774					NULL,
775					NULL,
776					CSSM_ALGID_NONE,		// wrapAlg
777					CSSM_ALGMODE_NONE,		// wrapMode
778					CSSM_KEYBLOB_WRAPPED_FORMAT_NONE,
779					CSSM_PADDING_NONE,		// wrapPad
780					encrAlg,
781					encrMode,
782					encrPad,
783					wrapOnly,
784					maxPtextSize,
785					quiet)) {
786				rtn = 1;
787				goto testDone;
788			}
789		}
790
791		if(origSess != NULL) {
792			cspFreeKey(cspHand, origSess);
793			CSSM_FREE(origSess);
794		}
795		if(genRsaKey) {
796			cspFreeKey(cspHand, &origPub);
797			cspFreeKey(cspHand, &origPriv);
798		}
799		if(loops && (loop == loops)) {
800			break;
801		}
802	}
803testDone:
804	CSSM_ModuleDetach(cspHand);
805	if((rtn == 0) && !quiet) {
806		printf("%s test complete\n", argv[0]);
807	}
808	return rtn;
809}
810