vfychain.c (28674B)
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 /**************************************************************************** 6 * Read in a cert chain from one or more files, and verify the chain for 7 * some usage. 8 * * 9 * This code was modified from other code also kept in the NSS directory. 10 ****************************************************************************/ 11 12 #include <stdio.h> 13 #include <string.h> 14 15 #if defined(XP_UNIX) 16 #include <unistd.h> 17 #endif 18 19 #include "prerror.h" 20 21 #include "pk11func.h" 22 #include "seccomon.h" 23 #include "secutil.h" 24 #include "secmod.h" 25 #include "secitem.h" 26 #include "cert.h" 27 #include "ocsp.h" 28 29 /* #include <stdlib.h> */ 30 /* #include <errno.h> */ 31 /* #include <fcntl.h> */ 32 /* #include <stdarg.h> */ 33 34 #include "nspr.h" 35 #include "plgetopt.h" 36 #include "prio.h" 37 #include "nss.h" 38 39 /* #include "vfyutil.h" */ 40 41 #define RD_BUF_SIZE (60 * 1024) 42 43 int verbose; 44 45 secuPWData pwdata = { PW_NONE, 0 }; 46 47 static void 48 Usage(const char *progName) 49 { 50 fprintf(stderr, 51 "Usage: %s [options] [revocation options] certfile " 52 "[[options] certfile] ...\n" 53 "\tWhere options are:\n" 54 "\t-a\t\t Following certfile is base64 encoded\n" 55 "\t-b YYMMDDHHMMZ\t Validate date (default: now)\n" 56 "\t-d directory\t Database directory\n" 57 "\t-i number of consecutive verifications\n" 58 "\t-f \t\t Enable cert fetching from AIA URL\n" 59 "\t-o oid\t\t Set policy OID for cert validation(Format OID.1.2.3)\n" 60 "\t-p \t\t Use PKIX Library to validate certificate by calling:\n" 61 "\t\t\t * CERT_VerifyCertificate if specified once,\n" 62 "\t\t\t * CERT_PKIXVerifyCert if specified twice and more.\n" 63 "\t-r\t\t Following certfile is raw binary DER (default)\n" 64 "\t-t\t\t Following cert is explicitly trusted (overrides db trust).\n" 65 "\t-u usage \t 0=SSL client, 1=SSL server, 2=SSL StepUp, 3=SSL CA,\n" 66 "\t\t\t 4=Email signer, 5=Email recipient, 6=Object signer,\n" 67 "\t\t\t 9=ProtectedObjectSigner, 10=OCSP responder, 11=Any CA,\n" 68 "\t\t\t 12=IPsec\n" 69 "\t-T\t\t Trust both explicit trust anchors (-t) and the database.\n" 70 "\t\t\t (Default is to only trust certificates marked -t, if there are any,\n" 71 "\t\t\t or to trust the database if there are certificates marked -t.)\n" 72 "\t-v\t\t Verbose mode. Prints root cert subject(double the\n" 73 "\t\t\t argument for whole root cert info)\n" 74 "\t-w password\t Database password.\n" 75 "\t-W pwfile\t Password file.\n\n" 76 "\tRevocation options for PKIX API(invoked with -pp options) is a\n" 77 "\tcollection of the following flags:\n" 78 "\t\t[-g type [-h flags] [-m type [-s flags]] ...] ...\n" 79 "\tWhere:\n" 80 "\t-g test type\t Sets status checking test type. Possible values\n" 81 "\t\t\tare \"leaf\" or \"chain\"\n" 82 "\t-h test flags\t Sets revocation flags for the test type it\n" 83 "\t\t\tfollows. Possible flags: \"testLocalInfoFirst\" and\n" 84 "\t\t\t\"requireFreshInfo\".\n" 85 "\t-m method type\t Sets method type for the test type it follows.\n" 86 "\t\t\tPossible types are \"crl\" and \"ocsp\".\n" 87 "\t-s method flags\t Sets revocation flags for the method it follows.\n" 88 "\t\t\tPossible types are \"doNotUse\", \"forbidFetching\",\n" 89 "\t\t\t\"ignoreDefaultSrc\", \"requireInfo\" and \"failIfNoInfo\".\n", 90 progName); 91 exit(1); 92 } 93 94 /************************************************************************** 95 ** 96 ** Error and information routines. 97 ** 98 **************************************************************************/ 99 100 void 101 errWarn(char *function) 102 { 103 fprintf(stderr, "Error in function %s: %s\n", 104 function, SECU_Strerror(PR_GetError())); 105 } 106 107 void 108 exitErr(char *function) 109 { 110 errWarn(function); 111 /* Exit gracefully. */ 112 /* ignoring return value of NSS_Shutdown as code exits with 1 anyway*/ 113 (void)NSS_Shutdown(); 114 PR_Cleanup(); 115 exit(1); 116 } 117 118 typedef struct certMemStr { 119 struct certMemStr *next; 120 CERTCertificate *cert; 121 } certMem; 122 123 certMem *theCerts; 124 CERTCertList *trustedCertList; 125 126 void 127 rememberCert(CERTCertificate *cert, PRBool trusted) 128 { 129 if (trusted) { 130 if (!trustedCertList) { 131 trustedCertList = CERT_NewCertList(); 132 } 133 CERT_AddCertToListTail(trustedCertList, cert); 134 } else { 135 certMem *newCertMem = PORT_ZNew(certMem); 136 if (newCertMem) { 137 newCertMem->next = theCerts; 138 newCertMem->cert = cert; 139 theCerts = newCertMem; 140 } 141 } 142 } 143 144 void 145 forgetCerts(void) 146 { 147 certMem *oldCertMem; 148 while (theCerts) { 149 oldCertMem = theCerts; 150 theCerts = theCerts->next; 151 CERT_DestroyCertificate(oldCertMem->cert); 152 PORT_Free(oldCertMem); 153 } 154 if (trustedCertList) { 155 CERT_DestroyCertList(trustedCertList); 156 } 157 } 158 159 CERTCertificate * 160 getCert(const char *name, PRBool isAscii, const char *progName) 161 { 162 CERTCertificate *cert; 163 CERTCertDBHandle *defaultDB; 164 PRFileDesc *fd; 165 SECStatus rv; 166 SECItem item = { 0, NULL, 0 }; 167 168 defaultDB = CERT_GetDefaultCertDB(); 169 170 /* First, let's try to find the cert in existing DB. */ 171 cert = CERT_FindCertByNicknameOrEmailAddr(defaultDB, name); 172 if (cert) { 173 return cert; 174 } 175 176 /* Don't have a cert with name "name" in the DB. Try to 177 * open a file with such name and get the cert from there.*/ 178 fd = PR_Open(name, PR_RDONLY, 0777); 179 if (!fd) { 180 PRErrorCode err = PR_GetError(); 181 fprintf(stderr, "open of %s failed, %d = %s\n", 182 name, err, SECU_Strerror(err)); 183 return cert; 184 } 185 186 rv = SECU_ReadDERFromFile(&item, fd, isAscii, PR_FALSE); 187 PR_Close(fd); 188 if (rv != SECSuccess) { 189 fprintf(stderr, "%s: SECU_ReadDERFromFile failed\n", progName); 190 return cert; 191 } 192 193 if (!item.len) { /* file was empty */ 194 fprintf(stderr, "cert file %s was empty.\n", name); 195 return cert; 196 } 197 198 cert = CERT_NewTempCertificate(defaultDB, &item, 199 NULL /* nickname */, 200 PR_FALSE /* isPerm */, 201 PR_TRUE /* copyDER */); 202 if (!cert) { 203 PRErrorCode err = PR_GetError(); 204 fprintf(stderr, "couldn't import %s, %d = %s\n", 205 name, err, SECU_Strerror(err)); 206 } 207 PORT_Free(item.data); 208 return cert; 209 } 210 211 #define REVCONFIG_TEST_UNDEFINED 0 212 #define REVCONFIG_TEST_LEAF 1 213 #define REVCONFIG_TEST_CHAIN 2 214 #define REVCONFIG_METHOD_CRL 1 215 #define REVCONFIG_METHOD_OCSP 2 216 217 #define REVCONFIG_TEST_LEAF_STR "leaf" 218 #define REVCONFIG_TEST_CHAIN_STR "chain" 219 #define REVCONFIG_METHOD_CRL_STR "crl" 220 #define REVCONFIG_METHOD_OCSP_STR "ocsp" 221 222 #define REVCONFIG_TEST_TESTLOCALINFOFIRST_STR "testLocalInfoFirst" 223 #define REVCONFIG_TEST_REQUIREFRESHINFO_STR "requireFreshInfo" 224 #define REVCONFIG_METHOD_DONOTUSEMETHOD_STR "doNotUse" 225 #define REVCONFIG_METHOD_FORBIDNETWORKFETCHIN_STR "forbidFetching" 226 #define REVCONFIG_METHOD_IGNOREDEFAULTSRC_STR "ignoreDefaultSrc" 227 #define REVCONFIG_METHOD_REQUIREINFO_STR "requireInfo" 228 #define REVCONFIG_METHOD_FAILIFNOINFO_STR "failIfNoInfo" 229 230 #define REV_METHOD_INDEX_MAX 4 231 232 typedef struct RevMethodsStruct { 233 unsigned int testType; 234 char *testTypeStr; 235 unsigned int testFlags; 236 char *testFlagsStr; 237 unsigned int methodType; 238 char *methodTypeStr; 239 unsigned int methodFlags; 240 char *methodFlagsStr; 241 } RevMethods; 242 243 RevMethods revMethodsData[REV_METHOD_INDEX_MAX]; 244 245 SECStatus 246 parseRevMethodsAndFlags() 247 { 248 int i; 249 unsigned int testType = 0; 250 251 for (i = 0; i < REV_METHOD_INDEX_MAX; i++) { 252 /* testType */ 253 if (revMethodsData[i].testTypeStr) { 254 char *typeStr = revMethodsData[i].testTypeStr; 255 256 testType = 0; 257 if (!PORT_Strcmp(typeStr, REVCONFIG_TEST_LEAF_STR)) { 258 testType = REVCONFIG_TEST_LEAF; 259 } else if (!PORT_Strcmp(typeStr, REVCONFIG_TEST_CHAIN_STR)) { 260 testType = REVCONFIG_TEST_CHAIN; 261 } 262 } 263 if (!testType) { 264 return SECFailure; 265 } 266 revMethodsData[i].testType = testType; 267 /* testFlags */ 268 if (revMethodsData[i].testFlagsStr) { 269 char *flagStr = revMethodsData[i].testFlagsStr; 270 unsigned int testFlags = 0; 271 272 if (PORT_Strstr(flagStr, REVCONFIG_TEST_TESTLOCALINFOFIRST_STR)) { 273 testFlags |= CERT_REV_MI_TEST_ALL_LOCAL_INFORMATION_FIRST; 274 } 275 if (PORT_Strstr(flagStr, REVCONFIG_TEST_REQUIREFRESHINFO_STR)) { 276 testFlags |= CERT_REV_MI_REQUIRE_SOME_FRESH_INFO_AVAILABLE; 277 } 278 revMethodsData[i].testFlags = testFlags; 279 } 280 /* method type */ 281 if (revMethodsData[i].methodTypeStr) { 282 char *methodStr = revMethodsData[i].methodTypeStr; 283 unsigned int methodType = 0; 284 285 if (!PORT_Strcmp(methodStr, REVCONFIG_METHOD_CRL_STR)) { 286 methodType = REVCONFIG_METHOD_CRL; 287 } else if (!PORT_Strcmp(methodStr, REVCONFIG_METHOD_OCSP_STR)) { 288 methodType = REVCONFIG_METHOD_OCSP; 289 } 290 if (!methodType) { 291 return SECFailure; 292 } 293 revMethodsData[i].methodType = methodType; 294 } 295 if (!revMethodsData[i].methodType) { 296 revMethodsData[i].testType = REVCONFIG_TEST_UNDEFINED; 297 continue; 298 } 299 /* method flags */ 300 if (revMethodsData[i].methodFlagsStr) { 301 char *flagStr = revMethodsData[i].methodFlagsStr; 302 unsigned int methodFlags = 0; 303 304 if (!PORT_Strstr(flagStr, REVCONFIG_METHOD_DONOTUSEMETHOD_STR)) { 305 methodFlags |= CERT_REV_M_TEST_USING_THIS_METHOD; 306 } 307 if (PORT_Strstr(flagStr, 308 REVCONFIG_METHOD_FORBIDNETWORKFETCHIN_STR)) { 309 methodFlags |= CERT_REV_M_FORBID_NETWORK_FETCHING; 310 } 311 if (PORT_Strstr(flagStr, REVCONFIG_METHOD_IGNOREDEFAULTSRC_STR)) { 312 methodFlags |= CERT_REV_M_IGNORE_IMPLICIT_DEFAULT_SOURCE; 313 } 314 if (PORT_Strstr(flagStr, REVCONFIG_METHOD_REQUIREINFO_STR)) { 315 methodFlags |= CERT_REV_M_REQUIRE_INFO_ON_MISSING_SOURCE; 316 } 317 if (PORT_Strstr(flagStr, REVCONFIG_METHOD_FAILIFNOINFO_STR)) { 318 methodFlags |= CERT_REV_M_FAIL_ON_MISSING_FRESH_INFO; 319 } 320 revMethodsData[i].methodFlags = methodFlags; 321 } else { 322 revMethodsData[i].methodFlags |= CERT_REV_M_TEST_USING_THIS_METHOD; 323 } 324 } 325 return SECSuccess; 326 } 327 328 SECStatus 329 configureRevocationParams(CERTRevocationFlags *flags) 330 { 331 int i; 332 unsigned int testType = REVCONFIG_TEST_UNDEFINED; 333 static CERTRevocationTests *revTests = NULL; 334 PRUint64 *revFlags = NULL; 335 336 for (i = 0; i < REV_METHOD_INDEX_MAX; i++) { 337 if (revMethodsData[i].testType == REVCONFIG_TEST_UNDEFINED) { 338 continue; 339 } 340 if (revMethodsData[i].testType != testType) { 341 testType = revMethodsData[i].testType; 342 if (testType == REVCONFIG_TEST_CHAIN) { 343 revTests = &flags->chainTests; 344 } else { 345 revTests = &flags->leafTests; 346 } 347 revTests->number_of_preferred_methods = 0; 348 revTests->preferred_methods = 0; 349 revFlags = revTests->cert_rev_flags_per_method; 350 } 351 /* Set the number of the methods independently to the max number of 352 * methods. If method flags are not set it will be ignored due to 353 * default DO_NOT_USE flag. */ 354 revTests->number_of_defined_methods = cert_revocation_method_count; 355 revTests->cert_rev_method_independent_flags |= 356 revMethodsData[i].testFlags; 357 if (revMethodsData[i].methodType == REVCONFIG_METHOD_CRL) { 358 revFlags[cert_revocation_method_crl] = 359 revMethodsData[i].methodFlags; 360 } else if (revMethodsData[i].methodType == REVCONFIG_METHOD_OCSP) { 361 revFlags[cert_revocation_method_ocsp] = 362 revMethodsData[i].methodFlags; 363 } 364 } 365 return SECSuccess; 366 } 367 368 void 369 freeRevocationMethodData() 370 { 371 int i = 0; 372 for (; i < REV_METHOD_INDEX_MAX; i++) { 373 if (revMethodsData[i].testTypeStr) { 374 PORT_Free(revMethodsData[i].testTypeStr); 375 } 376 if (revMethodsData[i].testFlagsStr) { 377 PORT_Free(revMethodsData[i].testFlagsStr); 378 } 379 if (revMethodsData[i].methodTypeStr) { 380 PORT_Free(revMethodsData[i].methodTypeStr); 381 } 382 if (revMethodsData[i].methodFlagsStr) { 383 PORT_Free(revMethodsData[i].methodFlagsStr); 384 } 385 } 386 } 387 388 PRBool 389 isOCSPEnabled() 390 { 391 int i; 392 393 for (i = 0; i < REV_METHOD_INDEX_MAX; i++) { 394 if (revMethodsData[i].methodType == REVCONFIG_METHOD_OCSP) { 395 return PR_TRUE; 396 } 397 } 398 return PR_FALSE; 399 } 400 401 int 402 main(int argc, char *argv[], char *envp[]) 403 { 404 char *certDir = NULL; 405 char *progName = NULL; 406 char *oidStr = NULL; 407 CERTCertificate *cert; 408 CERTCertificate *firstCert = NULL; 409 CERTCertificate *issuerCert = NULL; 410 CERTCertDBHandle *defaultDB = NULL; 411 PRBool isAscii = PR_FALSE; 412 PRBool trusted = PR_FALSE; 413 SECStatus secStatus; 414 SECCertificateUsage certUsage = certificateUsageSSLServer; 415 PLOptState *optstate; 416 PRTime time = 0; 417 PLOptStatus status; 418 int usePkix = 0; 419 int rv = 1; 420 int usage; 421 CERTVerifyLog log; 422 CERTCertList *builtChain = NULL; 423 PRBool certFetching = PR_FALSE; 424 int revDataIndex = 0; 425 PRBool ocsp_fetchingFailureIsAFailure = PR_TRUE; 426 PRBool useDefaultRevFlags = PR_TRUE; 427 PRBool onlyTrustAnchors = PR_TRUE; 428 int vfyCounts = 1; 429 430 PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); 431 432 progName = PL_strdup(argv[0]); 433 434 optstate = PL_CreateOptState(argc, argv, "ab:c:d:efg:h:i:m:o:prs:tTu:vw:W:"); 435 while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) { 436 switch (optstate->option) { 437 case 0: /* positional parameter */ 438 goto breakout; 439 case 'a': 440 isAscii = PR_TRUE; 441 break; 442 case 'b': 443 secStatus = DER_AsciiToTime(&time, optstate->value); 444 if (secStatus != SECSuccess) 445 Usage(progName); 446 break; 447 case 'd': 448 certDir = PL_strdup(optstate->value); 449 break; 450 case 'e': 451 ocsp_fetchingFailureIsAFailure = PR_FALSE; 452 break; 453 case 'f': 454 certFetching = PR_TRUE; 455 break; 456 case 'g': 457 if (revMethodsData[revDataIndex].testTypeStr || 458 revMethodsData[revDataIndex].methodTypeStr) { 459 revDataIndex += 1; 460 if (revDataIndex == REV_METHOD_INDEX_MAX) { 461 fprintf(stderr, "Invalid revocation configuration" 462 "specified.\n"); 463 secStatus = SECFailure; 464 break; 465 } 466 } 467 useDefaultRevFlags = PR_FALSE; 468 revMethodsData[revDataIndex].testTypeStr = 469 PL_strdup(optstate->value); 470 break; 471 case 'h': 472 revMethodsData[revDataIndex].testFlagsStr = 473 PL_strdup(optstate->value); 474 break; 475 case 'i': 476 vfyCounts = PORT_Atoi(optstate->value); 477 break; 478 break; 479 case 'm': 480 if (revMethodsData[revDataIndex].methodTypeStr) { 481 revDataIndex += 1; 482 if (revDataIndex == REV_METHOD_INDEX_MAX) { 483 fprintf(stderr, "Invalid revocation configuration" 484 "specified.\n"); 485 secStatus = SECFailure; 486 break; 487 } 488 } 489 useDefaultRevFlags = PR_FALSE; 490 revMethodsData[revDataIndex].methodTypeStr = 491 PL_strdup(optstate->value); 492 break; 493 case 'o': 494 oidStr = PL_strdup(optstate->value); 495 break; 496 case 'p': 497 usePkix += 1; 498 break; 499 case 'r': 500 isAscii = PR_FALSE; 501 break; 502 case 's': 503 revMethodsData[revDataIndex].methodFlagsStr = 504 PL_strdup(optstate->value); 505 break; 506 case 't': 507 trusted = PR_TRUE; 508 break; 509 case 'T': 510 onlyTrustAnchors = PR_FALSE; 511 break; 512 case 'u': 513 usage = PORT_Atoi(optstate->value); 514 if (usage < 0 || usage > 62) 515 Usage(progName); 516 certUsage = ((SECCertificateUsage)1) << usage; 517 if (certUsage > certificateUsageHighest) 518 Usage(progName); 519 break; 520 case 'w': 521 pwdata.source = PW_PLAINTEXT; 522 pwdata.data = PORT_Strdup(optstate->value); 523 break; 524 525 case 'W': 526 pwdata.source = PW_FROMFILE; 527 pwdata.data = PORT_Strdup(optstate->value); 528 break; 529 case 'v': 530 verbose++; 531 break; 532 default: 533 Usage(progName); 534 break; 535 } 536 } 537 breakout: 538 if (status != PL_OPT_OK) 539 Usage(progName); 540 541 if (usePkix < 2) { 542 if (oidStr) { 543 fprintf(stderr, "Policy oid(-o) can be used only with" 544 " CERT_PKIXVerifyCert(-pp) function.\n"); 545 Usage(progName); 546 } 547 if (trusted) { 548 fprintf(stderr, "Cert trust flag can be used only with" 549 " CERT_PKIXVerifyCert(-pp) function.\n"); 550 Usage(progName); 551 } 552 if (!onlyTrustAnchors) { 553 fprintf(stderr, "Cert trust anchor exclusiveness can be" 554 " used only with CERT_PKIXVerifyCert(-pp)" 555 " function.\n"); 556 } 557 } 558 559 if (!useDefaultRevFlags && parseRevMethodsAndFlags()) { 560 fprintf(stderr, "Invalid revocation configuration specified.\n"); 561 goto punt; 562 } 563 564 /* Set our password function callback. */ 565 PK11_SetPasswordFunc(SECU_GetModulePassword); 566 567 /* Initialize the NSS libraries. */ 568 if (certDir) { 569 secStatus = NSS_Init(certDir); 570 } else { 571 secStatus = NSS_NoDB_Init(NULL); 572 573 /* load the builtins */ 574 SECMOD_AddNewModule("Builtins", DLL_PREFIX "nssckbi." DLL_SUFFIX, 0, 0); 575 } 576 if (secStatus != SECSuccess) { 577 exitErr("NSS_Init"); 578 } 579 SECU_RegisterDynamicOids(); 580 if (isOCSPEnabled()) { 581 CERT_EnableOCSPChecking(CERT_GetDefaultCertDB()); 582 CERT_DisableOCSPDefaultResponder(CERT_GetDefaultCertDB()); 583 if (!ocsp_fetchingFailureIsAFailure) { 584 CERT_SetOCSPFailureMode(ocspMode_FailureIsNotAVerificationFailure); 585 } 586 } 587 588 while (status == PL_OPT_OK) { 589 switch (optstate->option) { 590 default: 591 Usage(progName); 592 break; 593 case 'a': 594 isAscii = PR_TRUE; 595 break; 596 case 'r': 597 isAscii = PR_FALSE; 598 break; 599 case 't': 600 trusted = PR_TRUE; 601 break; 602 case 0: /* positional parameter */ 603 if (usePkix < 2 && trusted) { 604 fprintf(stderr, "Cert trust flag can be used only with" 605 " CERT_PKIXVerifyCert(-pp) function.\n"); 606 Usage(progName); 607 } 608 cert = getCert(optstate->value, isAscii, progName); 609 if (!cert) 610 goto punt; 611 rememberCert(cert, trusted); 612 if (!firstCert) 613 firstCert = cert; 614 trusted = PR_FALSE; 615 } 616 status = PL_GetNextOpt(optstate); 617 } 618 PL_DestroyOptState(optstate); 619 if (status == PL_OPT_BAD || !firstCert) 620 Usage(progName); 621 622 /* Initialize log structure */ 623 log.arena = PORT_NewArena(512); 624 log.head = log.tail = NULL; 625 log.count = 0; 626 627 do { 628 if (usePkix < 2) { 629 /* NOW, verify the cert chain. */ 630 if (usePkix) { 631 /* Use old API with libpkix validation lib */ 632 CERT_SetUsePKIXForValidation(PR_TRUE); 633 } 634 if (!time) 635 time = PR_Now(); 636 637 defaultDB = CERT_GetDefaultCertDB(); 638 secStatus = CERT_VerifyCertificate(defaultDB, firstCert, 639 PR_TRUE /* check sig */, 640 certUsage, 641 time, 642 &pwdata, /* wincx */ 643 &log, /* error log */ 644 NULL); /* returned usages */ 645 } else 646 do { 647 static CERTValOutParam cvout[4]; 648 static CERTValInParam cvin[7]; 649 SECOidTag oidTag; 650 int inParamIndex = 0; 651 static PRUint64 revFlagsLeaf[2]; 652 static PRUint64 revFlagsChain[2]; 653 static CERTRevocationFlags rev; 654 655 if (oidStr) { 656 PLArenaPool *arena; 657 SECOidData od; 658 memset(&od, 0, sizeof od); 659 od.offset = SEC_OID_UNKNOWN; 660 od.desc = "User Defined Policy OID"; 661 od.mechanism = CKM_INVALID_MECHANISM; 662 od.supportedExtension = INVALID_CERT_EXTENSION; 663 664 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 665 if (!arena) { 666 fprintf(stderr, "out of memory"); 667 goto punt; 668 } 669 670 secStatus = SEC_StringToOID(arena, &od.oid, oidStr, 0); 671 if (secStatus != SECSuccess) { 672 PORT_FreeArena(arena, PR_FALSE); 673 fprintf(stderr, "Can not encode oid: %s(%s)\n", oidStr, 674 SECU_Strerror(PORT_GetError())); 675 break; 676 } 677 678 oidTag = SECOID_AddEntry(&od); 679 PORT_FreeArena(arena, PR_FALSE); 680 if (oidTag == SEC_OID_UNKNOWN) { 681 fprintf(stderr, "Can not add new oid to the dynamic " 682 "table: %s\n", 683 oidStr); 684 secStatus = SECFailure; 685 break; 686 } 687 688 cvin[inParamIndex].type = cert_pi_policyOID; 689 cvin[inParamIndex].value.arraySize = 1; 690 cvin[inParamIndex].value.array.oids = &oidTag; 691 692 inParamIndex++; 693 } 694 695 if (trustedCertList) { 696 cvin[inParamIndex].type = cert_pi_trustAnchors; 697 cvin[inParamIndex].value.pointer.chain = trustedCertList; 698 699 inParamIndex++; 700 } 701 702 cvin[inParamIndex].type = cert_pi_useAIACertFetch; 703 cvin[inParamIndex].value.scalar.b = certFetching; 704 inParamIndex++; 705 706 rev.leafTests.cert_rev_flags_per_method = revFlagsLeaf; 707 rev.chainTests.cert_rev_flags_per_method = revFlagsChain; 708 secStatus = configureRevocationParams(&rev); 709 if (secStatus) { 710 fprintf(stderr, "Can not config revocation parameters "); 711 break; 712 } 713 714 cvin[inParamIndex].type = cert_pi_revocationFlags; 715 cvin[inParamIndex].value.pointer.revocation = &rev; 716 inParamIndex++; 717 718 if (time) { 719 cvin[inParamIndex].type = cert_pi_date; 720 cvin[inParamIndex].value.scalar.time = time; 721 inParamIndex++; 722 } 723 724 if (!onlyTrustAnchors) { 725 cvin[inParamIndex].type = cert_pi_useOnlyTrustAnchors; 726 cvin[inParamIndex].value.scalar.b = onlyTrustAnchors; 727 inParamIndex++; 728 } 729 730 cvin[inParamIndex].type = cert_pi_end; 731 732 cvout[0].type = cert_po_trustAnchor; 733 cvout[0].value.pointer.cert = NULL; 734 cvout[1].type = cert_po_certList; 735 cvout[1].value.pointer.chain = NULL; 736 737 /* setting pointer to CERTVerifyLog. Initialized structure 738 * will be used CERT_PKIXVerifyCert */ 739 cvout[2].type = cert_po_errorLog; 740 cvout[2].value.pointer.log = &log; 741 742 cvout[3].type = cert_po_end; 743 744 secStatus = CERT_PKIXVerifyCert(firstCert, certUsage, 745 cvin, cvout, &pwdata); 746 if (secStatus != SECSuccess) { 747 break; 748 } 749 issuerCert = cvout[0].value.pointer.cert; 750 builtChain = cvout[1].value.pointer.chain; 751 } while (0); 752 753 /* Display validation results */ 754 if (secStatus != SECSuccess || log.count > 0) { 755 CERTVerifyLogNode *node = NULL; 756 fprintf(stderr, "Chain is bad!\n"); 757 758 SECU_displayVerifyLog(stderr, &log, verbose); 759 /* Have cert refs in the log only in case of failure. 760 * Destroy them. */ 761 for (node = log.head; node; node = node->next) { 762 if (node->cert) 763 CERT_DestroyCertificate(node->cert); 764 } 765 log.head = log.tail = NULL; 766 log.count = 0; 767 rv = 1; 768 } else { 769 fprintf(stderr, "Chain is good!\n"); 770 if (issuerCert) { 771 if (verbose > 1) { 772 rv = SEC_PrintCertificateAndTrust(issuerCert, "Root Certificate", 773 NULL); 774 if (rv != SECSuccess) { 775 SECU_PrintError(progName, "problem printing certificate"); 776 } 777 } else if (verbose > 0) { 778 SECU_PrintName(stdout, &issuerCert->subject, "Root " 779 "Certificate Subject:", 780 0); 781 } 782 CERT_DestroyCertificate(issuerCert); 783 } 784 if (builtChain) { 785 CERTCertListNode *node; 786 int count = 0; 787 char buff[256]; 788 789 if (verbose) { 790 for (node = CERT_LIST_HEAD(builtChain); !CERT_LIST_END(node, builtChain); 791 node = CERT_LIST_NEXT(node), count++) { 792 snprintf(buff, sizeof(buff), "Certificate %d Subject", count + 1); 793 SECU_PrintName(stdout, &node->cert->subject, buff, 0); 794 } 795 } 796 CERT_DestroyCertList(builtChain); 797 } 798 rv = 0; 799 } 800 } while (--vfyCounts > 0); 801 802 /* Need to destroy CERTVerifyLog arena at the end */ 803 PORT_FreeArena(log.arena, PR_FALSE); 804 805 punt: 806 forgetCerts(); 807 if (NSS_Shutdown() != SECSuccess) { 808 SECU_PrintError(progName, "NSS_Shutdown"); 809 rv = 1; 810 } 811 PORT_Free(progName); 812 PORT_Free(certDir); 813 PORT_Free(oidStr); 814 freeRevocationMethodData(); 815 if (pwdata.data) { 816 PORT_Free(pwdata.data); 817 } 818 PL_ArenaFinish(); 819 PR_Cleanup(); 820 return rv; 821 }