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.

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

mercurial