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