1b886d83cSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2e0751257SDmitry Kasatkin /*
3e0751257SDmitry Kasatkin  * Copyright (C) 2013 Intel Corporation
4e0751257SDmitry Kasatkin  *
5e0751257SDmitry Kasatkin  * Author:
6e0751257SDmitry Kasatkin  * Dmitry Kasatkin <dmitry.kasatkin@intel.com>
7e0751257SDmitry Kasatkin  */
8e0751257SDmitry Kasatkin 
9e0751257SDmitry Kasatkin #include <linux/err.h>
10d9a2e5d7SDmitry Kasatkin #include <linux/ratelimit.h>
11e0751257SDmitry Kasatkin #include <linux/key-type.h>
12e0751257SDmitry Kasatkin #include <crypto/public_key.h>
134e8ae72aSDavid Howells #include <crypto/hash_info.h>
14e0751257SDmitry Kasatkin #include <keys/asymmetric-type.h>
1541c89b64SPetko Manolov #include <keys/system_keyring.h>
16e0751257SDmitry Kasatkin 
17e0751257SDmitry Kasatkin #include "integrity.h"
18e0751257SDmitry Kasatkin 
19e0751257SDmitry Kasatkin /*
20e0751257SDmitry Kasatkin  * Request an asymmetric key.
21e0751257SDmitry Kasatkin  */
request_asymmetric_key(struct key * keyring,uint32_t keyid)22e0751257SDmitry Kasatkin static struct key *request_asymmetric_key(struct key *keyring, uint32_t keyid)
23e0751257SDmitry Kasatkin {
24e0751257SDmitry Kasatkin 	struct key *key;
25e0751257SDmitry Kasatkin 	char name[12];
26e0751257SDmitry Kasatkin 
27594081eeSDmitry Kasatkin 	sprintf(name, "id:%08x", keyid);
28e0751257SDmitry Kasatkin 
29e0751257SDmitry Kasatkin 	pr_debug("key search: \"%s\"\n", name);
30e0751257SDmitry Kasatkin 
3141c89b64SPetko Manolov 	key = get_ima_blacklist_keyring();
3241c89b64SPetko Manolov 	if (key) {
3341c89b64SPetko Manolov 		key_ref_t kref;
3441c89b64SPetko Manolov 
3541c89b64SPetko Manolov 		kref = keyring_search(make_key_ref(key, 1),
36dcf49dbcSDavid Howells 				      &key_type_asymmetric, name, true);
3741c89b64SPetko Manolov 		if (!IS_ERR(kref)) {
3841c89b64SPetko Manolov 			pr_err("Key '%s' is in ima_blacklist_keyring\n", name);
3941c89b64SPetko Manolov 			return ERR_PTR(-EKEYREJECTED);
4041c89b64SPetko Manolov 		}
4141c89b64SPetko Manolov 	}
4241c89b64SPetko Manolov 
43e0751257SDmitry Kasatkin 	if (keyring) {
44e0751257SDmitry Kasatkin 		/* search in specific keyring */
45e0751257SDmitry Kasatkin 		key_ref_t kref;
4641c89b64SPetko Manolov 
47e0751257SDmitry Kasatkin 		kref = keyring_search(make_key_ref(keyring, 1),
48dcf49dbcSDavid Howells 				      &key_type_asymmetric, name, true);
49e0751257SDmitry Kasatkin 		if (IS_ERR(kref))
50e0751257SDmitry Kasatkin 			key = ERR_CAST(kref);
51e0751257SDmitry Kasatkin 		else
52e0751257SDmitry Kasatkin 			key = key_ref_to_ptr(kref);
53e0751257SDmitry Kasatkin 	} else {
54028db3e2SLinus Torvalds 		key = request_key(&key_type_asymmetric, name, NULL);
55e0751257SDmitry Kasatkin 	}
56e0751257SDmitry Kasatkin 
57e0751257SDmitry Kasatkin 	if (IS_ERR(key)) {
588c2f516cSBruno Meneguele 		if (keyring)
598c2f516cSBruno Meneguele 			pr_err_ratelimited("Request for unknown key '%s' in '%s' keyring. err %ld\n",
608c2f516cSBruno Meneguele 					   name, keyring->description,
618c2f516cSBruno Meneguele 					   PTR_ERR(key));
628c2f516cSBruno Meneguele 		else
63d9a2e5d7SDmitry Kasatkin 			pr_err_ratelimited("Request for unknown key '%s' err %ld\n",
64e0751257SDmitry Kasatkin 					   name, PTR_ERR(key));
658c2f516cSBruno Meneguele 
66e0751257SDmitry Kasatkin 		switch (PTR_ERR(key)) {
67e0751257SDmitry Kasatkin 			/* Hide some search errors */
68e0751257SDmitry Kasatkin 		case -EACCES:
69e0751257SDmitry Kasatkin 		case -ENOTDIR:
70e0751257SDmitry Kasatkin 		case -EAGAIN:
71e0751257SDmitry Kasatkin 			return ERR_PTR(-ENOKEY);
72e0751257SDmitry Kasatkin 		default:
73e0751257SDmitry Kasatkin 			return key;
74e0751257SDmitry Kasatkin 		}
75e0751257SDmitry Kasatkin 	}
76e0751257SDmitry Kasatkin 
77e0751257SDmitry Kasatkin 	pr_debug("%s() = 0 [%x]\n", __func__, key_serial(key));
78e0751257SDmitry Kasatkin 
79e0751257SDmitry Kasatkin 	return key;
80e0751257SDmitry Kasatkin }
81e0751257SDmitry Kasatkin 
asymmetric_verify(struct key * keyring,const char * sig,int siglen,const char * data,int datalen)82e0751257SDmitry Kasatkin int asymmetric_verify(struct key *keyring, const char *sig,
83e0751257SDmitry Kasatkin 		      int siglen, const char *data, int datalen)
84e0751257SDmitry Kasatkin {
85e0751257SDmitry Kasatkin 	struct public_key_signature pks;
86e0751257SDmitry Kasatkin 	struct signature_v2_hdr *hdr = (struct signature_v2_hdr *)sig;
87947d7059SStefan Berger 	const struct public_key *pk;
88e0751257SDmitry Kasatkin 	struct key *key;
893db0d0c2SColin Ian King 	int ret;
90e0751257SDmitry Kasatkin 
91e0751257SDmitry Kasatkin 	if (siglen <= sizeof(*hdr))
92e0751257SDmitry Kasatkin 		return -EBADMSG;
93e0751257SDmitry Kasatkin 
94e0751257SDmitry Kasatkin 	siglen -= sizeof(*hdr);
95e0751257SDmitry Kasatkin 
96bb543e39SThiago Jung Bauermann 	if (siglen != be16_to_cpu(hdr->sig_size))
97e0751257SDmitry Kasatkin 		return -EBADMSG;
98e0751257SDmitry Kasatkin 
994e8ae72aSDavid Howells 	if (hdr->hash_algo >= HASH_ALGO__LAST)
100e0751257SDmitry Kasatkin 		return -ENOPKG;
101e0751257SDmitry Kasatkin 
102bb543e39SThiago Jung Bauermann 	key = request_asymmetric_key(keyring, be32_to_cpu(hdr->keyid));
103e0751257SDmitry Kasatkin 	if (IS_ERR(key))
104e0751257SDmitry Kasatkin 		return PTR_ERR(key);
105e0751257SDmitry Kasatkin 
106e0751257SDmitry Kasatkin 	memset(&pks, 0, sizeof(pks));
107e0751257SDmitry Kasatkin 
1084e8ae72aSDavid Howells 	pks.hash_algo = hash_algo_name[hdr->hash_algo];
109947d7059SStefan Berger 
110947d7059SStefan Berger 	pk = asymmetric_key_public_key(key);
111947d7059SStefan Berger 	pks.pkey_algo = pk->pkey_algo;
112*0838d6d6SEric Biggers 	if (!strcmp(pk->pkey_algo, "rsa")) {
113fd35f192SMimi Zohar 		pks.encoding = "pkcs1";
114*0838d6d6SEric Biggers 	} else if (!strncmp(pk->pkey_algo, "ecdsa-", 6)) {
115947d7059SStefan Berger 		/* edcsa-nist-p192 etc. */
116947d7059SStefan Berger 		pks.encoding = "x962";
117*0838d6d6SEric Biggers 	} else if (!strcmp(pk->pkey_algo, "ecrdsa") ||
118*0838d6d6SEric Biggers 		   !strcmp(pk->pkey_algo, "sm2")) {
119947d7059SStefan Berger 		pks.encoding = "raw";
120*0838d6d6SEric Biggers 	} else {
121*0838d6d6SEric Biggers 		ret = -ENOPKG;
122*0838d6d6SEric Biggers 		goto out;
123*0838d6d6SEric Biggers 	}
124947d7059SStefan Berger 
125e0751257SDmitry Kasatkin 	pks.digest = (u8 *)data;
126e0751257SDmitry Kasatkin 	pks.digest_size = datalen;
127eb5798f2STadeusz Struk 	pks.s = hdr->sig;
128eb5798f2STadeusz Struk 	pks.s_size = siglen;
129e0751257SDmitry Kasatkin 	ret = verify_signature(key, &pks);
130*0838d6d6SEric Biggers out:
131e0751257SDmitry Kasatkin 	key_put(key);
132e0751257SDmitry Kasatkin 	pr_debug("%s() = %d\n", __func__, ret);
133e0751257SDmitry Kasatkin 	return ret;
134e0751257SDmitry Kasatkin }
1356eb864c1SMikhail Kurinnoi 
1366eb864c1SMikhail Kurinnoi /**
1376eb864c1SMikhail Kurinnoi  * integrity_kernel_module_request - prevent crypto-pkcs1pad(rsa,*) requests
1386eb864c1SMikhail Kurinnoi  * @kmod_name: kernel module name
1396eb864c1SMikhail Kurinnoi  *
1406eb864c1SMikhail Kurinnoi  * We have situation, when public_key_verify_signature() in case of RSA
1416eb864c1SMikhail Kurinnoi  * algorithm use alg_name to store internal information in order to
1426eb864c1SMikhail Kurinnoi  * construct an algorithm on the fly, but crypto_larval_lookup() will try
1436eb864c1SMikhail Kurinnoi  * to use alg_name in order to load kernel module with same name.
1446eb864c1SMikhail Kurinnoi  * Since we don't have any real "crypto-pkcs1pad(rsa,*)" kernel modules,
1456eb864c1SMikhail Kurinnoi  * we are safe to fail such module request from crypto_larval_lookup().
1466eb864c1SMikhail Kurinnoi  *
1476eb864c1SMikhail Kurinnoi  * In this way we prevent modprobe execution during digsig verification
1486eb864c1SMikhail Kurinnoi  * and avoid possible deadlock if modprobe and/or it's dependencies
1496eb864c1SMikhail Kurinnoi  * also signed with digsig.
1506eb864c1SMikhail Kurinnoi  */
integrity_kernel_module_request(char * kmod_name)1516eb864c1SMikhail Kurinnoi int integrity_kernel_module_request(char *kmod_name)
1526eb864c1SMikhail Kurinnoi {
1536eb864c1SMikhail Kurinnoi 	if (strncmp(kmod_name, "crypto-pkcs1pad(rsa,", 20) == 0)
1546eb864c1SMikhail Kurinnoi 		return -EINVAL;
1556eb864c1SMikhail Kurinnoi 
1566eb864c1SMikhail Kurinnoi 	return 0;
1576eb864c1SMikhail Kurinnoi }
158