printFields.c   [plain text]


/* Copyright (c) 2005-2007 Apple Inc. All Rights Reserved. */

/*
 * printFeilds.h - print various DER objects
 *
 * Created Nov. 9 2005 by dmitch
 */

#include <libDERUtils/printFields.h>
#include <libDER/DER_Decode.h>
#include <libDER/asn1Types.h>
#include <libDER/DER_Keys.h>
#include <libDERUtils/libDERUtils.h>
#include <stdlib.h>
#include <strings.h>
#include <stdio.h>

static int indentLevel = 0;

void doIndent()
{
	int i;
	for (i = 0; i<indentLevel; i++) {
		putchar(' ');
	}
} /* indent */

void incrIndent()
{
	indentLevel += 3;
}

void decrIndent()
{
	indentLevel -= 3;
}

#define TO_PRINT_MAX	12

void printHex(
	DERItem *item)
{
	unsigned dex;
	unsigned toPrint = item->length;
	
	printf("<%u> ", item->length);
	if(toPrint > TO_PRINT_MAX) {
		toPrint = TO_PRINT_MAX;
	}
	for(dex=0; dex<toPrint; dex++) {
		printf("%02x ", item->data[dex]);
	}
	if(item->length > TO_PRINT_MAX) {
		printf("...");
	}
	printf("\n");
}

void printBitString(
	DERItem *item)
{
	unsigned dex;
	unsigned toPrint = item->length;
	DERItem bitStringBytes;
	DERByte numUnused;
	DERReturn drtn;
			
	drtn = DERParseBitString(item, &bitStringBytes, &numUnused);
	if(drtn) {
		DERPerror("DERParseBitString", drtn);
		return;
	}

	printf("<%u, %u> ", bitStringBytes.length, numUnused);
	toPrint = bitStringBytes.length;
	if(toPrint > TO_PRINT_MAX) {
		toPrint = TO_PRINT_MAX;
	}
	for(dex=0; dex<toPrint; dex++) {
		printf("%02x ", bitStringBytes.data[dex]);
	}
	if(item->length > TO_PRINT_MAX) {
		printf("...");
	}
	printf("\n");
}

void printString(
	DERItem *item)
{
	unsigned dex;
	char *cp = (char *)item->data;
	printf("'");
	for(dex=0; dex<item->length; dex++) {
		putchar(*cp++);
	}
	printf("'\n");

}

#define COLON_COLUMN	20

/*
 * Print line header, with current indent, followed by specified label, followed
 * by a ':' in column COLON_COLUMN, followed by one space. 
 */
void printHeader(
	const char *label)
{
	unsigned numPrinted;
	
	doIndent();
	printf("%s", label);
	numPrinted = indentLevel + strlen(label);
	if(numPrinted < COLON_COLUMN) {
		unsigned numSpaces = COLON_COLUMN - numPrinted;
		unsigned dex;
		for(dex=0; dex<numSpaces; dex++) {
			putchar(' ');
		}
	}
	printf(": ");
}

void printItem(
	const char *label,
	ItemType itemType,
	int verbose,
	DERTag tag,         // maybe from decoding, maybe the real tag underlying
						// an implicitly tagged item
	DERItem *item)		// content 
{
	DERTag tagClass = tag & ASN1_CLASS_MASK;
	DERTag tagNum = tag & ASN1_TAGNUM_MASK;
	char printable = 0;
	char *asnType = NULL;

	printHeader(label);
	
	if((itemType == IT_Branch) && !verbose) {
		printf("\n");
		return;
	}
	switch(tagClass) {
		case ASN1_UNIVERSAL:
			break;		// proceed with normal tags */
		case ASN1_APPLICATION:
			printf("APPLICATION (tag %u) ", tagNum);
			printHex(item);
			return;
		case ASN1_CONTEXT_SPECIFIC:
			printf("CONTEXT SPECIFIC (tag %u) ", tagNum);
			printHex(item);
			return;
		case ASN1_PRIVATE:
			printf("PRIVATE (tag %u) ", tagNum);
			printHex(item);
			return;
	}
	switch(tagNum) {
		case ASN1_BOOLEAN:
			asnType = "BOOLEAN";
			break;
		case ASN1_INTEGER:
			asnType = "INTEGER";
			break;
		case ASN1_BIT_STRING:
			/* special case here... */
			printf("BIT STRING ");
			printBitString(item);
			return;
		case ASN1_OCTET_STRING:
			asnType = "OCTET STRING";
			break;
		case ASN1_NULL:
			asnType = "NULL";
			break;
		case ASN1_OBJECT_ID:
			asnType = "OID";
			break;
		case ASN1_OBJECT_DESCRIPTOR:
			asnType = "OBJECT_DESCRIPTOR";
			break;
		case ASN1_REAL:
			asnType = "REAL";
			break;
		case ASN1_ENUMERATED:
			asnType = "ENUM";
			break;
		case ASN1_EMBEDDED_PDV:
			asnType = "EMBEDDED_PDV";
			break;
		case ASN1_UTF8_STRING:
			asnType = "UTF8 STRING";
			/* FIXME print these too */
			break;
		case ASN1_SEQUENCE:
			asnType = "SEQ";
			break;
		case ASN1_SET:
			asnType = "SET";
			break;
		case ASN1_NUMERIC_STRING:
			asnType = "NUMERIC_STRING";
			break;
		case ASN1_PRINTABLE_STRING:
			asnType = "PRINTABLE_STRING";
			printable = 1;
			break;
		case ASN1_T61_STRING:
			asnType = "T61_STRING";
			printable = 1;
			break;
		case ASN1_VIDEOTEX_STRING:
			asnType = "VIDEOTEX_STRING";
			printable = 1;
			break;
		case ASN1_IA5_STRING:
			asnType = "IA5_STRING";
			printable = 1;
			break;
		case ASN1_UTC_TIME:
			asnType = "UTC_TIME";
			printable = 1;
			break;
		case ASN1_GENERALIZED_TIME:
			asnType = "GENERALIZED_TIME";
			printable = 1;
			break;
		case ASN1_GRAPHIC_STRING:
			asnType = "GRAPHIC_STRING";
			break;
		case ASN1_VISIBLE_STRING:
			asnType = "VISIBLE_STRING";
			break;
		case ASN1_GENERAL_STRING:
			asnType = "GENERAL_STRING";
			break;
		case ASN1_UNIVERSAL_STRING:
			asnType = "UNIVERSAL_STRING";
			break;
		case ASN1_BMP_STRING:
			asnType = "BMP_STRING";
			break;
		default:
			asnType = "[unknown]";
			break;
	}
	printf("%s ", asnType);
	if(printable) {
		printString(item);
	}
	else {
		printHex(item);
	}
}

