mirror of
https://github.com/u-boot/u-boot.git
synced 2025-04-20 20:04:46 +00:00
We have use cases where a previous stage boot loader doesn't have any
TPM drivers. Instead of extending the hardware PCRs it produces an EventLog that U-Boot later replays on the hardware. The only real example we have is TF-A, which produces the EventLog using hashing algorithms created at compile time. This creates a problem to the TPM since measurements need to extend all active PCR banks. Up to now we were exiting refusing the extend measurements. TPMs can be instructed to change their active PCR banks, as long as the device resets immediately after a reconfiguration. This PR is adding that functionality. U-Boot can now scan the currently active TPM PCR banks, the ones it was compiled to support and the ones present in an EventLog. It the reconfigures the TPM on the fly with the correct algorithms. -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEgWII69YpahbL5iK5gS8AYozs+qIFAmeYhMUACgkQgS8AYozs +qIzfxAAv0vngk2MycOWsQY1Mch0799o+QPN+J4avl52duLSCmiFUpoXOQCiRZSG 5SpjqygrWXOL6T0EUMVjv8qaGJTZY5uY296G8zt+Nboq08XRMb76kV3vl/9XQ9oh lsF44QcoSpWM+NCfQ00yWsmy1FQZg5soQMU1liW8qJH1yUuDZP7WGDG2N2Kng5ag MW38SWXVM8+RiA1UeuaQtVvH5BfL/kotsG4U2LZwp6k4eJttzbUQylF09K/h+4Qf 8nIwl6TQ7j59DRA2r7WHVmxFpYf+BOzf7wnLbAKKP9/QlEEo8+K8GabrNqcm/dx+ Bav6dzZUzAJ024ocvouanQmjJfj2WnqryfRNJrU3ggt2j6JXkjNW9xHXdBZoKRBj WNTXMUIxe1t+5jD9KXyAg/C7FE1EaJDZu0JfK0xeXHvnnYbL6eYHyRkZCA6MZ95O ZCvDXv9x7zhZkUj9VY5kFvmWbemjX33CHMToIafu7fZtsCe6oIrISzMW4T3/74pS y6142Ceoy7qxYCkBgTzt5UTj4pTS2ZYaiqZXUTftFtmaNt56lcFWqaTR7Fz1U8CV 1K8I3wKs8Fs5P326Y9fJ/kHfhHFTaVVDxWIhxK5Mg+vAIPeNECDybYH4q0FzAf1K h9ni39KC629MpMB2drYmYCtrzGk4nSyAwha1vSS9twltFi4Rgmo= =jn1D -----END PGP SIGNATURE----- Merge tag 'tpm-master-28012025' of https://source.denx.de/u-boot/custodians/u-boot-tpm CI: https://source.denx.de/u-boot/custodians/u-boot-tpm/-/pipelines/24375 We have use cases where a previous stage boot loader doesn't have any TPM drivers. Instead of extending the hardware PCRs it produces an EventLog that U-Boot later replays on the hardware. The only real example we have is TF-A, which produces the EventLog using hashing algorithms created at compile time. This creates a problem to the TPM since measurements need to extend all active PCR banks. Up to now we were exiting refusing the extend measurements. TPMs can be instructed to change their active PCR banks, as long as the device resets immediately after a reconfiguration. This PR is adding that functionality. U-Boot can now scan the currently active TPM PCR banks, the ones it was compiled to support and the ones present in an EventLog. It the reconfigures the TPM on the fly with the correct algorithms.
This commit is contained in:
commit
021baf7b08
15 changed files with 557 additions and 88 deletions
128
cmd/tpm-v2.c
128
cmd/tpm-v2.c
|
@ -18,11 +18,14 @@ static int do_tpm2_startup(struct cmd_tbl *cmdtp, int flag, int argc,
|
||||||
enum tpm2_startup_types mode;
|
enum tpm2_startup_types mode;
|
||||||
struct udevice *dev;
|
struct udevice *dev;
|
||||||
int ret;
|
int ret;
|
||||||
|
bool bon = true;
|
||||||
|
|
||||||
ret = get_tpm(&dev);
|
ret = get_tpm(&dev);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
if (argc != 2)
|
|
||||||
|
/* argv[2] is optional to perform a TPM2_CC_SHUTDOWN */
|
||||||
|
if (argc > 3 || (argc == 3 && strcasecmp("off", argv[2])))
|
||||||
return CMD_RET_USAGE;
|
return CMD_RET_USAGE;
|
||||||
|
|
||||||
if (!strcasecmp("TPM2_SU_CLEAR", argv[1])) {
|
if (!strcasecmp("TPM2_SU_CLEAR", argv[1])) {
|
||||||
|
@ -34,7 +37,10 @@ static int do_tpm2_startup(struct cmd_tbl *cmdtp, int flag, int argc,
|
||||||
return CMD_RET_FAILURE;
|
return CMD_RET_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return report_return_code(tpm2_startup(dev, mode));
|
if (argv[2])
|
||||||
|
bon = false;
|
||||||
|
|
||||||
|
return report_return_code(tpm2_startup(dev, bon, mode));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int do_tpm2_self_test(struct cmd_tbl *cmdtp, int flag, int argc,
|
static int do_tpm2_self_test(struct cmd_tbl *cmdtp, int flag, int argc,
|
||||||
|
@ -226,6 +232,106 @@ unmap_data:
|
||||||
return report_return_code(rc);
|
return report_return_code(rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static u32 select_mask(u32 mask, enum tpm2_algorithms algo, bool select)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(hash_algo_list); i++) {
|
||||||
|
if (hash_algo_list[i].hash_alg != algo)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (select)
|
||||||
|
mask |= hash_algo_list[i].hash_mask;
|
||||||
|
else
|
||||||
|
mask &= ~hash_algo_list[i].hash_mask;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
is_algo_in_pcrs(enum tpm2_algorithms algo, struct tpml_pcr_selection *pcrs)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < pcrs->count; i++) {
|
||||||
|
if (algo == pcrs->selection[i].hash)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int do_tpm2_pcrallocate(struct cmd_tbl *cmdtp, int flag, int argc,
|
||||||
|
char *const argv[])
|
||||||
|
{
|
||||||
|
struct udevice *dev;
|
||||||
|
int ret;
|
||||||
|
enum tpm2_algorithms algo;
|
||||||
|
const char *pw = (argc < 4) ? NULL : argv[3];
|
||||||
|
const ssize_t pw_sz = pw ? strlen(pw) : 0;
|
||||||
|
static struct tpml_pcr_selection pcr = { 0 };
|
||||||
|
u32 pcr_len = 0;
|
||||||
|
bool bon = false;
|
||||||
|
static u32 mask;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* argv[1]: algorithm (bank), argv[2]: on/off */
|
||||||
|
if (argc < 3 || argc > 4)
|
||||||
|
return CMD_RET_USAGE;
|
||||||
|
|
||||||
|
if (!strcasecmp("on", argv[2]))
|
||||||
|
bon = true;
|
||||||
|
else if (strcasecmp("off", argv[2]))
|
||||||
|
return CMD_RET_USAGE;
|
||||||
|
|
||||||
|
algo = tpm2_name_to_algorithm(argv[1]);
|
||||||
|
if (algo == -EINVAL)
|
||||||
|
return CMD_RET_USAGE;
|
||||||
|
|
||||||
|
ret = get_tpm(&dev);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (!pcr.count) {
|
||||||
|
/*
|
||||||
|
* Get current active algorithms (banks), PCRs and mask via the
|
||||||
|
* first call
|
||||||
|
*/
|
||||||
|
ret = tpm2_get_pcr_info(dev, &pcr);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
for (i = 0; i < pcr.count; i++) {
|
||||||
|
struct tpms_pcr_selection *sel = &pcr.selection[i];
|
||||||
|
const char *name;
|
||||||
|
|
||||||
|
if (!tpm2_is_active_bank(sel))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
mask = select_mask(mask, sel->hash, true);
|
||||||
|
name = tpm2_algorithm_name(sel->hash);
|
||||||
|
if (name)
|
||||||
|
printf("Active bank[%d]: %s\n", i, name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_algo_in_pcrs(algo, &pcr)) {
|
||||||
|
printf("%s is not supported by the tpm device\n", argv[1]);
|
||||||
|
return CMD_RET_USAGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
mask = select_mask(mask, algo, bon);
|
||||||
|
ret = tpm2_pcr_config_algo(dev, mask, &pcr, &pcr_len);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return report_return_code(tpm2_send_pcr_allocate(dev, pw, pw_sz, &pcr,
|
||||||
|
pcr_len));
|
||||||
|
}
|
||||||
|
|
||||||
static int do_tpm_dam_reset(struct cmd_tbl *cmdtp, int flag, int argc,
|
static int do_tpm_dam_reset(struct cmd_tbl *cmdtp, int flag, int argc,
|
||||||
char *const argv[])
|
char *const argv[])
|
||||||
{
|
{
|
||||||
|
@ -395,6 +501,7 @@ static struct cmd_tbl tpm2_commands[] = {
|
||||||
do_tpm_pcr_setauthpolicy, "", ""),
|
do_tpm_pcr_setauthpolicy, "", ""),
|
||||||
U_BOOT_CMD_MKENT(pcr_setauthvalue, 0, 1,
|
U_BOOT_CMD_MKENT(pcr_setauthvalue, 0, 1,
|
||||||
do_tpm_pcr_setauthvalue, "", ""),
|
do_tpm_pcr_setauthvalue, "", ""),
|
||||||
|
U_BOOT_CMD_MKENT(pcr_allocate, 0, 1, do_tpm2_pcrallocate, "", ""),
|
||||||
};
|
};
|
||||||
|
|
||||||
struct cmd_tbl *get_tpm2_commands(unsigned int *size)
|
struct cmd_tbl *get_tpm2_commands(unsigned int *size)
|
||||||
|
@ -420,11 +527,13 @@ U_BOOT_CMD(tpm2, CONFIG_SYS_MAXARGS, 1, do_tpm, "Issue a TPMv2.x command",
|
||||||
" Initialize the software stack. Always the first command to issue.\n"
|
" Initialize the software stack. Always the first command to issue.\n"
|
||||||
" 'tpm startup' is the only acceptable command after a 'tpm init' has been\n"
|
" 'tpm startup' is the only acceptable command after a 'tpm init' has been\n"
|
||||||
" issued\n"
|
" issued\n"
|
||||||
"startup <mode>\n"
|
"startup <mode> [<op>]\n"
|
||||||
" Issue a TPM2_Startup command.\n"
|
" Issue a TPM2_Startup command.\n"
|
||||||
" <mode> is one of:\n"
|
" <mode> is one of:\n"
|
||||||
" * TPM2_SU_CLEAR (reset state)\n"
|
" * TPM2_SU_CLEAR (reset state)\n"
|
||||||
" * TPM2_SU_STATE (preserved state)\n"
|
" * TPM2_SU_STATE (preserved state)\n"
|
||||||
|
" <op>:\n"
|
||||||
|
" * off - To shutdown the TPM\n"
|
||||||
"self_test <type>\n"
|
"self_test <type>\n"
|
||||||
" Test the TPM capabilities.\n"
|
" Test the TPM capabilities.\n"
|
||||||
" <type> is one of:\n"
|
" <type> is one of:\n"
|
||||||
|
@ -473,4 +582,17 @@ U_BOOT_CMD(tpm2, CONFIG_SYS_MAXARGS, 1, do_tpm, "Issue a TPMv2.x command",
|
||||||
" <pcr>: index of the PCR\n"
|
" <pcr>: index of the PCR\n"
|
||||||
" <key>: secret to protect the access of PCR #<pcr>\n"
|
" <key>: secret to protect the access of PCR #<pcr>\n"
|
||||||
" <password>: optional password of the PLATFORM hierarchy\n"
|
" <password>: optional password of the PLATFORM hierarchy\n"
|
||||||
|
"pcr_allocate <algorithm> <on/off> [<password>]\n"
|
||||||
|
" Issue a TPM2_PCR_Allocate Command to reconfig PCR bank algorithm.\n"
|
||||||
|
" <algorithm> is one of:\n"
|
||||||
|
" * sha1\n"
|
||||||
|
" * sha256\n"
|
||||||
|
" * sha384\n"
|
||||||
|
" * sha512\n"
|
||||||
|
" <on|off> is one of:\n"
|
||||||
|
" * on - Select all available PCRs associated with the specified\n"
|
||||||
|
" algorithm (bank)\n"
|
||||||
|
" * off - Clear all available PCRs associated with the specified\n"
|
||||||
|
" algorithm (bank)\n"
|
||||||
|
" <password>: optional password\n"
|
||||||
);
|
);
|
||||||
|
|
|
@ -222,14 +222,27 @@ static int bloblist_ensurerec(uint tag, struct bloblist_rec **recp, int size,
|
||||||
}
|
}
|
||||||
|
|
||||||
void *bloblist_find(uint tag, int size)
|
void *bloblist_find(uint tag, int size)
|
||||||
|
{
|
||||||
|
void *blob = NULL;
|
||||||
|
int blob_size;
|
||||||
|
|
||||||
|
blob = bloblist_get_blob(tag, &blob_size);
|
||||||
|
|
||||||
|
if (size && size != blob_size)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return blob;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *bloblist_get_blob(uint tag, int *sizep)
|
||||||
{
|
{
|
||||||
struct bloblist_rec *rec;
|
struct bloblist_rec *rec;
|
||||||
|
|
||||||
rec = bloblist_findrec(tag);
|
rec = bloblist_findrec(tag);
|
||||||
if (!rec)
|
if (!rec)
|
||||||
return NULL;
|
return NULL;
|
||||||
if (size && size != rec->size)
|
|
||||||
return NULL;
|
*sizep = rec->size;
|
||||||
|
|
||||||
return (void *)rec + rec_hdr_size(rec);
|
return (void *)rec + rec_hdr_size(rec);
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,3 +75,4 @@ CONFIG_SEMIHOSTING=y
|
||||||
CONFIG_MBEDTLS_LIB=y
|
CONFIG_MBEDTLS_LIB=y
|
||||||
CONFIG_TPM=y
|
CONFIG_TPM=y
|
||||||
CONFIG_GENERATE_SMBIOS_TABLE_VERBOSE=y
|
CONFIG_GENERATE_SMBIOS_TABLE_VERBOSE=y
|
||||||
|
CONFIG_TPM_PCR_ALLOCATE=y
|
||||||
|
|
|
@ -24,7 +24,6 @@ Requirements
|
||||||
|
|
||||||
* A hardware TPM 2.0 supported by an enabled U-Boot driver
|
* A hardware TPM 2.0 supported by an enabled U-Boot driver
|
||||||
* CONFIG_EFI_TCG2_PROTOCOL=y
|
* CONFIG_EFI_TCG2_PROTOCOL=y
|
||||||
* CONFIG_EFI_TCG2_PROTOCOL_EVENTLOG_SIZE=y
|
|
||||||
* optional CONFIG_EFI_TCG2_PROTOCOL_MEASURE_DTB=y will measure the loaded DTB
|
* optional CONFIG_EFI_TCG2_PROTOCOL_MEASURE_DTB=y will measure the loaded DTB
|
||||||
in PCR 1
|
in PCR 1
|
||||||
|
|
||||||
|
|
|
@ -209,6 +209,15 @@ config TPM2_MMIO
|
||||||
to the device using the standard TPM Interface Specification (TIS)
|
to the device using the standard TPM Interface Specification (TIS)
|
||||||
protocol.
|
protocol.
|
||||||
|
|
||||||
|
config TPM2_EVENT_LOG_SIZE
|
||||||
|
int "EventLog size"
|
||||||
|
depends on TPM_V2
|
||||||
|
default 65536
|
||||||
|
help
|
||||||
|
Define the size of the EventLog. Note that this is going to be
|
||||||
|
allocated twice. One for the eventlog it self and one for the
|
||||||
|
configuration table that is required from the TCG2 spec
|
||||||
|
|
||||||
endif # TPM_V2
|
endif # TPM_V2
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
|
|
@ -250,6 +250,24 @@ static inline void *bloblist_check_magic(ulong addr)
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if CONFIG_IS_ENABLED(BLOBLIST)
|
||||||
|
/**
|
||||||
|
* bloblist_get_blob() - Find a blob and get the size of it
|
||||||
|
*
|
||||||
|
* Searches the bloblist and returns the blob with the matching tag
|
||||||
|
*
|
||||||
|
* @tag: Tag to search for (enum bloblist_tag_t)
|
||||||
|
* @sizep: Size of the blob found
|
||||||
|
* Return: pointer to bloblist if found, or NULL if not found
|
||||||
|
*/
|
||||||
|
void *bloblist_get_blob(uint tag, int *sizep);
|
||||||
|
#else
|
||||||
|
static inline void *bloblist_get_blob(uint tag, int *sizep)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* bloblist_find() - Find a blob
|
* bloblist_find() - Find a blob
|
||||||
*
|
*
|
||||||
|
|
|
@ -28,8 +28,6 @@
|
||||||
#define EFI_TCG2_MAX_PCR_INDEX 23
|
#define EFI_TCG2_MAX_PCR_INDEX 23
|
||||||
#define EFI_TCG2_FINAL_EVENTS_TABLE_VERSION 1
|
#define EFI_TCG2_FINAL_EVENTS_TABLE_VERSION 1
|
||||||
|
|
||||||
#define TPM2_EVENT_LOG_SIZE CONFIG_EFI_TCG2_PROTOCOL_EVENTLOG_SIZE
|
|
||||||
|
|
||||||
typedef u32 efi_tcg_event_log_bitmap;
|
typedef u32 efi_tcg_event_log_bitmap;
|
||||||
typedef u32 efi_tcg_event_log_format;
|
typedef u32 efi_tcg_event_log_format;
|
||||||
typedef u32 efi_tcg_event_algorithm_bitmap;
|
typedef u32 efi_tcg_event_algorithm_bitmap;
|
||||||
|
|
|
@ -230,6 +230,8 @@ enum tpm2_command_codes {
|
||||||
TPM2_CC_PCR_READ = 0x017E,
|
TPM2_CC_PCR_READ = 0x017E,
|
||||||
TPM2_CC_PCR_EXTEND = 0x0182,
|
TPM2_CC_PCR_EXTEND = 0x0182,
|
||||||
TPM2_CC_PCR_SETAUTHVAL = 0x0183,
|
TPM2_CC_PCR_SETAUTHVAL = 0x0183,
|
||||||
|
TPM2_CC_PCR_ALLOCATE = 0x012B,
|
||||||
|
TPM2_CC_SHUTDOWN = 0x0145,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -430,7 +432,7 @@ enum {
|
||||||
*
|
*
|
||||||
* Return: code of the operation
|
* Return: code of the operation
|
||||||
*/
|
*/
|
||||||
u32 tpm2_startup(struct udevice *dev, enum tpm2_startup_types mode);
|
u32 tpm2_startup(struct udevice *dev, bool onoff, enum tpm2_startup_types mode);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Issue a TPM2_SelfTest command.
|
* Issue a TPM2_SelfTest command.
|
||||||
|
@ -701,6 +703,55 @@ u32 tpm2_report_state(struct udevice *dev, uint vendor_cmd, uint vendor_subcmd,
|
||||||
u32 tpm2_enable_nvcommits(struct udevice *dev, uint vendor_cmd,
|
u32 tpm2_enable_nvcommits(struct udevice *dev, uint vendor_cmd,
|
||||||
uint vendor_subcmd);
|
uint vendor_subcmd);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tpm2_scan_masks - Scan the bitmask of algorithms based on the
|
||||||
|
* active/supported banks and the one from eventlog.
|
||||||
|
*
|
||||||
|
* @dev TPM device
|
||||||
|
* @log_active Active algorithm bitmask
|
||||||
|
* @mask Bitmask to set
|
||||||
|
*
|
||||||
|
* Return: zero on success, negative errno otherwise
|
||||||
|
*/
|
||||||
|
int tpm2_scan_masks(struct udevice *dev, u32 log_active, u32 *mask);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tpm2_pcr_config_algo() - Allocate the active PCRs. Requires reboot
|
||||||
|
*
|
||||||
|
* @dev TPM device
|
||||||
|
* @algo_mask Mask of the algorithms
|
||||||
|
* @pcr PCR structure for allocation
|
||||||
|
* @pcr_len Actual PCR data length
|
||||||
|
*
|
||||||
|
* Return: code of the operation
|
||||||
|
*/
|
||||||
|
u32 tpm2_pcr_config_algo(struct udevice *dev, u32 algo_mask,
|
||||||
|
struct tpml_pcr_selection *pcr, u32 *pcr_len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tpm2_send_pcr_allocate() - Send PCR allocate command. Requires reboot
|
||||||
|
*
|
||||||
|
* @dev TPM device
|
||||||
|
* @pw Platform password
|
||||||
|
* @pw_sz Length of the password
|
||||||
|
* @pcr PCR structure for allocation
|
||||||
|
* @pcr_len Actual PCR data length
|
||||||
|
*
|
||||||
|
* Return: code of the operation
|
||||||
|
*/
|
||||||
|
u32 tpm2_send_pcr_allocate(struct udevice *dev, const char *pw,
|
||||||
|
const ssize_t pw_sz, struct tpml_pcr_selection *pcr,
|
||||||
|
u32 pcr_len);
|
||||||
|
/**
|
||||||
|
* tpm2_activate_banks() - Activate PCR banks
|
||||||
|
*
|
||||||
|
* @param dev TPM device
|
||||||
|
* @log_active Bitmask of eventlog algorithms
|
||||||
|
*
|
||||||
|
* Return: code of the operation
|
||||||
|
*/
|
||||||
|
int tpm2_activate_banks(struct udevice *dev, u32 log_active);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* tpm2_auto_start() - start up the TPM and perform selftests.
|
* tpm2_auto_start() - start up the TPM and perform selftests.
|
||||||
* If a testable function has not been tested and is
|
* If a testable function has not been tested and is
|
||||||
|
|
12
lib/Kconfig
12
lib/Kconfig
|
@ -514,6 +514,18 @@ config VPL_TPM
|
||||||
for the low-level TPM interface, but only one TPM is supported at
|
for the low-level TPM interface, but only one TPM is supported at
|
||||||
a time by the TPM library.
|
a time by the TPM library.
|
||||||
|
|
||||||
|
config TPM_PCR_ALLOCATE
|
||||||
|
bool "Re-configurate TPM algorithms in run-time (PCR allocate)"
|
||||||
|
depends on TPM_V2 && (MEASURED_BOOT || EFI_TCG2_PROTOCOL)
|
||||||
|
help
|
||||||
|
This enables a detection for the dismatches of algorithms among TPM
|
||||||
|
device, eventlog from previous boot stage and U-Boot support.
|
||||||
|
A PCR allocate command will be sent to reconfigurate the TPM device
|
||||||
|
in run-time to make sure algorithms in TPM device, eventlog and
|
||||||
|
U-Boot are aligned with each other.
|
||||||
|
A system reboot will be proceeded after then to activate the new
|
||||||
|
algorithms.
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
|
||||||
menu "Android Verified Boot"
|
menu "Android Verified Boot"
|
||||||
|
|
|
@ -438,15 +438,6 @@ config EFI_TCG2_PROTOCOL
|
||||||
Provide a EFI_TCG2_PROTOCOL implementation using the TPM hardware
|
Provide a EFI_TCG2_PROTOCOL implementation using the TPM hardware
|
||||||
of the platform.
|
of the platform.
|
||||||
|
|
||||||
config EFI_TCG2_PROTOCOL_EVENTLOG_SIZE
|
|
||||||
int "EFI_TCG2_PROTOCOL EventLog size"
|
|
||||||
depends on EFI_TCG2_PROTOCOL
|
|
||||||
default 65536
|
|
||||||
help
|
|
||||||
Define the size of the EventLog for EFI_TCG2_PROTOCOL. Note that
|
|
||||||
this is going to be allocated twice. One for the eventlog it self
|
|
||||||
and one for the configuration table that is required from the spec
|
|
||||||
|
|
||||||
config EFI_TCG2_PROTOCOL_MEASURE_DTB
|
config EFI_TCG2_PROTOCOL_MEASURE_DTB
|
||||||
bool "Measure DTB with EFI_TCG2_PROTOCOL"
|
bool "Measure DTB with EFI_TCG2_PROTOCOL"
|
||||||
depends on EFI_TCG2_PROTOCOL
|
depends on EFI_TCG2_PROTOCOL
|
||||||
|
|
|
@ -112,7 +112,7 @@ static efi_status_t tcg2_agile_log_append(u32 pcr_index, u32 event_type,
|
||||||
/* if ExitBootServices hasn't been called update the normal log */
|
/* if ExitBootServices hasn't been called update the normal log */
|
||||||
if (!event_log.ebs_called) {
|
if (!event_log.ebs_called) {
|
||||||
if (event_log.truncated ||
|
if (event_log.truncated ||
|
||||||
event_log.pos + event_size > TPM2_EVENT_LOG_SIZE) {
|
event_log.pos + event_size > CONFIG_TPM2_EVENT_LOG_SIZE) {
|
||||||
event_log.truncated = true;
|
event_log.truncated = true;
|
||||||
return EFI_VOLUME_FULL;
|
return EFI_VOLUME_FULL;
|
||||||
}
|
}
|
||||||
|
@ -125,7 +125,7 @@ static efi_status_t tcg2_agile_log_append(u32 pcr_index, u32 event_type,
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
/* if GetEventLog has been called update FinalEventLog as well */
|
/* if GetEventLog has been called update FinalEventLog as well */
|
||||||
if (event_log.final_pos + event_size > TPM2_EVENT_LOG_SIZE)
|
if (event_log.final_pos + event_size > CONFIG_TPM2_EVENT_LOG_SIZE)
|
||||||
return EFI_VOLUME_FULL;
|
return EFI_VOLUME_FULL;
|
||||||
|
|
||||||
log = (void *)((uintptr_t)event_log.final_buffer + event_log.final_pos);
|
log = (void *)((uintptr_t)event_log.final_buffer + event_log.final_pos);
|
||||||
|
@ -823,12 +823,12 @@ static efi_status_t create_final_event(void)
|
||||||
* EFI_TCG2_GET_EVENT_LOGS need to be stored in an instance of an
|
* EFI_TCG2_GET_EVENT_LOGS need to be stored in an instance of an
|
||||||
* EFI_CONFIGURATION_TABLE
|
* EFI_CONFIGURATION_TABLE
|
||||||
*/
|
*/
|
||||||
ret = efi_allocate_pool(EFI_ACPI_MEMORY_NVS, TPM2_EVENT_LOG_SIZE,
|
ret = efi_allocate_pool(EFI_ACPI_MEMORY_NVS, CONFIG_TPM2_EVENT_LOG_SIZE,
|
||||||
&event_log.final_buffer);
|
&event_log.final_buffer);
|
||||||
if (ret != EFI_SUCCESS)
|
if (ret != EFI_SUCCESS)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
memset(event_log.final_buffer, 0xff, TPM2_EVENT_LOG_SIZE);
|
memset(event_log.final_buffer, 0xff, CONFIG_TPM2_EVENT_LOG_SIZE);
|
||||||
final_event = event_log.final_buffer;
|
final_event = event_log.final_buffer;
|
||||||
final_event->number_of_events = 0;
|
final_event->number_of_events = 0;
|
||||||
final_event->version = EFI_TCG2_FINAL_EVENTS_TABLE_VERSION;
|
final_event->version = EFI_TCG2_FINAL_EVENTS_TABLE_VERSION;
|
||||||
|
@ -914,7 +914,8 @@ static efi_status_t efi_init_event_log(void)
|
||||||
if (tcg2_platform_get_tpm2(&dev))
|
if (tcg2_platform_get_tpm2(&dev))
|
||||||
return EFI_DEVICE_ERROR;
|
return EFI_DEVICE_ERROR;
|
||||||
|
|
||||||
ret = efi_allocate_pool(EFI_BOOT_SERVICES_DATA, TPM2_EVENT_LOG_SIZE,
|
ret = efi_allocate_pool(EFI_BOOT_SERVICES_DATA,
|
||||||
|
CONFIG_TPM2_EVENT_LOG_SIZE,
|
||||||
(void **)&event_log.buffer);
|
(void **)&event_log.buffer);
|
||||||
if (ret != EFI_SUCCESS)
|
if (ret != EFI_SUCCESS)
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -923,7 +924,7 @@ static efi_status_t efi_init_event_log(void)
|
||||||
* initialize log area as 0xff so the OS can easily figure out the
|
* initialize log area as 0xff so the OS can easily figure out the
|
||||||
* last log entry
|
* last log entry
|
||||||
*/
|
*/
|
||||||
memset(event_log.buffer, 0xff, TPM2_EVENT_LOG_SIZE);
|
memset(event_log.buffer, 0xff, CONFIG_TPM2_EVENT_LOG_SIZE);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The log header is defined to be in SHA1 event log entry format.
|
* The log header is defined to be in SHA1 event log entry format.
|
||||||
|
@ -940,7 +941,7 @@ static efi_status_t efi_init_event_log(void)
|
||||||
* platforms can use different ways to do so.
|
* platforms can use different ways to do so.
|
||||||
*/
|
*/
|
||||||
elog.log = event_log.buffer;
|
elog.log = event_log.buffer;
|
||||||
elog.log_size = TPM2_EVENT_LOG_SIZE;
|
elog.log_size = CONFIG_TPM2_EVENT_LOG_SIZE;
|
||||||
rc = tcg2_log_prepare_buffer(dev, &elog, false);
|
rc = tcg2_log_prepare_buffer(dev, &elog, false);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
ret = (rc == -ENOBUFS) ? EFI_BUFFER_TOO_SMALL : EFI_DEVICE_ERROR;
|
ret = (rc == -ENOBUFS) ? EFI_BUFFER_TOO_SMALL : EFI_DEVICE_ERROR;
|
||||||
|
|
257
lib/tpm-v2.c
257
lib/tpm-v2.c
|
@ -44,12 +44,134 @@ static int tpm2_update_active_banks(struct udevice *dev)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 tpm2_startup(struct udevice *dev, enum tpm2_startup_types mode)
|
static void tpm2_print_selected_algorithm_name(u32 selected)
|
||||||
{
|
{
|
||||||
|
size_t i;
|
||||||
|
const char *str;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(hash_algo_list); i++) {
|
||||||
|
const struct digest_info *algo = &hash_algo_list[i];
|
||||||
|
|
||||||
|
if (!(selected & algo->hash_mask))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
str = tpm2_algorithm_name(algo->hash_alg);
|
||||||
|
if (str)
|
||||||
|
log_info("%s\n", str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int tpm2_scan_masks(struct udevice *dev, u32 log_active, u32 *mask)
|
||||||
|
{
|
||||||
|
struct tpml_pcr_selection pcrs;
|
||||||
|
u32 active = 0;
|
||||||
|
u32 supported = 0;
|
||||||
|
int rc, i;
|
||||||
|
|
||||||
|
*mask = 0;
|
||||||
|
|
||||||
|
rc = tpm2_get_pcr_info(dev, &pcrs);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
for (i = 0; i < pcrs.count; i++) {
|
||||||
|
struct tpms_pcr_selection *sel = &pcrs.selection[i];
|
||||||
|
size_t j;
|
||||||
|
u32 hash_mask = 0;
|
||||||
|
|
||||||
|
for (j = 0; j < ARRAY_SIZE(hash_algo_list); j++) {
|
||||||
|
if (hash_algo_list[j].hash_alg == sel->hash)
|
||||||
|
hash_mask = hash_algo_list[j].hash_mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tpm2_algorithm_supported(sel->hash))
|
||||||
|
supported |= hash_mask;
|
||||||
|
|
||||||
|
if (tpm2_is_active_bank(sel))
|
||||||
|
active |= hash_mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* All eventlog algorithm(s) must be supported */
|
||||||
|
if (log_active & ~supported) {
|
||||||
|
log_err("EventLog contains U-Boot unsupported algorithm(s)\n");
|
||||||
|
tpm2_print_selected_algorithm_name(log_active & ~supported);
|
||||||
|
rc = -1;
|
||||||
|
}
|
||||||
|
if (log_active && active & ~log_active) {
|
||||||
|
log_warning("TPM active algorithm(s) not exist in eventlog\n");
|
||||||
|
tpm2_print_selected_algorithm_name(active & ~log_active);
|
||||||
|
*mask = log_active;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Any active algorithm(s) which are not supported must be removed */
|
||||||
|
if (active & ~supported) {
|
||||||
|
log_warning("TPM active algorithm(s) unsupported by u-boot\n");
|
||||||
|
tpm2_print_selected_algorithm_name(active & ~supported);
|
||||||
|
if (*mask)
|
||||||
|
*mask = active & supported & *mask;
|
||||||
|
else
|
||||||
|
*mask = active & supported;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tpm2_pcr_allocate(struct udevice *dev, u32 algo_mask)
|
||||||
|
{
|
||||||
|
struct tpml_pcr_selection pcr = { 0 };
|
||||||
|
u32 pcr_len = 0;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = tpm2_get_pcr_info(dev, &pcr);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
rc = tpm2_pcr_config_algo(dev, algo_mask, &pcr, &pcr_len);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
/* Assume no password */
|
||||||
|
rc = tpm2_send_pcr_allocate(dev, NULL, 0, &pcr, pcr_len);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
/* Send TPM2_Shutdown, assume mode = TPM2_SU_CLEAR */
|
||||||
|
return tpm2_startup(dev, false, TPM2_SU_CLEAR);
|
||||||
|
}
|
||||||
|
|
||||||
|
int tpm2_activate_banks(struct udevice *dev, u32 log_active)
|
||||||
|
{
|
||||||
|
u32 algo_mask = 0;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = tpm2_scan_masks(dev, log_active, &algo_mask);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
if (algo_mask) {
|
||||||
|
if (!IS_ENABLED(CONFIG_TPM_PCR_ALLOCATE))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
rc = tpm2_pcr_allocate(dev, algo_mask);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
log_info("PCR allocate done, shutdown TPM and reboot\n");
|
||||||
|
do_reset(NULL, 0, 0, NULL);
|
||||||
|
log_err("reset does not work!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 tpm2_startup(struct udevice *dev, bool bon, enum tpm2_startup_types mode)
|
||||||
|
{
|
||||||
|
int op = bon ? TPM2_CC_STARTUP : TPM2_CC_SHUTDOWN;
|
||||||
const u8 command_v2[12] = {
|
const u8 command_v2[12] = {
|
||||||
tpm_u16(TPM2_ST_NO_SESSIONS),
|
tpm_u16(TPM2_ST_NO_SESSIONS),
|
||||||
tpm_u32(12),
|
tpm_u32(12),
|
||||||
tpm_u32(TPM2_CC_STARTUP),
|
tpm_u32(op),
|
||||||
tpm_u16(mode),
|
tpm_u16(mode),
|
||||||
};
|
};
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -59,7 +181,7 @@ u32 tpm2_startup(struct udevice *dev, enum tpm2_startup_types mode)
|
||||||
* but will return RC_INITIALIZE otherwise.
|
* but will return RC_INITIALIZE otherwise.
|
||||||
*/
|
*/
|
||||||
ret = tpm_sendrecv_command(dev, command_v2, NULL, NULL);
|
ret = tpm_sendrecv_command(dev, command_v2, NULL, NULL);
|
||||||
if (ret && ret != TPM2_RC_INITIALIZE)
|
if ((ret && ret != TPM2_RC_INITIALIZE) || !bon)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
return tpm2_update_active_banks(dev);
|
return tpm2_update_active_banks(dev);
|
||||||
|
@ -84,7 +206,7 @@ u32 tpm2_auto_start(struct udevice *dev)
|
||||||
rc = tpm2_self_test(dev, TPMI_YES);
|
rc = tpm2_self_test(dev, TPMI_YES);
|
||||||
|
|
||||||
if (rc == TPM2_RC_INITIALIZE) {
|
if (rc == TPM2_RC_INITIALIZE) {
|
||||||
rc = tpm2_startup(dev, TPM2_SU_CLEAR);
|
rc = tpm2_startup(dev, true, TPM2_SU_CLEAR);
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
|
@ -222,6 +344,9 @@ u32 tpm2_pcr_extend(struct udevice *dev, u32 index, u32 algorithm,
|
||||||
|
|
||||||
if (!tpm2_check_active_banks(dev)) {
|
if (!tpm2_check_active_banks(dev)) {
|
||||||
log_err("Cannot extend PCRs if all the TPM enabled algorithms are not supported\n");
|
log_err("Cannot extend PCRs if all the TPM enabled algorithms are not supported\n");
|
||||||
|
|
||||||
|
ret = tpm2_pcr_allocate(dev, 0);
|
||||||
|
if (ret)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
|
@ -399,6 +524,130 @@ u32 tpm2_get_capability(struct udevice *dev, u32 capability, u32 property,
|
||||||
return 0;
|
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)
|
static int tpm2_get_num_pcr(struct udevice *dev, u32 *num_pcr)
|
||||||
{
|
{
|
||||||
u8 response[(sizeof(struct tpms_capability_data) -
|
u8 response[(sizeof(struct tpms_capability_data) -
|
||||||
|
|
|
@ -28,7 +28,7 @@ u32 tpm_startup(struct udevice *dev, enum tpm_startup_type mode)
|
||||||
case TPM_ST_DEACTIVATED:
|
case TPM_ST_DEACTIVATED:
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
return tpm2_startup(dev, type);
|
return tpm2_startup(dev, true, type);
|
||||||
} else {
|
} else {
|
||||||
return -ENOSYS;
|
return -ENOSYS;
|
||||||
}
|
}
|
||||||
|
@ -60,7 +60,7 @@ u32 tpm_resume(struct udevice *dev)
|
||||||
if (tpm_is_v1(dev))
|
if (tpm_is_v1(dev))
|
||||||
return tpm1_startup(dev, TPM_ST_STATE);
|
return tpm1_startup(dev, TPM_ST_STATE);
|
||||||
else if (tpm_is_v2(dev))
|
else if (tpm_is_v2(dev))
|
||||||
return tpm2_startup(dev, TPM2_SU_STATE);
|
return tpm2_startup(dev, true, TPM2_SU_STATE);
|
||||||
else
|
else
|
||||||
return -ENOSYS;
|
return -ENOSYS;
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include <linux/unaligned/generic.h>
|
#include <linux/unaligned/generic.h>
|
||||||
#include <linux/unaligned/le_byteshift.h>
|
#include <linux/unaligned/le_byteshift.h>
|
||||||
#include "tpm-utils.h"
|
#include "tpm-utils.h"
|
||||||
|
#include <bloblist.h>
|
||||||
|
|
||||||
int tcg2_get_pcr_info(struct udevice *dev, u32 *supported_bank, u32 *active_bank,
|
int tcg2_get_pcr_info(struct udevice *dev, u32 *supported_bank, u32 *active_bank,
|
||||||
u32 *bank_num)
|
u32 *bank_num)
|
||||||
|
@ -358,12 +359,12 @@ static int tcg2_replay_eventlog(struct tcg2_event_log *elog,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int tcg2_log_parse(struct udevice *dev, struct tcg2_event_log *elog)
|
static int tcg2_log_parse(struct udevice *dev, struct tcg2_event_log *elog,
|
||||||
|
u32 *log_active)
|
||||||
{
|
{
|
||||||
struct tpml_digest_values digest_list;
|
struct tpml_digest_values digest_list;
|
||||||
struct tcg_efi_spec_id_event *event;
|
struct tcg_efi_spec_id_event *event;
|
||||||
struct tcg_pcr_event *log;
|
struct tcg_pcr_event *log;
|
||||||
u32 log_active;
|
|
||||||
u32 calc_size;
|
u32 calc_size;
|
||||||
u32 active;
|
u32 active;
|
||||||
u32 count;
|
u32 count;
|
||||||
|
@ -374,6 +375,8 @@ static int tcg2_log_parse(struct udevice *dev, struct tcg2_event_log *elog)
|
||||||
int rc;
|
int rc;
|
||||||
u32 i;
|
u32 i;
|
||||||
|
|
||||||
|
*log_active = 0;
|
||||||
|
|
||||||
if (elog->log_size <= offsetof(struct tcg_pcr_event, event))
|
if (elog->log_size <= offsetof(struct tcg_pcr_event, event))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -419,7 +422,6 @@ static int tcg2_log_parse(struct udevice *dev, struct tcg2_event_log *elog)
|
||||||
* algorithms, so just check the EvenLog against the TPM active ones.
|
* algorithms, so just check the EvenLog against the TPM active ones.
|
||||||
*/
|
*/
|
||||||
digest_list.count = 0;
|
digest_list.count = 0;
|
||||||
log_active = 0;
|
|
||||||
for (i = 0; i < count; ++i) {
|
for (i = 0; i < count; ++i) {
|
||||||
algo = get_unaligned_le16(&event->digest_sizes[i].algorithm_id);
|
algo = get_unaligned_le16(&event->digest_sizes[i].algorithm_id);
|
||||||
mask = tcg2_algorithm_to_mask(algo);
|
mask = tcg2_algorithm_to_mask(algo);
|
||||||
|
@ -445,17 +447,15 @@ static int tcg2_log_parse(struct udevice *dev, struct tcg2_event_log *elog)
|
||||||
algo);
|
algo);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
log_active |= mask;
|
*log_active |= mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = tcg2_get_active_pcr_banks(dev, &active);
|
rc = tcg2_get_active_pcr_banks(dev, &active);
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
/* If the EventLog and active algorithms don't match exit */
|
/* If the EventLog and active algorithms don't match exit */
|
||||||
if (log_active != active) {
|
if (*log_active != active)
|
||||||
log_err("EventLog doesn't contain all active PCR banks\n");
|
return -ERESTARTSYS;
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read PCR0 to check if previous firmware extended the PCRs or not. */
|
/* Read PCR0 to check if previous firmware extended the PCRs or not. */
|
||||||
rc = tcg2_pcr_read(dev, 0, &digest_list);
|
rc = tcg2_pcr_read(dev, 0, &digest_list);
|
||||||
|
@ -552,43 +552,21 @@ int tcg2_log_prepare_buffer(struct udevice *dev, struct tcg2_event_log *elog,
|
||||||
bool ignore_existing_log)
|
bool ignore_existing_log)
|
||||||
{
|
{
|
||||||
struct tcg2_event_log log;
|
struct tcg2_event_log log;
|
||||||
int rc, i;
|
int rc;
|
||||||
|
u32 log_active = 0;
|
||||||
|
|
||||||
elog->log_position = 0;
|
elog->log_position = 0;
|
||||||
elog->found = false;
|
elog->found = false;
|
||||||
|
|
||||||
/*
|
|
||||||
* Make sure U-Boot is compiled with all the active PCRs
|
|
||||||
* since we are about to create an EventLog and we won't
|
|
||||||
* measure anything if the PCR banks don't match
|
|
||||||
*/
|
|
||||||
if (!tpm2_check_active_banks(dev)) {
|
|
||||||
log_err("Cannot create EventLog\n");
|
|
||||||
log_err("Mismatch between U-Boot and TPM hash algos\n");
|
|
||||||
log_info("TPM:\n");
|
|
||||||
tpm2_print_active_banks(dev);
|
|
||||||
log_info("U-Boot:\n");
|
|
||||||
for (i = 0; i < ARRAY_SIZE(hash_algo_list); i++) {
|
|
||||||
const struct digest_info *algo = &hash_algo_list[i];
|
|
||||||
const char *str;
|
|
||||||
|
|
||||||
if (!algo->supported)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
str = tpm2_algorithm_name(algo->hash_alg);
|
|
||||||
if (str)
|
|
||||||
log_info("%s\n", str);
|
|
||||||
}
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = tcg2_platform_get_log(dev, (void **)&log.log, &log.log_size);
|
rc = tcg2_platform_get_log(dev, (void **)&log.log, &log.log_size);
|
||||||
if (!rc) {
|
if (!rc) {
|
||||||
log.log_position = 0;
|
log.log_position = 0;
|
||||||
log.found = false;
|
log.found = false;
|
||||||
|
|
||||||
if (!ignore_existing_log) {
|
if (!ignore_existing_log) {
|
||||||
rc = tcg2_log_parse(dev, &log);
|
rc = tcg2_log_parse(dev, &log, &log_active);
|
||||||
|
if (rc == -ERESTARTSYS && log_active)
|
||||||
|
goto pcr_allocate;
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
@ -615,6 +593,11 @@ int tcg2_log_prepare_buffer(struct udevice *dev, struct tcg2_event_log *elog,
|
||||||
elog->found = log.found;
|
elog->found = log.found;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pcr_allocate:
|
||||||
|
rc = tpm2_activate_banks(dev, log_active);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize the log buffer if no log was discovered and the buffer is
|
* Initialize the log buffer if no log was discovered and the buffer is
|
||||||
* valid. User's can pass in their own buffer as a fallback if no
|
* valid. User's can pass in their own buffer as a fallback if no
|
||||||
|
@ -672,21 +655,42 @@ void tcg2_measurement_term(struct udevice *dev, struct tcg2_event_log *elog,
|
||||||
|
|
||||||
__weak int tcg2_platform_get_log(struct udevice *dev, void **addr, u32 *size)
|
__weak int tcg2_platform_get_log(struct udevice *dev, void **addr, u32 *size)
|
||||||
{
|
{
|
||||||
const __be32 *addr_prop;
|
const __be32 *addr_prop = NULL;
|
||||||
const __be32 *size_prop;
|
const __be32 *size_prop = NULL;
|
||||||
int asize;
|
int asize;
|
||||||
int ssize;
|
int ssize;
|
||||||
|
struct ofnode_phandle_args args;
|
||||||
|
phys_addr_t a;
|
||||||
|
fdt_size_t s;
|
||||||
|
|
||||||
*addr = NULL;
|
*addr = NULL;
|
||||||
*size = 0;
|
*size = 0;
|
||||||
|
|
||||||
addr_prop = dev_read_prop(dev, "tpm_event_log_addr", &asize);
|
*addr = bloblist_get_blob(BLOBLISTT_TPM_EVLOG, size);
|
||||||
if (!addr_prop)
|
if (*addr && *size) {
|
||||||
addr_prop = dev_read_prop(dev, "linux,sml-base", &asize);
|
*addr = map_physmem((uintptr_t)(*addr), *size, MAP_NOCACHE);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO:
|
||||||
|
* Replace BLOBLIST with a new kconfig for handoff all components
|
||||||
|
* (fdt, tpm event log, etc...) from previous boot stage via bloblist
|
||||||
|
* mandatorily following Firmware Handoff spec.
|
||||||
|
*/
|
||||||
|
if (!CONFIG_IS_ENABLED(BLOBLIST)) {
|
||||||
|
addr_prop = dev_read_prop(dev, "tpm_event_log_addr", &asize);
|
||||||
size_prop = dev_read_prop(dev, "tpm_event_log_size", &ssize);
|
size_prop = dev_read_prop(dev, "tpm_event_log_size", &ssize);
|
||||||
if (!size_prop)
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If no eventlog was observed, a sml buffer is required for the kernel
|
||||||
|
* to discover the eventlog.
|
||||||
|
*/
|
||||||
|
if (!addr_prop || !size_prop) {
|
||||||
|
addr_prop = dev_read_prop(dev, "linux,sml-base", &asize);
|
||||||
size_prop = dev_read_prop(dev, "linux,sml-size", &ssize);
|
size_prop = dev_read_prop(dev, "linux,sml-size", &ssize);
|
||||||
|
}
|
||||||
|
|
||||||
if (addr_prop && size_prop) {
|
if (addr_prop && size_prop) {
|
||||||
u64 a = of_read_number(addr_prop, asize / sizeof(__be32));
|
u64 a = of_read_number(addr_prop, asize / sizeof(__be32));
|
||||||
|
@ -694,13 +698,11 @@ __weak int tcg2_platform_get_log(struct udevice *dev, void **addr, u32 *size)
|
||||||
|
|
||||||
*addr = map_physmem(a, s, MAP_NOCACHE);
|
*addr = map_physmem(a, s, MAP_NOCACHE);
|
||||||
*size = (u32)s;
|
*size = (u32)s;
|
||||||
} else {
|
|
||||||
struct ofnode_phandle_args args;
|
|
||||||
phys_addr_t a;
|
|
||||||
fdt_size_t s;
|
|
||||||
|
|
||||||
if (dev_read_phandle_with_args(dev, "memory-region", NULL, 0,
|
return 0;
|
||||||
0, &args))
|
}
|
||||||
|
|
||||||
|
if (dev_read_phandle_with_args(dev, "memory-region", NULL, 0, 0, &args))
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
a = ofnode_get_addr_size(args.node, "reg", &s);
|
a = ofnode_get_addr_size(args.node, "reg", &s);
|
||||||
|
@ -709,7 +711,6 @@ __weak int tcg2_platform_get_log(struct udevice *dev, void **addr, u32 *size)
|
||||||
|
|
||||||
*addr = map_physmem(a, s, MAP_NOCACHE);
|
*addr = map_physmem(a, s, MAP_NOCACHE);
|
||||||
*size = (u32)s;
|
*size = (u32)s;
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -98,10 +98,12 @@ static int bloblist_test_blob(struct unit_test_state *uts)
|
||||||
struct bloblist_hdr *hdr;
|
struct bloblist_hdr *hdr;
|
||||||
struct bloblist_rec *rec, *rec2;
|
struct bloblist_rec *rec, *rec2;
|
||||||
char *data;
|
char *data;
|
||||||
|
int size = 0;
|
||||||
|
|
||||||
/* At the start there should be no records */
|
/* At the start there should be no records */
|
||||||
hdr = clear_bloblist();
|
hdr = clear_bloblist();
|
||||||
ut_assertnull(bloblist_find(TEST_TAG, TEST_BLOBLIST_SIZE));
|
ut_assertnull(bloblist_find(TEST_TAG, TEST_BLOBLIST_SIZE));
|
||||||
|
ut_assertnull(bloblist_get_blob(TEST_TAG, &size));
|
||||||
ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0, 0));
|
ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0, 0));
|
||||||
ut_asserteq(sizeof(struct bloblist_hdr), bloblist_get_size());
|
ut_asserteq(sizeof(struct bloblist_hdr), bloblist_get_size());
|
||||||
ut_asserteq(TEST_BLOBLIST_SIZE, bloblist_get_total_size());
|
ut_asserteq(TEST_BLOBLIST_SIZE, bloblist_get_total_size());
|
||||||
|
@ -114,6 +116,8 @@ static int bloblist_test_blob(struct unit_test_state *uts)
|
||||||
ut_asserteq_addr(rec + 1, data);
|
ut_asserteq_addr(rec + 1, data);
|
||||||
data = bloblist_find(TEST_TAG, TEST_SIZE);
|
data = bloblist_find(TEST_TAG, TEST_SIZE);
|
||||||
ut_asserteq_addr(rec + 1, data);
|
ut_asserteq_addr(rec + 1, data);
|
||||||
|
ut_asserteq_addr(bloblist_get_blob(TEST_TAG, &size), data);
|
||||||
|
ut_asserteq(size, TEST_SIZE);
|
||||||
|
|
||||||
/* Check the data is zeroed */
|
/* Check the data is zeroed */
|
||||||
ut_assertok(check_zero(data, TEST_SIZE));
|
ut_assertok(check_zero(data, TEST_SIZE));
|
||||||
|
|
Loading…
Add table
Reference in a new issue