diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/tpm-v2.c | 124 |
1 files changed, 124 insertions, 0 deletions
diff --git a/lib/tpm-v2.c b/lib/tpm-v2.c index 3946ac2dbb7..045b5dd9ebd 100644 --- a/lib/tpm-v2.c +++ b/lib/tpm-v2.c @@ -400,6 +400,130 @@ u32 tpm2_get_capability(struct udevice *dev, u32 capability, u32 property, return 0; } +u32 tpm2_pcr_config_algo(struct udevice *dev, u32 algo_mask, + struct tpml_pcr_selection *pcr, u32 *pcr_len) +{ + int i; + + if (pcr->count > TPM2_NUM_PCR_BANKS) + return TPM_LIB_ERROR; + + *pcr_len = sizeof(pcr->count); + + for (i = 0; i < pcr->count; i++) { + struct tpms_pcr_selection *sel = &pcr->selection[i]; + u8 pad = 0; + int j; + + if (sel->size_of_select > TPM2_PCR_SELECT_MAX) + return TPM_LIB_ERROR; + + /* + * Found the algorithm (bank) that matches, and enable all PCR + * bits. + * TODO: only select the bits needed + */ + for (j = 0; j < ARRAY_SIZE(hash_algo_list); j++) { + if (hash_algo_list[j].hash_alg != sel->hash) + continue; + + if (algo_mask & hash_algo_list[j].hash_mask) + pad = 0xff; + } + + for (j = 0; j < sel->size_of_select; j++) + sel->pcr_select[j] = pad; + + log_info("set bank[%d] %s %s\n", i, + tpm2_algorithm_name(sel->hash), + tpm2_is_active_bank(sel) ? "on" : "off"); + + *pcr_len += sizeof(sel->hash) + sizeof(sel->size_of_select) + + sel->size_of_select; + } + + return 0; +} + +u32 tpm2_send_pcr_allocate(struct udevice *dev, const char *pw, + const ssize_t pw_sz, struct tpml_pcr_selection *pcr, + u32 pcr_len) +{ + /* Length of the message header, up to start of password */ + uint offset = 27; + u8 command_v2[COMMAND_BUFFER_SIZE] = { + tpm_u16(TPM2_ST_SESSIONS), /* TAG */ + tpm_u32(offset + pw_sz + pcr_len), /* Length */ + tpm_u32(TPM2_CC_PCR_ALLOCATE), /* Command code */ + + /* handles 4 bytes */ + tpm_u32(TPM2_RH_PLATFORM), /* Primary platform seed */ + + /* AUTH_SESSION */ + tpm_u32(9 + pw_sz), /* Authorization size */ + tpm_u32(TPM2_RS_PW), /* Session handle */ + tpm_u16(0), /* Size of <nonce> */ + /* <nonce> (if any) */ + 0, /* Attributes: Cont/Excl/Rst */ + tpm_u16(pw_sz), /* Size of <hmac/password> */ + /* STRING(pw) <hmac/password> (if any) */ + + /* TPML_PCR_SELECTION */ + }; + u8 response[COMMAND_BUFFER_SIZE]; + size_t response_len = COMMAND_BUFFER_SIZE; + u32 i; + int ret; + + /* + * Fill the command structure starting from the first buffer: + * the password (if any) + */ + if (pack_byte_string(command_v2, sizeof(command_v2), "s", offset, pw, + pw_sz)) + return TPM_LIB_ERROR; + + offset += pw_sz; + + /* Pack the count field */ + if (pack_byte_string(command_v2, sizeof(command_v2), "d", offset, pcr->count)) + return TPM_LIB_ERROR; + + offset += sizeof(pcr->count); + + /* Pack each tpms_pcr_selection */ + for (i = 0; i < pcr->count; i++) { + struct tpms_pcr_selection *sel = &pcr->selection[i]; + + /* Pack hash (16-bit) */ + if (pack_byte_string(command_v2, sizeof(command_v2), "w", offset, + sel->hash)) + return TPM_LIB_ERROR; + + offset += sizeof(sel->hash); + + /* Pack size_of_select (8-bit) */ + if (pack_byte_string(command_v2, sizeof(command_v2), "b", offset, + sel->size_of_select)) + return TPM_LIB_ERROR; + + offset += sizeof(sel->size_of_select); + + /* Pack pcr_select array */ + if (pack_byte_string(command_v2, sizeof(command_v2), "s", offset, + sel->pcr_select, sel->size_of_select)) + return TPM_LIB_ERROR; + + offset += sel->size_of_select; + } + + ret = tpm_sendrecv_command(dev, command_v2, response, &response_len); + if (!ret) + tpm_init(dev); + + return ret; +} + static int tpm2_get_num_pcr(struct udevice *dev, u32 *num_pcr) { u8 response[(sizeof(struct tpms_capability_data) - |