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 3326d43845SDmitry Kasatkin static const char *pkcs_1_v1_5_decode_emsa(const unsigned char *msg, 34051dbb91SDmitry Kasatkin unsigned long msglen, 35051dbb91SDmitry Kasatkin unsigned long modulus_bitlen, 36b35e286aSDmitry Kasatkin unsigned long *outlen) 37051dbb91SDmitry Kasatkin { 38051dbb91SDmitry Kasatkin unsigned long modulus_len, ps_len, i; 39051dbb91SDmitry Kasatkin 40051dbb91SDmitry Kasatkin modulus_len = (modulus_bitlen >> 3) + (modulus_bitlen & 7 ? 1 : 0); 41051dbb91SDmitry Kasatkin 42051dbb91SDmitry Kasatkin /* test message size */ 43051dbb91SDmitry Kasatkin if ((msglen > modulus_len) || (modulus_len < 11)) 4426d43845SDmitry Kasatkin return NULL; 45051dbb91SDmitry Kasatkin 46051dbb91SDmitry Kasatkin /* separate encoded message */ 4726d43845SDmitry Kasatkin if (msg[0] != 0x00 || msg[1] != 0x01) 4826d43845SDmitry Kasatkin return NULL; 49051dbb91SDmitry Kasatkin 50051dbb91SDmitry Kasatkin for (i = 2; i < modulus_len - 1; i++) 51051dbb91SDmitry Kasatkin if (msg[i] != 0xFF) 52051dbb91SDmitry Kasatkin break; 53051dbb91SDmitry Kasatkin 54051dbb91SDmitry Kasatkin /* separator check */ 55b35e286aSDmitry Kasatkin if (msg[i] != 0) 56051dbb91SDmitry Kasatkin /* There was no octet with hexadecimal value 0x00 57051dbb91SDmitry Kasatkin to separate ps from m. */ 5826d43845SDmitry Kasatkin return NULL; 59051dbb91SDmitry Kasatkin 60051dbb91SDmitry Kasatkin ps_len = i - 2; 61051dbb91SDmitry Kasatkin 62051dbb91SDmitry Kasatkin *outlen = (msglen - (2 + ps_len + 1)); 63051dbb91SDmitry Kasatkin 6426d43845SDmitry Kasatkin return msg + 2 + ps_len + 1; 65051dbb91SDmitry Kasatkin } 66051dbb91SDmitry Kasatkin 67051dbb91SDmitry Kasatkin /* 68051dbb91SDmitry Kasatkin * RSA Signature verification with public key 69051dbb91SDmitry Kasatkin */ 70051dbb91SDmitry Kasatkin static int digsig_verify_rsa(struct key *key, 71051dbb91SDmitry Kasatkin const char *sig, int siglen, 72051dbb91SDmitry Kasatkin const char *h, int hlen) 73051dbb91SDmitry Kasatkin { 74051dbb91SDmitry Kasatkin int err = -EINVAL; 75051dbb91SDmitry Kasatkin unsigned long len; 76051dbb91SDmitry Kasatkin unsigned long mlen, mblen; 77051dbb91SDmitry Kasatkin unsigned nret, l; 78b35e286aSDmitry Kasatkin int head, i; 7926d43845SDmitry Kasatkin unsigned char *out1 = NULL; 8026d43845SDmitry Kasatkin const char *m; 81051dbb91SDmitry Kasatkin MPI in = NULL, res = NULL, pkey[2]; 82146aa8b1SDavid Howells uint8_t *p, *datap; 83146aa8b1SDavid Howells const uint8_t *endp; 84146aa8b1SDavid Howells const struct user_key_payload *ukp; 85051dbb91SDmitry Kasatkin struct pubkey_hdr *pkh; 86051dbb91SDmitry Kasatkin 87051dbb91SDmitry Kasatkin down_read(&key->sem); 88*0837e49aSDavid Howells ukp = user_key_payload_locked(key); 89f58a0815SDmitry Kasatkin 90f58a0815SDmitry Kasatkin if (ukp->datalen < sizeof(*pkh)) 91f58a0815SDmitry Kasatkin goto err1; 92f58a0815SDmitry Kasatkin 93051dbb91SDmitry Kasatkin pkh = (struct pubkey_hdr *)ukp->data; 94051dbb91SDmitry Kasatkin 95051dbb91SDmitry Kasatkin if (pkh->version != 1) 96051dbb91SDmitry Kasatkin goto err1; 97051dbb91SDmitry Kasatkin 98051dbb91SDmitry Kasatkin if (pkh->algo != PUBKEY_ALGO_RSA) 99051dbb91SDmitry Kasatkin goto err1; 100051dbb91SDmitry Kasatkin 101051dbb91SDmitry Kasatkin if (pkh->nmpi != 2) 102051dbb91SDmitry Kasatkin goto err1; 103051dbb91SDmitry Kasatkin 104051dbb91SDmitry Kasatkin datap = pkh->mpi; 105f58a0815SDmitry Kasatkin endp = ukp->data + ukp->datalen; 106051dbb91SDmitry Kasatkin 107051dbb91SDmitry Kasatkin for (i = 0; i < pkh->nmpi; i++) { 108051dbb91SDmitry Kasatkin unsigned int remaining = endp - datap; 109051dbb91SDmitry Kasatkin pkey[i] = mpi_read_from_buffer(datap, &remaining); 11003cdfaadSNicolai Stange if (IS_ERR(pkey[i])) { 11103cdfaadSNicolai Stange err = PTR_ERR(pkey[i]); 11286f8bedcSDmitry Kasatkin goto err; 11303cdfaadSNicolai Stange } 114051dbb91SDmitry Kasatkin datap += remaining; 115051dbb91SDmitry Kasatkin } 116051dbb91SDmitry Kasatkin 117051dbb91SDmitry Kasatkin mblen = mpi_get_nbits(pkey[0]); 11826d43845SDmitry Kasatkin mlen = DIV_ROUND_UP(mblen, 8); 119051dbb91SDmitry Kasatkin 120c5ce7c69SNicolai Stange if (mlen == 0) { 121c5ce7c69SNicolai Stange err = -EINVAL; 122f58a0815SDmitry Kasatkin goto err; 123c5ce7c69SNicolai Stange } 124c5ce7c69SNicolai Stange 125c5ce7c69SNicolai Stange err = -ENOMEM; 126051dbb91SDmitry Kasatkin 127051dbb91SDmitry Kasatkin out1 = kzalloc(mlen, GFP_KERNEL); 128051dbb91SDmitry Kasatkin if (!out1) 129051dbb91SDmitry Kasatkin goto err; 130051dbb91SDmitry Kasatkin 131051dbb91SDmitry Kasatkin nret = siglen; 132051dbb91SDmitry Kasatkin in = mpi_read_from_buffer(sig, &nret); 13303cdfaadSNicolai Stange if (IS_ERR(in)) { 13403cdfaadSNicolai Stange err = PTR_ERR(in); 135051dbb91SDmitry Kasatkin goto err; 13603cdfaadSNicolai Stange } 137051dbb91SDmitry Kasatkin 138051dbb91SDmitry Kasatkin res = mpi_alloc(mpi_get_nlimbs(in) * 2); 139051dbb91SDmitry Kasatkin if (!res) 140051dbb91SDmitry Kasatkin goto err; 141051dbb91SDmitry Kasatkin 142051dbb91SDmitry Kasatkin err = mpi_powm(res, in, pkey[1], pkey[0]); 143051dbb91SDmitry Kasatkin if (err) 144051dbb91SDmitry Kasatkin goto err; 145051dbb91SDmitry Kasatkin 146051dbb91SDmitry Kasatkin if (mpi_get_nlimbs(res) * BYTES_PER_MPI_LIMB > mlen) { 147051dbb91SDmitry Kasatkin err = -EINVAL; 148051dbb91SDmitry Kasatkin goto err; 149051dbb91SDmitry Kasatkin } 150051dbb91SDmitry Kasatkin 151051dbb91SDmitry Kasatkin p = mpi_get_buffer(res, &l, NULL); 152051dbb91SDmitry Kasatkin if (!p) { 153051dbb91SDmitry Kasatkin err = -EINVAL; 154051dbb91SDmitry Kasatkin goto err; 155051dbb91SDmitry Kasatkin } 156051dbb91SDmitry Kasatkin 157051dbb91SDmitry Kasatkin len = mlen; 158051dbb91SDmitry Kasatkin head = len - l; 159051dbb91SDmitry Kasatkin memset(out1, 0, head); 160051dbb91SDmitry Kasatkin memcpy(out1 + head, p, l); 161051dbb91SDmitry Kasatkin 1627810cc1eSYOSHIFUJI Hideaki kfree(p); 1637810cc1eSYOSHIFUJI Hideaki 16426d43845SDmitry Kasatkin m = pkcs_1_v1_5_decode_emsa(out1, len, mblen, &len); 165051dbb91SDmitry Kasatkin 16626d43845SDmitry Kasatkin if (!m || len != hlen || memcmp(m, h, hlen)) 167bc01637aSDmitry Kasatkin err = -EINVAL; 168051dbb91SDmitry Kasatkin 169051dbb91SDmitry Kasatkin err: 170051dbb91SDmitry Kasatkin mpi_free(in); 171051dbb91SDmitry Kasatkin mpi_free(res); 172051dbb91SDmitry Kasatkin kfree(out1); 17386f8bedcSDmitry Kasatkin while (--i >= 0) 17486f8bedcSDmitry Kasatkin mpi_free(pkey[i]); 175051dbb91SDmitry Kasatkin err1: 176051dbb91SDmitry Kasatkin up_read(&key->sem); 177051dbb91SDmitry Kasatkin 178051dbb91SDmitry Kasatkin return err; 179051dbb91SDmitry Kasatkin } 180051dbb91SDmitry Kasatkin 181051dbb91SDmitry Kasatkin /** 182051dbb91SDmitry Kasatkin * digsig_verify() - digital signature verification with public key 183051dbb91SDmitry Kasatkin * @keyring: keyring to search key in 184051dbb91SDmitry Kasatkin * @sig: digital signature 18554b14f40SFabian Frederick * @siglen: length of the signature 186051dbb91SDmitry Kasatkin * @data: data 187051dbb91SDmitry Kasatkin * @datalen: length of the data 18854b14f40SFabian Frederick * 18954b14f40SFabian Frederick * Returns 0 on success, -EINVAL otherwise 190051dbb91SDmitry Kasatkin * 191051dbb91SDmitry Kasatkin * Verifies data integrity against digital signature. 192051dbb91SDmitry Kasatkin * Currently only RSA is supported. 193051dbb91SDmitry Kasatkin * Normally hash of the content is used as a data for this function. 194051dbb91SDmitry Kasatkin * 195051dbb91SDmitry Kasatkin */ 196051dbb91SDmitry Kasatkin int digsig_verify(struct key *keyring, const char *sig, int siglen, 197051dbb91SDmitry Kasatkin const char *data, int datalen) 198051dbb91SDmitry Kasatkin { 199051dbb91SDmitry Kasatkin int err = -ENOMEM; 200051dbb91SDmitry Kasatkin struct signature_hdr *sh = (struct signature_hdr *)sig; 201051dbb91SDmitry Kasatkin struct shash_desc *desc = NULL; 202051dbb91SDmitry Kasatkin unsigned char hash[SHA1_DIGEST_SIZE]; 203051dbb91SDmitry Kasatkin struct key *key; 204051dbb91SDmitry Kasatkin char name[20]; 205051dbb91SDmitry Kasatkin 206051dbb91SDmitry Kasatkin if (siglen < sizeof(*sh) + 2) 207051dbb91SDmitry Kasatkin return -EINVAL; 208051dbb91SDmitry Kasatkin 209051dbb91SDmitry Kasatkin if (sh->algo != PUBKEY_ALGO_RSA) 210051dbb91SDmitry Kasatkin return -ENOTSUPP; 211051dbb91SDmitry Kasatkin 212051dbb91SDmitry Kasatkin sprintf(name, "%llX", __be64_to_cpup((uint64_t *)sh->keyid)); 213051dbb91SDmitry Kasatkin 214051dbb91SDmitry Kasatkin if (keyring) { 215051dbb91SDmitry Kasatkin /* search in specific keyring */ 216051dbb91SDmitry Kasatkin key_ref_t kref; 217051dbb91SDmitry Kasatkin kref = keyring_search(make_key_ref(keyring, 1UL), 218051dbb91SDmitry Kasatkin &key_type_user, name); 219051dbb91SDmitry Kasatkin if (IS_ERR(kref)) 220ff6092a8SDuan Jiong key = ERR_CAST(kref); 221051dbb91SDmitry Kasatkin else 222051dbb91SDmitry Kasatkin key = key_ref_to_ptr(kref); 223051dbb91SDmitry Kasatkin } else { 224051dbb91SDmitry Kasatkin key = request_key(&key_type_user, name, NULL); 225051dbb91SDmitry Kasatkin } 226051dbb91SDmitry Kasatkin if (IS_ERR(key)) { 227051dbb91SDmitry Kasatkin pr_err("key not found, id: %s\n", name); 228051dbb91SDmitry Kasatkin return PTR_ERR(key); 229051dbb91SDmitry Kasatkin } 230051dbb91SDmitry Kasatkin 231051dbb91SDmitry Kasatkin desc = kzalloc(sizeof(*desc) + crypto_shash_descsize(shash), 232051dbb91SDmitry Kasatkin GFP_KERNEL); 233051dbb91SDmitry Kasatkin if (!desc) 234051dbb91SDmitry Kasatkin goto err; 235051dbb91SDmitry Kasatkin 236051dbb91SDmitry Kasatkin desc->tfm = shash; 237051dbb91SDmitry Kasatkin desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP; 238051dbb91SDmitry Kasatkin 239051dbb91SDmitry Kasatkin crypto_shash_init(desc); 240051dbb91SDmitry Kasatkin crypto_shash_update(desc, data, datalen); 241051dbb91SDmitry Kasatkin crypto_shash_update(desc, sig, sizeof(*sh)); 242051dbb91SDmitry Kasatkin crypto_shash_final(desc, hash); 243051dbb91SDmitry Kasatkin 244051dbb91SDmitry Kasatkin kfree(desc); 245051dbb91SDmitry Kasatkin 246051dbb91SDmitry Kasatkin /* pass signature mpis address */ 247051dbb91SDmitry Kasatkin err = digsig_verify_rsa(key, sig + sizeof(*sh), siglen - sizeof(*sh), 248051dbb91SDmitry Kasatkin hash, sizeof(hash)); 249051dbb91SDmitry Kasatkin 250051dbb91SDmitry Kasatkin err: 251051dbb91SDmitry Kasatkin key_put(key); 252051dbb91SDmitry Kasatkin 253051dbb91SDmitry Kasatkin return err ? -EINVAL : 0; 254051dbb91SDmitry Kasatkin } 255051dbb91SDmitry Kasatkin EXPORT_SYMBOL_GPL(digsig_verify); 256051dbb91SDmitry Kasatkin 257051dbb91SDmitry Kasatkin static int __init digsig_init(void) 258051dbb91SDmitry Kasatkin { 259051dbb91SDmitry Kasatkin shash = crypto_alloc_shash("sha1", 0, 0); 260051dbb91SDmitry Kasatkin if (IS_ERR(shash)) { 261051dbb91SDmitry Kasatkin pr_err("shash allocation failed\n"); 262051dbb91SDmitry Kasatkin return PTR_ERR(shash); 263051dbb91SDmitry Kasatkin } 264051dbb91SDmitry Kasatkin 265051dbb91SDmitry Kasatkin return 0; 266051dbb91SDmitry Kasatkin 267051dbb91SDmitry Kasatkin } 268051dbb91SDmitry Kasatkin 269051dbb91SDmitry Kasatkin static void __exit digsig_cleanup(void) 270051dbb91SDmitry Kasatkin { 271051dbb91SDmitry Kasatkin crypto_free_shash(shash); 272051dbb91SDmitry Kasatkin } 273051dbb91SDmitry Kasatkin 274051dbb91SDmitry Kasatkin module_init(digsig_init); 275051dbb91SDmitry Kasatkin module_exit(digsig_cleanup); 276051dbb91SDmitry Kasatkin 277051dbb91SDmitry Kasatkin MODULE_LICENSE("GPL"); 278