-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This adds userspace access to Diffie-Hellman computations through a new keyctl() syscall command to calculate shared secrets or public keys using input parameters stored in the keyring. Input key ids are provided in a struct due to the current 5-arg limit for the keyctl syscall. Only user keys are supported in order to avoid exposing the content of logon or encrypted keys. The output is written to the provided buffer, based on the assumption that the values are only needed in userspace. Future support for other types of key derivation would involve a new command, like KEYCTL_ECDH_COMPUTE. Once Diffie-Hellman support is included in the crypto API, this code can be converted to use the crypto API to take advantage of possible hardware acceleration and reduce redundant code. Signed-off-by: Mat Martineau <mathew.j.martineau@linux.intel.com> Signed-off-by: David Howells <dhowells@redhat.com>
- Loading branch information
Mat Martineau
authored and
David Howells
committed
Apr 12, 2016
1 parent
13100a7
commit ddbb411
Showing
8 changed files
with
233 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,160 @@ | ||
/* 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) | ||
{ | ||
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; | ||
} | ||
|
||
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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters