[PATCH v2 09/10] keys/trusted_keys: enable PKWM wrapping key selection by label

R Nageswara Sastry rnsastry at linux.ibm.com
Fri Sep 4 06:17:33 UTC 2026


On 31.08.2026 4:47 PM, Srish Srinivasan wrote:
> The PKWM trusted source currently uses the default wrapping key for all
> seal and unseal operations. However, PKWM supports multiple wrapping keys,
> enabling better isolation between trusted keys.
>
> Allow users to provide an active wrapping key of their choice created
> through sysfs when sealing trusted keys through a new wrapping_key=<label>
> option. If no label is specified, the default wrapping key is used for
> sealing.
>
> Signed-off-by: Srish Srinivasan <ssrish at linux.ibm.com>
Tested-by: R Nageswara Sastry <rnsastry at linux.ibm.com>

Tested on ppc64le PowerVM LPARs on firmware with wrap/unwrap support,
with and without Secure Boot enabled.

Verified that:
   - Trusted key creation without specifying wrapping_key= continues to work
     (default wrapping key used).
   - Trusted key creation with wrapping_key=<label> works correctly.
   - A label longer than 239 characters is rejected.
   - wrap_flags=0x01 and wrap_flags=0x02 behave as expected with the
     wrapping_key= option under each Secure Boot mode.
