aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephan Mueller <smueller@chronox.de>2016-08-19 14:39:09 -0400
committerDavid Howells <dhowells@redhat.com>2017-04-04 17:33:38 -0400
commitf1c316a3ab9d24df6022682422fe897492f2c0c8 (patch)
tree369b53c45d1f0c2bbd4c6f745cb9a694e1b28cbe
parentf0df90cd7cf2f4a8195c3fff0d2f4c85088fd39c (diff)
KEYS: add SP800-56A KDF support for DH
SP800-56A defines the use of DH with key derivation function based on a counter. The input to the KDF is defined as (DH shared secret || other information). The value for the "other information" is to be provided by the caller. The KDF is implemented using the hash support from the kernel crypto API. The implementation uses the symmetric hash support as the input to the hash operation is usually very small. The caller is allowed to specify the hash name that he wants to use to derive the key material allowing the use of all supported hashes provided with the kernel crypto API. As the KDF implements the proper truncation of the DH shared secret to the requested size, this patch fills the caller buffer up to its size. The patch is tested with a new test added to the keyutils user space code which uses a CAVS test vector testing the compliance with SP800-56A. Signed-off-by: Stephan Mueller <smueller@chronox.de> Signed-off-by: David Howells <dhowells@redhat.com>
-rw-r--r--Documentation/security/keys.txt34
-rw-r--r--include/linux/compat.h7
-rw-r--r--include/uapi/linux/keyctl.h7
-rw-r--r--security/keys/Kconfig1
-rw-r--r--security/keys/Makefile3
-rw-r--r--security/keys/compat.c5
-rw-r--r--security/keys/compat_dh.c38
-rw-r--r--security/keys/dh.c220
-rw-r--r--security/keys/internal.h24
-rw-r--r--security/keys/keyctl.c2
10 files changed, 315 insertions, 26 deletions
diff --git a/Documentation/security/keys.txt b/Documentation/security/keys.txt
index 5f554aab8751..cd5019934d7f 100644
--- a/Documentation/security/keys.txt
+++ b/Documentation/security/keys.txt
@@ -827,7 +827,7 @@ The keyctl syscall functions are:
827 827
828 long keyctl(KEYCTL_DH_COMPUTE, struct keyctl_dh_params *params, 828 long keyctl(KEYCTL_DH_COMPUTE, struct keyctl_dh_params *params,
829 char *buffer, size_t buflen, 829 char *buffer, size_t buflen,
830 void *reserved); 830 struct keyctl_kdf_params *kdf);
831 831
832 The params struct contains serial numbers for three keys: 832 The params struct contains serial numbers for three keys:
833 833
@@ -844,18 +844,36 @@ The keyctl syscall functions are:
844 public key. If the base is the remote public key, the result is 844 public key. If the base is the remote public key, the result is
845 the shared secret. 845 the shared secret.
846 846
847 The reserved argument must be set to NULL. 847 If the parameter kdf is NULL, the following applies:
848 848
849 The buffer length must be at least the length of the prime, or zero. 849 - The buffer length must be at least the length of the prime, or zero.
850 850
851 If the buffer length is nonzero, the length of the result is 851 - If the buffer length is nonzero, the length of the result is
852 returned when it is successfully calculated and copied in to the 852 returned when it is successfully calculated and copied in to the
853 buffer. When the buffer length is zero, the minimum required 853 buffer. When the buffer length is zero, the minimum required
854 buffer length is returned. 854 buffer length is returned.
855
856 The kdf parameter allows the caller to apply a key derivation function
857 (KDF) on the Diffie-Hellman computation where only the result
858 of the KDF is returned to the caller. The KDF is characterized with
859 struct keyctl_kdf_params as follows:
860
861 - char *hashname specifies the NUL terminated string identifying
862 the hash used from the kernel crypto API and applied for the KDF
863 operation. The KDF implemenation complies with SP800-56A as well
864 as with SP800-108 (the counter KDF).
865
866 - char *otherinfo specifies the OtherInfo data as documented in
867 SP800-56A section 5.8.1.2. The length of the buffer is given with
868 otherinfolen. The format of OtherInfo is defined by the caller.
869 The otherinfo pointer may be NULL if no OtherInfo shall be used.
855 870
856 This function will return error EOPNOTSUPP if the key type is not 871 This function will return error EOPNOTSUPP if the key type is not
857 supported, error ENOKEY if the key could not be found, or error 872 supported, error ENOKEY if the key could not be found, or error
858 EACCES if the key is not readable by the caller. 873 EACCES if the key is not readable by the caller. In addition, the
874 function will return EMSGSIZE when the parameter kdf is non-NULL
875 and either the buffer length or the OtherInfo length exceeds the
876 allowed length.
859 877
860 (*) Restrict keyring linkage 878 (*) Restrict keyring linkage
861 879
diff --git a/include/linux/compat.h b/include/linux/compat.h
index aef47be2a5c1..993c87182e02 100644
--- a/include/linux/compat.h
+++ b/include/linux/compat.h
@@ -295,6 +295,13 @@ struct compat_old_sigaction {
295}; 295};
296#endif 296#endif
297 297
298struct compat_keyctl_kdf_params {
299 compat_uptr_t hashname;
300 compat_uptr_t otherinfo;
301 __u32 otherinfolen;
302 __u32 __spare[8];
303};
304
298struct compat_statfs; 305struct compat_statfs;
299struct compat_statfs64; 306struct compat_statfs64;
300struct compat_old_linux_dirent; 307struct compat_old_linux_dirent;
diff --git a/include/uapi/linux/keyctl.h b/include/uapi/linux/keyctl.h
index ff79c44e49a3..201c6644b237 100644
--- a/include/uapi/linux/keyctl.h
+++ b/include/uapi/linux/keyctl.h
@@ -69,4 +69,11 @@ struct keyctl_dh_params {
69 __s32 base; 69 __s32 base;
70}; 70};
71 71
72struct keyctl_kdf_params {
73 char *hashname;
74 char *otherinfo;
75 __u32 otherinfolen;
76 __u32 __spare[8];
77};
78
72#endif /* _LINUX_KEYCTL_H */ 79#endif /* _LINUX_KEYCTL_H */
diff --git a/security/keys/Kconfig b/security/keys/Kconfig
index d942c7c2bc0a..4ac1b83a23f8 100644
--- a/security/keys/Kconfig
+++ b/security/keys/Kconfig
@@ -90,6 +90,7 @@ config KEY_DH_OPERATIONS
90 bool "Diffie-Hellman operations on retained keys" 90 bool "Diffie-Hellman operations on retained keys"
91 depends on KEYS 91 depends on KEYS
92 select MPILIB 92 select MPILIB
93 select CRYPTO_HASH
93 help 94 help
94 This option provides support for calculating Diffie-Hellman 95 This option provides support for calculating Diffie-Hellman
95 public keys and shared secrets using values stored as keys 96 public keys and shared secrets using values stored as keys
diff --git a/security/keys/Makefile b/security/keys/Makefile
index 1fd4a16e6daf..57dff0c15809 100644
--- a/security/keys/Makefile
+++ b/security/keys/Makefile
@@ -15,7 +15,8 @@ obj-y := \
15 request_key.o \ 15 request_key.o \
16 request_key_auth.o \ 16 request_key_auth.o \
17 user_defined.o 17 user_defined.o
18obj-$(CONFIG_KEYS_COMPAT) += compat.o 18compat-obj-$(CONFIG_KEY_DH_OPERATIONS) += compat_dh.o
19obj-$(CONFIG_KEYS_COMPAT) += compat.o $(compat-obj-y)
19obj-$(CONFIG_PROC_FS) += proc.o 20obj-$(CONFIG_PROC_FS) += proc.o
20obj-$(CONFIG_SYSCTL) += sysctl.o 21obj-$(CONFIG_SYSCTL) += sysctl.o
21obj-$(CONFIG_PERSISTENT_KEYRINGS) += persistent.o 22obj-$(CONFIG_PERSISTENT_KEYRINGS) += persistent.o
diff --git a/security/keys/compat.c b/security/keys/compat.c
index bb98f2b8dd7d..e87c89c0177c 100644
--- a/security/keys/compat.c
+++ b/security/keys/compat.c
@@ -133,8 +133,9 @@ COMPAT_SYSCALL_DEFINE5(keyctl, u32, option,
133 return keyctl_get_persistent(arg2, arg3); 133 return keyctl_get_persistent(arg2, arg3);
134 134
135 case KEYCTL_DH_COMPUTE: 135 case KEYCTL_DH_COMPUTE:
136 return keyctl_dh_compute(compat_ptr(arg2), compat_ptr(arg3), 136 return compat_keyctl_dh_compute(compat_ptr(arg2),
137 arg4, compat_ptr(arg5)); 137 compat_ptr(arg3),
138 arg4, compat_ptr(arg5));
138 139
139 case KEYCTL_RESTRICT_KEYRING: 140 case KEYCTL_RESTRICT_KEYRING:
140 return keyctl_restrict_keyring(arg2, compat_ptr(arg3), 141 return keyctl_restrict_keyring(arg2, compat_ptr(arg3),
diff --git a/security/keys/compat_dh.c b/security/keys/compat_dh.c
new file mode 100644
index 000000000000..a6a659b6bcb6
--- /dev/null
+++ b/security/keys/compat_dh.c
@@ -0,0 +1,38 @@
1/* 32-bit compatibility syscall for 64-bit systems for DH operations
2 *
3 * Copyright (C) 2016 Stephan Mueller <smueller@chronox.de>
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/uaccess.h>
12
13#include "internal.h"
14
15/*
16 * Perform the DH computation or DH based key derivation.
17 *
18 * If successful, 0 will be returned.
19 */
20long compat_keyctl_dh_compute(struct keyctl_dh_params __user *params,
21 char __user *buffer, size_t buflen,
22 struct compat_keyctl_kdf_params __user *kdf)
23{
24 struct keyctl_kdf_params kdfcopy;
25 struct compat_keyctl_kdf_params compat_kdfcopy;
26
27 if (!kdf)
28 return __keyctl_dh_compute(params, buffer, buflen, NULL);
29
30 if (copy_from_user(&compat_kdfcopy, kdf, sizeof(compat_kdfcopy)) != 0)
31 return -EFAULT;
32
33 kdfcopy.hashname = compat_ptr(compat_kdfcopy.hashname);
34 kdfcopy.otherinfo = compat_ptr(compat_kdfcopy.otherinfo);
35 kdfcopy.otherinfolen = compat_kdfcopy.otherinfolen;
36
37 return __keyctl_dh_compute(params, buffer, buflen, &kdfcopy);
38}
diff --git a/security/keys/dh.c b/security/keys/dh.c
index 893af4c45038..e603bd912e4c 100644
--- a/security/keys/dh.c
+++ b/security/keys/dh.c
@@ -11,6 +11,8 @@
11#include <linux/mpi.h> 11#include <linux/mpi.h>
12#include <linux/slab.h> 12#include <linux/slab.h>
13#include <linux/uaccess.h> 13#include <linux/uaccess.h>
14#include <linux/crypto.h>
15#include <crypto/hash.h>
14#include <keys/user-type.h> 16#include <keys/user-type.h>
15#include "internal.h" 17#include "internal.h"
16 18
@@ -77,9 +79,146 @@ error:
77 return ret; 79 return ret;
78} 80}
79 81
80long keyctl_dh_compute(struct keyctl_dh_params __user *params, 82struct kdf_sdesc {
81 char __user *buffer, size_t buflen, 83 struct shash_desc shash;
82 void __user *reserved) 84 char ctx[];
85};
86
87static int kdf_alloc(struct kdf_sdesc **sdesc_ret, char *hashname)
88{
89 struct crypto_shash *tfm;
90 struct kdf_sdesc *sdesc;
91 int size;
92
93 /* allocate synchronous hash */
94 tfm = crypto_alloc_shash(hashname, 0, 0);
95 if (IS_ERR(tfm)) {
96 pr_info("could not allocate digest TFM handle %s\n", hashname);
97 return PTR_ERR(tfm);
98 }
99
100 size = sizeof(struct shash_desc) + crypto_shash_descsize(tfm);
101 sdesc = kmalloc(size, GFP_KERNEL);
102 if (!sdesc)
103 return -ENOMEM;
104 sdesc->shash.tfm = tfm;
105 sdesc->shash.flags = 0x0;
106
107 *sdesc_ret = sdesc;
108
109 return 0;
110}
111
112static void kdf_dealloc(struct kdf_sdesc *sdesc)
113{
114 if (!sdesc)
115 return;
116
117 if (sdesc->shash.tfm)
118 crypto_free_shash(sdesc->shash.tfm);
119
120 kzfree(sdesc);
121}
122
123/* convert 32 bit integer into its string representation */
124static inline void crypto_kw_cpu_to_be32(u32 val, u8 *buf)
125{
126 __be32 *a = (__be32 *)buf;
127
128 *a = cpu_to_be32(val);
129}
130
131/*
132 * Implementation of the KDF in counter mode according to SP800-108 section 5.1
133 * as well as SP800-56A section 5.8.1 (Single-step KDF).
134 *
135 * SP800-56A:
136 * The src pointer is defined as Z || other info where Z is the shared secret
137 * from DH and other info is an arbitrary string (see SP800-56A section
138 * 5.8.1.2).
139 */
140static int kdf_ctr(struct kdf_sdesc *sdesc, const u8 *src, unsigned int slen,
141 u8 *dst, unsigned int dlen)
142{
143 struct shash_desc *desc = &sdesc->shash;
144 unsigned int h = crypto_shash_digestsize(desc->tfm);
145 int err = 0;
146 u8 *dst_orig = dst;
147 u32 i = 1;
148 u8 iteration[sizeof(u32)];
149
150 while (dlen) {
151 err = crypto_shash_init(desc);
152 if (err)
153 goto err;
154
155 crypto_kw_cpu_to_be32(i, iteration);
156 err = crypto_shash_update(desc, iteration, sizeof(u32));
157 if (err)
158 goto err;
159
160 if (src && slen) {
161 err = crypto_shash_update(desc, src, slen);
162 if (err)
163 goto err;
164 }
165
166 if (dlen < h) {
167 u8 tmpbuffer[h];
168
169 err = crypto_shash_final(desc, tmpbuffer);
170 if (err)
171 goto err;
172 memcpy(dst, tmpbuffer, dlen);
173 memzero_explicit(tmpbuffer, h);
174 return 0;
175 } else {
176 err = crypto_shash_final(desc, dst);
177 if (err)
178 goto err;
179
180 dlen -= h;
181 dst += h;
182 i++;
183 }
184 }
185
186 return 0;
187
188err:
189 memzero_explicit(dst_orig, dlen);
190 return err;
191}
192
193static int keyctl_dh_compute_kdf(struct kdf_sdesc *sdesc,
194 char __user *buffer, size_t buflen,
195 uint8_t *kbuf, size_t kbuflen)
196{
197 uint8_t *outbuf = NULL;
198 int ret;
199
200 outbuf = kmalloc(buflen, GFP_KERNEL);
201 if (!outbuf) {
202 ret = -ENOMEM;
203 goto err;
204 }
205
206 ret = kdf_ctr(sdesc, kbuf, kbuflen, outbuf, buflen);
207 if (ret)
208 goto err;
209
210 ret = buflen;
211 if (copy_to_user(buffer, outbuf, buflen) != 0)
212 ret = -EFAULT;
213
214err:
215 kzfree(outbuf);
216 return ret;
217}
218
219long __keyctl_dh_compute(struct keyctl_dh_params __user *params,
220 char __user *buffer, size_t buflen,
221 struct keyctl_kdf_params *kdfcopy)
83{ 222{
84 long ret; 223 long ret;
85 MPI base, private, prime, result; 224 MPI base, private, prime, result;
@@ -88,6 +227,7 @@ long keyctl_dh_compute(struct keyctl_dh_params __user *params,
88 uint8_t *kbuf; 227 uint8_t *kbuf;
89 ssize_t keylen; 228 ssize_t keylen;
90 size_t resultlen; 229 size_t resultlen;
230 struct kdf_sdesc *sdesc = NULL;
91 231
92 if (!params || (!buffer && buflen)) { 232 if (!params || (!buffer && buflen)) {
93 ret = -EINVAL; 233 ret = -EINVAL;
@@ -98,12 +238,34 @@ long keyctl_dh_compute(struct keyctl_dh_params __user *params,
98 goto out; 238 goto out;
99 } 239 }
100 240
101 if (reserved) { 241 if (kdfcopy) {
102 ret = -EINVAL; 242 char *hashname;
103 goto out; 243
244 if (buflen > KEYCTL_KDF_MAX_OUTPUT_LEN ||
245 kdfcopy->otherinfolen > KEYCTL_KDF_MAX_OI_LEN) {
246 ret = -EMSGSIZE;
247 goto out;
248 }
249
250 /* get KDF name string */
251 hashname = strndup_user(kdfcopy->hashname, CRYPTO_MAX_ALG_NAME);
252 if (IS_ERR(hashname)) {
253 ret = PTR_ERR(hashname);
254 goto out;
255 }
256
257 /* allocate KDF from the kernel crypto API */
258 ret = kdf_alloc(&sdesc, hashname);
259 kfree(hashname);
260 if (ret)
261 goto out;
104 } 262 }
105 263
106 keylen = mpi_from_key(pcopy.prime, buflen, &prime); 264 /*
265 * If the caller requests postprocessing with a KDF, allow an
266 * arbitrary output buffer size since the KDF ensures proper truncation.
267 */
268 keylen = mpi_from_key(pcopy.prime, kdfcopy ? SIZE_MAX : buflen, &prime);
107 if (keylen < 0 || !prime) { 269 if (keylen < 0 || !prime) {
108 /* buflen == 0 may be used to query the required buffer size, 270 /* buflen == 0 may be used to query the required buffer size,
109 * which is the prime key length. 271 * which is the prime key length.
@@ -133,12 +295,25 @@ long keyctl_dh_compute(struct keyctl_dh_params __user *params,
133 goto error3; 295 goto error3;
134 } 296 }
135 297
136 kbuf = kmalloc(resultlen, GFP_KERNEL); 298 /* allocate space for DH shared secret and SP800-56A otherinfo */
299 kbuf = kmalloc(kdfcopy ? (resultlen + kdfcopy->otherinfolen) : resultlen,
300 GFP_KERNEL);
137 if (!kbuf) { 301 if (!kbuf) {
138 ret = -ENOMEM; 302 ret = -ENOMEM;
139 goto error4; 303 goto error4;
140 } 304 }
141 305
306 /*
307 * Concatenate SP800-56A otherinfo past DH shared secret -- the
308 * input to the KDF is (DH shared secret || otherinfo)
309 */
310 if (kdfcopy && kdfcopy->otherinfo &&
311 copy_from_user(kbuf + resultlen, kdfcopy->otherinfo,
312 kdfcopy->otherinfolen) != 0) {
313 ret = -EFAULT;
314 goto error5;
315 }
316
142 ret = do_dh(result, base, private, prime); 317 ret = do_dh(result, base, private, prime);
143 if (ret) 318 if (ret)
144 goto error5; 319 goto error5;
@@ -147,12 +322,17 @@ long keyctl_dh_compute(struct keyctl_dh_params __user *params,
147 if (ret != 0) 322 if (ret != 0)
148 goto error5; 323 goto error5;
149 324
150 ret = nbytes; 325 if (kdfcopy) {
151 if (copy_to_user(buffer, kbuf, nbytes) != 0) 326 ret = keyctl_dh_compute_kdf(sdesc, buffer, buflen, kbuf,
152 ret = -EFAULT; 327 resultlen + kdfcopy->otherinfolen);
328 } else {
329 ret = nbytes;
330 if (copy_to_user(buffer, kbuf, nbytes) != 0)
331 ret = -EFAULT;
332 }
153 333
154error5: 334error5:
155 kfree(kbuf); 335 kzfree(kbuf);
156error4: 336error4:
157 mpi_free(result); 337 mpi_free(result);
158error3: 338error3:
@@ -162,5 +342,21 @@ error2:
162error1: 342error1:
163 mpi_free(prime); 343 mpi_free(prime);
164out: 344out:
345 kdf_dealloc(sdesc);
165 return ret; 346 return ret;
166} 347}
348
349long keyctl_dh_compute(struct keyctl_dh_params __user *params,
350 char __user *buffer, size_t buflen,
351 struct keyctl_kdf_params __user *kdf)
352{
353 struct keyctl_kdf_params kdfcopy;
354
355 if (!kdf)
356 return __keyctl_dh_compute(params, buffer, buflen, NULL);
357
358 if (copy_from_user(&kdfcopy, kdf, sizeof(kdfcopy)) != 0)
359 return -EFAULT;
360
361 return __keyctl_dh_compute(params, buffer, buflen, &kdfcopy);
362}
diff --git a/security/keys/internal.h b/security/keys/internal.h
index 6ce016314897..c0f8682eba69 100644
--- a/security/keys/internal.h
+++ b/security/keys/internal.h
@@ -18,6 +18,7 @@
18#include <linux/task_work.h> 18#include <linux/task_work.h>
19#include <linux/keyctl.h> 19#include <linux/keyctl.h>
20#include <linux/refcount.h> 20#include <linux/refcount.h>
21#include <linux/compat.h>
21 22
22struct iovec; 23struct iovec;
23 24
@@ -267,15 +268,34 @@ static inline long keyctl_get_persistent(uid_t uid, key_serial_t destring)
267 268
268#ifdef CONFIG_KEY_DH_OPERATIONS 269#ifdef CONFIG_KEY_DH_OPERATIONS
269extern long keyctl_dh_compute(struct keyctl_dh_params __user *, char __user *, 270extern long keyctl_dh_compute(struct keyctl_dh_params __user *, char __user *,
270 size_t, void __user *); 271 size_t, struct keyctl_kdf_params __user *);
272extern long __keyctl_dh_compute(struct keyctl_dh_params __user *, char __user *,
273 size_t, struct keyctl_kdf_params *);
274#ifdef CONFIG_KEYS_COMPAT
275extern long compat_keyctl_dh_compute(struct keyctl_dh_params __user *params,
276 char __user *buffer, size_t buflen,
277 struct compat_keyctl_kdf_params __user *kdf);
278#endif
279#define KEYCTL_KDF_MAX_OUTPUT_LEN 1024 /* max length of KDF output */
280#define KEYCTL_KDF_MAX_OI_LEN 64 /* max length of otherinfo */
271#else 281#else
272static inline long keyctl_dh_compute(struct keyctl_dh_params __user *params, 282static inline long keyctl_dh_compute(struct keyctl_dh_params __user *params,
273 char __user *buffer, size_t buflen, 283 char __user *buffer, size_t buflen,
274 void __user *reserved) 284 struct keyctl_kdf_params __user *kdf)
285{
286 return -EOPNOTSUPP;
287}
288
289#ifdef CONFIG_KEYS_COMPAT
290static inline long compat_keyctl_dh_compute(
291 struct keyctl_dh_params __user *params,
292 char __user *buffer, size_t buflen,
293 struct keyctl_kdf_params __user *kdf)
275{ 294{
276 return -EOPNOTSUPP; 295 return -EOPNOTSUPP;
277} 296}
278#endif 297#endif
298#endif
279 299
280/* 300/*
281 * Debugging key validation 301 * Debugging key validation
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index 6ee2826a2d06..10fcea154c0f 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -1744,7 +1744,7 @@ SYSCALL_DEFINE5(keyctl, int, option, unsigned long, arg2, unsigned long, arg3,
1744 case KEYCTL_DH_COMPUTE: 1744 case KEYCTL_DH_COMPUTE:
1745 return keyctl_dh_compute((struct keyctl_dh_params __user *) arg2, 1745 return keyctl_dh_compute((struct keyctl_dh_params __user *) arg2,
1746 (char __user *) arg3, (size_t) arg4, 1746 (char __user *) arg3, (size_t) arg4,
1747 (void __user *) arg5); 1747 (struct keyctl_kdf_params __user *) arg5);
1748 1748
1749 case KEYCTL_RESTRICT_KEYRING: 1749 case KEYCTL_RESTRICT_KEYRING:
1750 return keyctl_restrict_keyring((key_serial_t) arg2, 1750 return keyctl_restrict_keyring((key_serial_t) arg2,