X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=blobdiff_plain;f=crypto%2Fx509%2Fx509_vfy.c;h=6f3274c3a20bb95790a88819761ba652482496d6;hp=05dcd8b0a32182cc548cd1940f9159d44242bbcc;hb=fa0f834c204020e9d2ce5508070f7a2eda663442;hpb=002e66c0e81f94ac01d9a206e43eabb7f1c72a74 diff --git a/crypto/x509/x509_vfy.c b/crypto/x509/x509_vfy.c index 05dcd8b0a3..6f3274c3a2 100644 --- a/crypto/x509/x509_vfy.c +++ b/crypto/x509/x509_vfy.c @@ -70,6 +70,44 @@ #include #include +/* CRL score values */ + +/* No unhandled critical extensions */ + +#define CRL_SCORE_NOCRITICAL 0x100 + +/* certificate is within CRL scope */ + +#define CRL_SCORE_SCOPE 0x080 + +/* CRL times valid */ + +#define CRL_SCORE_TIME 0x040 + +/* Issuer name matches certificate */ + +#define CRL_SCORE_ISSUER_NAME 0x020 + +/* If this score or above CRL is probably valid */ + +#define CRL_SCORE_VALID (CRL_SCORE_NOCRITICAL|CRL_SCORE_TIME|CRL_SCORE_SCOPE) + +/* CRL issuer is certificate issuer */ + +#define CRL_SCORE_ISSUER_CERT 0x018 + +/* CRL issuer is on certificate path */ + +#define CRL_SCORE_SAME_PATH 0x008 + +/* CRL issuer matches CRL AKID */ + +#define CRL_SCORE_AKID 0x004 + +/* Have a delta CRL with valid times */ + +#define CRL_SCORE_TIME_DELTA 0x002 + 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); @@ -79,8 +117,23 @@ 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 check_policy(X509_STORE_CTX *ctx); -static int crl_akid_check(X509_STORE_CTX *ctx, X509_CRL *crl, X509 **pissuer); -static int idp_check_scope(X509 *x, X509_CRL *crl); + +static int get_crl_score(X509_STORE_CTX *ctx, X509 **pissuer, + unsigned int *preasons, + X509_CRL *crl, X509 *x); +static int get_crl_delta(X509_STORE_CTX *ctx, + X509_CRL **pcrl, X509_CRL **pdcrl, X509 *x); +static void get_delta_sk(X509_STORE_CTX *ctx, X509_CRL **dcrl, int *pcrl_score, + X509_CRL *base, STACK_OF(X509_CRL) *crls); +static void crl_akid_check(X509_STORE_CTX *ctx, X509_CRL *crl, + X509 **pissuer, int *pcrl_score); +static int crl_crldp_check(X509 *x, X509_CRL *crl, int crl_score, + unsigned int *preasons); +static int check_crl_path(X509_STORE_CTX *ctx, X509 *x); +static int check_crl_chain(X509_STORE_CTX *ctx, + STACK_OF(X509) *cert_path, + STACK_OF(X509) *crl_path); + static int internal_verify(X509_STORE_CTX *ctx); const char X509_version[]="X.509" OPENSSL_VERSION_PTEXT; @@ -407,8 +460,8 @@ static int check_chain_extensions(X509_STORE_CTX *ctx) X509 *x; 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); + int purpose; + int allow_proxy_certs; cb=ctx->verify_cb; /* must_be_ca can have 1 of 3 values: @@ -421,10 +474,22 @@ static int check_chain_extensions(X509_STORE_CTX *ctx) */ 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; + /* CRL path validation */ + if (ctx->parent) + { + allow_proxy_certs = 0; + purpose = X509_PURPOSE_CRL_SIGN; + } + else + { + allow_proxy_certs = + !!(ctx->param->flags & X509_V_FLAG_ALLOW_PROXY_CERTS); + /* A hack to keep people who don't want to modify their + software happy */ + if (getenv("OPENSSL_ALLOW_PROXY_CERTS")) + allow_proxy_certs = 1; + purpose = ctx->param->purpose; + } /* Check all untrusted certificates */ for (i = 0; i < ctx->last_untrusted; i++) @@ -491,8 +556,7 @@ static int check_chain_extensions(X509_STORE_CTX *ctx) } if (ctx->param->purpose > 0) { - ret = X509_check_purpose(x, ctx->param->purpose, - must_be_ca > 0); + ret = X509_check_purpose(x, purpose, must_be_ca > 0); if ((ret == 0) || ((ctx->param->flags & X509_V_FLAG_X509_STRICT) && (ret != 1))) @@ -627,31 +691,65 @@ static int check_revocation(X509_STORE_CTX *ctx) static int check_cert(X509_STORE_CTX *ctx) { - X509_CRL *crl = NULL; + X509_CRL *crl = NULL, *dcrl = NULL; X509 *x; int ok, cnum; cnum = ctx->error_depth; x = sk_X509_value(ctx->chain, cnum); ctx->current_cert = x; ctx->current_issuer = NULL; - /* 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->current_reasons = 0; + while (ctx->current_reasons != CRLDP_ALL_REASONS) { - ctx->error = X509_V_ERR_UNABLE_TO_GET_CRL; - ok = ctx->verify_cb(0, ctx); - goto err; + /* Try to retrieve relevant CRL */ + if (ctx->get_crl) + ok = ctx->get_crl(ctx, &crl, x); + else + ok = get_crl_delta(ctx, &crl, &dcrl, 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; + + if (dcrl) + { + ok = ctx->check_crl(ctx, dcrl); + if (!ok) + goto err; + ok = ctx->cert_crl(ctx, dcrl, x); + if (!ok) + goto err; + } + else + ok = 1; + + /* Don't look in full CRL if delta reason is removefromCRL */ + if (ok != 2) + { + ok = ctx->cert_crl(ctx, crl, x); + if (!ok) + goto err; + } + + X509_CRL_free(crl); + X509_CRL_free(dcrl); + crl = NULL; + dcrl = NULL; } - 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); + X509_CRL_free(dcrl); + + ctx->current_crl = NULL; return ok; } @@ -662,7 +760,8 @@ static int check_crl_time(X509_STORE_CTX *ctx, X509_CRL *crl, int notify) { time_t *ptime; int i; - ctx->current_crl = crl; + if (notify) + ctx->current_crl = crl; if (ctx->param->flags & X509_V_FLAG_USE_CHECK_TIME) ptime = &ctx->param->check_time; else @@ -671,15 +770,19 @@ static int check_crl_time(X509_STORE_CTX *ctx, X509_CRL *crl, int notify) i=X509_cmp_time(X509_CRL_get_lastUpdate(crl), ptime); if (i == 0) { + if (!notify) + return 0; ctx->error=X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD; - if (!notify || !ctx->verify_cb(0, ctx)) + if (!ctx->verify_cb(0, ctx)) return 0; } if (i > 0) { + if (!notify) + return 0; ctx->error=X509_V_ERR_CRL_NOT_YET_VALID; - if (!notify || !ctx->verify_cb(0, ctx)) + if (!ctx->verify_cb(0, ctx)) return 0; } @@ -689,137 +792,366 @@ static int check_crl_time(X509_STORE_CTX *ctx, X509_CRL *crl, int notify) if (i == 0) { + if (!notify) + return 0; ctx->error=X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD; - if (!notify || !ctx->verify_cb(0, ctx)) + if (!ctx->verify_cb(0, ctx)) return 0; } - - if (i < 0) + /* Ignore expiry of base CRL is delta is valid */ + if ((i < 0) && !(ctx->current_crl_score & CRL_SCORE_TIME_DELTA)) { + if (!notify) + return 0; ctx->error=X509_V_ERR_CRL_HAS_EXPIRED; - if (!notify || !ctx->verify_cb(0, ctx)) + if (!ctx->verify_cb(0, ctx)) return 0; } } - ctx->current_crl = NULL; + if (notify) + ctx->current_crl = NULL; return 1; } -/* Based on a set of possible CRLs decide which one is best suited - * to handle the current certificate. This is determined by a number - * of criteria. If any of the "must" criteria is not satisfied then - * the candidate CRL is rejected. If all "must" and all "should" are - * satisfied the CRL is accepted. If no CRL satisfies all criteria then - * a "best CRL" is used to provide some meaningful error information. - * - * CRL issuer name must match "nm" if not NULL. - * If IDP is present: - * a. it must be consistent. - * b. onlyuser, onlyCA, onlyAA should match certificate being checked. - * c. indirectCRL must be FALSE. - * d. onlysomereason must be absent. - * e. if name present a DP in certificate CRLDP must match. - * If AKID present it should match certificate AKID. - * Check time should fall between lastUpdate and nextUpdate. - */ - -/* IDP name field matches CRLDP or IDP name not present */ -#define CRL_SCORE_SCOPE 4 -/* AKID present and matches cert, or AKID not present */ -#define CRL_SCORE_AKID 2 -/* times OK */ -#define CRL_SCORE_TIME 1 - -#define CRL_SCORE_ALL 7 - -/* IDP flags which cause a CRL to be rejected */ - -#define IDP_REJECT (IDP_INVALID|IDP_INDIRECT|IDP_REASONS) - -static int get_crl_sk(X509_STORE_CTX *ctx, X509_CRL **pcrl, - X509_NAME *nm, STACK_OF(X509_CRL) *crls) +static int get_crl_sk(X509_STORE_CTX *ctx, X509_CRL **pcrl, X509_CRL **pdcrl, + X509 **pissuer, int *pscore, unsigned int *preasons, + STACK_OF(X509_CRL) *crls) { - int i, crl_score, best_score = -1; + int i, crl_score, best_score = *pscore; + unsigned int reasons, best_reasons = 0; + X509 *x = ctx->current_cert; X509_CRL *crl, *best_crl = NULL; - X509 *crl_issuer, *best_crl_issuer = NULL; + X509 *crl_issuer = NULL, *best_crl_issuer = NULL; + for (i = 0; i < sk_X509_CRL_num(crls); i++) { - crl_score = 0; - crl_issuer = NULL; crl = sk_X509_CRL_value(crls, i); - if (nm && X509_NAME_cmp(nm, X509_CRL_get_issuer(crl))) - continue; - if (check_crl_time(ctx, crl, 0)) - crl_score |= CRL_SCORE_TIME; - - if (crl->idp_flags & IDP_PRESENT) - { - if (crl->idp_flags & IDP_REJECT) - continue; - if (idp_check_scope(ctx->current_cert, crl)) - crl_score |= CRL_SCORE_SCOPE; - } - else - crl_score |= CRL_SCORE_SCOPE; - - if (crl_akid_check(ctx, crl, &crl_issuer)) - crl_score |= CRL_SCORE_AKID; - /* If CRL matches criteria and issuer is not different use it */ - if (crl_score == CRL_SCORE_ALL && !crl_issuer) - { - *pcrl = crl; - CRYPTO_add(&crl->references, 1, CRYPTO_LOCK_X509_CRL); - return 1; - } + reasons = *preasons; + crl_score = get_crl_score(ctx, &crl_issuer, &reasons, crl, x); if (crl_score > best_score) { best_crl = crl; best_crl_issuer = crl_issuer; best_score = crl_score; + best_reasons = reasons; } } + if (best_crl) { + if (*pcrl) + X509_CRL_free(*pcrl); *pcrl = best_crl; - ctx->current_issuer = best_crl_issuer; - CRYPTO_add(&best_crl->references, 1, CRYPTO_LOCK_X509); + *pissuer = best_crl_issuer; + *pscore = best_score; + *preasons = best_reasons; + CRYPTO_add(&best_crl->references, 1, CRYPTO_LOCK_X509_CRL); + if (*pdcrl) + { + X509_CRL_free(*pdcrl); + *pdcrl = NULL; + } + get_delta_sk(ctx, pdcrl, pscore, best_crl, crls); } + if (best_score >= CRL_SCORE_VALID) + return 1; + return 0; } -static int crl_akid_check(X509_STORE_CTX *ctx, X509_CRL *crl, X509 **pissuer) +/* Compare two CRL extensions for delta checking purposes. They should be + * both present or both absent. If both present all fields must be identical. + */ + +static int crl_extension_match(X509_CRL *a, X509_CRL *b, int nid) { - X509 *crl_issuer; - int cidx = ctx->error_depth; - if (!crl->akid) + ASN1_OCTET_STRING *exta, *extb; + int i; + i = X509_CRL_get_ext_by_NID(a, nid, 0); + if (i >= 0) + { + /* Can't have multiple occurrences */ + if (X509_CRL_get_ext_by_NID(a, nid, i) != -1) + return 0; + exta = X509_EXTENSION_get_data(X509_CRL_get_ext(a, i)); + } + else + exta = NULL; + + i = X509_CRL_get_ext_by_NID(b, nid, 0); + + if (i >= 0) + { + + if (X509_CRL_get_ext_by_NID(b, nid, i) != -1) + return 0; + extb = X509_EXTENSION_get_data(X509_CRL_get_ext(b, i)); + } + else + extb = NULL; + + if (!exta && !extb) return 1; + + if (!exta || !extb) + return 0; + + + if (ASN1_OCTET_STRING_cmp(exta, extb)) + return 0; + + return 1; + } + +/* See if a base and delta are compatible */ + +static int check_delta_base(X509_CRL *delta, X509_CRL *base) + { + /* Delta CRL must be a delta */ + if (!delta->base_crl_number) + return 0; + /* Base must have a CRL number */ + if (!base->crl_number) + return 0; + /* Issuer names must match */ + if (X509_NAME_cmp(X509_CRL_get_issuer(base), + X509_CRL_get_issuer(delta))) + return 0; + /* AKID and IDP must match */ + if (!crl_extension_match(delta, base, NID_authority_key_identifier)) + return 0; + if (!crl_extension_match(delta, base, NID_issuing_distribution_point)) + return 0; + /* Delta CRL base number must not exceed Full CRL number. */ + if (ASN1_INTEGER_cmp(delta->base_crl_number, base->crl_number) > 0) + return 0; + /* Delta CRL number must exceed full CRL number */ + if (ASN1_INTEGER_cmp(delta->crl_number, base->crl_number) > 0) + return 1; + return 0; + } + +/* For a given base CRL find a delta... maybe extend to delta scoring + * or retrieve a chain of deltas... + */ + +static void get_delta_sk(X509_STORE_CTX *ctx, X509_CRL **dcrl, int *pscore, + X509_CRL *base, STACK_OF(X509_CRL) *crls) + { + X509_CRL *delta; + int i; + if (!(ctx->param->flags & X509_V_FLAG_USE_DELTAS)) + return; + if (!((ctx->current_cert->ex_flags | base->flags) & EXFLAG_FRESHEST)) + return; + for (i = 0; i < sk_X509_CRL_num(crls); i++) + { + delta = sk_X509_CRL_value(crls, i); + if (check_delta_base(delta, base)) + { + if (check_crl_time(ctx, delta, 0)) + *pscore |= CRL_SCORE_TIME_DELTA; + CRYPTO_add(&delta->references, 1, CRYPTO_LOCK_X509_CRL); + *dcrl = delta; + return; + } + } + *dcrl = NULL; + } + +/* For a given CRL return how suitable it is for the supplied certificate 'x'. + * The return value is a mask of several criteria. + * If the issuer is not the certificate issuer this is returned in *pissuer. + * The reasons mask is also used to determine if the CRL is suitable: if + * no new reasons the CRL is rejected, otherwise reasons is updated. + */ + +static int get_crl_score(X509_STORE_CTX *ctx, X509 **pissuer, + unsigned int *preasons, + X509_CRL *crl, X509 *x) + { + + int crl_score = 0; + unsigned int tmp_reasons = *preasons, crl_reasons; + + /* First see if we can reject CRL straight away */ + + /* Invalid IDP cannot be processed */ + if (crl->idp_flags & IDP_INVALID) + return 0; + /* Reason codes or indirect CRLs need extended CRL support */ + if (!(ctx->param->flags & X509_V_FLAG_EXTENDED_CRL_SUPPORT)) + { + if (crl->idp_flags & (IDP_INDIRECT | IDP_REASONS)) + return 0; + } + else if (crl->idp_flags & IDP_REASONS) + { + /* If no new reasons reject */ + if (!(crl->idp_reasons & ~tmp_reasons)) + return 0; + } + /* Don't process deltas at this stage */ + else if (crl->base_crl_number) + return 0; + /* If issuer name doesn't match certificate need indirect CRL */ + if (X509_NAME_cmp(X509_get_issuer_name(x), X509_CRL_get_issuer(crl))) + { + if (!(crl->idp_flags & IDP_INDIRECT)) + return 0; + } + else + crl_score |= CRL_SCORE_ISSUER_NAME; + + if (!(crl->flags & EXFLAG_CRITICAL)) + crl_score |= CRL_SCORE_NOCRITICAL; + + /* Check expiry */ + if (check_crl_time(ctx, crl, 0)) + crl_score |= CRL_SCORE_TIME; + + /* Check authority key ID and locate certificate issuer */ + crl_akid_check(ctx, crl, pissuer, &crl_score); + + /* If we can't locate certificate issuer at this point forget it */ + + if (!(crl_score & CRL_SCORE_AKID)) + return 0; + + /* Check cert for matching CRL distribution points */ + + if (crl_crldp_check(x, crl, crl_score, &crl_reasons)) + { + /* If no new reasons reject */ + if (!(crl_reasons & ~tmp_reasons)) + return 0; + tmp_reasons |= crl_reasons; + crl_score |= CRL_SCORE_SCOPE; + } + + *preasons = tmp_reasons; + + return crl_score; + + } + +static void crl_akid_check(X509_STORE_CTX *ctx, X509_CRL *crl, + X509 **pissuer, int *pcrl_score) + { + X509 *crl_issuer = NULL; + X509_NAME *cnm = X509_CRL_get_issuer(crl); + int cidx = ctx->error_depth; + int i; + if (cidx != sk_X509_num(ctx->chain) - 1) cidx++; + crl_issuer = sk_X509_value(ctx->chain, cidx); + if (X509_check_akid(crl_issuer, crl->akid) == X509_V_OK) - return 1; - /* If crl_issuer is self issued we may get a match further along the - * chain. + { + if (*pcrl_score & CRL_SCORE_ISSUER_NAME) + { + *pcrl_score |= CRL_SCORE_AKID|CRL_SCORE_ISSUER_CERT; + *pissuer = crl_issuer; + return; + } + } + + for (cidx++; cidx < sk_X509_num(ctx->chain); cidx++) + { + crl_issuer = sk_X509_value(ctx->chain, cidx); + if (X509_NAME_cmp(X509_get_subject_name(crl_issuer), cnm)) + continue; + if (X509_check_akid(crl_issuer, crl->akid) == X509_V_OK) + { + *pcrl_score |= CRL_SCORE_AKID|CRL_SCORE_SAME_PATH; + *pissuer = crl_issuer; + return; + } + } + + /* Anything else needs extended CRL support */ + + if (!(ctx->param->flags & X509_V_FLAG_EXTENDED_CRL_SUPPORT)) + return; + + /* Otherwise the CRL issuer is not on the path. Look for it in the + * set of untrusted certificates. */ - if (crl_issuer->ex_flags & EXFLAG_SI) + for (i = 0; i < sk_X509_num(ctx->untrusted); i++) { - for (cidx++; cidx < sk_X509_num(ctx->chain); cidx++) + crl_issuer = sk_X509_value(ctx->untrusted, i); + if (X509_NAME_cmp(X509_get_subject_name(crl_issuer), cnm)) + continue; + if (X509_check_akid(crl_issuer, crl->akid) == X509_V_OK) { - crl_issuer = sk_X509_value(ctx->chain, cidx); - if (X509_check_akid(crl_issuer, crl->akid) == X509_V_OK) - { - *pissuer = crl_issuer; - return 1; - } - if (!(crl_issuer->ex_flags & EXFLAG_SI)) - break; + *pissuer = crl_issuer; + *pcrl_score |= CRL_SCORE_AKID; + return; } } - + } + +/* Check the path of a CRL issuer certificate. This creates a new + * X509_STORE_CTX and populates it with most of the parameters from the + * parent. This could be optimised somewhat since a lot of path checking + * will be duplicated by the parent, but this will rarely be used in + * practice. + */ + +static int check_crl_path(X509_STORE_CTX *ctx, X509 *x) + { + X509_STORE_CTX crl_ctx; + int ret; + /* Don't allow recursive CRL path validation */ + if (ctx->parent) + return 0; + if (!X509_STORE_CTX_init(&crl_ctx, ctx->ctx, x, ctx->untrusted)) + return -1; + + crl_ctx.crls = ctx->crls; + /* Copy verify params across */ + X509_STORE_CTX_set0_param(&crl_ctx, ctx->param); + + crl_ctx.parent = ctx; + crl_ctx.verify_cb = ctx->verify_cb; + + /* Verify CRL issuer */ + ret = X509_verify_cert(&crl_ctx); + + if (!ret) + goto err; + + /* Check chain is acceptable */ + + ret = check_crl_chain(ctx, ctx->chain, crl_ctx.chain); + err: + X509_STORE_CTX_cleanup(&crl_ctx); + return ret; + } + +/* RFC3280 says nothing about the relationship between CRL path + * and certificate path, which could lead to situations where a + * certificate could be revoked or validated by a CA not authorised + * to do so. RFC5280 is more strict and states that the two paths must + * end in the same trust anchor, though some discussions remain... + * until this is resolved we use the RFC5280 version + */ + +static int check_crl_chain(X509_STORE_CTX *ctx, + STACK_OF(X509) *cert_path, + STACK_OF(X509) *crl_path) + { + X509 *cert_ta, *crl_ta; + cert_ta = sk_X509_value(cert_path, sk_X509_num(cert_path) - 1); + crl_ta = sk_X509_value(crl_path, sk_X509_num(crl_path) - 1); + if (!X509_cmp(cert_ta, crl_ta)) + return 1; return 0; } @@ -827,6 +1159,7 @@ static int crl_akid_check(X509_STORE_CTX *ctx, X509_CRL *crl, X509 **pissuer) * 1. Both are relative names and compare X509_NAME types. * 2. One full, one relative. Compare X509_NAME to GENERAL_NAMES. * 3. Both are full names and compare two GENERAL_NAMES. + * 4. One is NULL: automatic match. */ @@ -836,6 +1169,8 @@ static int idp_check_dp(DIST_POINT_NAME *a, DIST_POINT_NAME *b) GENERAL_NAMES *gens = NULL; GENERAL_NAME *gena, *genb; int i, j; + if (!a || !b) + return 1; if (a->type == 1) { if (!a->dpname) @@ -894,9 +1229,28 @@ static int idp_check_dp(DIST_POINT_NAME *a, DIST_POINT_NAME *b) } -/* Check IDP name matches at least one CRLDP name */ +static int crldp_check_crlissuer(DIST_POINT *dp, X509_CRL *crl, int crl_score) + { + int i; + X509_NAME *nm = X509_CRL_get_issuer(crl); + /* If no CRLissuer return is successful iff don't need a match */ + if (!dp->CRLissuer) + return !!(crl_score & CRL_SCORE_ISSUER_NAME); + for (i = 0; i < sk_GENERAL_NAME_num(dp->CRLissuer); i++) + { + GENERAL_NAME *gen = sk_GENERAL_NAME_value(dp->CRLissuer, i); + if (gen->type != GEN_DIRNAME) + continue; + if (!X509_NAME_cmp(gen->d.directoryName, nm)) + return 1; + } + return 0; + } + +/* Check CRLDP and IDP */ -static int idp_check_scope(X509 *x, X509_CRL *crl) +static int crl_crldp_check(X509 *x, X509_CRL *crl, int crl_score, + unsigned int *preasons) { int i; if (crl->idp_flags & IDP_ONLYATTR) @@ -911,64 +1265,68 @@ static int idp_check_scope(X509 *x, X509_CRL *crl) if (crl->idp_flags & IDP_ONLYCA) return 0; } - if (!crl->idp->distpoint) - return 1; - if (!x->crldp) - return 0; + *preasons = crl->idp_reasons; for (i = 0; i < sk_DIST_POINT_num(x->crldp); i++) { DIST_POINT *dp = sk_DIST_POINT_value(x->crldp, i); - /* We don't handle these at present */ - if (dp->reasons || dp->CRLissuer) - continue; - if (idp_check_dp(dp->distpoint, crl->idp->distpoint)) - return 1; + if (crldp_check_crlissuer(dp, crl, crl_score)) + { + if (!crl->idp || + idp_check_dp(dp->distpoint, crl->idp->distpoint)) + { + *preasons &= dp->dp_reasons; + return 1; + } + } } + if ((!crl->idp || !crl->idp->distpoint) && (crl_score & CRL_SCORE_ISSUER_NAME)) + return 1; return 0; } -/* Retrieve CRL corresponding to current certificate. Currently only - * one CRL is retrieved. Multiple CRLs may be needed if we handle - * CRLs partitioned on reason code later. +/* Retrieve CRL corresponding to current certificate. + * If deltas enabled try to find a delta CRL too */ -static int get_crl(X509_STORE_CTX *ctx, X509_CRL **pcrl, X509 *x) +static int get_crl_delta(X509_STORE_CTX *ctx, + X509_CRL **pcrl, X509_CRL **pdcrl, X509 *x) { int ok; - X509_CRL *crl = NULL; + X509 *issuer = NULL; + int crl_score = 0; + unsigned int reasons; + X509_CRL *crl = NULL, *dcrl = NULL; STACK_OF(X509_CRL) *skcrl; - X509_NAME *nm; - nm = X509_get_issuer_name(x); - ok = get_crl_sk(ctx, &crl, nm, ctx->crls); + X509_NAME *nm = X509_get_issuer_name(x); + reasons = ctx->current_reasons; + ok = get_crl_sk(ctx, &crl, &dcrl, + &issuer, &crl_score, &reasons, ctx->crls); + if (ok) - { - *pcrl = crl; - return 1; - } + goto done; /* Lookup CRLs from store */ skcrl = ctx->lookup_crls(ctx, nm); /* If no CRLs found and a near match from get_crl_sk use that */ - if (!skcrl) - { - if (crl) - { - *pcrl = crl; - return 1; - } - return 0; - } + if (!skcrl && crl) + goto done; - get_crl_sk(ctx, &crl, NULL, skcrl); + get_crl_sk(ctx, &crl, &dcrl, &issuer, &crl_score, &reasons, skcrl); sk_X509_CRL_pop_free(skcrl, X509_CRL_free); + done: + /* If we got any kind of CRL use it and return success */ if (crl) { + ctx->current_issuer = issuer; + ctx->current_crl_score = crl_score; + ctx->current_reasons = reasons; *pcrl = crl; + *pdcrl = dcrl; return 1; } @@ -986,6 +1344,7 @@ static int check_crl(X509_STORE_CTX *ctx, X509_CRL *crl) /* if we have an alternative CRL issuer cert use that */ if (ctx->current_issuer) issuer = ctx->current_issuer; + /* Else find CRL issuer: if not last certificate then issuer * is next certificate in chain. */ @@ -1005,35 +1364,52 @@ static int check_crl(X509_STORE_CTX *ctx, X509_CRL *crl) if(issuer) { - /* Check for cRLSign bit if keyUsage present */ - if ((issuer->ex_flags & EXFLAG_KUSAGE) && - !(issuer->ex_kusage & KU_CRL_SIGN)) - { - ctx->error = X509_V_ERR_KEYUSAGE_NO_CRL_SIGN; - ok = ctx->verify_cb(0, ctx); - if(!ok) goto err; - } - - if (crl->idp_flags & IDP_PRESENT) + /* Skip most tests for deltas because they have already + * been done + */ + if (!crl->base_crl_number) { - if (crl->idp_flags & IDP_INVALID) + /* Check for cRLSign bit if keyUsage present */ + if ((issuer->ex_flags & EXFLAG_KUSAGE) && + !(issuer->ex_kusage & KU_CRL_SIGN)) { - ctx->error = X509_V_ERR_INVALID_EXTENSION; + ctx->error = X509_V_ERR_KEYUSAGE_NO_CRL_SIGN; ok = ctx->verify_cb(0, ctx); if(!ok) goto err; } - if (crl->idp_flags & (IDP_REASONS|IDP_INDIRECT)) + + if (!(ctx->current_crl_score & CRL_SCORE_SCOPE)) { - ctx->error = X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE; + ctx->error = X509_V_ERR_DIFFERENT_CRL_SCOPE; ok = ctx->verify_cb(0, ctx); if(!ok) goto err; } - if (!idp_check_scope(ctx->current_cert, crl)) + + if (!(ctx->current_crl_score & CRL_SCORE_SAME_PATH)) { - ctx->error = X509_V_ERR_DIFFERENT_CRL_SCOPE; + if (!check_crl_path(ctx, ctx->current_issuer)) + { + ctx->error = X509_V_ERR_CRL_PATH_VALIDATION_ERROR; + ok = ctx->verify_cb(0, ctx); + if(!ok) goto err; + } + } + + if (crl->idp_flags & IDP_INVALID) + { + ctx->error = X509_V_ERR_INVALID_EXTENSION; ok = ctx->verify_cb(0, ctx); if(!ok) goto err; } + + + } + + if (!(ctx->current_crl_score & CRL_SCORE_TIME)) + { + ok = check_crl_time(ctx, crl, 1); + if (!ok) + goto err; } /* Attempt to get issuer certificate public key */ @@ -1057,10 +1433,6 @@ static int check_crl(X509_STORE_CTX *ctx, X509_CRL *crl) } } - ok = check_crl_time(ctx, crl, 1); - if (!ok) - goto err; - ok = 1; err: @@ -1072,18 +1444,12 @@ static int check_crl(X509_STORE_CTX *ctx, X509_CRL *crl) static int cert_crl(X509_STORE_CTX *ctx, X509_CRL *crl, X509 *x) { int ok; - /* Look for serial number of certificate in CRL - * If found assume revoked: want something cleverer than - * this to handle entry extensions in V2 CRLs. + X509_REVOKED *rev; + /* The rules changed for this... previously if a CRL contained + * unhandled critical extensions it could still be used to indicate + * a certificate was revoked. This has since been changed since + * critical extension can change the meaning of CRL entries. */ - if (X509_CRL_get0_by_serial(crl, NULL, X509_get_serialNumber(x)) > 0) - { - ctx->error = X509_V_ERR_CERT_REVOKED; - ok = ctx->verify_cb(0, ctx); - if (!ok) - return 0; - } - if (crl->flags & EXFLAG_CRITICAL) { if (ctx->param->flags & X509_V_FLAG_IGNORE_CRITICAL) @@ -1093,6 +1459,18 @@ static int cert_crl(X509_STORE_CTX *ctx, X509_CRL *crl, X509 *x) if(!ok) return 0; } + /* Look for serial number of certificate in CRL + * If found make sure reason is not removeFromCRL. + */ + if (X509_CRL_get0_by_cert(crl, &rev, x)) + { + if (rev->reason == CRL_REASON_REMOVE_FROM_CRL) + return 2; + ctx->error = X509_V_ERR_CERT_REVOKED; + ok = ctx->verify_cb(0, ctx); + if (!ok) + return 0; + } return 1; } @@ -1100,6 +1478,8 @@ static int cert_crl(X509_STORE_CTX *ctx, X509_CRL *crl, X509 *x) static int check_policy(X509_STORE_CTX *ctx) { int ret; + if (ctx->parent) + return 1; ret = X509_policy_check(&ctx->tree, &ctx->explicit_policy, ctx->chain, ctx->param->policies, ctx->param->flags); if (ret == 0) @@ -1608,6 +1988,7 @@ int X509_STORE_CTX_init(X509_STORE_CTX *ctx, X509_STORE *store, X509 *x509, ctx->current_cert=NULL; ctx->current_issuer=NULL; ctx->tree = NULL; + ctx->parent = NULL; ctx->param = X509_VERIFY_PARAM_new(); @@ -1673,7 +2054,7 @@ int X509_STORE_CTX_init(X509_STORE_CTX *ctx, X509_STORE *store, X509 *x509, if (store && store->get_crl) ctx->get_crl = store->get_crl; else - ctx->get_crl = get_crl; + ctx->get_crl = NULL; if (store && store->check_crl) ctx->check_crl = store->check_crl; @@ -1727,7 +2108,8 @@ void X509_STORE_CTX_cleanup(X509_STORE_CTX *ctx) if (ctx->cleanup) ctx->cleanup(ctx); if (ctx->param != NULL) { - X509_VERIFY_PARAM_free(ctx->param); + if (ctx->parent == NULL) + X509_VERIFY_PARAM_free(ctx->param); ctx->param=NULL; } if (ctx->tree != NULL)