1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright (c) 2018 Bootlin 4 * Author: Miquel Raynal <miquel.raynal@bootlin.com> 5 */ 6 7 #include <common.h> 8 #include <dm.h> 9 #include <tpm-common.h> 10 #include <tpm-v2.h> 11 #include "tpm-utils.h" 12 13 u32 tpm2_startup(struct udevice *dev, enum tpm2_startup_types mode) 14 { 15 const u8 command_v2[12] = { 16 tpm_u16(TPM2_ST_NO_SESSIONS), 17 tpm_u32(12), 18 tpm_u32(TPM2_CC_STARTUP), 19 tpm_u16(mode), 20 }; 21 int ret; 22 23 /* 24 * Note TPM2_Startup command will return RC_SUCCESS the first time, 25 * but will return RC_INITIALIZE otherwise. 26 */ 27 ret = tpm_sendrecv_command(dev, command_v2, NULL, NULL); 28 if (ret && ret != TPM2_RC_INITIALIZE) 29 return ret; 30 31 return 0; 32 } 33 34 u32 tpm2_self_test(struct udevice *dev, enum tpm2_yes_no full_test) 35 { 36 const u8 command_v2[12] = { 37 tpm_u16(TPM2_ST_NO_SESSIONS), 38 tpm_u32(11), 39 tpm_u32(TPM2_CC_SELF_TEST), 40 full_test, 41 }; 42 43 return tpm_sendrecv_command(dev, command_v2, NULL, NULL); 44 } 45 46 u32 tpm2_clear(struct udevice *dev, u32 handle, const char *pw, 47 const ssize_t pw_sz) 48 { 49 u8 command_v2[COMMAND_BUFFER_SIZE] = { 50 tpm_u16(TPM2_ST_SESSIONS), /* TAG */ 51 tpm_u32(27 + pw_sz), /* Length */ 52 tpm_u32(TPM2_CC_CLEAR), /* Command code */ 53 54 /* HANDLE */ 55 tpm_u32(handle), /* TPM resource handle */ 56 57 /* AUTH_SESSION */ 58 tpm_u32(9 + pw_sz), /* Authorization size */ 59 tpm_u32(TPM2_RS_PW), /* Session handle */ 60 tpm_u16(0), /* Size of <nonce> */ 61 /* <nonce> (if any) */ 62 0, /* Attributes: Cont/Excl/Rst */ 63 tpm_u16(pw_sz), /* Size of <hmac/password> */ 64 /* STRING(pw) <hmac/password> (if any) */ 65 }; 66 unsigned int offset = 27; 67 int ret; 68 69 /* 70 * Fill the command structure starting from the first buffer: 71 * - the password (if any) 72 */ 73 ret = pack_byte_string(command_v2, sizeof(command_v2), "s", 74 offset, pw, pw_sz); 75 offset += pw_sz; 76 if (ret) 77 return TPM_LIB_ERROR; 78 79 return tpm_sendrecv_command(dev, command_v2, NULL, NULL); 80 } 81 82 u32 tpm2_pcr_extend(struct udevice *dev, u32 index, const uint8_t *digest) 83 { 84 u8 command_v2[COMMAND_BUFFER_SIZE] = { 85 tpm_u16(TPM2_ST_SESSIONS), /* TAG */ 86 tpm_u32(33 + TPM2_DIGEST_LEN), /* Length */ 87 tpm_u32(TPM2_CC_PCR_EXTEND), /* Command code */ 88 89 /* HANDLE */ 90 tpm_u32(index), /* Handle (PCR Index) */ 91 92 /* AUTH_SESSION */ 93 tpm_u32(9), /* Authorization size */ 94 tpm_u32(TPM2_RS_PW), /* Session handle */ 95 tpm_u16(0), /* Size of <nonce> */ 96 /* <nonce> (if any) */ 97 0, /* Attributes: Cont/Excl/Rst */ 98 tpm_u16(0), /* Size of <hmac/password> */ 99 /* <hmac/password> (if any) */ 100 tpm_u32(1), /* Count (number of hashes) */ 101 tpm_u16(TPM2_ALG_SHA256), /* Algorithm of the hash */ 102 /* STRING(digest) Digest */ 103 }; 104 unsigned int offset = 33; 105 int ret; 106 107 /* 108 * Fill the command structure starting from the first buffer: 109 * - the digest 110 */ 111 ret = pack_byte_string(command_v2, sizeof(command_v2), "s", 112 offset, digest, TPM2_DIGEST_LEN); 113 offset += TPM2_DIGEST_LEN; 114 if (ret) 115 return TPM_LIB_ERROR; 116 117 return tpm_sendrecv_command(dev, command_v2, NULL, NULL); 118 } 119 120 u32 tpm2_pcr_read(struct udevice *dev, u32 idx, unsigned int idx_min_sz, 121 void *data, unsigned int *updates) 122 { 123 u8 idx_array_sz = max(idx_min_sz, DIV_ROUND_UP(idx, 8)); 124 u8 command_v2[COMMAND_BUFFER_SIZE] = { 125 tpm_u16(TPM2_ST_NO_SESSIONS), /* TAG */ 126 tpm_u32(17 + idx_array_sz), /* Length */ 127 tpm_u32(TPM2_CC_PCR_READ), /* Command code */ 128 129 /* TPML_PCR_SELECTION */ 130 tpm_u32(1), /* Number of selections */ 131 tpm_u16(TPM2_ALG_SHA256), /* Algorithm of the hash */ 132 idx_array_sz, /* Array size for selection */ 133 /* bitmap(idx) Selected PCR bitmap */ 134 }; 135 size_t response_len = COMMAND_BUFFER_SIZE; 136 u8 response[COMMAND_BUFFER_SIZE]; 137 unsigned int pcr_sel_idx = idx / 8; 138 u8 pcr_sel_bit = BIT(idx % 8); 139 unsigned int counter = 0; 140 int ret; 141 142 if (pack_byte_string(command_v2, COMMAND_BUFFER_SIZE, "b", 143 17 + pcr_sel_idx, pcr_sel_bit)) 144 return TPM_LIB_ERROR; 145 146 ret = tpm_sendrecv_command(dev, command_v2, response, &response_len); 147 if (ret) 148 return ret; 149 150 if (unpack_byte_string(response, response_len, "ds", 151 10, &counter, 152 response_len - TPM2_DIGEST_LEN, data, 153 TPM2_DIGEST_LEN)) 154 return TPM_LIB_ERROR; 155 156 if (updates) 157 *updates = counter; 158 159 return 0; 160 } 161 162 u32 tpm2_get_capability(struct udevice *dev, u32 capability, u32 property, 163 void *buf, size_t prop_count) 164 { 165 u8 command_v2[COMMAND_BUFFER_SIZE] = { 166 tpm_u16(TPM2_ST_NO_SESSIONS), /* TAG */ 167 tpm_u32(22), /* Length */ 168 tpm_u32(TPM2_CC_GET_CAPABILITY), /* Command code */ 169 170 tpm_u32(capability), /* Capability */ 171 tpm_u32(property), /* Property */ 172 tpm_u32(prop_count), /* Property count */ 173 }; 174 u8 response[COMMAND_BUFFER_SIZE]; 175 size_t response_len = COMMAND_BUFFER_SIZE; 176 unsigned int properties_off; 177 int ret; 178 179 ret = tpm_sendrecv_command(dev, command_v2, response, &response_len); 180 if (ret) 181 return ret; 182 183 /* 184 * In the response buffer, the properties are located after the: 185 * tag (u16), response size (u32), response code (u32), 186 * YES/NO flag (u8), TPM_CAP (u32) and TPMU_CAPABILITIES (u32). 187 */ 188 properties_off = sizeof(u16) + sizeof(u32) + sizeof(u32) + 189 sizeof(u8) + sizeof(u32) + sizeof(u32); 190 memcpy(buf, &response[properties_off], response_len - properties_off); 191 192 return 0; 193 } 194 195 u32 tpm2_dam_reset(struct udevice *dev, const char *pw, const ssize_t pw_sz) 196 { 197 u8 command_v2[COMMAND_BUFFER_SIZE] = { 198 tpm_u16(TPM2_ST_SESSIONS), /* TAG */ 199 tpm_u32(27 + pw_sz), /* Length */ 200 tpm_u32(TPM2_CC_DAM_RESET), /* Command code */ 201 202 /* HANDLE */ 203 tpm_u32(TPM2_RH_LOCKOUT), /* TPM resource handle */ 204 205 /* AUTH_SESSION */ 206 tpm_u32(9 + pw_sz), /* Authorization size */ 207 tpm_u32(TPM2_RS_PW), /* Session handle */ 208 tpm_u16(0), /* Size of <nonce> */ 209 /* <nonce> (if any) */ 210 0, /* Attributes: Cont/Excl/Rst */ 211 tpm_u16(pw_sz), /* Size of <hmac/password> */ 212 /* STRING(pw) <hmac/password> (if any) */ 213 }; 214 unsigned int offset = 27; 215 int ret; 216 217 /* 218 * Fill the command structure starting from the first buffer: 219 * - the password (if any) 220 */ 221 ret = pack_byte_string(command_v2, sizeof(command_v2), "s", 222 offset, pw, pw_sz); 223 offset += pw_sz; 224 if (ret) 225 return TPM_LIB_ERROR; 226 227 return tpm_sendrecv_command(dev, command_v2, NULL, NULL); 228 } 229 230 u32 tpm2_dam_parameters(struct udevice *dev, const char *pw, 231 const ssize_t pw_sz, unsigned int max_tries, 232 unsigned int recovery_time, 233 unsigned int lockout_recovery) 234 { 235 u8 command_v2[COMMAND_BUFFER_SIZE] = { 236 tpm_u16(TPM2_ST_SESSIONS), /* TAG */ 237 tpm_u32(27 + pw_sz + 12), /* Length */ 238 tpm_u32(TPM2_CC_DAM_PARAMETERS), /* Command code */ 239 240 /* HANDLE */ 241 tpm_u32(TPM2_RH_LOCKOUT), /* TPM resource handle */ 242 243 /* AUTH_SESSION */ 244 tpm_u32(9 + pw_sz), /* Authorization size */ 245 tpm_u32(TPM2_RS_PW), /* Session handle */ 246 tpm_u16(0), /* Size of <nonce> */ 247 /* <nonce> (if any) */ 248 0, /* Attributes: Cont/Excl/Rst */ 249 tpm_u16(pw_sz), /* Size of <hmac/password> */ 250 /* STRING(pw) <hmac/password> (if any) */ 251 252 /* LOCKOUT PARAMETERS */ 253 /* tpm_u32(max_tries) Max tries (0, always lock) */ 254 /* tpm_u32(recovery_time) Recovery time (0, no lock) */ 255 /* tpm_u32(lockout_recovery) Lockout recovery */ 256 }; 257 unsigned int offset = 27; 258 int ret; 259 260 /* 261 * Fill the command structure starting from the first buffer: 262 * - the password (if any) 263 * - max tries 264 * - recovery time 265 * - lockout recovery 266 */ 267 ret = pack_byte_string(command_v2, sizeof(command_v2), "sddd", 268 offset, pw, pw_sz, 269 offset + pw_sz, max_tries, 270 offset + pw_sz + 4, recovery_time, 271 offset + pw_sz + 8, lockout_recovery); 272 offset += pw_sz + 12; 273 if (ret) 274 return TPM_LIB_ERROR; 275 276 return tpm_sendrecv_command(dev, command_v2, NULL, NULL); 277 } 278 279 int tpm2_change_auth(struct udevice *dev, u32 handle, const char *newpw, 280 const ssize_t newpw_sz, const char *oldpw, 281 const ssize_t oldpw_sz) 282 { 283 unsigned int offset = 27; 284 u8 command_v2[COMMAND_BUFFER_SIZE] = { 285 tpm_u16(TPM2_ST_SESSIONS), /* TAG */ 286 tpm_u32(offset + oldpw_sz + 2 + newpw_sz), /* Length */ 287 tpm_u32(TPM2_CC_HIERCHANGEAUTH), /* Command code */ 288 289 /* HANDLE */ 290 tpm_u32(handle), /* TPM resource handle */ 291 292 /* AUTH_SESSION */ 293 tpm_u32(9 + oldpw_sz), /* Authorization size */ 294 tpm_u32(TPM2_RS_PW), /* Session handle */ 295 tpm_u16(0), /* Size of <nonce> */ 296 /* <nonce> (if any) */ 297 0, /* Attributes: Cont/Excl/Rst */ 298 tpm_u16(oldpw_sz) /* Size of <hmac/password> */ 299 /* STRING(oldpw) <hmac/password> (if any) */ 300 301 /* TPM2B_AUTH (TPM2B_DIGEST) */ 302 /* tpm_u16(newpw_sz) Digest size, new pw length */ 303 /* STRING(newpw) Digest buffer, new pw */ 304 }; 305 int ret; 306 307 /* 308 * Fill the command structure starting from the first buffer: 309 * - the old password (if any) 310 * - size of the new password 311 * - new password 312 */ 313 ret = pack_byte_string(command_v2, sizeof(command_v2), "sws", 314 offset, oldpw, oldpw_sz, 315 offset + oldpw_sz, newpw_sz, 316 offset + oldpw_sz + 2, newpw, newpw_sz); 317 offset += oldpw_sz + 2 + newpw_sz; 318 if (ret) 319 return TPM_LIB_ERROR; 320 321 return tpm_sendrecv_command(dev, command_v2, NULL, NULL); 322 } 323 324 u32 tpm2_pcr_setauthpolicy(struct udevice *dev, const char *pw, 325 const ssize_t pw_sz, u32 index, const char *key) 326 { 327 u8 command_v2[COMMAND_BUFFER_SIZE] = { 328 tpm_u16(TPM2_ST_SESSIONS), /* TAG */ 329 tpm_u32(35 + pw_sz + TPM2_DIGEST_LEN), /* Length */ 330 tpm_u32(TPM2_CC_PCR_SETAUTHPOL), /* Command code */ 331 332 /* HANDLE */ 333 tpm_u32(TPM2_RH_PLATFORM), /* TPM resource handle */ 334 335 /* AUTH_SESSION */ 336 tpm_u32(9 + pw_sz), /* Authorization size */ 337 tpm_u32(TPM2_RS_PW), /* session handle */ 338 tpm_u16(0), /* Size of <nonce> */ 339 /* <nonce> (if any) */ 340 0, /* Attributes: Cont/Excl/Rst */ 341 tpm_u16(pw_sz) /* Size of <hmac/password> */ 342 /* STRING(pw) <hmac/password> (if any) */ 343 344 /* TPM2B_AUTH (TPM2B_DIGEST) */ 345 /* tpm_u16(TPM2_DIGEST_LEN) Digest size length */ 346 /* STRING(key) Digest buffer (PCR key) */ 347 348 /* TPMI_ALG_HASH */ 349 /* tpm_u16(TPM2_ALG_SHA256) Algorithm of the hash */ 350 351 /* TPMI_DH_PCR */ 352 /* tpm_u32(index), PCR Index */ 353 }; 354 unsigned int offset = 27; 355 int ret; 356 357 /* 358 * Fill the command structure starting from the first buffer: 359 * - the password (if any) 360 * - the PCR key length 361 * - the PCR key 362 * - the hash algorithm 363 * - the PCR index 364 */ 365 ret = pack_byte_string(command_v2, sizeof(command_v2), "swswd", 366 offset, pw, pw_sz, 367 offset + pw_sz, TPM2_DIGEST_LEN, 368 offset + pw_sz + 2, key, TPM2_DIGEST_LEN, 369 offset + pw_sz + 2 + TPM2_DIGEST_LEN, 370 TPM2_ALG_SHA256, 371 offset + pw_sz + 4 + TPM2_DIGEST_LEN, index); 372 offset += pw_sz + 2 + TPM2_DIGEST_LEN + 2 + 4; 373 if (ret) 374 return TPM_LIB_ERROR; 375 376 return tpm_sendrecv_command(dev, command_v2, NULL, NULL); 377 } 378 379 u32 tpm2_pcr_setauthvalue(struct udevice *dev, const char *pw, 380 const ssize_t pw_sz, u32 index, const char *key, 381 const ssize_t key_sz) 382 { 383 u8 command_v2[COMMAND_BUFFER_SIZE] = { 384 tpm_u16(TPM2_ST_SESSIONS), /* TAG */ 385 tpm_u32(33 + pw_sz + TPM2_DIGEST_LEN), /* Length */ 386 tpm_u32(TPM2_CC_PCR_SETAUTHVAL), /* Command code */ 387 388 /* HANDLE */ 389 tpm_u32(index), /* Handle (PCR Index) */ 390 391 /* AUTH_SESSION */ 392 tpm_u32(9 + pw_sz), /* Authorization size */ 393 tpm_u32(TPM2_RS_PW), /* session handle */ 394 tpm_u16(0), /* Size of <nonce> */ 395 /* <nonce> (if any) */ 396 0, /* Attributes: Cont/Excl/Rst */ 397 tpm_u16(pw_sz), /* Size of <hmac/password> */ 398 /* STRING(pw) <hmac/password> (if any) */ 399 400 /* TPM2B_DIGEST */ 401 /* tpm_u16(key_sz) Key length */ 402 /* STRING(key) Key */ 403 }; 404 unsigned int offset = 27; 405 int ret; 406 407 /* 408 * Fill the command structure starting from the first buffer: 409 * - the password (if any) 410 * - the number of digests, 1 in our case 411 * - the algorithm, sha256 in our case 412 * - the digest (64 bytes) 413 */ 414 ret = pack_byte_string(command_v2, sizeof(command_v2), "sws", 415 offset, pw, pw_sz, 416 offset + pw_sz, key_sz, 417 offset + pw_sz + 2, key, key_sz); 418 offset += pw_sz + 2 + key_sz; 419 if (ret) 420 return TPM_LIB_ERROR; 421 422 return tpm_sendrecv_command(dev, command_v2, NULL, NULL); 423 } 424