1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Functions corresponding to secure platform management object type
4 * attributes under BIOS PASSWORD for use with hp-bioscfg driver
5 *
6 * Copyright (c) 2022 HP Development Company, L.P.
7 */
8
9 #include "bioscfg.h"
10
11 static const char * const spm_state_types[] = {
12 "not provisioned",
13 "provisioned",
14 "provisioning in progress",
15 };
16
17 static const char * const spm_mechanism_types[] = {
18 "not provisioned",
19 "signing-key",
20 "endorsement-key",
21 };
22
23 struct secureplatform_provisioning_data {
24 u8 state;
25 u8 version[2];
26 u8 reserved1;
27 u32 features;
28 u32 nonce;
29 u8 reserved2[28];
30 u8 sk_mod[MAX_KEY_MOD_SIZE];
31 u8 kek_mod[MAX_KEY_MOD_SIZE];
32 };
33
34 /**
35 * hp_calculate_security_buffer() - determines size of security buffer
36 * for authentication scheme
37 *
38 * @authentication: the authentication content
39 *
40 * Currently only supported type is Admin password
41 */
hp_calculate_security_buffer(const char * authentication)42 size_t hp_calculate_security_buffer(const char *authentication)
43 {
44 size_t size, authlen;
45
46 if (!authentication)
47 return sizeof(u16) * 2;
48
49 authlen = strlen(authentication);
50 if (!authlen)
51 return sizeof(u16) * 2;
52
53 size = sizeof(u16) + authlen * sizeof(u16);
54 if (!strstarts(authentication, BEAM_PREFIX))
55 size += strlen(UTF_PREFIX) * sizeof(u16);
56
57 return size;
58 }
59
60 /**
61 * hp_populate_security_buffer() - builds a security buffer for
62 * authentication scheme
63 *
64 * @authbuf: the security buffer
65 * @authentication: the authentication content
66 *
67 * Currently only supported type is PLAIN TEXT
68 */
hp_populate_security_buffer(u16 * authbuf,const char * authentication)69 int hp_populate_security_buffer(u16 *authbuf, const char *authentication)
70 {
71 u16 *auth = authbuf;
72 char *strprefix = NULL;
73 int ret = 0;
74
75 if (strstarts(authentication, BEAM_PREFIX)) {
76 /*
77 * BEAM_PREFIX is append to authbuf when a signature
78 * is provided and Sure Admin is enabled in BIOS
79 */
80 /* BEAM_PREFIX found, convert part to unicode */
81 auth = hp_ascii_to_utf16_unicode(auth, authentication);
82 if (!auth)
83 return -EINVAL;
84
85 } else {
86 /*
87 * UTF-16 prefix is append to the * authbuf when a BIOS
88 * admin password is configured in BIOS
89 */
90
91 /* append UTF_PREFIX to part and then convert it to unicode */
92 strprefix = kasprintf(GFP_KERNEL, "%s%s", UTF_PREFIX,
93 authentication);
94 if (!strprefix)
95 return -ENOMEM;
96
97 auth = hp_ascii_to_utf16_unicode(auth, strprefix);
98 kfree(strprefix);
99
100 if (!auth) {
101 ret = -EINVAL;
102 goto out_buffer;
103 }
104 }
105
106 out_buffer:
107 return ret;
108 }
109
update_spm_state(void)110 static ssize_t update_spm_state(void)
111 {
112 struct secureplatform_provisioning_data data;
113 int ret;
114
115 ret = hp_wmi_perform_query(HPWMI_SECUREPLATFORM_GET_STATE,
116 HPWMI_SECUREPLATFORM, &data, 0,
117 sizeof(data));
118 if (ret < 0)
119 return ret;
120
121 bioscfg_drv.spm_data.mechanism = data.state;
122 if (bioscfg_drv.spm_data.mechanism)
123 bioscfg_drv.spm_data.is_enabled = 1;
124
125 return 0;
126 }
127
statusbin(struct kobject * kobj,struct kobj_attribute * attr,struct secureplatform_provisioning_data * buf)128 static ssize_t statusbin(struct kobject *kobj,
129 struct kobj_attribute *attr,
130 struct secureplatform_provisioning_data *buf)
131 {
132 int ret = hp_wmi_perform_query(HPWMI_SECUREPLATFORM_GET_STATE,
133 HPWMI_SECUREPLATFORM, buf, 0,
134 sizeof(*buf));
135
136 if (ret < 0)
137 return ret;
138
139 return sizeof(struct secureplatform_provisioning_data);
140 }
141
142 /*
143 * status_show - Reads SPM status
144 */
status_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)145 static ssize_t status_show(struct kobject *kobj, struct kobj_attribute
146 *attr, char *buf)
147 {
148 int ret, i;
149 int len = 0;
150 struct secureplatform_provisioning_data data;
151
152 ret = statusbin(kobj, attr, &data);
153 if (ret < 0)
154 return ret;
155
156 /*
157 * 'status' is a read-only file that returns ASCII text in
158 * JSON format reporting the status information.
159 *
160 * "State": "not provisioned | provisioned | provisioning in progress ",
161 * "Version": " Major. Minor ",
162 * "Nonce": <16-bit unsigned number display in base 10>,
163 * "FeaturesInUse": <16-bit unsigned number display in base 10>,
164 * "EndorsementKeyMod": "<256 bytes in base64>",
165 * "SigningKeyMod": "<256 bytes in base64>"
166 */
167
168 len += sysfs_emit_at(buf, len, "{\n");
169 len += sysfs_emit_at(buf, len, "\t\"State\": \"%s\",\n",
170 spm_state_types[data.state]);
171 len += sysfs_emit_at(buf, len, "\t\"Version\": \"%d.%d\"",
172 data.version[0], data.version[1]);
173
174 /*
175 * state == 0 means secure platform management
176 * feature is not configured in BIOS.
177 */
178 if (data.state == 0) {
179 len += sysfs_emit_at(buf, len, "\n");
180 goto status_exit;
181 } else {
182 len += sysfs_emit_at(buf, len, ",\n");
183 }
184
185 len += sysfs_emit_at(buf, len, "\t\"Nonce\": %d,\n", data.nonce);
186 len += sysfs_emit_at(buf, len, "\t\"FeaturesInUse\": %d,\n", data.features);
187 len += sysfs_emit_at(buf, len, "\t\"EndorsementKeyMod\": \"");
188
189 for (i = 255; i >= 0; i--)
190 len += sysfs_emit_at(buf, len, " %u", data.kek_mod[i]);
191
192 len += sysfs_emit_at(buf, len, " \",\n");
193 len += sysfs_emit_at(buf, len, "\t\"SigningKeyMod\": \"");
194
195 for (i = 255; i >= 0; i--)
196 len += sysfs_emit_at(buf, len, " %u", data.sk_mod[i]);
197
198 /* Return buf contents */
199 len += sysfs_emit_at(buf, len, " \"\n");
200
201 status_exit:
202 len += sysfs_emit_at(buf, len, "}\n");
203
204 return len;
205 }
206
207 static struct kobj_attribute password_spm_status = __ATTR_RO(status);
208
209 ATTRIBUTE_SPM_N_PROPERTY_SHOW(is_enabled, spm);
210 static struct kobj_attribute password_spm_is_key_enabled = __ATTR_RO(is_enabled);
211
key_mechanism_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)212 static ssize_t key_mechanism_show(struct kobject *kobj, struct kobj_attribute *attr,
213 char *buf)
214 {
215 return sysfs_emit(buf, "%s\n",
216 spm_mechanism_types[bioscfg_drv.spm_data.mechanism]);
217 }
218
219 static struct kobj_attribute password_spm_key_mechanism = __ATTR_RO(key_mechanism);
220
sk_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t count)221 static ssize_t sk_store(struct kobject *kobj,
222 struct kobj_attribute *attr,
223 const char *buf, size_t count)
224 {
225 int ret;
226 int length;
227
228 length = count;
229 if (buf[length - 1] == '\n')
230 length--;
231
232 /* allocate space and copy current signing key */
233 bioscfg_drv.spm_data.signing_key = kmemdup(buf, length, GFP_KERNEL);
234 if (!bioscfg_drv.spm_data.signing_key)
235 return -ENOMEM;
236
237 /* submit signing key payload */
238 ret = hp_wmi_perform_query(HPWMI_SECUREPLATFORM_SET_SK,
239 HPWMI_SECUREPLATFORM,
240 (void *)bioscfg_drv.spm_data.signing_key,
241 count, 0);
242
243 if (!ret) {
244 bioscfg_drv.spm_data.mechanism = SIGNING_KEY;
245 hp_set_reboot_and_signal_event();
246 }
247
248 kfree(bioscfg_drv.spm_data.signing_key);
249 bioscfg_drv.spm_data.signing_key = NULL;
250
251 return ret ? ret : count;
252 }
253
254 static struct kobj_attribute password_spm_signing_key = __ATTR_WO(sk);
255
kek_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t count)256 static ssize_t kek_store(struct kobject *kobj,
257 struct kobj_attribute *attr,
258 const char *buf, size_t count)
259 {
260 int ret;
261 int length;
262
263 length = count;
264 if (buf[length - 1] == '\n')
265 length--;
266
267 /* allocate space and copy current signing key */
268 bioscfg_drv.spm_data.endorsement_key = kmemdup(buf, length, GFP_KERNEL);
269 if (!bioscfg_drv.spm_data.endorsement_key) {
270 ret = -ENOMEM;
271 goto exit_kek;
272 }
273
274 ret = hp_wmi_perform_query(HPWMI_SECUREPLATFORM_SET_KEK,
275 HPWMI_SECUREPLATFORM,
276 (void *)bioscfg_drv.spm_data.endorsement_key,
277 count, 0);
278
279 if (!ret) {
280 bioscfg_drv.spm_data.mechanism = ENDORSEMENT_KEY;
281 hp_set_reboot_and_signal_event();
282 }
283
284 exit_kek:
285 kfree(bioscfg_drv.spm_data.endorsement_key);
286 bioscfg_drv.spm_data.endorsement_key = NULL;
287
288 return ret ? ret : count;
289 }
290
291 static struct kobj_attribute password_spm_endorsement_key = __ATTR_WO(kek);
292
role_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)293 static ssize_t role_show(struct kobject *kobj, struct kobj_attribute *attr,
294 char *buf)
295 {
296 return sysfs_emit(buf, "%s\n", BIOS_SPM);
297 }
298
299 static struct kobj_attribute password_spm_role = __ATTR_RO(role);
300
auth_token_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t count)301 static ssize_t auth_token_store(struct kobject *kobj,
302 struct kobj_attribute *attr,
303 const char *buf, size_t count)
304 {
305 int ret = 0;
306 int length;
307
308 length = count;
309 if (buf[length - 1] == '\n')
310 length--;
311
312 /* allocate space and copy current auth token */
313 bioscfg_drv.spm_data.auth_token = kmemdup(buf, length, GFP_KERNEL);
314 if (!bioscfg_drv.spm_data.auth_token) {
315 ret = -ENOMEM;
316 goto exit_token;
317 }
318
319 return count;
320
321 exit_token:
322 kfree(bioscfg_drv.spm_data.auth_token);
323 bioscfg_drv.spm_data.auth_token = NULL;
324
325 return ret;
326 }
327
328 static struct kobj_attribute password_spm_auth_token = __ATTR_WO(auth_token);
329
330 static struct attribute *secure_platform_attrs[] = {
331 &password_spm_is_key_enabled.attr,
332 &password_spm_signing_key.attr,
333 &password_spm_endorsement_key.attr,
334 &password_spm_key_mechanism.attr,
335 &password_spm_status.attr,
336 &password_spm_role.attr,
337 &password_spm_auth_token.attr,
338 NULL,
339 };
340
341 static const struct attribute_group secure_platform_attr_group = {
342 .attrs = secure_platform_attrs,
343 };
344
hp_exit_secure_platform_attributes(void)345 void hp_exit_secure_platform_attributes(void)
346 {
347 /* remove secure platform sysfs entry and free key data*/
348
349 kfree(bioscfg_drv.spm_data.endorsement_key);
350 bioscfg_drv.spm_data.endorsement_key = NULL;
351
352 kfree(bioscfg_drv.spm_data.signing_key);
353 bioscfg_drv.spm_data.signing_key = NULL;
354
355 kfree(bioscfg_drv.spm_data.auth_token);
356 bioscfg_drv.spm_data.auth_token = NULL;
357
358 if (bioscfg_drv.spm_data.attr_name_kobj)
359 sysfs_remove_group(bioscfg_drv.spm_data.attr_name_kobj,
360 &secure_platform_attr_group);
361 }
362
hp_populate_secure_platform_data(struct kobject * attr_name_kobj)363 int hp_populate_secure_platform_data(struct kobject *attr_name_kobj)
364 {
365 /* Populate data for Secure Platform Management */
366 bioscfg_drv.spm_data.attr_name_kobj = attr_name_kobj;
367
368 strscpy(bioscfg_drv.spm_data.attribute_name, SPM_STR,
369 sizeof(bioscfg_drv.spm_data.attribute_name));
370
371 bioscfg_drv.spm_data.is_enabled = 0;
372 bioscfg_drv.spm_data.mechanism = 0;
373 bioscfg_drv.pending_reboot = false;
374 update_spm_state();
375
376 bioscfg_drv.spm_data.endorsement_key = NULL;
377 bioscfg_drv.spm_data.signing_key = NULL;
378 bioscfg_drv.spm_data.auth_token = NULL;
379
380 return sysfs_create_group(attr_name_kobj, &secure_platform_attr_group);
381 }
382