Пример #1
0
unsigned
_gnutls_check_if_same_key2(gnutls_x509_crt_t cert1,
			   gnutls_datum_t * cert2bin)
{
	int ret;
	gnutls_x509_crt_t cert2;

	ret = gnutls_x509_crt_init(&cert2);
	if (ret < 0)
		return gnutls_assert_val(0);

	ret = gnutls_x509_crt_import(cert2, cert2bin, GNUTLS_X509_FMT_DER);
	if (ret < 0) {
		gnutls_x509_crt_deinit(cert2);
		return gnutls_assert_val(0);
	}

	ret = _gnutls_check_if_same_key(cert1, cert2, 1);

	gnutls_x509_crt_deinit(cert2);
	return ret;
}
Пример #2
0
/* Verify X.509 certificate chain.
 *
 * Note that the return value is an OR of GNUTLS_CERT_* elements.
 *
 * This function verifies a X.509 certificate list. The certificate
 * list should lead to a trusted certificate in order to be trusted.
 */
unsigned int
_gnutls_verify_crt_status(const gnutls_x509_crt_t * certificate_list,
				int clist_size,
				const gnutls_x509_crt_t * trusted_cas,
				int tcas_size,
				unsigned int flags,
				const char *purpose,
				gnutls_verify_output_function func)
{
	int i = 0, ret;
	unsigned int status = 0, output;
	time_t now = gnutls_time(0);
	verify_state_st vparams;

	if (clist_size > 1) {
		/* Check if the last certificate in the path is self signed.
		 * In that case ignore it (a certificate is trusted only if it
		 * leads to a trusted party by us, not the server's).
		 *
		 * This prevents from verifying self signed certificates against
		 * themselves. This (although not bad) caused verification
		 * failures on some root self signed certificates that use the
		 * MD2 algorithm.
		 */
		if (gnutls_x509_crt_check_issuer
		    (certificate_list[clist_size - 1],
		     certificate_list[clist_size - 1]) != 0) {
			clist_size--;
		}
	}

	/* We want to shorten the chain by removing the cert that matches
	 * one of the certs we trust and all the certs after that i.e. if
	 * cert chain is A signed-by B signed-by C signed-by D (signed-by
	 * self-signed E but already removed above), and we trust B, remove
	 * B, C and D. */
	if (!(flags & GNUTLS_VERIFY_DO_NOT_ALLOW_SAME))
		i = 0;		/* also replace the first one */
	else
		i = 1;		/* do not replace the first one */

	for (; i < clist_size; i++) {
		int j;

		for (j = 0; j < tcas_size; j++) {
			/* we check for a certificate that may not be identical with the one
			 * sent by the client, but will have the same name and key. That is
			 * because it can happen that a CA certificate is upgraded from intermediate
			 * CA to self-signed CA at some point. */
			if (_gnutls_check_if_same_key
			    (certificate_list[i], trusted_cas[j], i) != 0) {
				/* explicit time check for trusted CA that we remove from
				 * list. GNUTLS_VERIFY_DISABLE_TRUSTED_TIME_CHECKS
				 */

				if (!(flags & GNUTLS_VERIFY_DISABLE_TRUSTED_TIME_CHECKS) &&
					!(flags & GNUTLS_VERIFY_DISABLE_TIME_CHECKS)) {
					status |=
					    check_time_status(trusted_cas[j],
						       now);
					if (status != 0) {
						if (func)
							func(certificate_list[i], trusted_cas[j], NULL, status);
						return status;
					}
				}

				if (func)
					func(certificate_list[i],
					     trusted_cas[j], NULL, status);
				clist_size = i;
				break;
			}
		}
		/* clist_size may have been changed which gets out of loop */
	}

	if (clist_size == 0) {
		/* The certificate is already present in the trusted certificate list.
		 * Nothing to verify. */
		return status;
	}

	memset(&vparams, 0, sizeof(vparams));
	vparams.now = now;
	vparams.max_path = MAX_VERIFY_DEPTH;
	vparams.func = func;

	ret = gnutls_x509_name_constraints_init(&vparams.nc);
	if (ret < 0) {
		gnutls_assert();
		status |= GNUTLS_CERT_INVALID;
		return status;
	}

	ret = gnutls_x509_tlsfeatures_init(&vparams.tls_feat);
	if (ret < 0) {
		gnutls_assert();
		status |= GNUTLS_CERT_INVALID;
		goto cleanup;
	}

	/* Verify the last certificate in the certificate path
	 * against the trusted CA certificate list.
	 *
	 * If no CAs are present returns CERT_INVALID. Thus works
	 * in self signed etc certificates.
	 */
	output = 0;

	ret = verify_crt(certificate_list[clist_size - 1],
					  trusted_cas, tcas_size, flags,
					  &output,
					  &vparams,
					  clist_size==1?1:0);
	if (ret != 1) {
		/* if the last certificate in the certificate
		 * list is invalid, then the certificate is not
		 * trusted.
		 */
		gnutls_assert();
		status |= output;
		status |= GNUTLS_CERT_INVALID;
		goto cleanup;
	}

	/* Verify the certificate path (chain)
	 */
	for (i = clist_size - 1; i > 0; i--) {
		output = 0;
		if (i - 1 < 0)
			break;

		if (purpose != NULL) {
			ret = _gnutls_check_key_purpose(certificate_list[i], purpose, 1);
			if (ret != 1) {
				gnutls_assert();
				status |= GNUTLS_CERT_INVALID;
				status |= GNUTLS_CERT_PURPOSE_MISMATCH;

				if (func)
					func(certificate_list[i-1],
					     certificate_list[i], NULL, status);
				goto cleanup;
			}
		}

		/* note that here we disable this V1 CA flag. So that no version 1
		 * certificates can exist in a supplied chain.
		 */
		if (!(flags & GNUTLS_VERIFY_ALLOW_ANY_X509_V1_CA_CRT)) {
			flags |= GNUTLS_VERIFY_DO_NOT_ALLOW_X509_V1_CA_CRT;
		}

		if ((ret =
		     verify_crt(certificate_list[i - 1],
						 &certificate_list[i], 1,
						 flags, &output,
						 &vparams,
						 i==1?1:0)) != 1) {
			gnutls_assert();
			status |= output;
			status |= GNUTLS_CERT_INVALID;
			goto cleanup;
		}
	}

cleanup:
	gnutls_x509_name_constraints_deinit(vparams.nc);
	gnutls_x509_tlsfeatures_deinit(vparams.tls_feat);
	return status;
}
Пример #3
0
/**
 * gnutls_x509_trust_list_add_cas:
 * @list: The structure of the list
 * @clist: A list of CAs
 * @clist_size: The length of the CA list
 * @flags: should be 0 or an or'ed sequence of %GNUTLS_TL options.
 *
 * This function will add the given certificate authorities
 * to the trusted list. The list of CAs must not be deinitialized
 * during this structure's lifetime.
 *
 * If the flag %GNUTLS_TL_NO_DUPLICATES is specified, then
 * the provided @clist entries that are duplicates will not be
 * added to the list and will be deinitialized.
 *
 * Returns: The number of added elements is returned.
 *
 * Since: 3.0.0
 **/
