Import 1.9b4 NSS tag from cvs
[mozilla-nss.git] / security / nss / cmd / lib / derprint.c
blob50c6d02e6b21478e28055bb97da7d747a7bc7528
1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
12 * License.
14 * The Original Code is the Netscape security libraries.
16 * The Initial Developer of the Original Code is
17 * Netscape Communications Corporation.
18 * Portions created by the Initial Developer are Copyright (C) 1994-2000
19 * the Initial Developer. All Rights Reserved.
21 * Contributor(s):
23 * Alternatively, the contents of this file may be used under the terms of
24 * either the GNU General Public License Version 2 or later (the "GPL"), or
25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 * in which case the provisions of the GPL or the LGPL are applicable instead
27 * of those above. If you wish to allow use of your version of this file only
28 * under the terms of either the GPL or the LGPL, and not to allow others to
29 * use your version of this file under the terms of the MPL, indicate your
30 * decision by deleting the provisions above and replace them with the notice
31 * and other provisions required by the GPL or the LGPL. If you do not delete
32 * the provisions above, a recipient may use your version of this file under
33 * the terms of any one of the MPL, the GPL or the LGPL.
35 * ***** END LICENSE BLOCK ***** */
36 #include "secutil.h"
37 #include "secoid.h"
39 #ifdef __sun
40 extern int fprintf(FILE *strm, const char *format, .../* args */);
41 extern int fflush(FILE *stream);
42 #endif
44 #define RIGHT_MARGIN 24
45 /*#define RAW_BYTES 1 */
47 static int prettyColumn = 0;
49 static int
50 getInteger256(unsigned char *data, unsigned int nb)
52 int val;
54 switch (nb) {
55 case 1:
56 val = data[0];
57 break;
58 case 2:
59 val = (data[0] << 8) | data[1];
60 break;
61 case 3:
62 val = (data[0] << 16) | (data[1] << 8) | data[2];
63 break;
64 case 4:
65 val = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
66 break;
67 default:
68 PORT_SetError(SEC_ERROR_BAD_DER);
69 return -1;
72 return val;
75 static int
76 prettyNewline(FILE *out)
78 int rv;
80 if (prettyColumn != -1) {
81 rv = fprintf(out, "\n");
82 prettyColumn = -1;
83 if (rv < 0) {
84 PORT_SetError(SEC_ERROR_IO);
85 return rv;
88 return 0;
91 static int
92 prettyIndent(FILE *out, unsigned level)
94 unsigned int i;
95 int rv;
97 if (prettyColumn == -1) {
98 prettyColumn = level;
99 for (i = 0; i < level; i++) {
100 rv = fprintf(out, " ");
101 if (rv < 0) {
102 PORT_SetError(SEC_ERROR_IO);
103 return rv;
108 return 0;
111 static int
112 prettyPrintByte(FILE *out, unsigned char item, unsigned int level)
114 int rv;
116 rv = prettyIndent(out, level);
117 if (rv < 0)
118 return rv;
120 rv = fprintf(out, "%02x ", item);
121 if (rv < 0) {
122 PORT_SetError(SEC_ERROR_IO);
123 return rv;
126 prettyColumn++;
127 if (prettyColumn >= RIGHT_MARGIN) {
128 return prettyNewline(out);
131 return 0;
134 static int
135 prettyPrintLeaf(FILE *out, unsigned char *data,
136 unsigned int len, unsigned int lv)
138 unsigned int i;
139 int rv;
141 for (i = 0; i < len; i++) {
142 rv = prettyPrintByte(out, *data++, lv);
143 if (rv < 0)
144 return rv;
146 return prettyNewline(out);
149 static int
150 prettyPrintStringStart(FILE *out, unsigned char *str,
151 unsigned int len, unsigned int level)
153 #define BUF_SIZE 100
154 unsigned char buf[BUF_SIZE];
155 int rv;
157 if (len >= BUF_SIZE)
158 len = BUF_SIZE - 1;
160 rv = prettyNewline(out);
161 if (rv < 0)
162 return rv;
164 rv = prettyIndent(out, level);
165 if (rv < 0)
166 return rv;
168 memcpy(buf, str, len);
169 buf[len] = '\000';
171 rv = fprintf(out, "\"%s\"", buf);
172 if (rv < 0) {
173 PORT_SetError(SEC_ERROR_IO);
174 return rv;
177 return 0;
178 #undef BUF_SIZE
181 static int
182 prettyPrintString(FILE *out, unsigned char *str,
183 unsigned int len, unsigned int level, PRBool raw)
185 int rv;
187 rv = prettyPrintStringStart(out, str, len, level);
188 if (rv < 0)
189 return rv;
191 rv = prettyNewline(out);
192 if (rv < 0)
193 return rv;
195 if (raw) {
196 rv = prettyPrintLeaf(out, str, len, level);
197 if (rv < 0)
198 return rv;
201 return 0;
204 static int
205 prettyPrintTime(FILE *out, unsigned char *str,
206 unsigned int len, unsigned int level, PRBool raw, PRBool utc)
208 SECItem time_item;
209 int rv;
211 rv = prettyPrintStringStart(out, str, len, level);
212 if (rv < 0)
213 return rv;
215 time_item.data = str;
216 time_item.len = len;
218 rv = fprintf(out, " (");
219 if (rv < 0) {
220 PORT_SetError(SEC_ERROR_IO);
221 return rv;
224 if (utc)
225 SECU_PrintUTCTime(out, &time_item, NULL, 0);
226 else
227 SECU_PrintGeneralizedTime(out, &time_item, NULL, 0);
229 rv = fprintf(out, ")");
230 if (rv < 0) {
231 PORT_SetError(SEC_ERROR_IO);
232 return rv;
235 rv = prettyNewline(out);
236 if (rv < 0)
237 return rv;
239 if (raw) {
240 rv = prettyPrintLeaf(out, str, len, level);
241 if (rv < 0)
242 return rv;
245 return 0;
248 static int
249 prettyPrintObjectID(FILE *out, unsigned char *data,
250 unsigned int len, unsigned int level, PRBool raw)
252 SECOidData *oiddata;
253 SECItem oiditem;
254 unsigned int i;
255 unsigned long val;
256 int rv;
260 * First print the Object Id in numeric format
263 rv = prettyIndent(out, level);
264 if (rv < 0)
265 return rv;
267 val = data[0];
268 i = val % 40;
269 val = val / 40;
270 rv = fprintf(out, "%lu %u ", val, i);
271 if (rv < 0) {
272 PORT_SetError(SEC_ERROR_IO);
273 return rv;
276 val = 0;
277 for (i = 1; i < len; ++i) {
278 unsigned long j;
280 j = data[i];
281 val = (val << 7) | (j & 0x7f);
282 if (j & 0x80)
283 continue;
284 rv = fprintf(out, "%lu ", val);
285 if (rv < 0) {
286 PORT_SetError(SEC_ERROR_IO);
287 return rv;
289 val = 0;
293 * Now try to look it up and print a symbolic version.
295 oiditem.data = data;
296 oiditem.len = len;
297 oiddata = SECOID_FindOID(&oiditem);
298 if (oiddata != NULL) {
299 i = PORT_Strlen(oiddata->desc);
300 if ((prettyColumn + 1 + (i / 3)) > RIGHT_MARGIN) {
301 rv = prettyNewline(out);
302 if (rv < 0)
303 return rv;
306 rv = prettyIndent(out, level);
307 if (rv < 0)
308 return rv;
310 rv = fprintf(out, "(%s)", oiddata->desc);
311 if (rv < 0) {
312 PORT_SetError(SEC_ERROR_IO);
313 return rv;
318 * Finally, on a new line, print the raw bytes (if requested).
320 if (raw) {
321 rv = prettyNewline(out);
322 if (rv < 0) {
323 PORT_SetError(SEC_ERROR_IO);
324 return rv;
327 for (i = 0; i < len; i++) {
328 rv = prettyPrintByte(out, *data++, level);
329 if (rv < 0)
330 return rv;
334 return prettyNewline(out);
337 static char *prettyTagType [32] = {
338 "End of Contents",
339 "Boolean",
340 "Integer",
341 "Bit String",
342 "Octet String",
343 "NULL",
344 "Object Identifier",
345 "0x07",
346 "0x08",
347 "0x09",
348 "Enumerated",
349 "0x0B",
350 "UTF8 String",
351 "0x0D",
352 "0x0E",
353 "0x0F",
354 "Sequence",
355 "Set",
356 "0x12",
357 "Printable String",
358 "T61 String",
359 "0x15",
360 "IA5 String",
361 "UTC Time",
362 "Generalized Time",
363 "0x19",
364 "Visible String",
365 "0x1B",
366 "Universal String",
367 "0x1D",
368 "BMP String",
369 "High-Tag-Number"
372 static int
373 prettyPrintTag(FILE *out, unsigned char *src, unsigned char *end,
374 unsigned char *codep, unsigned int level, PRBool raw)
376 int rv;
377 unsigned char code, tagnum;
379 if (src >= end) {
380 PORT_SetError(SEC_ERROR_BAD_DER);
381 return -1;
384 code = *src;
385 tagnum = code & SEC_ASN1_TAGNUM_MASK;
388 * NOTE: This code does not (yet) handle the high-tag-number form!
390 if (tagnum == SEC_ASN1_HIGH_TAG_NUMBER) {
391 PORT_SetError(SEC_ERROR_BAD_DER);
392 return -1;
395 if (raw)
396 rv = prettyPrintByte(out, code, level);
397 else
398 rv = prettyIndent(out, level);
400 if (rv < 0)
401 return rv;
403 if (code & SEC_ASN1_CONSTRUCTED) {
404 rv = fprintf(out, "C-");
405 if (rv < 0) {
406 PORT_SetError(SEC_ERROR_IO);
407 return rv;
411 switch (code & SEC_ASN1_CLASS_MASK) {
412 case SEC_ASN1_UNIVERSAL:
413 rv = fprintf(out, "%s ", prettyTagType[tagnum]);
414 break;
415 case SEC_ASN1_APPLICATION:
416 rv = fprintf(out, "Application: %d ", tagnum);
417 break;
418 case SEC_ASN1_CONTEXT_SPECIFIC:
419 rv = fprintf(out, "[%d] ", tagnum);
420 break;
421 case SEC_ASN1_PRIVATE:
422 rv = fprintf(out, "Private: %d ", tagnum);
423 break;
426 if (rv < 0) {
427 PORT_SetError(SEC_ERROR_IO);
428 return rv;
431 *codep = code;
433 return 1;
436 static int
437 prettyPrintLength(FILE *out, unsigned char *data, unsigned char *end,
438 int *lenp, PRBool *indefinitep, unsigned int lv, PRBool raw)
440 unsigned char lbyte;
441 int lenLen;
442 int rv;
444 if (data >= end) {
445 PORT_SetError(SEC_ERROR_BAD_DER);
446 return -1;
449 rv = fprintf(out, " ");
450 if (rv < 0) {
451 PORT_SetError(SEC_ERROR_IO);
452 return rv;
455 *indefinitep = PR_FALSE;
457 lbyte = *data++;
458 if (lbyte >= 0x80) {
459 /* Multibyte length */
460 unsigned nb = (unsigned) (lbyte & 0x7f);
461 if (nb > 4) {
462 PORT_SetError(SEC_ERROR_BAD_DER);
463 return -1;
465 if (nb > 0) {
466 int il;
468 if ((data + nb) > end) {
469 PORT_SetError(SEC_ERROR_BAD_DER);
470 return -1;
472 il = getInteger256(data, nb);
473 if (il < 0) return -1;
474 *lenp = (unsigned) il;
475 } else {
476 *lenp = 0;
477 *indefinitep = PR_TRUE;
479 lenLen = nb + 1;
480 if (raw) {
481 int i;
483 rv = prettyPrintByte(out, lbyte, lv);
484 if (rv < 0)
485 return rv;
486 for (i = 0; i < nb; i++) {
487 rv = prettyPrintByte(out, data[i], lv);
488 if (rv < 0)
489 return rv;
492 } else {
493 *lenp = lbyte;
494 lenLen = 1;
495 if (raw) {
496 rv = prettyPrintByte(out, lbyte, lv);
497 if (rv < 0)
498 return rv;
501 if (*indefinitep)
502 rv = fprintf(out, "(indefinite)\n");
503 else
504 rv = fprintf(out, "(%d)\n", *lenp);
505 if (rv < 0) {
506 PORT_SetError(SEC_ERROR_IO);
507 return rv;
510 prettyColumn = -1;
511 return lenLen;
514 static int
515 prettyPrintItem(FILE *out, unsigned char *data, unsigned char *end,
516 unsigned int lv, PRBool raw)
518 int slen;
519 int lenLen;
520 unsigned char *orig = data;
521 int rv;
523 while (data < end) {
524 unsigned char code;
525 PRBool indefinite;
527 slen = prettyPrintTag(out, data, end, &code, lv, raw);
528 if (slen < 0)
529 return slen;
530 data += slen;
532 lenLen = prettyPrintLength(out, data, end, &slen, &indefinite, lv, raw);
533 if (lenLen < 0)
534 return lenLen;
535 data += lenLen;
538 * Just quit now if slen more bytes puts us off the end.
540 if ((data + slen) > end) {
541 PORT_SetError(SEC_ERROR_BAD_DER);
542 return -1;
545 if (code & SEC_ASN1_CONSTRUCTED) {
546 if (slen > 0 || indefinite) {
547 slen = prettyPrintItem(out, data,
548 slen == 0 ? end : data + slen,
549 lv+1, raw);
550 if (slen < 0)
551 return slen;
552 data += slen;
554 } else if (code == 0) {
555 if (slen != 0 || lenLen != 1) {
556 PORT_SetError(SEC_ERROR_BAD_DER);
557 return -1;
559 break;
560 } else {
561 switch (code) {
562 case SEC_ASN1_PRINTABLE_STRING:
563 case SEC_ASN1_IA5_STRING:
564 case SEC_ASN1_VISIBLE_STRING:
565 rv = prettyPrintString(out, data, slen, lv+1, raw);
566 if (rv < 0)
567 return rv;
568 break;
569 case SEC_ASN1_UTC_TIME:
570 rv = prettyPrintTime(out, data, slen, lv+1, raw, PR_TRUE);
571 if (rv < 0)
572 return rv;
573 break;
574 case SEC_ASN1_GENERALIZED_TIME:
575 rv = prettyPrintTime(out, data, slen, lv+1, raw, PR_FALSE);
576 if (rv < 0)
577 return rv;
578 break;
579 case SEC_ASN1_OBJECT_ID:
580 rv = prettyPrintObjectID(out, data, slen, lv+1, raw);
581 if (rv < 0)
582 return rv;
583 break;
584 case SEC_ASN1_BOOLEAN: /* could do nicer job */
585 case SEC_ASN1_INTEGER: /* could do nicer job */
586 case SEC_ASN1_BIT_STRING: /* could do nicer job */
587 case SEC_ASN1_OCTET_STRING:
588 case SEC_ASN1_NULL:
589 case SEC_ASN1_ENUMERATED: /* could do nicer job, as INTEGER */
590 case SEC_ASN1_UTF8_STRING:
591 case SEC_ASN1_T61_STRING: /* print as printable string? */
592 case SEC_ASN1_UNIVERSAL_STRING:
593 case SEC_ASN1_BMP_STRING:
594 default:
595 rv = prettyPrintLeaf(out, data, slen, lv+1);
596 if (rv < 0)
597 return rv;
598 break;
600 data += slen;
604 rv = prettyNewline(out);
605 if (rv < 0)
606 return rv;
608 return data - orig;
611 SECStatus
612 DER_PrettyPrint(FILE *out, SECItem *it, PRBool raw)
614 int rv;
616 prettyColumn = -1;
618 rv = prettyPrintItem(out, it->data, it->data + it->len, 0, raw);
619 if (rv < 0)
620 return SECFailure;
621 return SECSuccess;