New function and options to check OCSP response validity.

This commit is contained in:
Dr. Stephen Henson 2001-02-24 13:50:06 +00:00
parent 4ff18c8c3e
commit f196522159
5 changed files with 150 additions and 5 deletions

11
CHANGES
View File

@ -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]

View File

@ -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: ");

View File

@ -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

View File

@ -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;
}

View File

@ -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}