Remove no longer reachable CRL path validation code
crl_akid_check now always, on success, leaves CRL_SCORE_SAME_PATH in the
score. (Note CRL_SCORE_ISSUER_CERT contains CRL_SCORE_SAME_PATH.) This
means the recursive validation logic in check_crl_path never runs, and
we can remove a very worrying re-entrant call in the validator. The CRL
must be issued by either the issuer, or some ancestor in the chain.
(This also matches the behavior of the new validator.)
Bug: 601
Change-Id: Ie5c0feb5bb5ade3bfd49e338a637196fce29fd2a
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/63942
Reviewed-by: Bob Beck <bbe@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
diff --git a/crypto/x509/internal.h b/crypto/x509/internal.h
index 36a244b..4256755 100644
--- a/crypto/x509/internal.h
+++ b/crypto/x509/internal.h
@@ -363,8 +363,6 @@
int current_crl_score; // score of current CRL
- X509_STORE_CTX *parent; // For CRL path validation: parent context
-
CRYPTO_EX_DATA ex_data;
} /* X509_STORE_CTX */;
diff --git a/crypto/x509/x509_vfy.c b/crypto/x509/x509_vfy.c
index 78ba18c..acf2d2c 100644
--- a/crypto/x509/x509_vfy.c
+++ b/crypto/x509/x509_vfy.c
@@ -115,12 +115,9 @@
static int get_crl_score(X509_STORE_CTX *ctx, X509 **pissuer, X509_CRL *crl,
X509 *x);
static int get_crl(X509_STORE_CTX *ctx, X509_CRL **pcrl, X509 *x);
-static void crl_akid_check(X509_STORE_CTX *ctx, X509_CRL *crl, X509 **pissuer,
- int *pcrl_score);
+static int 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);
-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);
@@ -533,10 +530,7 @@
static int check_chain_extensions(X509_STORE_CTX *ctx) {
int ok = 0, plen = 0;
-
- // If |ctx->parent| is set, this is CRL path validation.
- int purpose =
- ctx->parent == NULL ? ctx->param->purpose : X509_PURPOSE_CRL_SIGN;
+ int purpose = ctx->param->purpose;
// Check all untrusted certificates
for (int i = 0; i < ctx->last_untrusted; i++) {
@@ -795,10 +789,6 @@
if (ctx->param->flags & X509_V_FLAG_CRL_CHECK_ALL) {
last = (int)sk_X509_num(ctx->chain) - 1;
} else {
- // If checking CRL paths this isn't the EE certificate
- if (ctx->parent) {
- return 1;
- }
last = 0;
}
for (int i = 0; i <= last; i++) {
@@ -849,7 +839,6 @@
}
// Check CRL times against values in X509_STORE_CTX
-
static int check_crl_time(X509_STORE_CTX *ctx, X509_CRL *crl, int notify) {
if (ctx->param->flags & X509_V_FLAG_NO_CHECK_TIME) {
return 1;
@@ -997,11 +986,8 @@
}
// 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)) {
+ if (!crl_akid_check(ctx, crl, pissuer, &crl_score)) {
+ // If we can't locate certificate issuer at this point forget it
return 0;
}
@@ -1013,8 +999,8 @@
return crl_score;
}
-static void crl_akid_check(X509_STORE_CTX *ctx, X509_CRL *crl, X509 **pissuer,
- int *pcrl_score) {
+static int 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;
@@ -1028,7 +1014,7 @@
if (X509_check_akid(crl_issuer, crl->akid) == X509_V_OK) {
*pcrl_score |= CRL_SCORE_AKID | CRL_SCORE_ISSUER_CERT;
*pissuer = crl_issuer;
- return;
+ return 1;
}
for (cidx++; cidx < (int)sk_X509_num(ctx->chain); cidx++) {
@@ -1039,64 +1025,10 @@
if (X509_check_akid(crl_issuer, crl->akid) == X509_V_OK) {
*pcrl_score |= CRL_SCORE_AKID | CRL_SCORE_SAME_PATH;
*pissuer = crl_issuer;
- return;
+ return 1;
}
}
-}
-// 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 <= 0) {
- 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;
-}
-
-// RFC 3280 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. RFC 5280 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
-// RFC 5280 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;
}
@@ -1104,7 +1036,6 @@
// 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.
-
static int idp_check_dp(DIST_POINT_NAME *a, DIST_POINT_NAME *b) {
X509_NAME *nm = NULL;
GENERAL_NAMES *gens = NULL;
@@ -1292,16 +1223,6 @@
}
}
- if (!(ctx->current_crl_score & CRL_SCORE_SAME_PATH)) {
- if (check_crl_path(ctx, ctx->current_issuer) <= 0) {
- 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);
@@ -1374,11 +1295,6 @@
}
static int check_policy(X509_STORE_CTX *ctx) {
- // TODO(davidben): Why do we disable policy validation for CRL paths?
- if (ctx->parent) {
- return 1;
- }
-
X509 *current_cert = NULL;
int ret = X509_policy_check(ctx->chain, ctx->param->policies,
ctx->param->flags, ¤t_cert);
@@ -1635,7 +1551,10 @@
}
X509_STORE_CTX *X509_STORE_CTX_get0_parent_ctx(X509_STORE_CTX *ctx) {
- return ctx->parent;
+ // In OpenSSL, an |X509_STORE_CTX| sometimes has a parent context during CRL
+ // path validation for indirect CRLs. We require the CRL to be issued
+ // somewhere along the certificate path, so this is always NULL.
+ return NULL;
}
void X509_STORE_CTX_set_cert(X509_STORE_CTX *ctx, X509 *x) { ctx->cert = x; }
@@ -1861,16 +1780,10 @@
ctx->cleanup(ctx);
ctx->cleanup = NULL;
}
- if (ctx->param != NULL) {
- if (ctx->parent == NULL) {
- X509_VERIFY_PARAM_free(ctx->param);
- }
- ctx->param = NULL;
- }
- if (ctx->chain != NULL) {
- sk_X509_pop_free(ctx->chain, X509_free);
- ctx->chain = NULL;
- }
+ X509_VERIFY_PARAM_free(ctx->param);
+ ctx->param = NULL;
+ sk_X509_pop_free(ctx->chain, X509_free);
+ ctx->chain = NULL;
CRYPTO_free_ex_data(&g_ex_data_class, ctx, &(ctx->ex_data));
OPENSSL_memset(&ctx->ex_data, 0, sizeof(CRYPTO_EX_DATA));
}
diff --git a/include/openssl/x509.h b/include/openssl/x509.h
index 5e4a6b0..5022f46 100644
--- a/include/openssl/x509.h
+++ b/include/openssl/x509.h
@@ -2380,6 +2380,10 @@
OPENSSL_EXPORT int X509_NAME_get_text_by_NID(const X509_NAME *name, int nid,
char *buf, int len);
+// X509_STORE_CTX_get0_parent_ctx returns NULL.
+OPENSSL_EXPORT X509_STORE_CTX *X509_STORE_CTX_get0_parent_ctx(
+ X509_STORE_CTX *ctx);
+
// Private structures.
@@ -2979,8 +2983,6 @@
OPENSSL_EXPORT X509 *X509_STORE_CTX_get_current_cert(X509_STORE_CTX *ctx);
OPENSSL_EXPORT X509 *X509_STORE_CTX_get0_current_issuer(X509_STORE_CTX *ctx);
OPENSSL_EXPORT X509_CRL *X509_STORE_CTX_get0_current_crl(X509_STORE_CTX *ctx);
-OPENSSL_EXPORT X509_STORE_CTX *X509_STORE_CTX_get0_parent_ctx(
- X509_STORE_CTX *ctx);
OPENSSL_EXPORT STACK_OF(X509) *X509_STORE_CTX_get_chain(X509_STORE_CTX *ctx);
OPENSSL_EXPORT STACK_OF(X509) *X509_STORE_CTX_get0_chain(X509_STORE_CTX *ctx);
OPENSSL_EXPORT STACK_OF(X509) *X509_STORE_CTX_get1_chain(X509_STORE_CTX *ctx);