dbVerifyKey.cpp   [plain text]


/* Copyright (c) 2004-2005,2008 Apple Inc.
 *
 * dbVerifyKey.cpp - verify that specified DB has exactly one key of specified
 * algorithm, class, and key size - and no other keys.
 */
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <strings.h>
#include <ctype.h>
#include <Security/cssm.h>
#include <Security/cssmapple.h>
#include "cspwrap.h"
#include "common.h"
#include "cspdlTesting.h"


static void usage(char **argv)
{
	printf("usage: %s dbFileName alg class keysize [options]\n", argv[0]);
	printf("   alg   : rsa|dsa|dh|ecdsa\n");
	printf("   class : priv|pub\n");
	printf("Options:\n");
	printf("   -q   quiet\n");
	exit(1);
}

static const char *recordTypeStr(
	CSSM_DB_RECORDTYPE		recordType)
{
	static char unk[100];
	
	switch(recordType) {
		case CSSM_DL_DB_RECORD_PRIVATE_KEY:
			return "Private Key";
		case CSSM_DL_DB_RECORD_PUBLIC_KEY:
			return "Public Key";
		case CSSM_DL_DB_RECORD_SYMMETRIC_KEY:
			return "Symmetric Key";
		default:
			sprintf(unk, "**Unknown record type %u\n", (unsigned)recordType);
			return unk;
	}
}

/*
 * Search for specified record type; verify there is exactly one or zero
 * of them as specified.
 * Verify key algorthm and key size. Returns nonzero on error. 
 */
static int doVerify(
	CSSM_DL_DB_HANDLE 		dlDbHand,
	unsigned				numRecords,		// zero or one
	CSSM_DB_RECORDTYPE		recordType,
	uint32					keySize,
	CSSM_ALGORITHMS			keyAlg)
{
	CSSM_QUERY						query;
	CSSM_DB_UNIQUE_RECORD_PTR		record = NULL;
	CSSM_RETURN						crtn;
	CSSM_HANDLE						resultHand;
	CSSM_DB_RECORD_ATTRIBUTE_DATA	recordAttrs;
	
	/* no predicates, all records of specified type, no attrs, get the key */
	query.RecordType = recordType;
	query.Conjunctive = CSSM_DB_NONE;
	query.NumSelectionPredicates = 0;	
	query.QueryLimits.TimeLimit = 0;	// FIXME - meaningful?
	query.QueryLimits.SizeLimit = 1;	// FIXME - meaningful?
	query.QueryFlags = 0; // CSSM_QUERY_RETURN_DATA;	// FIXME - used?
	
	recordAttrs.DataRecordType		 = recordType;
	recordAttrs.NumberOfAttributes   = 0;
	recordAttrs.AttributeData        = NULL;

	CSSM_DATA recordData = {0, NULL};

	crtn = CSSM_DL_DataGetFirst(dlDbHand,
		&query,
		&resultHand,
		&recordAttrs,
		&recordData,	
		&record);
	switch(crtn) {
		case CSSM_OK:
			if(numRecords == 0) {
				printf("***Expected zero records of type %s, found one\n",
					recordTypeStr(recordType));
				CSSM_DL_FreeUniqueRecord(dlDbHand, record);
				CSSM_DL_DataAbortQuery(dlDbHand, resultHand);
				return 1;
			}
			break;		// proceed
		case CSSMERR_DL_ENDOFDATA:
			if(numRecords == 0) {
				/* cool */
				return 0;
			}
			printf("**Error: no records of type %s found\n",
				recordTypeStr(recordType));
			return 1;
		default:
			printError("DataGetFirst", crtn);
			return 1;
	}

	CSSM_KEY_PTR theKey = (CSSM_KEY_PTR)recordData.Data;
	int ourRtn = 0;
	CSSM_KEYHEADER &hdr = theKey->KeyHeader;
	if(hdr.AlgorithmId != keyAlg) {
		printf("***Algorithm mismatch: expect %u, got %u\n",
			(unsigned)keyAlg, (unsigned)hdr.AlgorithmId);
		ourRtn++;
	}
	if(hdr.LogicalKeySizeInBits != keySize) {
		printf("***Key Size: expect %u, got %u\n",
			(unsigned)keySize, (unsigned)hdr.LogicalKeySizeInBits);
		ourRtn++;
	}
	CSSM_DL_FreeUniqueRecord(dlDbHand, record);

	/* see if there are any more */
	crtn = CSSM_DL_DataGetNext(dlDbHand,
		resultHand, 
		&recordAttrs,
		NULL,
		&record);
	if(crtn == CSSM_OK) {
		printf("***More than 1 record of type %s found\n", 
			recordTypeStr(recordType));
		ourRtn++;
		CSSM_DL_FreeUniqueRecord(dlDbHand, record);
	}
	CSSM_DL_DataAbortQuery(dlDbHand, resultHand);
	return ourRtn;
}

int main(
	int argc, 
	char **argv)
{
	int					arg;
	char				*argp;
	char				*dbFileName;
	CSSM_ALGORITHMS		keyAlg;
	CSSM_DB_RECORDTYPE	recordType;
	uint32				keySize;
	CSSM_DL_DB_HANDLE	dlDbHand;
	CSSM_BOOL			quiet = CSSM_FALSE;
	CSSM_RETURN 		crtn = CSSM_OK;
	
	if(argc < 5) {
		usage(argv);
	}
	dbFileName = argv[1];
	
	/* key algorithm */
	if(!strcmp(argv[2], "rsa")) {
		keyAlg = CSSM_ALGID_RSA;
	}
	else if(!strcmp(argv[2], "dsa")) {
		keyAlg = CSSM_ALGID_DSA;
	}
	else if(!strcmp(argv[2], "dh")) {
		keyAlg = CSSM_ALGID_DH;
	}
	else if(!strcmp(argv[2], "ecdsa")) {
		keyAlg = CSSM_ALGID_ECDSA;
	}
	else {
		usage(argv);
	}
	
	/* key class */
	if(!strcmp(argv[3], "priv")) {
		recordType = CSSM_DL_DB_RECORD_PRIVATE_KEY;
	}
	else if(!strcmp(argv[3], "pub")) {
		recordType = CSSM_DL_DB_RECORD_PUBLIC_KEY;
	}
	else {
		usage(argv);
	}

	keySize = atoi(argv[4]);
	
	for(arg=5; arg<argc; arg++) {
		argp = argv[arg];
		if(!strcmp(argp, "-q")) {
			quiet = CSSM_TRUE;
		}
		else {
			usage(argv);
		}
	}
	
	dlDbHand.DLHandle = dlStartup();
	if(dlDbHand.DLHandle == 0) {
		exit(1);
	}
	crtn = dbCreateOpen(dlDbHand.DLHandle, dbFileName, 
		CSSM_FALSE, CSSM_FALSE, NULL, &dlDbHand.DBHandle);
	if(crtn) {
		exit(1);
	}
	
	if(doVerify(dlDbHand, 1, recordType, keySize, keyAlg)) {
		return 1;
	}
	if(doVerify(dlDbHand, 0, 
			(recordType == CSSM_DL_DB_RECORD_PRIVATE_KEY) ?
				CSSM_DL_DB_RECORD_PUBLIC_KEY : CSSM_DL_DB_RECORD_PRIVATE_KEY,
			keySize, keyAlg)) {
		return 1;
	}
	if(!quiet) {
		printf("...%s verify succussful\n", recordTypeStr(recordType));
	}
	CSSM_DL_DbClose(dlDbHand);
	CSSM_ModuleDetach(dlDbHand.DLHandle);
	return 0;
}