brintos

brintos / linux-shallow public Read only

0
0
Text · 9.3 KiB · 2b00a14 Raw
381 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Functions corresponding to secure platform management object type4 * attributes under BIOS PASSWORD for use with hp-bioscfg driver5 *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 buffer36 * for authentication scheme37 *38 * @authentication: the authentication content39 *40 * Currently only supported type is Admin password41 */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 for62 * authentication scheme63 *64 * @authbuf: the security buffer65 * @authentication: the authentication content66 *67 * Currently only supported type is PLAIN TEXT68 */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 signature78		 * is provided and Sure Admin is enabled in BIOS79		 */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 BIOS88		 * admin password is configured in BIOS89		 */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 status144 */145static ssize_t status_show(struct kobject *kobj, struct kobj_attribute146			   *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 in158	 * 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 management176	 * 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}381