提交 b545dc67 编写于 作者: D Dr. Stephen Henson

Initial CRL based revocation checking.
上级 02790299
......@@ -11,6 +11,21 @@
*) applies to 0.9.6a (/0.9.6b) and 0.9.7
+) applies to 0.9.7 only
+) Initial CRL based revocation checking. If the CRL checking flag(s)
are set then the CRL is looked up in the X509_STORE structure and
its validity and signature checked, then if the certificate is found
in the CRL the verify fails with a revoked error.
Various new CRL related callbacks added to X509_STORE_CTX structure.
Command line options added to 'verify' application to support this.
This needs some additional work, such as being able to handle multiple
CRLs with different times, extension based lookup (rather than just
by subject name) and ultimately more complete V2 CRL extension
handling.
[Steve Henson]
+) Add a general user interface API. This is designed to replace things
like des_read_password and friends (backward compatibility functions
using this new API are provided). The purpose is to remove prompting
......
......@@ -73,7 +73,7 @@
static int MS_CALLBACK cb(int ok, X509_STORE_CTX *ctx);
static int check(X509_STORE *ctx, char *file, STACK_OF(X509) *uchain, STACK_OF(X509) *tchain, int purpose);
static STACK_OF(X509) *load_untrusted(char *file);
static int v_verbose=0, issuer_checks = 0;
static int v_verbose=0, vflags = 0;
int MAIN(int, char **);
......@@ -148,7 +148,11 @@ int MAIN(int argc, char **argv)
else if (strcmp(*argv,"-help") == 0)
goto end;
else if (strcmp(*argv,"-issuer_checks") == 0)
issuer_checks=1;
vflags |= X509_V_FLAG_CB_ISSUER_CHECK;
else if (strcmp(*argv,"-crl_check") == 0)
vflags |= X509_V_FLAG_CRL_CHECK;
else if (strcmp(*argv,"-crl_check_all") == 0)
vflags |= X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL;
else if (strcmp(*argv,"-verbose") == 0)
v_verbose=1;
else if (argv[0][0] == '-')
......@@ -227,7 +231,7 @@ int MAIN(int argc, char **argv)
ret=0;
end:
if (ret == 1) {
BIO_printf(bio_err,"usage: verify [-verbose] [-CApath path] [-CAfile file] [-purpose purpose] [-engine e] cert1 cert2 ...\n");
BIO_printf(bio_err,"usage: verify [-verbose] [-CApath path] [-CAfile file] [-purpose purpose] [-crl_check] [-engine e] cert1 cert2 ...\n");
BIO_printf(bio_err,"recognized usages:\n");
for(i = 0; i < X509_PURPOSE_get_count(); i++) {
X509_PURPOSE *ptmp;
......@@ -286,8 +290,7 @@ static int check(X509_STORE *ctx, char *file, STACK_OF(X509) *uchain, STACK_OF(X
X509_STORE_CTX_init(csc,ctx,x,uchain);
if(tchain) X509_STORE_CTX_trusted_stack(csc, tchain);
if(purpose >= 0) X509_STORE_CTX_set_purpose(csc, purpose);
if(issuer_checks)
X509_STORE_CTX_set_flags(csc, X509_V_FLAG_CB_ISSUER_CHECK);
X509_STORE_CTX_set_flags(csc, vflags);
i=X509_verify_cert(csc);
X509_STORE_CTX_free(csc);
......@@ -375,6 +378,8 @@ static int MS_CALLBACK cb(int ok, X509_STORE_CTX *ctx)
if (ctx->error == X509_V_ERR_PATH_LENGTH_EXCEEDED) ok=1;
if (ctx->error == X509_V_ERR_INVALID_PURPOSE) ok=1;
if (ctx->error == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT) ok=1;
if (ctx->error == X509_V_ERR_CRL_HAS_EXPIRED) ok=1;
if (ctx->error == X509_V_ERR_CRL_NOT_YET_VALID) ok=1;
}
if (!v_verbose)
ERR_clear_error();
......
......@@ -83,7 +83,7 @@ const char *X509_verify_cert_error_string(long n)
case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE:
return("unable to decrypt certificate's signature");
case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE:
return("unable to decrypt CRL's's signature");
return("unable to decrypt CRL's signature");
case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY:
return("unable to decode issuer public key");
case X509_V_ERR_CERT_SIGNATURE_FAILURE:
......@@ -141,6 +141,9 @@ const char *X509_verify_cert_error_string(long n)
case X509_V_ERR_KEYUSAGE_NO_CERTSIGN:
return("key usage does not include certificate signing");
case X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER:
return("unable to get CRL issuer certificate");
default:
sprintf(buf,"error number %ld",n);
return(buf);
......
......@@ -75,6 +75,8 @@ static int check_issued(X509_STORE_CTX *ctx, X509 *x, X509 *issuer);
static X509 *find_issuer(X509_STORE_CTX *ctx, STACK_OF(X509) *sk, X509 *x);
static int check_chain_purpose(X509_STORE_CTX *ctx);
static int check_trust(X509_STORE_CTX *ctx);
static int check_revocation(X509_STORE_CTX *ctx);
static int check_cert(X509_STORE_CTX *ctx);
static int internal_verify(X509_STORE_CTX *ctx);
const char *X509_version="X.509" OPENSSL_VERSION_PTEXT;
......@@ -296,6 +298,13 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
/* We may as well copy down any DSA parameters that are required */
X509_get_pubkey_parameters(NULL,ctx->chain);
/* Check revocation status: we do this after copying parameters
* because they may be needed for CRL signature verification.
*/
ok = ctx->check_revocation(ctx);
if(!ok) goto end;
/* At this point, we have a chain and just need to verify it */
if (ctx->verify != NULL)
ok=ctx->verify(ctx);
......@@ -425,7 +434,7 @@ static int check_trust(X509_STORE_CTX *ctx)
ok = X509_check_trust(x, ctx->trust, 0);
if (ok == X509_TRUST_TRUSTED)
return 1;
ctx->error_depth = sk_X509_num(ctx->chain) - 1;
ctx->error_depth = i;
ctx->current_cert = x;
if (ok == X509_TRUST_REJECTED)
ctx->error = X509_V_ERR_CERT_REJECTED;
......@@ -436,6 +445,196 @@ static int check_trust(X509_STORE_CTX *ctx)
#endif
}
static int check_revocation(X509_STORE_CTX *ctx)
{
int i, last, ok;
if (!(ctx->flags & X509_V_FLAG_CRL_CHECK))
return 1;
if (ctx->flags & X509_V_FLAG_CRL_CHECK_ALL)
last = 0;
else
last = sk_X509_num(ctx->chain) - 1;
for(i = 0; i <= last; i++)
{
ctx->error_depth = i;
ok = check_cert(ctx);
if (!ok) return ok;
}
return 1;
}
static int check_cert(X509_STORE_CTX *ctx)
{
X509_CRL *crl = NULL;
X509 *x;
int ok, cnum;
cnum = ctx->error_depth;
x = sk_X509_value(ctx->chain, cnum);
ctx->current_cert = x;
/* Try to retrieve relevant CRL */
ok = ctx->get_crl(ctx, &crl, x);
/* If error looking up CRL, nothing we can do except
* notify callback
*/
if(!ok)
{
ctx->error = X509_V_ERR_UNABLE_TO_GET_CRL;
if (ctx->verify_cb)
ok = ctx->verify_cb(0, ctx);
goto err;
}
ctx->current_crl = crl;
ok = ctx->check_crl(ctx, crl);
if (!ok) goto err;
ok = ctx->cert_crl(ctx, crl, x);
err:
ctx->current_crl = NULL;
X509_CRL_free(crl);
return ok;
}
/* Retrieve CRL corresponding to certificate: currently just a
* subject lookup: maybe use AKID later...
* Also might look up any included CRLs too (e.g PKCS#7 signedData).
*/
static int get_crl(X509_STORE_CTX *ctx, X509_CRL **crl, X509 *x)
{
int ok;
X509_OBJECT xobj;
ok = X509_STORE_get_by_subject(ctx, X509_LU_CRL, X509_get_issuer_name(x), &xobj);
if (!ok) return 0;
*crl = xobj.data.crl;
return 1;
}
/* Check CRL validity */
static int check_crl(X509_STORE_CTX *ctx, X509_CRL *crl)
{
X509 *issuer = NULL;
EVP_PKEY *ikey = NULL;
int ok = 0, chnum, cnum, i;
time_t *ptime;
cnum = ctx->error_depth;
chnum = sk_X509_num(ctx->chain) - 1;
/* Find CRL issuer: if not last certificate then issuer
* is next certificate in chain.
*/
if(cnum < chnum)
issuer = sk_X509_value(ctx->chain, cnum + 1);
else
{
issuer = sk_X509_value(ctx->chain, chnum);
/* If not self signed, can't check signature */
if(!ctx->check_issued(ctx, issuer, issuer))
{
ctx->error = X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER;
if(ctx->verify_cb)
ok = ctx->verify_cb(0, ctx);
if(!ok) goto err;
}
}
if(issuer)
{
/* Attempt to get issuer certificate public key */
ikey = X509_get_pubkey(issuer);
if(!ikey)
{
ctx->error=X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY;
if(ctx->verify_cb)
ok = ctx->verify_cb(0, ctx);
if (!ok) goto err;
}
else
{
/* Verify CRL signature */
if(X509_CRL_verify(crl, ikey) <= 0)
{
ctx->error=X509_V_ERR_CRL_SIGNATURE_FAILURE;
if(ctx->verify_cb)
ok = ctx->verify_cb(0, ctx);
if (!ok) goto err;
}
}
}
/* OK, CRL signature valid check times */
if (ctx->flags & X509_V_FLAG_USE_CHECK_TIME)
ptime = &ctx->check_time;
else
ptime = NULL;
i=X509_cmp_time(X509_CRL_get_lastUpdate(crl), ptime);
if (i == 0)
{
ctx->error=X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD;
ok= 0;
if(ctx->verify_cb)
ok = ctx->verify_cb(0, ctx);
if (!ok) goto err;
}
if (i > 0)
{
ctx->error=X509_V_ERR_CRL_NOT_YET_VALID;
ok= 0;
if(ctx->verify_cb)
ok = ctx->verify_cb(0, ctx);
if (!ok) goto err;
}
if(X509_CRL_get_nextUpdate(crl))
{
i=X509_cmp_time(X509_CRL_get_nextUpdate(crl), ptime);
if (i == 0)
{
ctx->error=X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD;
ok= 0;
if(ctx->verify_cb)
ok = ctx->verify_cb(0, ctx);
if (!ok) goto err;
}
if (i < 0)
{
ctx->error=X509_V_ERR_CRL_HAS_EXPIRED;
ok= 0;
if(ctx->verify_cb)
ok = ctx->verify_cb(0, ctx);
if (!ok) goto err;
}
}
ok = 1;
err:
EVP_PKEY_free(ikey);
return ok;
}
/* Check certificate against CRL */
static int cert_crl(X509_STORE_CTX *ctx, X509_CRL *crl, X509 *x)
{
int idx, ok;
X509_REVOKED rtmp;
/* Look for serial number of certificate in CRL */
rtmp.serialNumber = X509_get_serialNumber(x);
idx = sk_X509_REVOKED_find(crl->crl->revoked, &rtmp);
/* Not found: OK */
if(idx == -1) return 1;
/* Otherwise revoked: want something cleverer than
* this to handle entry extensions in V2 CRLs.
*/
ctx->error = X509_V_ERR_CERT_REVOKED;
if (ctx->verify_cb)
ok = ctx->verify_cb(0, ctx);
return ok;
}
static int internal_verify(X509_STORE_CTX *ctx)
{
int i,ok=0,n;
......@@ -885,6 +1084,10 @@ void X509_STORE_CTX_init(X509_STORE_CTX *ctx, X509_STORE *store, X509 *x509,
ctx->get_issuer = X509_STORE_CTX_get1_issuer;
ctx->verify_cb = store->verify_cb;
ctx->verify = store->verify;
ctx->check_revocation = check_revocation;
ctx->get_crl = get_crl;
ctx->check_crl = check_crl;
ctx->cert_crl = cert_crl;
ctx->cleanup = 0;
memset(&(ctx->ex_data),0,sizeof(CRYPTO_EX_DATA));
}
......
......@@ -214,6 +214,10 @@ struct x509_store_ctx_st /* X509_STORE_CTX */
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 */
int (*cleanup)(X509_STORE_CTX *ctx);
/* The following is built up */
......@@ -227,6 +231,7 @@ struct x509_store_ctx_st /* X509_STORE_CTX */
int error;
X509 *current_cert;
X509 *current_issuer; /* cert currently being tested as valid issuer */
X509_CRL *current_crl; /* current CRL */
CRYPTO_EX_DATA ex_data;
};
......@@ -283,6 +288,8 @@ struct x509_store_ctx_st /* X509_STORE_CTX */
#define X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH 31
#define X509_V_ERR_KEYUSAGE_NO_CERTSIGN 32
#define X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER 33
/* The application is not happy */
#define X509_V_ERR_APPLICATION_VERIFICATION 50
......@@ -290,6 +297,8 @@ struct x509_store_ctx_st /* X509_STORE_CTX */
#define X509_V_FLAG_CB_ISSUER_CHECK 0x1 /* Send issuer+subject checks to verify_cb */
#define X509_V_FLAG_USE_CHECK_TIME 0x2 /* Use check time instead of current time */
#define X509_V_FLAG_CRL_CHECK 0x4 /* Lookup CRLs */
#define X509_V_FLAG_CRL_CHECK_ALL 0x8 /* Lookup CRLs for whole chain */
int X509_OBJECT_idx_by_subject(STACK_OF(X509_OBJECT) *h, int type,
X509_NAME *name);
......
......@@ -512,6 +512,7 @@ int ssl_verify_alarm_type(long type)
{
case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
case X509_V_ERR_UNABLE_TO_GET_CRL:
case X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER:
al=SSL_AD_UNKNOWN_CA;
break;
case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE:
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册