parseTrustedRootList.cpp   [plain text]


/*
 * parseTrustedRootList.cpp - parse the contents of a TrustedRootList record.
 *
 * Created May 26 2005 by dmitch. 
 */
 
#include <stdlib.h>
#include <strings.h>
#include <stdio.h>
#include <unistd.h>
#include "parseTrustedRootList.h"
#include "rootUtils.h"

#include <Security/TrustSettingsSchema.h>		/* private header */
#include <Security/SecTrustSettings.h>			
#include <CoreFoundation/CoreFoundation.h>
#include <security_utilities/cfutilities.h>

/*
 * Data is obtained from a SecKeychainItemRef; it's expected to be the XML encoding
 * of a CFPropertyList (specifically of a CFDictionaryRef).
 */
int parseTrustedRootList(
	CFDataRef plistData)
{
	/* First decode the XML */
	CFStringRef errStr = NULL;
	CFRef<CFPropertyListRef> rawPropList;
	int ourRtn = 0;
	OidParser parser;
	
	rawPropList.take(CFPropertyListCreateFromXMLData(
		NULL,
		plistData,
		kCFPropertyListImmutable,
		&errStr));
	CFPropertyListRef cfRawPropList = rawPropList;
	if(cfRawPropList == NULL) {
		printf("***parseTrustedRootList: Error decoding TrustedRootList XML data\n");
		if(errStr != NULL) {
			printf("Error string: "); CFShow(errStr);
			CFRelease(errStr);
		}
		return -1;
	}
	if(errStr != NULL) {
		CFRelease(errStr);
	}
	
	CFDictionaryRef topDict = (CFDictionaryRef)cfRawPropList;
	if(CFGetTypeID(topDict) != CFDictionaryGetTypeID()) {
		printf("***parseTrustedRootList: malformed propList");
		return -1;
	}

	printf("=== Parsed User Trust Record ===\n");
	
	/* that dictionary has two entries */
	CFNumberRef cfVers = (CFNumberRef)CFDictionaryGetValue(topDict, kTrustRecordVersion);
	if((cfVers == NULL) || (CFGetTypeID(cfVers) != CFNumberGetTypeID())) {
		printf("***parseTrustedRootList: malformed version");
	}
	else {
		SInt32 vers;
		if(!CFNumberGetValue(cfVers, kCFNumberSInt32Type, &vers)) {
			printf("***parseTrustedRootList: malformed version");
		}
		else {
			printf("Version = %ld\n", vers);
		}
	}
	
	CFDictionaryRef certsDict = (CFDictionaryRef)CFDictionaryGetValue(topDict, 
		kTrustRecordTrustList);
	if((certsDict == NULL) || (CFGetTypeID(certsDict) != CFDictionaryGetTypeID())) {
		printf("***parseTrustedRootList: malformed mTrustArray");
		return -1;
	}
	
	CFIndex numCerts = CFDictionaryGetCount(certsDict);
	const void *dictKeys[numCerts];
	const void *dictValues[numCerts];
	CFDictionaryGetKeysAndValues(certsDict, dictKeys, dictValues);

	CFDataRef certApp;
	CFDataRef certPolicy;
	CFDictionaryRef ucDict;
	CFArrayRef usageConstraints;
	CFDataRef cfd;
	CFIndex numUsageConstraints;
	CFStringRef policyStr;
	CFNumberRef cfNum;
	CFDateRef modDate;
	
	printf("Number of cert entries: %ld\n", numCerts);
	
	for(CFIndex dex=0; dex<numCerts; dex++) {
		printf("Cert %ld:\n", dex);
		indentIncr();
		
		/* per-cert key is ASCII representation of SHA1(cert) */
		CFStringRef certHashStr = (CFStringRef)dictKeys[dex];
		if(CFGetTypeID(certHashStr) != CFStringGetTypeID()) {
			printf("***parseTrustedRootList: malformed certsDict key");
			ourRtn = -1;
			goto nextCert;
		}
		indent(); printf("Cert Hash              : ");
		printCfStr(certHashStr);
		printf("\n");
	
		/* get per-cert dictionary */
		CFDictionaryRef certDict = (CFDictionaryRef)dictValues[dex];
		if(CFGetTypeID(certDict) != CFDictionaryGetTypeID()) {
			printf("***parseTrustedRootList: malformed certDict");
			ourRtn = -1;
			goto nextCert;
		}
		
		/* 
		 * That dictionary has exactly four entries...but the first
 		 * 
		 * First, the issuer. This is in non-normalized form.
		 */
		cfd = (CFDataRef)CFDictionaryGetValue(certDict, kTrustRecordIssuer);
		if(cfd == NULL) {
			printf("***parseTrustedRootList: missing issuer");
			ourRtn = -1;
			goto nextCert;
		}
		if(CFGetTypeID(cfd) != CFDataGetTypeID()) {
			printf("***parseTrustedRootList: malformed issuer");
			ourRtn = -1;
			goto nextCert;
		}
		indent(); 
		if(CFDataGetLength(cfd) == 0) {
			/* that's for a default setting */
			printf("Issuer                 : <none>\n");
		}
		else {
			printf("Issuer                 : \n");
			indentIncr(); printCfName(cfd, parser);
			indentDecr();
		}

		/* Serial number */
		cfd = (CFDataRef)CFDictionaryGetValue(certDict, kTrustRecordSerialNumber);
		if(cfd == NULL) {
			printf("***parseTrustedRootList: missing serial number");
			ourRtn = -1;
			goto nextCert;
		}
		if(CFGetTypeID(cfd) != CFDataGetTypeID()) {
			printf("***parseTrustedRootList: malformed serial number");
			ourRtn = -1;
			goto nextCert;
		}
		indent(); printData("Serial Number          ", cfd, PD_Hex, parser);

		/* modification date */
		modDate = (CFDateRef)CFDictionaryGetValue(certDict, kTrustRecordModDate);
		if(modDate == NULL) {
			printf("***parseTrustedRootList: missing modification date");
			ourRtn = -1;
			goto nextCert;
		}
		if(CFGetTypeID(modDate) != CFDateGetTypeID()) {
			printf("***parseTrustedRootList: malformed modification date");
			ourRtn = -1;
			goto nextCert;
		}
		indent(); 
		printf("Modification Date      : ");
		printCFDate(modDate);
		printf("\n");
		
		/* 
		 * Array of usageConstraint dictionaries - the array itself must be there,
		 * though it might be empty. 
		 */
		usageConstraints = (CFArrayRef)CFDictionaryGetValue(certDict,
				kTrustRecordTrustSettings);
		numUsageConstraints = 0;
		if(usageConstraints != NULL) {
			if(CFGetTypeID(usageConstraints) != CFArrayGetTypeID()) {
				printf("***parseTrustedRootList: malformed Usage Constraints array");
				ourRtn = -1;
				goto nextCert;
			}
		
			numUsageConstraints = CFArrayGetCount(usageConstraints);
		}
		indent(); printf("Num usage constraints  : ");
		if(usageConstraints) {
			printf("%ld\n", numUsageConstraints);
		}
		else {
			printf("<not present>\n");
		}		

		/* grind thru the usageConstraint dictionaries */
		for(CFIndex apDex=0; apDex<numUsageConstraints; apDex++) {
			indent(); printf("Usage constraint %ld:\n", apDex);
			indentIncr();
			
			ucDict = (CFDictionaryRef)CFArrayGetValueAtIndex(usageConstraints, apDex);
			if(CFGetTypeID(ucDict) != CFDictionaryGetTypeID()) {
				printf("***parseTrustedRootList: malformed usageConstraint dictionary");
				ourRtn = -1;
				goto nextAp;
			}
			
			/* policy - optional - an OID */
			certPolicy = (CFDataRef)CFDictionaryGetValue(ucDict, kSecTrustSettingsPolicy);
			if(certPolicy != NULL) {
				if(CFGetTypeID(certPolicy) != CFDataGetTypeID()) {
					printf("***parseTrustedRootList: malformed certPolicy");
					ourRtn = -1;
					goto nextAp;
				}
				indent(); printData("Policy OID          ", certPolicy, PD_OID, parser);
			}
			
			/* app - optional - data - opaque */
			certApp = (CFDataRef)CFDictionaryGetValue(ucDict, kSecTrustSettingsApplication);
			if(certApp != NULL) {
				if(CFGetTypeID(certApp) != CFDataGetTypeID()) {
					printf("***parseTrustedRootList: malformed certApp");
					ourRtn = -1;
					goto nextAp;
				}
				indent(); printData("Application         ", certApp, PD_Hex, parser);
			}
			
			/* policy string */
			policyStr = (CFStringRef)CFDictionaryGetValue(ucDict, kSecTrustSettingsPolicyString);
			if(policyStr != NULL) {
				if(CFGetTypeID(policyStr) != CFStringGetTypeID()) {
					printf("***parseTrustedRootList: malformed policyStr");
					ourRtn = -1;
					goto nextAp;
				}
				indent(); printf("Policy String       : ");
				printCfStr(policyStr); printf("\n");
			}

			/* Allowed error */
			cfNum = (CFNumberRef)CFDictionaryGetValue(ucDict, kSecTrustSettingsAllowedError);
			if(cfNum != NULL) {
				if(CFGetTypeID(cfNum) != CFNumberGetTypeID()) {
					printf("***parseTrustedRootList: malformed allowedError");
					ourRtn = -1;
					goto nextAp;
				}
				indent(); printf("Allowed Error       : ");
				printCssmErr(cfNum); printf("\n");
			}

			/* ResultType */
			cfNum = (CFNumberRef)CFDictionaryGetValue(ucDict, kSecTrustSettingsResult);
			if(cfNum != NULL) {
				if(CFGetTypeID(cfNum) != CFNumberGetTypeID()) {
					printf("***parseTrustedRootList: malformed Result");
					ourRtn = -1;
					goto nextAp;
				}
				indent(); printf("Result Type         : ");
				printResult(cfNum); printf("\n");
			}

			/* key usage */
			cfNum = (CFNumberRef)CFDictionaryGetValue(ucDict, kSecTrustSettingsKeyUsage);
			if(cfNum != NULL) {
				if(CFGetTypeID(cfNum) != CFNumberGetTypeID()) {
					printf("***parseTrustedRootList: malformed keyUsage");
					ourRtn = -1;
					goto nextAp;
				}
				indent(); printf("Key Usage           : ");
				printKeyUsage(cfNum); printf("\n");
			}

		nextAp:
			indentDecr();
		}
		
	nextCert:
		indentDecr();
	} /* for each cert dictionary  in top-level array */
	
	printf("=== End of Parsed User Trust Record ===\n");
	return ourRtn;

}