public inbox for linux-crypto@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH v6 0/2] New s390 specific protected key hmac
@ 2024-11-29 11:10 Harald Freudenberger
  2024-11-29 11:10 ` [PATCH v6 1/2] s390/crypto: Add protected key hmac subfunctions for KMAC Harald Freudenberger
  2024-11-29 11:10 ` [PATCH v6 2/2] s390/crypto: New s390 specific protected key hash phmac Harald Freudenberger
  0 siblings, 2 replies; 6+ messages in thread
From: Harald Freudenberger @ 2024-11-29 11:10 UTC (permalink / raw)
  To: herbert, davem, dengler; +Cc: linux-s390, linux-crypto

Add support for protected key hmac ("phmac") for s390 arch.

With the latest machine generation there is now support for
protected key (that is a key wrapped by a master key stored
in firmware) hmac for sha2 (sha224, sha256, sha384 and sha512)
for the s390 specific CPACF instruction kmac.

This patch adds support via 4 new hashes registered as
phmac(sha224), phmac(sha256), phmac(sha384) and phmac(sha512).

Please note that as of now, there is no selftest enabled for
these shashes, but the implementation has been tested with
testcases via AF_ALG interface. However, there may come an
improvement soon to use the available clear key hmac selftests.

Changelog:
v1: Initial version
v2: Increase HASH_MAX_DESCSIZE generic (not just for arch s390).
    Fix one finding to use kmemdup instead of kmalloc/memcpy from test
    robot. Remove unneeded cpacf subfunctions checks. Simplify
    clone_tfm() function. Rebased to s390/features.
v3: Feedback from Herbert: Use GFP_ATOMIC in setkey function.
    Feedback from Holger: rework tfm clone function, move convert key
    invocation from setkey to init function. Rebased to updated
    s390/features from 11/7/2024. Ready for integration if there are
    no complains on v3.
v4: Rewind back more or less to v2. Add code to check for non-sleeping
    context. Non-sleeping context during attempt to derive the
    protected key from raw key material is not accepted and
    -EOPNOTSUPP is returned (also currently all derivation pathes
    would in fact never sleep). In general the phmac implementation is
    not to be used within non-sleeping context and the code header
    mentions this. Tested with (patched) dm-integrity - works fine.
v5: As suggested by Herbert now the shashes have been marked as
    'internal' and wrapped by ahashes which use the cryptd if an
    atomic context is detected. So the visible phmac algorithms are
    now ahashes. Unfortunately the dm-integrity implementation
    currently requests and deals only with shashes and this phmac
    implementation is not fitting to the original goal any more...
v6: As suggested by Herbert now a pure async phmac implementation.
    Tested via AF_ALG interface. Untested via dm-integrity as this layer
    only supports shashes. Maybe I'll develop a patch to switch the
    dm-integrity to ahash as it is anyway the more flexible interface.

Harald Freudenberger (1):
  s390/crypto: New s390 specific protected key hash phmac

Holger Dengler (1):
  s390/crypto: Add protected key hmac subfunctions for KMAC

 arch/s390/configs/debug_defconfig |   1 +
 arch/s390/configs/defconfig       |   1 +
 arch/s390/crypto/Makefile         |   1 +
 arch/s390/crypto/phmac_s390.c     | 474 ++++++++++++++++++++++++++++++
 arch/s390/include/asm/cpacf.h     |   4 +
 drivers/crypto/Kconfig            |  12 +
 6 files changed, 493 insertions(+)
 create mode 100644 arch/s390/crypto/phmac_s390.c


base-commit: 3f020399e4f1c690ce87b4c472f75b1fc89e07d5
--
2.43.0


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH v6 1/2] s390/crypto: Add protected key hmac subfunctions for KMAC
  2024-11-29 11:10 [PATCH v6 0/2] New s390 specific protected key hmac Harald Freudenberger
@ 2024-11-29 11:10 ` Harald Freudenberger
  2024-11-29 11:10 ` [PATCH v6 2/2] s390/crypto: New s390 specific protected key hash phmac Harald Freudenberger
  1 sibling, 0 replies; 6+ messages in thread
From: Harald Freudenberger @ 2024-11-29 11:10 UTC (permalink / raw)
  To: herbert, davem, dengler; +Cc: linux-s390, linux-crypto

From: Holger Dengler <dengler@linux.ibm.com>

The CPACF KMAC instruction supports new subfunctions for
protected key hmac. Add defines for these 4 new subfuctions.

