Commit f1965221 authored by Dr. Stephen Henson's avatar Dr. Stephen Henson
Browse files

New function and options to check OCSP response validity.

parent 4ff18c8c
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -3,6 +3,17 @@

 Changes between 0.9.6 and 0.9.7  [xx XXX 2000]

  *) Add OCSP_check_validity() function to check the validity of OCSP
     responses. OCSP responses are prepared in real time and may only
     be a few seconds old. Simply checking that the current time lies
     between thisUpdate and nextUpdate max reject otherwise valid responses
     caused by either OCSP responder or client clock innacuracy. Instead
     we allow thisUpdate and nextUpdate to fall within a certain period of
     the current time. The age of the response can also optionally be
     checked. Two new options -validity_period and -status_age added to
     ocsp utility.
     [Steve Henson]

  *) If signature or public key algorithm is unrecognized print out its
     OID rather that just UNKOWN.
     [Steve Henson]
+52 −3
Original line number Diff line number Diff line
@@ -64,12 +64,16 @@
#include <openssl/ssl.h>
#include "apps.h"

/* Maximum leeway in validity period: default 5 minutes */
#define MAX_VALIDITY_PERIOD	(5 * 60)

static int add_ocsp_cert(OCSP_REQUEST **req, X509 *cert, X509 *issuer,
				STACK_OF(OCSP_CERTID) *ids);
static int add_ocsp_serial(OCSP_REQUEST **req, char *serial, X509 *issuer,
				STACK_OF(OCSP_CERTID) *ids);
static int print_ocsp_summary(BIO *out, OCSP_BASICRESP *bs, OCSP_REQUEST *req,
				STACK *names, STACK_OF(OCSP_CERTID) *ids);
				STACK *names, STACK_OF(OCSP_CERTID) *ids,
				long nsec, long maxage);

#undef PROG
#define PROG ocsp_main
@@ -94,6 +98,7 @@ int MAIN(int argc, char **argv)
	BIO *cbio = NULL, *derbio = NULL;
	BIO *out = NULL;
	int req_text = 0, resp_text = 0;
	long nsec = MAX_VALIDITY_PERIOD, maxage = -1;
	char *CAfile = NULL, *CApath = NULL;
	X509_STORE *store = NULL;
	SSL_CTX *ctx = NULL;
@@ -247,6 +252,38 @@ int MAIN(int argc, char **argv)
				}
			else badarg = 1;
			}
		else if (!strcmp (*args, "-validity_period"))
			{
			if (args[1])
				{
				args++;
				nsec = atol(*args);
				if (nsec < 0)
					{
					BIO_printf(bio_err,
						"Illegal validity period %s\n",
						*args);
					badarg = 1;
					}
				}
			else badarg = 1;
			}
		else if (!strcmp (*args, "-status_age"))
			{
			if (args[1])
				{
				args++;
				maxage = atol(*args);
				if (maxage < 0)
					{
					BIO_printf(bio_err,
						"Illegal validity age %s\n",
						*args);
					badarg = 1;
					}
				}
			else badarg = 1;
			}
		 else if (!strcmp(*args, "-signkey"))
			{
			if (args[1])
@@ -356,6 +393,8 @@ int MAIN(int argc, char **argv)
		BIO_printf (bio_err, "-CApath dir        trusted certificates directory\n");
		BIO_printf (bio_err, "-CAfile file       trusted certificates file\n");
		BIO_printf (bio_err, "-VAfile file       validator certificates file\n");
		BIO_printf (bio_err, "-validity_period n maximum validity discrepancy in seconds\n");
		BIO_printf (bio_err, "-status_age n      maximum status age in seconds\n");
		BIO_printf (bio_err, "-noverify          don't verify response at all\n");
		BIO_printf (bio_err, "-verify_certs file additional certificates to search for signer\n");
		BIO_printf (bio_err, "-trust_other       don't verify additional certificates\n");
@@ -564,7 +603,7 @@ int MAIN(int argc, char **argv)

		}

	if (!print_ocsp_summary(out, bs, req, reqnames, ids))
	if (!print_ocsp_summary(out, bs, req, reqnames, ids, nsec, maxage))
		goto end;

	ret = 0;
@@ -652,7 +691,8 @@ static int add_ocsp_serial(OCSP_REQUEST **req, char *serial, X509 *issuer,
	}

