#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(' ');
}
}
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
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, DERItem *item) {
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; 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:
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";
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);
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();
}
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);
}