clTool.cpp   [plain text]


/*
 * clTool.cpp - menu-driven CL exerciser
 */
 
#include <security_cdsa_utils/cuPrintCert.h>
#include <security_cdsa_utils/cuOidParser.h>
#include <security_cdsa_utils/cuFileIo.h>
#include <clAppUtils/clutils.h>
#include <utilLib/common.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <Security/cssmtype.h>
#include <Security/cssmapi.h>
#include <Security/oidscert.h>

/*
 * A list of OIDs we inquire about. 
 */
static const CSSM_OID *knownOids[] = 
{
	&CSSMOID_X509V1Version,			// not always present
	&CSSMOID_X509V1SerialNumber,
	&CSSMOID_X509V1IssuerNameCStruct,
	&CSSMOID_X509V1SubjectNameCStruct,
	&CSSMOID_CSSMKeyStruct,
	&CSSMOID_X509V1SubjectPublicKeyCStruct,
	&CSSMOID_X509V1ValidityNotBefore,
	&CSSMOID_X509V1ValidityNotAfter,
	&CSSMOID_X509V1SignatureAlgorithmTBS,
	&CSSMOID_X509V1SignatureAlgorithm,
	&CSSMOID_X509V1Signature,
	&CSSMOID_X509V3CertificateExtensionCStruct,
	&CSSMOID_KeyUsage,
	&CSSMOID_BasicConstraints,
	&CSSMOID_ExtendedKeyUsage,
	&CSSMOID_CertificatePolicies,
	&CSSMOID_NetscapeCertType
};

#define NUM_KNOWN_OIDS	(sizeof(knownOids) / sizeof(CSSM_OID *))

static const char *oidNames[] = 
{
	"CSSMOID_X509V1Version",
	"CSSMOID_X509V1SerialNumber",
	"CSSMOID_X509V1IssuerNameCStruct",
	"CSSMOID_X509V1SubjectNameCStruct",
	"CSSMOID_CSSMKeyStruct",
	"CSSMOID_X509V1SubjectPublicKeyCStruct",
	"CSSMOID_X509V1ValidityNotBefore",
	"CSSMOID_X509V1ValidityNotAfter",
	"CSSMOID_X509V1SignatureAlgorithmTBS",
	"CSSMOID_X509V1SignatureAlgorithm",
	"CSSMOID_X509V1Signature",
	"CSSMOID_X509V3CertificateExtensionCStruct",
	"CSSMOID_KeyUsage",
	"CSSMOID_BasicConstraints",
	"CSSMOID_ExtendedKeyUsage",
	"CSSMOID_CertificatePolicies",
	"CSSMOID_NetscapeCertType"
};

static void usage(char **argv)
{
	printf("Usage: %s certFile\n", argv[0]);
	exit(1);
}

