+/* Copyright (c) 1997,2003-2005,2008 Apple Inc.
+ *
+ * common.c - Common CSP test code
+ *
+ * Revision History
+ * ----------------
+ * 4 May 2000 Doug Mitchell
+ * Ported to X/CDSA2.
+ * 6 Jul 1998 Doug Mitchell at Apple
+ * Added clStartup().
+ * 12 Aug 1997 Doug Mitchell at Apple
+ * Created.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <Security/cssm.h>
+#include "common.h"
+#include <Security/cssmapple.h> /* apple, not intel */
+#include <time.h>
+
+static CSSM_VERSION vers = {2, 0};
+//const static uint32 guidPrefix = 0xFADE;
+const CSSM_GUID testGuid = { 0xFADE, 0, 0, { 1,2,3,4,5,6,7,0 }};
+
+/*
+ * We can't enable this until all of these are fixed and integrated:
+ * 2890978 CSP
+ * 2927474 CSPDL
+ * 2928357 TP
+ */
+#define DETECT_MALLOC_ABUSE 1
+
+#if DETECT_MALLOC_ABUSE
+
+/*
+ * This set of allocator functions detects when we free something
+ * which was mallocd by CDSA or a plugin using something other than
+ * our callback malloc/realloc/calloc. With proper runtime support
+ * (which is present in Jaguar 6C35), the reverse is also detected
+ * by malloc (i.e., we malloc something and CDSA or a plugin frees
+ * it).
+ */
+#define APP_MALLOC_MAGIC 'Util'
+
+void * appMalloc (CSSM_SIZE size, void *allocRef) {
+ void *ptr;
+
+ /* scribble magic number in first four bytes */
+ ptr = malloc(size + 4);
+ *(uint32 *)ptr = APP_MALLOC_MAGIC;
+ ptr = (char *)ptr + 4;
+
+ return ptr;
+}
+
+void appFree (void *ptr, void *allocRef) {
+ if(ptr == NULL) {
+ return;
+ }
+ ptr = (char *)ptr - 4;
+ if(*(uint32 *)ptr != APP_MALLOC_MAGIC) {
+ printf("ERROR: appFree() freeing a block that we didn't allocate!\n");
+ return; // this free is not safe
+ }
+ *(uint32 *)ptr = 0;
+ free(ptr);
+}
+
+/* Realloc - adjust both original pointer and size */
+void * appRealloc (void *ptr, CSSM_SIZE size, void *allocRef) {
+ if(ptr == NULL) {
+ /* no ptr, no existing magic number */
+ return appMalloc(size, allocRef);
+ }
+ ptr = (char *)ptr - 4;
+ if(*(uint32 *)ptr != APP_MALLOC_MAGIC) {
+ printf("ERROR: appRealloc() on a block that we didn't allocate!\n");
+ }
+ *(uint32 *)ptr = 0;
+ ptr = realloc(ptr, size + 4);
+ *(uint32 *)ptr = APP_MALLOC_MAGIC;
+ ptr = (char *)ptr + 4;
+ return ptr;
+}
+
+/* Have to do this manually */
+void * appCalloc (uint32 num, CSSM_SIZE size, void *allocRef) {
+ uint32 memSize = num * size;
+
+ void *ptr = appMalloc(memSize, allocRef);
+ memset(ptr, 0, memSize);
+ return ptr;
+}
+
+#else /* DETECT_MALLOC_ABUSE */
+/*
+ * Standard app-level memory functions required by CDSA.
+ */
+void * appMalloc (CSSM_SIZE size, void *allocRef) {
+ return( malloc(size) );
+}
+void appFree (void *mem_ptr, void *allocRef) {
+ free(mem_ptr);
+ return;
+}
+void * appRealloc (void *ptr, CSSM_SIZE size, void *allocRef) {
+ return( realloc( ptr, size ) );
+}
+void * appCalloc (uint32 num, CSSM_SIZE size, void *allocRef) {
+ return( calloc( num, size ) );
+}
+#endif /* DETECT_MALLOC_ABUSE */
+
+static CSSM_API_MEMORY_FUNCS memFuncs = {
+ appMalloc,
+ appFree,
+ appRealloc,
+ appCalloc,
+ NULL
+ };
+
+/*
+ * Init CSSM; returns CSSM_FALSE on error. Reusable.
+ */
+static CSSM_BOOL cssmInitd = CSSM_FALSE;
+CSSM_BOOL cssmStartup()
+{
+ CSSM_RETURN crtn;
+ CSSM_PVC_MODE pvcPolicy = CSSM_PVC_NONE;
+
+ if(cssmInitd) {
+ return CSSM_TRUE;
+ }
+ crtn = CSSM_Init (&vers,
+ CSSM_PRIVILEGE_SCOPE_NONE,
+ &testGuid,
+ CSSM_KEY_HIERARCHY_NONE,
+ &pvcPolicy,
+ NULL /* reserved */);
+ if(crtn != CSSM_OK)
+ {
+ printError("CSSM_Init", crtn);
+ return CSSM_FALSE;
+ }
+ else {
+ cssmInitd = CSSM_TRUE;
+ return CSSM_TRUE;
+ }
+}
+
+/*
+ * Init CSSM and establish a session with the Apple CSP.
+ */
+CSSM_CSP_HANDLE cspStartup()
+{
+ return cspDlDbStartup(CSSM_TRUE, NULL);
+}
+
+/* like cspStartup, but also returns DB handle. If incoming dbHandPtr
+ * is NULL, no DB startup. */
+CSSM_CSP_HANDLE cspDbStartup(
+ CSSM_DB_HANDLE *dbHandPtr)
+{
+ return cspDlDbStartup(CSSM_TRUE, NULL);
+}
+
+CSSM_CSP_HANDLE cspDlDbStartup(
+ CSSM_BOOL bareCsp, // true ==> CSP, false ==> CSP/DL
+ CSSM_DB_HANDLE *dbHandPtr) // optional - TO BE DELETED
+{
+ CSSM_CSP_HANDLE cspHand;
+ CSSM_RETURN crtn;
+ const CSSM_GUID *guid;
+ char *modName;
+
+ if(dbHandPtr) {
+ *dbHandPtr = 0;
+ }
+ if(cssmStartup() == CSSM_FALSE) {
+ return 0;
+ }
+ if(bareCsp) {
+ guid = &gGuidAppleCSP;
+ modName = (char*) "AppleCSP";
+ }
+ else {
+ guid = &gGuidAppleCSPDL;
+ modName = (char *) "AppleCSPDL";
+ }
+ crtn = CSSM_ModuleLoad(guid,
+ CSSM_KEY_HIERARCHY_NONE,
+ NULL, // eventHandler
+ NULL); // AppNotifyCallbackCtx
+ if(crtn) {
+ char outStr[100];
+ sprintf(outStr, "CSSM_ModuleLoad(%s)", modName);
+ printError(outStr, crtn);
+ return 0;
+ }
+ crtn = CSSM_ModuleAttach (guid,
+ &vers,
+ &memFuncs, // memFuncs
+ 0, // SubserviceID
+ CSSM_SERVICE_CSP,
+ 0, // AttachFlags
+ CSSM_KEY_HIERARCHY_NONE,
+ NULL, // FunctionTable
+ 0, // NumFuncTable
+ NULL, // reserved
+ &cspHand);
+ if(crtn) {
+ char outStr[100];
+ sprintf(outStr, "CSSM_ModuleAttach(%s)", modName);
+ printError(outStr, crtn);
+ return 0;
+ }
+ return cspHand;
+}
+
+/*
+ * Detach and unload from a CSP.
+ */
+CSSM_RETURN cspShutdown(
+ CSSM_CSP_HANDLE cspHand,
+ CSSM_BOOL bareCsp) // true ==> CSP, false ==> CSP/DL
+{
+ CSSM_RETURN crtn;
+ const CSSM_GUID *guid;
+ char *modName;
+
+ if(bareCsp) {
+ guid = &gGuidAppleCSP;
+ modName = (char *) "AppleCSP";
+ }
+ else {
+ guid = &gGuidAppleCSPDL;
+ modName = (char *) "AppleCSPDL";
+ }
+ crtn = CSSM_ModuleDetach(cspHand);
+ if(crtn) {
+ printf("Error detaching from %s\n", modName);
+ printError("CSSM_ModuleDetach", crtn);
+ return crtn;
+ }
+ crtn = CSSM_ModuleUnload(guid, NULL, NULL);
+ if(crtn) {
+ printf("Error unloading %s\n", modName);
+ printError("CSSM_ModuleUnload", crtn);
+ }
+ return crtn;
+}
+
+/* Attach to DL side of CSPDL */
+CSSM_DL_HANDLE dlStartup()
+{
+ CSSM_DL_HANDLE dlHand = 0;
+ CSSM_RETURN crtn;
+
+ if(cssmStartup() == CSSM_FALSE) {
+ return 0;
+ }
+ crtn = CSSM_ModuleLoad(&gGuidAppleCSPDL,
+ CSSM_KEY_HIERARCHY_NONE,
+ NULL, // eventHandler
+ NULL); // AppNotifyCallbackCtx
+ if(crtn) {
+ printError("CSSM_ModuleLoad(Apple CSPDL)", crtn);
+ return 0;
+ }
+ crtn = CSSM_ModuleAttach (&gGuidAppleCSPDL,
+ &vers,
+ &memFuncs, // memFuncs
+ 0, // SubserviceID
+ CSSM_SERVICE_DL,
+ 0, // AttachFlags
+ CSSM_KEY_HIERARCHY_NONE,
+ NULL, // FunctionTable
+ 0, // NumFuncTable
+ NULL, // reserved
+ &dlHand);
+ if(crtn) {
+ printError("CSSM_ModuleAttach(Apple CSPDL)", crtn);
+ return 0;
+ }
+ return dlHand;
+}
+
+/*
+ * Delete a DB.
+ */
+#define DELETE_WITH_AUTHENT 0
+CSSM_RETURN dbDelete(
+ CSSM_DL_HANDLE dlHand, // from dlStartup()
+ const char *dbName)
+{
+ return CSSM_DL_DbDelete(dlHand, dbName, NULL, NULL);
+}
+
+/*
+ * open a DB, ensure it's empty.
+ */
+CSSM_DB_HANDLE dbStartup(
+ CSSM_DL_HANDLE dlHand, // from dlStartup()
+ const char *dbName)
+{
+ CSSM_DB_HANDLE dbHand = 0;
+
+ CSSM_RETURN crtn = dbCreateOpen(dlHand, dbName,
+ CSSM_TRUE, // create
+ CSSM_TRUE, // delete
+ NULL, // pwd
+ &dbHand);
+ if(crtn == CSSM_OK) {
+ return dbHand;
+ }
+ else {
+ return 0;
+ }
+}
+
+#if 0
+/*
+ * Attach to existing DB or create an empty new one.
+ */
+CSSM_DB_HANDLE dbStartupByName(CSSM_DL_HANDLE dlHand,
+ char *dbName,
+ CSSM_BOOL doCreate)
+{
+ CSSM_RETURN crtn;
+ CSSM_DB_HANDLE dbHand;
+
+ /* try to open existing DB in either case */
+
+ crtn = CSSM_DL_DbOpen(dlHand,
+ dbName,
+ NULL, // DbLocation
+ CSSM_DB_ACCESS_READ | CSSM_DB_ACCESS_WRITE,
+ NULL, // CSSM_ACCESS_CREDENTIALS *AccessCred
+ NULL, // void *OpenParameters
+ &dbHand);
+ if(dbHand != 0) {
+ return dbHand;
+ }
+ if(!doCreate) {
+ printf("***no such data base (%s)\n", dbName);
+ printError("CSSM_DL_DbOpen", crtn);
+ return 0;
+ }
+ /* have to create one */
+ return dbStartup(dlHand, dbName);
+}
+#endif
+
+/*
+ * routines which convert various types to untyped byte arrays.
+ */
+void intToBytes(unsigned i, unsigned char *buf)
+{
+ *buf++ = (unsigned char)((i >> 24) & 0xff);
+ *buf++ = (unsigned char)((i >> 16) & 0xff);
+ *buf++ = (unsigned char)((i >> 8) & 0xff);
+ *buf = (unsigned char)(i & 0xff);
+}
+void shortToBytes(unsigned short s, unsigned char *buf)
+{
+ *buf++ = (unsigned char)((s >> 8) & 0xff);
+ *buf = (unsigned char)(s & 0xff);
+}
+unsigned bytesToInt(const unsigned char *buf) {
+ unsigned result;
+ result = (((unsigned)buf[0] << 24) & 0xff000000) |
+ (((unsigned)buf[1] << 16) & 0x00ff0000) |
+ (((unsigned)buf[2] << 8) & 0xff00) |
+ (((unsigned)buf[3]) & 0xff);
+ return result;
+}
+unsigned short bytesToShort(const unsigned char *buf) {
+ unsigned short result;
+ result = (((unsigned short)buf[0] << 8) & 0xff00) |
+ (((unsigned short)buf[1]) & 0xff);
+ return result;
+}
+
+/*
+ * Given a context specified via a CSSM_CC_HANDLE, add a new
+ * CSSM_CONTEXT_ATTRIBUTE to the context as specified by AttributeType,
+ * AttributeLength, and an untyped pointer.
+ *
+ * This is currently used to add a second CSSM_KEY attribute when performing
+ * ops with algorithm CSSM_ALGID_FEED and CSSM_ALGID_FEECFILE.
+ */
+CSSM_RETURN AddContextAttribute(CSSM_CC_HANDLE CCHandle,
+ uint32 AttributeType,
+ uint32 AttributeLength,
+ ContextAttrType attrType,
+ /* specify exactly one of these */
+ const void *AttributePtr,
+ uint32 attributeInt)
+{
+ CSSM_CONTEXT_ATTRIBUTE newAttr;
+ CSSM_RETURN crtn;
+
+ newAttr.AttributeType = AttributeType;
+ newAttr.AttributeLength = AttributeLength;
+ if(attrType == CAT_Uint32) {
+ newAttr.Attribute.Uint32 = attributeInt;
+ }
+ else {
+ newAttr.Attribute.Data = (CSSM_DATA_PTR)AttributePtr;
+ }
+ crtn = CSSM_UpdateContextAttributes(CCHandle, 1, &newAttr);
+ if(crtn) {
+ printError("CSSM_UpdateContextAttributes", crtn);
+ }
+ return crtn;
+}
+
+/*
+ * Set up a CSSM data.
+ */
+CSSM_RETURN appSetupCssmData(
+ CSSM_DATA_PTR data,
+ uint32 numBytes)
+{
+ if(data == NULL) {
+ printf("Hey! appSetupCssmData with NULL Data!\n");
+ return CSSMERR_CSSM_INTERNAL_ERROR;
+ }
+ data->Data = (uint8 *)CSSM_MALLOC(numBytes);
+ if(data->Data == NULL) {
+ return CSSMERR_CSSM_MEMORY_ERROR;
+ }
+ data->Length = numBytes;
+ return CSSM_OK;
+}
+
+/*
+ * Free the data referenced by a CSSM data, and optionally, the struct itself.
+ */
+void appFreeCssmData(CSSM_DATA_PTR data,
+ CSSM_BOOL freeStruct)
+{
+ if(data == NULL) {
+ return;
+ }
+ if(data->Length != 0) {
+ CSSM_FREE(data->Data);
+ }
+ if(freeStruct) {
+ CSSM_FREE(data);
+ }
+ else {
+ data->Length = 0;
+ data->Data = NULL;
+ }
+}
+
+/*
+ * Copy src to dst, mallocing dst.
+ */
+CSSM_RETURN appCopyCssmData(const CSSM_DATA *src,
+ CSSM_DATA_PTR dst)
+{
+ return appCopyData(src->Data, src->Length, dst);
+}
+
+/* copy raw data to a CSSM_DATA, mallocing dst. */
+CSSM_RETURN appCopyData(const void *src,
+ uint32 len,
+ CSSM_DATA_PTR dst)
+{
+ dst->Length = 0;
+ if(len == 0) {
+ dst->Data = NULL;
+ return CSSM_OK;
+ }
+ dst->Data = (uint8 *)CSSM_MALLOC(len);
+ if(dst->Data == NULL) {
+ return CSSM_ERRCODE_MEMORY_ERROR;
+ }
+ dst->Length = len;
+ memcpy(dst->Data, src, len);
+ return CSSM_OK;
+}
+
+CSSM_BOOL appCompareCssmData(const CSSM_DATA *d1,
+ const CSSM_DATA *d2)
+{
+ if(d1->Length != d2->Length) {
+ return CSSM_FALSE;
+ }
+ if(memcmp(d1->Data, d2->Data, d1->Length)) {
+ return CSSM_FALSE;
+ }
+ return CSSM_TRUE;
+}
+
+/* min <= return <= max */
+unsigned genRand(unsigned min, unsigned max)
+{
+ unsigned i;
+ if(min == max) {
+ return min;
+ }
+ appGetRandomBytes(&i, 4);
+ return (min + (i % (max - min + 1)));
+}
+
+void simpleGenData(CSSM_DATA_PTR dbuf, unsigned minBufSize, unsigned maxBufSize)
+{
+ unsigned len = genRand(minBufSize, maxBufSize);
+ appGetRandomBytes(dbuf->Data, len);
+ dbuf->Length = len;
+}
+
+#define MIN_OFFSET 0
+#define MAX_OFFSET 99
+#define MIN_ASCII 'a'
+#define MAX_ASCII 'z'
+
+/*
+ * Calculate random data size, fill dataPool with that many random bytes.
+ *
+ * (10**minExp + MIN_OFFSET) <= size <= (10**maxExp + MAX_OFFSET)
+ */
+unsigned genData(unsigned char *dataPool,
+ unsigned minExp,
+ unsigned maxExp,
+ dataType type)
+{
+ int exp;
+ int offset;
+ int size;
+ char *cp;
+ int i;
+ char ac;
+
+ /*
+ * Calculate "random" size : (10 ** (random exponent)) + random offset
+ */
+ exp = genRand(minExp, maxExp);
+ offset = genRand(MIN_OFFSET, MAX_OFFSET);
+ size = 1;
+ while(exp--) { // size = 10 ** exp
+ size *= 10;
+ }
+ size += offset;
+ switch(type) {
+ case DT_Zero:
+ bzero(dataPool, size);
+ break;
+ case DT_Increment:
+ {
+ int i;
+ for(i=0; i<size; i++) {
+ dataPool[i] = i;
+ }
+ }
+ break;
+ case DT_ASCII:
+ ac = MIN_ASCII;
+ cp = (char *)dataPool;
+ for(i=0; i<size; i++) {
+ *cp++ = ac++;
+ if(ac > MAX_ASCII) {
+ ac = MIN_ASCII;
+ }
+ }
+ break;
+ case DT_Random:
+ appGetRandomBytes(dataPool, size);
+ break;
+ }
+ return size;
+}
+
+void dumpBuffer(
+ const char *bufName, // optional
+ unsigned char *buf,
+ unsigned len)
+{
+ unsigned i;
+
+ if(bufName) {
+ printf("%s\n", bufName);
+ }
+ printf(" ");
+ for(i=0; i<len; i++) {
+ printf("%02X ", buf[i]);
+ if((i % 24) == 23) {
+ printf("\n ");
+ }
+ }
+ printf("\n");
+}
+
+int testError(CSSM_BOOL quiet)
+{
+ char resp;
+
+ if(quiet) {
+ printf("\n***Test aborting.\n");
+ exit(1);
+ }
+ fpurge(stdin);
+ printf("a to abort, c to continue: ");
+ resp = getchar();
+ return (resp == 'a');
+}
+
+void testStartBanner(
+ const char *testName,
+ int argc,
+ char **argv)
+{
+ printf("Starting %s; args: ", testName);
+ for(int i=1; i<argc; i++) {
+ printf("%s ", argv[i]);
+ }
+ printf("\n");
+}
+