81
81
Usage(const char *progName)
84
"Usage: %s [options] certfile [[options] certfile] ...\n"
84
"Usage: %s [options] [revocation options] certfile "
85
"[[options] certfile] ...\n"
85
86
"\tWhere options are:\n"
86
87
"\t-a\t\t Following certfile is base64 encoded\n"
87
88
"\t-b YYMMDDHHMMZ\t Validate date (default: now)\n"
88
89
"\t-d directory\t Database directory\n"
90
"\t-i number of consecutive verifications\n"
89
91
"\t-f \t\t Enable cert fetching from AIA URL\n"
90
92
"\t-o oid\t\t Set policy OID for cert validation(Format OID.1.2.3)\n"
91
93
"\t-p \t\t Use PKIX Library to validate certificate by calling:\n"
92
94
"\t\t\t * CERT_VerifyCertificate if specified once,\n"
93
95
"\t\t\t * CERT_PKIXVerifyCert if specified twice and more.\n"
94
96
"\t-r\t\t Following certfile is raw binary DER (default)\n"
95
"\t-s\t\t Status checking, following a configuration description.\n"
96
"\t\t\t Implemented as of today are:\n"
97
"\t\t\t * allow-crl (default)\n"
98
"\t\t\t * allow-crl-and-ocsp\n"
99
97
"\t-t\t\t Following cert is explicitly trusted (overrides db trust).\n"
100
98
"\t-u usage \t 0=SSL client, 1=SSL server, 2=SSL StepUp, 3=SSL CA,\n"
101
99
"\t\t\t 4=Email signer, 5=Email recipient, 6=Object signer,\n"
102
100
"\t\t\t 9=ProtectedObjectSigner, 10=OCSP responder, 11=Any CA\n"
103
101
"\t-v\t\t Verbose mode. Prints root cert subject(double the\n"
104
102
"\t\t\t argument for whole root cert info)\n"
105
"\t-w password\t Database password.\n",
106
"\t-W pwfile\t Password file.\n",
103
"\t-w password\t Database password.\n"
104
"\t-W pwfile\t Password file.\n\n"
105
"\tRevocation options for PKIX API(invoked with -pp options) is a\n"
106
"\tcollection of the following flags:\n"
107
"\t\t[-g type [-h flags] [-m type [-s flags]] ...] ...\n"
109
"\t-g test type\t Sets status checking test type. Possible values\n"
110
"\t\t\tare \"leaf\" or \"chain\"\n"
111
"\t-h test flags\t Sets revocation flags for the test type it\n"
112
"\t\t\tfollows. Possible flags: \"testLocalInfoFirst\" and\n"
113
"\t\t\t\"requireFreshInfo\".\n"
114
"\t-m method type\t Sets method type for the test type it follows.\n"
115
"\t\t\tPossible types are \"crl\" and \"ocsp\".\n"
116
"\t-s method flags\t Sets revocation flags for the method it follows.\n"
117
"\t\t\tPossible types are \"doNotUse\", \"forbidFetching\",\n"
118
"\t\t\t\"ignoreDefaultSrc\", \"requireInfo\" and \"failIfNoInfo\".\n",
232
#define REVCONFIG_ALLOW_CRL "allow-crl"
233
#define REVCONFIG_ALLOW_CRL_OCSP "allow-crl-and-ocsp"
245
#define REVCONFIG_TEST_UNDEFINED 0
246
#define REVCONFIG_TEST_LEAF 1
247
#define REVCONFIG_TEST_CHAIN 2
248
#define REVCONFIG_METHOD_CRL 1
249
#define REVCONFIG_METHOD_OCSP 2
251
#define REVCONFIG_TEST_LEAF_STR "leaf"
252
#define REVCONFIG_TEST_CHAIN_STR "chain"
253
#define REVCONFIG_METHOD_CRL_STR "crl"
254
#define REVCONFIG_METHOD_OCSP_STR "ocsp"
256
#define REVCONFIG_TEST_TESTLOCALINFOFIRST_STR "testLocalInfoFirst"
257
#define REVCONFIG_TEST_REQUIREFRESHINFO_STR "requireFreshInfo"
258
#define REVCONFIG_METHOD_DONOTUSEMETHOD_STR "doNotUse"
259
#define REVCONFIG_METHOD_FORBIDNETWORKFETCHIN_STR "forbidFetching"
260
#define REVCONFIG_METHOD_IGNOREDEFAULTSRC_STR "ignoreDefaultSrc"
261
#define REVCONFIG_METHOD_REQUIREINFO_STR "requireInfo"
262
#define REVCONFIG_METHOD_FAILIFNOINFO_STR "failIfNoInfo"
264
#define REV_METHOD_INDEX_MAX 4
266
typedef struct RevMethodsStruct {
274
char *methodFlagsStr;
277
RevMethods revMethodsData[REV_METHOD_INDEX_MAX];
280
parseRevMethodsAndFlags()
285
for(i = 0;i < REV_METHOD_INDEX_MAX;i++) {
287
if (revMethodsData[i].testTypeStr) {
288
char *typeStr = revMethodsData[i].testTypeStr;
291
if (!PORT_Strcmp(typeStr, REVCONFIG_TEST_LEAF_STR)) {
292
testType = REVCONFIG_TEST_LEAF;
293
} else if (!PORT_Strcmp(typeStr, REVCONFIG_TEST_CHAIN_STR)) {
294
testType = REVCONFIG_TEST_CHAIN;
300
revMethodsData[i].testType = testType;
302
if (revMethodsData[i].testFlagsStr) {
303
char *flagStr = revMethodsData[i].testFlagsStr;
306
if (PORT_Strstr(flagStr, REVCONFIG_TEST_TESTLOCALINFOFIRST_STR)) {
307
testFlags |= CERT_REV_MI_TEST_ALL_LOCAL_INFORMATION_FIRST;
309
if (PORT_Strstr(flagStr, REVCONFIG_TEST_REQUIREFRESHINFO_STR)) {
310
testFlags |= CERT_REV_MI_REQUIRE_SOME_FRESH_INFO_AVAILABLE;
312
revMethodsData[i].testFlags = testFlags;
315
if (revMethodsData[i].methodTypeStr) {
316
char *methodStr = revMethodsData[i].methodTypeStr;
319
if (!PORT_Strcmp(methodStr, REVCONFIG_METHOD_CRL_STR)) {
320
methodType = REVCONFIG_METHOD_CRL;
321
} else if (!PORT_Strcmp(methodStr, REVCONFIG_METHOD_OCSP_STR)) {
322
methodType = REVCONFIG_METHOD_OCSP;
327
revMethodsData[i].methodType = methodType;
329
if (!revMethodsData[i].methodType) {
330
revMethodsData[i].testType = REVCONFIG_TEST_UNDEFINED;
334
if (revMethodsData[i].methodFlagsStr) {
335
char *flagStr = revMethodsData[i].methodFlagsStr;
336
uint methodFlags = 0;
338
if (!PORT_Strstr(flagStr, REVCONFIG_METHOD_DONOTUSEMETHOD_STR)) {
339
methodFlags |= CERT_REV_M_TEST_USING_THIS_METHOD;
341
if (PORT_Strstr(flagStr,
342
REVCONFIG_METHOD_FORBIDNETWORKFETCHIN_STR)) {
343
methodFlags |= CERT_REV_M_FORBID_NETWORK_FETCHING;
345
if (PORT_Strstr(flagStr, REVCONFIG_METHOD_IGNOREDEFAULTSRC_STR)) {
346
methodFlags |= CERT_REV_M_IGNORE_IMPLICIT_DEFAULT_SOURCE;
348
if (PORT_Strstr(flagStr, REVCONFIG_METHOD_REQUIREINFO_STR)) {
349
methodFlags |= CERT_REV_M_REQUIRE_INFO_ON_MISSING_SOURCE;
351
if (PORT_Strstr(flagStr, REVCONFIG_METHOD_FAILIFNOINFO_STR)) {
352
methodFlags |= CERT_REV_M_FAIL_ON_MISSING_FRESH_INFO;
354
revMethodsData[i].methodFlags = methodFlags;
356
revMethodsData[i].methodFlags |= CERT_REV_M_TEST_USING_THIS_METHOD;
363
configureRevocationParams(CERTRevocationFlags *flags)
366
uint testType = REVCONFIG_TEST_UNDEFINED;
367
static CERTRevocationTests *revTests = NULL;
370
for(i = 0;i < REV_METHOD_INDEX_MAX;i++) {
371
if (revMethodsData[i].testType == REVCONFIG_TEST_UNDEFINED) {
374
if (revMethodsData[i].testType != testType) {
375
testType = revMethodsData[i].testType;
376
if (testType == REVCONFIG_TEST_CHAIN) {
377
revTests = &flags->chainTests;
379
revTests = &flags->leafTests;
381
revTests->number_of_preferred_methods = 0;
382
revTests->preferred_methods = 0;
383
revFlags = revTests->cert_rev_flags_per_method;
385
/* Set the number of the methods independently to the max number of
386
* methods. If method flags are not set it will be ignored due to
387
* default DO_NOT_USE flag. */
388
revTests->number_of_defined_methods = cert_revocation_method_count;
389
revTests->cert_rev_method_independent_flags |=
390
revMethodsData[i].testFlags;
391
if (revMethodsData[i].methodType == REVCONFIG_METHOD_CRL) {
392
revFlags[cert_revocation_method_crl] =
393
revMethodsData[i].methodFlags;
394
} else if (revMethodsData[i].methodType == REVCONFIG_METHOD_OCSP) {
395
revFlags[cert_revocation_method_ocsp] =
396
revMethodsData[i].methodFlags;
403
freeRevocationMethodData()
406
for(;i < REV_METHOD_INDEX_MAX;i++) {
407
if (revMethodsData[i].testTypeStr) {
408
PORT_Free(revMethodsData[i].testTypeStr);
410
if (revMethodsData[i].testFlagsStr) {
411
PORT_Free(revMethodsData[i].testFlagsStr);
413
if (revMethodsData[i].methodTypeStr) {
414
PORT_Free(revMethodsData[i].methodTypeStr);
416
if (revMethodsData[i].methodFlagsStr) {
417
PORT_Free(revMethodsData[i].methodFlagsStr);
236
isAllowedRevConfig(const char *name)
238
if (strcmp(REVCONFIG_ALLOW_CRL, name) == 0)
241
if (strcmp(REVCONFIG_ALLOW_CRL_OCSP, name) == 0)
427
for(i = 0;i < REV_METHOD_INDEX_MAX;i++) {
428
if (revMethodsData[i].methodType == REVCONFIG_METHOD_OCSP) {
374
603
if (status == PL_OPT_BAD || !firstCert)
380
606
/* Initialize log structure */
381
607
log.arena = PORT_NewArena(512);
382
608
log.head = log.tail = NULL;
386
/* NOW, verify the cert chain. */
388
/* Use old API with libpkix validation lib */
389
CERT_SetUsePKIXForValidation(PR_TRUE);
391
defaultDB = CERT_GetDefaultCertDB();
392
secStatus = CERT_VerifyCertificate(defaultDB, firstCert,
393
PR_TRUE /* check sig */,
397
&log, /* error log */
613
/* NOW, verify the cert chain. */
615
/* Use old API with libpkix validation lib */
616
CERT_SetUsePKIXForValidation(PR_TRUE);
621
defaultDB = CERT_GetDefaultCertDB();
622
secStatus = CERT_VerifyCertificate(defaultDB, firstCert,
623
PR_TRUE /* check sig */,
627
&log, /* error log */
398
628
NULL);/* returned usages */
400
static CERTValOutParam cvout[4];
401
static CERTValInParam cvin[6];
403
int inParamIndex = 0;
404
static CERTRevocationFlags rev;
405
static PRUint64 revFlags[2];
410
memset(&od, 0, sizeof od);
411
od.offset = SEC_OID_UNKNOWN;
412
od.desc = "User Defined Policy OID";
413
od.mechanism = CKM_INVALID_MECHANISM;
414
od.supportedExtension = INVALID_CERT_EXTENSION;
416
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
418
fprintf(stderr, "out of memory");
422
secStatus = SEC_StringToOID(arena, &od.oid, oidStr, 0);
423
if (secStatus != SECSuccess) {
424
PORT_FreeArena(arena, PR_FALSE);
425
fprintf(stderr, "Can not encode oid: %s(%s)\n", oidStr,
426
SECU_Strerror(PORT_GetError()));
430
oidTag = SECOID_AddEntry(&od);
431
PORT_FreeArena(arena, PR_FALSE);
432
if (oidTag == SEC_OID_UNKNOWN) {
433
fprintf(stderr, "Can not add new oid to the dynamic "
434
"table: %s\n", oidStr);
435
secStatus = SECFailure;
439
cvin[inParamIndex].type = cert_pi_policyOID;
440
cvin[inParamIndex].value.arraySize = 1;
441
cvin[inParamIndex].value.array.oids = &oidTag;
446
if (trustedCertList) {
447
cvin[inParamIndex].type = cert_pi_trustAnchors;
448
cvin[inParamIndex].value.pointer.chain = trustedCertList;
453
cvin[inParamIndex].type = cert_pi_useAIACertFetch;
454
cvin[inParamIndex].value.scalar.b = certFetching;
457
cvin[inParamIndex].type = cert_pi_date;
458
cvin[inParamIndex].value.scalar.time = time;
461
revFlags[cert_revocation_method_crl] =
462
CERT_REV_M_TEST_USING_THIS_METHOD;
463
rev.leafTests.number_of_defined_methods =
464
cert_revocation_method_crl +1;
465
rev.chainTests.number_of_defined_methods =
466
cert_revocation_method_crl +1;
468
if (revConfig && strcmp(REVCONFIG_ALLOW_CRL_OCSP, revConfig) == 0) {
469
revFlags[cert_revocation_method_ocsp] =
470
CERT_REV_M_TEST_USING_THIS_METHOD;
471
rev.leafTests.number_of_defined_methods =
472
cert_revocation_method_ocsp +1;
473
rev.chainTests.number_of_defined_methods =
474
cert_revocation_method_ocsp +1;
477
rev.leafTests.cert_rev_flags_per_method = revFlags;
478
rev.leafTests.number_of_preferred_methods = 0;
479
rev.leafTests.preferred_methods = 0;
480
rev.leafTests.cert_rev_method_independent_flags = 0;
482
rev.chainTests.cert_rev_flags_per_method = revFlags;
483
rev.chainTests.number_of_preferred_methods = 0;
484
rev.chainTests.preferred_methods = 0;
485
rev.chainTests.cert_rev_method_independent_flags = 0;
487
cvin[inParamIndex].type = cert_pi_revocationFlags;
488
cvin[inParamIndex].value.pointer.revocation = &rev;
491
cvin[inParamIndex].type = cert_pi_end;
493
cvout[0].type = cert_po_trustAnchor;
494
cvout[0].value.pointer.cert = NULL;
495
cvout[1].type = cert_po_certList;
496
cvout[1].value.pointer.chain = NULL;
498
/* setting pointer to CERTVerifyLog. Initialized structure
499
* will be used CERT_PKIXVerifyCert */
500
cvout[2].type = cert_po_errorLog;
501
cvout[2].value.pointer.log = &log;
503
cvout[3].type = cert_po_end;
505
secStatus = CERT_PKIXVerifyCert(firstCert, certUsage,
506
cvin, cvout, &pwdata);
507
if (secStatus != SECSuccess) {
510
issuerCert = cvout[0].value.pointer.cert;
511
builtChain = cvout[1].value.pointer.chain;
514
/* Display validation results */
515
if (secStatus != SECSuccess || log.count > 0) {
516
CERTVerifyLogNode *node = NULL;
517
PRIntn err = PR_GetError();
518
fprintf(stderr, "Chain is bad, %d = %s\n", err, SECU_Strerror(err));
520
SECU_displayVerifyLog(stderr, &log, verbose);
521
/* Have cert refs in the log only in case of failure.
523
for (node = log.head; node; node = node->next) {
525
CERT_DestroyCertificate(node->cert);
529
fprintf(stderr, "Chain is good!\n");
532
rv = SEC_PrintCertificateAndTrust(issuerCert, "Root Certificate",
534
if (rv != SECSuccess) {
535
SECU_PrintError(progName, "problem printing certificate");
537
} else if (verbose > 0) {
538
SECU_PrintName(stdout, &issuerCert->subject, "Root "
539
"Certificate Subject:", 0);
541
CERT_DestroyCertificate(issuerCert);
544
CERTCertListNode *node;
549
for(node = CERT_LIST_HEAD(builtChain); !CERT_LIST_END(node, builtChain);
550
node = CERT_LIST_NEXT(node), count++ ) {
551
sprintf(buff, "Certificate %d Subject", count + 1);
552
SECU_PrintName(stdout, &node->cert->subject, buff, 0);
555
CERT_DestroyCertList(builtChain);
630
static CERTValOutParam cvout[4];
631
static CERTValInParam cvin[6];
633
int inParamIndex = 0;
634
static PRUint64 revFlagsLeaf[2];
635
static PRUint64 revFlagsChain[2];
636
static CERTRevocationFlags rev;
641
memset(&od, 0, sizeof od);
642
od.offset = SEC_OID_UNKNOWN;
643
od.desc = "User Defined Policy OID";
644
od.mechanism = CKM_INVALID_MECHANISM;
645
od.supportedExtension = INVALID_CERT_EXTENSION;
647
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
649
fprintf(stderr, "out of memory");
653
secStatus = SEC_StringToOID(arena, &od.oid, oidStr, 0);
654
if (secStatus != SECSuccess) {
655
PORT_FreeArena(arena, PR_FALSE);
656
fprintf(stderr, "Can not encode oid: %s(%s)\n", oidStr,
657
SECU_Strerror(PORT_GetError()));
661
oidTag = SECOID_AddEntry(&od);
662
PORT_FreeArena(arena, PR_FALSE);
663
if (oidTag == SEC_OID_UNKNOWN) {
664
fprintf(stderr, "Can not add new oid to the dynamic "
665
"table: %s\n", oidStr);
666
secStatus = SECFailure;
670
cvin[inParamIndex].type = cert_pi_policyOID;
671
cvin[inParamIndex].value.arraySize = 1;
672
cvin[inParamIndex].value.array.oids = &oidTag;
677
if (trustedCertList) {
678
cvin[inParamIndex].type = cert_pi_trustAnchors;
679
cvin[inParamIndex].value.pointer.chain = trustedCertList;
684
cvin[inParamIndex].type = cert_pi_useAIACertFetch;
685
cvin[inParamIndex].value.scalar.b = certFetching;
688
rev.leafTests.cert_rev_flags_per_method = revFlagsLeaf;
689
rev.chainTests.cert_rev_flags_per_method = revFlagsChain;
690
secStatus = configureRevocationParams(&rev);
692
fprintf(stderr, "Can not config revocation parameters ");
696
cvin[inParamIndex].type = cert_pi_revocationFlags;
697
cvin[inParamIndex].value.pointer.revocation = &rev;
701
cvin[inParamIndex].type = cert_pi_date;
702
cvin[inParamIndex].value.scalar.time = time;
706
cvin[inParamIndex].type = cert_pi_end;
708
cvout[0].type = cert_po_trustAnchor;
709
cvout[0].value.pointer.cert = NULL;
710
cvout[1].type = cert_po_certList;
711
cvout[1].value.pointer.chain = NULL;
713
/* setting pointer to CERTVerifyLog. Initialized structure
714
* will be used CERT_PKIXVerifyCert */
715
cvout[2].type = cert_po_errorLog;
716
cvout[2].value.pointer.log = &log;
718
cvout[3].type = cert_po_end;
720
secStatus = CERT_PKIXVerifyCert(firstCert, certUsage,
721
cvin, cvout, &pwdata);
722
if (secStatus != SECSuccess) {
725
issuerCert = cvout[0].value.pointer.cert;
726
builtChain = cvout[1].value.pointer.chain;
729
/* Display validation results */
730
if (secStatus != SECSuccess || log.count > 0) {
731
CERTVerifyLogNode *node = NULL;
732
PRIntn err = PR_GetError();
733
fprintf(stderr, "Chain is bad, %d = %s\n", err, SECU_Strerror(err));
735
SECU_displayVerifyLog(stderr, &log, verbose);
736
/* Have cert refs in the log only in case of failure.
738
for (node = log.head; node; node = node->next) {
740
CERT_DestroyCertificate(node->cert);
744
fprintf(stderr, "Chain is good!\n");
747
rv = SEC_PrintCertificateAndTrust(issuerCert, "Root Certificate",
749
if (rv != SECSuccess) {
750
SECU_PrintError(progName, "problem printing certificate");
752
} else if (verbose > 0) {
753
SECU_PrintName(stdout, &issuerCert->subject, "Root "
754
"Certificate Subject:", 0);
756
CERT_DestroyCertificate(issuerCert);
759
CERTCertListNode *node;
764
for(node = CERT_LIST_HEAD(builtChain); !CERT_LIST_END(node, builtChain);
765
node = CERT_LIST_NEXT(node), count++ ) {
766
sprintf(buff, "Certificate %d Subject", count + 1);
767
SECU_PrintName(stdout, &node->cert->subject, buff, 0);
770
CERT_DestroyCertList(builtChain);
774
} while (--vfyCounts > 0);
560
776
/* Need to destroy CERTVerifyLog arena at the end */
561
777
PORT_FreeArena(log.arena, PR_FALSE);