#include <time.h>
#include <errno.h>
-#include "cryptlib.h"
+#include "internal/cryptlib.h"
#include <openssl/crypto.h>
#include <openssl/lhash.h>
#include <openssl/buffer.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include <openssl/objects.h>
+#include "internal/x509_int.h"
#include "x509_lcl.h"
/* CRL score values */
STACK_OF(X509) *crl_path);
static int internal_verify(X509_STORE_CTX *ctx);
-const char X509_version[] = "X.509" OPENSSL_VERSION_PTEXT;
static int null_callback(int ok, X509_STORE_CTX *e)
{
break;
}
if (i < sk_X509_num(certs))
- CRYPTO_add(&xtmp->references, 1, CRYPTO_LOCK_X509);
+ X509_up_ref(xtmp);
else
xtmp = NULL;
sk_X509_pop_free(certs, X509_free);
int X509_verify_cert(X509_STORE_CTX *ctx)
{
- X509 *x, *xtmp, *chain_ss = NULL;
+ X509 *x, *xtmp, *xtmp2, *chain_ss = NULL;
int bad_chain = 0;
X509_VERIFY_PARAM *param = ctx->param;
int depth, i, ok = 0;
- int num;
+ int num, j, retry;
int (*cb) (int xok, X509_STORE_CTX *xctx);
STACK_OF(X509) *sktmp = NULL;
if (ctx->cert == NULL) {
X509err(X509_F_X509_VERIFY_CERT, X509_R_NO_CERT_SET_FOR_US_TO_VERIFY);
return -1;
}
+ if (ctx->chain != NULL) {
+ /*
+ * This X509_STORE_CTX has already been used to verify a cert. We
+ * cannot do another one.
+ */
+ X509err(X509_F_X509_VERIFY_CERT, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+ return -1;
+ }
cb = ctx->verify_cb;
* first we make sure the chain we are going to build is present and that
* the first entry is in place
*/
- if (ctx->chain == NULL) {
- 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;
- }
- CRYPTO_add(&ctx->cert->references, 1, CRYPTO_LOCK_X509);
- ctx->last_untrusted = 1;
+ 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;
}
+ X509_up_ref(ctx->cert);
+ ctx->last_untrusted = 1;
/* We use a temporary STACK so we can chop and hack at it */
if (ctx->untrusted != NULL
if (ctx->param->flags & X509_V_FLAG_TRUSTED_FIRST) {
ok = ctx->get_issuer(&xtmp, ctx, x);
if (ok < 0)
- return ok;
+ goto end;
/*
* If successful for now free up cert so it will be picked up
* again later.
X509err(X509_F_X509_VERIFY_CERT, ERR_R_MALLOC_FAILURE);
goto end;
}
- CRYPTO_add(&xtmp->references, 1, CRYPTO_LOCK_X509);
+ X509_up_ref(xtmp);
(void)sk_X509_delete_ptr(sktmp, xtmp);
ctx->last_untrusted++;
x = xtmp;
break;
}
+ /* Remember how many untrusted certs we have */
+ j = num;
/*
* at this point, chain should contain a list of untrusted certificates.
* We now need to add at least one trusted one, if possible, otherwise we
* complain.
*/
- /*
- * Examine last certificate in chain and see if it is self signed.
- */
-
- i = sk_X509_num(ctx->chain);
- x = sk_X509_value(ctx->chain, i - 1);
- if (cert_self_signed(x)) {
- /* we have a self signed certificate */
- if (sk_X509_num(ctx->chain) == 1) {
- /*
- * We have a single self signed certificate: see if we can find
- * it in the store. We must have an exact match to avoid possible
- * impersonation.
- */
- ok = ctx->get_issuer(&xtmp, ctx, x);
- if ((ok <= 0) || X509_cmp(x, xtmp)) {
- ctx->error = X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT;
- ctx->current_cert = x;
- ctx->error_depth = i - 1;
- if (ok == 1)
- X509_free(xtmp);
- bad_chain = 1;
- ok = cb(0, ctx);
- if (!ok)
- goto end;
+ do {
+ /*
+ * Examine last certificate in chain and see if it is self signed.
+ */
+ i = sk_X509_num(ctx->chain);
+ x = sk_X509_value(ctx->chain, i - 1);
+ if (cert_self_signed(x)) {
+ /* we have a self signed certificate */
+ if (sk_X509_num(ctx->chain) == 1) {
+ /*
+ * We have a single self signed certificate: see if we can
+ * find it in the store. We must have an exact match to avoid
+ * possible impersonation.
+ */
+ ok = ctx->get_issuer(&xtmp, ctx, x);
+ if ((ok <= 0) || X509_cmp(x, xtmp)) {
+ ctx->error = X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT;
+ ctx->current_cert = x;
+ ctx->error_depth = i - 1;
+ if (ok == 1)
+ X509_free(xtmp);
+ bad_chain = 1;
+ ok = cb(0, ctx);
+ if (!ok)
+ goto end;
+ } else {
+ /*
+ * We have a match: replace certificate with store
+ * version so we get any trust settings.
+ */
+ X509_free(x);
+ x = xtmp;
+ (void)sk_X509_set(ctx->chain, i - 1, x);
+ ctx->last_untrusted = 0;
+ }
} else {
/*
- * We have a match: replace certificate with store version so
- * we get any trust settings.
+ * extract and save self signed certificate for later use
*/
- X509_free(x);
- x = xtmp;
- (void)sk_X509_set(ctx->chain, i - 1, x);
- ctx->last_untrusted = 0;
+ chain_ss = sk_X509_pop(ctx->chain);
+ ctx->last_untrusted--;
+ num--;
+ j--;
+ x = sk_X509_value(ctx->chain, num - 1);
}
- } else {
- /*
- * extract and save self signed certificate for later use
- */
- chain_ss = sk_X509_pop(ctx->chain);
- ctx->last_untrusted--;
- num--;
- x = sk_X509_value(ctx->chain, num - 1);
}
- }
-
- /* We now lookup certs from the certificate store */
- for (;;) {
- /* If we have enough, we break */
- if (depth < num)
- break;
+ /* We now lookup certs from the certificate store */
+ for (;;) {
+ /* If we have enough, we break */
+ if (depth < num)
+ break;
+ /* If we are self signed, we break */
+ if (cert_self_signed(x))
+ break;
+ ok = ctx->get_issuer(&xtmp, ctx, x);
- /* If we are self signed, we break */
- if (cert_self_signed(x))
- break;
+ if (ok < 0)
+ goto end;
+ 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);
+ ok = 0;
+ goto done;
+ }
+ num++;
+ }
- ok = ctx->get_issuer(&xtmp, ctx, x);
+ /* we now have our chain, lets check it... */
+ i = check_trust(ctx);
- if (ok < 0)
- return ok;
- if (ok == 0)
- break;
+ /* If explicitly rejected error */
+ if (i == X509_TRUST_REJECTED)
+ goto end;
+ /*
+ * 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 (i != X509_TRUST_TRUSTED
+ && !(ctx->param->flags & X509_V_FLAG_TRUSTED_FIRST)
+ && !(ctx->param->flags & X509_V_FLAG_NO_ALT_CHAINS)) {
+ while (j-- > 1) {
+ STACK_OF(X509) *chtmp = ctx->chain;
+ xtmp2 = sk_X509_value(ctx->chain, j - 1);
+ /*
+ * Temporarily set chain to NULL so we don't discount
+ * duplicates: the same certificate could be an untrusted
+ * CA found in the trusted store.
+ */
+ ctx->chain = NULL;
+ ok = ctx->get_issuer(&xtmp, ctx, xtmp2);
+ ctx->chain = chtmp;
+ if (ok < 0)
+ goto end;
+ /* Check if we found an alternate chain */
+ if (ok > 0) {
+ /*
+ * Free up the found cert we'll add it again later
+ */
+ X509_free(xtmp);
- x = xtmp;
- if (!sk_X509_push(ctx->chain, x)) {
- X509_free(xtmp);
- X509err(X509_F_X509_VERIFY_CERT, ERR_R_MALLOC_FAILURE);
- return 0;
+ /*
+ * Dump all the certs above this point - we've found an
+ * alternate chain
+ */
+ while (num > j) {
+ xtmp = sk_X509_pop(ctx->chain);
+ X509_free(xtmp);
+ num--;
+ }
+ ctx->last_untrusted = sk_X509_num(ctx->chain);
+ retry = 1;
+ break;
+ }
+ }
}
- num++;
- }
-
- /* we now have our chain, lets check it... */
-
- i = check_trust(ctx);
+ } while (retry);
- /* If explicitly rejected error */
- if (i == X509_TRUST_REJECTED)
- goto end;
/*
* If not explicitly trusted then indicate error unless it's a single
* self signed certificate in which case we've indicated an error already
if (!ok)
goto end;
+#ifndef OPENSSL_NO_RFC3779
/* RFC 3779 path validation, now that CRL check has been done */
ok = v3_asid_validate_path(ctx);
if (!ok)
ok = v3_addr_validate_path(ctx);
if (!ok)
goto end;
+#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;
- if (0) {
+ if (ok)
+ goto done;
+
end:
- X509_get_pubkey_parameters(NULL, ctx->chain);
- }
- if (sktmp != NULL)
- sk_X509_free(sktmp);
- if (chain_ss != NULL)
- X509_free(chain_ss);
+ X509_get_pubkey_parameters(NULL, ctx->chain);
+ done:
+ sk_X509_free(sktmp);
+ X509_free(chain_ss);
return ok;
}
{
*issuer = find_issuer(ctx, ctx->other_ctx, x);
if (*issuer) {
- CRYPTO_add(&(*issuer)->references, 1, CRYPTO_LOCK_X509);
+ X509_up_ref(*issuer);
return 1;
} else
return 0;
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)
static int check_revocation(X509_STORE_CTX *ctx)
{
- int i, last, ok;
+ int i = 0, last = 0, ok = 0;
if (!(ctx->param->flags & X509_V_FLAG_CRL_CHECK))
return 1;
if (ctx->param->flags & X509_V_FLAG_CRL_CHECK_ALL)
static int check_cert(X509_STORE_CTX *ctx)
{
X509_CRL *crl = NULL, *dcrl = NULL;
- X509 *x;
- int ok, cnum;
- unsigned int last_reasons;
+ X509 *x = NULL;
+ int ok = 0, cnum = 0;
+ unsigned int last_reasons = 0;
cnum = ctx->error_depth;
x = sk_X509_value(ctx->chain, cnum);
ctx->current_cert = x;
}
if (best_crl) {
- if (*pcrl)
- X509_CRL_free(*pcrl);
+ X509_CRL_free(*pcrl);
*pcrl = best_crl;
*pissuer = best_crl_issuer;
*pscore = best_score;
*preasons = best_reasons;
- CRYPTO_add(&best_crl->references, 1, CRYPTO_LOCK_X509_CRL);
- if (*pdcrl) {
- X509_CRL_free(*pdcrl);
- *pdcrl = NULL;
- }
+ X509_CRL_up_ref(best_crl);
+ X509_CRL_free(*pdcrl);
+ *pdcrl = NULL;
get_delta_sk(ctx, pdcrl, pscore, best_crl, crls);
}
if (check_delta_base(delta, base)) {
if (check_crl_time(ctx, delta, 0))
*pscore |= CRL_SCORE_TIME_DELTA;
- CRYPTO_add(&delta->references, 1, CRYPTO_LOCK_X509_CRL);
+ X509_CRL_up_ref(delta);
*dcrl = delta;
return;
}
ASN1_TIME atm;
long offset;
char buff1[24], buff2[24], *p;
- int i, j;
+ int i, j, remaining;
p = buff1;
- i = ctm->length;
+ remaining = ctm->length;
str = (char *)ctm->data;
+ /*
+ * Note that the following (historical) code allows much more slack in the
+ * time format than RFC5280. In RFC5280, the representation is fixed:
+ * UTCTime: YYMMDDHHMMSSZ
+ * GeneralizedTime: YYYYMMDDHHMMSSZ
+ */
if (ctm->type == V_ASN1_UTCTIME) {
- if ((i < 11) || (i > 17))
+ /* YYMMDDHHMM[SS]Z or YYMMDDHHMM[SS](+-)hhmm */
+ int min_length = sizeof("YYMMDDHHMMZ") - 1;
+ int max_length = sizeof("YYMMDDHHMMSS+hhmm") - 1;
+ if (remaining < min_length || remaining > max_length)
return 0;
memcpy(p, str, 10);
p += 10;
str += 10;
+ remaining -= 10;
} else {
- if (i < 13)
+ /* YYYYMMDDHHMM[SS[.fff]]Z or YYYYMMDDHHMM[SS[.f[f[f]]]](+-)hhmm */
+ int min_length = sizeof("YYYYMMDDHHMMZ") - 1;
+ int max_length = sizeof("YYYYMMDDHHMMSS.fff+hhmm") - 1;
+ if (remaining < min_length || remaining > max_length)
return 0;
memcpy(p, str, 12);
p += 12;
str += 12;
+ remaining -= 12;
}
if ((*str == 'Z') || (*str == '-') || (*str == '+')) {
*(p++) = '0';
*(p++) = '0';
} else {
+ /* SS (seconds) */
+ if (remaining < 2)
+ return 0;
*(p++) = *(str++);
*(p++) = *(str++);
- /* Skip any fractional seconds... */
- if (*str == '.') {
+ remaining -= 2;
+ /*
+ * Skip any (up to three) fractional seconds...
+ * TODO(emilia): in RFC5280, fractional seconds are forbidden.
+ * Can we just kill them altogether?
+ */
+ if (remaining && *str == '.') {
str++;
- while ((*str >= '0') && (*str <= '9'))
- str++;
+ remaining--;
+ for (i = 0; i < 3 && remaining; i++, str++, remaining--) {
+ if (*str < '0' || *str > '9')
+ break;
+ }
}
}
*(p++) = 'Z';
*(p++) = '\0';
- if (*str == 'Z')
+ /* We now need either a terminating 'Z' or an offset. */
+ if (!remaining)
+ return 0;
+ if (*str == 'Z') {
+ if (remaining != 1)
+ return 0;
offset = 0;
- else {
+ } else {
+ /* (+-)HHMM */
if ((*str != '+') && (*str != '-'))
return 0;
+ /* Historical behaviour: the (+-)hhmm offset is forbidden in RFC5280. */
+ if (remaining != 5)
+ return 0;
+ if (str[1] < '0' || str[1] > '9' || str[2] < '0' || str[2] > '9' ||
+ str[3] < '0' || str[3] > '9' || str[4] < '0' || str[4] > '9')
+ return 0;
offset = ((str[1] - '0') * 10 + (str[2] - '0')) * 60;
offset += (str[3] - '0') * 10 + (str[4] - '0');
if (*str == '-')
}
if (!EVP_PKEY_missing_parameters(ktmp))
break;
- else {
- EVP_PKEY_free(ktmp);
- ktmp = NULL;
- }
+ EVP_PKEY_free(ktmp);
+ ktmp = NULL;
}
if (ktmp == NULL) {
X509err(X509_F_X509_GET_PUBKEY_PARAMETERS,
memerr:
X509err(X509_F_X509_CRL_DIFF, ERR_R_MALLOC_FAILURE);
- if (crl)
- X509_CRL_free(crl);
+ X509_CRL_free(crl);
return NULL;
}
X509_STORE_CTX *X509_STORE_CTX_new(void)
{
- X509_STORE_CTX *ctx;
- ctx = (X509_STORE_CTX *)OPENSSL_malloc(sizeof(X509_STORE_CTX));
+ X509_STORE_CTX *ctx = OPENSSL_zalloc(sizeof(*ctx));
+
if (!ctx) {
X509err(X509_F_X509_STORE_CTX_NEW, ERR_R_MALLOC_FAILURE);
return NULL;
}
- memset(ctx, 0, sizeof(X509_STORE_CTX));
return ctx;
}
void X509_STORE_CTX_free(X509_STORE_CTX *ctx)
{
+ if (!ctx)
+ return;
X509_STORE_CTX_cleanup(ctx);
OPENSSL_free(ctx);
}
ctx->check_policy = check_policy;
/*
- * This memset() can't make any sense anyway, so it's removed. As
- * X509_STORE_CTX_cleanup does a proper "free" on the ex_data, we put a
- * corresponding "new" here and remove this bogus initialisation.
+ * Since X509_STORE_CTX_cleanup does a proper "free" on the ex_data, we
+ * put a corresponding "new" here.
*/
- /* memset(&(ctx->ex_data),0,sizeof(CRYPTO_EX_DATA)); */
if (!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_X509_STORE_CTX, ctx,
&(ctx->ex_data))) {
OPENSSL_free(ctx);
X509_VERIFY_PARAM_free(ctx->param);
ctx->param = NULL;
}
- if (ctx->tree != NULL) {
- X509_policy_tree_free(ctx->tree);
- ctx->tree = NULL;
- }
- if (ctx->chain != NULL) {
- sk_X509_pop_free(ctx->chain, X509_free);
- ctx->chain = NULL;
- }
+ X509_policy_tree_free(ctx->tree);
+ ctx->tree = NULL;
+ sk_X509_pop_free(ctx->chain, X509_free);
+ ctx->chain = NULL;
CRYPTO_free_ex_data(CRYPTO_EX_INDEX_X509_STORE_CTX, ctx, &(ctx->ex_data));
- memset(&ctx->ex_data, 0, sizeof(CRYPTO_EX_DATA));
+ memset(&ctx->ex_data, 0, sizeof(ctx->ex_data));
}
void X509_STORE_CTX_set_depth(X509_STORE_CTX *ctx, int depth)
return ctx->explicit_policy;
}
+int X509_STORE_CTX_get_num_untrusted(X509_STORE_CTX *ctx)
+{
+ return ctx->last_untrusted;
+}
+
int X509_STORE_CTX_set_default(X509_STORE_CTX *ctx, const char *name)
{
const X509_VERIFY_PARAM *param;
void X509_STORE_CTX_set0_param(X509_STORE_CTX *ctx, X509_VERIFY_PARAM *param)
{
- if (ctx->param)
- X509_VERIFY_PARAM_free(ctx->param);
+ X509_VERIFY_PARAM_free(ctx->param);
ctx->param = param;
}