diff options
Diffstat (limited to 'crypto/x509/x509_vfy.c')
-rw-r--r-- | crypto/x509/x509_vfy.c | 176 |
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). |