X-Git-Url: https://git.openssl.org/?p=openssl.git;a=blobdiff_plain;f=crypto%2Fx509%2Fx509_vfy.c;h=79dae3d3bf23702b009864bf9d37f03a95eba9e5;hp=4d9b53e997aa592dd5172853f58dbdffaa1b460b;hb=0b0a60d861e7b13e8a3c1198fbe02585adac023e;hpb=5d7c222db8f26a53c00646cc1dde2bdded38027e diff --git a/crypto/x509/x509_vfy.c b/crypto/x509/x509_vfy.c index 4d9b53e997..79dae3d3bf 100644 --- a/crypto/x509/x509_vfy.c +++ b/crypto/x509/x509_vfy.c @@ -73,7 +73,7 @@ static int null_callback(int ok,X509_STORE_CTX *e); 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_chain_extensions(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); @@ -102,7 +102,7 @@ int X509_verify_cert(X509_STORE_CTX *ctx) X509_VERIFY_PARAM *param = ctx->param; int depth,i,ok=0; int num; - int (*cb)(); + int (*cb)(int xok,X509_STORE_CTX *xctx); STACK_OF(X509) *sktmp=NULL; if (ctx->cert == NULL) { @@ -285,7 +285,7 @@ int X509_verify_cert(X509_STORE_CTX *ctx) } /* We have the chain complete: now we need to check its purpose */ - if (param->purpose > 0) ok = check_chain_purpose(ctx); + ok = check_chain_extensions(ctx); if (!ok) goto end; @@ -381,15 +381,34 @@ static int get_issuer_sk(X509 **issuer, X509_STORE_CTX *ctx, X509 *x) * with the supplied purpose */ -static int check_chain_purpose(X509_STORE_CTX *ctx) +static int check_chain_extensions(X509_STORE_CTX *ctx) { #ifdef OPENSSL_NO_CHAIN_VERIFY return 1; #else - int i, ok=0; + int i, ok=0, must_be_ca; X509 *x; - int (*cb)(); + int (*cb)(int xok,X509_STORE_CTX *xctx); + int proxy_path_length = 0; + int allow_proxy_certs = + !!(ctx->param->flags & X509_V_FLAG_ALLOW_PROXY_CERTS); cb=ctx->verify_cb; + + /* must_be_ca can have 1 of 3 values: + -1: we accept both CA and non-CA certificates, to allow direct + use of self-signed certificates (which are marked as CA). + 0: we only accept non-CA certificates. This is currently not + used, but the possibility is present for future extensions. + 1: we only accept CA certificates. This is currently used for + all certificates in the chain except the leaf certificate. + */ + must_be_ca = -1; + + /* A hack to keep people who don't want to modify their software + happy */ + if (getenv("OPENSSL_ALLOW_PROXY_CERTS")) + allow_proxy_certs = 1; + /* Check all untrusted certificates */ for (i = 0; i < ctx->last_untrusted; i++) { @@ -404,23 +423,73 @@ static int check_chain_purpose(X509_STORE_CTX *ctx) ok=cb(0,ctx); if (!ok) goto end; } - ret = X509_check_purpose(x, ctx->param->purpose, i); - if ((ret == 0) - || ((ctx->param->flags & X509_V_FLAG_X509_STRICT) - && (ret != 1))) + if (!allow_proxy_certs && (x->ex_flags & EXFLAG_PROXY)) { - if (i) + ctx->error = X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED; + ctx->error_depth = i; + ctx->current_cert = x; + ok=cb(0,ctx); + if (!ok) goto end; + } + ret = X509_check_ca(x); + switch(must_be_ca) + { + case -1: + if ((ctx->param->flags & X509_V_FLAG_X509_STRICT) + && (ret != 1) && (ret != 0)) + { + ret = 0; ctx->error = X509_V_ERR_INVALID_CA; + } else - ctx->error = X509_V_ERR_INVALID_PURPOSE; + ret = 1; + break; + case 0: + if (ret != 0) + { + ret = 0; + ctx->error = X509_V_ERR_INVALID_NON_CA; + } + else + ret = 1; + break; + default: + if ((ret == 0) + || ((ctx->param->flags & X509_V_FLAG_X509_STRICT) + && (ret != 1))) + { + ret = 0; + ctx->error = X509_V_ERR_INVALID_CA; + } + else + ret = 1; + break; + } + if (ret == 0) + { ctx->error_depth = i; ctx->current_cert = x; ok=cb(0,ctx); if (!ok) goto end; } + if (ctx->param->purpose > 0) + { + ret = X509_check_purpose(x, ctx->param->purpose, + must_be_ca > 0); + if ((ret == 0) + || ((ctx->param->flags & X509_V_FLAG_X509_STRICT) + && (ret != 1))) + { + ctx->error = X509_V_ERR_INVALID_PURPOSE; + ctx->error_depth = i; + ctx->current_cert = x; + ok=cb(0,ctx); + if (!ok) goto end; + } + } /* Check pathlen */ if ((i > 1) && (x->ex_pathlen != -1) - && (i > (x->ex_pathlen + 1))) + && (i > (x->ex_pathlen + proxy_path_length + 1))) { ctx->error = X509_V_ERR_PATH_LENGTH_EXCEEDED; ctx->error_depth = i; @@ -428,6 +497,26 @@ static int check_chain_purpose(X509_STORE_CTX *ctx) ok=cb(0,ctx); if (!ok) goto end; } + /* If this certificate is a proxy certificate, the next + certificate must be another proxy certificate or a EE + certificate. If not, the next certificate must be a + CA certificate. */ + if (x->ex_flags & EXFLAG_PROXY) + { + if (x->ex_pcpathlen != -1 && i > x->ex_pcpathlen) + { + ctx->error = + X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED; + ctx->error_depth = i; + ctx->current_cert = x; + ok=cb(0,ctx); + if (!ok) goto end; + } + proxy_path_length++; + must_be_ca = 0; + } + else + must_be_ca = 1; } ok = 1; end: @@ -442,7 +531,7 @@ static int check_trust(X509_STORE_CTX *ctx) #else int i, ok; X509 *x; - int (*cb)(); + int (*cb)(int xok,X509_STORE_CTX *xctx); cb=ctx->verify_cb; /* For now just check the last certificate in the chain */ i = sk_X509_num(ctx->chain) - 1; @@ -687,7 +776,8 @@ static int check_crl(X509_STORE_CTX *ctx, X509_CRL *crl) } } - if (!check_crl_time(ctx, crl, 1)) + ok = check_crl_time(ctx, crl, 1); + if (!ok) goto err; ok = 1; @@ -706,6 +796,15 @@ static int cert_crl(X509_STORE_CTX *ctx, X509_CRL *crl, X509 *x) 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. @@ -747,11 +846,11 @@ static int cert_crl(X509_STORE_CTX *ctx, X509_CRL *crl, X509 *x) static int check_policy(X509_STORE_CTX *ctx) { int ret; - ret = X509_policy_check(&ctx->tree, &ctx->explicit, ctx->chain, + ret = X509_policy_check(&ctx->tree, &ctx->explicit_policy, ctx->chain, ctx->param->policies, ctx->param->flags); if (ret == 0) { - X509err(X509_F_X509_VERIFY_CERT,ERR_R_MALLOC_FAILURE); + X509err(X509_F_CHECK_POLICY,ERR_R_MALLOC_FAILURE); return 0; } /* Invalid or inconsistent extensions */ @@ -843,7 +942,7 @@ static int internal_verify(X509_STORE_CTX *ctx) int ok=0,n; X509 *xs,*xi; EVP_PKEY *pkey=NULL; - int (*cb)(); + int (*cb)(int xok,X509_STORE_CTX *xctx); cb=ctx->verify_cb; @@ -908,10 +1007,12 @@ static int internal_verify(X509_STORE_CTX *ctx) xs->valid = 1; - if (!check_cert_time(ctx, xs)) + ok = check_cert_time(ctx, xs); + if (!ok) goto end; /* The last error (if any) is still in the error value */ + ctx->current_issuer=xi; ctx->current_cert=xs; ok=(*cb)(1,ctx); if (!ok) goto end; @@ -980,7 +1081,7 @@ int X509_cmp_time(ASN1_TIME *ctm, time_t *cmp_time) offset=0; else { - if ((*str != '+') && (str[5] != '-')) + if ((*str != '+') && (*str != '-')) return 0; offset=((str[1]-'0')*10+(str[2]-'0'))*60; offset+=(str[3]-'0')*10+(str[4]-'0'); @@ -991,7 +1092,8 @@ int X509_cmp_time(ASN1_TIME *ctm, time_t *cmp_time) atm.length=sizeof(buff2); atm.data=(unsigned char *)buff2; - X509_time_adj(&atm,-offset*60, cmp_time); + if (X509_time_adj(&atm,-offset*60, cmp_time) == NULL) + return 0; if (ctm->type == V_ASN1_UTCTIME) { @@ -1246,7 +1348,7 @@ int X509_STORE_CTX_init(X509_STORE_CTX *ctx, X509_STORE *store, X509 *x509, ctx->valid=0; ctx->chain=NULL; ctx->error=0; - ctx->explicit=0; + ctx->explicit_policy=0; ctx->error_depth=0; ctx->current_cert=NULL; ctx->current_issuer=NULL; @@ -1398,7 +1500,7 @@ X509_POLICY_TREE *X509_STORE_CTX_get0_policy_tree(X509_STORE_CTX *ctx) int X509_STORE_CTX_get_explicit_policy(X509_STORE_CTX *ctx) { - return ctx->explicit; + return ctx->explicit_policy; } int X509_STORE_CTX_set_default(X509_STORE_CTX *ctx, const char *name)