]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
crypto: s390/phmac - Refuse clear key material by default
authorHarald Freudenberger <freude@linux.ibm.com>
Thu, 15 Jan 2026 12:00:25 +0000 (13:00 +0100)
committerHerbert Xu <herbert@gondor.apana.org.au>
Sat, 31 Jan 2026 02:52:30 +0000 (10:52 +0800)
This patch exploits the new xflag PKEY_XFLAG_NOCLEARKEY from the pkey
layer. So now by default the phmac refuses 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_ahash_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>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
arch/s390/crypto/phmac_s390.c

index 88342bd4c37a7f4f075fa5b860f8ff8c09ea4604..03ca33ffe6ccfaa808c48000d8558e4dd385df78 100644 (file)
 static struct crypto_engine *phmac_crypto_engine;
 #define MAX_QLEN 10
 
+static bool pkey_clrkey_allowed;
+module_param_named(clrkey, pkey_clrkey_allowed, bool, 0444);
+MODULE_PARM_DESC(clrkey, "Allow clear key material (default N)");
+
 /*
  * A simple hash walk helper
  */
@@ -311,10 +315,14 @@ static inline int phmac_tfm_ctx_setkey(struct phmac_tfm_ctx *tfm_ctx,
  * This function may sleep - don't call in non-sleeping context.
  */
 static inline int convert_key(const u8 *key, unsigned int keylen,
-                             struct phmac_protkey *pk)
+                             struct phmac_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);
 
        /*
@@ -328,7 +336,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:
@@ -350,7 +358,7 @@ out:
  * unnecessary additional conversion but never to invalid data on the
  * hash operation.
  */
-static int phmac_convert_key(struct phmac_tfm_ctx *tfm_ctx)
+static int phmac_convert_key(struct phmac_tfm_ctx *tfm_ctx, bool tested)
 {
        struct phmac_protkey pk;
        int rc;
@@ -359,7 +367,7 @@ static int phmac_convert_key(struct phmac_tfm_ctx *tfm_ctx)
        tfm_ctx->pk_state = PK_STATE_CONVERT_IN_PROGRESS;
        spin_unlock_bh(&tfm_ctx->pk_lock);
 
-       rc = convert_key(tfm_ctx->keybuf, tfm_ctx->keylen, &pk);
+       rc = convert_key(tfm_ctx->keybuf, tfm_ctx->keylen, &pk, tested);
 
        /* update context */
        spin_lock_bh(&tfm_ctx->pk_lock);
@@ -404,6 +412,7 @@ static int phmac_kmac_update(struct ahash_request *req, bool maysleep)
        struct kmac_sha2_ctx *ctx = &req_ctx->kmac_ctx;
        struct hash_walk_helper *hwh = &req_ctx->hwh;
        unsigned int bs = crypto_ahash_blocksize(tfm);
+       bool tested = crypto_ahash_tested(tfm);
        unsigned int offset, k, n;
        int rc = 0;
 
@@ -444,7 +453,7 @@ static int phmac_kmac_update(struct ahash_request *req, bool maysleep)
                                        rc = -EKEYEXPIRED;
                                        goto out;
                                }
-                               rc = phmac_convert_key(tfm_ctx);
+                               rc = phmac_convert_key(tfm_ctx, tested);
                                if (rc)
                                        goto out;
                                spin_lock_bh(&tfm_ctx->pk_lock);
@@ -480,7 +489,7 @@ static int phmac_kmac_update(struct ahash_request *req, bool maysleep)
                                        rc = -EKEYEXPIRED;
                                        goto out;
                                }
-                               rc = phmac_convert_key(tfm_ctx);
+                               rc = phmac_convert_key(tfm_ctx, tested);
                                if (rc)
                                        goto out;
                                spin_lock_bh(&tfm_ctx->pk_lock);
@@ -517,6 +526,7 @@ static int phmac_kmac_final(struct ahash_request *req, bool maysleep)
        struct kmac_sha2_ctx *ctx = &req_ctx->kmac_ctx;
        unsigned int ds = crypto_ahash_digestsize(tfm);
        unsigned int bs = crypto_ahash_blocksize(tfm);
+       bool tested = crypto_ahash_tested(tfm);
        unsigned int k, n;
        int rc = 0;
 
@@ -537,7 +547,7 @@ static int phmac_kmac_final(struct ahash_request *req, bool maysleep)
                        rc = -EKEYEXPIRED;
                        goto out;
                }
-               rc = phmac_convert_key(tfm_ctx);
+               rc = phmac_convert_key(tfm_ctx, tested);
                if (rc)
                        goto out;
                spin_lock_bh(&tfm_ctx->pk_lock);
@@ -741,11 +751,12 @@ static int phmac_setkey(struct crypto_ahash *tfm,
        struct phmac_tfm_ctx *tfm_ctx = crypto_ahash_ctx(tfm);
        unsigned int ds = crypto_ahash_digestsize(tfm);
        unsigned int bs = crypto_ahash_blocksize(tfm);
+       bool tested = crypto_ahash_tested(tfm);
        unsigned int tmpkeylen;
        u8 *tmpkey = NULL;
        int rc = 0;
 
-       if (!crypto_ahash_tested(tfm)) {
+       if (!tested) {
                /*
                 * selftest running: key is a raw hmac clear key and needs
                 * to get embedded into a 'clear key token' in order to have
@@ -770,7 +781,7 @@ static int phmac_setkey(struct crypto_ahash *tfm,
                goto out;
 
        /* convert raw key into protected key */
-       rc = phmac_convert_key(tfm_ctx);
+       rc = phmac_convert_key(tfm_ctx, tested);
        if (rc)
                goto out;