1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/cmd/vfychain/vfychain.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,777 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +/**************************************************************************** 1.9 + * Read in a cert chain from one or more files, and verify the chain for 1.10 + * some usage. 1.11 + * * 1.12 + * This code was modified from other code also kept in the NSS directory. 1.13 + ****************************************************************************/ 1.14 + 1.15 +#include <stdio.h> 1.16 +#include <string.h> 1.17 + 1.18 +#if defined(XP_UNIX) 1.19 +#include <unistd.h> 1.20 +#endif 1.21 + 1.22 +#include "prerror.h" 1.23 + 1.24 +#include "pk11func.h" 1.25 +#include "seccomon.h" 1.26 +#include "secutil.h" 1.27 +#include "secmod.h" 1.28 +#include "secitem.h" 1.29 +#include "cert.h" 1.30 +#include "ocsp.h" 1.31 + 1.32 + 1.33 +/* #include <stdlib.h> */ 1.34 +/* #include <errno.h> */ 1.35 +/* #include <fcntl.h> */ 1.36 +/* #include <stdarg.h> */ 1.37 + 1.38 +#include "nspr.h" 1.39 +#include "plgetopt.h" 1.40 +#include "prio.h" 1.41 +#include "nss.h" 1.42 + 1.43 +/* #include "vfyutil.h" */ 1.44 + 1.45 +#define RD_BUF_SIZE (60 * 1024) 1.46 + 1.47 +int verbose; 1.48 + 1.49 +secuPWData pwdata = { PW_NONE, 0 }; 1.50 + 1.51 +static void 1.52 +Usage(const char *progName) 1.53 +{ 1.54 + fprintf(stderr, 1.55 + "Usage: %s [options] [revocation options] certfile " 1.56 + "[[options] certfile] ...\n" 1.57 + "\tWhere options are:\n" 1.58 + "\t-a\t\t Following certfile is base64 encoded\n" 1.59 + "\t-b YYMMDDHHMMZ\t Validate date (default: now)\n" 1.60 + "\t-d directory\t Database directory\n" 1.61 + "\t-i number of consecutive verifications\n" 1.62 + "\t-f \t\t Enable cert fetching from AIA URL\n" 1.63 + "\t-o oid\t\t Set policy OID for cert validation(Format OID.1.2.3)\n" 1.64 + "\t-p \t\t Use PKIX Library to validate certificate by calling:\n" 1.65 + "\t\t\t * CERT_VerifyCertificate if specified once,\n" 1.66 + "\t\t\t * CERT_PKIXVerifyCert if specified twice and more.\n" 1.67 + "\t-r\t\t Following certfile is raw binary DER (default)\n" 1.68 + "\t-t\t\t Following cert is explicitly trusted (overrides db trust).\n" 1.69 + "\t-u usage \t 0=SSL client, 1=SSL server, 2=SSL StepUp, 3=SSL CA,\n" 1.70 + "\t\t\t 4=Email signer, 5=Email recipient, 6=Object signer,\n" 1.71 + "\t\t\t 9=ProtectedObjectSigner, 10=OCSP responder, 11=Any CA\n" 1.72 + "\t-T\t\t Trust both explicit trust anchors (-t) and the database.\n" 1.73 + "\t\t\t (Default is to only trust certificates marked -t, if there are any,\n" 1.74 + "\t\t\t or to trust the database if there are certificates marked -t.)\n" 1.75 + "\t-v\t\t Verbose mode. Prints root cert subject(double the\n" 1.76 + "\t\t\t argument for whole root cert info)\n" 1.77 + "\t-w password\t Database password.\n" 1.78 + "\t-W pwfile\t Password file.\n\n" 1.79 + "\tRevocation options for PKIX API(invoked with -pp options) is a\n" 1.80 + "\tcollection of the following flags:\n" 1.81 + "\t\t[-g type [-h flags] [-m type [-s flags]] ...] ...\n" 1.82 + "\tWhere:\n" 1.83 + "\t-g test type\t Sets status checking test type. Possible values\n" 1.84 + "\t\t\tare \"leaf\" or \"chain\"\n" 1.85 + "\t-h test flags\t Sets revocation flags for the test type it\n" 1.86 + "\t\t\tfollows. Possible flags: \"testLocalInfoFirst\" and\n" 1.87 + "\t\t\t\"requireFreshInfo\".\n" 1.88 + "\t-m method type\t Sets method type for the test type it follows.\n" 1.89 + "\t\t\tPossible types are \"crl\" and \"ocsp\".\n" 1.90 + "\t-s method flags\t Sets revocation flags for the method it follows.\n" 1.91 + "\t\t\tPossible types are \"doNotUse\", \"forbidFetching\",\n" 1.92 + "\t\t\t\"ignoreDefaultSrc\", \"requireInfo\" and \"failIfNoInfo\".\n", 1.93 + progName); 1.94 + exit(1); 1.95 +} 1.96 + 1.97 +/************************************************************************** 1.98 +** 1.99 +** Error and information routines. 1.100 +** 1.101 +**************************************************************************/ 1.102 + 1.103 +void 1.104 +errWarn(char *function) 1.105 +{ 1.106 + fprintf(stderr, "Error in function %s: %s\n", 1.107 + function, SECU_Strerror(PR_GetError())); 1.108 +} 1.109 + 1.110 +void 1.111 +exitErr(char *function) 1.112 +{ 1.113 + errWarn(function); 1.114 + /* Exit gracefully. */ 1.115 + /* ignoring return value of NSS_Shutdown as code exits with 1 anyway*/ 1.116 + (void) NSS_Shutdown(); 1.117 + PR_Cleanup(); 1.118 + exit(1); 1.119 +} 1.120 + 1.121 +typedef struct certMemStr { 1.122 + struct certMemStr * next; 1.123 + CERTCertificate * cert; 1.124 +} certMem; 1.125 + 1.126 +certMem * theCerts; 1.127 +CERTCertList *trustedCertList; 1.128 + 1.129 +void 1.130 +rememberCert(CERTCertificate * cert, PRBool trusted) 1.131 +{ 1.132 + if (trusted) { 1.133 + if (!trustedCertList) { 1.134 + trustedCertList = CERT_NewCertList(); 1.135 + } 1.136 + CERT_AddCertToListTail(trustedCertList, cert); 1.137 + } else { 1.138 + certMem * newCertMem = PORT_ZNew(certMem); 1.139 + if (newCertMem) { 1.140 + newCertMem->next = theCerts; 1.141 + newCertMem->cert = cert; 1.142 + theCerts = newCertMem; 1.143 + } 1.144 + } 1.145 +} 1.146 + 1.147 +void 1.148 +forgetCerts(void) 1.149 +{ 1.150 + certMem * oldCertMem; 1.151 + while (theCerts) { 1.152 + oldCertMem = theCerts; 1.153 + theCerts = theCerts->next; 1.154 + CERT_DestroyCertificate(oldCertMem->cert); 1.155 + PORT_Free(oldCertMem); 1.156 + } 1.157 + if (trustedCertList) { 1.158 + CERT_DestroyCertList(trustedCertList); 1.159 + } 1.160 +} 1.161 + 1.162 + 1.163 +CERTCertificate * 1.164 +getCert(const char *name, PRBool isAscii, const char * progName) 1.165 +{ 1.166 + CERTCertificate * cert; 1.167 + CERTCertDBHandle *defaultDB; 1.168 + PRFileDesc* fd; 1.169 + SECStatus rv; 1.170 + SECItem item = {0, NULL, 0}; 1.171 + 1.172 + defaultDB = CERT_GetDefaultCertDB(); 1.173 + 1.174 + /* First, let's try to find the cert in existing DB. */ 1.175 + cert = CERT_FindCertByNicknameOrEmailAddr(defaultDB, name); 1.176 + if (cert) { 1.177 + return cert; 1.178 + } 1.179 + 1.180 + /* Don't have a cert with name "name" in the DB. Try to 1.181 + * open a file with such name and get the cert from there.*/ 1.182 + fd = PR_Open(name, PR_RDONLY, 0777); 1.183 + if (!fd) { 1.184 + PRErrorCode err = PR_GetError(); 1.185 + fprintf(stderr, "open of %s failed, %d = %s\n", 1.186 + name, err, SECU_Strerror(err)); 1.187 + return cert; 1.188 + } 1.189 + 1.190 + rv = SECU_ReadDERFromFile(&item, fd, isAscii, PR_FALSE); 1.191 + PR_Close(fd); 1.192 + if (rv != SECSuccess) { 1.193 + fprintf(stderr, "%s: SECU_ReadDERFromFile failed\n", progName); 1.194 + return cert; 1.195 + } 1.196 + 1.197 + if (!item.len) { /* file was empty */ 1.198 + fprintf(stderr, "cert file %s was empty.\n", name); 1.199 + return cert; 1.200 + } 1.201 + 1.202 + cert = CERT_NewTempCertificate(defaultDB, &item, 1.203 + NULL /* nickname */, 1.204 + PR_FALSE /* isPerm */, 1.205 + PR_TRUE /* copyDER */); 1.206 + if (!cert) { 1.207 + PRErrorCode err = PR_GetError(); 1.208 + fprintf(stderr, "couldn't import %s, %d = %s\n", 1.209 + name, err, SECU_Strerror(err)); 1.210 + } 1.211 + PORT_Free(item.data); 1.212 + return cert; 1.213 +} 1.214 + 1.215 + 1.216 +#define REVCONFIG_TEST_UNDEFINED 0 1.217 +#define REVCONFIG_TEST_LEAF 1 1.218 +#define REVCONFIG_TEST_CHAIN 2 1.219 +#define REVCONFIG_METHOD_CRL 1 1.220 +#define REVCONFIG_METHOD_OCSP 2 1.221 + 1.222 +#define REVCONFIG_TEST_LEAF_STR "leaf" 1.223 +#define REVCONFIG_TEST_CHAIN_STR "chain" 1.224 +#define REVCONFIG_METHOD_CRL_STR "crl" 1.225 +#define REVCONFIG_METHOD_OCSP_STR "ocsp" 1.226 + 1.227 +#define REVCONFIG_TEST_TESTLOCALINFOFIRST_STR "testLocalInfoFirst" 1.228 +#define REVCONFIG_TEST_REQUIREFRESHINFO_STR "requireFreshInfo" 1.229 +#define REVCONFIG_METHOD_DONOTUSEMETHOD_STR "doNotUse" 1.230 +#define REVCONFIG_METHOD_FORBIDNETWORKFETCHIN_STR "forbidFetching" 1.231 +#define REVCONFIG_METHOD_IGNOREDEFAULTSRC_STR "ignoreDefaultSrc" 1.232 +#define REVCONFIG_METHOD_REQUIREINFO_STR "requireInfo" 1.233 +#define REVCONFIG_METHOD_FAILIFNOINFO_STR "failIfNoInfo" 1.234 + 1.235 +#define REV_METHOD_INDEX_MAX 4 1.236 + 1.237 +typedef struct RevMethodsStruct { 1.238 + unsigned int testType; 1.239 + char *testTypeStr; 1.240 + unsigned int testFlags; 1.241 + char *testFlagsStr; 1.242 + unsigned int methodType; 1.243 + char *methodTypeStr; 1.244 + unsigned int methodFlags; 1.245 + char *methodFlagsStr; 1.246 +} RevMethods; 1.247 + 1.248 +RevMethods revMethodsData[REV_METHOD_INDEX_MAX]; 1.249 + 1.250 +SECStatus 1.251 +parseRevMethodsAndFlags() 1.252 +{ 1.253 + int i; 1.254 + unsigned int testType = 0; 1.255 + 1.256 + for(i = 0;i < REV_METHOD_INDEX_MAX;i++) { 1.257 + /* testType */ 1.258 + if (revMethodsData[i].testTypeStr) { 1.259 + char *typeStr = revMethodsData[i].testTypeStr; 1.260 + 1.261 + testType = 0; 1.262 + if (!PORT_Strcmp(typeStr, REVCONFIG_TEST_LEAF_STR)) { 1.263 + testType = REVCONFIG_TEST_LEAF; 1.264 + } else if (!PORT_Strcmp(typeStr, REVCONFIG_TEST_CHAIN_STR)) { 1.265 + testType = REVCONFIG_TEST_CHAIN; 1.266 + } 1.267 + } 1.268 + if (!testType) { 1.269 + return SECFailure; 1.270 + } 1.271 + revMethodsData[i].testType = testType; 1.272 + /* testFlags */ 1.273 + if (revMethodsData[i].testFlagsStr) { 1.274 + char *flagStr = revMethodsData[i].testFlagsStr; 1.275 + unsigned int testFlags = 0; 1.276 + 1.277 + if (PORT_Strstr(flagStr, REVCONFIG_TEST_TESTLOCALINFOFIRST_STR)) { 1.278 + testFlags |= CERT_REV_MI_TEST_ALL_LOCAL_INFORMATION_FIRST; 1.279 + } 1.280 + if (PORT_Strstr(flagStr, REVCONFIG_TEST_REQUIREFRESHINFO_STR)) { 1.281 + testFlags |= CERT_REV_MI_REQUIRE_SOME_FRESH_INFO_AVAILABLE; 1.282 + } 1.283 + revMethodsData[i].testFlags = testFlags; 1.284 + } 1.285 + /* method type */ 1.286 + if (revMethodsData[i].methodTypeStr) { 1.287 + char *methodStr = revMethodsData[i].methodTypeStr; 1.288 + unsigned int methodType = 0; 1.289 + 1.290 + if (!PORT_Strcmp(methodStr, REVCONFIG_METHOD_CRL_STR)) { 1.291 + methodType = REVCONFIG_METHOD_CRL; 1.292 + } else if (!PORT_Strcmp(methodStr, REVCONFIG_METHOD_OCSP_STR)) { 1.293 + methodType = REVCONFIG_METHOD_OCSP; 1.294 + } 1.295 + if (!methodType) { 1.296 + return SECFailure; 1.297 + } 1.298 + revMethodsData[i].methodType = methodType; 1.299 + } 1.300 + if (!revMethodsData[i].methodType) { 1.301 + revMethodsData[i].testType = REVCONFIG_TEST_UNDEFINED; 1.302 + continue; 1.303 + } 1.304 + /* method flags */ 1.305 + if (revMethodsData[i].methodFlagsStr) { 1.306 + char *flagStr = revMethodsData[i].methodFlagsStr; 1.307 + unsigned int methodFlags = 0; 1.308 + 1.309 + if (!PORT_Strstr(flagStr, REVCONFIG_METHOD_DONOTUSEMETHOD_STR)) { 1.310 + methodFlags |= CERT_REV_M_TEST_USING_THIS_METHOD; 1.311 + } 1.312 + if (PORT_Strstr(flagStr, 1.313 + REVCONFIG_METHOD_FORBIDNETWORKFETCHIN_STR)) { 1.314 + methodFlags |= CERT_REV_M_FORBID_NETWORK_FETCHING; 1.315 + } 1.316 + if (PORT_Strstr(flagStr, REVCONFIG_METHOD_IGNOREDEFAULTSRC_STR)) { 1.317 + methodFlags |= CERT_REV_M_IGNORE_IMPLICIT_DEFAULT_SOURCE; 1.318 + } 1.319 + if (PORT_Strstr(flagStr, REVCONFIG_METHOD_REQUIREINFO_STR)) { 1.320 + methodFlags |= CERT_REV_M_REQUIRE_INFO_ON_MISSING_SOURCE; 1.321 + } 1.322 + if (PORT_Strstr(flagStr, REVCONFIG_METHOD_FAILIFNOINFO_STR)) { 1.323 + methodFlags |= CERT_REV_M_FAIL_ON_MISSING_FRESH_INFO; 1.324 + } 1.325 + revMethodsData[i].methodFlags = methodFlags; 1.326 + } else { 1.327 + revMethodsData[i].methodFlags |= CERT_REV_M_TEST_USING_THIS_METHOD; 1.328 + } 1.329 + } 1.330 + return SECSuccess; 1.331 +} 1.332 + 1.333 +SECStatus 1.334 +configureRevocationParams(CERTRevocationFlags *flags) 1.335 +{ 1.336 + int i; 1.337 + unsigned int testType = REVCONFIG_TEST_UNDEFINED; 1.338 + static CERTRevocationTests *revTests = NULL; 1.339 + PRUint64 *revFlags; 1.340 + 1.341 + for(i = 0;i < REV_METHOD_INDEX_MAX;i++) { 1.342 + if (revMethodsData[i].testType == REVCONFIG_TEST_UNDEFINED) { 1.343 + continue; 1.344 + } 1.345 + if (revMethodsData[i].testType != testType) { 1.346 + testType = revMethodsData[i].testType; 1.347 + if (testType == REVCONFIG_TEST_CHAIN) { 1.348 + revTests = &flags->chainTests; 1.349 + } else { 1.350 + revTests = &flags->leafTests; 1.351 + } 1.352 + revTests->number_of_preferred_methods = 0; 1.353 + revTests->preferred_methods = 0; 1.354 + revFlags = revTests->cert_rev_flags_per_method; 1.355 + } 1.356 + /* Set the number of the methods independently to the max number of 1.357 + * methods. If method flags are not set it will be ignored due to 1.358 + * default DO_NOT_USE flag. */ 1.359 + revTests->number_of_defined_methods = cert_revocation_method_count; 1.360 + revTests->cert_rev_method_independent_flags |= 1.361 + revMethodsData[i].testFlags; 1.362 + if (revMethodsData[i].methodType == REVCONFIG_METHOD_CRL) { 1.363 + revFlags[cert_revocation_method_crl] = 1.364 + revMethodsData[i].methodFlags; 1.365 + } else if (revMethodsData[i].methodType == REVCONFIG_METHOD_OCSP) { 1.366 + revFlags[cert_revocation_method_ocsp] = 1.367 + revMethodsData[i].methodFlags; 1.368 + } 1.369 + } 1.370 + return SECSuccess; 1.371 +} 1.372 + 1.373 +void 1.374 +freeRevocationMethodData() 1.375 +{ 1.376 + int i = 0; 1.377 + for(;i < REV_METHOD_INDEX_MAX;i++) { 1.378 + if (revMethodsData[i].testTypeStr) { 1.379 + PORT_Free(revMethodsData[i].testTypeStr); 1.380 + } 1.381 + if (revMethodsData[i].testFlagsStr) { 1.382 + PORT_Free(revMethodsData[i].testFlagsStr); 1.383 + } 1.384 + if (revMethodsData[i].methodTypeStr) { 1.385 + PORT_Free(revMethodsData[i].methodTypeStr); 1.386 + } 1.387 + if (revMethodsData[i].methodFlagsStr) { 1.388 + PORT_Free(revMethodsData[i].methodFlagsStr); 1.389 + } 1.390 + } 1.391 +} 1.392 + 1.393 +PRBool 1.394 +isOCSPEnabled() 1.395 +{ 1.396 + int i; 1.397 + 1.398 + for(i = 0;i < REV_METHOD_INDEX_MAX;i++) { 1.399 + if (revMethodsData[i].methodType == REVCONFIG_METHOD_OCSP) { 1.400 + return PR_TRUE; 1.401 + } 1.402 + } 1.403 + return PR_FALSE; 1.404 +} 1.405 + 1.406 +int 1.407 +main(int argc, char *argv[], char *envp[]) 1.408 +{ 1.409 + char * certDir = NULL; 1.410 + char * progName = NULL; 1.411 + char * oidStr = NULL; 1.412 + CERTCertificate * cert; 1.413 + CERTCertificate * firstCert = NULL; 1.414 + CERTCertificate * issuerCert = NULL; 1.415 + CERTCertDBHandle * defaultDB = NULL; 1.416 + PRBool isAscii = PR_FALSE; 1.417 + PRBool trusted = PR_FALSE; 1.418 + SECStatus secStatus; 1.419 + SECCertificateUsage certUsage = certificateUsageSSLServer; 1.420 + PLOptState * optstate; 1.421 + PRTime time = 0; 1.422 + PLOptStatus status; 1.423 + int usePkix = 0; 1.424 + int rv = 1; 1.425 + int usage; 1.426 + CERTVerifyLog log; 1.427 + CERTCertList *builtChain = NULL; 1.428 + PRBool certFetching = PR_FALSE; 1.429 + int revDataIndex = 0; 1.430 + PRBool ocsp_fetchingFailureIsAFailure = PR_TRUE; 1.431 + PRBool useDefaultRevFlags = PR_TRUE; 1.432 + PRBool onlyTrustAnchors = PR_TRUE; 1.433 + int vfyCounts = 1; 1.434 + 1.435 + PR_Init( PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); 1.436 + 1.437 + progName = PL_strdup(argv[0]); 1.438 + 1.439 + optstate = PL_CreateOptState(argc, argv, "ab:c:d:efg:h:i:m:o:prs:tTu:vw:W:"); 1.440 + while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) { 1.441 + switch(optstate->option) { 1.442 + case 0 : /* positional parameter */ goto breakout; 1.443 + case 'a' : isAscii = PR_TRUE; break; 1.444 + case 'b' : secStatus = DER_AsciiToTime(&time, optstate->value); 1.445 + if (secStatus != SECSuccess) Usage(progName); break; 1.446 + case 'd' : certDir = PL_strdup(optstate->value); break; 1.447 + case 'e' : ocsp_fetchingFailureIsAFailure = PR_FALSE; break; 1.448 + case 'f' : certFetching = PR_TRUE; break; 1.449 + case 'g' : 1.450 + if (revMethodsData[revDataIndex].testTypeStr || 1.451 + revMethodsData[revDataIndex].methodTypeStr) { 1.452 + revDataIndex += 1; 1.453 + if (revDataIndex == REV_METHOD_INDEX_MAX) { 1.454 + fprintf(stderr, "Invalid revocation configuration" 1.455 + "specified.\n"); 1.456 + secStatus = SECFailure; 1.457 + break; 1.458 + } 1.459 + } 1.460 + useDefaultRevFlags = PR_FALSE; 1.461 + revMethodsData[revDataIndex]. 1.462 + testTypeStr = PL_strdup(optstate->value); break; 1.463 + case 'h' : 1.464 + revMethodsData[revDataIndex]. 1.465 + testFlagsStr = PL_strdup(optstate->value);break; 1.466 + case 'i' : vfyCounts = PORT_Atoi(optstate->value); break; 1.467 + break; 1.468 + case 'm' : 1.469 + if (revMethodsData[revDataIndex].methodTypeStr) { 1.470 + revDataIndex += 1; 1.471 + if (revDataIndex == REV_METHOD_INDEX_MAX) { 1.472 + fprintf(stderr, "Invalid revocation configuration" 1.473 + "specified.\n"); 1.474 + secStatus = SECFailure; 1.475 + break; 1.476 + } 1.477 + } 1.478 + useDefaultRevFlags = PR_FALSE; 1.479 + revMethodsData[revDataIndex]. 1.480 + methodTypeStr = PL_strdup(optstate->value); break; 1.481 + case 'o' : oidStr = PL_strdup(optstate->value); break; 1.482 + case 'p' : usePkix += 1; break; 1.483 + case 'r' : isAscii = PR_FALSE; break; 1.484 + case 's' : 1.485 + revMethodsData[revDataIndex]. 1.486 + methodFlagsStr = PL_strdup(optstate->value); break; 1.487 + case 't' : trusted = PR_TRUE; break; 1.488 + case 'T' : onlyTrustAnchors = PR_FALSE; break; 1.489 + case 'u' : usage = PORT_Atoi(optstate->value); 1.490 + if (usage < 0 || usage > 62) Usage(progName); 1.491 + certUsage = ((SECCertificateUsage)1) << usage; 1.492 + if (certUsage > certificateUsageHighest) Usage(progName); 1.493 + break; 1.494 + case 'w': 1.495 + pwdata.source = PW_PLAINTEXT; 1.496 + pwdata.data = PORT_Strdup(optstate->value); 1.497 + break; 1.498 + 1.499 + case 'W': 1.500 + pwdata.source = PW_FROMFILE; 1.501 + pwdata.data = PORT_Strdup(optstate->value); 1.502 + break; 1.503 + case 'v' : verbose++; break; 1.504 + default : Usage(progName); break; 1.505 + } 1.506 + } 1.507 +breakout: 1.508 + if (status != PL_OPT_OK) 1.509 + Usage(progName); 1.510 + 1.511 + if (usePkix < 2) { 1.512 + if (oidStr) { 1.513 + fprintf(stderr, "Policy oid(-o) can be used only with" 1.514 + " CERT_PKIXVerifyCert(-pp) function.\n"); 1.515 + Usage(progName); 1.516 + } 1.517 + if (trusted) { 1.518 + fprintf(stderr, "Cert trust flag can be used only with" 1.519 + " CERT_PKIXVerifyCert(-pp) function.\n"); 1.520 + Usage(progName); 1.521 + } 1.522 + if (!onlyTrustAnchors) { 1.523 + fprintf(stderr, "Cert trust anchor exclusiveness can be" 1.524 + " used only with CERT_PKIXVerifyCert(-pp)" 1.525 + " function.\n"); 1.526 + } 1.527 + } 1.528 + 1.529 + if (!useDefaultRevFlags && parseRevMethodsAndFlags()) { 1.530 + fprintf(stderr, "Invalid revocation configuration specified.\n"); 1.531 + goto punt; 1.532 + } 1.533 + 1.534 + /* Set our password function callback. */ 1.535 + PK11_SetPasswordFunc(SECU_GetModulePassword); 1.536 + 1.537 + /* Initialize the NSS libraries. */ 1.538 + if (certDir) { 1.539 + secStatus = NSS_Init(certDir); 1.540 + } else { 1.541 + secStatus = NSS_NoDB_Init(NULL); 1.542 + 1.543 + /* load the builtins */ 1.544 + SECMOD_AddNewModule("Builtins", DLL_PREFIX"nssckbi."DLL_SUFFIX, 0, 0); 1.545 + } 1.546 + if (secStatus != SECSuccess) { 1.547 + exitErr("NSS_Init"); 1.548 + } 1.549 + SECU_RegisterDynamicOids(); 1.550 + if (isOCSPEnabled()) { 1.551 + CERT_EnableOCSPChecking(CERT_GetDefaultCertDB()); 1.552 + CERT_DisableOCSPDefaultResponder(CERT_GetDefaultCertDB()); 1.553 + if (!ocsp_fetchingFailureIsAFailure) { 1.554 + CERT_SetOCSPFailureMode(ocspMode_FailureIsNotAVerificationFailure); 1.555 + } 1.556 + } 1.557 + 1.558 + while (status == PL_OPT_OK) { 1.559 + switch(optstate->option) { 1.560 + default : Usage(progName); break; 1.561 + case 'a' : isAscii = PR_TRUE; break; 1.562 + case 'r' : isAscii = PR_FALSE; break; 1.563 + case 't' : trusted = PR_TRUE; break; 1.564 + case 0 : /* positional parameter */ 1.565 + if (usePkix < 2 && trusted) { 1.566 + fprintf(stderr, "Cert trust flag can be used only with" 1.567 + " CERT_PKIXVerifyCert(-pp) function.\n"); 1.568 + Usage(progName); 1.569 + } 1.570 + cert = getCert(optstate->value, isAscii, progName); 1.571 + if (!cert) 1.572 + goto punt; 1.573 + rememberCert(cert, trusted); 1.574 + if (!firstCert) 1.575 + firstCert = cert; 1.576 + trusted = PR_FALSE; 1.577 + } 1.578 + status = PL_GetNextOpt(optstate); 1.579 + } 1.580 + PL_DestroyOptState(optstate); 1.581 + if (status == PL_OPT_BAD || !firstCert) 1.582 + Usage(progName); 1.583 + 1.584 + /* Initialize log structure */ 1.585 + log.arena = PORT_NewArena(512); 1.586 + log.head = log.tail = NULL; 1.587 + log.count = 0; 1.588 + 1.589 + do { 1.590 + if (usePkix < 2) { 1.591 + /* NOW, verify the cert chain. */ 1.592 + if (usePkix) { 1.593 + /* Use old API with libpkix validation lib */ 1.594 + CERT_SetUsePKIXForValidation(PR_TRUE); 1.595 + } 1.596 + if (!time) 1.597 + time = PR_Now(); 1.598 + 1.599 + defaultDB = CERT_GetDefaultCertDB(); 1.600 + secStatus = CERT_VerifyCertificate(defaultDB, firstCert, 1.601 + PR_TRUE /* check sig */, 1.602 + certUsage, 1.603 + time, 1.604 + &pwdata, /* wincx */ 1.605 + &log, /* error log */ 1.606 + NULL);/* returned usages */ 1.607 + } else do { 1.608 + static CERTValOutParam cvout[4]; 1.609 + static CERTValInParam cvin[7]; 1.610 + SECOidTag oidTag; 1.611 + int inParamIndex = 0; 1.612 + static PRUint64 revFlagsLeaf[2]; 1.613 + static PRUint64 revFlagsChain[2]; 1.614 + static CERTRevocationFlags rev; 1.615 + 1.616 + if (oidStr) { 1.617 + PLArenaPool *arena; 1.618 + SECOidData od; 1.619 + memset(&od, 0, sizeof od); 1.620 + od.offset = SEC_OID_UNKNOWN; 1.621 + od.desc = "User Defined Policy OID"; 1.622 + od.mechanism = CKM_INVALID_MECHANISM; 1.623 + od.supportedExtension = INVALID_CERT_EXTENSION; 1.624 + 1.625 + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.626 + if ( !arena ) { 1.627 + fprintf(stderr, "out of memory"); 1.628 + goto punt; 1.629 + } 1.630 + 1.631 + secStatus = SEC_StringToOID(arena, &od.oid, oidStr, 0); 1.632 + if (secStatus != SECSuccess) { 1.633 + PORT_FreeArena(arena, PR_FALSE); 1.634 + fprintf(stderr, "Can not encode oid: %s(%s)\n", oidStr, 1.635 + SECU_Strerror(PORT_GetError())); 1.636 + break; 1.637 + } 1.638 + 1.639 + oidTag = SECOID_AddEntry(&od); 1.640 + PORT_FreeArena(arena, PR_FALSE); 1.641 + if (oidTag == SEC_OID_UNKNOWN) { 1.642 + fprintf(stderr, "Can not add new oid to the dynamic " 1.643 + "table: %s\n", oidStr); 1.644 + secStatus = SECFailure; 1.645 + break; 1.646 + } 1.647 + 1.648 + cvin[inParamIndex].type = cert_pi_policyOID; 1.649 + cvin[inParamIndex].value.arraySize = 1; 1.650 + cvin[inParamIndex].value.array.oids = &oidTag; 1.651 + 1.652 + inParamIndex++; 1.653 + } 1.654 + 1.655 + if (trustedCertList) { 1.656 + cvin[inParamIndex].type = cert_pi_trustAnchors; 1.657 + cvin[inParamIndex].value.pointer.chain = trustedCertList; 1.658 + 1.659 + inParamIndex++; 1.660 + } 1.661 + 1.662 + cvin[inParamIndex].type = cert_pi_useAIACertFetch; 1.663 + cvin[inParamIndex].value.scalar.b = certFetching; 1.664 + inParamIndex++; 1.665 + 1.666 + rev.leafTests.cert_rev_flags_per_method = revFlagsLeaf; 1.667 + rev.chainTests.cert_rev_flags_per_method = revFlagsChain; 1.668 + secStatus = configureRevocationParams(&rev); 1.669 + if (secStatus) { 1.670 + fprintf(stderr, "Can not config revocation parameters "); 1.671 + break; 1.672 + } 1.673 + 1.674 + cvin[inParamIndex].type = cert_pi_revocationFlags; 1.675 + cvin[inParamIndex].value.pointer.revocation = &rev; 1.676 + inParamIndex++; 1.677 + 1.678 + if (time) { 1.679 + cvin[inParamIndex].type = cert_pi_date; 1.680 + cvin[inParamIndex].value.scalar.time = time; 1.681 + inParamIndex++; 1.682 + } 1.683 + 1.684 + if (!onlyTrustAnchors) { 1.685 + cvin[inParamIndex].type = cert_pi_useOnlyTrustAnchors; 1.686 + cvin[inParamIndex].value.scalar.b = onlyTrustAnchors; 1.687 + inParamIndex++; 1.688 + } 1.689 + 1.690 + cvin[inParamIndex].type = cert_pi_end; 1.691 + 1.692 + cvout[0].type = cert_po_trustAnchor; 1.693 + cvout[0].value.pointer.cert = NULL; 1.694 + cvout[1].type = cert_po_certList; 1.695 + cvout[1].value.pointer.chain = NULL; 1.696 + 1.697 + /* setting pointer to CERTVerifyLog. Initialized structure 1.698 + * will be used CERT_PKIXVerifyCert */ 1.699 + cvout[2].type = cert_po_errorLog; 1.700 + cvout[2].value.pointer.log = &log; 1.701 + 1.702 + cvout[3].type = cert_po_end; 1.703 + 1.704 + secStatus = CERT_PKIXVerifyCert(firstCert, certUsage, 1.705 + cvin, cvout, &pwdata); 1.706 + if (secStatus != SECSuccess) { 1.707 + break; 1.708 + } 1.709 + issuerCert = cvout[0].value.pointer.cert; 1.710 + builtChain = cvout[1].value.pointer.chain; 1.711 + } while (0); 1.712 + 1.713 + /* Display validation results */ 1.714 + if (secStatus != SECSuccess || log.count > 0) { 1.715 + CERTVerifyLogNode *node = NULL; 1.716 + fprintf(stderr, "Chain is bad!\n"); 1.717 + 1.718 + SECU_displayVerifyLog(stderr, &log, verbose); 1.719 + /* Have cert refs in the log only in case of failure. 1.720 + * Destroy them. */ 1.721 + for (node = log.head; node; node = node->next) { 1.722 + if (node->cert) 1.723 + CERT_DestroyCertificate(node->cert); 1.724 + } 1.725 + log.head = log.tail = NULL; 1.726 + log.count = 0; 1.727 + rv = 1; 1.728 + } else { 1.729 + fprintf(stderr, "Chain is good!\n"); 1.730 + if (issuerCert) { 1.731 + if (verbose > 1) { 1.732 + rv = SEC_PrintCertificateAndTrust(issuerCert, "Root Certificate", 1.733 + NULL); 1.734 + if (rv != SECSuccess) { 1.735 + SECU_PrintError(progName, "problem printing certificate"); 1.736 + } 1.737 + } else if (verbose > 0) { 1.738 + SECU_PrintName(stdout, &issuerCert->subject, "Root " 1.739 + "Certificate Subject:", 0); 1.740 + } 1.741 + CERT_DestroyCertificate(issuerCert); 1.742 + } 1.743 + if (builtChain) { 1.744 + CERTCertListNode *node; 1.745 + int count = 0; 1.746 + char buff[256]; 1.747 + 1.748 + if (verbose) { 1.749 + for(node = CERT_LIST_HEAD(builtChain); !CERT_LIST_END(node, builtChain); 1.750 + node = CERT_LIST_NEXT(node), count++ ) { 1.751 + sprintf(buff, "Certificate %d Subject", count + 1); 1.752 + SECU_PrintName(stdout, &node->cert->subject, buff, 0); 1.753 + } 1.754 + } 1.755 + CERT_DestroyCertList(builtChain); 1.756 + } 1.757 + rv = 0; 1.758 + } 1.759 + } while (--vfyCounts > 0); 1.760 + 1.761 + /* Need to destroy CERTVerifyLog arena at the end */ 1.762 + PORT_FreeArena(log.arena, PR_FALSE); 1.763 + 1.764 +punt: 1.765 + forgetCerts(); 1.766 + if (NSS_Shutdown() != SECSuccess) { 1.767 + SECU_PrintError(progName, "NSS_Shutdown"); 1.768 + rv = 1; 1.769 + } 1.770 + PORT_Free(progName); 1.771 + PORT_Free(certDir); 1.772 + PORT_Free(oidStr); 1.773 + freeRevocationMethodData(); 1.774 + if (pwdata.data) { 1.775 + PORT_Free(pwdata.data); 1.776 + } 1.777 + PL_ArenaFinish(); 1.778 + PR_Cleanup(); 1.779 + return rv; 1.780 +}