[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <12c867b87e67e7d7db0633928654f92b3bfc83d7.camel@kernel.org>
Date: Tue, 12 Jan 2021 03:34:16 +0200
From: Jarkko Sakkinen <jarkko@...nel.org>
To: Stephan Müller <smueller@...onox.de>,
herbert@...dor.apana.org.au, ebiggers@...nel.org,
mathew.j.martineau@...ux.intel.com, dhowells@...hat.com
Cc: linux-crypto@...r.kernel.org, linux-fscrypt@...r.kernel.org,
linux-kernel@...r.kernel.org, keyrings@...r.kernel.org
Subject: Re: [PATCH 4/5] security: DH - use KDF implementation from crypto
API
On Mon, 2021-01-04 at 22:49 +0100, Stephan Müller wrote:
> The kernel crypto API provides the SP800-108 counter KDF implementation.
> Thus, the separate implementation provided as part of the keys subsystem
> can be replaced with calls to the KDF offered by the kernel crypto API.
>
> The keys subsystem uses the counter KDF with a hash cipher primitive.
> Thus, it only uses the call to crypto_kdf108_ctr_generate.
>
> The change removes the specific code that adds a zero padding that was
> intended to be invoked when the DH operation result was smaller than the
> modulus. However, this cannot occur any more these days because the
> function mpi_write_to_sgl is used in the code path that calculates the
> shared secret in dh_compute_value. This MPI service function guarantees
> that leading zeros are introduced as needed to ensure the resulting data
> is exactly as long as the modulus. This implies that the specific code
> to add zero padding is dead code which can be safely removed.
Should be thn split into two patches, i.e. prepended with a patch
removing the dead code.
/Jarkko
> Signed-off-by: Stephan Mueller <smueller@...onox.de>
> ---
> security/keys/Kconfig | 2 +-
> security/keys/dh.c | 118 ++++++------------------------------------
> 2 files changed, 17 insertions(+), 103 deletions(-)
>
> diff --git a/security/keys/Kconfig b/security/keys/Kconfig
> index 83bc23409164..e6604499f0a8 100644
> --- a/security/keys/Kconfig
> +++ b/security/keys/Kconfig
> @@ -106,7 +106,7 @@ config KEY_DH_OPERATIONS
> bool "Diffie-Hellman operations on retained keys"
> depends on KEYS
> select CRYPTO
> - select CRYPTO_HASH
> + select CRYPTO_KDF800108_CTR
> select CRYPTO_DH
> help
> This option provides support for calculating Diffie-Hellman
> diff --git a/security/keys/dh.c b/security/keys/dh.c
> index 1abfa70ed6e1..46fa442b81ec 100644
> --- a/security/keys/dh.c
> +++ b/security/keys/dh.c
> @@ -11,6 +11,7 @@
> #include <crypto/hash.h>
> #include <crypto/kpp.h>
> #include <crypto/dh.h>
> +#include <crypto/kdf_sp800108.h>
> #include <keys/user-type.h>
> #include "internal.h"
>
> @@ -79,16 +80,9 @@ static void dh_crypto_done(struct crypto_async_request *req, int err)
> complete(&compl->completion);
> }
>
> -struct kdf_sdesc {
> - struct shash_desc shash;
> - char ctx[];
> -};
> -
> -static int kdf_alloc(struct kdf_sdesc **sdesc_ret, char *hashname)
> +static int kdf_alloc(struct crypto_shash **hash, char *hashname)
> {
> struct crypto_shash *tfm;
> - struct kdf_sdesc *sdesc;
> - int size;
> int err;
>
> /* allocate synchronous hash */
> @@ -102,14 +96,7 @@ static int kdf_alloc(struct kdf_sdesc **sdesc_ret, char *hashname)
> if (crypto_shash_digestsize(tfm) == 0)
> goto out_free_tfm;
>
> - err = -ENOMEM;
> - size = sizeof(struct shash_desc) + crypto_shash_descsize(tfm);
> - sdesc = kmalloc(size, GFP_KERNEL);
> - if (!sdesc)
> - goto out_free_tfm;
> - sdesc->shash.tfm = tfm;
> -
> - *sdesc_ret = sdesc;
> + *hash = tfm;
>
> return 0;
>
> @@ -118,92 +105,20 @@ static int kdf_alloc(struct kdf_sdesc **sdesc_ret, char *hashname)
> return err;
> }
>
> -static void kdf_dealloc(struct kdf_sdesc *sdesc)
> -{
> - if (!sdesc)
> - return;
> -
> - if (sdesc->shash.tfm)
> - crypto_free_shash(sdesc->shash.tfm);
> -
> - kfree_sensitive(sdesc);
> -}
> -
> -/*
> - * Implementation of the KDF in counter mode according to SP800-108 section 5.1
> - * as well as SP800-56A section 5.8.1 (Single-step KDF).
> - *
> - * SP800-56A:
> - * The src pointer is defined as Z || other info where Z is the shared secret
> - * from DH and other info is an arbitrary string (see SP800-56A section
> - * 5.8.1.2).
> - *
> - * 'dlen' must be a multiple of the digest size.
> - */
> -static int kdf_ctr(struct kdf_sdesc *sdesc, const u8 *src, unsigned int slen,
> - u8 *dst, unsigned int dlen, unsigned int zlen)
> +static void kdf_dealloc(struct crypto_shash *hash)
> {
> - struct shash_desc *desc = &sdesc->shash;
> - unsigned int h = crypto_shash_digestsize(desc->tfm);
> - int err = 0;
> - u8 *dst_orig = dst;
> - __be32 counter = cpu_to_be32(1);
> -
> - while (dlen) {
> - err = crypto_shash_init(desc);
> - if (err)
> - goto err;
> -
> - err = crypto_shash_update(desc, (u8 *)&counter, sizeof(__be32));
> - if (err)
> - goto err;
> -
> - if (zlen && h) {
> - u8 tmpbuffer[32];
> - size_t chunk = min_t(size_t, zlen, sizeof(tmpbuffer));
> - memset(tmpbuffer, 0, chunk);
> -
> - do {
> - err = crypto_shash_update(desc, tmpbuffer,
> - chunk);
> - if (err)
> - goto err;
> -
> - zlen -= chunk;
> - chunk = min_t(size_t, zlen, sizeof(tmpbuffer));
> - } while (zlen);
> - }
> -
> - if (src && slen) {
> - err = crypto_shash_update(desc, src, slen);
> - if (err)
> - goto err;
> - }
> -
> - err = crypto_shash_final(desc, dst);
> - if (err)
> - goto err;
> -
> - dlen -= h;
> - dst += h;
> - counter = cpu_to_be32(be32_to_cpu(counter) + 1);
> - }
> -
> - return 0;
> -
> -err:
> - memzero_explicit(dst_orig, dlen);
> - return err;
> + if (hash)
> + crypto_free_shash(hash);
> }
>
> -static int keyctl_dh_compute_kdf(struct kdf_sdesc *sdesc,
> +static int keyctl_dh_compute_kdf(struct crypto_shash *hash,
> char __user *buffer, size_t buflen,
> - uint8_t *kbuf, size_t kbuflen, size_t lzero)
> + uint8_t *kbuf, size_t kbuflen)
> {
> + struct kvec kbuf_iov = { .iov_base = kbuf, .iov_len = kbuflen };
> uint8_t *outbuf = NULL;
> int ret;
> - size_t outbuf_len = roundup(buflen,
> - crypto_shash_digestsize(sdesc->shash.tfm));
> + size_t outbuf_len = roundup(buflen, crypto_shash_digestsize(hash));
>
> outbuf = kmalloc(outbuf_len, GFP_KERNEL);
> if (!outbuf) {
> @@ -211,7 +126,7 @@ static int keyctl_dh_compute_kdf(struct kdf_sdesc *sdesc,
> goto err;
> }
>
> - ret = kdf_ctr(sdesc, kbuf, kbuflen, outbuf, outbuf_len, lzero);
> + ret = crypto_kdf108_ctr_generate(hash, &kbuf_iov, 1, outbuf, outbuf_len);
> if (ret)
> goto err;
>
> @@ -240,7 +155,7 @@ long __keyctl_dh_compute(struct keyctl_dh_params __user *params,
> struct kpp_request *req;
> uint8_t *secret;
> uint8_t *outbuf;
> - struct kdf_sdesc *sdesc = NULL;
> + struct crypto_shash *hash = NULL;
>
> if (!params || (!buffer && buflen)) {
> ret = -EINVAL;
> @@ -273,7 +188,7 @@ long __keyctl_dh_compute(struct keyctl_dh_params __user *params,
> }
>
> /* allocate KDF from the kernel crypto API */
> - ret = kdf_alloc(&sdesc, hashname);
> + ret = kdf_alloc(&hash, hashname);
> kfree(hashname);
> if (ret)
> goto out1;
> @@ -383,9 +298,8 @@ long __keyctl_dh_compute(struct keyctl_dh_params __user *params,
> goto out6;
> }
>
> - ret = keyctl_dh_compute_kdf(sdesc, buffer, buflen, outbuf,
> - req->dst_len + kdfcopy->otherinfolen,
> - outlen - req->dst_len);
> + ret = keyctl_dh_compute_kdf(hash, buffer, buflen, outbuf,
> + req->dst_len + kdfcopy->otherinfolen);
> } else if (copy_to_user(buffer, outbuf, req->dst_len) == 0) {
> ret = req->dst_len;
> } else {
> @@ -403,7 +317,7 @@ long __keyctl_dh_compute(struct keyctl_dh_params __user *params,
> out2:
> dh_free_data(&dh_inputs);
> out1:
> - kdf_dealloc(sdesc);
> + kdf_dealloc(hash);
> return ret;
> }
>
Powered by blists - more mailing lists