summaryrefslogtreecommitdiff
path: root/drivers/builtin_openssl2/crypto/x509/x509_vfy.c
diff options
context:
space:
mode:
authormrezai <mhd.rezai@gmail.com>2016-04-15 19:03:35 +0430
committermrezai <mhd.rezai@gmail.com>2016-04-15 19:03:35 +0430
commite97922f22038e9049ed4c2db5b3736dfaa0edde3 (patch)
tree37e036a343e7482a387b7acd0a88509af78a69eb /drivers/builtin_openssl2/crypto/x509/x509_vfy.c
parent880f4abda44a42532abb6f15999a90bc85f6264a (diff)
Update OpenSSL to version 1.0.2g
Diffstat (limited to 'drivers/builtin_openssl2/crypto/x509/x509_vfy.c')
-rw-r--r--drivers/builtin_openssl2/crypto/x509/x509_vfy.c387
1 files changed, 327 insertions, 60 deletions
diff --git a/drivers/builtin_openssl2/crypto/x509/x509_vfy.c b/drivers/builtin_openssl2/crypto/x509/x509_vfy.c
index 3bad523f71..4d34dbac93 100644
--- a/drivers/builtin_openssl2/crypto/x509/x509_vfy.c
+++ b/drivers/builtin_openssl2/crypto/x509/x509_vfy.c
@@ -69,6 +69,7 @@
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include <openssl/objects.h>
+#include "vpm_int.h"
/* CRL score values */
@@ -113,6 +114,7 @@ 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);
static int check_chain_extensions(X509_STORE_CTX *ctx);
static int check_name_constraints(X509_STORE_CTX *ctx);
+static int check_id(X509_STORE_CTX *ctx);
static int check_trust(X509_STORE_CTX *ctx);
static int check_revocation(X509_STORE_CTX *ctx);
static int check_cert(X509_STORE_CTX *ctx);
@@ -148,6 +150,40 @@ static int x509_subject_cmp(X509 **a, X509 **b)
return X509_subject_name_cmp(*a, *b);
}
#endif
+/* Return 1 is a certificate is self signed */
+static int cert_self_signed(X509 *x)
+{
+ X509_check_purpose(x, -1, 0);
+ if (x->ex_flags & EXFLAG_SS)
+ return 1;
+ else
+ return 0;
+}
+
+/* Given a certificate try and find an exact match in the store */
+
+static X509 *lookup_cert_match(X509_STORE_CTX *ctx, X509 *x)
+{
+ STACK_OF(X509) *certs;
+ X509 *xtmp = NULL;
+ int i;
+ /* Lookup all certs with matching subject name */
+ certs = ctx->lookup_certs(ctx, X509_get_subject_name(x));
+ if (certs == NULL)
+ return NULL;
+ /* Look for exact match */
+ for (i = 0; i < sk_X509_num(certs); i++) {
+ xtmp = sk_X509_value(certs, i);
+ if (!X509_cmp(xtmp, x))
+ break;
+ }
+ if (i < sk_X509_num(certs))
+ CRYPTO_add(&xtmp->references, 1, CRYPTO_LOCK_X509);
+ else
+ xtmp = NULL;
+ sk_X509_pop_free(certs, X509_free);
+ return xtmp;
+}
int X509_verify_cert(X509_STORE_CTX *ctx)
{
@@ -158,6 +194,9 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
int num, j, retry;
int (*cb) (int xok, X509_STORE_CTX *xctx);
STACK_OF(X509) *sktmp = NULL;
+ int trust = X509_TRUST_UNTRUSTED;
+ int err;
+
if (ctx->cert == NULL) {
X509err(X509_F_X509_VERIFY_CERT, X509_R_NO_CERT_SET_FOR_US_TO_VERIFY);
return -1;
@@ -180,7 +219,8 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
if (((ctx->chain = sk_X509_new_null()) == NULL) ||
(!sk_X509_push(ctx->chain, ctx->cert))) {
X509err(X509_F_X509_VERIFY_CERT, ERR_R_MALLOC_FAILURE);
- goto end;
+ ok = -1;
+ goto err;
}
CRYPTO_add(&ctx->cert->references, 1, CRYPTO_LOCK_X509);
ctx->last_untrusted = 1;
@@ -189,7 +229,8 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
if (ctx->untrusted != NULL
&& (sktmp = sk_X509_dup(ctx->untrusted)) == NULL) {
X509err(X509_F_X509_VERIFY_CERT, ERR_R_MALLOC_FAILURE);
- goto end;
+ ok = -1;
+ goto err;
}
num = sk_X509_num(ctx->chain);
@@ -205,8 +246,24 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
* later. */
/* If we are self signed, we break */
- if (ctx->check_issued(ctx, x, x))
+ if (cert_self_signed(x))
break;
+ /*
+ * If asked see if we can find issuer in trusted store first
+ */
+ if (ctx->param->flags & X509_V_FLAG_TRUSTED_FIRST) {
+ ok = ctx->get_issuer(&xtmp, ctx, x);
+ if (ok < 0)
+ goto err;
+ /*
+ * If successful for now free up cert so it will be picked up
+ * again later.
+ */
+ if (ok > 0) {
+ X509_free(xtmp);
+ break;
+ }
+ }
/* If we were passed a cert chain, use it first */
if (ctx->untrusted != NULL) {
@@ -214,7 +271,8 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
if (xtmp != NULL) {
if (!sk_X509_push(ctx->chain, xtmp)) {
X509err(X509_F_X509_VERIFY_CERT, ERR_R_MALLOC_FAILURE);
- goto end;
+ ok = -1;
+ goto err;
}
CRYPTO_add(&xtmp->references, 1, CRYPTO_LOCK_X509);
(void)sk_X509_delete_ptr(sktmp, xtmp);
@@ -244,7 +302,7 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
*/
i = sk_X509_num(ctx->chain);
x = sk_X509_value(ctx->chain, i - 1);
- if (ctx->check_issued(ctx, x, x)) {
+ if (cert_self_signed(x)) {
/* we have a self signed certificate */
if (sk_X509_num(ctx->chain) == 1) {
/*
@@ -262,7 +320,7 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
bad_chain = 1;
ok = cb(0, ctx);
if (!ok)
- goto end;
+ goto err;
} else {
/*
* We have a match: replace certificate with store
@@ -290,35 +348,46 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
if (depth < num)
break;
/* If we are self signed, we break */
- if (ctx->check_issued(ctx, x, x))
+ if (cert_self_signed(x))
break;
ok = ctx->get_issuer(&xtmp, ctx, x);
+
if (ok < 0)
- return ok;
+ goto err;
if (ok == 0)
break;
x = xtmp;
if (!sk_X509_push(ctx->chain, x)) {
X509_free(xtmp);
X509err(X509_F_X509_VERIFY_CERT, ERR_R_MALLOC_FAILURE);
- return 0;
+ ok = -1;
+ goto err;
}
num++;
}
+ /* we now have our chain, lets check it... */
+ if ((trust = check_trust(ctx)) == X509_TRUST_REJECTED) {
+ /* Callback already issued */
+ ok = 0;
+ goto err;
+ }
+
/*
- * If we haven't got a least one certificate from our store then check
- * if there is an alternative chain that could be used. We only do this
- * if the user hasn't switched off alternate chain checking
+ * If it's not explicitly trusted then check if there is an alternative
+ * chain that could be used. We only do this if we haven't already
+ * checked via TRUSTED_FIRST and the user hasn't switched off alternate
+ * chain checking
*/
retry = 0;
- if (num == ctx->last_untrusted &&
- !(ctx->param->flags & X509_V_FLAG_NO_ALT_CHAINS)) {
+ if (trust != X509_TRUST_TRUSTED
+ && !(ctx->param->flags & X509_V_FLAG_TRUSTED_FIRST)
+ && !(ctx->param->flags & X509_V_FLAG_NO_ALT_CHAINS)) {
while (j-- > 1) {
xtmp2 = sk_X509_value(ctx->chain, j - 1);
ok = ctx->get_issuer(&xtmp, ctx, xtmp2);
if (ok < 0)
- goto end;
+ goto err;
/* Check if we found an alternate chain */
if (ok > 0) {
/*
@@ -343,8 +412,12 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
}
} while (retry);
- /* Is last certificate looked up self signed? */
- if (!ctx->check_issued(ctx, x, x)) {
+ /*
+ * If not explicitly trusted then indicate error unless it's a single
+ * self signed certificate in which case we've indicated an error already
+ * and set bad_chain == 1
+ */
+ if (trust != X509_TRUST_TRUSTED && !bad_chain) {
if ((chain_ss == NULL) || !ctx->check_issued(ctx, x, chain_ss)) {
if (ctx->last_untrusted >= num)
ctx->error = X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY;
@@ -365,29 +438,26 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
bad_chain = 1;
ok = cb(0, ctx);
if (!ok)
- goto end;
+ goto err;
}
/* We have the chain complete: now we need to check its purpose */
ok = check_chain_extensions(ctx);
if (!ok)
- goto end;
+ goto err;
/* Check name constraints */
ok = check_name_constraints(ctx);
if (!ok)
- goto end;
-
- /* The chain extensions are OK: check trust */
+ goto err;
- if (param->trust > 0)
- ok = check_trust(ctx);
+ ok = check_id(ctx);
if (!ok)
- goto end;
+ goto err;
/* We may as well copy down any DSA parameters that are required */
X509_get_pubkey_parameters(NULL, ctx->chain);
@@ -399,7 +469,17 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
ok = ctx->check_revocation(ctx);
if (!ok)
- goto end;
+ goto err;
+
+ err = X509_chain_check_suiteb(&ctx->error_depth, NULL, ctx->chain,
+ ctx->param->flags);
+ if (err != X509_V_OK) {
+ ctx->error = err;
+ ctx->current_cert = sk_X509_value(ctx->chain, ctx->error_depth);
+ ok = cb(0, ctx);
+ if (!ok)
+ goto err;
+ }
/* At this point, we have a chain and need to verify it */
if (ctx->verify != NULL)
@@ -407,25 +487,28 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
else
ok = internal_verify(ctx);
if (!ok)
- goto end;
+ goto err;
#ifndef OPENSSL_NO_RFC3779
/* RFC 3779 path validation, now that CRL check has been done */
ok = v3_asid_validate_path(ctx);
if (!ok)
- goto end;
+ goto err;
ok = v3_addr_validate_path(ctx);
if (!ok)
- goto end;
+ goto err;
#endif
/* If we get this far evaluate policies */
if (!bad_chain && (ctx->param->flags & X509_V_FLAG_POLICY_CHECK))
ok = ctx->check_policy(ctx);
if (!ok)
- goto end;
+ goto err;
if (0) {
- end:
+ err:
+ /* Ensure we return an error */
+ if (ok > 0)
+ ok = 0;
X509_get_pubkey_parameters(NULL, ctx->chain);
}
if (sktmp != NULL)
@@ -467,7 +550,6 @@ static int check_issued(X509_STORE_CTX *ctx, X509 *x, X509 *issuer)
ctx->current_cert = x;
ctx->current_issuer = issuer;
return ctx->verify_cb(0, ctx);
- return 0;
}
/* Alternative lookup method: look from a STACK stored in other_ctx */
@@ -667,30 +749,101 @@ static int check_name_constraints(X509_STORE_CTX *ctx)
return 1;
}
-static int check_trust(X509_STORE_CTX *ctx)
+static int check_id_error(X509_STORE_CTX *ctx, int errcode)
{
-#ifdef OPENSSL_NO_CHAIN_VERIFY
+ ctx->error = errcode;
+ ctx->current_cert = ctx->cert;
+ ctx->error_depth = 0;
+ return ctx->verify_cb(0, ctx);
+}
+
+static int check_hosts(X509 *x, X509_VERIFY_PARAM_ID *id)
+{
+ int i;
+ int n = sk_OPENSSL_STRING_num(id->hosts);
+ char *name;
+
+ if (id->peername != NULL) {
+ OPENSSL_free(id->peername);
+ id->peername = NULL;
+ }
+ for (i = 0; i < n; ++i) {
+ name = sk_OPENSSL_STRING_value(id->hosts, i);
+ if (X509_check_host(x, name, 0, id->hostflags, &id->peername) > 0)
+ return 1;
+ }
+ return n == 0;
+}
+
+static int check_id(X509_STORE_CTX *ctx)
+{
+ X509_VERIFY_PARAM *vpm = ctx->param;
+ X509_VERIFY_PARAM_ID *id = vpm->id;
+ X509 *x = ctx->cert;
+ if (id->hosts && check_hosts(x, id) <= 0) {
+ if (!check_id_error(ctx, X509_V_ERR_HOSTNAME_MISMATCH))
+ return 0;
+ }
+ if (id->email && X509_check_email(x, id->email, id->emaillen, 0) <= 0) {
+ if (!check_id_error(ctx, X509_V_ERR_EMAIL_MISMATCH))
+ return 0;
+ }
+ if (id->ip && X509_check_ip(x, id->ip, id->iplen, 0) <= 0) {
+ if (!check_id_error(ctx, X509_V_ERR_IP_ADDRESS_MISMATCH))
+ return 0;
+ }
return 1;
-#else
+}
+
+static int check_trust(X509_STORE_CTX *ctx)
+{
int i, ok;
- X509 *x;
+ X509 *x = NULL;
int (*cb) (int xok, X509_STORE_CTX *xctx);
cb = ctx->verify_cb;
-/* For now just check the last certificate in the chain */
- i = sk_X509_num(ctx->chain) - 1;
- x = sk_X509_value(ctx->chain, i);
- ok = X509_check_trust(x, ctx->param->trust, 0);
- if (ok == X509_TRUST_TRUSTED)
- return 1;
- ctx->error_depth = i;
- ctx->current_cert = x;
- if (ok == X509_TRUST_REJECTED)
- ctx->error = X509_V_ERR_CERT_REJECTED;
- else
- ctx->error = X509_V_ERR_CERT_UNTRUSTED;
- ok = cb(0, ctx);
- return ok;
-#endif
+ /* Check all trusted certificates in chain */
+ for (i = ctx->last_untrusted; i < sk_X509_num(ctx->chain); i++) {
+ x = sk_X509_value(ctx->chain, i);
+ ok = X509_check_trust(x, ctx->param->trust, 0);
+ /* If explicitly trusted return trusted */
+ if (ok == X509_TRUST_TRUSTED)
+ return X509_TRUST_TRUSTED;
+ /*
+ * If explicitly rejected notify callback and reject if not
+ * overridden.
+ */
+ if (ok == X509_TRUST_REJECTED) {
+ ctx->error_depth = i;
+ ctx->current_cert = x;
+ ctx->error = X509_V_ERR_CERT_REJECTED;
+ ok = cb(0, ctx);
+ if (!ok)
+ return X509_TRUST_REJECTED;
+ }
+ }
+ /*
+ * If we accept partial chains and have at least one trusted certificate
+ * return success.
+ */
+ if (ctx->param->flags & X509_V_FLAG_PARTIAL_CHAIN) {
+ X509 *mx;
+ if (ctx->last_untrusted < sk_X509_num(ctx->chain))
+ return X509_TRUST_TRUSTED;
+ x = sk_X509_value(ctx->chain, 0);
+ mx = lookup_cert_match(ctx, x);
+ if (mx) {
+ (void)sk_X509_set(ctx->chain, 0, mx);
+ X509_free(x);
+ ctx->last_untrusted = 0;
+ return X509_TRUST_TRUSTED;
+ }
+ }
+
+ /*
+ * If no trusted certs in chain at all return untrusted and allow
+ * standard (no issuer cert) etc errors to be indicated.
+ */
+ return X509_TRUST_UNTRUSTED;
}
static int check_revocation(X509_STORE_CTX *ctx)
@@ -1409,6 +1562,14 @@ static int check_crl(X509_STORE_CTX *ctx, X509_CRL *crl)
if (!ok)
goto err;
} else {
+ int rv;
+ rv = X509_CRL_check_suiteb(crl, ikey, ctx->param->flags);
+ if (rv != X509_V_OK) {
+ ctx->error = rv;
+ ok = ctx->verify_cb(0, ctx);
+ if (!ok)
+ goto err;
+ }
/* Verify CRL signature */
if (X509_CRL_verify(crl, ikey) <= 0) {
ctx->error = X509_V_ERR_CRL_SIGNATURE_FAILURE;
@@ -1565,6 +1726,10 @@ static int internal_verify(X509_STORE_CTX *ctx)
if (ctx->check_issued(ctx, xi, xi))
xs = xi;
else {
+ if (ctx->param->flags & X509_V_FLAG_PARTIAL_CHAIN) {
+ xs = xi;
+ goto check_cert;
+ }
if (n <= 0) {
ctx->error = X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE;
ctx->current_cert = xi;
@@ -1610,6 +1775,7 @@ static int internal_verify(X509_STORE_CTX *ctx)
xs->valid = 1;
+ check_cert:
ok = check_cert_time(ctx, xs);
if (!ok)
goto end;
@@ -1824,6 +1990,114 @@ int X509_get_pubkey_parameters(EVP_PKEY *pkey, STACK_OF(X509) *chain)
return 1;
}
+/* Make a delta CRL as the diff between two full CRLs */
+
+X509_CRL *X509_CRL_diff(X509_CRL *base, X509_CRL *newer,
+ EVP_PKEY *skey, const EVP_MD *md, unsigned int flags)
+{
+ X509_CRL *crl = NULL;
+ int i;
+ STACK_OF(X509_REVOKED) *revs = NULL;
+ /* CRLs can't be delta already */
+ if (base->base_crl_number || newer->base_crl_number) {
+ X509err(X509_F_X509_CRL_DIFF, X509_R_CRL_ALREADY_DELTA);
+ return NULL;
+ }
+ /* Base and new CRL must have a CRL number */
+ if (!base->crl_number || !newer->crl_number) {
+ X509err(X509_F_X509_CRL_DIFF, X509_R_NO_CRL_NUMBER);
+ return NULL;
+ }
+ /* Issuer names must match */
+ if (X509_NAME_cmp(X509_CRL_get_issuer(base), X509_CRL_get_issuer(newer))) {
+ X509err(X509_F_X509_CRL_DIFF, X509_R_ISSUER_MISMATCH);
+ return NULL;
+ }
+ /* AKID and IDP must match */
+ if (!crl_extension_match(base, newer, NID_authority_key_identifier)) {
+ X509err(X509_F_X509_CRL_DIFF, X509_R_AKID_MISMATCH);
+ return NULL;
+ }
+ if (!crl_extension_match(base, newer, NID_issuing_distribution_point)) {
+ X509err(X509_F_X509_CRL_DIFF, X509_R_IDP_MISMATCH);
+ return NULL;
+ }
+ /* Newer CRL number must exceed full CRL number */
+ if (ASN1_INTEGER_cmp(newer->crl_number, base->crl_number) <= 0) {
+ X509err(X509_F_X509_CRL_DIFF, X509_R_NEWER_CRL_NOT_NEWER);
+ return NULL;
+ }
+ /* CRLs must verify */
+ if (skey && (X509_CRL_verify(base, skey) <= 0 ||
+ X509_CRL_verify(newer, skey) <= 0)) {
+ X509err(X509_F_X509_CRL_DIFF, X509_R_CRL_VERIFY_FAILURE);
+ return NULL;
+ }
+ /* Create new CRL */
+ crl = X509_CRL_new();
+ if (!crl || !X509_CRL_set_version(crl, 1))
+ goto memerr;
+ /* Set issuer name */
+ if (!X509_CRL_set_issuer_name(crl, X509_CRL_get_issuer(newer)))
+ goto memerr;
+
+ if (!X509_CRL_set_lastUpdate(crl, X509_CRL_get_lastUpdate(newer)))
+ goto memerr;
+ if (!X509_CRL_set_nextUpdate(crl, X509_CRL_get_nextUpdate(newer)))
+ goto memerr;
+
+ /* Set base CRL number: must be critical */
+
+ if (!X509_CRL_add1_ext_i2d(crl, NID_delta_crl, base->crl_number, 1, 0))
+ goto memerr;
+
+ /*
+ * Copy extensions across from newest CRL to delta: this will set CRL
+ * number to correct value too.
+ */
+
+ for (i = 0; i < X509_CRL_get_ext_count(newer); i++) {
+ X509_EXTENSION *ext;
+ ext = X509_CRL_get_ext(newer, i);
+ if (!X509_CRL_add_ext(crl, ext, -1))
+ goto memerr;
+ }
+
+ /* Go through revoked entries, copying as needed */
+
+ revs = X509_CRL_get_REVOKED(newer);
+
+ for (i = 0; i < sk_X509_REVOKED_num(revs); i++) {
+ X509_REVOKED *rvn, *rvtmp;
+ rvn = sk_X509_REVOKED_value(revs, i);
+ /*
+ * Add only if not also in base. TODO: need something cleverer here
+ * for some more complex CRLs covering multiple CAs.
+ */
+ if (!X509_CRL_get0_by_serial(base, &rvtmp, rvn->serialNumber)) {
+ rvtmp = X509_REVOKED_dup(rvn);
+ if (!rvtmp)
+ goto memerr;
+ if (!X509_CRL_add0_revoked(crl, rvtmp)) {
+ X509_REVOKED_free(rvtmp);
+ goto memerr;
+ }
+ }
+ }
+ /* TODO: optionally prune deleted entries */
+
+ if (skey && md && !X509_CRL_sign(crl, skey, md))
+ goto memerr;
+
+ return crl;
+
+ memerr:
+ X509err(X509_F_X509_CRL_DIFF, ERR_R_MALLOC_FAILURE);
+ if (crl)
+ X509_CRL_free(crl);
+ return NULL;
+}
+
int X509_STORE_CTX_get_ex_new_index(long argl, void *argp,
CRYPTO_EX_new *new_func,
CRYPTO_EX_dup *dup_func,
@@ -1874,16 +2148,9 @@ STACK_OF(X509) *X509_STORE_CTX_get_chain(X509_STORE_CTX *ctx)
STACK_OF(X509) *X509_STORE_CTX_get1_chain(X509_STORE_CTX *ctx)
{
- int i;
- X509 *x;
- STACK_OF(X509) *chain;
- if (!ctx->chain || !(chain = sk_X509_dup(ctx->chain)))
+ if (!ctx->chain)
return NULL;
- for (i = 0; i < sk_X509_num(chain); i++) {
- x = sk_X509_value(chain, i);
- CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509);
- }
- return chain;
+ return X509_chain_up_ref(ctx->chain);
}
X509 *X509_STORE_CTX_get0_current_issuer(X509_STORE_CTX *ctx)