All of lore.kernel.org
 help / color / mirror / Atom feed
From: Harald Freudenberger <freude@linux.ibm.com>
To: herbert@gondor.apana.org.au
Cc: linux-crypto@vger.kernel.org, linux-s390@vger.kernel.org,
	hca@linux.ibm.com, gor@linux.ibm.com, agordeev@linux.ibm.com
Subject: [PATCH v2 4/4] crypto: s390/paes - Refuse clear key material by default
Date: Thu, 15 Jan 2026 13:00:26 +0100	[thread overview]
Message-ID: <20260115120026.4286-5-freude@linux.ibm.com> (raw)
In-Reply-To: <20260115120026.4286-1-freude@linux.ibm.com>

This patch exploits the new xflag PKEY_XFLAG_NOCLEARKEY from the pkey
layer. So now by default all the paes algorithms refuse the use of
clear key material ("clear key tokens") in the setkey function with
-EINVAL.

With a new kernel module parameter "clrkey" this behavior can be
controlled. By default clrkey is 'N' but for testing purpose on module
load a true value (1, 'Y') may be given to accept clear key tokens.

Note that during selftest clear keys are always used and thus the
xflag PKEY_XFLAG_NOCLEARKEY is NOT set as long as the algorithm is in
a larval state indicated by crypto_skcipher_tested() returning false.

Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
Reviewed-by: Holger Dengler <dengler@linux.ibm.com>
Reviewed-by: Ingo Franzki <ifranzki@linux.ibm.com>
---
 arch/s390/crypto/paes_s390.c | 93 ++++++++++++++++++++++--------------
 1 file changed, 57 insertions(+), 36 deletions(-)

diff --git a/arch/s390/crypto/paes_s390.c b/arch/s390/crypto/paes_s390.c
index 64aef7eb2030..8cfe6166c193 100644
--- a/arch/s390/crypto/paes_s390.c
+++ b/arch/s390/crypto/paes_s390.c
@@ -40,6 +40,10 @@
 #define PAES_256_PROTKEY_SIZE	(32 + 32)	/* key + verification pattern */
 #define PXTS_256_PROTKEY_SIZE	(32 + 32 + 32)	/* k1 + k2 + verification pattern */
 
+static bool pkey_clrkey_allowed;
+module_param_named(clrkey, pkey_clrkey_allowed, bool, 0444);
+MODULE_PARM_DESC(clrkey, "Allow clear key material (default N)");
+
 static u8 *ctrblk;
 static DEFINE_MUTEX(ctrblk_lock);
 
