Example #1
0
/**
 * gnutls_x509_crl_verify:
 * @crl: is the crl to be verified
 * @trusted_cas: is a certificate list that is considered to be trusted one
 * @tcas_size: holds the number of CA certificates in CA_list
 * @flags: Flags that may be used to change the verification algorithm. Use OR of the gnutls_certificate_verify_flags enumerations.
 * @verify: will hold the crl verification output.
 *
 * This function will try to verify the given crl and return its verification status.
 * See gnutls_x509_crt_list_verify() for a detailed description of
 * return values. Note that since GnuTLS 3.1.4 this function includes
 * the time checks.
 *
 * Note that value in @verify is set only when the return value of this 
 * function is success (i.e, failure to trust a CRL a certificate does not imply 
 * a negative return value).
 *
 * Before GnuTLS 3.5.7 this function would return zero or a positive
 * number on success.
 *
 * Returns: On success, %GNUTLS_E_SUCCESS (0), otherwise a
 *   negative error value.
 **/
int
gnutls_x509_crl_verify(gnutls_x509_crl_t crl,
		       const gnutls_x509_crt_t * trusted_cas,
		       unsigned tcas_size, unsigned int flags,
		       unsigned int *verify)
{
/* CRL is ignored for now */
	gnutls_datum_t crl_signed_data = { NULL, 0 };
	gnutls_datum_t crl_signature = { NULL, 0 };
	gnutls_x509_crt_t issuer = NULL;
	int result, hash_algo;
	time_t now = gnutls_time(0);
	unsigned int usage;

	if (verify)
		*verify = 0;

	if (tcas_size >= 1)
		issuer = find_crl_issuer(crl, trusted_cas, tcas_size);

	result =
	    _gnutls_x509_get_signed_data(crl->crl, &crl->der, "tbsCertList",
					 &crl_signed_data);
	if (result < 0) {
		gnutls_assert();
		if (verify)
			*verify |= GNUTLS_CERT_INVALID;
		goto cleanup;
	}

	result =
	    _gnutls_x509_get_signature(crl->crl, "signature",
				       &crl_signature);
	if (result < 0) {
		gnutls_assert();
		if (verify)
			*verify |= GNUTLS_CERT_INVALID;
		goto cleanup;
	}

	result =
	    _gnutls_x509_get_signature_algorithm(crl->crl,
						 "signatureAlgorithm.algorithm");
	if (result < 0) {
		gnutls_assert();
		if (verify)
			*verify |= GNUTLS_CERT_INVALID;
		goto cleanup;
	}

	hash_algo = gnutls_sign_get_hash_algorithm(result);

	/* issuer is not in trusted certificate
	 * authorities.
	 */
	if (issuer == NULL) {
		gnutls_assert();
		if (verify)
			*verify |=
			    GNUTLS_CERT_SIGNER_NOT_FOUND |
			    GNUTLS_CERT_INVALID;
	} else {
		if (!(flags & GNUTLS_VERIFY_DISABLE_CA_SIGN)) {
			if (gnutls_x509_crt_get_ca_status(issuer, NULL) != 1) {
				gnutls_assert();
				if (verify)
					*verify |=
					    GNUTLS_CERT_SIGNER_NOT_CA |
					    GNUTLS_CERT_INVALID;
			}

			result =
			    gnutls_x509_crt_get_key_usage(issuer, &usage, NULL);
			if (result != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
				if (result < 0) {
					gnutls_assert();
					if (verify)
						*verify |= GNUTLS_CERT_INVALID;
				} else if (!(usage & GNUTLS_KEY_CRL_SIGN)) {
					gnutls_assert();
					if (verify)
						*verify |=
						    GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE
						    | GNUTLS_CERT_INVALID;
				}
			}
		}

		result =
		    _gnutls_x509_verify_data(mac_to_entry(hash_algo),
					     &crl_signed_data, &crl_signature,
					     issuer);
		if (result == GNUTLS_E_PK_SIG_VERIFY_FAILED) {
			gnutls_assert();
			/* error. ignore it */
			if (verify)
				*verify |= GNUTLS_CERT_SIGNATURE_FAILURE;
			result = 0;
		} else if (result < 0) {
			gnutls_assert();
			if (verify)
				*verify |= GNUTLS_CERT_INVALID;
			goto cleanup;
		} else if (result >= 0) {
			result = 0; /* everything ok */
		}
	}

	{
		int sigalg;

		sigalg = gnutls_x509_crl_get_signature_algorithm(crl);

		if (((sigalg == GNUTLS_SIGN_RSA_MD2) &&
		     !(flags & GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD2)) ||
		    ((sigalg == GNUTLS_SIGN_RSA_MD5) &&
		     !(flags & GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5))) {
			if (verify)
				*verify |= GNUTLS_CERT_INSECURE_ALGORITHM;
			result = 0;
		}
	}

	if (gnutls_x509_crl_get_this_update(crl) > now && verify)
		*verify |= GNUTLS_CERT_REVOCATION_DATA_ISSUED_IN_FUTURE;

	if (gnutls_x509_crl_get_next_update(crl) < now && verify)
		*verify |= GNUTLS_CERT_REVOCATION_DATA_SUPERSEDED;


      cleanup:
	if (verify && *verify != 0)
		*verify |= GNUTLS_CERT_INVALID;

	_gnutls_free_datum(&crl_signed_data);
	_gnutls_free_datum(&crl_signature);

	return result;
}
Example #2
0
/**
 * gnutls_x509_trust_list_add_crls:
 * @list: The list
 * @crl_list: A list of CRLs
 * @crl_size: The length of the CRL list
 * @flags: flags from %gnutls_trust_list_flags_t
 * @verification_flags: gnutls_certificate_verify_flags if flags specifies GNUTLS_TL_VERIFY_CRL
 *
 * This function will add the given certificate revocation lists
 * to the trusted list. The CRLs in @crl_list must not be deinitialized
 * during the lifetime of @list.
 *
 * This function must be called after gnutls_x509_trust_list_add_cas()
 * to allow verifying the CRLs for validity. If the flag %GNUTLS_TL_NO_DUPLICATES
 * is given, then the final CRL list will not contain duplicate entries.
 *
 * If the flag %GNUTLS_TL_NO_DUPLICATES is given, gnutls_x509_trust_list_deinit() must be
 * called with parameter @all being 1.
 *
 * If flag %GNUTLS_TL_VERIFY_CRL is given the CRLs will be verified before being added,
 * and if verification fails, they will be skipped.
 *
 * Returns: The number of added elements is returned; that includes
 *          duplicate entries.
 *
 * Since: 3.0
 **/
