-/*
- * Decodes and prints ASN.1 BER.
- *
- * Written by Henning Schulzrinne, Columbia University, (c) 1997.
- * Updated by Doug Mitchell 9/6/00 to use oidParser
- */
-
-#include <stdio.h>
-#include <ctype.h>
-#include <string.h>
-#include <stdlib.h>
-#include <security_cdsa_utils/cuFileIo.h>
-#include <security_cdsa_utils/cuOidParser.h>
-
-static void usage(char **argv)
-{
- printf("Usage: %s berfile [o (parse octet strings)] "
- "[b (parse bit strings) ]\n", argv[0]);
- exit(1);
-}
-
-#define PARSE_BIT_STR 0x01
-#define PARSE_OCTET_STR 0x02
-
-/* bogus infinite length loop index target */
-#define INDEFINITE 1000000
-
-typedef unsigned char uchar;
-
-#define CLASS_MASK 0xc0
-#define CLASS_UNIV 0x00
-#define CLASS_APPL 0x40
-#define CLASS_CONTEXT 0x80
-#define CLASS_PRIVATE 0xc0
-#define CONSTRUCT_BIT 0x20
-
-static int sequence(int t, const char *tag, uchar *b, int length,
- OidParser &parser, unsigned parseFlags);
-static int value(int t, uchar *b, int length, OidParser &parser,
- unsigned parseFlags);
-
-static void indent(int t)
-{
- int i;
- for (i = 0; i < t; i++) putchar(' ');
-} /* indent */
-
-static int oid(int t, uchar *b, int length, OidParser &parser)
-{
- indent(t);
- char oidStr[OID_PARSER_STRING_SIZE];
- parser.oidParse(b, length, oidStr);
- printf("OID <%d>: %s\n", length, oidStr);
- return length;
-} /* oid */
-
-
-static int integer(int t, const char *type, uchar *b, int length)
-{
- int i;
-
- indent(t);
- printf("%s <%d>:", type, length);
- for (i = 0; i < length; i++) {
- printf("%02x ", b[i]);
- }
- printf("\n");
- return length;
-} /* integer */
-
-
-static int bitstring(int t, uchar *b, int length)
-{
- int i;
-
- indent(t);
- printf("BIT STRING <%d, %d>:", length, b[0]);
- for (i = 1; i < length; i++) {
- if ((i % 16) == 0) {
- printf("\n");
- indent(t+3);
- }
- printf("%02x ", b[i]);
- }
- printf("\n");
- return length;
-} /* bitstring */
-
-
-static int octetstring(int t, uchar *b, int length)
-{
- int i;
-
- indent(t);
- printf("OCTET STRING <%d>:", length);
- for (i = 0; i < length; i++) {
- if ((i % 16) == 0) {
- printf("\n");
- indent(t+3);
- }
- printf("%02x ", b[i]);
- }
- printf("\n");
- return length;
-} /* bitstring */
-
-static int bmpstring(int t, uchar *b, int length)
-{
- /* enventually convert via unicode to printable */
- int i;
-
- indent(t);
- printf("BMP STRING <%d>:", length);
- for (i = 0; i < length; i++) {
- if ((i % 16) == 0) {
- printf("\n");
- indent(t+3);
- }
- printf("%02x ", b[i]);
- }
- printf("\n");
- return length;
-} /* bmpstring */
-
-
-
-static int string(int t, const char *tag, uchar *b, int length)
-{
- indent(t);
- printf("%s <%d>: %*.*s\n", tag, length, length, length, b);
- return length;
-} /* string */
-
-static int unparsed(int t, uchar *b, int length)
-{
- int i;
-
- indent(t);
- printf("UNPARSED DATA <%d>:", length);
- for (i = 0; i < length; i++) {
- if ((i % 16) == 0) {
- printf("\n");
- indent(t+3);
- }
- printf("%02x ", b[i]);
- }
- printf("\n");
- return length;
-} /* unparsed */
-
-
-static int metaClass(int t, // indent
- uchar tag, // tag
- uchar *b, // start of contents
- int length, // content length
- const char *className,
- OidParser &parser,
- unsigned parseFlags)
-{
- uchar underlyingTag = tag & ~(CLASS_MASK | CONSTRUCT_BIT);
- indent(t);
- if(length == -1) {
- printf("%s (tag %d) <indefinite> {\n", className, underlyingTag);
- }
- else {
- printf("%s (tag %d) <%d> {\n", className, underlyingTag, length);
- }
- /* just print uninterpreted bytes if !constructed, !universal */
- if( ( ( tag & CLASS_MASK) != CLASS_UNIV) &&
- !(tag & CONSTRUCT_BIT) ) {
- /* fixme - can't do this for indefinite length */
- unparsed(t+3, b, length);
- }
- else {
- length = value(t + 3, b, length, parser, parseFlags);
- }
- indent(t);
- printf("}\n");
- return length;
-} /* metaClass */
-
-
-static int value(
- int t, // indent depth
- uchar *b, // start of item (at tag)
- int length, // length if item, -1 ==> indefinite
- OidParser &parser,
- unsigned parseFlags) // PARSE_BIT_STR, etc.
-{
- int i, j, k;
- int tag_length, length_length, len;
- uchar classId;
- uchar constructBit;
- const char *parseStr = NULL; // name of recursively parsed bit/octet string
- uchar *parseVal = NULL; // contents to parse
- unsigned parseLen = 0;
-
- if (length == -1) length = INDEFINITE;
-
- for (i = 0; i < length; ) {
- /* tag length */
- tag_length = 1;
-
- /* get length: short form (single byte) or 0x8b or 0x80 (indefinite) */
- if (b[i+1] == 0x80) {
- len = -1;
- length_length = 1;
- }
- else if (b[i+1] & 0x80) {
- /* long length of n bytes */
- length_length = (b[i+1] & 0x7f) + 1;
- len = 0;
- for (j = 1; j < length_length; j++) {
- len = len * 256 + b[i+1+j];
- }
- }
- else {
- /* short length form */
- len = b[i+1];
- length_length = 1;
- }
-
- /*
- * i is index of current tag
- * len is content length of current item
- * set k as index to start of content
- */
- k = i + tag_length + length_length;
-
- if(length != INDEFINITE) {
- if((k + len) > length) {
- printf("***content overflow\n");
- }
- }
- /* handle special case classes */
- classId = b[i] & CLASS_MASK;
- constructBit = b[i] & CONSTRUCT_BIT;
-
- switch(classId) {
- case CLASS_UNIV: // normal case handled below
- goto parseTag;
- case CLASS_CONTEXT:
- i += metaClass(t, b[i], &b[k], len, "CONTEXT SPECIFIC",
- parser, parseFlags);
- break;
- case CLASS_APPL:
- i += metaClass(t, b[i], &b[k], len, "APPLICATION SPECIFIC",
- parser, parseFlags);
- break;
- case CLASS_PRIVATE:
- i += metaClass(t, b[i], &b[k], len, "PRIVATE",
- parser, parseFlags);
- break;
- default:
- /* not reached */
- break;
- }
- goto done; // this item already parsed per class
- parseTag:
- parseStr = NULL;
- parseVal = b + k; // default recursively parsed value
- parseLen = len;
-
- switch(b[i]) {
- case 0x0: /* end of indefinite length */
- i += tag_length + length_length;
- return i;
-
- case 0x01: /* BOOLEAN, a one-byte integer */
- i += integer(t, "BOOLEAN", &b[k], len);
- break;
-
- case 0x02: /* INTEGER */
- i += integer(t, "INTEGER", &b[k], len);
- break;
-
- case 0x03: /* BIT STRING */
- i += bitstring(t, &b[k], len);
- if(parseFlags & PARSE_OCTET_STR) {
- parseStr = "BIT STRING";
- parseVal++; // skip reminder byte
- parseLen--;
- }
- break;
-
- case 0x04: /* OCTET STRING */
- i += octetstring(t, &b[k], len);
- if(parseFlags & PARSE_OCTET_STR) {
- parseStr = "OCTET STRING";
- }
- break;
-
- case 0x5: /* NULL */
- indent(t);
- printf("NULL\n");
- break;
-
- case 0x06: /* OBJECT IDENTIFIER */
- i += oid(t, &b[k], len, parser);
- break;
-
- case 0x0A: /* enumerated */
- i += integer(t, "ENUM", &b[k], len);
- break;
-
- case 0xc: /* UTF8 string */
- i += string(t, "UTF8String", &b[k], len);
- break;
-
- case 0x13: /* PrintableString */
- i += string(t, "PrintableString", &b[k], len);
- break;
-
- case 0x14: /* T61String */
- i += string(t, "T61String", &b[k], len);
- break;
-
- case 0x16: /* IA5String */
- i += string(t, "IA5String", &b[k], len);
- break;
-
- case 0x17: /* UTCTime */
- i += string(t, "UTCTime", &b[k], len);
- break;
-
- case 0x18: /* generalized Time */
- i += string(t, "GenTime", &b[k], len);
- break;
-
- case 0x19: /* SEC_ASN1_GRAPHIC_STRING */
- i += string(t, "Graphic", &b[k], len);
- break;
-
- case 0x1a: /* SEC_ASN1_VISIBLE_STRING */
- i += string(t, "Visible", &b[k], len);
- break;
-
- case 0x1b: /* SEC_ASN1_GENERAL_STRING */
- i += string(t, "General", &b[k], len);
- break;
-
- case 0x1e: /* BMP string, unicode */
- i += bmpstring(t, &b[k], len);
- break;
-
- case 0xA0: /* SIGNED? */
- i += sequence(t, "EXPLICIT", &b[k], len, parser,
- parseFlags);
- break;
-
- case 0x30: /* SEQUENCE OF */
- i += sequence(t, "SEQUENCE OF", &b[k], len, parser,
- parseFlags);
- break;
-
- case 0x31: /* SET OF */
- i += sequence(t, "SET OF", &b[k], len, parser,
- parseFlags);
- break;
-
- case 0x39: /* SET OF */
- i += sequence(t, "structured", &b[k], len, parser,
- parseFlags);
- break;
-
- case 0x24: /* CONSTRUCTED octet string */
- i += sequence(t, "CONSTR OCTET STRING", &b[k], len,
- parser, parseFlags);
- if(parseFlags & PARSE_OCTET_STR) {
- parseStr = "OCTET STRING";
- }
- break;
-
- default:
- printf("ACK! Unknown tag (0x%x); aborting\n", b[i]);
- exit(1);
- } /* switch tag */
- done:
- if(parseStr) {
- indent(t);
- fpurge(stdin);
- printf("Parse contents (y/anything)? ");
- char resp = getchar();
- if(resp == 'y') {
- indent(t+3);
- printf("Parsed %s contents {\n", parseStr);
- value(t+6, parseVal, parseLen, parser, parseFlags);
- indent(t+3);
- printf("} end of Parsed %s\n", parseStr);
- }
- }
- i += tag_length + length_length;
- } /* main loop for i to length */
- return i;
-} /* value */
-
-
-static int sequence(int t, const char *tag, uchar *b, int length,
- OidParser &parser, unsigned parseFlags)
-{
- int len;
-
- indent(t);
- if (length < 0) {
- printf("%s <indefinite> {\n", tag);
- }
- else {
- printf("%s <%d> {\n", tag, length);
- }
- len = value(t + 3, b, length, parser, parseFlags);
- indent(t);
- printf("}\n");
- return len;
-} /* sequence */
-
-
-int main(int argc, char *argv[])
-{
- uchar* bfr;
- int i = 0;
- if(argc < 2) {
- usage(argv);
- }
- if(readFile(argv[1], &bfr, (unsigned int *)&i)) {
- printf("Error reading %s\n", argv[1]);
- exit(1);
- }
-
- unsigned parseFlags = 0;
-
- for(int dex=2; dex<argc; dex++) {
- switch(argv[dex][0]) {
- case 'b':
- parseFlags |= PARSE_BIT_STR;
- break;
- case 'o':
- parseFlags |= PARSE_OCTET_STR;
- break;
- default:
- usage(argv);
- }
- }
-
- OidParser parser;
- value(0, bfr, i, parser, parseFlags);
- free(bfr);
- return 0;
-} /* main */