From: Dr. Stephen Henson Date: Thu, 21 Sep 2006 12:42:15 +0000 (+0000) Subject: Tidy up CRL handling by checking for critical extensions when it is X-Git-Tag: OpenSSL_0_9_8k^2~1136 X-Git-Url: https://git.openssl.org/?p=openssl.git;a=commitdiff_plain;h=010fa0b33169cfc9179bda29c34c05af80f78e27 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. --- diff --git a/CHANGES b/CHANGES index 8f9c9a1ae3..93db3118e1 100644 --- a/CHANGES +++ b/CHANGES @@ -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 diff --git a/crypto/asn1/asn1_locl.h b/crypto/asn1/asn1_locl.h index 099690203a..318e27eeb4 100644 --- a/crypto/asn1/asn1_locl.h +++ b/crypto/asn1/asn1_locl.h @@ -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); + }; diff --git a/crypto/asn1/x_crl.c b/crypto/asn1/x_crl.c index f8ad1f3417..266c497f33 100644 --- a/crypto/asn1/x_crl.c +++ b/crypto/asn1/x_crl.c @@ -58,6 +58,7 @@ #include #include "cryptlib.h" +#include "asn1_locl.h" #include #include #include @@ -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) diff --git a/crypto/ossl_typ.h b/crypto/ossl_typ.h index 5ebf0fab1c..b132405098 100644 --- a/crypto/ossl_typ.h +++ b/crypto/ossl_typ.h @@ -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; diff --git a/crypto/x509/x509.h b/crypto/x509/x509.h index de93bf9005..f28086c175 100644 --- a/crypto/x509/x509.h +++ b/crypto/x509/x509.h @@ -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); diff --git a/crypto/x509/x509_vfy.c b/crypto/x509/x509_vfy.c index 1252439f1e..d1aa3dafd6 100644 --- a/crypto/x509/x509_vfy.c +++ b/crypto/x509/x509_vfy.c @@ -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; } diff --git a/crypto/x509/x_all.c b/crypto/x509/x_all.c index 9039caad60..de516f8fd4 100644 --- a/crypto/x509/x_all.c +++ b/crypto/x509/x_all.c @@ -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),