xref: /linux/drivers/platform/x86/hp/hp-bioscfg/spmobj-attributes.c (revision a1ff5a7d78a036d6c2178ee5acd6ba4946243800)
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 
370 	bioscfg_drv.spm_data.is_enabled = 0;
371 	bioscfg_drv.spm_data.mechanism = 0;
372 	bioscfg_drv.pending_reboot = false;
373 	update_spm_state();
374 
375 	bioscfg_drv.spm_data.endorsement_key = NULL;
376 	bioscfg_drv.spm_data.signing_key = NULL;
377 	bioscfg_drv.spm_data.auth_token = NULL;
378 
379 	return sysfs_create_group(attr_name_kobj, &secure_platform_attr_group);
380 }
381