/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* * Test program for client-side OCSP.
*/
#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 */
pr_stderr = PR_STDERR;
synopsis(progname);
PR_fprintf(pr_stderr, "\nCommands (must specify exactly one):\n");
PR_fprintf(pr_stderr, " %-13s Pretty-print a binary request read from stdin\n", "-p");
PR_fprintf(pr_stderr, " %-13s Pretty-print a binary response read from stdin\n", "-P");
PR_fprintf(pr_stderr, " %-13s Create a request for cert \"nickname\" on stdout\n", "-r nickname");
PR_fprintf(pr_stderr, " %-13s Get response for cert \"nickname\", dump to stdout\n", "-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 check\n", "-V nickname");
PR_fprintf(pr_stderr, "\n %-10s also can be the name of the file with DER or\n" " %-13s PEM(use -a option) cert encoding\n", "nickname", "");
PR_fprintf(pr_stderr, "Options:\n");
PR_fprintf(pr_stderr, " %-13s Decode input cert from PEM format. DER is default\n", "-a");
PR_fprintf(pr_stderr, " %-13s Add the service locator extension to the request\n", "-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 responder\n", "-l location");
PR_fprintf(pr_stderr, " %-13s Trust cert \"nickname\" as response signer\n", "-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 Client\n", "");
PR_fprintf(pr_stderr, "%-17s s SSL Server\n", "");
PR_fprintf(pr_stderr, "%-17s I IPsec\n", "");
PR_fprintf(pr_stderr, "%-17s e Email Recipient\n", "");
PR_fprintf(pr_stderr, "%-17s E Email Signer\n", "");
PR_fprintf(pr_stderr, "%-17s S Object Signer\n", "");
PR_fprintf(pr_stderr, "%-17s C CA\n", "");
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");
}
#ifdefined(WIN32) /* We're going to write binary data to stdout, or read binary from stdin. * We must put stdout or stdin into O_BINARY mode or else outgoing \n's will become \r\n's, and incoming \r\n's will become \n's.
*/ static SECStatus
make_file_binary(FILE *binfile)
{ int smrv = _setmode(_fileno(binfile), _O_BINARY); if (smrv == -1) {
fprintf(stderr, "%s: Cannot change stdout to binary mode.\n",
program_name);
} return smrv;
} #define MAKE_FILE_BINARY make_file_binary #else #define MAKE_FILE_BINARY(file) #endif
/* * 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;
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;
} elseif (bytes_read == 0) { /* Something went wrong; we read nothing. But no system/nspr error. */ /* XXX Need to set an error here. */ goto loser;
} elseif (item->len != (unsignedint)bytes_read) { /* Something went wrong; we read less (or more!?) than we expected. */ /* XXX Need to set an error here. */ goto loser;
}
MAKE_FILE_BINARY(out_file); 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 (myCert != NULL)
CERT_DestroyCertificate(myCert);
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, CERTCertificate *cert, constchar *responder_url)
{
CERTCertList *certs = NULL;
CERTCertificate *myCert = NULL; char *loc = NULL;
PRTime now = PR_Now();
SECItem *response = NULL;
SECStatus rv = SECFailure;
PRBool includeServiceLocator;
if (handle == NULL || cert == NULL) return rv;
myCert = CERT_DupCertificate(cert); if (myCert == 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, myCert) != 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.
*/
myCert = NULL;
MAKE_FILE_BINARY(out_file); 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 (myCert != NULL)
CERT_DestroyCertificate(myCert); if (loc != NULL && loc != responder_url)
PORT_Free(loc);
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,
CERTCertificate *cert, constchar *cert_name,
PRTime verify_time)
{
SECStatus rv = SECFailure;
/* * 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, CERTCertificate *cert, constchar *cert_name, SECCertUsage cert_usage, PRTime verify_time)
{
SECStatus rv = SECFailure;
if (ascii == PR_FALSE) { /* by default need to check if there is cert nick is given */
cert = CERT_FindCertByNicknameOrEmailAddr(handle, (char *)name); if (cert != NULL) return cert;
}
/* * 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 requestorName\n");
} 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");
}
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;
}
}
/* * Note this must match (exactly) the enumeration ocspResponseStatus.
*/ staticchar *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)"
};
/* * 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;
if (response->statusValue >= ocspResponse_min &&
response->statusValue <= ocspResponse_max) {
fprintf(out_file, "Response Status: %s\n",
responseStatusNames[response->statusValue]);
} else {
fprintf(out_file, "Response Status: other (Status value %d out of defined range)\n",
(int)response->statusValue);
}
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 location\n\n",
program_name); else
PR_fprintf(PR_STDERR, "%s: must also specify responder name\n\n",
program_name);
short_usage(program_name); return retval;
}
}
/* * 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;
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.