File Index
Files and directories
Sign in
FILE

spmobj-attributes.c

File preview with syntax highlighting.

linux-6.19.14/drivers/platform/x86/hp/hp-bioscfg/spmobj-attributes.c C
  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
 11static const char * const spm_state_types[] = {
 12	"not provisioned",
 13	"provisioned",
 14	"provisioning in progress",
 15};
 16
 17static const char * const spm_mechanism_types[] = {
 18	"not provisioned",
 19	"signing-key",
 20	"endorsement-key",
 21};
 22
 23struct 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 */
 42size_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 */
 69int 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
106out_buffer:
107	return ret;
108}
109
110static 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
128static 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 */
145static 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
201status_exit:
202	len += sysfs_emit_at(buf, len, "}\n");
203
204	return len;
205}
206
207static struct kobj_attribute password_spm_status = __ATTR_RO(status);
208
209ATTRIBUTE_SPM_N_PROPERTY_SHOW(is_enabled, spm);
210static struct kobj_attribute password_spm_is_key_enabled = __ATTR_RO(is_enabled);
211
212static 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
219static struct kobj_attribute password_spm_key_mechanism = __ATTR_RO(key_mechanism);
220
221static 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
254static struct kobj_attribute password_spm_signing_key = __ATTR_WO(sk);
255
256static 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
284exit_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
291static struct kobj_attribute password_spm_endorsement_key = __ATTR_WO(kek);
292
293static 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
299static struct kobj_attribute password_spm_role = __ATTR_RO(role);
300
301static 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
321exit_token:
322	kfree(bioscfg_drv.spm_data.auth_token);
323	bioscfg_drv.spm_data.auth_token = NULL;
324
325	return ret;
326}
327
328static struct kobj_attribute password_spm_auth_token = __ATTR_WO(auth_token);
329
330static 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
341static const struct attribute_group secure_platform_attr_group = {
342	.attrs = secure_platform_attrs,
343};
344
345void 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
363int 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}
~/ Read-only file preview.