1
linux/arch/s390/crypto/sha_common.c
Ingo Franzki 992b706680 s390/sha3: Fix SHA3 selftests failures
Since commit "s390/sha3: Support sha3 performance enhancements"
the selftests of the sha3_256_s390 and sha3_512_s390 kernel digests
sometimes fail with:

  alg: shash: sha3-256-s390 test failed (wrong result) on test vector 3,
              cfg="import/export"
  alg: self-tests for sha3-256 using sha3-256-s390 failed (rc=-22)

or with

  alg: ahash: sha3-256-s390 test failed (wrong result) on test vector 3,
              cfg="digest misaligned splits crossing pages"
  alg: self-tests for sha3-256 using sha3-256-s390 failed (rc=-22)

The first failure is because the newly introduced context field
'first_message_part' is not copied during export and import operations.
Because of that the value of 'first_message_part' is more or less random
after an import into a newly allocated context and may or may not fit to
the state of the imported SHA3 operation, causing an invalid hash when it
does not fit.

Save the 'first_message_part' field in the currently unused field 'partial'
of struct sha3_state, even though the meaning of 'partial' is not exactly
the same as 'first_message_part'. For the caller the returned state blob
is opaque and it must only be ensured that the state can be imported later
on by the module that exported it.

The second failure is when on entry of s390_sha_update() the flag
'first_message_part' is on, and kimd is called in the first 'if (index)'
block as well as in the second 'if (len >= bsize)' block. In this case,
the 'first_message_part' is turned off after the first kimd, but the
function code incorrectly retains the NIP flag. Reset the NIP flag after
the first kimd unconditionally besides turning 'first_message_part' off.

Reported-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Fixes: 88c02b3f79 ("s390/sha3: Support sha3 performance enhancements")
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
Reviewed-by: Holger Dengler <dengler@linux.ibm.com>
Reviewed-by: Joerg Schmidbauer <jschmidb@de.ibm.com>
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
2024-09-05 15:17:23 +02:00

137 lines
3.1 KiB
C

// SPDX-License-Identifier: GPL-2.0+
/*
* Cryptographic API.
*
* s390 generic implementation of the SHA Secure Hash Algorithms.
*
* Copyright IBM Corp. 2007
* Author(s): Jan Glauber (jang@de.ibm.com)
*/
#include <crypto/internal/hash.h>
#include <linux/module.h>
#include <asm/cpacf.h>
#include "sha.h"
int s390_sha_update(struct shash_desc *desc, const u8 *data, unsigned int len)
{
struct s390_sha_ctx *ctx = shash_desc_ctx(desc);
unsigned int bsize = crypto_shash_blocksize(desc->tfm);
unsigned int index, n;
int fc;
/* how much is already in the buffer? */
index = ctx->count % bsize;
ctx->count += len;
if ((index + len) < bsize)
goto store;
fc = ctx->func;
if (ctx->first_message_part)
fc |= test_facility(86) ? CPACF_KIMD_NIP : 0;
/* process one stored block */
if (index) {
memcpy(ctx->buf + index, data, bsize - index);
cpacf_kimd(fc, ctx->state, ctx->buf, bsize);
ctx->first_message_part = 0;
fc &= ~CPACF_KIMD_NIP;
data += bsize - index;
len -= bsize - index;
index = 0;
}
/* process as many blocks as possible */
if (len >= bsize) {
n = (len / bsize) * bsize;
cpacf_kimd(fc, ctx->state, data, n);
ctx->first_message_part = 0;
data += n;
len -= n;
}
store:
if (len)
memcpy(ctx->buf + index , data, len);
return 0;
}
EXPORT_SYMBOL_GPL(s390_sha_update);
static int s390_crypto_shash_parmsize(int func)
{
switch (func) {
case CPACF_KLMD_SHA_1:
return 20;
case CPACF_KLMD_SHA_256:
return 32;
case CPACF_KLMD_SHA_512:
return 64;
case CPACF_KLMD_SHA3_224:
case CPACF_KLMD_SHA3_256:
case CPACF_KLMD_SHA3_384:
case CPACF_KLMD_SHA3_512:
return 200;
default:
return -EINVAL;
}
}
int s390_sha_final(struct shash_desc *desc, u8 *out)
{
struct s390_sha_ctx *ctx = shash_desc_ctx(desc);
unsigned int bsize = crypto_shash_blocksize(desc->tfm);
u64 bits;
unsigned int n;
int mbl_offset, fc;
n = ctx->count % bsize;
bits = ctx->count * 8;
mbl_offset = s390_crypto_shash_parmsize(ctx->func);
if (mbl_offset < 0)
return -EINVAL;
mbl_offset = mbl_offset / sizeof(u32);
/* set total msg bit length (mbl) in CPACF parmblock */
switch (ctx->func) {
case CPACF_KLMD_SHA_1:
case CPACF_KLMD_SHA_256:
memcpy(ctx->state + mbl_offset, &bits, sizeof(bits));
break;
case CPACF_KLMD_SHA_512:
/*
* the SHA512 parmblock has a 128-bit mbl field, clear
* high-order u64 field, copy bits to low-order u64 field
*/
memset(ctx->state + mbl_offset, 0x00, sizeof(bits));
mbl_offset += sizeof(u64) / sizeof(u32);
memcpy(ctx->state + mbl_offset, &bits, sizeof(bits));
break;
case CPACF_KLMD_SHA3_224:
case CPACF_KLMD_SHA3_256:
case CPACF_KLMD_SHA3_384:
case CPACF_KLMD_SHA3_512:
break;
default:
return -EINVAL;
}
fc = ctx->func;
fc |= test_facility(86) ? CPACF_KLMD_DUFOP : 0;
if (ctx->first_message_part)
fc |= CPACF_KLMD_NIP;
cpacf_klmd(fc, ctx->state, ctx->buf, n);
/* copy digest to out */
memcpy(out, ctx->state, crypto_shash_digestsize(desc->tfm));
/* wipe context */
memset(ctx, 0, sizeof *ctx);
return 0;
}
EXPORT_SYMBOL_GPL(s390_sha_final);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("s390 SHA cipher common functions");