Skip to content

Commit 418f4c9

Browse files
zx2c4popcornmix
authored andcommitted
security/keys: rewrite all of big_key crypto
commit 428490e upstream. This started out as just replacing the use of crypto/rng with get_random_bytes_wait, so that we wouldn't use bad randomness at boot time. But, upon looking further, it appears that there were even deeper underlying cryptographic problems, and that this seems to have been committed with very little crypto review. So, I rewrote the whole thing, trying to keep to the conventions introduced by the previous author, to fix these cryptographic flaws. It makes no sense to seed crypto/rng at boot time and then keep using it like this, when in fact there's already get_random_bytes_wait, which can ensure there's enough entropy and be a much more standard way of generating keys. Since this sensitive material is being stored untrusted, using ECB and no authentication is simply not okay at all. I find it surprising and a bit horrifying that this code even made it past basic crypto review, which perhaps points to some larger issues. This patch moves from using AES-ECB to using AES-GCM. Since keys are uniquely generated each time, we can set the nonce to zero. There was also a race condition in which the same key would be reused at the same time in different threads. A mutex fixes this issue now. So, to summarize, this commit fixes the following vulnerabilities: * Low entropy key generation, allowing an attacker to potentially guess or predict keys. * Unauthenticated encryption, allowing an attacker to modify the cipher text in particular ways in order to manipulate the plaintext, which is is even more frightening considering the next point. * Use of ECB mode, allowing an attacker to trivially swap blocks or compare identical plaintext blocks. * Key re-use. * Faulty memory zeroing. [Note that in backporting this commit to 4.9, get_random_bytes_wait was replaced with get_random_bytes, since 4.9 does not have the former function. This might result in slightly worse entropy in key generation, but common use cases of big_keys makes that likely not a huge deal. And, this is the best we can do with this old kernel. Alas.] Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com> Reviewed-by: Eric Biggers <ebiggers3@gmail.com> Signed-off-by: David Howells <dhowells@redhat.com> Cc: Herbert Xu <herbert@gondor.apana.org.au> Cc: Kirill Marinushkin <k.marinushkin@gmail.com> Cc: security@kernel.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent d790db3 commit 418f4c9

File tree

2 files changed

+59
-71
lines changed

2 files changed

+59
-71
lines changed

security/keys/Kconfig

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,8 @@ config BIG_KEYS
4141
bool "Large payload keys"
4242
depends on KEYS
4343
depends on TMPFS
44-
depends on (CRYPTO_ANSI_CPRNG = y || CRYPTO_DRBG = y)
4544
select CRYPTO_AES
46-
select CRYPTO_ECB
47-
select CRYPTO_RNG
45+
select CRYPTO_GCM
4846
help
4947
This option provides support for holding large keys within the kernel
5048
(for example Kerberos ticket caches). The data may be stored out to

security/keys/big_key.c

Lines changed: 58 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/* Large capacity key type
22
*
3+
* Copyright (C) 2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
34
* Copyright (C) 2013 Red Hat, Inc. All Rights Reserved.
45
* Written by David Howells (dhowells@redhat.com)
56
*
@@ -16,10 +17,10 @@
1617
#include <linux/shmem_fs.h>
1718
#include <linux/err.h>
1819
#include <linux/scatterlist.h>
20+
#include <linux/random.h>
1921
#include <keys/user-type.h>
2022
#include <keys/big_key-type.h>
21-
#include <crypto/rng.h>
22-
#include <crypto/skcipher.h>
23+
#include <crypto/aead.h>
2324

2425
/*
2526
* Layout of key payload words.
@@ -49,7 +50,12 @@ enum big_key_op {
4950
/*
5051
* Key size for big_key data encryption
5152
*/
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
5359

5460
/*
5561
* big_key defined keys take an arbitrary string as the description and an
@@ -64,57 +70,62 @@ struct key_type key_type_big_key = {
6470
.destroy = big_key_destroy,
6571
.describe = big_key_describe,
6672
.read = big_key_read,
73+
/* no ->update(); don't add it without changing big_key_crypt() nonce */
6774
};
6875

6976
/*
70-
* Crypto names for big_key data encryption
77+
* Crypto names for big_key data authenticated encryption
7178
*/
72-
static const char big_key_rng_name[] = "stdrng";
73-
static const char big_key_alg_name[] = "ecb(aes)";
79+
static const char big_key_alg_name[] = "gcm(aes)";
7480

7581
/*
76-
* Crypto algorithms for big_key data encryption
82+
* Crypto algorithms for big_key data authenticated encryption
7783
*/
78-
static struct crypto_rng *big_key_rng;
79-
static struct crypto_skcipher *big_key_skcipher;
84+
static struct crypto_aead *big_key_aead;
8085

8186
/*
82-
* Generate random key to encrypt big_key data
87+
* Since changing the key affects the entire object, we need a mutex.
8388
*/
84-
static inline int big_key_gen_enckey(u8 *key)
85-
{
86-
return crypto_rng_get_bytes(big_key_rng, key, ENC_KEY_SIZE);
87-
}
89+
static DEFINE_MUTEX(big_key_aead_lock);
8890

