123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167 |
- /* Crypto operations using stored keys
- *
- * Copyright (c) 2016, Intel Corporation
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
- #include <linux/mpi.h>
- #include <linux/slab.h>
- #include <linux/uaccess.h>
- #include <keys/user-type.h>
- #include "internal.h"
- /*
- * Public key or shared secret generation function [RFC2631 sec 2.1.1]
- *
- * ya = g^xa mod p;
- * or
- * ZZ = yb^xa mod p;
- *
- * where xa is the local private key, ya is the local public key, g is
- * the generator, p is the prime, yb is the remote public key, and ZZ
- * is the shared secret.
- *
- * Both are the same calculation, so g or yb are the "base" and ya or
- * ZZ are the "result".
- */
- static int do_dh(MPI result, MPI base, MPI xa, MPI p)
- {
- return mpi_powm(result, base, xa, p);
- }
- static ssize_t mpi_from_key(key_serial_t keyid, size_t maxlen, MPI *mpi)
- {
- struct key *key;
- key_ref_t key_ref;
- long status;
- ssize_t ret;
- key_ref = lookup_user_key(keyid, 0, KEY_NEED_READ);
- if (IS_ERR(key_ref)) {
- ret = -ENOKEY;
- goto error;
- }
- key = key_ref_to_ptr(key_ref);
- ret = -EOPNOTSUPP;
- if (key->type == &key_type_user) {
- down_read(&key->sem);
- status = key_validate(key);
- if (status == 0) {
- const struct user_key_payload *payload;
- payload = user_key_payload(key);
- if (maxlen == 0) {
- *mpi = NULL;
- ret = payload->datalen;
- } else if (payload->datalen <= maxlen) {
- *mpi = mpi_read_raw_data(payload->data,
- payload->datalen);
- if (*mpi)
- ret = payload->datalen;
- } else {
- ret = -EINVAL;
- }
- }
- up_read(&key->sem);
- }
- key_put(key);
- error:
- return ret;
- }
- long keyctl_dh_compute(struct keyctl_dh_params __user *params,
- char __user *buffer, size_t buflen,
- void __user *reserved)
- {
- long ret;
- MPI base, private, prime, result;
- unsigned nbytes;
- struct keyctl_dh_params pcopy;
- uint8_t *kbuf;
- ssize_t keylen;
- size_t resultlen;
- if (!params || (!buffer && buflen)) {
- ret = -EINVAL;
- goto out;
- }
- if (copy_from_user(&pcopy, params, sizeof(pcopy)) != 0) {
- ret = -EFAULT;
- goto out;
- }
- if (reserved) {
- ret = -EINVAL;
- goto out;
- }
- keylen = mpi_from_key(pcopy.prime, buflen, &prime);
- if (keylen < 0 || !prime) {
- /* buflen == 0 may be used to query the required buffer size,
- * which is the prime key length.
- */
- ret = keylen;
- goto out;
- }
- /* The result is never longer than the prime */
- resultlen = keylen;
- keylen = mpi_from_key(pcopy.base, SIZE_MAX, &base);
- if (keylen < 0 || !base) {
- ret = keylen;
- goto error1;
- }
- keylen = mpi_from_key(pcopy.private, SIZE_MAX, &private);
- if (keylen < 0 || !private) {
- ret = keylen;
- goto error2;
- }
- result = mpi_alloc(0);
- if (!result) {
- ret = -ENOMEM;
- goto error3;
- }
- kbuf = kmalloc(resultlen, GFP_KERNEL);
- if (!kbuf) {
- ret = -ENOMEM;
- goto error4;
- }
- ret = do_dh(result, base, private, prime);
- if (ret)
- goto error5;
- ret = mpi_read_buffer(result, kbuf, resultlen, &nbytes, NULL);
- if (ret != 0)
- goto error5;
- ret = nbytes;
- if (copy_to_user(buffer, kbuf, nbytes) != 0)
- ret = -EFAULT;
- error5:
- kfree(kbuf);
- error4:
- mpi_free(result);
- error3:
- mpi_free(private);
- error2:
- mpi_free(base);
- error1:
- mpi_free(prime);
- out:
- return ret;
- }
|