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:
parent
4ca7d975af
commit
010fa0b331
6
CHANGES
6
CHANGES
@ -4,6 +4,12 @@
|
|||||||
|
|
||||||
Changes between 0.9.8d and 0.9.9 [xx XXX xxxx]
|
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
|
*) 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
|
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
|
-verify_return_error to s_client and s_server. This causes real errors
|
||||||
|
@ -113,3 +113,18 @@ struct evp_pkey_asn1_method_st
|
|||||||
int (*old_priv_encode)(const EVP_PKEY *pkey, unsigned char **pder);
|
int (*old_priv_encode)(const EVP_PKEY *pkey, unsigned char **pder);
|
||||||
|
|
||||||
} /* EVP_PKEY_ASN1_METHOD */;
|
} /* 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);
|
||||||
|
};
|
||||||
|
@ -58,6 +58,7 @@
|
|||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "cryptlib.h"
|
#include "cryptlib.h"
|
||||||
|
#include "asn1_locl.h"
|
||||||
#include <openssl/asn1t.h>
|
#include <openssl/asn1t.h>
|
||||||
#include <openssl/x509.h>
|
#include <openssl/x509.h>
|
||||||
#include <openssl/x509v3.h>
|
#include <openssl/x509v3.h>
|
||||||
@ -111,6 +112,9 @@ static int crl_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
|
|||||||
void *exarg)
|
void *exarg)
|
||||||
{
|
{
|
||||||
X509_CRL *crl = (X509_CRL *)*pval;
|
X509_CRL *crl = (X509_CRL *)*pval;
|
||||||
|
STACK_OF(X509_EXTENSION) *exts;
|
||||||
|
X509_EXTENSION *ext;
|
||||||
|
int idx;
|
||||||
|
|
||||||
switch(operation)
|
switch(operation)
|
||||||
{
|
{
|
||||||
@ -119,6 +123,7 @@ static int crl_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
|
|||||||
crl->akid = NULL;
|
crl->akid = NULL;
|
||||||
crl->flags = 0;
|
crl->flags = 0;
|
||||||
crl->idp_flags = 0;
|
crl->idp_flags = 0;
|
||||||
|
crl->meth = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ASN1_OP_D2I_POST:
|
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,
|
crl->akid = X509_CRL_get_ext_d2i(crl,
|
||||||
NID_authority_key_identifier, NULL, NULL);
|
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;
|
break;
|
||||||
|
|
||||||
case ASN1_OP_FREE_POST:
|
case ASN1_OP_FREE_POST:
|
||||||
|
if (crl->meth && crl->meth->crl_free)
|
||||||
|
return crl->meth->crl_free(crl);
|
||||||
if (crl->akid)
|
if (crl->akid)
|
||||||
AUTHORITY_KEYID_free(crl->akid);
|
AUTHORITY_KEYID_free(crl->akid);
|
||||||
if (crl->idp)
|
if (crl->idp)
|
||||||
@ -217,6 +250,44 @@ int X509_CRL_add0_revoked(X509_CRL *crl, X509_REVOKED *rev)
|
|||||||
return 1;
|
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_STACK_OF(X509_REVOKED)
|
||||||
IMPLEMENT_ASN1_SET_OF(X509_REVOKED)
|
IMPLEMENT_ASN1_SET_OF(X509_REVOKED)
|
||||||
IMPLEMENT_STACK_OF(X509_CRL)
|
IMPLEMENT_STACK_OF(X509_CRL)
|
||||||
|
@ -143,6 +143,8 @@ typedef struct ecdsa_method ECDSA_METHOD;
|
|||||||
typedef struct x509_st X509;
|
typedef struct x509_st X509;
|
||||||
typedef struct X509_algor_st X509_ALGOR;
|
typedef struct X509_algor_st X509_ALGOR;
|
||||||
typedef struct X509_crl_st X509_CRL;
|
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_name_st X509_NAME;
|
||||||
typedef struct X509_pubkey_st X509_PUBKEY;
|
typedef struct X509_pubkey_st X509_PUBKEY;
|
||||||
typedef struct x509_store_st X509_STORE;
|
typedef struct x509_store_st X509_STORE;
|
||||||
|
@ -420,13 +420,13 @@ typedef struct x509_cert_pair_st {
|
|||||||
XN_FLAG_FN_LN | \
|
XN_FLAG_FN_LN | \
|
||||||
XN_FLAG_FN_ALIGN)
|
XN_FLAG_FN_ALIGN)
|
||||||
|
|
||||||
typedef struct X509_revoked_st
|
struct x509_revoked_st
|
||||||
{
|
{
|
||||||
ASN1_INTEGER *serialNumber;
|
ASN1_INTEGER *serialNumber;
|
||||||
ASN1_TIME *revocationDate;
|
ASN1_TIME *revocationDate;
|
||||||
STACK_OF(X509_EXTENSION) /* optional */ *extensions;
|
STACK_OF(X509_EXTENSION) /* optional */ *extensions;
|
||||||
int sequence; /* load sequence */
|
int sequence; /* load sequence */
|
||||||
} X509_REVOKED;
|
};
|
||||||
|
|
||||||
DECLARE_STACK_OF(X509_REVOKED)
|
DECLARE_STACK_OF(X509_REVOKED)
|
||||||
DECLARE_ASN1_SET_OF(X509_REVOKED)
|
DECLARE_ASN1_SET_OF(X509_REVOKED)
|
||||||
@ -460,6 +460,7 @@ struct X509_crl_st
|
|||||||
#ifndef OPENSSL_NO_SHA
|
#ifndef OPENSSL_NO_SHA
|
||||||
unsigned char sha1_hash[SHA_DIGEST_LENGTH];
|
unsigned char sha1_hash[SHA_DIGEST_LENGTH];
|
||||||
#endif
|
#endif
|
||||||
|
X509_CRL_METHOD *meth;
|
||||||
} /* X509_CRL */;
|
} /* X509_CRL */;
|
||||||
|
|
||||||
DECLARE_STACK_OF(X509_CRL)
|
DECLARE_STACK_OF(X509_CRL)
|
||||||
@ -969,6 +970,8 @@ DECLARE_ASN1_FUNCTIONS(X509_CRL_INFO)
|
|||||||
DECLARE_ASN1_FUNCTIONS(X509_CRL)
|
DECLARE_ASN1_FUNCTIONS(X509_CRL)
|
||||||
|
|
||||||
int X509_CRL_add0_revoked(X509_CRL *crl, X509_REVOKED *rev);
|
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 );
|
X509_PKEY * X509_PKEY_new(void );
|
||||||
void X509_PKEY_free(X509_PKEY *a);
|
void X509_PKEY_free(X509_PKEY *a);
|
||||||
|
@ -937,60 +937,29 @@ static int check_crl(X509_STORE_CTX *ctx, X509_CRL *crl)
|
|||||||
/* Check certificate against CRL */
|
/* Check certificate against CRL */
|
||||||
static int cert_crl(X509_STORE_CTX *ctx, X509_CRL *crl, X509 *x)
|
static int cert_crl(X509_STORE_CTX *ctx, X509_CRL *crl, X509 *x)
|
||||||
{
|
{
|
||||||
int idx, ok;
|
int ok;
|
||||||
X509_REVOKED rtmp;
|
/* Look for serial number of certificate in CRL
|
||||||
STACK_OF(X509_EXTENSION) *exts;
|
* If found assume revoked: want something cleverer than
|
||||||
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
|
|
||||||
* this to handle entry extensions in V2 CRLs.
|
* 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;
|
ctx->error = X509_V_ERR_CERT_REVOKED;
|
||||||
ok = ctx->verify_cb(0, ctx);
|
ok = ctx->verify_cb(0, ctx);
|
||||||
if (!ok) return 0;
|
if (!ok)
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx->param->flags & X509_V_FLAG_IGNORE_CRITICAL)
|
if (crl->flags & EXFLAG_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++)
|
|
||||||
{
|
{
|
||||||
ext = sk_X509_EXTENSION_value(exts, idx);
|
if (ctx->param->flags & X509_V_FLAG_IGNORE_CRITICAL)
|
||||||
if (ext->critical > 0)
|
return 1;
|
||||||
{
|
ctx->error = X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION;
|
||||||
/* We handle IDP now so permit it */
|
ok = ctx->verify_cb(0, ctx);
|
||||||
if (OBJ_obj2nid(ext->object) ==
|
if(!ok)
|
||||||
NID_issuing_distribution_point)
|
return 0;
|
||||||
continue;
|
|
||||||
ctx->error =
|
|
||||||
X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION;
|
|
||||||
ok = ctx->verify_cb(0, ctx);
|
|
||||||
if(!ok) return 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,12 +83,6 @@ int X509_REQ_verify(X509_REQ *a, EVP_PKEY *r)
|
|||||||
a->sig_alg,a->signature,a->req_info,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)
|
int NETSCAPE_SPKI_verify(NETSCAPE_SPKI *a, EVP_PKEY *r)
|
||||||
{
|
{
|
||||||
return(ASN1_item_verify(ASN1_ITEM_rptr(NETSCAPE_SPKAC),
|
return(ASN1_item_verify(ASN1_ITEM_rptr(NETSCAPE_SPKAC),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user