p12Decode.cpp   [plain text]


/*
 * Decode P12 PFX using either C++ P12Coder or public
 * C API (both from SecurityNssPkcs12)
 */

#include <security_pkcs12/pkcs12Coder.h>
#include <stdlib.h>
#include <stdio.h>
#include <Security/cssmtype.h>
#include <security_cdsa_utils/cuPrintCert.h>
#include <security_cdsa_utils/cuCdsaUtils.h>
#include "p12GetPassKey.h"
#include "p12.h"

/* use this option to debug the P12Coder class directly */
#define P12_DECODE_VIA_CPP		0

/*
 * Print CFString - stored as unicode, we get the C string,
 * print it plus newline
 */
static void printUcStr(
	CFStringRef cfstr)
{
	CFIndex len = CFStringGetLength(cfstr) + 1;
	char *outStr = (char *)malloc(len);
	if(CFStringGetCString(cfstr, outStr, len, kCFStringEncodingASCII)) {
		printf("%s\n", outStr);
	}
	else {
		printf("***Error converting from unicode to ASCII\n");
	}
	free(outStr);
}

static void printDataAsHex(
	CFDataRef d,
	unsigned maxToPrint = 0)		// optional, 0 means print it all
{
	unsigned i;
	bool more = false;
	uint32 len = CFDataGetLength(d);
	const uint8 *cp = CFDataGetBytePtr(d);
	
	if((maxToPrint != 0) && (len > maxToPrint)) {
		len = maxToPrint;
		more = true;
	}	
	for(i=0; i<len; i++) {
		printf("%02X ", ((unsigned char *)cp)[i]);
	}
	if(more) {
		printf("...\n");
	}
	else {
		printf("\n");
	}
}

static void printAlgAsString(
	CSSM_ALGORITHMS alg)
{
	char *s = "unknown alg";
	switch(alg) {
		case CSSM_ALGID_RSA:
			s = "RSA";
			break;
		case CSSM_ALGID_DSA:
			s = "DSA";
			break;
		case CSSM_ALGID_FEE:
			s = "FEE";
			break;
		default:
			break;
	}
	printf("%s\n", s);
}

#if		P12_DECODE_VIA_CPP

/* common bag attrs - friendlyName, localKeyId */
static void printBagAttrs(
	P12SafeBag &bag)
{
	CFStringRef friendlyName = bag.friendlyName();
	if(friendlyName) {
		printf("   friendlyName : ");
		printUcStr(friendlyName);
		CFRelease(friendlyName);
	}

	CFDataRef keyId = bag.localKeyId();
	if(keyId) {
		printf("   localKeyId   : ");
		printDataAsHex(keyId, 16);
		CFRelease(keyId);
	}
	if((friendlyName == NULL) && (keyId == NULL)) {
		printf("   <no attributes found>\n");
	}
}

