secutil.c (148107B)
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 /* 5 ** secutil.c - various functions used by security stuff 6 ** 7 */ 8 9 #include "prtypes.h" 10 #include "prtime.h" 11 #include "prlong.h" 12 #include "prerror.h" 13 #include "prprf.h" 14 #include "plgetopt.h" 15 #include "prenv.h" 16 #include "prnetdb.h" 17 18 #include "cryptohi.h" 19 #include "secutil.h" 20 #include "secpkcs7.h" 21 #include "secpkcs5.h" 22 #include <stdarg.h> 23 #include <stdio.h> 24 #include <sys/stat.h> 25 #include <errno.h> 26 #include <limits.h> 27 28 #ifdef XP_UNIX 29 #include <unistd.h> 30 #endif 31 32 /* for SEC_TraverseNames */ 33 #include "cert.h" 34 #include "certt.h" 35 #include "certdb.h" 36 37 #include "secmod.h" 38 #include "pk11func.h" 39 #include "secoid.h" 40 41 static char consoleName[] = { 42 #ifdef XP_UNIX 43 "/dev/tty" 44 #else 45 "CON:" 46 #endif 47 }; 48 49 #include "cert.h" 50 #include "nssutil.h" 51 #include "ssl.h" 52 #include "sslproto.h" 53 #include "xconst.h" 54 55 #define DEFN_EXTEN_EXT_VALUE_ENCODER(mmm) \ 56 SECStatus EXTEN_EXT_VALUE_ENCODER_##mmm(PLArenaPool *extHandleArena, \ 57 void *value, SECItem *encodedValue) \ 58 { \ 59 return mmm(extHandleArena, value, encodedValue); \ 60 } 61 62 DEFN_EXTEN_EXT_VALUE_ENCODER(CERT_EncodeAltNameExtension) 63 DEFN_EXTEN_EXT_VALUE_ENCODER(CERT_EncodeAuthKeyID) 64 DEFN_EXTEN_EXT_VALUE_ENCODER(CERT_EncodeBasicConstraintValue) 65 DEFN_EXTEN_EXT_VALUE_ENCODER(CERT_EncodeCRLDistributionPoints) 66 DEFN_EXTEN_EXT_VALUE_ENCODER(CERT_EncodeCertPoliciesExtension) 67 DEFN_EXTEN_EXT_VALUE_ENCODER(CERT_EncodeInfoAccessExtension) 68 DEFN_EXTEN_EXT_VALUE_ENCODER(CERT_EncodeInhibitAnyExtension) 69 DEFN_EXTEN_EXT_VALUE_ENCODER(CERT_EncodeNameConstraintsExtension) 70 DEFN_EXTEN_EXT_VALUE_ENCODER(CERT_EncodePolicyConstraintsExtension) 71 DEFN_EXTEN_EXT_VALUE_ENCODER(CERT_EncodePolicyMappingExtension) 72 DEFN_EXTEN_EXT_VALUE_ENCODER(CERT_EncodeSubjectKeyID) 73 74 static PRBool utf8DisplayEnabled = PR_FALSE; 75 76 /* The minimum password/pin length (in Unicode characters) in FIPS mode, 77 * defined in lib/softoken/pkcs11i.h. */ 78 #define FIPS_MIN_PIN 7 79 80 void 81 SECU_EnableUtf8Display(PRBool enable) 82 { 83 utf8DisplayEnabled = enable; 84 } 85 86 PRBool 87 SECU_GetUtf8DisplayEnabled(void) 88 { 89 return utf8DisplayEnabled; 90 } 91 92 static void 93 secu_ClearPassword(char *p) 94 { 95 if (p) { 96 PORT_Memset(p, 0, PORT_Strlen(p)); 97 PORT_Free(p); 98 } 99 } 100 101 char * 102 SECU_GetPasswordString(void *arg, char *prompt) 103 { 104 #ifndef _WINDOWS 105 char *p = NULL; 106 FILE *input, *output; 107 108 /* open terminal */ 109 input = fopen(consoleName, "r"); 110 if (input == NULL) { 111 fprintf(stderr, "Error opening input terminal for read\n"); 112 return NULL; 113 } 114 115 output = fopen(consoleName, "w"); 116 if (output == NULL) { 117 fprintf(stderr, "Error opening output terminal for write\n"); 118 fclose(input); 119 return NULL; 120 } 121 122 p = SEC_GetPassword(input, output, prompt, SEC_BlindCheckPassword); 123 124 fclose(input); 125 fclose(output); 126 127 return p; 128 129 #else 130 /* Win32 version of above. opening the console may fail 131 on windows95, and certainly isn't necessary.. */ 132 133 char *p = NULL; 134 135 p = SEC_GetPassword(stdin, stdout, prompt, SEC_BlindCheckPassword); 136 return p; 137 138 #endif 139 } 140 141 /* 142 * p a s s w o r d _ h a r d c o d e 143 * 144 * A function to use the password passed in the -f(pwfile) argument 145 * of the command line. 146 * After use once, null it out otherwise PKCS11 calls us forever.? 147 * 148 */ 149 char * 150 SECU_FilePasswd(PK11SlotInfo *slot, PRBool retry, void *arg) 151 { 152 char *phrases, *phrase; 153 PRFileDesc *fd; 154 PRInt32 nb; 155 char *pwFile = arg; 156 int i; 157 const long maxPwdFileSize = 4096; 158 char *tokenName = NULL; 159 int tokenLen = 0; 160 161 if (!pwFile) 162 return 0; 163 164 if (retry) { 165 return 0; /* no good retrying - the files contents will be the same */ 166 } 167 168 phrases = PORT_ZAlloc(maxPwdFileSize); 169 170 if (!phrases) { 171 return 0; /* out of memory */ 172 } 173 174 fd = PR_Open(pwFile, PR_RDONLY, 0); 175 if (!fd) { 176 fprintf(stderr, "No password file \"%s\" exists.\n", pwFile); 177 PORT_Free(phrases); 178 return NULL; 179 } 180 181 nb = PR_Read(fd, phrases, maxPwdFileSize); 182 183 PR_Close(fd); 184 185 if (nb == 0) { 186 fprintf(stderr, "password file contains no data\n"); 187 PORT_Free(phrases); 188 return NULL; 189 } 190 191 if (slot) { 192 tokenName = PK11_GetTokenName(slot); 193 if (tokenName) { 194 tokenLen = PORT_Strlen(tokenName); 195 } 196 } 197 i = 0; 198 do { 199 int startphrase = i; 200 int phraseLen; 201 202 /* handle the Windows EOL case */ 203 while (phrases[i] != '\r' && phrases[i] != '\n' && i < nb) 204 i++; 205 /* terminate passphrase */ 206 phrases[i++] = '\0'; 207 /* clean up any EOL before the start of the next passphrase */ 208 while ((i < nb) && (phrases[i] == '\r' || phrases[i] == '\n')) { 209 phrases[i++] = '\0'; 210 } 211 /* now analyze the current passphrase */ 212 phrase = &phrases[startphrase]; 213 if (!tokenName) 214 break; 215 if (PORT_Strncmp(phrase, tokenName, tokenLen)) 216 continue; 217 phraseLen = PORT_Strlen(phrase); 218 if (phraseLen < (tokenLen + 1)) 219 continue; 220 if (phrase[tokenLen] != ':') 221 continue; 222 phrase = &phrase[tokenLen + 1]; 223 break; 224 225 } while (i < nb); 226 227 phrase = PORT_Strdup((char *)phrase); 228 PORT_Free(phrases); 229 return phrase; 230 } 231 232 char * 233 SECU_GetModulePassword(PK11SlotInfo *slot, PRBool retry, void *arg) 234 { 235 char prompt[255]; 236 secuPWData *pwdata = (secuPWData *)arg; 237 secuPWData pwnull = { PW_NONE, 0 }; 238 secuPWData pwxtrn = { PW_EXTERNAL, "external" }; 239 240 if (pwdata == NULL) 241 pwdata = &pwnull; 242 243 if (PK11_ProtectedAuthenticationPath(slot)) { 244 pwdata = &pwxtrn; 245 } 246 if (retry && pwdata->source != PW_NONE) { 247 PR_fprintf(PR_STDERR, "Incorrect password/PIN entered.\n"); 248 return NULL; 249 } 250 251 switch (pwdata->source) { 252 case PW_NONE: 253 snprintf(prompt, sizeof(prompt), "Enter Password or Pin for \"%s\":", 254 PK11_GetTokenName(slot)); 255 return SECU_GetPasswordString(NULL, prompt); 256 case PW_FROMFILE: 257 return SECU_FilePasswd(slot, retry, pwdata->data); 258 case PW_EXTERNAL: 259 snprintf(prompt, sizeof(prompt), 260 "Press Enter, then enter PIN for \"%s\" on external device.\n", 261 PK11_GetTokenName(slot)); 262 char *pw = SECU_GetPasswordString(NULL, prompt); 263 PORT_Free(pw); 264 /* Fall Through */ 265 case PW_PLAINTEXT: 266 return PL_strdup(pwdata->data); 267 default: 268 break; 269 } 270 271 PR_fprintf(PR_STDERR, "Password check failed: No password found.\n"); 272 return NULL; 273 } 274 275 char * 276 secu_InitSlotPassword(PK11SlotInfo *slot, PRBool retry, void *arg) 277 { 278 char *p0 = NULL; 279 char *p1 = NULL; 280 FILE *input, *output; 281 secuPWData *pwdata = arg; 282 283 if (pwdata->source == PW_FROMFILE) { 284 return SECU_FilePasswd(slot, retry, pwdata->data); 285 } 286 if (pwdata->source == PW_PLAINTEXT) { 287 return PL_strdup(pwdata->data); 288 } 289 290 /* PW_NONE - get it from tty */ 291 /* open terminal */ 292 #ifdef _WINDOWS 293 input = stdin; 294 #else 295 input = fopen(consoleName, "r"); 296 #endif 297 if (input == NULL) { 298 PR_fprintf(PR_STDERR, "Error opening input terminal for read\n"); 299 return NULL; 300 } 301 302 /* we have no password, so initialize database with one */ 303 if (PK11_IsFIPS()) { 304 PR_fprintf(PR_STDERR, 305 "Enter a password which will be used to encrypt your keys.\n" 306 "The password should be at least %d characters long,\n" 307 "and should consist of at least three character classes.\n" 308 "The available character classes are: digits (0-9), ASCII\n" 309 "lowercase letters, ASCII uppercase letters, ASCII\n" 310 "non-alphanumeric characters, and non-ASCII characters.\n\n" 311 "If an ASCII uppercase letter appears at the beginning of\n" 312 "the password, it is not counted toward its character class.\n" 313 "Similarly, if a digit appears at the end of the password,\n" 314 "it is not counted toward its character class.\n\n", 315 FIPS_MIN_PIN); 316 } else { 317 PR_fprintf(PR_STDERR, 318 "Enter a password which will be used to encrypt your keys.\n" 319 "The password should be at least 8 characters long,\n" 320 "and should contain at least one non-alphabetic character.\n\n"); 321 } 322 323 output = fopen(consoleName, "w"); 324 if (output == NULL) { 325 PR_fprintf(PR_STDERR, "Error opening output terminal for write\n"); 326 #ifndef _WINDOWS 327 fclose(input); 328 #endif 329 return NULL; 330 } 331 332 for (;;) { 333 if (p0) 334 PORT_Free(p0); 335 p0 = SEC_GetPassword(input, output, "Enter new password: ", 336 SEC_BlindCheckPassword); 337 338 if (p1) 339 PORT_Free(p1); 340 p1 = SEC_GetPassword(input, output, "Re-enter password: ", 341 SEC_BlindCheckPassword); 342 if (p0 && p1 && !PORT_Strcmp(p0, p1)) { 343 break; 344 } 345 PR_fprintf(PR_STDERR, "Passwords do not match. Try again.\n"); 346 } 347 348 /* clear out the duplicate password string */ 349 secu_ClearPassword(p1); 350 351 fclose(input); 352 fclose(output); 353 354 return p0; 355 } 356 357 SECStatus 358 SECU_ChangePW(PK11SlotInfo *slot, char *passwd, char *pwFile) 359 { 360 return SECU_ChangePW2(slot, passwd, 0, pwFile, 0); 361 } 362 363 SECStatus 364 SECU_ChangePW2(PK11SlotInfo *slot, char *oldPass, char *newPass, 365 char *oldPwFile, char *newPwFile) 366 { 367 SECStatus rv; 368 secuPWData pwdata, newpwdata; 369 char *oldpw = NULL, *newpw = NULL; 370 371 if (oldPass) { 372 pwdata.source = PW_PLAINTEXT; 373 pwdata.data = oldPass; 374 } else if (oldPwFile) { 375 pwdata.source = PW_FROMFILE; 376 pwdata.data = oldPwFile; 377 } else { 378 pwdata.source = PW_NONE; 379 pwdata.data = NULL; 380 } 381 382 if (newPass) { 383 newpwdata.source = PW_PLAINTEXT; 384 newpwdata.data = newPass; 385 } else if (newPwFile) { 386 newpwdata.source = PW_FROMFILE; 387 newpwdata.data = newPwFile; 388 } else { 389 newpwdata.source = PW_NONE; 390 newpwdata.data = NULL; 391 } 392 393 if (PK11_NeedUserInit(slot)) { 394 newpw = secu_InitSlotPassword(slot, PR_FALSE, &pwdata); 395 rv = PK11_InitPin(slot, (char *)NULL, newpw); 396 goto done; 397 } 398 399 for (;;) { 400 oldpw = SECU_GetModulePassword(slot, PR_FALSE, &pwdata); 401 402 if (PK11_CheckUserPassword(slot, oldpw) != SECSuccess) { 403 if (pwdata.source == PW_NONE) { 404 PR_fprintf(PR_STDERR, "Invalid password. Try again.\n"); 405 } else { 406 PR_fprintf(PR_STDERR, "Invalid password.\n"); 407 PORT_Memset(oldpw, 0, PL_strlen(oldpw)); 408 PORT_Free(oldpw); 409 rv = SECFailure; 410 goto done; 411 } 412 } else 413 break; 414 415 PORT_Free(oldpw); 416 } 417 418 newpw = secu_InitSlotPassword(slot, PR_FALSE, &newpwdata); 419 420 rv = PK11_ChangePW(slot, oldpw, newpw); 421 if (rv != SECSuccess) { 422 PR_fprintf(PR_STDERR, "Failed to change password.\n"); 423 } else { 424 PR_fprintf(PR_STDOUT, "Password changed successfully.\n"); 425 } 426 427 PORT_Memset(oldpw, 0, PL_strlen(oldpw)); 428 PORT_Free(oldpw); 429 430 done: 431 if (newpw) { 432 PORT_Memset(newpw, 0, PL_strlen(newpw)); 433 PORT_Free(newpw); 434 } 435 return rv; 436 } 437 438 struct matchobj { 439 SECItem index; 440 char *nname; 441 PRBool found; 442 }; 443 444 char * 445 SECU_DefaultSSLDir(void) 446 { 447 char *dir; 448 static char sslDir[1000]; 449 450 dir = PR_GetEnvSecure("SSL_DIR"); 451 if (!dir) 452 return NULL; 453 454 if (strlen(dir) >= PR_ARRAY_SIZE(sslDir)) { 455 return NULL; 456 } 457 snprintf(sslDir, sizeof(sslDir), "%s", dir); 458 459 if (sslDir[strlen(sslDir) - 1] == '/') 460 sslDir[strlen(sslDir) - 1] = 0; 461 462 return sslDir; 463 } 464 465 char * 466 SECU_AppendFilenameToDir(char *dir, char *filename) 467 { 468 static char path[1000]; 469 470 if (dir[strlen(dir) - 1] == '/') 471 snprintf(path, sizeof(path), "%s%s", dir, filename); 472 else 473 snprintf(path, sizeof(path), "%s/%s", dir, filename); 474 return path; 475 } 476 477 char * 478 SECU_ConfigDirectory(const char *base) 479 { 480 static PRBool initted = PR_FALSE; 481 const char *dir = ".netscape"; 482 char *home; 483 static char buf[1000]; 484 485 if (initted) 486 return buf; 487 488 if (base == NULL || *base == 0) { 489 home = PR_GetEnvSecure("HOME"); 490 if (!home) 491 home = ""; 492 493 if (*home && home[strlen(home) - 1] == '/') 494 snprintf(buf, sizeof(buf), "%.900s%s", home, dir); 495 else 496 snprintf(buf, sizeof(buf), "%.900s/%s", home, dir); 497 } else { 498 snprintf(buf, sizeof(buf), "%.900s", base); 499 if (buf[strlen(buf) - 1] == '/') 500 buf[strlen(buf) - 1] = 0; 501 } 502 503 initted = PR_TRUE; 504 return buf; 505 } 506 507 SECStatus 508 SECU_ReadDERFromFile(SECItem *der, PRFileDesc *inFile, PRBool ascii, 509 PRBool warnOnPrivateKeyInAsciiFile) 510 { 511 SECStatus rv; 512 if (ascii) { 513 /* First convert ascii to binary */ 514 SECItem filedata; 515 516 /* Read in ascii data */ 517 rv = SECU_FileToItem(&filedata, inFile); 518 if (rv != SECSuccess) 519 return rv; 520 if (!filedata.data) { 521 fprintf(stderr, "unable to read data from input file\n"); 522 return SECFailure; 523 } 524 /* need one additional byte for zero terminator */ 525 rv = SECITEM_ReallocItemV2(NULL, &filedata, filedata.len + 1); 526 if (rv != SECSuccess) { 527 PORT_Free(filedata.data); 528 return rv; 529 } 530 char *asc = (char *)filedata.data; 531 asc[filedata.len - 1] = '\0'; 532 533 if (warnOnPrivateKeyInAsciiFile && strstr(asc, "PRIVATE KEY")) { 534 fprintf(stderr, "Warning: ignoring private key. Consider to use " 535 "pk12util.\n"); 536 } 537 538 char *body; 539 /* check for headers and trailers and remove them */ 540 if ((body = strstr(asc, "-----BEGIN")) != NULL) { 541 char *trailer = NULL; 542 asc = body; 543 body = PORT_Strchr(body, '\n'); 544 if (!body) 545 body = PORT_Strchr(asc, '\r'); /* maybe this is a MAC file */ 546 if (body) 547 trailer = strstr(++body, "-----END"); 548 if (trailer != NULL) { 549 *trailer = '\0'; 550 } else { 551 fprintf(stderr, "input has header but no trailer\n"); 552 PORT_Free(filedata.data); 553 return SECFailure; 554 } 555 } else { 556 body = asc; 557 } 558 559 /* Convert to binary */ 560 rv = ATOB_ConvertAsciiToItem(der, body); 561 if (rv != SECSuccess) { 562 fprintf(stderr, "error converting ascii to binary (%s)\n", 563 SECU_Strerror(PORT_GetError())); 564 PORT_Free(filedata.data); 565 return SECFailure; 566 } 567 568 PORT_Free(filedata.data); 569 } else { 570 /* Read in binary der */ 571 rv = SECU_FileToItem(der, inFile); 572 if (rv != SECSuccess) { 573 fprintf(stderr, "error converting der (%s)\n", 574 SECU_Strerror(PORT_GetError())); 575 return SECFailure; 576 } 577 } 578 return SECSuccess; 579 } 580 581 #define INDENT_MULT 4 582 583 /* 584 * remove the tag and length and just leave the bare BER data 585 */ 586 SECStatus 587 SECU_StripTagAndLength(SECItem *i) 588 { 589 unsigned int start; 590 PRBool isIndefinite; 591 592 if (!i || !i->data || i->len < 2) { /* must be at least tag and length */ 593 PORT_SetError(SEC_ERROR_BAD_DER); 594 return SECFailure; 595 } 596 isIndefinite = (i->data[1] == 0x80); 597 start = ((i->data[1] & 0x80) ? (i->data[1] & 0x7f) + 2 : 2); 598 if (i->len < start) { 599 PORT_SetError(SEC_ERROR_BAD_DER); 600 return SECFailure; 601 } 602 i->data += start; 603 i->len -= start; 604 /* we are using indefinite encoding, drop the trailing zero */ 605 if (isIndefinite) { 606 if (i->len <= 1) { 607 PORT_SetError(SEC_ERROR_BAD_DER); 608 return SECFailure; 609 } 610 /* verify tags are zero */ 611 if ((i->data[i->len - 1] != 0) || (i->data[i->len - 2] != 0)) { 612 PORT_SetError(SEC_ERROR_BAD_DER); 613 return SECFailure; 614 } 615 i->len -= 2; 616 } 617 618 return SECSuccess; 619 } 620 621 /* 622 * Create a new SECItem which points to the current BER tag and length with 623 * all it's data. For indefinite encoding, this will also include the trailing 624 * indefinite markers 625 * The 'in' item is advanced to point to the next BER tag. 626 * You don't want to use this in an actual BER/DER parser as NSS already 627 * has 3 to choose from) 628 */ 629 SECStatus 630 SECU_ExtractBERAndStep(SECItem *in, SECItem *out) 631 { 632 if (!in || !in->data || in->len < 2) { /* must be at least tag and length */ 633 PORT_SetError(SEC_ERROR_BAD_DER); 634 return SECFailure; 635 } 636 637 *out = *in; 638 639 /* first handle indefinite encoding */ 640 if (out->data[1] == 0x80) { 641 SECItem this = *out; 642 SECItem next; 643 this.data += 2; 644 this.len -= 2; 645 out->len = 2; 646 /* walk through all the entries until we find the '0' */ 647 while ((this.len >= 2) && (this.data[0] != 0)) { 648 SECStatus rv = SECU_ExtractBERAndStep(&this, &next); 649 if (rv != SECSuccess) { 650 return rv; 651 } 652 out->len += next.len; 653 } 654 if ((this.len < 2) || ((this.data[0] != 0) && (this.data[1] != 0))) { 655 PORT_SetError(SEC_ERROR_BAD_DER); 656 return SECFailure; 657 } 658 out->len += 2; /* include the trailing zeros */ 659 in->data += out->len; 660 in->len -= out->len; 661 return SECSuccess; 662 } 663 664 /* now handle normal DER encoding */ 665 if (out->data[1] & 0x80) { 666 unsigned int i; 667 unsigned int lenlen = out->data[1] & 0x7f; 668 unsigned int len = 0; 669 if (lenlen > sizeof out->len) { 670 PORT_SetError(SEC_ERROR_BAD_DER); 671 return SECFailure; 672 } 673 for (i = 0; i < lenlen; i++) { 674 len = (len << 8) | out->data[2 + i]; 675 } 676 out->len = len + lenlen + 2; 677 } else { 678 out->len = out->data[1] + 2; 679 } 680 if (out->len > in->len) { 681 /* we've ran into a truncated file */ 682 PORT_SetError(SEC_ERROR_BAD_DER); 683 return SECFailure; 684 } 685 in->data += out->len; 686 in->len -= out->len; 687 return SECSuccess; 688 } 689 690 static void 691 secu_PrintRawStringQuotesOptional(FILE *out, SECItem *si, const char *m, 692 int level, PRBool quotes) 693 { 694 int column; 695 unsigned int i; 696 697 if (m) { 698 SECU_Indent(out, level); 699 fprintf(out, "%s: ", m); 700 column = (level * INDENT_MULT) + strlen(m) + 2; 701 level++; 702 } else { 703 SECU_Indent(out, level); 704 column = level * INDENT_MULT; 705 } 706 if (quotes) { 707 fprintf(out, "\""); 708 column++; 709 } 710 711 for (i = 0; i < si->len; i++) { 712 unsigned char val = si->data[i]; 713 unsigned char c; 714 if (SECU_GetWrapEnabled() && column > 76) { 715 SECU_Newline(out); 716 SECU_Indent(out, level); 717 column = level * INDENT_MULT; 718 } 719 720 if (utf8DisplayEnabled) { 721 if (val < 32) 722 c = '.'; 723 else 724 c = val; 725 } else { 726 c = printable[val]; 727 } 728 fprintf(out, "%c", c); 729 column++; 730 } 731 732 if (quotes) { 733 fprintf(out, "\""); 734 column++; 735 } 736 if (SECU_GetWrapEnabled() && 737 (column != level * INDENT_MULT || column > 76)) { 738 SECU_Newline(out); 739 } 740 } 741 742 static void 743 secu_PrintRawString(FILE *out, SECItem *si, const char *m, int level) 744 { 745 secu_PrintRawStringQuotesOptional(out, si, m, level, PR_TRUE); 746 } 747 748 void 749 SECU_PrintString(FILE *out, const SECItem *si, const char *m, int level) 750 { 751 SECItem my = *si; 752 753 if (SECSuccess != SECU_StripTagAndLength(&my) || !my.len) 754 return; 755 secu_PrintRawString(out, &my, m, level); 756 } 757 758 /* print an unencoded boolean */ 759 static void 760 secu_PrintBoolean(FILE *out, SECItem *i, const char *m, int level) 761 { 762 int val = 0; 763 764 if (i->data && i->len) { 765 val = i->data[0]; 766 } 767 768 if (!m) { 769 m = "Boolean"; 770 } 771 SECU_Indent(out, level); 772 fprintf(out, "%s: %s\n", m, (val ? "True" : "False")); 773 } 774 775 /* 776 * Format and print "time". If the tag message "m" is not NULL, 777 * do indent formatting based on "level" and add a newline afterward; 778 * otherwise just print the formatted time string only. 779 */ 780 static void 781 secu_PrintTime(FILE *out, const PRTime time, const char *m, int level) 782 { 783 PRExplodedTime printableTime; 784 char *timeString; 785 786 /* Convert to local time */ 787 PR_ExplodeTime(time, PR_GMTParameters, &printableTime); 788 789 timeString = PORT_Alloc(256); 790 if (timeString == NULL) 791 return; 792 793 if (m != NULL) { 794 SECU_Indent(out, level); 795 fprintf(out, "%s: ", m); 796 } 797 798 if (PR_FormatTime(timeString, 256, "%a %b %d %H:%M:%S %Y", &printableTime)) { 799 fputs(timeString, out); 800 } 801 802 if (m != NULL) 803 fprintf(out, "\n"); 804 805 PORT_Free(timeString); 806 } 807 808 /* 809 * Format and print the UTC Time "t". If the tag message "m" is not NULL, 810 * do indent formatting based on "level" and add a newline afterward; 811 * otherwise just print the formatted time string only. 812 */ 813 void 814 SECU_PrintUTCTime(FILE *out, const SECItem *t, const char *m, int level) 815 { 816 PRTime time; 817 SECStatus rv; 818 819 rv = DER_UTCTimeToTime(&time, t); 820 if (rv != SECSuccess) 821 return; 822 823 secu_PrintTime(out, time, m, level); 824 } 825 826 /* 827 * Format and print the Generalized Time "t". If the tag message "m" 828 * is not NULL, * do indent formatting based on "level" and add a newline 829 * afterward; otherwise just print the formatted time string only. 830 */ 831 void 832 SECU_PrintGeneralizedTime(FILE *out, const SECItem *t, const char *m, int level) 833 { 834 PRTime time; 835 SECStatus rv; 836 837 rv = DER_GeneralizedTimeToTime(&time, t); 838 if (rv != SECSuccess) 839 return; 840 841 secu_PrintTime(out, time, m, level); 842 } 843 844 /* 845 * Format and print the UTC or Generalized Time "t". If the tag message 846 * "m" is not NULL, do indent formatting based on "level" and add a newline 847 * afterward; otherwise just print the formatted time string only. 848 */ 849 void 850 SECU_PrintTimeChoice(FILE *out, const SECItem *t, const char *m, int level) 851 { 852 switch (t->type) { 853 case siUTCTime: 854 SECU_PrintUTCTime(out, t, m, level); 855 break; 856 857 case siGeneralizedTime: 858 SECU_PrintGeneralizedTime(out, t, m, level); 859 break; 860 861 default: 862 PORT_Assert(0); 863 break; 864 } 865 } 866 867 /* This prints a SET or SEQUENCE */ 868 static void 869 SECU_PrintSet(FILE *out, const SECItem *t, const char *m, int level) 870 { 871 int type = t->data[0] & SEC_ASN1_TAGNUM_MASK; 872 int constructed = t->data[0] & SEC_ASN1_CONSTRUCTED; 873 const char *label; 874 SECItem my = *t; 875 876 if (!constructed) { 877 SECU_PrintAsHex(out, t, m, level); 878 return; 879 } 880 if (SECSuccess != SECU_StripTagAndLength(&my)) 881 return; 882 883 SECU_Indent(out, level); 884 if (m) { 885 fprintf(out, "%s: ", m); 886 } 887 888 if (type == SEC_ASN1_SET) 889 label = "Set "; 890 else if (type == SEC_ASN1_SEQUENCE) 891 label = "Sequence "; 892 else 893 label = ""; 894 fprintf(out, "%s{\n", label); /* } */ 895 896 while (my.len >= 2) { 897 SECItem tmp; 898 if (SECSuccess != SECU_ExtractBERAndStep(&my, &tmp)) { 899 break; 900 } 901 SECU_PrintAny(out, &tmp, NULL, level + 1); 902 } 903 SECU_Indent(out, level); 904 fprintf(out, /* { */ "}\n"); 905 } 906 907 static void 908 secu_PrintContextSpecific(FILE *out, const SECItem *i, const char *m, int level) 909 { 910 int type = i->data[0] & SEC_ASN1_TAGNUM_MASK; 911 int constructed = i->data[0] & SEC_ASN1_CONSTRUCTED; 912 SECItem tmp; 913 914 if (constructed) { 915 char *m2; 916 if (!m) 917 m2 = PR_smprintf("[%d]", type); 918 else 919 m2 = PR_smprintf("%s: [%d]", m, type); 920 if (m2) { 921 SECU_PrintSet(out, i, m2, level); 922 PR_smprintf_free(m2); 923 } 924 return; 925 } 926 927 SECU_Indent(out, level); 928 if (m) { 929 fprintf(out, "%s: ", m); 930 } 931 fprintf(out, "[%d]\n", type); 932 933 tmp = *i; 934 if (SECSuccess == SECU_StripTagAndLength(&tmp)) 935 SECU_PrintAsHex(out, &tmp, m, level + 1); 936 } 937 938 static void 939 secu_PrintOctetString(FILE *out, const SECItem *i, const char *m, int level) 940 { 941 SECItem tmp = *i; 942 if (SECSuccess == SECU_StripTagAndLength(&tmp)) 943 SECU_PrintAsHex(out, &tmp, m, level); 944 } 945 946 static void 947 secu_PrintBitString(FILE *out, const SECItem *i, const char *m, int level) 948 { 949 int unused_bits; 950 SECItem tmp = *i; 951 952 if (SECSuccess != SECU_StripTagAndLength(&tmp) || tmp.len < 2) 953 return; 954 955 unused_bits = *tmp.data++; 956 tmp.len--; 957 958 SECU_PrintAsHex(out, &tmp, m, level); 959 if (unused_bits) { 960 SECU_Indent(out, level + 1); 961 fprintf(out, "(%d least significant bits unused)\n", unused_bits); 962 } 963 } 964 965 /* in a decoded bit string, the len member is a bit length. */ 966 static void 967 secu_PrintDecodedBitString(FILE *out, const SECItem *i, const char *m, int level) 968 { 969 int unused_bits; 970 SECItem tmp = *i; 971 972 unused_bits = (tmp.len & 0x7) ? 8 - (tmp.len & 7) : 0; 973 DER_ConvertBitString(&tmp); /* convert length to byte length */ 974 975 SECU_PrintAsHex(out, &tmp, m, level); 976 if (unused_bits) { 977 SECU_Indent(out, level + 1); 978 fprintf(out, "(%d least significant bits unused)\n", unused_bits); 979 } 980 } 981 982 /* Print a DER encoded Boolean */ 983 void 984 SECU_PrintEncodedBoolean(FILE *out, const SECItem *i, const char *m, int level) 985 { 986 SECItem my = *i; 987 if (SECSuccess == SECU_StripTagAndLength(&my)) 988 secu_PrintBoolean(out, &my, m, level); 989 } 990 991 /* Print a DER encoded integer */ 992 void 993 SECU_PrintEncodedInteger(FILE *out, const SECItem *i, const char *m, int level) 994 { 995 SECItem my = *i; 996 if (SECSuccess == SECU_StripTagAndLength(&my)) 997 SECU_PrintInteger(out, &my, m, level); 998 } 999 1000 /* Print a DER encoded OID */ 1001 SECOidTag 1002 SECU_PrintEncodedObjectID(FILE *out, const SECItem *i, const char *m, int level) 1003 { 1004 SECItem my = *i; 1005 SECOidTag tag = SEC_OID_UNKNOWN; 1006 if (SECSuccess == SECU_StripTagAndLength(&my)) 1007 tag = SECU_PrintObjectID(out, &my, m, level); 1008 return tag; 1009 } 1010 1011 static void 1012 secu_PrintBMPString(FILE *out, const SECItem *i, const char *m, int level) 1013 { 1014 unsigned char *s; 1015 unsigned char *d; 1016 int len; 1017 SECItem tmp = { 0, 0, 0 }; 1018 SECItem my = *i; 1019 1020 if (SECSuccess != SECU_StripTagAndLength(&my)) 1021 goto loser; 1022 if (my.len % 2) 1023 goto loser; 1024 len = (int)(my.len / 2); 1025 tmp.data = (unsigned char *)PORT_Alloc(len); 1026 if (!tmp.data) 1027 goto loser; 1028 tmp.len = len; 1029 for (s = my.data, d = tmp.data; len > 0; len--) { 1030 PRUint32 bmpChar = (s[0] << 8) | s[1]; 1031 s += 2; 1032 if (!isprint(bmpChar)) 1033 goto loser; 1034 *d++ = (unsigned char)bmpChar; 1035 } 1036 secu_PrintRawString(out, &tmp, m, level); 1037 PORT_Free(tmp.data); 1038 return; 1039 1040 loser: 1041 SECU_PrintAsHex(out, i, m, level); 1042 if (tmp.data) 1043 PORT_Free(tmp.data); 1044 } 1045 1046 static void 1047 secu_PrintUniversalString(FILE *out, const SECItem *i, const char *m, int level) 1048 { 1049 unsigned char *s; 1050 unsigned char *d; 1051 int len; 1052 SECItem tmp = { 0, 0, 0 }; 1053 SECItem my = *i; 1054 1055 if (SECSuccess != SECU_StripTagAndLength(&my)) 1056 goto loser; 1057 if (my.len % 4) 1058 goto loser; 1059 len = (int)(my.len / 4); 1060 tmp.data = (unsigned char *)PORT_Alloc(len); 1061 if (!tmp.data) 1062 goto loser; 1063 tmp.len = len; 1064 for (s = my.data, d = tmp.data; len > 0; len--) { 1065 PRUint32 bmpChar = (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3]; 1066 s += 4; 1067 if (!isprint(bmpChar & 0xFF)) 1068 goto loser; 1069 *d++ = (unsigned char)bmpChar; 1070 } 1071 secu_PrintRawString(out, &tmp, m, level); 1072 PORT_Free(tmp.data); 1073 return; 1074 1075 loser: 1076 SECU_PrintAsHex(out, i, m, level); 1077 if (tmp.data) 1078 PORT_Free(tmp.data); 1079 } 1080 1081 static void 1082 secu_PrintUniversal(FILE *out, const SECItem *i, const char *m, int level) 1083 { 1084 switch (i->data[0] & SEC_ASN1_TAGNUM_MASK) { 1085 case SEC_ASN1_ENUMERATED: 1086 case SEC_ASN1_INTEGER: 1087 SECU_PrintEncodedInteger(out, i, m, level); 1088 break; 1089 case SEC_ASN1_OBJECT_ID: 1090 SECU_PrintEncodedObjectID(out, i, m, level); 1091 break; 1092 case SEC_ASN1_BOOLEAN: 1093 SECU_PrintEncodedBoolean(out, i, m, level); 1094 break; 1095 case SEC_ASN1_UTF8_STRING: 1096 case SEC_ASN1_PRINTABLE_STRING: 1097 case SEC_ASN1_VISIBLE_STRING: 1098 case SEC_ASN1_IA5_STRING: 1099 case SEC_ASN1_T61_STRING: 1100 SECU_PrintString(out, i, m, level); 1101 break; 1102 case SEC_ASN1_GENERALIZED_TIME: 1103 SECU_PrintGeneralizedTime(out, i, m, level); 1104 break; 1105 case SEC_ASN1_UTC_TIME: 1106 SECU_PrintUTCTime(out, i, m, level); 1107 break; 1108 case SEC_ASN1_NULL: 1109 SECU_Indent(out, level); 1110 if (m && m[0]) 1111 fprintf(out, "%s: NULL\n", m); 1112 else 1113 fprintf(out, "NULL\n"); 1114 break; 1115 case SEC_ASN1_SET: 1116 case SEC_ASN1_SEQUENCE: 1117 SECU_PrintSet(out, i, m, level); 1118 break; 1119 case SEC_ASN1_OCTET_STRING: 1120 secu_PrintOctetString(out, i, m, level); 1121 break; 1122 case SEC_ASN1_BIT_STRING: 1123 secu_PrintBitString(out, i, m, level); 1124 break; 1125 case SEC_ASN1_BMP_STRING: 1126 secu_PrintBMPString(out, i, m, level); 1127 break; 1128 case SEC_ASN1_UNIVERSAL_STRING: 1129 secu_PrintUniversalString(out, i, m, level); 1130 break; 1131 default: 1132 SECU_PrintAsHex(out, i, m, level); 1133 break; 1134 } 1135 } 1136 1137 void 1138 SECU_PrintAny(FILE *out, const SECItem *i, const char *m, int level) 1139 { 1140 if (i && i->len && i->data) { 1141 switch (i->data[0] & SEC_ASN1_CLASS_MASK) { 1142 case SEC_ASN1_CONTEXT_SPECIFIC: 1143 secu_PrintContextSpecific(out, i, m, level); 1144 break; 1145 case SEC_ASN1_UNIVERSAL: 1146 secu_PrintUniversal(out, i, m, level); 1147 break; 1148 default: 1149 SECU_PrintAsHex(out, i, m, level); 1150 break; 1151 } 1152 } 1153 } 1154 1155 static int 1156 secu_PrintValidity(FILE *out, CERTValidity *v, char *m, int level) 1157 { 1158 SECU_Indent(out, level); 1159 fprintf(out, "%s:\n", m); 1160 SECU_PrintTimeChoice(out, &v->notBefore, "Not Before", level + 1); 1161 SECU_PrintTimeChoice(out, &v->notAfter, "Not After ", level + 1); 1162 return 0; 1163 } 1164 1165 /* This function does NOT expect a DER type and length. */ 1166 SECOidTag 1167 SECU_PrintObjectID(FILE *out, const SECItem *oid, const char *m, int level) 1168 { 1169 SECOidData *oiddata; 1170 char *oidString = NULL; 1171 1172 oiddata = SECOID_FindOID(oid); 1173 if (oiddata != NULL) { 1174 const char *name = oiddata->desc; 1175 SECU_Indent(out, level); 1176 if (m != NULL) 1177 fprintf(out, "%s: ", m); 1178 fprintf(out, "%s\n", name); 1179 return oiddata->offset; 1180 } 1181 oidString = CERT_GetOidString(oid); 1182 if (oidString) { 1183 SECU_Indent(out, level); 1184 if (m != NULL) 1185 fprintf(out, "%s: ", m); 1186 fprintf(out, "%s\n", oidString); 1187 PR_smprintf_free(oidString); 1188 return SEC_OID_UNKNOWN; 1189 } 1190 SECU_PrintAsHex(out, oid, m, level); 1191 return SEC_OID_UNKNOWN; 1192 } 1193 1194 void 1195 SECU_PrintOidTag(FILE *out, SECOidTag tag, const char *m, int level) 1196 { 1197 const char *desc = SECOID_FindOIDTagDescription(tag); 1198 1199 if (desc == NULL) { 1200 desc = SECOID_FindOIDTagDescription(SEC_OID_UNKNOWN); 1201 } 1202 SECU_Indent(out, level); 1203 if (m != NULL) 1204 fprintf(out, "%s\n", m); 1205 fprintf(out, "%s\n", desc); 1206 } 1207 1208 typedef struct secuPBEParamsStr { 1209 SECItem salt; 1210 SECItem iterationCount; 1211 SECItem keyLength; 1212 SECAlgorithmID cipherAlg; 1213 SECAlgorithmID kdfAlg; 1214 } secuPBEParams; 1215 1216 SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate) 1217 1218 /* SECOID_PKCS5_PBKDF2 */ 1219 const SEC_ASN1Template secuKDF2Params[] = { 1220 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(secuPBEParams) }, 1221 { SEC_ASN1_OCTET_STRING, offsetof(secuPBEParams, salt) }, 1222 { SEC_ASN1_INTEGER, offsetof(secuPBEParams, iterationCount) }, 1223 { SEC_ASN1_INTEGER | SEC_ASN1_OPTIONAL, offsetof(secuPBEParams, keyLength) }, 1224 { SEC_ASN1_INLINE | SEC_ASN1_XTRN | SEC_ASN1_OPTIONAL, offsetof(secuPBEParams, kdfAlg), 1225 SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, 1226 { 0 } 1227 }; 1228 1229 /* PKCS5v1 & PKCS12 */ 1230 const SEC_ASN1Template secuPBEParamsTemp[] = { 1231 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(secuPBEParams) }, 1232 { SEC_ASN1_OCTET_STRING, offsetof(secuPBEParams, salt) }, 1233 { SEC_ASN1_INTEGER, offsetof(secuPBEParams, iterationCount) }, 1234 { 0 } 1235 }; 1236 1237 /* SEC_OID_PKCS5_PBES2, SEC_OID_PKCS5_PBMAC1 */ 1238 const SEC_ASN1Template secuPBEV2Params[] = { 1239 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(secuPBEParams) }, 1240 { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(secuPBEParams, kdfAlg), 1241 SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, 1242 { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(secuPBEParams, cipherAlg), 1243 SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, 1244 { 0 } 1245 }; 1246 1247 void 1248 secu_PrintRSAPSSParams(FILE *out, SECItem *value, char *m, int level) 1249 { 1250 PLArenaPool *pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1251 SECStatus rv; 1252 SECKEYRSAPSSParams param; 1253 SECAlgorithmID maskHashAlg; 1254 1255 if (m) { 1256 SECU_Indent(out, level); 1257 fprintf(out, "%s:\n", m); 1258 } 1259 1260 if (!pool) { 1261 SECU_Indent(out, level); 1262 fprintf(out, "Out of memory\n"); 1263 return; 1264 } 1265 1266 PORT_Memset(¶m, 0, sizeof param); 1267 1268 rv = SEC_QuickDERDecodeItem(pool, ¶m, 1269 SEC_ASN1_GET(SECKEY_RSAPSSParamsTemplate), 1270 value); 1271 if (rv == SECSuccess) { 1272 if (!param.hashAlg) { 1273 SECU_Indent(out, level + 1); 1274 fprintf(out, "Hash algorithm: default, SHA-1\n"); 1275 } else { 1276 SECU_PrintObjectID(out, ¶m.hashAlg->algorithm, 1277 "Hash algorithm", level + 1); 1278 } 1279 if (!param.maskAlg) { 1280 SECU_Indent(out, level + 1); 1281 fprintf(out, "Mask algorithm: default, MGF1\n"); 1282 SECU_Indent(out, level + 1); 1283 fprintf(out, "Mask hash algorithm: default, SHA-1\n"); 1284 } else { 1285 SECU_PrintObjectID(out, ¶m.maskAlg->algorithm, 1286 "Mask algorithm", level + 1); 1287 rv = SEC_QuickDERDecodeItem(pool, &maskHashAlg, 1288 SEC_ASN1_GET(SECOID_AlgorithmIDTemplate), 1289 ¶m.maskAlg->parameters); 1290 if (rv == SECSuccess) { 1291 SECU_PrintObjectID(out, &maskHashAlg.algorithm, 1292 "Mask hash algorithm", level + 1); 1293 } else { 1294 SECU_Indent(out, level + 1); 1295 fprintf(out, "Invalid mask generation algorithm parameters\n"); 1296 } 1297 } 1298 if (!param.saltLength.data) { 1299 SECU_Indent(out, level + 1); 1300 fprintf(out, "Salt length: default, %i (0x%2X)\n", 20, 20); 1301 } else { 1302 SECU_PrintInteger(out, ¶m.saltLength, "Salt length", level + 1); 1303 } 1304 } else { 1305 SECU_Indent(out, level + 1); 1306 fprintf(out, "Invalid RSA-PSS parameters\n"); 1307 } 1308 PORT_FreeArena(pool, PR_FALSE); 1309 } 1310 1311 void 1312 secu_PrintKDF2Params(FILE *out, SECItem *value, char *m, int level) 1313 { 1314 PLArenaPool *pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1315 SECStatus rv; 1316 secuPBEParams param; 1317 1318 if (m) { 1319 SECU_Indent(out, level); 1320 fprintf(out, "%s:\n", m); 1321 } 1322 1323 if (!pool) { 1324 SECU_Indent(out, level); 1325 fprintf(out, "Out of memory\n"); 1326 return; 1327 } 1328 1329 PORT_Memset(¶m, 0, sizeof param); 1330 rv = SEC_QuickDERDecodeItem(pool, ¶m, secuKDF2Params, value); 1331 if (rv == SECSuccess) { 1332 SECU_PrintAsHex(out, ¶m.salt, "Salt", level + 1); 1333 SECU_PrintInteger(out, ¶m.iterationCount, "Iteration Count", 1334 level + 1); 1335 if (param.keyLength.data != NULL) { 1336 SECU_PrintInteger(out, ¶m.keyLength, "Key Length", level + 1); 1337 } 1338 if (param.kdfAlg.algorithm.data != NULL) { 1339 SECU_PrintAlgorithmID(out, ¶m.kdfAlg, "KDF algorithm", level + 1); 1340 } else { 1341 SECU_Indent(out, level + 1); 1342 fprintf(out, "Implicit KDF Algorithm: HMAC-SHA-1\n"); 1343 } 1344 } 1345 PORT_FreeArena(pool, PR_FALSE); 1346 } 1347 1348 void 1349 secu_PrintPKCS5V2Params(FILE *out, SECItem *value, char *m, int level) 1350 { 1351 PLArenaPool *pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1352 SECStatus rv; 1353 secuPBEParams param; 1354 1355 if (m) { 1356 SECU_Indent(out, level); 1357 fprintf(out, "%s:\n", m); 1358 } 1359 1360 if (!pool) { 1361 SECU_Indent(out, level); 1362 fprintf(out, "Out of memory\n"); 1363 return; 1364 } 1365 1366 PORT_Memset(¶m, 0, sizeof param); 1367 rv = SEC_QuickDERDecodeItem(pool, ¶m, secuPBEV2Params, value); 1368 if (rv == SECSuccess) { 1369 SECU_PrintAlgorithmID(out, ¶m.kdfAlg, "KDF", level + 1); 1370 SECU_PrintAlgorithmID(out, ¶m.cipherAlg, "Cipher", level + 1); 1371 } 1372 PORT_FreeArena(pool, PR_FALSE); 1373 } 1374 1375 void 1376 secu_PrintPBEParams(FILE *out, SECItem *value, char *m, int level) 1377 { 1378 PLArenaPool *pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1379 SECStatus rv; 1380 secuPBEParams param; 1381 1382 if (m) { 1383 SECU_Indent(out, level); 1384 fprintf(out, "%s:\n", m); 1385 } 1386 1387 if (!pool) { 1388 SECU_Indent(out, level); 1389 fprintf(out, "Out of memory\n"); 1390 return; 1391 } 1392 1393 PORT_Memset(¶m, 0, sizeof(secuPBEParams)); 1394 rv = SEC_QuickDERDecodeItem(pool, ¶m, secuPBEParamsTemp, value); 1395 if (rv == SECSuccess) { 1396 SECU_PrintAsHex(out, ¶m.salt, "Salt", level + 1); 1397 SECU_PrintInteger(out, ¶m.iterationCount, "Iteration Count", 1398 level + 1); 1399 } 1400 PORT_FreeArena(pool, PR_FALSE); 1401 } 1402 1403 /* This function does NOT expect a DER type and length. */ 1404 void 1405 SECU_PrintAlgorithmID(FILE *out, SECAlgorithmID *a, char *m, int level) 1406 { 1407 SECOidTag algtag; 1408 SECU_PrintObjectID(out, &a->algorithm, m, level); 1409 1410 algtag = SECOID_GetAlgorithmTag(a); 1411 if (SEC_PKCS5IsAlgorithmPBEAlgTag(algtag)) { 1412 switch (algtag) { 1413 case SEC_OID_PKCS5_PBKDF2: 1414 secu_PrintKDF2Params(out, &a->parameters, "Parameters", level + 1); 1415 break; 1416 case SEC_OID_PKCS5_PBES2: 1417 secu_PrintPKCS5V2Params(out, &a->parameters, "Encryption", level + 1); 1418 break; 1419 case SEC_OID_PKCS5_PBMAC1: 1420 secu_PrintPKCS5V2Params(out, &a->parameters, "MAC", level + 1); 1421 break; 1422 default: 1423 secu_PrintPBEParams(out, &a->parameters, "Parameters", level + 1); 1424 break; 1425 } 1426 return; 1427 } 1428 1429 if (a->parameters.len == 0 || 1430 (a->parameters.len == 2 && 1431 PORT_Memcmp(a->parameters.data, "\005\000", 2) == 0)) { 1432 /* No arguments or NULL argument */ 1433 } else if (algtag == SEC_OID_PKCS1_RSA_PSS_SIGNATURE) { 1434 secu_PrintRSAPSSParams(out, &a->parameters, "Parameters", level + 1); 1435 } else { 1436 /* Print args to algorithm */ 1437 SECU_PrintAsHex(out, &a->parameters, "Args", level + 1); 1438 } 1439 } 1440 1441 static void 1442 secu_PrintAttribute(FILE *out, SEC_PKCS7Attribute *attr, char *m, int level) 1443 { 1444 SECItem *value; 1445 int i; 1446 char om[100]; 1447 1448 if (m) { 1449 SECU_Indent(out, level); 1450 fprintf(out, "%s:\n", m); 1451 } 1452 1453 /* 1454 * Should make this smarter; look at the type field and then decode 1455 * and print the value(s) appropriately! 1456 */ 1457 SECU_PrintObjectID(out, &(attr->type), "Type", level + 1); 1458 if (attr->values != NULL) { 1459 i = 0; 1460 while ((value = attr->values[i++]) != NULL) { 1461 snprintf(om, sizeof(om), "Value (%d)%s", i, attr->encoded ? " (encoded)" : ""); 1462 if (attr->encoded || attr->typeTag == NULL) { 1463 SECU_PrintAny(out, value, om, level + 1); 1464 } else { 1465 switch (attr->typeTag->offset) { 1466 default: 1467 SECU_PrintAsHex(out, value, om, level + 1); 1468 break; 1469 case SEC_OID_PKCS9_CONTENT_TYPE: 1470 SECU_PrintObjectID(out, value, om, level + 1); 1471 break; 1472 case SEC_OID_PKCS9_SIGNING_TIME: 1473 SECU_PrintTimeChoice(out, value, om, level + 1); 1474 break; 1475 } 1476 } 1477 } 1478 } 1479 } 1480 1481 static void 1482 secu_PrintECPublicKey(FILE *out, SECKEYPublicKey *pk, char *m, int level) 1483 { 1484 SECItem curveOID = { siBuffer, NULL, 0 }; 1485 1486 SECU_Indent(out, level); 1487 fprintf(out, "%s:\n", m); 1488 SECU_PrintInteger(out, &pk->u.ec.publicValue, "PublicValue", level + 1); 1489 /* For named curves, the DEREncodedParams field contains an 1490 * ASN Object ID (0x06 is SEC_ASN1_OBJECT_ID). 1491 */ 1492 if ((pk->u.ec.DEREncodedParams.len > 2) && 1493 (pk->u.ec.DEREncodedParams.data[0] == 0x06)) { 1494 curveOID.len = pk->u.ec.DEREncodedParams.data[1]; 1495 curveOID.data = pk->u.ec.DEREncodedParams.data + 2; 1496 curveOID.len = PR_MIN(curveOID.len, pk->u.ec.DEREncodedParams.len - 2); 1497 SECU_PrintObjectID(out, &curveOID, "Curve", level + 1); 1498 } 1499 } 1500 1501 void 1502 SECU_PrintRSAPublicKey(FILE *out, SECKEYPublicKey *pk, char *m, int level) 1503 { 1504 SECU_Indent(out, level); 1505 fprintf(out, "%s:\n", m); 1506 SECU_PrintInteger(out, &pk->u.rsa.modulus, "Modulus", level + 1); 1507 SECU_PrintInteger(out, &pk->u.rsa.publicExponent, "Exponent", level + 1); 1508 if (pk->u.rsa.publicExponent.len == 1 && 1509 pk->u.rsa.publicExponent.data[0] == 1) { 1510 SECU_Indent(out, level + 1); 1511 fprintf(out, "Error: INVALID RSA KEY!\n"); 1512 } 1513 } 1514 1515 void 1516 SECU_PrintDSAPublicKey(FILE *out, SECKEYPublicKey *pk, char *m, int level) 1517 { 1518 SECU_Indent(out, level); 1519 fprintf(out, "%s:\n", m); 1520 SECU_PrintInteger(out, &pk->u.dsa.params.prime, "Prime", level + 1); 1521 SECU_PrintInteger(out, &pk->u.dsa.params.subPrime, "Subprime", level + 1); 1522 SECU_PrintInteger(out, &pk->u.dsa.params.base, "Base", level + 1); 1523 SECU_PrintInteger(out, &pk->u.dsa.publicValue, "PublicValue", level + 1); 1524 } 1525 1526 void 1527 SECU_PrintMLDSAPublicKey(FILE *out, SECKEYPublicKey *pk, char *m, int level) 1528 { 1529 1530 SECU_Indent(out, level); 1531 fprintf(out, "%s:\n", m); 1532 1533 SECU_PrintOidTag(out, pk->u.mldsa.paramSet, "Parameter Set", level + 1); 1534 SECU_PrintInteger(out, &pk->u.mldsa.publicValue, "PublicValue", level + 1); 1535 } 1536 1537 static void 1538 secu_PrintSubjectPublicKeyInfo(FILE *out, PLArenaPool *arena, 1539 CERTSubjectPublicKeyInfo *i, char *msg, int level) 1540 { 1541 SECKEYPublicKey *pk; 1542 1543 SECU_Indent(out, level); 1544 fprintf(out, "%s:\n", msg); 1545 SECU_PrintAlgorithmID(out, &i->algorithm, "Public Key Algorithm", level + 1); 1546 1547 pk = SECKEY_ExtractPublicKey(i); 1548 if (pk) { 1549 switch (pk->keyType) { 1550 case rsaKey: 1551 SECU_PrintRSAPublicKey(out, pk, "RSA Public Key", level + 1); 1552 break; 1553 1554 case dsaKey: 1555 SECU_PrintDSAPublicKey(out, pk, "DSA Public Key", level + 1); 1556 break; 1557 1558 case ecKey: 1559 secu_PrintECPublicKey(out, pk, "EC Public Key", level + 1); 1560 break; 1561 1562 case mldsaKey: 1563 SECU_PrintMLDSAPublicKey(out, pk, "ML-DSA Public Key", level + 1); 1564 break; 1565 1566 case dhKey: 1567 case fortezzaKey: 1568 case keaKey: 1569 SECU_Indent(out, level); 1570 fprintf(out, "unable to format this SPKI algorithm type\n"); 1571 goto loser; 1572 default: 1573 SECU_Indent(out, level); 1574 fprintf(out, "unknown SPKI algorithm type\n"); 1575 goto loser; 1576 } 1577 PORT_FreeArena(pk->arena, PR_FALSE); 1578 } else { 1579 SECU_PrintErrMsg(out, level, "Error", "Parsing public key"); 1580 loser: 1581 if (i->subjectPublicKey.data) { 1582 SECItem tmp = i->subjectPublicKey; 1583 DER_ConvertBitString(&tmp); 1584 SECU_PrintAny(out, &tmp, "Raw", level); 1585 } 1586 } 1587 } 1588 1589 static void 1590 printStringWithoutCRLF(FILE *out, const char *str) 1591 { 1592 const char *c = str; 1593 while (*c) { 1594 if (*c != '\r' && *c != '\n') { 1595 fputc(*c, out); 1596 } 1597 ++c; 1598 } 1599 } 1600 1601 int 1602 SECU_PrintDumpDerIssuerAndSerial(FILE *out, const SECItem *der, const char *m, 1603 int level) 1604 { 1605 PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1606 CERTCertificate *c; 1607 int rv = SEC_ERROR_NO_MEMORY; 1608 char *derIssuerB64; 1609 char *derSerialB64; 1610 1611 if (!arena) 1612 return rv; 1613 1614 /* Decode certificate */ 1615 c = PORT_ArenaZNew(arena, CERTCertificate); 1616 if (!c) 1617 goto loser; 1618 c->arena = arena; 1619 rv = SEC_ASN1DecodeItem(arena, c, 1620 SEC_ASN1_GET(CERT_CertificateTemplate), der); 1621 if (rv) { 1622 SECU_PrintErrMsg(out, 0, "Error", "Parsing extension"); 1623 goto loser; 1624 } 1625 1626 SECU_PrintName(out, &c->subject, "Subject", 0); 1627 if (!SECU_GetWrapEnabled()) /*SECU_PrintName didn't add newline*/ 1628 SECU_Newline(out); 1629 SECU_PrintName(out, &c->issuer, "Issuer", 0); 1630 if (!SECU_GetWrapEnabled()) /*SECU_PrintName didn't add newline*/ 1631 SECU_Newline(out); 1632 SECU_PrintInteger(out, &c->serialNumber, "Serial Number", 0); 1633 1634 derIssuerB64 = BTOA_ConvertItemToAscii(&c->derIssuer); 1635 derSerialB64 = BTOA_ConvertItemToAscii(&c->serialNumber); 1636 1637 fprintf(out, "Issuer DER Base64:\n"); 1638 if (SECU_GetWrapEnabled()) { 1639 fprintf(out, "%s\n", derIssuerB64); 1640 } else { 1641 printStringWithoutCRLF(out, derIssuerB64); 1642 fputs("\n", out); 1643 } 1644 1645 fprintf(out, "Serial DER Base64:\n"); 1646 if (SECU_GetWrapEnabled()) { 1647 fprintf(out, "%s\n", derSerialB64); 1648 } else { 1649 printStringWithoutCRLF(out, derSerialB64); 1650 fputs("\n", out); 1651 } 1652 1653 PORT_Free(derIssuerB64); 1654 PORT_Free(derSerialB64); 1655 1656 fprintf(out, "Serial DER as C source: \n{ %d, \"", c->serialNumber.len); 1657 1658 { 1659 unsigned int i; 1660 for (i = 0; i < c->serialNumber.len; ++i) { 1661 unsigned char *chardata = (unsigned char *)(c->serialNumber.data); 1662 unsigned char ch = *(chardata + i); 1663 1664 fprintf(out, "\\x%02x", ch); 1665 } 1666 fprintf(out, "\" }\n"); 1667 } 1668 1669 loser: 1670 PORT_FreeArena(arena, PR_FALSE); 1671 return rv; 1672 } 1673 1674 static SECStatus 1675 secu_PrintX509InvalidDate(FILE *out, SECItem *value, char *msg, int level) 1676 { 1677 SECItem decodedValue; 1678 SECStatus rv; 1679 PRTime invalidTime; 1680 char *formattedTime = NULL; 1681 1682 decodedValue.data = NULL; 1683 rv = SEC_ASN1DecodeItem(NULL, &decodedValue, 1684 SEC_ASN1_GET(SEC_GeneralizedTimeTemplate), 1685 value); 1686 if (rv == SECSuccess) { 1687 rv = DER_GeneralizedTimeToTime(&invalidTime, &decodedValue); 1688 if (rv == SECSuccess) { 1689 formattedTime = CERT_GenTime2FormattedAscii(invalidTime, "%a %b %d %H:%M:%S %Y"); 1690 SECU_Indent(out, level + 1); 1691 fprintf(out, "%s: %s\n", msg, formattedTime); 1692 PORT_Free(formattedTime); 1693 } 1694 } 1695 PORT_Free(decodedValue.data); 1696 return (rv); 1697 } 1698 1699 static SECStatus 1700 PrintExtKeyUsageExtension(FILE *out, SECItem *value, char *msg, int level) 1701 { 1702 CERTOidSequence *os; 1703 SECItem **op; 1704 1705 os = CERT_DecodeOidSequence(value); 1706 if ((CERTOidSequence *)NULL == os) { 1707 return SECFailure; 1708 } 1709 1710 for (op = os->oids; *op; op++) { 1711 SECU_PrintObjectID(out, *op, msg, level + 1); 1712 } 1713 CERT_DestroyOidSequence(os); 1714 return SECSuccess; 1715 } 1716 1717 static SECStatus 1718 secu_PrintBasicConstraints(FILE *out, SECItem *value, char *msg, int level) 1719 { 1720 CERTBasicConstraints constraints; 1721 SECStatus rv; 1722 1723 SECU_Indent(out, level); 1724 if (msg) { 1725 fprintf(out, "%s: ", msg); 1726 } 1727 rv = CERT_DecodeBasicConstraintValue(&constraints, value); 1728 if (rv == SECSuccess && constraints.isCA) { 1729 if (constraints.pathLenConstraint >= 0) { 1730 fprintf(out, "Is a CA with a maximum path length of %d.\n", 1731 constraints.pathLenConstraint); 1732 } else { 1733 fprintf(out, "Is a CA with no maximum path length.\n"); 1734 } 1735 } else { 1736 fprintf(out, "Is not a CA.\n"); 1737 } 1738 return SECSuccess; 1739 } 1740 1741 static const char *const nsTypeBits[] = { 1742 "SSL Client", 1743 "SSL Server", 1744 "S/MIME", 1745 "Object Signing", 1746 "Reserved", 1747 "SSL CA", 1748 "S/MIME CA", 1749 "ObjectSigning CA" 1750 }; 1751 1752 /* NSCertType is merely a bit string whose bits are displayed symbolically */ 1753 static SECStatus 1754 secu_PrintNSCertType(FILE *out, SECItem *value, char *msg, int level) 1755 { 1756 int unused; 1757 int NS_Type; 1758 int i; 1759 int found = 0; 1760 SECItem my = *value; 1761 1762 if ((my.data[0] != SEC_ASN1_BIT_STRING) || 1763 SECSuccess != SECU_StripTagAndLength(&my)) { 1764 SECU_PrintAny(out, value, "Data", level); 1765 return SECSuccess; 1766 } 1767 1768 unused = (my.len == 2) ? (my.data[0] & 0x0f) : 0; 1769 NS_Type = my.data[1] & (0xff << unused); 1770 1771 SECU_Indent(out, level); 1772 if (msg) { 1773 fprintf(out, "%s: ", msg); 1774 } else { 1775 fprintf(out, "Netscape Certificate Type: "); 1776 } 1777 for (i = 0; i < 8; i++) { 1778 if ((0x80 >> i) & NS_Type) { 1779 fprintf(out, "%c%s", (found ? ',' : '<'), nsTypeBits[i]); 1780 found = 1; 1781 } 1782 } 1783 fprintf(out, (found ? ">\n" : "none\n")); 1784 return SECSuccess; 1785 } 1786 1787 static const char *const usageBits[] = { 1788 "Digital Signature", /* 0x80 */ 1789 "Non-Repudiation", /* 0x40 */ 1790 "Key Encipherment", /* 0x20 */ 1791 "Data Encipherment", /* 0x10 */ 1792 "Key Agreement", /* 0x08 */ 1793 "Certificate Signing", /* 0x04 */ 1794 "CRL Signing", /* 0x02 */ 1795 "Encipher Only", /* 0x01 */ 1796 "Decipher Only", /* 0x0080 */ 1797 NULL 1798 }; 1799 1800 /* X509KeyUsage is merely a bit string whose bits are displayed symbolically */ 1801 static void 1802 secu_PrintX509KeyUsage(FILE *out, SECItem *value, char *msg, int level) 1803 { 1804 int unused; 1805 int usage; 1806 int i; 1807 int found = 0; 1808 SECItem my = *value; 1809 1810 if ((my.data[0] != SEC_ASN1_BIT_STRING) || 1811 SECSuccess != SECU_StripTagAndLength(&my)) { 1812 SECU_PrintAny(out, value, "Data", level); 1813 return; 1814 } 1815 1816 unused = (my.len >= 2) ? (my.data[0] & 0x0f) : 0; 1817 usage = (my.len == 2) ? (my.data[1] & (0xff << unused)) << 8 1818 : (my.data[1] << 8) | 1819 (my.data[2] & (0xff << unused)); 1820 1821 SECU_Indent(out, level); 1822 fprintf(out, "Usages: "); 1823 for (i = 0; usageBits[i]; i++) { 1824 if ((0x8000 >> i) & usage) { 1825 if (found) 1826 SECU_Indent(out, level + 2); 1827 fprintf(out, "%s\n", usageBits[i]); 1828 found = 1; 1829 } 1830 } 1831 if (!found) { 1832 fprintf(out, "(none)\n"); 1833 } 1834 } 1835 1836 static void 1837 secu_PrintIPAddress(FILE *out, SECItem *value, char *msg, int level) 1838 { 1839 PRStatus st; 1840 PRNetAddr addr; 1841 char addrBuf[80]; 1842 1843 memset(&addr, 0, sizeof addr); 1844 if (value->len == 4) { 1845 addr.inet.family = PR_AF_INET; 1846 memcpy(&addr.inet.ip, value->data, value->len); 1847 } else if (value->len == 16) { 1848 addr.ipv6.family = PR_AF_INET6; 1849 memcpy(addr.ipv6.ip.pr_s6_addr, value->data, value->len); 1850 if (PR_IsNetAddrType(&addr, PR_IpAddrV4Mapped)) { 1851 /* convert to IPv4. */ 1852 addr.inet.family = PR_AF_INET; 1853 memcpy(&addr.inet.ip, &addr.ipv6.ip.pr_s6_addr[12], 4); 1854 memset(&addr.inet.pad[0], 0, sizeof addr.inet.pad); 1855 } 1856 } else { 1857 goto loser; 1858 } 1859 1860 st = PR_NetAddrToString(&addr, addrBuf, sizeof addrBuf); 1861 if (st == PR_SUCCESS) { 1862 SECU_Indent(out, level); 1863 fprintf(out, "%s: %s\n", msg, addrBuf); 1864 } else { 1865 loser: 1866 SECU_PrintAsHex(out, value, msg, level); 1867 } 1868 } 1869 1870 static void 1871 secu_PrintGeneralName(FILE *out, CERTGeneralName *gname, char *msg, int level) 1872 { 1873 char label[40]; 1874 if (msg && msg[0]) { 1875 SECU_Indent(out, level++); 1876 fprintf(out, "%s: \n", msg); 1877 } 1878 switch (gname->type) { 1879 case certOtherName: 1880 SECU_PrintAny(out, &gname->name.OthName.name, "Other Name", level); 1881 SECU_PrintObjectID(out, &gname->name.OthName.oid, "OID", level + 1); 1882 break; 1883 case certDirectoryName: 1884 SECU_PrintName(out, &gname->name.directoryName, "Directory Name", level); 1885 break; 1886 case certRFC822Name: 1887 secu_PrintRawString(out, &gname->name.other, "RFC822 Name", level); 1888 break; 1889 case certDNSName: 1890 secu_PrintRawString(out, &gname->name.other, "DNS name", level); 1891 break; 1892 case certURI: 1893 secu_PrintRawString(out, &gname->name.other, "URI", level); 1894 break; 1895 case certIPAddress: 1896 secu_PrintIPAddress(out, &gname->name.other, "IP Address", level); 1897 break; 1898 case certRegisterID: 1899 SECU_PrintObjectID(out, &gname->name.other, "Registered ID", level); 1900 break; 1901 case certX400Address: 1902 SECU_PrintAny(out, &gname->name.other, "X400 Address", level); 1903 break; 1904 case certEDIPartyName: 1905 SECU_PrintAny(out, &gname->name.other, "EDI Party", level); 1906 break; 1907 default: 1908 PR_snprintf(label, sizeof label, "unknown type [%d]", 1909 (int)gname->type - 1); 1910 SECU_PrintAsHex(out, &gname->name.other, label, level); 1911 break; 1912 } 1913 } 1914 1915 static void 1916 secu_PrintGeneralNames(FILE *out, CERTGeneralName *gname, char *msg, int level) 1917 { 1918 CERTGeneralName *name = gname; 1919 do { 1920 secu_PrintGeneralName(out, name, msg, level); 1921 name = CERT_GetNextGeneralName(name); 1922 } while (name && name != gname); 1923 } 1924 1925 static void 1926 secu_PrintAuthKeyIDExtension(FILE *out, SECItem *value, char *msg, int level) 1927 { 1928 CERTAuthKeyID *kid = NULL; 1929 PLArenaPool *pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1930 1931 if (!pool) { 1932 SECU_PrintError("Error", "Allocating new ArenaPool"); 1933 return; 1934 } 1935 kid = CERT_DecodeAuthKeyID(pool, value); 1936 if (!kid) { 1937 SECU_PrintErrMsg(out, level, "Error", "Parsing extension"); 1938 SECU_PrintAny(out, value, "Data", level); 1939 } else { 1940 int keyIDPresent = (kid->keyID.data && kid->keyID.len); 1941 int issuerPresent = kid->authCertIssuer != NULL; 1942 int snPresent = (kid->authCertSerialNumber.data && 1943 kid->authCertSerialNumber.len); 1944 1945 if (keyIDPresent) 1946 SECU_PrintAsHex(out, &kid->keyID, "Key ID", level); 1947 if (issuerPresent) 1948 secu_PrintGeneralName(out, kid->authCertIssuer, "Issuer", level); 1949 if (snPresent) 1950 SECU_PrintInteger(out, &kid->authCertSerialNumber, 1951 "Serial Number", level); 1952 } 1953 PORT_FreeArena(pool, PR_FALSE); 1954 } 1955 1956 static void 1957 secu_PrintAltNameExtension(FILE *out, SECItem *value, char *msg, int level) 1958 { 1959 CERTGeneralName *nameList; 1960 CERTGeneralName *current; 1961 PLArenaPool *pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1962 1963 if (!pool) { 1964 SECU_PrintError("Error", "Allocating new ArenaPool"); 1965 return; 1966 } 1967 nameList = current = CERT_DecodeAltNameExtension(pool, value); 1968 if (!current) { 1969 if (PORT_GetError() == SEC_ERROR_EXTENSION_NOT_FOUND) { 1970 /* Decoder found empty sequence, which is invalid. */ 1971 PORT_SetError(SEC_ERROR_EXTENSION_VALUE_INVALID); 1972 } 1973 SECU_PrintErrMsg(out, level, "Error", "Parsing extension"); 1974 SECU_PrintAny(out, value, "Data", level); 1975 } else { 1976 do { 1977 secu_PrintGeneralName(out, current, msg, level); 1978 current = CERT_GetNextGeneralName(current); 1979 } while (current != nameList); 1980 } 1981 PORT_FreeArena(pool, PR_FALSE); 1982 } 1983 1984 static void 1985 secu_PrintCRLDistPtsExtension(FILE *out, SECItem *value, char *msg, int level) 1986 { 1987 CERTCrlDistributionPoints *dPoints; 1988 PLArenaPool *pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1989 1990 if (!pool) { 1991 SECU_PrintError("Error", "Allocating new ArenaPool"); 1992 return; 1993 } 1994 dPoints = CERT_DecodeCRLDistributionPoints(pool, value); 1995 if (dPoints && dPoints->distPoints && dPoints->distPoints[0]) { 1996 CRLDistributionPoint **pPoints = dPoints->distPoints; 1997 CRLDistributionPoint *pPoint; 1998 while (NULL != (pPoint = *pPoints++)) { 1999 SECU_Indent(out, level); 2000 fputs("Distribution point:\n", out); 2001 if (pPoint->distPointType == generalName && 2002 pPoint->distPoint.fullName != NULL) { 2003 secu_PrintGeneralNames(out, pPoint->distPoint.fullName, NULL, 2004 level + 1); 2005 } else if (pPoint->distPointType == relativeDistinguishedName && 2006 pPoint->distPoint.relativeName.avas) { 2007 SECU_PrintRDN(out, &pPoint->distPoint.relativeName, "RDN", 2008 level + 1); 2009 } else if (pPoint->derDistPoint.data) { 2010 SECU_PrintAny(out, &pPoint->derDistPoint, "Point", level + 1); 2011 } 2012 if (pPoint->reasons.data) { 2013 secu_PrintDecodedBitString(out, &pPoint->reasons, "Reasons", 2014 level + 1); 2015 } 2016 if (pPoint->crlIssuer) { 2017 secu_PrintGeneralName(out, pPoint->crlIssuer, "CRL issuer", 2018 level + 1); 2019 } 2020 } 2021 } else { 2022 SECU_PrintErrMsg(out, level, "Error", "Parsing extension"); 2023 SECU_PrintAny(out, value, "Data", level); 2024 } 2025 PORT_FreeArena(pool, PR_FALSE); 2026 } 2027 2028 static void 2029 secu_PrintNameConstraintSubtree(FILE *out, CERTNameConstraint *value, 2030 char *msg, int level) 2031 { 2032 CERTNameConstraint *head = value; 2033 SECU_Indent(out, level); 2034 fprintf(out, "%s Subtree:\n", msg); 2035 level++; 2036 do { 2037 secu_PrintGeneralName(out, &value->name, NULL, level); 2038 if (value->min.data) 2039 SECU_PrintInteger(out, &value->min, "Minimum", level + 1); 2040 if (value->max.data) 2041 SECU_PrintInteger(out, &value->max, "Maximum", level + 1); 2042 value = CERT_GetNextNameConstraint(value); 2043 } while (value != head); 2044 } 2045 2046 static void 2047 secu_PrintNameConstraintsExtension(FILE *out, SECItem *value, char *msg, int level) 2048 { 2049 CERTNameConstraints *cnstrnts; 2050 PLArenaPool *pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 2051 2052 if (!pool) { 2053 SECU_PrintError("Error", "Allocating new ArenaPool"); 2054 return; 2055 } 2056 cnstrnts = CERT_DecodeNameConstraintsExtension(pool, value); 2057 if (!cnstrnts) { 2058 SECU_PrintErrMsg(out, level, "Error", "Parsing extension"); 2059 SECU_PrintAny(out, value, "Raw", level); 2060 } else { 2061 if (cnstrnts->permited) 2062 secu_PrintNameConstraintSubtree(out, cnstrnts->permited, 2063 "Permitted", level); 2064 if (cnstrnts->excluded) 2065 secu_PrintNameConstraintSubtree(out, cnstrnts->excluded, 2066 "Excluded", level); 2067 } 2068 PORT_FreeArena(pool, PR_FALSE); 2069 } 2070 2071 static void 2072 secu_PrintAuthorityInfoAcess(FILE *out, SECItem *value, char *msg, int level) 2073 { 2074 CERTAuthInfoAccess **infos = NULL; 2075 PLArenaPool *pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 2076 2077 if (!pool) { 2078 SECU_PrintError("Error", "Allocating new ArenaPool"); 2079 return; 2080 } 2081 infos = CERT_DecodeAuthInfoAccessExtension(pool, value); 2082 if (!infos) { 2083 SECU_PrintErrMsg(out, level, "Error", "Parsing extension"); 2084 SECU_PrintAny(out, value, "Raw", level); 2085 } else { 2086 CERTAuthInfoAccess *info; 2087 while (NULL != (info = *infos++)) { 2088 if (info->method.data) { 2089 SECU_PrintObjectID(out, &info->method, "Method", level); 2090 } else { 2091 SECU_Indent(out, level); 2092 fprintf(out, "Error: missing method\n"); 2093 } 2094 if (info->location) { 2095 secu_PrintGeneralName(out, info->location, "Location", level); 2096 } else { 2097 SECU_PrintAny(out, &info->derLocation, "Location", level); 2098 } 2099 } 2100 } 2101 PORT_FreeArena(pool, PR_FALSE); 2102 } 2103 2104 void 2105 SECU_PrintExtensions(FILE *out, CERTCertExtension **extensions, 2106 char *msg, int level) 2107 { 2108 SECOidTag oidTag; 2109 2110 if (extensions) { 2111 if (msg && *msg) { 2112 SECU_Indent(out, level++); 2113 fprintf(out, "%s:\n", msg); 2114 } 2115 2116 while (*extensions) { 2117 SECItem *tmpitem; 2118 2119 tmpitem = &(*extensions)->id; 2120 SECU_PrintObjectID(out, tmpitem, "Name", level); 2121 2122 tmpitem = &(*extensions)->critical; 2123 if (tmpitem->len) { 2124 secu_PrintBoolean(out, tmpitem, "Critical", level); 2125 } 2126 2127 oidTag = SECOID_FindOIDTag(&((*extensions)->id)); 2128 tmpitem = &((*extensions)->value); 2129 2130 switch (oidTag) { 2131 case SEC_OID_X509_INVALID_DATE: 2132 case SEC_OID_NS_CERT_EXT_CERT_RENEWAL_TIME: 2133 secu_PrintX509InvalidDate(out, tmpitem, "Date", level); 2134 break; 2135 case SEC_OID_X509_CERTIFICATE_POLICIES: 2136 SECU_PrintPolicy(out, tmpitem, "Data", level); 2137 break; 2138 case SEC_OID_NS_CERT_EXT_BASE_URL: 2139 case SEC_OID_NS_CERT_EXT_REVOCATION_URL: 2140 case SEC_OID_NS_CERT_EXT_CA_REVOCATION_URL: 2141 case SEC_OID_NS_CERT_EXT_CA_CRL_URL: 2142 case SEC_OID_NS_CERT_EXT_CA_CERT_URL: 2143 case SEC_OID_NS_CERT_EXT_CERT_RENEWAL_URL: 2144 case SEC_OID_NS_CERT_EXT_CA_POLICY_URL: 2145 case SEC_OID_NS_CERT_EXT_HOMEPAGE_URL: 2146 case SEC_OID_NS_CERT_EXT_LOST_PASSWORD_URL: 2147 case SEC_OID_OCSP_RESPONDER: 2148 SECU_PrintString(out, tmpitem, "URL", level); 2149 break; 2150 case SEC_OID_NS_CERT_EXT_COMMENT: 2151 SECU_PrintString(out, tmpitem, "Comment", level); 2152 break; 2153 case SEC_OID_NS_CERT_EXT_SSL_SERVER_NAME: 2154 SECU_PrintString(out, tmpitem, "ServerName", level); 2155 break; 2156 case SEC_OID_NS_CERT_EXT_CERT_TYPE: 2157 secu_PrintNSCertType(out, tmpitem, "Data", level); 2158 break; 2159 case SEC_OID_X509_BASIC_CONSTRAINTS: 2160 secu_PrintBasicConstraints(out, tmpitem, "Data", level); 2161 break; 2162 case SEC_OID_X509_EXT_KEY_USAGE: 2163 PrintExtKeyUsageExtension(out, tmpitem, NULL, level); 2164 break; 2165 case SEC_OID_X509_KEY_USAGE: 2166 secu_PrintX509KeyUsage(out, tmpitem, NULL, level); 2167 break; 2168 case SEC_OID_X509_AUTH_KEY_ID: 2169 secu_PrintAuthKeyIDExtension(out, tmpitem, NULL, level); 2170 break; 2171 case SEC_OID_X509_SUBJECT_ALT_NAME: 2172 case SEC_OID_X509_ISSUER_ALT_NAME: 2173 secu_PrintAltNameExtension(out, tmpitem, NULL, level); 2174 break; 2175 case SEC_OID_X509_CRL_DIST_POINTS: 2176 secu_PrintCRLDistPtsExtension(out, tmpitem, NULL, level); 2177 break; 2178 case SEC_OID_X509_PRIVATE_KEY_USAGE_PERIOD: 2179 SECU_PrintPrivKeyUsagePeriodExtension(out, tmpitem, NULL, 2180 level); 2181 break; 2182 case SEC_OID_X509_NAME_CONSTRAINTS: 2183 secu_PrintNameConstraintsExtension(out, tmpitem, NULL, level); 2184 break; 2185 case SEC_OID_X509_AUTH_INFO_ACCESS: 2186 secu_PrintAuthorityInfoAcess(out, tmpitem, NULL, level); 2187 break; 2188 2189 case SEC_OID_X509_CRL_NUMBER: 2190 case SEC_OID_X509_REASON_CODE: 2191 2192 /* PKIX OIDs */ 2193 case SEC_OID_PKIX_OCSP: 2194 case SEC_OID_PKIX_OCSP_BASIC_RESPONSE: 2195 case SEC_OID_PKIX_OCSP_NONCE: 2196 case SEC_OID_PKIX_OCSP_CRL: 2197 case SEC_OID_PKIX_OCSP_RESPONSE: 2198 case SEC_OID_PKIX_OCSP_NO_CHECK: 2199 case SEC_OID_PKIX_OCSP_ARCHIVE_CUTOFF: 2200 case SEC_OID_PKIX_OCSP_SERVICE_LOCATOR: 2201 case SEC_OID_PKIX_REGCTRL_REGTOKEN: 2202 case SEC_OID_PKIX_REGCTRL_AUTHENTICATOR: 2203 case SEC_OID_PKIX_REGCTRL_PKIPUBINFO: 2204 case SEC_OID_PKIX_REGCTRL_PKI_ARCH_OPTIONS: 2205 case SEC_OID_PKIX_REGCTRL_OLD_CERT_ID: 2206 case SEC_OID_PKIX_REGCTRL_PROTOCOL_ENC_KEY: 2207 case SEC_OID_PKIX_REGINFO_UTF8_PAIRS: 2208 case SEC_OID_PKIX_REGINFO_CERT_REQUEST: 2209 2210 /* Netscape extension OIDs. */ 2211 case SEC_OID_NS_CERT_EXT_NETSCAPE_OK: 2212 case SEC_OID_NS_CERT_EXT_ISSUER_LOGO: 2213 case SEC_OID_NS_CERT_EXT_SUBJECT_LOGO: 2214 case SEC_OID_NS_CERT_EXT_ENTITY_LOGO: 2215 case SEC_OID_NS_CERT_EXT_USER_PICTURE: 2216 2217 /* x.509 v3 Extensions */ 2218 case SEC_OID_X509_SUBJECT_DIRECTORY_ATTR: 2219 case SEC_OID_X509_SUBJECT_KEY_ID: 2220 case SEC_OID_X509_POLICY_MAPPINGS: 2221 case SEC_OID_X509_POLICY_CONSTRAINTS: 2222 2223 default: 2224 SECU_PrintAny(out, tmpitem, "Data", level); 2225 break; 2226 } 2227 2228 SECU_Newline(out); 2229 extensions++; 2230 } 2231 } 2232 } 2233 2234 /* An RDN is a subset of a DirectoryName, and we already know how to 2235 * print those, so make a directory name out of the RDN, and print it. 2236 */ 2237 void 2238 SECU_PrintRDN(FILE *out, CERTRDN *rdn, const char *msg, int level) 2239 { 2240 CERTName name; 2241 CERTRDN *rdns[2]; 2242 2243 name.arena = NULL; 2244 name.rdns = rdns; 2245 rdns[0] = rdn; 2246 rdns[1] = NULL; 2247 SECU_PrintName(out, &name, msg, level); 2248 } 2249 2250 void 2251 SECU_PrintNameQuotesOptional(FILE *out, CERTName *name, const char *msg, 2252 int level, PRBool quotes) 2253 { 2254 char *nameStr = NULL; 2255 char *str; 2256 SECItem my; 2257 2258 if (!name) { 2259 PORT_SetError(SEC_ERROR_INVALID_ARGS); 2260 return; 2261 } 2262 if (!name->rdns || !name->rdns[0]) { 2263 str = "(empty)"; 2264 } else { 2265 str = nameStr = CERT_NameToAscii(name); 2266 } 2267 if (!str) { 2268 str = "!Invalid AVA!"; 2269 } 2270 my.data = (unsigned char *)str; 2271 my.len = PORT_Strlen(str); 2272 #if 1 2273 secu_PrintRawStringQuotesOptional(out, &my, msg, level, quotes); 2274 #else 2275 SECU_Indent(out, level); 2276 fprintf(out, "%s: ", msg); 2277 fprintf(out, str); 2278 SECU_Newline(out); 2279 #endif 2280 PORT_Free(nameStr); 2281 } 2282 2283 void 2284 SECU_PrintName(FILE *out, CERTName *name, const char *msg, int level) 2285 { 2286 SECU_PrintNameQuotesOptional(out, name, msg, level, PR_TRUE); 2287 } 2288 2289 void 2290 printflags(char *trusts, unsigned int flags) 2291 { 2292 if (flags & CERTDB_VALID_CA) 2293 if (!(flags & CERTDB_TRUSTED_CA) && 2294 !(flags & CERTDB_TRUSTED_CLIENT_CA)) 2295 PORT_Strcat(trusts, "c"); 2296 if (flags & CERTDB_TERMINAL_RECORD) 2297 if (!(flags & CERTDB_TRUSTED)) 2298 PORT_Strcat(trusts, "p"); 2299 if (flags & CERTDB_TRUSTED_CA) 2300 PORT_Strcat(trusts, "C"); 2301 if (flags & CERTDB_TRUSTED_CLIENT_CA) 2302 PORT_Strcat(trusts, "T"); 2303 if (flags & CERTDB_TRUSTED) 2304 PORT_Strcat(trusts, "P"); 2305 if (flags & CERTDB_USER) 2306 PORT_Strcat(trusts, "u"); 2307 if (flags & CERTDB_SEND_WARN) 2308 PORT_Strcat(trusts, "w"); 2309 if (flags & CERTDB_INVISIBLE_CA) 2310 PORT_Strcat(trusts, "I"); 2311 if (flags & CERTDB_GOVT_APPROVED_CA) 2312 PORT_Strcat(trusts, "G"); 2313 return; 2314 } 2315 2316 /* callback for listing certs through pkcs11 */ 2317 SECStatus 2318 SECU_PrintCertNickname(CERTCertListNode *node, void *data) 2319 { 2320 CERTCertTrust trust; 2321 CERTCertificate *cert; 2322 FILE *out; 2323 char trusts[30]; 2324 char *name; 2325 2326 cert = node->cert; 2327 2328 PORT_Memset(trusts, 0, sizeof(trusts)); 2329 out = (FILE *)data; 2330 2331 name = node->appData; 2332 if (!name || !name[0]) { 2333 name = cert->nickname; 2334 } 2335 if (!name || !name[0]) { 2336 name = cert->emailAddr; 2337 } 2338 if (!name || !name[0]) { 2339 name = "(NULL)"; 2340 } 2341 2342 if (CERT_GetCertTrust(cert, &trust) == SECSuccess) { 2343 printflags(trusts, trust.sslFlags); 2344 PORT_Strcat(trusts, ","); 2345 printflags(trusts, trust.emailFlags); 2346 PORT_Strcat(trusts, ","); 2347 printflags(trusts, trust.objectSigningFlags); 2348 } else { 2349 PORT_Memcpy(trusts, ",,", 3); 2350 } 2351 fprintf(out, "%-60s %-5s\n", name, trusts); 2352 2353 return (SECSuccess); 2354 } 2355 2356 int 2357 SECU_DecodeAndPrintExtensions(FILE *out, SECItem *any, char *m, int level) 2358 { 2359 CERTCertExtension **extensions = NULL; 2360 PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 2361 int rv = 0; 2362 2363 if (!arena) 2364 return SEC_ERROR_NO_MEMORY; 2365 2366 rv = SEC_QuickDERDecodeItem(arena, &extensions, 2367 SEC_ASN1_GET(CERT_SequenceOfCertExtensionTemplate), any); 2368 if (!rv) 2369 SECU_PrintExtensions(out, extensions, m, level); 2370 else 2371 SECU_PrintAny(out, any, m, level); 2372 PORT_FreeArena(arena, PR_FALSE); 2373 return rv; 2374 } 2375 2376 /* print a decoded SET OF or SEQUENCE OF Extensions */ 2377 int 2378 SECU_PrintSetOfExtensions(FILE *out, SECItem **any, char *m, int level) 2379 { 2380 int rv = 0; 2381 if (m && *m) { 2382 SECU_Indent(out, level++); 2383 fprintf(out, "%s:\n", m); 2384 } 2385 while (any && any[0]) { 2386 rv |= SECU_DecodeAndPrintExtensions(out, any[0], "", level); 2387 any++; 2388 } 2389 return rv; 2390 } 2391 2392 /* print a decoded SET OF or SEQUENCE OF "ANY" */ 2393 int 2394 SECU_PrintSetOfAny(FILE *out, SECItem **any, char *m, int level) 2395 { 2396 int rv = 0; 2397 if (m && *m) { 2398 SECU_Indent(out, level++); 2399 fprintf(out, "%s:\n", m); 2400 } 2401 while (any && any[0]) { 2402 SECU_PrintAny(out, any[0], "", level); 2403 any++; 2404 } 2405 return rv; 2406 } 2407 2408 int 2409 SECU_PrintCertAttribute(FILE *out, CERTAttribute *attr, char *m, int level) 2410 { 2411 int rv = 0; 2412 SECOidTag tag; 2413 tag = SECU_PrintObjectID(out, &attr->attrType, "Attribute Type", level); 2414 if (tag == SEC_OID_PKCS9_EXTENSION_REQUEST) { 2415 rv = SECU_PrintSetOfExtensions(out, attr->attrValue, "Extensions", level); 2416 } else { 2417 rv = SECU_PrintSetOfAny(out, attr->attrValue, "Attribute Values", level); 2418 } 2419 return rv; 2420 } 2421 2422 int 2423 SECU_PrintCertAttributes(FILE *out, CERTAttribute **attrs, char *m, int level) 2424 { 2425 int rv = 0; 2426 while (attrs[0]) { 2427 rv |= SECU_PrintCertAttribute(out, attrs[0], m, level + 1); 2428 attrs++; 2429 } 2430 return rv; 2431 } 2432 2433 /* sometimes a PRErrorCode, other times a SECStatus. Sigh. */ 2434 int 2435 SECU_PrintCertificateRequest(FILE *out, const SECItem *der, const char *m, int level) 2436 { 2437 PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 2438 CERTCertificateRequest *cr; 2439 int rv = SEC_ERROR_NO_MEMORY; 2440 2441 if (!arena) 2442 return rv; 2443 2444 /* Decode certificate request */ 2445 cr = PORT_ArenaZNew(arena, CERTCertificateRequest); 2446 if (!cr) 2447 goto loser; 2448 cr->arena = arena; 2449 rv = SEC_QuickDERDecodeItem(arena, cr, 2450 SEC_ASN1_GET(CERT_CertificateRequestTemplate), der); 2451 if (rv) 2452 goto loser; 2453 2454 /* Pretty print it out */ 2455 SECU_Indent(out, level); 2456 fprintf(out, "%s:\n", m); 2457 SECU_PrintInteger(out, &cr->version, "Version", level + 1); 2458 SECU_PrintName(out, &cr->subject, "Subject", level + 1); 2459 if (!SECU_GetWrapEnabled()) /*SECU_PrintName didn't add newline*/ 2460 SECU_Newline(out); 2461 secu_PrintSubjectPublicKeyInfo(out, arena, &cr->subjectPublicKeyInfo, 2462 "Subject Public Key Info", level + 1); 2463 if (cr->attributes) 2464 SECU_PrintCertAttributes(out, cr->attributes, "Attributes", level + 1); 2465 rv = 0; 2466 loser: 2467 PORT_FreeArena(arena, PR_FALSE); 2468 return rv; 2469 } 2470 2471 int 2472 SECU_PrintCertificate(FILE *out, const SECItem *der, const char *m, int level) 2473 { 2474 PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 2475 CERTCertificate *c; 2476 int rv = SEC_ERROR_NO_MEMORY; 2477 int iv; 2478 2479 if (!arena) 2480 return rv; 2481 2482 /* Decode certificate */ 2483 c = PORT_ArenaZNew(arena, CERTCertificate); 2484 if (!c) 2485 goto loser; 2486 c->arena = arena; 2487 rv = SEC_ASN1DecodeItem(arena, c, 2488 SEC_ASN1_GET(CERT_CertificateTemplate), der); 2489 if (rv) { 2490 SECU_Indent(out, level); 2491 SECU_PrintErrMsg(out, level, "Error", "Parsing extension"); 2492 SECU_PrintAny(out, der, "Raw", level); 2493 goto loser; 2494 } 2495 /* Pretty print it out */ 2496 SECU_Indent(out, level); 2497 fprintf(out, "%s:\n", m); 2498 iv = c->version.len ? DER_GetInteger(&c->version) : 0; /* version is optional */ 2499 SECU_Indent(out, level + 1); 2500 fprintf(out, "%s: %d (0x%x)\n", "Version", iv + 1, iv); 2501 2502 SECU_PrintInteger(out, &c->serialNumber, "Serial Number", level + 1); 2503 SECU_PrintAlgorithmID(out, &c->signature, "Signature Algorithm", level + 1); 2504 SECU_PrintName(out, &c->issuer, "Issuer", level + 1); 2505 if (!SECU_GetWrapEnabled()) /*SECU_PrintName didn't add newline*/ 2506 SECU_Newline(out); 2507 secu_PrintValidity(out, &c->validity, "Validity", level + 1); 2508 SECU_PrintName(out, &c->subject, "Subject", level + 1); 2509 if (!SECU_GetWrapEnabled()) /*SECU_PrintName didn't add newline*/ 2510 SECU_Newline(out); 2511 secu_PrintSubjectPublicKeyInfo(out, arena, &c->subjectPublicKeyInfo, 2512 "Subject Public Key Info", level + 1); 2513 if (c->issuerID.data) 2514 secu_PrintDecodedBitString(out, &c->issuerID, "Issuer Unique ID", level + 1); 2515 if (c->subjectID.data) 2516 secu_PrintDecodedBitString(out, &c->subjectID, "Subject Unique ID", level + 1); 2517 SECU_PrintExtensions(out, c->extensions, "Signed Extensions", level + 1); 2518 loser: 2519 PORT_FreeArena(arena, PR_FALSE); 2520 return rv; 2521 } 2522 2523 int 2524 SECU_PrintCertificateBasicInfo(FILE *out, const SECItem *der, const char *m, int level) 2525 { 2526 PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 2527 CERTCertificate *c; 2528 int rv = SEC_ERROR_NO_MEMORY; 2529 2530 if (!arena) 2531 return rv; 2532 2533 /* Decode certificate */ 2534 c = PORT_ArenaZNew(arena, CERTCertificate); 2535 if (!c) 2536 goto loser; 2537 c->arena = arena; 2538 rv = SEC_ASN1DecodeItem(arena, c, 2539 SEC_ASN1_GET(CERT_CertificateTemplate), der); 2540 if (rv) { 2541 SECU_Indent(out, level); 2542 SECU_PrintErrMsg(out, level, "Error", "Parsing extension"); 2543 SECU_PrintAny(out, der, "Raw", level); 2544 goto loser; 2545 } 2546 /* Pretty print it out */ 2547 SECU_Indent(out, level); 2548 fprintf(out, "%s:\n", m); 2549 SECU_PrintInteger(out, &c->serialNumber, "Serial Number", level + 1); 2550 SECU_PrintAlgorithmID(out, &c->signature, "Signature Algorithm", level + 1); 2551 SECU_PrintName(out, &c->issuer, "Issuer", level + 1); 2552 if (!SECU_GetWrapEnabled()) /*SECU_PrintName didn't add newline*/ 2553 SECU_Newline(out); 2554 secu_PrintValidity(out, &c->validity, "Validity", level + 1); 2555 SECU_PrintName(out, &c->subject, "Subject", level + 1); 2556 if (!SECU_GetWrapEnabled()) /*SECU_PrintName didn't add newline*/ 2557 SECU_Newline(out); 2558 loser: 2559 PORT_FreeArena(arena, PR_FALSE); 2560 return rv; 2561 } 2562 2563 int 2564 SECU_PrintSubjectPublicKeyInfo(FILE *out, SECItem *der, char *m, int level) 2565 { 2566 PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 2567 int rv = SEC_ERROR_NO_MEMORY; 2568 CERTSubjectPublicKeyInfo spki; 2569 2570 if (!arena) 2571 return rv; 2572 2573 PORT_Memset(&spki, 0, sizeof spki); 2574 rv = SEC_ASN1DecodeItem(arena, &spki, 2575 SEC_ASN1_GET(CERT_SubjectPublicKeyInfoTemplate), 2576 der); 2577 if (!rv) { 2578 if (m && *m) { 2579 SECU_Indent(out, level); 2580 fprintf(out, "%s:\n", m); 2581 } 2582 secu_PrintSubjectPublicKeyInfo(out, arena, &spki, 2583 "Subject Public Key Info", level + 1); 2584 } 2585 2586 PORT_FreeArena(arena, PR_FALSE); 2587 return rv; 2588 } 2589 2590 int 2591 SECU_PrintPrivateKey(FILE *out, SECItem *der, char *m, int level) 2592 { 2593 PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 2594 SECKEYEncryptedPrivateKeyInfo key; 2595 int rv = SEC_ERROR_NO_MEMORY; 2596 2597 if (!arena) 2598 return rv; 2599 2600 PORT_Memset(&key, 0, sizeof(key)); 2601 rv = SEC_ASN1DecodeItem(arena, &key, 2602 SEC_ASN1_GET(SECKEY_EncryptedPrivateKeyInfoTemplate), der); 2603 if (rv) 2604 goto loser; 2605 2606 /* Pretty print it out */ 2607 SECU_Indent(out, level); 2608 fprintf(out, "%s:\n", m); 2609 SECU_PrintAlgorithmID(out, &key.algorithm, "Encryption Algorithm", 2610 level + 1); 2611 SECU_PrintAsHex(out, &key.encryptedData, "Encrypted Data", level + 1); 2612 loser: 2613 PORT_FreeArena(arena, PR_TRUE); 2614 return rv; 2615 } 2616 2617 int 2618 SECU_PrintFingerprints(FILE *out, SECItem *derCert, char *m, int level) 2619 { 2620 unsigned char fingerprint[SHA256_LENGTH]; 2621 char *fpStr = NULL; 2622 int err = PORT_GetError(); 2623 SECStatus rv; 2624 SECItem fpItem; 2625 2626 /* Print SHA-256 fingerprint */ 2627 memset(fingerprint, 0, sizeof fingerprint); 2628 rv = PK11_HashBuf(SEC_OID_SHA256, fingerprint, derCert->data, derCert->len); 2629 fpItem.data = fingerprint; 2630 fpItem.len = SHA256_LENGTH; 2631 fpStr = CERT_Hexify(&fpItem, 1); 2632 SECU_Indent(out, level); 2633 fprintf(out, "%s (SHA-256):", m); 2634 if (SECU_GetWrapEnabled()) { 2635 fprintf(out, "\n"); 2636 SECU_Indent(out, level + 1); 2637 } else { 2638 fprintf(out, " "); 2639 } 2640 fprintf(out, "%s\n", fpStr); 2641 PORT_Free(fpStr); 2642 fpStr = NULL; 2643 if (rv != SECSuccess && !err) 2644 err = PORT_GetError(); 2645 2646 /* print SHA1 fingerprint */ 2647 memset(fingerprint, 0, sizeof fingerprint); 2648 rv = PK11_HashBuf(SEC_OID_SHA1, fingerprint, derCert->data, derCert->len); 2649 fpItem.data = fingerprint; 2650 fpItem.len = SHA1_LENGTH; 2651 fpStr = CERT_Hexify(&fpItem, 1); 2652 SECU_Indent(out, level); 2653 fprintf(out, "%s (SHA1):", m); 2654 if (SECU_GetWrapEnabled()) { 2655 fprintf(out, "\n"); 2656 SECU_Indent(out, level + 1); 2657 } else { 2658 fprintf(out, " "); 2659 } 2660 fprintf(out, "%s\n", fpStr); 2661 PORT_Free(fpStr); 2662 if (SECU_GetWrapEnabled()) 2663 fprintf(out, "\n"); 2664 2665 if (err) 2666 PORT_SetError(err); 2667 if (err || rv != SECSuccess) 2668 return SECFailure; 2669 2670 return 0; 2671 } 2672 2673 /* 2674 ** PKCS7 Support 2675 */ 2676 2677 /* forward declaration */ 2678 typedef enum { 2679 secuPKCS7Unknown = 0, 2680 secuPKCS7PKCS12AuthSafe, 2681 secuPKCS7PKCS12Safe 2682 } secuPKCS7State; 2683 2684 static int 2685 secu_PrintPKCS7ContentInfo(FILE *, SEC_PKCS7ContentInfo *, secuPKCS7State, 2686 const char *, int); 2687 static int 2688 secu_PrintDERPKCS7ContentInfo(FILE *, SECItem *, secuPKCS7State, 2689 const char *, int); 2690 2691 /* 2692 ** secu_PrintPKCS7EncContent 2693 ** Prints a SEC_PKCS7EncryptedContentInfo (without decrypting it) 2694 */ 2695 static int 2696 secu_PrintPKCS7EncContent(FILE *out, SEC_PKCS7EncryptedContentInfo *src, 2697 secuPKCS7State state, const char *m, int level) 2698 { 2699 if (src->contentTypeTag == NULL) 2700 src->contentTypeTag = SECOID_FindOID(&(src->contentType)); 2701 2702 SECU_Indent(out, level); 2703 fprintf(out, "%s:\n", m); 2704 SECU_Indent(out, level + 1); 2705 fprintf(out, "Content Type: %s\n", 2706 (src->contentTypeTag != NULL) ? src->contentTypeTag->desc 2707 : "Unknown"); 2708 SECU_PrintAlgorithmID(out, &(src->contentEncAlg), 2709 "Content Encryption Algorithm", level + 1); 2710 SECU_PrintAsHex(out, &(src->encContent), 2711 "Encrypted Content", level + 1); 2712 return 0; 2713 } 2714 2715 /* 2716 ** secu_PrintRecipientInfo 2717 ** Prints a PKCS7RecipientInfo type 2718 */ 2719 static void 2720 secu_PrintRecipientInfo(FILE *out, SEC_PKCS7RecipientInfo *info, 2721 const char *m, int level) 2722 { 2723 SECU_Indent(out, level); 2724 fprintf(out, "%s:\n", m); 2725 SECU_PrintInteger(out, &(info->version), "Version", level + 1); 2726 2727 SECU_PrintName(out, &(info->issuerAndSN->issuer), "Issuer", 2728 level + 1); 2729 SECU_PrintInteger(out, &(info->issuerAndSN->serialNumber), 2730 "Serial Number", level + 1); 2731 2732 /* Parse and display encrypted key */ 2733 SECU_PrintAlgorithmID(out, &(info->keyEncAlg), 2734 "Key Encryption Algorithm", level + 1); 2735 SECU_PrintAsHex(out, &(info->encKey), "Encrypted Key", level + 1); 2736 } 2737 2738 /* 2739 ** secu_PrintSignerInfo 2740 ** Prints a PKCS7SingerInfo type 2741 */ 2742 static void 2743 secu_PrintSignerInfo(FILE *out, SEC_PKCS7SignerInfo *info, 2744 const char *m, int level) 2745 { 2746 SEC_PKCS7Attribute *attr; 2747 int iv; 2748 char om[100]; 2749 2750 SECU_Indent(out, level); 2751 fprintf(out, "%s:\n", m); 2752 SECU_PrintInteger(out, &(info->version), "Version", level + 1); 2753 2754 SECU_PrintName(out, &(info->issuerAndSN->issuer), "Issuer", 2755 level + 1); 2756 SECU_PrintInteger(out, &(info->issuerAndSN->serialNumber), 2757 "Serial Number", level + 1); 2758 2759 SECU_PrintAlgorithmID(out, &(info->digestAlg), "Digest Algorithm", 2760 level + 1); 2761 2762 if (info->authAttr != NULL) { 2763 SECU_Indent(out, level + 1); 2764 fprintf(out, "Authenticated Attributes:\n"); 2765 iv = 0; 2766 while ((attr = info->authAttr[iv++]) != NULL) { 2767 snprintf(om, sizeof(om), "Attribute (%d)", iv); 2768 secu_PrintAttribute(out, attr, om, level + 2); 2769 } 2770 } 2771 2772 /* Parse and display signature */ 2773 SECU_PrintAlgorithmID(out, &(info->digestEncAlg), 2774 "Digest Encryption Algorithm", level + 1); 2775 SECU_PrintAsHex(out, &(info->encDigest), "Encrypted Digest", level + 1); 2776 2777 if (info->unAuthAttr != NULL) { 2778 SECU_Indent(out, level + 1); 2779 fprintf(out, "Unauthenticated Attributes:\n"); 2780 iv = 0; 2781 while ((attr = info->unAuthAttr[iv++]) != NULL) { 2782 snprintf(om, sizeof(om), "Attribute (%x)", iv); 2783 secu_PrintAttribute(out, attr, om, level + 2); 2784 } 2785 } 2786 } 2787 2788 /* callers of this function must make sure that the CERTSignedCrl 2789 from which they are extracting the CERTCrl has been fully-decoded. 2790 Otherwise it will not have the entries even though the CRL may have 2791 some */ 2792 2793 void 2794 SECU_PrintCRLInfo(FILE *out, CERTCrl *crl, const char *m, int level) 2795 { 2796 CERTCrlEntry *entry; 2797 int iv; 2798 char om[100]; 2799 2800 SECU_Indent(out, level); 2801 fprintf(out, "%s:\n", m); 2802 /* version is optional */ 2803 iv = crl->version.len ? DER_GetInteger(&crl->version) : 0; 2804 SECU_Indent(out, level + 1); 2805 fprintf(out, "%s: %d (0x%x)\n", "Version", iv + 1, iv); 2806 SECU_PrintAlgorithmID(out, &(crl->signatureAlg), "Signature Algorithm", 2807 level + 1); 2808 SECU_PrintName(out, &(crl->name), "Issuer", level + 1); 2809 SECU_PrintTimeChoice(out, &(crl->lastUpdate), "This Update", level + 1); 2810 if (crl->nextUpdate.data && crl->nextUpdate.len) /* is optional */ 2811 SECU_PrintTimeChoice(out, &(crl->nextUpdate), "Next Update", level + 1); 2812 2813 if (crl->entries != NULL) { 2814 iv = 0; 2815 while ((entry = crl->entries[iv++]) != NULL) { 2816 snprintf(om, sizeof(om), "Entry %d (0x%x):\n", iv, iv); 2817 SECU_Indent(out, level + 1); 2818 fputs(om, out); 2819 SECU_PrintInteger(out, &(entry->serialNumber), "Serial Number", 2820 level + 2); 2821 SECU_PrintTimeChoice(out, &(entry->revocationDate), 2822 "Revocation Date", level + 2); 2823 SECU_PrintExtensions(out, entry->extensions, 2824 "Entry Extensions", level + 2); 2825 } 2826 } 2827 SECU_PrintExtensions(out, crl->extensions, "CRL Extensions", level + 1); 2828 } 2829 2830 /* 2831 ** secu_PrintPKCS7Signed 2832 ** Pretty print a PKCS7 signed data type (up to version 1). 2833 */ 2834 static int 2835 secu_PrintPKCS7Signed(FILE *out, SEC_PKCS7SignedData *src, 2836 secuPKCS7State state, const char *m, int level) 2837 { 2838 SECAlgorithmID *digAlg; /* digest algorithms */ 2839 SECItem *aCert; /* certificate */ 2840 CERTSignedCrl *aCrl; /* certificate revocation list */ 2841 SEC_PKCS7SignerInfo *sigInfo; /* signer information */ 2842 int rv, iv; 2843 char om[100]; 2844 2845 SECU_Indent(out, level); 2846 fprintf(out, "%s:\n", m); 2847 SECU_PrintInteger(out, &(src->version), "Version", level + 1); 2848 2849 /* Parse and list digest algorithms (if any) */ 2850 if (src->digestAlgorithms != NULL) { 2851 SECU_Indent(out, level + 1); 2852 fprintf(out, "Digest Algorithm List:\n"); 2853 iv = 0; 2854 while ((digAlg = src->digestAlgorithms[iv++]) != NULL) { 2855 snprintf(om, sizeof(om), "Digest Algorithm (%x)", iv); 2856 SECU_PrintAlgorithmID(out, digAlg, om, level + 2); 2857 } 2858 } 2859 2860 /* Now for the content */ 2861 rv = secu_PrintPKCS7ContentInfo(out, &(src->contentInfo), 2862 state, "Content Information", level + 1); 2863 if (rv != 0) 2864 return rv; 2865 2866 /* Parse and list certificates (if any) */ 2867 if (src->rawCerts != NULL) { 2868 SECU_Indent(out, level + 1); 2869 fprintf(out, "Certificate List:\n"); 2870 iv = 0; 2871 while ((aCert = src->rawCerts[iv++]) != NULL) { 2872 snprintf(om, sizeof(om), "Certificate (%x)", iv); 2873 rv = SECU_PrintSignedData(out, aCert, om, level + 2, 2874 SECU_PrintCertificate); 2875 if (rv) 2876 return rv; 2877 } 2878 } 2879 2880 /* Parse and list CRL's (if any) */ 2881 if (src->crls != NULL) { 2882 SECU_Indent(out, level + 1); 2883 fprintf(out, "Signed Revocation Lists:\n"); 2884 iv = 0; 2885 while ((aCrl = src->crls[iv++]) != NULL) { 2886 snprintf(om, sizeof(om), "Signed Revocation List (%x)", iv); 2887 SECU_Indent(out, level + 2); 2888 fprintf(out, "%s:\n", om); 2889 SECU_PrintAlgorithmID(out, &aCrl->signatureWrap.signatureAlgorithm, 2890 "Signature Algorithm", level + 3); 2891 DER_ConvertBitString(&aCrl->signatureWrap.signature); 2892 SECU_PrintAsHex(out, &aCrl->signatureWrap.signature, "Signature", 2893 level + 3); 2894 SECU_PrintCRLInfo(out, &aCrl->crl, "Certificate Revocation List", 2895 level + 3); 2896 } 2897 } 2898 2899 /* Parse and list signatures (if any) */ 2900 if (src->signerInfos != NULL) { 2901 SECU_Indent(out, level + 1); 2902 fprintf(out, "Signer Information List:\n"); 2903 iv = 0; 2904 while ((sigInfo = src->signerInfos[iv++]) != NULL) { 2905 snprintf(om, sizeof(om), "Signer Information (%x)", iv); 2906 secu_PrintSignerInfo(out, sigInfo, om, level + 2); 2907 } 2908 } 2909 2910 return 0; 2911 } 2912 2913 /* 2914 ** secu_PrintPKCS7Enveloped 2915 ** Pretty print a PKCS7 enveloped data type (up to version 1). 2916 */ 2917 static int 2918 secu_PrintPKCS7Enveloped(FILE *out, SEC_PKCS7EnvelopedData *src, 2919 secuPKCS7State state, const char *m, int level) 2920 { 2921 SEC_PKCS7RecipientInfo *recInfo; /* pointer for signer information */ 2922 int iv; 2923 char om[100]; 2924 2925 SECU_Indent(out, level); 2926 fprintf(out, "%s:\n", m); 2927 SECU_PrintInteger(out, &(src->version), "Version", level + 1); 2928 2929 /* Parse and list recipients (this is not optional) */ 2930 if (src->recipientInfos != NULL) { 2931 SECU_Indent(out, level + 1); 2932 fprintf(out, "Recipient Information List:\n"); 2933 iv = 0; 2934 while ((recInfo = src->recipientInfos[iv++]) != NULL) { 2935 snprintf(om, sizeof(om), "Recipient Information (%x)", iv); 2936 secu_PrintRecipientInfo(out, recInfo, om, level + 2); 2937 } 2938 } 2939 2940 return secu_PrintPKCS7EncContent(out, &src->encContentInfo, state, 2941 "Encrypted Content Information", level + 1); 2942 } 2943 2944 /* 2945 ** secu_PrintPKCS7SignedEnveloped 2946 ** Pretty print a PKCS7 singed and enveloped data type (up to version 1). 2947 */ 2948 static int 2949 secu_PrintPKCS7SignedAndEnveloped(FILE *out, 2950 SEC_PKCS7SignedAndEnvelopedData *src, 2951 secuPKCS7State state, const char *m, 2952 int level) 2953 { 2954 SECAlgorithmID *digAlg; /* pointer for digest algorithms */ 2955 SECItem *aCert; /* pointer for certificate */ 2956 CERTSignedCrl *aCrl; /* pointer for certificate revocation list */ 2957 SEC_PKCS7SignerInfo *sigInfo; /* pointer for signer information */ 2958 SEC_PKCS7RecipientInfo *recInfo; /* pointer for recipient information */ 2959 int rv, iv; 2960 char om[100]; 2961 2962 SECU_Indent(out, level); 2963 fprintf(out, "%s:\n", m); 2964 SECU_PrintInteger(out, &(src->version), "Version", level + 1); 2965 2966 /* Parse and list recipients (this is not optional) */ 2967 if (src->recipientInfos != NULL) { 2968 SECU_Indent(out, level + 1); 2969 fprintf(out, "Recipient Information List:\n"); 2970 iv = 0; 2971 while ((recInfo = src->recipientInfos[iv++]) != NULL) { 2972 snprintf(om, sizeof(om), "Recipient Information (%x)", iv); 2973 secu_PrintRecipientInfo(out, recInfo, om, level + 2); 2974 } 2975 } 2976 2977 /* Parse and list digest algorithms (if any) */ 2978 if (src->digestAlgorithms != NULL) { 2979 SECU_Indent(out, level + 1); 2980 fprintf(out, "Digest Algorithm List:\n"); 2981 iv = 0; 2982 while ((digAlg = src->digestAlgorithms[iv++]) != NULL) { 2983 snprintf(om, sizeof(om), "Digest Algorithm (%x)", iv); 2984 SECU_PrintAlgorithmID(out, digAlg, om, level + 2); 2985 } 2986 } 2987 2988 rv = secu_PrintPKCS7EncContent(out, &src->encContentInfo, state, 2989 "Encrypted Content Information", level + 1); 2990 if (rv) 2991 return rv; 2992 2993 /* Parse and list certificates (if any) */ 2994 if (src->rawCerts != NULL) { 2995 SECU_Indent(out, level + 1); 2996 fprintf(out, "Certificate List:\n"); 2997 iv = 0; 2998 while ((aCert = src->rawCerts[iv++]) != NULL) { 2999 snprintf(om, sizeof(om), "Certificate (%x)", iv); 3000 rv = SECU_PrintSignedData(out, aCert, om, level + 2, 3001 SECU_PrintCertificate); 3002 if (rv) 3003 return rv; 3004 } 3005 } 3006 3007 /* Parse and list CRL's (if any) */ 3008 if (src->crls != NULL) { 3009 SECU_Indent(out, level + 1); 3010 fprintf(out, "Signed Revocation Lists:\n"); 3011 iv = 0; 3012 while ((aCrl = src->crls[iv++]) != NULL) { 3013 snprintf(om, sizeof(om), "Signed Revocation List (%x)", iv); 3014 SECU_Indent(out, level + 2); 3015 fprintf(out, "%s:\n", om); 3016 SECU_PrintAlgorithmID(out, &aCrl->signatureWrap.signatureAlgorithm, 3017 "Signature Algorithm", level + 3); 3018 DER_ConvertBitString(&aCrl->signatureWrap.signature); 3019 SECU_PrintAsHex(out, &aCrl->signatureWrap.signature, "Signature", 3020 level + 3); 3021 SECU_PrintCRLInfo(out, &aCrl->crl, "Certificate Revocation List", 3022 level + 3); 3023 } 3024 } 3025 3026 /* Parse and list signatures (if any) */ 3027 if (src->signerInfos != NULL) { 3028 SECU_Indent(out, level + 1); 3029 fprintf(out, "Signer Information List:\n"); 3030 iv = 0; 3031 while ((sigInfo = src->signerInfos[iv++]) != NULL) { 3032 snprintf(om, sizeof(om), "Signer Information (%x)", iv); 3033 secu_PrintSignerInfo(out, sigInfo, om, level + 2); 3034 } 3035 } 3036 3037 return 0; 3038 } 3039 3040 int 3041 SECU_PrintCrl(FILE *out, const SECItem *der, const char *m, int level) 3042 { 3043 PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 3044 CERTCrl *c = NULL; 3045 int rv = SEC_ERROR_NO_MEMORY; 3046 3047 if (!arena) 3048 return rv; 3049 do { 3050 /* Decode CRL */ 3051 c = PORT_ArenaZNew(arena, CERTCrl); 3052 if (!c) 3053 break; 3054 3055 rv = SEC_QuickDERDecodeItem(arena, c, SEC_ASN1_GET(CERT_CrlTemplate), der); 3056 if (rv != SECSuccess) 3057 break; 3058 SECU_PrintCRLInfo(out, c, m, level); 3059 } while (0); 3060 PORT_FreeArena(arena, PR_FALSE); 3061 return rv; 3062 } 3063 3064 /* 3065 ** secu_PrintPKCS7Encrypted 3066 ** Pretty print a PKCS7 encrypted data type (up to version 1). 3067 */ 3068 static int 3069 secu_PrintPKCS7Encrypted(FILE *out, SEC_PKCS7EncryptedData *src, 3070 secuPKCS7State state, const char *m, int level) 3071 { 3072 SECU_Indent(out, level); 3073 fprintf(out, "%s:\n", m); 3074 SECU_PrintInteger(out, &(src->version), "Version", level + 1); 3075 3076 return secu_PrintPKCS7EncContent(out, &src->encContentInfo, state, 3077 "Encrypted Content Information", level + 1); 3078 } 3079 3080 /* 3081 ** secu_PrintPKCS7Digested 3082 ** Pretty print a PKCS7 digested data type (up to version 1). 3083 */ 3084 static int 3085 secu_PrintPKCS7Digested(FILE *out, SEC_PKCS7DigestedData *src, 3086 secuPKCS7State state, const char *m, int level) 3087 { 3088 SECU_Indent(out, level); 3089 fprintf(out, "%s:\n", m); 3090 SECU_PrintInteger(out, &(src->version), "Version", level + 1); 3091 3092 SECU_PrintAlgorithmID(out, &src->digestAlg, "Digest Algorithm", 3093 level + 1); 3094 secu_PrintPKCS7ContentInfo(out, &src->contentInfo, state, 3095 "Content Information", level + 1); 3096 SECU_PrintAsHex(out, &src->digest, "Digest", level + 1); 3097 return 0; 3098 } 3099 3100 static int 3101 secu_PrintPKCS12Attributes(FILE *out, SECItem *item, const char *m, int level) 3102 { 3103 SECItem my = *item; 3104 SECItem attribute; 3105 SECItem attributeID; 3106 SECItem attributeValues; 3107 3108 if ((my.data[0] != (SEC_ASN1_CONSTRUCTED | SEC_ASN1_SET)) || 3109 SECSuccess != SECU_StripTagAndLength(&my)) { 3110 PORT_SetError(SEC_ERROR_BAD_DER); 3111 return SECFailure; 3112 } 3113 SECU_Indent(out, level); 3114 fprintf(out, "%s:\n", m); 3115 level++; 3116 3117 while (my.len) { 3118 if (SECSuccess != SECU_ExtractBERAndStep(&my, &attribute)) { 3119 return SECFailure; 3120 } 3121 if ((attribute.data[0] != (SEC_ASN1_CONSTRUCTED | SEC_ASN1_SEQUENCE)) || 3122 SECSuccess != SECU_StripTagAndLength(&attribute)) { 3123 PORT_SetError(SEC_ERROR_BAD_DER); 3124 return SECFailure; 3125 } 3126 3127 /* attribute ID */ 3128 if (SECSuccess != SECU_ExtractBERAndStep(&attribute, &attributeID)) { 3129 return SECFailure; 3130 } 3131 if ((attributeID.data[0] & SEC_ASN1_TAGNUM_MASK) != SEC_ASN1_OBJECT_ID) { 3132 PORT_SetError(SEC_ERROR_BAD_DER); 3133 return SECFailure; 3134 } 3135 SECU_PrintEncodedObjectID(out, &attributeID, "Attribute ID", level); 3136 3137 /* attribute values */ 3138 if (!attribute.len) { /* skip if there aren't any */ 3139 continue; 3140 } 3141 if (SECSuccess != SECU_ExtractBERAndStep(&attribute, &attributeValues)) { 3142 return SECFailure; 3143 } 3144 if (SECSuccess != SECU_StripTagAndLength(&attributeValues)) { 3145 return SECFailure; 3146 } 3147 while (attributeValues.len) { 3148 SECItem tmp; 3149 if (SECSuccess != SECU_ExtractBERAndStep(&attributeValues, &tmp)) { 3150 return SECFailure; 3151 } 3152 SECU_PrintAny(out, &tmp, NULL, level + 1); 3153 } 3154 } 3155 return SECSuccess; 3156 } 3157 3158 static int 3159 secu_PrintPKCS12Bag(FILE *out, SECItem *item, const char *desc, int level) 3160 { 3161 SECItem my = *item; 3162 SECItem bagID; 3163 SECItem bagValue; 3164 SECItem bagAttributes; 3165 SECOidTag bagTag; 3166 SECStatus rv; 3167 int i; 3168 char *m; 3169 3170 if ((my.data[0] != (SEC_ASN1_CONSTRUCTED | SEC_ASN1_SEQUENCE)) || 3171 SECSuccess != SECU_StripTagAndLength(&my)) { 3172 PORT_SetError(SEC_ERROR_BAD_DER); 3173 return SECFailure; 3174 } 3175 3176 /* bagId BAG-TYPE.&id ({PKCS12BagSet}) */ 3177 if (SECSuccess != SECU_ExtractBERAndStep(&my, &bagID)) { 3178 return SECFailure; 3179 } 3180 if ((bagID.data[0] & SEC_ASN1_TAGNUM_MASK) != SEC_ASN1_OBJECT_ID) { 3181 PORT_SetError(SEC_ERROR_BAD_DER); 3182 return SECFailure; 3183 } 3184 m = PR_smprintf("%s ID", desc); 3185 bagTag = SECU_PrintEncodedObjectID(out, &bagID, m ? m : "Bag ID", level); 3186 if (m) 3187 PR_smprintf_free(m); 3188 3189 /* bagValue [0] EXPLICIT BAG-TYPE.&type({PKCS12BagSet}{@bagID}) */ 3190 if (SECSuccess != SECU_ExtractBERAndStep(&my, &bagValue)) { 3191 return SECFailure; 3192 } 3193 if ((bagValue.data[0] & (SEC_ASN1_CLASS_MASK | SEC_ASN1_TAGNUM_MASK)) != 3194 (SEC_ASN1_CONTEXT_SPECIFIC | 0)) { 3195 PORT_SetError(SEC_ERROR_BAD_DER); 3196 return SECFailure; 3197 } 3198 if (SECSuccess != SECU_StripTagAndLength(&bagValue)) { 3199 return SECFailure; 3200 } 3201 3202 rv = SECSuccess; 3203 switch (bagTag) { 3204 case SEC_OID_PKCS12_V1_KEY_BAG_ID: 3205 /* Future we need to print out raw private keys. Not a priority since 3206 * p12util can't create files with unencrypted private keys, but 3207 * some tools can and do */ 3208 SECU_PrintAny(out, &bagValue, "Private Key", level); 3209 break; 3210 case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID: 3211 rv = SECU_PrintPrivateKey(out, &bagValue, 3212 "Encrypted Private Key", level); 3213 break; 3214 case SEC_OID_PKCS12_V1_CERT_BAG_ID: 3215 rv = secu_PrintPKCS12Bag(out, &bagValue, "Certificate Bag", level + 1); 3216 break; 3217 case SEC_OID_PKCS12_V1_CRL_BAG_ID: 3218 rv = secu_PrintPKCS12Bag(out, &bagValue, "Crl Bag", level + 1); 3219 break; 3220 case SEC_OID_PKCS12_V1_SECRET_BAG_ID: 3221 rv = secu_PrintPKCS12Bag(out, &bagValue, "Secret Bag", level + 1); 3222 break; 3223 /* from recursive call from CRL and certificate Bag */ 3224 case SEC_OID_PKCS9_X509_CRL: 3225 case SEC_OID_PKCS9_X509_CERT: 3226 case SEC_OID_PKCS9_SDSI_CERT: 3227 /* unwrap the octect string */ 3228 rv = SECU_StripTagAndLength(&bagValue); 3229 if (rv != SECSuccess) { 3230 break; 3231 } 3232 /* fall through */ 3233 case SEC_OID_PKCS12_CERT_AND_CRL_BAG_ID: 3234 case SEC_OID_PKCS12_X509_CERT_CRL_BAG: 3235 case SEC_OID_PKCS12_SDSI_CERT_BAG: 3236 if (strcmp(desc, "Crl Bag") == 0) { 3237 rv = SECU_PrintSignedData(out, &bagValue, NULL, level + 1, 3238 SECU_PrintCrl); 3239 } else { 3240 rv = SECU_PrintSignedData(out, &bagValue, NULL, level + 1, 3241 SECU_PrintCertificate); 3242 } 3243 break; 3244 case SEC_OID_PKCS12_V1_SAFE_CONTENTS_BAG_ID: 3245 for (i = 1; my.len; i++) { 3246 SECItem nextBag; 3247 rv = SECU_ExtractBERAndStep(&bagValue, &nextBag); 3248 if (rv != SECSuccess) { 3249 break; 3250 } 3251 m = PR_smprintf("Nested Bag %d", i); 3252 rv = secu_PrintPKCS12Bag(out, &nextBag, 3253 m ? m : "Nested Bag", level + 1); 3254 if (m) 3255 PR_smprintf_free(m); 3256 if (rv != SECSuccess) { 3257 break; 3258 } 3259 } 3260 break; 3261 default: 3262 m = PR_smprintf("%s Value", desc); 3263 SECU_PrintAny(out, &bagValue, m ? m : "Bag Value", level); 3264 if (m) 3265 PR_smprintf_free(m); 3266 } 3267 if (rv != SECSuccess) { 3268 return rv; 3269 } 3270 3271 /* bagAttributes SET OF PKCS12Attributes OPTIONAL */ 3272 if (my.len && 3273 (my.data[0] == (SEC_ASN1_CONSTRUCTED | SEC_ASN1_SET))) { 3274 if (SECSuccess != SECU_ExtractBERAndStep(&my, &bagAttributes)) { 3275 return SECFailure; 3276 } 3277 m = PR_smprintf("%s Attributes", desc); 3278 rv = secu_PrintPKCS12Attributes(out, &bagAttributes, 3279 m ? m : "Bag Attributes", level); 3280 if (m) 3281 PR_smprintf_free(m); 3282 } 3283 return rv; 3284 } 3285 3286 static int 3287 secu_PrintPKCS7Data(FILE *out, SECItem *item, secuPKCS7State state, 3288 const char *desc, int level) 3289 { 3290 SECItem my = *item; 3291 SECItem nextbag; 3292 int i; 3293 SECStatus rv; 3294 3295 /* walk down each safe */ 3296 switch (state) { 3297 case secuPKCS7PKCS12AuthSafe: 3298 if ((my.data[0] != (SEC_ASN1_CONSTRUCTED | SEC_ASN1_SEQUENCE)) || 3299 SECSuccess != SECU_StripTagAndLength(&my)) { 3300 PORT_SetError(SEC_ERROR_BAD_DER); 3301 return SECFailure; 3302 } 3303 for (i = 1; my.len; i++) { 3304 char *m; 3305 if (SECSuccess != SECU_ExtractBERAndStep(&my, &nextbag)) { 3306 return SECFailure; 3307 } 3308 m = PR_smprintf("Safe %d", i); 3309 rv = secu_PrintDERPKCS7ContentInfo(out, &nextbag, 3310 secuPKCS7PKCS12Safe, 3311 m ? m : "Safe", level); 3312 if (m) 3313 PR_smprintf_free(m); 3314 if (rv != SECSuccess) { 3315 return SECFailure; 3316 } 3317 } 3318 return SECSuccess; 3319 case secuPKCS7PKCS12Safe: 3320 if ((my.data[0] != (SEC_ASN1_CONSTRUCTED | SEC_ASN1_SEQUENCE)) || 3321 SECSuccess != SECU_StripTagAndLength(&my)) { 3322 PORT_SetError(SEC_ERROR_BAD_DER); 3323 return SECFailure; 3324 } 3325 for (i = 1; my.len; i++) { 3326 char *m; 3327 if (SECSuccess != SECU_ExtractBERAndStep(&my, &nextbag)) { 3328 return SECFailure; 3329 } 3330 m = PR_smprintf("Bag %d", i); 3331 rv = secu_PrintPKCS12Bag(out, &nextbag, 3332 m ? m : "Bag", level); 3333 if (m) 3334 PR_smprintf_free(m); 3335 if (rv != SECSuccess) { 3336 return SECFailure; 3337 } 3338 } 3339 return SECSuccess; 3340 case secuPKCS7Unknown: 3341 SECU_PrintAsHex(out, item, desc, level); 3342 break; 3343 } 3344 return SECSuccess; 3345 } 3346 3347 /* 3348 ** secu_PrintPKCS7ContentInfo 3349 ** Takes a SEC_PKCS7ContentInfo type and sends the contents to the 3350 ** appropriate function 3351 */ 3352 static int 3353 secu_PrintPKCS7ContentInfo(FILE *out, SEC_PKCS7ContentInfo *src, 3354 secuPKCS7State state, const char *m, int level) 3355 { 3356 const char *desc; 3357 SECOidTag kind; 3358 int rv; 3359 3360 SECU_Indent(out, level); 3361 fprintf(out, "%s:\n", m); 3362 level++; 3363 3364 if (src->contentTypeTag == NULL) 3365 src->contentTypeTag = SECOID_FindOID(&(src->contentType)); 3366 3367 if (src->contentTypeTag == NULL) { 3368 desc = "Unknown"; 3369 kind = SEC_OID_UNKNOWN; 3370 } else { 3371 desc = src->contentTypeTag->desc; 3372 kind = src->contentTypeTag->offset; 3373 } 3374 3375 if (src->content.data == NULL) { 3376 SECU_Indent(out, level); 3377 fprintf(out, "%s:\n", desc); 3378 level++; 3379 SECU_Indent(out, level); 3380 fprintf(out, "<no content>\n"); 3381 return 0; 3382 } 3383 3384 rv = 0; 3385 switch (kind) { 3386 case SEC_OID_PKCS7_SIGNED_DATA: /* Signed Data */ 3387 rv = secu_PrintPKCS7Signed(out, src->content.signedData, 3388 state, desc, level); 3389 break; 3390 3391 case SEC_OID_PKCS7_ENVELOPED_DATA: /* Enveloped Data */ 3392 rv = secu_PrintPKCS7Enveloped(out, src->content.envelopedData, 3393 state, desc, level); 3394 break; 3395 3396 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: /* Signed and Enveloped */ 3397 rv = secu_PrintPKCS7SignedAndEnveloped(out, 3398 src->content.signedAndEnvelopedData, 3399 state, desc, level); 3400 break; 3401 3402 case SEC_OID_PKCS7_DIGESTED_DATA: /* Digested Data */ 3403 rv = secu_PrintPKCS7Digested(out, src->content.digestedData, 3404 state, desc, level); 3405 break; 3406 3407 case SEC_OID_PKCS7_ENCRYPTED_DATA: /* Encrypted Data */ 3408 rv = secu_PrintPKCS7Encrypted(out, src->content.encryptedData, 3409 state, desc, level); 3410 break; 3411 3412 case SEC_OID_PKCS7_DATA: 3413 rv = secu_PrintPKCS7Data(out, src->content.data, state, desc, level); 3414 break; 3415 3416 default: 3417 SECU_PrintAsHex(out, src->content.data, desc, level); 3418 break; 3419 } 3420 3421 return rv; 3422 } 3423 3424 /* 3425 ** SECU_PrintPKCS7ContentInfo 3426 ** Decode and print any major PKCS7 data type (up to version 1). 3427 */ 3428 static int 3429 secu_PrintDERPKCS7ContentInfo(FILE *out, SECItem *der, secuPKCS7State state, 3430 const char *m, int level) 3431 { 3432 SEC_PKCS7ContentInfo *cinfo; 3433 int rv; 3434 3435 cinfo = SEC_PKCS7DecodeItem(der, NULL, NULL, NULL, NULL, NULL, NULL, NULL); 3436 if (cinfo != NULL) { 3437 /* Send it to recursive parsing and printing module */ 3438 rv = secu_PrintPKCS7ContentInfo(out, cinfo, state, m, level); 3439 SEC_PKCS7DestroyContentInfo(cinfo); 3440 } else { 3441 rv = -1; 3442 } 3443 3444 return rv; 3445 } 3446 3447 int 3448 SECU_PrintPKCS7ContentInfo(FILE *out, SECItem *der, char *m, int level) 3449 { 3450 return secu_PrintDERPKCS7ContentInfo(out, der, secuPKCS7Unknown, m, level); 3451 } 3452 3453 /* 3454 ** End of PKCS7 functions 3455 */ 3456 3457 void 3458 printFlags(FILE *out, unsigned int flags, int level) 3459 { 3460 if (flags & CERTDB_TERMINAL_RECORD) { 3461 SECU_Indent(out, level); 3462 fprintf(out, "Terminal Record\n"); 3463 } 3464 if (flags & CERTDB_TRUSTED) { 3465 SECU_Indent(out, level); 3466 fprintf(out, "Trusted\n"); 3467 } 3468 if (flags & CERTDB_SEND_WARN) { 3469 SECU_Indent(out, level); 3470 fprintf(out, "Warn When Sending\n"); 3471 } 3472 if (flags & CERTDB_VALID_CA) { 3473 SECU_Indent(out, level); 3474 fprintf(out, "Valid CA\n"); 3475 } 3476 if (flags & CERTDB_TRUSTED_CA) { 3477 SECU_Indent(out, level); 3478 fprintf(out, "Trusted CA\n"); 3479 } 3480 if (flags & CERTDB_NS_TRUSTED_CA) { 3481 SECU_Indent(out, level); 3482 fprintf(out, "Netscape Trusted CA\n"); 3483 } 3484 if (flags & CERTDB_USER) { 3485 SECU_Indent(out, level); 3486 fprintf(out, "User\n"); 3487 } 3488 if (flags & CERTDB_TRUSTED_CLIENT_CA) { 3489 SECU_Indent(out, level); 3490 fprintf(out, "Trusted Client CA\n"); 3491 } 3492 if (flags & CERTDB_GOVT_APPROVED_CA) { 3493 SECU_Indent(out, level); 3494 fprintf(out, "Step-up\n"); 3495 } 3496 } 3497 3498 void 3499 SECU_PrintTrustFlags(FILE *out, CERTCertTrust *trust, char *m, int level) 3500 { 3501 SECU_Indent(out, level); 3502 fprintf(out, "%s:\n", m); 3503 SECU_Indent(out, level + 1); 3504 fprintf(out, "SSL Flags:\n"); 3505 printFlags(out, trust->sslFlags, level + 2); 3506 SECU_Indent(out, level + 1); 3507 fprintf(out, "Email Flags:\n"); 3508 printFlags(out, trust->emailFlags, level + 2); 3509 SECU_Indent(out, level + 1); 3510 fprintf(out, "Object Signing Flags:\n"); 3511 printFlags(out, trust->objectSigningFlags, level + 2); 3512 } 3513 3514 int 3515 SECU_PrintDERName(FILE *out, SECItem *der, const char *m, int level) 3516 { 3517 PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 3518 CERTName *name; 3519 int rv = SEC_ERROR_NO_MEMORY; 3520 3521 if (!arena) 3522 return rv; 3523 3524 name = PORT_ArenaZNew(arena, CERTName); 3525 if (!name) 3526 goto loser; 3527 3528 rv = SEC_ASN1DecodeItem(arena, name, SEC_ASN1_GET(CERT_NameTemplate), der); 3529 if (rv) 3530 goto loser; 3531 3532 SECU_PrintName(out, name, m, level); 3533 if (!SECU_GetWrapEnabled()) /*SECU_PrintName didn't add newline*/ 3534 SECU_Newline(out); 3535 loser: 3536 PORT_FreeArena(arena, PR_FALSE); 3537 return rv; 3538 } 3539 3540 typedef enum { 3541 noSignature = 0, 3542 withSignature = 1 3543 } SignatureOptionType; 3544 3545 static int 3546 secu_PrintSignedDataSigOpt(FILE *out, SECItem *der, const char *m, 3547 int level, SECU_PPFunc inner, 3548 SignatureOptionType signatureOption) 3549 { 3550 PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 3551 CERTSignedData *sd; 3552 int rv = SEC_ERROR_NO_MEMORY; 3553 3554 if (!arena) 3555 return rv; 3556 3557 /* Strip off the signature */ 3558 sd = PORT_ArenaZNew(arena, CERTSignedData); 3559 if (!sd) 3560 goto loser; 3561 3562 rv = SEC_ASN1DecodeItem(arena, sd, SEC_ASN1_GET(CERT_SignedDataTemplate), 3563 der); 3564 if (rv) 3565 goto loser; 3566 3567 if (m) { 3568 SECU_Indent(out, level); 3569 fprintf(out, "%s:\n", m); 3570 } else { 3571 level -= 1; 3572 } 3573 rv = (*inner)(out, &sd->data, "Data", level + 1); 3574 3575 if (signatureOption == withSignature) { 3576 SECU_PrintAlgorithmID(out, &sd->signatureAlgorithm, "Signature Algorithm", 3577 level + 1); 3578 DER_ConvertBitString(&sd->signature); 3579 SECU_PrintAsHex(out, &sd->signature, "Signature", level + 1); 3580 } 3581 SECU_PrintFingerprints(out, der, "Fingerprint", level + 1); 3582 loser: 3583 PORT_FreeArena(arena, PR_FALSE); 3584 return rv; 3585 } 3586 3587 int 3588 SECU_PrintSignedData(FILE *out, SECItem *der, const char *m, 3589 int level, SECU_PPFunc inner) 3590 { 3591 return secu_PrintSignedDataSigOpt(out, der, m, level, inner, 3592 withSignature); 3593 } 3594 3595 int 3596 SECU_PrintSignedContent(FILE *out, SECItem *der, char *m, 3597 int level, SECU_PPFunc inner) 3598 { 3599 return secu_PrintSignedDataSigOpt(out, der, m, level, inner, 3600 noSignature); 3601 } 3602 3603 SECStatus 3604 SEC_PrintCertificateAndTrust(CERTCertificate *cert, 3605 const char *label, 3606 CERTCertTrust *trust) 3607 { 3608 SECStatus rv; 3609 SECItem data; 3610 CERTCertTrust certTrust; 3611 PK11SlotList *slotList; 3612 PRBool falseAttributeFound = PR_FALSE; 3613 PRBool trueAttributeFound = PR_FALSE; 3614 const char *moz_policy_ca_info = NULL; 3615 3616 data.data = cert->derCert.data; 3617 data.len = cert->derCert.len; 3618 3619 rv = SECU_PrintSignedData(stdout, &data, label, 0, 3620 SECU_PrintCertificate); 3621 if (rv) { 3622 return (SECFailure); 3623 } 3624 3625 slotList = PK11_GetAllSlotsForCert(cert, NULL); 3626 if (slotList) { 3627 PK11SlotListElement *se = PK11_GetFirstSafe(slotList); 3628 for (; se; se = PK11_GetNextSafe(slotList, se, PR_FALSE)) { 3629 CK_OBJECT_HANDLE handle = PK11_FindCertInSlot(se->slot, cert, NULL); 3630 if (handle != CK_INVALID_HANDLE) { 3631 PORT_SetError(0); 3632 if (PK11_HasAttributeSet(se->slot, handle, 3633 CKA_NSS_MOZILLA_CA_POLICY, PR_FALSE)) { 3634 trueAttributeFound = PR_TRUE; 3635 } else if (!PORT_GetError()) { 3636 falseAttributeFound = PR_TRUE; 3637 } 3638 } 3639 } 3640 PK11_FreeSlotList(slotList); 3641 } 3642 3643 if (trueAttributeFound) { 3644 moz_policy_ca_info = "true (attribute present)"; 3645 } else if (falseAttributeFound) { 3646 moz_policy_ca_info = "false (attribute present)"; 3647 } else { 3648 moz_policy_ca_info = "false (attribute missing)"; 3649 } 3650 SECU_Indent(stdout, 1); 3651 printf("Mozilla-CA-Policy: %s\n", moz_policy_ca_info); 3652 3653 if (trust) { 3654 SECU_PrintTrustFlags(stdout, trust, 3655 "Certificate Trust Flags", 1); 3656 } else if (CERT_GetCertTrust(cert, &certTrust) == SECSuccess) { 3657 SECU_PrintTrustFlags(stdout, &certTrust, 3658 "Certificate Trust Flags", 1); 3659 } 3660 3661 /* The distrust fields are hard-coded in nssckbi and read-only. 3662 * If verifying some cert, with vfychain, for instance, the certificate may 3663 * not have a defined slot if not imported. */ 3664 if (cert->slot != NULL && cert->distrust != NULL) { 3665 const unsigned int kDistrustFieldSize = 13; 3666 fprintf(stdout, "\n"); 3667 SECU_Indent(stdout, 1); 3668 fprintf(stdout, "%s:\n", "Certificate Distrust Dates"); 3669 if (cert->distrust->serverDistrustAfter.len == kDistrustFieldSize) { 3670 SECU_PrintTimeChoice(stdout, 3671 &cert->distrust->serverDistrustAfter, 3672 "Server Distrust After", 2); 3673 } 3674 if (cert->distrust->emailDistrustAfter.len == kDistrustFieldSize) { 3675 SECU_PrintTimeChoice(stdout, 3676 &cert->distrust->emailDistrustAfter, 3677 "E-mail Distrust After", 2); 3678 } 3679 } 3680 3681 printf("\n"); 3682 3683 return (SECSuccess); 3684 } 3685 3686 static char * 3687 bestCertName(CERTCertificate *cert) 3688 { 3689 if (cert->nickname) { 3690 return cert->nickname; 3691 } 3692 if (cert->emailAddr && cert->emailAddr[0]) { 3693 return cert->emailAddr; 3694 } 3695 return cert->subjectName; 3696 } 3697 3698 void 3699 SECU_printCertProblemsOnDate(FILE *outfile, CERTCertDBHandle *handle, 3700 CERTCertificate *cert, PRBool checksig, 3701 SECCertificateUsage certUsage, void *pinArg, PRBool verbose, 3702 PRTime datetime) 3703 { 3704 CERTVerifyLog log; 3705 CERTVerifyLogNode *node; 3706 3707 PRErrorCode err = PORT_GetError(); 3708 3709 log.arena = PORT_NewArena(512); 3710 log.head = log.tail = NULL; 3711 log.count = 0; 3712 CERT_VerifyCertificate(handle, cert, checksig, certUsage, datetime, pinArg, &log, NULL); 3713 3714 SECU_displayVerifyLog(outfile, &log, verbose); 3715 3716 for (node = log.head; node; node = node->next) { 3717 if (node->cert) 3718 CERT_DestroyCertificate(node->cert); 3719 } 3720 PORT_FreeArena(log.arena, PR_FALSE); 3721 3722 PORT_SetError(err); /* restore original error code */ 3723 } 3724 3725 void 3726 SECU_displayVerifyLog(FILE *outfile, CERTVerifyLog *log, 3727 PRBool verbose) 3728 { 3729 CERTVerifyLogNode *node = NULL; 3730 unsigned int depth = (unsigned int)-1; 3731 unsigned int flags = 0; 3732 char *errstr = NULL; 3733 3734 if (log->count > 0) { 3735 fprintf(outfile, "PROBLEM WITH THE CERT CHAIN:\n"); 3736 for (node = log->head; node; node = node->next) { 3737 if (depth != node->depth) { 3738 depth = node->depth; 3739 fprintf(outfile, "CERT %d. %s %s:\n", depth, 3740 bestCertName(node->cert), 3741 depth ? "[Certificate Authority]" : ""); 3742 if (verbose) { 3743 const char *emailAddr; 3744 emailAddr = CERT_GetFirstEmailAddress(node->cert); 3745 if (emailAddr) { 3746 fprintf(outfile, "Email Address(es): "); 3747 do { 3748 fprintf(outfile, "%s\n", emailAddr); 3749 emailAddr = CERT_GetNextEmailAddress(node->cert, 3750 emailAddr); 3751 } while (emailAddr); 3752 } 3753 } 3754 } 3755 fprintf(outfile, " ERROR %ld: %s\n", node->error, 3756 SECU_Strerror(node->error)); 3757 errstr = NULL; 3758 switch (node->error) { 3759 case SEC_ERROR_INADEQUATE_KEY_USAGE: 3760 flags = (unsigned int)((char *)node->arg - (char *)NULL); 3761 switch (flags) { 3762 case KU_DIGITAL_SIGNATURE: 3763 errstr = "Cert cannot sign."; 3764 break; 3765 case KU_KEY_ENCIPHERMENT: 3766 errstr = "Cert cannot encrypt."; 3767 break; 3768 case KU_KEY_CERT_SIGN: 3769 errstr = "Cert cannot sign other certs."; 3770 break; 3771 default: 3772 errstr = "[unknown usage]."; 3773 break; 3774 } 3775 break; 3776 case SEC_ERROR_INADEQUATE_CERT_TYPE: 3777 flags = (unsigned int)((char *)node->arg - (char *)NULL); 3778 switch (flags) { 3779 case NS_CERT_TYPE_SSL_CLIENT: 3780 case NS_CERT_TYPE_SSL_SERVER: 3781 errstr = "Cert cannot be used for SSL."; 3782 break; 3783 case NS_CERT_TYPE_SSL_CA: 3784 errstr = "Cert cannot be used as an SSL CA."; 3785 break; 3786 case NS_CERT_TYPE_EMAIL: 3787 errstr = "Cert cannot be used for SMIME."; 3788 break; 3789 case NS_CERT_TYPE_EMAIL_CA: 3790 errstr = "Cert cannot be used as an SMIME CA."; 3791 break; 3792 case NS_CERT_TYPE_OBJECT_SIGNING: 3793 errstr = "Cert cannot be used for object signing."; 3794 break; 3795 case NS_CERT_TYPE_OBJECT_SIGNING_CA: 3796 errstr = "Cert cannot be used as an object signing CA."; 3797 break; 3798 default: 3799 errstr = "[unknown usage]."; 3800 break; 3801 } 3802 break; 3803 case SEC_ERROR_UNKNOWN_ISSUER: 3804 case SEC_ERROR_UNTRUSTED_ISSUER: 3805 case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE: 3806 errstr = node->cert->issuerName; 3807 break; 3808 default: 3809 break; 3810 } 3811 if (errstr) { 3812 fprintf(stderr, " %s\n", errstr); 3813 } 3814 } 3815 } 3816 } 3817 3818 void 3819 SECU_printCertProblems(FILE *outfile, CERTCertDBHandle *handle, 3820 CERTCertificate *cert, PRBool checksig, 3821 SECCertificateUsage certUsage, void *pinArg, PRBool verbose) 3822 { 3823 SECU_printCertProblemsOnDate(outfile, handle, cert, checksig, 3824 certUsage, pinArg, verbose, PR_Now()); 3825 } 3826 3827 SECStatus 3828 SECU_StoreCRL(PK11SlotInfo *slot, SECItem *derCrl, PRFileDesc *outFile, 3829 PRBool ascii, char *url) 3830 { 3831 PORT_Assert(derCrl != NULL); 3832 if (!derCrl) { 3833 PORT_SetError(SEC_ERROR_INVALID_ARGS); 3834 return SECFailure; 3835 } 3836 3837 if (outFile != NULL) { 3838 if (ascii) { 3839 PR_fprintf(outFile, "%s\n%s\n%s\n", NS_CRL_HEADER, 3840 BTOA_DataToAscii(derCrl->data, derCrl->len), 3841 NS_CRL_TRAILER); 3842 } else { 3843 if (PR_Write(outFile, derCrl->data, derCrl->len) != derCrl->len) { 3844 return SECFailure; 3845 } 3846 } 3847 } 3848 if (slot) { 3849 CERTSignedCrl *newCrl = PK11_ImportCRL(slot, derCrl, url, 3850 SEC_CRL_TYPE, NULL, 0, NULL, 0); 3851 if (newCrl != NULL) { 3852 SEC_DestroyCrl(newCrl); 3853 return SECSuccess; 3854 } 3855 return SECFailure; 3856 } 3857 if (!outFile && !slot) { 3858 PORT_SetError(SEC_ERROR_INVALID_ARGS); 3859 return SECFailure; 3860 } 3861 return SECSuccess; 3862 } 3863 3864 SECStatus 3865 SECU_SignAndEncodeCRL(CERTCertificate *issuer, CERTSignedCrl *signCrl, 3866 SECOidTag hashAlgTag, SignAndEncodeFuncExitStat *resCode) 3867 { 3868 SECItem der; 3869 SECKEYPrivateKey *caPrivateKey = NULL; 3870 SECStatus rv; 3871 PLArenaPool *arena; 3872 SECOidTag algID; 3873 void *dummy; 3874 3875 PORT_Assert(issuer != NULL && signCrl != NULL); 3876 if (!issuer || !signCrl) { 3877 PORT_SetError(SEC_ERROR_INVALID_ARGS); 3878 return SECFailure; 3879 } 3880 3881 arena = signCrl->arena; 3882 3883 caPrivateKey = PK11_FindKeyByAnyCert(issuer, NULL); 3884 if (caPrivateKey == NULL) { 3885 *resCode = noKeyFound; 3886 return SECFailure; 3887 } 3888 3889 algID = SEC_GetSignatureAlgorithmOidTagByKey(caPrivateKey, NULL, hashAlgTag); 3890 if (algID == SEC_OID_UNKNOWN) { 3891 *resCode = noSignatureMatch; 3892 rv = SECFailure; 3893 goto done; 3894 } 3895 3896 if (!signCrl->crl.signatureAlg.parameters.data) { 3897 rv = SECOID_SetAlgorithmID(arena, &signCrl->crl.signatureAlg, algID, 0); 3898 if (rv != SECSuccess) { 3899 *resCode = failToEncode; 3900 goto done; 3901 } 3902 } 3903 3904 der.len = 0; 3905 der.data = NULL; 3906 dummy = SEC_ASN1EncodeItem(arena, &der, &signCrl->crl, 3907 SEC_ASN1_GET(CERT_CrlTemplate)); 3908 if (!dummy) { 3909 *resCode = failToEncode; 3910 rv = SECFailure; 3911 goto done; 3912 } 3913 3914 rv = SECU_DerSignDataCRL(arena, &signCrl->signatureWrap, 3915 der.data, der.len, caPrivateKey, algID); 3916 if (rv != SECSuccess) { 3917 *resCode = failToSign; 3918 goto done; 3919 } 3920 3921 signCrl->derCrl = PORT_ArenaZNew(arena, SECItem); 3922 if (signCrl->derCrl == NULL) { 3923 *resCode = noMem; 3924 PORT_SetError(SEC_ERROR_NO_MEMORY); 3925 rv = SECFailure; 3926 goto done; 3927 } 3928 3929 signCrl->derCrl->len = 0; 3930 signCrl->derCrl->data = NULL; 3931 dummy = SEC_ASN1EncodeItem(arena, signCrl->derCrl, signCrl, 3932 SEC_ASN1_GET(CERT_SignedCrlTemplate)); 3933 if (!dummy) { 3934 *resCode = failToEncode; 3935 rv = SECFailure; 3936 goto done; 3937 } 3938 3939 done: 3940 SECKEY_DestroyPrivateKey(caPrivateKey); 3941 return rv; 3942 } 3943 3944 SECStatus 3945 SECU_CopyCRL(PLArenaPool *destArena, CERTCrl *destCrl, CERTCrl *srcCrl) 3946 { 3947 void *dummy; 3948 SECStatus rv = SECSuccess; 3949 SECItem der; 3950 3951 PORT_Assert(destArena && srcCrl && destCrl); 3952 if (!destArena || !srcCrl || !destCrl) { 3953 PORT_SetError(SEC_ERROR_INVALID_ARGS); 3954 return SECFailure; 3955 } 3956 3957 der.len = 0; 3958 der.data = NULL; 3959 dummy = SEC_ASN1EncodeItem(destArena, &der, srcCrl, 3960 SEC_ASN1_GET(CERT_CrlTemplate)); 3961 if (!dummy) { 3962 return SECFailure; 3963 } 3964 3965 rv = SEC_QuickDERDecodeItem(destArena, destCrl, 3966 SEC_ASN1_GET(CERT_CrlTemplate), &der); 3967 if (rv != SECSuccess) { 3968 return SECFailure; 3969 } 3970 3971 destCrl->arena = destArena; 3972 3973 return rv; 3974 } 3975 3976 SECStatus 3977 SECU_DerSignDataCRL(PLArenaPool *arena, CERTSignedData *sd, 3978 unsigned char *buf, int len, SECKEYPrivateKey *pk, 3979 SECOidTag algID) 3980 { 3981 SECItem it; 3982 SECStatus rv; 3983 3984 it.data = 0; 3985 3986 /* XXX We should probably have some asserts here to make sure the key type 3987 * and algID match 3988 */ 3989 3990 /* Sign input buffer */ 3991 rv = SEC_SignData(&it, buf, len, pk, algID); 3992 if (rv != SECSuccess) { 3993 goto loser; 3994 } 3995 3996 /* Fill out SignedData object */ 3997 PORT_Memset(sd, 0, sizeof(*sd)); 3998 sd->data.data = buf; 3999 sd->data.len = len; 4000 rv = SECITEM_CopyItem(arena, &sd->signature, &it); 4001 if (rv != SECSuccess) { 4002 goto loser; 4003 } 4004 4005 sd->signature.len <<= 3; /* convert to bit string */ 4006 rv = SECOID_SetAlgorithmID(arena, &sd->signatureAlgorithm, algID, 0); 4007 if (rv != SECSuccess) { 4008 goto loser; 4009 } 4010 4011 loser: 4012 PORT_Free(it.data); 4013 return rv; 4014 } 4015 4016 /* 4017 * Find the issuer of a Crl. Use the authorityKeyID if it exists. 4018 */ 4019 CERTCertificate * 4020 SECU_FindCrlIssuer(CERTCertDBHandle *dbhandle, SECItem *subject, 4021 CERTAuthKeyID *authorityKeyID, PRTime validTime) 4022 { 4023 CERTCertificate *issuerCert = NULL; 4024 CERTCertList *certList = NULL; 4025 CERTCertTrust trust; 4026 4027 if (!subject) { 4028 PORT_SetError(SEC_ERROR_INVALID_ARGS); 4029 return NULL; 4030 } 4031 4032 certList = 4033 CERT_CreateSubjectCertList(NULL, dbhandle, subject, 4034 validTime, PR_TRUE); 4035 if (certList) { 4036 CERTCertListNode *node = CERT_LIST_HEAD(certList); 4037 4038 /* XXX and authoritykeyid in the future */ 4039 while (!CERT_LIST_END(node, certList)) { 4040 CERTCertificate *cert = node->cert; 4041 /* check cert CERTCertTrust data is allocated, check cert 4042 usage extension, check that cert has pkey in db. Select 4043 the first (newest) user cert */ 4044 if (CERT_GetCertTrust(cert, &trust) == SECSuccess && 4045 CERT_CheckCertUsage(cert, KU_CRL_SIGN) == SECSuccess && 4046 CERT_IsUserCert(cert)) { 4047 4048 issuerCert = CERT_DupCertificate(cert); 4049 break; 4050 } 4051 node = CERT_LIST_NEXT(node); 4052 } 4053 CERT_DestroyCertList(certList); 4054 } 4055 return (issuerCert); 4056 } 4057 4058 /* Encodes and adds extensions to the CRL or CRL entries. */ 4059 SECStatus 4060 SECU_EncodeAndAddExtensionValue(PLArenaPool *arena, void *extHandle, 4061 void *value, PRBool criticality, int extenType, 4062 EXTEN_EXT_VALUE_ENCODER EncodeValueFn) 4063 { 4064 SECItem encodedValue; 4065 SECStatus rv; 4066 4067 encodedValue.data = NULL; 4068 encodedValue.len = 0; 4069 do { 4070 rv = (*EncodeValueFn)(arena, value, &encodedValue); 4071 if (rv != SECSuccess) 4072 break; 4073 4074 rv = CERT_AddExtension(extHandle, extenType, &encodedValue, 4075 criticality, PR_TRUE); 4076 if (rv != SECSuccess) 4077 break; 4078 } while (0); 4079 4080 return (rv); 4081 } 4082 4083 CERTCertificate * 4084 SECU_FindCertByNicknameOrFilename(CERTCertDBHandle *handle, 4085 char *name, PRBool ascii, 4086 void *pwarg) 4087 { 4088 CERTCertificate *the_cert; 4089 the_cert = CERT_FindCertByNicknameOrEmailAddrCX(handle, name, pwarg); 4090 if (the_cert) { 4091 return the_cert; 4092 } 4093 the_cert = PK11_FindCertFromNickname(name, pwarg); 4094 if (!the_cert) { 4095 /* Don't have a cert with name "name" in the DB. Try to 4096 * open a file with such name and get the cert from there.*/ 4097 SECStatus rv; 4098 SECItem item = { 0, NULL, 0 }; 4099 PRFileDesc *fd = PR_Open(name, PR_RDONLY, 0777); 4100 if (!fd) { 4101 return NULL; 4102 } 4103 rv = SECU_ReadDERFromFile(&item, fd, ascii, PR_FALSE); 4104 PR_Close(fd); 4105 if (rv != SECSuccess || !item.len) { 4106 PORT_Free(item.data); 4107 return NULL; 4108 } 4109 the_cert = CERT_NewTempCertificate(handle, &item, 4110 NULL /* nickname */, 4111 PR_FALSE /* isPerm */, 4112 PR_TRUE /* copyDER */); 4113 PORT_Free(item.data); 4114 } 4115 return the_cert; 4116 } 4117 4118 /* Convert a SSL/TLS protocol version string into the respective numeric value 4119 * defined by the SSL_LIBRARY_VERSION_* constants, 4120 * while accepting a flexible set of case-insensitive identifiers. 4121 * 4122 * Caller must specify bufLen, allowing the function to operate on substrings. 4123 */ 4124 static SECStatus 4125 SECU_GetSSLVersionFromName(const char *buf, size_t bufLen, PRUint16 *version) 4126 { 4127 if (!buf || !version) { 4128 PORT_SetError(SEC_ERROR_INVALID_ARGS); 4129 return SECFailure; 4130 } 4131 4132 if (!PL_strncasecmp(buf, "ssl3", bufLen)) { 4133 *version = SSL_LIBRARY_VERSION_3_0; 4134 return SECSuccess; 4135 } 4136 if (!PL_strncasecmp(buf, "tls1.0", bufLen)) { 4137 *version = SSL_LIBRARY_VERSION_TLS_1_0; 4138 return SECSuccess; 4139 } 4140 if (!PL_strncasecmp(buf, "tls1.1", bufLen)) { 4141 *version = SSL_LIBRARY_VERSION_TLS_1_1; 4142 return SECSuccess; 4143 } 4144 if (!PL_strncasecmp(buf, "tls1.2", bufLen)) { 4145 *version = SSL_LIBRARY_VERSION_TLS_1_2; 4146 return SECSuccess; 4147 } 4148 4149 if (!PL_strncasecmp(buf, "tls1.3", bufLen)) { 4150 *version = SSL_LIBRARY_VERSION_TLS_1_3; 4151 return SECSuccess; 4152 } 4153 4154 PORT_SetError(SEC_ERROR_INVALID_ARGS); 4155 return SECFailure; 4156 } 4157 4158 SECStatus 4159 SECU_ParseSSLVersionRangeString(const char *input, 4160 const SSLVersionRange defaultVersionRange, 4161 SSLVersionRange *vrange) 4162 { 4163 const char *colonPos; 4164 size_t colonIndex; 4165 const char *maxStr; 4166 4167 if (!input || !vrange) { 4168 PORT_SetError(SEC_ERROR_INVALID_ARGS); 4169 return SECFailure; 4170 } 4171 4172 // We don't support SSL2 any longer. 4173 if (defaultVersionRange.min < SSL_LIBRARY_VERSION_3_0 || 4174 defaultVersionRange.max < SSL_LIBRARY_VERSION_3_0) { 4175 PORT_SetError(SEC_ERROR_INVALID_ARGS); 4176 return SECFailure; 4177 } 4178 4179 if (!strcmp(input, ":")) { 4180 /* special value, use default */ 4181 *vrange = defaultVersionRange; 4182 return SECSuccess; 4183 } 4184 4185 colonPos = strchr(input, ':'); 4186 if (!colonPos) { 4187 PORT_SetError(SEC_ERROR_INVALID_ARGS); 4188 return SECFailure; 4189 } 4190 4191 colonIndex = colonPos - input; 4192 maxStr = colonPos + 1; 4193 4194 if (!colonIndex) { 4195 /* colon was first character, min version is empty */ 4196 vrange->min = defaultVersionRange.min; 4197 } else { 4198 PRUint16 version; 4199 /* colonIndex is equivalent to the length of the min version substring */ 4200 if (SECU_GetSSLVersionFromName(input, colonIndex, &version) != SECSuccess) { 4201 PORT_SetError(SEC_ERROR_INVALID_ARGS); 4202 return SECFailure; 4203 } 4204 4205 vrange->min = version; 4206 } 4207 4208 if (!*maxStr) { 4209 vrange->max = defaultVersionRange.max; 4210 } else { 4211 PRUint16 version; 4212 /* if max version is empty, then maxStr points to the string terminator */ 4213 if (SECU_GetSSLVersionFromName(maxStr, strlen(maxStr), &version) != 4214 SECSuccess) { 4215 PORT_SetError(SEC_ERROR_INVALID_ARGS); 4216 return SECFailure; 4217 } 4218 4219 vrange->max = version; 4220 } 4221 4222 if (vrange->min > vrange->max) { 4223 PORT_SetError(SEC_ERROR_INVALID_ARGS); 4224 return SECFailure; 4225 } 4226 4227 return SECSuccess; 4228 } 4229 4230 #define NAME_AND_LEN(s) sizeof(s) - 1, s 4231 static const struct SSLNamedGroupString { 4232 int len; 4233 char *name; 4234 SSLNamedGroup grp; 4235 } sslNamedGroupStringArray[] = { 4236 { NAME_AND_LEN("P256"), ssl_grp_ec_secp256r1 }, 4237 { NAME_AND_LEN("P384"), ssl_grp_ec_secp384r1 }, 4238 { NAME_AND_LEN("P521"), ssl_grp_ec_secp521r1 }, 4239 { NAME_AND_LEN("x25519"), ssl_grp_ec_curve25519 }, 4240 { NAME_AND_LEN("FF2048"), ssl_grp_ffdhe_2048 }, 4241 { NAME_AND_LEN("FF3072"), ssl_grp_ffdhe_3072 }, 4242 { NAME_AND_LEN("FF4096"), ssl_grp_ffdhe_4096 }, 4243 { NAME_AND_LEN("FF6144"), ssl_grp_ffdhe_6144 }, 4244 { NAME_AND_LEN("FF8192"), ssl_grp_ffdhe_8192 }, 4245 #ifndef NSS_DISABLE_KYBER 4246 { NAME_AND_LEN("xyber76800"), ssl_grp_kem_xyber768d00 }, 4247 #endif 4248 { NAME_AND_LEN("x25519mlkem768"), ssl_grp_kem_mlkem768x25519 }, 4249 { NAME_AND_LEN("secp256r1mlkem768"), ssl_grp_kem_secp256r1mlkem768 }, 4250 { NAME_AND_LEN("secp384r1mlkem1024"), ssl_grp_kem_secp384r1mlkem1024 }, 4251 // keep for compatibility 4252 { NAME_AND_LEN("mlkem768x25519"), ssl_grp_kem_mlkem768x25519 }, 4253 }; 4254 4255 static const size_t sslNamedGroupStringLen = PR_ARRAY_SIZE(sslNamedGroupStringArray); 4256 4257 static SSLNamedGroup 4258 groupNameToNamedGroup(char *name) 4259 { 4260 int len = PL_strlen(name); 4261 int i; 4262 4263 for (i = 0; i < sslNamedGroupStringLen; i++) { 4264 const struct SSLNamedGroupString *ngs = &sslNamedGroupStringArray[i]; 4265 if (len == ngs->len) { 4266 if (!strncmp(name, ngs->name, len)) { 4267 return ngs->grp; 4268 } 4269 } 4270 } 4271 return ssl_grp_none; 4272 } 4273 4274 static SECStatus 4275 countItems(const char *arg, unsigned int *numItems) 4276 { 4277 char *str = PORT_Strdup(arg); 4278 if (!str) { 4279 return SECFailure; 4280 } 4281 char *p = strtok(str, ","); 4282 while (p) { 4283 ++(*numItems); 4284 p = strtok(NULL, ","); 4285 } 4286 PORT_Free(str); 4287 str = NULL; 4288 return SECSuccess; 4289 } 4290 4291 SECStatus 4292 parseGroupList(const char *arg, SSLNamedGroup **enabledGroups, 4293 unsigned int *enabledGroupsCount) 4294 { 4295 SSLNamedGroup *groups; 4296 char *str; 4297 char *p; 4298 unsigned int numValues = 0; 4299 unsigned int count = 0; 4300 4301 if (countItems(arg, &numValues) != SECSuccess) { 4302 return SECFailure; 4303 } 4304 groups = PORT_ZNewArray(SSLNamedGroup, numValues); 4305 if (!groups) { 4306 return SECFailure; 4307 } 4308 4309 /* Get group names. */ 4310 str = PORT_Strdup(arg); 4311 if (!str) { 4312 goto done; 4313 } 4314 p = strtok(str, ","); 4315 while (p) { 4316 SSLNamedGroup group = groupNameToNamedGroup(p); 4317 if (group == ssl_grp_none) { 4318 count = 0; 4319 goto done; 4320 } 4321 groups[count++] = group; 4322 p = strtok(NULL, ","); 4323 } 4324 4325 done: 4326 PORT_Free(str); 4327 if (!count) { 4328 PORT_Free(groups); 4329 return SECFailure; 4330 } 4331 4332 *enabledGroupsCount = count; 4333 *enabledGroups = groups; 4334 return SECSuccess; 4335 } 4336 4337 const char * 4338 SECU_NamedGroupToGroupName(SSLNamedGroup grp) 4339 { 4340 int i; 4341 static char unknownBuf[32]; 4342 4343 if (grp == ssl_grp_none) { 4344 return "None"; 4345 } 4346 4347 for (i = 0; i < sslNamedGroupStringLen; i++) { 4348 const struct SSLNamedGroupString *ngs = &sslNamedGroupStringArray[i]; 4349 if (grp == ngs->grp) { 4350 return ngs->name; 4351 } 4352 } 4353 snprintf(unknownBuf, sizeof(unknownBuf), "Unknown %04x\n", grp); 4354 4355 return unknownBuf; 4356 } 4357 4358 const char * 4359 SECU_NamedGroupGetNextName(size_t i) 4360 { 4361 if (i >= sslNamedGroupStringLen) { 4362 return NULL; 4363 } 4364 return sslNamedGroupStringArray[i].name; 4365 } 4366 4367 #define MAKE_SCHEME(x) \ 4368 { \ 4369 sizeof(#x) - 1, #x, ssl_sig_##x \ 4370 } 4371 static const struct SSLSignatureSchemeString { 4372 int len; 4373 char *name; 4374 SSLSignatureScheme scheme; 4375 } sslSignatureSchemeStringArray[] = { 4376 MAKE_SCHEME(rsa_pkcs1_sha1), 4377 MAKE_SCHEME(rsa_pkcs1_sha256), 4378 MAKE_SCHEME(rsa_pkcs1_sha384), 4379 MAKE_SCHEME(rsa_pkcs1_sha512), 4380 MAKE_SCHEME(ecdsa_sha1), 4381 MAKE_SCHEME(ecdsa_secp256r1_sha256), 4382 MAKE_SCHEME(ecdsa_secp384r1_sha384), 4383 MAKE_SCHEME(ecdsa_secp521r1_sha512), 4384 MAKE_SCHEME(rsa_pss_rsae_sha256), 4385 MAKE_SCHEME(rsa_pss_rsae_sha384), 4386 MAKE_SCHEME(rsa_pss_rsae_sha512), 4387 MAKE_SCHEME(ed25519), 4388 MAKE_SCHEME(ed448), 4389 MAKE_SCHEME(rsa_pss_pss_sha256), 4390 MAKE_SCHEME(rsa_pss_pss_sha384), 4391 MAKE_SCHEME(rsa_pss_pss_sha512), 4392 MAKE_SCHEME(dsa_sha1), 4393 MAKE_SCHEME(dsa_sha256), 4394 MAKE_SCHEME(dsa_sha384), 4395 MAKE_SCHEME(dsa_sha512), 4396 }; 4397 4398 static const size_t sslSignatureSchemeStringLen = 4399 PR_ARRAY_SIZE(sslSignatureSchemeStringArray); 4400 4401 const char * 4402 SECU_SignatureSchemeGetNextScheme(size_t i) 4403 { 4404 if (i >= sslSignatureSchemeStringLen) { 4405 return NULL; 4406 } 4407 return sslSignatureSchemeStringArray[i].name; 4408 } 4409 4410 const char * 4411 SECU_SignatureSchemeName(SSLSignatureScheme scheme) 4412 { 4413 int i; 4414 static char unknownBuf[32]; 4415 4416 if (scheme == ssl_sig_none) { 4417 return "None"; 4418 } 4419 4420 for (i = 0; i < sslSignatureSchemeStringLen; i++) { 4421 const struct SSLSignatureSchemeString *schemp = 4422 &sslSignatureSchemeStringArray[i]; 4423 if (scheme == schemp->scheme) { 4424 return schemp->name; 4425 } 4426 } 4427 4428 /* we don't include ssl_sig_rsa_pks1_sha1md5 in our list because we 4429 * don't want to select it from the command line, but if you are using 4430 * ssl3, it's possible for this signataure scheme to pop out, so we 4431 * want output it. The name is the same value tstclnt used for this 4432 * scheme originally */ 4433 if (scheme == ssl_sig_rsa_pkcs1_sha1md5) { 4434 return "RSA PKCS#1 SHA1+MD5"; 4435 } 4436 4437 snprintf(unknownBuf, sizeof(unknownBuf), "Unknown %04x\n", scheme); 4438 4439 return unknownBuf; 4440 } 4441 4442 SSLSignatureScheme 4443 schemeNameToScheme(const char *name) 4444 { 4445 int len = PL_strlen(name); 4446 int i; 4447 4448 for (i = 0; i < sslSignatureSchemeStringLen; i++) { 4449 const struct SSLSignatureSchemeString *schemp = 4450 &sslSignatureSchemeStringArray[i]; 4451 if (len == schemp->len) { 4452 if (!strncmp(name, schemp->name, len)) { 4453 return schemp->scheme; 4454 } 4455 } 4456 } 4457 return ssl_sig_none; 4458 } 4459 4460 SECStatus 4461 parseSigSchemeList(const char *arg, const SSLSignatureScheme **enabledSigSchemes, 4462 unsigned int *enabledSigSchemeCount) 4463 { 4464 SSLSignatureScheme *schemes; 4465 unsigned int numValues = 0; 4466 unsigned int count = 0; 4467 4468 if (countItems(arg, &numValues) != SECSuccess) { 4469 return SECFailure; 4470 } 4471 schemes = PORT_ZNewArray(SSLSignatureScheme, numValues); 4472 if (!schemes) { 4473 return SECFailure; 4474 } 4475 4476 /* Get group names. */ 4477 char *str = PORT_Strdup(arg); 4478 if (!str) { 4479 goto done; 4480 } 4481 char *p = strtok(str, ","); 4482 while (p) { 4483 SSLSignatureScheme scheme = schemeNameToScheme(p); 4484 if (scheme == ssl_sig_none) { 4485 count = 0; 4486 goto done; 4487 } 4488 schemes[count++] = scheme; 4489 p = strtok(NULL, ","); 4490 } 4491 4492 done: 4493 PORT_Free(str); 4494 if (!count) { 4495 PORT_Free(schemes); 4496 return SECFailure; 4497 } 4498 4499 *enabledSigSchemeCount = count; 4500 *enabledSigSchemes = schemes; 4501 return SECSuccess; 4502 } 4503 4504 /* Parse the exporter spec in the form: LABEL[:OUTPUT-LENGTH[:CONTEXT]] */ 4505 static SECStatus 4506 parseExporter(const char *arg, 4507 secuExporter *exporter) 4508 { 4509 SECStatus rv = SECSuccess; 4510 4511 char *str = PORT_Strdup(arg); 4512 if (!str) { 4513 rv = SECFailure; 4514 goto done; 4515 } 4516 4517 char *labelEnd = strchr(str, ':'); 4518 if (labelEnd) { 4519 *labelEnd = '\0'; 4520 labelEnd++; 4521 4522 /* To extract CONTEXT, first skip OUTPUT-LENGTH */ 4523 char *outputEnd = strchr(labelEnd, ':'); 4524 if (outputEnd) { 4525 *outputEnd = '\0'; 4526 outputEnd++; 4527 4528 exporter->hasContext = PR_TRUE; 4529 exporter->context.data = (unsigned char *)PORT_Strdup(outputEnd); 4530 exporter->context.len = strlen(outputEnd); 4531 if (PORT_Strncasecmp((char *)exporter->context.data, "0x", 2) == 0) { 4532 rv = SECU_SECItemHexStringToBinary(&exporter->context); 4533 if (rv != SECSuccess) { 4534 goto done; 4535 } 4536 } 4537 } 4538 } 4539 4540 if (labelEnd && *labelEnd != '\0') { 4541 long int outputLength = strtol(labelEnd, NULL, 10); 4542 if (!(outputLength > 0 && outputLength <= UINT_MAX)) { 4543 PORT_SetError(SEC_ERROR_INVALID_ARGS); 4544 rv = SECFailure; 4545 goto done; 4546 } 4547 exporter->outputLength = outputLength; 4548 } else { 4549 exporter->outputLength = 20; 4550 } 4551 4552 char *label = PORT_Strdup(str); 4553 exporter->label.data = (unsigned char *)label; 4554 exporter->label.len = strlen(label); 4555 if (PORT_Strncasecmp((char *)exporter->label.data, "0x", 2) == 0) { 4556 rv = SECU_SECItemHexStringToBinary(&exporter->label); 4557 if (rv != SECSuccess) { 4558 goto done; 4559 } 4560 } 4561 4562 done: 4563 PORT_Free(str); 4564 4565 return rv; 4566 } 4567 4568 SECStatus 4569 parseExporters(const char *arg, 4570 const secuExporter **enabledExporters, 4571 unsigned int *enabledExporterCount) 4572 { 4573 secuExporter *exporters; 4574 unsigned int numValues = 0; 4575 unsigned int count = 0; 4576 4577 if (countItems(arg, &numValues) != SECSuccess) { 4578 return SECFailure; 4579 } 4580 exporters = PORT_ZNewArray(secuExporter, numValues); 4581 if (!exporters) { 4582 return SECFailure; 4583 } 4584 4585 /* Get exporter definitions. */ 4586 char *str = PORT_Strdup(arg); 4587 if (!str) { 4588 goto done; 4589 } 4590 char *p = strtok(str, ","); 4591 while (p) { 4592 SECStatus rv = parseExporter(p, &exporters[count++]); 4593 if (rv != SECSuccess) { 4594 count = 0; 4595 goto done; 4596 } 4597 p = strtok(NULL, ","); 4598 } 4599 4600 done: 4601 PORT_Free(str); 4602 if (!count) { 4603 PORT_Free(exporters); 4604 return SECFailure; 4605 } 4606 4607 *enabledExporterCount = count; 4608 *enabledExporters = exporters; 4609 return SECSuccess; 4610 } 4611 4612 static SECStatus 4613 exportKeyingMaterial(PRFileDesc *fd, const secuExporter *exporter) 4614 { 4615 SECStatus rv = SECSuccess; 4616 unsigned char *out = PORT_Alloc(exporter->outputLength); 4617 4618 if (!out) { 4619 fprintf(stderr, "Unable to allocate buffer for keying material\n"); 4620 return SECFailure; 4621 } 4622 rv = SSL_ExportKeyingMaterial(fd, 4623 (char *)exporter->label.data, 4624 exporter->label.len, 4625 exporter->hasContext, 4626 exporter->context.data, 4627 exporter->context.len, 4628 out, 4629 exporter->outputLength); 4630 if (rv != SECSuccess) { 4631 goto done; 4632 } 4633 fprintf(stdout, "Exported Keying Material:\n"); 4634 secu_PrintRawString(stdout, (SECItem *)&exporter->label, "Label", 1); 4635 if (exporter->hasContext) { 4636 SECU_PrintAsHex(stdout, &exporter->context, "Context", 1); 4637 } 4638 SECU_Indent(stdout, 1); 4639 fprintf(stdout, "Length: %u\n", exporter->outputLength); 4640 SECItem temp = { siBuffer, out, exporter->outputLength }; 4641 SECU_PrintAsHex(stdout, &temp, "Keying Material", 1); 4642 4643 done: 4644 PORT_Free(out); 4645 return rv; 4646 } 4647 4648 SECStatus 4649 exportKeyingMaterials(PRFileDesc *fd, 4650 const secuExporter *exporters, 4651 unsigned int exporterCount) 4652 { 4653 unsigned int i; 4654 4655 for (i = 0; i < exporterCount; i++) { 4656 SECStatus rv = exportKeyingMaterial(fd, &exporters[i]); 4657 if (rv != SECSuccess) { 4658 return rv; 4659 } 4660 } 4661 4662 return SECSuccess; 4663 } 4664 4665 SECStatus 4666 readPSK(const char *arg, SECItem *psk, SECItem *label) 4667 { 4668 SECStatus rv = SECFailure; 4669 char *str = PORT_Strdup(arg); 4670 if (!str) { 4671 goto cleanup; 4672 } 4673 4674 char *pskBytes = strtok(str, ":"); 4675 if (!pskBytes) { 4676 goto cleanup; 4677 } 4678 if (PORT_Strncasecmp(pskBytes, "0x", 2) != 0) { 4679 goto cleanup; 4680 } 4681 4682 psk = SECU_HexString2SECItem(NULL, psk, &pskBytes[2]); 4683 if (!psk || !psk->data || psk->len != strlen(&str[2]) / 2) { 4684 goto cleanup; 4685 } 4686 4687 SECItem labelItem = { siBuffer, NULL, 0 }; 4688 char *inLabel = strtok(NULL, ":"); 4689 if (inLabel) { 4690 labelItem.data = (unsigned char *)PORT_Strdup(inLabel); 4691 if (!labelItem.data) { 4692 goto cleanup; 4693 } 4694 labelItem.len = strlen(inLabel); 4695 4696 if (PORT_Strncasecmp(inLabel, "0x", 2) == 0) { 4697 rv = SECU_SECItemHexStringToBinary(&labelItem); 4698 if (rv != SECSuccess) { 4699 SECITEM_FreeItem(&labelItem, PR_FALSE); 4700 goto cleanup; 4701 } 4702 } 4703 rv = SECSuccess; 4704 } else { 4705 PRUint8 defaultLabel[] = { 'C', 'l', 'i', 'e', 'n', 't', '_', 4706 'i', 'd', 'e', 'n', 't', 'i', 't', 'y' }; 4707 SECItem src = { siBuffer, defaultLabel, sizeof(defaultLabel) }; 4708 rv = SECITEM_CopyItem(NULL, &labelItem, &src); 4709 } 4710 if (rv == SECSuccess) { 4711 *label = labelItem; 4712 } 4713 4714 cleanup: 4715 PORT_Free(str); 4716 return rv; 4717 } 4718 4719 static SECStatus 4720 secu_PrintPKCS12DigestInfo(FILE *out, const SECItem *t, char *m, int level) 4721 { 4722 SECItem my = *t; 4723 SECItem rawDigestAlgID; 4724 SECItem digestData; 4725 SECStatus rv; 4726 PLArenaPool *arena; 4727 SECAlgorithmID digestAlgID; 4728 char *mAlgID = NULL; 4729 char *mDigest = NULL; 4730 4731 /* strip the outer sequence */ 4732 if ((my.data[0] != (SEC_ASN1_CONSTRUCTED | SEC_ASN1_SEQUENCE)) || 4733 SECSuccess != SECU_StripTagAndLength(&my)) { 4734 PORT_SetError(SEC_ERROR_BAD_DER); 4735 return SECFailure; 4736 } 4737 4738 /* get the algorithm ID */ 4739 if (SECSuccess != SECU_ExtractBERAndStep(&my, &rawDigestAlgID)) { 4740 return SECFailure; 4741 } 4742 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 4743 if (arena == NULL) { 4744 return SECFailure; 4745 } 4746 #define DIGEST_ALGID_STRING "Digest Algorithm ID" 4747 if (m) 4748 mAlgID = PR_smprintf("%s " DIGEST_ALGID_STRING, m); 4749 rv = SEC_QuickDERDecodeItem(arena, &digestAlgID, 4750 SEC_ASN1_GET(SECOID_AlgorithmIDTemplate), 4751 &rawDigestAlgID); 4752 if (rv == SECSuccess) { 4753 SECU_PrintAlgorithmID(out, &digestAlgID, 4754 mAlgID ? mAlgID : DIGEST_ALGID_STRING, level); 4755 } 4756 if (mAlgID) 4757 PR_smprintf_free(mAlgID); 4758 PORT_FreeArena(arena, PR_FALSE); 4759 if (rv != SECSuccess) { 4760 return rv; 4761 } 4762 4763 /* get the mac data */ 4764 if (SECSuccess != SECU_ExtractBERAndStep(&my, &digestData)) { 4765 return SECFailure; 4766 } 4767 if ((digestData.data[0] & SEC_ASN1_TAGNUM_MASK) != SEC_ASN1_OCTET_STRING) { 4768 PORT_SetError(SEC_ERROR_BAD_DER); 4769 return SECFailure; 4770 } 4771 #define DIGEST_STRING "Digest" 4772 if (m) 4773 mDigest = PR_smprintf("%s " DIGEST_STRING, m); 4774 secu_PrintOctetString(out, &digestData, 4775 mDigest ? mDigest : DIGEST_STRING, level); 4776 if (mDigest) 4777 PR_smprintf_free(mDigest); 4778 return SECSuccess; 4779 } 4780 4781 static SECStatus 4782 secu_PrintPKCS12MacData(FILE *out, const SECItem *t, char *m, int level) 4783 { 4784 SECItem my = *t; 4785 SECItem hash; 4786 SECItem salt; 4787 4788 if (m) { 4789 SECU_Indent(out, level); 4790 fprintf(out, "%s: \n", m); 4791 level++; 4792 } 4793 4794 /* strip the outer sequence */ 4795 if ((my.data[0] != (SEC_ASN1_CONSTRUCTED | SEC_ASN1_SEQUENCE)) || 4796 SECSuccess != SECU_StripTagAndLength(&my)) { 4797 PORT_SetError(SEC_ERROR_BAD_DER); 4798 return SECFailure; 4799 } 4800 4801 if (SECSuccess != SECU_ExtractBERAndStep(&my, &hash)) { 4802 return SECFailure; 4803 } 4804 if (SECSuccess != secu_PrintPKCS12DigestInfo(out, &hash, "Mac", level)) { 4805 return SECFailure; 4806 } 4807 4808 /* handle the salt */ 4809 if (SECSuccess != SECU_ExtractBERAndStep(&my, &salt)) { 4810 return SECFailure; 4811 ; 4812 } 4813 if ((salt.data[0] & SEC_ASN1_TAGNUM_MASK) != SEC_ASN1_OCTET_STRING) { 4814 PORT_SetError(SEC_ERROR_BAD_DER); 4815 return SECFailure; 4816 } 4817 secu_PrintOctetString(out, &salt, "Mac Salt", level); 4818 4819 if (my.len && 4820 ((my.data[0] & SEC_ASN1_TAGNUM_MASK) == SEC_ASN1_INTEGER)) { 4821 SECItem iterator; 4822 if (SECSuccess != SECU_ExtractBERAndStep(&my, &iterator)) { 4823 return SECFailure; 4824 } 4825 SECU_PrintEncodedInteger(out, &iterator, "Iterations", level); 4826 } 4827 return SECSuccess; 4828 } 4829 4830 SECStatus 4831 SECU_PrintPKCS12(FILE *out, const SECItem *t, char *m, int level) 4832 { 4833 SECItem my = *t; 4834 SECItem authSafe; 4835 SECItem macData; 4836 4837 SECU_Indent(out, level); 4838 fprintf(out, "%s:\n", m); 4839 level++; 4840 4841 /* strip the outer sequence */ 4842 if ((my.data[0] != (SEC_ASN1_CONSTRUCTED | SEC_ASN1_SEQUENCE)) || 4843 SECSuccess != SECU_StripTagAndLength(&my)) { 4844 PORT_SetError(SEC_ERROR_BAD_DER); 4845 return SECFailure; 4846 } 4847 /* print and remove the optional version number */ 4848 if (my.len && ((my.data[0] & SEC_ASN1_TAGNUM_MASK) == SEC_ASN1_INTEGER)) { 4849 SECItem version; 4850 4851 if (SECSuccess != SECU_ExtractBERAndStep(&my, &version)) { 4852 return SECFailure; 4853 } 4854 SECU_PrintEncodedInteger(out, &version, "Version", level); 4855 } 4856 4857 /* print the authSafe */ 4858 if (SECSuccess != SECU_ExtractBERAndStep(&my, &authSafe)) { 4859 return SECFailure; 4860 } 4861 if (SECSuccess != secu_PrintDERPKCS7ContentInfo(out, &authSafe, 4862 secuPKCS7PKCS12AuthSafe, 4863 "AuthSafe", level)) { 4864 return SECFailure; 4865 } 4866 4867 /* print the mac data (optional) */ 4868 if (!my.len) { 4869 return SECSuccess; 4870 } 4871 if (SECSuccess != SECU_ExtractBERAndStep(&my, &macData)) { 4872 return SECFailure; 4873 } 4874 if (SECSuccess != secu_PrintPKCS12MacData(out, &macData, 4875 "Mac Data", level)) { 4876 return SECFailure; 4877 } 4878 4879 if (my.len) { 4880 fprintf(out, "Unknown extra data found \n"); 4881 } 4882 return SECSuccess; 4883 }