2016-08-30 15:53:49

by Iaroslav Gridin

[permalink] [raw]
Subject: (unknown)


This set of patches fixes QCE digest code, preventing lockups and incorrect results.


2016-08-30 15:53:50

by Iaroslav Gridin

[permalink] [raw]
Subject: [PATCH 1/4] crypto: qce: Remove unneeded length check for scatterlist

From: Voker57 <[email protected]>

Current code avoids supplying scatterlist containing more data than used
to DMA. This leads to dropping data from scatterlists which would
leave some for next run.
Signed-off-by: Iaroslav Gridin <[email protected]>
---
drivers/crypto/qce/sha.c | 2 --
1 file changed, 2 deletions(-)

diff --git a/drivers/crypto/qce/sha.c b/drivers/crypto/qce/sha.c
index 47e114a..a124bb9 100644
--- a/drivers/crypto/qce/sha.c
+++ b/drivers/crypto/qce/sha.c
@@ -282,8 +282,6 @@ static int qce_ahash_update(struct ahash_request *req)
sg = sg_last = req->src;

while (len < nbytes && sg) {
- if (len + sg_dma_len(sg) > nbytes)
- break;
len += sg_dma_len(sg);
sg_last = sg;
sg = sg_next(sg);
--
2.9.3

2016-08-30 15:53:51

by Iaroslav Gridin

[permalink] [raw]
Subject: [PATCH 2/4] crypto: qce: Avoid repeat hash finalization

From: Voker57 <[email protected]>

Calling QCE finalization when hash have already been finalized causes
a lockup. Avoid it by introducing finalized flag.
Signed-off-by: Iaroslav Gridin <[email protected]>
---
drivers/crypto/qce/sha.c | 6 ++++++
drivers/crypto/qce/sha.h | 1 +
2 files changed, 7 insertions(+)

diff --git a/drivers/crypto/qce/sha.c b/drivers/crypto/qce/sha.c
index a124bb9..a068d39 100644
--- a/drivers/crypto/qce/sha.c
+++ b/drivers/crypto/qce/sha.c
@@ -139,6 +139,7 @@ static int qce_ahash_init(struct ahash_request *req)
rctx->first_blk = true;
rctx->last_blk = false;
rctx->flags = tmpl->alg_flags;
+ rctx->finalized = false;
memcpy(rctx->digest, std_iv, sizeof(rctx->digest));

return 0;
@@ -314,7 +315,12 @@ static int qce_ahash_final(struct ahash_request *req)
if (!rctx->buflen)
return 0;

+ /* If hash is already been finalized, don't do anything */
+ if (rctx->finalized)
+ return 0;
+
rctx->last_blk = true;
+ rctx->finalized = true;

rctx->src_orig = req->src;
rctx->nbytes_orig = req->nbytes;
diff --git a/drivers/crypto/qce/sha.h b/drivers/crypto/qce/sha.h
index 236bb5e9..b24568f 100644
--- a/drivers/crypto/qce/sha.h
+++ b/drivers/crypto/qce/sha.h
@@ -59,6 +59,7 @@ struct qce_sha_reqctx {
u64 count;
bool first_blk;
bool last_blk;
+ bool finalized;
struct scatterlist sg[2];
u8 *authkey;
unsigned int authklen;
--
2.9.3

2016-08-30 15:54:25

by Iaroslav Gridin

[permalink] [raw]
Subject: [PATCH 4/4] crypto: qce: If total text size is zero, return pre-computed digest

From: Voker57 <[email protected]>

If total data amount to hash is zero, we cannot submit it to QCE,
since it locks up on zero-sized updates. So, return pre-computed
SHA256/SHA1 hash.
Signed-off-by: Iaroslav Gridin <[email protected]>
---
drivers/crypto/qce/sha.c | 27 ++++++++++++++++++++++++---
1 file changed, 24 insertions(+), 3 deletions(-)

diff --git a/drivers/crypto/qce/sha.c b/drivers/crypto/qce/sha.c
index f199f28..c627b5d 100644
--- a/drivers/crypto/qce/sha.c
+++ b/drivers/crypto/qce/sha.c
@@ -80,6 +80,7 @@ static int qce_ahash_async_req_handle(struct crypto_async_request *async_req)
struct qce_sha_ctx *ctx = crypto_tfm_ctx(async_req->tfm);
struct qce_alg_template *tmpl = to_ahash_tmpl(async_req->tfm);
struct qce_device *qce = tmpl->qce;
+ unsigned int digestsize = crypto_ahash_digestsize(crypto_ahash_reqtfm(req));
unsigned long flags = rctx->flags;
int ret;

@@ -91,6 +92,29 @@ static int qce_ahash_async_req_handle(struct crypto_async_request *async_req)
rctx->authklen = AES_KEYSIZE_128;
}

+ if (!req->nbytes) {
+ /* Only way that can happen is if total size of digest is zero
+ * So since QCE gets stuck on zero-sized texts, we return
+ * pre-calculated hash
+ */
+ if (digestsize == SHA1_DIGEST_SIZE) {
+ memcpy(rctx->digest,
+ "\xda\x39\xa3\xee\x5e\x6b\x4b\x0d\x32\x55\xbf\xef\x95\x60\x18\x90\xaf\xd8\x07\x09",
+ SHA1_DIGEST_SIZE);
+ } else if (digestsize == SHA256_DIGEST_SIZE) {
+ memcpy(rctx->digest,
+ "\xe3\xb0\xc4\x42\x98\xfc\x1c\x14\x9a\xfb\xf4\xc8\x99\x6f\xb9\x24\x27\xae\x41\xe4\x64\x9b\x93\x4c\xa4\x95\x99\x1b\x78\x52\xb8\x55",
+ SHA256_DIGEST_SIZE);
+ } else {
+ qce->async_req_done(tmpl->qce, -EINVAL);
+ return -EINVAL;
+ }
+ if (req->result)
+ memcpy(req->result, rctx->digest, digestsize);
+ qce->async_req_done(tmpl->qce, 0);
+ return 0;
+ }
+
rctx->src_nents = sg_nents_for_len(req->src, req->nbytes);
if (rctx->src_nents < 0) {
dev_err(qce->dev, "Invalid numbers of src SG.\n");
@@ -322,9 +346,6 @@ static int qce_ahash_final(struct ahash_request *req)
struct qce_alg_template *tmpl = to_ahash_tmpl(req->base.tfm);
struct qce_device *qce = tmpl->qce;

- if (!rctx->buflen)
- return 0;
-
/* If hash is already been finalized, don't do anything */
if (rctx->finalized)
return 0;
--
2.9.3

2016-08-30 15:54:22

by Iaroslav Gridin

[permalink] [raw]
Subject: [PATCH 3/4] crypto: qce: Ensure QCE receives no zero-sized updates

From: Voker57 <[email protected]>

Zero-sized updates lock QCE, so ensure there's always some data left
for the final update, up to blocksize.
Signed-off-by: Iaroslav Gridin <[email protected]>
---
drivers/crypto/qce/sha.c | 30 ++++++++++++++++++++----------
1 file changed, 20 insertions(+), 10 deletions(-)

diff --git a/drivers/crypto/qce/sha.c b/drivers/crypto/qce/sha.c
index a068d39..f199f28 100644
--- a/drivers/crypto/qce/sha.c
+++ b/drivers/crypto/qce/sha.c
@@ -240,9 +240,11 @@ static int qce_ahash_update(struct ahash_request *req)
struct qce_device *qce = tmpl->qce;
struct scatterlist *sg_last, *sg;
unsigned int total, len;
+ unsigned int tmpbuflen = 0;
unsigned int hash_later;
unsigned int nbytes;
unsigned int blocksize;
+ unsigned int src_offset;

blocksize = crypto_tfm_alg_blocksize(crypto_ahash_tfm(tfm));
rctx->count += req->nbytes;
@@ -265,21 +267,30 @@ static int qce_ahash_update(struct ahash_request *req)
* if we have data from previous update copy them on buffer. The old
* data will be combined with current request bytes.
*/
- if (rctx->buflen)
+ if (rctx->buflen) {
memcpy(rctx->tmpbuf, rctx->buf, rctx->buflen);
+ tmpbuflen = rctx->buflen;
+ }

/* calculate how many bytes will be hashed later */
hash_later = total % blocksize;
- if (hash_later) {
- unsigned int src_offset = req->nbytes - hash_later;
- scatterwalk_map_and_copy(rctx->buf, req->src, src_offset,
- hash_later, 0);
- }
+ /* ensure we always have something on buffer */
+ if (hash_later == 0)
+ hash_later = blocksize;
+ src_offset = req->nbytes - hash_later;
+ scatterwalk_map_and_copy(rctx->buf, req->src, src_offset,
+ hash_later, 0);
+ rctx->buflen = hash_later;

/* here nbytes is multiple of blocksize */
nbytes = total - hash_later;

- len = rctx->buflen;
+ len = tmpbuflen;
+
+ /* Zero-length update is a no-op */
+ if (nbytes == 0)
+ return 0;
+
sg = sg_last = req->src;

while (len < nbytes && sg) {
@@ -293,15 +304,14 @@ static int qce_ahash_update(struct ahash_request *req)

sg_mark_end(sg_last);

- if (rctx->buflen) {
+ if (tmpbuflen) {
sg_init_table(rctx->sg, 2);
- sg_set_buf(rctx->sg, rctx->tmpbuf, rctx->buflen);
+ sg_set_buf(rctx->sg, rctx->tmpbuf, tmpbuflen);
sg_chain(rctx->sg, 2, req->src);
req->src = rctx->sg;
}

req->nbytes = nbytes;
- rctx->buflen = hash_later;

return qce->async_req_enqueue(tmpl->qce, &req->base);
}
--
2.9.3

2016-08-30 16:02:46

by Corentin Labbe

[permalink] [raw]
Subject: Re: [PATCH 4/4] crypto: qce: If total text size is zero, return pre-computed digest

On 30/08/2016 17:53, Iaroslav Gridin wrote:
> From: Voker57 <[email protected]>
>
> If total data amount to hash is zero, we cannot submit it to QCE,
> since it locks up on zero-sized updates. So, return pre-computed
> SHA256/SHA1 hash.
> Signed-off-by: Iaroslav Gridin <[email protected]>
> ---
> drivers/crypto/qce/sha.c | 27 ++++++++++++++++++++++++---
> 1 file changed, 24 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/crypto/qce/sha.c b/drivers/crypto/qce/sha.c
> index f199f28..c627b5d 100644
> --- a/drivers/crypto/qce/sha.c
> +++ b/drivers/crypto/qce/sha.c
> @@ -80,6 +80,7 @@ static int qce_ahash_async_req_handle(struct crypto_async_request *async_req)
> struct qce_sha_ctx *ctx = crypto_tfm_ctx(async_req->tfm);
> struct qce_alg_template *tmpl = to_ahash_tmpl(async_req->tfm);
> struct qce_device *qce = tmpl->qce;
> + unsigned int digestsize = crypto_ahash_digestsize(crypto_ahash_reqtfm(req));
> unsigned long flags = rctx->flags;
> int ret;
>
> @@ -91,6 +92,29 @@ static int qce_ahash_async_req_handle(struct crypto_async_request *async_req)
> rctx->authklen = AES_KEYSIZE_128;
> }
>
> + if (!req->nbytes) {
> + /* Only way that can happen is if total size of digest is zero
> + * So since QCE gets stuck on zero-sized texts, we return
> + * pre-calculated hash
> + */
> + if (digestsize == SHA1_DIGEST_SIZE) {
> + memcpy(rctx->digest,
> + "\xda\x39\xa3\xee\x5e\x6b\x4b\x0d\x32\x55\xbf\xef\x95\x60\x18\x90\xaf\xd8\x07\x09",
> + SHA1_DIGEST_SIZE);
> + } else if (digestsize == SHA256_DIGEST_SIZE) {
> + memcpy(rctx->digest,
> + "\xe3\xb0\xc4\x42\x98\xfc\x1c\x14\x9a\xfb\xf4\xc8\x99\x6f\xb9\x24\x27\xae\x41\xe4\x64\x9b\x93\x4c\xa4\x95\x99\x1b\x78\x52\xb8\x55",
> + SHA256_DIGEST_SIZE);

Hello

You could use sha1_zero_message_hash/sha256_zero_message_hash declared in crypto/sha.h

Regards