1/* 2 * Decodes and prints ASN.1 BER. 3 * 4 * Written by Henning Schulzrinne, Columbia University, (c) 1997. 5 * Updated by Doug Mitchell 9/6/00 to use oidParser 6 */ 7 8#include <stdio.h> 9#include <ctype.h> 10#include <string.h> 11#include <stdlib.h> 12#include <security_cdsa_utils/cuFileIo.h> 13#include <security_cdsa_utils/cuOidParser.h> 14 15static void usage(char **argv) 16{ 17 printf("Usage: %s berfile [o (parse octet strings)] " 18 "[b (parse bit strings) ]\n", argv[0]); 19 exit(1); 20} 21 22#define PARSE_BIT_STR 0x01 23#define PARSE_OCTET_STR 0x02 24 25/* bogus infinite length loop index target */ 26#define INDEFINITE 1000000 27 28typedef unsigned char uchar; 29 30#define CLASS_MASK 0xc0 31#define CLASS_UNIV 0x00 32#define CLASS_APPL 0x40 33#define CLASS_CONTEXT 0x80 34#define CLASS_PRIVATE 0xc0 35#define CONSTRUCT_BIT 0x20 36 37static int sequence(int t, const char *tag, uchar *b, int length, 38 OidParser &parser, unsigned parseFlags); 39static int value(int t, uchar *b, int length, OidParser &parser, 40 unsigned parseFlags); 41 42static void indent(int t) 43{ 44 int i; 45 for (i = 0; i < t; i++) putchar(' '); 46} /* indent */ 47 48static int oid(int t, uchar *b, int length, OidParser &parser) 49{ 50 indent(t); 51 char oidStr[OID_PARSER_STRING_SIZE]; 52 parser.oidParse(b, length, oidStr); 53 printf("OID <%d>: %s\n", length, oidStr); 54 return length; 55} /* oid */ 56 57 58static int integer(int t, const char *type, uchar *b, int length) 59{ 60 int i; 61 62 indent(t); 63 printf("%s <%d>:", type, length); 64 for (i = 0; i < length; i++) { 65 printf("%02x ", b[i]); 66 } 67 printf("\n"); 68 return length; 69} /* integer */ 70 71 72static int bitstring(int t, uchar *b, int length) 73{ 74 int i; 75 76 indent(t); 77 printf("BIT STRING <%d, %d>:", length, b[0]); 78 for (i = 1; i < length; i++) { 79 if ((i % 16) == 0) { 80 printf("\n"); 81 indent(t+3); 82 } 83 printf("%02x ", b[i]); 84 } 85 printf("\n"); 86 return length; 87} /* bitstring */ 88 89 90static int octetstring(int t, uchar *b, int length) 91{ 92 int i; 93 94 indent(t); 95 printf("OCTET STRING <%d>:", length); 96 for (i = 0; i < length; i++) { 97 if ((i % 16) == 0) { 98 printf("\n"); 99 indent(t+3); 100 } 101 printf("%02x ", b[i]); 102 } 103 printf("\n"); 104 return length; 105} /* bitstring */ 106 107static int bmpstring(int t, uchar *b, int length) 108{ 109 /* enventually convert via unicode to printable */ 110 int i; 111 112 indent(t); 113 printf("BMP STRING <%d>:", length); 114 for (i = 0; i < length; i++) { 115 if ((i % 16) == 0) { 116 printf("\n"); 117 indent(t+3); 118 } 119 printf("%02x ", b[i]); 120 } 121 printf("\n"); 122 return length; 123} /* bmpstring */ 124 125 126 127static int string(int t, const char *tag, uchar *b, int length) 128{ 129 indent(t); 130 printf("%s <%d>: %*.*s\n", tag, length, length, length, b); 131 return length; 132} /* string */ 133 134static int unparsed(int t, uchar *b, int length) 135{ 136 int i; 137 138 indent(t); 139 printf("UNPARSED DATA <%d>:", length); 140 for (i = 0; i < length; i++) { 141 if ((i % 16) == 0) { 142 printf("\n"); 143 indent(t+3); 144 } 145 printf("%02x ", b[i]); 146 } 147 printf("\n"); 148 return length; 149} /* unparsed */ 150 151 152static int metaClass(int t, // indent 153 uchar tag, // tag 154 uchar *b, // start of contents 155 int length, // content length 156 const char *className, 157 OidParser &parser, 158 unsigned parseFlags) 159{ 160 uchar underlyingTag = tag & ~(CLASS_MASK | CONSTRUCT_BIT); 161 indent(t); 162 if(length == -1) { 163 printf("%s (tag %d) <indefinite> {\n", className, underlyingTag); 164 } 165 else { 166 printf("%s (tag %d) <%d> {\n", className, underlyingTag, length); 167 } 168 /* just print uninterpreted bytes if !constructed, !universal */ 169 if( ( ( tag & CLASS_MASK) != CLASS_UNIV) && 170 !(tag & CONSTRUCT_BIT) ) { 171 /* fixme - can't do this for indefinite length */ 172 unparsed(t+3, b, length); 173 } 174 else { 175 length = value(t + 3, b, length, parser, parseFlags); 176 } 177 indent(t); 178 printf("}\n"); 179 return length; 180} /* metaClass */ 181 182 183static int value( 184 int t, // indent depth 185 uchar *b, // start of item (at tag) 186 int length, // length if item, -1 ==> indefinite 187 OidParser &parser, 188 unsigned parseFlags) // PARSE_BIT_STR, etc. 189{ 190 int i, j, k; 191 int tag_length, length_length, len; 192 uchar classId; 193 uchar constructBit; 194 const char *parseStr = NULL; // name of recursively parsed bit/octet string 195 uchar *parseVal = NULL; // contents to parse 196 unsigned parseLen = 0; 197 198 if (length == -1) length = INDEFINITE; 199 200 for (i = 0; i < length; ) { 201 /* tag length */ 202 tag_length = 1; 203 204 /* get length: short form (single byte) or 0x8b or 0x80 (indefinite) */ 205 if (b[i+1] == 0x80) { 206 len = -1; 207 length_length = 1; 208 } 209 else if (b[i+1] & 0x80) { 210 /* long length of n bytes */ 211 length_length = (b[i+1] & 0x7f) + 1; 212 len = 0; 213 for (j = 1; j < length_length; j++) { 214 len = len * 256 + b[i+1+j]; 215 } 216 } 217 else { 218 /* short length form */ 219 len = b[i+1]; 220 length_length = 1; 221 } 222 223 /* 224 * i is index of current tag 225 * len is content length of current item 226 * set k as index to start of content 227 */ 228 k = i + tag_length + length_length; 229 230 if(length != INDEFINITE) { 231 if((k + len) > length) { 232 printf("***content overflow\n"); 233 } 234 } 235 /* handle special case classes */ 236 classId = b[i] & CLASS_MASK; 237 constructBit = b[i] & CONSTRUCT_BIT; 238 239 switch(classId) { 240 case CLASS_UNIV: // normal case handled below 241 goto parseTag; 242 case CLASS_CONTEXT: 243 i += metaClass(t, b[i], &b[k], len, "CONTEXT SPECIFIC", 244 parser, parseFlags); 245 break; 246 case CLASS_APPL: 247 i += metaClass(t, b[i], &b[k], len, "APPLICATION SPECIFIC", 248 parser, parseFlags); 249 break; 250 case CLASS_PRIVATE: 251 i += metaClass(t, b[i], &b[k], len, "PRIVATE", 252 parser, parseFlags); 253 break; 254 default: 255 /* not reached */ 256 break; 257 } 258 goto done; // this item already parsed per class 259 parseTag: 260 parseStr = NULL; 261 parseVal = b + k; // default recursively parsed value 262 parseLen = len; 263 264 switch(b[i]) { 265 case 0x0: /* end of indefinite length */ 266 i += tag_length + length_length; 267 return i; 268 269 case 0x01: /* BOOLEAN, a one-byte integer */ 270 i += integer(t, "BOOLEAN", &b[k], len); 271 break; 272 273 case 0x02: /* INTEGER */ 274 i += integer(t, "INTEGER", &b[k], len); 275 break; 276 277 case 0x03: /* BIT STRING */ 278 i += bitstring(t, &b[k], len); 279 if(parseFlags & PARSE_OCTET_STR) { 280 parseStr = "BIT STRING"; 281 parseVal++; // skip reminder byte 282 parseLen--; 283 } 284 break; 285 286 case 0x04: /* OCTET STRING */ 287 i += octetstring(t, &b[k], len); 288 if(parseFlags & PARSE_OCTET_STR) { 289 parseStr = "OCTET STRING"; 290 } 291 break; 292 293 case 0x5: /* NULL */ 294 indent(t); 295 printf("NULL\n"); 296 break; 297 298 case 0x06: /* OBJECT IDENTIFIER */ 299 i += oid(t, &b[k], len, parser); 300 break; 301 302 case 0x0A: /* enumerated */ 303 i += integer(t, "ENUM", &b[k], len); 304 break; 305 306 case 0xc: /* UTF8 string */ 307 i += string(t, "UTF8String", &b[k], len); 308 break; 309 310 case 0x13: /* PrintableString */ 311 i += string(t, "PrintableString", &b[k], len); 312 break; 313 314 case 0x14: /* T61String */ 315 i += string(t, "T61String", &b[k], len); 316 break; 317 318 case 0x16: /* IA5String */ 319 i += string(t, "IA5String", &b[k], len); 320 break; 321 322 case 0x17: /* UTCTime */ 323 i += string(t, "UTCTime", &b[k], len); 324 break; 325 326 case 0x18: /* generalized Time */ 327 i += string(t, "GenTime", &b[k], len); 328 break; 329 330 case 0x19: /* SEC_ASN1_GRAPHIC_STRING */ 331 i += string(t, "Graphic", &b[k], len); 332 break; 333 334 case 0x1a: /* SEC_ASN1_VISIBLE_STRING */ 335 i += string(t, "Visible", &b[k], len); 336 break; 337 338 case 0x1b: /* SEC_ASN1_GENERAL_STRING */ 339 i += string(t, "General", &b[k], len); 340 break; 341 342 case 0x1e: /* BMP string, unicode */ 343 i += bmpstring(t, &b[k], len); 344 break; 345 346 case 0xA0: /* SIGNED? */ 347 i += sequence(t, "EXPLICIT", &b[k], len, parser, 348 parseFlags); 349 break; 350 351 case 0x30: /* SEQUENCE OF */ 352 i += sequence(t, "SEQUENCE OF", &b[k], len, parser, 353 parseFlags); 354 break; 355 356 case 0x31: /* SET OF */ 357 i += sequence(t, "SET OF", &b[k], len, parser, 358 parseFlags); 359 break; 360 361 case 0x39: /* SET OF */ 362 i += sequence(t, "structured", &b[k], len, parser, 363 parseFlags); 364 break; 365 366 case 0x24: /* CONSTRUCTED octet string */ 367 i += sequence(t, "CONSTR OCTET STRING", &b[k], len, 368 parser, parseFlags); 369 if(parseFlags & PARSE_OCTET_STR) { 370 parseStr = "OCTET STRING"; 371 } 372 break; 373 374 default: 375 printf("ACK! Unknown tag (0x%x); aborting\n", b[i]); 376 exit(1); 377 } /* switch tag */ 378 done: 379 if(parseStr) { 380 indent(t); 381 fpurge(stdin); 382 printf("Parse contents (y/anything)? "); 383 char resp = getchar(); 384 if(resp == 'y') { 385 indent(t+3); 386 printf("Parsed %s contents {\n", parseStr); 387 value(t+6, parseVal, parseLen, parser, parseFlags); 388 indent(t+3); 389 printf("} end of Parsed %s\n", parseStr); 390 } 391 } 392 i += tag_length + length_length; 393 } /* main loop for i to length */ 394 return i; 395} /* value */ 396 397 398static int sequence(int t, const char *tag, uchar *b, int length, 399 OidParser &parser, unsigned parseFlags) 400{ 401 int len; 402 403 indent(t); 404 if (length < 0) { 405 printf("%s <indefinite> {\n", tag); 406 } 407 else { 408 printf("%s <%d> {\n", tag, length); 409 } 410 len = value(t + 3, b, length, parser, parseFlags); 411 indent(t); 412 printf("}\n"); 413 return len; 414} /* sequence */ 415 416 417int main(int argc, char *argv[]) 418{ 419 uchar* bfr; 420 int i = 0; 421 if(argc < 2) { 422 usage(argv); 423 } 424 if(readFile(argv[1], &bfr, (unsigned int *)&i)) { 425 printf("Error reading %s\n", argv[1]); 426 exit(1); 427 } 428 429 unsigned parseFlags = 0; 430 431 for(int dex=2; dex<argc; dex++) { 432 switch(argv[dex][0]) { 433 case 'b': 434 parseFlags |= PARSE_BIT_STR; 435 break; 436 case 'o': 437 parseFlags |= PARSE_OCTET_STR; 438 break; 439 default: 440 usage(argv); 441 } 442 } 443 444 OidParser parser; 445 value(0, bfr, i, parser, parseFlags); 446 free(bfr); 447 return 0; 448} /* main */ 449