162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci
362306a36Sopenharmony_ci#include <linux/kernel.h>
462306a36Sopenharmony_ci#include <linux/key.h>
562306a36Sopenharmony_ci#include <keys/asymmetric-type.h>
662306a36Sopenharmony_ci
762306a36Sopenharmony_ciint x509_load_certificate_list(const u8 cert_list[],
862306a36Sopenharmony_ci			       const unsigned long list_size,
962306a36Sopenharmony_ci			       const struct key *keyring)
1062306a36Sopenharmony_ci{
1162306a36Sopenharmony_ci	key_ref_t key;
1262306a36Sopenharmony_ci	const u8 *p, *end;
1362306a36Sopenharmony_ci	size_t plen;
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci	p = cert_list;
1662306a36Sopenharmony_ci	end = p + list_size;
1762306a36Sopenharmony_ci	while (p < end) {
1862306a36Sopenharmony_ci		/* Each cert begins with an ASN.1 SEQUENCE tag and must be more
1962306a36Sopenharmony_ci		 * than 256 bytes in size.
2062306a36Sopenharmony_ci		 */
2162306a36Sopenharmony_ci		if (end - p < 4)
2262306a36Sopenharmony_ci			goto dodgy_cert;
2362306a36Sopenharmony_ci		if (p[0] != 0x30 &&
2462306a36Sopenharmony_ci		    p[1] != 0x82)
2562306a36Sopenharmony_ci			goto dodgy_cert;
2662306a36Sopenharmony_ci		plen = (p[2] << 8) | p[3];
2762306a36Sopenharmony_ci		plen += 4;
2862306a36Sopenharmony_ci		if (plen > end - p)
2962306a36Sopenharmony_ci			goto dodgy_cert;
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci		key = key_create_or_update(make_key_ref(keyring, 1),
3262306a36Sopenharmony_ci					   "asymmetric",
3362306a36Sopenharmony_ci					   NULL,
3462306a36Sopenharmony_ci					   p,
3562306a36Sopenharmony_ci					   plen,
3662306a36Sopenharmony_ci					   ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
3762306a36Sopenharmony_ci					   KEY_USR_VIEW | KEY_USR_READ),
3862306a36Sopenharmony_ci					   KEY_ALLOC_NOT_IN_QUOTA |
3962306a36Sopenharmony_ci					   KEY_ALLOC_BUILT_IN |
4062306a36Sopenharmony_ci					   KEY_ALLOC_BYPASS_RESTRICTION);
4162306a36Sopenharmony_ci		if (IS_ERR(key)) {
4262306a36Sopenharmony_ci			pr_err("Problem loading in-kernel X.509 certificate (%ld)\n",
4362306a36Sopenharmony_ci			       PTR_ERR(key));
4462306a36Sopenharmony_ci		} else {
4562306a36Sopenharmony_ci			pr_notice("Loaded X.509 cert '%s'\n",
4662306a36Sopenharmony_ci				  key_ref_to_ptr(key)->description);
4762306a36Sopenharmony_ci			key_ref_put(key);
4862306a36Sopenharmony_ci		}
4962306a36Sopenharmony_ci		p += plen;
5062306a36Sopenharmony_ci	}
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	return 0;
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_cidodgy_cert:
5562306a36Sopenharmony_ci	pr_err("Problem parsing in-kernel X.509 certificate list\n");
5662306a36Sopenharmony_ci	return 0;
5762306a36Sopenharmony_ci}
5862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(x509_load_certificate_list);
59