| From f699594d436960160f6d5ba84ed4a222f20d11cd Mon Sep 17 00:00:00 2001 |
| From: Eric Biggers <ebiggers@google.com> |
| Date: Thu, 18 Apr 2019 14:43:02 -0700 |
| Subject: crypto: gcm - fix incompatibility between "gcm" and "gcm_base" |
| |
| From: Eric Biggers <ebiggers@google.com> |
| |
| commit f699594d436960160f6d5ba84ed4a222f20d11cd upstream. |
| |
| GCM instances can be created by either the "gcm" template, which only |
| allows choosing the block cipher, e.g. "gcm(aes)"; or by "gcm_base", |
| which allows choosing the ctr and ghash implementations, e.g. |
| "gcm_base(ctr(aes-generic),ghash-generic)". |
| |
| However, a "gcm_base" instance prevents a "gcm" instance from being |
| registered using the same implementations. Nor will the instance be |
| found by lookups of "gcm". This can be used as a denial of service. |
| Moreover, "gcm_base" instances are never tested by the crypto |
| self-tests, even if there are compatible "gcm" tests. |
| |
| The root cause of these problems is that instances of the two templates |
| use different cra_names. Therefore, fix these problems by making |
| "gcm_base" instances set the same cra_name as "gcm" instances, e.g. |
| "gcm(aes)" instead of "gcm_base(ctr(aes-generic),ghash-generic)". |
| |
| This requires extracting the block cipher name from the name of the ctr |
| algorithm. It also requires starting to verify that the algorithms are |
| really ctr and ghash, not something else entirely. But it would be |
| bizarre if anyone were actually using non-gcm-compatible algorithms with |
| gcm_base, so this shouldn't break anyone in practice. |
| |
| Fixes: d00aa19b507b ("[CRYPTO] gcm: Allow block cipher parameter") |
| Cc: stable@vger.kernel.org |
| Signed-off-by: Eric Biggers <ebiggers@google.com> |
| Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| |
| --- |
| crypto/gcm.c | 34 +++++++++++----------------------- |
| 1 file changed, 11 insertions(+), 23 deletions(-) |
| |
| --- a/crypto/gcm.c |
| +++ b/crypto/gcm.c |
| @@ -616,7 +616,6 @@ static void crypto_gcm_free(struct aead_ |
| |
| static int crypto_gcm_create_common(struct crypto_template *tmpl, |
| struct rtattr **tb, |
| - const char *full_name, |
| const char *ctr_name, |
| const char *ghash_name) |
| { |
| @@ -657,7 +656,8 @@ static int crypto_gcm_create_common(stru |
| goto err_free_inst; |
| |
| err = -EINVAL; |
| - if (ghash->digestsize != 16) |
| + if (strcmp(ghash->base.cra_name, "ghash") != 0 || |
| + ghash->digestsize != 16) |
| goto err_drop_ghash; |
| |
| crypto_set_skcipher_spawn(&ctx->ctr, aead_crypto_instance(inst)); |
| @@ -669,24 +669,24 @@ static int crypto_gcm_create_common(stru |
| |
| ctr = crypto_skcipher_spawn_alg(&ctx->ctr); |
| |
| - /* We only support 16-byte blocks. */ |
| + /* The skcipher algorithm must be CTR mode, using 16-byte blocks. */ |
| err = -EINVAL; |
| - if (ctr->cra_ablkcipher.ivsize != 16) |
| + if (strncmp(ctr->cra_name, "ctr(", 4) != 0 || |
| + ctr->cra_ablkcipher.ivsize != 16 || |
| + ctr->cra_blocksize != 1) |
| goto out_put_ctr; |
| |
| - /* Not a stream cipher? */ |
| - if (ctr->cra_blocksize != 1) |
| + err = -ENAMETOOLONG; |
| + if (snprintf(inst->alg.base.cra_name, CRYPTO_MAX_ALG_NAME, |
| + "gcm(%s", ctr->cra_name + 4) >= CRYPTO_MAX_ALG_NAME) |
| goto out_put_ctr; |
| |
| - err = -ENAMETOOLONG; |
| if (snprintf(inst->alg.base.cra_driver_name, CRYPTO_MAX_ALG_NAME, |
| "gcm_base(%s,%s)", ctr->cra_driver_name, |
| ghash_alg->cra_driver_name) >= |
| CRYPTO_MAX_ALG_NAME) |
| goto out_put_ctr; |
| |
| - memcpy(inst->alg.base.cra_name, full_name, CRYPTO_MAX_ALG_NAME); |
| - |
| inst->alg.base.cra_flags = (ghash->base.cra_flags | ctr->cra_flags) & |
| CRYPTO_ALG_ASYNC; |
| inst->alg.base.cra_priority = (ghash->base.cra_priority + |
| @@ -727,7 +727,6 @@ static int crypto_gcm_create(struct cryp |
| { |
| const char *cipher_name; |
| char ctr_name[CRYPTO_MAX_ALG_NAME]; |
| - char full_name[CRYPTO_MAX_ALG_NAME]; |
| |
| cipher_name = crypto_attr_alg_name(tb[1]); |
| if (IS_ERR(cipher_name)) |
| @@ -737,12 +736,7 @@ static int crypto_gcm_create(struct cryp |
| CRYPTO_MAX_ALG_NAME) |
| return -ENAMETOOLONG; |
| |
| - if (snprintf(full_name, CRYPTO_MAX_ALG_NAME, "gcm(%s)", cipher_name) >= |
| - CRYPTO_MAX_ALG_NAME) |
| - return -ENAMETOOLONG; |
| - |
| - return crypto_gcm_create_common(tmpl, tb, full_name, |
| - ctr_name, "ghash"); |
| + return crypto_gcm_create_common(tmpl, tb, ctr_name, "ghash"); |
| } |
| |
| static struct crypto_template crypto_gcm_tmpl = { |
| @@ -756,7 +750,6 @@ static int crypto_gcm_base_create(struct |
| { |
| const char *ctr_name; |
| const char *ghash_name; |
| - char full_name[CRYPTO_MAX_ALG_NAME]; |
| |
| ctr_name = crypto_attr_alg_name(tb[1]); |
| if (IS_ERR(ctr_name)) |
| @@ -766,12 +759,7 @@ static int crypto_gcm_base_create(struct |
| if (IS_ERR(ghash_name)) |
| return PTR_ERR(ghash_name); |
| |
| - if (snprintf(full_name, CRYPTO_MAX_ALG_NAME, "gcm_base(%s,%s)", |
| - ctr_name, ghash_name) >= CRYPTO_MAX_ALG_NAME) |
| - return -ENAMETOOLONG; |
| - |
| - return crypto_gcm_create_common(tmpl, tb, full_name, |
| - ctr_name, ghash_name); |
| + return crypto_gcm_create_common(tmpl, tb, ctr_name, ghash_name); |
| } |
| |
| static struct crypto_template crypto_gcm_base_tmpl = { |