Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
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"
7 #ifdef __sun
8 extern int fprintf(FILE *strm, const char *format, .../* args */);
9 extern int fflush(FILE *stream);
10 #endif
12 #define RIGHT_MARGIN 24
13 /*#define RAW_BYTES 1 */
15 static int prettyColumn = 0;
17 static int
18 getInteger256(const unsigned char *data, unsigned int nb)
19 {
20 int val;
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 }
40 return val;
41 }
43 static int
44 prettyNewline(FILE *out)
45 {
46 int rv;
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 }
59 static int
60 prettyIndent(FILE *out, unsigned level)
61 {
62 unsigned int i;
63 int rv;
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 }
76 return 0;
77 }
79 static int
80 prettyPrintByte(FILE *out, unsigned char item, unsigned int level)
81 {
82 int rv;
84 rv = prettyIndent(out, level);
85 if (rv < 0)
86 return rv;
88 rv = fprintf(out, "%02x ", item);
89 if (rv < 0) {
90 PORT_SetError(SEC_ERROR_IO);
91 return rv;
92 }
94 prettyColumn++;
95 if (prettyColumn >= RIGHT_MARGIN) {
96 return prettyNewline(out);
97 }
99 return 0;
100 }
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;
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 }
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;
125 if (len >= BUF_SIZE)
126 len = BUF_SIZE - 1;
128 rv = prettyNewline(out);
129 if (rv < 0)
130 return rv;
132 rv = prettyIndent(out, level);
133 if (rv < 0)
134 return rv;
136 memcpy(buf, str, len);
137 buf[len] = '\000';
139 rv = fprintf(out, "\"%s\"", buf);
140 if (rv < 0) {
141 PORT_SetError(SEC_ERROR_IO);
142 return rv;
143 }
145 return 0;
146 #undef BUF_SIZE
147 }
149 static int
150 prettyPrintString(FILE *out, const unsigned char *str,
151 unsigned int len, unsigned int level, PRBool raw)
152 {
153 int rv;
155 rv = prettyPrintStringStart(out, str, len, level);
156 if (rv < 0)
157 return rv;
159 rv = prettyNewline(out);
160 if (rv < 0)
161 return rv;
163 if (raw) {
164 rv = prettyPrintLeaf(out, str, len, level);
165 if (rv < 0)
166 return rv;
167 }
169 return 0;
170 }
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;
179 rv = prettyPrintStringStart(out, str, len, level);
180 if (rv < 0)
181 return rv;
183 time_item.data = (unsigned char *)str;
184 time_item.len = len;
186 rv = fprintf(out, " (");
187 if (rv < 0) {
188 PORT_SetError(SEC_ERROR_IO);
189 return rv;
190 }
192 if (utc)
193 SECU_PrintUTCTime(out, &time_item, NULL, 0);
194 else
195 SECU_PrintGeneralizedTime(out, &time_item, NULL, 0);
197 rv = fprintf(out, ")");
198 if (rv < 0) {
199 PORT_SetError(SEC_ERROR_IO);
200 return rv;
201 }
203 rv = prettyNewline(out);
204 if (rv < 0)
205 return rv;
207 if (raw) {
208 rv = prettyPrintLeaf(out, str, len, level);
209 if (rv < 0)
210 return rv;
211 }
213 return 0;
214 }
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;
227 /*
228 * First print the Object Id in numeric format
229 */
231 rv = prettyIndent(out, level);
232 if (rv < 0)
233 return rv;
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 }
244 val = 0;
245 for (i = 1; i < len; ++i) {
246 unsigned long j;
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 }
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 }
274 rv = prettyIndent(out, level);
275 if (rv < 0)
276 return rv;
278 rv = fprintf(out, "(%s)", oiddata->desc);
279 if (rv < 0) {
280 PORT_SetError(SEC_ERROR_IO);
281 return rv;
282 }
283 }
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 }
295 for (i = 0; i < len; i++) {
296 rv = prettyPrintByte(out, *data++, level);
297 if (rv < 0)
298 return rv;
299 }
300 }
302 return prettyNewline(out);
303 }
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 };
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;
347 if (src >= end) {
348 PORT_SetError(SEC_ERROR_BAD_DER);
349 return -1;
350 }
352 code = *src;
353 tagnum = code & SEC_ASN1_TAGNUM_MASK;
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 }
363 if (raw)
364 rv = prettyPrintByte(out, code, level);
365 else
366 rv = prettyIndent(out, level);
368 if (rv < 0)
369 return rv;
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 }
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 }
394 if (rv < 0) {
395 PORT_SetError(SEC_ERROR_IO);
396 return rv;
397 }
399 *codep = code;
401 return 1;
402 }
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;
412 if (data >= end) {
413 PORT_SetError(SEC_ERROR_BAD_DER);
414 return -1;
415 }
417 rv = fprintf(out, " ");
418 if (rv < 0) {
419 PORT_SetError(SEC_ERROR_IO);
420 return rv;
421 }
423 *indefinitep = PR_FALSE;
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;
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;
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 }
478 prettyColumn = -1;
479 return lenLen;
480 }
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;
491 while (data < end) {
492 unsigned char code;
493 PRBool indefinite;
495 slen = prettyPrintTag(out, data, end, &code, lv, raw);
496 if (slen < 0)
497 return slen;
498 data += slen;
500 lenLen = prettyPrintLength(out, data, end, &slen, &indefinite, lv, raw);
501 if (lenLen < 0)
502 return lenLen;
503 data += lenLen;
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 }
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 }
572 rv = prettyNewline(out);
573 if (rv < 0)
574 return rv;
576 return data - orig;
577 }
579 SECStatus
580 DER_PrettyPrint(FILE *out, const SECItem *it, PRBool raw)
581 {
582 int rv;
584 prettyColumn = -1;
586 rv = prettyPrintItem(out, it->data, it->data + it->len, 0, raw);
587 if (rv < 0)
588 return SECFailure;
589 return SECSuccess;
590 }