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
Usage(const char * progName)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
errWarn(char * function)101 errWarn(char *function)
102 {
103 fprintf(stderr, "Error in function %s: %s\n",
104 function, SECU_Strerror(PR_GetError()));
105 }
106
107 void
exitErr(char * function)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
rememberCert(CERTCertificate * cert,PRBool trusted)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
forgetCerts(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 *
getCert(const char * name,PRBool isAscii,const char * progName)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
parseRevMethodsAndFlags()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
configureRevocationParams(CERTRevocationFlags * flags)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
freeRevocationMethodData()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
isOCSPEnabled()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
main(int argc,char * argv[],char * envp[])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 sprintf(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 }
822