OSStatus p12Decode(
	const CSSM_DATA &pfx,
	CSSM_CSP_HANDLE cspHand,
	CFStringRef pwd,
	bool verbose,
	unsigned loops)
{
	OSStatus ourRtn;
	
	for(unsigned loop=0; loop<loops; loop++) {
		{
			/* localize scope of coder for malloc test */
			P12Coder coder;
			CFDataRef cfd = CFDataCreate(NULL, pfx.Data, pfx.Length);
			ourRtn = noErr;
			
			try { 
				coder.setCsp(cspHand);
				coder.setMacPassPhrase(pwd);
				coder.decode(cfd);
			}
			catch(...) {
				printf("***decode error\n");
				ourRtn = 1;
			}
			CFRelease(cfd);
			
			try {
				unsigned i;

				unsigned numCerts = coder.numCerts();
				printf("\n%u certs found\n", numCerts);
				for(i=0; i<numCerts; i++) {
					P12CertBag *cert = coder.getCert(i);
					printf("=== Cert %u ===\n", i);
					printBagAttrs(*cert);
					if(verbose) {
						CSSM_DATA &certData = cert->certData();
						printCert(certData.Data, certData.Length,
							CSSM_FALSE);

					}
					printf("\n");
				}
				
				unsigned numCrls = coder.numCrls();
				printf("%u crls  found\n", numCrls);
				for(i=0; i<numCrls; i++) {
					P12CrlBag *crl = coder.getCrl(i);
					printf("=== Crl %u ===\n", i);
					printBagAttrs(*crl);
					if(verbose) {
						CSSM_DATA &crlData = crl->crlData();
						printCrl(crlData.Data, crlData.Length, CSSM_FALSE);

					}
					printf("\n");
				}

				unsigned numKeys = coder.numKeys();
				printf("%u keys  found\n", numKeys);
				for(i=0; i<numKeys; i++) {
					P12KeyBag *key = coder.getKey(i);
					printf("\n=== Key %u ===\n", i);
					printBagAttrs(*key);
					/* fix this up */
					CSSM_KEY_PTR ckey = key->key();
					CSSM_KEYHEADER &hdr = ckey->KeyHeader;
					printf("   Key Alg      : ");
					printAlgAsString(hdr.AlgorithmId);
					printf("   Key Size     : %u bits\n", 
						(unsigned)hdr.LogicalKeySizeInBits);
					printf("\n");
				}

				unsigned numBlobs = coder.numOpaqueBlobs();
				printf("%u blobs found\n", numBlobs);
			} 
			catch(...) {
				printf("***exception extracting fields\n");
				ourRtn = 1;
			}
		}
		if(loops > 1) {
			fpurge(stdin);
			printf("CR to continue: ");
			getchar();
		}
		if(ourRtn) {
			return ourRtn;
		}
	}
	return ourRtn;
}

#else	/* P12_DECODE_VIA_CPP */

/* Normal decode using public API in SecPkcs12.h */

/* common bag attrs - friendlyName, localKeyId */
static void printBagAttrs(
	CFStringRef friendlyName,
	CFDataRef localKeyId)
{
	if(friendlyName) {
		printf("   friendlyName : ");
		printUcStr(friendlyName);
	}

	if(localKeyId) {
		printf("   localKeyId   : ");
		printDataAsHex(localKeyId, 20);
	}
	if((friendlyName == NULL) && (localKeyId == NULL)) {
		printf("   <no attributes found>\n");
	}
}

/* release attrs if present */
static void releaseAttrs(
	CFStringRef friendlyName,
	CFDataRef localKeyId,
	SecPkcs12AttrsRef attrs)
{
	if(friendlyName) {
		CFRelease(friendlyName);
	}
	if(localKeyId) {
		CFRelease(localKeyId);
	}
	if(attrs) {
		SecPkcs12AttrsRelease(attrs);
	}
}
	
static void printOsError(
	const char *op,
	OSStatus ortn)
{
	/* may want to parse out CSSM errors */
	cssmPerror(op, ortn);
	printf("\n");
}

/* Sec calls all return 1 - not the fault of SecNssPkcs12 */
#define GET_CERTS_WORKING	1

