[PATCH] crypto: hash - Add default handlers for digest, export, import

From: David Yang
Date: Thu May 04 2023 - 05:33:42 EST


The document of struct ahash_alg explicitly states that @finup,
combination of @update and @final, is optional, while said nothing about
@digest, which is combination of @init and @finup (@update and @final).

This gives a illusion that @digest might be optional. However
crypto_ahash_init_tfm() strangely does expect a non-NULL @digest,
otherwise it'll result in NULL pointer dereference.

Add default handlers for digest, export, import according to the behavior
in the document, and mark them optional.

Signed-off-by: David Yang <mmyangfl@xxxxxxxxx>
---
crypto/ahash.c | 28 +++++++++++++++++++++++++---
include/crypto/hash.h | 12 ++++++------
2 files changed, 31 insertions(+), 9 deletions(-)

diff --git a/crypto/ahash.c b/crypto/ahash.c
index b8a607928e72..53abbfe58a5f 100644
--- a/crypto/ahash.c
+++ b/crypto/ahash.c
@@ -417,6 +417,28 @@ static int ahash_def_finup(struct ahash_request *req)
return ahash_def_finup_finish1(req, err);
}

+static int ahash_def_digest(struct ahash_request *req)
+{
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ int err;
+
+ err = tfm->init(req);
+ if (err)
+ return err;
+
+ return ahash_def_finup(req);
+}
+
+static int ahash_def_noexport(struct ahash_request *req, void *out)
+{
+ return -EINVAL;
+}
+
+static int ahash_def_noimport(struct ahash_request *req, const void *in)
+{
+ return -EINVAL;
+}
+
static void crypto_ahash_exit_tfm(struct crypto_tfm *tfm)
{
struct crypto_ahash *hash = __crypto_ahash_cast(tfm);
@@ -439,9 +461,9 @@ static int crypto_ahash_init_tfm(struct crypto_tfm *tfm)
hash->update = alg->update;
hash->final = alg->final;
hash->finup = alg->finup ?: ahash_def_finup;
- hash->digest = alg->digest;
- hash->export = alg->export;
- hash->import = alg->import;
+ hash->digest = alg->digest ?: ahash_def_digest;
+ hash->export = alg->export ?: ahash_def_noexport;
+ hash->import = alg->import ?: ahash_def_noimport;

if (alg->setkey) {
hash->setkey = alg->setkey;
diff --git a/include/crypto/hash.h b/include/crypto/hash.h
index e69542d86a2b..17dee80ac76a 100644
--- a/include/crypto/hash.h
+++ b/include/crypto/hash.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Hash: Hash algorithms under the crypto API
- *
+ *
* Copyright (c) 2008 Herbert Xu <herbert@xxxxxxxxxxxxxxxxxxx>
*/

@@ -110,7 +110,7 @@ struct ahash_request {
* added to allow such hardware to be used at least by IPsec. Data
* processing can happen synchronously [SHASH] or asynchronously [AHASH]
* at this point.
- * @digest: Combination of @init and @update and @final. This function
+ * @digest: **[optional]** Combination of @init and @update and @final. This function
* effectively behaves as the entire chain of operations, @init,
* @update and @final issued in sequence. Just like @finup, this was
* added for hardware which cannot do even the @finup, but can only do
@@ -129,15 +129,15 @@ struct ahash_request {
* this function. This function must be called before any other of the
* @init, @update, @final, @finup, @digest is called. No data
* processing happens at this point.
- * @export: Export partial state of the transformation. This function dumps the
- * entire state of the ongoing transformation into a provided block of
+ * @export: **[optional]** Export partial state of the transformation. This function
+ * dumps the entire state of the ongoing transformation into a provided block of
* data so it can be @import 'ed back later on. This is useful in case
* you want to save partial result of the transformation after
* processing certain amount of data and reload this partial result
* multiple times later on for multiple re-use. No data processing
* happens at this point. Driver must not use req->result.
- * @import: Import partial state of the transformation. This function loads the
- * entire state of the ongoing transformation from a provided block of
+ * @import: **[optional]** Import partial state of the transformation. This function
+ * loads the entire state of the ongoing transformation from a provided block of
* data so the transformation can continue from this point onward. No
* data processing happens at this point. Driver must not use
* req->result.
--
2.39.2