X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=crypto%2Fx509%2Fx509_vfy.c;h=0a5dcbe2ab414f891afa3db031d981d5508131ff;hb=4b49bf6a93d1958513aff6a1254194fb581500cb;hp=db62c9f6a348cead99bae90c22fa592edab3a160;hpb=f684090cbe0706bcd0280f7a14f609bed3c640c0;p=oweals%2Fopenssl.git diff --git a/crypto/x509/x509_vfy.c b/crypto/x509/x509_vfy.c index db62c9f6a3..0a5dcbe2ab 100644 --- a/crypto/x509/x509_vfy.c +++ b/crypto/x509/x509_vfy.c @@ -75,15 +75,14 @@ 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; static STACK_OF(CRYPTO_EX_DATA_FUNCS) *x509_store_ctx_method=NULL; static int x509_store_ctx_num=0; -#if 0 -static int x509_store_num=1; -static STACK *x509_store_method=NULL; -#endif + static int null_callback(int ok, X509_STORE_CTX *e) { @@ -113,7 +112,6 @@ int X509_verify_cert(X509_STORE_CTX *ctx) } cb=ctx->verify_cb; - if (cb == NULL) cb=null_callback; /* first we make sure the chain we are going to build is * present and that the first entry is in place */ @@ -299,6 +297,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); @@ -339,16 +344,14 @@ static int check_issued(X509_STORE_CTX *ctx, X509 *x, X509 *issuer) ret = X509_check_issued(issuer, x); if (ret == X509_V_OK) return 1; - else - { - ctx->error = ret; - ctx->current_cert = x; - ctx->current_issuer = issuer; - if ((ctx->flags & X509_V_FLAG_CB_ISSUER_CHECK) && ctx->verify_cb) - return ctx->verify_cb(0, ctx); - else - return 0; - } + /* If we haven't asked for issuer errors don't set ctx */ + if (!(ctx->flags & X509_V_FLAG_CB_ISSUER_CHECK)) + return 0; + + ctx->error = ret; + ctx->current_cert = x; + ctx->current_issuer = issuer; + return ctx->verify_cb(0, ctx); return 0; } @@ -373,14 +376,13 @@ static int get_issuer_sk(X509 **issuer, X509_STORE_CTX *ctx, X509 *x) static int check_chain_purpose(X509_STORE_CTX *ctx) { -#ifdef NO_CHAIN_VERIFY +#ifdef OPENSSL_NO_CHAIN_VERIFY return 1; #else int i, ok=0; X509 *x; int (*cb)(); cb=ctx->verify_cb; - if (cb == NULL) cb=null_callback; /* Check all untrusted certificates */ for (i = 0; i < ctx->last_untrusted; i++) { @@ -415,21 +417,20 @@ static int check_chain_purpose(X509_STORE_CTX *ctx) static int check_trust(X509_STORE_CTX *ctx) { -#ifdef NO_CHAIN_VERIFY +#ifdef OPENSSL_NO_CHAIN_VERIFY return 1; #else int i, ok; X509 *x; int (*cb)(); cb=ctx->verify_cb; - if (cb == NULL) cb=null_callback; /* For now just check the last certificate in the chain */ i = sk_X509_num(ctx->chain) - 1; x = sk_X509_value(ctx->chain, i); 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; @@ -440,6 +441,183 @@ 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; + 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; + 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; + 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; + 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 = ctx->verify_cb(0, ctx); + if (!ok) goto err; + } + + if (i > 0) + { + ctx->error=X509_V_ERR_CRL_NOT_YET_VALID; + 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 = ctx->verify_cb(0, ctx); + if (!ok) goto err; + } + + if (i < 0) + { + ctx->error=X509_V_ERR_CRL_HAS_EXPIRED; + 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; + ok = ctx->verify_cb(0, ctx); + return ok; + } + static int internal_verify(X509_STORE_CTX *ctx) { int i,ok=0,n; @@ -449,7 +627,6 @@ static int internal_verify(X509_STORE_CTX *ctx) int (*cb)(); cb=ctx->verify_cb; - if (cb == NULL) cb=null_callback; n=sk_X509_num(ctx->chain); ctx->error_depth=n-1; @@ -492,6 +669,13 @@ static int internal_verify(X509_STORE_CTX *ctx) if (!ok) goto end; } if (X509_verify(xs,pkey) <= 0) + /* XXX For the final trusted self-signed cert, + * this is a waste of time. That check should + * optional so that e.g. 'openssl x509' can be + * used to detect invalid self-signatures, but + * we don't verify again and again in SSL + * handshakes and the like once the cert has + * been declared trusted. */ { ctx->error=X509_V_ERR_CERT_SIGNATURE_FAILURE; ctx->current_cert=xs; @@ -649,14 +833,16 @@ ASN1_TIME *X509_gmtime_adj(ASN1_TIME *s, long adj) ASN1_TIME *X509_time_adj(ASN1_TIME *s, long adj, time_t *in_tm) { time_t t; + int type = -1; if (in_tm) t = *in_tm; else time(&t); t+=adj; - if (!s) return ASN1_TIME_set(s, t); - if (s->type == V_ASN1_UTCTIME) return ASN1_UTCTIME_set(s,t); - return ASN1_GENERALIZEDTIME_set(s, t); + if (s) type = s->type; + if (type == V_ASN1_UTCTIME) return ASN1_UTCTIME_set(s,t); + if (type == V_ASN1_GENERALIZEDTIME) return ASN1_GENERALIZEDTIME_set(s, t); + return ASN1_TIME_set(s, t); } int X509_get_pubkey_parameters(EVP_PKEY *pkey, STACK_OF(X509) *chain) @@ -703,12 +889,17 @@ int X509_get_pubkey_parameters(EVP_PKEY *pkey, STACK_OF(X509) *chain) int X509_STORE_CTX_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func) - { - x509_store_ctx_num++; - return CRYPTO_get_ex_new_index(x509_store_ctx_num-1, + { + /* This function is (usually) called only once, by + * SSL_get_ex_data_X509_STORE_CTX_idx (ssl/ssl_cert.c). + * That function uses locking, so we don't (usually) + * have to worry about locking here. For the whole cruel + * truth, see crypto/ex_data.c */ + x509_store_ctx_num++; + return CRYPTO_get_ex_new_index(x509_store_ctx_num-1, &x509_store_ctx_method, - argl,argp,new_func,dup_func,free_func); - } + argl,argp,new_func,dup_func,free_func); + } int X509_STORE_CTX_set_ex_data(X509_STORE_CTX *ctx, int idx, void *data) { @@ -832,8 +1023,8 @@ int X509_STORE_CTX_purpose_inherit(X509_STORE_CTX *ctx, int def_purpose, } } - if (purpose) ctx->purpose = purpose; - if (trust) ctx->trust = trust; + if (purpose && !ctx->purpose) ctx->purpose = purpose; + if (trust && !ctx->trust) ctx->trust = trust; return 1; } @@ -859,8 +1050,8 @@ void X509_STORE_CTX_init(X509_STORE_CTX *ctx, X509_STORE *store, X509 *x509, ctx->cert=x509; ctx->untrusted=chain; ctx->last_untrusted=0; - ctx->purpose=0; - ctx->trust=0; + ctx->purpose=store->purpose; + ctx->trust=store->trust; ctx->check_time=0; ctx->flags=0; ctx->other_ctx=NULL; @@ -871,11 +1062,55 @@ void X509_STORE_CTX_init(X509_STORE_CTX *ctx, X509_STORE *store, X509 *x509, ctx->error_depth=0; ctx->current_cert=NULL; ctx->current_issuer=NULL; - ctx->check_issued = check_issued; - ctx->get_issuer = X509_STORE_CTX_get1_issuer; - ctx->verify_cb = store->verify_cb; - ctx->verify = store->verify; - ctx->cleanup = 0; + + /* Inherit callbacks and flags from X509_STORE if not set + * use defaults. + */ + + ctx->flags = store->flags; + + if (store->check_issued) + ctx->check_issued = store->check_issued; + else + ctx->check_issued = check_issued; + + if (store->get_issuer) + ctx->get_issuer = store->get_issuer; + else + ctx->get_issuer = X509_STORE_CTX_get1_issuer; + + if (store->verify_cb) + ctx->verify_cb = store->verify_cb; + else + ctx->verify_cb = null_callback; + + if (store->verify) + ctx->verify = store->verify; + else + ctx->verify = internal_verify; + + if (store->check_revocation) + ctx->check_revocation = store->check_revocation; + else + ctx->check_revocation = check_revocation; + + if (store->get_crl) + ctx->get_crl = store->get_crl; + else + ctx->get_crl = get_crl; + + if (store->check_crl) + ctx->check_crl = store->check_crl; + else + ctx->check_crl = check_crl; + + if (store->cert_crl) + ctx->cert_crl = store->cert_crl; + else + ctx->cert_crl = cert_crl; + + ctx->cleanup = store->cleanup; + memset(&(ctx->ex_data),0,sizeof(CRYPTO_EX_DATA)); }