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