Skip to content

Commit c99fcb0

Browse files
ssrish17maddy-kerneldev
authored andcommitted
keys/trusted_keys: establish PKWM as a trusted source
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
1 parent 133aa79 commit c99fcb0

7 files changed

Lines changed: 253 additions & 2 deletions

File tree

MAINTAINERS

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14003,6 +14003,15 @@ S: Supported
1400314003
F: include/keys/trusted_dcp.h
1400414004
F: security/keys/trusted-keys/trusted_dcp.c
1400514005

14006+
KEYS-TRUSTED-PLPKS
14007+
M: Srish Srinivasan <ssrish@linux.ibm.com>
14008+
M: Nayna Jain <nayna@linux.ibm.com>
14009+
L: linux-integrity@vger.kernel.org
14010+
L: keyrings@vger.kernel.org
14011+
S: Supported
14012+
F: include/keys/trusted_pkwm.h
14013+
F: security/keys/trusted-keys/trusted_pkwm.c
14014+
1400614015
KEYS-TRUSTED-TEE
1400714016
M: Sumit Garg <sumit.garg@kernel.org>
1400814017
L: linux-integrity@vger.kernel.org

include/keys/trusted-type.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,11 @@
1919

2020
#define MIN_KEY_SIZE 32
2121
#define MAX_KEY_SIZE 128
22-
#define MAX_BLOB_SIZE 512
22+
#if IS_ENABLED(CONFIG_TRUSTED_KEYS_PKWM)
23+
#define MAX_BLOB_SIZE 1152
24+
#else
25+
#define MAX_BLOB_SIZE 512
26+
#endif
2327
#define MAX_PCRINFO_SIZE 64
2428
#define MAX_DIGEST_SIZE 64
2529

@@ -46,6 +50,7 @@ struct trusted_key_options {
4650
uint32_t policydigest_len;
4751
unsigned char policydigest[MAX_DIGEST_SIZE];
4852
uint32_t policyhandle;
53+
void *private;
4954
};
5055

