1ddbb4114SMat Martineau /* Crypto operations using stored keys 2ddbb4114SMat Martineau * 3ddbb4114SMat Martineau * Copyright (c) 2016, Intel Corporation 4ddbb4114SMat Martineau * 5ddbb4114SMat Martineau * This program is free software; you can redistribute it and/or 6ddbb4114SMat Martineau * modify it under the terms of the GNU General Public License 7ddbb4114SMat Martineau * as published by the Free Software Foundation; either version 8ddbb4114SMat Martineau * 2 of the License, or (at your option) any later version. 9ddbb4114SMat Martineau */ 10ddbb4114SMat Martineau 11ddbb4114SMat Martineau #include <linux/mpi.h> 12ddbb4114SMat Martineau #include <linux/slab.h> 13ddbb4114SMat Martineau #include <linux/uaccess.h> 14ddbb4114SMat Martineau #include <keys/user-type.h> 15ddbb4114SMat Martineau #include "internal.h" 16ddbb4114SMat Martineau 17ddbb4114SMat Martineau /* 18ddbb4114SMat Martineau * Public key or shared secret generation function [RFC2631 sec 2.1.1] 19ddbb4114SMat Martineau * 20ddbb4114SMat Martineau * ya = g^xa mod p; 21ddbb4114SMat Martineau * or 22ddbb4114SMat Martineau * ZZ = yb^xa mod p; 23ddbb4114SMat Martineau * 24ddbb4114SMat Martineau * where xa is the local private key, ya is the local public key, g is 25ddbb4114SMat Martineau * the generator, p is the prime, yb is the remote public key, and ZZ 26ddbb4114SMat Martineau * is the shared secret. 27ddbb4114SMat Martineau * 28ddbb4114SMat Martineau * Both are the same calculation, so g or yb are the "base" and ya or 29ddbb4114SMat Martineau * ZZ are the "result". 30ddbb4114SMat Martineau */ 31ddbb4114SMat Martineau static int do_dh(MPI result, MPI base, MPI xa, MPI p) 32ddbb4114SMat Martineau { 33ddbb4114SMat Martineau return mpi_powm(result, base, xa, p); 34ddbb4114SMat Martineau } 35ddbb4114SMat Martineau 36ddbb4114SMat Martineau static ssize_t mpi_from_key(key_serial_t keyid, size_t maxlen, MPI *mpi) 37ddbb4114SMat Martineau { 38ddbb4114SMat Martineau struct key *key; 39ddbb4114SMat Martineau key_ref_t key_ref; 40ddbb4114SMat Martineau long status; 41ddbb4114SMat Martineau ssize_t ret; 42ddbb4114SMat Martineau 43ddbb4114SMat Martineau key_ref = lookup_user_key(keyid, 0, KEY_NEED_READ); 44ddbb4114SMat Martineau if (IS_ERR(key_ref)) { 45ddbb4114SMat Martineau ret = -ENOKEY; 46ddbb4114SMat Martineau goto error; 47ddbb4114SMat Martineau } 48ddbb4114SMat Martineau 49ddbb4114SMat Martineau key = key_ref_to_ptr(key_ref); 50ddbb4114SMat Martineau 51ddbb4114SMat Martineau ret = -EOPNOTSUPP; 52ddbb4114SMat Martineau if (key->type == &key_type_user) { 53ddbb4114SMat Martineau down_read(&key->sem); 54ddbb4114SMat Martineau status = key_validate(key); 55ddbb4114SMat Martineau if (status == 0) { 56ddbb4114SMat Martineau const struct user_key_payload *payload; 57ddbb4114SMat Martineau 58ddbb4114SMat Martineau payload = user_key_payload(key); 59ddbb4114SMat Martineau 60ddbb4114SMat Martineau if (maxlen == 0) { 61ddbb4114SMat Martineau *mpi = NULL; 62ddbb4114SMat Martineau ret = payload->datalen; 63ddbb4114SMat Martineau } else if (payload->datalen <= maxlen) { 64ddbb4114SMat Martineau *mpi = mpi_read_raw_data(payload->data, 65ddbb4114SMat Martineau payload->datalen); 66ddbb4114SMat Martineau if (*mpi) 67ddbb4114SMat Martineau ret = payload->datalen; 68ddbb4114SMat Martineau } else { 69ddbb4114SMat Martineau ret = -EINVAL; 70ddbb4114SMat Martineau } 71ddbb4114SMat Martineau } 72ddbb4114SMat Martineau up_read(&key->sem); 73ddbb4114SMat Martineau } 74ddbb4114SMat Martineau 75ddbb4114SMat Martineau key_put(key); 76ddbb4114SMat Martineau error: 77ddbb4114SMat Martineau return ret; 78ddbb4114SMat Martineau } 79ddbb4114SMat Martineau 80ddbb4114SMat Martineau long keyctl_dh_compute(struct keyctl_dh_params __user *params, 81*4693fc73SStephan Mueller char __user *buffer, size_t buflen, 82*4693fc73SStephan Mueller void __user *reserved) 83ddbb4114SMat Martineau { 84ddbb4114SMat Martineau long ret; 85ddbb4114SMat Martineau MPI base, private, prime, result; 86ddbb4114SMat Martineau unsigned nbytes; 87ddbb4114SMat Martineau struct keyctl_dh_params pcopy; 88ddbb4114SMat Martineau uint8_t *kbuf; 89ddbb4114SMat Martineau ssize_t keylen; 90ddbb4114SMat Martineau size_t resultlen; 91ddbb4114SMat Martineau 92ddbb4114SMat Martineau if (!params || (!buffer && buflen)) { 93ddbb4114SMat Martineau ret = -EINVAL; 94ddbb4114SMat Martineau goto out; 95ddbb4114SMat Martineau } 96ddbb4114SMat Martineau if (copy_from_user(&pcopy, params, sizeof(pcopy)) != 0) { 97ddbb4114SMat Martineau ret = -EFAULT; 98ddbb4114SMat Martineau goto out; 99ddbb4114SMat Martineau } 100ddbb4114SMat Martineau 101*4693fc73SStephan Mueller if (reserved) { 102*4693fc73SStephan Mueller ret = -EINVAL; 103*4693fc73SStephan Mueller goto out; 104*4693fc73SStephan Mueller } 105*4693fc73SStephan Mueller 106ddbb4114SMat Martineau keylen = mpi_from_key(pcopy.prime, buflen, &prime); 107ddbb4114SMat Martineau if (keylen < 0 || !prime) { 108ddbb4114SMat Martineau /* buflen == 0 may be used to query the required buffer size, 109ddbb4114SMat Martineau * which is the prime key length. 110ddbb4114SMat Martineau */ 111ddbb4114SMat Martineau ret = keylen; 112ddbb4114SMat Martineau goto out; 113ddbb4114SMat Martineau } 114ddbb4114SMat Martineau 115ddbb4114SMat Martineau /* The result is never longer than the prime */ 116ddbb4114SMat Martineau resultlen = keylen; 117ddbb4114SMat Martineau 118ddbb4114SMat Martineau keylen = mpi_from_key(pcopy.base, SIZE_MAX, &base); 119ddbb4114SMat Martineau if (keylen < 0 || !base) { 120ddbb4114SMat Martineau ret = keylen; 121ddbb4114SMat Martineau goto error1; 122ddbb4114SMat Martineau } 123ddbb4114SMat Martineau 124ddbb4114SMat Martineau keylen = mpi_from_key(pcopy.private, SIZE_MAX, &private); 125ddbb4114SMat Martineau if (keylen < 0 || !private) { 126ddbb4114SMat Martineau ret = keylen; 127ddbb4114SMat Martineau goto error2; 128ddbb4114SMat Martineau } 129ddbb4114SMat Martineau 130ddbb4114SMat Martineau result = mpi_alloc(0); 131ddbb4114SMat Martineau if (!result) { 132ddbb4114SMat Martineau ret = -ENOMEM; 133ddbb4114SMat Martineau goto error3; 134ddbb4114SMat Martineau } 135ddbb4114SMat Martineau 136ddbb4114SMat Martineau kbuf = kmalloc(resultlen, GFP_KERNEL); 137ddbb4114SMat Martineau if (!kbuf) { 138ddbb4114SMat Martineau ret = -ENOMEM; 139ddbb4114SMat Martineau goto error4; 140ddbb4114SMat Martineau } 141ddbb4114SMat Martineau 142ddbb4114SMat Martineau ret = do_dh(result, base, private, prime); 143ddbb4114SMat Martineau if (ret) 144ddbb4114SMat Martineau goto error5; 145ddbb4114SMat Martineau 146ddbb4114SMat Martineau ret = mpi_read_buffer(result, kbuf, resultlen, &nbytes, NULL); 147ddbb4114SMat Martineau if (ret != 0) 148ddbb4114SMat Martineau goto error5; 149ddbb4114SMat Martineau 150ddbb4114SMat Martineau ret = nbytes; 151ddbb4114SMat Martineau if (copy_to_user(buffer, kbuf, nbytes) != 0) 152ddbb4114SMat Martineau ret = -EFAULT; 153ddbb4114SMat Martineau 154ddbb4114SMat Martineau error5: 155ddbb4114SMat Martineau kfree(kbuf); 156ddbb4114SMat Martineau error4: 157ddbb4114SMat Martineau mpi_free(result); 158ddbb4114SMat Martineau error3: 159ddbb4114SMat Martineau mpi_free(private); 160ddbb4114SMat Martineau error2: 161ddbb4114SMat Martineau mpi_free(base); 162ddbb4114SMat Martineau error1: 163ddbb4114SMat Martineau mpi_free(prime); 164ddbb4114SMat Martineau out: 165ddbb4114SMat Martineau return ret; 166ddbb4114SMat Martineau } 167