1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* Crypto operations using stored keys 3 * 4 * Copyright (c) 2016, Intel Corporation 5 */ 6 7 #include <linux/slab.h> 8 #include <linux/uaccess.h> 9 #include <linux/scatterlist.h> 10 #include <linux/crypto.h> 11 #include <crypto/hash.h> 12 #include <crypto/kpp.h> 13 #include <crypto/dh.h> 14 #include <crypto/kdf_sp800108.h> 15 #include <keys/user-type.h> 16 #include "internal.h" 17 18 static ssize_t dh_data_from_key(key_serial_t keyid, const void **data) 19 { 20 struct key *key; 21 key_ref_t key_ref; 22 long status; 23 ssize_t ret; 24 25 key_ref = lookup_user_key(keyid, 0, KEY_NEED_READ); 26 if (IS_ERR(key_ref)) { 27 ret = -ENOKEY; 28 goto error; 29 } 30 31 key = key_ref_to_ptr(key_ref); 32 33 ret = -EOPNOTSUPP; 34 if (key->type == &key_type_user) { 35 down_read(&key->sem); 36 status = key_validate(key); 37 if (status == 0) { 38 const struct user_key_payload *payload; 39 uint8_t *duplicate; 40 41 payload = user_key_payload_locked(key); 42 43 duplicate = kmemdup(payload->data, payload->datalen, 44 GFP_KERNEL); 45 if (duplicate) { 46 *data = duplicate; 47 ret = payload->datalen; 48 } else { 49 ret = -ENOMEM; 50 } 51 } 52 up_read(&key->sem); 53 } 54 55 key_put(key); 56 error: 57 return ret; 58 } 59 60 static void dh_free_data(struct dh *dh) 61 { 62 kfree_sensitive(dh->key); 63 kfree_sensitive(dh->p); 64 kfree_sensitive(dh->g); 65 } 66 67 static int kdf_alloc(struct crypto_shash **hash, char *hashname) 68 { 69 struct crypto_shash *tfm; 70 71 /* allocate synchronous hash */ 72 tfm = crypto_alloc_shash(hashname, 0, 0); 73 if (IS_ERR(tfm)) { 74 pr_info("could not allocate digest TFM handle %s\n", hashname); 75 return PTR_ERR(tfm); 76 } 77 78 if (crypto_shash_digestsize(tfm) == 0) { 79 crypto_free_shash(tfm); 80 return -EINVAL; 81 } 82 83 *hash = tfm; 84 85 return 0; 86 } 87 88 static void kdf_dealloc(struct crypto_shash *hash) 89 { 90 if (hash) 91 crypto_free_shash(hash); 92 } 93 94 static int keyctl_dh_compute_kdf(struct crypto_shash *hash, 95 char __user *buffer, size_t buflen, 96 uint8_t *kbuf, size_t kbuflen) 97 { 98 struct kvec kbuf_iov = { .iov_base = kbuf, .iov_len = kbuflen }; 99 uint8_t *outbuf = NULL; 100 int ret; 101 size_t outbuf_len = roundup(buflen, crypto_shash_digestsize(hash)); 102 103 outbuf = kmalloc(outbuf_len, GFP_KERNEL); 104 if (!outbuf) { 105 ret = -ENOMEM; 106 goto err; 107 } 108 109 ret = crypto_kdf108_ctr_generate(hash, &kbuf_iov, 1, outbuf, outbuf_len); 110 if (ret) 111 goto err; 112 113 ret = buflen; 114 if (copy_to_user(buffer, outbuf, buflen) != 0) 115 ret = -EFAULT; 116 117 err: 118 kfree_sensitive(outbuf); 119 return ret; 120 } 121 122 long __keyctl_dh_compute(struct keyctl_dh_params __user *params, 123 char __user *buffer, size_t buflen, 124 struct keyctl_kdf_params *kdfcopy) 125 { 126 long ret; 127 ssize_t dlen; 128 int secretlen; 129 int outlen; 130 struct keyctl_dh_params pcopy; 131 struct dh dh_inputs; 132 struct scatterlist outsg; 133 DECLARE_CRYPTO_WAIT(compl); 134 struct crypto_kpp *tfm; 135 struct kpp_request *req; 136 uint8_t *secret; 137 uint8_t *outbuf; 138 struct crypto_shash *hash = NULL; 139 140 if (!params || (!buffer && buflen)) { 141 ret = -EINVAL; 142 goto out1; 143 } 144 if (copy_from_user(&pcopy, params, sizeof(pcopy)) != 0) { 145 ret = -EFAULT; 146 goto out1; 147 } 148 149 if (kdfcopy) { 150 char *hashname; 151 152 if (memchr_inv(kdfcopy->__spare, 0, sizeof(kdfcopy->__spare))) { 153 ret = -EINVAL; 154 goto out1; 155 } 156 157 if (buflen > KEYCTL_KDF_MAX_OUTPUT_LEN || 158 kdfcopy->otherinfolen > KEYCTL_KDF_MAX_OI_LEN) { 159 ret = -EMSGSIZE; 160 goto out1; 161 } 162 163 /* get KDF name string */ 164 hashname = strndup_user(kdfcopy->hashname, CRYPTO_MAX_ALG_NAME); 165 if (IS_ERR(hashname)) { 166 ret = PTR_ERR(hashname); 167 goto out1; 168 } 169 170 /* allocate KDF from the kernel crypto API */ 171 ret = kdf_alloc(&hash, hashname); 172 kfree(hashname); 173 if (ret) 174 goto out1; 175 } 176 177 memset(&dh_inputs, 0, sizeof(dh_inputs)); 178 179 dlen = dh_data_from_key(pcopy.prime, &dh_inputs.p); 180 if (dlen < 0) { 181 ret = dlen; 182 goto out1; 183 } 184 dh_inputs.p_size = dlen; 185 186 dlen = dh_data_from_key(pcopy.base, &dh_inputs.g); 187 if (dlen < 0) { 188 ret = dlen; 189 goto out2; 190 } 191 dh_inputs.g_size = dlen; 192 193 dlen = dh_data_from_key(pcopy.private, &dh_inputs.key); 194 if (dlen < 0) { 195 ret = dlen; 196 goto out2; 197 } 198 dh_inputs.key_size = dlen; 199 200 secretlen = crypto_dh_key_len(&dh_inputs); 201 secret = kmalloc(secretlen, GFP_KERNEL); 202 if (!secret) { 203 ret = -ENOMEM; 204 goto out2; 205 } 206 ret = crypto_dh_encode_key(secret, secretlen, &dh_inputs); 207 if (ret) 208 goto out3; 209 210 tfm = crypto_alloc_kpp("dh", 0, 0); 211 if (IS_ERR(tfm)) { 212 ret = PTR_ERR(tfm); 213 goto out3; 214 } 215 216 ret = crypto_kpp_set_secret(tfm, secret, secretlen); 217 if (ret) 218 goto out4; 219 220 outlen = crypto_kpp_maxsize(tfm); 221 222 if (!kdfcopy) { 223 /* 224 * When not using a KDF, buflen 0 is used to read the 225 * required buffer length 226 */ 227 if (buflen == 0) { 228 ret = outlen; 229 goto out4; 230 } else if (outlen > buflen) { 231 ret = -EOVERFLOW; 232 goto out4; 233 } 234 } 235 236 outbuf = kzalloc(kdfcopy ? (outlen + kdfcopy->otherinfolen) : outlen, 237 GFP_KERNEL); 238 if (!outbuf) { 239 ret = -ENOMEM; 240 goto out4; 241 } 242 243 sg_init_one(&outsg, outbuf, outlen); 244 245 req = kpp_request_alloc(tfm, GFP_KERNEL); 246 if (!req) { 247 ret = -ENOMEM; 248 goto out5; 249 } 250 251 kpp_request_set_input(req, NULL, 0); 252 kpp_request_set_output(req, &outsg, outlen); 253 kpp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG | 254 CRYPTO_TFM_REQ_MAY_SLEEP, 255 crypto_req_done, &compl); 256 257 /* 258 * For DH, generate_public_key and generate_shared_secret are 259 * the same calculation 260 */ 261 ret = crypto_kpp_generate_public_key(req); 262 ret = crypto_wait_req(ret, &compl); 263 if (ret) 264 goto out6; 265 266 if (kdfcopy) { 267 /* 268 * Concatenate SP800-56A otherinfo past DH shared secret -- the 269 * input to the KDF is (DH shared secret || otherinfo) 270 */ 271 if (copy_from_user(outbuf + req->dst_len, kdfcopy->otherinfo, 272 kdfcopy->otherinfolen) != 0) { 273 ret = -EFAULT; 274 goto out6; 275 } 276 277 ret = keyctl_dh_compute_kdf(hash, buffer, buflen, outbuf, 278 req->dst_len + kdfcopy->otherinfolen); 279 } else if (copy_to_user(buffer, outbuf, req->dst_len) == 0) { 280 ret = req->dst_len; 281 } else { 282 ret = -EFAULT; 283 } 284 285 out6: 286 kpp_request_free(req); 287 out5: 288 kfree_sensitive(outbuf); 289 out4: 290 crypto_free_kpp(tfm); 291 out3: 292 kfree_sensitive(secret); 293 out2: 294 dh_free_data(&dh_inputs); 295 out1: 296 kdf_dealloc(hash); 297 return ret; 298 } 299 300 long keyctl_dh_compute(struct keyctl_dh_params __user *params, 301 char __user *buffer, size_t buflen, 302 struct keyctl_kdf_params __user *kdf) 303 { 304 struct keyctl_kdf_params kdfcopy; 305 306 if (!kdf) 307 return __keyctl_dh_compute(params, buffer, buflen, NULL); 308 309 if (copy_from_user(&kdfcopy, kdf, sizeof(kdfcopy)) != 0) 310 return -EFAULT; 311 312 return __keyctl_dh_compute(params, buffer, buflen, &kdfcopy); 313 } 314
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.