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
getoptions(char * datablob,struct trusted_key_options * opt)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
trusted_options_alloc(void)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
trusted_pkwm_seal(struct trusted_key_payload * p,char * datablob)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
trusted_pkwm_unseal(struct trusted_key_payload * p,char * datablob)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
trusted_pkwm_init(void)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
trusted_pkwm_exit(void)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