@@ -192,10 +196,14 @@ static inline int pxts_ctx_setkey(struct s390_pxts_ctx *ctx,
  * This function may sleep - don't call in non-sleeping context.
  */
 static inline int convert_key(const u8 *key, unsigned int keylen,
-			      struct paes_protkey *pk)
+			      struct paes_protkey *pk, bool tested)
 {
+	u32 xflags = PKEY_XFLAG_NOMEMALLOC;
 	int rc, i;
 
+	if (tested && !pkey_clrkey_allowed)
+		xflags |= PKEY_XFLAG_NOCLEARKEY;
+
 	pk->len = sizeof(pk->protkey);
 
 	/*
@@ -209,7 +217,7 @@ static inline int convert_key(const u8 *key, unsigned int keylen,
 		}
 		rc = pkey_key2protkey(key, keylen,
 				      pk->protkey, &pk->len, &pk->type,
-				      PKEY_XFLAG_NOMEMALLOC);
+				      xflags);
 	}
 
 out:
@@ -231,7 +239,7 @@ static inline int convert_key(const u8 *key, unsigned int keylen,
  * unnecessary additional conversion but never to invalid data on en-
  * or decrypt operations.
  */
-static int paes_convert_key(struct s390_paes_ctx *ctx)
+static int paes_convert_key(struct s390_paes_ctx *ctx, bool tested)
 {
 	struct paes_protkey pk;
 	int rc;
@@ -240,7 +248,7 @@ static int paes_convert_key(struct s390_paes_ctx *ctx)
 	ctx->pk_state = PK_STATE_CONVERT_IN_PROGRESS;
 	spin_unlock_bh(&ctx->pk_lock);
 
-	rc = convert_key(ctx->keybuf, ctx->keylen, &pk);
+	rc = convert_key(ctx->keybuf, ctx->keylen, &pk, tested);
 
 	/* update context */
 	spin_lock_bh(&ctx->pk_lock);
@@ -263,7 +271,7 @@ static int paes_convert_key(struct s390_paes_ctx *ctx)
  * pk_type, pk_len and the protected key in the tfm context.
  * See also comments on function paes_convert_key.
  */
-static int pxts_convert_key(struct s390_pxts_ctx *ctx)
+static int pxts_convert_key(struct s390_pxts_ctx *ctx, bool tested)
 {
 	struct paes_protkey pk0, pk1;
 	size_t split_keylen;
@@ -273,7 +281,7 @@ static int pxts_convert_key(struct s390_pxts_ctx *ctx)
 	ctx->pk_state = PK_STATE_CONVERT_IN_PROGRESS;
 	spin_unlock_bh(&ctx->pk_lock);
 
-	rc = convert_key(ctx->keybuf, ctx->keylen, &pk0);
+	rc = convert_key(ctx->keybuf, ctx->keylen, &pk0, tested);
 	if (rc)
 		goto out;
 
@@ -287,7 +295,7 @@ static int pxts_convert_key(struct s390_pxts_ctx *ctx)
 		}
 		split_keylen = ctx->keylen / 2;
 		rc = convert_key(ctx->keybuf + split_keylen,
-				 split_keylen, &pk1);
+				 split_keylen, &pk1, tested);
 		if (rc)
 			goto out;
 		if (pk0.type != pk1.type) {
@@ -343,6 +351,7 @@ static int ecb_paes_setkey(struct crypto_skcipher *tfm, const u8 *in_key,
 			   unsigned int key_len)
 {
 	struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm);
+	bool tested = crypto_skcipher_tested(tfm);
 	long fc;
 	int rc;
 
@@ -352,7 +361,7 @@ static int ecb_paes_setkey(struct crypto_skcipher *tfm, const u8 *in_key,
 		goto out;
 
 	/* convert key into protected key */
-	rc = paes_convert_key(ctx);
+	rc = paes_convert_key(ctx, tested);
 	if (rc)
 		goto out;
 
@@ -382,7 +391,7 @@ static int ecb_paes_setkey(struct crypto_skcipher *tfm, const u8 *in_key,
 
 static int ecb_paes_do_crypt(struct s390_paes_ctx *ctx,
 			     struct s390_pecb_req_ctx *req_ctx,
-			     bool maysleep)
+			     bool tested, bool maysleep)
 {
 	struct ecb_param *param = &req_ctx->param;
 	struct skcipher_walk *walk = &req_ctx->walk;
@@ -430,7 +439,7 @@ static int ecb_paes_do_crypt(struct s390_paes_ctx *ctx,
 				rc = -EKEYEXPIRED;
 				goto out;
 			}
-			rc = paes_convert_key(ctx);
+			rc = paes_convert_key(ctx, tested);
 			if (rc)
 				goto out;
 			spin_lock_bh(&ctx->pk_lock);
@@ -450,6 +459,7 @@ static int ecb_paes_crypt(struct skcipher_request *req, unsigned long modifier)
 	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
 	struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm);
 	struct skcipher_walk *walk = &req_ctx->walk;
+	bool tested = crypto_skcipher_tested(tfm);
 	int rc;
 
 	/*
@@ -468,7 +478,7 @@ static int ecb_paes_crypt(struct skcipher_request *req, unsigned long modifier)
 
 	/* Try synchronous operation if no active engine usage */
 	if (!atomic_read(&ctx->via_engine_ctr)) {
-		rc = ecb_paes_do_crypt(ctx, req_ctx, false);
+		rc = ecb_paes_do_crypt(ctx, req_ctx, tested, false);
 		if (rc == 0)
 			goto out;
 	}
@@ -531,11 +541,12 @@ static int ecb_paes_do_one_request(struct crypto_engine *engine, void *areq)
 	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
 	struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm);
 	struct skcipher_walk *walk = &req_ctx->walk;
+	bool tested = crypto_skcipher_tested(tfm);
 	int rc;
 
 	/* walk has already been prepared */
 
-	rc = ecb_paes_do_crypt(ctx, req_ctx, true);
+	rc = ecb_paes_do_crypt(ctx, req_ctx, tested, true);
 	if (rc == -EKEYEXPIRED) {
 		/*
 		 * Protected key expired, conversion is in process.
@@ -602,6 +613,7 @@ static int cbc_paes_setkey(struct crypto_skcipher *tfm, const u8 *in_key,
 			   unsigned int key_len)
 {
 	struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm);
+	bool tested = crypto_skcipher_tested(tfm);
 	long fc;
 	int rc;
 
@@ -611,7 +623,7 @@ static int cbc_paes_setkey(struct crypto_skcipher *tfm, const u8 *in_key,
 		goto out;
 
 	/* convert raw key into protected key */
-	rc = paes_convert_key(ctx);
+	rc = paes_convert_key(ctx, tested);
 	if (rc)
 		goto out;
 
@@ -641,7 +653,7 @@ static int cbc_paes_setkey(struct crypto_skcipher *tfm, const u8 *in_key,
 
 static int cbc_paes_do_crypt(struct s390_paes_ctx *ctx,
 			     struct s390_pcbc_req_ctx *req_ctx,
-			     bool maysleep)
+			     bool tested, bool maysleep)
 {
 	struct cbc_param *param = &req_ctx->param;
 	struct skcipher_walk *walk = &req_ctx->walk;
@@ -693,7 +705,7 @@ static int cbc_paes_do_crypt(struct s390_paes_ctx *ctx,
 				rc = -EKEYEXPIRED;
 				goto out;
 			}
-			rc = paes_convert_key(ctx);
+			rc = paes_convert_key(ctx, tested);
 			if (rc)
 				goto out;
 			spin_lock_bh(&ctx->pk_lock);
@@ -713,6 +725,7 @@ static int cbc_paes_crypt(struct skcipher_request *req, unsigned long modifier)
 	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
 	struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm);
 	struct skcipher_walk *walk = &req_ctx->walk;
+	bool tested = crypto_skcipher_tested(tfm);
 	int rc;
 
 	/*
@@ -731,7 +744,7 @@ static int cbc_paes_crypt(struct skcipher_request *req, unsigned long modifier)
 
 	/* Try synchronous operation if no active engine usage */
 	if (!atomic_read(&ctx->via_engine_ctr)) {
-		rc = cbc_paes_do_crypt(ctx, req_ctx, false);
+		rc = cbc_paes_do_crypt(ctx, req_ctx, tested, false);
 		if (rc == 0)
 			goto out;
 	}
@@ -794,11 +807,12 @@ static int cbc_paes_do_one_request(struct crypto_engine *engine, void *areq)
 	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
 	struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm);
 	struct skcipher_walk *walk = &req_ctx->walk;
+	bool tested = crypto_skcipher_tested(tfm);
 	int rc;
 
 	/* walk has already been prepared */
 
-	rc = cbc_paes_do_crypt(ctx, req_ctx, true);
+	rc = cbc_paes_do_crypt(ctx, req_ctx, tested, true);
 	if (rc == -EKEYEXPIRED) {
 		/*
 		 * Protected key expired, conversion is in process.
@@ -865,6 +879,7 @@ static int ctr_paes_setkey(struct crypto_skcipher *tfm, const u8 *in_key,
 			   unsigned int key_len)
 {
 	struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm);
+	bool tested = crypto_skcipher_tested(tfm);
 	long fc;
 	int rc;
 
@@ -874,7 +889,7 @@ static int ctr_paes_setkey(struct crypto_skcipher *tfm, const u8 *in_key,
 		goto out;
 
 	/* convert raw key into protected key */
-	rc = paes_convert_key(ctx);
+	rc = paes_convert_key(ctx, tested);
 	if (rc)
 		goto out;
 
@@ -919,7 +934,7 @@ static inline unsigned int __ctrblk_init(u8 *ctrptr, u8 *iv, unsigned int nbytes
 
 static int ctr_paes_do_crypt(struct s390_paes_ctx *ctx,
 			     struct s390_pctr_req_ctx *req_ctx,
-			     bool maysleep)
+			     bool tested, bool maysleep)
 {
 	struct ctr_param *param = &req_ctx->param;
 	struct skcipher_walk *walk = &req_ctx->walk;
@@ -979,7 +994,7 @@ static int ctr_paes_do_crypt(struct s390_paes_ctx *ctx,
 				rc = -EKEYEXPIRED;
 				goto out;
 			}
-			rc = paes_convert_key(ctx);
+			rc = paes_convert_key(ctx, tested);
 			if (rc) {
 				if (locked)
 					mutex_unlock(&ctrblk_lock);
@@ -1006,7 +1021,7 @@ static int ctr_paes_do_crypt(struct s390_paes_ctx *ctx,
 				rc = -EKEYEXPIRED;
 				goto out;
 			}
-			rc = paes_convert_key(ctx);
+			rc = paes_convert_key(ctx, tested);
 			if (rc)
 				goto out;
 			spin_lock_bh(&ctx->pk_lock);
@@ -1029,6 +1044,7 @@ static int ctr_paes_crypt(struct skcipher_request *req)
 	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
 	struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm);
 	struct skcipher_walk *walk = &req_ctx->walk;
+	bool tested = crypto_skcipher_tested(tfm);
 	int rc;
 
 	/*
@@ -1046,7 +1062,7 @@ static int ctr_paes_crypt(struct skcipher_request *req)
 
 	/* Try synchronous operation if no active engine usage */
 	if (!atomic_read(&ctx->via_engine_ctr)) {
-		rc = ctr_paes_do_crypt(ctx, req_ctx, false);
+		rc = ctr_paes_do_crypt(ctx, req_ctx, tested, false);
 		if (rc == 0)
 			goto out;
 	}
@@ -1099,11 +1115,12 @@ static int ctr_paes_do_one_request(struct crypto_engine *engine, void *areq)
 	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
 	struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm);
 	struct skcipher_walk *walk = &req_ctx->walk;
+	bool tested = crypto_skcipher_tested(tfm);
 	int rc;
 
 	/* walk has already been prepared */
 
-	rc = ctr_paes_do_crypt(ctx, req_ctx, true);
+	rc = ctr_paes_do_crypt(ctx, req_ctx, tested, true);
 	if (rc == -EKEYEXPIRED) {
 		/*
 		 * Protected key expired, conversion is in process.
@@ -1190,6 +1207,7 @@ static int xts_paes_setkey(struct crypto_skcipher *tfm, const u8 *in_key,
 			   unsigned int in_keylen)
 {
 	struct s390_pxts_ctx *ctx = crypto_skcipher_ctx(tfm);
+	bool tested = crypto_skcipher_tested(tfm);
 	u8 ckey[2 * AES_MAX_KEY_SIZE];
 	unsigned int ckey_len;
 	long fc;
@@ -1205,7 +1223,7 @@ static int xts_paes_setkey(struct crypto_skcipher *tfm, const u8 *in_key,
 		goto out;
 
 	/* convert raw key(s) into protected key(s) */
-	rc = pxts_convert_key(ctx);
+	rc = pxts_convert_key(ctx, tested);
 	if (rc)
 		goto out;
 
@@ -1255,7 +1273,7 @@ static int xts_paes_setkey(struct crypto_skcipher *tfm, const u8 *in_key,
 
 static int xts_paes_do_crypt_fullkey(struct s390_pxts_ctx *ctx,
 				     struct s390_pxts_req_ctx *req_ctx,
-				     bool maysleep)
+				     bool tested, bool maysleep)
 {
 	struct xts_full_km_param *param = &req_ctx->param.full_km_param;
 	struct skcipher_walk *walk = &req_ctx->walk;
@@ -1299,7 +1317,7 @@ static int xts_paes_do_crypt_fullkey(struct s390_pxts_ctx *ctx,
 				rc = -EKEYEXPIRED;
 				goto out;
 			}
-			rc = pxts_convert_key(ctx);
+			rc = pxts_convert_key(ctx, tested);
 			if (rc)
 				goto out;
 			spin_lock_bh(&ctx->pk_lock);
@@ -1318,7 +1336,8 @@ static inline int __xts_2keys_prep_param(struct s390_pxts_ctx *ctx,
 					 struct xts_km_param *param,
 					 struct skcipher_walk *walk,
 					 unsigned int keylen,
-					 unsigned int offset, bool maysleep)
+					 unsigned int offset,
+					 bool tested, bool maysleep)
 {
 	struct xts_pcc_param pcc_param;
 	unsigned long cc = 1;
@@ -1337,7 +1356,7 @@ static inline int __xts_2keys_prep_param(struct s390_pxts_ctx *ctx,
 				rc = -EKEYEXPIRED;
 				break;
 			}
-			rc = pxts_convert_key(ctx);
+			rc = pxts_convert_key(ctx, tested);
 			if (rc)
 				break;
 			continue;
@@ -1351,7 +1370,7 @@ static inline int __xts_2keys_prep_param(struct s390_pxts_ctx *ctx,
 
 static int xts_paes_do_crypt_2keys(struct s390_pxts_ctx *ctx,
 				   struct s390_pxts_req_ctx *req_ctx,
-				   bool maysleep)
+				   bool tested, bool maysleep)
 {
 	struct xts_km_param *param = &req_ctx->param.km_param;
 	struct skcipher_walk *walk = &req_ctx->walk;
@@ -1369,7 +1388,7 @@ static int xts_paes_do_crypt_2keys(struct s390_pxts_ctx *ctx,
 
 	if (!req_ctx->param_init_done) {
 		rc = __xts_2keys_prep_param(ctx, param, walk,
-					    keylen, offset, maysleep);
+					    keylen, offset, tested, maysleep);
 		if (rc)
 			goto out;
 		req_ctx->param_init_done = true;
@@ -1392,7 +1411,7 @@ static int xts_paes_do_crypt_2keys(struct s390_pxts_ctx *ctx,
 				rc = -EKEYEXPIRED;
 				goto out;
 			}
-			rc = pxts_convert_key(ctx);
+			rc = pxts_convert_key(ctx, tested);
 			if (rc)
 				goto out;
 			spin_lock_bh(&ctx->pk_lock);
@@ -1408,7 +1427,7 @@ static int xts_paes_do_crypt_2keys(struct s390_pxts_ctx *ctx,
 
 static int xts_paes_do_crypt(struct s390_pxts_ctx *ctx,
 			     struct s390_pxts_req_ctx *req_ctx,
-			     bool maysleep)
+			     bool tested, bool maysleep)
 {
 	int pk_state, rc = 0;
 
@@ -1436,11 +1455,11 @@ static int xts_paes_do_crypt(struct s390_pxts_ctx *ctx,
 	switch (ctx->fc) {
 	case CPACF_KM_PXTS_128:
 	case CPACF_KM_PXTS_256:
-		rc = xts_paes_do_crypt_2keys(ctx, req_ctx, maysleep);
+		rc = xts_paes_do_crypt_2keys(ctx, req_ctx, tested, maysleep);
 		break;
 	case CPACF_KM_PXTS_128_FULL:
 	case CPACF_KM_PXTS_256_FULL:
-		rc = xts_paes_do_crypt_fullkey(ctx, req_ctx, maysleep);
+		rc = xts_paes_do_crypt_fullkey(ctx, req_ctx, tested, maysleep);
 		break;
 	default:
 		rc = -EINVAL;
@@ -1457,6 +1476,7 @@ static inline int xts_paes_crypt(struct skcipher_request *req, unsigned long mod
 	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
 	struct s390_pxts_ctx *ctx = crypto_skcipher_ctx(tfm);
 	struct skcipher_walk *walk = &req_ctx->walk;
+	bool tested = crypto_skcipher_tested(tfm);
 	int rc;
 
 	/*
@@ -1475,7 +1495,7 @@ static inline int xts_paes_crypt(struct skcipher_request *req, unsigned long mod
 
 	/* Try synchronous operation if no active engine usage */
 	if (!atomic_read(&ctx->via_engine_ctr)) {
-		rc = xts_paes_do_crypt(ctx, req_ctx, false);
+		rc = xts_paes_do_crypt(ctx, req_ctx, tested, false);
 		if (rc == 0)
 			goto out;
 	}
@@ -1538,11 +1558,12 @@ static int xts_paes_do_one_request(struct crypto_engine *engine, void *areq)
 	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
 	struct s390_pxts_ctx *ctx = crypto_skcipher_ctx(tfm);
 	struct skcipher_walk *walk = &req_ctx->walk;
+	bool tested = crypto_skcipher_tested(tfm);
 	int rc;
 
 	/* walk has already been prepared */
 
-	rc = xts_paes_do_crypt(ctx, req_ctx, true);
+	rc = xts_paes_do_crypt(ctx, req_ctx, tested, true);
 	if (rc == -EKEYEXPIRED) {
 		/*
 		 * Protected key expired, conversion is in process.
-- 
2.43.0


  parent reply	other threads:[~2026-01-15 12:00 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-01-15 12:00 [PATCH v2 0/4] Paes and Phmac: Refuse clear key material by default Harald Freudenberger
2026-01-15 12:00 ` [PATCH v2 1/4] crypto: skcipher - Add new helper function crypto_skcipher_tested Harald Freudenberger
2026-01-15 12:00 ` [PATCH v2 2/4] s390/pkey: Support new xflag PKEY_XFLAG_NOCLEARKEY Harald Freudenberger
2026-01-15 12:00 ` [PATCH v2 3/4] crypto: s390/phmac - Refuse clear key material by default Harald Freudenberger
2026-01-15 12:00 ` Harald Freudenberger [this message]
2026-01-31  2:57 ` [PATCH v2 0/4] Paes and Phmac: " Herbert Xu

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=20260115120026.4286-5-freude@linux.ibm.com \
    --to=freude@linux.ibm.com \
    --cc=agordeev@linux.ibm.com \
    --cc=gor@linux.ibm.com \
    --cc=hca@linux.ibm.com \
    --cc=herbert@gondor.apana.org.au \
    --cc=linux-crypto@vger.kernel.org \
    --cc=linux-s390@vger.kernel.org \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.