static int print_ocsp_summary(BIO *out, OCSP_BASICRESP *bs, OCSP_REQUEST *req,
					STACK *names, STACK_OF(OCSP_CERTID) *ids)
					STACK *names, STACK_OF(OCSP_CERTID) *ids,
					long nsec, long maxage)
	{
	OCSP_CERTID *id;
	char *name;
@@ -677,6 +717,15 @@ static int print_ocsp_summary(BIO *out, OCSP_BASICRESP *bs, OCSP_REQUEST *req,
			BIO_puts(out, "ERROR: No Status found.\n");
			continue;
			}

		/* Check validity: if invalid write to output BIO so we
		 * know which response this refers to.
		 */
		if (!OCSP_check_validity(thisupd, nextupd, nsec, maxage))
			{
			BIO_puts(out, "WARNING: Status times invalid.\n");
			ERR_print_errors(out);
			}
		BIO_printf(out, "%s\n", OCSP_cert_status_str(status));

		BIO_puts(out, "\tThis Update: ");
+10 −0
Original line number Diff line number Diff line
@@ -444,6 +444,9 @@ int OCSP_resp_find_status(OCSP_BASICRESP *bs, OCSP_CERTID *id, int *status,
				ASN1_GENERALIZEDTIME **revtime,
				ASN1_GENERALIZEDTIME **thisupd,
				ASN1_GENERALIZEDTIME **nextupd);
int OCSP_check_validity(ASN1_GENERALIZEDTIME *thisupd,
			ASN1_GENERALIZEDTIME *nextupd,
			long sec, long maxsec);

int OCSP_request_verify(OCSP_REQUEST *req, EVP_PKEY *pkey);

@@ -569,6 +572,7 @@ void ERR_load_OCSP_strings(void);
#define OCSP_F_OCSP_CHECK_DELEGATED			 106
#define OCSP_F_OCSP_CHECK_IDS				 107
#define OCSP_F_OCSP_CHECK_ISSUER			 108
#define OCSP_F_OCSP_CHECK_VALIDITY			 115
#define OCSP_F_OCSP_MATCH_ISSUERID			 109
#define OCSP_F_OCSP_PARSE_URL				 114
#define OCSP_F_OCSP_REQUEST_SIGN			 110
@@ -580,8 +584,11 @@ void ERR_load_OCSP_strings(void);
#define OCSP_R_BAD_DATA					 100
#define OCSP_R_CERTIFICATE_VERIFY_ERROR			 101
#define OCSP_R_DIGEST_ERR				 102
#define OCSP_R_ERROR_IN_NEXTUPDATE_FIELD		 122
#define OCSP_R_ERROR_IN_THISUPDATE_FIELD		 123
#define OCSP_R_ERROR_PARSING_URL			 121
#define OCSP_R_MISSING_OCSPSIGNING_USAGE		 103
#define OCSP_R_NEXTUPDATE_BEFORE_THISUPDATE		 124
#define OCSP_R_NOT_BASIC_RESPONSE			 104
#define OCSP_R_NO_CERTIFICATES_IN_CHAIN			 105
#define OCSP_R_NO_CONTENT				 106
@@ -597,6 +604,9 @@ void ERR_load_OCSP_strings(void);
#define OCSP_R_SERVER_WRITE_ERROR			 116
#define OCSP_R_SIGNATURE_FAILURE			 117
#define OCSP_R_SIGNER_CERTIFICATE_NOT_FOUND		 118
#define OCSP_R_STATUS_EXPIRED				 125
#define OCSP_R_STATUS_NOT_YET_VALID			 126
#define OCSP_R_STATUS_TOO_OLD				 127
#define OCSP_R_UNKNOWN_MESSAGE_DIGEST			 119
#define OCSP_R_UNKNOWN_NID				 120

+70 −2
Original line number Diff line number Diff line
@@ -62,6 +62,7 @@
 */

#include <stdio.h>
#include <time.h>
#include <cryptlib.h>
#include <openssl/objects.h>
#include <openssl/rand.h>
@@ -259,8 +260,9 @@ int OCSP_single_get0_status(OCSP_SINGLERESP *single, int *reason,
				ASN1_GENERALIZEDTIME **nextupd)
	{
	int ret;
	OCSP_CERTSTATUS *cst = single->certStatus;
	OCSP_CERTSTATUS *cst;
	if(!single) return -1;
	cst = single->certStatus;
	ret = cst->type;
	if (ret == V_OCSP_CERTSTATUS_REVOKED)
		{
@@ -278,7 +280,7 @@ int OCSP_single_get0_status(OCSP_SINGLERESP *single, int *reason,
	return ret;
	}

/* This function combines the previous ones: look a certificate ID and
/* This function combines the previous ones: look up a certificate ID and
 * if found extract status information. Return 0 is successful.
 */

@@ -299,4 +301,70 @@ int OCSP_resp_find_status(OCSP_BASICRESP *bs, OCSP_CERTID *id, int *status,
	return 1;
	}

/* Check validity of thisUpdate and nextUpdate fields. It is possible that the request will
 * take a few seconds to process and/or the time wont be totally accurate. Therefore to avoid
 * rejecting otherwise valid time we allow the times to be within 'nsec' of the current time.
 * Also to avoid accepting very old responses without a nextUpdate field an optional maxage
 * parameter specifies the maximum age the thisUpdate field can be.
 */

int OCSP_check_validity(ASN1_GENERALIZEDTIME *thisupd, ASN1_GENERALIZEDTIME *nextupd, long nsec, long maxsec)
	{
	int ret = 1;
	time_t t_now, t_tmp;
	time(&t_now);
	/* Check thisUpdate is valid and not more than nsec in the future */
	if (!ASN1_GENERALIZEDTIME_check(thisupd))
		{
		OCSPerr(OCSP_F_OCSP_CHECK_VALIDITY, OCSP_R_ERROR_IN_THISUPDATE_FIELD);
		ret = 0;
		}
	else 
		{
			t_tmp = t_now + nsec;
			if (X509_cmp_time(thisupd, &t_tmp) > 0)
			{
			OCSPerr(OCSP_F_OCSP_CHECK_VALIDITY, OCSP_R_STATUS_NOT_YET_VALID);
			ret = 0;
			}

		/* If maxsec specified check thisUpdate is not more than maxsec in the past */
		if (maxsec >= 0)
			{
			t_tmp = t_now - maxsec;
			if (X509_cmp_time(thisupd, &t_tmp) < 0)
				{
				OCSPerr(OCSP_F_OCSP_CHECK_VALIDITY, OCSP_R_STATUS_TOO_OLD);
				ret = 0;
				}
			}
		}
		

	if (!nextupd) return ret;

	/* Check nextUpdate is valid and not more than nsec in the past */
	if (!ASN1_GENERALIZEDTIME_check(nextupd))
		{
		OCSPerr(OCSP_F_OCSP_CHECK_VALIDITY, OCSP_R_ERROR_IN_NEXTUPDATE_FIELD);
		ret = 0;
		}
	else 
		{
		t_tmp = t_now - nsec;
		if (X509_cmp_time(nextupd, &t_tmp) < 0)
			{
			OCSPerr(OCSP_F_OCSP_CHECK_VALIDITY, OCSP_R_STATUS_EXPIRED);
			ret = 0;
			}
		}

	/* Also don't allow nextUpdate to precede thisUpdate */
	if (ASN1_STRING_cmp(nextupd, thisupd) < 0)
		{
		OCSPerr(OCSP_F_OCSP_CHECK_VALIDITY, OCSP_R_NEXTUPDATE_BEFORE_THISUPDATE);
		ret = 0;
		}

	return ret;
	}
+7 −0
Original line number Diff line number Diff line
@@ -75,6 +75,7 @@ static ERR_STRING_DATA OCSP_str_functs[]=
{ERR_PACK(0,OCSP_F_OCSP_CHECK_DELEGATED,0),	"OCSP_CHECK_DELEGATED"},
{ERR_PACK(0,OCSP_F_OCSP_CHECK_IDS,0),	"OCSP_CHECK_IDS"},
{ERR_PACK(0,OCSP_F_OCSP_CHECK_ISSUER,0),	"OCSP_CHECK_ISSUER"},
{ERR_PACK(0,OCSP_F_OCSP_CHECK_VALIDITY,0),	"OCSP_check_validity"},
{ERR_PACK(0,OCSP_F_OCSP_MATCH_ISSUERID,0),	"OCSP_MATCH_ISSUERID"},
{ERR_PACK(0,OCSP_F_OCSP_PARSE_URL,0),	"OCSP_parse_url"},
{ERR_PACK(0,OCSP_F_OCSP_REQUEST_SIGN,0),	"OCSP_request_sign"},
@@ -89,8 +90,11 @@ static ERR_STRING_DATA OCSP_str_reasons[]=
{OCSP_R_BAD_DATA                         ,"bad data"},
{OCSP_R_CERTIFICATE_VERIFY_ERROR         ,"certificate verify error"},
{OCSP_R_DIGEST_ERR                       ,"digest err"},
{OCSP_R_ERROR_IN_NEXTUPDATE_FIELD        ,"error in nextupdate field"},
{OCSP_R_ERROR_IN_THISUPDATE_FIELD        ,"error in thisupdate field"},
{OCSP_R_ERROR_PARSING_URL                ,"error parsing url"},
{OCSP_R_MISSING_OCSPSIGNING_USAGE        ,"missing ocspsigning usage"},
{OCSP_R_NEXTUPDATE_BEFORE_THISUPDATE     ,"nextupdate before thisupdate"},
{OCSP_R_NOT_BASIC_RESPONSE               ,"not basic response"},
{OCSP_R_NO_CERTIFICATES_IN_CHAIN         ,"no certificates in chain"},
{OCSP_R_NO_CONTENT                       ,"no content"},
@@ -106,6 +110,9 @@ static ERR_STRING_DATA OCSP_str_reasons[]=
{OCSP_R_SERVER_WRITE_ERROR               ,"server write error"},
{OCSP_R_SIGNATURE_FAILURE                ,"signature failure"},
{OCSP_R_SIGNER_CERTIFICATE_NOT_FOUND     ,"signer certificate not found"},
{OCSP_R_STATUS_EXPIRED                   ,"status expired"},
{OCSP_R_STATUS_NOT_YET_VALID             ,"status not yet valid"},
{OCSP_R_STATUS_TOO_OLD                   ,"status too old"},
{OCSP_R_UNKNOWN_MESSAGE_DIGEST           ,"unknown message digest"},
{OCSP_R_UNKNOWN_NID                      ,"unknown nid"},
{0,NULL}