1051dbb91SDmitry Kasatkin /* 2051dbb91SDmitry Kasatkin * Copyright (C) 2011 Nokia Corporation 3051dbb91SDmitry Kasatkin * Copyright (C) 2011 Intel Corporation 4051dbb91SDmitry Kasatkin * 5051dbb91SDmitry Kasatkin * Author: 6051dbb91SDmitry Kasatkin * Dmitry Kasatkin <dmitry.kasatkin@nokia.com> 7051dbb91SDmitry Kasatkin * <dmitry.kasatkin@intel.com> 8051dbb91SDmitry Kasatkin * 9051dbb91SDmitry Kasatkin * This program is free software; you can redistribute it and/or modify 10051dbb91SDmitry Kasatkin * it under the terms of the GNU General Public License as published by 11051dbb91SDmitry Kasatkin * the Free Software Foundation, version 2 of the License. 12051dbb91SDmitry Kasatkin * 13051dbb91SDmitry Kasatkin * File: sign.c 14051dbb91SDmitry Kasatkin * implements signature (RSA) verification 15051dbb91SDmitry Kasatkin * pkcs decoding is based on LibTomCrypt code 16051dbb91SDmitry Kasatkin */ 17051dbb91SDmitry Kasatkin 18051dbb91SDmitry Kasatkin #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 19051dbb91SDmitry Kasatkin 20051dbb91SDmitry Kasatkin #include <linux/err.h> 21051dbb91SDmitry Kasatkin #include <linux/module.h> 22051dbb91SDmitry Kasatkin #include <linux/slab.h> 23051dbb91SDmitry Kasatkin #include <linux/key.h> 24051dbb91SDmitry Kasatkin #include <linux/crypto.h> 25051dbb91SDmitry Kasatkin #include <crypto/hash.h> 26051dbb91SDmitry Kasatkin #include <crypto/sha.h> 27051dbb91SDmitry Kasatkin #include <keys/user-type.h> 28051dbb91SDmitry Kasatkin #include <linux/mpi.h> 29051dbb91SDmitry Kasatkin #include <linux/digsig.h> 30051dbb91SDmitry Kasatkin 31051dbb91SDmitry Kasatkin static struct crypto_shash *shash; 32051dbb91SDmitry Kasatkin 33051dbb91SDmitry Kasatkin static int pkcs_1_v1_5_decode_emsa(const unsigned char *msg, 34051dbb91SDmitry Kasatkin unsigned long msglen, 35051dbb91SDmitry Kasatkin unsigned long modulus_bitlen, 36051dbb91SDmitry Kasatkin unsigned char *out, 37*b35e286aSDmitry Kasatkin unsigned long *outlen) 38051dbb91SDmitry Kasatkin { 39051dbb91SDmitry Kasatkin unsigned long modulus_len, ps_len, i; 40051dbb91SDmitry Kasatkin 41051dbb91SDmitry Kasatkin modulus_len = (modulus_bitlen >> 3) + (modulus_bitlen & 7 ? 1 : 0); 42051dbb91SDmitry Kasatkin 43051dbb91SDmitry Kasatkin /* test message size */ 44051dbb91SDmitry Kasatkin if ((msglen > modulus_len) || (modulus_len < 11)) 45051dbb91SDmitry Kasatkin return -EINVAL; 46051dbb91SDmitry Kasatkin 47051dbb91SDmitry Kasatkin /* separate encoded message */ 48*b35e286aSDmitry Kasatkin if ((msg[0] != 0x00) || (msg[1] != (unsigned char)1)) 49*b35e286aSDmitry Kasatkin return -EINVAL; 50051dbb91SDmitry Kasatkin 51051dbb91SDmitry Kasatkin for (i = 2; i < modulus_len - 1; i++) 52051dbb91SDmitry Kasatkin if (msg[i] != 0xFF) 53051dbb91SDmitry Kasatkin break; 54051dbb91SDmitry Kasatkin 55051dbb91SDmitry Kasatkin /* separator check */ 56*b35e286aSDmitry Kasatkin if (msg[i] != 0) 57051dbb91SDmitry Kasatkin /* There was no octet with hexadecimal value 0x00 58051dbb91SDmitry Kasatkin to separate ps from m. */ 59*b35e286aSDmitry Kasatkin return -EINVAL; 60051dbb91SDmitry Kasatkin 61051dbb91SDmitry Kasatkin ps_len = i - 2; 62051dbb91SDmitry Kasatkin 63051dbb91SDmitry Kasatkin if (*outlen < (msglen - (2 + ps_len + 1))) { 64051dbb91SDmitry Kasatkin *outlen = msglen - (2 + ps_len + 1); 65*b35e286aSDmitry Kasatkin return -EOVERFLOW; 66051dbb91SDmitry Kasatkin } 67051dbb91SDmitry Kasatkin 68051dbb91SDmitry Kasatkin *outlen = (msglen - (2 + ps_len + 1)); 69051dbb91SDmitry Kasatkin memcpy(out, &msg[2 + ps_len + 1], *outlen); 70051dbb91SDmitry Kasatkin 71*b35e286aSDmitry Kasatkin return 0; 72051dbb91SDmitry Kasatkin } 73051dbb91SDmitry Kasatkin 74051dbb91SDmitry Kasatkin /* 75051dbb91SDmitry Kasatkin * RSA Signature verification with public key 76051dbb91SDmitry Kasatkin */ 77051dbb91SDmitry Kasatkin static int digsig_verify_rsa(struct key *key, 78051dbb91SDmitry Kasatkin const char *sig, int siglen, 79051dbb91SDmitry Kasatkin const char *h, int hlen) 80051dbb91SDmitry Kasatkin { 81051dbb91SDmitry Kasatkin int err = -EINVAL; 82051dbb91SDmitry Kasatkin unsigned long len; 83051dbb91SDmitry Kasatkin unsigned long mlen, mblen; 84051dbb91SDmitry Kasatkin unsigned nret, l; 85*b35e286aSDmitry Kasatkin int head, i; 86051dbb91SDmitry Kasatkin unsigned char *out1 = NULL, *out2 = NULL; 87051dbb91SDmitry Kasatkin MPI in = NULL, res = NULL, pkey[2]; 88051dbb91SDmitry Kasatkin uint8_t *p, *datap, *endp; 89051dbb91SDmitry Kasatkin struct user_key_payload *ukp; 90051dbb91SDmitry Kasatkin struct pubkey_hdr *pkh; 91051dbb91SDmitry Kasatkin 92051dbb91SDmitry Kasatkin down_read(&key->sem); 93051dbb91SDmitry Kasatkin ukp = key->payload.data; 94f58a0815SDmitry Kasatkin 95f58a0815SDmitry Kasatkin if (ukp->datalen < sizeof(*pkh)) 96f58a0815SDmitry Kasatkin goto err1; 97f58a0815SDmitry Kasatkin 98051dbb91SDmitry Kasatkin pkh = (struct pubkey_hdr *)ukp->data; 99051dbb91SDmitry Kasatkin 100051dbb91SDmitry Kasatkin if (pkh->version != 1) 101051dbb91SDmitry Kasatkin goto err1; 102051dbb91SDmitry Kasatkin 103051dbb91SDmitry Kasatkin if (pkh->algo != PUBKEY_ALGO_RSA) 104051dbb91SDmitry Kasatkin goto err1; 105051dbb91SDmitry Kasatkin 106051dbb91SDmitry Kasatkin if (pkh->nmpi != 2) 107051dbb91SDmitry Kasatkin goto err1; 108051dbb91SDmitry Kasatkin 109051dbb91SDmitry Kasatkin datap = pkh->mpi; 110f58a0815SDmitry Kasatkin endp = ukp->data + ukp->datalen; 111051dbb91SDmitry Kasatkin 112051dbb91SDmitry Kasatkin for (i = 0; i < pkh->nmpi; i++) { 113051dbb91SDmitry Kasatkin unsigned int remaining = endp - datap; 114051dbb91SDmitry Kasatkin pkey[i] = mpi_read_from_buffer(datap, &remaining); 115051dbb91SDmitry Kasatkin datap += remaining; 116051dbb91SDmitry Kasatkin } 117051dbb91SDmitry Kasatkin 118051dbb91SDmitry Kasatkin mblen = mpi_get_nbits(pkey[0]); 119051dbb91SDmitry Kasatkin mlen = (mblen + 7)/8; 120051dbb91SDmitry Kasatkin 121f58a0815SDmitry Kasatkin if (mlen == 0) 122f58a0815SDmitry Kasatkin goto err; 123051dbb91SDmitry Kasatkin 124051dbb91SDmitry Kasatkin out1 = kzalloc(mlen, GFP_KERNEL); 125051dbb91SDmitry Kasatkin if (!out1) 126051dbb91SDmitry Kasatkin goto err; 127051dbb91SDmitry Kasatkin 128051dbb91SDmitry Kasatkin out2 = kzalloc(mlen, GFP_KERNEL); 129051dbb91SDmitry Kasatkin if (!out2) 130051dbb91SDmitry Kasatkin goto err; 131051dbb91SDmitry Kasatkin 132051dbb91SDmitry Kasatkin nret = siglen; 133051dbb91SDmitry Kasatkin in = mpi_read_from_buffer(sig, &nret); 134051dbb91SDmitry Kasatkin if (!in) 135051dbb91SDmitry Kasatkin goto err; 136051dbb91SDmitry Kasatkin 137051dbb91SDmitry Kasatkin res = mpi_alloc(mpi_get_nlimbs(in) * 2); 138051dbb91SDmitry Kasatkin if (!res) 139051dbb91SDmitry Kasatkin goto err; 140051dbb91SDmitry Kasatkin 141051dbb91SDmitry Kasatkin err = mpi_powm(res, in, pkey[1], pkey[0]); 142051dbb91SDmitry Kasatkin if (err) 143051dbb91SDmitry Kasatkin goto err; 144051dbb91SDmitry Kasatkin 145051dbb91SDmitry Kasatkin if (mpi_get_nlimbs(res) * BYTES_PER_MPI_LIMB > mlen) { 146051dbb91SDmitry Kasatkin err = -EINVAL; 147051dbb91SDmitry Kasatkin goto err; 148051dbb91SDmitry Kasatkin } 149051dbb91SDmitry Kasatkin 150051dbb91SDmitry Kasatkin p = mpi_get_buffer(res, &l, NULL); 151051dbb91SDmitry Kasatkin if (!p) { 152051dbb91SDmitry Kasatkin err = -EINVAL; 153051dbb91SDmitry Kasatkin goto err; 154051dbb91SDmitry Kasatkin } 155051dbb91SDmitry Kasatkin 156051dbb91SDmitry Kasatkin len = mlen; 157051dbb91SDmitry Kasatkin head = len - l; 158051dbb91SDmitry Kasatkin memset(out1, 0, head); 159051dbb91SDmitry Kasatkin memcpy(out1 + head, p, l); 160051dbb91SDmitry Kasatkin 161*b35e286aSDmitry Kasatkin err = pkcs_1_v1_5_decode_emsa(out1, len, mblen, out2, &len); 162051dbb91SDmitry Kasatkin 163*b35e286aSDmitry Kasatkin if (!err && len == hlen) 164051dbb91SDmitry Kasatkin err = memcmp(out2, h, hlen); 165051dbb91SDmitry Kasatkin 166051dbb91SDmitry Kasatkin err: 167051dbb91SDmitry Kasatkin mpi_free(in); 168051dbb91SDmitry Kasatkin mpi_free(res); 169051dbb91SDmitry Kasatkin kfree(out1); 170051dbb91SDmitry Kasatkin kfree(out2); 171051dbb91SDmitry Kasatkin mpi_free(pkey[0]); 172051dbb91SDmitry Kasatkin mpi_free(pkey[1]); 173051dbb91SDmitry Kasatkin err1: 174051dbb91SDmitry Kasatkin up_read(&key->sem); 175051dbb91SDmitry Kasatkin 176051dbb91SDmitry Kasatkin return err; 177051dbb91SDmitry Kasatkin } 178051dbb91SDmitry Kasatkin 179051dbb91SDmitry Kasatkin /** 180051dbb91SDmitry Kasatkin * digsig_verify() - digital signature verification with public key 181051dbb91SDmitry Kasatkin * @keyring: keyring to search key in 182051dbb91SDmitry Kasatkin * @sig: digital signature 183051dbb91SDmitry Kasatkin * @sigen: length of the signature 184051dbb91SDmitry Kasatkin * @data: data 185051dbb91SDmitry Kasatkin * @datalen: length of the data 186051dbb91SDmitry Kasatkin * @return: 0 on success, -EINVAL otherwise 187051dbb91SDmitry Kasatkin * 188051dbb91SDmitry Kasatkin * Verifies data integrity against digital signature. 189051dbb91SDmitry Kasatkin * Currently only RSA is supported. 190051dbb91SDmitry Kasatkin * Normally hash of the content is used as a data for this function. 191051dbb91SDmitry Kasatkin * 192051dbb91SDmitry Kasatkin */ 193051dbb91SDmitry Kasatkin int digsig_verify(struct key *keyring, const char *sig, int siglen, 194051dbb91SDmitry Kasatkin const char *data, int datalen) 195051dbb91SDmitry Kasatkin { 196051dbb91SDmitry Kasatkin int err = -ENOMEM; 197051dbb91SDmitry Kasatkin struct signature_hdr *sh = (struct signature_hdr *)sig; 198051dbb91SDmitry Kasatkin struct shash_desc *desc = NULL; 199051dbb91SDmitry Kasatkin unsigned char hash[SHA1_DIGEST_SIZE]; 200051dbb91SDmitry Kasatkin struct key *key; 201051dbb91SDmitry Kasatkin char name[20]; 202051dbb91SDmitry Kasatkin 203051dbb91SDmitry Kasatkin if (siglen < sizeof(*sh) + 2) 204051dbb91SDmitry Kasatkin return -EINVAL; 205051dbb91SDmitry Kasatkin 206051dbb91SDmitry Kasatkin if (sh->algo != PUBKEY_ALGO_RSA) 207051dbb91SDmitry Kasatkin return -ENOTSUPP; 208051dbb91SDmitry Kasatkin 209051dbb91SDmitry Kasatkin sprintf(name, "%llX", __be64_to_cpup((uint64_t *)sh->keyid)); 210051dbb91SDmitry Kasatkin 211051dbb91SDmitry Kasatkin if (keyring) { 212051dbb91SDmitry Kasatkin /* search in specific keyring */ 213051dbb91SDmitry Kasatkin key_ref_t kref; 214051dbb91SDmitry Kasatkin kref = keyring_search(make_key_ref(keyring, 1UL), 215051dbb91SDmitry Kasatkin &key_type_user, name); 216051dbb91SDmitry Kasatkin if (IS_ERR(kref)) 217051dbb91SDmitry Kasatkin key = ERR_PTR(PTR_ERR(kref)); 218051dbb91SDmitry Kasatkin else 219051dbb91SDmitry Kasatkin key = key_ref_to_ptr(kref); 220051dbb91SDmitry Kasatkin } else { 221051dbb91SDmitry Kasatkin key = request_key(&key_type_user, name, NULL); 222051dbb91SDmitry Kasatkin } 223051dbb91SDmitry Kasatkin if (IS_ERR(key)) { 224051dbb91SDmitry Kasatkin pr_err("key not found, id: %s\n", name); 225051dbb91SDmitry Kasatkin return PTR_ERR(key); 226051dbb91SDmitry Kasatkin } 227051dbb91SDmitry Kasatkin 228051dbb91SDmitry Kasatkin desc = kzalloc(sizeof(*desc) + crypto_shash_descsize(shash), 229051dbb91SDmitry Kasatkin GFP_KERNEL); 230051dbb91SDmitry Kasatkin if (!desc) 231051dbb91SDmitry Kasatkin goto err; 232051dbb91SDmitry Kasatkin 233051dbb91SDmitry Kasatkin desc->tfm = shash; 234051dbb91SDmitry Kasatkin desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP; 235051dbb91SDmitry Kasatkin 236051dbb91SDmitry Kasatkin crypto_shash_init(desc); 237051dbb91SDmitry Kasatkin crypto_shash_update(desc, data, datalen); 238051dbb91SDmitry Kasatkin crypto_shash_update(desc, sig, sizeof(*sh)); 239051dbb91SDmitry Kasatkin crypto_shash_final(desc, hash); 240051dbb91SDmitry Kasatkin 241051dbb91SDmitry Kasatkin kfree(desc); 242051dbb91SDmitry Kasatkin 243051dbb91SDmitry Kasatkin /* pass signature mpis address */ 244051dbb91SDmitry Kasatkin err = digsig_verify_rsa(key, sig + sizeof(*sh), siglen - sizeof(*sh), 245051dbb91SDmitry Kasatkin hash, sizeof(hash)); 246051dbb91SDmitry Kasatkin 247051dbb91SDmitry Kasatkin err: 248051dbb91SDmitry Kasatkin key_put(key); 249051dbb91SDmitry Kasatkin 250051dbb91SDmitry Kasatkin return err ? -EINVAL : 0; 251051dbb91SDmitry Kasatkin } 252051dbb91SDmitry Kasatkin EXPORT_SYMBOL_GPL(digsig_verify); 253051dbb91SDmitry Kasatkin 254051dbb91SDmitry Kasatkin static int __init digsig_init(void) 255051dbb91SDmitry Kasatkin { 256051dbb91SDmitry Kasatkin shash = crypto_alloc_shash("sha1", 0, 0); 257051dbb91SDmitry Kasatkin if (IS_ERR(shash)) { 258051dbb91SDmitry Kasatkin pr_err("shash allocation failed\n"); 259051dbb91SDmitry Kasatkin return PTR_ERR(shash); 260051dbb91SDmitry Kasatkin } 261051dbb91SDmitry Kasatkin 262051dbb91SDmitry Kasatkin return 0; 263051dbb91SDmitry Kasatkin 264051dbb91SDmitry Kasatkin } 265051dbb91SDmitry Kasatkin 266051dbb91SDmitry Kasatkin static void __exit digsig_cleanup(void) 267051dbb91SDmitry Kasatkin { 268051dbb91SDmitry Kasatkin crypto_free_shash(shash); 269051dbb91SDmitry Kasatkin } 270051dbb91SDmitry Kasatkin 271051dbb91SDmitry Kasatkin module_init(digsig_init); 272051dbb91SDmitry Kasatkin module_exit(digsig_cleanup); 273051dbb91SDmitry Kasatkin 274051dbb91SDmitry Kasatkin MODULE_LICENSE("GPL"); 275