I'd like to propose an enhancement I've worked on recently: integrating OCSP and CRL revocation checks when verifying a certificate using X509_STORE. It does not break compatibility with the existing mechanism, it just adds additonal parameters to allow OCSP revocation checking as an opt-in feature.
I added the features based on the sources in HEAD, so I'm not sure if and how far this could be backported. I already apologize for the long mail, but I wanted to explain my motivations to make reviewing the code easier, and also to make it easier to spot mistakes I made. The main motivation was to add OCSP support to the verification process and to minimize the implementation effort for clients by providing them an implementation that a) covers most cases (particularly web SSL/TLS connections) and b) minimizes the PKI expertise needed. Client implementation effort is now reduced to simply providing two callbacks that are solely responsible of downloading either a CRL or the OCSP response from a given URL (and sending the request data in the OCSP case). Once HTTP is supported, default implementations for those two callbacks could also be added. Overview of new features: CRL integration: - in addition to the already existing get_crl callback (that was set to NULL by default), a dl_crl callback is added and there is a default implementation for get_crl. This default implementation tries to look up a download URL in the CRL distribution points of the current certificate. If it finds one, it passes the URL to the dl_crl callback (NULL by default, has to be provided by the client); i.e. dl_crl is responsible of downloading the CRL and passing it back. OCSP integration: - can be turned on with the flag X509_V_FLAG_OCSP_CHECK. Semantics are that whenever a CRL check would be made for a certificate, the default implementation tries to check via OCSP first. This can have three possible outcomes: 1. The certificate is valid 2. The certificate is revoked 3. The certificate has status UNKNOWN, an error occurs while trying to validate via OCSP, or the OCSP response is invalid In case 3, the implementation falls back to CRL, i.e. it tries to check revocation via the existing CRL mechanism. In case 1, CRL validation is skipped, since we can already be sure of the certificate's validity. Case 2 is the same except that we can be sure of the certificate's revocation. - OCSP is controlled using the new structure X509_OCSP_CTX which can be set for X509_STORE and X509_STORE_CTX. X509_OCSP_CTX contains OCSP flags (those already existing for the present OCSP code) and various callback methods: 1. dl_ocsp: similar to dl_crl - takes a URL and is simply responsible of retrieving the OCSP_RESPONSE by sending the OCSP_REQUEST to a specific URL. NULL by default, must be set and implemented by the client. 2. get_ocsp: Again similar to get_crl. Tries to look up a valid OCSP URL in the certificate's AuthorityAccessInformation extension. If found, the default implementation delegates to dl_ocsp. 3. check_ocsp: Responsible of verifying a OCSP_RESPONSE with respect to a given certificate, issuer certificate and OCSP_REQUEST. Default implementation exists. Additionally, there are fields to support signed OCSP requests and a stack of X509 to represent "authorized responders", i.e. to allow support of the authorized responder approach mentioned in RFC 2560. There are a few things I noticed in the existing implementation that seemed strange and that I changed. Please correct me if my thoughts were wrong: In File x509_vfy.c 1. If a "get_crl" callback is set in the X509_STORE(_CTX), then there seem to be some complications with the existing workflow. a) current_crl_score and current_reasons are never explicitly set to a default value in X509_STORE_CTX_init. I explicitly set them to 0 on initialization. b. In "static int check_cert(X509_STORE_CTX *ctx)". There's the lines: if (ctx->get_crl) ok = ctx->get_crl(ctx, &crl, x); else ok = get_crl_delta(ctx, &crl, &dcrl, x); I made this: if (ctx->get_crl) { ok = ctx->get_crl(ctx, &crl, x); if (ok) { /* add crl to ctx->crls, so that it will get considered in get_crl_delta */ } } ok = get_crl_delta(ctx, &crl, &dcrl, x); Otherwise you will inevitably run into an error in check_crl for the current_crl_score checks; current_reasons is never set to CRLDP_ALL_REASONS. This might cause an infinite loop if you set the current_crl_score appropriately in your own get_crl callback but forget to set current_reasons. If the above code snippet is applied, current_crl_score and current_reasons are updated correctly and the CRL download will fit nicely in the existing workflow. 2. static int check_revocation(X509_STORE_CTX *ctx): There's if (ctx->param->flags & X509_V_FLAG_CRL_CHECK_ALL) last = sk_X509_num(ctx->chain) - 1; shouldn't it be if (ctx->param->flags & X509_V_FLAG_CRL_CHECK_ALL) last = sk_X509_num(ctx->chain) - 2; We already have a chain with a trusted anchor certificate at the point when we enter revocation checking. Additionally, if the anchor happens to be a self-signed certificate, it's very unlikely to find a CRL for this certificate and you will run into an error. In file ocsp_vfy.c: int OCSP_basic_verify(OCSP_BASICRESP *bs, STACK_OF(X509) *certs, X509_STORE *st, unsigned long flags): Upon verification of an OCSP_BASICRESP, there's the lines: if(flags & OCSP_NOCHAIN) init_res = X509_STORE_CTX_init(&ctx, st, signer, NULL); else init_res = X509_STORE_CTX_init(&ctx, st, signer, bs->certs); The else case seems insufficient. Imagine the case where the CA just adds the OCSP signing certificate and no intermediate certificates. Then the existing call is doomed to fail. I changed this to add not only bs->certs, but also the certificates already available in certs, as they possibly contain the necessary intermediate certificates. Thanks in advance for any comments and corrections! Best regards, Martin Boßlet
Index: crypto/ossl_typ.h =================================================================== RCS file: /v/openssl/cvs/openssl/crypto/ossl_typ.h,v retrieving revision 1.24 diff -u -r1.24 ossl_typ.h --- crypto/ossl_typ.h 13 Dec 2010 18:15:27 -0000 1.24 +++ crypto/ossl_typ.h 30 Dec 2010 01:13:12 -0000 @@ -197,7 +197,11 @@ int idx, long argl, void *argp); typedef struct ocsp_req_ctx_st OCSP_REQ_CTX; +typedef struct ocsp_request_st OCSP_REQUEST; typedef struct ocsp_response_st OCSP_RESPONSE; +typedef struct ocsp_basic_response_st OCSP_BASICRESP; typedef struct ocsp_responder_id_st OCSP_RESPID; +typedef struct x509_ocsp_ctx_st X509_OCSP_CTX; + #endif /* def HEADER_OPENSSL_TYPES_H */ Index: crypto/ocsp/ocsp.h =================================================================== RCS file: /v/openssl/cvs/openssl/crypto/ocsp/ocsp.h,v retrieving revision 1.42 diff -u -r1.42 ocsp.h --- crypto/ocsp/ocsp.h 30 Sep 2009 21:40:55 -0000 1.42 +++ crypto/ocsp/ocsp.h 30 Dec 2010 01:13:13 -0000 @@ -88,7 +88,8 @@ #define OCSP_NOCHECKS 0x100 #define OCSP_TRUSTOTHER 0x200 #define OCSP_RESPID_KEY 0x400 -#define OCSP_NOTIME 0x800 +#define OCSP_NOTIME 0x800 +#define OCSP_NONONCE 0x1000 /* CertID ::= SEQUENCE { * hashAlgorithm AlgorithmIdentifier, @@ -150,11 +151,11 @@ * tbsRequest TBSRequest, * optionalSignature [0] EXPLICIT Signature OPTIONAL } */ -typedef struct ocsp_request_st +struct ocsp_request_st { OCSP_REQINFO *tbsRequest; OCSP_SIGNATURE *optionalSignature; /* OPTIONAL */ - } OCSP_REQUEST; + } /* OCSP_REQUEST */; /* OCSPResponseStatus ::= ENUMERATED { * successful (0), --Response has valid confirmations @@ -300,13 +301,13 @@ that it doesn't do the double hashing that the RFC seems to say one should. Therefore, all relevant functions take a flag saying which variant should be used. -- Richard Levitte, OpenSSL team and CeloCom */ -typedef struct ocsp_basic_response_st +struct ocsp_basic_response_st { OCSP_RESPDATA *tbsResponseData; X509_ALGOR *signatureAlgorithm; ASN1_BIT_STRING *signature; STACK_OF(X509) *certs; - } OCSP_BASICRESP; + } /* OCSP_BASICRESP */; /* * CRLReason ::= ENUMERATED { @@ -555,6 +556,8 @@ int OCSP_basic_verify(OCSP_BASICRESP *bs, STACK_OF(X509) *certs, X509_STORE *st, unsigned long flags); +int OCSP_basic_find_signer(X509 **psigner, OCSP_BASICRESP *bs, STACK_OF(X509) *certs, + unsigned long flags); /* BEGIN ERROR CODES */ /* The following lines are auto generated by the script mkerr.pl. Any changes Index: crypto/ocsp/ocsp_vfy.c =================================================================== RCS file: /v/openssl/cvs/openssl/crypto/ocsp/ocsp_vfy.c,v retrieving revision 1.16 diff -u -r1.16 ocsp_vfy.c --- crypto/ocsp/ocsp_vfy.c 29 Dec 2008 16:11:55 -0000 1.16 +++ crypto/ocsp/ocsp_vfy.c 30 Dec 2010 01:13:13 -0000 @@ -60,8 +60,6 @@ #include <openssl/err.h> #include <string.h> -static int ocsp_find_signer(X509 **psigner, OCSP_BASICRESP *bs, STACK_OF(X509) *certs, - X509_STORE *st, unsigned long flags); static X509 *ocsp_find_signer_sk(STACK_OF(X509) *certs, OCSP_RESPID *id); static int ocsp_check_issuer(OCSP_BASICRESP *bs, STACK_OF(X509) *chain, unsigned long flags); static int ocsp_check_ids(STACK_OF(OCSP_SINGLERESP) *sresp, OCSP_CERTID **ret); @@ -77,9 +75,10 @@ { X509 *signer, *x; STACK_OF(X509) *chain = NULL; + STACK_OF(X509) *intermediates = NULL; X509_STORE_CTX ctx; int i, ret = 0; - ret = ocsp_find_signer(&signer, bs, certs, st, flags); + ret = OCSP_basic_find_signer(&signer, bs, certs, flags); if (!ret) { OCSPerr(OCSP_F_OCSP_BASIC_VERIFY, OCSP_R_SIGNER_CERTIFICATE_NOT_FOUND); @@ -105,7 +104,25 @@ if(flags & OCSP_NOCHAIN) init_res = X509_STORE_CTX_init(&ctx, st, signer, NULL); else - init_res = X509_STORE_CTX_init(&ctx, st, signer, bs->certs); + { + if (!(intermediates = sk_X509_dup(bs->certs))) + { + OCSPerr(OCSP_F_OCSP_BASIC_VERIFY,ERR_R_X509_LIB); + goto end; + } + if (certs) + { + for (i=0; i < sk_X509_num(certs); i++) + { + if (!(sk_X509_push(intermediates, sk_X509_value(certs, i)))) + { + OCSPerr(OCSP_F_OCSP_BASIC_VERIFY,ERR_R_X509_LIB); + goto end; + } + } + } + init_res = X509_STORE_CTX_init(&ctx, st, signer, intermediates); + } if(!init_res) { OCSPerr(OCSP_F_OCSP_BASIC_VERIFY,ERR_R_X509_LIB); @@ -155,16 +172,17 @@ end: if(chain) sk_X509_pop_free(chain, X509_free); + if (intermediates) sk_X509_free(intermediates); /* free stack only, leave certs */ return ret; } -static int ocsp_find_signer(X509 **psigner, OCSP_BASICRESP *bs, STACK_OF(X509) *certs, - X509_STORE *st, unsigned long flags) +int OCSP_basic_find_signer(X509 **psigner, OCSP_BASICRESP *bs, STACK_OF(X509) *certs, + unsigned long flags) { X509 *signer; OCSP_RESPID *rid = bs->tbsResponseData->responderId; - if ((signer = ocsp_find_signer_sk(certs, rid))) + if (certs && (signer = ocsp_find_signer_sk(certs, rid))) { *psigner = signer; return 2; Index: crypto/x509/x509.h =================================================================== RCS file: /v/openssl/cvs/openssl/crypto/x509/x509.h,v retrieving revision 1.172 diff -u -r1.172 x509.h --- crypto/x509/x509.h 3 Oct 2010 18:58:09 -0000 1.172 +++ crypto/x509/x509.h 30 Dec 2010 01:13:14 -0000 @@ -1257,6 +1257,7 @@ #define X509_F_X509_STORE_CTX_GET1_ISSUER 146 #define X509_F_X509_STORE_CTX_INIT 143 #define X509_F_X509_STORE_CTX_NEW 142 +#define X509_F_X509_OCSP_CTX_NEW 199 #define X509_F_X509_STORE_CTX_PURPOSE_INHERIT 134 #define X509_F_X509_TO_X509_REQ 126 #define X509_F_X509_TRUST_ADD 133 @@ -1291,6 +1292,8 @@ #define X509_R_WRONG_LOOKUP_TYPE 112 #define X509_R_WRONG_TYPE 122 + + #ifdef __cplusplus } #endif Index: crypto/x509/x509_lu.c =================================================================== RCS file: /v/openssl/cvs/openssl/crypto/x509/x509_lu.c,v retrieving revision 1.34 diff -u -r1.34 x509_lu.c --- crypto/x509/x509_lu.c 19 Feb 2010 18:27:07 -0000 1.34 +++ crypto/x509/x509_lu.c 30 Dec 2010 01:13:15 -0000 @@ -200,6 +200,8 @@ ret->lookup_crls = 0; ret->cleanup = 0; + ret->ocsp_ctx = NULL; + if (!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_X509_STORE, ret, &ret->ex_data)) { sk_X509_OBJECT_free(ret->objs); @@ -248,6 +250,8 @@ sk_X509_LOOKUP_free(sk); sk_X509_OBJECT_pop_free(vfy->objs, cleanup); + if (vfy->ocsp_ctx) X509_OCSP_CTX_free(vfy->ocsp_ctx); + CRYPTO_free_ex_data(CRYPTO_EX_INDEX_X509_STORE, vfy, &vfy->ex_data); if (vfy->param) X509_VERIFY_PARAM_free(vfy->param); Index: crypto/x509/x509_txt.c =================================================================== RCS file: /v/openssl/cvs/openssl/crypto/x509/x509_txt.c,v retrieving revision 1.25 diff -u -r1.25 x509_txt.c --- crypto/x509/x509_txt.c 25 Dec 2010 20:45:58 -0000 1.25 +++ crypto/x509/x509_txt.c 30 Dec 2010 01:13:15 -0000 @@ -186,6 +186,43 @@ case X509_V_ERR_PATH_LOOP: return("Path Loop"); + case X509_V_ERR_ERROR_IN_OCSP_PRODUCED_AT_FIELD: + return("format error in OCSP producedAt field"); + case X509_V_ERR_ERROR_IN_OCSP_THIS_UPDATE_FIELD: + return("format error in OCSP thisUpdate field"); + case X509_V_ERR_ERROR_IN_OCSP_NEXT_UPDATE_FIELD: + return("format error in OCSP nextUpdate field"); + case X509_V_ERR_OCSP_NOT_YET_VALID: + return("OCSP response is not valid yet"); + case X509_V_ERR_OCSP_HAS_EXPIRED: + return("OCSP response has expired"); + case X509_V_ERR_UNABLE_TO_FIND_AIA: + return("unable to find AuthorityInformationAccess extension in certificate"); + case X509_V_ERR_UNABLE_TO_FIND_AIA_URL: + return("unable to find OCSP URL in AuthorityInformationAccess extension"); + case X509_V_ERR_ERROR_RETRIEVING_OCSP_RESPONSE: + return("error retrieving the OCSP response remotely"); + case X509_V_ERR_OCSP_RESPONSE_NOT_SUCCESSFUL: + return("OCSP response had a status other than SUCCESSFUL"); + case X509_V_ERR_OCSP_SIGNATURE_FAILURE: + return("error when validating the OCSP signature"); + case X509_V_ERR_OCSP_UNSUPPORTED_MULTIPLE_RESP: + return("multiple OCSP certIDs are not supported"); + case X509_V_ERR_OCSP_CERT_ID_MISMATCH: + return("certID in OCSP request differs from that in response"); + case X509_V_ERR_OCSP_NONCE_MISMATCH: + return("nonces differ in OCSP request and response"); + case X509_V_ERR_UNABLE_TO_FIND_CRL_DPS: + return("unable to find cRLDistributionPoint extension in certificate"); + case X509_V_ERR_UNABLE_TO_FIND_CRL_DP_URL: + return("unable to find CRL URL in cRLDistributionPoint extension"); + case X509_V_ERR_ERROR_RETRIEVING_CRL: + return("error retrieving the CRL remotely"); + case X509_V_ERR_OCSP_SIGNING_CERT_NOT_FOUND: + return("could not find OCSP signing certificate"); + case X509_V_ERR_OCSP_CERT_ISSUER_NOT_TRUSTED: + return("OCSP certificate issuer is not trusted"); + default: BIO_snprintf(buf,sizeof buf,"error number %ld",n); return(buf); Index: crypto/x509/x509_vfy.c =================================================================== RCS file: /v/openssl/cvs/openssl/crypto/x509/x509_vfy.c,v retrieving revision 1.119 diff -u -r1.119 x509_vfy.c --- crypto/x509/x509_vfy.c 25 Dec 2010 20:45:58 -0000 1.119 +++ crypto/x509/x509_vfy.c 30 Dec 2010 01:13:16 -0000 @@ -69,6 +69,9 @@ #include <openssl/x509.h> #include <openssl/x509v3.h> #include <openssl/objects.h> +#include <openssl/ocsp.h> +#include <openssl/ssl.h> +#include <openssl/x509_vfy.h> /* CRL score values */ @@ -118,6 +121,7 @@ static int check_cert(X509_STORE_CTX *ctx); static int check_policy(X509_STORE_CTX *ctx); +static int get_crl(X509_STORE_CTX *ctx, X509_CRL **pcrl, X509 *x); static int get_crl_score(X509_STORE_CTX *ctx, X509 **pissuer, unsigned int *preasons, X509_CRL *crl, X509 *x); @@ -134,6 +138,19 @@ STACK_OF(X509) *cert_path, STACK_OF(X509) *crl_path); +static int check_cert_ocsp(X509_STORE_CTX *ctx, X509* x, X509 *xi); +static int check_ocsp(X509_STORE_CTX *ctx, + OCSP_REQUEST *request, + OCSP_RESPONSE *ocsp, + X509 *x, + X509 *issuer); +static int check_ocsp_times(X509_STORE_CTX *ctx, OCSP_BASICRESP *ocsp); +static int get_ocsp(X509_STORE_CTX *ctx, + OCSP_REQUEST **request, + OCSP_RESPONSE **ocsp, + X509 *x, + X509 *issuer); + static int internal_verify(X509_STORE_CTX *ctx); const char X509_version[]="X.509" OPENSSL_VERSION_PTEXT; @@ -719,7 +736,8 @@ if (!(ctx->param->flags & X509_V_FLAG_CRL_CHECK)) return 1; if (ctx->param->flags & X509_V_FLAG_CRL_CHECK_ALL) - last = sk_X509_num(ctx->chain) - 1; + /* do not check the root of the chain, it's trusted already */ + last = sk_X509_num(ctx->chain) - 2; else { /* If checking CRL paths this isn't the EE certificate */ @@ -736,23 +754,98 @@ return 1; } +/* Returns + * 0 if an error occurs or if the certificate has a status of UNKNOWN (i.e. + * we want to use CRL information as a fallback) + * 1 if the response was valid and the certificate is also (i.e. we can skip + * CRL lookup) + * -1 if the certificate is revoked (i.e. we can also skip CRL lookup) + */ +static int check_cert_ocsp(X509_STORE_CTX *ctx, X509* x, X509 *xi) + { + OCSP_REQUEST *req = NULL; + OCSP_RESPONSE *resp = NULL; + int ok = 0; + + /* skip if OCSP checking was not requested or the retrieval method + is missing + */ + if(!(ctx->ocsp_ctx->get_ocsp)) + return 0; + if (!(ok = ctx->ocsp_ctx->get_ocsp(ctx, &req, &resp, x, xi))) + goto end; + + ctx->current_ocsp = OCSP_response_get1_basic(resp); + ok = ctx->ocsp_ctx->check_ocsp(ctx, req, resp, x, xi); + +end: + ctx->current_ocsp = NULL; + if (req) OCSP_REQUEST_free(req); + if (resp) OCSP_RESPONSE_free(resp); + if (!ok) + { + ok = ctx->verify_cb(0, ctx); + } + return ok; + } + static int check_cert(X509_STORE_CTX *ctx) { - X509_CRL *crl = NULL, *dcrl = NULL; - X509 *x; + X509_CRL *crl = NULL, *dcrl = NULL; + X509 *x, *xi; int ok, cnum; cnum = ctx->error_depth; x = sk_X509_value(ctx->chain, cnum); + xi = sk_X509_value(ctx->chain, cnum + 1); ctx->current_cert = x; ctx->current_issuer = NULL; ctx->current_reasons = 0; + + if (ctx->param->flags & X509_V_FLAG_OCSP_CHECK) + { + ok = check_cert_ocsp(ctx, x, xi); + if (ok == 1) /* certificate is valid, skip CRLs */ + goto err; + if (ok == -1) /* certificate is revoked, skip CRLs */ + { + ctx->error = X509_V_ERR_CERT_REVOKED; + ok = 0; + goto err; + } + } + + /* (ok == 0 if OCSP was enabled) + * means revocation status was not detectable via OCSP + * -> perform CRL fallback + */ while (ctx->current_reasons != CRLDP_ALL_REASONS) { /* Try to retrieve relevant CRL */ if (ctx->get_crl) + { ok = ctx->get_crl(ctx, &crl, x); - else - ok = get_crl_delta(ctx, &crl, &dcrl, x); + if (ok) + { + /* Add downloaded CRL to the ones already constained in + * store and then proceed with the usual workflow + */ + if (!ctx->crls && !(ctx->crls = sk_X509_CRL_new_null())) + { + ctx->error = X509_V_ERR_OUT_OF_MEM; + ok = ctx->verify_cb(0, ctx); + goto err; + } + if (!sk_X509_CRL_push(ctx->crls, crl)) + { + ctx->error = X509_V_ERR_OUT_OF_MEM; + ok = ctx->verify_cb(0, ctx); + goto err; + } + CRYPTO_add(&crl->references, 1, CRYPTO_LOCK_X509_CRL); + } + } + + ok = get_crl_delta(ctx, &crl, &dcrl, x); /* If error looking up CRL, nothing we can do except * notify callback */ @@ -801,6 +894,89 @@ } +static int get_crl(X509_STORE_CTX *ctx, X509_CRL **pcrl, X509 *x) + { + X509_CRL *crl = NULL; + X509_EXTENSION *crldp_ext; + CRL_DIST_POINTS *crldps = NULL; + DIST_POINT *dp; + DIST_POINT_NAME *dpn; + GENERAL_NAMES *names; + GENERAL_NAME *tmp; + ASN1_OCTET_STRING *data; + int crldppos, i, j, ret = 0; + unsigned char *uri = NULL; + + if (!ctx->dl_crl) + goto err; + + /* Parse CRL URL from CRL DP */ + if ((crldppos = X509_get_ext_by_NID(x, NID_crl_distribution_points, 0)) < 0) + { + ctx->error = X509_V_ERR_UNABLE_TO_FIND_CRL_DPS; + goto err; + } + if (!(crldp_ext = X509_get_ext(x, crldppos))) + { + ctx->error = X509_V_ERR_APPLICATION_VERIFICATION; + goto err; + } + if (!(data = X509_EXTENSION_get_data(crldp_ext))) + { + ctx->error = X509_V_ERR_APPLICATION_VERIFICATION; + goto err; + } + if (!(crldps = d2i_CRL_DIST_POINTS(NULL, + (const unsigned char **)&(data->data), + data->length))) + { + ctx->error = X509_V_ERR_APPLICATION_VERIFICATION; + goto err; + } + + for (i=0; i < sk_DIST_POINT_num(crldps); i++) + { + dp = sk_DIST_POINT_value(crldps, i); + if (!dp->distpoint) + continue; + dpn = dp->distpoint; + if (!dpn->name.fullname) + continue; + names = dpn->name.fullname; + for (j=0; j<sk_GENERAL_NAME_num(names); j++) + { + tmp = sk_GENERAL_NAME_value(names, j); + if(tmp->type == GEN_URI) + { + uri = tmp->d.ia5->data; + break; + } + } + } + + if (!uri) + { + ctx->error = X509_V_ERR_UNABLE_TO_FIND_CRL_DP_URL; + goto err; + } + + if (!(crl = ctx->dl_crl(ctx, (char*)uri))) + { + ctx->error = X509_V_ERR_ERROR_RETRIEVING_CRL; + goto err; + } + + *pcrl = crl; + ret = 1; +err: + if (crldps) CRL_DIST_POINTS_free(crldps); + if (!ret) + { + ret = ctx->verify_cb(0, ctx); + } + return ret; + } + /* Check CRL times against values in X509_STORE_CTX */ static int check_crl_time(X509_STORE_CTX *ctx, X509_CRL *crl, int notify) @@ -1434,7 +1610,7 @@ if (!(ctx->current_crl_score & CRL_SCORE_SAME_PATH)) { - if (check_crl_path(ctx, ctx->current_issuer) <= 0) + if (check_crl_path(ctx, issuer) <= 0) { ctx->error = X509_V_ERR_CRL_PATH_VALIDATION_ERROR; ok = ctx->verify_cb(0, ctx); @@ -1522,6 +1698,322 @@ return 1; } +/* Check OCSP response times against values in X509_STORE_CTX */ +static int check_ocsp_times(X509_STORE_CTX *ctx, OCSP_BASICRESP *ocsp) + { + time_t *ptime; + int cmp, i; + OCSP_SINGLERESP *resp; + + if (ctx->param->flags & X509_V_FLAG_USE_CHECK_TIME) + ptime = &ctx->param->check_time; + else + ptime = NULL; + + /* first check the producedAt value */ + cmp=X509_cmp_time(ocsp->tbsResponseData->producedAt, ptime); + if (cmp == 0) + { + ctx->error=X509_V_ERR_ERROR_IN_OCSP_PRODUCED_AT_FIELD; + goto err; + } + + if (cmp > 0) + { + ctx->error=X509_V_ERR_OCSP_NOT_YET_VALID; + goto err; + } + + for (i=0; i < sk_OCSP_SINGLERESP_num(ocsp->tbsResponseData->responses); i++) + { + resp = sk_OCSP_SINGLERESP_value(ocsp->tbsResponseData->responses, i); + cmp=X509_cmp_time(resp->thisUpdate, ptime); + if (cmp == 0) + { + ctx->error=X509_V_ERR_ERROR_IN_OCSP_THIS_UPDATE_FIELD; + goto err; + } + + if (cmp > 0) + { + ctx->error=X509_V_ERR_OCSP_NOT_YET_VALID; + goto err; + } + if (resp->nextUpdate) + { + cmp = X509_cmp_time(resp->nextUpdate, ptime); + if (cmp == 0) + { + ctx->error=X509_V_ERR_ERROR_IN_OCSP_NEXT_UPDATE_FIELD; + goto err; + } + if (cmp < 0) + { + ctx->error=X509_V_ERR_OCSP_HAS_EXPIRED; + goto err; + } + } + } + + return 1; + +err: + return ctx->verify_cb(0, ctx); + } + + +/* Retrieves an OCSP response for x. Sets the OCSP_RESPONSE, but also + * the OCSP_REQUEST that was created. + * Returns 0 in case of an error, 1 otherwise. + */ +static int get_ocsp(X509_STORE_CTX *ctx, + OCSP_REQUEST **request, + OCSP_RESPONSE **ocsp, + X509 *x, + X509 *issuer) + { + OCSP_REQUEST *req; + OCSP_RESPONSE *resp; + OCSP_CERTID *id; + X509_EXTENSION *aia_ext; + AUTHORITY_INFO_ACCESS *aia = NULL; + ACCESS_DESCRIPTION *ocsp_desc = NULL, *tmp; + ASN1_OCTET_STRING *data; + int aiapos, i, ok = 0; + unsigned char *uri; + + if (!ctx->ocsp_ctx->dl_ocsp) + goto err; + + if (!(req = OCSP_REQUEST_new())) + { + ctx->error = X509_V_ERR_OUT_OF_MEM; + goto err; + } + id = OCSP_cert_to_id(EVP_sha1(), x, issuer); + if(!id || !OCSP_request_add0_id(req, id)) + { + ctx->error = X509_V_ERR_APPLICATION_VERIFICATION; + goto err; + } + + /* add a nonce if requested */ + if (!(ctx->ocsp_ctx->flags & OCSP_NONONCE)) + OCSP_request_add1_nonce(req, NULL, -1); + + /* if signer certificate, key and digest are set, then sign the request */ + if (ctx->ocsp_ctx->signer) + { + if (!(ctx->ocsp_ctx->key && ctx->ocsp_ctx->dgst)) + { + ctx->error = X509_V_ERR_OCSP_SIGNING_FAILED; + goto err; + } + if (!(OCSP_request_sign(req, + ctx->ocsp_ctx->signer, + ctx->ocsp_ctx->key, + ctx->ocsp_ctx->dgst, + ctx->ocsp_ctx->signer_certs, + ctx->ocsp_ctx->flags))) + { + ctx->error = X509_V_ERR_OCSP_SIGNING_FAILED; + goto err; + } + } + + /* Parse responder URL from AIA */ + if ((aiapos = X509_get_ext_by_NID(x, NID_info_access, 0)) < 0) + { + ctx->error = X509_V_ERR_UNABLE_TO_FIND_AIA; + goto err; + } + if (!(aia_ext = X509_get_ext(x, aiapos))) + { + ctx->error = X509_V_ERR_APPLICATION_VERIFICATION; + goto err; + } + if (!(data = X509_EXTENSION_get_data(aia_ext))) + { + ctx->error = X509_V_ERR_APPLICATION_VERIFICATION; + goto err; + } + if (!(aia = d2i_AUTHORITY_INFO_ACCESS(NULL, + (const unsigned char **)&(data->data), + data->length))) + { + ctx->error = X509_V_ERR_APPLICATION_VERIFICATION; + goto err; + } + + for (i=0; i < sk_ACCESS_DESCRIPTION_num(aia); i++) + { + tmp = sk_ACCESS_DESCRIPTION_value(aia, i); + if (OBJ_cmp(tmp->method, OBJ_nid2obj(NID_ad_OCSP)) == 0) + { + ocsp_desc = tmp; + break; + } + } + /* We are only interested in an ACCESS_DESCRIPTION for OCSP of type URI*/ + if (!ocsp_desc || !ocsp_desc->location->type == GEN_URI) + { + ctx->error = X509_V_ERR_UNABLE_TO_FIND_AIA_URL; + goto err; + } + + uri = ocsp_desc->location->d.ia5->data; + if (!(resp = ctx->ocsp_ctx->dl_ocsp(ctx, req, (char*)uri))) + { + ctx->error = X509_V_ERR_ERROR_RETRIEVING_OCSP_RESPONSE; + goto err; + } + + *request = req; + *ocsp = resp; + ok = 1; +err: + if (aia) AUTHORITY_INFO_ACCESS_free(aia); + if (!ok) + { + ok = ctx->verify_cb(0, ctx); + } + return ok; + } + +/* First validates the OCSP response and then checks the revocation status. + * Returns + * 0 if an error occurs or if the certificate has a status of UNKNOWN + * 1 if the response was valid and the certificate is also + * -1 if the certificate is revoked + */ + +static int check_ocsp(X509_STORE_CTX *ctx, + OCSP_REQUEST *request, + OCSP_RESPONSE *ocsp, + X509 *x, + X509 *issuer) + { + int ret = 0, status; + unsigned long flags; + OCSP_ONEREQ *single_req; + OCSP_SINGLERESP *single_resp; + X509 *ocsp_cert; + + OCSP_BASICRESP *basic = NULL; + + /* Check the status, reject anything else than SUCCESSFUL */ + if (OCSP_response_status(ocsp) != OCSP_RESPONSE_STATUS_SUCCESSFUL) + { + ctx->error = X509_V_ERR_OCSP_RESPONSE_NOT_SUCCESSFUL; + goto end; + } + + if (!(basic = OCSP_response_get1_basic(ocsp))) + { + ctx->error = X509_V_ERR_APPLICATION_VERIFICATION; + goto end; + } + + ctx->current_ocsp = basic; + + /* Check if the issuer of the OCSP certificate is the same as of the + * certificate currently checked. + */ + if (!(OCSP_basic_find_signer(&ocsp_cert, basic, ctx->untrusted, 0))) + { + ctx->error = X509_V_ERR_OCSP_SIGNING_CERT_NOT_FOUND; + goto end; + } + if (!(ctx->check_issued(ctx, ocsp_cert, issuer))) + { + /* OCSP certificate could still be one of the authorized responders */ + if (!ctx->ocsp_ctx->auth_responders) + { + ctx->error = X509_V_ERR_OCSP_CERT_ISSUER_NOT_TRUSTED; + goto end; + } + int found = 0, i; + for (i=0; i < sk_X509_num(ctx->ocsp_ctx->auth_responders); i++) + { + if(X509_cmp(ocsp_cert, sk_X509_value(ctx->ocsp_ctx->auth_responders, i)) == 0) + { + found = 1; + break; + } + } + if (!found) + { + ctx->error = X509_V_ERR_OCSP_CERT_ISSUER_NOT_TRUSTED; + goto end; + } + } + /* We don't need certificate path validation, issuers are equal*/ + flags = ctx->ocsp_ctx->flags | OCSP_NOVERIFY; + /* Verify the signature and validate the OCSP certificate */ + if (!(OCSP_basic_verify(basic, + ctx->untrusted, + ctx->ctx, + flags))) + { + ctx->error = X509_V_ERR_OCSP_SIGNATURE_FAILURE; + goto end; + } + + /* We only accept one OCSP_ONEREQ and OCSP_SINGLERESP */ + if (OCSP_request_onereq_count(request) != 1 + || OCSP_resp_count(basic) != 1) + { + ctx->error = X509_V_ERR_OCSP_UNSUPPORTED_MULTIPLE_RESP; + goto end; + } + + single_req = sk_OCSP_ONEREQ_value(request->tbsRequest->requestList, 0); + /* Check whether request CertID matches response CertID */ + if (OCSP_resp_find(basic, single_req->reqCert, -1) != 0) + { + ctx->error = X509_V_ERR_OCSP_CERT_ID_MISMATCH; + goto end; + } + single_resp = sk_OCSP_SINGLERESP_value(basic->tbsResponseData->responses, 0); + + + /* Check nonces, error case if return value is <= 0 */ + if (OCSP_check_nonce(request, basic) <= 0) + { + ctx->error = X509_V_ERR_OCSP_NONCE_MISMATCH; + goto end; + } + + if (!check_ocsp_times(ctx, basic)) + { + /* error set appropriately in method */ + goto end; + } + + status = single_resp->certStatus->type; + switch (status) + { + case V_OCSP_CERTSTATUS_GOOD: + ret = 1; + break; + case V_OCSP_CERTSTATUS_REVOKED: + ret = -1; + break; + case V_OCSP_CERTSTATUS_UNKNOWN: + ret = 0; + break; + } + +end: + if (basic) + OCSP_BASICRESP_free(basic); + if (!ret) + { + ret = ctx->verify_cb(0, ctx); + } + return ret; + } + static int check_policy(X509_STORE_CTX *ctx) { int ret; @@ -2033,9 +2525,50 @@ return ctx; } +X509_OCSP_CTX *X509_OCSP_CTX_new(void) +{ + X509_OCSP_CTX *ctx; + ctx = (X509_OCSP_CTX *)OPENSSL_malloc(sizeof(X509_OCSP_CTX)); + if (!ctx) + { + X509err(X509_F_X509_OCSP_CTX_NEW, ERR_R_MALLOC_FAILURE); + return NULL; + } + memset(ctx, 0, sizeof(X509_OCSP_CTX)); + + ctx->auth_responders = NULL; + ctx->dgst = NULL; + ctx->key = NULL; + ctx->signer = NULL; + ctx->signer_certs = NULL; + ctx->flags = 0; + + return ctx; +} + +void X509_OCSP_CTX_free(X509_OCSP_CTX *ctx) +{ + if (!ctx) + return; + if (ctx->auth_responders) sk_X509_pop_free(ctx->auth_responders, X509_free); + if (ctx->key) EVP_PKEY_free(ctx->key); + if (ctx->signer) X509_free(ctx->signer); + if (ctx->signer_certs) sk_X509_pop_free(ctx->signer_certs, X509_free); + OPENSSL_free(ctx); +} + void X509_STORE_CTX_free(X509_STORE_CTX *ctx) { X509_STORE_CTX_cleanup(ctx); + if (ctx->ocsp_ctx != NULL) + { + /* resources are only freed when X509_STORE holding them is freed*/ + ctx->ocsp_ctx->auth_responders = NULL; + ctx->ocsp_ctx->signer = NULL; + ctx->ocsp_ctx->signer_certs = NULL; + ctx->ocsp_ctx->key = NULL; + OPENSSL_free(ctx->ocsp_ctx); + } OPENSSL_free(ctx); } @@ -2057,6 +2590,10 @@ ctx->error_depth=0; ctx->current_cert=NULL; ctx->current_issuer=NULL; + ctx->current_crl = NULL; + ctx->current_ocsp = NULL; + ctx->current_crl_score = 0; + ctx->current_reasons = 0; ctx->tree = NULL; ctx->parent = NULL; @@ -2121,10 +2658,15 @@ else ctx->check_revocation = check_revocation; + if (store && store->dl_crl) + ctx->dl_crl = store->dl_crl; + else + ctx->dl_crl = NULL; + if (store && store->get_crl) ctx->get_crl = store->get_crl; else - ctx->get_crl = NULL; + ctx->get_crl = get_crl; if (store && store->check_crl) ctx->check_crl = store->check_crl; @@ -2136,6 +2678,60 @@ else ctx->cert_crl = cert_crl; + if (ctx->param->flags & X509_V_FLAG_OCSP_CHECK) + { + if (!(ctx->ocsp_ctx = X509_OCSP_CTX_new())) + { + OPENSSL_free(ctx); + X509err(X509_F_X509_STORE_CTX_INIT,ERR_R_MALLOC_FAILURE); + return 0; + } + + /* copy flags */ + if (store && store->ocsp_ctx) + ctx->ocsp_ctx->flags |= store->ocsp_ctx->flags; + + if (store && store->ocsp_ctx) + ctx->ocsp_ctx->auth_responders = store->ocsp_ctx->auth_responders; + else + ctx->ocsp_ctx->auth_responders = NULL; + + if (store && store->ocsp_ctx) + ctx->ocsp_ctx->signer = store->ocsp_ctx->signer; + else + ctx->ocsp_ctx->signer = NULL; + + if (store && store->ocsp_ctx) + ctx->ocsp_ctx->signer_certs = store->ocsp_ctx->signer_certs; + else + ctx->ocsp_ctx->signer_certs = NULL; + + if (store && store->ocsp_ctx) + ctx->ocsp_ctx->key = store->ocsp_ctx->key; + else + ctx->ocsp_ctx->key = NULL; + + if (store && store->ocsp_ctx) + ctx->ocsp_ctx->dgst = store->ocsp_ctx->dgst; + else + ctx->ocsp_ctx->dgst = NULL; + + if (store && store->ocsp_ctx && store->ocsp_ctx->get_ocsp) + ctx->ocsp_ctx->get_ocsp = store->ocsp_ctx->get_ocsp; + else + ctx->ocsp_ctx->get_ocsp = get_ocsp; + + if (store && store->ocsp_ctx && store->ocsp_ctx->dl_ocsp) + ctx->ocsp_ctx->dl_ocsp = store->ocsp_ctx->dl_ocsp; + else + ctx->ocsp_ctx->dl_ocsp = NULL; + + if (store && store->ocsp_ctx && store->ocsp_ctx->check_ocsp) + ctx->ocsp_ctx->check_ocsp = store->ocsp_ctx->check_ocsp; + else + ctx->ocsp_ctx->check_ocsp = check_ocsp; + } + if (store && store->lookup_certs) ctx->lookup_certs = store->lookup_certs; else Index: crypto/x509/x509_vfy.h =================================================================== RCS file: /v/openssl/cvs/openssl/crypto/x509/x509_vfy.h,v retrieving revision 1.73 diff -u -r1.73 x509_vfy.h --- crypto/x509/x509_vfy.h 25 Dec 2010 20:45:59 -0000 1.73 +++ crypto/x509/x509_vfy.h 30 Dec 2010 01:13:16 -0000 @@ -166,17 +166,47 @@ typedef struct X509_VERIFY_PARAM_st { char *name; - time_t check_time; /* Time to use */ - unsigned long inh_flags; /* Inheritance flags */ - unsigned long flags; /* Various verify flags */ - int purpose; /* purpose to check untrusted certificates */ - int trust; /* trust setting to check */ - int depth; /* Verify depth */ + time_t check_time; /* Time to use */ + unsigned long inh_flags; /* Inheritance flags */ + unsigned long flags; /* Various verify flags */ + int purpose; /* purpose to check untrusted certificates */ + int trust; /* trust setting to check */ + int depth; /* Verify depth */ STACK_OF(ASN1_OBJECT) *policies; /* Permissible policies */ } X509_VERIFY_PARAM; DECLARE_STACK_OF(X509_VERIFY_PARAM) +struct x509_ocsp_ctx_st + { + unsigned long flags; /* Flags for OCSP verification/requests */ + + /* If the request is to be signed, the next three must be set */ + X509 *signer; + EVP_PKEY *key; + const EVP_MD *dgst; + + /* Additional certificates to be added to the request signature */ + STACK_OF(X509) *signer_certs; + + /* If an OCSP response is signed by one of these, the certificate + is explicitly trusted (cf. "authorized responder approachin RFC 2560 */ + STACK_OF(X509) *auth_responders; + + /* Callbacks for various operations */ + + /* Download an OCSP response from a given URL by sending the request */ + OCSP_RESPONSE* (*dl_ocsp)(X509_STORE_CTX *ctx, OCSP_REQUEST *request, + char *url); + /* Retrieve OCSP response */ + int (*get_ocsp)(X509_STORE_CTX *ctx, OCSP_REQUEST **request, + OCSP_RESPONSE **ocsp, X509 *x, X509 *issuer); + /* Check OCSP validity and revocation status */ + int (*check_ocsp)(X509_STORE_CTX *ctx, OCSP_REQUEST *request, + OCSP_RESPONSE *ocsp, X509 *x, X509 *issuer); + + } /* X509_OCSP_CTX */; + /* This is used to hold everything. It is used for all certificate * validation. Once we have a certificate chain, the 'verify' * function is then called to actually check the cert chain. */ @@ -192,14 +222,29 @@ X509_VERIFY_PARAM *param; /* Callbacks for various operations */ - int (*verify)(X509_STORE_CTX *ctx); /* called to verify a certificate */ - int (*verify_cb)(int ok,X509_STORE_CTX *ctx); /* error callback */ - int (*get_issuer)(X509 **issuer, X509_STORE_CTX *ctx, X509 *x); /* get issuers cert from ctx */ - int (*check_issued)(X509_STORE_CTX *ctx, X509 *x, X509 *issuer); /* check issued */ - int (*check_revocation)(X509_STORE_CTX *ctx); /* Check revocation status of chain */ - int (*get_crl)(X509_STORE_CTX *ctx, X509_CRL **crl, X509 *x); /* retrieve CRL */ - int (*check_crl)(X509_STORE_CTX *ctx, X509_CRL *crl); /* Check CRL validity */ - int (*cert_crl)(X509_STORE_CTX *ctx, X509_CRL *crl, X509 *x); /* Check certificate against CRL */ + + /* called to verify a certificate */ + int (*verify)(X509_STORE_CTX *ctx); + /* error callback */ + int (*verify_cb)(int ok,X509_STORE_CTX *ctx); + /* get issuers cert from ctx */ + int (*get_issuer)(X509 **issuer, X509_STORE_CTX *ctx, X509 *x); + /* check issued */ + int (*check_issued)(X509_STORE_CTX *ctx, X509 *x, X509 *issuer); + /* Check revocation status of chain */ + int (*check_revocation)(X509_STORE_CTX *ctx); + /* download a CRL from a given URL */ + X509_CRL* (*dl_crl)(X509_STORE_CTX *ctx, char *url); + /* retrieve CRL */ + int (*get_crl)(X509_STORE_CTX *ctx, X509_CRL **crl, X509 *x); + /* Check CRL validity */ + int (*check_crl)(X509_STORE_CTX *ctx, X509_CRL *crl); + /* Check certificate against CRL */ + int (*cert_crl)(X509_STORE_CTX *ctx, X509_CRL *crl, X509 *x); + + /* Contains flags and callbacks for OCSP */ + X509_OCSP_CTX *ocsp_ctx; + STACK_OF(X509) * (*lookup_certs)(X509_STORE_CTX *ctx, X509_NAME *nm); STACK_OF(X509_CRL) * (*lookup_crls)(X509_STORE_CTX *ctx, X509_NAME *nm); int (*cleanup)(X509_STORE_CTX *ctx); @@ -241,14 +286,29 @@ void *other_ctx; /* Other info for use with get_issuer() */ /* Callbacks for various operations */ - int (*verify)(X509_STORE_CTX *ctx); /* called to verify a certificate */ - int (*verify_cb)(int ok,X509_STORE_CTX *ctx); /* error callback */ - int (*get_issuer)(X509 **issuer, X509_STORE_CTX *ctx, X509 *x); /* get issuers cert from ctx */ - int (*check_issued)(X509_STORE_CTX *ctx, X509 *x, X509 *issuer); /* check issued */ - int (*check_revocation)(X509_STORE_CTX *ctx); /* Check revocation status of chain */ - int (*get_crl)(X509_STORE_CTX *ctx, X509_CRL **crl, X509 *x); /* retrieve CRL */ - int (*check_crl)(X509_STORE_CTX *ctx, X509_CRL *crl); /* Check CRL validity */ - int (*cert_crl)(X509_STORE_CTX *ctx, X509_CRL *crl, X509 *x); /* Check certificate against CRL */ + + /* called to verify a certificate */ + int (*verify)(X509_STORE_CTX *ctx); + /* error callback */ + int (*verify_cb)(int ok,X509_STORE_CTX *ctx); + /* get issuers cert from ctx */ + int (*get_issuer)(X509 **issuer, X509_STORE_CTX *ctx, X509 *x); + /* check issued */ + int (*check_issued)(X509_STORE_CTX *ctx, X509 *x, X509 *issuer); + /* Check revocation status of chain */ + int (*check_revocation)(X509_STORE_CTX *ctx); + /* download a CRL from a given URL */ + X509_CRL* (*dl_crl)(X509_STORE_CTX *ctx, char *url); + /* retrieve CRL */ + int (*get_crl)(X509_STORE_CTX *ctx, X509_CRL **crl, X509 *x); + /* Check CRL validity */ + int (*check_crl)(X509_STORE_CTX *ctx, X509_CRL *crl); + /* Check certificate against CRL */ + int (*cert_crl)(X509_STORE_CTX *ctx, X509_CRL *crl, X509 *x); + + /* Contains flags and callbacks for OCSP */ + X509_OCSP_CTX *ocsp_ctx; + int (*check_policy)(X509_STORE_CTX *ctx); STACK_OF(X509) * (*lookup_certs)(X509_STORE_CTX *ctx, X509_NAME *nm); STACK_OF(X509_CRL) * (*lookup_crls)(X509_STORE_CTX *ctx, X509_NAME *nm); @@ -268,7 +328,8 @@ X509 *current_cert; X509 *current_issuer; /* cert currently being tested as valid issuer */ X509_CRL *current_crl; /* current CRL */ - + OCSP_BASICRESP *current_ocsp; /* current OCSP */ + int current_crl_score; /* score of current CRL */ unsigned int current_reasons; /* Reason mask */ @@ -356,6 +417,26 @@ /* Another issuer check debug option */ #define X509_V_ERR_PATH_LOOP 55 +#define X509_V_ERR_ERROR_IN_OCSP_PRODUCED_AT_FIELD 55 +#define X509_V_ERR_ERROR_IN_OCSP_THIS_UPDATE_FIELD 56 +#define X509_V_ERR_ERROR_IN_OCSP_NEXT_UPDATE_FIELD 57 +#define X509_V_ERR_OCSP_NOT_YET_VALID 58 +#define X509_V_ERR_OCSP_HAS_EXPIRED 59 +#define X509_V_ERR_UNABLE_TO_FIND_AIA 60 +#define X509_V_ERR_UNABLE_TO_FIND_AIA_URL 61 +#define X509_V_ERR_ERROR_RETRIEVING_OCSP_RESPONSE 62 +#define X509_V_ERR_OCSP_RESPONSE_NOT_SUCCESSFUL 63 +#define X509_V_ERR_OCSP_SIGNATURE_FAILURE 64 +#define X509_V_ERR_OCSP_UNSUPPORTED_MULTIPLE_RESP 65 +#define X509_V_ERR_OCSP_CERT_ID_MISMATCH 66 +#define X509_V_ERR_OCSP_NONCE_MISMATCH 67 +#define X509_V_ERR_UNABLE_TO_FIND_CRL_DPS 68 +#define X509_V_ERR_UNABLE_TO_FIND_CRL_DP_URL 69 +#define X509_V_ERR_ERROR_RETRIEVING_CRL 70 +#define X509_V_ERR_OCSP_SIGNING_CERT_NOT_FOUND 71 +#define X509_V_ERR_OCSP_CERT_ISSUER_NOT_TRUSTED 72 +#define X509_V_ERR_OCSP_SIGNING_FAILED 73 + /* The application is not happy */ #define X509_V_ERR_APPLICATION_VERIFICATION 50 @@ -393,6 +474,8 @@ #define X509_V_FLAG_CHECK_SS_SIGNATURE 0x4000 /* Use trusted store first */ #define X509_V_FLAG_TRUSTED_FIRST 0x8000 +/* Use OCSP whenever possible */ +#define X509_V_FLAG_OCSP_CHECK 0x10000 #define X509_VP_FLAG_DEFAULT 0x1 @@ -436,6 +519,10 @@ void X509_STORE_CTX_trusted_stack(X509_STORE_CTX *ctx, STACK_OF(X509) *sk); void X509_STORE_CTX_cleanup(X509_STORE_CTX *ctx); +X509_OCSP_CTX *X509_OCSP_CTX_new(void); +void X509_OCSP_CTX_free(X509_OCSP_CTX *ctx); +void X509_OCSP_CTX_cleanup(X509_OCSP_CTX *ctx); + X509_LOOKUP *X509_STORE_add_lookup(X509_STORE *v, X509_LOOKUP_METHOD *m); X509_LOOKUP_METHOD *X509_LOOKUP_hash_dir(void);