aboutsummaryrefslogtreecommitdiff
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.c176
1 files changed, 133 insertions, 43 deletions
diff --git a/crypto/x509/x509_vfy.c b/crypto/x509/x509_vfy.c
index 41625e75ad6a..801055f5a087 100644
--- a/crypto/x509/x509_vfy.c
+++ b/crypto/x509/x509_vfy.c
@@ -80,6 +80,7 @@ static int get_issuer_sk(X509 **issuer, X509_STORE_CTX *ctx, X509 *x);
static int check_dane_issuer(X509_STORE_CTX *ctx, int depth);
static int check_key_level(X509_STORE_CTX *ctx, X509 *cert);
static int check_sig_level(X509_STORE_CTX *ctx, X509 *cert);
+static int check_curve(X509 *cert);
static int get_crl_score(X509_STORE_CTX *ctx, X509 **pissuer,
unsigned int *preasons, X509_CRL *crl, X509 *x);
@@ -104,7 +105,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)
@@ -131,10 +137,9 @@ static X509 *lookup_cert_match(X509_STORE_CTX *ctx, X509 *x)
xtmp = sk_X509_value(certs, i);
if (!X509_cmp(xtmp, x))
break;
+ xtmp = NULL;
}
- if (i < sk_X509_num(certs))
- X509_up_ref(xtmp);
- else
+ if (xtmp != NULL && !X509_up_ref(xtmp))
xtmp = NULL;
sk_X509_pop_free(certs, X509_free);
return xtmp;
@@ -267,17 +272,24 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
return -1;
}
+ if (!X509_up_ref(ctx->cert)) {
+ X509err(X509_F_X509_VERIFY_CERT, ERR_R_INTERNAL_ERROR);
+ ctx->error = X509_V_ERR_UNSPECIFIED;
+ return -1;
+ }
+
/*
* first we make sure the chain we are going to build is present and that
* the first entry is in place
*/
- if (((ctx->chain = sk_X509_new_null()) == NULL) ||
- (!sk_X509_push(ctx->chain, ctx->cert))) {
+ if ((ctx->chain = sk_X509_new_null()) == NULL
+ || !sk_X509_push(ctx->chain, ctx->cert)) {
+ X509_free(ctx->cert);
X509err(X509_F_X509_VERIFY_CERT, ERR_R_MALLOC_FAILURE);
ctx->error = X509_V_ERR_OUT_OF_MEM;
return -1;
}
- X509_up_ref(ctx->cert);
+
ctx->num_untrusted = 1;
/* If the peer's public key is too weak, we can stop early. */
@@ -319,30 +331,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 */
@@ -350,11 +358,15 @@ static int check_issued(X509_STORE_CTX *ctx, X509 *x, X509 *issuer)
static int get_issuer_sk(X509 **issuer, X509_STORE_CTX *ctx, X509 *x)
{
*issuer = find_issuer(ctx, ctx->other_ctx, x);
- if (*issuer) {
- X509_up_ref(*issuer);
- return 1;
- } else
- return 0;
+
+ if (*issuer == NULL || !X509_up_ref(*issuer))
+ goto err;
+
+ return 1;
+
+ err:
+ *issuer = NULL;
+ return 0;
}
static STACK_OF(X509) *lookup_certs_sk(X509_STORE_CTX *ctx, X509_NAME *nm)
@@ -366,15 +378,21 @@ static STACK_OF(X509) *lookup_certs_sk(X509_STORE_CTX *ctx, X509_NAME *nm)
for (i = 0; i < sk_X509_num(ctx->other_ctx); i++) {
x = sk_X509_value(ctx->other_ctx, i);
if (X509_NAME_cmp(nm, X509_get_subject_name(x)) == 0) {
+ if (!X509_up_ref(x)) {
+ sk_X509_pop_free(sk, X509_free);
+ X509err(X509_F_LOOKUP_CERTS_SK, ERR_R_INTERNAL_ERROR);
+ ctx->error = X509_V_ERR_UNSPECIFIED;
+ return NULL;
+ }
if (sk == NULL)
sk = sk_X509_new_null();
- if (sk == NULL || sk_X509_push(sk, x) == 0) {
+ if (sk == NULL || !sk_X509_push(sk, x)) {
+ X509_free(x);
sk_X509_pop_free(sk, X509_free);
X509err(X509_F_LOOKUP_CERTS_SK, ERR_R_MALLOC_FAILURE);
ctx->error = X509_V_ERR_OUT_OF_MEM;
return NULL;
}
- X509_up_ref(x);
}
}
return sk;
@@ -508,6 +526,14 @@ static int check_chain_extensions(X509_STORE_CTX *ctx)
ret = 1;
break;
}
+ if ((ctx->param->flags & X509_V_FLAG_X509_STRICT) && num > 1) {
+ /* Check for presence of explicit elliptic curve parameters */
+ ret = check_curve(x);
+ if (ret < 0)
+ ctx->error = X509_V_ERR_UNSPECIFIED;
+ else if (ret == 0)
+ ctx->error = X509_V_ERR_EC_KEY_EXPLICIT_PARAMS;
+ }
if ((x->ex_flags & EXFLAG_CA) == 0
&& x->ex_pathlen != -1
&& (ctx->param->flags & X509_V_FLAG_X509_STRICT)) {
@@ -1699,6 +1725,7 @@ int x509_check_cert_time(X509_STORE_CTX *ctx, X509 *x, int depth)
return 1;
}
+/* verify the issuer signatures and cert times of ctx->chain */
static int internal_verify(X509_STORE_CTX *ctx)
{
int n = sk_X509_num(ctx->chain) - 1;
@@ -1717,7 +1744,7 @@ static int internal_verify(X509_STORE_CTX *ctx)
}
if (ctx->check_issued(ctx, xi, xi))
- xs = xi;
+ xs = xi; /* the typical case: last cert in the chain is self-issued */
else {
if (ctx->param->flags & X509_V_FLAG_PARTIAL_CHAIN) {
xs = xi;
@@ -1736,22 +1763,50 @@ 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
- * and its depth (rather than the depth of the subject).
+ * For each iteration of this loop:
+ * n is the subject depth
+ * xs is the subject cert, for which the signature is to be checked
+ * xi is the supposed issuer cert containing the public key to use
+ * Initially xs == xi if the last cert in the chain is self-issued.
+ *
+ * Skip signature check for self-signed certificates unless explicitly
+ * asked for because it does not add any security and just wastes time.
*/
- if (xs != xi || (ctx->param->flags & X509_V_FLAG_CHECK_SS_SIGNATURE)) {
+ if (xs != xi || ((ctx->param->flags & X509_V_FLAG_CHECK_SS_SIGNATURE)
+ && (xi->ex_flags & EXFLAG_SS) != 0)) {
+ EVP_PKEY *pkey;
+ /*
+ * If the issuer's public key is not available or its key usage
+ * does not support issuing the subject cert, report the issuer
+ * cert and its depth (rather than n, the depth of the subject).
+ */
+ int issuer_depth = n + (xs == xi ? 0 : 1);
+ /*
+ * According to https://tools.ietf.org/html/rfc5280#section-6.1.4
+ * step (n) we must check any given key usage extension in a CA cert
+ * when preparing the verification of a certificate issued by it.
+ * According to https://tools.ietf.org/html/rfc5280#section-4.2.1.3
+ * we must not verify a certifiate signature if the key usage of the
+ * CA certificate that issued the certificate prohibits signing.
+ * In case the 'issuing' certificate is the last in the chain and is
+ * not a CA certificate but a 'self-issued' end-entity cert (i.e.,
+ * xs == xi && !(xi->ex_flags & EXFLAG_CA)) RFC 5280 does not apply
+ * (see https://tools.ietf.org/html/rfc6818#section-2) and thus
+ * we are free to ignore any key usage restrictions on such certs.
+ */
+ int ret = xs == xi && (xi->ex_flags & EXFLAG_CA) == 0
+ ? X509_V_OK : 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))
+ ret = X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY;
+ if (!verify_cb_cert(ctx, xi, issuer_depth, ret))
return 0;
} else if (X509_verify(xs, pkey) <= 0) {
- if (!verify_cb_cert(ctx, xs, n,
- X509_V_ERR_CERT_SIGNATURE_FAILURE))
+ ret = X509_V_ERR_CERT_SIGNATURE_FAILURE;
+ if (!verify_cb_cert(ctx, xs, n, ret))
return 0;
}
}
@@ -3158,7 +3213,16 @@ static int build_chain(X509_STORE_CTX *ctx)
/* Drop this issuer from future consideration */
(void) sk_X509_delete_ptr(sktmp, xtmp);
+ if (!X509_up_ref(xtmp)) {
+ X509err(X509_F_BUILD_CHAIN, ERR_R_INTERNAL_ERROR);
+ trust = X509_TRUST_REJECTED;
+ ctx->error = X509_V_ERR_UNSPECIFIED;
+ search = 0;
+ continue;
+ }
+
if (!sk_X509_push(ctx->chain, xtmp)) {
+ X509_free(xtmp);
X509err(X509_F_BUILD_CHAIN, ERR_R_MALLOC_FAILURE);
trust = X509_TRUST_REJECTED;
ctx->error = X509_V_ERR_OUT_OF_MEM;
@@ -3166,7 +3230,7 @@ static int build_chain(X509_STORE_CTX *ctx)
continue;
}
- X509_up_ref(x = xtmp);
+ x = xtmp;
++ctx->num_untrusted;
ss = cert_self_signed(xtmp);
@@ -3258,6 +3322,32 @@ static int check_key_level(X509_STORE_CTX *ctx, X509 *cert)
}
/*
+ * Check whether the public key of ``cert`` does not use explicit params
+ * for an elliptic curve.
+ *
+ * Returns 1 on success, 0 if check fails, -1 for other errors.
+ */
+static int check_curve(X509 *cert)
+{
+#ifndef OPENSSL_NO_EC
+ EVP_PKEY *pkey = X509_get0_pubkey(cert);
+
+ /* Unsupported or malformed key */
+ if (pkey == NULL)
+ return -1;
+
+ if (EVP_PKEY_id(pkey) == EVP_PKEY_EC) {
+ int ret;
+
+ ret = EC_KEY_decoded_from_explicit_params(EVP_PKEY_get0_EC_KEY(pkey));
+ return ret < 0 ? ret : !ret;
+ }
+#endif
+
+ return 1;
+}
+
+/*
* Check whether the signature digest algorithm of ``cert`` meets the security
* level of ``ctx``. Should not be checked for trust anchors (whether
* self-signed or otherwise).