diff options
Diffstat (limited to 'security/keys/big_key.c')
-rw-r--r-- | security/keys/big_key.c | 139 |
1 files changed, 65 insertions, 74 deletions
diff --git a/security/keys/big_key.c b/security/keys/big_key.c index 6acb00f6f22c..e607830b6154 100644 --- a/security/keys/big_key.c +++ b/security/keys/big_key.c | |||
@@ -1,5 +1,6 @@ | |||
1 | /* Large capacity key type | 1 | /* Large capacity key type |
2 | * | 2 | * |
3 | * Copyright (C) 2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. | ||
3 | * Copyright (C) 2013 Red Hat, Inc. All Rights Reserved. | 4 | * Copyright (C) 2013 Red Hat, Inc. All Rights Reserved. |
4 | * Written by David Howells (dhowells@redhat.com) | 5 | * Written by David Howells (dhowells@redhat.com) |
5 | * | 6 | * |
@@ -16,10 +17,10 @@ | |||
16 | #include <linux/shmem_fs.h> | 17 | #include <linux/shmem_fs.h> |
17 | #include <linux/err.h> | 18 | #include <linux/err.h> |
18 | #include <linux/scatterlist.h> | 19 | #include <linux/scatterlist.h> |
20 | #include <linux/random.h> | ||
19 | #include <keys/user-type.h> | 21 | #include <keys/user-type.h> |
20 | #include <keys/big_key-type.h> | 22 | #include <keys/big_key-type.h> |
21 | #include <crypto/rng.h> | 23 | #include <crypto/aead.h> |
22 | #include <crypto/skcipher.h> | ||
23 | 24 | ||
24 | /* | 25 | /* |
25 | * Layout of key payload words. | 26 | * Layout of key payload words. |
@@ -49,7 +50,12 @@ enum big_key_op { | |||
49 | /* | 50 | /* |
50 | * Key size for big_key data encryption | 51 | * Key size for big_key data encryption |
51 | */ | 52 | */ |
52 | #define ENC_KEY_SIZE 16 | 53 | #define ENC_KEY_SIZE 32 |
54 | |||
55 | /* | ||
56 | * Authentication tag length | ||
57 | */ | ||
58 | #define ENC_AUTHTAG_SIZE 16 | ||
53 | 59 | ||
54 | /* | 60 | /* |
55 | * big_key defined keys take an arbitrary string as the description and an | 61 | * big_key defined keys take an arbitrary string as the description and an |
@@ -64,57 +70,62 @@ struct key_type key_type_big_key = { | |||
64 | .destroy = big_key_destroy, | 70 | .destroy = big_key_destroy, |
65 | .describe = big_key_describe, | 71 | .describe = big_key_describe, |
66 | .read = big_key_read, | 72 | .read = big_key_read, |
73 | /* no ->update(); don't add it without changing big_key_crypt() nonce */ | ||
67 | }; | 74 | }; |
68 | 75 | ||
69 | /* | 76 | /* |
70 | * Crypto names for big_key data encryption | 77 | * Crypto names for big_key data authenticated encryption |
71 | */ | 78 | */ |
72 | static const char big_key_rng_name[] = "stdrng"; | 79 | static const char big_key_alg_name[] = "gcm(aes)"; |
73 | static const char big_key_alg_name[] = "ecb(aes)"; | ||
74 | 80 | ||
75 | /* | 81 | /* |
76 | * Crypto algorithms for big_key data encryption | 82 | * Crypto algorithms for big_key data authenticated encryption |
77 | */ | 83 | */ |
78 | static struct crypto_rng *big_key_rng; | 84 | static struct crypto_aead *big_key_aead; |
79 | static struct crypto_skcipher *big_key_skcipher; | ||
80 | 85 | ||
81 | /* | 86 | /* |
82 | * Generate random key to encrypt big_key data | 87 | * Since changing the key affects the entire object, we need a mutex. |
83 | */ | 88 | */ |
84 | static inline int big_key_gen_enckey(u8 *key) | 89 | static DEFINE_MUTEX(big_key_aead_lock); |
85 | { | ||
86 | return crypto_rng_get_bytes(big_key_rng, key, ENC_KEY_SIZE); | ||
87 | } | ||
88 | 90 | ||
89 | /* | 91 | /* |
90 | * Encrypt/decrypt big_key data | 92 | * Encrypt/decrypt big_key data |
91 | */ | 93 | */ |
92 | static int big_key_crypt(enum big_key_op op, u8 *data, size_t datalen, u8 *key) | 94 | static int big_key_crypt(enum big_key_op op, u8 *data, size_t datalen, u8 *key) |
93 | { | 95 | { |
94 | int ret = -EINVAL; | 96 | int ret; |
95 | struct scatterlist sgio; | 97 | struct scatterlist sgio; |
96 | SKCIPHER_REQUEST_ON_STACK(req, big_key_skcipher); | 98 | struct aead_request *aead_req; |
97 | 99 | /* We always use a zero nonce. The reason we can get away with this is | |
98 | if (crypto_skcipher_setkey(big_key_skcipher, key, ENC_KEY_SIZE)) { | 100 | * because we're using a different randomly generated key for every |
101 | * different encryption. Notably, too, key_type_big_key doesn't define | ||
102 | * an .update function, so there's no chance we'll wind up reusing the | ||
103 | * key to encrypt updated data. Simply put: one key, one encryption. | ||
104 | */ | ||
105 | u8 zero_nonce[crypto_aead_ivsize(big_key_aead)]; | ||
106 | |||
107 | aead_req = aead_request_alloc(big_key_aead, GFP_KERNEL); | ||
108 | if (!aead_req) | ||
109 | return -ENOMEM; | ||
110 | |||
111 | memset(zero_nonce, 0, sizeof(zero_nonce)); | ||
112 | sg_init_one(&sgio, data, datalen + (op == BIG_KEY_ENC ? ENC_AUTHTAG_SIZE : 0)); | ||
113 | aead_request_set_crypt(aead_req, &sgio, &sgio, datalen, zero_nonce); | ||
114 | aead_request_set_callback(aead_req, CRYPTO_TFM_REQ_MAY_SLEEP, NULL, NULL); | ||
115 | aead_request_set_ad(aead_req, 0); | ||
116 | |||
117 | mutex_lock(&big_key_aead_lock); | ||
118 | if (crypto_aead_setkey(big_key_aead, key, ENC_KEY_SIZE)) { | ||
99 | ret = -EAGAIN; | 119 | ret = -EAGAIN; |
100 | goto error; | 120 | goto error; |
101 | } | 121 | } |
102 | |||
103 | skcipher_request_set_tfm(req, big_key_skcipher); | ||
104 | skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_SLEEP, | ||
105 | NULL, NULL); | ||
106 | |||
107 | sg_init_one(&sgio, data, datalen); | ||
108 | skcipher_request_set_crypt(req, &sgio, &sgio, datalen, NULL); | ||
109 | |||
110 | if (op == BIG_KEY_ENC) | 122 | if (op == BIG_KEY_ENC) |
111 | ret = crypto_skcipher_encrypt(req); | 123 | ret = crypto_aead_encrypt(aead_req); |
112 | else | 124 | else |
113 | ret = crypto_skcipher_decrypt(req); | 125 | ret = crypto_aead_decrypt(aead_req); |
114 | |||
115 | skcipher_request_zero(req); | ||
116 | |||
117 | error: | 126 | error: |
127 | mutex_unlock(&big_key_aead_lock); | ||
128 | aead_request_free(aead_req); | ||
118 | return ret; | 129 | return ret; |
119 | } | 130 | } |
120 | 131 | ||
@@ -146,16 +157,13 @@ int big_key_preparse(struct key_preparsed_payload *prep) | |||
146 | * | 157 | * |
147 | * File content is stored encrypted with randomly generated key. | 158 | * File content is stored encrypted with randomly generated key. |
148 | */ | 159 | */ |
149 | size_t enclen = ALIGN(datalen, crypto_skcipher_blocksize(big_key_skcipher)); | 160 | size_t enclen = datalen + ENC_AUTHTAG_SIZE; |
150 | loff_t pos = 0; | 161 | loff_t pos = 0; |
151 | 162 | ||
152 | /* prepare aligned data to encrypt */ | ||
153 | data = kmalloc(enclen, GFP_KERNEL); | 163 | data = kmalloc(enclen, GFP_KERNEL); |
154 | if (!data) | 164 | if (!data) |
155 | return -ENOMEM; | 165 | return -ENOMEM; |
156 | |||
157 | memcpy(data, prep->data, datalen); | 166 | memcpy(data, prep->data, datalen); |
158 | memset(data + datalen, 0x00, enclen - datalen); | ||
159 | 167 | ||
160 | /* generate random key */ | 168 | /* generate random key */ |
161 | enckey = kmalloc(ENC_KEY_SIZE, GFP_KERNEL); | 169 | enckey = kmalloc(ENC_KEY_SIZE, GFP_KERNEL); |
@@ -163,13 +171,12 @@ int big_key_preparse(struct key_preparsed_payload *prep) | |||
163 | ret = -ENOMEM; | 171 | ret = -ENOMEM; |
164 | goto error; | 172 | goto error; |
165 | } | 173 | } |
166 | 174 | ret = get_random_bytes_wait(enckey, ENC_KEY_SIZE); | |
167 | ret = big_key_gen_enckey(enckey); | 175 | if (unlikely(ret)) |
168 | if (ret) | ||
169 | goto err_enckey; | 176 | goto err_enckey; |
170 | 177 | ||
171 | /* encrypt aligned data */ | 178 | /* encrypt aligned data */ |
172 | ret = big_key_crypt(BIG_KEY_ENC, data, enclen, enckey); | 179 | ret = big_key_crypt(BIG_KEY_ENC, data, datalen, enckey); |
173 | if (ret) | 180 | if (ret) |
174 | goto err_enckey; | 181 | goto err_enckey; |
175 | 182 | ||
@@ -195,7 +202,7 @@ int big_key_preparse(struct key_preparsed_payload *prep) | |||
195 | *path = file->f_path; | 202 | *path = file->f_path; |
196 | path_get(path); | 203 | path_get(path); |
197 | fput(file); | 204 | fput(file); |
198 | kfree(data); | 205 | kzfree(data); |
199 | } else { | 206 | } else { |
200 | /* Just store the data in a buffer */ | 207 | /* Just store the data in a buffer */ |
201 | void *data = kmalloc(datalen, GFP_KERNEL); | 208 | void *data = kmalloc(datalen, GFP_KERNEL); |
@@ -211,9 +218,9 @@ int big_key_preparse(struct key_preparsed_payload *prep) | |||
211 | err_fput: | 218 | err_fput: |
212 | fput(file); | 219 | fput(file); |
213 | err_enckey: | 220 | err_enckey: |
214 | kfree(enckey); | 221 | kzfree(enckey); |
215 | error: | 222 | error: |
216 | kfree(data); | 223 | kzfree(data); |
217 | return ret; | 224 | return ret; |
218 | } | 225 | } |
219 | 226 | ||
@@ -227,7 +234,7 @@ void big_key_free_preparse(struct key_preparsed_payload *prep) | |||
227 | 234 | ||
228 | path_put(path); | 235 | path_put(path); |
229 | } | 236 | } |
230 | kfree(prep->payload.data[big_key_data]); | 237 | kzfree(prep->payload.data[big_key_data]); |
231 | } | 238 | } |
232 | 239 | ||
233 | /* | 240 | /* |
@@ -259,7 +266,7 @@ void big_key_destroy(struct key *key) | |||
259 | path->mnt = NULL; | 266 | path->mnt = NULL; |
260 | path->dentry = NULL; | 267 | path->dentry = NULL; |
261 | } | 268 | } |
262 | kfree(key->payload.data[big_key_data]); | 269 | kzfree(key->payload.data[big_key_data]); |
263 | key->payload.data[big_key_data] = NULL; | 270 | key->payload.data[big_key_data] = NULL; |
264 | } | 271 | } |
265 | 272 | ||
@@ -295,7 +302,7 @@ long big_key_read(const struct key *key, char __user *buffer, size_t buflen) | |||
295 | struct file *file; | 302 | struct file *file; |
296 | u8 *data; | 303 | u8 *data; |
297 | u8 *enckey = (u8 *)key->payload.data[big_key_data]; | 304 | u8 *enckey = (u8 *)key->payload.data[big_key_data]; |
298 | size_t enclen = ALIGN(datalen, crypto_skcipher_blocksize(big_key_skcipher)); | 305 | size_t enclen = datalen + ENC_AUTHTAG_SIZE; |
299 | loff_t pos = 0; | 306 | loff_t pos = 0; |
300 | 307 | ||
301 | data = kmalloc(enclen, GFP_KERNEL); | 308 | data = kmalloc(enclen, GFP_KERNEL); |
@@ -328,7 +335,7 @@ long big_key_read(const struct key *key, char __user *buffer, size_t buflen) | |||
328 | err_fput: | 335 | err_fput: |
329 | fput(file); | 336 | fput(file); |
330 | error: | 337 | error: |
331 | kfree(data); | 338 | kzfree(data); |
332 | } else { | 339 | } else { |
333 | ret = datalen; | 340 | ret = datalen; |
334 | if (copy_to_user(buffer, key->payload.data[big_key_data], | 341 | if (copy_to_user(buffer, key->payload.data[big_key_data], |
@@ -344,47 +351,31 @@ error: | |||
344 | */ | 351 | */ |
345 | static int __init big_key_init(void) | 352 | static int __init big_key_init(void) |
346 | { | 353 | { |
347 | struct crypto_skcipher *cipher; | ||
348 | struct crypto_rng *rng; | ||
349 | int ret; | 354 | int ret; |
350 | 355 | ||
351 | rng = crypto_alloc_rng(big_key_rng_name, 0, 0); | ||
352 | if (IS_ERR(rng)) { | ||
353 | pr_err("Can't alloc rng: %ld\n", PTR_ERR(rng)); | ||
354 | return PTR_ERR(rng); | ||
355 | } | ||
356 | |||
357 | big_key_rng = rng; | ||
358 | |||
359 | /* seed RNG */ | ||
360 | ret = crypto_rng_reset(rng, NULL, crypto_rng_seedsize(rng)); | ||
361 | if (ret) { | ||
362 | pr_err("Can't reset rng: %d\n", ret); | ||
363 | goto error_rng; | ||
364 | } | ||
365 | |||
366 | /* init block cipher */ | 356 | /* init block cipher */ |
367 | cipher = crypto_alloc_skcipher(big_key_alg_name, 0, CRYPTO_ALG_ASYNC); | 357 | big_key_aead = crypto_alloc_aead(big_key_alg_name, 0, CRYPTO_ALG_ASYNC); |
368 | if (IS_ERR(cipher)) { | 358 | if (IS_ERR(big_key_aead)) { |
369 | ret = PTR_ERR(cipher); | 359 | ret = PTR_ERR(big_key_aead); |
370 | pr_err("Can't alloc crypto: %d\n", ret); | 360 | pr_err("Can't alloc crypto: %d\n", ret); |
371 | goto error_rng; | 361 | return ret; |
362 | } | ||
363 | ret = crypto_aead_setauthsize(big_key_aead, ENC_AUTHTAG_SIZE); | ||
364 | if (ret < 0) { | ||
365 | pr_err("Can't set crypto auth tag len: %d\n", ret); | ||
366 | goto free_aead; | ||
372 | } | 367 | } |
373 | |||
374 | big_key_skcipher = cipher; | ||
375 | 368 | ||
376 | ret = register_key_type(&key_type_big_key); | 369 | ret = register_key_type(&key_type_big_key); |
377 | if (ret < 0) { | 370 | if (ret < 0) { |
378 | pr_err("Can't register type: %d\n", ret); | 371 | pr_err("Can't register type: %d\n", ret); |
379 | goto error_cipher; | 372 | goto free_aead; |
380 | } | 373 | } |
381 | 374 | ||
382 | return 0; | 375 | return 0; |
383 | 376 | ||
384 | error_cipher: | 377 | free_aead: |
385 | crypto_free_skcipher(big_key_skcipher); | 378 | crypto_free_aead(big_key_aead); |
386 | error_rng: | ||
387 | crypto_free_rng(big_key_rng); | ||
388 | return ret; | 379 | return ret; |
389 | } | 380 | } |
390 | 381 | ||