Signed-off-by: Holger Dengler <dengler@linux.ibm.com>
Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
---
 arch/s390/include/asm/cpacf.h | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/arch/s390/include/asm/cpacf.h b/arch/s390/include/asm/cpacf.h
index 59ab1192e2d5..0468dd5c4690 100644
--- a/arch/s390/include/asm/cpacf.h
+++ b/arch/s390/include/asm/cpacf.h
@@ -129,6 +129,10 @@
 #define CPACF_KMAC_HMAC_SHA_256	0x71
 #define CPACF_KMAC_HMAC_SHA_384	0x72
 #define CPACF_KMAC_HMAC_SHA_512	0x73
+#define CPACF_KMAC_PHMAC_SHA_224	0x78
+#define CPACF_KMAC_PHMAC_SHA_256	0x79
+#define CPACF_KMAC_PHMAC_SHA_384	0x7a
+#define CPACF_KMAC_PHMAC_SHA_512	0x7b
 
 /*
  * Function codes for the PCKMO (PERFORM CRYPTOGRAPHIC KEY MANAGEMENT)
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH v6 2/2] s390/crypto: New s390 specific protected key hash phmac
  2024-11-29 11:10 [PATCH v6 0/2] New s390 specific protected key hmac Harald Freudenberger
  2024-11-29 11:10 ` [PATCH v6 1/2] s390/crypto: Add protected key hmac subfunctions for KMAC Harald Freudenberger
@ 2024-11-29 11:10 ` Harald Freudenberger
  2024-11-29 14:48   ` Herbert Xu
  1 sibling, 1 reply; 6+ messages in thread
From: Harald Freudenberger @ 2024-11-29 11:10 UTC (permalink / raw)
  To: herbert, davem, dengler; +Cc: linux-s390, linux-crypto

Add support for protected key hmac ("phmac") for s390 arch.

With the latest machine generation there is now support for
protected key (that is a key wrapped by a master key stored
in firmware) hmac for sha2 (sha224, sha256, sha384 and sha512)
for the s390 specific CPACF instruction kmac.

This patch adds support via 4 new ahashes registered as
phmac(sha224), phmac(sha256), phmac(sha384) and phmac(sha512).

Please note that as of now, there is no selftest enabled for
these hashes, but the implementation has been tested with
testcases via AF_ALG interface.

Co-developed-by: Holger Dengler <dengler@linux.ibm.com>
Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
---
 arch/s390/configs/debug_defconfig |   1 +
 arch/s390/configs/defconfig       |   1 +
 arch/s390/crypto/Makefile         |   1 +
 arch/s390/crypto/phmac_s390.c     | 474 ++++++++++++++++++++++++++++++
 drivers/crypto/Kconfig            |  12 +
 5 files changed, 489 insertions(+)
 create mode 100644 arch/s390/crypto/phmac_s390.c

diff --git a/arch/s390/configs/debug_defconfig b/arch/s390/configs/debug_defconfig
index d8d227ab82de..c857618087fe 100644
--- a/arch/s390/configs/debug_defconfig
+++ b/arch/s390/configs/debug_defconfig
@@ -813,6 +813,7 @@ CONFIG_PKEY_EP11=m
 CONFIG_PKEY_PCKMO=m
 CONFIG_PKEY_UV=m
 CONFIG_CRYPTO_PAES_S390=m
+CONFIG_CRYPTO_PHMAC_S390=m
 CONFIG_CRYPTO_DEV_VIRTIO=m
 CONFIG_SYSTEM_BLACKLIST_KEYRING=y
 CONFIG_CORDIC=m
diff --git a/arch/s390/configs/defconfig b/arch/s390/configs/defconfig
index 6c2f2bb4fbf8..94bde39967a5 100644
--- a/arch/s390/configs/defconfig
+++ b/arch/s390/configs/defconfig
@@ -800,6 +800,7 @@ CONFIG_PKEY_EP11=m
 CONFIG_PKEY_PCKMO=m
 CONFIG_PKEY_UV=m
 CONFIG_CRYPTO_PAES_S390=m
+CONFIG_CRYPTO_PHMAC_S390=m
 CONFIG_CRYPTO_DEV_VIRTIO=m
 CONFIG_SYSTEM_BLACKLIST_KEYRING=y
 CONFIG_CORDIC=m
diff --git a/arch/s390/crypto/Makefile b/arch/s390/crypto/Makefile
index a0cb96937c3d..47637140b95c 100644
--- a/arch/s390/crypto/Makefile
+++ b/arch/s390/crypto/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_S390_PRNG) += prng.o
 obj-$(CONFIG_CRYPTO_GHASH_S390) += ghash_s390.o
 obj-$(CONFIG_CRYPTO_CRC32_S390) += crc32-vx_s390.o
 obj-$(CONFIG_CRYPTO_HMAC_S390) += hmac_s390.o
+obj-$(CONFIG_CRYPTO_PHMAC_S390) += phmac_s390.o
 obj-y += arch_random.o
 
 crc32-vx_s390-y := crc32-vx.o crc32le-vx.o crc32be-vx.o
diff --git a/arch/s390/crypto/phmac_s390.c b/arch/s390/crypto/phmac_s390.c
new file mode 100644
index 000000000000..923f97720f86
--- /dev/null
+++ b/arch/s390/crypto/phmac_s390.c
@@ -0,0 +1,474 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright IBM Corp. 2024
+ *
+ * s390 specific HMAC support for protected keys.
+ */
+
+#define KMSG_COMPONENT	"phmac_s390"
+#define pr_fmt(fmt)	KMSG_COMPONENT ": " fmt
+
+#include <asm/cpacf.h>
+#include <asm/pkey.h>
+#include <crypto/cryptd.h>
+#include <crypto/internal/hash.h>
+#include <crypto/sha2.h>
+#include <linux/cpufeature.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+
+/*
+ * KMAC param block layout for sha2 function codes:
+ * The layout of the param block for the KMAC instruction depends on the
+ * blocksize of the used hashing sha2-algorithm function codes. The param block
+ * contains the hash chaining value (cv), the input message bit-length (imbl)
+ * and the hmac-secret (key). To prevent code duplication, the sizes of all
+ * these are calculated based on the blocksize.
+ *
+ * param-block:
+ * +-------+
+ * | cv    |
+ * +-------+
+ * | imbl  |
+ * +-------+
+ * | key   |
+ * +-------+
+ *
+ * sizes:
+ * part | sh2-alg | calculation | size | type
+ * -----+---------+-------------+------+--------
+ * cv   | 224/256 | blocksize/2 |   32 |  u64[8]
+ *      | 384/512 |             |   64 | u128[8]
+ * imbl | 224/256 | blocksize/8 |    8 |     u64
+ *      | 384/512 |             |   16 |    u128
+ * key  | 224/256 | blocksize   |   96 |  u8[96]
+ *      | 384/512 |             |  160 | u8[160]
+ */
+
+#define MAX_DIGEST_SIZE		SHA512_DIGEST_SIZE
+#define MAX_IMBL_SIZE		sizeof(u128)
+#define MAX_BLOCK_SIZE		SHA512_BLOCK_SIZE
+
+#define SHA2_CV_SIZE(bs)	((bs) >> 1)
+#define SHA2_IMBL_SIZE(bs)	((bs) >> 3)
+
+#define SHA2_IMBL_OFFSET(bs)	(SHA2_CV_SIZE(bs))
+#define SHA2_KEY_OFFSET(bs)	(SHA2_CV_SIZE(bs) + SHA2_IMBL_SIZE(bs))
+
+#define PHMAC_SHA256_KEY_SIZE	(SHA256_BLOCK_SIZE + 32)
+#define PHMAC_SHA512_KEY_SIZE	(SHA512_BLOCK_SIZE + 32)
+#define PHMAC_MAX_KEY_SIZE	PHMAC_SHA512_KEY_SIZE
+
+struct phmac_protkey {
+	u32 type;
+	u32 len;
+	u8 protkey[PHMAC_MAX_KEY_SIZE];
+};
+
+struct s390_phmac_ctx {
+	u8 *key;
+	unsigned int keylen;
+
+	struct phmac_protkey pk;
+	/* spinlock to atomic update pk */
+	spinlock_t pk_lock;
+};
+
+union s390_kmac_gr0 {
+	unsigned long reg;
+	struct {
+		unsigned long		: 48;
+		unsigned long ikp	:  1;
+		unsigned long iimp	:  1;
+		unsigned long ccup	:  1;
+		unsigned long		:  6;
+		unsigned long fc	:  7;
+	};
+};
+
+struct s390_kmac_sha2_ctx {
+	u8 param[MAX_DIGEST_SIZE + MAX_IMBL_SIZE + PHMAC_MAX_KEY_SIZE];
+	union s390_kmac_gr0 gr0;
+	u8 buf[MAX_BLOCK_SIZE];
+	unsigned int buflen;
+};
+
+/*
+ * kmac_sha2_set_imbl - sets the input message bit-length based on the blocksize
+ */
+static inline void kmac_sha2_set_imbl(u8 *param, unsigned int buflen,
+				      unsigned int blocksize)
+{
+	u8 *imbl = param + SHA2_IMBL_OFFSET(blocksize);
+
+	switch (blocksize) {
+	case SHA256_BLOCK_SIZE:
+		*(u64 *)imbl = (u64)buflen * BITS_PER_BYTE;
+		break;
+	case SHA512_BLOCK_SIZE:
+		*(u128 *)imbl = (u128)buflen * BITS_PER_BYTE;
+		break;
+	default:
+		break;
+	}
+}
+
+static inline int phmac_keyblob2pkey(const u8 *key, unsigned int keylen,
+				     struct phmac_protkey *pk)
+{
+	int i, rc = -EIO;
+
+	/* try three times in case of busy card */
+	for (i = 0; rc && i < 3; i++) {
+		if (rc == -EBUSY && msleep_interruptible(1000))
+			return -EINTR;
+		rc = pkey_key2protkey(key, keylen,
+				      pk->protkey, &pk->len, &pk->type);
+	}
+
+	return rc;
+}
+
+static inline int phmac_convert_key(struct s390_phmac_ctx *tfm_ctx)
+{
+	struct phmac_protkey pk;
+	int rc;
+
+	pk.len = sizeof(pk.protkey);
+	rc = phmac_keyblob2pkey(tfm_ctx->key, tfm_ctx->keylen, &pk);
+	if (rc)
+		return rc;
+
+	spin_lock_bh(&tfm_ctx->pk_lock);
+	tfm_ctx->pk = pk;
+	spin_unlock_bh(&tfm_ctx->pk_lock);
+
+	return 0;
+}
+
+static int s390_phmac_init(struct ahash_request *req)
+{
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+	struct s390_phmac_ctx *tfm_ctx = crypto_ahash_ctx(tfm);
+	struct s390_kmac_sha2_ctx *ctx = ahash_request_ctx(req);
+	unsigned int bs = crypto_ahash_blocksize(tfm);
+
+	spin_lock_bh(&tfm_ctx->pk_lock);
+	memcpy(ctx->param + SHA2_KEY_OFFSET(bs),
+	       tfm_ctx->pk.protkey, tfm_ctx->pk.len);
+	spin_unlock_bh(&tfm_ctx->pk_lock);
+
+	ctx->buflen = 0;
+	ctx->gr0.reg = 0;
+
+	switch (crypto_ahash_digestsize(tfm)) {
+	case SHA224_DIGEST_SIZE:
+		ctx->gr0.fc = CPACF_KMAC_PHMAC_SHA_224;
+		break;
+	case SHA256_DIGEST_SIZE:
+		ctx->gr0.fc = CPACF_KMAC_PHMAC_SHA_256;
+		break;
+	case SHA384_DIGEST_SIZE:
+		ctx->gr0.fc = CPACF_KMAC_PHMAC_SHA_384;
+		break;
+	case SHA512_DIGEST_SIZE:
+		ctx->gr0.fc = CPACF_KMAC_PHMAC_SHA_512;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static inline int s390_phmac_walk(struct s390_phmac_ctx *tfm_ctx,
+				  struct s390_kmac_sha2_ctx *ctx,
+				  unsigned int blocksize,
+				  const u8 *data, unsigned int len)
+{
+	unsigned int offset, n, k;
+
+	/* check current buffer */
+	offset = ctx->buflen % blocksize;
+	ctx->buflen += len;
+	if (offset + len < blocksize)
+		goto store;
+
+	/* process one stored block */
+	if (offset) {
+		n = blocksize - offset;
+		memcpy(ctx->buf + offset, data, n);
+		ctx->gr0.iimp = 1;
+		for (k = blocksize;;) {
+			k -= _cpacf_kmac(&ctx->gr0.reg, ctx->param,
+					 ctx->buf + blocksize - k, k);
+			if (!k)
+				break;
+			if (phmac_convert_key(tfm_ctx))
+				return -EIO;
+			spin_lock_bh(&tfm_ctx->pk_lock);
+			memcpy(ctx->param + SHA2_KEY_OFFSET(blocksize),
+			       tfm_ctx->pk.protkey, tfm_ctx->pk.len);
+			spin_unlock_bh(&tfm_ctx->pk_lock);
+		}
+		data += n;
+		len -= n;
+		offset = 0;
+	}
+
+	/* process as many blocks as possible */
+	if (len >= blocksize) {
+		n = (len / blocksize) * blocksize;
+		ctx->gr0.iimp = 1;
+		for (k = n;;) {
+			k -= _cpacf_kmac(&ctx->gr0.reg, ctx->param,
+					 data + n - k, k);
+			if (!k)
+				break;
+			if (phmac_convert_key(tfm_ctx))
+				return -EIO;
+			spin_lock_bh(&tfm_ctx->pk_lock);
+			memcpy(ctx->param + SHA2_KEY_OFFSET(blocksize),
+			       tfm_ctx->pk.protkey, tfm_ctx->pk.len);
+			spin_unlock_bh(&tfm_ctx->pk_lock);
+		}
+		data += n;
+		len -= n;
+	}
+
+store:
+	/* store incomplete block in buffer */
+	if (len)
+		memcpy(ctx->buf + offset, data, len);
+
+	return 0;
+}
+
+static int s390_phmac_update(struct ahash_request *req)
+{
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+	struct s390_phmac_ctx *tfm_ctx = crypto_ahash_ctx(tfm);
+	struct s390_kmac_sha2_ctx *ctx = ahash_request_ctx(req);
+	unsigned int bs = crypto_ahash_blocksize(tfm);
+	struct crypto_hash_walk walk;
+	int nbytes, rc;
+
+	for (nbytes = crypto_hash_walk_first(req, &walk); nbytes > 0;
+	     nbytes = crypto_hash_walk_done(&walk, 0)) {
+		rc = s390_phmac_walk(tfm_ctx, ctx, bs, walk.data, nbytes);
+		if (rc)
+			return crypto_hash_walk_done(&walk, rc);
+	}
+
+	return 0;
+}
+
+static int s390_phmac_final(struct ahash_request *req)
+{
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+	struct s390_phmac_ctx *tfm_ctx = crypto_ahash_ctx(tfm);
+	struct s390_kmac_sha2_ctx *ctx = ahash_request_ctx(req);
+	unsigned int bs = crypto_ahash_blocksize(tfm);
+	unsigned int ds = crypto_ahash_digestsize(tfm);
+	struct crypto_hash_walk walk;
+	unsigned int n, k;
+	int nbytes, rc;
+
+	for (nbytes = crypto_hash_walk_first(req, &walk); nbytes > 0;
+	     nbytes = crypto_hash_walk_done(&walk, 0)) {
+		rc = s390_phmac_walk(tfm_ctx, ctx, bs, walk.data, nbytes);
+		if (rc)
+			return crypto_hash_walk_done(&walk, rc);
+	}
+
+	n = ctx->buflen % bs;
+	ctx->gr0.iimp = 0;
+	kmac_sha2_set_imbl(ctx->param, ctx->buflen, bs);
+	for (k = n;;) {
+		k -= _cpacf_kmac(&ctx->gr0.reg, ctx->param,
+				 ctx->buf + n - k, k);
+		if (!k)
+			break;
+		if (phmac_convert_key(tfm_ctx))
+			return -EIO;
+		spin_lock_bh(&tfm_ctx->pk_lock);
+		memcpy(ctx->param + SHA2_KEY_OFFSET(bs),
+		       tfm_ctx->pk.protkey, tfm_ctx->pk.len);
+		spin_unlock_bh(&tfm_ctx->pk_lock);
+	}
+	memcpy(req->result, ctx->param, ds);
+
+	return 0;
+}
+
+static int s390_phmac_setkey(struct crypto_ahash *tfm,
+			     const u8 *key, unsigned int keylen)
+{
+	struct s390_phmac_ctx *tfm_ctx = crypto_ahash_ctx(tfm);
+	int rc = -ENOMEM;
+
+	if (tfm_ctx->keylen) {
+		kfree_sensitive(tfm_ctx->key);
+		tfm_ctx->key = NULL;
+		tfm_ctx->keylen = 0;
+	}
+
+	tfm_ctx->key = kmemdup(key, keylen, GFP_KERNEL);
+	if (!tfm_ctx->key)
+		goto out;
+	tfm_ctx->keylen = keylen;
+
+	rc = phmac_convert_key(tfm_ctx);
+	if (rc)
+		goto out;
+
+	rc = -EINVAL;
+	switch (crypto_ahash_digestsize(tfm)) {
+	case SHA224_DIGEST_SIZE:
+	case SHA256_DIGEST_SIZE:
+		if (tfm_ctx->pk.type != PKEY_KEYTYPE_HMAC_512)
+			goto out;
+		break;
+	case SHA384_DIGEST_SIZE:
+	case SHA512_DIGEST_SIZE:
+		if (tfm_ctx->pk.type != PKEY_KEYTYPE_HMAC_1024)
+			goto out;
+		break;
+	default:
+		goto out;
+	}
+	rc = 0;
+
+out:
+	pr_debug("rc=%d\n", rc);
+	return rc;
+}
+
+static int s390_phmac_import(struct ahash_request *req, const void *in)
+{
+	return -EOPNOTSUPP;
+}
+
+static int s390_phmac_export(struct ahash_request *req, void *out)
+{
+	return -EOPNOTSUPP;
+}
+
+static int s390_phmac_init_tfm(struct crypto_ahash *tfm)
+{
+	struct s390_phmac_ctx *tfm_ctx = crypto_ahash_ctx(tfm);
+
+	tfm_ctx->key = NULL;
+	tfm_ctx->keylen = 0;
+	spin_lock_init(&tfm_ctx->pk_lock);
+
+	crypto_ahash_set_reqsize(tfm, sizeof(struct s390_kmac_sha2_ctx));
+
+	return 0;
+}
+
+static void s390_phmac_exit_tfm(struct crypto_ahash *tfm)
+{
+	struct s390_phmac_ctx *tfm_ctx = crypto_ahash_ctx(tfm);
+
+	memzero_explicit(&tfm_ctx->pk, sizeof(tfm_ctx->pk));
+	kfree_sensitive(tfm_ctx->key);
+}
+
+#define S390_ASYNC_PHMAC_ALG(x)						\
+{									\
+	.init = s390_phmac_init,					\
+	.update = s390_phmac_update,					\
+	.final = s390_phmac_final,					\
+	.setkey = s390_phmac_setkey,					\
+	.import = s390_phmac_import,					\
+	.export = s390_phmac_export,					\
+	.init_tfm = s390_phmac_init_tfm,				\
+	.exit_tfm = s390_phmac_exit_tfm,				\
+	.halg = {							\
+		.digestsize = SHA##x##_DIGEST_SIZE,			\
+		.statesize = sizeof(struct s390_kmac_sha2_ctx),		\
+		.base = {						\
+			.cra_name = "phmac(sha" #x ")",			\
+			.cra_driver_name = "phmac_s390_sha" #x,		\
+			.cra_blocksize = SHA##x##_BLOCK_SIZE,		\
+			.cra_priority = 400,				\
+			.cra_flags = CRYPTO_ALG_ASYNC,			\
+			.cra_ctxsize = sizeof(struct s390_phmac_ctx),	\
+			.cra_module = THIS_MODULE,			\
+		},							\
+	},								\
+}
+
+static struct s390_hmac_alg {
+	unsigned int fc;
+	struct ahash_alg alg;
+	bool registered;
+} s390_hmac_algs[] = {
+	{
+		.fc = CPACF_KMAC_PHMAC_SHA_224,
+		.alg = S390_ASYNC_PHMAC_ALG(224),
+	}, {
+		.fc = CPACF_KMAC_PHMAC_SHA_256,
+		.alg = S390_ASYNC_PHMAC_ALG(256),
+	}, {
+		.fc = CPACF_KMAC_PHMAC_SHA_384,
+		.alg = S390_ASYNC_PHMAC_ALG(384),
+	}, {
+		.fc = CPACF_KMAC_PHMAC_SHA_512,
+		.alg = S390_ASYNC_PHMAC_ALG(512),
+	}
+};
+
+static __always_inline void _s390_hmac_algs_unregister(void)
+{
+	struct s390_hmac_alg *hmac;
+	int i;
+
+	for (i = ARRAY_SIZE(s390_hmac_algs) - 1; i >= 0; i--) {
+		hmac = &s390_hmac_algs[i];
+		if (hmac->registered)
+			crypto_unregister_ahash(&hmac->alg);
+	}
+}
+
+static int __init phmac_s390_init(void)
+{
+	struct s390_hmac_alg *hmac;
+	int i, rc = -ENODEV;
+
+	for (i = 0; i < ARRAY_SIZE(s390_hmac_algs); i++) {
+		hmac = &s390_hmac_algs[i];
+		if (!cpacf_query_func(CPACF_KMAC, hmac->fc))
+			continue;
+		rc = crypto_register_ahash(&hmac->alg);
+		if (rc) {
+			pr_err("unable to register %s\n",
+			       hmac->alg.halg.base.cra_name);
+			goto out;
+		}
+		hmac->registered = true;
+		pr_debug("registered %s\n", hmac->alg.halg.base.cra_name);
+	}
+	return rc;
+out:
+	_s390_hmac_algs_unregister();
+	return rc;
+}
+
+static void __exit phmac_s390_exit(void)
+{
+	_s390_hmac_algs_unregister();
+}
+
+module_init(phmac_s390_init);
+module_exit(phmac_s390_exit);
+
+MODULE_ALIAS_CRYPTO("phmac(sha224)");
+MODULE_ALIAS_CRYPTO("phmac(sha256)");
+MODULE_ALIAS_CRYPTO("phmac(sha384)");
+MODULE_ALIAS_CRYPTO("phmac(sha512)");
+
+MODULE_DESCRIPTION("S390 HMAC driver for protected keys");
+MODULE_LICENSE("GPL");
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index 0a9cdd31cbd9..519305e04f18 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -187,6 +187,18 @@ config CRYPTO_PAES_S390
 	  Select this option if you want to use the paes cipher
 	  for example to use protected key encrypted devices.
 
+config CRYPTO_PHMAC_S390
+	tristate "PHMAC cipher algorithms"
+	depends on S390
+	depends on PKEY
+	select CRYPTO_HASH
+	help
+	  This is the s390 hardware accelerated implementation of the
+	  protected key HMAC support for SHA224, SHA256, SHA384 and SHA512.
+
+	  Select this option if you want to use the phmac digests
+	  for example to use dm-integrity with secure/protected keys.
+
 config S390_PRNG
 	tristate "Pseudo random number generator device driver"
 	depends on S390
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH v6 2/2] s390/crypto: New s390 specific protected key hash phmac
  2024-11-29 11:10 ` [PATCH v6 2/2] s390/crypto: New s390 specific protected key hash phmac Harald Freudenberger
@ 2024-11-29 14:48   ` Herbert Xu
  2024-12-02 17:25     ` Harald Freudenberger
  0 siblings, 1 reply; 6+ messages in thread
From: Herbert Xu @ 2024-11-29 14:48 UTC (permalink / raw)
  To: Harald Freudenberger; +Cc: davem, dengler, linux-s390, linux-crypto

On Fri, Nov 29, 2024 at 12:10:58PM +0100, Harald Freudenberger wrote:
>
> +static inline int phmac_keyblob2pkey(const u8 *key, unsigned int keylen,
> +				     struct phmac_protkey *pk)
> +{
> +	int i, rc = -EIO;
> +
> +	/* try three times in case of busy card */
> +	for (i = 0; rc && i < 3; i++) {
> +		if (rc == -EBUSY && msleep_interruptible(1000))
> +			return -EINTR;

You can't sleep in an ahash algorithm either.  What you can do
however is schedule a delayed work and pick up where you left
off.  That's how asynchronous completion works.

But my question still stands, under what circumstances can
this fail? I don't think storage folks will be too happy with
a crypto algorithm that can produce random failures.

Cheers,
-- 
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v6 2/2] s390/crypto: New s390 specific protected key hash phmac
  2024-11-29 14:48   ` Herbert Xu
@ 2024-12-02 17:25     ` Harald Freudenberger
  2024-12-03  8:50       ` Herbert Xu
  0 siblings, 1 reply; 6+ messages in thread
From: Harald Freudenberger @ 2024-12-02 17:25 UTC (permalink / raw)
  To: Herbert Xu; +Cc: davem, dengler, linux-s390, linux-crypto

On 2024-11-29 15:48, Herbert Xu wrote:
> On Fri, Nov 29, 2024 at 12:10:58PM +0100, Harald Freudenberger wrote:
>> 
>> +static inline int phmac_keyblob2pkey(const u8 *key, unsigned int 
>> keylen,
>> +				     struct phmac_protkey *pk)
>> +{
>> +	int i, rc = -EIO;
>> +
>> +	/* try three times in case of busy card */
>> +	for (i = 0; rc && i < 3; i++) {
>> +		if (rc == -EBUSY && msleep_interruptible(1000))
>> +			return -EINTR;
> 
> You can't sleep in an ahash algorithm either.  What you can do
> however is schedule a delayed work and pick up where you left
> off.  That's how asynchronous completion works.
> 
> But my question still stands, under what circumstances can
> this fail? I don't think storage folks will be too happy with
> a crypto algorithm that can produce random failures.
> 
> Cheers,

- The attempt to derive a protected key usable by the cpacf instructions
   depends of the raw key material used. For 'clear key' material the
   derivation process is a simple instruction which can't fail.
   A more preferred way however is to use 'secure key' material which
   is transferred to a crypto card and then re-wrapped to be usable
   with cpacf instructions. This requires communication with a crypto
   card and thus may fail - because there is no card at all or there
   is temporarily no card available or the card is in bad state. If there
   is no usable card the AP bus returns -EBUSY at the pkey_key2protkey()
   function and triggers an asynchronous bus scan. As long as this scan
   is running (usually about 100ms or so) the -EBUSY is returned to 
indicate
   that the caller should retry "later". Other states are covered with
   other return codes like ENODEV or EIO and the caller is not supposed
   to loop but should fail. When there is no accessible hardware 
available
   to derive a protected key either the user or the admin broke something
   or something went really the bad way and then there is no help but the
   storage device must fail.
- How can it happen that a re-derive is needed? A re-derive is triggered 
when
   the cpacf instruction detects that the protected key is not valid any 
more.
   A protected key includes a verification pattern (hash) of the firmware 
key
   used to encrypt the key. This hash is checked on each invocation of a
   cpacf instruction. So when the code execution "awakes" on another 
machine
   ("live guest migration" of an KVM guest to another machine) the next
   cpacf instruction will complain about verification pattern mismatch 
and
   the protected key needs to get re-derived from the source material.
   It could also happen via suspend/resume on the very same machine when
   there is something in between (for example the whole machine runs a
   cold-start). It does NOT happen out of the sudden without any reason,
   but the code affected is not aware of any "live guest migration" or
   "suspend/resume cycle" and thus as the crypto algorithm implementation 
has
   no awareness of a "live guest migration" just happened - it looks like
   this occurred suddenly.
- Do I get you right, that a completion is ok? I always had the 
impression
   that waiting on a completion is also a sleeping act and thus not 
allowed?

Thanks for your help and being so patient with us.




^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v6 2/2] s390/crypto: New s390 specific protected key hash phmac
  2024-12-02 17:25     ` Harald Freudenberger
@ 2024-12-03  8:50       ` Herbert Xu
  0 siblings, 0 replies; 6+ messages in thread
From: Herbert Xu @ 2024-12-03  8:50 UTC (permalink / raw)
  To: Harald Freudenberger
  Cc: davem, dengler, linux-s390, linux-crypto, Eric Biggers

On Mon, Dec 02, 2024 at 06:25:22PM +0100, Harald Freudenberger wrote:
>
> - The attempt to derive a protected key usable by the cpacf instructions
>   depends of the raw key material used. For 'clear key' material the
>   derivation process is a simple instruction which can't fail.
>   A more preferred way however is to use 'secure key' material which
>   is transferred to a crypto card and then re-wrapped to be usable
>   with cpacf instructions. This requires communication with a crypto
>   card and thus may fail - because there is no card at all or there
>   is temporarily no card available or the card is in bad state. If there
>   is no usable card the AP bus returns -EBUSY at the pkey_key2protkey()
>   function and triggers an asynchronous bus scan. As long as this scan
>   is running (usually about 100ms or so) the -EBUSY is returned to indicate
>   that the caller should retry "later". Other states are covered with
>   other return codes like ENODEV or EIO and the caller is not supposed
>   to loop but should fail. When there is no accessible hardware available
>   to derive a protected key either the user or the admin broke something
>   or something went really the bad way and then there is no help but the
>   storage device must fail.

Thanks for the explanation.  I think it's fair enough to fail an
op if the hardware is absent or broken.

So all I need is for you to turn the BUSY case into a delayed retry
and I think that should be good enough.

> - Do I get you right, that a completion is ok? I always had the impression
>   that waiting on a completion is also a sleeping act and thus not allowed?

No, what I mean is that if you get an EBUSY, you should return
-EINPROGRESS to indicate that the operation is pending, and then
schedule a delayed work to retry the operation.  When the retry
fails or succeeds, it should invoke the callback with the correct
error status.

If the retry gets EBUSY again, then schedule another delayed
work, or fail permanently by invoking the callback if you hit
some sort of threshold like your existing limit of 3.

Cheers,
-- 
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2024-12-03  8:50 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-11-29 11:10 [PATCH v6 0/2] New s390 specific protected key hmac Harald Freudenberger
2024-11-29 11:10 ` [PATCH v6 1/2] s390/crypto: Add protected key hmac subfunctions for KMAC Harald Freudenberger
2024-11-29 11:10 ` [PATCH v6 2/2] s390/crypto: New s390 specific protected key hash phmac Harald Freudenberger
2024-11-29 14:48   ` Herbert Xu
2024-12-02 17:25     ` Harald Freudenberger
2024-12-03  8:50       ` Herbert Xu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox