brintos

brintos / linux-shallow public Read only

0
0
Text · 5.5 KiB · 04b5e55 Raw
280 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2011 Nokia Corporation4 * Copyright (C) 2011 Intel Corporation5 *6 * Author:7 * Dmitry Kasatkin <dmitry.kasatkin@nokia.com>8 *                 <dmitry.kasatkin@intel.com>9 *10 * File: sign.c11 *	implements signature (RSA) verification12 *	pkcs decoding is based on LibTomCrypt code13 */14 15#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt16 17#include <linux/err.h>18#include <linux/module.h>19#include <linux/slab.h>20#include <linux/key.h>21#include <linux/crypto.h>22#include <crypto/hash.h>23#include <crypto/sha1.h>24#include <keys/user-type.h>25#include <linux/mpi.h>26#include <linux/digsig.h>27 28static struct crypto_shash *shash;29 30static const char *pkcs_1_v1_5_decode_emsa(const unsigned char *msg,31						unsigned long  msglen,32						unsigned long  modulus_bitlen,33						unsigned long *outlen)34{35	unsigned long modulus_len, ps_len, i;36 37	modulus_len = (modulus_bitlen >> 3) + (modulus_bitlen & 7 ? 1 : 0);38 39	/* test message size */40	if ((msglen > modulus_len) || (modulus_len < 11))41		return NULL;42 43	/* separate encoded message */44	if (msg[0] != 0x00 || msg[1] != 0x01)45		return NULL;46 47	for (i = 2; i < modulus_len - 1; i++)48		if (msg[i] != 0xFF)49			break;50 51	/* separator check */52	if (msg[i] != 0)53		/* There was no octet with hexadecimal value 0x0054		to separate ps from m. */55		return NULL;56 57	ps_len = i - 2;58 59	*outlen = (msglen - (2 + ps_len + 1));60 61	return msg + 2 + ps_len + 1;62}63 64/*65 * RSA Signature verification with public key66 */67static int digsig_verify_rsa(struct key *key,68		    const char *sig, int siglen,69		       const char *h, int hlen)70{71	int err = -EINVAL;72	unsigned long len;73	unsigned long mlen, mblen;74	unsigned nret, l;75	int head, i;76	unsigned char *out1 = NULL;77	const char *m;78	MPI in = NULL, res = NULL, pkey[2];79	uint8_t *p, *datap;80	const uint8_t *endp;81	const struct user_key_payload *ukp;82	struct pubkey_hdr *pkh;83 84	down_read(&key->sem);85	ukp = user_key_payload_locked(key);86 87	if (!ukp) {88		/* key was revoked before we acquired its semaphore */89		err = -EKEYREVOKED;90		goto err1;91	}92 93	if (ukp->datalen < sizeof(*pkh))94		goto err1;95 96	pkh = (struct pubkey_hdr *)ukp->data;97 98	if (pkh->version != 1)99		goto err1;100 101	if (pkh->algo != PUBKEY_ALGO_RSA)102		goto err1;103 104	if (pkh->nmpi != 2)105		goto err1;106 107	datap = pkh->mpi;108	endp = ukp->data + ukp->datalen;109 110	for (i = 0; i < pkh->nmpi; i++) {111		unsigned int remaining = endp - datap;112		pkey[i] = mpi_read_from_buffer(datap, &remaining);113		if (IS_ERR(pkey[i])) {114			err = PTR_ERR(pkey[i]);115			goto err;116		}117		datap += remaining;118	}119 120	mblen = mpi_get_nbits(pkey[0]);121	mlen = DIV_ROUND_UP(mblen, 8);122 123	if (mlen == 0) {124		err = -EINVAL;125		goto err;126	}127 128	err = -ENOMEM;129 130	out1 = kzalloc(mlen, GFP_KERNEL);131	if (!out1)132		goto err;133 134	nret = siglen;135	in = mpi_read_from_buffer(sig, &nret);136	if (IS_ERR(in)) {137		err = PTR_ERR(in);138		goto err;139	}140 141	res = mpi_alloc(mpi_get_nlimbs(in) * 2);142	if (!res)143		goto err;144 145	err = mpi_powm(res, in, pkey[1], pkey[0]);146	if (err)147		goto err;148 149	if (mpi_get_nlimbs(res) * BYTES_PER_MPI_LIMB > mlen) {150		err = -EINVAL;151		goto err;152	}153 154	p = mpi_get_buffer(res, &l, NULL);155	if (!p) {156		err = -EINVAL;157		goto err;158	}159 160	len = mlen;161	head = len - l;162	memset(out1, 0, head);163	memcpy(out1 + head, p, l);164 165	kfree(p);166 167	m = pkcs_1_v1_5_decode_emsa(out1, len, mblen, &len);168 169	if (!m || len != hlen || memcmp(m, h, hlen))170		err = -EINVAL;171 172err:173	mpi_free(in);174	mpi_free(res);175	kfree(out1);176	while (--i >= 0)177		mpi_free(pkey[i]);178err1:179	up_read(&key->sem);180 181	return err;182}183 184/**185 * digsig_verify() - digital signature verification with public key186 * @keyring:	keyring to search key in187 * @sig:	digital signature188 * @siglen:	length of the signature189 * @data:	data190 * @datalen:	length of the data191 *192 * Returns 0 on success, -EINVAL otherwise193 *194 * Verifies data integrity against digital signature.195 * Currently only RSA is supported.196 * Normally hash of the content is used as a data for this function.197 *198 */199int digsig_verify(struct key *keyring, const char *sig, int siglen,200						const char *data, int datalen)201{202	int err = -ENOMEM;203	struct signature_hdr *sh = (struct signature_hdr *)sig;204	struct shash_desc *desc = NULL;205	unsigned char hash[SHA1_DIGEST_SIZE];206	struct key *key;207	char name[20];208 209	if (siglen < sizeof(*sh) + 2)210		return -EINVAL;211 212	if (sh->algo != PUBKEY_ALGO_RSA)213		return -ENOTSUPP;214 215	sprintf(name, "%llX", __be64_to_cpup((uint64_t *)sh->keyid));216 217	if (keyring) {218		/* search in specific keyring */219		key_ref_t kref;220		kref = keyring_search(make_key_ref(keyring, 1UL),221				      &key_type_user, name, true);222		if (IS_ERR(kref))223			key = ERR_CAST(kref);224		else225			key = key_ref_to_ptr(kref);226	} else {227		key = request_key(&key_type_user, name, NULL);228	}229	if (IS_ERR(key)) {230		pr_err("key not found, id: %s\n", name);231		return PTR_ERR(key);232	}233 234	desc = kzalloc(sizeof(*desc) + crypto_shash_descsize(shash),235		       GFP_KERNEL);236	if (!desc)237		goto err;238 239	desc->tfm = shash;240 241	crypto_shash_init(desc);242	crypto_shash_update(desc, data, datalen);243	crypto_shash_update(desc, sig, sizeof(*sh));244	crypto_shash_final(desc, hash);245 246	kfree(desc);247 248	/* pass signature mpis address */249	err = digsig_verify_rsa(key, sig + sizeof(*sh), siglen - sizeof(*sh),250			     hash, sizeof(hash));251 252err:253	key_put(key);254 255	return err ? -EINVAL : 0;256}257EXPORT_SYMBOL_GPL(digsig_verify);258 259static int __init digsig_init(void)260{261	shash = crypto_alloc_shash("sha1", 0, 0);262	if (IS_ERR(shash)) {263		pr_err("shash allocation failed\n");264		return  PTR_ERR(shash);265	}266 267	return 0;268 269}270 271static void __exit digsig_cleanup(void)272{273	crypto_free_shash(shash);274}275 276module_init(digsig_init);277module_exit(digsig_cleanup);278 279MODULE_LICENSE("GPL");280