1/* Copyright (c) 1997,2003-2005,2008 Apple Inc.
2 *
3 * common.c - Common CSP test code
4 *
5 * Revision History
6 * ----------------
7 *   4 May 2000 Doug Mitchell
8 *		Ported to X/CDSA2.
9 *   6 Jul 1998 Doug Mitchell at Apple
10 *		Added clStartup().
11 *  12 Aug 1997	Doug Mitchell at Apple
12 *		Created.
13 */
14
15#include <stdlib.h>
16#include <stdio.h>
17#include <string.h>
18#include <Security/cssm.h>
19#include "common.h"
20#include <Security/cssmapple.h>			/* apple, not intel */
21#include <time.h>
22
23static CSSM_VERSION vers = {2, 0};
24//const static uint32 guidPrefix = 0xFADE;
25const CSSM_GUID testGuid = { 0xFADE, 0, 0, { 1,2,3,4,5,6,7,0 }};
26
27/*
28 * We can't enable this until all of these are fixed and integrated:
29 * 2890978 CSP
30 * 2927474 CSPDL
31 * 2928357 TP
32 */
33#define DETECT_MALLOC_ABUSE		1
34
35#if		DETECT_MALLOC_ABUSE
36
37/*
38 * This set of allocator functions detects when we free something
39 * which was mallocd by CDSA or a plugin using something other than
40 * our callback malloc/realloc/calloc. With proper runtime support
41 * (which is present in Jaguar 6C35), the reverse is also detected
42 * by malloc (i.e., we malloc something and CDSA or a plugin frees
43 * it).
44 */
45#define APP_MALLOC_MAGIC		'Util'
46
47void * appMalloc (CSSM_SIZE size, void *allocRef) {
48	void *ptr;
49
50	/* scribble magic number in first four bytes */
51	ptr = malloc(size + 4);
52	*(uint32 *)ptr = APP_MALLOC_MAGIC;
53	ptr = (char *)ptr + 4;
54
55	return ptr;
56}
57
58void appFree (void *ptr, void *allocRef) {
59	if(ptr == NULL) {
60		return;
61	}
62	ptr = (char *)ptr - 4;
63	if(*(uint32 *)ptr != APP_MALLOC_MAGIC) {
64		printf("ERROR: appFree() freeing a block that we didn't allocate!\n");
65		return;		// this free is not safe
66	}
67	*(uint32 *)ptr = 0;
68	free(ptr);
69}
70
71/* Realloc - adjust both original pointer and size */
72void * appRealloc (void *ptr, CSSM_SIZE size, void *allocRef) {
73	if(ptr == NULL) {
74		/* no ptr, no existing magic number */
75		return appMalloc(size, allocRef);
76	}
77	ptr = (char *)ptr - 4;
78	if(*(uint32 *)ptr != APP_MALLOC_MAGIC) {
79		printf("ERROR: appRealloc() on a block that we didn't allocate!\n");
80	}
81	*(uint32 *)ptr = 0;
82	ptr = realloc(ptr, size + 4);
83	*(uint32 *)ptr = APP_MALLOC_MAGIC;
84	ptr = (char *)ptr + 4;
85	return ptr;
86}
87
88/* Have to do this manually */
89void * appCalloc (uint32 num, CSSM_SIZE size, void *allocRef) {
90	uint32 memSize = num * size;
91
92	void *ptr = appMalloc(memSize, allocRef);
93	memset(ptr, 0, memSize);
94	return ptr;
95}
96
97#else	/* DETECT_MALLOC_ABUSE */
98/*
99 * Standard app-level memory functions required by CDSA.
100 */
101void * appMalloc (CSSM_SIZE size, void *allocRef) {
102	return( malloc(size) );
103}
104void appFree (void *mem_ptr, void *allocRef) {
105	free(mem_ptr);
106 	return;
107}
108void * appRealloc (void *ptr, CSSM_SIZE size, void *allocRef) {
109	return( realloc( ptr, size ) );
110}
111void * appCalloc (uint32 num, CSSM_SIZE size, void *allocRef) {
112	return( calloc( num, size ) );
113}
114#endif	/* DETECT_MALLOC_ABUSE */
115
116static CSSM_API_MEMORY_FUNCS memFuncs = {
117	appMalloc,
118	appFree,
119	appRealloc,
120 	appCalloc,
121 	NULL
122 };
123
124/*
125 * Init CSSM; returns CSSM_FALSE on error. Reusable.
126 */
127static CSSM_BOOL cssmInitd = CSSM_FALSE;
128CSSM_BOOL cssmStartup()
129{
130	CSSM_RETURN  crtn;
131    CSSM_PVC_MODE pvcPolicy = CSSM_PVC_NONE;
132
133	if(cssmInitd) {
134		return CSSM_TRUE;
135	}
136	crtn = CSSM_Init (&vers,
137		CSSM_PRIVILEGE_SCOPE_NONE,
138		&testGuid,
139		CSSM_KEY_HIERARCHY_NONE,
140		&pvcPolicy,
141		NULL /* reserved */);
142	if(crtn != CSSM_OK)
143	{
144		printError("CSSM_Init", crtn);
145		return CSSM_FALSE;
146	}
147	else {
148		cssmInitd = CSSM_TRUE;
149		return CSSM_TRUE;
150	}
151}
152
153/*
154 * Init CSSM and establish a session with the Apple CSP.
155 */
156CSSM_CSP_HANDLE cspStartup()
157{
158	return cspDlDbStartup(CSSM_TRUE, NULL);
159}
160
161/* like cspStartup, but also returns DB handle. If incoming dbHandPtr
162 * is NULL, no DB startup. */
163CSSM_CSP_HANDLE cspDbStartup(
164	CSSM_DB_HANDLE *dbHandPtr)
165{
166	return cspDlDbStartup(CSSM_TRUE, NULL);
167}
168
169CSSM_CSP_HANDLE cspDlDbStartup(
170	CSSM_BOOL bareCsp,			// true ==> CSP, false ==> CSP/DL
171	CSSM_DB_HANDLE *dbHandPtr)	// optional - TO BE DELETED
172{
173	CSSM_CSP_HANDLE cspHand;
174	CSSM_RETURN		crtn;
175	const CSSM_GUID *guid;
176	char *modName;
177
178	if(dbHandPtr) {
179		*dbHandPtr = 0;
180	}
181	if(cssmStartup() == CSSM_FALSE) {
182		return 0;
183	}
184	if(bareCsp) {
185		guid = &gGuidAppleCSP;
186		modName = (char*) "AppleCSP";
187	}
188	else {
189		guid = &gGuidAppleCSPDL;
190		modName = (char *) "AppleCSPDL";
191	}
192	crtn = CSSM_ModuleLoad(guid,
193		CSSM_KEY_HIERARCHY_NONE,
194		NULL,			// eventHandler
195		NULL);			// AppNotifyCallbackCtx
196	if(crtn) {
197		char outStr[100];
198		sprintf(outStr, "CSSM_ModuleLoad(%s)", modName);
199		printError(outStr, crtn);
200		return 0;
201	}
202	crtn = CSSM_ModuleAttach (guid,
203		&vers,
204		&memFuncs,			// memFuncs
205		0,					// SubserviceID
206		CSSM_SERVICE_CSP,
207		0,					// AttachFlags
208		CSSM_KEY_HIERARCHY_NONE,
209		NULL,				// FunctionTable
210		0,					// NumFuncTable
211		NULL,				// reserved
212		&cspHand);
213	if(crtn) {
214		char outStr[100];
215		sprintf(outStr, "CSSM_ModuleAttach(%s)", modName);
216		printError(outStr, crtn);
217		return 0;
218	}
219	return cspHand;
220}
221
222/*
223 * Detach and unload from a CSP.
224 */
225CSSM_RETURN cspShutdown(
226	CSSM_CSP_HANDLE	cspHand,
227	CSSM_BOOL bareCsp)			// true ==> CSP, false ==> CSP/DL
228{
229	CSSM_RETURN crtn;
230	const CSSM_GUID *guid;
231	char *modName;
232
233	if(bareCsp) {
234		guid = &gGuidAppleCSP;
235		modName = (char *) "AppleCSP";
236	}
237	else {
238		guid = &gGuidAppleCSPDL;
239		modName = (char *) "AppleCSPDL";
240	}
241	crtn = CSSM_ModuleDetach(cspHand);
242	if(crtn) {
243		printf("Error detaching from %s\n", modName);
244		printError("CSSM_ModuleDetach", crtn);
245		return crtn;
246	}
247	crtn = CSSM_ModuleUnload(guid, NULL, NULL);
248	if(crtn) {
249		printf("Error unloading %s\n", modName);
250		printError("CSSM_ModuleUnload", crtn);
251	}
252	return crtn;
253}
254
255/* Attach to DL side of CSPDL */
256CSSM_DL_HANDLE dlStartup()
257{
258	CSSM_DL_HANDLE 	dlHand = 0;
259	CSSM_RETURN		crtn;
260
261	if(cssmStartup() == CSSM_FALSE) {
262		return 0;
263	}
264	crtn = CSSM_ModuleLoad(&gGuidAppleCSPDL,
265		CSSM_KEY_HIERARCHY_NONE,
266		NULL,			// eventHandler
267		NULL);			// AppNotifyCallbackCtx
268	if(crtn) {
269		printError("CSSM_ModuleLoad(Apple CSPDL)", crtn);
270		return 0;
271	}
272	crtn = CSSM_ModuleAttach (&gGuidAppleCSPDL,
273		&vers,
274		&memFuncs,			// memFuncs
275		0,					// SubserviceID
276		CSSM_SERVICE_DL,
277		0,					// AttachFlags
278		CSSM_KEY_HIERARCHY_NONE,
279		NULL,				// FunctionTable
280		0,					// NumFuncTable
281		NULL,				// reserved
282		&dlHand);
283	if(crtn) {
284		printError("CSSM_ModuleAttach(Apple CSPDL)", crtn);
285		return 0;
286	}
287	return dlHand;
288}
289
290/*
291 * Delete a DB.
292 */
293#define DELETE_WITH_AUTHENT		0
294CSSM_RETURN dbDelete(
295	CSSM_DL_HANDLE		dlHand,			// from dlStartup()
296	const char 			*dbName)
297{
298	return CSSM_DL_DbDelete(dlHand, dbName, NULL, NULL);
299}
300
301/*
302 * open a DB, ensure it's empty.
303 */
304CSSM_DB_HANDLE dbStartup(
305	CSSM_DL_HANDLE		dlHand,			// from dlStartup()
306	const char 			*dbName)
307{
308	CSSM_DB_HANDLE dbHand = 0;
309
310	CSSM_RETURN crtn = dbCreateOpen(dlHand, dbName,
311		CSSM_TRUE,		// create
312		CSSM_TRUE,		// delete
313		NULL,			// pwd
314		&dbHand);
315	if(crtn == CSSM_OK) {
316		return dbHand;
317	}
318	else {
319		return 0;
320	}
321}
322
323#if 0
324/*
325 * Attach to existing DB or create an empty new one.
326 */
327CSSM_DB_HANDLE dbStartupByName(CSSM_DL_HANDLE dlHand,
328	char 		*dbName,
329	CSSM_BOOL 	doCreate)
330{
331	CSSM_RETURN crtn;
332	CSSM_DB_HANDLE				dbHand;
333
334	/* try to open existing DB in either case */
335
336	crtn = CSSM_DL_DbOpen(dlHand,
337		dbName,
338		NULL,			// DbLocation
339		CSSM_DB_ACCESS_READ | CSSM_DB_ACCESS_WRITE,
340		NULL, 			// CSSM_ACCESS_CREDENTIALS *AccessCred
341		NULL,			// void *OpenParameters
342		&dbHand);
343	if(dbHand != 0) {
344		return dbHand;
345	}
346	if(!doCreate) {
347		printf("***no such data base (%s)\n", dbName);
348		printError("CSSM_DL_DbOpen", crtn);
349		return 0;
350	}
351	/* have to create one */
352	return dbStartup(dlHand, dbName);
353}
354#endif
355
356/*
357 * routines which convert various types to untyped byte arrays.
358 */
359void intToBytes(unsigned i, unsigned char *buf)
360{
361	*buf++ = (unsigned char)((i >> 24) & 0xff);
362	*buf++ = (unsigned char)((i >> 16) & 0xff);
363	*buf++ = (unsigned char)((i >> 8)  & 0xff);
364	*buf   = (unsigned char)(i & 0xff);
365}
366void shortToBytes(unsigned short s, unsigned char *buf)
367{
368	*buf++ = (unsigned char)((s >> 8)  & 0xff);
369	*buf   = (unsigned char)(s & 0xff);
370}
371unsigned bytesToInt(const unsigned char *buf) {
372	unsigned result;
373	result = (((unsigned)buf[0] << 24) & 0xff000000) |
374		(((unsigned)buf[1] << 16) & 0x00ff0000) |
375		(((unsigned)buf[2] << 8) & 0xff00) |
376		(((unsigned)buf[3]) & 0xff);
377	return result;
378}
379unsigned short bytesToShort(const unsigned char *buf) {
380    	unsigned short result;
381    	result = (((unsigned short)buf[0] << 8) & 0xff00) |
382		 (((unsigned short)buf[1]) & 0xff);
383    	return result;
384}
385
386/*
387 * Given a context specified via a CSSM_CC_HANDLE, add a new
388 * CSSM_CONTEXT_ATTRIBUTE to the context as specified by AttributeType,
389 * AttributeLength, and an untyped pointer.
390 *
391 * This is currently used to add a second CSSM_KEY attribute when performing
392 * ops with algorithm CSSM_ALGID_FEED and CSSM_ALGID_FEECFILE.
393 */
394CSSM_RETURN AddContextAttribute(CSSM_CC_HANDLE CCHandle,
395	uint32 AttributeType,
396	uint32 AttributeLength,
397	ContextAttrType attrType,
398	/* specify exactly one of these */
399	const void *AttributePtr,
400	uint32 attributeInt)
401{
402	CSSM_CONTEXT_ATTRIBUTE		newAttr;
403	CSSM_RETURN					crtn;
404
405	newAttr.AttributeType     = AttributeType;
406	newAttr.AttributeLength   = AttributeLength;
407	if(attrType == CAT_Uint32) {
408		newAttr.Attribute.Uint32  = attributeInt;
409	}
410	else {
411		newAttr.Attribute.Data    = (CSSM_DATA_PTR)AttributePtr;
412	}
413	crtn = CSSM_UpdateContextAttributes(CCHandle, 1, &newAttr);
414	if(crtn) {
415		printError("CSSM_UpdateContextAttributes", crtn);
416	}
417	return crtn;
418}
419
420/*
421 * Set up a CSSM data.
422 */
423CSSM_RETURN appSetupCssmData(
424	CSSM_DATA_PTR	data,
425	uint32			numBytes)
426{
427	if(data == NULL) {
428		printf("Hey! appSetupCssmData with NULL Data!\n");
429		return CSSMERR_CSSM_INTERNAL_ERROR;
430	}
431	data->Data = (uint8 *)CSSM_MALLOC(numBytes);
432	if(data->Data == NULL) {
433		return CSSMERR_CSSM_MEMORY_ERROR;
434	}
435	data->Length = numBytes;
436	return CSSM_OK;
437}
438
439/*
440 * Free the data referenced by a CSSM data, and optionally, the struct itself.
441 */
442void appFreeCssmData(CSSM_DATA_PTR data,
443	CSSM_BOOL freeStruct)
444{
445	if(data == NULL) {
446		return;
447	}
448	if(data->Length != 0) {
449		CSSM_FREE(data->Data);
450	}
451	if(freeStruct) {
452		CSSM_FREE(data);
453	}
454	else {
455		data->Length = 0;
456		data->Data = NULL;
457	}
458}
459
460/*
461 * Copy src to dst, mallocing dst.
462 */
463CSSM_RETURN appCopyCssmData(const CSSM_DATA *src,
464	CSSM_DATA_PTR dst)
465{
466	return appCopyData(src->Data, src->Length, dst);
467}
468
469/* copy raw data to a CSSM_DATA, mallocing dst. */
470CSSM_RETURN  appCopyData(const void *src,
471	uint32 len,
472	CSSM_DATA_PTR dst)
473{
474	dst->Length = 0;
475	if(len == 0) {
476		dst->Data = NULL;
477		return CSSM_OK;
478	}
479	dst->Data = (uint8 *)CSSM_MALLOC(len);
480	if(dst->Data == NULL) {
481		return CSSM_ERRCODE_MEMORY_ERROR;
482	}
483	dst->Length = len;
484	memcpy(dst->Data, src, len);
485	return CSSM_OK;
486}
487
488CSSM_BOOL appCompareCssmData(const CSSM_DATA *d1,
489	const CSSM_DATA *d2)
490{
491	if(d1->Length != d2->Length) {
492		return CSSM_FALSE;
493	}
494	if(memcmp(d1->Data, d2->Data, d1->Length)) {
495		return CSSM_FALSE;
496	}
497	return CSSM_TRUE;
498}
499
500/* min <= return <= max */
501unsigned genRand(unsigned min, unsigned max)
502{
503	unsigned i;
504	if(min == max) {
505		return min;
506	}
507	appGetRandomBytes(&i, 4);
508	return (min + (i % (max - min + 1)));
509}
510
511void simpleGenData(CSSM_DATA_PTR dbuf, unsigned minBufSize, unsigned maxBufSize)
512{
513	unsigned len = genRand(minBufSize, maxBufSize);
514	appGetRandomBytes(dbuf->Data, len);
515	dbuf->Length = len;
516}
517
518#define MIN_OFFSET	0
519#define MAX_OFFSET	99
520#define MIN_ASCII	'a'
521#define MAX_ASCII	'z'
522
523/*
524 * Calculate random data size, fill dataPool with that many random bytes.
525 *
526 * (10**minExp + MIN_OFFSET) <= size <= (10**maxExp + MAX_OFFSET)
527 */
528unsigned genData(unsigned char *dataPool,
529	unsigned minExp,
530	unsigned maxExp,
531	dataType type)
532{
533	int 		exp;
534	int 		offset;
535	int 		size;
536	char 		*cp;
537	int 		i;
538	char		ac;
539
540	/*
541	 * Calculate "random" size : (10 ** (random exponent)) + random offset
542	 */
543	exp = genRand(minExp, maxExp);
544	offset = genRand(MIN_OFFSET, MAX_OFFSET);
545	size = 1;
546	while(exp--) {			// size = 10 ** exp
547		size *= 10;
548	}
549	size += offset;
550	switch(type) {
551	    case DT_Zero:
552			bzero(dataPool, size);
553			break;
554	    case DT_Increment:
555			{
556				int i;
557				for(i=0; i<size; i++) {
558					dataPool[i] = i;
559				}
560			}
561			break;
562	    case DT_ASCII:
563	    	ac = MIN_ASCII;
564			cp = (char *)dataPool;
565	    	for(i=0; i<size; i++) {
566				*cp++ = ac++;
567				if(ac > MAX_ASCII) {
568					ac = MIN_ASCII;
569				}
570			}
571			break;
572	    case DT_Random:
573			appGetRandomBytes(dataPool, size);
574			break;
575	}
576	return size;
577}
578
579void dumpBuffer(
580	const char *bufName,	// optional
581	unsigned char *buf,
582	unsigned len)
583{
584	unsigned i;
585
586	if(bufName) {
587		printf("%s\n", bufName);
588	}
589	printf("   ");
590	for(i=0; i<len; i++) {
591		printf("%02X ", buf[i]);
592		if((i % 24) == 23) {
593			printf("\n   ");
594		}
595	}
596	printf("\n");
597}
598
599int testError(CSSM_BOOL quiet)
600{
601	char resp;
602
603	if(quiet) {
604		printf("\n***Test aborting.\n");
605		exit(1);
606	}
607	fpurge(stdin);
608	printf("a to abort, c to continue: ");
609	resp = getchar();
610	return (resp == 'a');
611}
612
613void testStartBanner(
614	const char *testName,
615	int argc,
616	char **argv)
617{
618	printf("Starting %s; args: ", testName);
619	for(int i=1; i<argc; i++) {
620		printf("%s ", argv[i]);
621	}
622	printf("\n");
623}
624
625