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