cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

digsig.c (5647B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (C) 2011 Nokia Corporation
      4 * Copyright (C) 2011 Intel Corporation
      5 *
      6 * Author:
      7 * Dmitry Kasatkin <dmitry.kasatkin@nokia.com>
      8 *                 <dmitry.kasatkin@intel.com>
      9 *
     10 * File: sign.c
     11 *	implements signature (RSA) verification
     12 *	pkcs decoding is based on LibTomCrypt code
     13 */
     14
     15#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
     16
     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 0x00
     54		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 key
     66 */
     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 key
    186 * @keyring:	keyring to search key in
    187 * @sig:	digital signature
    188 * @siglen:	length of the signature
    189 * @data:	data
    190 * @datalen:	length of the data
    191 *
    192 * Returns 0 on success, -EINVAL otherwise
    193 *
    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		else
    225			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");