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]
#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
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;
}
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])
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");
}
- if (!print_ocsp_summary(out, bs, req, reqnames, ids))
+ if (!print_ocsp_summary(out, bs, req, reqnames, ids, nsec, maxage))
goto end;
ret = 0;
}
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;
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: ");
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);
#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
#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
#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
*/
#include <stdio.h>
+#include <time.h>
#include <cryptlib.h>
#include <openssl/objects.h>
#include <openssl/rand.h>
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)
{
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.
*/
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;
+ }
{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"},
{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"},
{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}