security/nss/cmd/vfychain/vfychain.c

Wed, 31 Dec 2014 07:16:47 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:16:47 +0100
branch
TOR_BUG_9701
changeset 3
141e0f1194b1
permissions
-rw-r--r--

Revert simplistic fix pending revisit of Mozilla integration attempt.

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

mercurial