mirror of
https://github.com/openssl/openssl.git
synced 2025-03-25 20:00:44 +08:00
Initial CRL based revocation checking.
This commit is contained in:
parent
027902999e
commit
b545dc6775
15
CHANGES
15
CHANGES
@ -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:
|
||||
|
Loading…
x
Reference in New Issue
Block a user