8991
/*
9092
* Encrypt/decrypt big_key data
9193
*/
9294
static int big_key_crypt(enum big_key_op op, u8 *data, size_t datalen, u8 *key)
9395
{
94-
int ret = -EINVAL;
96+
int ret;
9597
struct scatterlist sgio;
96-
SKCIPHER_REQUEST_ON_STACK(req, big_key_skcipher);
97-
98-
if (crypto_skcipher_setkey(big_key_skcipher, key, ENC_KEY_SIZE)) {
98+
struct aead_request *aead_req;
99+
/* We always use a zero nonce. The reason we can get away with this is
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)) {
99119
ret = -EAGAIN;
100120
goto error;
101121
}
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-
110122
if (op == BIG_KEY_ENC)
111-
ret = crypto_skcipher_encrypt(req);
123+
ret = crypto_aead_encrypt(aead_req);
112124
else
113-
ret = crypto_skcipher_decrypt(req);
114-
115-
skcipher_request_zero(req);
116-
125+
ret = crypto_aead_decrypt(aead_req);
117126
error:
127+
mutex_unlock(&big_key_aead_lock);
128+
aead_request_free(aead_req);
118129
return ret;
119130
}
120131

@@ -146,29 +157,24 @@ int big_key_preparse(struct key_preparsed_payload *prep)
146157
*
147158
* File content is stored encrypted with randomly generated key.
148159
*/
149-
size_t enclen = ALIGN(datalen, crypto_skcipher_blocksize(big_key_skcipher));
160+
size_t enclen = datalen + ENC_AUTHTAG_SIZE;
150161

151-
/* prepare aligned data to encrypt */
152162
data = kmalloc(enclen, GFP_KERNEL);
153163
if (!data)
154164
return -ENOMEM;
155165

156166
memcpy(data, prep->data, datalen);
157-
memset(data + datalen, 0x00, enclen - datalen);
158167

159168
/* generate random key */
160169
enckey = kmalloc(ENC_KEY_SIZE, GFP_KERNEL);
161170
if (!enckey) {
162171
ret = -ENOMEM;
163172
goto error;
164173
}
165-
166-
ret = big_key_gen_enckey(enckey);
167-
if (ret)
168-
goto err_enckey;
174+
get_random_bytes(enckey, ENC_KEY_SIZE);
169175

170176
/* encrypt aligned data */
171-
ret = big_key_crypt(BIG_KEY_ENC, data, enclen, enckey);
177+
ret = big_key_crypt(BIG_KEY_ENC, data, datalen, enckey);
172178
if (ret)
173179
goto err_enckey;
174180

@@ -294,7 +300,7 @@ long big_key_read(const struct key *key, char __user *buffer, size_t buflen)
294300
struct file *file;
295301
u8 *data;
296302
u8 *enckey = (u8 *)key->payload.data[big_key_data];
297-
size_t enclen = ALIGN(datalen, crypto_skcipher_blocksize(big_key_skcipher));
303+
size_t enclen = datalen + ENC_AUTHTAG_SIZE;
298304

299305
data = kmalloc(enclen, GFP_KERNEL);
300306
if (!data)
@@ -342,47 +348,31 @@ long big_key_read(const struct key *key, char __user *buffer, size_t buflen)
342348
*/
343349
static int __init big_key_init(void)
344350
{
345-
struct crypto_skcipher *cipher;
346-
struct crypto_rng *rng;
347351
int ret;
348352

349-
rng = crypto_alloc_rng(big_key_rng_name, 0, 0);
350-
if (IS_ERR(rng)) {
351-
pr_err("Can't alloc rng: %ld\n", PTR_ERR(rng));
352-
return PTR_ERR(rng);
353-
}
354-
355-
big_key_rng = rng;
356-
357-
/* seed RNG */
358-
ret = crypto_rng_reset(rng, NULL, crypto_rng_seedsize(rng));
359-
if (ret) {
360-
pr_err("Can't reset rng: %d\n", ret);
361-
goto error_rng;
362-
}
363-
364353
/* init block cipher */
365-
cipher = crypto_alloc_skcipher(big_key_alg_name, 0, CRYPTO_ALG_ASYNC);
366-
if (IS_ERR(cipher)) {
367-
ret = PTR_ERR(cipher);
354+
big_key_aead = crypto_alloc_aead(big_key_alg_name, 0, CRYPTO_ALG_ASYNC);
355+
if (IS_ERR(big_key_aead)) {
356+
ret = PTR_ERR(big_key_aead);
368357
pr_err("Can't alloc crypto: %d\n", ret);
369-
goto error_rng;
358+
return ret;
359+
}
360+
ret = crypto_aead_setauthsize(big_key_aead, ENC_AUTHTAG_SIZE);
361+
if (ret < 0) {
362+
pr_err("Can't set crypto auth tag len: %d\n", ret);
363+
goto free_aead;
370364
}
371-
372-
big_key_skcipher = cipher;
373365

374366
ret = register_key_type(&key_type_big_key);
375367
if (ret < 0) {
376368
pr_err("Can't register type: %d\n", ret);
377-
goto error_cipher;
369+
goto free_aead;
378370
}
379371

380372
return 0;
381373

382-
error_cipher:
383-
crypto_free_skcipher(big_key_skcipher);
384-
error_rng:
385-
crypto_free_rng(big_key_rng);
374+
free_aead:
375+
crypto_free_aead(big_key_aead);
386376
return ret;
387377
}
388378

0 commit comments

Comments
 (0)