1/* 2 * certcrl - generic cert/CRL verifier 3 */ 4#include <security_cdsa_utils/cuFileIo.h> 5#include <utilLib/common.h> 6#include <clAppUtils/clutils.h> 7#include <stdlib.h> 8#include <stdio.h> 9#include <string.h> 10#include <Security/cssm.h> 11#include <clAppUtils/BlobList.h> 12#include <clAppUtils/certVerify.h> 13#include "script.h" 14 15static void usage(char **argv) 16{ 17 printf("Usage: %s [options]\n", argv[0]); 18 printf("Options:\n"); 19 printf(" -c certFileName [...]\n"); 20 printf(" -C rootCertFileName [...]\n"); 21 printf(" -r crlFileName [...]\n"); 22 printf(" -d certDbName\n"); 23 printf(" -D crlDlDbName\n"); 24 printf(" -s (use system anchor certs)\n"); 25 printf(" -g (use Trust Settings)\n"); 26 printf(" -i (implicit anchors)\n"); 27 printf(" -l=loopCount (default = 1)\n"); 28 printf(" -f (leaf cert is a CA)\n"); 29 printf(" -w(rite CRLs to dlDbName)\n"); 30 printf("Policy options:\n"); 31 printf(" -y ssl|smime|swuSign|codeSign|pkgSign|resourceSign|iChat|pkinitServer|\n" 32 " pkinitClient|IPSec\n"); 33 printf(" -h sslHostName (implies SSL policy; default is basic)\n"); 34 printf(" -t SSL client side (implies SSL policy, default is server side)\n"); 35 printf(" -E senderEmail (implies SMIME policy unless iChat is specified)\n"); 36 printf("Revocation options:\n"); 37 printf(" -R revocationPolicy (crl|ocsp|both|none); default = none\n"); 38 printf(" -a (allow certs unverified by CRL or OCSP)\n"); 39 printf(" -A (require CRL verification if present in cert\n"); 40 printf(" -4 (require CRL verification for all certs)\n"); 41 printf(" -Q (require OCSP if present in cert)\n"); 42 printf(" -5 (require OCSP verification for all certs)\n"); 43 printf(" -u responderURI\n"); 44 printf(" -U responderCert\n"); 45 printf(" -H (OCSP cache disable)\n"); 46 printf(" -W (network OCSP disable)\n"); 47 printf(" -o generate OCSP nonce\n"); 48 printf(" -O require nonce in OCSP response\n"); 49 printf("Misc. options:\n"); 50 printf(" -n (no network fetch of CRLs)\n"); 51 printf(" -N (no network fetch of certs)\n"); 52 printf(" -k keyUsage (In HEX starting with 0x)\n"); 53 printf(" -T verifyTime (in CSSM_TIMESTRING format, like 20041217154316)\n"); 54 printf(" -e=expectedError (default is CSSM_OK)\n"); 55 printf(" -S scriptFile\n"); 56 printf(" -p (print script variable names)\n"); 57 printf(" -P (pause after each script test)\n"); 58 printf(" -v (verbose)\n"); 59 printf(" -q (quiet)\n"); 60 printf(" -L (silent)\n"); 61 exit(1); 62} 63 64 65 66/* add files named by successive items in argv to blobList, up until the 67 * next '-' arg */ 68static void gatherFiles( 69 BlobList &blobList, 70 char **argv, 71 int argc, 72 int &currArg) 73{ 74 if((currArg == argc) || (argv[currArg][0] == '-')) { 75 /* need at least one file name */ 76 usage(argv); 77 } 78 while(currArg<argc) { 79 char *argp = argv[currArg]; 80 if(argp[0] == '-') { 81 /* done with this file list */ 82 currArg--; 83 return; 84 } 85 int rtn = blobList.addFile(argv[currArg]); 86 if(rtn) { 87 exit(1); 88 } 89 currArg++; 90 } 91 /* out of args */ 92 return; 93} 94 95int main(int argc, char **argv) 96{ 97 BlobList certs; 98 BlobList roots; 99 BlobList crls; 100 int rtn; 101 CSSM_DL_HANDLE dlHand; 102 int loop; 103 int arg; 104 char *argp; 105 CSSM_DL_DB_HANDLE_PTR crlDbHandPtr = NULL; 106 CSSM_DL_DB_LIST dlDbList; 107 CSSM_DL_DB_HANDLE dlDbHandles[2]; 108 CSSM_RETURN crtn; 109 CSSM_RETURN silent = CSSM_FALSE; 110 CSSM_BOOL scriptPause = CSSM_FALSE; 111 112 CertVerifyArgs vfyArgs; 113 memset(&vfyArgs, 0, sizeof(vfyArgs)); 114 115 vfyArgs.version = CERT_VFY_ARGS_VERS; 116 vfyArgs.certs = &certs; 117 vfyArgs.roots = &roots; 118 vfyArgs.crls = &crls; 119 120 /* for historical reasons the defaults for these are true */ 121 vfyArgs.crlNetFetchEnable = CSSM_TRUE; 122 vfyArgs.certNetFetchEnable = CSSM_TRUE; 123 124 /* user-specd variables */ 125 int loops = 1; 126 const char *crlDbName = NULL; 127 const char *certDbName = NULL; 128 char *scriptFile = NULL; 129 130 if(argc < 2) { 131 usage(argv); 132 } 133 for(arg=1; arg<argc; arg++) { 134 argp = argv[arg]; 135 if(argp[0] != '-') { 136 usage(argv); 137 } 138 switch(argp[1]) { 139 case 'l': 140 loops = atoi(&argp[3]); 141 break; 142 case 'r': 143 arg++; 144 gatherFiles(crls, argv, argc, arg); 145 break; 146 case 'c': 147 arg++; 148 gatherFiles(certs, argv, argc, arg); 149 break; 150 case 'C': 151 arg++; 152 gatherFiles(roots, argv, argc, arg); 153 break; 154 case 'v': 155 vfyArgs.verbose = CSSM_TRUE; 156 break; 157 case 'q': 158 vfyArgs.quiet = CSSM_TRUE; 159 break; 160 case 's': 161 vfyArgs.useSystemAnchors = CSSM_TRUE; 162 break; 163 case 'g': 164 vfyArgs.useTrustSettings = CSSM_TRUE; 165 break; 166 case 'i': 167 vfyArgs.implicitAnchors = CSSM_TRUE; 168 break; 169 case 'a': 170 vfyArgs.allowUnverified = CSSM_TRUE; 171 break; 172 case 'e': 173 vfyArgs.expectedErrStr = &argp[3]; 174 break; 175 case 'n': 176 vfyArgs.crlNetFetchEnable = CSSM_FALSE; 177 break; 178 case 'N': 179 vfyArgs.certNetFetchEnable = CSSM_FALSE; 180 break; 181 case 'f': 182 vfyArgs.leafCertIsCA = CSSM_TRUE; 183 break; 184 case 'd': 185 arg++; 186 if(arg == argc) { 187 usage(argv); 188 } 189 certDbName = argv[arg]; 190 break; 191 case 'D': 192 arg++; 193 if(arg == argc) { 194 usage(argv); 195 } 196 crlDbName = argv[arg]; 197 break; 198 case 'S': 199 arg++; 200 if(arg == argc) { 201 usage(argv); 202 } 203 scriptFile = argv[arg]; 204 break; 205 case 'h': 206 arg++; 207 if(arg == argc) { 208 usage(argv); 209 } 210 vfyArgs.sslHost= argv[arg]; 211 vfyArgs.vfyPolicy = CVP_SSL; 212 break; 213 case 'E': 214 arg++; 215 if(arg == argc) { 216 usage(argv); 217 } 218 if(vfyArgs.vfyPolicy == CVP_Basic) { 219 /* user hasn't specified; now default to SMIME - still 220 * can override (e.g., for iChat) */ 221 vfyArgs.vfyPolicy = CVP_SMIME; 222 } 223 vfyArgs.senderEmail = argv[arg]; 224 break; 225 case 'k': 226 arg++; 227 if(arg == argc) { 228 usage(argv); 229 } 230 vfyArgs.intendedKeyUse = hexToBin(argv[arg]); 231 break; 232 case 't': 233 vfyArgs.sslClient = CSSM_TRUE; 234 vfyArgs.vfyPolicy = CVP_SSL; 235 break; 236 case 'y': 237 arg++; 238 if(arg == argc) { 239 usage(argv); 240 } 241 argp = argv[arg]; 242 if(parsePolicyString(argp, &vfyArgs.vfyPolicy)) { 243 printf("Bogus policyValue (%s)\n", argp); 244 printPolicyStrings(); 245 exit(1); 246 } 247 break; 248 case 'R': 249 arg++; 250 if(arg == argc) { 251 usage(argv); 252 } 253 argp = argv[arg]; 254 if(!strcmp(argp, "none")) { 255 vfyArgs.revokePolicy = CRP_None; 256 } 257 else if(!strcmp(argp, "crl")) { 258 vfyArgs.revokePolicy = CRP_CRL; 259 } 260 else if(!strcmp(argp, "ocsp")) { 261 vfyArgs.revokePolicy = CRP_OCSP; 262 } 263 else if(!strcmp(argp, "both")) { 264 vfyArgs.revokePolicy = CRP_CRL_OCSP; 265 } 266 else { 267 usage(argv); 268 } 269 break; 270 case 'u': 271 arg++; 272 if(arg == argc) { 273 usage(argv); 274 } 275 vfyArgs.responderURI = argv[arg]; 276 /* no implied policy yet - could be CRP_OCSP or CRP_CRL_OCSP */ 277 break; 278 case 'U': 279 if(readFile(argv[arg], (unsigned char **)vfyArgs.responderCert, 280 &vfyArgs.responderCertLen)) { 281 printf("***Error reading responderCert from %s. Aborting.\n", 282 argv[arg]); 283 exit(1); 284 } 285 /* no implied policy yet - could be CRP_OCSP or CRP_CRL_OCSP */ 286 break; 287 case 'H': 288 vfyArgs.disableCache = CSSM_TRUE; 289 break; 290 case 'W': 291 vfyArgs.disableOcspNet = CSSM_TRUE; 292 break; 293 case 'Q': 294 vfyArgs.requireOcspIfPresent = CSSM_TRUE; 295 break; 296 case '5': 297 vfyArgs.requireOcspForAll = CSSM_TRUE; 298 break; 299 case 'o': 300 vfyArgs.generateOcspNonce = CSSM_TRUE; 301 break; 302 case 'O': 303 vfyArgs.requireOcspRespNonce = CSSM_TRUE; 304 break; 305 case 'A': 306 vfyArgs.requireCrlIfPresent = CSSM_TRUE; 307 break; 308 case '4': 309 vfyArgs.requireCrlForAll = CSSM_TRUE; 310 break; 311 case 'T': 312 arg++; 313 if(arg == argc) { 314 usage(argv); 315 } 316 vfyArgs.vfyTime = argv[arg]; 317 break; 318 case 'p': 319 printScriptVars(); 320 exit(0); 321 case 'P': 322 scriptPause = CSSM_TRUE; 323 break; 324 case 'L': 325 silent = CSSM_TRUE; // inhibits start banner 326 vfyArgs.quiet = CSSM_TRUE; // inhibits stdout from certVerify 327 break; 328 default: 329 usage(argv); 330 } 331 } 332 333 if((vfyArgs.responderCert != NULL) || (vfyArgs.responderURI != NULL)) { 334 switch(vfyArgs.revokePolicy) { 335 case CRP_None: 336 vfyArgs.revokePolicy = CRP_OCSP; 337 break; 338 case CRP_OCSP: 339 case CRP_CRL_OCSP: 340 break; 341 case CRP_CRL: 342 printf("*** OCSP options (responderURI, responderCert) only valid " 343 "with OCSP policy\n"); 344 usage(argv); 345 } 346 } 347 348 vfyArgs.clHand = clStartup(); 349 if(vfyArgs.clHand == CSSM_INVALID_HANDLE) { 350 return 1; 351 } 352 vfyArgs.tpHand = tpStartup(); 353 if(vfyArgs.tpHand == CSSM_INVALID_HANDLE) { 354 return 1; 355 } 356 vfyArgs.cspHand = cspStartup(); 357 if(vfyArgs.cspHand == CSSM_INVALID_HANDLE) { 358 return 1; 359 } 360 dlHand = dlStartup(); 361 if(dlHand == CSSM_INVALID_HANDLE) { 362 return 1; 363 } 364 365 if(!silent) { 366 testStartBanner("certcrl", argc, argv); 367 } 368 369 if(scriptFile) { 370 ScriptVars vars; 371 vars.allowUnverified = vfyArgs.allowUnverified; 372 vars.requireCrlIfPresent = vfyArgs.requireCrlIfPresent; 373 vars.requireOcspIfPresent = vfyArgs.requireOcspIfPresent; 374 vars.crlNetFetchEnable = vfyArgs.crlNetFetchEnable; 375 vars.certNetFetchEnable = vfyArgs.certNetFetchEnable; 376 vars.useSystemAnchors = vfyArgs.useSystemAnchors; 377 vars.useTrustSettings = vfyArgs.useTrustSettings; 378 vars.leafCertIsCA = vfyArgs.leafCertIsCA; 379 vars.cacheDisable = vfyArgs.disableCache; 380 vars.ocspNetFetchDisable = vfyArgs.disableOcspNet; 381 vars.requireCrlForAll = vfyArgs.requireCrlForAll; 382 vars.requireOcspForAll = vfyArgs.requireOcspForAll; 383 return runScript(scriptFile, vfyArgs.tpHand, vfyArgs.clHand, 384 vfyArgs.cspHand, dlHand, 385 &vars, vfyArgs.quiet, vfyArgs.verbose, scriptPause); 386 } 387 388 /* open DlDbs if enabled */ 389 dlDbList.NumHandles = 0; 390 dlDbList.DLDBHandle = &dlDbHandles[0]; 391 dlDbList.DLDBHandle[0].DLHandle = dlHand; 392 dlDbList.DLDBHandle[1].DLHandle = dlHand; 393 if(certDbName != NULL) { 394 crtn = CSSM_DL_DbOpen(dlHand, 395 certDbName, 396 NULL, // DbLocation 397 CSSM_DB_ACCESS_READ, 398 NULL, // CSSM_ACCESS_CREDENTIALS *AccessCred 399 NULL, // void *OpenParameters 400 &dlDbList.DLDBHandle[0].DBHandle); 401 if(crtn) { 402 printError("CSSM_DL_DbOpen", crtn); 403 printf("***Error opening DB %s. Aborting.\n", certDbName); 404 return 1; 405 } 406 dlDbList.NumHandles++; 407 vfyArgs.dlDbList = &dlDbList; 408 } 409 if(crlDbName != NULL) { 410 vfyArgs.crlDlDb = &dlDbList.DLDBHandle[dlDbList.NumHandles]; 411 crtn = CSSM_DL_DbOpen(dlHand, 412 crlDbName, 413 NULL, // DbLocation 414 CSSM_DB_ACCESS_READ | CSSM_DB_ACCESS_WRITE, 415 NULL, // CSSM_ACCESS_CREDENTIALS *AccessCred 416 NULL, // void *OpenParameters 417 &crlDbHandPtr->DBHandle); 418 if(crtn) { 419 printError("CSSM_DL_DbOpen", crtn); 420 printf("***Error opening DB %s. Aborting.\n", crlDbName); 421 return 1; 422 } 423 dlDbList.NumHandles++; 424 vfyArgs.dlDbList = &dlDbList; 425 } 426 for(loop=0; loop<loops; loop++) { 427 rtn = certVerify(&vfyArgs); 428 if(rtn) { 429 break; 430 } 431 432 if(loops != 1) { 433 fpurge(stdin); 434 printf("CR to continue, q to quit: "); 435 char c = getchar(); 436 if(c == 'q') { 437 break; 438 } 439 } 440 } 441 return rtn; 442} 443 444