]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
keys/trusted_keys: establish PKWM as a trusted source
authorSrish Srinivasan <ssrish@linux.ibm.com>
Tue, 27 Jan 2026 14:52:27 +0000 (20:22 +0530)
committerMadhavan Srinivasan <maddy@linux.ibm.com>
Fri, 30 Jan 2026 03:57:26 +0000 (09:27 +0530)
The wrapping key does not exist by default and is generated by the
hypervisor as a part of PKWM initialization. This key is then persisted by
the hypervisor and is used to wrap trusted keys. These are variable length
symmetric keys, which in the case of PowerVM Key Wrapping Module (PKWM) are
generated using the kernel RNG. PKWM can be used as a trust source through
the following example keyctl commands:

keyctl add trusted my_trusted_key "new 32" @u

Use the wrap_flags command option to set the secure boot requirement for
the wrapping request through the following keyctl commands

case1: no secure boot requirement. (default)
keyctl usage: keyctl add trusted my_trusted_key "new 32" @u
      OR
      keyctl add trusted my_trusted_key "new 32 wrap_flags=0x00" @u

case2: secure boot required to in either audit or enforce mode. set bit 0
keyctl usage: keyctl add trusted my_trusted_key "new 32 wrap_flags=0x01" @u

case3: secure boot required to be in enforce mode. set bit 1
keyctl usage: keyctl add trusted my_trusted_key "new 32 wrap_flags=0x02" @u

NOTE:
-> Setting the secure boot requirement is NOT a must.
-> Only either of the secure boot requirement options should be set. Not
both.
-> All the other bits are required to be not set.
-> Set the kernel parameter trusted.source=pkwm to choose PKWM as the
backend for trusted keys implementation.
-> CONFIG_PSERIES_PLPKS must be enabled to build PKWM.

Add PKWM, which is a combination of IBM PowerVM and Power LPAR Platform
KeyStore, as a new trust source for trusted keys.

Signed-off-by: Srish Srinivasan <ssrish@linux.ibm.com>
Tested-by: Nayna Jain <nayna@linux.ibm.com>
Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
Reviewed-by: Nayna Jain <nayna@linux.ibm.com>
Reviewed-by: Jarkko Sakkinen <jarkko@kernel.org>
Signed-off-by: Madhavan Srinivasan <maddy@linux.ibm.com>
Link: https://patch.msgid.link/20260127145228.48320-6-ssrish@linux.ibm.com
MAINTAINERS
include/keys/trusted-type.h
include/keys/trusted_pkwm.h [new file with mode: 0644]
security/keys/trusted-keys/Kconfig
security/keys/trusted-keys/Makefile
security/keys/trusted-keys/trusted_core.c
security/keys/trusted-keys/trusted_pkwm.c [new file with mode: 0644]

index 765ad2daa21831072ac97ce4a35d01515fe9b1e7..103c79f476727572f1eac7f91077087c77a5707b 100644 (file)
@@ -14003,6 +14003,15 @@ S:     Supported
 F:     include/keys/trusted_dcp.h
 F:     security/keys/trusted-keys/trusted_dcp.c
 
+KEYS-TRUSTED-PLPKS
+M:     Srish Srinivasan <ssrish@linux.ibm.com>
+M:     Nayna Jain <nayna@linux.ibm.com>
+L:     linux-integrity@vger.kernel.org
+L:     keyrings@vger.kernel.org
+S:     Supported
+F:     include/keys/trusted_pkwm.h
+F:     security/keys/trusted-keys/trusted_pkwm.c
+
 KEYS-TRUSTED-TEE
 M:     Sumit Garg <sumit.garg@kernel.org>
 L:     linux-integrity@vger.kernel.org
index 4eb64548a74f1ad0b636a8caa35cb8b4544f573e..03527162613f72584459e1407cd36ed85afc1a05 100644 (file)
 
 #define MIN_KEY_SIZE                   32
 #define MAX_KEY_SIZE                   128
-#define MAX_BLOB_SIZE                  512
+#if IS_ENABLED(CONFIG_TRUSTED_KEYS_PKWM)
+#define MAX_BLOB_SIZE                  1152
+#else
+#define MAX_BLOB_SIZE                   512
+#endif
 #define MAX_PCRINFO_SIZE               64
 #define MAX_DIGEST_SIZE                        64
 
