diff options
author | Eric Biggers <ebiggers@google.com> | 2019-01-06 21:47:42 -0500 |
---|---|---|
committer | Herbert Xu <herbert@gondor.apana.org.au> | 2019-01-18 05:40:24 -0500 |
commit | ba7d7433a0e998c902132bd47330e355a1eaa894 (patch) | |
tree | 173b444702f5d2114d687711b3376477dbbde26b /crypto | |
parent | 6b476662b09c393936e0f62c97ad9988d410fd36 (diff) |
crypto: hash - set CRYPTO_TFM_NEED_KEY if ->setkey() fails
Some algorithms have a ->setkey() method that is not atomic, in the
sense that setting a key can fail after changes were already made to the
tfm context. In this case, if a key was already set the tfm can end up
in a state that corresponds to neither the old key nor the new key.
It's not feasible to make all ->setkey() methods atomic, especially ones
that have to key multiple sub-tfms. Therefore, make the crypto API set
CRYPTO_TFM_NEED_KEY if ->setkey() fails and the algorithm requires a
key, to prevent the tfm from being used until a new key is set.
Note: we can't set CRYPTO_TFM_NEED_KEY for OPTIONAL_KEY algorithms, so
->setkey() for those must nevertheless be atomic. That's fine for now
since only the crc32 and crc32c algorithms set OPTIONAL_KEY, and it's
not intended that OPTIONAL_KEY be used much.
[Cc stable mainly because when introducing the NEED_KEY flag I changed
AF_ALG to rely on it; and unlike in-kernel crypto API users, AF_ALG
previously didn't have this problem. So these "incompletely keyed"
states became theoretically accessible via AF_ALG -- though, the
opportunities for causing real mischief seem pretty limited.]
Fixes: 9fa68f620041 ("crypto: hash - prevent using keyed hashes without setting key")
Cc: stable@vger.kernel.org
Signed-off-by: Eric Biggers <ebiggers@google.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Diffstat (limited to 'crypto')
-rw-r--r-- | crypto/ahash.c | 28 | ||||
-rw-r--r-- | crypto/shash.c | 18 |
2 files changed, 32 insertions, 14 deletions
diff --git a/crypto/ahash.c b/crypto/ahash.c index 5d320a811f75..ca0d3e281fef 100644 --- a/crypto/ahash.c +++ b/crypto/ahash.c | |||
@@ -190,6 +190,21 @@ static int ahash_setkey_unaligned(struct crypto_ahash *tfm, const u8 *key, | |||
190 | return ret; | 190 | return ret; |
191 | } | 191 | } |
192 | 192 | ||
193 | static int ahash_nosetkey(struct crypto_ahash *tfm, const u8 *key, | ||
194 | unsigned int keylen) | ||
195 | { | ||
196 | return -ENOSYS; | ||
197 | } | ||
198 | |||
199 | static void ahash_set_needkey(struct crypto_ahash *tfm) | ||
200 | { | ||
201 | const struct hash_alg_common *alg = crypto_hash_alg_common(tfm); | ||
202 | |||
203 | if (tfm->setkey != ahash_nosetkey && | ||
204 | !(alg->base.cra_flags & CRYPTO_ALG_OPTIONAL_KEY)) | ||
205 | crypto_ahash_set_flags(tfm, CRYPTO_TFM_NEED_KEY); | ||
206 | } | ||
207 | |||
193 | int crypto_ahash_setkey(struct crypto_ahash *tfm, const u8 *key, | 208 | int crypto_ahash_setkey(struct crypto_ahash *tfm, const u8 *key, |
194 | unsigned int keylen) | 209 | unsigned int keylen) |
195 | { | 210 | { |
@@ -201,20 +216,16 @@ int crypto_ahash_setkey(struct crypto_ahash *tfm, const u8 *key, | |||
201 | else | 216 | else |
202 | err = tfm->setkey(tfm, key, keylen); | 217 | err = tfm->setkey(tfm, key, keylen); |
203 | 218 | ||
204 | if (err) | 219 | if (unlikely(err)) { |
220 | ahash_set_needkey(tfm); | ||
205 | return err; | 221 | return err; |
222 | } | ||
206 | 223 | ||
207 | crypto_ahash_clear_flags(tfm, CRYPTO_TFM_NEED_KEY); | 224 | crypto_ahash_clear_flags(tfm, CRYPTO_TFM_NEED_KEY); |
208 | return 0; | 225 | return 0; |
209 | } | 226 | } |
210 | EXPORT_SYMBOL_GPL(crypto_ahash_setkey); | 227 | EXPORT_SYMBOL_GPL(crypto_ahash_setkey); |
211 | 228 | ||
212 | static int ahash_nosetkey(struct crypto_ahash *tfm, const u8 *key, | ||
213 | unsigned int keylen) | ||
214 | { | ||
215 | return -ENOSYS; | ||
216 | } | ||
217 | |||
218 | static inline unsigned int ahash_align_buffer_size(unsigned len, | 229 | static inline unsigned int ahash_align_buffer_size(unsigned len, |
219 | unsigned long mask) | 230 | unsigned long mask) |
220 | { | 231 | { |
@@ -489,8 +500,7 @@ static int crypto_ahash_init_tfm(struct crypto_tfm *tfm) | |||
489 | 500 | ||
490 | if (alg->setkey) { | 501 | if (alg->setkey) { |
491 | hash->setkey = alg->setkey; | 502 | hash->setkey = alg->setkey; |
492 | if (!(alg->halg.base.cra_flags & CRYPTO_ALG_OPTIONAL_KEY)) | 503 | ahash_set_needkey(hash); |
493 | crypto_ahash_set_flags(hash, CRYPTO_TFM_NEED_KEY); | ||
494 | } | 504 | } |
495 | 505 | ||
496 | return 0; | 506 | return 0; |
diff --git a/crypto/shash.c b/crypto/shash.c index 44d297b82a8f..40311ccad3fa 100644 --- a/crypto/shash.c +++ b/crypto/shash.c | |||
@@ -53,6 +53,13 @@ static int shash_setkey_unaligned(struct crypto_shash *tfm, const u8 *key, | |||
53 | return err; | 53 | return err; |
54 | } | 54 | } |
55 | 55 | ||
56 | static void shash_set_needkey(struct crypto_shash *tfm, struct shash_alg *alg) | ||
57 | { | ||
58 | if (crypto_shash_alg_has_setkey(alg) && | ||
59 | !(alg->base.cra_flags & CRYPTO_ALG_OPTIONAL_KEY)) | ||
60 | crypto_shash_set_flags(tfm, CRYPTO_TFM_NEED_KEY); | ||
61 | } | ||
62 | |||
56 | int crypto_shash_setkey(struct crypto_shash *tfm, const u8 *key, | 63 | int crypto_shash_setkey(struct crypto_shash *tfm, const u8 *key, |
57 | unsigned int keylen) | 64 | unsigned int keylen) |
58 | { | 65 | { |
@@ -65,8 +72,10 @@ int crypto_shash_setkey(struct crypto_shash *tfm, const u8 *key, | |||
65 | else | 72 | else |
66 | err = shash->setkey(tfm, key, keylen); | 73 | err = shash->setkey(tfm, key, keylen); |
67 | 74 | ||
68 | if (err) | 75 | if (unlikely(err)) { |
76 | shash_set_needkey(tfm, shash); | ||
69 | return err; | 77 | return err; |
78 | } | ||
70 | 79 | ||
71 | crypto_shash_clear_flags(tfm, CRYPTO_TFM_NEED_KEY); | 80 | crypto_shash_clear_flags(tfm, CRYPTO_TFM_NEED_KEY); |
72 | return 0; | 81 | return 0; |
@@ -373,7 +382,8 @@ int crypto_init_shash_ops_async(struct crypto_tfm *tfm) | |||
373 | crt->final = shash_async_final; | 382 | crt->final = shash_async_final; |
374 | crt->finup = shash_async_finup; | 383 | crt->finup = shash_async_finup; |
375 | crt->digest = shash_async_digest; | 384 | crt->digest = shash_async_digest; |
376 | crt->setkey = shash_async_setkey; | 385 | if (crypto_shash_alg_has_setkey(alg)) |
386 | crt->setkey = shash_async_setkey; | ||
377 | 387 | ||
378 | crypto_ahash_set_flags(crt, crypto_shash_get_flags(shash) & | 388 | crypto_ahash_set_flags(crt, crypto_shash_get_flags(shash) & |
379 | CRYPTO_TFM_NEED_KEY); | 389 | CRYPTO_TFM_NEED_KEY); |
@@ -395,9 +405,7 @@ static int crypto_shash_init_tfm(struct crypto_tfm *tfm) | |||
395 | 405 | ||
396 | hash->descsize = alg->descsize; | 406 | hash->descsize = alg->descsize; |
397 | 407 | ||
398 | if (crypto_shash_alg_has_setkey(alg) && | 408 | shash_set_needkey(hash, alg); |
399 | !(alg->base.cra_flags & CRYPTO_ALG_OPTIONAL_KEY)) | ||
400 | crypto_shash_set_flags(hash, CRYPTO_TFM_NEED_KEY); | ||
401 | 409 | ||
402 | return 0; | 410 | return 0; |
403 | } | 411 | } |