1/* Copyright (c) 1997,2003-2006,2008,2010,2013 Apple Inc.
2 *
3 * cspwrap.c - wrappers to simplify access to CDSA
4 *
5 * Revision History
6 * ----------------
7 *   3 May 2000 Doug Mitchell
8 *		Ported to X/CDSA2.
9 *  12 Aug 1997	Doug Mitchell at Apple
10 *		Created.
11 */
12
13#include <Security/cssmapple.h>
14#include <Security/cssm.h>
15#include "cspwrap.h"
16#include "common.h"
17#include <stdio.h>
18#include <stdlib.h>
19#include <string.h>
20/* MCF hack */
21// #include <CarbonCore/MacTypes.h>
22#include <MacTypes.h>
23/* end MCF */
24
25#ifndef	NULL
26#define NULL ((void *)0)
27#endif	/* NULL */
28#ifndef	MAX
29#define MAX(a,b)	((a > b) ? a : b)
30#define MIN(a,b)	((a < b) ? a : b)
31#endif
32
33#pragma mark --------- Key Generation ---------
34
35/*
36 * Key generation
37 */
38#define FEE_PRIV_DATA_SIZE	20
39/*
40 * Debug/test only. BsafeCSP only (long since disabled, in Puma).
41 * This results in quicker but less secure RSA key generation.
42 */
43#define RSA_WEAK_KEYS		0
44
45/*
46 * Force bad data in KeyData prior to generating, deriving, or
47 * wrapping key to ensure that the CSP ignores incoming
48 * KeyData.
49 */
50static void setBadKeyData(
51	CSSM_KEY_PTR key)
52{
53	key->KeyData.Data = (uint8 *)0xeaaaeaaa;	// bad ptr
54	key->KeyData.Length = 1;	// no key can fit here
55}
56
57/*
58 * Generate key pair of arbitrary algorithm.
59 * FEE keys will have random private data.
60 */
61CSSM_RETURN cspGenKeyPair(CSSM_CSP_HANDLE cspHand,
62	uint32 algorithm,
63	const char *keyLabel,
64	unsigned keyLabelLen,
65	uint32 keySize,					// in bits
66	CSSM_KEY_PTR pubKey,			// mallocd by caller
67	CSSM_BOOL pubIsRef,				// true - reference key, false - data
68	uint32 pubKeyUsage,				// CSSM_KEYUSE_ENCRYPT, etc.
69	CSSM_KEYBLOB_FORMAT pubFormat,	// Optional. Specify 0 or CSSM_KEYBLOB_RAW_FORMAT_NONE
70									//   to get the default format.
71	CSSM_KEY_PTR privKey,			// mallocd by caller
72	CSSM_BOOL privIsRef,			// true - reference key, false - data
73	uint32 privKeyUsage,			// CSSM_KEYUSE_DECRYPT, etc.
74	CSSM_KEYBLOB_FORMAT privFormat,	// optional 0 ==> default
75	CSSM_BOOL genSeed)				// FEE only. True: we generate seed and CSP
76									// will hash it. False: CSP generates random
77									// seed.
78{
79	CSSM_RETURN				crtn;
80	CSSM_CC_HANDLE 			ccHand;
81	CSSM_DATA				privData = {0, NULL};		// mallocd for FEE
82	CSSM_CRYPTO_DATA		privCData;
83	CSSM_CRYPTO_DATA_PTR	privCDataPtr = NULL;
84	CSSM_DATA				keyLabelData;
85	uint32					pubAttr;
86	uint32					privAttr;
87	CSSM_RETURN 			ocrtn = CSSM_OK;
88
89	if(keySize == CSP_KEY_SIZE_DEFAULT) {
90		keySize = cspDefaultKeySize(algorithm);
91	}
92
93	/* pre-context-create algorithm-specific stuff */
94	switch(algorithm) {
95		case CSSM_ALGID_FEE:
96			if(genSeed) {
97				/* cook up random privData */
98				privData.Data = (uint8 *)CSSM_MALLOC(FEE_PRIV_DATA_SIZE);
99				privData.Length = FEE_PRIV_DATA_SIZE;
100				appGetRandomBytes(privData.Data, FEE_PRIV_DATA_SIZE);
101				privCData.Param = privData;
102				privCData.Callback = NULL;
103				privCDataPtr = &privCData;
104			}
105			/* else CSP generates random seed/key */
106			break;
107		case CSSM_ALGID_RSA:
108			break;
109		case CSSM_ALGID_DSA:
110			break;
111		case CSSM_ALGID_ECDSA:
112			break;
113		default:
114			printf("cspGenKeyPair: Unknown algorithm\n");
115			/* but what the hey */
116			privCDataPtr = NULL;
117			break;
118	}
119	keyLabelData.Data        = (uint8 *)keyLabel,
120	keyLabelData.Length      = keyLabelLen;
121	memset(pubKey, 0, sizeof(CSSM_KEY));
122	memset(privKey, 0, sizeof(CSSM_KEY));
123	setBadKeyData(pubKey);
124	setBadKeyData(privKey);
125
126	crtn = CSSM_CSP_CreateKeyGenContext(cspHand,
127		algorithm,
128		keySize,
129		privCDataPtr,			// Seed
130		NULL,					// Salt
131		NULL,					// StartDate
132		NULL,					// EndDate
133		NULL,					// Params
134		&ccHand);
135	if(crtn) {
136		printError("CSSM_CSP_CreateKeyGenContext", crtn);
137		ocrtn = crtn;
138		goto abort;
139	}
140	/* cook up attribute bits */
141	if(pubIsRef) {
142		pubAttr = CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE;
143	}
144	else {
145		pubAttr = CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE;
146	}
147	if(privIsRef) {
148		privAttr = CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE;
149	}
150	else {
151		privAttr = CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE;
152	}
153
154	/* post-context-create algorithm-specific stuff */
155	switch(algorithm) {
156		case CSSM_ALGID_RSA:
157
158			#if	RSA_WEAK_KEYS
159			{
160				/* for testing, speed up key gen by using the
161				* undocumented "CUSTOM" key gen mode. This
162				* results in the CSP using AI_RsaKeyGen instead of
163				* AI_RSAStrongKeyGen.
164				*/
165				crtn = AddContextAttribute(ccHand,
166					CSSM_ATTRIBUTE_MODE,
167					sizeof(uint32),
168					CAT_Uint32,
169					NULL,
170					CSSM_ALGMODE_CUSTOM);
171				if(crtn) {
172					printError("CSSM_UpdateContextAttributes", crtn);
173					return crtn;
174				}
175			}
176			#endif	// RSA_WEAK_KEYS
177			break;
178
179		 case CSSM_ALGID_DSA:
180			/*
181			 * extra step - generate params - this just adds some
182			 * info to the context
183			 */
184			{
185				CSSM_DATA dummy = {0, NULL};
186				crtn = CSSM_GenerateAlgorithmParams(ccHand,
187					keySize, &dummy);
188				if(crtn) {
189					printError("CSSM_GenerateAlgorithmParams", crtn);
190					return crtn;
191				}
192				appFreeCssmData(&dummy, CSSM_FALSE);
193			}
194			break;
195		default:
196			break;
197	}
198
199	/* optional format specifiers */
200	if(!pubIsRef && (pubFormat != CSSM_KEYBLOB_RAW_FORMAT_NONE)) {
201		crtn = AddContextAttribute(ccHand,
202			CSSM_ATTRIBUTE_PUBLIC_KEY_FORMAT,
203			sizeof(uint32),
204			CAT_Uint32,
205			NULL,
206			pubFormat);
207		if(crtn) {
208			printError("AddContextAttribute(CSSM_ATTRIBUTE_PUBLIC_KEY_FORMAT)", crtn);
209			return crtn;
210		}
211	}
212	if(!privIsRef && (privFormat != CSSM_KEYBLOB_RAW_FORMAT_NONE)) {
213		crtn = AddContextAttribute(ccHand,
214			CSSM_ATTRIBUTE_PRIVATE_KEY_FORMAT,
215			sizeof(uint32),			// currently sizeof CSSM_DATA
216			CAT_Uint32,
217			NULL,
218			privFormat);
219		if(crtn) {
220			printError("AddContextAttribute(CSSM_ATTRIBUTE_PRIVATE_KEY_FORMAT)", crtn);
221			return crtn;
222		}
223	}
224	crtn = CSSM_GenerateKeyPair(ccHand,
225		pubKeyUsage,
226		pubAttr,
227		&keyLabelData,
228		pubKey,
229		privKeyUsage,
230		privAttr,
231		&keyLabelData,			// same labels
232		NULL,					// CredAndAclEntry
233		privKey);
234	if(crtn) {
235		printError("CSSM_GenerateKeyPair", crtn);
236		ocrtn = crtn;
237		goto abort;
238	}
239	/* basic checks...*/
240	if(privIsRef) {
241		if(privKey->KeyHeader.BlobType != CSSM_KEYBLOB_REFERENCE) {
242			printf("privKey blob type: exp %u got %u\n",
243				CSSM_KEYBLOB_REFERENCE, (unsigned)privKey->KeyHeader.BlobType);
244			ocrtn = CSSM_ERRCODE_INTERNAL_ERROR;
245			goto abort;
246		}
247	}
248	else {
249		switch(privKey->KeyHeader.BlobType) {
250			case CSSM_KEYBLOB_RAW:
251				break;
252			default:
253				printf("privKey blob type: exp raw, got %u\n",
254					(unsigned)privKey->KeyHeader.BlobType);
255				ocrtn = CSSM_ERRCODE_INTERNAL_ERROR;
256				goto abort;
257		}
258	}
259	if(pubIsRef) {
260		if(pubKey->KeyHeader.BlobType != CSSM_KEYBLOB_REFERENCE) {
261			printf("pubKey blob type: exp %u got %u\n",
262				CSSM_KEYBLOB_REFERENCE, (unsigned)pubKey->KeyHeader.BlobType);
263			ocrtn = CSSM_ERRCODE_INTERNAL_ERROR;
264			goto abort;
265		}
266	}
267	else {
268		switch(pubKey->KeyHeader.BlobType) {
269			case CSSM_KEYBLOB_RAW:
270				break;
271			default:
272				printf("pubKey blob type: exp raw or raw_berder, got %u\n",
273					(unsigned)pubKey->KeyHeader.BlobType);
274				ocrtn = CSSM_ERRCODE_INTERNAL_ERROR;
275				goto abort;
276		}
277	}
278abort:
279	if(ccHand != 0) {
280		crtn = CSSM_DeleteContext(ccHand);
281		if(crtn) {
282			printError("CSSM_DeleteContext", crtn);
283			ocrtn = CSSM_ERRCODE_INTERNAL_ERROR;
284		}
285	}
286	if(privData.Data != NULL) {
287		CSSM_FREE(privData.Data);
288	}
289	return ocrtn;
290}
291
292/*
293 * Generate FEE key pair with optional primeType, curveType, and seed (password) data.
294 */
295CSSM_RETURN cspGenFEEKeyPair(CSSM_CSP_HANDLE cspHand,
296	const char *keyLabel,
297	unsigned keyLabelLen,
298	uint32 keySize,					// in bits
299	uint32 primeType,				// CSSM_FEE_PRIME_TYPE_MERSENNE, etc.
300	uint32 curveType,				// CSSM_FEE_CURVE_TYPE_MONTGOMERY, etc.
301	CSSM_KEY_PTR pubKey,			// mallocd by caller
302	CSSM_BOOL pubIsRef,				// true - reference key, false - data
303	uint32 pubKeyUsage,				// CSSM_KEYUSE_ENCRYPT, etc.
304	CSSM_KEYBLOB_FORMAT pubFormat,	// Optional. Specify 0 or CSSM_KEYBLOB_RAW_FORMAT_NONE
305									//   to get the default format.
306	CSSM_KEY_PTR privKey,			// mallocd by caller
307	CSSM_BOOL privIsRef,			// true - reference key, false - data
308	uint32 privKeyUsage,			// CSSM_KEYUSE_DECRYPT, etc.
309	CSSM_KEYBLOB_FORMAT privFormat,	// optional 0 ==> default
310	const CSSM_DATA *seedData)		// Present: CSP will hash this for private data.
311									// NULL: CSP generates random seed.
312{
313	CSSM_RETURN				crtn;
314	CSSM_CC_HANDLE 			ccHand;
315	CSSM_CRYPTO_DATA		privCData;
316	CSSM_CRYPTO_DATA_PTR	privCDataPtr = NULL;
317	CSSM_DATA				keyLabelData;
318	uint32					pubAttr;
319	uint32					privAttr;
320	CSSM_RETURN 			ocrtn = CSSM_OK;
321
322	/* pre-context-create algorithm-specific stuff */
323	if(seedData) {
324		privCData.Param = *((CSSM_DATA_PTR)seedData);
325		privCData.Callback = NULL;
326		privCDataPtr = &privCData;
327	}
328	/* else CSP generates random seed/key */
329
330	if(keySize == CSP_KEY_SIZE_DEFAULT) {
331		keySize = CSP_FEE_KEY_SIZE_DEFAULT;
332	}
333
334	keyLabelData.Data        = (uint8 *)keyLabel,
335	keyLabelData.Length      = keyLabelLen;
336	memset(pubKey, 0, sizeof(CSSM_KEY));
337	memset(privKey, 0, sizeof(CSSM_KEY));
338	setBadKeyData(pubKey);
339	setBadKeyData(privKey);
340
341	crtn = CSSM_CSP_CreateKeyGenContext(cspHand,
342		CSSM_ALGID_FEE,
343		keySize,
344		privCDataPtr,			// Seed
345		NULL,					// Salt
346		NULL,					// StartDate
347		NULL,					// EndDate
348		NULL,					// Params
349		&ccHand);
350	if(crtn) {
351		printError("CSSM_CSP_CreateKeyGenContext", crtn);
352		ocrtn = crtn;
353		goto abort;
354	}
355	/* cook up attribute bits */
356	if(pubIsRef) {
357		pubAttr = CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE;
358	}
359	else {
360		pubAttr = CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE;
361	}
362	if(privIsRef) {
363		privAttr = CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE;
364	}
365	else {
366		privAttr = CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE;
367	}
368
369	/* optional post-context-create stuff */
370	if(primeType != CSSM_FEE_PRIME_TYPE_DEFAULT) {
371		crtn = AddContextAttribute(ccHand,
372			CSSM_ATTRIBUTE_FEE_PRIME_TYPE,
373			sizeof(uint32),
374			CAT_Uint32,
375			NULL,
376			primeType);
377		if(crtn) {
378			printError("AddContextAttribute(CSSM_ATTRIBUTE_FEE_PRIME_TYPE)", crtn);
379			return crtn;
380		}
381	}
382	if(curveType != CSSM_FEE_CURVE_TYPE_DEFAULT) {
383		crtn = AddContextAttribute(ccHand,
384			CSSM_ATTRIBUTE_FEE_CURVE_TYPE,
385			sizeof(uint32),
386			CAT_Uint32,
387			NULL,
388			curveType);
389		if(crtn) {
390			printError("AddContextAttribute(CSSM_ATTRIBUTE_FEE_CURVE_TYPE)", crtn);
391			return crtn;
392		}
393	}
394
395	if(pubFormat != CSSM_KEYBLOB_RAW_FORMAT_NONE) {
396		crtn = AddContextAttribute(ccHand,
397			CSSM_ATTRIBUTE_PUBLIC_KEY_FORMAT,
398			sizeof(uint32),
399			CAT_Uint32,
400			NULL,
401			pubFormat);
402		if(crtn) {
403			printError("AddContextAttribute(CSSM_ATTRIBUTE_PUBLIC_KEY_FORMAT)", crtn);
404			return crtn;
405		}
406	}
407	if(privFormat != CSSM_KEYBLOB_RAW_FORMAT_NONE) {
408		crtn = AddContextAttribute(ccHand,
409			CSSM_ATTRIBUTE_PRIVATE_KEY_FORMAT,
410			sizeof(uint32),			// currently sizeof CSSM_DATA
411			CAT_Uint32,
412			NULL,
413			pubFormat);
414		if(crtn) {
415			printError("AddContextAttribute(CSSM_ATTRIBUTE_PRIVATE_KEY_FORMAT)", crtn);
416			return crtn;
417		}
418	}
419	crtn = CSSM_GenerateKeyPair(ccHand,
420		pubKeyUsage,
421		pubAttr,
422		&keyLabelData,
423		pubKey,
424		privKeyUsage,
425		privAttr,
426		&keyLabelData,			// same labels
427		NULL,					// CredAndAclEntry
428		privKey);
429	if(crtn) {
430		printError("CSSM_GenerateKeyPair", crtn);
431		ocrtn = crtn;
432		goto abort;
433	}
434	/* basic checks...*/
435	if(privIsRef) {
436		if(privKey->KeyHeader.BlobType != CSSM_KEYBLOB_REFERENCE) {
437			printf("privKey blob type: exp %u got %u\n",
438				CSSM_KEYBLOB_REFERENCE, (unsigned)privKey->KeyHeader.BlobType);
439			ocrtn = CSSM_ERRCODE_INTERNAL_ERROR;
440			goto abort;
441		}
442	}
443	else {
444		switch(privKey->KeyHeader.BlobType) {
445			case CSSM_KEYBLOB_RAW:
446				break;
447			default:
448				printf("privKey blob type: exp raw, got %u\n",
449					(unsigned)privKey->KeyHeader.BlobType);
450				ocrtn = CSSM_ERRCODE_INTERNAL_ERROR;
451				goto abort;
452		}
453	}
454	if(pubIsRef) {
455		if(pubKey->KeyHeader.BlobType != CSSM_KEYBLOB_REFERENCE) {
456			printf("pubKey blob type: exp %u got %u\n",
457				CSSM_KEYBLOB_REFERENCE, (unsigned)pubKey->KeyHeader.BlobType);
458			ocrtn = CSSM_ERRCODE_INTERNAL_ERROR;
459			goto abort;
460		}
461	}
462	else {
463		switch(pubKey->KeyHeader.BlobType) {
464			case CSSM_KEYBLOB_RAW:
465				break;
466			default:
467				printf("pubKey blob type: exp raw or raw_berder, got %u\n",
468					(unsigned)pubKey->KeyHeader.BlobType);
469				ocrtn = CSSM_ERRCODE_INTERNAL_ERROR;
470				goto abort;
471		}
472	}
473abort:
474	if(ccHand != 0) {
475		crtn = CSSM_DeleteContext(ccHand);
476		if(crtn) {
477			printError("CSSM_DeleteContext", crtn);
478			ocrtn = CSSM_ERRCODE_INTERNAL_ERROR;
479		}
480	}
481	return ocrtn;
482}
483
484/*
485 * Generate DSA key pair with optional generateAlgParams and optional
486 * incoming parameters.
487 */
488CSSM_RETURN cspGenDSAKeyPair(CSSM_CSP_HANDLE cspHand,
489	const char *keyLabel,
490	unsigned keyLabelLen,
491	uint32 keySize,					// in bits
492	CSSM_KEY_PTR pubKey,			// mallocd by caller
493	CSSM_BOOL pubIsRef,				// true - reference key, false - data
494	uint32 pubKeyUsage,				// CSSM_KEYUSE_ENCRYPT, etc.
495	CSSM_KEYBLOB_FORMAT pubFormat,	// Optional. Specify 0 or CSSM_KEYBLOB_RAW_FORMAT_NONE
496									//   to get the default format.
497	CSSM_KEY_PTR privKey,			// mallocd by caller
498	CSSM_BOOL privIsRef,			// true - reference key, false - data
499	uint32 privKeyUsage,			// CSSM_KEYUSE_DECRYPT, etc.
500	CSSM_KEYBLOB_FORMAT privFormat,	// Optional. Specify 0 or CSSM_KEYBLOB_RAW_FORMAT_NONE
501									//   to get the default format.
502	CSSM_BOOL genParams,
503	CSSM_DATA_PTR paramData)		// optional
504{
505	CSSM_RETURN				crtn;
506	CSSM_CC_HANDLE 			ccHand;
507	CSSM_DATA				keyLabelData;
508	uint32					pubAttr;
509	uint32					privAttr;
510	CSSM_RETURN 			ocrtn = CSSM_OK;
511
512	if(keySize == CSP_KEY_SIZE_DEFAULT) {
513		keySize = CSP_DSA_KEY_SIZE_DEFAULT;
514	}
515	keyLabelData.Data        = (uint8 *)keyLabel,
516	keyLabelData.Length      = keyLabelLen;
517	memset(pubKey, 0, sizeof(CSSM_KEY));
518	memset(privKey, 0, sizeof(CSSM_KEY));
519	setBadKeyData(pubKey);
520	setBadKeyData(privKey);
521
522	crtn = CSSM_CSP_CreateKeyGenContext(cspHand,
523		CSSM_ALGID_DSA,
524		keySize,
525		NULL,					// Seed
526		NULL,					// Salt
527		NULL,					// StartDate
528		NULL,					// EndDate
529		paramData,
530		&ccHand);
531	if(crtn) {
532		printError("CSSM_CSP_CreateKeyGenContext", crtn);
533		ocrtn = crtn;
534		goto abort;
535	}
536
537	/* cook up attribute bits */
538	if(pubIsRef) {
539		pubAttr = CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE;
540	}
541	else {
542		pubAttr = CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE;
543	}
544	if(privIsRef) {
545		privAttr = CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE;
546	}
547	else {
548		privAttr = CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE;
549	}
550
551	if(genParams) {
552		/*
553		 * extra step - generate params - this just adds some
554		 * info to the context
555		 */
556		CSSM_DATA dummy = {0, NULL};
557		crtn = CSSM_GenerateAlgorithmParams(ccHand,
558			keySize, &dummy);
559		if(crtn) {
560			printError("CSSM_GenerateAlgorithmParams", crtn);
561			return crtn;
562		}
563		appFreeCssmData(&dummy, CSSM_FALSE);
564	}
565
566	/* optional format specifiers */
567	if(!pubIsRef && (pubFormat != CSSM_KEYBLOB_RAW_FORMAT_NONE)) {
568		crtn = AddContextAttribute(ccHand,
569			CSSM_ATTRIBUTE_PUBLIC_KEY_FORMAT,
570			sizeof(uint32),
571			CAT_Uint32,
572			NULL,
573			pubFormat);
574		if(crtn) {
575			printError("AddContextAttribute(CSSM_ATTRIBUTE_PUBLIC_KEY_FORMAT)", crtn);
576			return crtn;
577		}
578	}
579	if(!privIsRef && (privFormat != CSSM_KEYBLOB_RAW_FORMAT_NONE)) {
580		crtn = AddContextAttribute(ccHand,
581			CSSM_ATTRIBUTE_PRIVATE_KEY_FORMAT,
582			sizeof(uint32),			// currently sizeof CSSM_DATA
583			CAT_Uint32,
584			NULL,
585			privFormat);
586		if(crtn) {
587			printError("AddContextAttribute(CSSM_ATTRIBUTE_PRIVATE_KEY_FORMAT)", crtn);
588			return crtn;
589		}
590	}
591
592	crtn = CSSM_GenerateKeyPair(ccHand,
593		pubKeyUsage,
594		pubAttr,
595		&keyLabelData,
596		pubKey,
597		privKeyUsage,
598		privAttr,
599		&keyLabelData,			// same labels
600		NULL,					// CredAndAclEntry
601		privKey);
602	if(crtn) {
603		printError("CSSM_GenerateKeyPair", crtn);
604		ocrtn = crtn;
605		goto abort;
606	}
607	/* basic checks...*/
608	if(privIsRef) {
609		if(privKey->KeyHeader.BlobType != CSSM_KEYBLOB_REFERENCE) {
610			printf("privKey blob type: exp %u got %u\n",
611				CSSM_KEYBLOB_REFERENCE, (unsigned)privKey->KeyHeader.BlobType);
612			ocrtn = CSSM_ERRCODE_INTERNAL_ERROR;
613			goto abort;
614		}
615	}
616	else {
617		switch(privKey->KeyHeader.BlobType) {
618			case CSSM_KEYBLOB_RAW:
619				break;
620			default:
621				printf("privKey blob type: exp raw, got %u\n",
622					(unsigned)privKey->KeyHeader.BlobType);
623				ocrtn = CSSM_ERRCODE_INTERNAL_ERROR;
624				goto abort;
625		}
626	}
627	if(pubIsRef) {
628		if(pubKey->KeyHeader.BlobType != CSSM_KEYBLOB_REFERENCE) {
629			printf("pubKey blob type: exp %u got %u\n",
630				CSSM_KEYBLOB_REFERENCE, (unsigned)pubKey->KeyHeader.BlobType);
631			ocrtn = CSSM_ERRCODE_INTERNAL_ERROR;
632			goto abort;
633		}
634	}
635	else {
636		switch(pubKey->KeyHeader.BlobType) {
637			case CSSM_KEYBLOB_RAW:
638				break;
639			default:
640				printf("pubKey blob type: exp raw or raw_berder, got %u\n",
641					(unsigned)pubKey->KeyHeader.BlobType);
642				ocrtn = CSSM_ERRCODE_INTERNAL_ERROR;
643				goto abort;
644		}
645	}
646abort:
647	if(ccHand != 0) {
648		crtn = CSSM_DeleteContext(ccHand);
649		if(crtn) {
650			printError("CSSM_DeleteContext", crtn);
651			ocrtn = CSSM_ERRCODE_INTERNAL_ERROR;
652		}
653	}
654	return ocrtn;
655}
656
657
658uint32 cspDefaultKeySize(uint32 alg)
659{
660	uint32 keySizeInBits;
661	switch(alg) {
662		case CSSM_ALGID_DES:
663			keySizeInBits = CSP_DES_KEY_SIZE_DEFAULT;
664			break;
665		case CSSM_ALGID_3DES_3KEY:
666		case CSSM_ALGID_DESX:
667			keySizeInBits = CSP_DES3_KEY_SIZE_DEFAULT;
668			break;
669		case CSSM_ALGID_RC2:
670			keySizeInBits = CSP_RC2_KEY_SIZE_DEFAULT;
671			break;
672		case CSSM_ALGID_RC4:
673			keySizeInBits = CSP_RC4_KEY_SIZE_DEFAULT;
674			break;
675		case CSSM_ALGID_RC5:
676			keySizeInBits = CSP_RC5_KEY_SIZE_DEFAULT;
677			break;
678		case CSSM_ALGID_ASC:
679			keySizeInBits = CSP_ASC_KEY_SIZE_DEFAULT;
680			break;
681		case CSSM_ALGID_BLOWFISH:
682			keySizeInBits = CSP_BFISH_KEY_SIZE_DEFAULT;
683			break;
684		case CSSM_ALGID_CAST:
685			keySizeInBits = CSP_CAST_KEY_SIZE_DEFAULT;
686			break;
687		case CSSM_ALGID_IDEA:
688			keySizeInBits = CSP_IDEA_KEY_SIZE_DEFAULT;
689			break;
690		case CSSM_ALGID_AES:
691			keySizeInBits = CSP_AES_KEY_SIZE_DEFAULT;
692			break;
693		case CSSM_ALGID_SHA1HMAC:
694			keySizeInBits = CSP_HMAC_SHA_KEY_SIZE_DEFAULT;
695			break;
696		case CSSM_ALGID_MD5HMAC:
697			keySizeInBits = CSP_HMAC_MD5_KEY_SIZE_DEFAULT;
698			break;
699		case CSSM_ALGID_FEE:
700			keySizeInBits = CSP_FEE_KEY_SIZE_DEFAULT;
701			break;
702		case CSSM_ALGID_RSA:
703			keySizeInBits = CSP_RSA_KEY_SIZE_DEFAULT;
704			break;
705		case CSSM_ALGID_DSA:
706			keySizeInBits = CSP_DSA_KEY_SIZE_DEFAULT;
707			break;
708		case CSSM_ALGID_ECDSA:
709			keySizeInBits = CSP_ECDSA_KEY_SIZE_DEFAULT;
710			break;
711		case CSSM_ALGID_NONE:
712			keySizeInBits = CSP_NULL_CRYPT_KEY_SIZE_DEF;
713			break;
714		default:
715			printf("***cspDefaultKeySize: Unknown symmetric algorithm\n");
716			keySizeInBits = 0;
717			break;
718	}
719	return keySizeInBits;
720}
721
722/*
723 * Create a random symmetric key.
724 */
725CSSM_KEY_PTR cspGenSymKey(CSSM_CSP_HANDLE cspHand,
726		uint32 				alg,
727		const char 			*keyLabel,
728		unsigned 			keyLabelLen,
729		uint32 				keyUsage,		// CSSM_KEYUSE_ENCRYPT, etc.
730		uint32 				keySizeInBits,
731		CSSM_BOOL			refKey)
732{
733	CSSM_KEY_PTR 		symKey = (CSSM_KEY_PTR)CSSM_MALLOC(sizeof(CSSM_KEY));
734	CSSM_RETURN			crtn;
735	CSSM_CC_HANDLE 		ccHand;
736	uint32				keyAttr;
737	CSSM_DATA			dummyLabel;
738
739	if(symKey == NULL) {
740		printf("Insufficient heap space\n");
741		return NULL;
742	}
743	memset(symKey, 0, sizeof(CSSM_KEY));
744	setBadKeyData(symKey);
745	if(keySizeInBits == CSP_KEY_SIZE_DEFAULT) {
746		keySizeInBits = cspDefaultKeySize(alg);
747	}
748	crtn = CSSM_CSP_CreateKeyGenContext(cspHand,
749		alg,
750		keySizeInBits,	// keySizeInBits
751		NULL,			// Seed
752		NULL,			// Salt
753		NULL,			// StartDate
754		NULL,			// EndDate
755		NULL,			// Params
756		&ccHand);
757	if(crtn) {
758		printError("CSSM_CSP_CreateKeyGenContext", crtn);
759		goto errorOut;
760	}
761	if(refKey) {
762		keyAttr = CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE;
763	}
764	else {
765		keyAttr = CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE;
766	}
767	dummyLabel.Length = keyLabelLen;
768	dummyLabel.Data = (uint8 *)keyLabel;
769
770	crtn = CSSM_GenerateKey(ccHand,
771		keyUsage,
772		keyAttr,
773		&dummyLabel,
774		NULL,			// ACL
775		symKey);
776	if(crtn) {
777		printError("CSSM_GenerateKey", crtn);
778		goto errorOut;
779	}
780	crtn = CSSM_DeleteContext(ccHand);
781	if(crtn) {
782		printError("CSSM_DeleteContext", crtn);
783		goto errorOut;
784	}
785	return symKey;
786errorOut:
787	CSSM_FREE(symKey);
788	return NULL;
789}
790
791/*
792 * Derive symmetric key.
793 * Note in the X CSP, we never return an IV.
794 */
795CSSM_KEY_PTR cspDeriveKey(CSSM_CSP_HANDLE cspHand,
796		uint32 				deriveAlg,		// CSSM_ALGID_PKCS5_PBKDF2, etc.
797		uint32				keyAlg,			// CSSM_ALGID_RC5, etc.
798		const char 			*keyLabel,
799		unsigned 			keyLabelLen,
800		uint32 				keyUsage,		// CSSM_KEYUSE_ENCRYPT, etc.
801		uint32 				keySizeInBits,
802		CSSM_BOOL			isRefKey,
803		CSSM_DATA_PTR		password,		// in PKCS-5 lingo
804		CSSM_DATA_PTR		salt,			// ditto
805		uint32				iterationCnt,	// ditto
806		CSSM_DATA_PTR		initVector)		// mallocd & RETURNED
807{
808	CSSM_KEY_PTR 				symKey = (CSSM_KEY_PTR)
809									CSSM_MALLOC(sizeof(CSSM_KEY));
810	CSSM_RETURN					crtn;
811	CSSM_CC_HANDLE 				ccHand;
812	uint32						keyAttr;
813	CSSM_DATA					dummyLabel;
814	CSSM_PKCS5_PBKDF2_PARAMS 	pbeParams;
815	CSSM_DATA					pbeData;
816	CSSM_ACCESS_CREDENTIALS		creds;
817
818	if(symKey == NULL) {
819		printf("Insufficient heap space\n");
820		return NULL;
821	}
822	memset(symKey, 0, sizeof(CSSM_KEY));
823	setBadKeyData(symKey);
824	memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
825	if(keySizeInBits == CSP_KEY_SIZE_DEFAULT) {
826		keySizeInBits = cspDefaultKeySize(keyAlg);
827	}
828	crtn = CSSM_CSP_CreateDeriveKeyContext(cspHand,
829		deriveAlg,
830		keyAlg,
831		keySizeInBits,
832		&creds,
833		NULL,			// BaseKey
834		iterationCnt,
835		salt,
836		NULL,			// seed
837		&ccHand);
838	if(crtn) {
839		printError("CSSM_CSP_CreateDeriveKeyContext", crtn);
840		goto errorOut;
841	}
842	keyAttr = CSSM_KEYATTR_EXTRACTABLE;
843	if(isRefKey) {
844		keyAttr |= (CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_SENSITIVE);
845	}
846	else {
847		keyAttr |= CSSM_KEYATTR_RETURN_DATA;
848	}
849	dummyLabel.Length = keyLabelLen;
850	dummyLabel.Data = (uint8 *)keyLabel;
851
852	/* passing in password is pretty strange....*/
853	pbeParams.Passphrase = *password;
854	pbeParams.PseudoRandomFunction =
855			CSSM_PKCS5_PBKDF2_PRF_HMAC_SHA1;
856	pbeData.Data = (uint8 *)&pbeParams;
857	pbeData.Length = sizeof(pbeParams);
858	crtn = CSSM_DeriveKey(ccHand,
859		&pbeData,
860		keyUsage,
861		keyAttr,
862		&dummyLabel,
863		NULL,			// cred and acl
864		symKey);
865	if(crtn) {
866		printError("CSSM_DeriveKey", crtn);
867		goto errorOut;
868	}
869	/* copy IV back to caller */
870	/* Nope, not supported */
871	#if 0
872	if(pbeParams.InitVector.Data != NULL) {
873		if(initVector->Data != NULL) {
874			if(initVector->Length < pbeParams.InitVector.Length) {
875				printf("***Insufficient InitVector\n");
876				goto errorOut;
877			}
878		}
879		else {
880			initVector->Data =
881				(uint8 *)CSSM_MALLOC(pbeParams.InitVector.Length);
882		}
883		memmove(initVector->Data, pbeParams.InitVector.Data,
884				pbeParams.InitVector.Length);
885		initVector->Length = pbeParams.InitVector.Length;
886		CSSM_FREE(pbeParams.InitVector.Data);
887	}
888	else {
889		printf("***Warning: CSSM_DeriveKey, no InitVector\n");
890	}
891	#endif
892	crtn = CSSM_DeleteContext(ccHand);
893	if(crtn) {
894		printError("CSSM_DeleteContext", crtn);
895		goto errorOut;
896	}
897	return symKey;
898errorOut:
899	CSSM_FREE(symKey);
900	return NULL;
901}
902
903/*
904 * Cook up a symmetric key with specified key bits and other
905 * params. Currently the CSPDL can only deal with reference keys except when
906 * doing wrap/unwrap, so we manually cook up a raw key, then we null-unwrap it.
907 */
908CSSM_RETURN cspGenSymKeyWithBits(
909	CSSM_CSP_HANDLE		cspHand,
910	CSSM_ALGORITHMS		keyAlg,
911	CSSM_KEYUSE			keyUsage,
912	const CSSM_DATA		*keyBits,
913	unsigned			keySizeInBytes,
914	CSSM_KEY_PTR		refKey)				// init'd and RETURNED
915{
916	CSSM_KEY			rawKey;
917	CSSM_KEYHEADER_PTR	hdr = &rawKey.KeyHeader;
918	CSSM_RETURN			crtn;
919
920	/* set up a raw key the CSP will accept */
921	memset(&rawKey, 0, sizeof(CSSM_KEY));
922	hdr->HeaderVersion = CSSM_KEYHEADER_VERSION;
923	hdr->BlobType = CSSM_KEYBLOB_RAW;
924	hdr->Format = CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING;
925	hdr->AlgorithmId = keyAlg;
926	hdr->KeyClass = CSSM_KEYCLASS_SESSION_KEY;
927	hdr->LogicalKeySizeInBits = keySizeInBytes * 8;
928	hdr->KeyAttr = CSSM_KEYATTR_EXTRACTABLE;
929	hdr->KeyUsage = keyUsage;
930	appSetupCssmData(&rawKey.KeyData, keySizeInBytes);
931	memmove(rawKey.KeyData.Data, keyBits->Data, keySizeInBytes);
932
933	/* convert to a ref key */
934	crtn = cspRawKeyToRef(cspHand, &rawKey, refKey);
935	appFreeCssmData(&rawKey.KeyData, CSSM_FALSE);
936	return crtn;
937}
938
939/*
940 * Free a key. This frees a CSP's resources associated with the key if
941 * the key is a reference key. It also frees key->KeyData. The CSSM_KEY
942 * struct itself is not freed.
943 * Note this has no effect on the CSP or DL cached keys unless the incoming
944 * key is a reference key.
945 */
946CSSM_RETURN	cspFreeKey(CSSM_CSP_HANDLE cspHand,
947	CSSM_KEY_PTR key)
948{
949	CSSM_RETURN crtn;
950	crtn = CSSM_FreeKey(cspHand,
951		NULL,		// access cred
952		key,
953		CSSM_FALSE);	// delete - OK? maybe should parameterize?
954	if(crtn) {
955		printError("CSSM_FreeKey", crtn);
956	}
957	return crtn;
958}
959
960/* generate a random and reasonable key size in bits for specified CSSM algorithm */
961uint32 randKeySizeBits(uint32 alg,
962	opType op)			// OT_Encrypt, etc.
963{
964	uint32 minSize;
965	uint32 maxSize;
966	uint32 size;
967
968	switch(alg) {
969		case CSSM_ALGID_DES:
970			return CSP_DES_KEY_SIZE_DEFAULT;
971		case CSSM_ALGID_3DES_3KEY:
972		case CSSM_ALGID_DESX:
973			return CSP_DES3_KEY_SIZE_DEFAULT;
974		case CSSM_ALGID_ASC:
975		case CSSM_ALGID_RC2:
976		case CSSM_ALGID_RC4:
977		case CSSM_ALGID_RC5:
978			minSize = 5 * 8;
979			maxSize = MAX_KEY_SIZE_RC245_BYTES * 8 ;	// somewhat arbitrary
980			break;
981		case CSSM_ALGID_BLOWFISH:
982			minSize = 32;
983			maxSize = 448;
984			break;
985		case CSSM_ALGID_CAST:
986			minSize = 40;
987			maxSize = 128;
988			break;
989		case CSSM_ALGID_IDEA:
990			return CSP_IDEA_KEY_SIZE_DEFAULT;
991		case CSSM_ALGID_RSA:
992			minSize = CSP_RSA_KEY_SIZE_DEFAULT;
993			maxSize = 1024;
994			break;
995		case CSSM_ALGID_DSA:
996			/* signature only, no export restriction */
997			minSize = 512;
998			maxSize = 1024;
999			break;
1000		case CSSM_ALGID_SHA1HMAC:
1001			minSize = 20 * 8;
1002			maxSize = 256 * 8;
1003			break;
1004		case CSSM_ALGID_MD5HMAC:
1005			minSize = 16 * 8;
1006			maxSize = 256 * 8;
1007			break;
1008		case CSSM_ALGID_FEE:
1009			/* FEE requires discrete sizes */
1010			size = genRand(1,4);
1011			switch(size) {
1012				case 1:
1013					return 31;
1014				case 2:
1015					if(alg == CSSM_ALGID_FEE) {
1016						return 127;
1017					}
1018					else {
1019						return 128;
1020					}
1021				case 3:
1022					return 161;
1023				case 4:
1024					return 192;
1025				default:
1026					printf("randKeySizeBits: internal error\n");
1027					return 0;
1028			}
1029		case CSSM_ALGID_ECDSA:
1030		case CSSM_ALGID_SHA1WithECDSA:
1031			/* ECDSA require discrete sizes */
1032			size = genRand(1,4);
1033			switch(size) {
1034				case 1:
1035					return 192;
1036				case 2:
1037					return 256;
1038				case 3:
1039					return 384;
1040				case 4:
1041				default:
1042					return 521;
1043			}
1044		case CSSM_ALGID_AES:
1045			size = genRand(1, 3);
1046			switch(size) {
1047				case 1:
1048					return 128;
1049				case 2:
1050					return 192;
1051				case 3:
1052					return 256;
1053			}
1054		case CSSM_ALGID_NONE:
1055			return CSP_NULL_CRYPT_KEY_SIZE_DEF;
1056		default:
1057			printf("randKeySizeBits: unknown alg\n");
1058			return CSP_KEY_SIZE_DEFAULT;
1059	}
1060	size = genRand(minSize, maxSize);
1061
1062	/* per-alg postprocessing.... */
1063	if(alg != CSSM_ALGID_RC2) {
1064		size &= ~0x7;
1065	}
1066	switch(alg) {
1067		case CSSM_ALGID_RSA:
1068			// new for X - strong keys */
1069			size &= ~(16 - 1);
1070			break;
1071		case CSSM_ALGID_DSA:
1072			/* size mod 64 == 0 */
1073			size &= ~(64 - 1);
1074			break;
1075		default:
1076			break;
1077	}
1078	return size;
1079}
1080
1081#pragma mark --------- Encrypt/Decrypt ---------
1082
1083/*
1084 * Encrypt/Decrypt
1085 */
1086/*
1087 * Common routine for encrypt/decrypt - cook up an appropriate context handle
1088 */
1089/*
1090 * When true, effectiveKeySizeInBits is passed down via the Params argument.
1091 * Otherwise, we add a customized context attribute.
1092 * Setting this true works with the stock Intel CSSM; this may well change.
1093 * Note this overloading prevent us from specifying RC5 rounds....
1094 */
1095#define EFFECTIVE_SIZE_VIA_PARAMS		0
1096CSSM_CC_HANDLE genCryptHandle(CSSM_CSP_HANDLE cspHand,
1097		uint32 algorithm,					// CSSM_ALGID_FEED, etc.
1098		uint32 mode,						// CSSM_ALGMODE_CBC, etc. - only for symmetric algs
1099		CSSM_PADDING padding,				// CSSM_PADDING_PKCS1, etc.
1100		const CSSM_KEY *key0,
1101		const CSSM_KEY *key1,				// for CSSM_ALGID_FEED only - must be the
1102											// public key
1103		const CSSM_DATA *iv,				// optional
1104		uint32 effectiveKeySizeInBits,		// 0 means skip this attribute
1105		uint32 rounds)						// ditto
1106{
1107	CSSM_CC_HANDLE cryptHand = 0;
1108	uint32 params;
1109	CSSM_RETURN crtn;
1110	CSSM_ACCESS_CREDENTIALS	creds;
1111
1112	memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
1113	#if	EFFECTIVE_SIZE_VIA_PARAMS
1114	params = effectiveKeySizeInBits;
1115	#else
1116	params = 0;
1117	#endif
1118	switch(algorithm) {
1119		case CSSM_ALGID_DES:
1120		case CSSM_ALGID_3DES_3KEY_EDE:
1121		case CSSM_ALGID_DESX:
1122		case CSSM_ALGID_ASC:
1123		case CSSM_ALGID_RC2:
1124		case CSSM_ALGID_RC4:
1125		case CSSM_ALGID_RC5:
1126		case CSSM_ALGID_AES:
1127		case CSSM_ALGID_BLOWFISH:
1128		case CSSM_ALGID_CAST:
1129		case CSSM_ALGID_IDEA:
1130		case CSSM_ALGID_NONE:		// used for wrapKey()
1131			crtn = CSSM_CSP_CreateSymmetricContext(cspHand,
1132				algorithm,
1133				mode,
1134				NULL,			// access cred
1135				key0,
1136				iv,				// InitVector
1137				padding,
1138				NULL,			// Params
1139				&cryptHand);
1140			if(crtn) {
1141				printError("CSSM_CSP_CreateSymmetricContext", crtn);
1142				return 0;
1143			}
1144			break;
1145		case CSSM_ALGID_FEED:
1146		case CSSM_ALGID_FEEDEXP:
1147		case CSSM_ALGID_FEECFILE:
1148		case CSSM_ALGID_RSA:
1149			 crtn = CSSM_CSP_CreateAsymmetricContext(cspHand,
1150				algorithm,
1151				&creds,			// access
1152				key0,
1153				padding,
1154				&cryptHand);
1155			if(crtn) {
1156				printError("CSSM_CSP_CreateAsymmetricContext", crtn);
1157				return 0;
1158			}
1159			if(key1 != NULL) {
1160				/*
1161				 * FEED, some CFILE. Add (non-standard) second key attribute.
1162				 */
1163				crtn = AddContextAttribute(cryptHand,
1164						CSSM_ATTRIBUTE_PUBLIC_KEY,
1165						sizeof(CSSM_KEY),			// currently sizeof CSSM_DATA
1166						CAT_Ptr,
1167						key1,
1168						0);
1169				if(crtn) {
1170					printError("AddContextAttribute", crtn);
1171					return 0;
1172				}
1173			}
1174			if(mode != CSSM_ALGMODE_NONE) {
1175				/* special case, e.g., CSSM_ALGMODE_PUBLIC_KEY */
1176				crtn = AddContextAttribute(cryptHand,
1177						CSSM_ATTRIBUTE_MODE,
1178						sizeof(uint32),
1179						CAT_Uint32,
1180						NULL,
1181						mode);
1182				if(crtn) {
1183					printError("AddContextAttribute", crtn);
1184					return 0;
1185				}
1186			}
1187			break;
1188		default:
1189			printf("genCryptHandle: bogus algorithm\n");
1190			return 0;
1191	}
1192	#if		!EFFECTIVE_SIZE_VIA_PARAMS
1193	/* add optional EffectiveKeySizeInBits and rounds attributes */
1194	if(effectiveKeySizeInBits != 0) {
1195		CSSM_CONTEXT_ATTRIBUTE attr;
1196		attr.AttributeType = CSSM_ATTRIBUTE_EFFECTIVE_BITS;
1197		attr.AttributeLength = sizeof(uint32);
1198		attr.Attribute.Uint32 = effectiveKeySizeInBits;
1199		crtn = CSSM_UpdateContextAttributes(
1200			cryptHand,
1201			1,
1202			&attr);
1203		if(crtn) {
1204			printError("CSSM_UpdateContextAttributes", crtn);
1205			return crtn;
1206		}
1207	}
1208	#endif
1209
1210	if(rounds != 0) {
1211		CSSM_CONTEXT_ATTRIBUTE attr;
1212		attr.AttributeType = CSSM_ATTRIBUTE_ROUNDS;
1213		attr.AttributeLength = sizeof(uint32);
1214		attr.Attribute.Uint32 = rounds;
1215		crtn = CSSM_UpdateContextAttributes(
1216			cryptHand,
1217			1,
1218			&attr);
1219		if(crtn) {
1220			printError("CSSM_UpdateContextAttributes", crtn);
1221			return crtn;
1222		}
1223	}
1224
1225	return cryptHand;
1226}
1227
1228CSSM_RETURN cspEncrypt(CSSM_CSP_HANDLE cspHand,
1229		uint32 algorithm,					// CSSM_ALGID_FEED, etc.
1230		uint32 mode,						// CSSM_ALGMODE_CBC, etc. - only for symmetric algs
1231		CSSM_PADDING padding,				// CSSM_PADDING_PKCS1, etc.
1232		const CSSM_KEY *key,				// public or session key
1233		const CSSM_KEY *pubKey,				// for CSSM_ALGID_FEED, CSSM_ALGID_FEECFILE only
1234		uint32 effectiveKeySizeInBits,		// 0 means skip this attribute
1235		uint32 rounds,						// ditto
1236		const CSSM_DATA *iv,				// init vector, optional
1237		const CSSM_DATA *ptext,
1238		CSSM_DATA_PTR ctext,				// RETURNED
1239		CSSM_BOOL mallocCtext)				// if true, and ctext empty, malloc
1240											// by getting size from CSP
1241{
1242	CSSM_CC_HANDLE 	cryptHand;
1243	CSSM_RETURN		crtn;
1244	CSSM_SIZE		bytesEncrypted;
1245	CSSM_DATA		remData = {0, NULL};
1246	CSSM_RETURN		ocrtn = CSSM_OK;
1247	unsigned		origCtextLen;			// the amount we malloc, if any
1248	CSSM_RETURN		savedErr = CSSM_OK;
1249	CSSM_BOOL		restoreErr = CSSM_FALSE;
1250
1251	cryptHand = genCryptHandle(cspHand,
1252		algorithm,
1253		mode,
1254		padding,
1255		key,
1256		pubKey,
1257		iv,
1258		effectiveKeySizeInBits,
1259		rounds);
1260	if(cryptHand == 0) {
1261		return CSSMERR_CSSM_INTERNAL_ERROR;
1262	}
1263	if(mallocCtext && (ctext->Length == 0)) {
1264		CSSM_QUERY_SIZE_DATA querySize;
1265		querySize.SizeInputBlock = ptext->Length;
1266		crtn = CSSM_QuerySize(cryptHand,
1267			CSSM_TRUE,						// encrypt
1268			1,
1269			&querySize);
1270		if(crtn) {
1271			printError("CSSM_QuerySize", crtn);
1272			ocrtn = crtn;
1273			goto abort;
1274		}
1275		if(querySize.SizeOutputBlock == 0) {
1276			/* CSP couldn't figure this out; skip our malloc */
1277			printf("***cspEncrypt: warning: cipherTextSize unknown; "
1278				"skipping malloc\n");
1279			origCtextLen = 0;
1280		}
1281		else {
1282			ctext->Data = (uint8 *)
1283				appMalloc(querySize.SizeOutputBlock, NULL);
1284			if(ctext->Data == NULL) {
1285				printf("Insufficient heap space\n");
1286				ocrtn = CSSM_ERRCODE_MEMORY_ERROR;
1287				goto abort;
1288			}
1289			ctext->Length = origCtextLen = querySize.SizeOutputBlock;
1290			memset(ctext->Data, 0, ctext->Length);
1291		}
1292	}
1293	else {
1294		origCtextLen = ctext->Length;
1295	}
1296	crtn = CSSM_EncryptData(cryptHand,
1297		ptext,
1298		1,
1299		ctext,
1300		1,
1301		&bytesEncrypted,
1302		&remData);
1303	if(crtn == CSSM_OK) {
1304		/*
1305		 * Deal with remData - its contents are included in bytesEncrypted.
1306		 */
1307		if((remData.Length != 0) && mallocCtext) {
1308			/* shouldn't happen - right? */
1309			if(bytesEncrypted > origCtextLen) {
1310				/* malloc and copy a new one */
1311				uint8 *newCdata = (uint8 *)appMalloc(bytesEncrypted, NULL);
1312				printf("**Warning: app malloced cipherBuf, but got nonzero "
1313					"remData!\n");
1314				if(newCdata == NULL) {
1315					printf("Insufficient heap space\n");
1316					ocrtn = CSSM_ERRCODE_MEMORY_ERROR;
1317					goto abort;
1318				}
1319				memmove(newCdata, ctext->Data, ctext->Length);
1320				memmove(newCdata+ctext->Length, remData.Data, remData.Length);
1321				CSSM_FREE(ctext->Data);
1322				ctext->Data = newCdata;
1323			}
1324			else {
1325				/* there's room left over */
1326				memmove(ctext->Data+ctext->Length, remData.Data, remData.Length);
1327			}
1328			ctext->Length = bytesEncrypted;
1329		}
1330		// NOTE: We return the proper length in ctext....
1331		ctext->Length = bytesEncrypted;
1332	}
1333	else {
1334		savedErr = crtn;
1335		restoreErr = CSSM_TRUE;
1336		printError("CSSM_EncryptData", crtn);
1337	}
1338abort:
1339	crtn = CSSM_DeleteContext(cryptHand);
1340	if(crtn) {
1341		printError("CSSM_DeleteContext", crtn);
1342		ocrtn = crtn;
1343	}
1344	if(restoreErr) {
1345		ocrtn = savedErr;
1346	}
1347	return ocrtn;
1348}
1349
1350#define PAD_IMPLIES_RAND_PTEXTSIZE	1
1351#define LOG_STAGED_OPS				0
1352#if		LOG_STAGED_OPS
1353#define soprintf(s)	printf s
1354#else
1355#define soprintf(s)
1356#endif
1357
1358CSSM_RETURN cspStagedEncrypt(CSSM_CSP_HANDLE cspHand,
1359		uint32 algorithm,					// CSSM_ALGID_FEED, etc.
1360		uint32 mode,						// CSSM_ALGMODE_CBC, etc. - only for symmetric algs
1361		CSSM_PADDING padding,				// CSSM_PADDING_PKCS1, etc.
1362		const CSSM_KEY *key,				// public or session key
1363		const CSSM_KEY *pubKey,				// for CSSM_ALGID_FEED, CSSM_ALGID_FEECFILE only
1364		uint32 effectiveKeySizeInBits,		// 0 means skip this attribute
1365		uint32 cipherBlockSize,				// ditto
1366		uint32 rounds,						// ditto
1367		const CSSM_DATA *iv,				// init vector, optional
1368		const CSSM_DATA *ptext,
1369		CSSM_DATA_PTR ctext,				// RETURNED, we malloc
1370		CSSM_BOOL multiUpdates)				// false:single update, true:multi updates
1371{
1372	CSSM_CC_HANDLE 	cryptHand;
1373	CSSM_RETURN		crtn;
1374	CSSM_SIZE		bytesEncrypted;			// per update
1375	CSSM_SIZE		bytesEncryptedTotal = 0;
1376	CSSM_RETURN		ocrtn = CSSM_OK;		// 'our' crtn
1377	unsigned		toMove;					// remaining
1378	unsigned		thisMove;				// bytes to encrypt on this update
1379	CSSM_DATA		thisPtext;				// running ptr into ptext
1380	CSSM_DATA		ctextWork;				// per update, mallocd by CSP
1381	CSSM_QUERY_SIZE_DATA querySize;
1382	uint8			*origCtext;				// initial ctext->Data
1383	unsigned		origCtextLen;			// amount we mallocd
1384	CSSM_BOOL		restoreErr = CSSM_FALSE;
1385	CSSM_RETURN		savedErr = CSSM_OK;
1386
1387
1388	cryptHand = genCryptHandle(cspHand,
1389		algorithm,
1390		mode,
1391		padding,
1392		key,
1393		pubKey,
1394		iv,
1395		effectiveKeySizeInBits,
1396		rounds);
1397	if(cryptHand == 0) {
1398		return CSSMERR_CSP_INTERNAL_ERROR;
1399	}
1400	if(cipherBlockSize) {
1401		crtn = AddContextAttribute(cryptHand,
1402			CSSM_ATTRIBUTE_BLOCK_SIZE,
1403			sizeof(uint32),
1404			CAT_Uint32,
1405			NULL,
1406			cipherBlockSize);
1407		if(crtn) {
1408			printError("CSSM_UpdateContextAttributes", crtn);
1409			goto abort;
1410		}
1411	}
1412
1413	/* obtain total required ciphertext size and block size */
1414	querySize.SizeInputBlock = ptext->Length;
1415	crtn = CSSM_QuerySize(cryptHand,
1416		CSSM_TRUE,						// encrypt
1417		1,
1418		&querySize);
1419	if(crtn) {
1420		printError("CSSM_QuerySize(1)", crtn);
1421		ocrtn = CSSMERR_CSP_INTERNAL_ERROR;
1422		goto abort;
1423	}
1424	if(querySize.SizeOutputBlock == 0) {
1425		/* CSP couldn't figure this out; skip our malloc - caller is taking its
1426		 * chances */
1427		printf("***cspStagedEncrypt: warning: cipherTextSize unknown; aborting\n");
1428		ocrtn = CSSMERR_CSP_INTERNAL_ERROR;
1429		goto abort;
1430	}
1431	else {
1432		origCtextLen = querySize.SizeOutputBlock;
1433		if(algorithm == CSSM_ALGID_ASC) {
1434			/* ASC is weird - the more chunks we do, the bigger the
1435			 * resulting ctext...*/
1436			origCtextLen *= 2;
1437		}
1438		ctext->Length = origCtextLen;
1439		ctext->Data   = origCtext = (uint8 *)appMalloc(origCtextLen, NULL);
1440		if(ctext->Data == NULL) {
1441			printf("Insufficient heap space\n");
1442			ocrtn = CSSMERR_CSP_MEMORY_ERROR;
1443			goto abort;
1444		}
1445		memset(ctext->Data, 0, ctext->Length);
1446	}
1447
1448	crtn = CSSM_EncryptDataInit(cryptHand);
1449	if(crtn) {
1450		printError("CSSM_EncryptDataInit", crtn);
1451		ocrtn = crtn;
1452		goto abort;
1453	}
1454
1455	toMove = ptext->Length;
1456	thisPtext.Data = ptext->Data;
1457	while(toMove) {
1458		if(multiUpdates) {
1459			thisMove = genRand(1, toMove);
1460		}
1461		else {
1462			/* just do one pass thru this loop */
1463			thisMove = toMove;
1464		}
1465		thisPtext.Length = thisMove;
1466		/* let CSP do the individual mallocs */
1467		ctextWork.Data = NULL;
1468		ctextWork.Length = 0;
1469		soprintf(("*** EncryptDataUpdate: ptextLen 0x%x\n", thisMove));
1470		crtn = CSSM_EncryptDataUpdate(cryptHand,
1471			&thisPtext,
1472			1,
1473			&ctextWork,
1474			1,
1475			&bytesEncrypted);
1476		if(crtn) {
1477			printError("CSSM_EncryptDataUpdate", crtn);
1478			ocrtn = crtn;
1479			goto abort;
1480		}
1481		// NOTE: We return the proper length in ctext....
1482		ctextWork.Length = bytesEncrypted;
1483		soprintf(("*** EncryptDataUpdate: ptextLen 0x%x  bytesEncrypted 0x%x\n",
1484			thisMove, bytesEncrypted));
1485		thisPtext.Data += thisMove;
1486		toMove         -= thisMove;
1487		if(bytesEncrypted > ctext->Length) {
1488			printf("cspStagedEncrypt: ctext overflow!\n");
1489			ocrtn = crtn;
1490			goto abort;
1491		}
1492		if(bytesEncrypted != 0) {
1493			memmove(ctext->Data, ctextWork.Data, bytesEncrypted);
1494			bytesEncryptedTotal += bytesEncrypted;
1495			ctext->Data         += bytesEncrypted;
1496			ctext->Length       -= bytesEncrypted;
1497		}
1498		if(ctextWork.Data != NULL) {
1499			CSSM_FREE(ctextWork.Data);
1500		}
1501	}
1502	/* OK, one more */
1503	ctextWork.Data = NULL;
1504	ctextWork.Length = 0;
1505	crtn = CSSM_EncryptDataFinal(cryptHand, &ctextWork);
1506	if(crtn) {
1507		printError("CSSM_EncryptDataFinal", crtn);
1508		savedErr = crtn;
1509		restoreErr = CSSM_TRUE;
1510		goto abort;
1511	}
1512	if(ctextWork.Length != 0) {
1513		bytesEncryptedTotal += ctextWork.Length;
1514		if(ctextWork.Length > ctext->Length) {
1515			printf("cspStagedEncrypt: ctext overflow (2)!\n");
1516			ocrtn = CSSMERR_CSP_INTERNAL_ERROR;
1517			goto abort;
1518		}
1519		memmove(ctext->Data, ctextWork.Data, ctextWork.Length);
1520	}
1521	if(ctextWork.Data) {
1522		/* this could have gotten mallocd and Length still be zero */
1523		CSSM_FREE(ctextWork.Data);
1524	}
1525
1526	/* retweeze ctext */
1527	ctext->Data   = origCtext;
1528	ctext->Length = bytesEncryptedTotal;
1529abort:
1530	crtn = CSSM_DeleteContext(cryptHand);
1531	if(crtn) {
1532		printError("CSSM_DeleteContext", crtn);
1533		ocrtn = crtn;
1534	}
1535	if(restoreErr) {
1536		/* give caller the error from the encrypt */
1537		ocrtn = savedErr;
1538	}
1539	return ocrtn;
1540}
1541
1542CSSM_RETURN cspDecrypt(CSSM_CSP_HANDLE cspHand,
1543		uint32 algorithm,					// CSSM_ALGID_FEED, etc.
1544		uint32 mode,						// CSSM_ALGMODE_CBC, etc. - only for symmetric algs
1545		CSSM_PADDING padding,				// CSSM_PADDING_PKCS1, etc.
1546		const CSSM_KEY *key,				// public or session key
1547		const CSSM_KEY *pubKey,				// for CSSM_ALGID_FEED, CSSM_ALGID_FEECFILE only
1548		uint32 effectiveKeySizeInBits,		// 0 means skip this attribute
1549		uint32 rounds,						// ditto
1550		const CSSM_DATA *iv,				// init vector, optional
1551		const CSSM_DATA *ctext,
1552		CSSM_DATA_PTR ptext,				// RETURNED
1553		CSSM_BOOL mallocPtext)				// if true and ptext->Length = 0,
1554											//   we'll malloc
1555{
1556	CSSM_CC_HANDLE 	cryptHand;
1557	CSSM_RETURN		crtn;
1558	CSSM_RETURN		ocrtn = CSSM_OK;
1559	CSSM_SIZE		bytesDecrypted;
1560	CSSM_DATA		remData = {0, NULL};
1561	unsigned		origPtextLen;			// the amount we malloc, if any
1562
1563	cryptHand = genCryptHandle(cspHand,
1564		algorithm,
1565		mode,
1566		padding,
1567		key,
1568		pubKey,
1569		iv,
1570		effectiveKeySizeInBits,
1571		rounds);
1572	if(cryptHand == 0) {
1573		return CSSMERR_CSP_INTERNAL_ERROR;
1574	}
1575	if(mallocPtext && (ptext->Length == 0)) {
1576		CSSM_QUERY_SIZE_DATA querySize;
1577		querySize.SizeInputBlock = ctext->Length;
1578		crtn = CSSM_QuerySize(cryptHand,
1579			CSSM_FALSE,						// encrypt
1580			1,
1581			&querySize);
1582		if(crtn) {
1583			printError("CSSM_QuerySize", crtn);
1584			ocrtn = crtn;
1585			goto abort;
1586		}
1587		if(querySize.SizeOutputBlock == 0) {
1588			/* CSP couldn't figure this one out; skip our malloc */
1589			printf("***cspDecrypt: warning: plainTextSize unknown; "
1590				"skipping malloc\n");
1591			origPtextLen = 0;
1592		}
1593		else {
1594			ptext->Data =
1595				(uint8 *)appMalloc(querySize.SizeOutputBlock, NULL);
1596			if(ptext->Data == NULL) {
1597				printf("Insufficient heap space\n");
1598				ocrtn = CSSMERR_CSP_MEMORY_ERROR;
1599				goto abort;
1600			}
1601			ptext->Length = origPtextLen = querySize.SizeOutputBlock;
1602			memset(ptext->Data, 0, ptext->Length);
1603		}
1604	}
1605	else {
1606		origPtextLen = ptext->Length;
1607	}
1608	crtn = CSSM_DecryptData(cryptHand,
1609		ctext,
1610		1,
1611		ptext,
1612		1,
1613		&bytesDecrypted,
1614		&remData);
1615	if(crtn == CSSM_OK) {
1616		/*
1617		 * Deal with remData - its contents are included in bytesDecrypted.
1618		 */
1619		if((remData.Length != 0) && mallocPtext) {
1620			/* shouldn't happen - right? */
1621			if(bytesDecrypted > origPtextLen) {
1622				/* malloc and copy a new one */
1623				uint8 *newPdata = (uint8 *)appMalloc(bytesDecrypted, NULL);
1624				printf("**Warning: app malloced ClearBuf, but got nonzero "
1625					"remData!\n");
1626				if(newPdata == NULL) {
1627					printf("Insufficient heap space\n");
1628					ocrtn = CSSMERR_CSP_MEMORY_ERROR;
1629					goto abort;
1630				}
1631				memmove(newPdata, ptext->Data, ptext->Length);
1632				memmove(newPdata + ptext->Length,
1633					remData.Data, remData.Length);
1634				CSSM_FREE(ptext->Data);
1635				ptext->Data = newPdata;
1636			}
1637			else {
1638				/* there's room left over */
1639				memmove(ptext->Data + ptext->Length,
1640					remData.Data, remData.Length);
1641			}
1642			ptext->Length = bytesDecrypted;
1643		}
1644		// NOTE: We return the proper length in ptext....
1645		ptext->Length = bytesDecrypted;
1646
1647		// FIXME - sometimes get mallocd RemData here, but never any valid data
1648		// there...side effect of CSPFullPluginSession's buffer handling logic;
1649		// but will we ever actually see valid data in RemData? So far we never
1650		// have....
1651		if(remData.Data != NULL) {
1652			appFree(remData.Data, NULL);
1653		}
1654	}
1655	else {
1656		printError("CSSM_DecryptData", crtn);
1657		ocrtn = crtn;
1658	}
1659abort:
1660	crtn = CSSM_DeleteContext(cryptHand);
1661	if(crtn) {
1662		printError("CSSM_DeleteContext", crtn);
1663		ocrtn = crtn;
1664	}
1665	return ocrtn;
1666}
1667
1668CSSM_RETURN cspStagedDecrypt(CSSM_CSP_HANDLE cspHand,
1669		uint32 algorithm,					// CSSM_ALGID_FEED, etc.
1670		uint32 mode,						// CSSM_ALGMODE_CBC, etc. - only for symmetric algs
1671		CSSM_PADDING padding,				// CSSM_PADDING_PKCS1, etc.
1672		const CSSM_KEY *key,				// public or session key
1673		const CSSM_KEY *pubKey,				// for CSSM_ALGID_FEED, CSSM_ALGID_FEECFILE only
1674		uint32 effectiveKeySizeInBits,		// 0 means skip this attribute
1675		uint32 cipherBlockSize,				// ditto
1676		uint32 rounds,						// ditto
1677		const CSSM_DATA *iv,				// init vector, optional
1678		const CSSM_DATA *ctext,
1679		CSSM_DATA_PTR ptext,				// RETURNED, we malloc
1680		CSSM_BOOL multiUpdates)				// false:single update, true:multi updates
1681{
1682	CSSM_CC_HANDLE 	cryptHand;
1683	CSSM_RETURN		crtn;
1684	CSSM_SIZE		bytesDecrypted;			// per update
1685	CSSM_SIZE		bytesDecryptedTotal = 0;
1686	CSSM_RETURN		ocrtn = CSSM_OK;		// 'our' crtn
1687	unsigned		toMove;					// remaining
1688	unsigned		thisMove;				// bytes to encrypt on this update
1689	CSSM_DATA		thisCtext;				// running ptr into ptext
1690	CSSM_DATA		ptextWork;				// per update, mallocd by CSP
1691	CSSM_QUERY_SIZE_DATA querySize;
1692	uint8			*origPtext;				// initial ptext->Data
1693	unsigned		origPtextLen;			// amount we mallocd
1694
1695	cryptHand = genCryptHandle(cspHand,
1696		algorithm,
1697		mode,
1698		padding,
1699		key,
1700		pubKey,
1701		iv,
1702		effectiveKeySizeInBits,
1703		rounds);
1704	if(cryptHand == 0) {
1705		return CSSMERR_CSP_INTERNAL_ERROR;
1706	}
1707	if(cipherBlockSize) {
1708		crtn = AddContextAttribute(cryptHand,
1709			CSSM_ATTRIBUTE_BLOCK_SIZE,
1710			sizeof(uint32),
1711			CAT_Uint32,
1712			NULL,
1713			cipherBlockSize);
1714		if(crtn) {
1715			printError("CSSM_UpdateContextAttributes", crtn);
1716			goto abort;
1717		}
1718	}
1719
1720	/* obtain total required ciphertext size and block size */
1721	querySize.SizeInputBlock = ctext->Length;
1722	crtn = CSSM_QuerySize(cryptHand,
1723		CSSM_FALSE,						// encrypt
1724		1,
1725		&querySize);
1726	if(crtn) {
1727		printError("CSSM_QuerySize(1)", crtn);
1728		ocrtn = crtn;
1729		goto abort;
1730	}
1731
1732	/* required ptext size should be independent of number of chunks */
1733	if(querySize.SizeOutputBlock == 0) {
1734		printf("***warning: cspStagedDecrypt: plainTextSize unknown; aborting\n");
1735		ocrtn = CSSMERR_CSP_INTERNAL_ERROR;
1736		goto abort;
1737	}
1738	else {
1739		// until exit, ptext->Length indicates remaining bytes of usable data in
1740		// ptext->Data
1741		ptext->Length = origPtextLen = querySize.SizeOutputBlock;
1742		ptext->Data   = origPtext    =
1743			(uint8 *)appMalloc(origPtextLen, NULL);
1744		if(ptext->Data == NULL) {
1745			printf("Insufficient heap space\n");
1746			ocrtn = CSSMERR_CSP_INTERNAL_ERROR;
1747			goto abort;
1748		}
1749		memset(ptext->Data, 0, ptext->Length);
1750	}
1751
1752	crtn = CSSM_DecryptDataInit(cryptHand);
1753	if(crtn) {
1754		printError("CSSM_DecryptDataInit", crtn);
1755		ocrtn = crtn;
1756		goto abort;
1757	}
1758	toMove = ctext->Length;
1759	thisCtext.Data = ctext->Data;
1760	while(toMove) {
1761		if(multiUpdates) {
1762			thisMove = genRand(1, toMove);
1763		}
1764		else {
1765			/* just do one pass thru this loop */
1766			thisMove = toMove;
1767		}
1768		thisCtext.Length = thisMove;
1769		/* let CSP do the individual mallocs */
1770		ptextWork.Data = NULL;
1771		ptextWork.Length = 0;
1772		soprintf(("*** DecryptDataUpdate: ctextLen 0x%x\n", thisMove));
1773		crtn = CSSM_DecryptDataUpdate(cryptHand,
1774			&thisCtext,
1775			1,
1776			&ptextWork,
1777			1,
1778			&bytesDecrypted);
1779		if(crtn) {
1780			printError("CSSM_DecryptDataUpdate", crtn);
1781			ocrtn = crtn;
1782			goto abort;
1783		}
1784		//
1785		// NOTE: We return the proper length in ptext....
1786		ptextWork.Length = bytesDecrypted;
1787		thisCtext.Data += thisMove;
1788		toMove         -= thisMove;
1789		if(bytesDecrypted > ptext->Length) {
1790			printf("cspStagedDecrypt: ptext overflow!\n");
1791			ocrtn = CSSMERR_CSP_INTERNAL_ERROR;
1792			goto abort;
1793		}
1794		if(bytesDecrypted != 0) {
1795			memmove(ptext->Data, ptextWork.Data, bytesDecrypted);
1796			bytesDecryptedTotal += bytesDecrypted;
1797			ptext->Data         += bytesDecrypted;
1798			ptext->Length       -= bytesDecrypted;
1799		}
1800		if(ptextWork.Data != NULL) {
1801			CSSM_FREE(ptextWork.Data);
1802		}
1803	}
1804	/* OK, one more */
1805	ptextWork.Data = NULL;
1806	ptextWork.Length = 0;
1807	crtn = CSSM_DecryptDataFinal(cryptHand, &ptextWork);
1808	if(crtn) {
1809		printError("CSSM_DecryptDataFinal", crtn);
1810		ocrtn = crtn;
1811		goto abort;
1812	}
1813	if(ptextWork.Length != 0) {
1814		bytesDecryptedTotal += ptextWork.Length;
1815		if(ptextWork.Length > ptext->Length) {
1816			printf("cspStagedDecrypt: ptext overflow (2)!\n");
1817			ocrtn = CSSMERR_CSP_INTERNAL_ERROR;
1818			goto abort;
1819		}
1820		memmove(ptext->Data, ptextWork.Data, ptextWork.Length);
1821	}
1822	if(ptextWork.Data) {
1823		/* this could have gotten mallocd and Length still be zero */
1824		CSSM_FREE(ptextWork.Data);
1825	}
1826
1827	/* retweeze ptext */
1828	ptext->Data   = origPtext;
1829	ptext->Length = bytesDecryptedTotal;
1830abort:
1831	crtn = CSSM_DeleteContext(cryptHand);
1832	if(crtn) {
1833		printError("CSSM_DeleteContext", crtn);
1834		ocrtn = crtn;
1835	}
1836	return ocrtn;
1837}
1838
1839#pragma mark --------- sign/verify/MAC ---------
1840
1841/*
1842 * Signature routines
1843 * This all-in-one sign op has a special case for RSA keys. If the requested
1844 * alg is MD5 or SHA1, we'll do a manual digest op followed by raw RSA sign.
1845 * Likewise, if it's CSSM_ALGID_DSA, we'll do manual SHA1 digest followed by
1846 * raw DSA sign.
1847 */
1848
1849CSSM_RETURN cspSign(CSSM_CSP_HANDLE cspHand,
1850		uint32 algorithm,					// CSSM_ALGID_FEE_MD5, etc.
1851		CSSM_KEY_PTR key,					// private key
1852		const CSSM_DATA *text,
1853		CSSM_DATA_PTR sig)					// RETURNED
1854{
1855	CSSM_CC_HANDLE	sigHand;
1856	CSSM_RETURN		crtn;
1857	CSSM_RETURN		ocrtn = CSSM_OK;
1858	const CSSM_DATA	*ptext;
1859	CSSM_DATA		digest = {0, NULL};
1860	CSSM_ALGORITHMS	digestAlg = CSSM_ALGID_NONE;
1861
1862	/* handle special cases for raw sign */
1863	switch(algorithm) {
1864		case CSSM_ALGID_SHA1:
1865			digestAlg = CSSM_ALGID_SHA1;
1866			algorithm = CSSM_ALGID_RSA;
1867			break;
1868		case CSSM_ALGID_MD5:
1869			digestAlg = CSSM_ALGID_MD5;
1870			algorithm = CSSM_ALGID_RSA;
1871			break;
1872		case CSSM_ALGID_DSA:
1873			digestAlg = CSSM_ALGID_SHA1;
1874			algorithm = CSSM_ALGID_DSA;
1875			break;
1876		default:
1877			break;
1878	}
1879	if(digestAlg != CSSM_ALGID_NONE) {
1880		crtn = cspDigest(cspHand,
1881			digestAlg,
1882			CSSM_FALSE,			// mallocDigest
1883			text,
1884			&digest);
1885		if(crtn) {
1886			return crtn;
1887		}
1888		/* sign digest with raw RSA/DSA */
1889		ptext = &digest;
1890	}
1891	else {
1892		ptext = text;
1893	}
1894	crtn = CSSM_CSP_CreateSignatureContext(cspHand,
1895		algorithm,
1896		NULL,				// passPhrase
1897		key,
1898		&sigHand);
1899	if(crtn) {
1900		printError("CSSM_CSP_CreateSignatureContext (1)", crtn);
1901		return crtn;
1902	}
1903	crtn = CSSM_SignData(sigHand,
1904		ptext,
1905		1,
1906		digestAlg,
1907		sig);
1908	if(crtn) {
1909		printError("CSSM_SignData", crtn);
1910		ocrtn = crtn;
1911	}
1912	crtn = CSSM_DeleteContext(sigHand);
1913	if(crtn) {
1914		printError("CSSM_DeleteContext", crtn);
1915		ocrtn = crtn;
1916	}
1917	if(digest.Data != NULL) {
1918		CSSM_FREE(digest.Data);
1919	}
1920	return ocrtn;
1921}
1922
1923/*
1924 * Staged sign. Each update does a random number of bytes 'till through.
1925 */
1926CSSM_RETURN cspStagedSign(CSSM_CSP_HANDLE cspHand,
1927		uint32 algorithm,					// CSSM_ALGID_FEE_MD5, etc.
1928		CSSM_KEY_PTR key,					// private key
1929		const CSSM_DATA *text,
1930		CSSM_BOOL multiUpdates,				// false:single update, true:multi updates
1931		CSSM_DATA_PTR sig)					// RETURNED
1932{
1933	CSSM_CC_HANDLE	sigHand;
1934	CSSM_RETURN		crtn;
1935	CSSM_RETURN		ocrtn = CSSM_OK;
1936	unsigned		thisMove;				// this update
1937	unsigned		toMove;					// total to go
1938	CSSM_DATA		thisText;				// actaully passed to update
1939	crtn = CSSM_CSP_CreateSignatureContext(cspHand,
1940		algorithm,
1941		NULL,				// passPhrase
1942		key,
1943		&sigHand);
1944	if(crtn) {
1945		printError("CSSM_CSP_CreateSignatureContext (1)", crtn);
1946		return crtn;
1947	}
1948	crtn = CSSM_SignDataInit(sigHand);
1949	if(crtn) {
1950		printError("CSSM_SignDataInit", crtn);
1951		ocrtn = crtn;
1952		goto abort;
1953	}
1954	toMove = text->Length;
1955	thisText.Data = text->Data;
1956	while(toMove) {
1957		if(multiUpdates) {
1958			thisMove = genRand(1, toMove);
1959		}
1960		else {
1961			thisMove = toMove;
1962		}
1963		thisText.Length = thisMove;
1964		crtn = CSSM_SignDataUpdate(sigHand,
1965			&thisText,
1966			1);
1967		if(crtn) {
1968			printError("CSSM_SignDataUpdate", crtn);
1969			ocrtn = crtn;
1970			goto abort;
1971		}
1972		thisText.Data += thisMove;
1973		toMove -= thisMove;
1974	}
1975	crtn = CSSM_SignDataFinal(sigHand, sig);
1976	if(crtn) {
1977		printError("CSSM_SignDataFinal", crtn);
1978		ocrtn = crtn;
1979		goto abort;
1980	}
1981abort:
1982	crtn = CSSM_DeleteContext(sigHand);
1983	if(crtn) {
1984		printError("CSSM_DeleteContext", crtn);
1985		ocrtn = crtn;
1986	}
1987	return ocrtn;
1988}
1989
1990/*
1991 * This all-in-one verify op has a special case for RSA keys. If the requested
1992 * alg is MD5 or SHA1, we'll do a manual digest op followed by raw RSA verify.
1993 * Likewise, if it's CSSM_ALGID_DSA, we'll do manual SHA1 digest followed by
1994 * raw DSA sign.
1995 */
1996
1997CSSM_RETURN cspSigVerify(CSSM_CSP_HANDLE cspHand,
1998		uint32 algorithm,					// CSSM_ALGID_FEE_MD5, etc.
1999		CSSM_KEY_PTR key,					// public key
2000		const CSSM_DATA *text,
2001		const CSSM_DATA *sig,
2002		CSSM_RETURN expectResult)			// expected result is verify failure
2003											// CSSM_OK - expect success
2004{
2005	CSSM_CC_HANDLE	sigHand;
2006	CSSM_RETURN		ocrtn = CSSM_OK;
2007	CSSM_RETURN		crtn;
2008	const CSSM_DATA	*ptext;
2009	CSSM_DATA		digest = {0, NULL};
2010	CSSM_ALGORITHMS	digestAlg = CSSM_ALGID_NONE;
2011
2012	/* handle special cases for raw sign */
2013	switch(algorithm) {
2014		case CSSM_ALGID_SHA1:
2015			digestAlg = CSSM_ALGID_SHA1;
2016			algorithm = CSSM_ALGID_RSA;
2017			break;
2018		case CSSM_ALGID_MD5:
2019			digestAlg = CSSM_ALGID_MD5;
2020			algorithm = CSSM_ALGID_RSA;
2021			break;
2022		case CSSM_ALGID_DSA:
2023			digestAlg = CSSM_ALGID_SHA1;
2024			algorithm = CSSM_ALGID_DSA;
2025			break;
2026		default:
2027			break;
2028	}
2029	if(digestAlg != CSSM_ALGID_NONE) {
2030		crtn = cspDigest(cspHand,
2031			digestAlg,
2032			CSSM_FALSE,			// mallocDigest
2033			text,
2034			&digest);
2035		if(crtn) {
2036			return crtn;
2037		}
2038		/* sign digest with raw RSA/DSA */
2039		ptext = &digest;
2040	}
2041	else {
2042		ptext = text;
2043	}
2044	crtn = CSSM_CSP_CreateSignatureContext(cspHand,
2045		algorithm,
2046		NULL,				// passPhrase
2047		key,
2048		&sigHand);
2049	if(crtn) {
2050		printError("CSSM_CSP_CreateSignatureContext (3)", crtn);
2051		return crtn;
2052	}
2053
2054	crtn = CSSM_VerifyData(sigHand,
2055		ptext,
2056		1,
2057		digestAlg,
2058		sig);
2059	if(crtn != expectResult) {
2060		if(!crtn) {
2061			printf("Unexpected good Sig Verify\n");
2062		}
2063		else {
2064			printError("CSSM_VerifyData", crtn);
2065		}
2066		ocrtn = CSSMERR_CSSM_INTERNAL_ERROR;
2067	}
2068	crtn = CSSM_DeleteContext(sigHand);
2069	if(crtn) {
2070		printError("CSSM_DeleteContext", crtn);
2071		ocrtn = crtn;
2072	}
2073	if(digest.Data != NULL) {
2074		CSSM_FREE(digest.Data);
2075	}
2076	return ocrtn;
2077}
2078
2079/*
2080 * Staged verify. Each update does a random number of bytes 'till through.
2081 */
2082CSSM_RETURN cspStagedSigVerify(CSSM_CSP_HANDLE cspHand,
2083		uint32 algorithm,					// CSSM_ALGID_FEE_MD5, etc.
2084		CSSM_KEY_PTR key,					// private key
2085		const CSSM_DATA *text,
2086		const CSSM_DATA *sig,
2087		CSSM_BOOL multiUpdates,				// false:single update, true:multi updates
2088		CSSM_RETURN expectResult)			// expected result is verify failure
2089											// CSSM_TRUE - expect success
2090{
2091	CSSM_CC_HANDLE	sigHand;
2092	CSSM_RETURN		crtn;
2093	CSSM_RETURN		ocrtn = CSSM_OK;
2094	unsigned		thisMove;				// this update
2095	unsigned		toMove;					// total to go
2096	CSSM_DATA		thisText;				// actaully passed to update
2097	crtn = CSSM_CSP_CreateSignatureContext(cspHand,
2098		algorithm,
2099		NULL,				// passPhrase
2100		key,
2101		&sigHand);
2102	if(crtn) {
2103		printError("CSSM_CSP_CreateSignatureContext (4)", crtn);
2104		return crtn;
2105	}
2106	crtn = CSSM_VerifyDataInit(sigHand);
2107	if(crtn) {
2108		printError("CSSM_VerifyDataInit", crtn);
2109		ocrtn = crtn;
2110		goto abort;
2111	}
2112	toMove = text->Length;
2113	thisText.Data = text->Data;
2114	while(toMove) {
2115		if(multiUpdates) {
2116			thisMove = genRand(1, toMove);
2117		}
2118		else {
2119			thisMove = toMove;
2120		}
2121		thisText.Length = thisMove;
2122		crtn = CSSM_VerifyDataUpdate(sigHand,
2123			&thisText,
2124			1);
2125		if(crtn) {
2126			printError("CSSM_VerifyDataUpdate", crtn);
2127			ocrtn = crtn;
2128			goto abort;
2129		}
2130		thisText.Data += thisMove;
2131		toMove -= thisMove;
2132	}
2133	crtn = CSSM_VerifyDataFinal(sigHand, sig);
2134	if(crtn != expectResult) {
2135		if(crtn) {
2136			printError("CSSM_VerifyDataFinal", crtn);
2137		}
2138		else {
2139			printf("Unexpected good Staged Sig Verify\n");
2140		}
2141		ocrtn = CSSMERR_CSSM_INTERNAL_ERROR;
2142	}
2143abort:
2144	crtn = CSSM_DeleteContext(sigHand);
2145	if(crtn) {
2146		printError("CSSM_DeleteContext", crtn);
2147		ocrtn = crtn;
2148	}
2149	return ocrtn;
2150}
2151
2152/*
2153 * MAC routines
2154 */
2155CSSM_RETURN cspGenMac(CSSM_CSP_HANDLE cspHand,
2156		uint32 algorithm,					// CSSM_ALGID_FEE_MD5, etc.
2157		CSSM_KEY_PTR key,					// session key
2158		const CSSM_DATA *text,
2159		CSSM_DATA_PTR mac)					// RETURNED
2160{
2161	CSSM_CC_HANDLE	macHand;
2162	CSSM_RETURN		crtn;
2163	CSSM_RETURN		ocrtn = CSSM_OK;
2164	crtn = CSSM_CSP_CreateMacContext(cspHand,
2165		algorithm,
2166		key,
2167		&macHand);
2168	if(crtn) {
2169		printError("CSSM_CSP_CreateMacContext (1)", crtn);
2170		return crtn;
2171	}
2172	crtn = CSSM_GenerateMac(macHand,
2173		text,
2174		1,
2175		mac);
2176	if(crtn) {
2177		printError("CSSM_GenerateMac", crtn);
2178		ocrtn = crtn;
2179	}
2180	crtn = CSSM_DeleteContext(macHand);
2181	if(crtn) {
2182		printError("CSSM_DeleteContext", crtn);
2183		ocrtn = crtn;
2184	}
2185	return ocrtn;
2186}
2187
2188/*
2189 * Staged generate mac.
2190 */
2191CSSM_RETURN cspStagedGenMac(CSSM_CSP_HANDLE cspHand,
2192		uint32 algorithm,					// CSSM_ALGID_FEE_MD5, etc.
2193		CSSM_KEY_PTR key,					// private key
2194		const CSSM_DATA *text,
2195		CSSM_BOOL mallocMac,				// if true and digest->Length = 0, we'll
2196											//		malloc
2197		CSSM_BOOL multiUpdates,				// false:single update, true:multi updates
2198		CSSM_DATA_PTR mac)					// RETURNED
2199{
2200	CSSM_CC_HANDLE	macHand;
2201	CSSM_RETURN		crtn;
2202	CSSM_RETURN		ocrtn = CSSM_OK;
2203	unsigned		thisMove;				// this update
2204	unsigned		toMove;					// total to go
2205	CSSM_DATA		thisText;				// actaully passed to update
2206
2207	crtn = CSSM_CSP_CreateMacContext(cspHand,
2208		algorithm,
2209		key,
2210		&macHand);
2211	if(crtn) {
2212		printError("CSSM_CSP_CreateMacContext (2)", crtn);
2213		return crtn;
2214	}
2215
2216	if(mallocMac && (mac->Length == 0)) {
2217		/* malloc mac - ask CSP for size */
2218		CSSM_QUERY_SIZE_DATA	querySize = {0, 0};
2219		crtn = CSSM_QuerySize(macHand,
2220			CSSM_TRUE,						// encrypt
2221			1,
2222			&querySize);
2223		if(crtn) {
2224			printError("CSSM_QuerySize(mac)", crtn);
2225			ocrtn = crtn;
2226			goto abort;
2227		}
2228		if(querySize.SizeOutputBlock == 0) {
2229			printf("Unknown mac size\n");
2230			ocrtn = CSSMERR_CSSM_INTERNAL_ERROR;
2231			goto abort;
2232		}
2233		mac->Data = (uint8 *)appMalloc(querySize.SizeOutputBlock, NULL);
2234		if(mac->Data == NULL) {
2235			printf("malloc failure\n");
2236			ocrtn = CSSMERR_CSSM_MEMORY_ERROR;
2237			goto abort;
2238		}
2239		mac->Length = querySize.SizeOutputBlock;
2240	}
2241
2242	crtn = CSSM_GenerateMacInit(macHand);
2243	if(crtn) {
2244		printError("CSSM_GenerateMacInit", crtn);
2245		ocrtn = crtn;
2246		goto abort;
2247	}
2248	toMove = text->Length;
2249	thisText.Data = text->Data;
2250
2251	while(toMove) {
2252		if(multiUpdates) {
2253			thisMove = genRand(1, toMove);
2254		}
2255		else {
2256			thisMove = toMove;
2257		}
2258		thisText.Length = thisMove;
2259		crtn = CSSM_GenerateMacUpdate(macHand,
2260			&thisText,
2261			1);
2262		if(crtn) {
2263			printError("CSSM_GenerateMacUpdate", crtn);
2264			ocrtn = crtn;
2265			goto abort;
2266		}
2267		thisText.Data += thisMove;
2268		toMove -= thisMove;
2269	}
2270	crtn = CSSM_GenerateMacFinal(macHand, mac);
2271	if(crtn) {
2272		printError("CSSM_GenerateMacFinal", crtn);
2273		ocrtn = crtn;
2274		goto abort;
2275	}
2276abort:
2277	crtn = CSSM_DeleteContext(macHand);
2278	if(crtn) {
2279		printError("CSSM_DeleteContext", crtn);
2280		ocrtn = crtn;
2281	}
2282	return ocrtn;
2283}
2284
2285CSSM_RETURN cspMacVerify(CSSM_CSP_HANDLE cspHand,
2286		uint32 algorithm,					// CSSM_ALGID_FEE_MD5, etc.
2287		CSSM_KEY_PTR key,					// public key
2288		const CSSM_DATA *text,
2289		const CSSM_DATA_PTR mac,
2290		CSSM_RETURN expectResult)			// expected result
2291											// CSSM_OK - expect success
2292{
2293	CSSM_CC_HANDLE	macHand;
2294	CSSM_RETURN		ocrtn = CSSM_OK;
2295	CSSM_RETURN		crtn;
2296	crtn = CSSM_CSP_CreateMacContext(cspHand,
2297		algorithm,
2298		key,
2299		&macHand);
2300	if(crtn) {
2301		printError("CSSM_CSP_CreateMacContext (3)", crtn);
2302		return crtn;
2303	}
2304	crtn = CSSM_VerifyMac(macHand,
2305		text,
2306		1,
2307		mac);
2308	if(crtn != expectResult) {
2309		if(crtn) {
2310			printError("CSSM_VerifyMac", crtn);
2311		}
2312		else {
2313			printf("Unexpected good Mac Verify\n");
2314		}
2315		ocrtn = CSSMERR_CSSM_INTERNAL_ERROR;
2316	}
2317	crtn = CSSM_DeleteContext(macHand);
2318	if(crtn) {
2319		printError("CSSM_DeleteContext", crtn);
2320		ocrtn = crtn;
2321	}
2322	return ocrtn;
2323}
2324
2325/*
2326 * Staged mac verify. Each update does a random number of bytes 'till through.
2327 */
2328CSSM_RETURN cspStagedMacVerify(CSSM_CSP_HANDLE cspHand,
2329		uint32 algorithm,					// CSSM_ALGID_FEE_MD5, etc.
2330		CSSM_KEY_PTR key,					// private key
2331		const CSSM_DATA *text,
2332		const CSSM_DATA_PTR mac,
2333		CSSM_BOOL multiUpdates,				// false:single update, true:multi updates
2334		CSSM_RETURN expectResult)			// expected result is verify failure
2335											// CSSM_OK - expect success
2336{
2337	CSSM_CC_HANDLE	macHand;
2338	CSSM_RETURN		crtn;
2339	CSSM_RETURN		ocrtn = CSSM_OK;
2340	unsigned		thisMove;				// this update
2341	unsigned		toMove;					// total to go
2342	CSSM_DATA		thisText;				// actaully passed to update
2343
2344	crtn = CSSM_CSP_CreateMacContext(cspHand,
2345		algorithm,
2346		key,
2347		&macHand);
2348	if(crtn) {
2349		printError("CSSM_CSP_CreateMacContext (4)", crtn);
2350		return crtn;
2351	}
2352	crtn = CSSM_VerifyMacInit(macHand);
2353	if(crtn) {
2354		printError("CSSM_VerifyMacInit", crtn);
2355		ocrtn = crtn;
2356		goto abort;
2357	}
2358	toMove = text->Length;
2359	thisText.Data = text->Data;
2360
2361	while(toMove) {
2362		if(multiUpdates) {
2363			thisMove = genRand(1, toMove);
2364		}
2365		else {
2366			thisMove = toMove;
2367		}
2368		thisText.Length = thisMove;
2369		crtn = CSSM_VerifyMacUpdate(macHand,
2370			&thisText,
2371			1);
2372		if(crtn) {
2373			printError("CSSM_VerifyMacUpdate", crtn);
2374			ocrtn = crtn;
2375			goto abort;
2376		}
2377		thisText.Data += thisMove;
2378		toMove -= thisMove;
2379	}
2380	crtn = CSSM_VerifyMacFinal(macHand, mac);
2381	if(crtn != expectResult) {
2382		if(crtn) {
2383			printError("CSSM_VerifyMacFinal", crtn);
2384		}
2385		else {
2386			printf("Unexpected good Staged Mac Verify\n");
2387		}
2388		ocrtn = CSSMERR_CSSM_INTERNAL_ERROR;
2389	}
2390abort:
2391	crtn = CSSM_DeleteContext(macHand);
2392	if(crtn) {
2393		printError("CSSM_DeleteContext", crtn);
2394		ocrtn = crtn;
2395	}
2396	return ocrtn;
2397}
2398
2399#pragma mark --------- Digest ---------
2400
2401/*
2402 * Digest functions
2403 */
2404CSSM_RETURN cspDigest(CSSM_CSP_HANDLE cspHand,
2405		uint32 algorithm,					// CSSM_ALGID_MD5, etc.
2406		CSSM_BOOL mallocDigest,				// if true and digest->Length = 0, we'll malloc
2407		const CSSM_DATA *text,
2408		CSSM_DATA_PTR digest)
2409{
2410	CSSM_CC_HANDLE	digestHand;
2411	CSSM_RETURN		crtn;
2412	CSSM_RETURN		ocrtn = CSSM_OK;
2413
2414	crtn = CSSM_CSP_CreateDigestContext(cspHand,
2415		algorithm,
2416		&digestHand);
2417	if(crtn) {
2418		printError("CSSM_CSP_CreateDIgestContext (1)", crtn);
2419		return crtn;
2420	}
2421	if(mallocDigest && (digest->Length == 0)) {
2422		/* malloc digest - ask CSP for size */
2423		CSSM_QUERY_SIZE_DATA	querySize = {0, 0};
2424		crtn = CSSM_QuerySize(digestHand,
2425			CSSM_FALSE,						// encrypt
2426			1,
2427			&querySize);
2428		if(crtn) {
2429			printError("CSSM_QuerySize(3)", crtn);
2430			ocrtn = crtn;
2431			goto abort;
2432		}
2433		if(querySize.SizeOutputBlock == 0) {
2434			printf("Unknown digest size\n");
2435			ocrtn = CSSMERR_CSSM_INTERNAL_ERROR;
2436			goto abort;
2437		}
2438		digest->Data = (uint8 *)appMalloc(querySize.SizeOutputBlock, NULL);
2439		if(digest->Data == NULL) {
2440			printf("malloc failure\n");
2441			ocrtn = CSSMERR_CSSM_MEMORY_ERROR;
2442			goto abort;
2443		}
2444		digest->Length = querySize.SizeOutputBlock;
2445	}
2446	crtn = CSSM_DigestData(digestHand,
2447		text,
2448		1,
2449		digest);
2450	if(crtn) {
2451		printError("CSSM_DigestData", crtn);
2452		ocrtn = crtn;
2453	}
2454abort:
2455	crtn = CSSM_DeleteContext(digestHand);
2456	if(crtn) {
2457		printError("CSSM_DeleteContext", crtn);
2458		ocrtn = crtn;
2459	}
2460	return ocrtn;
2461}
2462
2463CSSM_RETURN cspStagedDigest(CSSM_CSP_HANDLE cspHand,
2464		uint32 algorithm,					// CSSM_ALGID_MD5, etc.
2465		CSSM_BOOL mallocDigest,				// if true and digest->Length = 0, we'll
2466											//		malloc
2467		CSSM_BOOL multiUpdates,				// false:single update, true:multi updates
2468		const CSSM_DATA *text,
2469		CSSM_DATA_PTR digest)
2470{
2471	CSSM_CC_HANDLE	digestHand;
2472	CSSM_RETURN		crtn;
2473	CSSM_RETURN		ocrtn = CSSM_OK;
2474	unsigned		thisMove;				// this update
2475	unsigned		toMove;					// total to go
2476	CSSM_DATA		thisText;				// actually passed to update
2477
2478	crtn = CSSM_CSP_CreateDigestContext(cspHand,
2479		algorithm,
2480		&digestHand);
2481	if(crtn) {
2482		printError("CSSM_CSP_CreateDigestContext (2)", crtn);
2483		return crtn;
2484	}
2485	if(mallocDigest && (digest->Length == 0)) {
2486		/* malloc digest - ask CSP for size */
2487		CSSM_QUERY_SIZE_DATA	querySize = {0, 0};
2488		crtn = CSSM_QuerySize(digestHand,
2489			CSSM_FALSE,						// encrypt
2490			1,
2491			&querySize);
2492		if(crtn) {
2493			printError("CSSM_QuerySize(4)", crtn);
2494			ocrtn = crtn;
2495			goto abort;
2496		}
2497		if(querySize.SizeOutputBlock == 0) {
2498			printf("Unknown digest size\n");
2499			ocrtn = CSSMERR_CSSM_INTERNAL_ERROR;
2500			goto abort;
2501		}
2502		digest->Data = (uint8 *)appMalloc(querySize.SizeOutputBlock, NULL);
2503		if(digest->Data == NULL) {
2504			printf("malloc failure\n");
2505			ocrtn = CSSMERR_CSSM_MEMORY_ERROR;
2506			goto abort;
2507		}
2508		digest->Length = querySize.SizeOutputBlock;
2509	}
2510	crtn = CSSM_DigestDataInit(digestHand);
2511	if(crtn) {
2512		printError("CSSM_DigestDataInit", crtn);
2513		ocrtn = crtn;
2514		goto abort;
2515	}
2516	toMove = text->Length;
2517	thisText.Data = text->Data;
2518	while(toMove) {
2519		if(multiUpdates) {
2520			thisMove = genRand(1, toMove);
2521		}
2522		else {
2523			thisMove = toMove;
2524		}
2525		thisText.Length = thisMove;
2526		crtn = CSSM_DigestDataUpdate(digestHand,
2527			&thisText,
2528			1);
2529		if(crtn) {
2530			printError("CSSM_DigestDataUpdate", crtn);
2531			ocrtn = crtn;
2532			goto abort;
2533		}
2534		thisText.Data += thisMove;
2535		toMove -= thisMove;
2536	}
2537	crtn = CSSM_DigestDataFinal(digestHand, digest);
2538	if(crtn) {
2539		printError("CSSM_DigestDataFinal", crtn);
2540		ocrtn = crtn;
2541		goto abort;
2542	}
2543abort:
2544	crtn = CSSM_DeleteContext(digestHand);
2545	if(crtn) {
2546		printError("CSSM_DeleteContext", crtn);
2547		ocrtn = crtn;
2548	}
2549	return ocrtn;
2550}
2551
2552#pragma mark --------- wrap/unwrap ---------
2553
2554/* wrap key function. */
2555CSSM_RETURN cspWrapKey(CSSM_CSP_HANDLE cspHand,
2556	const CSSM_KEY			*unwrappedKey,
2557	const CSSM_KEY			*wrappingKey,
2558	CSSM_ALGORITHMS			wrapAlg,
2559	CSSM_ENCRYPT_MODE		wrapMode,
2560	CSSM_KEYBLOB_FORMAT		wrapFormat,			// NONE, PKCS7, PKCS8
2561	CSSM_PADDING			wrapPad,
2562	CSSM_DATA_PTR			initVector,			// for some wrapping algs
2563	CSSM_DATA_PTR			descrData,			// optional
2564	CSSM_KEY_PTR			wrappedKey)			// RETURNED
2565{
2566	CSSM_CC_HANDLE		ccHand;
2567	CSSM_RETURN			crtn;
2568	CSSM_ACCESS_CREDENTIALS	creds;
2569
2570	memset(wrappedKey, 0, sizeof(CSSM_KEY));
2571	setBadKeyData(wrappedKey);
2572	memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
2573	/* special case for NULL wrap - no wrapping key */
2574	if((wrappingKey == NULL) ||
2575	   (wrappingKey->KeyHeader.KeyClass == CSSM_KEYCLASS_SESSION_KEY)) {
2576		crtn = CSSM_CSP_CreateSymmetricContext(cspHand,
2577				wrapAlg,
2578				wrapMode,
2579				&creds,			// passPhrase,
2580				wrappingKey,
2581				initVector,
2582				wrapPad,		// Padding
2583				0,				// Params
2584				&ccHand);
2585	}
2586	else {
2587		crtn = CSSM_CSP_CreateAsymmetricContext(cspHand,
2588				wrapAlg,
2589				&creds,
2590				wrappingKey,
2591				wrapPad,		// padding
2592				&ccHand);
2593		if(crtn) {
2594			printError("cspWrapKey/CreateContext", crtn);
2595			return crtn;
2596		}
2597		if(initVector) {
2598			/* manually add IV for CMS. The actual low-level encrypt doesn't
2599			 * use it (and must ignore it). */
2600			crtn = AddContextAttribute(ccHand,
2601				CSSM_ATTRIBUTE_INIT_VECTOR,
2602				sizeof(CSSM_DATA),
2603				CAT_Ptr,
2604				initVector,
2605				0);
2606			if(crtn) {
2607				printError("CSSM_UpdateContextAttributes", crtn);
2608				return crtn;
2609			}
2610		}
2611	}
2612	if(crtn) {
2613		printError("cspWrapKey/CreateContext", crtn);
2614		return crtn;
2615	}
2616	if(wrapFormat != CSSM_KEYBLOB_WRAPPED_FORMAT_NONE) {
2617		/* only add this attribute if it's not the default */
2618		CSSM_CONTEXT_ATTRIBUTE attr;
2619		attr.AttributeType = CSSM_ATTRIBUTE_WRAPPED_KEY_FORMAT;
2620		attr.AttributeLength = sizeof(uint32);
2621		attr.Attribute.Uint32 = wrapFormat;
2622		crtn = CSSM_UpdateContextAttributes(
2623			ccHand,
2624			1,
2625			&attr);
2626		if(crtn) {
2627			printError("CSSM_UpdateContextAttributes", crtn);
2628			return crtn;
2629		}
2630	}
2631	crtn = CSSM_WrapKey(ccHand,
2632		&creds,
2633		unwrappedKey,
2634		descrData,			// DescriptiveData
2635		wrappedKey);
2636	if(crtn != CSSM_OK) {
2637		printError("CSSM_WrapKey", crtn);
2638	}
2639	if(CSSM_DeleteContext(ccHand)) {
2640		printf("CSSM_DeleteContext failure\n");
2641	}
2642	return crtn;
2643}
2644
2645/* unwrap key function. */
2646CSSM_RETURN cspUnwrapKey(CSSM_CSP_HANDLE cspHand,
2647	const CSSM_KEY			*wrappedKey,
2648	const CSSM_KEY			*unwrappingKey,
2649	CSSM_ALGORITHMS			unwrapAlg,
2650	CSSM_ENCRYPT_MODE		unwrapMode,
2651	CSSM_PADDING 			unwrapPad,
2652	CSSM_DATA_PTR			initVector,			// for some wrapping algs
2653	CSSM_KEY_PTR			unwrappedKey,		// RETURNED
2654	CSSM_DATA_PTR			descrData,			// required
2655	const char 				*keyLabel,
2656	unsigned 				keyLabelLen)
2657{
2658	CSSM_CC_HANDLE		ccHand;
2659	CSSM_RETURN			crtn;
2660	CSSM_DATA			labelData;
2661	uint32				keyAttr;
2662	CSSM_ACCESS_CREDENTIALS	creds;
2663
2664	memset(unwrappedKey, 0, sizeof(CSSM_KEY));
2665	setBadKeyData(unwrappedKey);
2666	memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
2667	if((unwrappingKey == NULL) ||
2668	   (unwrappingKey->KeyHeader.KeyClass == CSSM_KEYCLASS_SESSION_KEY)) {
2669		crtn = CSSM_CSP_CreateSymmetricContext(cspHand,
2670				unwrapAlg,
2671				unwrapMode,
2672				&creds,
2673				unwrappingKey,
2674				initVector,
2675				unwrapPad,
2676				0,				// Params
2677				&ccHand);
2678	}
2679	else {
2680		crtn = CSSM_CSP_CreateAsymmetricContext(cspHand,
2681				unwrapAlg,
2682				&creds,			// passPhrase,
2683				unwrappingKey,
2684				unwrapPad,		// Padding
2685				&ccHand);
2686		if(crtn) {
2687			printError("cspUnwrapKey/CreateContext", crtn);
2688			return crtn;
2689		}
2690		if(initVector) {
2691			/* manually add IV for CMS. The actual low-level encrypt doesn't
2692			 * use it (and must ignore it). */
2693			crtn = AddContextAttribute(ccHand,
2694				CSSM_ATTRIBUTE_INIT_VECTOR,
2695				sizeof(CSSM_DATA),
2696				CAT_Ptr,
2697				initVector,
2698				0);
2699			if(crtn) {
2700				printError("CSSM_UpdateContextAttributes", crtn);
2701				return crtn;
2702			}
2703		}
2704	}
2705	if(crtn) {
2706		printError("cspUnwrapKey/CreateContext", crtn);
2707		return crtn;
2708	}
2709	labelData.Data = (uint8 *)keyLabel;
2710	labelData.Length = keyLabelLen;
2711
2712	/*
2713	 * New keyAttr - clear some old bits, make sure we ask for ref key
2714	 */
2715	keyAttr = wrappedKey->KeyHeader.KeyAttr;
2716	keyAttr &= ~(CSSM_KEYATTR_ALWAYS_SENSITIVE | CSSM_KEYATTR_NEVER_EXTRACTABLE);
2717	keyAttr |= CSSM_KEYATTR_RETURN_REF;
2718	crtn = CSSM_UnwrapKey(ccHand,
2719		NULL,				// PublicKey
2720		wrappedKey,
2721		wrappedKey->KeyHeader.KeyUsage,
2722		keyAttr,
2723		&labelData,
2724		NULL,				// CredAndAclEntry
2725		unwrappedKey,
2726		descrData);			// required
2727	if(crtn != CSSM_OK) {
2728		printError("CSSM_UnwrapKey", crtn);
2729	}
2730	if(CSSM_DeleteContext(ccHand)) {
2731		printf("CSSM_DeleteContext failure\n");
2732	}
2733	return crtn;
2734}
2735
2736/*
2737 * Simple NULL wrap to convert a reference key to a raw key.
2738 */
2739CSSM_RETURN cspRefKeyToRaw(
2740	CSSM_CSP_HANDLE cspHand,
2741	const CSSM_KEY *refKey,
2742	CSSM_KEY_PTR rawKey)		// init'd and RETURNED
2743{
2744	CSSM_DATA descData = {0, 0};
2745
2746	memset(rawKey, 0, sizeof(CSSM_KEY));
2747	return cspWrapKey(cspHand,
2748		refKey,
2749		NULL,					// unwrappingKey
2750		CSSM_ALGID_NONE,
2751		CSSM_ALGMODE_NONE,
2752		CSSM_KEYBLOB_WRAPPED_FORMAT_NONE,
2753		CSSM_PADDING_NONE,
2754		NULL,					// IV
2755		&descData,
2756		rawKey);
2757}
2758
2759/*
2760 * Convert ref key to raw key with specified format.
2761 */
2762CSSM_RETURN cspRefKeyToRawWithFormat(
2763	CSSM_CSP_HANDLE cspHand,
2764	const CSSM_KEY *refKey,
2765	CSSM_KEYBLOB_FORMAT format,
2766	CSSM_KEY_PTR rawKey)		// init'd and RETURNED
2767{
2768	memset(rawKey, 0, sizeof(CSSM_KEY));
2769	CSSM_ATTRIBUTE_TYPE attrType;
2770
2771	switch(refKey->KeyHeader.KeyClass) {
2772		case CSSM_KEYCLASS_PUBLIC_KEY:
2773			attrType = CSSM_ATTRIBUTE_PUBLIC_KEY_FORMAT;
2774			break;
2775		case CSSM_KEYCLASS_PRIVATE_KEY:
2776			attrType = CSSM_ATTRIBUTE_PRIVATE_KEY_FORMAT;
2777			break;
2778		case CSSM_KEYCLASS_SESSION_KEY:
2779			attrType = CSSM_ATTRIBUTE_SYMMETRIC_KEY_FORMAT;
2780			break;
2781		default:
2782			printf("***Unknown key class\n");
2783			return CSSMERR_CSP_INVALID_KEY;
2784	}
2785
2786	CSSM_DATA descData = {0, 0};
2787	CSSM_CC_HANDLE		ccHand;
2788	CSSM_RETURN			crtn;
2789//	uint32				keyAttr;
2790	CSSM_ACCESS_CREDENTIALS	creds;
2791
2792	memset(rawKey, 0, sizeof(CSSM_KEY));
2793	memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
2794	crtn = CSSM_CSP_CreateSymmetricContext(cspHand,
2795				CSSM_ALGID_NONE,
2796				CSSM_ALGMODE_NONE,
2797				&creds,
2798				NULL,			// unwrappingKey
2799				NULL,			// initVector
2800				CSSM_PADDING_NONE,
2801				NULL,			// Reserved
2802				&ccHand);
2803	if(crtn) {
2804		printError("cspRefKeyToRawWithFormat/CreateContext", crtn);
2805		return crtn;
2806	}
2807
2808	/* Add the spec for the resulting format */
2809	crtn = AddContextAttribute(ccHand,
2810		attrType,
2811		sizeof(uint32),
2812		CAT_Uint32,
2813		NULL,
2814		format);
2815
2816	crtn = CSSM_WrapKey(ccHand,
2817		&creds,
2818		refKey,
2819		&descData,			// DescriptiveData
2820		rawKey);
2821	if(crtn != CSSM_OK) {
2822		printError("CSSM_WrapKey", crtn);
2823	}
2824	if(rawKey->KeyHeader.Format != format) {
2825		printf("***cspRefKeyToRawWithFormat format scewup\n");
2826		crtn = CSSMERR_CSP_INTERNAL_ERROR;
2827	}
2828	if(CSSM_DeleteContext(ccHand)) {
2829		printf("CSSM_DeleteContext failure\n");
2830	}
2831	return crtn;
2832}
2833
2834/* unwrap raw key --> ref */
2835CSSM_RETURN cspRawKeyToRef(
2836	CSSM_CSP_HANDLE cspHand,
2837	const CSSM_KEY *rawKey,
2838	CSSM_KEY_PTR refKey)				// init'd and RETURNED
2839{
2840	CSSM_DATA descData = {0, 0};
2841
2842	memset(refKey, 0, sizeof(CSSM_KEY));
2843	return cspUnwrapKey(cspHand,
2844		rawKey,
2845		NULL,		// unwrappingKey
2846		CSSM_ALGID_NONE,
2847		CSSM_ALGMODE_NONE,
2848		CSSM_PADDING_NONE,
2849		NULL,		// init vector
2850		refKey,
2851		&descData,
2852		"noLabel",
2853		7);
2854}
2855
2856
2857#pragma mark --------- FEE key/curve support ---------
2858
2859/*
2860 * Generate random key size, primeType, curveType for FEE key for specified op.
2861 *
2862 * First just enumerate the curves we know about, with ECDSA-INcapable first
2863 */
2864
2865typedef struct {
2866	uint32	keySizeInBits;
2867	uint32 	primeType;				// CSSM_FEE_PRIME_TYPE_xxx
2868	uint32 	curveType;				// CSSM_FEE_CURVE_TYPE_xxx
2869} feeCurveParams;
2870
2871#define FEE_PROTOTYPE_CURVES	0
2872#if 	FEE_PROTOTYPE_CURVES
2873/* obsolete as of 4/9/2001 */
2874static feeCurveParams feeCurves[] = {
2875	{	31,		CSSM_FEE_PRIME_TYPE_MERSENNE,	CSSM_FEE_CURVE_TYPE_MONTGOMERY },
2876	{	127,	CSSM_FEE_PRIME_TYPE_MERSENNE,	CSSM_FEE_CURVE_TYPE_MONTGOMERY },
2877	{	127,	CSSM_FEE_PRIME_TYPE_GENERAL,	CSSM_FEE_CURVE_TYPE_MONTGOMERY },
2878	#define NUM_NON_ECDSA_CURVES	3
2879
2880	/* start of Weierstrass, IEEE P1363-capable curves */
2881	{	31,		CSSM_FEE_PRIME_TYPE_MERSENNE,	CSSM_FEE_CURVE_TYPE_WEIERSTRASS },
2882	{	40,		CSSM_FEE_PRIME_TYPE_FEE,		CSSM_FEE_CURVE_TYPE_WEIERSTRASS },
2883	{	127,	CSSM_FEE_PRIME_TYPE_MERSENNE,	CSSM_FEE_CURVE_TYPE_WEIERSTRASS },
2884	{	160,	CSSM_FEE_PRIME_TYPE_FEE,		CSSM_FEE_CURVE_TYPE_WEIERSTRASS },
2885	{	160,	CSSM_FEE_PRIME_TYPE_GENERAL,	CSSM_FEE_CURVE_TYPE_WEIERSTRASS },
2886	{	192,	CSSM_FEE_PRIME_TYPE_FEE,		CSSM_FEE_CURVE_TYPE_WEIERSTRASS },
2887};
2888#else	/* FEE_PROTOTYPE_CURVES */
2889static feeCurveParams feeCurves[] = {
2890	{	31,		CSSM_FEE_PRIME_TYPE_MERSENNE,	CSSM_FEE_CURVE_TYPE_MONTGOMERY },
2891	{	127,	CSSM_FEE_PRIME_TYPE_MERSENNE,	CSSM_FEE_CURVE_TYPE_MONTGOMERY },
2892	#define NUM_NON_ECDSA_CURVES	2
2893
2894	/* start of Weierstrass, IEEE P1363-capable curves */
2895	{	31,		CSSM_FEE_PRIME_TYPE_MERSENNE,	CSSM_FEE_CURVE_TYPE_WEIERSTRASS },
2896	{	128,	CSSM_FEE_PRIME_TYPE_FEE,		CSSM_FEE_CURVE_TYPE_WEIERSTRASS },
2897	{	161,	CSSM_FEE_PRIME_TYPE_FEE,		CSSM_FEE_CURVE_TYPE_WEIERSTRASS },
2898	{	161,	CSSM_FEE_PRIME_TYPE_GENERAL,	CSSM_FEE_CURVE_TYPE_WEIERSTRASS },
2899	{	192,	CSSM_FEE_PRIME_TYPE_GENERAL,	CSSM_FEE_CURVE_TYPE_WEIERSTRASS },
2900};
2901#endif	/* FEE_PROTOTYPE_CURVES */
2902#define NUM_FEE_CURVES	(sizeof(feeCurves) / sizeof(feeCurveParams))
2903
2904void randFeeKeyParams(
2905	CSSM_ALGORITHMS	alg,			// ALGID_FEED, CSSM_ALGID_FEE_MD5, etc.
2906	uint32			*keySizeInBits,	// RETURNED
2907	uint32 			*primeType,		// CSSM_FEE_PRIME_TYPE_xxx, RETURNED
2908	uint32 			*curveType)		// CSSM_FEE_CURVE_TYPE_xxx, RETURNED
2909{
2910	unsigned minParams;
2911	unsigned die;
2912	feeCurveParams *feeParams;
2913
2914	switch(alg) {
2915		case CSSM_ALGID_SHA1WithECDSA:
2916			minParams = NUM_NON_ECDSA_CURVES;
2917			break;
2918		default:
2919			minParams = 0;
2920			break;
2921	}
2922	die = genRand(minParams, (NUM_FEE_CURVES - 1));
2923	feeParams = &feeCurves[die];
2924	*keySizeInBits = feeParams->keySizeInBits;
2925	*primeType = feeParams->primeType;
2926	*curveType = feeParams->curveType;
2927}
2928
2929/*
2930 * Obtain strings for primeType and curveType.
2931 */
2932const char *primeTypeStr(uint32 primeType)
2933{
2934	const char *p;
2935	switch(primeType) {
2936		case CSSM_FEE_PRIME_TYPE_MERSENNE:
2937			p = "Mersenne";
2938			break;
2939		case CSSM_FEE_PRIME_TYPE_FEE:
2940			p = "FEE";
2941			break;
2942		case CSSM_FEE_PRIME_TYPE_GENERAL:
2943			p = "General";
2944			break;
2945		case CSSM_FEE_PRIME_TYPE_DEFAULT:
2946			p = "Default";
2947			break;
2948		default:
2949			p = "***UNKNOWN***";
2950			break;
2951	}
2952	return p;
2953}
2954
2955const char *curveTypeStr(uint32 curveType)
2956{
2957	const char *c;
2958	switch(curveType) {
2959		case CSSM_FEE_CURVE_TYPE_DEFAULT:
2960			c = "Default";
2961			break;
2962		case CSSM_FEE_CURVE_TYPE_MONTGOMERY:
2963			c = "Montgomery";
2964			break;
2965		case CSSM_FEE_CURVE_TYPE_WEIERSTRASS:
2966			c = "Weierstrass";
2967			break;
2968		default:
2969			c = "***UNKNOWN***";
2970			break;
2971	}
2972	return c;
2973}
2974
2975/*
2976 * Perform FEE Key exchange via CSSM_DeriveKey.
2977 */
2978#if 0
2979/* Not implemented in OS X */
2980CSSM_RETURN cspFeeKeyExchange(CSSM_CSP_HANDLE cspHand,
2981	CSSM_KEY_PTR 	privKey,
2982	CSSM_KEY_PTR 	pubKey,
2983	CSSM_KEY_PTR 	derivedKey,		// mallocd by caller
2984
2985	/* remaining fields apply to derivedKey */
2986	uint32 			keyAlg,
2987	const char 		*keyLabel,
2988	unsigned 		keyLabelLen,
2989	uint32 			keyUsage,		// CSSM_KEYUSE_ENCRYPT, etc.
2990	uint32 			keySizeInBits)
2991{
2992	CSSM_CC_HANDLE	dkHand;
2993	CSSM_RETURN 	crtn;
2994	CSSM_DATA		labelData;
2995
2996	if(derivedKey == NULL) {
2997		printf("cspFeeKeyExchange: no derivedKey\n");
2998		return CSSMERR_CSSM_INTERNAL_ERROR;
2999	}
3000	if((pubKey == NULL) ||
3001	   (pubKey->KeyHeader.KeyClass != CSSM_KEYCLASS_PUBLIC_KEY) ||
3002	   (pubKey->KeyHeader.BlobType != CSSM_KEYBLOB_RAW)) {
3003	 	printf("cspFeeKeyExchange: bad pubKey\n");
3004	 	return CSSMERR_CSSM_INTERNAL_ERROR;
3005	}
3006	if((privKey == NULL) ||
3007	   (privKey->KeyHeader.KeyClass != CSSM_KEYCLASS_PRIVATE_KEY) ||
3008	   (privKey->KeyHeader.BlobType != CSSM_KEYBLOB_REFERENCE)) {
3009	 	printf("cspFeeKeyExchange: bad privKey\n");
3010	 	return CSSMERR_CSSM_INTERNAL_ERROR;
3011	}
3012	memset(derivedKey, 0, sizeof(CSSM_KEY));
3013
3014	crtn = CSSM_CSP_CreateDeriveKeyContext(cspHand,
3015		CSSM_ALGID_FEE_KEYEXCH,			// AlgorithmID
3016		keyAlg,							// alg of the derived key
3017		keySizeInBits,
3018		NULL,							// access creds
3019		// FIXME
3020		0,								// IterationCount
3021		NULL,							// Salt
3022		NULL,							// Seed
3023		NULL);							// PassPhrase
3024	if(dkHand == 0) {
3025		printError("CSSM_CSP_CreateDeriveKeyContext");
3026		return CSSM_FAIL;
3027	}
3028	labelData.Length = keyLabelLen;
3029	labelData.Data = (uint8 *)keyLabel;
3030	crtn = CSSM_DeriveKey(dkHand,
3031		privKey,
3032		&pubKey->KeyData,		// Param - pub key blob
3033		keyUsage,
3034		CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE |
3035				  CSSM_KEYATTR_SENSITIVE,
3036		&labelData,
3037		derivedKey);
3038
3039	/* FIXME - save/restore error */
3040	CSSM_DeleteContext(dkHand);
3041	if(crtn) {
3042		printError("CSSM_DeriveKey");
3043	}
3044	return crtn;
3045}
3046#endif
3047
3048#pragma mark --------- Key/DL/DB support ---------
3049
3050/*
3051 * Add a DL/DB handle to a crypto context.
3052 */
3053CSSM_RETURN cspAddDlDbToContext(
3054	CSSM_CC_HANDLE ccHand,
3055	CSSM_DL_HANDLE dlHand,
3056	CSSM_DB_HANDLE dbHand)
3057{
3058	CSSM_DL_DB_HANDLE dlDb = { dlHand, dbHand };
3059	return AddContextAttribute(ccHand,
3060		CSSM_ATTRIBUTE_DL_DB_HANDLE,
3061		sizeof(CSSM_ATTRIBUTE_DL_DB_HANDLE),
3062		CAT_Ptr,
3063		&dlDb,
3064		0);
3065}
3066
3067/*
3068 * Common routine to do a basic DB lookup by label and key type.
3069 * Query is aborted prior to exit.
3070 */
3071static CSSM_DB_UNIQUE_RECORD_PTR dlLookup(
3072	CSSM_DL_DB_HANDLE	dlDbHand,
3073	const CSSM_DATA		*keyLabel,
3074	CT_KeyType 			keyType,
3075	CSSM_HANDLE 		*resultHand,			// RETURNED
3076	CSSM_DATA_PTR		theData,				// RETURED
3077	CSSM_DB_RECORDTYPE	*recordType)			// RETURNED
3078{
3079	CSSM_QUERY						query;
3080	CSSM_SELECTION_PREDICATE		predicate;
3081	CSSM_DB_UNIQUE_RECORD_PTR		record = NULL;
3082	CSSM_RETURN						crtn;
3083
3084	switch(keyType) {
3085		case CKT_Public:
3086			query.RecordType = *recordType = CSSM_DL_DB_RECORD_PUBLIC_KEY;
3087			break;
3088		case CKT_Private:
3089			query.RecordType = *recordType = CSSM_DL_DB_RECORD_PRIVATE_KEY;
3090			break;
3091		case CKT_Session:
3092			query.RecordType = *recordType = CSSM_DL_DB_RECORD_SYMMETRIC_KEY;
3093			break;
3094		default:
3095			printf("Hey bozo! Give me a valid key type!\n");
3096			return NULL;
3097	}
3098	query.Conjunctive = CSSM_DB_NONE;
3099	query.NumSelectionPredicates = 1;
3100	predicate.DbOperator = CSSM_DB_EQUAL;
3101
3102	predicate.Attribute.Info.AttributeNameFormat =
3103		CSSM_DB_ATTRIBUTE_NAME_AS_STRING;
3104	predicate.Attribute.Info.Label.AttributeName = (char *) "Label";
3105	predicate.Attribute.Info.AttributeFormat = CSSM_DB_ATTRIBUTE_FORMAT_BLOB;
3106	/* hope this cast is OK */
3107	predicate.Attribute.Value = (CSSM_DATA_PTR)keyLabel;
3108	query.SelectionPredicate = &predicate;
3109
3110	query.QueryLimits.TimeLimit = 0;	// FIXME - meaningful?
3111	query.QueryLimits.SizeLimit = 1;	// FIXME - meaningful?
3112	query.QueryFlags = CSSM_QUERY_RETURN_DATA;	// FIXME - used?
3113
3114	crtn = CSSM_DL_DataGetFirst(dlDbHand,
3115		&query,
3116		resultHand,
3117		NULL,
3118		theData,
3119		&record);
3120	/* abort only on success */
3121	if(crtn == CSSM_OK) {
3122		crtn = CSSM_DL_DataAbortQuery(dlDbHand, *resultHand);
3123		if(crtn) {
3124			printError("CSSM_DL_AbortQuery", crtn);
3125			return NULL;
3126		}
3127	}
3128	return record;
3129}
3130
3131/*
3132 * Look up a key by label and type.
3133 */
3134CSSM_KEY_PTR cspLookUpKeyByLabel(
3135	CSSM_DL_HANDLE dlHand,
3136	CSSM_DB_HANDLE dbHand,
3137	const CSSM_DATA *labelData,
3138	CT_KeyType keyType)
3139{
3140	CSSM_DB_UNIQUE_RECORD_PTR	record;
3141	CSSM_HANDLE					resultHand;
3142	CSSM_DATA					theData;
3143	CSSM_KEY_PTR				key;
3144	CSSM_DB_RECORDTYPE 			recordType;
3145	CSSM_DL_DB_HANDLE			dlDbHand;
3146
3147	dlDbHand.DLHandle = dlHand;
3148	dlDbHand.DBHandle = dbHand;
3149
3150	theData.Length = 0;
3151	theData.Data = NULL;
3152
3153	record = dlLookup(dlDbHand,
3154		labelData,
3155		keyType,
3156		&resultHand,
3157		&theData,
3158		&recordType);
3159	if(record == NULL) {
3160		//printf("cspLookUpKeyByLabel: key not found\n");
3161		return NULL;
3162	}
3163	key = (CSSM_KEY_PTR)theData.Data;
3164	CSSM_DL_FreeUniqueRecord(dlDbHand, record);
3165	return key;
3166}
3167
3168/*
3169 * Delete and free a key
3170 */
3171CSSM_RETURN cspDeleteKey(
3172	CSSM_CSP_HANDLE		cspHand,		// for free
3173	CSSM_DL_HANDLE		dlHand,			// for delete
3174	CSSM_DB_HANDLE		dbHand,			// ditto
3175	const CSSM_DATA 	*labelData,
3176	CSSM_KEY_PTR		key)
3177{
3178	CSSM_DB_UNIQUE_RECORD_PTR	record;
3179	CSSM_HANDLE					resultHand;
3180	CT_KeyType					keyType;
3181	CSSM_RETURN					crtn = CSSM_OK;
3182	CSSM_DB_RECORDTYPE 			recordType;
3183	CSSM_DL_DB_HANDLE			dlDbHand;
3184
3185	if(key->KeyHeader.KeyAttr & CSSM_KEYATTR_PERMANENT) {
3186		/* first do a lookup based in this key's fields */
3187		switch(key->KeyHeader.KeyClass) {
3188			case CSSM_KEYCLASS_PUBLIC_KEY:
3189				keyType = CKT_Public;
3190				break;
3191			case CSSM_KEYCLASS_PRIVATE_KEY:
3192				keyType = CKT_Private;
3193				break;
3194			case CSSM_KEYCLASS_SESSION_KEY:
3195				keyType = CKT_Session;
3196				break;
3197			default:
3198				printf("Hey bozo! Give me a valid key type!\n");
3199				return -1;
3200		}
3201
3202		dlDbHand.DLHandle = dlHand;
3203		dlDbHand.DBHandle = dbHand;
3204
3205		record = dlLookup(dlDbHand,
3206			labelData,
3207			keyType,
3208			&resultHand,
3209			NULL,			// don't want actual data
3210			&recordType);
3211		if(record == NULL) {
3212			printf("cspDeleteKey: key not found in DL\n");
3213			return CSSMERR_DL_RECORD_NOT_FOUND;
3214		}
3215
3216		/* OK, nuke it */
3217		crtn = CSSM_DL_DataDelete(dlDbHand, record);
3218		if(crtn) {
3219			printError("CSSM_DL_DataDelete", crtn);
3220		}
3221		CSSM_DL_FreeUniqueRecord(dlDbHand, record);
3222	}
3223
3224	/* CSSM_FreeKey() should fail due to the delete, but it will
3225	 * still free KeyData....
3226	 * FIXME - we should be able to do this in this one single call - right?
3227	 */
3228	CSSM_FreeKey(cspHand, NULL, key, CSSM_FALSE);
3229
3230	return crtn;
3231}
3232
3233/*
3234 * Given any key in either blob or reference format,
3235 * obtain the associated SHA-1 hash.
3236 */
3237CSSM_RETURN cspKeyHash(
3238	CSSM_CSP_HANDLE		cspHand,
3239	const CSSM_KEY_PTR	key,			/* public key */
3240	CSSM_DATA_PTR		*hashData)		/* hash mallocd and RETURNED here */
3241{
3242	CSSM_CC_HANDLE		ccHand;
3243	CSSM_RETURN			crtn;
3244	CSSM_DATA_PTR		dp;
3245
3246	*hashData = NULL;
3247
3248	/* validate input params */
3249	if((key == NULL) ||
3250	   (hashData == NULL)) {
3251	   	printf("cspKeyHash: bogus args\n");
3252		return CSSMERR_CSSM_INTERNAL_ERROR;
3253	}
3254
3255	/* cook up a context for a passthrough op */
3256	crtn = CSSM_CSP_CreatePassThroughContext(cspHand,
3257	 	key,
3258		&ccHand);
3259	if(ccHand == 0) {
3260		printError("CSSM_CSP_CreatePassThroughContext", crtn);
3261		return crtn;
3262	}
3263
3264	/* now it's up to the CSP */
3265	crtn = CSSM_CSP_PassThrough(ccHand,
3266		CSSM_APPLECSP_KEYDIGEST,
3267		NULL,
3268		(void **)&dp);
3269	if(crtn) {
3270		printError("CSSM_CSP_PassThrough(PUBKEYHASH)", crtn);
3271	}
3272	else {
3273		*hashData = dp;
3274		crtn = CSSM_OK;
3275	}
3276	CSSM_DeleteContext(ccHand);
3277	return crtn;
3278}
3279
3280