From: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
To: Thara Gopinath <thara.gopinath@gmail.com>,
Herbert Xu <herbert@gondor.apana.org.au>,
"David S. Miller" <davem@davemloft.net>,
Stanimir Varbanov <svarbanov@mm-sol.com>,
Eneas U de Queiroz <cotequeiroz@gmail.com>,
Kuldeep Singh <kuldeep.singh@oss.qualcomm.com>,
Eric Biggers <ebiggers@kernel.org>
Cc: linux-crypto@vger.kernel.org, linux-arm-msm@vger.kernel.org,
linux-kernel@vger.kernel.org, brgl@kernel.org,
Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>,
stable@vger.kernel.org
Subject: [PATCH v3 2/8] crypto: qce - Fix HMAC self-test failures for empty messages
Date: Wed, 17 Jun 2026 17:49:31 +0200 [thread overview]
Message-ID: <20260617-qce-fix-self-tests-v3-2-ecc2b4dedcfd@oss.qualcomm.com> (raw)
In-Reply-To: <20260617-qce-fix-self-tests-v3-0-ecc2b4dedcfd@oss.qualcomm.com>
BAM DMA cannot process zero-length transfers. For plain hashes this is
handled by returning the precomputed hash of the empty message
(tmpl->hash_zero), but for keyed HMAC the result depends on the key and
cannot be a constant. As a result, hmac(sha256) produced an incorrect
digest for an empty message and the crypto self-tests failed.
Allocate a software fallback ahash for the HMAC transforms and use it to
compute the digest whenever the message is empty (in both the .final()
and .digest() paths). The fallback is allocated in a dedicated cra_init
for the HMAC algorithms and is excluded from matching the crypto engine's
own algorithm to avoid recursion. It is kept keyed in sync with the
hardware transform in .setkey().
Cc: stable@vger.kernel.org
Fixes: ec8f5d8f6f76 ("crypto: qce - Qualcomm crypto engine driver")
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
---
drivers/crypto/qce/sha.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++-
drivers/crypto/qce/sha.h | 1 +
2 files changed, 84 insertions(+), 1 deletion(-)
diff --git a/drivers/crypto/qce/sha.c b/drivers/crypto/qce/sha.c
index 0a3f88aaf5169ea7b47a549bbc10ea87d3ae7a2b..d4d0bf88dea6bf1c58ee103cdccbbbfc266110e1 100644
--- a/drivers/crypto/qce/sha.c
+++ b/drivers/crypto/qce/sha.c
@@ -270,6 +270,36 @@ static int qce_ahash_update(struct ahash_request *req)
return qce->async_req_enqueue(tmpl->qce, &req->base);
}
+/*
+ * BAM DMA cannot handle zero-length transfers. For plain hashes the result of
+ * an empty message is a known constant (hash_zero), for keyed HMAC it depends
+ * on the key, so compute it with the software fallback.
+ */
+static int qce_ahash_hmac_zero(struct ahash_request *req)
+{
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct qce_sha_ctx *ctx = crypto_tfm_ctx(crypto_ahash_tfm(tfm));
+ struct ahash_request *subreq;
+ struct crypto_wait wait;
+ struct scatterlist sg;
+ int ret;
+
+ subreq = ahash_request_alloc(ctx->fallback, GFP_ATOMIC);
+ if (!subreq)
+ return -ENOMEM;
+
+ crypto_init_wait(&wait);
+ ahash_request_set_callback(subreq, CRYPTO_TFM_REQ_MAY_BACKLOG,
+ crypto_req_done, &wait);
+ sg_init_one(&sg, NULL, 0);
+ ahash_request_set_crypt(subreq, &sg, req->result, 0);
+
+ ret = crypto_wait_req(crypto_ahash_digest(subreq), &wait);
+
+ ahash_request_free(subreq);
+ return ret;
+}
+
static int qce_ahash_final(struct ahash_request *req)
{
struct qce_sha_reqctx *rctx = ahash_request_ctx_dma(req);
@@ -280,6 +310,8 @@ static int qce_ahash_final(struct ahash_request *req)
if (tmpl->hash_zero)
memcpy(req->result, tmpl->hash_zero,
tmpl->alg.ahash.halg.digestsize);
+ else if (IS_SHA_HMAC(rctx->flags))
+ return qce_ahash_hmac_zero(req);
return 0;
}
@@ -317,6 +349,8 @@ static int qce_ahash_digest(struct ahash_request *req)
if (tmpl->hash_zero)
memcpy(req->result, tmpl->hash_zero,
tmpl->alg.ahash.halg.digestsize);
+ else if (IS_SHA_HMAC(rctx->flags))
+ return qce_ahash_hmac_zero(req);
return 0;
}
@@ -340,6 +374,17 @@ static int qce_ahash_hmac_setkey(struct crypto_ahash *tfm, const u8 *key,
blocksize = crypto_tfm_alg_blocksize(crypto_ahash_tfm(tfm));
memset(ctx->authkey, 0, sizeof(ctx->authkey));
+ /*
+ * Keep the software fallback keyed in sync - it is used for empty
+ * messages, which the DMA engine cannot process.
+ */
+ crypto_ahash_clear_flags(ctx->fallback, CRYPTO_TFM_REQ_MASK);
+ crypto_ahash_set_flags(ctx->fallback,
+ crypto_ahash_get_flags(tfm) & CRYPTO_TFM_REQ_MASK);
+ ret = crypto_ahash_setkey(ctx->fallback, key, keylen);
+ if (ret)
+ return ret;
+
if (keylen <= blocksize) {
memcpy(ctx->authkey, key, keylen);
return 0;
@@ -395,6 +440,36 @@ static int qce_ahash_cra_init(struct crypto_tfm *tfm)
return 0;
}
+static int qce_ahash_hmac_cra_init(struct crypto_tfm *tfm)
+{
+ struct qce_sha_ctx *ctx = crypto_tfm_ctx(tfm);
+ struct crypto_ahash *fallback;
+ int ret;
+
+ ret = qce_ahash_cra_init(tfm);
+ if (ret)
+ return ret;
+
+ /*
+ * The fallback is used to compute HMACs of empty messages, which the
+ * DMA engine cannot process.
+ */
+ fallback = crypto_alloc_ahash(crypto_tfm_alg_name(tfm), 0,
+ CRYPTO_ALG_NEED_FALLBACK);
+ if (IS_ERR(fallback))
+ return PTR_ERR(fallback);
+
+ ctx->fallback = fallback;
+ return 0;
+}
+
+static void qce_ahash_hmac_cra_exit(struct crypto_tfm *tfm)
+{
+ struct qce_sha_ctx *ctx = crypto_tfm_ctx(tfm);
+
+ crypto_free_ahash(ctx->fallback);
+}
+
struct qce_ahash_def {
unsigned long flags;
const char *name;
@@ -462,7 +537,14 @@ static int qce_ahash_register_one(const struct qce_ahash_def *def,
base->cra_ctxsize = sizeof(struct qce_sha_ctx);
base->cra_alignmask = 0;
base->cra_module = THIS_MODULE;
- base->cra_init = qce_ahash_cra_init;
+
+ if (IS_SHA_HMAC(def->flags)) {
+ base->cra_flags |= CRYPTO_ALG_NEED_FALLBACK;
+ base->cra_init = qce_ahash_hmac_cra_init;
+ base->cra_exit = qce_ahash_hmac_cra_exit;
+ } else {
+ base->cra_init = qce_ahash_cra_init;
+ }
strscpy(base->cra_name, def->name);
strscpy(base->cra_driver_name, def->drv_name);
diff --git a/drivers/crypto/qce/sha.h b/drivers/crypto/qce/sha.h
index cb822fc334dc187cf1c66e2a332822a596ebcef3..2fa173ff2b2ec4031710ab6e3b14c28b04e0a746 100644
--- a/drivers/crypto/qce/sha.h
+++ b/drivers/crypto/qce/sha.h
@@ -17,6 +17,7 @@
struct qce_sha_ctx {
u8 authkey[QCE_SHA_MAX_BLOCKSIZE];
+ struct crypto_ahash *fallback;
};
/**
--
2.47.3
next prev parent reply other threads:[~2026-06-17 15:49 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-17 15:49 [PATCH v3 0/8] crypto: qce - Fix crypto self-test failures Bartosz Golaszewski
2026-06-17 15:49 ` [PATCH v3 1/8] crypto: qce - Remove unsafe/deprecated algorithms Bartosz Golaszewski
2026-06-17 16:05 ` Eric Biggers
2026-06-17 15:49 ` Bartosz Golaszewski [this message]
2026-06-17 15:49 ` [PATCH v3 3/8] crypto: qce - Reject empty messages for AES-XTS Bartosz Golaszewski
2026-06-17 15:49 ` [PATCH v3 4/8] crypto: qce - Fix CTR-AES for partial block requests Bartosz Golaszewski
2026-06-17 15:49 ` [PATCH v3 5/8] crypto: qce - Use a fallback for AES-CTR with a partial final block Bartosz Golaszewski
2026-06-17 15:49 ` [PATCH v3 6/8] crypto: qce - Fix xts-aes-qce for weak keys Bartosz Golaszewski
2026-06-17 15:49 ` [PATCH v3 7/8] crypto: qce - Use a fallback for CCM with a partial final block Bartosz Golaszewski
2026-06-17 15:49 ` [PATCH v3 8/8] crypto: qce - Use fallback for CCM with a fragmented payload Bartosz Golaszewski
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260617-qce-fix-self-tests-v3-2-ecc2b4dedcfd@oss.qualcomm.com \
--to=bartosz.golaszewski@oss.qualcomm.com \
--cc=brgl@kernel.org \
--cc=cotequeiroz@gmail.com \
--cc=davem@davemloft.net \
--cc=ebiggers@kernel.org \
--cc=herbert@gondor.apana.org.au \
--cc=kuldeep.singh@oss.qualcomm.com \
--cc=linux-arm-msm@vger.kernel.org \
--cc=linux-crypto@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=stable@vger.kernel.org \
--cc=svarbanov@mm-sol.com \
--cc=thara.gopinath@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox