1 /* $NetBSD: asn1_print.c,v 1.1.1.1 2011/04/13 18:14:39 elric Exp $ */ 2 3 /* 4 * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan 5 * (Royal Institute of Technology, Stockholm, Sweden). 6 * All rights reserved. 7 * 8 * Portions Copyright (c) 2009 Apple Inc. All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 21 * 3. Neither the name of the Institute nor the names of its contributors 22 * may be used to endorse or promote products derived from this software 23 * without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 */ 37 38 #include "der_locl.h" 39 #include <krb5/com_err.h> 40 #include <sys/types.h> 41 #include <sys/stat.h> 42 #include <krb5/getarg.h> 43 #include <err.h> 44 #include <krb5/der.h> 45 46 __RCSID("$NetBSD: asn1_print.c,v 1.1.1.1 2011/04/13 18:14:39 elric Exp $"); 47 48 static int indent_flag = 1; 49 50 static unsigned long indefinite_form_loop; 51 static unsigned long indefinite_form_loop_max = 10000; 52 53 static size_t 54 loop (unsigned char *buf, size_t len, int indent) 55 { 56 unsigned char *start_buf = buf; 57 58 while (len > 0) { 59 int ret; 60 Der_class class; 61 Der_type type; 62 unsigned int tag; 63 size_t sz; 64 size_t length; 65 size_t loop_length = 0; 66 int end_tag = 0; 67 const char *tagname; 68 69 ret = der_get_tag (buf, len, &class, &type, &tag, &sz); 70 if (ret) 71 errx (1, "der_get_tag: %s", error_message (ret)); 72 if (sz > len) 73 errx (1, "unreasonable length (%u) > %u", 74 (unsigned)sz, (unsigned)len); 75 buf += sz; 76 len -= sz; 77 if (indent_flag) { 78 int i; 79 for (i = 0; i < indent; ++i) 80 printf (" "); 81 } 82 printf ("%s %s ", der_get_class_name(class), der_get_type_name(type)); 83 tagname = der_get_tag_name(tag); 84 if (class == ASN1_C_UNIV && tagname != NULL) 85 printf ("%s = ", tagname); 86 else 87 printf ("tag %d = ", tag); 88 ret = der_get_length (buf, len, &length, &sz); 89 if (ret) 90 errx (1, "der_get_tag: %s", error_message (ret)); 91 if (sz > len) 92 errx (1, "unreasonable tag length (%u) > %u", 93 (unsigned)sz, (unsigned)len); 94 buf += sz; 95 len -= sz; 96 if (length == ASN1_INDEFINITE) { 97 if ((class == ASN1_C_UNIV && type == PRIM && tag == UT_OctetString) || 98 (class == ASN1_C_CONTEXT && type == CONS) || 99 (class == ASN1_C_UNIV && type == CONS && tag == UT_Sequence) || 100 (class == ASN1_C_UNIV && type == CONS && tag == UT_Set)) { 101 printf("*INDEFINITE FORM*"); 102 } else { 103 fflush(stdout); 104 errx(1, "indef form used on unsupported object"); 105 } 106 end_tag = 1; 107 if (indefinite_form_loop > indefinite_form_loop_max) 108 errx(1, "indefinite form used recursively more then %lu " 109 "times, aborting", indefinite_form_loop_max); 110 indefinite_form_loop++; 111 length = len; 112 } else if (length > len) { 113 printf("\n"); 114 fflush(stdout); 115 errx (1, "unreasonable inner length (%u) > %u", 116 (unsigned)length, (unsigned)len); 117 } 118 if (class == ASN1_C_CONTEXT || class == ASN1_C_APPL) { 119 printf ("%lu bytes [%u]", (unsigned long)length, tag); 120 if (type == CONS) { 121 printf("\n"); 122 loop_length = loop (buf, length, indent + 2); 123 } else { 124 printf(" IMPLICIT content\n"); 125 } 126 } else if (class == ASN1_C_UNIV) { 127 switch (tag) { 128 case UT_EndOfContent: 129 printf (" INDEFINITE length was %lu\n", 130 (unsigned long)(buf - start_buf)); 131 break; 132 case UT_Set : 133 case UT_Sequence : 134 printf ("%lu bytes {\n", (unsigned long)length); 135 loop_length = loop (buf, length, indent + 2); 136 if (indent_flag) { 137 int i; 138 for (i = 0; i < indent; ++i) 139 printf (" "); 140 printf ("}\n"); 141 } else 142 printf ("} indent = %d\n", indent / 2); 143 break; 144 case UT_Integer : { 145 int val; 146 147 if (length <= sizeof(val)) { 148 ret = der_get_integer (buf, length, &val, NULL); 149 if (ret) 150 errx (1, "der_get_integer: %s", error_message (ret)); 151 printf ("integer %d\n", val); 152 } else { 153 heim_integer vali; 154 char *p; 155 156 ret = der_get_heim_integer(buf, length, &vali, NULL); 157 if (ret) 158 errx (1, "der_get_heim_integer: %s", 159 error_message (ret)); 160 ret = der_print_hex_heim_integer(&vali, &p); 161 if (ret) 162 errx (1, "der_print_hex_heim_integer: %s", 163 error_message (ret)); 164 printf ("BIG NUM integer: length %lu %s\n", 165 (unsigned long)length, p); 166 free(p); 167 } 168 break; 169 } 170 case UT_OctetString : { 171 heim_octet_string str; 172 int i; 173 unsigned char *uc; 174 175 ret = der_get_octet_string (buf, length, &str, NULL); 176 if (ret) 177 errx (1, "der_get_octet_string: %s", error_message (ret)); 178 printf ("(length %lu), ", (unsigned long)length); 179 uc = (unsigned char *)str.data; 180 for (i = 0; i < min(16,length); ++i) 181 printf ("%02x", uc[i]); 182 printf ("\n"); 183 free (str.data); 184 break; 185 } 186 case UT_IA5String : 187 case UT_PrintableString : { 188 heim_printable_string str; 189 unsigned char *s; 190 size_t n; 191 192 memset(&str, 0, sizeof(str)); 193 194 ret = der_get_printable_string (buf, length, &str, NULL); 195 if (ret) 196 errx (1, "der_get_general_string: %s", 197 error_message (ret)); 198 s = str.data; 199 printf("\""); 200 for (n = 0; n < str.length; n++) { 201 if (isprint((int)s[n])) 202 printf ("%c", s[n]); 203 else 204 printf ("#%02x", s[n]); 205 } 206 printf("\"\n"); 207 der_free_printable_string(&str); 208 break; 209 } 210 case UT_GeneralizedTime : 211 case UT_GeneralString : 212 case UT_VisibleString : 213 case UT_UTF8String : { 214 heim_general_string str; 215 216 ret = der_get_general_string (buf, length, &str, NULL); 217 if (ret) 218 errx (1, "der_get_general_string: %s", 219 error_message (ret)); 220 printf ("\"%s\"\n", str); 221 free (str); 222 break; 223 } 224 case UT_OID: { 225 heim_oid o; 226 char *p; 227 228 ret = der_get_oid(buf, length, &o, NULL); 229 if (ret) 230 errx (1, "der_get_oid: %s", error_message (ret)); 231 ret = der_print_heim_oid(&o, '.', &p); 232 der_free_oid(&o); 233 if (ret) 234 errx (1, "der_print_heim_oid: %s", error_message (ret)); 235 printf("%s\n", p); 236 free(p); 237 238 break; 239 } 240 case UT_Enumerated: { 241 int num; 242 243 ret = der_get_integer (buf, length, &num, NULL); 244 if (ret) 245 errx (1, "der_get_enum: %s", error_message (ret)); 246 247 printf("%u\n", num); 248 break; 249 } 250 default : 251 printf ("%lu bytes\n", (unsigned long)length); 252 break; 253 } 254 } 255 if (end_tag) { 256 if (loop_length == 0) 257 errx(1, "zero length INDEFINITE data ? indent = %d\n", 258 indent / 2); 259 if (loop_length < length) 260 length = loop_length; 261 if (indefinite_form_loop == 0) 262 errx(1, "internal error in indefinite form loop detection"); 263 indefinite_form_loop--; 264 } else if (loop_length) 265 errx(1, "internal error for INDEFINITE form"); 266 buf += length; 267 len -= length; 268 } 269 return 0; 270 } 271 272 static int 273 doit (const char *filename) 274 { 275 int fd = open (filename, O_RDONLY); 276 struct stat sb; 277 unsigned char *buf; 278 size_t len; 279 int ret; 280 281 if(fd < 0) 282 err (1, "opening %s for read", filename); 283 if (fstat (fd, &sb) < 0) 284 err (1, "stat %s", filename); 285 len = sb.st_size; 286 buf = emalloc (len); 287 if (read (fd, buf, len) != len) 288 errx (1, "read failed"); 289 close (fd); 290 ret = loop (buf, len, 0); 291 free (buf); 292 return ret; 293 } 294 295 296 static int version_flag; 297 static int help_flag; 298 struct getargs args[] = { 299 { "indent", 0, arg_negative_flag, &indent_flag }, 300 { "version", 0, arg_flag, &version_flag }, 301 { "help", 0, arg_flag, &help_flag } 302 }; 303 int num_args = sizeof(args) / sizeof(args[0]); 304 305 static void 306 usage(int code) 307 { 308 arg_printusage(args, num_args, NULL, "dump-file"); 309 exit(code); 310 } 311 312 int 313 main(int argc, char **argv) 314 { 315 int optidx = 0; 316 317 setprogname (argv[0]); 318 initialize_asn1_error_table (); 319 if(getarg(args, num_args, argc, argv, &optidx)) 320 usage(1); 321 if(help_flag) 322 usage(0); 323 if(version_flag) { 324 print_version(NULL); 325 exit(0); 326 } 327 argv += optidx; 328 argc -= optidx; 329 if (argc != 1) 330 usage (1); 331 return doit (argv[0]); 332 } 333