security/nss/cmd/lib/derprint.c

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

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.

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

mercurial