ocspclnt.c
上传用户:lyxiangda
上传日期:2007-01-12
资源大小:3042k
文件大小:31k
- /*
- * The contents of this file are subject to the Mozilla Public
- * License Version 1.1 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of
- * the License at http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS
- * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
- * implied. See the License for the specific language governing
- * rights and limitations under the License.
- *
- * The Original Code is the Netscape security libraries.
- *
- * The Initial Developer of the Original Code is Netscape
- * Communications Corporation. Portions created by Netscape are
- * Copyright (C) 1994-2000 Netscape Communications Corporation. All
- * Rights Reserved.
- *
- * Contributor(s):
- *
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License Version 2 or later (the
- * "GPL"), in which case the provisions of the GPL are applicable
- * instead of those above. If you wish to allow use of your
- * version of this file only under the terms of the GPL and not to
- * allow others to use your version of this file under the MPL,
- * indicate your decision by deleting the provisions above and
- * replace them with the notice and other provisions required by
- * the GPL. If you do not delete the provisions above, a recipient
- * may use your version of this file under either the MPL or the
- * GPL.
- */
- /*
- * Test program for client-side OCSP.
- *
- * $Id: ocspclnt.c,v 1.1 2000/03/31 20:09:29 relyea%netscape.com Exp $
- */
- #include "secutil.h"
- #include "nspr.h"
- #include "plgetopt.h"
- #include "nss.h"
- #include "cert.h"
- #include "ocsp.h"
- #include "xconst.h" /*
- * XXX internal header file; needed to get at
- * cert_DecodeAuthInfoAccessExtension -- would be
- * nice to not need this, but that would require
- * better/different APIs.
- */
- #ifndef NO_PP /*
- * Compile with this every once in a while to be
- * sure that no dependencies on it get added
- * outside of the pretty-printing routines.
- */
- #include "ocspti.h" /* internals for pretty-printing routines *only* */
- #endif /* NO_PP */
- #define DEFAULT_DB_DIR "~/.netscape"
- static void
- synopsis (char *program_name)
- {
- PRFileDesc *pr_stderr;
- pr_stderr = PR_STDERR;
- PR_fprintf (pr_stderr, "Usage:");
- PR_fprintf (pr_stderr,
- "t%s -p [-d <dir>]n",
- program_name);
- PR_fprintf (pr_stderr,
- "t%s -P [-d <dir>]n",
- program_name);
- PR_fprintf (pr_stderr,
- "t%s -r <name> [-L] [-s <name>] [-d <dir>]n",
- program_name);
- PR_fprintf (pr_stderr,
- "t%s -R <name> [-l <location>] [-s <name>] [-d <dir>]n",
- program_name);
- PR_fprintf (pr_stderr,
- "t%s -S <name> [-l <location> -t <name>]n",
- program_name);
- PR_fprintf (pr_stderr,
- "tt [-s <name>] [-w <time>] [-d <dir>]n");
- PR_fprintf (pr_stderr,
- "t%s -V <name> -u <usage> [-l <location> -t <name>]n",
- program_name);
- PR_fprintf (pr_stderr,
- "tt [-s <name>] [-w <time>] [-d <dir>]n");
- }
- static void
- short_usage (char *program_name)
- {
- PR_fprintf (PR_STDERR,
- "Type %s -H for more detailed descriptionsn",
- program_name);
- synopsis (program_name);
- }
- static void
- long_usage (char *program_name)
- {
- PRFileDesc *pr_stderr;
- pr_stderr = PR_STDERR;
- synopsis (program_name);
- PR_fprintf (pr_stderr, "nCommands (must specify exactly one):n");
- PR_fprintf (pr_stderr,
- " %-13s Pretty-print a binary request read from stdinn",
- "-p");
- PR_fprintf (pr_stderr,
- " %-13s Pretty-print a binary response read from stdinn",
- "-P");
- PR_fprintf (pr_stderr,
- " %-13s Create a request for cert "nickname" on stdoutn",
- "-r nickname");
- PR_fprintf (pr_stderr,
- " %-13s Get response for cert "nickname", dump to stdoutn",
- "-R nickname");
- PR_fprintf (pr_stderr,
- " %-13s Get status for cert "nickname"n",
- "-S nickname");
- PR_fprintf (pr_stderr,
- " %-13s Fully verify cert "nickname", w/ status checkn",
- "-V nickname");
- PR_fprintf (pr_stderr, "Options:n");
- PR_fprintf (pr_stderr,
- " %-13s Add the service locator extension to the requestn",
- "-L");
- PR_fprintf (pr_stderr,
- " %-13s Find security databases in "dbdir" (default %s)n",
- "-d dbdir", DEFAULT_DB_DIR);
- PR_fprintf (pr_stderr,
- " %-13s Use "location" as URL of respondern",
- "-l location");
- PR_fprintf (pr_stderr,
- " %-13s Trust cert "nickname" as response signern",
- "-t nickname");
- PR_fprintf (pr_stderr,
- " %-13s Sign requests with cert "nickname"n",
- "-s nickname");
- PR_fprintf (pr_stderr,
- " %-13s Type of certificate usage for verification:n",
- "-u usage");
- PR_fprintf (pr_stderr,
- "%-17s c SSL Clientn", "");
- PR_fprintf (pr_stderr,
- "%-17s s SSL Servern", "");
- PR_fprintf (pr_stderr,
- "%-17s e Email Recipientn", "");
- PR_fprintf (pr_stderr,
- "%-17s E Email Signern", "");
- PR_fprintf (pr_stderr,
- "%-17s S Object Signern", "");
- PR_fprintf (pr_stderr,
- "%-17s C CAn", "");
- PR_fprintf (pr_stderr,
- " %-13s Validity time (default current time), one of:n",
- "-w time");
- PR_fprintf (pr_stderr,
- "%-17s %-25s (GMT)n", "", "YYMMDDhhmm[ss]Z");
- PR_fprintf (pr_stderr,
- "%-17s %-25s (later than GMT)n", "", "YYMMDDhhmm[ss]+hhmm");
- PR_fprintf (pr_stderr,
- "%-17s %-25s (earlier than GMT)n", "", "YYMMDDhhmm[ss]-hhmm");
- }
- /*
- * XXX This is a generic function that would probably make a good
- * replacement for SECU_DER_Read (which is not at all specific to DER,
- * despite its name), but that requires fixing all of the tools...
- * Still, it should be done, whenenver I/somebody has the time.
- * (Also, consider whether this actually belongs in the security
- * library itself, not just in the command library.)
- *
- * This function takes an open file (a PRFileDesc *) and reads the
- * entire file into a SECItem. (Obviously, the file is intended to
- * be small enough that such a thing is advisable.) Both the SECItem
- * and the buffer it points to are allocated from the heap; the caller
- * is expected to free them. ("SECITEM_FreeItem(item, PR_TRUE)")
- */
- static SECItem *
- read_file_into_item (PRFileDesc *in_file, SECItemType si_type)
- {
- PRStatus prv;
- SECItem *item;
- PRFileInfo file_info;
- PRInt32 bytes_read;
- prv = PR_GetOpenFileInfo (in_file, &file_info);
- if (prv != PR_SUCCESS)
- return NULL;
- if (file_info.size == 0) {
- /* XXX Need a better error; just grabbed this one for expediency. */
- PORT_SetError (SEC_ERROR_INPUT_LEN);
- return NULL;
- }
- if (file_info.size > 0xffff) { /* I think this is too big. */
- PORT_SetError (SEC_ERROR_NO_MEMORY);
- return NULL;
- }
- item = PORT_Alloc (sizeof (SECItem));
- if (item == NULL)
- return NULL;
- item->type = si_type;
- item->len = (unsigned int) file_info.size;
- item->data = PORT_Alloc ((size_t)item->len);
- if (item->data == NULL)
- goto loser;
- bytes_read = PR_Read (in_file, item->data, (PRInt32) item->len);
- if (bytes_read < 0) {
- /* Something went wrong; error is already set for us. */
- goto loser;
- } else if (bytes_read == 0) {
- /* Something went wrong; we read nothing. But no system/nspr error. */
- /* XXX Need to set an error here. */
- goto loser;
- } else if (item->len != (unsigned int)bytes_read) {
- /* Something went wrong; we read less (or more!?) than we expected. */
- /* XXX Need to set an error here. */
- goto loser;
- }
- return item;
- loser:
- SECITEM_FreeItem (item, PR_TRUE);
- return NULL;
- }
- /*
- * Create a DER-encoded OCSP request (for the certificate whose nickname
- * is "name") and dump it out.
- */
- static SECStatus
- create_request (FILE *out_file, CERTCertDBHandle *handle, const char *cert_name,
- PRBool add_service_locator, PRBool add_acceptable_responses)
- {
- CERTCertificate *cert = NULL;
- CERTCertList *certs = NULL;
- CERTOCSPRequest *request = NULL;
- int64 now = PR_Now();
- SECItem *encoding = NULL;
- SECStatus rv = SECFailure;
- if (handle == NULL || cert_name == NULL)
- goto loser;
- cert = CERT_FindCertByNicknameOrEmailAddr (handle, (char *) cert_name);
- if (cert == NULL)
- goto loser;
- /*
- * We need to create a list of one.
- */
- certs = CERT_NewCertList();
- if (certs == NULL)
- goto loser;
- if (CERT_AddCertToListTail (certs, cert) != SECSuccess)
- goto loser;
- /*
- * Now that cert is included in the list, we need to be careful
- * that we do not try to destroy it twice. This will prevent that.
- */
- cert = NULL;
- request = CERT_CreateOCSPRequest (certs, now, add_service_locator, NULL);
- if (request == NULL)
- goto loser;
- if (add_acceptable_responses) {
- rv = CERT_AddOCSPAcceptableResponses(request,
- SEC_OID_PKIX_OCSP_BASIC_RESPONSE);
- if (rv != SECSuccess)
- goto loser;
- }
- encoding = CERT_EncodeOCSPRequest (NULL, request, NULL);
- if (encoding == NULL)
- goto loser;
- if (fwrite (encoding->data, encoding->len, 1, out_file) != 1)
- goto loser;
- rv = SECSuccess;
- loser:
- if (encoding != NULL)
- SECITEM_FreeItem(encoding, PR_TRUE);
- if (request != NULL)
- CERT_DestroyOCSPRequest(request);
- if (certs != NULL)
- CERT_DestroyCertList (certs);
- if (cert != NULL)
- CERT_DestroyCertificate (cert);
- return rv;
- }
- /*
- * Create a DER-encoded OCSP request (for the certificate whose nickname is
- * "cert_name"), then get and dump a corresponding response. The responder
- * location is either specified explicitly (as "responder_url") or found
- * via the AuthorityInfoAccess URL in the cert.
- */
- static SECStatus
- dump_response (FILE *out_file, CERTCertDBHandle *handle, const char *cert_name,
- const char *responder_url)
- {
- CERTCertificate *cert = NULL;
- CERTCertList *certs = NULL;
- char *loc = NULL;
- int64 now = PR_Now();
- SECItem *response = NULL;
- SECStatus rv = SECFailure;
- PRBool includeServiceLocator;
- if (handle == NULL || cert_name == NULL)
- goto loser;
- cert = CERT_FindCertByNicknameOrEmailAddr (handle, (char *) cert_name);
- if (cert == NULL)
- goto loser;
- if (responder_url != NULL) {
- loc = (char *) responder_url;
- includeServiceLocator = PR_TRUE;
- } else {
- loc = CERT_GetOCSPAuthorityInfoAccessLocation (cert);
- if (loc == NULL)
- goto loser;
- includeServiceLocator = PR_FALSE;
- }
- /*
- * We need to create a list of one.
- */
- certs = CERT_NewCertList();
- if (certs == NULL)
- goto loser;
- if (CERT_AddCertToListTail (certs, cert) != SECSuccess)
- goto loser;
- /*
- * Now that cert is included in the list, we need to be careful
- * that we do not try to destroy it twice. This will prevent that.
- */
- cert = NULL;
- response = CERT_GetEncodedOCSPResponse (NULL, certs, loc, now,
- includeServiceLocator,
- NULL, NULL, NULL);
- if (response == NULL)
- goto loser;
- if (fwrite (response->data, response->len, 1, out_file) != 1)
- goto loser;
- rv = SECSuccess;
- loser:
- if (response != NULL)
- SECITEM_FreeItem (response, PR_TRUE);
- if (certs != NULL)
- CERT_DestroyCertList (certs);
- if (loc != NULL && loc != responder_url)
- PORT_Free (loc);
- if (cert != NULL)
- CERT_DestroyCertificate (cert);
- return rv;
- }
- /*
- * Get the status for the specified certificate (whose nickname is "cert_name").
- * Directly use the OCSP function rather than doing a full verification.
- */
- static SECStatus
- get_cert_status (FILE *out_file, CERTCertDBHandle *handle,
- const char *cert_name, int64 verify_time)
- {
- CERTCertificate *cert = NULL;
- SECStatus rv = SECFailure;
- if (handle == NULL || cert_name == NULL)
- goto loser;
- cert = CERT_FindCertByNicknameOrEmailAddr (handle, (char *) cert_name);
- if (cert == NULL)
- goto loser;
- rv = CERT_CheckOCSPStatus (handle, cert, verify_time, NULL);
- fprintf (out_file, "Check of certificate "%s" ", cert_name);
- if (rv == SECSuccess) {
- fprintf (out_file, "succeeded.n");
- } else {
- const char *error_string = SECU_Strerror(PORT_GetError());
- fprintf (out_file, "failed. Reason:n");
- if (error_string != NULL && PORT_Strlen(error_string) > 0)
- fprintf (out_file, "%sn", error_string);
- else
- fprintf (out_file, "Unknownn");
- }
- rv = SECSuccess;
- loser:
- if (cert != NULL)
- CERT_DestroyCertificate (cert);
- return rv;
- }
- /*
- * Verify the specified certificate (whose nickname is "cert_name").
- * OCSP is already turned on, so we just need to call the standard
- * certificate verification API and let it do all the work.
- */
- static SECStatus
- verify_cert (FILE *out_file, CERTCertDBHandle *handle, const char *cert_name,
- SECCertUsage cert_usage, int64 verify_time)
- {
- CERTCertificate *cert = NULL;
- SECStatus rv = SECFailure;
- if (handle == NULL || cert_name == NULL)
- goto loser;
- cert = CERT_FindCertByNicknameOrEmailAddr (handle, (char *) cert_name);
- if (cert == NULL)
- goto loser;
- rv = CERT_VerifyCert (handle, cert, PR_TRUE, cert_usage, verify_time,
- NULL, NULL);
- fprintf (out_file, "Verification of certificate "%s" ", cert_name);
- if (rv == SECSuccess) {
- fprintf (out_file, "succeeded.n");
- } else {
- const char *error_string = SECU_Strerror(PORT_GetError());
- fprintf (out_file, "failed. Reason:n");
- if (error_string != NULL && PORT_Strlen(error_string) > 0)
- fprintf (out_file, "%sn", error_string);
- else
- fprintf (out_file, "Unknownn");
- }
- rv = SECSuccess;
- loser:
- if (cert != NULL)
- CERT_DestroyCertificate (cert);
- return rv;
- }
- #ifdef NO_PP
- static SECStatus
- print_request (FILE *out_file, SECItem *data)
- {
- fprintf (out_file, "Cannot pretty-print request compiled with NO_PP.n");
- return SECSuccess;
- }
- static SECStatus
- print_response (FILE *out_file, SECItem *data, CERTCertDBHandle *handle)
- {
- fprintf (out_file, "Cannot pretty-print response compiled with NO_PP.n");
- return SECSuccess;
- }
- #else /* NO_PP */
- static void
- print_ocsp_version (FILE *out_file, SECItem *version, int level)
- {
- if (version->len > 0) {
- SECU_PrintInteger (out_file, version, "Version", level);
- } else {
- SECU_Indent (out_file, level);
- fprintf (out_file, "Version: DEFAULTn");
- }
- }
- static void
- print_ocsp_cert_id (FILE *out_file, CERTOCSPCertID *cert_id, int level)
- {
- SECU_Indent (out_file, level);
- fprintf (out_file, "Cert ID:n");
- level++;
- SECU_PrintAlgorithmID (out_file, &(cert_id->hashAlgorithm),
- "Hash Algorithm", level);
- SECU_PrintAsHex (out_file, &(cert_id->issuerNameHash),
- "Issuer Name Hash", level);
- SECU_PrintAsHex (out_file, &(cert_id->issuerKeyHash),
- "Issuer Key Hash", level);
- SECU_PrintInteger (out_file, &(cert_id->serialNumber),
- "Serial Number", level);
- /* XXX lookup the cert; if found, print something nice (nickname?) */
- }
- static void
- print_raw_certificates (FILE *out_file, SECItem **raw_certs, int level)
- {
- SECItem *raw_cert;
- int i = 0;
- char cert_label[50];
- SECU_Indent (out_file, level);
- if (raw_certs == NULL) {
- fprintf (out_file, "No Certificates.n");
- return;
- }
- fprintf (out_file, "Certificate List:n");
- while ((raw_cert = raw_certs[i++]) != NULL) {
- sprintf (cert_label, "Certificate (%d)", i);
- (void) SECU_PrintSignedData (out_file, raw_cert, cert_label, level + 1,
- SECU_PrintCertificate);
- }
- }
- static void
- print_ocsp_extensions (FILE *out_file, CERTCertExtension **extensions,
- char *msg, int level)
- {
- if (extensions) {
- SECU_PrintExtensions (out_file, extensions, msg, level);
- } else {
- SECU_Indent (out_file, level);
- fprintf (out_file, "No %sn", msg);
- }
- }
- static void
- print_single_request (FILE *out_file, ocspSingleRequest *single, int level)
- {
- print_ocsp_cert_id (out_file, single->reqCert, level);
- print_ocsp_extensions (out_file, single->singleRequestExtensions,
- "Single Request Extensions", level);
- }
- /*
- * Decode the DER/BER-encoded item "data" as an OCSP request
- * and pretty-print the subfields.
- */
- static SECStatus
- print_request (FILE *out_file, SECItem *data)
- {
- CERTOCSPRequest *request;
- ocspTBSRequest *tbsRequest;
- int level = 0;
- PORT_Assert (out_file != NULL);
- PORT_Assert (data != NULL);
- if (out_file == NULL || data == NULL) {
- PORT_SetError (SEC_ERROR_INVALID_ARGS);
- return SECFailure;
- }
- request = CERT_DecodeOCSPRequest (data);
- if (request == NULL || request->tbsRequest == NULL)
- return SECFailure;
- tbsRequest = request->tbsRequest;
- fprintf (out_file, "TBS Request:n");
- level++;
- print_ocsp_version (out_file, &(tbsRequest->version), level);
- /*
- * XXX Probably should be an interface to get the signer name
- * without looking inside the tbsRequest at all.
- */
- if (tbsRequest->requestorName != NULL) {
- SECU_Indent (out_file, level);
- fprintf (out_file, "XXX print the requestorNamen");
- } else {
- SECU_Indent (out_file, level);
- fprintf (out_file, "No Requestor Name.n");
- }
- if (tbsRequest->requestList != NULL) {
- int i;
- for (i = 0; tbsRequest->requestList[i] != NULL; i++) {
- SECU_Indent (out_file, level);
- fprintf (out_file, "Request %d:n", i);
- print_single_request (out_file, tbsRequest->requestList[i],
- level + 1);
- }
- } else {
- fprintf (out_file, "Request list is empty.n");
- }
- print_ocsp_extensions (out_file, tbsRequest->requestExtensions,
- "Request Extensions", level);
- if (request->optionalSignature != NULL) {
- ocspSignature *whole_sig;
- SECItem rawsig;
- fprintf (out_file, "Signature:n");
- whole_sig = request->optionalSignature;
- SECU_PrintAlgorithmID (out_file, &(whole_sig->signatureAlgorithm),
- "Signature Algorithm", level);
- rawsig = whole_sig->signature;
- DER_ConvertBitString (&rawsig);
- SECU_PrintAsHex (out_file, &rawsig, "Signature", level);
- print_raw_certificates (out_file, whole_sig->derCerts, level);
- fprintf (out_file, "XXX verify the sig and print resultn");
- } else {
- fprintf (out_file, "No Signaturen");
- }
- CERT_DestroyOCSPRequest (request);
- return SECSuccess;
- }
- static void
- print_revoked_info (FILE *out_file, ocspRevokedInfo *revoked_info, int level)
- {
- SECU_PrintGeneralizedTime (out_file, &(revoked_info->revocationTime),
- "Revocation Time", level);
- if (revoked_info->revocationReason != NULL) {
- SECU_PrintAsHex (out_file, revoked_info->revocationReason,
- "Revocation Reason", level);
- } else {
- SECU_Indent (out_file, level);
- fprintf (out_file, "No Revocation Reason.n");
- }
- }
- static void
- print_cert_status (FILE *out_file, ocspCertStatus *status, int level)
- {
- SECU_Indent (out_file, level);
- fprintf (out_file, "Status: ");
- switch (status->certStatusType) {
- case ocspCertStatus_good:
- fprintf (out_file, "Cert is good.n");
- break;
- case ocspCertStatus_revoked:
- fprintf (out_file, "Cert has been revoked.n");
- print_revoked_info (out_file, status->certStatusInfo.revokedInfo,
- level + 1);
- break;
- case ocspCertStatus_unknown:
- fprintf (out_file, "Cert is unknown to responder.n");
- break;
- default:
- fprintf (out_file, "Unrecognized status.n");
- break;
- }
- }
- static void
- print_single_response (FILE *out_file, CERTOCSPSingleResponse *single,
- int level)
- {
- print_ocsp_cert_id (out_file, single->certID, level);
- print_cert_status (out_file, single->certStatus, level);
- SECU_PrintGeneralizedTime (out_file, &(single->thisUpdate),
- "This Update", level);
- if (single->nextUpdate != NULL) {
- SECU_PrintGeneralizedTime (out_file, single->nextUpdate,
- "Next Update", level);
- } else {
- SECU_Indent (out_file, level);
- fprintf (out_file, "No Next Updaten");
- }
- print_ocsp_extensions (out_file, single->singleExtensions,
- "Single Response Extensions", level);
- }
- static void
- print_responder_id (FILE *out_file, ocspResponderID *responderID, int level)
- {
- SECU_Indent (out_file, level);
- fprintf (out_file, "Responder ID ");
- switch (responderID->responderIDType) {
- case ocspResponderID_byName:
- fprintf (out_file, "(byName):n");
- SECU_PrintName (out_file, &(responderID->responderIDValue.name),
- "Name", level + 1);
- break;
- case ocspResponderID_byKey:
- fprintf (out_file, "(byKey):n");
- SECU_PrintAsHex (out_file, &(responderID->responderIDValue.keyHash),
- "Key Hash", level + 1);
- break;
- default:
- fprintf (out_file, "Unrecognized Responder ID Typen");
- break;
- }
- }
- static void
- print_response_data (FILE *out_file, ocspResponseData *responseData, int level)
- {
- SECU_Indent (out_file, level);
- fprintf (out_file, "Response Data:n");
- level++;
- print_ocsp_version (out_file, &(responseData->version), level);
- print_responder_id (out_file, responseData->responderID, level);
- SECU_PrintGeneralizedTime (out_file, &(responseData->producedAt),
- "Produced At", level);
- if (responseData->responses != NULL) {
- int i;
- for (i = 0; responseData->responses[i] != NULL; i++) {
- SECU_Indent (out_file, level);
- fprintf (out_file, "Response %d:n", i);
- print_single_response (out_file, responseData->responses[i],
- level + 1);
- }
- } else {
- fprintf (out_file, "Response list is empty.n");
- }
- print_ocsp_extensions (out_file, responseData->responseExtensions,
- "Response Extensions", level);
- }
- static void
- print_basic_response (FILE *out_file, ocspBasicOCSPResponse *basic, int level)
- {
- SECItem rawsig;
- SECU_Indent (out_file, level);
- fprintf (out_file, "Basic OCSP Response:n");
- level++;
- print_response_data (out_file, basic->tbsResponseData, level);
- SECU_PrintAlgorithmID (out_file,
- &(basic->responseSignature.signatureAlgorithm),
- "Signature Algorithm", level);
- rawsig = basic->responseSignature.signature;
- DER_ConvertBitString (&rawsig);
- SECU_PrintAsHex (out_file, &rawsig, "Signature", level);
- print_raw_certificates (out_file, basic->responseSignature.derCerts, level);
- }
- /*
- * Note this must match (exactly) the enumeration ocspResponseStatus.
- */
- static char *responseStatusNames[] = {
- "successful (Response has valid confirmations)",
- "malformedRequest (Illegal confirmation request)",
- "internalError (Internal error in issuer)",
- "tryLater (Try again later)",
- "unused ((4) is not used)",
- "sigRequired (Must sign the request)",
- "unauthorized (Request unauthorized)",
- "other (Status value out of defined range)"
- };
- /*
- * Decode the DER/BER-encoded item "data" as an OCSP response
- * and pretty-print the subfields.
- */
- static SECStatus
- print_response (FILE *out_file, SECItem *data, CERTCertDBHandle *handle)
- {
- CERTOCSPResponse *response;
- int level = 0;
- PORT_Assert (out_file != NULL);
- PORT_Assert (data != NULL);
- if (out_file == NULL || data == NULL) {
- PORT_SetError (SEC_ERROR_INVALID_ARGS);
- return SECFailure;
- }
- response = CERT_DecodeOCSPResponse (data);
- if (response == NULL)
- return SECFailure;
- PORT_Assert (response->statusValue <= ocspResponse_other);
- fprintf (out_file, "Response Status: %sn",
- responseStatusNames[response->statusValue]);
- if (response->statusValue == ocspResponse_successful) {
- ocspResponseBytes *responseBytes = response->responseBytes;
- SECStatus sigStatus;
- CERTCertificate *signerCert = NULL;
- PORT_Assert (responseBytes != NULL);
- level++;
- fprintf (out_file, "Response Bytes:n");
- SECU_PrintObjectID (out_file, &(responseBytes->responseType),
- "Response Type", level);
- switch (response->responseBytes->responseTypeTag) {
- case SEC_OID_PKIX_OCSP_BASIC_RESPONSE:
- print_basic_response (out_file,
- responseBytes->decodedResponse.basic,
- level);
- break;
- default:
- SECU_Indent (out_file, level);
- fprintf (out_file, "Unknown response syntaxn");
- break;
- }
- sigStatus = CERT_VerifyOCSPResponseSignature (response, handle,
- NULL, &signerCert);
- SECU_Indent (out_file, level);
- fprintf (out_file, "Signature verification ");
- if (sigStatus != SECSuccess) {
- fprintf (out_file, "failed: %sn", SECU_Strerror (PORT_GetError()));
- } else {
- fprintf (out_file, "succeeded.n");
- if (signerCert != NULL) {
- SECU_PrintName (out_file, &signerCert->subject, "Signer",
- level);
- CERT_DestroyCertificate (signerCert);
- } else {
- SECU_Indent (out_file, level);
- fprintf (out_file, "No signer cert returned?n");
- }
- }
- } else {
- SECU_Indent (out_file, level);
- fprintf (out_file, "Unsuccessful response, no more information.n");
- }
- CERT_DestroyOCSPResponse (response);
- return SECSuccess;
- }
- #endif /* NO_PP */
- static SECStatus
- cert_usage_from_char (const char *cert_usage_str, SECCertUsage *cert_usage)
- {
- PORT_Assert (cert_usage_str != NULL);
- PORT_Assert (cert_usage != NULL);
- if (PORT_Strlen (cert_usage_str) != 1)
- return SECFailure;
- switch (*cert_usage_str) {
- case 'c':
- *cert_usage = certUsageSSLClient;
- break;
- case 's':
- *cert_usage = certUsageSSLServer;
- break;
- case 'e':
- *cert_usage = certUsageEmailRecipient;
- break;
- case 'E':
- *cert_usage = certUsageEmailSigner;
- break;
- case 'S':
- *cert_usage = certUsageObjectSigner;
- break;
- case 'C':
- *cert_usage = certUsageVerifyCA;
- break;
- default:
- return SECFailure;
- }
- return SECSuccess;
- }
- int
- main (int argc, char **argv)
- {
- int retval;
- char *program_name;
- PRFileDesc *in_file;
- FILE *out_file; /* not PRFileDesc until SECU accepts it */
- int crequest, dresponse;
- int prequest, presponse;
- int ccert, vcert;
- const char *db_dir, *date_str, *cert_usage_str, *name;
- const char *responder_name, *responder_url, *signer_name;
- PRBool add_acceptable_responses, add_service_locator;
- SECItem *data = NULL;
- PLOptState *optstate;
- SECStatus rv;
- CERTCertDBHandle *handle = NULL;
- SECCertUsage cert_usage;
- int64 verify_time;
- retval = -1; /* what we return/exit with on error */
- program_name = PL_strrchr(argv[0], '/');
- program_name = program_name ? (program_name + 1) : argv[0];
- in_file = PR_STDIN;
- out_file = stdout;
- crequest = 0;
- dresponse = 0;
- prequest = 0;
- presponse = 0;
- ccert = 0;
- vcert = 0;
- db_dir = NULL;
- date_str = NULL;
- cert_usage_str = NULL;
- name = NULL;
- responder_name = NULL;
- responder_url = NULL;
- signer_name = NULL;
- add_acceptable_responses = PR_FALSE;
- add_service_locator = PR_FALSE;
- optstate = PL_CreateOptState (argc, argv, "AHLPR:S:V:d:l:pr:s:t:u:w:");
- if (optstate == NULL) {
- SECU_PrintError (program_name, "PL_CreateOptState failed");
- return retval;
- }
- while (PL_GetNextOpt (optstate) == PL_OPT_OK) {
- switch (optstate->option) {
- case '?':
- short_usage (program_name);
- return retval;
- case 'A':
- add_acceptable_responses = PR_TRUE;
- break;
- case 'H':
- long_usage (program_name);
- return retval;
- case 'L':
- add_service_locator = PR_TRUE;
- break;
- case 'P':
- presponse = 1;
- break;
- case 'R':
- dresponse = 1;
- name = optstate->value;
- break;
- case 'S':
- ccert = 1;
- name = optstate->value;
- break;
- case 'V':
- vcert = 1;
- name = optstate->value;
- break;
- case 'd':
- db_dir = optstate->value;
- break;
- case 'l':
- responder_url = optstate->value;
- break;
- case 'p':
- prequest = 1;
- break;
- case 'r':
- crequest = 1;
- name = optstate->value;
- break;
- case 's':
- signer_name = optstate->value;
- break;
- case 't':
- responder_name = optstate->value;
- break;
- case 'u':
- cert_usage_str = optstate->value;
- break;
- case 'w':
- date_str = optstate->value;
- break;
- }
- }
- if ((crequest + dresponse + prequest + presponse + ccert + vcert) != 1) {
- PR_fprintf (PR_STDERR, "%s: must specify exactly one commandnn",
- program_name);
- short_usage (program_name);
- return retval;
- }
- if (vcert) {
- if (cert_usage_str == NULL) {
- PR_fprintf (PR_STDERR, "%s: verification requires cert usagenn",
- program_name);
- short_usage (program_name);
- return retval;
- }
- rv = cert_usage_from_char (cert_usage_str, &cert_usage);
- if (rv != SECSuccess) {
- PR_fprintf (PR_STDERR, "%s: invalid cert usage ("%s")nn",
- program_name, cert_usage_str);
- long_usage (program_name);
- return retval;
- }
- }
- if (ccert + vcert) {
- if (responder_url != NULL || responder_name != NULL) {
- /*
- * To do a full status check, both the URL and the cert name
- * of the responder must be specified if either one is.
- */
- if (responder_url == NULL || responder_name == NULL) {
- if (responder_url == NULL)
- PR_fprintf (PR_STDERR,
- "%s: must also specify responder locationnn",
- program_name);
- else
- PR_fprintf (PR_STDERR,
- "%s: must also specify responder namenn",
- program_name);
- short_usage (program_name);
- return retval;
- }
- }
- if (date_str != NULL) {
- rv = DER_AsciiToTime (&verify_time, (char *) date_str);
- if (rv != SECSuccess) {
- SECU_PrintError (program_name, "error converting time string");
- PR_fprintf (PR_STDERR, "n");
- long_usage (program_name);
- return retval;
- }
- } else {
- verify_time = PR_Now();
- }
- }
- retval = -2; /* errors change from usage to runtime */
- /*
- * Initialize the NSPR and Security libraries.
- */
- PR_Init (PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
- db_dir = SECU_ConfigDirectory (db_dir);
- rv = NSS_Init (db_dir);
- if (rv != SECSuccess) {
- SECU_PrintError (program_name, "NSS_Init failed");
- goto prdone;
- }
- if (prequest + presponse) {
- data = read_file_into_item (in_file, siBuffer);
- if (data == NULL) {
- SECU_PrintError (program_name, "problem reading input");
- goto nssdone;
- }
- }
- if (crequest + dresponse + presponse + ccert + vcert) {
- handle = CERT_GetDefaultCertDB();
- if (handle == NULL) {
- SECU_PrintError (program_name, "problem getting certdb handle");
- goto nssdone;
- }
- /*
- * It would be fine to do the enable for all of these commands,
- * but this way we check that everything but an overall verify
- * can be done without it. That is, that the individual pieces
- * work on their own.
- */
- if (vcert) {
- rv = CERT_EnableOCSPChecking (handle);
- if (rv != SECSuccess) {
- SECU_PrintError (program_name, "error enabling OCSP checking");
- goto nssdone;
- }
- }
- if ((ccert + vcert) && (responder_name != NULL)) {
- rv = CERT_SetOCSPDefaultResponder (handle, responder_url,
- responder_name);
- if (rv != SECSuccess) {
- SECU_PrintError (program_name,
- "error setting default responder");
- goto nssdone;
- }
- rv = CERT_EnableOCSPDefaultResponder (handle);
- if (rv != SECSuccess) {
- SECU_PrintError (program_name,
- "error enabling default responder");
- goto nssdone;
- }
- }
- }
- #define NOTYET(opt)
- {
- PR_fprintf (PR_STDERR, "%s not yet workingn", opt);
- exit (-1);
- }
- if (crequest) {
- if (signer_name != NULL) {
- NOTYET("-s");
- }
- rv = create_request (out_file, handle, name, add_service_locator,
- add_acceptable_responses);
- } else if (dresponse) {
- if (signer_name != NULL) {
- NOTYET("-s");
- }
- rv = dump_response (out_file, handle, name, responder_url);
- } else if (prequest) {
- rv = print_request (out_file, data);
- } else if (presponse) {
- rv = print_response (out_file, data, handle);
- } else if (ccert) {
- if (signer_name != NULL) {
- NOTYET("-s");
- }
- rv = get_cert_status (out_file, handle, name, verify_time);
- } else if (vcert) {
- if (signer_name != NULL) {
- NOTYET("-s");
- }
- rv = verify_cert (out_file, handle, name, cert_usage, verify_time);
- }
- if (rv != SECSuccess)
- SECU_PrintError (program_name, "error performing requested operation");
- else
- retval = 0;
- nssdone:
- if (data != NULL) {
- SECITEM_FreeItem (data, PR_TRUE);
- }
- if (handle != NULL) {
- (void) CERT_DisableOCSPChecking (handle);
- CERT_ClosePermCertDB (handle);
- }
- NSS_Shutdown ();
- prdone:
- PR_Cleanup ();
- return retval;
- }