Example #1
0
int X509_verify_cert(X509_STORE_CTX *ctx)
	{
	X509 *x,*xtmp,*chain_ss=NULL;
	X509_NAME *xn;
	int depth,i,ok=0;
	int num;
	int (*cb)();
	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;
		}

	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;
		}

	/* We use a temporary STACK so we can chop and hack at it */
	if (ctx->untrusted != NULL
	    && (sktmp=sk_X509_dup(ctx->untrusted)) == NULL)
		{
		X509err(X509_F_X509_VERIFY_CERT,ERR_R_MALLOC_FAILURE);
		goto end;
		}

	num=sk_X509_num(ctx->chain);
	x=sk_X509_value(ctx->chain,num-1);
	depth=ctx->depth;


	for (;;)
		{
		/* If we have enough, we break */
		if (depth < num) break; /* FIXME: If this happens, we should take
		                         * note of it and, if appropriate, use the
		                         * X509_V_ERR_CERT_CHAIN_TOO_LONG error
		                         * code later.
		                         */

		/* If we are self signed, we break */
		xn=X509_get_issuer_name(x);
		if (ctx->check_issued(ctx, x,x)) break;

		/* If we were passed a cert chain, use it first */
		if (ctx->untrusted != NULL)
			{
			xtmp=find_issuer(ctx, sktmp,x);
			if (xtmp != NULL)
				{
				if (!sk_X509_push(ctx->chain,xtmp))
					{
					X509err(X509_F_X509_VERIFY_CERT,ERR_R_MALLOC_FAILURE);
					goto end;
					}
				CRYPTO_add(&xtmp->references,1,CRYPTO_LOCK_X509);
				sk_X509_delete_ptr(sktmp,xtmp);
				ctx->last_untrusted++;
				x=xtmp;
				num++;
				/* reparse the full chain for
				 * the next one */
				continue;
				}
			}
		break;
		}

	/* 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);
	xn = X509_get_subject_name(x);
	if (ctx->check_issued(ctx, x, 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);
				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;
				sk_X509_set(ctx->chain, i - 1, x);
				ctx->last_untrusted=0;
				}
			}
		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;

		/* If we are self signed, we break */
		xn=X509_get_issuer_name(x);
		if (ctx->check_issued(ctx,x,x)) break;

		ok = ctx->get_issuer(&xtmp, ctx, x);

		if (ok < 0) return ok;
		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;
			}
		num++;
		}

	/* we now have our chain, lets check it... */
	xn=X509_get_issuer_name(x);

	/* Is last certificate looked up self signed? */
	if (!ctx->check_issued(ctx,x,x))
		{
		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;
			else
				ctx->error=X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT;
			ctx->current_cert=x;
			}
		else
			{

			sk_X509_push(ctx->chain,chain_ss);
			num++;
			ctx->last_untrusted=num;
			ctx->current_cert=chain_ss;
			ctx->error=X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN;
			chain_ss=NULL;
			}

		ctx->error_depth=num-1;
		ok=cb(0,ctx);
		if (!ok) goto end;
		}

	/* We have the chain complete: now we need to check its purpose */
	ok = check_chain_extensions(ctx);

	if (!ok) goto end;

	/* The chain extensions are OK: check trust */

	if (ctx->trust > 0) ok = check_trust(ctx);

	if (!ok) goto end;

	/* We may as well copy down any DSA parameters that are required */
	X509_get_pubkey_parameters(NULL,ctx->chain);

	/* Check revocation status: we do this after copying parameters
	 * because they may be needed for CRL signature verification.
	 */

	ok = ctx->check_revocation(ctx);
	if(!ok) goto end;

	/* At this point, we have a chain and just need to verify it */
	if (ctx->verify != NULL)
		ok=ctx->verify(ctx);
	else
		ok=internal_verify(ctx);
	if (0)
		{
end:
		X509_get_pubkey_parameters(NULL,ctx->chain);
		}
	if (sktmp != NULL) sk_X509_free(sktmp);
	if (chain_ss != NULL) X509_free(chain_ss);
	return ok;
	}
/*
 * Please see comment in x509_vfy_apple.h
 */