int main(int argc, char **argv)
{
	CSSM_DATA 		certData = {0, NULL};
	CSSM_CL_HANDLE 	clHand = CSSM_INVALID_HANDLE;
	CSSM_HANDLE 	cacheHand = CSSM_INVALID_HANDLE;
	CSSM_HANDLE 	searchHand = CSSM_INVALID_HANDLE;
	char 			resp;
	CSSM_RETURN 	crtn;
	unsigned 		fieldDex;
	CSSM_DATA_PTR	fieldValue;
	uint32			numFields;
	CSSM_FIELD		field;
	CSSM_FIELD_PTR	fieldPtr;
	OidParser 		parser;
	unsigned		len;
	
	if(argc != 2) {
		usage(argv);
	}
	if(readFile(argv[1], &certData.Data, &len)) {
		printf("Can't read file %s' aborting.\n", argv[1]);
		exit(1);
	}
	certData.Length = len;
	
	while(1) {
		fpurge(stdin);
		printf("a  load/attach\n");
		printf("d  detach/unload\n");
		printf("c  cache the cert\n");
		printf("u  uncache the cert\n");
		printf("g  get field (uncached)\n");
		printf("G  get field (cached)\n");
		printf("f  get all fields, then free\n");
		printf("q  quit\n");
		printf("Enter command: ");
		resp = getchar();
		switch(resp) {
			case 'a':
				if(clHand != CSSM_INVALID_HANDLE) {
					printf("***Multiple attaches; expect leaks\n");
				}
				clHand = clStartup();
				if(clHand == CSSM_INVALID_HANDLE) {
					printf("***Error attaching to CL.\n");
				}
				else {
					printf("...ok\n");
				}
				break;
				
			case 'd':
				/* 
				 * Notes:
				 * -- this should cause the CL to free up all cached certs
				 *    no matter what - even if we've done multiple certCache
				 *    ops. However the plugin framework doesn't delete the
				 *    session object on detach (yet) so expect leaks in 
				 *    that case.
				 * -- we don't  clear out cacheHand or searchHand here; this
				 *    allows verification of proper handling of bogus handles. 
				 */
				clShutdown(clHand);
				clHand = CSSM_INVALID_HANDLE;
				printf("...ok\n");
				break;
				
			case 'c':
				/* cache the cert */
				if(cacheHand != CSSM_INVALID_HANDLE) {
					printf("***NOTE: a cert is already cached. Expect leaks.\n");						}
				crtn = CSSM_CL_CertCache(clHand, &certData, &cacheHand);
				if(crtn) {
					printError("CSSM_CL_CertCache", crtn);
				}
				else {
					printf("...ok\n");
				}
				break;
				
			case 'u':
				/* abort cache */
				crtn = CSSM_CL_CertAbortCache(clHand, cacheHand);
				if(crtn) {
					printError("CSSM_CL_CertAbortCache", crtn);
				}
				else {
					cacheHand = CSSM_INVALID_HANDLE;
					printf("...ok\n");
				}
				break;
				
			case 'g':
				/* get one field (uncached) */
				fieldDex = genRand(0, NUM_KNOWN_OIDS - 1);
				crtn = CSSM_CL_CertGetFirstFieldValue(clHand,
					&certData,
					knownOids[fieldDex],
					&searchHand,
					&numFields, 
					&fieldValue);
				if(crtn) {
					printf("***Error fetching field %s\n", oidNames[fieldDex]);
					printError("CSSM_CL_CertGetFirstFieldValue", crtn);
					break;
				}
				printf("%s: %u fields found\n", oidNames[fieldDex], (unsigned)numFields);
				field.FieldValue = *fieldValue;
				field.FieldOid   = *(knownOids[fieldDex]);
				printCertField(field, parser, CSSM_TRUE);
				crtn = CSSM_CL_FreeFieldValue(clHand, knownOids[fieldDex], fieldValue);
				if(crtn) {
					printError("CSSM_CL_FreeFieldValue", crtn);
					/* keep going */
				}
				for(unsigned i=1; i<numFields; i++) {
					crtn = CSSM_CL_CertGetNextFieldValue(clHand,
						searchHand,
						&fieldValue);
					if(crtn) {
						printError("CSSM_CL_CertGetNextFieldValue", crtn);
						break;
					}
					field.FieldValue = *fieldValue;
					printCertField(field, parser, CSSM_TRUE);
					crtn = CSSM_CL_FreeFieldValue(clHand, 
						knownOids[fieldDex], fieldValue);
					if(crtn) {
						printError("CSSM_CL_FreeFieldValue", crtn);
						/* keep going */
					}
				} /* for additional fields */
				
				/* verify one more getField results in error */
				crtn = CSSM_CL_CertGetNextFieldValue(clHand,
					searchHand,
					&fieldValue);
				if(crtn != CSSMERR_CL_NO_FIELD_VALUES) {
					if(crtn == CSSM_OK) {
						printf("***unexpected success on final GetNextFieldValue\n");
					}
					else {
						printError("Wrong error on final GetNextFieldValue", crtn);
					}
				}
				crtn = CSSM_CL_CertAbortQuery(clHand, searchHand);
				if(crtn) {
					printError("CSSM_CL_CertAbortQuery", crtn);
				}
				break;
				
			case 'G':
				/* get one field (uncached) */
				fieldDex = genRand(0, NUM_KNOWN_OIDS - 1);
				crtn = CSSM_CL_CertGetFirstCachedFieldValue(clHand,
					cacheHand,
					knownOids[fieldDex],
					&searchHand,
					&numFields, 
					&fieldValue);
				if(crtn) {
					printf("***Error fetching field %s\n", oidNames[fieldDex]);
					printError("CSSM_CL_CertGetFirstCachedFieldValue", crtn);
					break;
				}
				printf("%s: %u fields found\n", oidNames[fieldDex], (unsigned)numFields);
				field.FieldValue = *fieldValue;
				field.FieldOid   = *(knownOids[fieldDex]);
				printCertField(field, parser, CSSM_TRUE);
				crtn = CSSM_CL_FreeFieldValue(clHand, knownOids[fieldDex], fieldValue);
				if(crtn) {
					printError("CSSM_CL_FreeFieldValue", crtn);
					/* keep going */
				}
				for(unsigned i=1; i<numFields; i++) {
					crtn = CSSM_CL_CertGetNextCachedFieldValue(clHand,
						searchHand,
						&fieldValue);
					if(crtn) {
						printError("CSSM_CL_CertGetNextCachedFieldValue", crtn);
						break;
					}
					field.FieldValue = *fieldValue;
					printCertField(field, parser, CSSM_TRUE);
					crtn = CSSM_CL_FreeFieldValue(clHand, 
						knownOids[fieldDex], fieldValue);
					if(crtn) {
						printError("CSSM_CL_FreeFieldValue", crtn);
						/* keep going */
					}
				} /* for additional cached fields */
				
				/* verify one more getField results in error */
				crtn = CSSM_CL_CertGetNextCachedFieldValue(clHand,
					searchHand,
					&fieldValue);
				if(crtn != CSSMERR_CL_NO_FIELD_VALUES) {
					if(crtn == CSSM_OK) {
						printf("***unexpected success on final GetNextCachedFieldValue\n");
					}
					else {
						printError("Wrong error on final GetNextCachedFieldValue", crtn);
					}
				}
				crtn = CSSM_CL_CertAbortQuery(clHand, searchHand);
				if(crtn) {
					printError("CSSM_CL_CertAbortQuery", crtn);
				}
				break;
				
			case 'f':
				/* get all fields (for leak testing) */
				crtn = CSSM_CL_CertGetAllFields(clHand,
					&certData,
					&numFields,
					&fieldPtr);
				if(crtn) {
					printError("CSSM_CL_CertGetAllFields", crtn);
					break;
				}
				printf("...numFields %u\n", (unsigned)numFields);
				crtn = CSSM_CL_FreeFields(clHand, numFields, &fieldPtr);
				if(crtn) {
					printError("CSSM_CL_FreeFields", crtn);
				}
				break;
				
			case 'q':
				goto quit;
				
			default:
				printf("Huh?\n");
				break;
		}	/* switch resp */
	}
quit:
	free(certData.Data);
	if(clHand != CSSM_INVALID_HANDLE) {
		clShutdown(clHand);
	}
	return 0;
}