Tidy up CRL handling by checking for critical extensions when it is

loaded. Add new function X509_CRL_get0_by_serial() to lookup a revoked
entry to avoid the need to access the structure directly.

Add new X509_CRL_METHOD to allow common CRL operations (verify, lookup) to be
redirected.
This commit is contained in:
Dr. Stephen Henson 2006-09-21 12:42:15 +00:00
parent 4ca7d975af
commit 010fa0b331
7 changed files with 113 additions and 53 deletions

View File

@ -4,6 +4,12 @@
Changes between 0.9.8d and 0.9.9 [xx XXX xxxx]
*) Add an X509_CRL_METHOD structure to allow CRL processing to be redirected
to external functions. This can be used to increase CRL handling
efficiency especially when CRLs are very large by (for example) storing
the CRL revoked certificates in a database.
[Steve Henson]
*) Overhaul of by_dir code. Add support for dynamic loading of CRLs so
new CRLs added to a directory can be used. New command line option
-verify_return_error to s_client and s_server. This causes real errors

View File

@ -113,3 +113,18 @@ struct evp_pkey_asn1_method_st
int (*old_priv_encode)(const EVP_PKEY *pkey, unsigned char **pder);
} /* EVP_PKEY_ASN1_METHOD */;
/* Method to handle CRL access.
* In general a CRL could be very large (several Mb) and can consume large
* amounts of resources if stored in memory by multiple processes.
* This method allows general CRL operations to be redirected to more
* efficient callbacks: for example a CRL entry database.
*/
struct x509_crl_method_st
{
int (*crl_init)(X509_CRL *crl);
int (*crl_free)(X509_CRL *crl);
int (*crl_lookup)(X509_CRL *crl, X509_REVOKED **ret, ASN1_INTEGER *ser);
int (*crl_verify)(X509_CRL *crl, EVP_PKEY *pk);
};

View File

@ -58,6 +58,7 @@
#include <stdio.h>
#include "cryptlib.h"
#include "asn1_locl.h"
#include <openssl/asn1t.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
@ -111,6 +112,9 @@ static int crl_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
void *exarg)
{
X509_CRL *crl = (X509_CRL *)*pval;
STACK_OF(X509_EXTENSION) *exts;
X509_EXTENSION *ext;
int idx;
switch(operation)
{
@ -119,6 +123,7 @@ static int crl_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
crl->akid = NULL;
crl->flags = 0;
crl->idp_flags = 0;
crl->meth = 0;
break;
case ASN1_OP_D2I_POST:
@ -132,9 +137,37 @@ static int crl_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
crl->akid = X509_CRL_get_ext_d2i(crl,
NID_authority_key_identifier, NULL, NULL);
if (crl->meth && crl->meth->crl_init)
return crl->meth->crl_init(crl);
/* See if we have any unhandled critical CRL extensions and
* indicate this in a flag. We only currently handle IDP so
* anything else critical sets the flag.
*
* This code accesses the X509_CRL structure directly:
* applications shouldn't do this.
*/
exts = crl->crl->extensions;
for (idx = 0; idx < sk_X509_EXTENSION_num(exts); idx++)
{
ext = sk_X509_EXTENSION_value(exts, idx);
if (ext->critical > 0)
{
/* We handle IDP now so permit it */
if (OBJ_obj2nid(ext->object) ==
NID_issuing_distribution_point)
continue;
crl->flags |= EXFLAG_CRITICAL;
break;
}
}
break;
case ASN1_OP_FREE_POST:
if (crl->meth && crl->meth->crl_free)
return crl->meth->crl_free(crl);
if (crl->akid)
AUTHORITY_KEYID_free(crl->akid);
if (crl->idp)
@ -217,6 +250,44 @@ int X509_CRL_add0_revoked(X509_CRL *crl, X509_REVOKED *rev)
return 1;
}
int X509_CRL_verify(X509_CRL *crl, EVP_PKEY *r)
{
if (crl->meth && crl->meth->crl_verify)
return crl->meth->crl_verify(crl, r);
return(ASN1_item_verify(ASN1_ITEM_rptr(X509_CRL_INFO),
crl->sig_alg, crl->signature,crl->crl,r));
}
int X509_CRL_get0_by_serial(X509_CRL *crl,
X509_REVOKED **ret, ASN1_INTEGER *serial)
{
X509_REVOKED rtmp;
int idx;
if (crl->meth && crl->meth->crl_lookup)
return crl->meth->crl_lookup(crl, ret, serial);
rtmp.serialNumber = serial;
/* Sort revoked into serial number order if not already sorted.
* Do this under a lock to avoid race condition.
*/
if (!sk_X509_REVOKED_is_sorted(crl->crl->revoked))
{
CRYPTO_w_lock(CRYPTO_LOCK_X509_CRL);
sk_X509_REVOKED_sort(crl->crl->revoked);
CRYPTO_w_unlock(CRYPTO_LOCK_X509_CRL);
}
idx = sk_X509_REVOKED_find(crl->crl->revoked, &rtmp);
/* If found assume revoked: want something cleverer than
* this to handle entry extensions in V2 CRLs.
*/
if(idx >= 0)
{
if (ret)
*ret = sk_X509_REVOKED_value(crl->crl->revoked, idx);
return 1;
}
return 0;
}
IMPLEMENT_STACK_OF(X509_REVOKED)
IMPLEMENT_ASN1_SET_OF(X509_REVOKED)
IMPLEMENT_STACK_OF(X509_CRL)

View File

@ -143,6 +143,8 @@ typedef struct ecdsa_method ECDSA_METHOD;
typedef struct x509_st X509;
typedef struct X509_algor_st X509_ALGOR;
typedef struct X509_crl_st X509_CRL;
typedef struct x509_crl_method_st X509_CRL_METHOD;
typedef struct x509_revoked_st X509_REVOKED;
typedef struct X509_name_st X509_NAME;
typedef struct X509_pubkey_st X509_PUBKEY;
typedef struct x509_store_st X509_STORE;

View File

@ -420,13 +420,13 @@ typedef struct x509_cert_pair_st {
XN_FLAG_FN_LN | \
XN_FLAG_FN_ALIGN)
typedef struct X509_revoked_st
struct x509_revoked_st
{
ASN1_INTEGER *serialNumber;
ASN1_TIME *revocationDate;
STACK_OF(X509_EXTENSION) /* optional */ *extensions;
int sequence; /* load sequence */
} X509_REVOKED;
};
DECLARE_STACK_OF(X509_REVOKED)
DECLARE_ASN1_SET_OF(X509_REVOKED)
@ -460,6 +460,7 @@ struct X509_crl_st
#ifndef OPENSSL_NO_SHA
unsigned char sha1_hash[SHA_DIGEST_LENGTH];
#endif
X509_CRL_METHOD *meth;
} /* X509_CRL */;
DECLARE_STACK_OF(X509_CRL)
@ -969,6 +970,8 @@ DECLARE_ASN1_FUNCTIONS(X509_CRL_INFO)
DECLARE_ASN1_FUNCTIONS(X509_CRL)
int X509_CRL_add0_revoked(X509_CRL *crl, X509_REVOKED *rev);
int X509_CRL_get0_by_serial(X509_CRL *crl,
X509_REVOKED **ret, ASN1_INTEGER *serial);
X509_PKEY * X509_PKEY_new(void );
void X509_PKEY_free(X509_PKEY *a);