int
X509_verify_cert(X509_STORE_CTX *ctx)
{
	TEAResult		ret = kTEAResultCertNotTrusted;
	TEACertificateChainRef	inputChain = NULL;
	TEACertificateChainRef	outputChain = NULL;
	__block uint64_t	certCount = 0;
	uint64_t		certLastIndex = 0;
	uint64_t		i = 0;
	int			error = 0;
	TEAParams		params = { 0 };


	if (ctx == NULL || ctx->cert == NULL)
        return kTEAResultErrorOccured;

	/* Try OpenSSL, if we get a local certificate issue verify against trusted roots */
	ret = X509_verify_cert_orig(ctx);

	/* Verify TEA is enabled and should be used. */
	if (0 != X509_TEA_is_enabled() &&
		ret != 1 && TEA_might_correct_error(ctx->error)) {

		/* Verify that the certificate chain exists, otherwise make it. */
		if (ctx->chain == NULL && (ctx->chain = sk_X509_new_null()) == NULL) {
			TEALogDebug("Could not create the certificate chain");
			ret = kTEAResultCertNotTrusted;
			goto bail;
		}

		/* Verify chain depth */
		certLastIndex = sk_X509_num(ctx->untrusted);
		if (certLastIndex > ctx->param->depth) {
			TEALogInfo("Pruning certificate chain to %" PRIu64, certLastIndex);
			certLastIndex = ctx->param->depth;
		}

		inputChain = TEACertificateChainCreate();
		if (inputChain == NULL) {
			TEALogDebug("Certificate chain creation failed");
			goto bail;
		}

		unsigned char *asn1_cert_data = NULL;
		int asn1_cert_len = i2d_X509(ctx->cert, &asn1_cert_data);
		error = TEACertificateChainAddCert(inputChain, asn1_cert_data, asn1_cert_len);
		// TEACertificateChainAddCert made a copy of the ASN.1 data, so we get to free ours here
		OPENSSL_free(asn1_cert_data);
		if (error) {
			TEALogDebug("An error occured while inserting the certificate into the chain");
			goto bail;
		}

		for (i = 0; i < certLastIndex; ++i) {
			X509	*t = sk_X509_value(ctx->untrusted, i);

			asn1_cert_data = NULL;
			asn1_cert_len = i2d_X509(t, &asn1_cert_data);
			error = TEACertificateChainAddCert(inputChain, asn1_cert_data, asn1_cert_len);
			// TEACertificateChainAddCert made a copy of the ASN.1 data, so we get to free ours here
			OPENSSL_free(asn1_cert_data);
			if (error) {
				TEALogDebug("An error occured while inserting an untrusted certificate into the chain");
				goto bail;
			}
		}

		// We put ASN.1 encoded X509 on the CertificateChain, so we don't call TEACertificateChainSetEncodingHandler
		
		params.purpose = ctx->param->purpose;
		if (ctx->param->flags & X509_V_FLAG_USE_CHECK_TIME)
			params.check_time = ctx->param->check_time;

		outputChain = TEAVerifyCert(inputChain, &params);

		TEACertificateChainRelease(inputChain);
		inputChain = NULL;

		if (outputChain == NULL) {
			TEALogDebug("TEAVerifyCert() returned NULL.");
			goto bail;
		}

		/* Empty the context chain */
		for (i = 0; i < sk_X509_num(ctx->chain); ++i)
			sk_X509_pop(ctx->chain);

		error = TEACertificateChainGetCerts(outputChain, ^(const TEACertificateRef cert) {
			const unsigned char	*ptr = TEACertificateGetData(cert);
			X509			*c = NULL;

			if (certCount++ > certLastIndex)
				return 0;

			c = d2i_X509(NULL, &ptr, TEACertificateGetSize(cert));
			if (c == NULL) {
				TEALogDebug("Could not parse certificate");
				return 1;
			}

			if (!sk_X509_push(ctx->chain, c)) {
				TEALogDebug("Could not insert certificate into the chain");
				return 1;
			}

			return 0;
		});
		if (error) {
			TEALogDebug("An error occured while deserializing the trusted certificate chain");
			ret = kTEAResultCertNotTrusted;
			goto bail;
		}

		TEACertificateChainRelease(outputChain);
		outputChain = NULL;

		/* Fixup context data */
		ctx->current_cert   = sk_X509_value(ctx->chain, 0);
		ctx->current_issuer = sk_X509_value(ctx->chain, sk_X509_num(ctx->chain) - 1);
		ctx->error_depth = 0;
		ctx->error = 0;
		X509_get_pubkey_parameters(NULL, ctx->chain);

		ret = kTEAResultCertTrusted;
	}