OSStatus p12Decode(
	const CSSM_DATA &pfx,
	CSSM_CSP_HANDLE cspHand,
	CFStringRef pwd,			// explicit passphrase, mutually exclusive with...
	bool usePassKey,			// use SECURE_PASSPHRASE key
	bool verbose,
	unsigned loops)
{
	OSStatus ortn;
	CSSM_KEY		passKey;
	CSSM_KEY_PTR	passKeyPtr = NULL;
	
	CFDataRef cfd = CFDataCreate(NULL, pfx.Data, pfx.Length);
	if(usePassKey) {
		ortn = p12GetPassKey(cspHand, GPK_Decode, true, &passKey);
		if(ortn) {
			return ortn;
		}
		passKeyPtr = &passKey;
	}
	for(unsigned loop=0; loop<loops; loop++) {
		SecPkcs12CoderRef coder;
		ortn = SecPkcs12CoderCreate(&coder);
		if(ortn) {
			printOsError("SecPkcs12CoderCreate", ortn);
			return ortn;
		}

		ortn = SecPkcs12SetCspHandle(coder, cspHand);
		if(ortn) {
			printOsError("SecPkcs12SetCspHandle", ortn);
			return ortn;
		}
		
		if(usePassKey) {
			ortn = SecPkcs12SetMACPassKey(coder, passKeyPtr);
			if(ortn) {
				printOsError("SecPkcs12SetMACPassKey", ortn);
				return ortn;
			}
		}
		else {
			ortn = SecPkcs12SetMACPassphrase(coder, pwd);
			if(ortn) {
				printOsError("SecPkcs12SetMACPassphrase", ortn);
				return ortn;
			}
		}
		ortn = SecPkcs12Decode(coder, cfd);
		if(ortn) {
			printOsError("SecPkcs12Decode", ortn);
			return ortn;
		}
		
		CFIndex i;
		CFStringRef fname;
		CFDataRef keyId;

		CFIndex numCerts;
		SecPkcs12CertificateCount(coder, &numCerts);
		printf("\n=== %ld certs found ===\n", numCerts);
		#if GET_CERTS_WORKING
		for(i=0; i<numCerts; i++) {
			SecCertificateRef secCert;
			ortn = SecPkcs12CopyCertificate(coder,
				i,
				&secCert,
				&fname,
				&keyId,
				NULL);		// attrs
			if(ortn) {
				printOsError("SecPkcs12CopyCertificate", ortn);
				return ortn;
			}
			printf("Cert %ld:\n", i);
			printBagAttrs(fname, keyId);
			if(verbose) {
				CSSM_DATA certData;
				ortn = SecCertificateGetData(secCert, &certData);
				if(ortn) {
					printOsError("SecCertificateGetData", ortn);
					return ortn;
				}
				printCert(certData.Data, certData.Length,
					CSSM_FALSE);

			}
			releaseAttrs(fname, keyId, NULL);
			CFRelease(secCert);
			printf("\n");
		}
		#endif	/* GET_CERTS_WORKING */
		
		CFIndex numCrls;
		SecPkcs12CrlCount(coder, &numCrls);
		printf("=== %ld crls  found ===\n", numCrls);
		for(i=0; i<numCrls; i++) {
			CFDataRef crl;
			ortn = SecPkcs12CopyCrl(coder,
				i,
				&crl,
				&fname,
				&keyId,
				NULL);		// attrs
			if(ortn) {
				printOsError("SecPkcs12CopyCrl", ortn);
				return ortn;
			}
			printf("Crl %ld:\n", i);
			printBagAttrs(fname, keyId);
			if(verbose) {
				const CSSM_DATA crlData = {
					CFDataGetLength(crl),
					(uint8 *)CFDataGetBytePtr(crl) };
				printCrl(crlData.Data, crlData.Length, CSSM_FALSE);

			}
			releaseAttrs(fname, keyId, NULL);
			CFRelease(crl);
			printf("\n");
		}

		CFIndex numKeys;
		SecPkcs12PrivateKeyCount(coder, &numKeys);
		printf("=== %ld keys  found ===\n", numKeys);
		for(i=0; i<numKeys; i++) {
			CSSM_KEY_PTR key;
			ortn = SecPkcs12GetCssmPrivateKey(coder,
				i,
				&key,
				&fname,
				&keyId,
				NULL);
				
			printf("Key %ld:\n", i);
			printBagAttrs(fname, keyId);
			/* fix this up */
			CSSM_KEYHEADER &hdr = key->KeyHeader;
			printf("   Key Alg      : ");
			printAlgAsString(hdr.AlgorithmId);
			printf("   Key Size     : %u bits\n", 
				(unsigned)hdr.LogicalKeySizeInBits);
			printf("\n");
			releaseAttrs(fname, keyId, NULL);
		}

		CFIndex numBlobs;
		SecPkcs12OpaqueBlobCount(coder, &numBlobs);
		if(numBlobs != 0) {
			printf("%ld blobs found\n", numBlobs);
		}

		/* this should free all memory allocated in the decode */
		SecPkcs12CoderRelease(coder);
		
		if(loops > 1) {
			fpurge(stdin);
			printf("CR to continue: ");
			getchar();
		}
	}
	return 0;
}


#endif	/* P12_DECODE_VIA_CPP */