void printAlgId(
	const DERItem *content,
	int verbose)
{
	DERReturn drtn;
	DERAlgorithmId algId;
	
	drtn = DERParseSequenceContent(content,
		DERNumAlgorithmIdItemSpecs, DERAlgorithmIdItemSpecs,
		&algId, sizeof(algId));
	if(drtn) {
		DERPerror("DERParseSequenceContent(algId)", drtn);
		return;
	}
	printItem("alg", IT_Leaf, verbose, ASN1_OBJECT_ID, &algId.oid);
	if(algId.params.data) {
		printItem("params", IT_Leaf, verbose, algId.params.data[0], &algId.params);
	}
}

void printSubjPubKeyInfo(
	const DERItem *content,
	int verbose)
{
	DERReturn drtn;
	DERSubjPubKeyInfo pubKeyInfo;
	DERRSAPubKeyPKCS1 pkcs1Key;
	DERItem bitStringContents;
	DERByte numUnused;
	
	drtn = DERParseSequenceContent(content,
		DERNumSubjPubKeyInfoItemSpecs, DERSubjPubKeyInfoItemSpecs,
		&pubKeyInfo, sizeof(pubKeyInfo));
	if(drtn) {
		DERPerror("DERParseSequenceContent(pubKeyInfo)", drtn);
		return;
	}
	printItem("algId", IT_Branch, verbose, ASN1_CONSTR_SEQUENCE, &pubKeyInfo.algId);
	incrIndent();
	printAlgId(&pubKeyInfo.algId, verbose);
	decrIndent();

	printItem("pubKey", IT_Branch, verbose, ASN1_BIT_STRING, &pubKeyInfo.pubKey);
	
	/* 
	 * The contents of that bit string are a PKCS1 format RSA key. 
	 */
	drtn = DERParseBitString(&pubKeyInfo.pubKey, &bitStringContents, &numUnused);
	if(drtn) {
		DERPerror("DERParseBitString(pubKeyInfo.pubKey)", drtn);
		decrIndent();
		return;
	}
	drtn = DERParseSequence(&bitStringContents,
		DERNumRSAPubKeyPKCS1ItemSpecs, DERRSAPubKeyPKCS1ItemSpecs,
		&pkcs1Key, sizeof(pkcs1Key));
	if(drtn) {
		DERPerror("DERParseSequenceContent(pubKeyBits)", drtn);
		decrIndent();
		return;
	}
	incrIndent();
	printItem("modulus", IT_Leaf, verbose, ASN1_INTEGER, &pkcs1Key.modulus);
	printItem("pubExponent", IT_Leaf, verbose, ASN1_INTEGER, &pkcs1Key.pubExponent);
	
	decrIndent();
}

/* decode one item and print it */
void decodePrintItem(
	const char *label,
	ItemType itemType,
	int verbose,
	DERItem *derItem)
{
	DERDecodedInfo decoded;
	DERReturn drtn;
	
	drtn = DERDecodeItem(derItem, &decoded);
	if(drtn) {
		DERPerror("DERDecodeItem()", drtn);
		return;
	}
	printItem(label, IT_Leaf, 0, decoded.tag, &decoded.content);
}