5156
struct trusted_key_ops {

include/keys/trusted_pkwm.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
#ifndef __PKWM_TRUSTED_KEY_H
3+
#define __PKWM_TRUSTED_KEY_H
4+
5+
#include <keys/trusted-type.h>
6+
#include <linux/bitops.h>
7+
#include <linux/printk.h>
8+
9+
extern struct trusted_key_ops pkwm_trusted_key_ops;
10+
11+
struct trusted_pkwm_options {
12+
u16 wrap_flags;
13+
};
14+
15+
static inline void dump_options(struct trusted_key_options *o)
16+
{
17+
const struct trusted_pkwm_options *pkwm;
18+
bool sb_audit_or_enforce_bit;
19+
bool sb_enforce_bit;
20+
21+
pkwm = o->private;
22+
sb_audit_or_enforce_bit = pkwm->wrap_flags & BIT(0);
23+
sb_enforce_bit = pkwm->wrap_flags & BIT(1);
24+
25+
if (sb_audit_or_enforce_bit)
26+
pr_debug("secure boot mode required: audit or enforce");
27+
else if (sb_enforce_bit)
28+
pr_debug("secure boot mode required: enforce");
29+
else
30+
pr_debug("secure boot mode required: disabled");
31+
}
32+
33+
#endif

security/keys/trusted-keys/Kconfig

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,14 @@ config TRUSTED_KEYS_DCP
4646
help
4747
Enable use of NXP's DCP (Data Co-Processor) as trusted key backend.
4848

49+
config TRUSTED_KEYS_PKWM
50+
bool "PKWM-based trusted keys"
51+
depends on PSERIES_PLPKS >= TRUSTED_KEYS
52+
default y
53+
select HAVE_TRUSTED_KEYS
54+
help
55+
Enable use of IBM PowerVM Key Wrapping Module (PKWM) as a trusted key backend.
56+
4957
if !HAVE_TRUSTED_KEYS
5058
comment "No trust source selected!"
5159
endif

security/keys/trusted-keys/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,5 @@ trusted-$(CONFIG_TRUSTED_KEYS_TEE) += trusted_tee.o
1616
trusted-$(CONFIG_TRUSTED_KEYS_CAAM) += trusted_caam.o
1717

1818
trusted-$(CONFIG_TRUSTED_KEYS_DCP) += trusted_dcp.o
19+
20+
trusted-$(CONFIG_TRUSTED_KEYS_PKWM) += trusted_pkwm.o

security/keys/trusted-keys/trusted_core.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <keys/trusted_caam.h>
1313
#include <keys/trusted_dcp.h>
1414
#include <keys/trusted_tpm.h>
15+
#include <keys/trusted_pkwm.h>
1516
#include <linux/capability.h>
1617
#include <linux/err.h>
1718
#include <linux/init.h>
@@ -31,7 +32,7 @@ MODULE_PARM_DESC(rng, "Select trusted key RNG");
3132

3233
static char *trusted_key_source;
3334
module_param_named(source, trusted_key_source, charp, 0);
34-
MODULE_PARM_DESC(source, "Select trusted keys source (tpm, tee, caam or dcp)");
35+
MODULE_PARM_DESC(source, "Select trusted keys source (tpm, tee, caam, dcp or pkwm)");
3536

3637
static const struct trusted_key_source trusted_key_sources[] = {
3738
#if defined(CONFIG_TRUSTED_KEYS_TPM)
@@ -46,6 +47,9 @@ static const struct trusted_key_source trusted_key_sources[] = {
4647
#if defined(CONFIG_TRUSTED_KEYS_DCP)
4748
{ "dcp", &dcp_trusted_key_ops },
4849
#endif
50+
#if defined(CONFIG_TRUSTED_KEYS_PKWM)
51+
{ "pkwm", &pkwm_trusted_key_ops },
52+
#endif
4953
};
5054

5155
DEFINE_STATIC_CALL_NULL(trusted_key_seal, *trusted_key_sources[0].ops->seal);
Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
/*
3+
* Copyright (C) 2025 IBM Corporation, Srish Srinivasan <ssrish@linux.ibm.com>
4+
*/
5+
6+
#include <keys/trusted_pkwm.h>
7+
#include <keys/trusted-type.h>
8+
#include <linux/build_bug.h>
9+
#include <linux/key-type.h>
10+
#include <linux/parser.h>
11+
#include <asm/plpks.h>
12+
13+
enum {
14+
Opt_err,
15+
Opt_wrap_flags,
16+
};
17+
18+
static const match_table_t key_tokens = {
19+
{Opt_wrap_flags, "wrap_flags=%s"},
20+
{Opt_err, NULL}
21+
};
22+
23+
static int getoptions(char *datablob, struct trusted_key_options *opt)
24+
{
25+
substring_t args[MAX_OPT_ARGS];
26+
char *p = datablob;
27+
int token;
28+
int res;
29+
u16 wrap_flags;
30+
unsigned long token_mask = 0;
31+
struct trusted_pkwm_options *pkwm;
32+
33+
if (!datablob)
34+
return 0;
35+
36+
pkwm = opt->private;
37+
38+
while ((p = strsep(&datablob, " \t"))) {
39+
if (*p == '\0' || *p == ' ' || *p == '\t')
40+
continue;
41+
42+
token = match_token(p, key_tokens, args);
43+
if (test_and_set_bit(token, &token_mask))
44+
return -EINVAL;
45+
46+
switch (token) {
47+
case Opt_wrap_flags:
48+
res = kstrtou16(args[0].from, 16, &wrap_flags);
49+
if (res < 0 || wrap_flags > 2)
50+
return -EINVAL;
51+
pkwm->wrap_flags = wrap_flags;
52+
break;
53+
default:
54+
return -EINVAL;
55+
}
56+
}
57+
return 0;
58+
}
59+
60+
static struct trusted_key_options *trusted_options_alloc(void)
61+
{
62+
struct trusted_key_options *options;
63+
struct trusted_pkwm_options *pkwm;
64+
65+
options = kzalloc(sizeof(*options), GFP_KERNEL);
66+
67+
if (options) {
68+
pkwm = kzalloc(sizeof(*pkwm), GFP_KERNEL);
69+
70+
if (!pkwm) {
71+
kfree_sensitive(options);
72+
options = NULL;
73+
} else {
74+
options->private = pkwm;
75+
}
76+
}
77+
78+
return options;
79+
}
80+
81+
static int trusted_pkwm_seal(struct trusted_key_payload *p, char *datablob)
82+
{
83+
struct trusted_key_options *options = NULL;
84+
struct trusted_pkwm_options *pkwm = NULL;
85+
u8 *input_buf, *output_buf;
86+
u32 output_len, input_len;
87+
int rc;
88+
89+
options = trusted_options_alloc();
90+
91+
if (!options)
92+
return -ENOMEM;
93+
94+
rc = getoptions(datablob, options);
95+
if (rc < 0)
96+
goto out;
97+
dump_options(options);
98+
99+
input_len = p->key_len;
100+
input_buf = kmalloc(ALIGN(input_len, 4096), GFP_KERNEL);
101+
if (!input_buf) {
102+
pr_err("Input buffer allocation failed. Returning -ENOMEM.");
103+
rc = -ENOMEM;
104+
goto out;
105+
}
106+
107+
memcpy(input_buf, p->key, p->key_len);
108+
109+
pkwm = options->private;
110+
111+
rc = plpks_wrap_object(&input_buf, input_len, pkwm->wrap_flags,
112+
&output_buf, &output_len);
113+
if (!rc) {
114+
memcpy(p->blob, output_buf, output_len);
115+
p->blob_len = output_len;
116+
dump_payload(p);
117+
} else {
118+
pr_err("Wrapping of payload key failed: %d\n", rc);
119+
}
120+
121+
kfree(input_buf);
122+
kfree(output_buf);
123+
124+
out:
125+
kfree_sensitive(options->private);
126+
kfree_sensitive(options);
127+
return rc;
128+
}
129+
130+
static int trusted_pkwm_unseal(struct trusted_key_payload *p, char *datablob)
131+
{
132+
u8 *input_buf, *output_buf;
133+
u32 input_len, output_len;
134+
int rc;
135+
136+
input_len = p->blob_len;
137+
input_buf = kmalloc(ALIGN(input_len, 4096), GFP_KERNEL);
138+
if (!input_buf) {
139+
pr_err("Input buffer allocation failed. Returning -ENOMEM.");
140+
return -ENOMEM;
141+
}
142+
143+
memcpy(input_buf, p->blob, p->blob_len);
144+
145+
rc = plpks_unwrap_object(&input_buf, input_len, &output_buf,
146+
&output_len);
147+
if (!rc) {
148+
memcpy(p->key, output_buf, output_len);
149+
p->key_len = output_len;
150+
dump_payload(p);
151+
} else {
152+
pr_err("Unwrapping of payload failed: %d\n", rc);
153+
}
154+
155+
kfree(input_buf);
156+
kfree(output_buf);
157+
158+
return rc;
159+
}
160+
161+
static int trusted_pkwm_init(void)
162+
{
163+
int ret;
164+
165+
if (!plpks_wrapping_is_supported()) {
166+
pr_err("H_PKS_WRAP_OBJECT interface not supported\n");
167+
return -ENODEV;
168+
}
169+
170+
ret = plpks_gen_wrapping_key();
171+
if (ret) {
172+
pr_err("Failed to generate default wrapping key\n");
173+
return -EINVAL;
174+
}
175+
176+
return register_key_type(&key_type_trusted);
177+
}
178+
179+
static void trusted_pkwm_exit(void)
180+
{
181+
unregister_key_type(&key_type_trusted);
182+
}
183+
184+
struct trusted_key_ops pkwm_trusted_key_ops = {
185+
.migratable = 0, /* non-migratable */
186+
.init = trusted_pkwm_init,
187+
.seal = trusted_pkwm_seal,
188+
.unseal = trusted_pkwm_unseal,
189+
.exit = trusted_pkwm_exit,
190+
};

0 commit comments

Comments
 (0)