18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/* Verify the signature on a PKCS#7 message.
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
58c2ecf20Sopenharmony_ci * Written by David Howells (dhowells@redhat.com)
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#define pr_fmt(fmt) "PKCS7: "fmt
98c2ecf20Sopenharmony_ci#include <linux/kernel.h>
108c2ecf20Sopenharmony_ci#include <linux/export.h>
118c2ecf20Sopenharmony_ci#include <linux/slab.h>
128c2ecf20Sopenharmony_ci#include <linux/err.h>
138c2ecf20Sopenharmony_ci#include <linux/asn1.h>
148c2ecf20Sopenharmony_ci#include <crypto/hash.h>
158c2ecf20Sopenharmony_ci#include <crypto/hash_info.h>
168c2ecf20Sopenharmony_ci#include <crypto/public_key.h>
178c2ecf20Sopenharmony_ci#include "pkcs7_parser.h"
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci/*
208c2ecf20Sopenharmony_ci * Digest the relevant parts of the PKCS#7 data
218c2ecf20Sopenharmony_ci */
228c2ecf20Sopenharmony_cistatic int pkcs7_digest(struct pkcs7_message *pkcs7,
238c2ecf20Sopenharmony_ci			struct pkcs7_signed_info *sinfo)
248c2ecf20Sopenharmony_ci{
258c2ecf20Sopenharmony_ci	struct public_key_signature *sig = sinfo->sig;
268c2ecf20Sopenharmony_ci	struct crypto_shash *tfm;
278c2ecf20Sopenharmony_ci	struct shash_desc *desc;
288c2ecf20Sopenharmony_ci	size_t desc_size;
298c2ecf20Sopenharmony_ci	int ret;
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci	kenter(",%u,%s", sinfo->index, sinfo->sig->hash_algo);
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci	/* The digest was calculated already. */
348c2ecf20Sopenharmony_ci	if (sig->digest)
358c2ecf20Sopenharmony_ci		return 0;
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci	if (!sinfo->sig->hash_algo)
388c2ecf20Sopenharmony_ci		return -ENOPKG;
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	/* Allocate the hashing algorithm we're going to need and find out how
418c2ecf20Sopenharmony_ci	 * big the hash operational data will be.
428c2ecf20Sopenharmony_ci	 */
438c2ecf20Sopenharmony_ci	tfm = crypto_alloc_shash(sinfo->sig->hash_algo, 0, 0);
448c2ecf20Sopenharmony_ci	if (IS_ERR(tfm))
458c2ecf20Sopenharmony_ci		return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm);
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
488c2ecf20Sopenharmony_ci	sig->digest_size = crypto_shash_digestsize(tfm);
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci	ret = -ENOMEM;
518c2ecf20Sopenharmony_ci	sig->digest = kmalloc(sig->digest_size, GFP_KERNEL);
528c2ecf20Sopenharmony_ci	if (!sig->digest)
538c2ecf20Sopenharmony_ci		goto error_no_desc;
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	desc = kzalloc(desc_size, GFP_KERNEL);
568c2ecf20Sopenharmony_ci	if (!desc)
578c2ecf20Sopenharmony_ci		goto error_no_desc;
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	desc->tfm   = tfm;
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	/* Digest the message [RFC2315 9.3] */
628c2ecf20Sopenharmony_ci	ret = crypto_shash_digest(desc, pkcs7->data, pkcs7->data_len,
638c2ecf20Sopenharmony_ci				  sig->digest);
648c2ecf20Sopenharmony_ci	if (ret < 0)
658c2ecf20Sopenharmony_ci		goto error;
668c2ecf20Sopenharmony_ci	pr_devel("MsgDigest = [%*ph]\n", 8, sig->digest);
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	/* However, if there are authenticated attributes, there must be a
698c2ecf20Sopenharmony_ci	 * message digest attribute amongst them which corresponds to the
708c2ecf20Sopenharmony_ci	 * digest we just calculated.
718c2ecf20Sopenharmony_ci	 */
728c2ecf20Sopenharmony_ci	if (sinfo->authattrs) {
738c2ecf20Sopenharmony_ci		u8 tag;
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci		if (!sinfo->msgdigest) {
768c2ecf20Sopenharmony_ci			pr_warn("Sig %u: No messageDigest\n", sinfo->index);
778c2ecf20Sopenharmony_ci			ret = -EKEYREJECTED;
788c2ecf20Sopenharmony_ci			goto error;
798c2ecf20Sopenharmony_ci		}
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci		if (sinfo->msgdigest_len != sig->digest_size) {
828c2ecf20Sopenharmony_ci			pr_warn("Sig %u: Invalid digest size (%u)\n",
838c2ecf20Sopenharmony_ci				sinfo->index, sinfo->msgdigest_len);
848c2ecf20Sopenharmony_ci			ret = -EBADMSG;
858c2ecf20Sopenharmony_ci			goto error;
868c2ecf20Sopenharmony_ci		}
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci		if (memcmp(sig->digest, sinfo->msgdigest,
898c2ecf20Sopenharmony_ci			   sinfo->msgdigest_len) != 0) {
908c2ecf20Sopenharmony_ci			pr_warn("Sig %u: Message digest doesn't match\n",
918c2ecf20Sopenharmony_ci				sinfo->index);
928c2ecf20Sopenharmony_ci			ret = -EKEYREJECTED;
938c2ecf20Sopenharmony_ci			goto error;
948c2ecf20Sopenharmony_ci		}
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci		/* We then calculate anew, using the authenticated attributes
978c2ecf20Sopenharmony_ci		 * as the contents of the digest instead.  Note that we need to
988c2ecf20Sopenharmony_ci		 * convert the attributes from a CONT.0 into a SET before we
998c2ecf20Sopenharmony_ci		 * hash it.
1008c2ecf20Sopenharmony_ci		 */
1018c2ecf20Sopenharmony_ci		memset(sig->digest, 0, sig->digest_size);
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci		ret = crypto_shash_init(desc);
1048c2ecf20Sopenharmony_ci		if (ret < 0)
1058c2ecf20Sopenharmony_ci			goto error;
1068c2ecf20Sopenharmony_ci		tag = ASN1_CONS_BIT | ASN1_SET;
1078c2ecf20Sopenharmony_ci		ret = crypto_shash_update(desc, &tag, 1);
1088c2ecf20Sopenharmony_ci		if (ret < 0)
1098c2ecf20Sopenharmony_ci			goto error;
1108c2ecf20Sopenharmony_ci		ret = crypto_shash_finup(desc, sinfo->authattrs,
1118c2ecf20Sopenharmony_ci					 sinfo->authattrs_len, sig->digest);
1128c2ecf20Sopenharmony_ci		if (ret < 0)
1138c2ecf20Sopenharmony_ci			goto error;
1148c2ecf20Sopenharmony_ci		pr_devel("AADigest = [%*ph]\n", 8, sig->digest);
1158c2ecf20Sopenharmony_ci	}
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_cierror:
1188c2ecf20Sopenharmony_ci	kfree(desc);
1198c2ecf20Sopenharmony_cierror_no_desc:
1208c2ecf20Sopenharmony_ci	crypto_free_shash(tfm);
1218c2ecf20Sopenharmony_ci	kleave(" = %d", ret);
1228c2ecf20Sopenharmony_ci	return ret;
1238c2ecf20Sopenharmony_ci}
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ciint pkcs7_get_digest(struct pkcs7_message *pkcs7, const u8 **buf, u32 *len,
1268c2ecf20Sopenharmony_ci		     enum hash_algo *hash_algo)
1278c2ecf20Sopenharmony_ci{
1288c2ecf20Sopenharmony_ci	struct pkcs7_signed_info *sinfo = pkcs7->signed_infos;
1298c2ecf20Sopenharmony_ci	int i, ret;
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	/*
1328c2ecf20Sopenharmony_ci	 * This function doesn't support messages with more than one signature.
1338c2ecf20Sopenharmony_ci	 */
1348c2ecf20Sopenharmony_ci	if (sinfo == NULL || sinfo->next != NULL)
1358c2ecf20Sopenharmony_ci		return -EBADMSG;
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	ret = pkcs7_digest(pkcs7, sinfo);
1388c2ecf20Sopenharmony_ci	if (ret)
1398c2ecf20Sopenharmony_ci		return ret;
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	*buf = sinfo->sig->digest;
1428c2ecf20Sopenharmony_ci	*len = sinfo->sig->digest_size;
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	for (i = 0; i < HASH_ALGO__LAST; i++)
1458c2ecf20Sopenharmony_ci		if (!strcmp(hash_algo_name[i], sinfo->sig->hash_algo)) {
1468c2ecf20Sopenharmony_ci			*hash_algo = i;
1478c2ecf20Sopenharmony_ci			break;
1488c2ecf20Sopenharmony_ci		}
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	return 0;
1518c2ecf20Sopenharmony_ci}
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci/*
1548c2ecf20Sopenharmony_ci * Find the key (X.509 certificate) to use to verify a PKCS#7 message.  PKCS#7
1558c2ecf20Sopenharmony_ci * uses the issuer's name and the issuing certificate serial number for
1568c2ecf20Sopenharmony_ci * matching purposes.  These must match the certificate issuer's name (not
1578c2ecf20Sopenharmony_ci * subject's name) and the certificate serial number [RFC 2315 6.7].
1588c2ecf20Sopenharmony_ci */
1598c2ecf20Sopenharmony_cistatic int pkcs7_find_key(struct pkcs7_message *pkcs7,
1608c2ecf20Sopenharmony_ci			  struct pkcs7_signed_info *sinfo)
1618c2ecf20Sopenharmony_ci{
1628c2ecf20Sopenharmony_ci	struct x509_certificate *x509;
1638c2ecf20Sopenharmony_ci	unsigned certix = 1;
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	kenter("%u", sinfo->index);
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	for (x509 = pkcs7->certs; x509; x509 = x509->next, certix++) {
1688c2ecf20Sopenharmony_ci		/* I'm _assuming_ that the generator of the PKCS#7 message will
1698c2ecf20Sopenharmony_ci		 * encode the fields from the X.509 cert in the same way in the
1708c2ecf20Sopenharmony_ci		 * PKCS#7 message - but I can't be 100% sure of that.  It's
1718c2ecf20Sopenharmony_ci		 * possible this will need element-by-element comparison.
1728c2ecf20Sopenharmony_ci		 */
1738c2ecf20Sopenharmony_ci		if (!asymmetric_key_id_same(x509->id, sinfo->sig->auth_ids[0]))
1748c2ecf20Sopenharmony_ci			continue;
1758c2ecf20Sopenharmony_ci		pr_devel("Sig %u: Found cert serial match X.509[%u]\n",
1768c2ecf20Sopenharmony_ci			 sinfo->index, certix);
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci		sinfo->signer = x509;
1798c2ecf20Sopenharmony_ci		return 0;
1808c2ecf20Sopenharmony_ci	}
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	/* The relevant X.509 cert isn't found here, but it might be found in
1838c2ecf20Sopenharmony_ci	 * the trust keyring.
1848c2ecf20Sopenharmony_ci	 */
1858c2ecf20Sopenharmony_ci	pr_debug("Sig %u: Issuing X.509 cert not found (#%*phN)\n",
1868c2ecf20Sopenharmony_ci		 sinfo->index,
1878c2ecf20Sopenharmony_ci		 sinfo->sig->auth_ids[0]->len, sinfo->sig->auth_ids[0]->data);
1888c2ecf20Sopenharmony_ci	return 0;
1898c2ecf20Sopenharmony_ci}
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci/*
1928c2ecf20Sopenharmony_ci * Verify the internal certificate chain as best we can.
1938c2ecf20Sopenharmony_ci */
1948c2ecf20Sopenharmony_cistatic int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
1958c2ecf20Sopenharmony_ci				  struct pkcs7_signed_info *sinfo)
1968c2ecf20Sopenharmony_ci{
1978c2ecf20Sopenharmony_ci	struct public_key_signature *sig;
1988c2ecf20Sopenharmony_ci	struct x509_certificate *x509 = sinfo->signer, *p;
1998c2ecf20Sopenharmony_ci	struct asymmetric_key_id *auth;
2008c2ecf20Sopenharmony_ci	int ret;
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	kenter("");
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	for (p = pkcs7->certs; p; p = p->next)
2058c2ecf20Sopenharmony_ci		p->seen = false;
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	for (;;) {
2088c2ecf20Sopenharmony_ci		pr_debug("verify %s: %*phN\n",
2098c2ecf20Sopenharmony_ci			 x509->subject,
2108c2ecf20Sopenharmony_ci			 x509->raw_serial_size, x509->raw_serial);
2118c2ecf20Sopenharmony_ci		x509->seen = true;
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci		if (x509->blacklisted) {
2148c2ecf20Sopenharmony_ci			/* If this cert is blacklisted, then mark everything
2158c2ecf20Sopenharmony_ci			 * that depends on this as blacklisted too.
2168c2ecf20Sopenharmony_ci			 */
2178c2ecf20Sopenharmony_ci			sinfo->blacklisted = true;
2188c2ecf20Sopenharmony_ci			for (p = sinfo->signer; p != x509; p = p->signer)
2198c2ecf20Sopenharmony_ci				p->blacklisted = true;
2208c2ecf20Sopenharmony_ci			pr_debug("- blacklisted\n");
2218c2ecf20Sopenharmony_ci			return 0;
2228c2ecf20Sopenharmony_ci		}
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci		if (x509->unsupported_key)
2258c2ecf20Sopenharmony_ci			goto unsupported_crypto_in_x509;
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci		pr_debug("- issuer %s\n", x509->issuer);
2288c2ecf20Sopenharmony_ci		sig = x509->sig;
2298c2ecf20Sopenharmony_ci		if (sig->auth_ids[0])
2308c2ecf20Sopenharmony_ci			pr_debug("- authkeyid.id %*phN\n",
2318c2ecf20Sopenharmony_ci				 sig->auth_ids[0]->len, sig->auth_ids[0]->data);
2328c2ecf20Sopenharmony_ci		if (sig->auth_ids[1])
2338c2ecf20Sopenharmony_ci			pr_debug("- authkeyid.skid %*phN\n",
2348c2ecf20Sopenharmony_ci				 sig->auth_ids[1]->len, sig->auth_ids[1]->data);
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci		if (x509->self_signed) {
2378c2ecf20Sopenharmony_ci			/* If there's no authority certificate specified, then
2388c2ecf20Sopenharmony_ci			 * the certificate must be self-signed and is the root
2398c2ecf20Sopenharmony_ci			 * of the chain.  Likewise if the cert is its own
2408c2ecf20Sopenharmony_ci			 * authority.
2418c2ecf20Sopenharmony_ci			 */
2428c2ecf20Sopenharmony_ci			if (x509->unsupported_sig)
2438c2ecf20Sopenharmony_ci				goto unsupported_crypto_in_x509;
2448c2ecf20Sopenharmony_ci			x509->signer = x509;
2458c2ecf20Sopenharmony_ci			pr_debug("- self-signed\n");
2468c2ecf20Sopenharmony_ci			return 0;
2478c2ecf20Sopenharmony_ci		}
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci		/* Look through the X.509 certificates in the PKCS#7 message's
2508c2ecf20Sopenharmony_ci		 * list to see if the next one is there.
2518c2ecf20Sopenharmony_ci		 */
2528c2ecf20Sopenharmony_ci		auth = sig->auth_ids[0];
2538c2ecf20Sopenharmony_ci		if (auth) {
2548c2ecf20Sopenharmony_ci			pr_debug("- want %*phN\n", auth->len, auth->data);
2558c2ecf20Sopenharmony_ci			for (p = pkcs7->certs; p; p = p->next) {
2568c2ecf20Sopenharmony_ci				pr_debug("- cmp [%u] %*phN\n",
2578c2ecf20Sopenharmony_ci					 p->index, p->id->len, p->id->data);
2588c2ecf20Sopenharmony_ci				if (asymmetric_key_id_same(p->id, auth))
2598c2ecf20Sopenharmony_ci					goto found_issuer_check_skid;
2608c2ecf20Sopenharmony_ci			}
2618c2ecf20Sopenharmony_ci		} else if (sig->auth_ids[1]) {
2628c2ecf20Sopenharmony_ci			auth = sig->auth_ids[1];
2638c2ecf20Sopenharmony_ci			pr_debug("- want %*phN\n", auth->len, auth->data);
2648c2ecf20Sopenharmony_ci			for (p = pkcs7->certs; p; p = p->next) {
2658c2ecf20Sopenharmony_ci				if (!p->skid)
2668c2ecf20Sopenharmony_ci					continue;
2678c2ecf20Sopenharmony_ci				pr_debug("- cmp [%u] %*phN\n",
2688c2ecf20Sopenharmony_ci					 p->index, p->skid->len, p->skid->data);
2698c2ecf20Sopenharmony_ci				if (asymmetric_key_id_same(p->skid, auth))
2708c2ecf20Sopenharmony_ci					goto found_issuer;
2718c2ecf20Sopenharmony_ci			}
2728c2ecf20Sopenharmony_ci		}
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci		/* We didn't find the root of this chain */
2758c2ecf20Sopenharmony_ci		pr_debug("- top\n");
2768c2ecf20Sopenharmony_ci		return 0;
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	found_issuer_check_skid:
2798c2ecf20Sopenharmony_ci		/* We matched issuer + serialNumber, but if there's an
2808c2ecf20Sopenharmony_ci		 * authKeyId.keyId, that must match the CA subjKeyId also.
2818c2ecf20Sopenharmony_ci		 */
2828c2ecf20Sopenharmony_ci		if (sig->auth_ids[1] &&
2838c2ecf20Sopenharmony_ci		    !asymmetric_key_id_same(p->skid, sig->auth_ids[1])) {
2848c2ecf20Sopenharmony_ci			pr_warn("Sig %u: X.509 chain contains auth-skid nonmatch (%u->%u)\n",
2858c2ecf20Sopenharmony_ci				sinfo->index, x509->index, p->index);
2868c2ecf20Sopenharmony_ci			return -EKEYREJECTED;
2878c2ecf20Sopenharmony_ci		}
2888c2ecf20Sopenharmony_ci	found_issuer:
2898c2ecf20Sopenharmony_ci		pr_debug("- subject %s\n", p->subject);
2908c2ecf20Sopenharmony_ci		if (p->seen) {
2918c2ecf20Sopenharmony_ci			pr_warn("Sig %u: X.509 chain contains loop\n",
2928c2ecf20Sopenharmony_ci				sinfo->index);
2938c2ecf20Sopenharmony_ci			return 0;
2948c2ecf20Sopenharmony_ci		}
2958c2ecf20Sopenharmony_ci		ret = public_key_verify_signature(p->pub, x509->sig);
2968c2ecf20Sopenharmony_ci		if (ret < 0)
2978c2ecf20Sopenharmony_ci			return ret;
2988c2ecf20Sopenharmony_ci		x509->signer = p;
2998c2ecf20Sopenharmony_ci		if (x509 == p) {
3008c2ecf20Sopenharmony_ci			pr_debug("- self-signed\n");
3018c2ecf20Sopenharmony_ci			return 0;
3028c2ecf20Sopenharmony_ci		}
3038c2ecf20Sopenharmony_ci		x509 = p;
3048c2ecf20Sopenharmony_ci		might_sleep();
3058c2ecf20Sopenharmony_ci	}
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ciunsupported_crypto_in_x509:
3088c2ecf20Sopenharmony_ci	/* Just prune the certificate chain at this point if we lack some
3098c2ecf20Sopenharmony_ci	 * crypto module to go further.  Note, however, we don't want to set
3108c2ecf20Sopenharmony_ci	 * sinfo->unsupported_crypto as the signed info block may still be
3118c2ecf20Sopenharmony_ci	 * validatable against an X.509 cert lower in the chain that we have a
3128c2ecf20Sopenharmony_ci	 * trusted copy of.
3138c2ecf20Sopenharmony_ci	 */
3148c2ecf20Sopenharmony_ci	return 0;
3158c2ecf20Sopenharmony_ci}
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci/*
3188c2ecf20Sopenharmony_ci * Verify one signed information block from a PKCS#7 message.
3198c2ecf20Sopenharmony_ci */
3208c2ecf20Sopenharmony_cistatic int pkcs7_verify_one(struct pkcs7_message *pkcs7,
3218c2ecf20Sopenharmony_ci			    struct pkcs7_signed_info *sinfo)
3228c2ecf20Sopenharmony_ci{
3238c2ecf20Sopenharmony_ci	int ret;
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	kenter(",%u", sinfo->index);
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	/* First of all, digest the data in the PKCS#7 message and the
3288c2ecf20Sopenharmony_ci	 * signed information block
3298c2ecf20Sopenharmony_ci	 */
3308c2ecf20Sopenharmony_ci	ret = pkcs7_digest(pkcs7, sinfo);
3318c2ecf20Sopenharmony_ci	if (ret < 0)
3328c2ecf20Sopenharmony_ci		return ret;
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	/* Find the key for the signature if there is one */
3358c2ecf20Sopenharmony_ci	ret = pkcs7_find_key(pkcs7, sinfo);
3368c2ecf20Sopenharmony_ci	if (ret < 0)
3378c2ecf20Sopenharmony_ci		return ret;
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	if (!sinfo->signer)
3408c2ecf20Sopenharmony_ci		return 0;
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	pr_devel("Using X.509[%u] for sig %u\n",
3438c2ecf20Sopenharmony_ci		 sinfo->signer->index, sinfo->index);
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci	/* Check that the PKCS#7 signing time is valid according to the X.509
3468c2ecf20Sopenharmony_ci	 * certificate.  We can't, however, check against the system clock
3478c2ecf20Sopenharmony_ci	 * since that may not have been set yet and may be wrong.
3488c2ecf20Sopenharmony_ci	 */
3498c2ecf20Sopenharmony_ci	if (test_bit(sinfo_has_signing_time, &sinfo->aa_set)) {
3508c2ecf20Sopenharmony_ci		if (sinfo->signing_time < sinfo->signer->valid_from ||
3518c2ecf20Sopenharmony_ci		    sinfo->signing_time > sinfo->signer->valid_to) {
3528c2ecf20Sopenharmony_ci			pr_warn("Message signed outside of X.509 validity window\n");
3538c2ecf20Sopenharmony_ci			return -EKEYREJECTED;
3548c2ecf20Sopenharmony_ci		}
3558c2ecf20Sopenharmony_ci	}
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci	/* Verify the PKCS#7 binary against the key */
3588c2ecf20Sopenharmony_ci	ret = public_key_verify_signature(sinfo->signer->pub, sinfo->sig);
3598c2ecf20Sopenharmony_ci	if (ret < 0)
3608c2ecf20Sopenharmony_ci		return ret;
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	pr_devel("Verified signature %u\n", sinfo->index);
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	/* Verify the internal certificate chain */
3658c2ecf20Sopenharmony_ci	return pkcs7_verify_sig_chain(pkcs7, sinfo);
3668c2ecf20Sopenharmony_ci}
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci/**
3698c2ecf20Sopenharmony_ci * pkcs7_verify - Verify a PKCS#7 message
3708c2ecf20Sopenharmony_ci * @pkcs7: The PKCS#7 message to be verified
3718c2ecf20Sopenharmony_ci * @usage: The use to which the key is being put
3728c2ecf20Sopenharmony_ci *
3738c2ecf20Sopenharmony_ci * Verify a PKCS#7 message is internally consistent - that is, the data digest
3748c2ecf20Sopenharmony_ci * matches the digest in the AuthAttrs and any signature in the message or one
3758c2ecf20Sopenharmony_ci * of the X.509 certificates it carries that matches another X.509 cert in the
3768c2ecf20Sopenharmony_ci * message can be verified.
3778c2ecf20Sopenharmony_ci *
3788c2ecf20Sopenharmony_ci * This does not look to match the contents of the PKCS#7 message against any
3798c2ecf20Sopenharmony_ci * external public keys.
3808c2ecf20Sopenharmony_ci *
3818c2ecf20Sopenharmony_ci * Returns, in order of descending priority:
3828c2ecf20Sopenharmony_ci *
3838c2ecf20Sopenharmony_ci *  (*) -EKEYREJECTED if a key was selected that had a usage restriction at
3848c2ecf20Sopenharmony_ci *      odds with the specified usage, or:
3858c2ecf20Sopenharmony_ci *
3868c2ecf20Sopenharmony_ci *  (*) -EKEYREJECTED if a signature failed to match for which we found an
3878c2ecf20Sopenharmony_ci *	appropriate X.509 certificate, or:
3888c2ecf20Sopenharmony_ci *
3898c2ecf20Sopenharmony_ci *  (*) -EBADMSG if some part of the message was invalid, or:
3908c2ecf20Sopenharmony_ci *
3918c2ecf20Sopenharmony_ci *  (*) 0 if a signature chain passed verification, or:
3928c2ecf20Sopenharmony_ci *
3938c2ecf20Sopenharmony_ci *  (*) -EKEYREJECTED if a blacklisted key was encountered, or:
3948c2ecf20Sopenharmony_ci *
3958c2ecf20Sopenharmony_ci *  (*) -ENOPKG if none of the signature chains are verifiable because suitable
3968c2ecf20Sopenharmony_ci *	crypto modules couldn't be found.
3978c2ecf20Sopenharmony_ci */
3988c2ecf20Sopenharmony_ciint pkcs7_verify(struct pkcs7_message *pkcs7,
3998c2ecf20Sopenharmony_ci		 enum key_being_used_for usage)
4008c2ecf20Sopenharmony_ci{
4018c2ecf20Sopenharmony_ci	struct pkcs7_signed_info *sinfo;
4028c2ecf20Sopenharmony_ci	int actual_ret = -ENOPKG;
4038c2ecf20Sopenharmony_ci	int ret;
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci	kenter("");
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci	switch (usage) {
4088c2ecf20Sopenharmony_ci	case VERIFYING_MODULE_SIGNATURE:
4098c2ecf20Sopenharmony_ci		if (pkcs7->data_type != OID_data) {
4108c2ecf20Sopenharmony_ci			pr_warn("Invalid module sig (not pkcs7-data)\n");
4118c2ecf20Sopenharmony_ci			return -EKEYREJECTED;
4128c2ecf20Sopenharmony_ci		}
4138c2ecf20Sopenharmony_ci		if (pkcs7->have_authattrs) {
4148c2ecf20Sopenharmony_ci			pr_warn("Invalid module sig (has authattrs)\n");
4158c2ecf20Sopenharmony_ci			return -EKEYREJECTED;
4168c2ecf20Sopenharmony_ci		}
4178c2ecf20Sopenharmony_ci		break;
4188c2ecf20Sopenharmony_ci	case VERIFYING_FIRMWARE_SIGNATURE:
4198c2ecf20Sopenharmony_ci		if (pkcs7->data_type != OID_data) {
4208c2ecf20Sopenharmony_ci			pr_warn("Invalid firmware sig (not pkcs7-data)\n");
4218c2ecf20Sopenharmony_ci			return -EKEYREJECTED;
4228c2ecf20Sopenharmony_ci		}
4238c2ecf20Sopenharmony_ci		if (!pkcs7->have_authattrs) {
4248c2ecf20Sopenharmony_ci			pr_warn("Invalid firmware sig (missing authattrs)\n");
4258c2ecf20Sopenharmony_ci			return -EKEYREJECTED;
4268c2ecf20Sopenharmony_ci		}
4278c2ecf20Sopenharmony_ci		break;
4288c2ecf20Sopenharmony_ci	case VERIFYING_KEXEC_PE_SIGNATURE:
4298c2ecf20Sopenharmony_ci		if (pkcs7->data_type != OID_msIndirectData) {
4308c2ecf20Sopenharmony_ci			pr_warn("Invalid kexec sig (not Authenticode)\n");
4318c2ecf20Sopenharmony_ci			return -EKEYREJECTED;
4328c2ecf20Sopenharmony_ci		}
4338c2ecf20Sopenharmony_ci		/* Authattr presence checked in parser */
4348c2ecf20Sopenharmony_ci		break;
4358c2ecf20Sopenharmony_ci	case VERIFYING_UNSPECIFIED_SIGNATURE:
4368c2ecf20Sopenharmony_ci		if (pkcs7->data_type != OID_data) {
4378c2ecf20Sopenharmony_ci			pr_warn("Invalid unspecified sig (not pkcs7-data)\n");
4388c2ecf20Sopenharmony_ci			return -EKEYREJECTED;
4398c2ecf20Sopenharmony_ci		}
4408c2ecf20Sopenharmony_ci		break;
4418c2ecf20Sopenharmony_ci	default:
4428c2ecf20Sopenharmony_ci		return -EINVAL;
4438c2ecf20Sopenharmony_ci	}
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci	for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) {
4468c2ecf20Sopenharmony_ci		ret = pkcs7_verify_one(pkcs7, sinfo);
4478c2ecf20Sopenharmony_ci		if (sinfo->blacklisted) {
4488c2ecf20Sopenharmony_ci			if (actual_ret == -ENOPKG)
4498c2ecf20Sopenharmony_ci				actual_ret = -EKEYREJECTED;
4508c2ecf20Sopenharmony_ci			continue;
4518c2ecf20Sopenharmony_ci		}
4528c2ecf20Sopenharmony_ci		if (ret < 0) {
4538c2ecf20Sopenharmony_ci			if (ret == -ENOPKG) {
4548c2ecf20Sopenharmony_ci				sinfo->unsupported_crypto = true;
4558c2ecf20Sopenharmony_ci				continue;
4568c2ecf20Sopenharmony_ci			}
4578c2ecf20Sopenharmony_ci			kleave(" = %d", ret);
4588c2ecf20Sopenharmony_ci			return ret;
4598c2ecf20Sopenharmony_ci		}
4608c2ecf20Sopenharmony_ci		actual_ret = 0;
4618c2ecf20Sopenharmony_ci	}
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci	kleave(" = %d", actual_ret);
4648c2ecf20Sopenharmony_ci	return actual_ret;
4658c2ecf20Sopenharmony_ci}
4668c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pkcs7_verify);
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci/**
4698c2ecf20Sopenharmony_ci * pkcs7_supply_detached_data - Supply the data needed to verify a PKCS#7 message
4708c2ecf20Sopenharmony_ci * @pkcs7: The PKCS#7 message
4718c2ecf20Sopenharmony_ci * @data: The data to be verified
4728c2ecf20Sopenharmony_ci * @datalen: The amount of data
4738c2ecf20Sopenharmony_ci *
4748c2ecf20Sopenharmony_ci * Supply the detached data needed to verify a PKCS#7 message.  Note that no
4758c2ecf20Sopenharmony_ci * attempt to retain/pin the data is made.  That is left to the caller.  The
4768c2ecf20Sopenharmony_ci * data will not be modified by pkcs7_verify() and will not be freed when the
4778c2ecf20Sopenharmony_ci * PKCS#7 message is freed.
4788c2ecf20Sopenharmony_ci *
4798c2ecf20Sopenharmony_ci * Returns -EINVAL if data is already supplied in the message, 0 otherwise.
4808c2ecf20Sopenharmony_ci */
4818c2ecf20Sopenharmony_ciint pkcs7_supply_detached_data(struct pkcs7_message *pkcs7,
4828c2ecf20Sopenharmony_ci			       const void *data, size_t datalen)
4838c2ecf20Sopenharmony_ci{
4848c2ecf20Sopenharmony_ci	if (pkcs7->data) {
4858c2ecf20Sopenharmony_ci		pr_warn("Data already supplied\n");
4868c2ecf20Sopenharmony_ci		return -EINVAL;
4878c2ecf20Sopenharmony_ci	}
4888c2ecf20Sopenharmony_ci	pkcs7->data = data;
4898c2ecf20Sopenharmony_ci	pkcs7->data_len = datalen;
4908c2ecf20Sopenharmony_ci	return 0;
4918c2ecf20Sopenharmony_ci}
492