1/* 2 * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved. 3 * 4 * Licensed under the OpenSSL license (the "License"). You may not use 5 * this file except in compliance with the License. You can obtain a copy 6 * in the file LICENSE in the source distribution or at 7 * https://www.openssl.org/source/license.html 8 */ 9 10#include <stdio.h> 11#include "internal/cryptlib.h" 12#include <openssl/buffer.h> 13#include <openssl/objects.h> 14#include <openssl/asn1.h> 15 16#ifndef ASN1_PARSE_MAXDEPTH 17#define ASN1_PARSE_MAXDEPTH 128 18#endif 19 20static int asn1_print_info(BIO *bp, int tag, int xclass, int constructed, 21 int indent); 22static int asn1_parse2(BIO *bp, const unsigned char **pp, long length, 23 int offset, int depth, int indent, int dump); 24static int asn1_print_info(BIO *bp, int tag, int xclass, int constructed, 25 int indent) 26{ 27 static const char fmt[] = "%-18s"; 28 char str[128]; 29 const char *p; 30 31 if (constructed & V_ASN1_CONSTRUCTED) 32 p = "cons: "; 33 else 34 p = "prim: "; 35 if (BIO_write(bp, p, 6) < 6) 36 goto err; 37 BIO_indent(bp, indent, 128); 38 39 p = str; 40 if ((xclass & V_ASN1_PRIVATE) == V_ASN1_PRIVATE) 41 BIO_snprintf(str, sizeof(str), "priv [ %d ] ", tag); 42 else if ((xclass & V_ASN1_CONTEXT_SPECIFIC) == V_ASN1_CONTEXT_SPECIFIC) 43 BIO_snprintf(str, sizeof(str), "cont [ %d ]", tag); 44 else if ((xclass & V_ASN1_APPLICATION) == V_ASN1_APPLICATION) 45 BIO_snprintf(str, sizeof(str), "appl [ %d ]", tag); 46 else if (tag > 30) 47 BIO_snprintf(str, sizeof(str), "<ASN1 %d>", tag); 48 else 49 p = ASN1_tag2str(tag); 50 51 if (BIO_printf(bp, fmt, p) <= 0) 52 goto err; 53 return 1; 54 err: 55 return 0; 56} 57 58int ASN1_parse(BIO *bp, const unsigned char *pp, long len, int indent) 59{ 60 return asn1_parse2(bp, &pp, len, 0, 0, indent, 0); 61} 62 63int ASN1_parse_dump(BIO *bp, const unsigned char *pp, long len, int indent, 64 int dump) 65{ 66 return asn1_parse2(bp, &pp, len, 0, 0, indent, dump); 67} 68 69static int asn1_parse2(BIO *bp, const unsigned char **pp, long length, 70 int offset, int depth, int indent, int dump) 71{ 72 const unsigned char *p, *ep, *tot, *op, *opp; 73 long len; 74 int tag, xclass, ret = 0; 75 int nl, hl, j, r; 76 ASN1_OBJECT *o = NULL; 77 ASN1_OCTET_STRING *os = NULL; 78 ASN1_INTEGER *ai = NULL; 79 ASN1_ENUMERATED *ae = NULL; 80 /* ASN1_BMPSTRING *bmp=NULL; */ 81 int dump_indent, dump_cont = 0; 82 83 if (depth > ASN1_PARSE_MAXDEPTH) { 84 BIO_puts(bp, "BAD RECURSION DEPTH\n"); 85 return 0; 86 } 87 88 dump_indent = 6; /* Because we know BIO_dump_indent() */ 89 p = *pp; 90 tot = p + length; 91 while (length > 0) { 92 op = p; 93 j = ASN1_get_object(&p, &len, &tag, &xclass, length); 94 if (j & 0x80) { 95 if (BIO_write(bp, "Error in encoding\n", 18) <= 0) 96 goto end; 97 ret = 0; 98 goto end; 99 } 100 hl = (p - op); 101 length -= hl; 102 /* 103 * if j == 0x21 it is a constructed indefinite length object 104 */ 105 if (BIO_printf(bp, "%5ld:", (long)offset + (long)(op - *pp)) 106 <= 0) 107 goto end; 108 109 if (j != (V_ASN1_CONSTRUCTED | 1)) { 110 if (BIO_printf(bp, "d=%-2d hl=%ld l=%4ld ", 111 depth, (long)hl, len) <= 0) 112 goto end; 113 } else { 114 if (BIO_printf(bp, "d=%-2d hl=%ld l=inf ", depth, (long)hl) <= 0) 115 goto end; 116 } 117 if (!asn1_print_info(bp, tag, xclass, j, (indent) ? depth : 0)) 118 goto end; 119 if (j & V_ASN1_CONSTRUCTED) { 120 const unsigned char *sp = p; 121 122 ep = p + len; 123 if (BIO_write(bp, "\n", 1) <= 0) 124 goto end; 125 if (len > length) { 126 BIO_printf(bp, "length is greater than %ld\n", length); 127 ret = 0; 128 goto end; 129 } 130 if ((j == 0x21) && (len == 0)) { 131 for (;;) { 132 r = asn1_parse2(bp, &p, (long)(tot - p), 133 offset + (p - *pp), depth + 1, 134 indent, dump); 135 if (r == 0) { 136 ret = 0; 137 goto end; 138 } 139 if ((r == 2) || (p >= tot)) { 140 len = p - sp; 141 break; 142 } 143 } 144 } else { 145 long tmp = len; 146 147 while (p < ep) { 148 sp = p; 149 r = asn1_parse2(bp, &p, tmp, 150 offset + (p - *pp), depth + 1, 151 indent, dump); 152 if (r == 0) { 153 ret = 0; 154 goto end; 155 } 156 tmp -= p - sp; 157 } 158 } 159 } else if (xclass != 0) { 160 p += len; 161 if (BIO_write(bp, "\n", 1) <= 0) 162 goto end; 163 } else { 164 nl = 0; 165 if ((tag == V_ASN1_PRINTABLESTRING) || 166 (tag == V_ASN1_T61STRING) || 167 (tag == V_ASN1_IA5STRING) || 168 (tag == V_ASN1_VISIBLESTRING) || 169 (tag == V_ASN1_NUMERICSTRING) || 170 (tag == V_ASN1_UTF8STRING) || 171 (tag == V_ASN1_UTCTIME) || (tag == V_ASN1_GENERALIZEDTIME)) { 172 if (BIO_write(bp, ":", 1) <= 0) 173 goto end; 174 if ((len > 0) && BIO_write(bp, (const char *)p, (int)len) 175 != (int)len) 176 goto end; 177 } else if (tag == V_ASN1_OBJECT) { 178 opp = op; 179 if (d2i_ASN1_OBJECT(&o, &opp, len + hl) != NULL) { 180 if (BIO_write(bp, ":", 1) <= 0) 181 goto end; 182 i2a_ASN1_OBJECT(bp, o); 183 } else { 184 if (BIO_puts(bp, ":BAD OBJECT") <= 0) 185 goto end; 186 dump_cont = 1; 187 } 188 } else if (tag == V_ASN1_BOOLEAN) { 189 if (len != 1) { 190 if (BIO_puts(bp, ":BAD BOOLEAN") <= 0) 191 goto end; 192 dump_cont = 1; 193 } 194 if (len > 0) 195 BIO_printf(bp, ":%u", p[0]); 196 } else if (tag == V_ASN1_BMPSTRING) { 197 /* do the BMP thang */ 198 } else if (tag == V_ASN1_OCTET_STRING) { 199 int i, printable = 1; 200 201 opp = op; 202 os = d2i_ASN1_OCTET_STRING(NULL, &opp, len + hl); 203 if (os != NULL && os->length > 0) { 204 opp = os->data; 205 /* 206 * testing whether the octet string is printable 207 */ 208 for (i = 0; i < os->length; i++) { 209 if (((opp[i] < ' ') && 210 (opp[i] != '\n') && 211 (opp[i] != '\r') && 212 (opp[i] != '\t')) || (opp[i] > '~')) { 213 printable = 0; 214 break; 215 } 216 } 217 if (printable) 218 /* printable string */ 219 { 220 if (BIO_write(bp, ":", 1) <= 0) 221 goto end; 222 if (BIO_write(bp, (const char *)opp, os->length) <= 0) 223 goto end; 224 } else if (!dump) 225 /* 226 * not printable => print octet string as hex dump 227 */ 228 { 229 if (BIO_write(bp, "[HEX DUMP]:", 11) <= 0) 230 goto end; 231 for (i = 0; i < os->length; i++) { 232 if (BIO_printf(bp, "%02X", opp[i]) <= 0) 233 goto end; 234 } 235 } else 236 /* print the normal dump */ 237 { 238 if (!nl) { 239 if (BIO_write(bp, "\n", 1) <= 0) 240 goto end; 241 } 242 if (BIO_dump_indent(bp, 243 (const char *)opp, 244 ((dump == -1 || dump > 245 os-> 246 length) ? os->length : dump), 247 dump_indent) <= 0) 248 goto end; 249 nl = 1; 250 } 251 } 252 ASN1_OCTET_STRING_free(os); 253 os = NULL; 254 } else if (tag == V_ASN1_INTEGER) { 255 int i; 256 257 opp = op; 258 ai = d2i_ASN1_INTEGER(NULL, &opp, len + hl); 259 if (ai != NULL) { 260 if (BIO_write(bp, ":", 1) <= 0) 261 goto end; 262 if (ai->type == V_ASN1_NEG_INTEGER) 263 if (BIO_write(bp, "-", 1) <= 0) 264 goto end; 265 for (i = 0; i < ai->length; i++) { 266 if (BIO_printf(bp, "%02X", ai->data[i]) <= 0) 267 goto end; 268 } 269 if (ai->length == 0) { 270 if (BIO_write(bp, "00", 2) <= 0) 271 goto end; 272 } 273 } else { 274 if (BIO_puts(bp, ":BAD INTEGER") <= 0) 275 goto end; 276 dump_cont = 1; 277 } 278 ASN1_INTEGER_free(ai); 279 ai = NULL; 280 } else if (tag == V_ASN1_ENUMERATED) { 281 int i; 282 283 opp = op; 284 ae = d2i_ASN1_ENUMERATED(NULL, &opp, len + hl); 285 if (ae != NULL) { 286 if (BIO_write(bp, ":", 1) <= 0) 287 goto end; 288 if (ae->type == V_ASN1_NEG_ENUMERATED) 289 if (BIO_write(bp, "-", 1) <= 0) 290 goto end; 291 for (i = 0; i < ae->length; i++) { 292 if (BIO_printf(bp, "%02X", ae->data[i]) <= 0) 293 goto end; 294 } 295 if (ae->length == 0) { 296 if (BIO_write(bp, "00", 2) <= 0) 297 goto end; 298 } 299 } else { 300 if (BIO_puts(bp, ":BAD ENUMERATED") <= 0) 301 goto end; 302 dump_cont = 1; 303 } 304 ASN1_ENUMERATED_free(ae); 305 ae = NULL; 306 } else if (len > 0 && dump) { 307 if (!nl) { 308 if (BIO_write(bp, "\n", 1) <= 0) 309 goto end; 310 } 311 if (BIO_dump_indent(bp, (const char *)p, 312 ((dump == -1 || dump > len) ? len : dump), 313 dump_indent) <= 0) 314 goto end; 315 nl = 1; 316 } 317 if (dump_cont) { 318 int i; 319 const unsigned char *tmp = op + hl; 320 if (BIO_puts(bp, ":[") <= 0) 321 goto end; 322 for (i = 0; i < len; i++) { 323 if (BIO_printf(bp, "%02X", tmp[i]) <= 0) 324 goto end; 325 } 326 if (BIO_puts(bp, "]") <= 0) 327 goto end; 328 dump_cont = 0; 329 } 330 331 if (!nl) { 332 if (BIO_write(bp, "\n", 1) <= 0) 333 goto end; 334 } 335 p += len; 336 if ((tag == V_ASN1_EOC) && (xclass == 0)) { 337 ret = 2; /* End of sequence */ 338 goto end; 339 } 340 } 341 length -= len; 342 } 343 ret = 1; 344 end: 345 ASN1_OBJECT_free(o); 346 ASN1_OCTET_STRING_free(os); 347 ASN1_INTEGER_free(ai); 348 ASN1_ENUMERATED_free(ae); 349 *pp = p; 350 return ret; 351} 352 353const char *ASN1_tag2str(int tag) 354{ 355 static const char *const tag2str[] = { 356 /* 0-4 */ 357 "EOC", "BOOLEAN", "INTEGER", "BIT STRING", "OCTET STRING", 358 /* 5-9 */ 359 "NULL", "OBJECT", "OBJECT DESCRIPTOR", "EXTERNAL", "REAL", 360 /* 10-13 */ 361 "ENUMERATED", "<ASN1 11>", "UTF8STRING", "<ASN1 13>", 362 /* 15-17 */ 363 "<ASN1 14>", "<ASN1 15>", "SEQUENCE", "SET", 364 /* 18-20 */ 365 "NUMERICSTRING", "PRINTABLESTRING", "T61STRING", 366 /* 21-24 */ 367 "VIDEOTEXSTRING", "IA5STRING", "UTCTIME", "GENERALIZEDTIME", 368 /* 25-27 */ 369 "GRAPHICSTRING", "VISIBLESTRING", "GENERALSTRING", 370 /* 28-30 */ 371 "UNIVERSALSTRING", "<ASN1 29>", "BMPSTRING" 372 }; 373 374 if ((tag == V_ASN1_NEG_INTEGER) || (tag == V_ASN1_NEG_ENUMERATED)) 375 tag &= ~0x100; 376 377 if (tag < 0 || tag > 30) 378 return "(unknown)"; 379 return tag2str[tag]; 380} 381