int
gnutls_x509_trust_list_add_crls(gnutls_x509_trust_list_t list,
				const gnutls_x509_crl_t * crl_list,
				unsigned crl_size, unsigned int flags,
				unsigned int verification_flags)
{
	int ret;
	unsigned x, i, j = 0;
	unsigned int vret = 0;
	uint32_t hash;
	gnutls_x509_crl_t *tmp;

	/* Probably we can optimize things such as removing duplicates
	 * etc.
	 */
	if (crl_size == 0 || crl_list == NULL)
		return 0;

	for (i = 0; i < crl_size; i++) {
		hash =
		    hash_pjw_bare(crl_list[i]->raw_issuer_dn.data,
				  crl_list[i]->raw_issuer_dn.size);
		hash %= list->size;

		if (flags & GNUTLS_TL_VERIFY_CRL) {

			ret =
			    gnutls_x509_crl_verify(crl_list[i],
						   list->node[hash].
						   trusted_cas,
						   list->node[hash].
						   trusted_ca_size,
						   verification_flags,
						   &vret);
			if (ret < 0 || vret != 0) {
				_gnutls_debug_log("CRL verification failed, not adding it\n");
				if (flags & GNUTLS_TL_NO_DUPLICATES)
					gnutls_x509_crl_deinit(crl_list[i]);
				if (flags & GNUTLS_TL_FAIL_ON_INVALID_CRL)
					return gnutls_assert_val(GNUTLS_E_CRL_VERIFICATION_ERROR);
				continue;
			}
		}

		/* If the CRL added overrides a previous one, then overwrite
		 * the old one */
		if (flags & GNUTLS_TL_NO_DUPLICATES) {
			for (x=0;x<list->node[hash].crl_size;x++) {
				if (crl_list[i]->raw_issuer_dn.size == list->node[hash].crls[x]->raw_issuer_dn.size &&
				    memcmp(crl_list[i]->raw_issuer_dn.data, list->node[hash].crls[x]->raw_issuer_dn.data, crl_list[i]->raw_issuer_dn.size) == 0) {
					if (gnutls_x509_crl_get_this_update(crl_list[i]) >=
					    gnutls_x509_crl_get_this_update(list->node[hash].crls[x])) {

						gnutls_x509_crl_deinit(list->node[hash].crls[x]);
						list->node[hash].crls[x] = crl_list[i];
						goto next;
					} else {
						/* The new is older, discard it */
						gnutls_x509_crl_deinit(crl_list[i]);
						goto next;
					}
				}
			}
		}

		tmp =
		    gnutls_realloc(list->node[hash].crls,
					(list->node[hash].crl_size +
					 1) *
					sizeof(list->node[hash].
					       crls[0]));
		if (tmp == NULL) {
			ret = i;
			gnutls_assert();
			if (flags & GNUTLS_TL_NO_DUPLICATES)
				while (i < crl_size)
					gnutls_x509_crl_deinit(crl_list[i++]);
			return ret;
		}
		list->node[hash].crls = tmp;


		list->node[hash].crls[list->node[hash].crl_size] =
		    crl_list[i];
		list->node[hash].crl_size++;

 next:
		j++;
	}

	return j;
}