]> git.saurik.com Git - apple/security.git/blobdiff - SecurityTests/clxutils/unBER/unBER.cpp
Security-57031.1.35.tar.gz
[apple/security.git] / SecurityTests / clxutils / unBER / unBER.cpp
diff --git a/SecurityTests/clxutils/unBER/unBER.cpp b/SecurityTests/clxutils/unBER/unBER.cpp
new file mode 100644 (file)
index 0000000..12ee9a8
--- /dev/null
@@ -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 <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 */