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