security/nss/cmd/ocspclnt/ocspclnt.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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 * Test program for client-side OCSP.
michael@0 7 */
michael@0 8
michael@0 9 #include "secutil.h"
michael@0 10 #include "nspr.h"
michael@0 11 #include "plgetopt.h"
michael@0 12 #include "nss.h"
michael@0 13 #include "cert.h"
michael@0 14 #include "ocsp.h"
michael@0 15 #include "xconst.h" /*
michael@0 16 * XXX internal header file; needed to get at
michael@0 17 * cert_DecodeAuthInfoAccessExtension -- would be
michael@0 18 * nice to not need this, but that would require
michael@0 19 * better/different APIs.
michael@0 20 */
michael@0 21
michael@0 22 #ifndef NO_PP /*
michael@0 23 * Compile with this every once in a while to be
michael@0 24 * sure that no dependencies on it get added
michael@0 25 * outside of the pretty-printing routines.
michael@0 26 */
michael@0 27 #include "ocspti.h" /* internals for pretty-printing routines *only* */
michael@0 28 #endif /* NO_PP */
michael@0 29
michael@0 30 #if defined(_WIN32)
michael@0 31 #include "fcntl.h"
michael@0 32 #include "io.h"
michael@0 33 #endif
michael@0 34
michael@0 35 #define DEFAULT_DB_DIR "~/.netscape"
michael@0 36
michael@0 37 /* global */
michael@0 38 char *program_name;
michael@0 39
michael@0 40
michael@0 41 static void
michael@0 42 synopsis (char *program_name)
michael@0 43 {
michael@0 44 PRFileDesc *pr_stderr;
michael@0 45
michael@0 46 pr_stderr = PR_STDERR;
michael@0 47 PR_fprintf (pr_stderr, "Usage:");
michael@0 48 PR_fprintf (pr_stderr,
michael@0 49 "\t%s -p [-d <dir>]\n",
michael@0 50 program_name);
michael@0 51 PR_fprintf (pr_stderr,
michael@0 52 "\t%s -P [-d <dir>]\n",
michael@0 53 program_name);
michael@0 54 PR_fprintf (pr_stderr,
michael@0 55 "\t%s -r <name> [-a] [-L] [-s <name>] [-d <dir>]\n",
michael@0 56 program_name);
michael@0 57 PR_fprintf (pr_stderr,
michael@0 58 "\t%s -R <name> [-a] [-l <location>] [-s <name>] [-d <dir>]\n",
michael@0 59 program_name);
michael@0 60 PR_fprintf (pr_stderr,
michael@0 61 "\t%s -S <name> [-a] [-l <location> -t <name>]\n",
michael@0 62 program_name);
michael@0 63 PR_fprintf (pr_stderr,
michael@0 64 "\t\t [-s <name>] [-w <time>] [-d <dir>]\n");
michael@0 65 PR_fprintf (pr_stderr,
michael@0 66 "\t%s -V <name> [-a] -u <usage> [-l <location> -t <name>]\n",
michael@0 67 program_name);
michael@0 68 PR_fprintf (pr_stderr,
michael@0 69 "\t\t [-s <name>] [-w <time>] [-d <dir>]\n");
michael@0 70 }
michael@0 71
michael@0 72
michael@0 73 static void
michael@0 74 short_usage (char *program_name)
michael@0 75 {
michael@0 76 PR_fprintf (PR_STDERR,
michael@0 77 "Type %s -H for more detailed descriptions\n",
michael@0 78 program_name);
michael@0 79 synopsis (program_name);
michael@0 80 }
michael@0 81
michael@0 82
michael@0 83 static void
michael@0 84 long_usage (char *program_name)
michael@0 85 {
michael@0 86 PRFileDesc *pr_stderr;
michael@0 87
michael@0 88 pr_stderr = PR_STDERR;
michael@0 89 synopsis (program_name);
michael@0 90 PR_fprintf (pr_stderr, "\nCommands (must specify exactly one):\n");
michael@0 91 PR_fprintf (pr_stderr,
michael@0 92 " %-13s Pretty-print a binary request read from stdin\n",
michael@0 93 "-p");
michael@0 94 PR_fprintf (pr_stderr,
michael@0 95 " %-13s Pretty-print a binary response read from stdin\n",
michael@0 96 "-P");
michael@0 97 PR_fprintf (pr_stderr,
michael@0 98 " %-13s Create a request for cert \"nickname\" on stdout\n",
michael@0 99 "-r nickname");
michael@0 100 PR_fprintf (pr_stderr,
michael@0 101 " %-13s Get response for cert \"nickname\", dump to stdout\n",
michael@0 102 "-R nickname");
michael@0 103 PR_fprintf (pr_stderr,
michael@0 104 " %-13s Get status for cert \"nickname\"\n",
michael@0 105 "-S nickname");
michael@0 106 PR_fprintf (pr_stderr,
michael@0 107 " %-13s Fully verify cert \"nickname\", w/ status check\n",
michael@0 108 "-V nickname");
michael@0 109 PR_fprintf (pr_stderr,
michael@0 110 "\n %-10s also can be the name of the file with DER or\n"
michael@0 111 " %-13s PEM(use -a option) cert encoding\n", "nickname", "");
michael@0 112 PR_fprintf (pr_stderr, "Options:\n");
michael@0 113 PR_fprintf (pr_stderr,
michael@0 114 " %-13s Decode input cert from PEM format. DER is default\n",
michael@0 115 "-a");
michael@0 116 PR_fprintf (pr_stderr,
michael@0 117 " %-13s Add the service locator extension to the request\n",
michael@0 118 "-L");
michael@0 119 PR_fprintf (pr_stderr,
michael@0 120 " %-13s Find security databases in \"dbdir\" (default %s)\n",
michael@0 121 "-d dbdir", DEFAULT_DB_DIR);
michael@0 122 PR_fprintf (pr_stderr,
michael@0 123 " %-13s Use \"location\" as URL of responder\n",
michael@0 124 "-l location");
michael@0 125 PR_fprintf (pr_stderr,
michael@0 126 " %-13s Trust cert \"nickname\" as response signer\n",
michael@0 127 "-t nickname");
michael@0 128 PR_fprintf (pr_stderr,
michael@0 129 " %-13s Sign requests with cert \"nickname\"\n",
michael@0 130 "-s nickname");
michael@0 131 PR_fprintf (pr_stderr,
michael@0 132 " %-13s Type of certificate usage for verification:\n",
michael@0 133 "-u usage");
michael@0 134 PR_fprintf (pr_stderr,
michael@0 135 "%-17s c SSL Client\n", "");
michael@0 136 PR_fprintf (pr_stderr,
michael@0 137 "%-17s s SSL Server\n", "");
michael@0 138 PR_fprintf (pr_stderr,
michael@0 139 "%-17s e Email Recipient\n", "");
michael@0 140 PR_fprintf (pr_stderr,
michael@0 141 "%-17s E Email Signer\n", "");
michael@0 142 PR_fprintf (pr_stderr,
michael@0 143 "%-17s S Object Signer\n", "");
michael@0 144 PR_fprintf (pr_stderr,
michael@0 145 "%-17s C CA\n", "");
michael@0 146 PR_fprintf (pr_stderr,
michael@0 147 " %-13s Validity time (default current time), one of:\n",
michael@0 148 "-w time");
michael@0 149 PR_fprintf (pr_stderr,
michael@0 150 "%-17s %-25s (GMT)\n", "", "YYMMDDhhmm[ss]Z");
michael@0 151 PR_fprintf (pr_stderr,
michael@0 152 "%-17s %-25s (later than GMT)\n", "", "YYMMDDhhmm[ss]+hhmm");
michael@0 153 PR_fprintf (pr_stderr,
michael@0 154 "%-17s %-25s (earlier than GMT)\n", "", "YYMMDDhhmm[ss]-hhmm");
michael@0 155 }
michael@0 156
michael@0 157 #if defined(WIN32)
michael@0 158 /* We're going to write binary data to stdout, or read binary from stdin.
michael@0 159 * We must put stdout or stdin into O_BINARY mode or else
michael@0 160 outgoing \n's will become \r\n's, and incoming \r\n's will become \n's.
michael@0 161 */
michael@0 162 static SECStatus
michael@0 163 make_file_binary(FILE * binfile)
michael@0 164 {
michael@0 165 int smrv = _setmode(_fileno(binfile), _O_BINARY);
michael@0 166 if (smrv == -1) {
michael@0 167 fprintf(stderr, "%s: Cannot change stdout to binary mode.\n",
michael@0 168 program_name);
michael@0 169 }
michael@0 170 return smrv;
michael@0 171 }
michael@0 172 #define MAKE_FILE_BINARY make_file_binary
michael@0 173 #else
michael@0 174 #define MAKE_FILE_BINARY(file)
michael@0 175 #endif
michael@0 176
michael@0 177 /*
michael@0 178 * XXX This is a generic function that would probably make a good
michael@0 179 * replacement for SECU_DER_Read (which is not at all specific to DER,
michael@0 180 * despite its name), but that requires fixing all of the tools...
michael@0 181 * Still, it should be done, whenenver I/somebody has the time.
michael@0 182 * (Also, consider whether this actually belongs in the security
michael@0 183 * library itself, not just in the command library.)
michael@0 184 *
michael@0 185 * This function takes an open file (a PRFileDesc *) and reads the
michael@0 186 * entire file into a SECItem. (Obviously, the file is intended to
michael@0 187 * be small enough that such a thing is advisable.) Both the SECItem
michael@0 188 * and the buffer it points to are allocated from the heap; the caller
michael@0 189 * is expected to free them. ("SECITEM_FreeItem(item, PR_TRUE)")
michael@0 190 */
michael@0 191 static SECItem *
michael@0 192 read_file_into_item (PRFileDesc *in_file, SECItemType si_type)
michael@0 193 {
michael@0 194 PRStatus prv;
michael@0 195 SECItem *item;
michael@0 196 PRFileInfo file_info;
michael@0 197 PRInt32 bytes_read;
michael@0 198
michael@0 199 prv = PR_GetOpenFileInfo (in_file, &file_info);
michael@0 200 if (prv != PR_SUCCESS)
michael@0 201 return NULL;
michael@0 202
michael@0 203 if (file_info.size == 0) {
michael@0 204 /* XXX Need a better error; just grabbed this one for expediency. */
michael@0 205 PORT_SetError (SEC_ERROR_INPUT_LEN);
michael@0 206 return NULL;
michael@0 207 }
michael@0 208
michael@0 209 if (file_info.size > 0xffff) { /* I think this is too big. */
michael@0 210 PORT_SetError (SEC_ERROR_NO_MEMORY);
michael@0 211 return NULL;
michael@0 212 }
michael@0 213
michael@0 214 item = PORT_Alloc (sizeof (SECItem));
michael@0 215 if (item == NULL)
michael@0 216 return NULL;
michael@0 217
michael@0 218 item->type = si_type;
michael@0 219 item->len = (unsigned int) file_info.size;
michael@0 220 item->data = PORT_Alloc ((size_t)item->len);
michael@0 221 if (item->data == NULL)
michael@0 222 goto loser;
michael@0 223
michael@0 224 bytes_read = PR_Read (in_file, item->data, (PRInt32) item->len);
michael@0 225 if (bytes_read < 0) {
michael@0 226 /* Something went wrong; error is already set for us. */
michael@0 227 goto loser;
michael@0 228 } else if (bytes_read == 0) {
michael@0 229 /* Something went wrong; we read nothing. But no system/nspr error. */
michael@0 230 /* XXX Need to set an error here. */
michael@0 231 goto loser;
michael@0 232 } else if (item->len != (unsigned int)bytes_read) {
michael@0 233 /* Something went wrong; we read less (or more!?) than we expected. */
michael@0 234 /* XXX Need to set an error here. */
michael@0 235 goto loser;
michael@0 236 }
michael@0 237
michael@0 238 return item;
michael@0 239
michael@0 240 loser:
michael@0 241 SECITEM_FreeItem (item, PR_TRUE);
michael@0 242 return NULL;
michael@0 243 }
michael@0 244
michael@0 245
michael@0 246 /*
michael@0 247 * Create a DER-encoded OCSP request (for the certificate whose nickname
michael@0 248 * is "name") and dump it out.
michael@0 249 */
michael@0 250 static SECStatus
michael@0 251 create_request (FILE *out_file, CERTCertDBHandle *handle, CERTCertificate *cert,
michael@0 252 PRBool add_service_locator, PRBool add_acceptable_responses)
michael@0 253 {
michael@0 254 CERTCertList *certs = NULL;
michael@0 255 CERTCertificate *myCert = NULL;
michael@0 256 CERTOCSPRequest *request = NULL;
michael@0 257 PRTime now = PR_Now();
michael@0 258 SECItem *encoding = NULL;
michael@0 259 SECStatus rv = SECFailure;
michael@0 260
michael@0 261 if (handle == NULL || cert == NULL)
michael@0 262 return rv;
michael@0 263
michael@0 264 myCert = CERT_DupCertificate(cert);
michael@0 265 if (myCert == NULL)
michael@0 266 goto loser;
michael@0 267
michael@0 268 /*
michael@0 269 * We need to create a list of one.
michael@0 270 */
michael@0 271 certs = CERT_NewCertList();
michael@0 272 if (certs == NULL)
michael@0 273 goto loser;
michael@0 274
michael@0 275 if (CERT_AddCertToListTail (certs, myCert) != SECSuccess)
michael@0 276 goto loser;
michael@0 277
michael@0 278 /*
michael@0 279 * Now that cert is included in the list, we need to be careful
michael@0 280 * that we do not try to destroy it twice. This will prevent that.
michael@0 281 */
michael@0 282 myCert = NULL;
michael@0 283
michael@0 284 request = CERT_CreateOCSPRequest (certs, now, add_service_locator, NULL);
michael@0 285 if (request == NULL)
michael@0 286 goto loser;
michael@0 287
michael@0 288 if (add_acceptable_responses) {
michael@0 289 rv = CERT_AddOCSPAcceptableResponses(request,
michael@0 290 SEC_OID_PKIX_OCSP_BASIC_RESPONSE);
michael@0 291 if (rv != SECSuccess)
michael@0 292 goto loser;
michael@0 293 }
michael@0 294
michael@0 295 encoding = CERT_EncodeOCSPRequest (NULL, request, NULL);
michael@0 296 if (encoding == NULL)
michael@0 297 goto loser;
michael@0 298
michael@0 299 MAKE_FILE_BINARY(out_file);
michael@0 300 if (fwrite (encoding->data, encoding->len, 1, out_file) != 1)
michael@0 301 goto loser;
michael@0 302
michael@0 303 rv = SECSuccess;
michael@0 304
michael@0 305 loser:
michael@0 306 if (encoding != NULL)
michael@0 307 SECITEM_FreeItem(encoding, PR_TRUE);
michael@0 308 if (request != NULL)
michael@0 309 CERT_DestroyOCSPRequest(request);
michael@0 310 if (certs != NULL)
michael@0 311 CERT_DestroyCertList (certs);
michael@0 312 if (myCert != NULL)
michael@0 313 CERT_DestroyCertificate(myCert);
michael@0 314
michael@0 315 return rv;
michael@0 316 }
michael@0 317
michael@0 318
michael@0 319 /*
michael@0 320 * Create a DER-encoded OCSP request (for the certificate whose nickname is
michael@0 321 * "cert_name"), then get and dump a corresponding response. The responder
michael@0 322 * location is either specified explicitly (as "responder_url") or found
michael@0 323 * via the AuthorityInfoAccess URL in the cert.
michael@0 324 */
michael@0 325 static SECStatus
michael@0 326 dump_response (FILE *out_file, CERTCertDBHandle *handle, CERTCertificate *cert,
michael@0 327 const char *responder_url)
michael@0 328 {
michael@0 329 CERTCertList *certs = NULL;
michael@0 330 CERTCertificate *myCert = NULL;
michael@0 331 char *loc = NULL;
michael@0 332 PRTime now = PR_Now();
michael@0 333 SECItem *response = NULL;
michael@0 334 SECStatus rv = SECFailure;
michael@0 335 PRBool includeServiceLocator;
michael@0 336
michael@0 337 if (handle == NULL || cert == NULL)
michael@0 338 return rv;
michael@0 339
michael@0 340 myCert = CERT_DupCertificate(cert);
michael@0 341 if (myCert == NULL)
michael@0 342 goto loser;
michael@0 343
michael@0 344 if (responder_url != NULL) {
michael@0 345 loc = (char *) responder_url;
michael@0 346 includeServiceLocator = PR_TRUE;
michael@0 347 } else {
michael@0 348 loc = CERT_GetOCSPAuthorityInfoAccessLocation (cert);
michael@0 349 if (loc == NULL)
michael@0 350 goto loser;
michael@0 351 includeServiceLocator = PR_FALSE;
michael@0 352 }
michael@0 353
michael@0 354 /*
michael@0 355 * We need to create a list of one.
michael@0 356 */
michael@0 357 certs = CERT_NewCertList();
michael@0 358 if (certs == NULL)
michael@0 359 goto loser;
michael@0 360
michael@0 361 if (CERT_AddCertToListTail (certs, myCert) != SECSuccess)
michael@0 362 goto loser;
michael@0 363
michael@0 364 /*
michael@0 365 * Now that cert is included in the list, we need to be careful
michael@0 366 * that we do not try to destroy it twice. This will prevent that.
michael@0 367 */
michael@0 368 myCert = NULL;
michael@0 369
michael@0 370 response = CERT_GetEncodedOCSPResponse (NULL, certs, loc, now,
michael@0 371 includeServiceLocator,
michael@0 372 NULL, NULL, NULL);
michael@0 373 if (response == NULL)
michael@0 374 goto loser;
michael@0 375
michael@0 376 MAKE_FILE_BINARY(out_file);
michael@0 377 if (fwrite (response->data, response->len, 1, out_file) != 1)
michael@0 378 goto loser;
michael@0 379
michael@0 380 rv = SECSuccess;
michael@0 381
michael@0 382 loser:
michael@0 383 if (response != NULL)
michael@0 384 SECITEM_FreeItem (response, PR_TRUE);
michael@0 385 if (certs != NULL)
michael@0 386 CERT_DestroyCertList (certs);
michael@0 387 if (myCert != NULL)
michael@0 388 CERT_DestroyCertificate(myCert);
michael@0 389 if (loc != NULL && loc != responder_url)
michael@0 390 PORT_Free (loc);
michael@0 391
michael@0 392 return rv;
michael@0 393 }
michael@0 394
michael@0 395
michael@0 396 /*
michael@0 397 * Get the status for the specified certificate (whose nickname is "cert_name").
michael@0 398 * Directly use the OCSP function rather than doing a full verification.
michael@0 399 */
michael@0 400 static SECStatus
michael@0 401 get_cert_status (FILE *out_file, CERTCertDBHandle *handle,
michael@0 402 CERTCertificate *cert, const char *cert_name,
michael@0 403 PRTime verify_time)
michael@0 404 {
michael@0 405 SECStatus rv = SECFailure;
michael@0 406
michael@0 407 if (handle == NULL || cert == NULL)
michael@0 408 goto loser;
michael@0 409
michael@0 410 rv = CERT_CheckOCSPStatus (handle, cert, verify_time, NULL);
michael@0 411
michael@0 412 fprintf (out_file, "Check of certificate \"%s\" ", cert_name);
michael@0 413 if (rv == SECSuccess) {
michael@0 414 fprintf (out_file, "succeeded.\n");
michael@0 415 } else {
michael@0 416 const char *error_string = SECU_Strerror(PORT_GetError());
michael@0 417 fprintf (out_file, "failed. Reason:\n");
michael@0 418 if (error_string != NULL && PORT_Strlen(error_string) > 0)
michael@0 419 fprintf (out_file, "%s\n", error_string);
michael@0 420 else
michael@0 421 fprintf (out_file, "Unknown\n");
michael@0 422 }
michael@0 423
michael@0 424 rv = SECSuccess;
michael@0 425
michael@0 426 loser:
michael@0 427
michael@0 428 return rv;
michael@0 429 }
michael@0 430
michael@0 431
michael@0 432 /*
michael@0 433 * Verify the specified certificate (whose nickname is "cert_name").
michael@0 434 * OCSP is already turned on, so we just need to call the standard
michael@0 435 * certificate verification API and let it do all the work.
michael@0 436 */
michael@0 437 static SECStatus
michael@0 438 verify_cert (FILE *out_file, CERTCertDBHandle *handle, CERTCertificate *cert,
michael@0 439 const char *cert_name, SECCertUsage cert_usage, PRTime verify_time)
michael@0 440 {
michael@0 441 SECStatus rv = SECFailure;
michael@0 442
michael@0 443 if (handle == NULL || cert == NULL)
michael@0 444 return rv;
michael@0 445
michael@0 446 rv = CERT_VerifyCert (handle, cert, PR_TRUE, cert_usage, verify_time,
michael@0 447 NULL, NULL);
michael@0 448
michael@0 449 fprintf (out_file, "Verification of certificate \"%s\" ", cert_name);
michael@0 450 if (rv == SECSuccess) {
michael@0 451 fprintf (out_file, "succeeded.\n");
michael@0 452 } else {
michael@0 453 const char *error_string = SECU_Strerror(PORT_GetError());
michael@0 454 fprintf (out_file, "failed. Reason:\n");
michael@0 455 if (error_string != NULL && PORT_Strlen(error_string) > 0)
michael@0 456 fprintf (out_file, "%s\n", error_string);
michael@0 457 else
michael@0 458 fprintf (out_file, "Unknown\n");
michael@0 459 }
michael@0 460
michael@0 461 rv = SECSuccess;
michael@0 462
michael@0 463 return rv;
michael@0 464 }
michael@0 465
michael@0 466 CERTCertificate*
michael@0 467 find_certificate(CERTCertDBHandle *handle, const char *name, PRBool ascii)
michael@0 468 {
michael@0 469 CERTCertificate *cert = NULL;
michael@0 470 SECItem der;
michael@0 471 PRFileDesc *certFile;
michael@0 472
michael@0 473 if (handle == NULL || name == NULL)
michael@0 474 return NULL;
michael@0 475
michael@0 476 if (ascii == PR_FALSE) {
michael@0 477 /* by default need to check if there is cert nick is given */
michael@0 478 cert = CERT_FindCertByNicknameOrEmailAddr (handle, (char *) name);
michael@0 479 if (cert != NULL)
michael@0 480 return cert;
michael@0 481 }
michael@0 482
michael@0 483 certFile = PR_Open(name, PR_RDONLY, 0);
michael@0 484 if (certFile == NULL) {
michael@0 485 return NULL;
michael@0 486 }
michael@0 487
michael@0 488 if (SECU_ReadDERFromFile(&der, certFile, ascii, PR_FALSE) == SECSuccess) {
michael@0 489 cert = CERT_DecodeCertFromPackage((char*)der.data, der.len);
michael@0 490 SECITEM_FreeItem(&der, PR_FALSE);
michael@0 491 }
michael@0 492 PR_Close(certFile);
michael@0 493
michael@0 494 return cert;
michael@0 495 }
michael@0 496
michael@0 497
michael@0 498 #ifdef NO_PP
michael@0 499
michael@0 500 static SECStatus
michael@0 501 print_request (FILE *out_file, SECItem *data)
michael@0 502 {
michael@0 503 fprintf (out_file, "Cannot pretty-print request compiled with NO_PP.\n");
michael@0 504 return SECSuccess;
michael@0 505 }
michael@0 506
michael@0 507 static SECStatus
michael@0 508 print_response (FILE *out_file, SECItem *data, CERTCertDBHandle *handle)
michael@0 509 {
michael@0 510 fprintf (out_file, "Cannot pretty-print response compiled with NO_PP.\n");
michael@0 511 return SECSuccess;
michael@0 512 }
michael@0 513
michael@0 514 #else /* NO_PP */
michael@0 515
michael@0 516 static void
michael@0 517 print_ocsp_version (FILE *out_file, SECItem *version, int level)
michael@0 518 {
michael@0 519 if (version->len > 0) {
michael@0 520 SECU_PrintInteger (out_file, version, "Version", level);
michael@0 521 } else {
michael@0 522 SECU_Indent (out_file, level);
michael@0 523 fprintf (out_file, "Version: DEFAULT\n");
michael@0 524 }
michael@0 525 }
michael@0 526
michael@0 527
michael@0 528 static void
michael@0 529 print_ocsp_cert_id (FILE *out_file, CERTOCSPCertID *cert_id, int level)
michael@0 530 {
michael@0 531 SECU_Indent (out_file, level);
michael@0 532 fprintf (out_file, "Cert ID:\n");
michael@0 533 level++;
michael@0 534
michael@0 535 SECU_PrintAlgorithmID (out_file, &(cert_id->hashAlgorithm),
michael@0 536 "Hash Algorithm", level);
michael@0 537 SECU_PrintAsHex (out_file, &(cert_id->issuerNameHash),
michael@0 538 "Issuer Name Hash", level);
michael@0 539 SECU_PrintAsHex (out_file, &(cert_id->issuerKeyHash),
michael@0 540 "Issuer Key Hash", level);
michael@0 541 SECU_PrintInteger (out_file, &(cert_id->serialNumber),
michael@0 542 "Serial Number", level);
michael@0 543 /* XXX lookup the cert; if found, print something nice (nickname?) */
michael@0 544 }
michael@0 545
michael@0 546
michael@0 547 static void
michael@0 548 print_raw_certificates (FILE *out_file, SECItem **raw_certs, int level)
michael@0 549 {
michael@0 550 SECItem *raw_cert;
michael@0 551 int i = 0;
michael@0 552 char cert_label[50];
michael@0 553
michael@0 554 SECU_Indent (out_file, level);
michael@0 555
michael@0 556 if (raw_certs == NULL) {
michael@0 557 fprintf (out_file, "No Certificates.\n");
michael@0 558 return;
michael@0 559 }
michael@0 560
michael@0 561 fprintf (out_file, "Certificate List:\n");
michael@0 562 while ((raw_cert = raw_certs[i++]) != NULL) {
michael@0 563 sprintf (cert_label, "Certificate (%d)", i);
michael@0 564 (void) SECU_PrintSignedData (out_file, raw_cert, cert_label, level + 1,
michael@0 565 SECU_PrintCertificate);
michael@0 566 }
michael@0 567 }
michael@0 568
michael@0 569
michael@0 570 static void
michael@0 571 print_ocsp_extensions (FILE *out_file, CERTCertExtension **extensions,
michael@0 572 char *msg, int level)
michael@0 573 {
michael@0 574 if (extensions) {
michael@0 575 SECU_PrintExtensions (out_file, extensions, msg, level);
michael@0 576 } else {
michael@0 577 SECU_Indent (out_file, level);
michael@0 578 fprintf (out_file, "No %s\n", msg);
michael@0 579 }
michael@0 580 }
michael@0 581
michael@0 582
michael@0 583 static void
michael@0 584 print_single_request (FILE *out_file, ocspSingleRequest *single, int level)
michael@0 585 {
michael@0 586 print_ocsp_cert_id (out_file, single->reqCert, level);
michael@0 587 print_ocsp_extensions (out_file, single->singleRequestExtensions,
michael@0 588 "Single Request Extensions", level);
michael@0 589 }
michael@0 590
michael@0 591
michael@0 592 /*
michael@0 593 * Decode the DER/BER-encoded item "data" as an OCSP request
michael@0 594 * and pretty-print the subfields.
michael@0 595 */
michael@0 596 static SECStatus
michael@0 597 print_request (FILE *out_file, SECItem *data)
michael@0 598 {
michael@0 599 CERTOCSPRequest *request;
michael@0 600 ocspTBSRequest *tbsRequest;
michael@0 601 int level = 0;
michael@0 602
michael@0 603 PORT_Assert (out_file != NULL);
michael@0 604 PORT_Assert (data != NULL);
michael@0 605 if (out_file == NULL || data == NULL) {
michael@0 606 PORT_SetError (SEC_ERROR_INVALID_ARGS);
michael@0 607 return SECFailure;
michael@0 608 }
michael@0 609
michael@0 610 request = CERT_DecodeOCSPRequest (data);
michael@0 611 if (request == NULL || request->tbsRequest == NULL)
michael@0 612 return SECFailure;
michael@0 613
michael@0 614 tbsRequest = request->tbsRequest;
michael@0 615
michael@0 616 fprintf (out_file, "TBS Request:\n");
michael@0 617 level++;
michael@0 618
michael@0 619 print_ocsp_version (out_file, &(tbsRequest->version), level);
michael@0 620
michael@0 621 /*
michael@0 622 * XXX Probably should be an interface to get the signer name
michael@0 623 * without looking inside the tbsRequest at all.
michael@0 624 */
michael@0 625 if (tbsRequest->requestorName != NULL) {
michael@0 626 SECU_Indent (out_file, level);
michael@0 627 fprintf (out_file, "XXX print the requestorName\n");
michael@0 628 } else {
michael@0 629 SECU_Indent (out_file, level);
michael@0 630 fprintf (out_file, "No Requestor Name.\n");
michael@0 631 }
michael@0 632
michael@0 633 if (tbsRequest->requestList != NULL) {
michael@0 634 int i;
michael@0 635
michael@0 636 for (i = 0; tbsRequest->requestList[i] != NULL; i++) {
michael@0 637 SECU_Indent (out_file, level);
michael@0 638 fprintf (out_file, "Request %d:\n", i);
michael@0 639 print_single_request (out_file, tbsRequest->requestList[i],
michael@0 640 level + 1);
michael@0 641 }
michael@0 642 } else {
michael@0 643 fprintf (out_file, "Request list is empty.\n");
michael@0 644 }
michael@0 645
michael@0 646 print_ocsp_extensions (out_file, tbsRequest->requestExtensions,
michael@0 647 "Request Extensions", level);
michael@0 648
michael@0 649 if (request->optionalSignature != NULL) {
michael@0 650 ocspSignature *whole_sig;
michael@0 651 SECItem rawsig;
michael@0 652
michael@0 653 fprintf (out_file, "Signature:\n");
michael@0 654
michael@0 655 whole_sig = request->optionalSignature;
michael@0 656 SECU_PrintAlgorithmID (out_file, &(whole_sig->signatureAlgorithm),
michael@0 657 "Signature Algorithm", level);
michael@0 658
michael@0 659 rawsig = whole_sig->signature;
michael@0 660 DER_ConvertBitString (&rawsig);
michael@0 661 SECU_PrintAsHex (out_file, &rawsig, "Signature", level);
michael@0 662
michael@0 663 print_raw_certificates (out_file, whole_sig->derCerts, level);
michael@0 664
michael@0 665 fprintf (out_file, "XXX verify the sig and print result\n");
michael@0 666 } else {
michael@0 667 fprintf (out_file, "No Signature\n");
michael@0 668 }
michael@0 669
michael@0 670 CERT_DestroyOCSPRequest (request);
michael@0 671 return SECSuccess;
michael@0 672 }
michael@0 673
michael@0 674
michael@0 675 static void
michael@0 676 print_revoked_info (FILE *out_file, ocspRevokedInfo *revoked_info, int level)
michael@0 677 {
michael@0 678 SECU_PrintGeneralizedTime (out_file, &(revoked_info->revocationTime),
michael@0 679 "Revocation Time", level);
michael@0 680
michael@0 681 if (revoked_info->revocationReason != NULL) {
michael@0 682 SECU_PrintAsHex (out_file, revoked_info->revocationReason,
michael@0 683 "Revocation Reason", level);
michael@0 684 } else {
michael@0 685 SECU_Indent (out_file, level);
michael@0 686 fprintf (out_file, "No Revocation Reason.\n");
michael@0 687 }
michael@0 688 }
michael@0 689
michael@0 690
michael@0 691 static void
michael@0 692 print_cert_status (FILE *out_file, ocspCertStatus *status, int level)
michael@0 693 {
michael@0 694 SECU_Indent (out_file, level);
michael@0 695 fprintf (out_file, "Status: ");
michael@0 696
michael@0 697 switch (status->certStatusType) {
michael@0 698 case ocspCertStatus_good:
michael@0 699 fprintf (out_file, "Cert is good.\n");
michael@0 700 break;
michael@0 701 case ocspCertStatus_revoked:
michael@0 702 fprintf (out_file, "Cert has been revoked.\n");
michael@0 703 print_revoked_info (out_file, status->certStatusInfo.revokedInfo,
michael@0 704 level + 1);
michael@0 705 break;
michael@0 706 case ocspCertStatus_unknown:
michael@0 707 fprintf (out_file, "Cert is unknown to responder.\n");
michael@0 708 break;
michael@0 709 default:
michael@0 710 fprintf (out_file, "Unrecognized status.\n");
michael@0 711 break;
michael@0 712 }
michael@0 713 }
michael@0 714
michael@0 715
michael@0 716 static void
michael@0 717 print_single_response (FILE *out_file, CERTOCSPSingleResponse *single,
michael@0 718 int level)
michael@0 719 {
michael@0 720 print_ocsp_cert_id (out_file, single->certID, level);
michael@0 721
michael@0 722 print_cert_status (out_file, single->certStatus, level);
michael@0 723
michael@0 724 SECU_PrintGeneralizedTime (out_file, &(single->thisUpdate),
michael@0 725 "This Update", level);
michael@0 726
michael@0 727 if (single->nextUpdate != NULL) {
michael@0 728 SECU_PrintGeneralizedTime (out_file, single->nextUpdate,
michael@0 729 "Next Update", level);
michael@0 730 } else {
michael@0 731 SECU_Indent (out_file, level);
michael@0 732 fprintf (out_file, "No Next Update\n");
michael@0 733 }
michael@0 734
michael@0 735 print_ocsp_extensions (out_file, single->singleExtensions,
michael@0 736 "Single Response Extensions", level);
michael@0 737 }
michael@0 738
michael@0 739
michael@0 740 static void
michael@0 741 print_responder_id (FILE *out_file, ocspResponderID *responderID, int level)
michael@0 742 {
michael@0 743 SECU_Indent (out_file, level);
michael@0 744 fprintf (out_file, "Responder ID ");
michael@0 745
michael@0 746 switch (responderID->responderIDType) {
michael@0 747 case ocspResponderID_byName:
michael@0 748 fprintf (out_file, "(byName):\n");
michael@0 749 SECU_PrintName (out_file, &(responderID->responderIDValue.name),
michael@0 750 "Name", level + 1);
michael@0 751 break;
michael@0 752 case ocspResponderID_byKey:
michael@0 753 fprintf (out_file, "(byKey):\n");
michael@0 754 SECU_PrintAsHex (out_file, &(responderID->responderIDValue.keyHash),
michael@0 755 "Key Hash", level + 1);
michael@0 756 break;
michael@0 757 default:
michael@0 758 fprintf (out_file, "Unrecognized Responder ID Type\n");
michael@0 759 break;
michael@0 760 }
michael@0 761 }
michael@0 762
michael@0 763
michael@0 764 static void
michael@0 765 print_response_data (FILE *out_file, ocspResponseData *responseData, int level)
michael@0 766 {
michael@0 767 SECU_Indent (out_file, level);
michael@0 768 fprintf (out_file, "Response Data:\n");
michael@0 769 level++;
michael@0 770
michael@0 771 print_ocsp_version (out_file, &(responseData->version), level);
michael@0 772
michael@0 773 print_responder_id (out_file, responseData->responderID, level);
michael@0 774
michael@0 775 SECU_PrintGeneralizedTime (out_file, &(responseData->producedAt),
michael@0 776 "Produced At", level);
michael@0 777
michael@0 778 if (responseData->responses != NULL) {
michael@0 779 int i;
michael@0 780
michael@0 781 for (i = 0; responseData->responses[i] != NULL; i++) {
michael@0 782 SECU_Indent (out_file, level);
michael@0 783 fprintf (out_file, "Response %d:\n", i);
michael@0 784 print_single_response (out_file, responseData->responses[i],
michael@0 785 level + 1);
michael@0 786 }
michael@0 787 } else {
michael@0 788 fprintf (out_file, "Response list is empty.\n");
michael@0 789 }
michael@0 790
michael@0 791 print_ocsp_extensions (out_file, responseData->responseExtensions,
michael@0 792 "Response Extensions", level);
michael@0 793 }
michael@0 794
michael@0 795
michael@0 796 static void
michael@0 797 print_basic_response (FILE *out_file, ocspBasicOCSPResponse *basic, int level)
michael@0 798 {
michael@0 799 SECItem rawsig;
michael@0 800
michael@0 801 SECU_Indent (out_file, level);
michael@0 802 fprintf (out_file, "Basic OCSP Response:\n");
michael@0 803 level++;
michael@0 804
michael@0 805 print_response_data (out_file, basic->tbsResponseData, level);
michael@0 806
michael@0 807 SECU_PrintAlgorithmID (out_file,
michael@0 808 &(basic->responseSignature.signatureAlgorithm),
michael@0 809 "Signature Algorithm", level);
michael@0 810
michael@0 811 rawsig = basic->responseSignature.signature;
michael@0 812 DER_ConvertBitString (&rawsig);
michael@0 813 SECU_PrintAsHex (out_file, &rawsig, "Signature", level);
michael@0 814
michael@0 815 print_raw_certificates (out_file, basic->responseSignature.derCerts, level);
michael@0 816 }
michael@0 817
michael@0 818
michael@0 819 /*
michael@0 820 * Note this must match (exactly) the enumeration ocspResponseStatus.
michael@0 821 */
michael@0 822 static char *responseStatusNames[] = {
michael@0 823 "successful (Response has valid confirmations)",
michael@0 824 "malformedRequest (Illegal confirmation request)",
michael@0 825 "internalError (Internal error in issuer)",
michael@0 826 "tryLater (Try again later)",
michael@0 827 "unused ((4) is not used)",
michael@0 828 "sigRequired (Must sign the request)",
michael@0 829 "unauthorized (Request unauthorized)"
michael@0 830 };
michael@0 831
michael@0 832 /*
michael@0 833 * Decode the DER/BER-encoded item "data" as an OCSP response
michael@0 834 * and pretty-print the subfields.
michael@0 835 */
michael@0 836 static SECStatus
michael@0 837 print_response (FILE *out_file, SECItem *data, CERTCertDBHandle *handle)
michael@0 838 {
michael@0 839 CERTOCSPResponse *response;
michael@0 840 int level = 0;
michael@0 841
michael@0 842 PORT_Assert (out_file != NULL);
michael@0 843 PORT_Assert (data != NULL);
michael@0 844 if (out_file == NULL || data == NULL) {
michael@0 845 PORT_SetError (SEC_ERROR_INVALID_ARGS);
michael@0 846 return SECFailure;
michael@0 847 }
michael@0 848
michael@0 849 response = CERT_DecodeOCSPResponse (data);
michael@0 850 if (response == NULL)
michael@0 851 return SECFailure;
michael@0 852
michael@0 853 if (response->statusValue >= ocspResponse_min &&
michael@0 854 response->statusValue <= ocspResponse_max) {
michael@0 855 fprintf (out_file, "Response Status: %s\n",
michael@0 856 responseStatusNames[response->statusValue]);
michael@0 857 } else {
michael@0 858 fprintf (out_file,
michael@0 859 "Response Status: other (Status value %d out of defined range)\n",
michael@0 860 (int)response->statusValue);
michael@0 861 }
michael@0 862
michael@0 863 if (response->statusValue == ocspResponse_successful) {
michael@0 864 ocspResponseBytes *responseBytes = response->responseBytes;
michael@0 865 SECStatus sigStatus;
michael@0 866 CERTCertificate *signerCert = NULL;
michael@0 867
michael@0 868 PORT_Assert (responseBytes != NULL);
michael@0 869
michael@0 870 level++;
michael@0 871 fprintf (out_file, "Response Bytes:\n");
michael@0 872 SECU_PrintObjectID (out_file, &(responseBytes->responseType),
michael@0 873 "Response Type", level);
michael@0 874 switch (response->responseBytes->responseTypeTag) {
michael@0 875 case SEC_OID_PKIX_OCSP_BASIC_RESPONSE:
michael@0 876 print_basic_response (out_file,
michael@0 877 responseBytes->decodedResponse.basic,
michael@0 878 level);
michael@0 879 break;
michael@0 880 default:
michael@0 881 SECU_Indent (out_file, level);
michael@0 882 fprintf (out_file, "Unknown response syntax\n");
michael@0 883 break;
michael@0 884 }
michael@0 885
michael@0 886 sigStatus = CERT_VerifyOCSPResponseSignature (response, handle,
michael@0 887 NULL, &signerCert, NULL);
michael@0 888 SECU_Indent (out_file, level);
michael@0 889 fprintf (out_file, "Signature verification ");
michael@0 890 if (sigStatus != SECSuccess) {
michael@0 891 fprintf (out_file, "failed: %s\n", SECU_Strerror (PORT_GetError()));
michael@0 892 } else {
michael@0 893 fprintf (out_file, "succeeded.\n");
michael@0 894 if (signerCert != NULL) {
michael@0 895 SECU_PrintName (out_file, &signerCert->subject, "Signer",
michael@0 896 level);
michael@0 897 CERT_DestroyCertificate (signerCert);
michael@0 898 } else {
michael@0 899 SECU_Indent (out_file, level);
michael@0 900 fprintf (out_file, "No signer cert returned?\n");
michael@0 901 }
michael@0 902 }
michael@0 903 } else {
michael@0 904 SECU_Indent (out_file, level);
michael@0 905 fprintf (out_file, "Unsuccessful response, no more information.\n");
michael@0 906 }
michael@0 907
michael@0 908 CERT_DestroyOCSPResponse (response);
michael@0 909 return SECSuccess;
michael@0 910 }
michael@0 911
michael@0 912 #endif /* NO_PP */
michael@0 913
michael@0 914
michael@0 915 static SECStatus
michael@0 916 cert_usage_from_char (const char *cert_usage_str, SECCertUsage *cert_usage)
michael@0 917 {
michael@0 918 PORT_Assert (cert_usage_str != NULL);
michael@0 919 PORT_Assert (cert_usage != NULL);
michael@0 920
michael@0 921 if (PORT_Strlen (cert_usage_str) != 1)
michael@0 922 return SECFailure;
michael@0 923
michael@0 924 switch (*cert_usage_str) {
michael@0 925 case 'c':
michael@0 926 *cert_usage = certUsageSSLClient;
michael@0 927 break;
michael@0 928 case 's':
michael@0 929 *cert_usage = certUsageSSLServer;
michael@0 930 break;
michael@0 931 case 'e':
michael@0 932 *cert_usage = certUsageEmailRecipient;
michael@0 933 break;
michael@0 934 case 'E':
michael@0 935 *cert_usage = certUsageEmailSigner;
michael@0 936 break;
michael@0 937 case 'S':
michael@0 938 *cert_usage = certUsageObjectSigner;
michael@0 939 break;
michael@0 940 case 'C':
michael@0 941 *cert_usage = certUsageVerifyCA;
michael@0 942 break;
michael@0 943 default:
michael@0 944 return SECFailure;
michael@0 945 }
michael@0 946
michael@0 947 return SECSuccess;
michael@0 948 }
michael@0 949
michael@0 950
michael@0 951 int
michael@0 952 main (int argc, char **argv)
michael@0 953 {
michael@0 954 int retval;
michael@0 955 PRFileDesc *in_file;
michael@0 956 FILE *out_file; /* not PRFileDesc until SECU accepts it */
michael@0 957 int crequest, dresponse;
michael@0 958 int prequest, presponse;
michael@0 959 int ccert, vcert;
michael@0 960 const char *db_dir, *date_str, *cert_usage_str, *name;
michael@0 961 const char *responder_name, *responder_url, *signer_name;
michael@0 962 PRBool add_acceptable_responses, add_service_locator;
michael@0 963 SECItem *data = NULL;
michael@0 964 PLOptState *optstate;
michael@0 965 SECStatus rv;
michael@0 966 CERTCertDBHandle *handle = NULL;
michael@0 967 SECCertUsage cert_usage;
michael@0 968 PRTime verify_time;
michael@0 969 CERTCertificate *cert = NULL;
michael@0 970 PRBool ascii = PR_FALSE;
michael@0 971
michael@0 972 retval = -1; /* what we return/exit with on error */
michael@0 973
michael@0 974 program_name = PL_strrchr(argv[0], '/');
michael@0 975 program_name = program_name ? (program_name + 1) : argv[0];
michael@0 976
michael@0 977 in_file = PR_STDIN;
michael@0 978 out_file = stdout;
michael@0 979
michael@0 980 crequest = 0;
michael@0 981 dresponse = 0;
michael@0 982 prequest = 0;
michael@0 983 presponse = 0;
michael@0 984 ccert = 0;
michael@0 985 vcert = 0;
michael@0 986
michael@0 987 db_dir = NULL;
michael@0 988 date_str = NULL;
michael@0 989 cert_usage_str = NULL;
michael@0 990 name = NULL;
michael@0 991 responder_name = NULL;
michael@0 992 responder_url = NULL;
michael@0 993 signer_name = NULL;
michael@0 994
michael@0 995 add_acceptable_responses = PR_FALSE;
michael@0 996 add_service_locator = PR_FALSE;
michael@0 997
michael@0 998 optstate = PL_CreateOptState (argc, argv, "AHLPR:S:V:d:l:pr:s:t:u:w:");
michael@0 999 if (optstate == NULL) {
michael@0 1000 SECU_PrintError (program_name, "PL_CreateOptState failed");
michael@0 1001 return retval;
michael@0 1002 }
michael@0 1003
michael@0 1004 while (PL_GetNextOpt (optstate) == PL_OPT_OK) {
michael@0 1005 switch (optstate->option) {
michael@0 1006 case '?':
michael@0 1007 short_usage (program_name);
michael@0 1008 return retval;
michael@0 1009
michael@0 1010 case 'A':
michael@0 1011 add_acceptable_responses = PR_TRUE;
michael@0 1012 break;
michael@0 1013
michael@0 1014 case 'H':
michael@0 1015 long_usage (program_name);
michael@0 1016 return retval;
michael@0 1017
michael@0 1018 case 'L':
michael@0 1019 add_service_locator = PR_TRUE;
michael@0 1020 break;
michael@0 1021
michael@0 1022 case 'P':
michael@0 1023 presponse = 1;
michael@0 1024 break;
michael@0 1025
michael@0 1026 case 'R':
michael@0 1027 dresponse = 1;
michael@0 1028 name = optstate->value;
michael@0 1029 break;
michael@0 1030
michael@0 1031 case 'S':
michael@0 1032 ccert = 1;
michael@0 1033 name = optstate->value;
michael@0 1034 break;
michael@0 1035
michael@0 1036 case 'V':
michael@0 1037 vcert = 1;
michael@0 1038 name = optstate->value;
michael@0 1039 break;
michael@0 1040
michael@0 1041 case 'a':
michael@0 1042 ascii = PR_TRUE;
michael@0 1043 break;
michael@0 1044
michael@0 1045 case 'd':
michael@0 1046 db_dir = optstate->value;
michael@0 1047 break;
michael@0 1048
michael@0 1049 case 'l':
michael@0 1050 responder_url = optstate->value;
michael@0 1051 break;
michael@0 1052
michael@0 1053 case 'p':
michael@0 1054 prequest = 1;
michael@0 1055 break;
michael@0 1056
michael@0 1057 case 'r':
michael@0 1058 crequest = 1;
michael@0 1059 name = optstate->value;
michael@0 1060 break;
michael@0 1061
michael@0 1062 case 's':
michael@0 1063 signer_name = optstate->value;
michael@0 1064 break;
michael@0 1065
michael@0 1066 case 't':
michael@0 1067 responder_name = optstate->value;
michael@0 1068 break;
michael@0 1069
michael@0 1070 case 'u':
michael@0 1071 cert_usage_str = optstate->value;
michael@0 1072 break;
michael@0 1073
michael@0 1074 case 'w':
michael@0 1075 date_str = optstate->value;
michael@0 1076 break;
michael@0 1077 }
michael@0 1078 }
michael@0 1079
michael@0 1080 PL_DestroyOptState(optstate);
michael@0 1081
michael@0 1082 if ((crequest + dresponse + prequest + presponse + ccert + vcert) != 1) {
michael@0 1083 PR_fprintf (PR_STDERR, "%s: must specify exactly one command\n\n",
michael@0 1084 program_name);
michael@0 1085 short_usage (program_name);
michael@0 1086 return retval;
michael@0 1087 }
michael@0 1088
michael@0 1089 if (vcert) {
michael@0 1090 if (cert_usage_str == NULL) {
michael@0 1091 PR_fprintf (PR_STDERR, "%s: verification requires cert usage\n\n",
michael@0 1092 program_name);
michael@0 1093 short_usage (program_name);
michael@0 1094 return retval;
michael@0 1095 }
michael@0 1096
michael@0 1097 rv = cert_usage_from_char (cert_usage_str, &cert_usage);
michael@0 1098 if (rv != SECSuccess) {
michael@0 1099 PR_fprintf (PR_STDERR, "%s: invalid cert usage (\"%s\")\n\n",
michael@0 1100 program_name, cert_usage_str);
michael@0 1101 long_usage (program_name);
michael@0 1102 return retval;
michael@0 1103 }
michael@0 1104 }
michael@0 1105
michael@0 1106 if (ccert + vcert) {
michael@0 1107 if (responder_url != NULL || responder_name != NULL) {
michael@0 1108 /*
michael@0 1109 * To do a full status check, both the URL and the cert name
michael@0 1110 * of the responder must be specified if either one is.
michael@0 1111 */
michael@0 1112 if (responder_url == NULL || responder_name == NULL) {
michael@0 1113 if (responder_url == NULL)
michael@0 1114 PR_fprintf (PR_STDERR,
michael@0 1115 "%s: must also specify responder location\n\n",
michael@0 1116 program_name);
michael@0 1117 else
michael@0 1118 PR_fprintf (PR_STDERR,
michael@0 1119 "%s: must also specify responder name\n\n",
michael@0 1120 program_name);
michael@0 1121 short_usage (program_name);
michael@0 1122 return retval;
michael@0 1123 }
michael@0 1124 }
michael@0 1125
michael@0 1126 if (date_str != NULL) {
michael@0 1127 rv = DER_AsciiToTime (&verify_time, (char *) date_str);
michael@0 1128 if (rv != SECSuccess) {
michael@0 1129 SECU_PrintError (program_name, "error converting time string");
michael@0 1130 PR_fprintf (PR_STDERR, "\n");
michael@0 1131 long_usage (program_name);
michael@0 1132 return retval;
michael@0 1133 }
michael@0 1134 } else {
michael@0 1135 verify_time = PR_Now();
michael@0 1136 }
michael@0 1137 }
michael@0 1138
michael@0 1139 retval = -2; /* errors change from usage to runtime */
michael@0 1140
michael@0 1141 /*
michael@0 1142 * Initialize the NSPR and Security libraries.
michael@0 1143 */
michael@0 1144 PR_Init (PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
michael@0 1145 db_dir = SECU_ConfigDirectory (db_dir);
michael@0 1146 rv = NSS_Init (db_dir);
michael@0 1147 if (rv != SECSuccess) {
michael@0 1148 SECU_PrintError (program_name, "NSS_Init failed");
michael@0 1149 goto prdone;
michael@0 1150 }
michael@0 1151 SECU_RegisterDynamicOids();
michael@0 1152
michael@0 1153 if (prequest + presponse) {
michael@0 1154 MAKE_FILE_BINARY(stdin);
michael@0 1155 data = read_file_into_item (in_file, siBuffer);
michael@0 1156 if (data == NULL) {
michael@0 1157 SECU_PrintError (program_name, "problem reading input");
michael@0 1158 goto nssdone;
michael@0 1159 }
michael@0 1160 }
michael@0 1161
michael@0 1162 if (crequest + dresponse + presponse + ccert + vcert) {
michael@0 1163 handle = CERT_GetDefaultCertDB();
michael@0 1164 if (handle == NULL) {
michael@0 1165 SECU_PrintError (program_name, "problem getting certdb handle");
michael@0 1166 goto nssdone;
michael@0 1167 }
michael@0 1168
michael@0 1169 /*
michael@0 1170 * It would be fine to do the enable for all of these commands,
michael@0 1171 * but this way we check that everything but an overall verify
michael@0 1172 * can be done without it. That is, that the individual pieces
michael@0 1173 * work on their own.
michael@0 1174 */
michael@0 1175 if (vcert) {
michael@0 1176 rv = CERT_EnableOCSPChecking (handle);
michael@0 1177 if (rv != SECSuccess) {
michael@0 1178 SECU_PrintError (program_name, "error enabling OCSP checking");
michael@0 1179 goto nssdone;
michael@0 1180 }
michael@0 1181 }
michael@0 1182
michael@0 1183 if ((ccert + vcert) && (responder_name != NULL)) {
michael@0 1184 rv = CERT_SetOCSPDefaultResponder (handle, responder_url,
michael@0 1185 responder_name);
michael@0 1186 if (rv != SECSuccess) {
michael@0 1187 SECU_PrintError (program_name,
michael@0 1188 "error setting default responder");
michael@0 1189 goto nssdone;
michael@0 1190 }
michael@0 1191
michael@0 1192 rv = CERT_EnableOCSPDefaultResponder (handle);
michael@0 1193 if (rv != SECSuccess) {
michael@0 1194 SECU_PrintError (program_name,
michael@0 1195 "error enabling default responder");
michael@0 1196 goto nssdone;
michael@0 1197 }
michael@0 1198 }
michael@0 1199 }
michael@0 1200
michael@0 1201 #define NOTYET(opt) \
michael@0 1202 { \
michael@0 1203 PR_fprintf (PR_STDERR, "%s not yet working\n", opt); \
michael@0 1204 exit (-1); \
michael@0 1205 }
michael@0 1206
michael@0 1207 if (name) {
michael@0 1208 cert = find_certificate(handle, name, ascii);
michael@0 1209 }
michael@0 1210
michael@0 1211 if (crequest) {
michael@0 1212 if (signer_name != NULL) {
michael@0 1213 NOTYET("-s");
michael@0 1214 }
michael@0 1215 rv = create_request (out_file, handle, cert, add_service_locator,
michael@0 1216 add_acceptable_responses);
michael@0 1217 } else if (dresponse) {
michael@0 1218 if (signer_name != NULL) {
michael@0 1219 NOTYET("-s");
michael@0 1220 }
michael@0 1221 rv = dump_response (out_file, handle, cert, responder_url);
michael@0 1222 } else if (prequest) {
michael@0 1223 rv = print_request (out_file, data);
michael@0 1224 } else if (presponse) {
michael@0 1225 rv = print_response (out_file, data, handle);
michael@0 1226 } else if (ccert) {
michael@0 1227 if (signer_name != NULL) {
michael@0 1228 NOTYET("-s");
michael@0 1229 }
michael@0 1230 rv = get_cert_status (out_file, handle, cert, name, verify_time);
michael@0 1231 } else if (vcert) {
michael@0 1232 if (signer_name != NULL) {
michael@0 1233 NOTYET("-s");
michael@0 1234 }
michael@0 1235 rv = verify_cert (out_file, handle, cert, name, cert_usage, verify_time);
michael@0 1236 }
michael@0 1237
michael@0 1238 if (rv != SECSuccess)
michael@0 1239 SECU_PrintError (program_name, "error performing requested operation");
michael@0 1240 else
michael@0 1241 retval = 0;
michael@0 1242
michael@0 1243 nssdone:
michael@0 1244 if (cert) {
michael@0 1245 CERT_DestroyCertificate(cert);
michael@0 1246 }
michael@0 1247
michael@0 1248 if (data != NULL) {
michael@0 1249 SECITEM_FreeItem (data, PR_TRUE);
michael@0 1250 }
michael@0 1251
michael@0 1252 if (handle != NULL) {
michael@0 1253 CERT_DisableOCSPDefaultResponder(handle);
michael@0 1254 CERT_DisableOCSPChecking (handle);
michael@0 1255 }
michael@0 1256
michael@0 1257 if (NSS_Shutdown () != SECSuccess) {
michael@0 1258 retval = 1;
michael@0 1259 }
michael@0 1260
michael@0 1261 prdone:
michael@0 1262 PR_Cleanup ();
michael@0 1263 return retval;
michael@0 1264 }

mercurial