@@ -46,6 +50,7 @@ struct trusted_key_options {
        uint32_t policydigest_len;
        unsigned char policydigest[MAX_DIGEST_SIZE];
        uint32_t policyhandle;
+       void *private;
 };
 
 struct trusted_key_ops {
diff --git a/include/keys/trusted_pkwm.h b/include/keys/trusted_pkwm.h
new file mode 100644 (file)
index 0000000..4035b97
--- /dev/null
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __PKWM_TRUSTED_KEY_H
+#define __PKWM_TRUSTED_KEY_H
+
+#include <keys/trusted-type.h>
+#include <linux/bitops.h>
+#include <linux/printk.h>
+
+extern struct trusted_key_ops pkwm_trusted_key_ops;
+
+struct trusted_pkwm_options {
+       u16 wrap_flags;
+};
+
+static inline void dump_options(struct trusted_key_options *o)
+{
+       const struct trusted_pkwm_options *pkwm;
+       bool sb_audit_or_enforce_bit;
+       bool sb_enforce_bit;
+
+       pkwm = o->private;
+       sb_audit_or_enforce_bit = pkwm->wrap_flags & BIT(0);
+       sb_enforce_bit = pkwm->wrap_flags & BIT(1);
+
+       if (sb_audit_or_enforce_bit)
+               pr_debug("secure boot mode required: audit or enforce");
+       else if (sb_enforce_bit)
+               pr_debug("secure boot mode required: enforce");
+       else
+               pr_debug("secure boot mode required: disabled");
+}
+
+#endif
index 204a68c1429df796bcd838b25b452ff1b0b3f009..9e00482d886a5ae9d7f998e2bd41e954f1daa71a 100644 (file)
@@ -46,6 +46,14 @@ config TRUSTED_KEYS_DCP
        help
          Enable use of NXP's DCP (Data Co-Processor) as trusted key backend.
 
+config TRUSTED_KEYS_PKWM
+       bool "PKWM-based trusted keys"
+       depends on PSERIES_PLPKS >= TRUSTED_KEYS
+       default y
+       select HAVE_TRUSTED_KEYS
+       help
+         Enable use of IBM PowerVM Key Wrapping Module (PKWM) as a trusted key backend.
+
 if !HAVE_TRUSTED_KEYS
        comment "No trust source selected!"
 endif
index f0f3b27f688bc82cf8d59e03e4d9f2c92b56775d..5fc053a21dadf2abe35f516a181664f007128351 100644 (file)
@@ -16,3 +16,5 @@ trusted-$(CONFIG_TRUSTED_KEYS_TEE) += trusted_tee.o
 trusted-$(CONFIG_TRUSTED_KEYS_CAAM) += trusted_caam.o
 
 trusted-$(CONFIG_TRUSTED_KEYS_DCP) += trusted_dcp.o
+
+trusted-$(CONFIG_TRUSTED_KEYS_PKWM) += trusted_pkwm.o
index b1680ee53f86192711a9c95be7e2bfb9ade1a6f0..2d328de170e8c3a9403312ab590a70c32484de76 100644 (file)
@@ -12,6 +12,7 @@
 #include <keys/trusted_caam.h>
 #include <keys/trusted_dcp.h>
 #include <keys/trusted_tpm.h>
+#include <keys/trusted_pkwm.h>
 #include <linux/capability.h>
 #include <linux/err.h>
 #include <linux/init.h>
@@ -31,7 +32,7 @@ MODULE_PARM_DESC(rng, "Select trusted key RNG");
 
 static char *trusted_key_source;
 module_param_named(source, trusted_key_source, charp, 0);
-MODULE_PARM_DESC(source, "Select trusted keys source (tpm, tee, caam or dcp)");
+MODULE_PARM_DESC(source, "Select trusted keys source (tpm, tee, caam, dcp or pkwm)");
 
 static const struct trusted_key_source trusted_key_sources[] = {
 #if defined(CONFIG_TRUSTED_KEYS_TPM)
@@ -46,6 +47,9 @@ static const struct trusted_key_source trusted_key_sources[] = {
 #if defined(CONFIG_TRUSTED_KEYS_DCP)
        { "dcp", &dcp_trusted_key_ops },
 #endif
+#if defined(CONFIG_TRUSTED_KEYS_PKWM)
+       { "pkwm", &pkwm_trusted_key_ops },
+#endif
 };
 
 DEFINE_STATIC_CALL_NULL(trusted_key_seal, *trusted_key_sources[0].ops->seal);
diff --git a/security/keys/trusted-keys/trusted_pkwm.c b/security/keys/trusted-keys/trusted_pkwm.c
new file mode 100644 (file)
index 0000000..4f391b7
--- /dev/null
@@ -0,0 +1,190 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2025 IBM Corporation, Srish Srinivasan <ssrish@linux.ibm.com>
+ */
+
+#include <keys/trusted_pkwm.h>
+#include <keys/trusted-type.h>
+#include <linux/build_bug.h>
+#include <linux/key-type.h>
+#include <linux/parser.h>
+#include <asm/plpks.h>
+
+enum {
+       Opt_err,
+       Opt_wrap_flags,
+};
+
+static const match_table_t key_tokens = {
+       {Opt_wrap_flags, "wrap_flags=%s"},
+       {Opt_err, NULL}
+};
+
+static int getoptions(char *datablob, struct trusted_key_options *opt)
+{
+       substring_t args[MAX_OPT_ARGS];
+       char *p = datablob;
+       int token;
+       int res;
+       u16 wrap_flags;
+       unsigned long token_mask = 0;
+       struct trusted_pkwm_options *pkwm;
+
+       if (!datablob)
+               return 0;
+
+       pkwm = opt->private;
+
+       while ((p = strsep(&datablob, " \t"))) {
+               if (*p == '\0' || *p == ' ' || *p == '\t')
+                       continue;
+
+               token = match_token(p, key_tokens, args);
+               if (test_and_set_bit(token, &token_mask))
+                       return -EINVAL;
+
+               switch (token) {
+               case Opt_wrap_flags:
+                       res = kstrtou16(args[0].from, 16, &wrap_flags);
+                       if (res < 0 || wrap_flags > 2)
+                               return -EINVAL;
+                       pkwm->wrap_flags = wrap_flags;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+       }
+       return 0;
+}
+
+static struct trusted_key_options *trusted_options_alloc(void)
+{
+       struct trusted_key_options *options;
+       struct trusted_pkwm_options *pkwm;
+
+       options = kzalloc(sizeof(*options), GFP_KERNEL);
+
+       if (options) {
+               pkwm = kzalloc(sizeof(*pkwm), GFP_KERNEL);
+
+               if (!pkwm) {
+                       kfree_sensitive(options);
+                       options = NULL;
+               } else {
+                       options->private = pkwm;
+               }
+       }
+
+       return options;
+}
+
+static int trusted_pkwm_seal(struct trusted_key_payload *p, char *datablob)
+{
+       struct trusted_key_options *options = NULL;
+       struct trusted_pkwm_options *pkwm = NULL;
+       u8 *input_buf, *output_buf;
+       u32 output_len, input_len;
+       int rc;
+
+       options = trusted_options_alloc();
+
+       if (!options)
+               return -ENOMEM;
+
+       rc = getoptions(datablob, options);
+       if (rc < 0)
+               goto out;
+       dump_options(options);
+
+       input_len = p->key_len;
+       input_buf = kmalloc(ALIGN(input_len, 4096), GFP_KERNEL);
+       if (!input_buf) {
+               pr_err("Input buffer allocation failed. Returning -ENOMEM.");
+               rc = -ENOMEM;
+               goto out;
+       }
+
+       memcpy(input_buf, p->key, p->key_len);
+
+       pkwm = options->private;
+
+       rc = plpks_wrap_object(&input_buf, input_len, pkwm->wrap_flags,
+                              &output_buf, &output_len);
+       if (!rc) {
+               memcpy(p->blob, output_buf, output_len);
+               p->blob_len = output_len;
+               dump_payload(p);
+       } else {
+               pr_err("Wrapping of payload key failed: %d\n", rc);
+       }
+
+       kfree(input_buf);
+       kfree(output_buf);
+
+out:
+       kfree_sensitive(options->private);
+       kfree_sensitive(options);
+       return rc;
+}
+
+static int trusted_pkwm_unseal(struct trusted_key_payload *p, char *datablob)
+{
+       u8 *input_buf, *output_buf;
+       u32 input_len, output_len;
+       int rc;
+
+       input_len = p->blob_len;
+       input_buf = kmalloc(ALIGN(input_len, 4096), GFP_KERNEL);
+       if (!input_buf) {
+               pr_err("Input buffer allocation failed. Returning -ENOMEM.");
+               return -ENOMEM;
+       }
+
+       memcpy(input_buf, p->blob, p->blob_len);
+
+       rc = plpks_unwrap_object(&input_buf, input_len, &output_buf,
+                                &output_len);
+       if (!rc) {
+               memcpy(p->key, output_buf, output_len);
+               p->key_len = output_len;
+               dump_payload(p);
+       } else {
+               pr_err("Unwrapping of payload failed: %d\n", rc);
+       }
+
+       kfree(input_buf);
+       kfree(output_buf);
+
+       return rc;
+}
+
+static int trusted_pkwm_init(void)
+{
+       int ret;
+
+       if (!plpks_wrapping_is_supported()) {
+               pr_err("H_PKS_WRAP_OBJECT interface not supported\n");
+               return -ENODEV;
+       }
+
+       ret = plpks_gen_wrapping_key();
+       if (ret) {
+               pr_err("Failed to generate default wrapping key\n");
+               return -EINVAL;
+       }
+
+       return register_key_type(&key_type_trusted);
+}
+
+static void trusted_pkwm_exit(void)
+{
+       unregister_key_type(&key_type_trusted);
+}
+
+struct trusted_key_ops pkwm_trusted_key_ops = {
+       .migratable = 0, /* non-migratable */
+       .init = trusted_pkwm_init,
+       .seal = trusted_pkwm_seal,
+       .unseal = trusted_pkwm_unseal,
+       .exit = trusted_pkwm_exit,
+};