View File

@ -937,60 +937,29 @@ static int check_crl(X509_STORE_CTX *ctx, X509_CRL *crl)
/* Check certificate against CRL */
static int cert_crl(X509_STORE_CTX *ctx, X509_CRL *crl, X509 *x)
{
int idx, ok;
X509_REVOKED rtmp;
STACK_OF(X509_EXTENSION) *exts;
X509_EXTENSION *ext;
/* Look for serial number of certificate in CRL */
rtmp.serialNumber = X509_get_serialNumber(x);
/* Sort revoked into serial number order if not already sorted.
* Do this under a lock to avoid race condition.
*/
if (!sk_X509_REVOKED_is_sorted(crl->crl->revoked))
{
CRYPTO_w_lock(CRYPTO_LOCK_X509_CRL);
sk_X509_REVOKED_sort(crl->crl->revoked);
CRYPTO_w_unlock(CRYPTO_LOCK_X509_CRL);
}
idx = sk_X509_REVOKED_find(crl->crl->revoked, &rtmp);
/* If found assume revoked: want something cleverer than
int ok;
/* Look for serial number of certificate in CRL
* If found assume revoked: want something cleverer than
* this to handle entry extensions in V2 CRLs.
*/
if(idx >= 0)
if (X509_CRL_get0_by_serial(crl, NULL, X509_get_serialNumber(x)) > 0)
{
ctx->error = X509_V_ERR_CERT_REVOKED;
ok = ctx->verify_cb(0, ctx);
if (!ok) return 0;
if (!ok)
return 0;
}
if (ctx->param->flags & X509_V_FLAG_IGNORE_CRITICAL)
return 1;
/* See if we have any critical CRL extensions: since we
* currently only handle IDP the CRL must be rejected if any others
* are present.
* This code accesses the X509_CRL structure directly: applications
* shouldn't do this.
*/
exts = crl->crl->extensions;
for (idx = 0; idx < sk_X509_EXTENSION_num(exts); idx++)
if (crl->flags & EXFLAG_CRITICAL)
{
ext = sk_X509_EXTENSION_value(exts, idx);
if (ext->critical > 0)
{
/* We handle IDP now so permit it */
if (OBJ_obj2nid(ext->object) ==
NID_issuing_distribution_point)
continue;
ctx->error =
X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION;
ok = ctx->verify_cb(0, ctx);
if(!ok) return 0;
break;
}
if (ctx->param->flags & X509_V_FLAG_IGNORE_CRITICAL)
return 1;
ctx->error = X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION;
ok = ctx->verify_cb(0, ctx);
if(!ok)
return 0;
}
return 1;
}

View File

@ -83,12 +83,6 @@ int X509_REQ_verify(X509_REQ *a, EVP_PKEY *r)
a->sig_alg,a->signature,a->req_info,r));
}
int X509_CRL_verify(X509_CRL *a, EVP_PKEY *r)
{
return(ASN1_item_verify(ASN1_ITEM_rptr(X509_CRL_INFO),
a->sig_alg, a->signature,a->crl,r));
}
int NETSCAPE_SPKI_verify(NETSCAPE_SPKI *a, EVP_PKEY *r)
{
return(ASN1_item_verify(ASN1_ITEM_rptr(NETSCAPE_SPKAC),