tpm: add TPM2_PCR_Allocate command
TPM2_PCR_Allocate command is required to reconfigure a TPM device
to enable or disable algorithms in run-time, thus this patch introduces
the implementation of PCR allocate APIs and adds related cmd functions
for testing.
To test the feature, ensure that TPM is started up.
Run pcr_allocate command to turn on/off an algorithm, multiple calls
are supported and all changes will be cached:
`tpm2 pcr_allocate <algorithm_name> <on|off>`
Run startup command with argument 'off' to shutdown the TPM.
`tpm2 startup TPM2_SU_CLEAR off`
Reboot the board via `reset` to activate the changes.
Signed-off-by: Raymond Mao <raymond.mao@linaro.org>
Acked-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
Signed-off-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
diff --git a/lib/tpm-v2.c b/lib/tpm-v2.c
index 3946ac2..045b5dd 100644
--- a/lib/tpm-v2.c
+++ b/lib/tpm-v2.c
@@ -400,6 +400,130 @@
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) -