aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKirill Marinushkin <k.marinushkin@gmail.com>2016-04-12 14:54:58 -0400
committerDavid Howells <dhowells@redhat.com>2016-04-12 14:54:58 -0400
commit13100a72f40f5748a04017e0ab3df4cf27c809ef (patch)
tree71d7421ab174d63edb7fabc0d10571f028cc5a44
parent898de7d0f298e53568891f0ec3547b14fe8bb5d5 (diff)
Security: Keys: Big keys stored encrypted
Solved TODO task: big keys saved to shmem file are now stored encrypted. The encryption key is randomly generated and saved to payload[big_key_data]. Signed-off-by: Kirill Marinushkin <k.marinushkin@gmail.com> Signed-off-by: David Howells <dhowells@redhat.com>
-rw-r--r--security/keys/Kconfig4
-rw-r--r--security/keys/big_key.c198
2 files changed, 184 insertions, 18 deletions
diff --git a/security/keys/Kconfig b/security/keys/Kconfig
index fe4d74e126a7..45828095080d 100644
--- a/security/keys/Kconfig
+++ b/security/keys/Kconfig
@@ -41,6 +41,10 @@ config BIG_KEYS
41 bool "Large payload keys" 41 bool "Large payload keys"
42 depends on KEYS 42 depends on KEYS
43 depends on TMPFS 43 depends on TMPFS
44 select CRYPTO
45 select CRYPTO_AES
46 select CRYPTO_ECB
47 select CRYPTO_RNG
44 help 48 help
45 This option provides support for holding large keys within the kernel 49 This option provides support for holding large keys within the kernel
46 (for example Kerberos ticket caches). The data may be stored out to 50 (for example Kerberos ticket caches). The data may be stored out to
diff --git a/security/keys/big_key.c b/security/keys/big_key.c
index c721e398893a..9e443fccad4c 100644
--- a/security/keys/big_key.c
+++ b/security/keys/big_key.c
@@ -14,8 +14,10 @@
14#include <linux/file.h> 14#include <linux/file.h>
15#include <linux/shmem_fs.h> 15#include <linux/shmem_fs.h>
16#include <linux/err.h> 16#include <linux/err.h>
17#include <linux/scatterlist.h>
17#include <keys/user-type.h> 18#include <keys/user-type.h>
18#include <keys/big_key-type.h> 19#include <keys/big_key-type.h>
20#include <crypto/rng.h>
19 21
20/* 22/*
21 * Layout of key payload words. 23 * Layout of key payload words.
@@ -28,6 +30,14 @@ enum {
28}; 30};
29 31
30/* 32/*
33 * Crypto operation with big_key data
34 */
35enum big_key_op {
36 BIG_KEY_ENC,
37 BIG_KEY_DEC,
38};
39
40/*
31 * If the data is under this limit, there's no point creating a shm file to 41 * If the data is under this limit, there's no point creating a shm file to
32 * hold it as the permanently resident metadata for the shmem fs will be at 42 * hold it as the permanently resident metadata for the shmem fs will be at
33 * least as large as the data. 43 * least as large as the data.
@@ -35,6 +45,11 @@ enum {
35#define BIG_KEY_FILE_THRESHOLD (sizeof(struct inode) + sizeof(struct dentry)) 45#define BIG_KEY_FILE_THRESHOLD (sizeof(struct inode) + sizeof(struct dentry))
36 46
37/* 47/*
48 * Key size for big_key data encryption
49 */
50#define ENC_KEY_SIZE 16
51
52/*
38 * big_key defined keys take an arbitrary string as the description and an 53 * big_key defined keys take an arbitrary string as the description and an
39 * arbitrary blob of data as the payload 54 * arbitrary blob of data as the payload
40 */ 55 */
@@ -50,12 +65,62 @@ struct key_type key_type_big_key = {
50}; 65};
51 66
52/* 67/*
68 * Crypto names for big_key data encryption
69 */
70static const char big_key_rng_name[] = "stdrng";
71static const char big_key_alg_name[] = "ecb(aes)";
72
73/*
74 * Crypto algorithms for big_key data encryption
75 */
76static struct crypto_rng *big_key_rng;
77static struct crypto_blkcipher *big_key_blkcipher;
78
79/*
80 * Generate random key to encrypt big_key data
81 */
82static inline int big_key_gen_enckey(u8 *key)
83{
84 return crypto_rng_get_bytes(big_key_rng, key, ENC_KEY_SIZE);
85}
86
87/*
88 * Encrypt/decrypt big_key data
89 */
90static int big_key_crypt(enum big_key_op op, u8 *data, size_t datalen, u8 *key)
91{
92 int ret = -EINVAL;
93 struct scatterlist sgio;
94 struct blkcipher_desc desc;
95
96 if (crypto_blkcipher_setkey(big_key_blkcipher, key, ENC_KEY_SIZE)) {
97 ret = -EAGAIN;
98 goto error;
99 }
100
101 desc.flags = 0;
102 desc.tfm = big_key_blkcipher;
103
104 sg_init_one(&sgio, data, datalen);
105
106 if (op == BIG_KEY_ENC)
107 ret = crypto_blkcipher_encrypt(&desc, &sgio, &sgio, datalen);
108 else
109 ret = crypto_blkcipher_decrypt(&desc, &sgio, &sgio, datalen);
110
111error:
112 return ret;
113}
114
115/*
53 * Preparse a big key 116 * Preparse a big key
54 */ 117 */
55int big_key_preparse(struct key_preparsed_payload *prep) 118int big_key_preparse(struct key_preparsed_payload *prep)
56{ 119{
57 struct path *path = (struct path *)&prep->payload.data[big_key_path]; 120 struct path *path = (struct path *)&prep->payload.data[big_key_path];
58 struct file *file; 121 struct file *file;
122 u8 *enckey;
123 u8 *data = NULL;
59 ssize_t written; 124 ssize_t written;
60 size_t datalen = prep->datalen; 125 size_t datalen = prep->datalen;
61 int ret; 126 int ret;
@@ -73,16 +138,43 @@ int big_key_preparse(struct key_preparsed_payload *prep)
73 /* Create a shmem file to store the data in. This will permit the data 138 /* Create a shmem file to store the data in. This will permit the data
74 * to be swapped out if needed. 139 * to be swapped out if needed.
75 * 140 *
76 * TODO: Encrypt the stored data with a temporary key. 141 * File content is stored encrypted with randomly generated key.
77 */ 142 */
78 file = shmem_kernel_file_setup("", datalen, 0); 143 size_t enclen = ALIGN(datalen, crypto_blkcipher_blocksize(big_key_blkcipher));
144
145 /* prepare aligned data to encrypt */
146 data = kmalloc(enclen, GFP_KERNEL);
147 if (!data)
148 return -ENOMEM;
149
150 memcpy(data, prep->data, datalen);
151 memset(data + datalen, 0x00, enclen - datalen);
152
153 /* generate random key */
154 enckey = kmalloc(ENC_KEY_SIZE, GFP_KERNEL);
155 if (!enckey) {
156 ret = -ENOMEM;
157 goto error;
158 }
159
160 ret = big_key_gen_enckey(enckey);
161 if (ret)
162 goto err_enckey;
163
164 /* encrypt aligned data */
165 ret = big_key_crypt(BIG_KEY_ENC, data, enclen, enckey);
166 if (ret)
167 goto err_enckey;
168
169 /* save aligned data to file */
170 file = shmem_kernel_file_setup("", enclen, 0);
79 if (IS_ERR(file)) { 171 if (IS_ERR(file)) {
80 ret = PTR_ERR(file); 172 ret = PTR_ERR(file);
81 goto error; 173 goto err_enckey;
82 } 174 }
83 175
84 written = kernel_write(file, prep->data, prep->datalen, 0); 176 written = kernel_write(file, data, enclen, 0);
85 if (written != datalen) { 177 if (written != enclen) {
86 ret = written; 178 ret = written;
87 if (written >= 0) 179 if (written >= 0)
88 ret = -ENOMEM; 180 ret = -ENOMEM;
@@ -92,12 +184,15 @@ int big_key_preparse(struct key_preparsed_payload *prep)
92 /* Pin the mount and dentry to the key so that we can open it again 184 /* Pin the mount and dentry to the key so that we can open it again
93 * later 185 * later
94 */ 186 */
187 prep->payload.data[big_key_data] = enckey;
95 *path = file->f_path; 188 *path = file->f_path;
96 path_get(path); 189 path_get(path);
97 fput(file); 190 fput(file);
191 kfree(data);
98 } else { 192 } else {
99 /* Just store the data in a buffer */ 193 /* Just store the data in a buffer */
100 void *data = kmalloc(datalen, GFP_KERNEL); 194 void *data = kmalloc(datalen, GFP_KERNEL);
195
101 if (!data) 196 if (!data)
102 return -ENOMEM; 197 return -ENOMEM;
103 198
@@ -108,7 +203,10 @@ int big_key_preparse(struct key_preparsed_payload *prep)
108 203
109err_fput: 204err_fput:
110 fput(file); 205 fput(file);
206err_enckey:
207 kfree(enckey);
111error: 208error:
209 kfree(data);
112 return ret; 210 return ret;
113} 211}
114 212
@@ -119,10 +217,10 @@ void big_key_free_preparse(struct key_preparsed_payload *prep)
119{ 217{
120 if (prep->datalen > BIG_KEY_FILE_THRESHOLD) { 218 if (prep->datalen > BIG_KEY_FILE_THRESHOLD) {
121 struct path *path = (struct path *)&prep->payload.data[big_key_path]; 219 struct path *path = (struct path *)&prep->payload.data[big_key_path];
220
122 path_put(path); 221 path_put(path);
123 } else {
124 kfree(prep->payload.data[big_key_data]);
125 } 222 }
223 kfree(prep->payload.data[big_key_data]);
126} 224}
127 225
128/* 226/*
@@ -147,15 +245,15 @@ void big_key_destroy(struct key *key)
147{ 245{
148 size_t datalen = (size_t)key->payload.data[big_key_len]; 246 size_t datalen = (size_t)key->payload.data[big_key_len];
149 247
150 if (datalen) { 248 if (datalen > BIG_KEY_FILE_THRESHOLD) {
151 struct path *path = (struct path *)&key->payload.data[big_key_path]; 249 struct path *path = (struct path *)&key->payload.data[big_key_path];
250
152 path_put(path); 251 path_put(path);
153 path->mnt = NULL; 252 path->mnt = NULL;
154 path->dentry = NULL; 253 path->dentry = NULL;
155 } else {
156 kfree(key->payload.data[big_key_data]);
157 key->payload.data[big_key_data] = NULL;
158 } 254 }
255 kfree(key->payload.data[big_key_data]);
256 key->payload.data[big_key_data] = NULL;
159} 257}
160 258
161/* 259/*
@@ -188,17 +286,41 @@ long big_key_read(const struct key *key, char __user *buffer, size_t buflen)
188 if (datalen > BIG_KEY_FILE_THRESHOLD) { 286 if (datalen > BIG_KEY_FILE_THRESHOLD) {
189 struct path *path = (struct path *)&key->payload.data[big_key_path]; 287 struct path *path = (struct path *)&key->payload.data[big_key_path];
190 struct file *file; 288 struct file *file;
191 loff_t pos; 289 u8 *data;
290 u8 *enckey = (u8 *)key->payload.data[big_key_data];
291 size_t enclen = ALIGN(datalen, crypto_blkcipher_blocksize(big_key_blkcipher));
292
293 data = kmalloc(enclen, GFP_KERNEL);
294 if (!data)
295 return -ENOMEM;
192 296
193 file = dentry_open(path, O_RDONLY, current_cred()); 297 file = dentry_open(path, O_RDONLY, current_cred());
194 if (IS_ERR(file)) 298 if (IS_ERR(file)) {
195 return PTR_ERR(file); 299 ret = PTR_ERR(file);
300 goto error;
301 }
196 302
197 pos = 0; 303 /* read file to kernel and decrypt */
198 ret = vfs_read(file, buffer, datalen, &pos); 304 ret = kernel_read(file, 0, data, enclen);
199 fput(file); 305 if (ret >= 0 && ret != enclen) {
200 if (ret >= 0 && ret != datalen)
201 ret = -EIO; 306 ret = -EIO;
307 goto err_fput;
308 }
309
310 ret = big_key_crypt(BIG_KEY_DEC, data, enclen, enckey);
311 if (ret)
312 goto err_fput;
313
314 ret = datalen;
315
316 /* copy decrypted data to user */
317 if (copy_to_user(buffer, data, datalen) != 0)
318 ret = -EFAULT;
319
320err_fput:
321 fput(file);
322error:
323 kfree(data);
202 } else { 324 } else {
203 ret = datalen; 325 ret = datalen;
204 if (copy_to_user(buffer, key->payload.data[big_key_data], 326 if (copy_to_user(buffer, key->payload.data[big_key_data],
@@ -209,8 +331,48 @@ long big_key_read(const struct key *key, char __user *buffer, size_t buflen)
209 return ret; 331 return ret;
210} 332}
211 333
334/*
335 * Register key type
336 */
212static int __init big_key_init(void) 337static int __init big_key_init(void)
213{ 338{
214 return register_key_type(&key_type_big_key); 339 return register_key_type(&key_type_big_key);
215} 340}
341
342/*
343 * Initialize big_key crypto and RNG algorithms
344 */
345static int __init big_key_crypto_init(void)
346{
347 int ret = -EINVAL;
348
349 /* init RNG */
350 big_key_rng = crypto_alloc_rng(big_key_rng_name, 0, 0);
351 if (IS_ERR(big_key_rng)) {
352 big_key_rng = NULL;
353 return -EFAULT;
354 }
355
356 /* seed RNG */
357 ret = crypto_rng_reset(big_key_rng, NULL, crypto_rng_seedsize(big_key_rng));
358 if (ret)
359 goto error;
360
361 /* init block cipher */
362 big_key_blkcipher = crypto_alloc_blkcipher(big_key_alg_name, 0, 0);
363 if (IS_ERR(big_key_blkcipher)) {
364 big_key_blkcipher = NULL;
365 ret = -EFAULT;
366 goto error;
367 }
368
369 return 0;
370
371error:
372 crypto_free_rng(big_key_rng);
373 big_key_rng = NULL;
374 return ret;
375}
376
216device_initcall(big_key_init); 377device_initcall(big_key_init);
378late_initcall(big_key_crypto_init);