155714Skris/* crypto/asn1/asn1_par.c */ 255714Skris/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 355714Skris * All rights reserved. 455714Skris * 555714Skris * This package is an SSL implementation written 655714Skris * by Eric Young (eay@cryptsoft.com). 755714Skris * The implementation was written so as to conform with Netscapes SSL. 8280297Sjkim * 955714Skris * This library is free for commercial and non-commercial use as long as 1055714Skris * the following conditions are aheared to. The following conditions 1155714Skris * apply to all code found in this distribution, be it the RC4, RSA, 1255714Skris * lhash, DES, etc., code; not just the SSL code. The SSL documentation 1355714Skris * included with this distribution is covered by the same copyright terms 1455714Skris * except that the holder is Tim Hudson (tjh@cryptsoft.com). 15280297Sjkim * 1655714Skris * Copyright remains Eric Young's, and as such any Copyright notices in 1755714Skris * the code are not to be removed. 1855714Skris * If this package is used in a product, Eric Young should be given attribution 1955714Skris * as the author of the parts of the library used. 2055714Skris * This can be in the form of a textual message at program startup or 2155714Skris * in documentation (online or textual) provided with the package. 22280297Sjkim * 2355714Skris * Redistribution and use in source and binary forms, with or without 2455714Skris * modification, are permitted provided that the following conditions 2555714Skris * are met: 2655714Skris * 1. Redistributions of source code must retain the copyright 2755714Skris * notice, this list of conditions and the following disclaimer. 2855714Skris * 2. Redistributions in binary form must reproduce the above copyright 2955714Skris * notice, this list of conditions and the following disclaimer in the 3055714Skris * documentation and/or other materials provided with the distribution. 3155714Skris * 3. All advertising materials mentioning features or use of this software 3255714Skris * must display the following acknowledgement: 3355714Skris * "This product includes cryptographic software written by 3455714Skris * Eric Young (eay@cryptsoft.com)" 3555714Skris * The word 'cryptographic' can be left out if the rouines from the library 3655714Skris * being used are not cryptographic related :-). 37280297Sjkim * 4. If you include any Windows specific code (or a derivative thereof) from 3855714Skris * the apps directory (application code) you must include an acknowledgement: 3955714Skris * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" 40280297Sjkim * 4155714Skris * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND 4255714Skris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 4355714Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 4455714Skris * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 4555714Skris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 4655714Skris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 4755714Skris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 4855714Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 4955714Skris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 5055714Skris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 5155714Skris * SUCH DAMAGE. 52280297Sjkim * 5355714Skris * The licence and distribution terms for any publically available version or 5455714Skris * derivative of this code cannot be changed. i.e. this code cannot simply be 5555714Skris * copied and put under another distribution licence 5655714Skris * [including the GNU Public Licence.] 5755714Skris */ 5855714Skris 5955714Skris#include <stdio.h> 6055714Skris#include "cryptlib.h" 6155714Skris#include <openssl/buffer.h> 6255714Skris#include <openssl/objects.h> 6355714Skris#include <openssl/asn1.h> 6455714Skris 65291719Sjkim#ifndef ASN1_PARSE_MAXDEPTH 66291719Sjkim#define ASN1_PARSE_MAXDEPTH 128 67291719Sjkim#endif 68291719Sjkim 69280297Sjkimstatic int asn1_print_info(BIO *bp, int tag, int xclass, int constructed, 70280297Sjkim int indent); 71160814Ssimonstatic int asn1_parse2(BIO *bp, const unsigned char **pp, long length, 72280297Sjkim int offset, int depth, int indent, int dump); 7355714Skrisstatic int asn1_print_info(BIO *bp, int tag, int xclass, int constructed, 74280297Sjkim int indent) 75280297Sjkim{ 76280297Sjkim static const char fmt[] = "%-18s"; 77280297Sjkim char str[128]; 78280297Sjkim const char *p; 7955714Skris 80280297Sjkim if (constructed & V_ASN1_CONSTRUCTED) 81280297Sjkim p = "cons: "; 82280297Sjkim else 83280297Sjkim p = "prim: "; 84280297Sjkim if (BIO_write(bp, p, 6) < 6) 85280297Sjkim goto err; 86280297Sjkim BIO_indent(bp, indent, 128); 8755714Skris 88280297Sjkim p = str; 89280297Sjkim if ((xclass & V_ASN1_PRIVATE) == V_ASN1_PRIVATE) 90331638Sjkim BIO_snprintf(str, sizeof(str), "priv [ %d ] ", tag); 91280297Sjkim else if ((xclass & V_ASN1_CONTEXT_SPECIFIC) == V_ASN1_CONTEXT_SPECIFIC) 92331638Sjkim BIO_snprintf(str, sizeof(str), "cont [ %d ]", tag); 93280297Sjkim else if ((xclass & V_ASN1_APPLICATION) == V_ASN1_APPLICATION) 94331638Sjkim BIO_snprintf(str, sizeof(str), "appl [ %d ]", tag); 95280297Sjkim else if (tag > 30) 96331638Sjkim BIO_snprintf(str, sizeof(str), "<ASN1 %d>", tag); 97280297Sjkim else 98280297Sjkim p = ASN1_tag2str(tag); 9955714Skris 100280297Sjkim if (BIO_printf(bp, fmt, p) <= 0) 101280297Sjkim goto err; 102280297Sjkim return (1); 103280297Sjkim err: 104280297Sjkim return (0); 105280297Sjkim} 10655714Skris 107160814Ssimonint ASN1_parse(BIO *bp, const unsigned char *pp, long len, int indent) 108280297Sjkim{ 109280297Sjkim return (asn1_parse2(bp, &pp, len, 0, 0, indent, 0)); 110280297Sjkim} 11155714Skris 112280297Sjkimint ASN1_parse_dump(BIO *bp, const unsigned char *pp, long len, int indent, 113280297Sjkim int dump) 114280297Sjkim{ 115280297Sjkim return (asn1_parse2(bp, &pp, len, 0, 0, indent, dump)); 116280297Sjkim} 11768651Skris 118280297Sjkimstatic int asn1_parse2(BIO *bp, const unsigned char **pp, long length, 119280297Sjkim int offset, int depth, int indent, int dump) 120280297Sjkim{ 121280297Sjkim const unsigned char *p, *ep, *tot, *op, *opp; 122280297Sjkim long len; 123280297Sjkim int tag, xclass, ret = 0; 124280297Sjkim int nl, hl, j, r; 125280297Sjkim ASN1_OBJECT *o = NULL; 126280297Sjkim ASN1_OCTET_STRING *os = NULL; 127280297Sjkim /* ASN1_BMPSTRING *bmp=NULL; */ 128280297Sjkim int dump_indent; 12955714Skris 13068651Skris#if 0 131280297Sjkim dump_indent = indent; 13268651Skris#else 133280297Sjkim dump_indent = 6; /* Because we know BIO_dump_indent() */ 13468651Skris#endif 135291719Sjkim 136291719Sjkim if (depth > ASN1_PARSE_MAXDEPTH) { 137291719Sjkim BIO_puts(bp, "BAD RECURSION DEPTH\n"); 138291719Sjkim return 0; 139291719Sjkim } 140291719Sjkim 141280297Sjkim p = *pp; 142280297Sjkim tot = p + length; 143280297Sjkim op = p - 1; 144280297Sjkim while ((p < tot) && (op < p)) { 145280297Sjkim op = p; 146280297Sjkim j = ASN1_get_object(&p, &len, &tag, &xclass, length); 14755714Skris#ifdef LINT 148280297Sjkim j = j; 14955714Skris#endif 150280297Sjkim if (j & 0x80) { 151280297Sjkim if (BIO_write(bp, "Error in encoding\n", 18) <= 0) 152280297Sjkim goto end; 153280297Sjkim ret = 0; 154280297Sjkim goto end; 155280297Sjkim } 156280297Sjkim hl = (p - op); 157280297Sjkim length -= hl; 158280297Sjkim /* 159280297Sjkim * if j == 0x21 it is a constructed indefinite length object 160280297Sjkim */ 161280297Sjkim if (BIO_printf(bp, "%5ld:", (long)offset + (long)(op - *pp)) 162280297Sjkim <= 0) 163280297Sjkim goto end; 16455714Skris 165280297Sjkim if (j != (V_ASN1_CONSTRUCTED | 1)) { 166280297Sjkim if (BIO_printf(bp, "d=%-2d hl=%ld l=%4ld ", 167280297Sjkim depth, (long)hl, len) <= 0) 168280297Sjkim goto end; 169280297Sjkim } else { 170280297Sjkim if (BIO_printf(bp, "d=%-2d hl=%ld l=inf ", depth, (long)hl) <= 0) 171280297Sjkim goto end; 172280297Sjkim } 173280297Sjkim if (!asn1_print_info(bp, tag, xclass, j, (indent) ? depth : 0)) 174280297Sjkim goto end; 175280297Sjkim if (j & V_ASN1_CONSTRUCTED) { 176298998Sjkim const unsigned char *sp; 177298998Sjkim 178280297Sjkim ep = p + len; 179280297Sjkim if (BIO_write(bp, "\n", 1) <= 0) 180280297Sjkim goto end; 181280297Sjkim if (len > length) { 182280297Sjkim BIO_printf(bp, "length is greater than %ld\n", length); 183280297Sjkim ret = 0; 184280297Sjkim goto end; 185280297Sjkim } 186280297Sjkim if ((j == 0x21) && (len == 0)) { 187298998Sjkim sp = p; 188280297Sjkim for (;;) { 189280297Sjkim r = asn1_parse2(bp, &p, (long)(tot - p), 190280297Sjkim offset + (p - *pp), depth + 1, 191280297Sjkim indent, dump); 192280297Sjkim if (r == 0) { 193280297Sjkim ret = 0; 194280297Sjkim goto end; 195280297Sjkim } 196298998Sjkim if ((r == 2) || (p >= tot)) { 197298998Sjkim len = p - sp; 198280297Sjkim break; 199298998Sjkim } 200280297Sjkim } 201298998Sjkim } else { 202298998Sjkim long tmp = len; 203298998Sjkim 204280297Sjkim while (p < ep) { 205298998Sjkim sp = p; 206298998Sjkim r = asn1_parse2(bp, &p, tmp, offset + (p - *pp), depth + 1, 207280297Sjkim indent, dump); 208280297Sjkim if (r == 0) { 209280297Sjkim ret = 0; 210280297Sjkim goto end; 211280297Sjkim } 212298998Sjkim tmp -= p - sp; 213280297Sjkim } 214298998Sjkim } 215280297Sjkim } else if (xclass != 0) { 216280297Sjkim p += len; 217280297Sjkim if (BIO_write(bp, "\n", 1) <= 0) 218280297Sjkim goto end; 219280297Sjkim } else { 220280297Sjkim nl = 0; 221280297Sjkim if ((tag == V_ASN1_PRINTABLESTRING) || 222280297Sjkim (tag == V_ASN1_T61STRING) || 223280297Sjkim (tag == V_ASN1_IA5STRING) || 224280297Sjkim (tag == V_ASN1_VISIBLESTRING) || 225280297Sjkim (tag == V_ASN1_NUMERICSTRING) || 226280297Sjkim (tag == V_ASN1_UTF8STRING) || 227280297Sjkim (tag == V_ASN1_UTCTIME) || (tag == V_ASN1_GENERALIZEDTIME)) { 228280297Sjkim if (BIO_write(bp, ":", 1) <= 0) 229280297Sjkim goto end; 230280297Sjkim if ((len > 0) && BIO_write(bp, (const char *)p, (int)len) 231280297Sjkim != (int)len) 232280297Sjkim goto end; 233280297Sjkim } else if (tag == V_ASN1_OBJECT) { 234280297Sjkim opp = op; 235280297Sjkim if (d2i_ASN1_OBJECT(&o, &opp, len + hl) != NULL) { 236280297Sjkim if (BIO_write(bp, ":", 1) <= 0) 237280297Sjkim goto end; 238280297Sjkim i2a_ASN1_OBJECT(bp, o); 239280297Sjkim } else { 240280297Sjkim if (BIO_write(bp, ":BAD OBJECT", 11) <= 0) 241280297Sjkim goto end; 242280297Sjkim } 243280297Sjkim } else if (tag == V_ASN1_BOOLEAN) { 244280297Sjkim int ii; 24555714Skris 246280297Sjkim opp = op; 247280297Sjkim ii = d2i_ASN1_BOOLEAN(NULL, &opp, len + hl); 248280297Sjkim if (ii < 0) { 249280297Sjkim if (BIO_write(bp, "Bad boolean\n", 12) <= 0) 250280297Sjkim goto end; 251280297Sjkim } 252280297Sjkim BIO_printf(bp, ":%d", ii); 253280297Sjkim } else if (tag == V_ASN1_BMPSTRING) { 254280297Sjkim /* do the BMP thang */ 255280297Sjkim } else if (tag == V_ASN1_OCTET_STRING) { 256280297Sjkim int i, printable = 1; 25755714Skris 258280297Sjkim opp = op; 259280297Sjkim os = d2i_ASN1_OCTET_STRING(NULL, &opp, len + hl); 260280297Sjkim if (os != NULL && os->length > 0) { 261280297Sjkim opp = os->data; 262280297Sjkim /* 263280297Sjkim * testing whether the octet string is printable 264280297Sjkim */ 265280297Sjkim for (i = 0; i < os->length; i++) { 266280297Sjkim if (((opp[i] < ' ') && 267280297Sjkim (opp[i] != '\n') && 268280297Sjkim (opp[i] != '\r') && 269280297Sjkim (opp[i] != '\t')) || (opp[i] > '~')) { 270280297Sjkim printable = 0; 271280297Sjkim break; 272280297Sjkim } 273280297Sjkim } 274280297Sjkim if (printable) 275280297Sjkim /* printable string */ 276280297Sjkim { 277280297Sjkim if (BIO_write(bp, ":", 1) <= 0) 278280297Sjkim goto end; 279280297Sjkim if (BIO_write(bp, (const char *)opp, os->length) <= 0) 280280297Sjkim goto end; 281280297Sjkim } else if (!dump) 282280297Sjkim /* 283280297Sjkim * not printable => print octet string as hex dump 284280297Sjkim */ 285280297Sjkim { 286280297Sjkim if (BIO_write(bp, "[HEX DUMP]:", 11) <= 0) 287280297Sjkim goto end; 288280297Sjkim for (i = 0; i < os->length; i++) { 289280297Sjkim if (BIO_printf(bp, "%02X", opp[i]) <= 0) 290280297Sjkim goto end; 291280297Sjkim } 292280297Sjkim } else 293280297Sjkim /* print the normal dump */ 294280297Sjkim { 295280297Sjkim if (!nl) { 296280297Sjkim if (BIO_write(bp, "\n", 1) <= 0) 297280297Sjkim goto end; 298280297Sjkim } 299280297Sjkim if (BIO_dump_indent(bp, 300280297Sjkim (const char *)opp, 301280297Sjkim ((dump == -1 || dump > 302280297Sjkim os-> 303280297Sjkim length) ? os->length : dump), 304280297Sjkim dump_indent) <= 0) 305280297Sjkim goto end; 306280297Sjkim nl = 1; 307280297Sjkim } 308280297Sjkim } 309280297Sjkim if (os != NULL) { 310280297Sjkim M_ASN1_OCTET_STRING_free(os); 311280297Sjkim os = NULL; 312280297Sjkim } 313280297Sjkim } else if (tag == V_ASN1_INTEGER) { 314280297Sjkim ASN1_INTEGER *bs; 315280297Sjkim int i; 31655714Skris 317280297Sjkim opp = op; 318280297Sjkim bs = d2i_ASN1_INTEGER(NULL, &opp, len + hl); 319280297Sjkim if (bs != NULL) { 320280297Sjkim if (BIO_write(bp, ":", 1) <= 0) 321280297Sjkim goto end; 322280297Sjkim if (bs->type == V_ASN1_NEG_INTEGER) 323280297Sjkim if (BIO_write(bp, "-", 1) <= 0) 324280297Sjkim goto end; 325280297Sjkim for (i = 0; i < bs->length; i++) { 326280297Sjkim if (BIO_printf(bp, "%02X", bs->data[i]) <= 0) 327280297Sjkim goto end; 328280297Sjkim } 329280297Sjkim if (bs->length == 0) { 330280297Sjkim if (BIO_write(bp, "00", 2) <= 0) 331280297Sjkim goto end; 332280297Sjkim } 333280297Sjkim } else { 334280297Sjkim if (BIO_write(bp, "BAD INTEGER", 11) <= 0) 335280297Sjkim goto end; 336280297Sjkim } 337280297Sjkim M_ASN1_INTEGER_free(bs); 338280297Sjkim } else if (tag == V_ASN1_ENUMERATED) { 339280297Sjkim ASN1_ENUMERATED *bs; 340280297Sjkim int i; 34155714Skris 342280297Sjkim opp = op; 343280297Sjkim bs = d2i_ASN1_ENUMERATED(NULL, &opp, len + hl); 344280297Sjkim if (bs != NULL) { 345280297Sjkim if (BIO_write(bp, ":", 1) <= 0) 346280297Sjkim goto end; 347280297Sjkim if (bs->type == V_ASN1_NEG_ENUMERATED) 348280297Sjkim if (BIO_write(bp, "-", 1) <= 0) 349280297Sjkim goto end; 350280297Sjkim for (i = 0; i < bs->length; i++) { 351280297Sjkim if (BIO_printf(bp, "%02X", bs->data[i]) <= 0) 352280297Sjkim goto end; 353280297Sjkim } 354280297Sjkim if (bs->length == 0) { 355280297Sjkim if (BIO_write(bp, "00", 2) <= 0) 356280297Sjkim goto end; 357280297Sjkim } 358280297Sjkim } else { 359280297Sjkim if (BIO_write(bp, "BAD ENUMERATED", 14) <= 0) 360280297Sjkim goto end; 361280297Sjkim } 362280297Sjkim M_ASN1_ENUMERATED_free(bs); 363280297Sjkim } else if (len > 0 && dump) { 364280297Sjkim if (!nl) { 365280297Sjkim if (BIO_write(bp, "\n", 1) <= 0) 366280297Sjkim goto end; 367280297Sjkim } 368280297Sjkim if (BIO_dump_indent(bp, (const char *)p, 369280297Sjkim ((dump == -1 || dump > len) ? len : dump), 370280297Sjkim dump_indent) <= 0) 371280297Sjkim goto end; 372280297Sjkim nl = 1; 373280297Sjkim } 37455714Skris 375280297Sjkim if (!nl) { 376280297Sjkim if (BIO_write(bp, "\n", 1) <= 0) 377280297Sjkim goto end; 378280297Sjkim } 379280297Sjkim p += len; 380280297Sjkim if ((tag == V_ASN1_EOC) && (xclass == 0)) { 381280297Sjkim ret = 2; /* End of sequence */ 382280297Sjkim goto end; 383280297Sjkim } 384280297Sjkim } 385280297Sjkim length -= len; 386280297Sjkim } 387280297Sjkim ret = 1; 388280297Sjkim end: 389280297Sjkim if (o != NULL) 390280297Sjkim ASN1_OBJECT_free(o); 391280297Sjkim if (os != NULL) 392280297Sjkim M_ASN1_OCTET_STRING_free(os); 393280297Sjkim *pp = p; 394280297Sjkim return (ret); 395280297Sjkim} 39659191Skris 39759191Skrisconst char *ASN1_tag2str(int tag) 39859191Skris{ 399280297Sjkim static const char *const tag2str[] = { 400280297Sjkim /* 0-4 */ 401280297Sjkim "EOC", "BOOLEAN", "INTEGER", "BIT STRING", "OCTET STRING", 402280297Sjkim /* 5-9 */ 403280297Sjkim "NULL", "OBJECT", "OBJECT DESCRIPTOR", "EXTERNAL", "REAL", 404280297Sjkim /* 10-13 */ 405280297Sjkim "ENUMERATED", "<ASN1 11>", "UTF8STRING", "<ASN1 13>", 406280297Sjkim /* 15-17 */ 407280297Sjkim "<ASN1 14>", "<ASN1 15>", "SEQUENCE", "SET", 408280297Sjkim /* 18-20 */ 409280297Sjkim "NUMERICSTRING", "PRINTABLESTRING", "T61STRING", 410280297Sjkim /* 21-24 */ 411280297Sjkim "VIDEOTEXSTRING", "IA5STRING", "UTCTIME", "GENERALIZEDTIME", 412280297Sjkim /* 25-27 */ 413280297Sjkim "GRAPHICSTRING", "VISIBLESTRING", "GENERALSTRING", 414280297Sjkim /* 28-30 */ 415280297Sjkim "UNIVERSALSTRING", "<ASN1 29>", "BMPSTRING" 416280297Sjkim }; 41759191Skris 418280297Sjkim if ((tag == V_ASN1_NEG_INTEGER) || (tag == V_ASN1_NEG_ENUMERATED)) 419280297Sjkim tag &= ~0x100; 42059191Skris 421280297Sjkim if (tag < 0 || tag > 30) 422280297Sjkim return "(unknown)"; 423280297Sjkim return tag2str[tag]; 42459191Skris} 425