xref: /linux/security/keys/trusted-keys/trusted_pkwm.c (revision bf4afc53b77aeaa48b5409da5c8da6bb4eff7f43)
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_obj(*options);
66 
67 	if (options) {
68 		pkwm = kzalloc_obj(*pkwm);
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 };
191