security/nss/cmd/lib/derprint.c

branch
TOR_BUG_9701
changeset 3
141e0f1194b1
equal deleted inserted replaced
-1:000000000000 0:205bd6a5edbc
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 #include "secutil.h"
5 #include "secoid.h"
6
7 #ifdef __sun
8 extern int fprintf(FILE *strm, const char *format, .../* args */);
9 extern int fflush(FILE *stream);
10 #endif
11
12 #define RIGHT_MARGIN 24
13 /*#define RAW_BYTES 1 */
14
15 static int prettyColumn = 0;
16
17 static int
18 getInteger256(const unsigned char *data, unsigned int nb)
19 {
20 int val;
21
22 switch (nb) {
23 case 1:
24 val = data[0];
25 break;
26 case 2:
27 val = (data[0] << 8) | data[1];
28 break;
29 case 3:
30 val = (data[0] << 16) | (data[1] << 8) | data[2];
31 break;
32 case 4:
33 val = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
34 break;
35 default:
36 PORT_SetError(SEC_ERROR_BAD_DER);
37 return -1;
38 }
39
40 return val;
41 }
42
43 static int
44 prettyNewline(FILE *out)
45 {
46 int rv;
47
48 if (prettyColumn != -1) {
49 rv = fprintf(out, "\n");
50 prettyColumn = -1;
51 if (rv < 0) {
52 PORT_SetError(SEC_ERROR_IO);
53 return rv;
54 }
55 }
56 return 0;
57 }
58
59 static int
60 prettyIndent(FILE *out, unsigned level)
61 {
62 unsigned int i;
63 int rv;
64
65 if (prettyColumn == -1) {
66 prettyColumn = level;
67 for (i = 0; i < level; i++) {
68 rv = fprintf(out, " ");
69 if (rv < 0) {
70 PORT_SetError(SEC_ERROR_IO);
71 return rv;
72 }
73 }
74 }
75
76 return 0;
77 }
78
79 static int
80 prettyPrintByte(FILE *out, unsigned char item, unsigned int level)
81 {
82 int rv;
83
84 rv = prettyIndent(out, level);
85 if (rv < 0)
86 return rv;
87
88 rv = fprintf(out, "%02x ", item);
89 if (rv < 0) {
90 PORT_SetError(SEC_ERROR_IO);
91 return rv;
92 }
93
94 prettyColumn++;
95 if (prettyColumn >= RIGHT_MARGIN) {
96 return prettyNewline(out);
97 }
98
99 return 0;
100 }
101
102 static int
103 prettyPrintLeaf(FILE *out, const unsigned char *data,
104 unsigned int len, unsigned int lv)
105 {
106 unsigned int i;
107 int rv;
108
109 for (i = 0; i < len; i++) {
110 rv = prettyPrintByte(out, *data++, lv);
111 if (rv < 0)
112 return rv;
113 }
114 return prettyNewline(out);
115 }
116
117 static int
118 prettyPrintStringStart(FILE *out, const unsigned char *str,
119 unsigned int len, unsigned int level)
120 {
121 #define BUF_SIZE 100
122 unsigned char buf[BUF_SIZE];
123 int rv;
124
125 if (len >= BUF_SIZE)
126 len = BUF_SIZE - 1;
127
128 rv = prettyNewline(out);
129 if (rv < 0)
130 return rv;
131
132 rv = prettyIndent(out, level);
133 if (rv < 0)
134 return rv;
135
136 memcpy(buf, str, len);
137 buf[len] = '\000';
138
139 rv = fprintf(out, "\"%s\"", buf);
140 if (rv < 0) {
141 PORT_SetError(SEC_ERROR_IO);
142 return rv;
143 }
144
145 return 0;
146 #undef BUF_SIZE
147 }
148
149 static int
150 prettyPrintString(FILE *out, const unsigned char *str,
151 unsigned int len, unsigned int level, PRBool raw)
152 {
153 int rv;
154
155 rv = prettyPrintStringStart(out, str, len, level);
156 if (rv < 0)
157 return rv;
158
159 rv = prettyNewline(out);
160 if (rv < 0)
161 return rv;
162
163 if (raw) {
164 rv = prettyPrintLeaf(out, str, len, level);
165 if (rv < 0)
166 return rv;
167 }
168
169 return 0;
170 }
171
172 static int
173 prettyPrintTime(FILE *out, const unsigned char *str,
174 unsigned int len, unsigned int level, PRBool raw, PRBool utc)
175 {
176 SECItem time_item;
177 int rv;
178
179 rv = prettyPrintStringStart(out, str, len, level);
180 if (rv < 0)
181 return rv;
182
183 time_item.data = (unsigned char *)str;
184 time_item.len = len;
185
186 rv = fprintf(out, " (");
187 if (rv < 0) {
188 PORT_SetError(SEC_ERROR_IO);
189 return rv;
190 }
191
192 if (utc)
193 SECU_PrintUTCTime(out, &time_item, NULL, 0);
194 else
195 SECU_PrintGeneralizedTime(out, &time_item, NULL, 0);
196
197 rv = fprintf(out, ")");
198 if (rv < 0) {
199 PORT_SetError(SEC_ERROR_IO);
200 return rv;
201 }
202
203 rv = prettyNewline(out);
204 if (rv < 0)
205 return rv;
206
207 if (raw) {
208 rv = prettyPrintLeaf(out, str, len, level);
209 if (rv < 0)
210 return rv;
211 }
212
213 return 0;
214 }
215
216 static int
217 prettyPrintObjectID(FILE *out, const unsigned char *data,
218 unsigned int len, unsigned int level, PRBool raw)
219 {
220 SECOidData *oiddata;
221 SECItem oiditem;
222 unsigned int i;
223 unsigned long val;
224 int rv;
225
226
227 /*
228 * First print the Object Id in numeric format
229 */
230
231 rv = prettyIndent(out, level);
232 if (rv < 0)
233 return rv;
234
235 val = data[0];
236 i = val % 40;
237 val = val / 40;
238 rv = fprintf(out, "%lu %u ", val, i);
239 if (rv < 0) {
240 PORT_SetError(SEC_ERROR_IO);
241 return rv;
242 }
243
244 val = 0;
245 for (i = 1; i < len; ++i) {
246 unsigned long j;
247
248 j = data[i];
249 val = (val << 7) | (j & 0x7f);
250 if (j & 0x80)
251 continue;
252 rv = fprintf(out, "%lu ", val);
253 if (rv < 0) {
254 PORT_SetError(SEC_ERROR_IO);
255 return rv;
256 }
257 val = 0;
258 }
259
260 /*
261 * Now try to look it up and print a symbolic version.
262 */
263 oiditem.data = (unsigned char *)data;
264 oiditem.len = len;
265 oiddata = SECOID_FindOID(&oiditem);
266 if (oiddata != NULL) {
267 i = PORT_Strlen(oiddata->desc);
268 if ((prettyColumn + 1 + (i / 3)) > RIGHT_MARGIN) {
269 rv = prettyNewline(out);
270 if (rv < 0)
271 return rv;
272 }
273
274 rv = prettyIndent(out, level);
275 if (rv < 0)
276 return rv;
277
278 rv = fprintf(out, "(%s)", oiddata->desc);
279 if (rv < 0) {
280 PORT_SetError(SEC_ERROR_IO);
281 return rv;
282 }
283 }
284
285 /*
286 * Finally, on a new line, print the raw bytes (if requested).
287 */
288 if (raw) {
289 rv = prettyNewline(out);
290 if (rv < 0) {
291 PORT_SetError(SEC_ERROR_IO);
292 return rv;
293 }
294
295 for (i = 0; i < len; i++) {
296 rv = prettyPrintByte(out, *data++, level);
297 if (rv < 0)
298 return rv;
299 }
300 }
301
302 return prettyNewline(out);
303 }
304
305 static char *prettyTagType [32] = {
306 "End of Contents",
307 "Boolean",
308 "Integer",
309 "Bit String",
310 "Octet String",
311 "NULL",
312 "Object Identifier",
313 "0x07",
314 "0x08",
315 "0x09",
316 "Enumerated",
317 "0x0B",
318 "UTF8 String",
319 "0x0D",
320 "0x0E",
321 "0x0F",
322 "Sequence",
323 "Set",
324 "0x12",
325 "Printable String",
326 "T61 String",
327 "0x15",
328 "IA5 String",
329 "UTC Time",
330 "Generalized Time",
331 "0x19",
332 "Visible String",
333 "0x1B",
334 "Universal String",
335 "0x1D",
336 "BMP String",
337 "High-Tag-Number"
338 };
339
340 static int
341 prettyPrintTag(FILE *out, const unsigned char *src, const unsigned char *end,
342 unsigned char *codep, unsigned int level, PRBool raw)
343 {
344 int rv;
345 unsigned char code, tagnum;
346
347 if (src >= end) {
348 PORT_SetError(SEC_ERROR_BAD_DER);
349 return -1;
350 }
351
352 code = *src;
353 tagnum = code & SEC_ASN1_TAGNUM_MASK;
354
355 /*
356 * NOTE: This code does not (yet) handle the high-tag-number form!
357 */
358 if (tagnum == SEC_ASN1_HIGH_TAG_NUMBER) {
359 PORT_SetError(SEC_ERROR_BAD_DER);
360 return -1;
361 }
362
363 if (raw)
364 rv = prettyPrintByte(out, code, level);
365 else
366 rv = prettyIndent(out, level);
367
368 if (rv < 0)
369 return rv;
370
371 if (code & SEC_ASN1_CONSTRUCTED) {
372 rv = fprintf(out, "C-");
373 if (rv < 0) {
374 PORT_SetError(SEC_ERROR_IO);
375 return rv;
376 }
377 }
378
379 switch (code & SEC_ASN1_CLASS_MASK) {
380 case SEC_ASN1_UNIVERSAL:
381 rv = fprintf(out, "%s ", prettyTagType[tagnum]);
382 break;
383 case SEC_ASN1_APPLICATION:
384 rv = fprintf(out, "Application: %d ", tagnum);
385 break;
386 case SEC_ASN1_CONTEXT_SPECIFIC:
387 rv = fprintf(out, "[%d] ", tagnum);
388 break;
389 case SEC_ASN1_PRIVATE:
390 rv = fprintf(out, "Private: %d ", tagnum);
391 break;
392 }
393
394 if (rv < 0) {
395 PORT_SetError(SEC_ERROR_IO);
396 return rv;
397 }
398
399 *codep = code;
400
401 return 1;
402 }
403
404 static int
405 prettyPrintLength(FILE *out, const unsigned char *data, const unsigned char *end,
406 int *lenp, PRBool *indefinitep, unsigned int lv, PRBool raw)
407 {
408 unsigned char lbyte;
409 int lenLen;
410 int rv;
411
412 if (data >= end) {
413 PORT_SetError(SEC_ERROR_BAD_DER);
414 return -1;
415 }
416
417 rv = fprintf(out, " ");
418 if (rv < 0) {
419 PORT_SetError(SEC_ERROR_IO);
420 return rv;
421 }
422
423 *indefinitep = PR_FALSE;
424
425 lbyte = *data++;
426 if (lbyte >= 0x80) {
427 /* Multibyte length */
428 unsigned nb = (unsigned) (lbyte & 0x7f);
429 if (nb > 4) {
430 PORT_SetError(SEC_ERROR_BAD_DER);
431 return -1;
432 }
433 if (nb > 0) {
434 int il;
435
436 if ((data + nb) > end) {
437 PORT_SetError(SEC_ERROR_BAD_DER);
438 return -1;
439 }
440 il = getInteger256(data, nb);
441 if (il < 0) return -1;
442 *lenp = (unsigned) il;
443 } else {
444 *lenp = 0;
445 *indefinitep = PR_TRUE;
446 }
447 lenLen = nb + 1;
448 if (raw) {
449 int i;
450
451 rv = prettyPrintByte(out, lbyte, lv);
452 if (rv < 0)
453 return rv;
454 for (i = 0; i < nb; i++) {
455 rv = prettyPrintByte(out, data[i], lv);
456 if (rv < 0)
457 return rv;
458 }
459 }
460 } else {
461 *lenp = lbyte;
462 lenLen = 1;
463 if (raw) {
464 rv = prettyPrintByte(out, lbyte, lv);
465 if (rv < 0)
466 return rv;
467 }
468 }
469 if (*indefinitep)
470 rv = fprintf(out, "(indefinite)\n");
471 else
472 rv = fprintf(out, "(%d)\n", *lenp);
473 if (rv < 0) {
474 PORT_SetError(SEC_ERROR_IO);
475 return rv;
476 }
477
478 prettyColumn = -1;
479 return lenLen;
480 }
481
482 static int
483 prettyPrintItem(FILE *out, const unsigned char *data, const unsigned char *end,
484 unsigned int lv, PRBool raw)
485 {
486 int slen;
487 int lenLen;
488 const unsigned char *orig = data;
489 int rv;
490
491 while (data < end) {
492 unsigned char code;
493 PRBool indefinite;
494
495 slen = prettyPrintTag(out, data, end, &code, lv, raw);
496 if (slen < 0)
497 return slen;
498 data += slen;
499
500 lenLen = prettyPrintLength(out, data, end, &slen, &indefinite, lv, raw);
501 if (lenLen < 0)
502 return lenLen;
503 data += lenLen;
504
505 /*
506 * Just quit now if slen more bytes puts us off the end.
507 */
508 if ((data + slen) > end) {
509 PORT_SetError(SEC_ERROR_BAD_DER);
510 return -1;
511 }
512
513 if (code & SEC_ASN1_CONSTRUCTED) {
514 if (slen > 0 || indefinite) {
515 slen = prettyPrintItem(out, data,
516 slen == 0 ? end : data + slen,
517 lv+1, raw);
518 if (slen < 0)
519 return slen;
520 data += slen;
521 }
522 } else if (code == 0) {
523 if (slen != 0 || lenLen != 1) {
524 PORT_SetError(SEC_ERROR_BAD_DER);
525 return -1;
526 }
527 break;
528 } else {
529 switch (code) {
530 case SEC_ASN1_PRINTABLE_STRING:
531 case SEC_ASN1_IA5_STRING:
532 case SEC_ASN1_VISIBLE_STRING:
533 rv = prettyPrintString(out, data, slen, lv+1, raw);
534 if (rv < 0)
535 return rv;
536 break;
537 case SEC_ASN1_UTC_TIME:
538 rv = prettyPrintTime(out, data, slen, lv+1, raw, PR_TRUE);
539 if (rv < 0)
540 return rv;
541 break;
542 case SEC_ASN1_GENERALIZED_TIME:
543 rv = prettyPrintTime(out, data, slen, lv+1, raw, PR_FALSE);
544 if (rv < 0)
545 return rv;
546 break;
547 case SEC_ASN1_OBJECT_ID:
548 rv = prettyPrintObjectID(out, data, slen, lv+1, raw);
549 if (rv < 0)
550 return rv;
551 break;
552 case SEC_ASN1_BOOLEAN: /* could do nicer job */
553 case SEC_ASN1_INTEGER: /* could do nicer job */
554 case SEC_ASN1_BIT_STRING: /* could do nicer job */
555 case SEC_ASN1_OCTET_STRING:
556 case SEC_ASN1_NULL:
557 case SEC_ASN1_ENUMERATED: /* could do nicer job, as INTEGER */
558 case SEC_ASN1_UTF8_STRING:
559 case SEC_ASN1_T61_STRING: /* print as printable string? */
560 case SEC_ASN1_UNIVERSAL_STRING:
561 case SEC_ASN1_BMP_STRING:
562 default:
563 rv = prettyPrintLeaf(out, data, slen, lv+1);
564 if (rv < 0)
565 return rv;
566 break;
567 }
568 data += slen;
569 }
570 }
571
572 rv = prettyNewline(out);
573 if (rv < 0)
574 return rv;
575
576 return data - orig;
577 }
578
579 SECStatus
580 DER_PrettyPrint(FILE *out, const SECItem *it, PRBool raw)
581 {
582 int rv;
583
584 prettyColumn = -1;
585
586 rv = prettyPrintItem(out, it->data, it->data + it->len, 0, raw);
587 if (rv < 0)
588 return SECFailure;
589 return SECSuccess;
590 }

mercurial