]>
Commit | Line | Data |
---|---|---|
84d167bb GKH |
1 | From ba7d7433a0e998c902132bd47330e355a1eaa894 Mon Sep 17 00:00:00 2001 |
2 | From: Eric Biggers <ebiggers@google.com> | |
3 | Date: Sun, 6 Jan 2019 18:47:42 -0800 | |
4 | Subject: crypto: hash - set CRYPTO_TFM_NEED_KEY if ->setkey() fails | |
5 | ||
6 | From: Eric Biggers <ebiggers@google.com> | |
7 | ||
8 | commit ba7d7433a0e998c902132bd47330e355a1eaa894 upstream. | |
9 | ||
10 | Some algorithms have a ->setkey() method that is not atomic, in the | |
11 | sense that setting a key can fail after changes were already made to the | |
12 | tfm context. In this case, if a key was already set the tfm can end up | |
13 | in a state that corresponds to neither the old key nor the new key. | |
14 | ||
15 | It's not feasible to make all ->setkey() methods atomic, especially ones | |
16 | that have to key multiple sub-tfms. Therefore, make the crypto API set | |
17 | CRYPTO_TFM_NEED_KEY if ->setkey() fails and the algorithm requires a | |
18 | key, to prevent the tfm from being used until a new key is set. | |
19 | ||
20 | Note: we can't set CRYPTO_TFM_NEED_KEY for OPTIONAL_KEY algorithms, so | |
21 | ->setkey() for those must nevertheless be atomic. That's fine for now | |
22 | since only the crc32 and crc32c algorithms set OPTIONAL_KEY, and it's | |
23 | not intended that OPTIONAL_KEY be used much. | |
24 | ||
25 | [Cc stable mainly because when introducing the NEED_KEY flag I changed | |
26 | AF_ALG to rely on it; and unlike in-kernel crypto API users, AF_ALG | |
27 | previously didn't have this problem. So these "incompletely keyed" | |
28 | states became theoretically accessible via AF_ALG -- though, the | |
29 | opportunities for causing real mischief seem pretty limited.] | |
30 | ||
31 | Fixes: 9fa68f620041 ("crypto: hash - prevent using keyed hashes without setting key") | |
32 | Cc: stable@vger.kernel.org | |
33 | Signed-off-by: Eric Biggers <ebiggers@google.com> | |
34 | Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> | |
35 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
36 | ||
37 | --- | |
38 | crypto/ahash.c | 28 +++++++++++++++++++--------- | |
39 | crypto/shash.c | 18 +++++++++++++----- | |
40 | 2 files changed, 32 insertions(+), 14 deletions(-) | |
41 | ||
42 | --- a/crypto/ahash.c | |
43 | +++ b/crypto/ahash.c | |
44 | @@ -190,6 +190,21 @@ static int ahash_setkey_unaligned(struct | |
45 | return ret; | |
46 | } | |
47 | ||
48 | +static int ahash_nosetkey(struct crypto_ahash *tfm, const u8 *key, | |
49 | + unsigned int keylen) | |
50 | +{ | |
51 | + return -ENOSYS; | |
52 | +} | |
53 | + | |
54 | +static void ahash_set_needkey(struct crypto_ahash *tfm) | |
55 | +{ | |
56 | + const struct hash_alg_common *alg = crypto_hash_alg_common(tfm); | |
57 | + | |
58 | + if (tfm->setkey != ahash_nosetkey && | |
59 | + !(alg->base.cra_flags & CRYPTO_ALG_OPTIONAL_KEY)) | |
60 | + crypto_ahash_set_flags(tfm, CRYPTO_TFM_NEED_KEY); | |
61 | +} | |
62 | + | |
63 | int crypto_ahash_setkey(struct crypto_ahash *tfm, const u8 *key, | |
64 | unsigned int keylen) | |
65 | { | |
66 | @@ -201,20 +216,16 @@ int crypto_ahash_setkey(struct crypto_ah | |
67 | else | |
68 | err = tfm->setkey(tfm, key, keylen); | |
69 | ||
70 | - if (err) | |
71 | + if (unlikely(err)) { | |
72 | + ahash_set_needkey(tfm); | |
73 | return err; | |
74 | + } | |
75 | ||
76 | crypto_ahash_clear_flags(tfm, CRYPTO_TFM_NEED_KEY); | |
77 | return 0; | |
78 | } | |
79 | EXPORT_SYMBOL_GPL(crypto_ahash_setkey); | |
80 | ||
81 | -static int ahash_nosetkey(struct crypto_ahash *tfm, const u8 *key, | |
82 | - unsigned int keylen) | |
83 | -{ | |
84 | - return -ENOSYS; | |
85 | -} | |
86 | - | |
87 | static inline unsigned int ahash_align_buffer_size(unsigned len, | |
88 | unsigned long mask) | |
89 | { | |
90 | @@ -483,8 +494,7 @@ static int crypto_ahash_init_tfm(struct | |
91 | ||
92 | if (alg->setkey) { | |
93 | hash->setkey = alg->setkey; | |
94 | - if (!(alg->halg.base.cra_flags & CRYPTO_ALG_OPTIONAL_KEY)) | |
95 | - crypto_ahash_set_flags(hash, CRYPTO_TFM_NEED_KEY); | |
96 | + ahash_set_needkey(hash); | |
97 | } | |
98 | if (alg->export) | |
99 | hash->export = alg->export; | |
100 | --- a/crypto/shash.c | |
101 | +++ b/crypto/shash.c | |
102 | @@ -53,6 +53,13 @@ static int shash_setkey_unaligned(struct | |
103 | return err; | |
104 | } | |
105 | ||
106 | +static void shash_set_needkey(struct crypto_shash *tfm, struct shash_alg *alg) | |
107 | +{ | |
108 | + if (crypto_shash_alg_has_setkey(alg) && | |
109 | + !(alg->base.cra_flags & CRYPTO_ALG_OPTIONAL_KEY)) | |
110 | + crypto_shash_set_flags(tfm, CRYPTO_TFM_NEED_KEY); | |
111 | +} | |
112 | + | |
113 | int crypto_shash_setkey(struct crypto_shash *tfm, const u8 *key, | |
114 | unsigned int keylen) | |
115 | { | |
116 | @@ -65,8 +72,10 @@ int crypto_shash_setkey(struct crypto_sh | |
117 | else | |
118 | err = shash->setkey(tfm, key, keylen); | |
119 | ||
120 | - if (err) | |
121 | + if (unlikely(err)) { | |
122 | + shash_set_needkey(tfm, shash); | |
123 | return err; | |
124 | + } | |
125 | ||
126 | crypto_shash_clear_flags(tfm, CRYPTO_TFM_NEED_KEY); | |
127 | return 0; | |
128 | @@ -368,7 +377,8 @@ int crypto_init_shash_ops_async(struct c | |
129 | crt->final = shash_async_final; | |
130 | crt->finup = shash_async_finup; | |
131 | crt->digest = shash_async_digest; | |
132 | - crt->setkey = shash_async_setkey; | |
133 | + if (crypto_shash_alg_has_setkey(alg)) | |
134 | + crt->setkey = shash_async_setkey; | |
135 | ||
136 | crypto_ahash_set_flags(crt, crypto_shash_get_flags(shash) & | |
137 | CRYPTO_TFM_NEED_KEY); | |
138 | @@ -390,9 +400,7 @@ static int crypto_shash_init_tfm(struct | |
139 | ||
140 | hash->descsize = alg->descsize; | |
141 | ||
142 | - if (crypto_shash_alg_has_setkey(alg) && | |
143 | - !(alg->base.cra_flags & CRYPTO_ALG_OPTIONAL_KEY)) | |
144 | - crypto_shash_set_flags(hash, CRYPTO_TFM_NEED_KEY); | |
145 | + shash_set_needkey(hash, alg); | |
146 | ||
147 | return 0; | |
148 | } |