> ---
>   .../security/keys/trusted-encrypted.rst       |  4 +-
>   arch/powerpc/include/asm/plpks.h              | 10 ++-
>   arch/powerpc/platforms/pseries/plpks.c        | 64 ++++++++++---------
>   include/keys/trusted_pkwm.h                   |  3 +
>   security/keys/trusted-keys/trusted_pkwm.c     | 34 +++++++++-
>   5 files changed, 80 insertions(+), 35 deletions(-)
>
> diff --git a/Documentation/security/keys/trusted-encrypted.rst b/Documentation/security/keys/trusted-encrypted.rst
> index ddff7c7c2582..76fda28fddb1 100644
> --- a/Documentation/security/keys/trusted-encrypted.rst
> +++ b/Documentation/security/keys/trusted-encrypted.rst
> @@ -83,7 +83,7 @@ safe.
>   
>        (5) PKWM (PowerVM Key Wrapping Module: IBM PowerVM + Platform KeyStore)
>   
> -         Rooted to a unique, per-LPAR key, which is derived from a system-wide,
> +         Rooted to unique, per-LPAR keys, which are derived from a system-wide,
>            randomly generated LPAR root key. Both the per-LPAR keys and the LPAR
>            root key are stored in hypervisor-owned secure memory at runtime,
>            and the LPAR root key is additionally persisted in secure locations
> @@ -366,6 +366,8 @@ Usage::
>                          0x01: require secure boot to be in either audit or
>                                enforced mode
>                          0x02: require secure boot to be in enforced mode
> +       wrapping_key= optional wrapping key label as a string. The default
> +                     wrapping key is used when no label is provided.
>   
>   "keyctl print" returns an ASCII hex copy of the sealed key, which is in format
>   specific to PKWM key-blob implementation.  The key length for new keys is
> diff --git a/arch/powerpc/include/asm/plpks.h b/arch/powerpc/include/asm/plpks.h
> index c39d1f07017e..badb07afe749 100644
> --- a/arch/powerpc/include/asm/plpks.h
> +++ b/arch/powerpc/include/asm/plpks.h
> @@ -50,6 +50,12 @@
>   #define PLPKS_MAX_TIMEOUT		(5 * USEC_PER_SEC)
>   #define PLPKS_FLUSH_SLEEP		10000 // usec
>   
> +// Label for the PKWM default wrapping key
> +#define PLPKS_DEFAULT_WRAPKEY_LABEL	"default-wrapping-key"
> +
> +// Component for a PKWM wrapping key
> +#define PLPKS_WRAPKEY_COMPONENT	"PLPKSWR"
> +
>   struct plpks_var {
>   	char *component;
>   	u8 *name;
> @@ -117,10 +123,10 @@ int plpks_config_create_softlink(struct kobject *from);
>   
>   bool plpks_wrapping_is_supported(void);
>   
> -int plpks_gen_wrapping_key(void);
> +int plpks_gen_wrapping_key(struct plpks_var *var);
>   
>   int plpks_wrap_object(u8 **input_buf, u64 input_len, u16 wrap_flags,
> -		      u8 **output_buf, u64 *output_len);
> +		      u8 **output_buf, u64 *output_len, struct plpks_var *var);
>   
>   int plpks_unwrap_object(u8 **input_buf, u64 input_len,
>   			u8 **output_buf, u64 *output_len);
> diff --git a/arch/powerpc/platforms/pseries/plpks.c b/arch/powerpc/platforms/pseries/plpks.c
> index 3b1e6f00b4ae..5cdaabe9de06 100644
> --- a/arch/powerpc/platforms/pseries/plpks.c
> +++ b/arch/powerpc/platforms/pseries/plpks.c
> @@ -9,9 +9,6 @@
>   
>   #define pr_fmt(fmt) "plpks: " fmt
>   
> -#define PLPKS_WRAPKEY_COMPONENT	"PLPKSWR"
> -#define PLPKS_DEFAULT_WRAPKEY_LABEL	"default-wrapping-key"
> -
>   /*
>    * To 4K align the {input, output} buffers to the {UN}WRAP H_CALLs
>    */
> @@ -935,6 +932,7 @@ EXPORT_SYMBOL_GPL(plpks_revoke_is_supported);
>   /**
>    * plpks_gen_wrapping_key() - Generate a new random key with the 'wrapping key'
>    * policy set.
> + * @var: variable representing the wrapping key to be created
>    *
>    * The H_PKS_GEN_KEY HCALL makes the hypervisor generate a new random key and
>    * store the key in a PLPKS object with the provided object label. With the
> @@ -960,25 +958,27 @@ EXPORT_SYMBOL_GPL(plpks_revoke_is_supported);
>    *
>    * Returns: On success 0 is returned, a negative errno if not.
>    */
> -int plpks_gen_wrapping_key(void)
> +int plpks_gen_wrapping_key(struct plpks_var *var)
>   {
>   	unsigned long retbuf[PLPAR_HCALL_BUFSIZE] = { 0 };
>   	struct plpks_auth *auth;
>   	struct label *label;
>   	int rc = 0, pseries_status = 0;
> -	struct plpks_var var = {
> -		.name = PLPKS_DEFAULT_WRAPKEY_LABEL,
> -		.namelen = sizeof(PLPKS_DEFAULT_WRAPKEY_LABEL) - 1,
> -		.policy = PLPKS_WRAPPINGKEY,
> -		.os = PLPKS_VAR_LINUX,
> -		.component = PLPKS_WRAPKEY_COMPONENT
> -	};
> +
> +	if (!var)
> +		return -EINVAL;
> +
> +	if (!var->name || !*var->name) {
> +		pr_err("key label cannot be NULL/empty\n");
> +		return -EINVAL;
> +	}
>   
>   	auth = construct_auth(PLPKS_OS_OWNER);
>   	if (IS_ERR(auth))
>   		return PTR_ERR(auth);
>   
> -	label = construct_label(var.component, var.os, var.name, var.namelen);
> +	label = construct_label(var->component, var->os, var->name,
> +				var->namelen);
>   	if (IS_ERR(label)) {
>   		rc = PTR_ERR(label);
>   		goto out;
> @@ -986,7 +986,7 @@ int plpks_gen_wrapping_key(void)
>   
>   	rc = plpar_hcall(H_PKS_GEN_KEY, retbuf,
>   			 virt_to_phys(auth), virt_to_phys(label),
> -			 label->size, var.policy,
> +			 label->size, var->policy,
>   			 NULL, PLPKS_WRAPPING_KEY_LENGTH);
>   
>   	if (!rc)
> @@ -995,11 +995,13 @@ int plpks_gen_wrapping_key(void)
>   	pseries_status = rc;
>   	rc = pseries_status_to_err(rc);
>   
> -	if (rc && rc != -EEXIST) {
> -		pr_err("H_PKS_GEN_KEY failed. pseries_status=%d, rc=%d",
> -		       pseries_status, rc);
> -	} else {
> -		rc = 0;
> +	if (rc) {
> +		if (rc == -EEXIST)
> +			pr_info("wrapping key <%s> already exists\n",
> +				(char *)var->name);
> +		else
> +			pr_err("H_PKS_GEN_KEY failed. pseries_status=%d, rc=%d\n",
> +			       pseries_status, rc);
>   	}
>   
>   	kfree(label);
> @@ -1010,13 +1012,14 @@ int plpks_gen_wrapping_key(void)
>   EXPORT_SYMBOL_GPL(plpks_gen_wrapping_key);
>   
>   /**
> - * plpks_wrap_object() - Wrap an object using the default wrapping key stored in
> - * the PLPKS.
> + * plpks_wrap_object() - Wrap an object using the specified wrapping key stored
> + * in the PLPKS.
>    * @input_buf: buffer containing the data to be wrapped
>    * @input_len: length of the input buffer
>    * @wrap_flags: object wrapping flags
>    * @output_buf: buffer to store the wrapped data
>    * @output_len: length of the output buffer
> + * @var: variable representing the wrapping key to be used
>    *
>    * The H_PKS_WRAP_OBJECT HCALL wraps an object using a wrapping key stored in
>    * the PLPKS and returns the wrapped object to the caller. The caller provides a
> @@ -1051,7 +1054,7 @@ EXPORT_SYMBOL_GPL(plpks_gen_wrapping_key);
>    * Returns: On success 0 is returned, a negative errno if not.
>    */
>   int plpks_wrap_object(u8 **input_buf, u64 input_len, u16 wrap_flags,
> -		      u8 **output_buf, u64 *output_len)
> +		      u8 **output_buf, u64 *output_len, struct plpks_var *var)
>   {
>   	unsigned long retbuf[PLPAR_HCALL9_BUFSIZE] = { 0 };
>   	struct plpks_auth *auth;
> @@ -1061,18 +1064,21 @@ int plpks_wrap_object(u8 **input_buf, u64 input_len, u16 wrap_flags,
>   	int rc = 0, pseries_status = 0;
>   	bool sb_audit_or_enforce_bit = wrap_flags & BIT(0);
>   	bool sb_enforce_bit = wrap_flags & BIT(1);
> -	struct plpks_var var = {
> -		.name = PLPKS_DEFAULT_WRAPKEY_LABEL,
> -		.namelen = sizeof(PLPKS_DEFAULT_WRAPKEY_LABEL) - 1,
> -		.os = PLPKS_VAR_LINUX,
> -		.component = PLPKS_WRAPKEY_COMPONENT
> -	};
> +
> +	if (!var)
> +		return -EINVAL;
> +
> +	if (!var->name || !*var->name) {
> +		pr_err("key label cannot be NULL/empty\n");
> +		return -EINVAL;
> +	}
>   
>   	auth = construct_auth(PLPKS_OS_OWNER);
>   	if (IS_ERR(auth))
>   		return PTR_ERR(auth);
>   
> -	label = construct_label(var.component, var.os, var.name, var.namelen);
> +	label = construct_label(var->component, var->os, var->name,
> +				var->namelen);
>   	if (IS_ERR(label)) {
>   		rc = PTR_ERR(label);
>   		goto out;
> @@ -1135,7 +1141,7 @@ int plpks_wrap_object(u8 **input_buf, u64 input_len, u16 wrap_flags,
>   EXPORT_SYMBOL_GPL(plpks_wrap_object);
>   
>   /**
> - * plpks_unwrap_object() - Unwrap an object using the default wrapping key
> + * plpks_unwrap_object() - Unwrap an object using its associated wrapping key
>    * stored in the PLPKS.
>    * @input_buf: buffer containing the data to be unwrapped
>    * @input_len: length of the input buffer
> diff --git a/include/keys/trusted_pkwm.h b/include/keys/trusted_pkwm.h
> index 4035b9776394..53a5f780edd2 100644
> --- a/include/keys/trusted_pkwm.h
> +++ b/include/keys/trusted_pkwm.h
> @@ -6,10 +6,13 @@
>   #include <linux/bitops.h>
>   #include <linux/printk.h>
>   
> +#define WRAPPING_KEY_LABEL_LEN_MAX	239
> +
>   extern struct trusted_key_ops pkwm_trusted_key_ops;
>   
>   struct trusted_pkwm_options {
>   	u16 wrap_flags;
> +	unsigned char wrapping_key_label[WRAPPING_KEY_LABEL_LEN_MAX + 1];
>   };
>   
>   static inline void dump_options(struct trusted_key_options *o)
> diff --git a/security/keys/trusted-keys/trusted_pkwm.c b/security/keys/trusted-keys/trusted_pkwm.c
> index 633a7674d065..7bfe98d79cd7 100644
> --- a/security/keys/trusted-keys/trusted_pkwm.c
> +++ b/security/keys/trusted-keys/trusted_pkwm.c
> @@ -13,10 +13,12 @@
>   enum {
>   	Opt_err,
>   	Opt_wrap_flags,
> +	Opt_wrapping_key_label,
>   };
>   
>   static const match_table_t key_tokens = {
>   	{Opt_wrap_flags, "wrap_flags=%s"},
> +	{Opt_wrapping_key_label, "wrapping_key=%s"},
>   	{Opt_err, NULL}
>   };
>   
> @@ -50,6 +52,12 @@ static int getoptions(char *datablob, struct trusted_key_options *opt)
>   				return -EINVAL;
>   			pkwm->wrap_flags = wrap_flags;
>   			break;
> +		case Opt_wrapping_key_label:
> +			if (strlen(args[0].from) > WRAPPING_KEY_LABEL_LEN_MAX)
> +				return -EINVAL;
> +			strscpy(pkwm->wrapping_key_label, args[0].from,
> +				sizeof(pkwm->wrapping_key_label));
> +			break;
>   		default:
>   			return -EINVAL;
>   		}
> @@ -82,6 +90,7 @@ static int trusted_pkwm_seal(struct trusted_key_payload *p, char *datablob)
>   {
>   	struct trusted_key_options *options = NULL;
>   	struct trusted_pkwm_options *pkwm = NULL;
> +	struct plpks_var var;
>   	u8 *input_buf, *output_buf;
>   	u64 output_len, input_len;
>   	int rc;
> @@ -108,8 +117,18 @@ static int trusted_pkwm_seal(struct trusted_key_payload *p, char *datablob)
>   
>   	pkwm = options->private;
>   
> +	if (pkwm->wrapping_key_label[0]) {
> +		var.name = (u8 *)pkwm->wrapping_key_label;
> +		var.namelen = strlen(pkwm->wrapping_key_label);
> +	} else {
> +		var.name = (u8 *)PLPKS_DEFAULT_WRAPKEY_LABEL;
> +		var.namelen = strlen(PLPKS_DEFAULT_WRAPKEY_LABEL);
> +	}
> +	var.os = PLPKS_VAR_LINUX;
> +	var.component = PLPKS_WRAPKEY_COMPONENT;
> +
>   	rc = plpks_wrap_object(&input_buf, input_len, pkwm->wrap_flags,
> -			       &output_buf, &output_len);
> +			       &output_buf, &output_len, &var);
>   	if (!rc) {
>   		memcpy(p->blob, output_buf, output_len);
>   		p->blob_len = output_len;
> @@ -161,14 +180,23 @@ static int trusted_pkwm_unseal(struct trusted_key_payload *p, char *datablob)
>   static int trusted_pkwm_init(void)
>   {
>   	int ret;
> +	struct plpks_var var;
>   
>   	if (!plpks_wrapping_is_supported()) {
>   		pr_err("H_PKS_WRAP_OBJECT interface not supported\n");
>   		return -ENODEV;
>   	}
>   
> -	ret = plpks_gen_wrapping_key();
> -	if (ret) {
> +	var = (struct plpks_var) {
> +		.name = (u8 *)PLPKS_DEFAULT_WRAPKEY_LABEL,
> +		.namelen = sizeof(PLPKS_DEFAULT_WRAPKEY_LABEL) - 1,
> +		.policy = PLPKS_WRAPPINGKEY,
> +		.os = PLPKS_VAR_LINUX,
> +		.component = PLPKS_WRAPKEY_COMPONENT
> +	};
> +
> +	ret = plpks_gen_wrapping_key(&var);
> +	if (ret && ret != -EEXIST) {
>   		pr_err("Failed to generate default wrapping key\n");
>   		return ret;
>   	}

-- 
Thanks and Regards
R.Nageswara Sastry




More information about the Linux-security-module-archive mailing list