aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMat Martineau <mathew.j.martineau@linux.intel.com>2016-04-12 14:54:58 -0400
committerDavid Howells <dhowells@redhat.com>2016-04-12 14:54:58 -0400
commitddbb41148724367394d0880c516bfaeed127b52e (patch)
tree3e5cc20804b646256525cd9c2de7a9681d7e4996
parent13100a72f40f5748a04017e0ab3df4cf27c809ef (diff)
KEYS: Add KEYCTL_DH_COMPUTE command
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>
-rw-r--r--Documentation/security/keys.txt30
-rw-r--r--include/uapi/linux/keyctl.h10
-rw-r--r--security/keys/Kconfig11
-rw-r--r--security/keys/Makefile1
-rw-r--r--security/keys/compat.c4
-rw-r--r--security/keys/dh.c160
-rw-r--r--security/keys/internal.h12
-rw-r--r--security/keys/keyctl.c5
8 files changed, 233 insertions, 0 deletions
diff --git a/Documentation/security/keys.txt b/Documentation/security/keys.txt
index 8c183873b2b7..a2f70cf6763a 100644
--- a/Documentation/security/keys.txt
+++ b/Documentation/security/keys.txt
@@ -823,6 +823,36 @@ The keyctl syscall functions are:
823 A process must have search permission on the key for this function to be 823 A process must have search permission on the key for this function to be
824 successful. 824 successful.
825 825
826 (*) Compute a Diffie-Hellman shared secret or public key
827
828 long keyctl(KEYCTL_DH_COMPUTE, struct keyctl_dh_params *params,
829 char *buffer, size_t buflen);
830
831 The params struct contains serial numbers for three keys:
832
833 - The prime, p, known to both parties
834 - The local private key
835 - The base integer, which is either a shared generator or the
836 remote public key
837
838 The value computed is:
839
840 result = base ^ private (mod prime)
841
842 If the base is the shared generator, the result is the local
843 public key. If the base is the remote public key, the result is
844 the shared secret.
845
846 The buffer length must be at least the length of the prime, or zero.
847
848 If the buffer length is nonzero, the length of the result is
849 returned when it is successfully calculated and copied in to the
850 buffer. When the buffer length is zero, the minimum required
851 buffer length is returned.
852
853 This function will return error EOPNOTSUPP if the key type is not
854 supported, error ENOKEY if the key could not be found, or error
855 EACCES if the key is not readable by the caller.
826 856
827=============== 857===============
828KERNEL SERVICES 858KERNEL SERVICES
diff --git a/include/uapi/linux/keyctl.h b/include/uapi/linux/keyctl.h
index 840cb990abe2..86eddd6241f3 100644
--- a/include/uapi/linux/keyctl.h
+++ b/include/uapi/linux/keyctl.h
@@ -12,6 +12,8 @@
12#ifndef _LINUX_KEYCTL_H 12#ifndef _LINUX_KEYCTL_H
13#define _LINUX_KEYCTL_H 13#define _LINUX_KEYCTL_H
14 14
15#include <linux/types.h>
16
15/* special process keyring shortcut IDs */ 17/* special process keyring shortcut IDs */
16#define KEY_SPEC_THREAD_KEYRING -1 /* - key ID for thread-specific keyring */ 18#define KEY_SPEC_THREAD_KEYRING -1 /* - key ID for thread-specific keyring */
17#define KEY_SPEC_PROCESS_KEYRING -2 /* - key ID for process-specific keyring */ 19#define KEY_SPEC_PROCESS_KEYRING -2 /* - key ID for process-specific keyring */
@@ -57,5 +59,13 @@
57#define KEYCTL_INSTANTIATE_IOV 20 /* instantiate a partially constructed key */ 59#define KEYCTL_INSTANTIATE_IOV 20 /* instantiate a partially constructed key */
58#define KEYCTL_INVALIDATE 21 /* invalidate a key */ 60#define KEYCTL_INVALIDATE 21 /* invalidate a key */
59#define KEYCTL_GET_PERSISTENT 22 /* get a user's persistent keyring */ 61#define KEYCTL_GET_PERSISTENT 22 /* get a user's persistent keyring */
62#define KEYCTL_DH_COMPUTE 23 /* Compute Diffie-Hellman values */
63
64/* keyctl structures */
65struct keyctl_dh_params {
66 __s32 private;
67 __s32 prime;
68 __s32 base;
69};
60 70
61#endif /* _LINUX_KEYCTL_H */ 71#endif /* _LINUX_KEYCTL_H */
diff --git a/security/keys/Kconfig b/security/keys/Kconfig
index 45828095080d..f826e8739023 100644
--- a/security/keys/Kconfig
+++ b/security/keys/Kconfig
@@ -85,3 +85,14 @@ config ENCRYPTED_KEYS
85 Userspace only ever sees/stores encrypted blobs. 85 Userspace only ever sees/stores encrypted blobs.
86 86
87 If you are unsure as to whether this is required, answer N. 87 If you are unsure as to whether this is required, answer N.
88
89config KEY_DH_OPERATIONS
90 bool "Diffie-Hellman operations on retained keys"
91 depends on KEYS
92 select MPILIB
93 help
94 This option provides support for calculating Diffie-Hellman
95 public keys and shared secrets using values stored as keys
96 in the kernel.
97
98 If you are unsure as to whether this is required, answer N.
diff --git a/security/keys/Makefile b/security/keys/Makefile
index dfb3a7bededf..1fd4a16e6daf 100644
--- a/security/keys/Makefile
+++ b/security/keys/Makefile
@@ -19,6 +19,7 @@ obj-$(CONFIG_KEYS_COMPAT) += compat.o
19obj-$(CONFIG_PROC_FS) += proc.o 19obj-$(CONFIG_PROC_FS) += proc.o
20obj-$(CONFIG_SYSCTL) += sysctl.o 20obj-$(CONFIG_SYSCTL) += sysctl.o
21obj-$(CONFIG_PERSISTENT_KEYRINGS) += persistent.o 21obj-$(CONFIG_PERSISTENT_KEYRINGS) += persistent.o
22obj-$(CONFIG_KEY_DH_OPERATIONS) += dh.o
22 23
23# 24#
24# Key types 25# Key types
diff --git a/security/keys/compat.c b/security/keys/compat.c
index 25430a3aa7f7..c8783b3b628c 100644
--- a/security/keys/compat.c
+++ b/security/keys/compat.c
@@ -132,6 +132,10 @@ COMPAT_SYSCALL_DEFINE5(keyctl, u32, option,
132 case KEYCTL_GET_PERSISTENT: 132 case KEYCTL_GET_PERSISTENT:
133 return keyctl_get_persistent(arg2, arg3); 133 return keyctl_get_persistent(arg2, arg3);
134 134
135 case KEYCTL_DH_COMPUTE:
136 return keyctl_dh_compute(compat_ptr(arg2), compat_ptr(arg3),
137 arg4);
138
135 default: 139 default:
136 return -EOPNOTSUPP; 140 return -EOPNOTSUPP;
137 } 141 }
diff --git a/security/keys/dh.c b/security/keys/dh.c
new file mode 100644
index 000000000000..880505a4b9f1
--- /dev/null
+++ b/security/keys/dh.c
@@ -0,0 +1,160 @@
1/* Crypto operations using stored keys
2 *
3 * Copyright (c) 2016, Intel Corporation
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version
8 * 2 of the License, or (at your option) any later version.
9 */
10
11#include <linux/mpi.h>
12#include <linux/slab.h>
13#include <linux/uaccess.h>
14#include <keys/user-type.h>
15#include "internal.h"
16
17/*
18 * Public key or shared secret generation function [RFC2631 sec 2.1.1]
19 *
20 * ya = g^xa mod p;
21 * or
22 * ZZ = yb^xa mod p;
23 *
24 * where xa is the local private key, ya is the local public key, g is
25 * the generator, p is the prime, yb is the remote public key, and ZZ
26 * is the shared secret.
27 *
28 * Both are the same calculation, so g or yb are the "base" and ya or
29 * ZZ are the "result".
30 */
31static int do_dh(MPI result, MPI base, MPI xa, MPI p)
32{
33 return mpi_powm(result, base, xa, p);
34}
35
36static ssize_t mpi_from_key(key_serial_t keyid, size_t maxlen, MPI *mpi)
37{
38 struct key *key;
39 key_ref_t key_ref;
40 long status;
41 ssize_t ret;
42
43 key_ref = lookup_user_key(keyid, 0, KEY_NEED_READ);
44 if (IS_ERR(key_ref)) {
45 ret = -ENOKEY;
46 goto error;
47 }
48
49 key = key_ref_to_ptr(key_ref);
50
51 ret = -EOPNOTSUPP;
52 if (key->type == &key_type_user) {
53 down_read(&key->sem);
54 status = key_validate(key);
55 if (status == 0) {
56 const struct user_key_payload *payload;
57
58 payload = user_key_payload(key);
59
60 if (maxlen == 0) {
61 *mpi = NULL;
62 ret = payload->datalen;
63 } else if (payload->datalen <= maxlen) {
64 *mpi = mpi_read_raw_data(payload->data,
65 payload->datalen);
66 if (*mpi)
67 ret = payload->datalen;
68 } else {
69 ret = -EINVAL;
70 }
71 }
72 up_read(&key->sem);
73 }
74
75 key_put(key);
76error:
77 return ret;
78}
79
80long keyctl_dh_compute(struct keyctl_dh_params __user *params,
81 char __user *buffer, size_t buflen)
82{
83 long ret;
84 MPI base, private, prime, result;
85 unsigned nbytes;
86 struct keyctl_dh_params pcopy;
87 uint8_t *kbuf;
88 ssize_t keylen;
89 size_t resultlen;
90
91 if (!params || (!buffer && buflen)) {
92 ret = -EINVAL;
93 goto out;
94 }
95 if (copy_from_user(&pcopy, params, sizeof(pcopy)) != 0) {
96 ret = -EFAULT;
97 goto out;
98 }
99
100 keylen = mpi_from_key(pcopy.prime, buflen, &prime);
101 if (keylen < 0 || !prime) {
102 /* buflen == 0 may be used to query the required buffer size,
103 * which is the prime key length.
104 */
105 ret = keylen;
106 goto out;
107 }
108
109 /* The result is never longer than the prime */
110 resultlen = keylen;
111
112 keylen = mpi_from_key(pcopy.base, SIZE_MAX, &base);
113 if (keylen < 0 || !base) {
114 ret = keylen;
115 goto error1;
116 }
117
118 keylen = mpi_from_key(pcopy.private, SIZE_MAX, &private);
119 if (keylen < 0 || !private) {
120 ret = keylen;
121 goto error2;
122 }
123
124 result = mpi_alloc(0);
125 if (!result) {
126 ret = -ENOMEM;
127 goto error3;
128 }
129
130 kbuf = kmalloc(resultlen, GFP_KERNEL);
131 if (!kbuf) {
132 ret = -ENOMEM;
133 goto error4;
134 }
135
136 ret = do_dh(result, base, private, prime);
137 if (ret)
138 goto error5;
139
140 ret = mpi_read_buffer(result, kbuf, resultlen, &nbytes, NULL);
141 if (ret != 0)
142 goto error5;
143
144 ret = nbytes;
145 if (copy_to_user(buffer, kbuf, nbytes) != 0)
146 ret = -EFAULT;
147
148error5:
149 kfree(kbuf);
150error4:
151 mpi_free(result);
152error3:
153 mpi_free(private);
154error2:
155 mpi_free(base);
156error1:
157 mpi_free(prime);
158out:
159 return ret;
160}
diff --git a/security/keys/internal.h b/security/keys/internal.h
index 5105c2c2da75..8ec7a528365d 100644
--- a/security/keys/internal.h
+++ b/security/keys/internal.h
@@ -15,6 +15,7 @@
15#include <linux/sched.h> 15#include <linux/sched.h>
16#include <linux/key-type.h> 16#include <linux/key-type.h>
17#include <linux/task_work.h> 17#include <linux/task_work.h>
18#include <linux/keyctl.h>
18 19
19struct iovec; 20struct iovec;
20 21
@@ -257,6 +258,17 @@ static inline long keyctl_get_persistent(uid_t uid, key_serial_t destring)
257} 258}
258#endif 259#endif
259 260
261#ifdef CONFIG_KEY_DH_OPERATIONS
262extern long keyctl_dh_compute(struct keyctl_dh_params __user *, char __user *,
263 size_t);
264#else
265static inline long keyctl_dh_compute(struct keyctl_dh_params __user *params,
266 char __user *buffer, size_t buflen)
267{
268 return -EOPNOTSUPP;
269}
270#endif
271
260/* 272/*
261 * Debugging key validation 273 * Debugging key validation
262 */ 274 */
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index ed73c6c1c326..3b135a0af344 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -1686,6 +1686,11 @@ SYSCALL_DEFINE5(keyctl, int, option, unsigned long, arg2, unsigned long, arg3,
1686 case KEYCTL_GET_PERSISTENT: 1686 case KEYCTL_GET_PERSISTENT:
1687 return keyctl_get_persistent((uid_t)arg2, (key_serial_t)arg3); 1687 return keyctl_get_persistent((uid_t)arg2, (key_serial_t)arg3);
1688 1688
1689 case KEYCTL_DH_COMPUTE:
1690 return keyctl_dh_compute((struct keyctl_dh_params __user *) arg2,
1691 (char __user *) arg3,
1692 (size_t) arg4);
1693
1689 default: 1694 default:
1690 return -EOPNOTSUPP; 1695 return -EOPNOTSUPP;
1691 } 1696 }