X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/80e2389990082500d76eb566d4946be3e786c3ef..d8f41ccd20de16f8ebe2ccc84d47bf1cb2b26bbb:/SecurityTests/clxutils/unBER/unBER.cpp?ds=inline diff --git a/SecurityTests/clxutils/unBER/unBER.cpp b/SecurityTests/clxutils/unBER/unBER.cpp new file mode 100644 index 00000000..12ee9a86 --- /dev/null +++ b/SecurityTests/clxutils/unBER/unBER.cpp @@ -0,0 +1,448 @@ +/* + * 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 +#include +#include +#include +#include +#include + +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) {\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 {\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