summaryrefslogtreecommitdiffstats
path: root/crypto/x509/x509_vfy.c
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/x509/x509_vfy.c')
-rw-r--r--crypto/x509/x509_vfy.c52
1 files changed, 29 insertions, 23 deletions
diff --git a/crypto/x509/x509_vfy.c b/crypto/x509/x509_vfy.c
index 5bd3c4c159..87b51e990d 100644
--- a/crypto/x509/x509_vfy.c
+++ b/crypto/x509/x509_vfy.c
@@ -104,7 +104,12 @@ static int null_callback(int ok, X509_STORE_CTX *e)
return ok;
}
-/* Return 1 is a certificate is self signed */
+/*
+ * Return 1 if given cert is considered self-signed, 0 if not or on error.
+ * This does not verify self-signedness but relies on x509v3_cache_extensions()
+ * matching issuer and subject names (i.e., the cert being self-issued) and any
+ * present authority key identifier matching the subject key identifier, etc.
+ */
static int cert_self_signed(X509 *x)
{
if (X509_check_purpose(x, -1, 0) != 1)
@@ -325,30 +330,26 @@ static X509 *find_issuer(X509_STORE_CTX *ctx, STACK_OF(X509) *sk, X509 *x)
return rv;
}
-/* Given a possible certificate and issuer check them */
-
+/*
+ * Check that the given certificate 'x' is issued by the certificate 'issuer'
+ * and the issuer is not yet in ctx->chain, where the exceptional case
+ * that 'x' is self-issued and ctx->chain has just one element is allowed.
+ */
static int check_issued(X509_STORE_CTX *ctx, X509 *x, X509 *issuer)
{
- int ret;
- if (x == issuer)
- return cert_self_signed(x);
- ret = X509_check_issued(issuer, x);
- if (ret == X509_V_OK) {
+ if (x509_likely_issued(issuer, x) != X509_V_OK)
+ return 0;
+ if ((x->ex_flags & EXFLAG_SI) == 0 || sk_X509_num(ctx->chain) != 1) {
int i;
X509 *ch;
- /* Special case: single self signed certificate */
- if (cert_self_signed(x) && sk_X509_num(ctx->chain) == 1)
- return 1;
+
for (i = 0; i < sk_X509_num(ctx->chain); i++) {
ch = sk_X509_value(ctx->chain, i);
- if (ch == issuer || !X509_cmp(ch, issuer)) {
- ret = X509_V_ERR_PATH_LOOP;
- break;
- }
+ if (ch == issuer || X509_cmp(ch, issuer) == 0)
+ return 0;
}
}
-
- return (ret == X509_V_OK);
+ return 1;
}
/* Alternative lookup method: look from a STACK stored in other_ctx */
@@ -1752,18 +1753,23 @@ static int internal_verify(X509_STORE_CTX *ctx)
* is allowed to reset errors (at its own peril).
*/
while (n >= 0) {
- EVP_PKEY *pkey;
-
/*
- * Skip signature check for self signed certificates unless explicitly
- * asked for. It doesn't add any security and just wastes time. If
- * the issuer's public key is unusable, report the issuer certificate
+ * Skip signature check for self-issued certificates unless explicitly
+ * asked for because it does not add any security and just wastes time.
+ * If the issuer's public key is not available or its key usage does
+ * not support issuing the subject cert, report the issuer certificate
* and its depth (rather than the depth of the subject).
*/
if (xs != xi || (ctx->param->flags & X509_V_FLAG_CHECK_SS_SIGNATURE)) {
+ EVP_PKEY *pkey;
+ int issuer_depth = n + (xs == xi ? 0 : 1);
+ int ret = x509_signing_allowed(xi, xs);
+
+ if (ret != X509_V_OK && !verify_cb_cert(ctx, xi, issuer_depth, ret))
+ return 0;
if ((pkey = X509_get0_pubkey(xi)) == NULL) {
if (!verify_cb_cert(ctx, xi, xi != xs ? n+1 : n,
- X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY))
+ X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY))
return 0;
} else if (X509_verify(xs, pkey) <= 0) {
if (!verify_cb_cert(ctx, xs, n,