int
gnutls_x509_trust_list_add_cas(gnutls_x509_trust_list_t list,
			       const gnutls_x509_crt_t * clist,
			       unsigned clist_size, unsigned int flags)
{
	unsigned i, j;
	uint32_t hash;
	int ret;
	unsigned exists;

	for (i = 0; i < clist_size; i++) {
		exists = 0;
		hash =
		    hash_pjw_bare(clist[i]->raw_dn.data,
				  clist[i]->raw_dn.size);
		hash %= list->size;

		/* avoid duplicates */
		if (flags & GNUTLS_TL_NO_DUPLICATES || flags & GNUTLS_TL_NO_DUPLICATE_KEY) {
			for (j=0;j<list->node[hash].trusted_ca_size;j++) {
				if (flags & GNUTLS_TL_NO_DUPLICATES)
					ret = _gnutls_check_if_same_cert(list->node[hash].trusted_cas[j], clist[i]);
				else
					ret = _gnutls_check_if_same_key(list->node[hash].trusted_cas[j], clist[i], 1);
				if (ret != 0) {
					exists = 1;
					break;
				}
			}

			if (exists != 0) {
				gnutls_x509_crt_deinit(list->node[hash].trusted_cas[j]);
				list->node[hash].trusted_cas[j] = clist[i];
				continue;
			}
		}

		list->node[hash].trusted_cas =
		    gnutls_realloc_fast(list->node[hash].trusted_cas,
					(list->node[hash].trusted_ca_size +
					 1) *
					sizeof(list->node[hash].
					       trusted_cas[0]));
		if (list->node[hash].trusted_cas == NULL) {
			gnutls_assert();
			return i;
		}

		if (gnutls_x509_crt_get_version(clist[i]) >= 3 &&
		    gnutls_x509_crt_get_ca_status(clist[i], NULL) <= 0) {
			gnutls_datum_t dn;
			gnutls_assert();
			if (gnutls_x509_crt_get_dn2(clist[i], &dn) >= 0) {
				_gnutls_audit_log(NULL,
					  "There was a non-CA certificate in the trusted list: %s.\n",
					  dn.data);
				gnutls_free(dn.data);
			}
		}

		list->node[hash].trusted_cas[list->node[hash].
					     trusted_ca_size] = clist[i];
		list->node[hash].trusted_ca_size++;

		if (flags & GNUTLS_TL_USE_IN_TLS) {
			ret = add_new_ca_to_rdn_seq(list, clist[i]);
			if (ret < 0) {
				gnutls_assert();
				return i;
			}
		}
	}

	return i;
}