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 */ 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 */ 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 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 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 */ 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 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 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 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 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 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 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 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