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