diff mbox series

[3/5] efi_loader: add boot variable measurement

Message ID 20210707133638.12630-4-masahisa.kojima@linaro.org
State New
Headers show
Series add measurement support | expand

Commit Message

Masahisa Kojima July 7, 2021, 1:36 p.m. UTC
TCG PC Client PFP spec requires to measure "Boot####"
and "BootOrder" variables, EV_SEPARATOR event prior
to the Ready to Boot invocation.
Since u-boot does not implement Ready to Boot event,
these measurements are performed when efi_start_image() is called.

TCG spec also requires to measure "Calling EFI Application from
Boot Option" for each boot attempt, and "Returning from EFI
Application from Boot Option" if a boot device returns control
back to the Boot Manager.

Signed-off-by: Masahisa Kojima <masahisa.kojima@linaro.org>

---
 include/efi_loader.h          |   4 ++
 include/tpm-v2.h              |  18 ++++-
 lib/efi_loader/efi_boottime.c |  20 ++++++
 lib/efi_loader/efi_tcg2.c     | 123 ++++++++++++++++++++++++++++++++++
 4 files changed, 164 insertions(+), 1 deletion(-)

-- 
2.17.1

Comments

Ilias Apalodimas July 7, 2021, 6:56 p.m. UTC | #1
Hi Kojima-san,
> +{


[...]

> +	u16 *boot_order;

> +	u16 var_name[] = L"BootOrder";

> +	u16 boot_name[] = L"Boot0000";

> +	u16 hexmap[] = L"0123456789ABCDEF";

> +	u8 *bootvar;

> +	efi_uintn_t var_data_size;

> +	u32 count, i;

> +	efi_status_t ret;

> +

> +	boot_order = efi_get_var(var_name, &efi_global_variable_guid,

> +				 &var_data_size);

> +	if (!boot_order) {

> +		log_info("BootOrder not defined\n");

> +		ret = EFI_NOT_FOUND;

> +		goto error;

> +	}

> +

> +	ret = tcg2_measure_variable(dev, 1, EV_EFI_VARIABLE_BOOT2, var_name,

> +				    &efi_global_variable_guid, var_data_size,

> +				    (u8 *)boot_order);

> +	if (ret != EFI_SUCCESS)

> +		goto error;

> +

> +	count = var_data_size / sizeof(*boot_order);

> +	for (i = 0; i < count; i++) {

> +		boot_name[4] = hexmap[(boot_order[i] & 0xf000) >> 12];

> +		boot_name[5] = hexmap[(boot_order[i] & 0x0f00) >> 8];

> +		boot_name[6] = hexmap[(boot_order[i] & 0x00f0) >> 4];

> +		boot_name[7] = hexmap[(boot_order[i] & 0x000f)];


Can you use efi_create_indexed_name() instead?

[...]
> +	for (pcr_index = 0; pcr_index <= 7; pcr_index++) {

> +		ret = tcg2_measure_event(dev, pcr_index, EV_SEPARATOR,

> +					 sizeof(event), (u8 *)&event);


I assume adding a separator event on all these PCRs is described on the
standard?

> +		if (ret != EFI_SUCCESS)

> +			goto out;

> +	}

> +

> +	tcg2_efi_app_invoked = true;

> +out:

> +	return ret;

> +}

> +

> +/**

> + * efi_tcg2_measure_efi_app_exit() - measure efi app exit

> + *

> + * Return:	status code

> + */

> +efi_status_t EFIAPI efi_tcg2_measure_efi_app_exit(void)

> +{

> +	efi_status_t ret;

> +	struct udevice *dev;

> +

> +	ret = platform_get_tpm2_device(&dev);

> +	if (ret != EFI_SUCCESS)

> +		return ret;

> +

> +	ret = tcg2_measure_event(dev, 4, EV_EFI_ACTION,

> +				 strlen(EFI_RETURNING_FROM_EFI_APPLICATION),


Do we need a NUL terminator on this string or not?


Regards
/Ilias
Masahisa Kojima July 8, 2021, 2:44 a.m. UTC | #2
On Thu, 8 Jul 2021 at 03:56, Ilias Apalodimas
<ilias.apalodimas@linaro.org> wrote:
>

> Hi Kojima-san,

> > +{

>

> [...]

>

> > +     u16 *boot_order;

> > +     u16 var_name[] = L"BootOrder";

> > +     u16 boot_name[] = L"Boot0000";

> > +     u16 hexmap[] = L"0123456789ABCDEF";

> > +     u8 *bootvar;

> > +     efi_uintn_t var_data_size;

> > +     u32 count, i;

> > +     efi_status_t ret;

> > +

> > +     boot_order = efi_get_var(var_name, &efi_global_variable_guid,

> > +                              &var_data_size);

> > +     if (!boot_order) {

> > +             log_info("BootOrder not defined\n");

> > +             ret = EFI_NOT_FOUND;

> > +             goto error;

> > +     }

> > +

> > +     ret = tcg2_measure_variable(dev, 1, EV_EFI_VARIABLE_BOOT2, var_name,

> > +                                 &efi_global_variable_guid, var_data_size,

> > +                                 (u8 *)boot_order);

> > +     if (ret != EFI_SUCCESS)

> > +             goto error;

> > +

> > +     count = var_data_size / sizeof(*boot_order);

> > +     for (i = 0; i < count; i++) {

> > +             boot_name[4] = hexmap[(boot_order[i] & 0xf000) >> 12];

> > +             boot_name[5] = hexmap[(boot_order[i] & 0x0f00) >> 8];

> > +             boot_name[6] = hexmap[(boot_order[i] & 0x00f0) >> 4];

> > +             boot_name[7] = hexmap[(boot_order[i] & 0x000f)];

>

> Can you use efi_create_indexed_name() instead?


I have not noticed this utility function, thank you.

>

> [...]

> > +     for (pcr_index = 0; pcr_index <= 7; pcr_index++) {

> > +             ret = tcg2_measure_event(dev, pcr_index, EV_SEPARATOR,

> > +                                      sizeof(event), (u8 *)&event);

>

> I assume adding a separator event on all these PCRs is described on the

> standard?


Yes, TCG spec requires EV_SEPARATOR event prior to the first invocation of
the first Ready to Boot call.
Spec also says EV_SEPARATOR must be the last entry for PCR0, 1, 2, 3, 6.

>

> > +             if (ret != EFI_SUCCESS)

> > +                     goto out;

> > +     }

> > +

> > +     tcg2_efi_app_invoked = true;

> > +out:

> > +     return ret;

> > +}

> > +

> > +/**

> > + * efi_tcg2_measure_efi_app_exit() - measure efi app exit

> > + *

> > + * Return:   status code

> > + */

> > +efi_status_t EFIAPI efi_tcg2_measure_efi_app_exit(void)

> > +{

> > +     efi_status_t ret;

> > +     struct udevice *dev;

> > +

> > +     ret = platform_get_tpm2_device(&dev);

> > +     if (ret != EFI_SUCCESS)

> > +             return ret;

> > +

> > +     ret = tcg2_measure_event(dev, 4, EV_EFI_ACTION,

> > +                              strlen(EFI_RETURNING_FROM_EFI_APPLICATION),

>

> Do we need a NUL terminator on this string or not?


No, TCG spec says
"the actual log entries SHALL NOT include the quote characters
or a NUL terminator."

Thanks,
Masahisa Kojima

>

>

> Regards

> /Ilias
Heinrich Schuchardt July 8, 2021, 5:46 p.m. UTC | #3
On 7/7/21 3:36 PM, Masahisa Kojima wrote:
> TCG PC Client PFP spec requires to measure "Boot####"

> and "BootOrder" variables, EV_SEPARATOR event prior

> to the Ready to Boot invocation.

> Since u-boot does not implement Ready to Boot event,

> these measurements are performed when efi_start_image() is called.

>

> TCG spec also requires to measure "Calling EFI Application from

> Boot Option" for each boot attempt, and "Returning from EFI

> Application from Boot Option" if a boot device returns control

> back to the Boot Manager.

>

> Signed-off-by: Masahisa Kojima <masahisa.kojima@linaro.org>

> ---

>   include/efi_loader.h          |   4 ++

>   include/tpm-v2.h              |  18 ++++-

>   lib/efi_loader/efi_boottime.c |  20 ++++++

>   lib/efi_loader/efi_tcg2.c     | 123 ++++++++++++++++++++++++++++++++++

>   4 files changed, 164 insertions(+), 1 deletion(-)

>

> diff --git a/include/efi_loader.h b/include/efi_loader.h

> index 0a9c82a257..281ffff30f 100644

> --- a/include/efi_loader.h

> +++ b/include/efi_loader.h

> @@ -407,6 +407,10 @@ efi_status_t efi_run_image(void *source_buffer, efi_uintn_t source_size);

>   efi_status_t efi_init_variables(void);

>   /* Notify ExitBootServices() is called */

>   void efi_variables_boot_exit_notify(void);

> +/* Measure efi application invocation */

> +efi_status_t EFIAPI efi_tcg2_measure_efi_app_invocation(void);

> +/* Measure efi application exit */

> +efi_status_t EFIAPI efi_tcg2_measure_efi_app_exit(void);

>   /* Called by bootefi to initialize root node */

>   efi_status_t efi_root_node_register(void);

>   /* Called by bootefi to initialize runtime */

> diff --git a/include/tpm-v2.h b/include/tpm-v2.h

> index 3e48e35861..8a7b7f1874 100644

> --- a/include/tpm-v2.h

> +++ b/include/tpm-v2.h

> @@ -73,7 +73,7 @@ struct udevice;

>   /*

>    * event types, cf.

>    * "TCG PC Client Platform Firmware Profile Specification", Family "2.0"

> - * rev 1.04, June 3, 2019

> + * Level 00 Version 1.05 Revision 23, May 7, 2021

>    */

>   #define EV_EFI_EVENT_BASE			((u32)0x80000000)

>   #define EV_EFI_VARIABLE_DRIVER_CONFIG		((u32)0x80000001)

> @@ -85,8 +85,24 @@ struct udevice;

>   #define EV_EFI_ACTION				((u32)0x80000007)

>   #define EV_EFI_PLATFORM_FIRMWARE_BLOB		((u32)0x80000008)

>   #define EV_EFI_HANDOFF_TABLES			((u32)0x80000009)

> +#define EV_EFI_PLATFORM_FIRMWARE_BLOB2		((u32)0x8000000A)

> +#define EV_EFI_HANDOFF_TABLES2			((u32)0x8000000B)

> +#define EV_EFI_VARIABLE_BOOT2			((u32)0x8000000C)

>   #define EV_EFI_HCRTM_EVENT			((u32)0x80000010)

>   #define EV_EFI_VARIABLE_AUTHORITY		((u32)0x800000E0)

> +#define EV_EFI_SPDM_FIRMWARE_BLOB		((u32)0x800000E1)

> +#define EV_EFI_SPDM_FIRMWARE_CONFIG		((u32)0x800000E2)

> +

> +#define EFI_CALLING_EFI_APPLICATION         \

> +	"Calling EFI Application from Boot Option"

> +#define EFI_RETURNING_FROM_EFI_APPLICATION  \

> +	"Returning from EFI Application from Boot Option"

> +#define EFI_EXIT_BOOT_SERVICES_INVOCATION   \

> +	"Exit Boot Services Invocation"

> +#define EFI_EXIT_BOOT_SERVICES_FAILED       \

> +	"Exit Boot Services Returned with Failure"

> +#define EFI_EXIT_BOOT_SERVICES_SUCCEEDED    \

> +	"Exit Boot Services Returned with Success"


Which spec defines if the string in the event log shall be utf-8 or utf-16?

Best regards

Heinrich

>

>   /* TPMS_TAGGED_PROPERTY Structure */

>   struct tpms_tagged_property {

> diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c

> index f6d5ba05e3..2914800c56 100644

> --- a/lib/efi_loader/efi_boottime.c

> +++ b/lib/efi_loader/efi_boottime.c

> @@ -2993,6 +2993,16 @@ efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle,

>   	image_obj->exit_status = &exit_status;

>   	image_obj->exit_jmp = &exit_jmp;

>

> +	if (IS_ENABLED(CONFIG_EFI_TCG2_PROTOCOL)) {

> +		if (image_obj->image_type == IMAGE_SUBSYSTEM_EFI_APPLICATION) {

> +			ret = efi_tcg2_measure_efi_app_invocation();

> +			if (ret != EFI_SUCCESS) {

> +				EFI_PRINT("tcg2 measurement fails(0x%lx)\n",

> +					  ret);

> +			}

> +		}

> +	}

> +

>   	/* call the image! */

>   	if (setjmp(&exit_jmp)) {

>   		/*

> @@ -3251,6 +3261,16 @@ static efi_status_t EFIAPI efi_exit(efi_handle_t image_handle,

>   	    exit_status != EFI_SUCCESS)

>   		efi_delete_image(image_obj, loaded_image_protocol);

>

> +	if (IS_ENABLED(CONFIG_EFI_TCG2_PROTOCOL)) {

> +		if (image_obj->image_type == IMAGE_SUBSYSTEM_EFI_APPLICATION) {

> +			ret = efi_tcg2_measure_efi_app_exit();

> +			if (ret != EFI_SUCCESS) {

> +				EFI_PRINT("tcg2 measurement fails(0x%lx)\n",

> +					  ret);

> +			}

> +		}

> +	}

> +

>   	/* Make sure entry/exit counts for EFI world cross-overs match */

>   	EFI_EXIT(exit_status);

>

> diff --git a/lib/efi_loader/efi_tcg2.c b/lib/efi_loader/efi_tcg2.c

> index 2a248bd62a..6e903e3cb3 100644

> --- a/lib/efi_loader/efi_tcg2.c

> +++ b/lib/efi_loader/efi_tcg2.c

> @@ -35,6 +35,7 @@ struct event_log_buffer {

>   };

>

>   static struct event_log_buffer event_log;

> +static bool tcg2_efi_app_invoked;

>   /*

>    * When requesting TPM2_CAP_TPM_PROPERTIES the value is on a standard offset.

>    * Since the current tpm2_get_capability() response buffers starts at

> @@ -1383,6 +1384,128 @@ static efi_status_t tcg2_measure_variable(struct udevice *dev, u32 pcr_index,

>   	return ret;

>   }

>

> +/**

> + * tcg2_measure_boot_variable() - measure boot variables

> + *

> + * @dev:	TPM device

> + *

> + * Return:	status code

> + */

> +static efi_status_t tcg2_measure_boot_variable(struct udevice *dev)

> +{

> +	u16 *boot_order;

> +	u16 var_name[] = L"BootOrder";

> +	u16 boot_name[] = L"Boot0000";

> +	u16 hexmap[] = L"0123456789ABCDEF";

> +	u8 *bootvar;

> +	efi_uintn_t var_data_size;

> +	u32 count, i;

> +	efi_status_t ret;

> +

> +	boot_order = efi_get_var(var_name, &efi_global_variable_guid,

> +				 &var_data_size);

> +	if (!boot_order) {

> +		log_info("BootOrder not defined\n");

> +		ret = EFI_NOT_FOUND;

> +		goto error;

> +	}

> +

> +	ret = tcg2_measure_variable(dev, 1, EV_EFI_VARIABLE_BOOT2, var_name,

> +				    &efi_global_variable_guid, var_data_size,

> +				    (u8 *)boot_order);

> +	if (ret != EFI_SUCCESS)

> +		goto error;

> +

> +	count = var_data_size / sizeof(*boot_order);

> +	for (i = 0; i < count; i++) {

> +		boot_name[4] = hexmap[(boot_order[i] & 0xf000) >> 12];

> +		boot_name[5] = hexmap[(boot_order[i] & 0x0f00) >> 8];

> +		boot_name[6] = hexmap[(boot_order[i] & 0x00f0) >> 4];

> +		boot_name[7] = hexmap[(boot_order[i] & 0x000f)];

> +

> +		bootvar = efi_get_var(boot_name, &efi_global_variable_guid,

> +				      &var_data_size);

> +

> +		if (!bootvar) {

> +			log_info("%ls not found\n", boot_name);

> +			continue;

> +		}

> +

> +		ret = tcg2_measure_variable(dev, 1, EV_EFI_VARIABLE_BOOT2,

> +					    boot_name,

> +					    &efi_global_variable_guid,

> +					    var_data_size, bootvar);

> +		free(bootvar);

> +		if (ret != EFI_SUCCESS)

> +			goto error;

> +	}

> +

> +error:

> +	free(boot_order);

> +	return ret;

> +}

> +

> +/**

> + * efi_tcg2_measure_efi_app_invocation() - measure efi app invocation

> + *

> + * Return:	status code

> + */

> +efi_status_t EFIAPI efi_tcg2_measure_efi_app_invocation(void)

> +{

> +	efi_status_t ret;

> +	u32 pcr_index;

> +	struct udevice *dev;

> +	u32 event = 0;

> +

> +	if (tcg2_efi_app_invoked)

> +		return EFI_SUCCESS;

> +

> +	ret = platform_get_tpm2_device(&dev);

> +	if (ret != EFI_SUCCESS)

> +		return ret;

> +

> +	ret = tcg2_measure_boot_variable(dev);

> +	if (ret != EFI_SUCCESS)

> +		goto out;

> +

> +	ret = tcg2_measure_event(dev, 4, EV_EFI_ACTION,

> +				 strlen(EFI_CALLING_EFI_APPLICATION),

> +				 (u8 *)EFI_CALLING_EFI_APPLICATION);

> +	if (ret != EFI_SUCCESS)

> +		goto out;

> +

> +	for (pcr_index = 0; pcr_index <= 7; pcr_index++) {

> +		ret = tcg2_measure_event(dev, pcr_index, EV_SEPARATOR,

> +					 sizeof(event), (u8 *)&event);

> +		if (ret != EFI_SUCCESS)

> +			goto out;

> +	}

> +

> +	tcg2_efi_app_invoked = true;

> +out:

> +	return ret;

> +}

> +

> +/**

> + * efi_tcg2_measure_efi_app_exit() - measure efi app exit

> + *

> + * Return:	status code

> + */

> +efi_status_t EFIAPI efi_tcg2_measure_efi_app_exit(void)

> +{

> +	efi_status_t ret;

> +	struct udevice *dev;

> +

> +	ret = platform_get_tpm2_device(&dev);

> +	if (ret != EFI_SUCCESS)

> +		return ret;

> +

> +	ret = tcg2_measure_event(dev, 4, EV_EFI_ACTION,

> +				 strlen(EFI_RETURNING_FROM_EFI_APPLICATION),

> +				 (u8 *)EFI_RETURNING_FROM_EFI_APPLICATION);

> +	return ret;

> +}

> +

>   /**

>    * tcg2_measure_secure_boot_variable() - measure secure boot variables

>    *

>
Masahisa Kojima July 9, 2021, 2:44 a.m. UTC | #4
On Fri, 9 Jul 2021 at 02:46, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
>

> On 7/7/21 3:36 PM, Masahisa Kojima wrote:

> > TCG PC Client PFP spec requires to measure "Boot####"

> > and "BootOrder" variables, EV_SEPARATOR event prior

> > to the Ready to Boot invocation.

> > Since u-boot does not implement Ready to Boot event,

> > these measurements are performed when efi_start_image() is called.

> >

> > TCG spec also requires to measure "Calling EFI Application from

> > Boot Option" for each boot attempt, and "Returning from EFI

> > Application from Boot Option" if a boot device returns control

> > back to the Boot Manager.

> >

> > Signed-off-by: Masahisa Kojima <masahisa.kojima@linaro.org>

> > ---

> >   include/efi_loader.h          |   4 ++

> >   include/tpm-v2.h              |  18 ++++-

> >   lib/efi_loader/efi_boottime.c |  20 ++++++

> >   lib/efi_loader/efi_tcg2.c     | 123 ++++++++++++++++++++++++++++++++++

> >   4 files changed, 164 insertions(+), 1 deletion(-)

> >

> > diff --git a/include/efi_loader.h b/include/efi_loader.h

> > index 0a9c82a257..281ffff30f 100644

> > --- a/include/efi_loader.h

> > +++ b/include/efi_loader.h

> > @@ -407,6 +407,10 @@ efi_status_t efi_run_image(void *source_buffer, efi_uintn_t source_size);

> >   efi_status_t efi_init_variables(void);

> >   /* Notify ExitBootServices() is called */

> >   void efi_variables_boot_exit_notify(void);

> > +/* Measure efi application invocation */

> > +efi_status_t EFIAPI efi_tcg2_measure_efi_app_invocation(void);

> > +/* Measure efi application exit */

> > +efi_status_t EFIAPI efi_tcg2_measure_efi_app_exit(void);

> >   /* Called by bootefi to initialize root node */

> >   efi_status_t efi_root_node_register(void);

> >   /* Called by bootefi to initialize runtime */

> > diff --git a/include/tpm-v2.h b/include/tpm-v2.h

> > index 3e48e35861..8a7b7f1874 100644

> > --- a/include/tpm-v2.h

> > +++ b/include/tpm-v2.h

> > @@ -73,7 +73,7 @@ struct udevice;

> >   /*

> >    * event types, cf.

> >    * "TCG PC Client Platform Firmware Profile Specification", Family "2.0"

> > - * rev 1.04, June 3, 2019

> > + * Level 00 Version 1.05 Revision 23, May 7, 2021

> >    */

> >   #define EV_EFI_EVENT_BASE                   ((u32)0x80000000)

> >   #define EV_EFI_VARIABLE_DRIVER_CONFIG               ((u32)0x80000001)

> > @@ -85,8 +85,24 @@ struct udevice;

> >   #define EV_EFI_ACTION                               ((u32)0x80000007)

> >   #define EV_EFI_PLATFORM_FIRMWARE_BLOB               ((u32)0x80000008)

> >   #define EV_EFI_HANDOFF_TABLES                       ((u32)0x80000009)

> > +#define EV_EFI_PLATFORM_FIRMWARE_BLOB2               ((u32)0x8000000A)

> > +#define EV_EFI_HANDOFF_TABLES2                       ((u32)0x8000000B)

> > +#define EV_EFI_VARIABLE_BOOT2                        ((u32)0x8000000C)

> >   #define EV_EFI_HCRTM_EVENT                  ((u32)0x80000010)

> >   #define EV_EFI_VARIABLE_AUTHORITY           ((u32)0x800000E0)

> > +#define EV_EFI_SPDM_FIRMWARE_BLOB            ((u32)0x800000E1)

> > +#define EV_EFI_SPDM_FIRMWARE_CONFIG          ((u32)0x800000E2)

> > +

> > +#define EFI_CALLING_EFI_APPLICATION         \

> > +     "Calling EFI Application from Boot Option"

> > +#define EFI_RETURNING_FROM_EFI_APPLICATION  \

> > +     "Returning from EFI Application from Boot Option"

> > +#define EFI_EXIT_BOOT_SERVICES_INVOCATION   \

> > +     "Exit Boot Services Invocation"

> > +#define EFI_EXIT_BOOT_SERVICES_FAILED       \

> > +     "Exit Boot Services Returned with Failure"

> > +#define EFI_EXIT_BOOT_SERVICES_SUCCEEDED    \

> > +     "Exit Boot Services Returned with Success"

>

> Which spec defines if the string in the event log shall be utf-8 or utf-16?


TCG PC Client PFP spec does not clearly define the character encoding.
In my understanding, the string derived from UEFI spec such as
UEFI variable name uses utf-16(CHAR16).
Other strings like "Calling EFI Application from Boot Option" defind in TCG PC
Client spec use 1 byte ASCII encoding.

EDK2 implementation also uses 1 byte ASCII encoding for these strings,
and tpm2-tools::tpm2_eventlog command can handles properly.

Thanks,
Masahisa Kojima

>

> Best regards

>

> Heinrich

>

> >

> >   /* TPMS_TAGGED_PROPERTY Structure */

> >   struct tpms_tagged_property {

> > diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c

> > index f6d5ba05e3..2914800c56 100644

> > --- a/lib/efi_loader/efi_boottime.c

> > +++ b/lib/efi_loader/efi_boottime.c

> > @@ -2993,6 +2993,16 @@ efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle,

> >       image_obj->exit_status = &exit_status;

> >       image_obj->exit_jmp = &exit_jmp;

> >

> > +     if (IS_ENABLED(CONFIG_EFI_TCG2_PROTOCOL)) {

> > +             if (image_obj->image_type == IMAGE_SUBSYSTEM_EFI_APPLICATION) {

> > +                     ret = efi_tcg2_measure_efi_app_invocation();

> > +                     if (ret != EFI_SUCCESS) {

> > +                             EFI_PRINT("tcg2 measurement fails(0x%lx)\n",

> > +                                       ret);

> > +                     }

> > +             }

> > +     }

> > +

> >       /* call the image! */

> >       if (setjmp(&exit_jmp)) {

> >               /*

> > @@ -3251,6 +3261,16 @@ static efi_status_t EFIAPI efi_exit(efi_handle_t image_handle,

> >           exit_status != EFI_SUCCESS)

> >               efi_delete_image(image_obj, loaded_image_protocol);

> >

> > +     if (IS_ENABLED(CONFIG_EFI_TCG2_PROTOCOL)) {

> > +             if (image_obj->image_type == IMAGE_SUBSYSTEM_EFI_APPLICATION) {

> > +                     ret = efi_tcg2_measure_efi_app_exit();

> > +                     if (ret != EFI_SUCCESS) {

> > +                             EFI_PRINT("tcg2 measurement fails(0x%lx)\n",

> > +                                       ret);

> > +                     }

> > +             }

> > +     }

> > +

> >       /* Make sure entry/exit counts for EFI world cross-overs match */

> >       EFI_EXIT(exit_status);

> >

> > diff --git a/lib/efi_loader/efi_tcg2.c b/lib/efi_loader/efi_tcg2.c

> > index 2a248bd62a..6e903e3cb3 100644

> > --- a/lib/efi_loader/efi_tcg2.c

> > +++ b/lib/efi_loader/efi_tcg2.c

> > @@ -35,6 +35,7 @@ struct event_log_buffer {

> >   };

> >

> >   static struct event_log_buffer event_log;

> > +static bool tcg2_efi_app_invoked;

> >   /*

> >    * When requesting TPM2_CAP_TPM_PROPERTIES the value is on a standard offset.

> >    * Since the current tpm2_get_capability() response buffers starts at

> > @@ -1383,6 +1384,128 @@ static efi_status_t tcg2_measure_variable(struct udevice *dev, u32 pcr_index,

> >       return ret;

> >   }

> >

> > +/**

> > + * tcg2_measure_boot_variable() - measure boot variables

> > + *

> > + * @dev:     TPM device

> > + *

> > + * Return:   status code

> > + */

> > +static efi_status_t tcg2_measure_boot_variable(struct udevice *dev)

> > +{

> > +     u16 *boot_order;

> > +     u16 var_name[] = L"BootOrder";

> > +     u16 boot_name[] = L"Boot0000";

> > +     u16 hexmap[] = L"0123456789ABCDEF";

> > +     u8 *bootvar;

> > +     efi_uintn_t var_data_size;

> > +     u32 count, i;

> > +     efi_status_t ret;

> > +

> > +     boot_order = efi_get_var(var_name, &efi_global_variable_guid,

> > +                              &var_data_size);

> > +     if (!boot_order) {

> > +             log_info("BootOrder not defined\n");

> > +             ret = EFI_NOT_FOUND;

> > +             goto error;

> > +     }

> > +

> > +     ret = tcg2_measure_variable(dev, 1, EV_EFI_VARIABLE_BOOT2, var_name,

> > +                                 &efi_global_variable_guid, var_data_size,

> > +                                 (u8 *)boot_order);

> > +     if (ret != EFI_SUCCESS)

> > +             goto error;

> > +

> > +     count = var_data_size / sizeof(*boot_order);

> > +     for (i = 0; i < count; i++) {

> > +             boot_name[4] = hexmap[(boot_order[i] & 0xf000) >> 12];

> > +             boot_name[5] = hexmap[(boot_order[i] & 0x0f00) >> 8];

> > +             boot_name[6] = hexmap[(boot_order[i] & 0x00f0) >> 4];

> > +             boot_name[7] = hexmap[(boot_order[i] & 0x000f)];

> > +

> > +             bootvar = efi_get_var(boot_name, &efi_global_variable_guid,

> > +                                   &var_data_size);

> > +

> > +             if (!bootvar) {

> > +                     log_info("%ls not found\n", boot_name);

> > +                     continue;

> > +             }

> > +

> > +             ret = tcg2_measure_variable(dev, 1, EV_EFI_VARIABLE_BOOT2,

> > +                                         boot_name,

> > +                                         &efi_global_variable_guid,

> > +                                         var_data_size, bootvar);

> > +             free(bootvar);

> > +             if (ret != EFI_SUCCESS)

> > +                     goto error;

> > +     }

> > +

> > +error:

> > +     free(boot_order);

> > +     return ret;

> > +}

> > +

> > +/**

> > + * efi_tcg2_measure_efi_app_invocation() - measure efi app invocation

> > + *

> > + * Return:   status code

> > + */

> > +efi_status_t EFIAPI efi_tcg2_measure_efi_app_invocation(void)

> > +{

> > +     efi_status_t ret;

> > +     u32 pcr_index;

> > +     struct udevice *dev;

> > +     u32 event = 0;

> > +

> > +     if (tcg2_efi_app_invoked)

> > +             return EFI_SUCCESS;

> > +

> > +     ret = platform_get_tpm2_device(&dev);

> > +     if (ret != EFI_SUCCESS)

> > +             return ret;

> > +

> > +     ret = tcg2_measure_boot_variable(dev);

> > +     if (ret != EFI_SUCCESS)

> > +             goto out;

> > +

> > +     ret = tcg2_measure_event(dev, 4, EV_EFI_ACTION,

> > +                              strlen(EFI_CALLING_EFI_APPLICATION),

> > +                              (u8 *)EFI_CALLING_EFI_APPLICATION);

> > +     if (ret != EFI_SUCCESS)

> > +             goto out;

> > +

> > +     for (pcr_index = 0; pcr_index <= 7; pcr_index++) {

> > +             ret = tcg2_measure_event(dev, pcr_index, EV_SEPARATOR,

> > +                                      sizeof(event), (u8 *)&event);

> > +             if (ret != EFI_SUCCESS)

> > +                     goto out;

> > +     }

> > +

> > +     tcg2_efi_app_invoked = true;

> > +out:

> > +     return ret;

> > +}

> > +

> > +/**

> > + * efi_tcg2_measure_efi_app_exit() - measure efi app exit

> > + *

> > + * Return:   status code

> > + */

> > +efi_status_t EFIAPI efi_tcg2_measure_efi_app_exit(void)

> > +{

> > +     efi_status_t ret;

> > +     struct udevice *dev;

> > +

> > +     ret = platform_get_tpm2_device(&dev);

> > +     if (ret != EFI_SUCCESS)

> > +             return ret;

> > +

> > +     ret = tcg2_measure_event(dev, 4, EV_EFI_ACTION,

> > +                              strlen(EFI_RETURNING_FROM_EFI_APPLICATION),

> > +                              (u8 *)EFI_RETURNING_FROM_EFI_APPLICATION);

> > +     return ret;

> > +}

> > +

> >   /**

> >    * tcg2_measure_secure_boot_variable() - measure secure boot variables

> >    *

> >

>
Masahisa Kojima July 13, 2021, 8:31 a.m. UTC | #5
Hi Heinrich,

> > > TCG spec also requires to measure "Calling EFI Application from

> > > Boot Option" for each boot attempt, and "Returning from EFI

> > > Application from Boot Option" if a boot device returns control

> > > back to the Boot Manager.


I would like to hear your opinion regarding
"Calling EFI Application from Boot Option" measurement.

My current(v1 patch series) implementation considers
both "bootefi bootmgr" and "bootefi $image_addr" cases,
so I do this "Calling EFI Application from Boot Option" measurement
at efi_boottime.c::efi_start_image().
Do I need to implement only the case UEFI application boot from bootmgr?
If yes, I will move the timing of this measurement at
efi_bootmgr.c::efi_bootmgr_load().

As a reference, in edk2, this measurement is performed in
ready_to_boot event handler, ready_to_boot handler is called
upon the user selects the boot option in boot manager.

What do you think?

Thanks,
Masahisa Kojima





On Fri, 9 Jul 2021 at 11:44, Masahisa Kojima <masahisa.kojima@linaro.org> wrote:
>

> On Fri, 9 Jul 2021 at 02:46, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:

> >

> > On 7/7/21 3:36 PM, Masahisa Kojima wrote:

> > > TCG PC Client PFP spec requires to measure "Boot####"

> > > and "BootOrder" variables, EV_SEPARATOR event prior

> > > to the Ready to Boot invocation.

> > > Since u-boot does not implement Ready to Boot event,

> > > these measurements are performed when efi_start_image() is called.

> > >

> > > TCG spec also requires to measure "Calling EFI Application from

> > > Boot Option" for each boot attempt, and "Returning from EFI

> > > Application from Boot Option" if a boot device returns control

> > > back to the Boot Manager.

> > >

> > > Signed-off-by: Masahisa Kojima <masahisa.kojima@linaro.org>

> > > ---

> > >   include/efi_loader.h          |   4 ++

> > >   include/tpm-v2.h              |  18 ++++-

> > >   lib/efi_loader/efi_boottime.c |  20 ++++++

> > >   lib/efi_loader/efi_tcg2.c     | 123 ++++++++++++++++++++++++++++++++++

> > >   4 files changed, 164 insertions(+), 1 deletion(-)

> > >

> > > diff --git a/include/efi_loader.h b/include/efi_loader.h

> > > index 0a9c82a257..281ffff30f 100644

> > > --- a/include/efi_loader.h

> > > +++ b/include/efi_loader.h

> > > @@ -407,6 +407,10 @@ efi_status_t efi_run_image(void *source_buffer, efi_uintn_t source_size);

> > >   efi_status_t efi_init_variables(void);

> > >   /* Notify ExitBootServices() is called */

> > >   void efi_variables_boot_exit_notify(void);

> > > +/* Measure efi application invocation */

> > > +efi_status_t EFIAPI efi_tcg2_measure_efi_app_invocation(void);

> > > +/* Measure efi application exit */

> > > +efi_status_t EFIAPI efi_tcg2_measure_efi_app_exit(void);

> > >   /* Called by bootefi to initialize root node */

> > >   efi_status_t efi_root_node_register(void);

> > >   /* Called by bootefi to initialize runtime */

> > > diff --git a/include/tpm-v2.h b/include/tpm-v2.h

> > > index 3e48e35861..8a7b7f1874 100644

> > > --- a/include/tpm-v2.h

> > > +++ b/include/tpm-v2.h

> > > @@ -73,7 +73,7 @@ struct udevice;

> > >   /*

> > >    * event types, cf.

> > >    * "TCG PC Client Platform Firmware Profile Specification", Family "2.0"

> > > - * rev 1.04, June 3, 2019

> > > + * Level 00 Version 1.05 Revision 23, May 7, 2021

> > >    */

> > >   #define EV_EFI_EVENT_BASE                   ((u32)0x80000000)

> > >   #define EV_EFI_VARIABLE_DRIVER_CONFIG               ((u32)0x80000001)

> > > @@ -85,8 +85,24 @@ struct udevice;

> > >   #define EV_EFI_ACTION                               ((u32)0x80000007)

> > >   #define EV_EFI_PLATFORM_FIRMWARE_BLOB               ((u32)0x80000008)

> > >   #define EV_EFI_HANDOFF_TABLES                       ((u32)0x80000009)

> > > +#define EV_EFI_PLATFORM_FIRMWARE_BLOB2               ((u32)0x8000000A)

> > > +#define EV_EFI_HANDOFF_TABLES2                       ((u32)0x8000000B)

> > > +#define EV_EFI_VARIABLE_BOOT2                        ((u32)0x8000000C)

> > >   #define EV_EFI_HCRTM_EVENT                  ((u32)0x80000010)

> > >   #define EV_EFI_VARIABLE_AUTHORITY           ((u32)0x800000E0)

> > > +#define EV_EFI_SPDM_FIRMWARE_BLOB            ((u32)0x800000E1)

> > > +#define EV_EFI_SPDM_FIRMWARE_CONFIG          ((u32)0x800000E2)

> > > +

> > > +#define EFI_CALLING_EFI_APPLICATION         \

> > > +     "Calling EFI Application from Boot Option"

> > > +#define EFI_RETURNING_FROM_EFI_APPLICATION  \

> > > +     "Returning from EFI Application from Boot Option"

> > > +#define EFI_EXIT_BOOT_SERVICES_INVOCATION   \

> > > +     "Exit Boot Services Invocation"

> > > +#define EFI_EXIT_BOOT_SERVICES_FAILED       \

> > > +     "Exit Boot Services Returned with Failure"

> > > +#define EFI_EXIT_BOOT_SERVICES_SUCCEEDED    \

> > > +     "Exit Boot Services Returned with Success"

> >

> > Which spec defines if the string in the event log shall be utf-8 or utf-16?

>

> TCG PC Client PFP spec does not clearly define the character encoding.

> In my understanding, the string derived from UEFI spec such as

> UEFI variable name uses utf-16(CHAR16).

> Other strings like "Calling EFI Application from Boot Option" defind in TCG PC

> Client spec use 1 byte ASCII encoding.

>

> EDK2 implementation also uses 1 byte ASCII encoding for these strings,

> and tpm2-tools::tpm2_eventlog command can handles properly.

>

> Thanks,

> Masahisa Kojima

>

> >

> > Best regards

> >

> > Heinrich

> >

> > >

> > >   /* TPMS_TAGGED_PROPERTY Structure */

> > >   struct tpms_tagged_property {

> > > diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c

> > > index f6d5ba05e3..2914800c56 100644

> > > --- a/lib/efi_loader/efi_boottime.c

> > > +++ b/lib/efi_loader/efi_boottime.c

> > > @@ -2993,6 +2993,16 @@ efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle,

> > >       image_obj->exit_status = &exit_status;

> > >       image_obj->exit_jmp = &exit_jmp;

> > >

> > > +     if (IS_ENABLED(CONFIG_EFI_TCG2_PROTOCOL)) {

> > > +             if (image_obj->image_type == IMAGE_SUBSYSTEM_EFI_APPLICATION) {

> > > +                     ret = efi_tcg2_measure_efi_app_invocation();

> > > +                     if (ret != EFI_SUCCESS) {

> > > +                             EFI_PRINT("tcg2 measurement fails(0x%lx)\n",

> > > +                                       ret);

> > > +                     }

> > > +             }

> > > +     }

> > > +

> > >       /* call the image! */

> > >       if (setjmp(&exit_jmp)) {

> > >               /*

> > > @@ -3251,6 +3261,16 @@ static efi_status_t EFIAPI efi_exit(efi_handle_t image_handle,

> > >           exit_status != EFI_SUCCESS)

> > >               efi_delete_image(image_obj, loaded_image_protocol);

> > >

> > > +     if (IS_ENABLED(CONFIG_EFI_TCG2_PROTOCOL)) {

> > > +             if (image_obj->image_type == IMAGE_SUBSYSTEM_EFI_APPLICATION) {

> > > +                     ret = efi_tcg2_measure_efi_app_exit();

> > > +                     if (ret != EFI_SUCCESS) {

> > > +                             EFI_PRINT("tcg2 measurement fails(0x%lx)\n",

> > > +                                       ret);

> > > +                     }

> > > +             }

> > > +     }

> > > +

> > >       /* Make sure entry/exit counts for EFI world cross-overs match */

> > >       EFI_EXIT(exit_status);

> > >

> > > diff --git a/lib/efi_loader/efi_tcg2.c b/lib/efi_loader/efi_tcg2.c

> > > index 2a248bd62a..6e903e3cb3 100644

> > > --- a/lib/efi_loader/efi_tcg2.c

> > > +++ b/lib/efi_loader/efi_tcg2.c

> > > @@ -35,6 +35,7 @@ struct event_log_buffer {

> > >   };

> > >

> > >   static struct event_log_buffer event_log;

> > > +static bool tcg2_efi_app_invoked;

> > >   /*

> > >    * When requesting TPM2_CAP_TPM_PROPERTIES the value is on a standard offset.

> > >    * Since the current tpm2_get_capability() response buffers starts at

> > > @@ -1383,6 +1384,128 @@ static efi_status_t tcg2_measure_variable(struct udevice *dev, u32 pcr_index,

> > >       return ret;

> > >   }

> > >

> > > +/**

> > > + * tcg2_measure_boot_variable() - measure boot variables

> > > + *

> > > + * @dev:     TPM device

> > > + *

> > > + * Return:   status code

> > > + */

> > > +static efi_status_t tcg2_measure_boot_variable(struct udevice *dev)

> > > +{

> > > +     u16 *boot_order;

> > > +     u16 var_name[] = L"BootOrder";

> > > +     u16 boot_name[] = L"Boot0000";

> > > +     u16 hexmap[] = L"0123456789ABCDEF";

> > > +     u8 *bootvar;

> > > +     efi_uintn_t var_data_size;

> > > +     u32 count, i;

> > > +     efi_status_t ret;

> > > +

> > > +     boot_order = efi_get_var(var_name, &efi_global_variable_guid,

> > > +                              &var_data_size);

> > > +     if (!boot_order) {

> > > +             log_info("BootOrder not defined\n");

> > > +             ret = EFI_NOT_FOUND;

> > > +             goto error;

> > > +     }

> > > +

> > > +     ret = tcg2_measure_variable(dev, 1, EV_EFI_VARIABLE_BOOT2, var_name,

> > > +                                 &efi_global_variable_guid, var_data_size,

> > > +                                 (u8 *)boot_order);

> > > +     if (ret != EFI_SUCCESS)

> > > +             goto error;

> > > +

> > > +     count = var_data_size / sizeof(*boot_order);

> > > +     for (i = 0; i < count; i++) {

> > > +             boot_name[4] = hexmap[(boot_order[i] & 0xf000) >> 12];

> > > +             boot_name[5] = hexmap[(boot_order[i] & 0x0f00) >> 8];

> > > +             boot_name[6] = hexmap[(boot_order[i] & 0x00f0) >> 4];

> > > +             boot_name[7] = hexmap[(boot_order[i] & 0x000f)];

> > > +

> > > +             bootvar = efi_get_var(boot_name, &efi_global_variable_guid,

> > > +                                   &var_data_size);

> > > +

> > > +             if (!bootvar) {

> > > +                     log_info("%ls not found\n", boot_name);

> > > +                     continue;

> > > +             }

> > > +

> > > +             ret = tcg2_measure_variable(dev, 1, EV_EFI_VARIABLE_BOOT2,

> > > +                                         boot_name,

> > > +                                         &efi_global_variable_guid,

> > > +                                         var_data_size, bootvar);

> > > +             free(bootvar);

> > > +             if (ret != EFI_SUCCESS)

> > > +                     goto error;

> > > +     }

> > > +

> > > +error:

> > > +     free(boot_order);

> > > +     return ret;

> > > +}

> > > +

> > > +/**

> > > + * efi_tcg2_measure_efi_app_invocation() - measure efi app invocation

> > > + *

> > > + * Return:   status code

> > > + */

> > > +efi_status_t EFIAPI efi_tcg2_measure_efi_app_invocation(void)

> > > +{

> > > +     efi_status_t ret;

> > > +     u32 pcr_index;

> > > +     struct udevice *dev;

> > > +     u32 event = 0;

> > > +

> > > +     if (tcg2_efi_app_invoked)

> > > +             return EFI_SUCCESS;

> > > +

> > > +     ret = platform_get_tpm2_device(&dev);

> > > +     if (ret != EFI_SUCCESS)

> > > +             return ret;

> > > +

> > > +     ret = tcg2_measure_boot_variable(dev);

> > > +     if (ret != EFI_SUCCESS)

> > > +             goto out;

> > > +

> > > +     ret = tcg2_measure_event(dev, 4, EV_EFI_ACTION,

> > > +                              strlen(EFI_CALLING_EFI_APPLICATION),

> > > +                              (u8 *)EFI_CALLING_EFI_APPLICATION);

> > > +     if (ret != EFI_SUCCESS)

> > > +             goto out;

> > > +

> > > +     for (pcr_index = 0; pcr_index <= 7; pcr_index++) {

> > > +             ret = tcg2_measure_event(dev, pcr_index, EV_SEPARATOR,

> > > +                                      sizeof(event), (u8 *)&event);

> > > +             if (ret != EFI_SUCCESS)

> > > +                     goto out;

> > > +     }

> > > +

> > > +     tcg2_efi_app_invoked = true;

> > > +out:

> > > +     return ret;

> > > +}

> > > +

> > > +/**

> > > + * efi_tcg2_measure_efi_app_exit() - measure efi app exit

> > > + *

> > > + * Return:   status code

> > > + */

> > > +efi_status_t EFIAPI efi_tcg2_measure_efi_app_exit(void)

> > > +{

> > > +     efi_status_t ret;

> > > +     struct udevice *dev;

> > > +

> > > +     ret = platform_get_tpm2_device(&dev);

> > > +     if (ret != EFI_SUCCESS)

> > > +             return ret;

> > > +

> > > +     ret = tcg2_measure_event(dev, 4, EV_EFI_ACTION,

> > > +                              strlen(EFI_RETURNING_FROM_EFI_APPLICATION),

> > > +                              (u8 *)EFI_RETURNING_FROM_EFI_APPLICATION);

> > > +     return ret;

> > > +}

> > > +

> > >   /**

> > >    * tcg2_measure_secure_boot_variable() - measure secure boot variables

> > >    *

> > >

> >
Heinrich Schuchardt July 13, 2021, 2:24 p.m. UTC | #6
On 13.07.21 10:31, Masahisa Kojima wrote:
> Hi Heinrich,

>

>>>> TCG spec also requires to measure "Calling EFI Application from

>>>> Boot Option" for each boot attempt, and "Returning from EFI

>>>> Application from Boot Option" if a boot device returns control

>>>> back to the Boot Manager.

>

> I would like to hear your opinion regarding

> "Calling EFI Application from Boot Option" measurement.

>

> My current(v1 patch series) implementation considers

> both "bootefi bootmgr" and "bootefi $image_addr" cases,

> so I do this "Calling EFI Application from Boot Option" measurement

> at efi_boottime.c::efi_start_image().

> Do I need to implement only the case UEFI application boot from bootmgr?

> If yes, I will move the timing of this measurement at

> efi_bootmgr.c::efi_bootmgr_load().

>

> As a reference, in edk2, this measurement is performed in

> ready_to_boot event handler, ready_to_boot handler is called

> upon the user selects the boot option in boot manager.


When booting you can call

    bootefi $driver1
    booefii $driver2
    bootefi bootmgr

in sequence.

Any of the binaries can call LoadImage(), StartImage() multiple times to
execute further images. E.g. I am loading iPXE. By default it loads GRUB
from an iSCSI drive but I can choose in the menu or the iPXE console to
invoke another UEFI binary.

I suggest to measure any image no matter how it is invoked. The
measurement must depend on the sequence of invocation.

Best regards

Heinrich

>

> What do you think?

>

> Thanks,

> Masahisa Kojima

>

>

>

>

>

> On Fri, 9 Jul 2021 at 11:44, Masahisa Kojima <masahisa.kojima@linaro.org> wrote:

>>

>> On Fri, 9 Jul 2021 at 02:46, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:

>>>

>>> On 7/7/21 3:36 PM, Masahisa Kojima wrote:

>>>> TCG PC Client PFP spec requires to measure "Boot####"

>>>> and "BootOrder" variables, EV_SEPARATOR event prior

>>>> to the Ready to Boot invocation.

>>>> Since u-boot does not implement Ready to Boot event,

>>>> these measurements are performed when efi_start_image() is called.

>>>>

>>>> TCG spec also requires to measure "Calling EFI Application from

>>>> Boot Option" for each boot attempt, and "Returning from EFI

>>>> Application from Boot Option" if a boot device returns control

>>>> back to the Boot Manager.

>>>>

>>>> Signed-off-by: Masahisa Kojima <masahisa.kojima@linaro.org>

>>>> ---

>>>>    include/efi_loader.h          |   4 ++

>>>>    include/tpm-v2.h              |  18 ++++-

>>>>    lib/efi_loader/efi_boottime.c |  20 ++++++

>>>>    lib/efi_loader/efi_tcg2.c     | 123 ++++++++++++++++++++++++++++++++++

>>>>    4 files changed, 164 insertions(+), 1 deletion(-)

>>>>

>>>> diff --git a/include/efi_loader.h b/include/efi_loader.h

>>>> index 0a9c82a257..281ffff30f 100644

>>>> --- a/include/efi_loader.h

>>>> +++ b/include/efi_loader.h

>>>> @@ -407,6 +407,10 @@ efi_status_t efi_run_image(void *source_buffer, efi_uintn_t source_size);

>>>>    efi_status_t efi_init_variables(void);

>>>>    /* Notify ExitBootServices() is called */

>>>>    void efi_variables_boot_exit_notify(void);

>>>> +/* Measure efi application invocation */

>>>> +efi_status_t EFIAPI efi_tcg2_measure_efi_app_invocation(void);

>>>> +/* Measure efi application exit */

>>>> +efi_status_t EFIAPI efi_tcg2_measure_efi_app_exit(void);

>>>>    /* Called by bootefi to initialize root node */

>>>>    efi_status_t efi_root_node_register(void);

>>>>    /* Called by bootefi to initialize runtime */

>>>> diff --git a/include/tpm-v2.h b/include/tpm-v2.h

>>>> index 3e48e35861..8a7b7f1874 100644

>>>> --- a/include/tpm-v2.h

>>>> +++ b/include/tpm-v2.h

>>>> @@ -73,7 +73,7 @@ struct udevice;

>>>>    /*

>>>>     * event types, cf.

>>>>     * "TCG PC Client Platform Firmware Profile Specification", Family "2.0"

>>>> - * rev 1.04, June 3, 2019

>>>> + * Level 00 Version 1.05 Revision 23, May 7, 2021

>>>>     */

>>>>    #define EV_EFI_EVENT_BASE                   ((u32)0x80000000)

>>>>    #define EV_EFI_VARIABLE_DRIVER_CONFIG               ((u32)0x80000001)

>>>> @@ -85,8 +85,24 @@ struct udevice;

>>>>    #define EV_EFI_ACTION                               ((u32)0x80000007)

>>>>    #define EV_EFI_PLATFORM_FIRMWARE_BLOB               ((u32)0x80000008)

>>>>    #define EV_EFI_HANDOFF_TABLES                       ((u32)0x80000009)

>>>> +#define EV_EFI_PLATFORM_FIRMWARE_BLOB2               ((u32)0x8000000A)

>>>> +#define EV_EFI_HANDOFF_TABLES2                       ((u32)0x8000000B)

>>>> +#define EV_EFI_VARIABLE_BOOT2                        ((u32)0x8000000C)

>>>>    #define EV_EFI_HCRTM_EVENT                  ((u32)0x80000010)

>>>>    #define EV_EFI_VARIABLE_AUTHORITY           ((u32)0x800000E0)

>>>> +#define EV_EFI_SPDM_FIRMWARE_BLOB            ((u32)0x800000E1)

>>>> +#define EV_EFI_SPDM_FIRMWARE_CONFIG          ((u32)0x800000E2)

>>>> +

>>>> +#define EFI_CALLING_EFI_APPLICATION         \

>>>> +     "Calling EFI Application from Boot Option"

>>>> +#define EFI_RETURNING_FROM_EFI_APPLICATION  \

>>>> +     "Returning from EFI Application from Boot Option"

>>>> +#define EFI_EXIT_BOOT_SERVICES_INVOCATION   \

>>>> +     "Exit Boot Services Invocation"

>>>> +#define EFI_EXIT_BOOT_SERVICES_FAILED       \

>>>> +     "Exit Boot Services Returned with Failure"

>>>> +#define EFI_EXIT_BOOT_SERVICES_SUCCEEDED    \

>>>> +     "Exit Boot Services Returned with Success"

>>>

>>> Which spec defines if the string in the event log shall be utf-8 or utf-16?

>>

>> TCG PC Client PFP spec does not clearly define the character encoding.

>> In my understanding, the string derived from UEFI spec such as

>> UEFI variable name uses utf-16(CHAR16).

>> Other strings like "Calling EFI Application from Boot Option" defind in TCG PC

>> Client spec use 1 byte ASCII encoding.

>>

>> EDK2 implementation also uses 1 byte ASCII encoding for these strings,

>> and tpm2-tools::tpm2_eventlog command can handles properly.

>>

>> Thanks,

>> Masahisa Kojima

>>

>>>

>>> Best regards

>>>

>>> Heinrich

>>>

>>>>

>>>>    /* TPMS_TAGGED_PROPERTY Structure */

>>>>    struct tpms_tagged_property {

>>>> diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c

>>>> index f6d5ba05e3..2914800c56 100644

>>>> --- a/lib/efi_loader/efi_boottime.c

>>>> +++ b/lib/efi_loader/efi_boottime.c

>>>> @@ -2993,6 +2993,16 @@ efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle,

>>>>        image_obj->exit_status = &exit_status;

>>>>        image_obj->exit_jmp = &exit_jmp;

>>>>

>>>> +     if (IS_ENABLED(CONFIG_EFI_TCG2_PROTOCOL)) {

>>>> +             if (image_obj->image_type == IMAGE_SUBSYSTEM_EFI_APPLICATION) {

>>>> +                     ret = efi_tcg2_measure_efi_app_invocation();

>>>> +                     if (ret != EFI_SUCCESS) {

>>>> +                             EFI_PRINT("tcg2 measurement fails(0x%lx)\n",

>>>> +                                       ret);

>>>> +                     }

>>>> +             }

>>>> +     }

>>>> +

>>>>        /* call the image! */

>>>>        if (setjmp(&exit_jmp)) {

>>>>                /*

>>>> @@ -3251,6 +3261,16 @@ static efi_status_t EFIAPI efi_exit(efi_handle_t image_handle,

>>>>            exit_status != EFI_SUCCESS)

>>>>                efi_delete_image(image_obj, loaded_image_protocol);

>>>>

>>>> +     if (IS_ENABLED(CONFIG_EFI_TCG2_PROTOCOL)) {

>>>> +             if (image_obj->image_type == IMAGE_SUBSYSTEM_EFI_APPLICATION) {

>>>> +                     ret = efi_tcg2_measure_efi_app_exit();

>>>> +                     if (ret != EFI_SUCCESS) {

>>>> +                             EFI_PRINT("tcg2 measurement fails(0x%lx)\n",

>>>> +                                       ret);

>>>> +                     }

>>>> +             }

>>>> +     }

>>>> +

>>>>        /* Make sure entry/exit counts for EFI world cross-overs match */

>>>>        EFI_EXIT(exit_status);

>>>>

>>>> diff --git a/lib/efi_loader/efi_tcg2.c b/lib/efi_loader/efi_tcg2.c

>>>> index 2a248bd62a..6e903e3cb3 100644

>>>> --- a/lib/efi_loader/efi_tcg2.c

>>>> +++ b/lib/efi_loader/efi_tcg2.c

>>>> @@ -35,6 +35,7 @@ struct event_log_buffer {

>>>>    };

>>>>

>>>>    static struct event_log_buffer event_log;

>>>> +static bool tcg2_efi_app_invoked;

>>>>    /*

>>>>     * When requesting TPM2_CAP_TPM_PROPERTIES the value is on a standard offset.

>>>>     * Since the current tpm2_get_capability() response buffers starts at

>>>> @@ -1383,6 +1384,128 @@ static efi_status_t tcg2_measure_variable(struct udevice *dev, u32 pcr_index,

>>>>        return ret;

>>>>    }

>>>>

>>>> +/**

>>>> + * tcg2_measure_boot_variable() - measure boot variables

>>>> + *

>>>> + * @dev:     TPM device

>>>> + *

>>>> + * Return:   status code

>>>> + */

>>>> +static efi_status_t tcg2_measure_boot_variable(struct udevice *dev)

>>>> +{

>>>> +     u16 *boot_order;

>>>> +     u16 var_name[] = L"BootOrder";

>>>> +     u16 boot_name[] = L"Boot0000";

>>>> +     u16 hexmap[] = L"0123456789ABCDEF";

>>>> +     u8 *bootvar;

>>>> +     efi_uintn_t var_data_size;

>>>> +     u32 count, i;

>>>> +     efi_status_t ret;

>>>> +

>>>> +     boot_order = efi_get_var(var_name, &efi_global_variable_guid,

>>>> +                              &var_data_size);

>>>> +     if (!boot_order) {

>>>> +             log_info("BootOrder not defined\n");

>>>> +             ret = EFI_NOT_FOUND;

>>>> +             goto error;

>>>> +     }

>>>> +

>>>> +     ret = tcg2_measure_variable(dev, 1, EV_EFI_VARIABLE_BOOT2, var_name,

>>>> +                                 &efi_global_variable_guid, var_data_size,

>>>> +                                 (u8 *)boot_order);

>>>> +     if (ret != EFI_SUCCESS)

>>>> +             goto error;

>>>> +

>>>> +     count = var_data_size / sizeof(*boot_order);

>>>> +     for (i = 0; i < count; i++) {

>>>> +             boot_name[4] = hexmap[(boot_order[i] & 0xf000) >> 12];

>>>> +             boot_name[5] = hexmap[(boot_order[i] & 0x0f00) >> 8];

>>>> +             boot_name[6] = hexmap[(boot_order[i] & 0x00f0) >> 4];

>>>> +             boot_name[7] = hexmap[(boot_order[i] & 0x000f)];

>>>> +

>>>> +             bootvar = efi_get_var(boot_name, &efi_global_variable_guid,

>>>> +                                   &var_data_size);

>>>> +

>>>> +             if (!bootvar) {

>>>> +                     log_info("%ls not found\n", boot_name);

>>>> +                     continue;

>>>> +             }

>>>> +

>>>> +             ret = tcg2_measure_variable(dev, 1, EV_EFI_VARIABLE_BOOT2,

>>>> +                                         boot_name,

>>>> +                                         &efi_global_variable_guid,

>>>> +                                         var_data_size, bootvar);

>>>> +             free(bootvar);

>>>> +             if (ret != EFI_SUCCESS)

>>>> +                     goto error;

>>>> +     }

>>>> +

>>>> +error:

>>>> +     free(boot_order);

>>>> +     return ret;

>>>> +}

>>>> +

>>>> +/**

>>>> + * efi_tcg2_measure_efi_app_invocation() - measure efi app invocation

>>>> + *

>>>> + * Return:   status code

>>>> + */

>>>> +efi_status_t EFIAPI efi_tcg2_measure_efi_app_invocation(void)

>>>> +{

>>>> +     efi_status_t ret;

>>>> +     u32 pcr_index;

>>>> +     struct udevice *dev;

>>>> +     u32 event = 0;

>>>> +

>>>> +     if (tcg2_efi_app_invoked)

>>>> +             return EFI_SUCCESS;

>>>> +

>>>> +     ret = platform_get_tpm2_device(&dev);

>>>> +     if (ret != EFI_SUCCESS)

>>>> +             return ret;

>>>> +

>>>> +     ret = tcg2_measure_boot_variable(dev);

>>>> +     if (ret != EFI_SUCCESS)

>>>> +             goto out;

>>>> +

>>>> +     ret = tcg2_measure_event(dev, 4, EV_EFI_ACTION,

>>>> +                              strlen(EFI_CALLING_EFI_APPLICATION),

>>>> +                              (u8 *)EFI_CALLING_EFI_APPLICATION);

>>>> +     if (ret != EFI_SUCCESS)

>>>> +             goto out;

>>>> +

>>>> +     for (pcr_index = 0; pcr_index <= 7; pcr_index++) {

>>>> +             ret = tcg2_measure_event(dev, pcr_index, EV_SEPARATOR,

>>>> +                                      sizeof(event), (u8 *)&event);

>>>> +             if (ret != EFI_SUCCESS)

>>>> +                     goto out;

>>>> +     }

>>>> +

>>>> +     tcg2_efi_app_invoked = true;

>>>> +out:

>>>> +     return ret;

>>>> +}

>>>> +

>>>> +/**

>>>> + * efi_tcg2_measure_efi_app_exit() - measure efi app exit

>>>> + *

>>>> + * Return:   status code

>>>> + */

>>>> +efi_status_t EFIAPI efi_tcg2_measure_efi_app_exit(void)

>>>> +{

>>>> +     efi_status_t ret;

>>>> +     struct udevice *dev;

>>>> +

>>>> +     ret = platform_get_tpm2_device(&dev);

>>>> +     if (ret != EFI_SUCCESS)

>>>> +             return ret;

>>>> +

>>>> +     ret = tcg2_measure_event(dev, 4, EV_EFI_ACTION,

>>>> +                              strlen(EFI_RETURNING_FROM_EFI_APPLICATION),

>>>> +                              (u8 *)EFI_RETURNING_FROM_EFI_APPLICATION);

>>>> +     return ret;

>>>> +}

>>>> +

>>>>    /**

>>>>     * tcg2_measure_secure_boot_variable() - measure secure boot variables

>>>>     *

>>>>

>>>
AKASHI Takahiro July 13, 2021, 11:54 p.m. UTC | #7
On Tue, Jul 13, 2021 at 04:24:52PM +0200, Heinrich Schuchardt wrote:
> 

> 

> On 13.07.21 10:31, Masahisa Kojima wrote:

> > Hi Heinrich,

> > 

> > > > > TCG spec also requires to measure "Calling EFI Application from

> > > > > Boot Option" for each boot attempt, and "Returning from EFI

> > > > > Application from Boot Option" if a boot device returns control

> > > > > back to the Boot Manager.

> > 

> > I would like to hear your opinion regarding

> > "Calling EFI Application from Boot Option" measurement.

> > 

> > My current(v1 patch series) implementation considers

> > both "bootefi bootmgr" and "bootefi $image_addr" cases,

> > so I do this "Calling EFI Application from Boot Option" measurement

> > at efi_boottime.c::efi_start_image().

> > Do I need to implement only the case UEFI application boot from bootmgr?

> > If yes, I will move the timing of this measurement at

> > efi_bootmgr.c::efi_bootmgr_load().

> > 

> > As a reference, in edk2, this measurement is performed in

> > ready_to_boot event handler, ready_to_boot handler is called

> > upon the user selects the boot option in boot manager.

> 

> When booting you can call

> 

>    bootefi $driver1

>    booefii $driver2

>    bootefi bootmgr

> 

> in sequence.

> 

> Any of the binaries can call LoadImage(), StartImage() multiple times to

> execute further images. E.g. I am loading iPXE. By default it loads GRUB

> from an iSCSI drive but I can choose in the menu or the iPXE console to

> invoke another UEFI binary.

> 

> I suggest to measure any image no matter how it is invoked. The

> measurement must depend on the sequence of invocation.


Moreover,
booting from the default path, like /EFI/BOOT/BOOTAA64.EFI,
is only implemented by using bootefi <addr> syntax.

-Takahiro Akashi


> Best regards

> 

> Heinrich

> 

> > 

> > What do you think?

> > 

> > Thanks,

> > Masahisa Kojima

> > 

> > 

> > 

> > 

> > 

> > On Fri, 9 Jul 2021 at 11:44, Masahisa Kojima <masahisa.kojima@linaro.org> wrote:

> > > 

> > > On Fri, 9 Jul 2021 at 02:46, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:

> > > > 

> > > > On 7/7/21 3:36 PM, Masahisa Kojima wrote:

> > > > > TCG PC Client PFP spec requires to measure "Boot####"

> > > > > and "BootOrder" variables, EV_SEPARATOR event prior

> > > > > to the Ready to Boot invocation.

> > > > > Since u-boot does not implement Ready to Boot event,

> > > > > these measurements are performed when efi_start_image() is called.

> > > > > 

> > > > > TCG spec also requires to measure "Calling EFI Application from

> > > > > Boot Option" for each boot attempt, and "Returning from EFI

> > > > > Application from Boot Option" if a boot device returns control

> > > > > back to the Boot Manager.

> > > > > 

> > > > > Signed-off-by: Masahisa Kojima <masahisa.kojima@linaro.org>

> > > > > ---

> > > > >    include/efi_loader.h          |   4 ++

> > > > >    include/tpm-v2.h              |  18 ++++-

> > > > >    lib/efi_loader/efi_boottime.c |  20 ++++++

> > > > >    lib/efi_loader/efi_tcg2.c     | 123 ++++++++++++++++++++++++++++++++++

> > > > >    4 files changed, 164 insertions(+), 1 deletion(-)

> > > > > 

> > > > > diff --git a/include/efi_loader.h b/include/efi_loader.h

> > > > > index 0a9c82a257..281ffff30f 100644

> > > > > --- a/include/efi_loader.h

> > > > > +++ b/include/efi_loader.h

> > > > > @@ -407,6 +407,10 @@ efi_status_t efi_run_image(void *source_buffer, efi_uintn_t source_size);

> > > > >    efi_status_t efi_init_variables(void);

> > > > >    /* Notify ExitBootServices() is called */

> > > > >    void efi_variables_boot_exit_notify(void);

> > > > > +/* Measure efi application invocation */

> > > > > +efi_status_t EFIAPI efi_tcg2_measure_efi_app_invocation(void);

> > > > > +/* Measure efi application exit */

> > > > > +efi_status_t EFIAPI efi_tcg2_measure_efi_app_exit(void);

> > > > >    /* Called by bootefi to initialize root node */

> > > > >    efi_status_t efi_root_node_register(void);

> > > > >    /* Called by bootefi to initialize runtime */

> > > > > diff --git a/include/tpm-v2.h b/include/tpm-v2.h

> > > > > index 3e48e35861..8a7b7f1874 100644

> > > > > --- a/include/tpm-v2.h

> > > > > +++ b/include/tpm-v2.h

> > > > > @@ -73,7 +73,7 @@ struct udevice;

> > > > >    /*

> > > > >     * event types, cf.

> > > > >     * "TCG PC Client Platform Firmware Profile Specification", Family "2.0"

> > > > > - * rev 1.04, June 3, 2019

> > > > > + * Level 00 Version 1.05 Revision 23, May 7, 2021

> > > > >     */

> > > > >    #define EV_EFI_EVENT_BASE                   ((u32)0x80000000)

> > > > >    #define EV_EFI_VARIABLE_DRIVER_CONFIG               ((u32)0x80000001)

> > > > > @@ -85,8 +85,24 @@ struct udevice;

> > > > >    #define EV_EFI_ACTION                               ((u32)0x80000007)

> > > > >    #define EV_EFI_PLATFORM_FIRMWARE_BLOB               ((u32)0x80000008)

> > > > >    #define EV_EFI_HANDOFF_TABLES                       ((u32)0x80000009)

> > > > > +#define EV_EFI_PLATFORM_FIRMWARE_BLOB2               ((u32)0x8000000A)

> > > > > +#define EV_EFI_HANDOFF_TABLES2                       ((u32)0x8000000B)

> > > > > +#define EV_EFI_VARIABLE_BOOT2                        ((u32)0x8000000C)

> > > > >    #define EV_EFI_HCRTM_EVENT                  ((u32)0x80000010)

> > > > >    #define EV_EFI_VARIABLE_AUTHORITY           ((u32)0x800000E0)

> > > > > +#define EV_EFI_SPDM_FIRMWARE_BLOB            ((u32)0x800000E1)

> > > > > +#define EV_EFI_SPDM_FIRMWARE_CONFIG          ((u32)0x800000E2)

> > > > > +

> > > > > +#define EFI_CALLING_EFI_APPLICATION         \

> > > > > +     "Calling EFI Application from Boot Option"

> > > > > +#define EFI_RETURNING_FROM_EFI_APPLICATION  \

> > > > > +     "Returning from EFI Application from Boot Option"

> > > > > +#define EFI_EXIT_BOOT_SERVICES_INVOCATION   \

> > > > > +     "Exit Boot Services Invocation"

> > > > > +#define EFI_EXIT_BOOT_SERVICES_FAILED       \

> > > > > +     "Exit Boot Services Returned with Failure"

> > > > > +#define EFI_EXIT_BOOT_SERVICES_SUCCEEDED    \

> > > > > +     "Exit Boot Services Returned with Success"

> > > > 

> > > > Which spec defines if the string in the event log shall be utf-8 or utf-16?

> > > 

> > > TCG PC Client PFP spec does not clearly define the character encoding.

> > > In my understanding, the string derived from UEFI spec such as

> > > UEFI variable name uses utf-16(CHAR16).

> > > Other strings like "Calling EFI Application from Boot Option" defind in TCG PC

> > > Client spec use 1 byte ASCII encoding.

> > > 

> > > EDK2 implementation also uses 1 byte ASCII encoding for these strings,

> > > and tpm2-tools::tpm2_eventlog command can handles properly.

> > > 

> > > Thanks,

> > > Masahisa Kojima

> > > 

> > > > 

> > > > Best regards

> > > > 

> > > > Heinrich

> > > > 

> > > > > 

> > > > >    /* TPMS_TAGGED_PROPERTY Structure */

> > > > >    struct tpms_tagged_property {

> > > > > diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c

> > > > > index f6d5ba05e3..2914800c56 100644

> > > > > --- a/lib/efi_loader/efi_boottime.c

> > > > > +++ b/lib/efi_loader/efi_boottime.c

> > > > > @@ -2993,6 +2993,16 @@ efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle,

> > > > >        image_obj->exit_status = &exit_status;

> > > > >        image_obj->exit_jmp = &exit_jmp;

> > > > > 

> > > > > +     if (IS_ENABLED(CONFIG_EFI_TCG2_PROTOCOL)) {

> > > > > +             if (image_obj->image_type == IMAGE_SUBSYSTEM_EFI_APPLICATION) {

> > > > > +                     ret = efi_tcg2_measure_efi_app_invocation();

> > > > > +                     if (ret != EFI_SUCCESS) {

> > > > > +                             EFI_PRINT("tcg2 measurement fails(0x%lx)\n",

> > > > > +                                       ret);

> > > > > +                     }

> > > > > +             }

> > > > > +     }

> > > > > +

> > > > >        /* call the image! */

> > > > >        if (setjmp(&exit_jmp)) {

> > > > >                /*

> > > > > @@ -3251,6 +3261,16 @@ static efi_status_t EFIAPI efi_exit(efi_handle_t image_handle,

> > > > >            exit_status != EFI_SUCCESS)

> > > > >                efi_delete_image(image_obj, loaded_image_protocol);

> > > > > 

> > > > > +     if (IS_ENABLED(CONFIG_EFI_TCG2_PROTOCOL)) {

> > > > > +             if (image_obj->image_type == IMAGE_SUBSYSTEM_EFI_APPLICATION) {

> > > > > +                     ret = efi_tcg2_measure_efi_app_exit();

> > > > > +                     if (ret != EFI_SUCCESS) {

> > > > > +                             EFI_PRINT("tcg2 measurement fails(0x%lx)\n",

> > > > > +                                       ret);

> > > > > +                     }

> > > > > +             }

> > > > > +     }

> > > > > +

> > > > >        /* Make sure entry/exit counts for EFI world cross-overs match */

> > > > >        EFI_EXIT(exit_status);

> > > > > 

> > > > > diff --git a/lib/efi_loader/efi_tcg2.c b/lib/efi_loader/efi_tcg2.c

> > > > > index 2a248bd62a..6e903e3cb3 100644

> > > > > --- a/lib/efi_loader/efi_tcg2.c

> > > > > +++ b/lib/efi_loader/efi_tcg2.c

> > > > > @@ -35,6 +35,7 @@ struct event_log_buffer {

> > > > >    };

> > > > > 

> > > > >    static struct event_log_buffer event_log;

> > > > > +static bool tcg2_efi_app_invoked;

> > > > >    /*

> > > > >     * When requesting TPM2_CAP_TPM_PROPERTIES the value is on a standard offset.

> > > > >     * Since the current tpm2_get_capability() response buffers starts at

> > > > > @@ -1383,6 +1384,128 @@ static efi_status_t tcg2_measure_variable(struct udevice *dev, u32 pcr_index,

> > > > >        return ret;

> > > > >    }

> > > > > 

> > > > > +/**

> > > > > + * tcg2_measure_boot_variable() - measure boot variables

> > > > > + *

> > > > > + * @dev:     TPM device

> > > > > + *

> > > > > + * Return:   status code

> > > > > + */

> > > > > +static efi_status_t tcg2_measure_boot_variable(struct udevice *dev)

> > > > > +{

> > > > > +     u16 *boot_order;

> > > > > +     u16 var_name[] = L"BootOrder";

> > > > > +     u16 boot_name[] = L"Boot0000";

> > > > > +     u16 hexmap[] = L"0123456789ABCDEF";

> > > > > +     u8 *bootvar;

> > > > > +     efi_uintn_t var_data_size;

> > > > > +     u32 count, i;

> > > > > +     efi_status_t ret;

> > > > > +

> > > > > +     boot_order = efi_get_var(var_name, &efi_global_variable_guid,

> > > > > +                              &var_data_size);

> > > > > +     if (!boot_order) {

> > > > > +             log_info("BootOrder not defined\n");

> > > > > +             ret = EFI_NOT_FOUND;

> > > > > +             goto error;

> > > > > +     }

> > > > > +

> > > > > +     ret = tcg2_measure_variable(dev, 1, EV_EFI_VARIABLE_BOOT2, var_name,

> > > > > +                                 &efi_global_variable_guid, var_data_size,

> > > > > +                                 (u8 *)boot_order);

> > > > > +     if (ret != EFI_SUCCESS)

> > > > > +             goto error;

> > > > > +

> > > > > +     count = var_data_size / sizeof(*boot_order);

> > > > > +     for (i = 0; i < count; i++) {

> > > > > +             boot_name[4] = hexmap[(boot_order[i] & 0xf000) >> 12];

> > > > > +             boot_name[5] = hexmap[(boot_order[i] & 0x0f00) >> 8];

> > > > > +             boot_name[6] = hexmap[(boot_order[i] & 0x00f0) >> 4];

> > > > > +             boot_name[7] = hexmap[(boot_order[i] & 0x000f)];

> > > > > +

> > > > > +             bootvar = efi_get_var(boot_name, &efi_global_variable_guid,

> > > > > +                                   &var_data_size);

> > > > > +

> > > > > +             if (!bootvar) {

> > > > > +                     log_info("%ls not found\n", boot_name);

> > > > > +                     continue;

> > > > > +             }

> > > > > +

> > > > > +             ret = tcg2_measure_variable(dev, 1, EV_EFI_VARIABLE_BOOT2,

> > > > > +                                         boot_name,

> > > > > +                                         &efi_global_variable_guid,

> > > > > +                                         var_data_size, bootvar);

> > > > > +             free(bootvar);

> > > > > +             if (ret != EFI_SUCCESS)

> > > > > +                     goto error;

> > > > > +     }

> > > > > +

> > > > > +error:

> > > > > +     free(boot_order);

> > > > > +     return ret;

> > > > > +}

> > > > > +

> > > > > +/**

> > > > > + * efi_tcg2_measure_efi_app_invocation() - measure efi app invocation

> > > > > + *

> > > > > + * Return:   status code

> > > > > + */

> > > > > +efi_status_t EFIAPI efi_tcg2_measure_efi_app_invocation(void)

> > > > > +{

> > > > > +     efi_status_t ret;

> > > > > +     u32 pcr_index;

> > > > > +     struct udevice *dev;

> > > > > +     u32 event = 0;

> > > > > +

> > > > > +     if (tcg2_efi_app_invoked)

> > > > > +             return EFI_SUCCESS;

> > > > > +

> > > > > +     ret = platform_get_tpm2_device(&dev);

> > > > > +     if (ret != EFI_SUCCESS)

> > > > > +             return ret;

> > > > > +

> > > > > +     ret = tcg2_measure_boot_variable(dev);

> > > > > +     if (ret != EFI_SUCCESS)

> > > > > +             goto out;

> > > > > +

> > > > > +     ret = tcg2_measure_event(dev, 4, EV_EFI_ACTION,

> > > > > +                              strlen(EFI_CALLING_EFI_APPLICATION),

> > > > > +                              (u8 *)EFI_CALLING_EFI_APPLICATION);

> > > > > +     if (ret != EFI_SUCCESS)

> > > > > +             goto out;

> > > > > +

> > > > > +     for (pcr_index = 0; pcr_index <= 7; pcr_index++) {

> > > > > +             ret = tcg2_measure_event(dev, pcr_index, EV_SEPARATOR,

> > > > > +                                      sizeof(event), (u8 *)&event);

> > > > > +             if (ret != EFI_SUCCESS)

> > > > > +                     goto out;

> > > > > +     }

> > > > > +

> > > > > +     tcg2_efi_app_invoked = true;

> > > > > +out:

> > > > > +     return ret;

> > > > > +}

> > > > > +

> > > > > +/**

> > > > > + * efi_tcg2_measure_efi_app_exit() - measure efi app exit

> > > > > + *

> > > > > + * Return:   status code

> > > > > + */

> > > > > +efi_status_t EFIAPI efi_tcg2_measure_efi_app_exit(void)

> > > > > +{

> > > > > +     efi_status_t ret;

> > > > > +     struct udevice *dev;

> > > > > +

> > > > > +     ret = platform_get_tpm2_device(&dev);

> > > > > +     if (ret != EFI_SUCCESS)

> > > > > +             return ret;

> > > > > +

> > > > > +     ret = tcg2_measure_event(dev, 4, EV_EFI_ACTION,

> > > > > +                              strlen(EFI_RETURNING_FROM_EFI_APPLICATION),

> > > > > +                              (u8 *)EFI_RETURNING_FROM_EFI_APPLICATION);

> > > > > +     return ret;

> > > > > +}

> > > > > +

> > > > >    /**

> > > > >     * tcg2_measure_secure_boot_variable() - measure secure boot variables

> > > > >     *

> > > > > 

> > > >
Masahisa Kojima July 14, 2021, 12:40 a.m. UTC | #8
Hi Heinrich, Akashi-san,

Thank you for your comment.
I will keep current implementation.

Thanks,
Masahisa Kojima

On Wed, 14 Jul 2021 at 08:54, AKASHI Takahiro
<takahiro.akashi@linaro.org> wrote:
>

> On Tue, Jul 13, 2021 at 04:24:52PM +0200, Heinrich Schuchardt wrote:

> >

> >

> > On 13.07.21 10:31, Masahisa Kojima wrote:

> > > Hi Heinrich,

> > >

> > > > > > TCG spec also requires to measure "Calling EFI Application from

> > > > > > Boot Option" for each boot attempt, and "Returning from EFI

> > > > > > Application from Boot Option" if a boot device returns control

> > > > > > back to the Boot Manager.

> > >

> > > I would like to hear your opinion regarding

> > > "Calling EFI Application from Boot Option" measurement.

> > >

> > > My current(v1 patch series) implementation considers

> > > both "bootefi bootmgr" and "bootefi $image_addr" cases,

> > > so I do this "Calling EFI Application from Boot Option" measurement

> > > at efi_boottime.c::efi_start_image().

> > > Do I need to implement only the case UEFI application boot from bootmgr?

> > > If yes, I will move the timing of this measurement at

> > > efi_bootmgr.c::efi_bootmgr_load().

> > >

> > > As a reference, in edk2, this measurement is performed in

> > > ready_to_boot event handler, ready_to_boot handler is called

> > > upon the user selects the boot option in boot manager.

> >

> > When booting you can call

> >

> >    bootefi $driver1

> >    booefii $driver2

> >    bootefi bootmgr

> >

> > in sequence.

> >

> > Any of the binaries can call LoadImage(), StartImage() multiple times to

> > execute further images. E.g. I am loading iPXE. By default it loads GRUB

> > from an iSCSI drive but I can choose in the menu or the iPXE console to

> > invoke another UEFI binary.

> >

> > I suggest to measure any image no matter how it is invoked. The

> > measurement must depend on the sequence of invocation.

>

> Moreover,

> booting from the default path, like /EFI/BOOT/BOOTAA64.EFI,

> is only implemented by using bootefi <addr> syntax.

>

> -Takahiro Akashi

>

>

> > Best regards

> >

> > Heinrich

> >

> > >

> > > What do you think?

> > >

> > > Thanks,

> > > Masahisa Kojima

> > >

> > >

> > >

> > >

> > >

> > > On Fri, 9 Jul 2021 at 11:44, Masahisa Kojima <masahisa.kojima@linaro.org> wrote:

> > > >

> > > > On Fri, 9 Jul 2021 at 02:46, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:

> > > > >

> > > > > On 7/7/21 3:36 PM, Masahisa Kojima wrote:

> > > > > > TCG PC Client PFP spec requires to measure "Boot####"

> > > > > > and "BootOrder" variables, EV_SEPARATOR event prior

> > > > > > to the Ready to Boot invocation.

> > > > > > Since u-boot does not implement Ready to Boot event,

> > > > > > these measurements are performed when efi_start_image() is called.

> > > > > >

> > > > > > TCG spec also requires to measure "Calling EFI Application from

> > > > > > Boot Option" for each boot attempt, and "Returning from EFI

> > > > > > Application from Boot Option" if a boot device returns control

> > > > > > back to the Boot Manager.

> > > > > >

> > > > > > Signed-off-by: Masahisa Kojima <masahisa.kojima@linaro.org>

> > > > > > ---

> > > > > >    include/efi_loader.h          |   4 ++

> > > > > >    include/tpm-v2.h              |  18 ++++-

> > > > > >    lib/efi_loader/efi_boottime.c |  20 ++++++

> > > > > >    lib/efi_loader/efi_tcg2.c     | 123 ++++++++++++++++++++++++++++++++++

> > > > > >    4 files changed, 164 insertions(+), 1 deletion(-)

> > > > > >

> > > > > > diff --git a/include/efi_loader.h b/include/efi_loader.h

> > > > > > index 0a9c82a257..281ffff30f 100644

> > > > > > --- a/include/efi_loader.h

> > > > > > +++ b/include/efi_loader.h

> > > > > > @@ -407,6 +407,10 @@ efi_status_t efi_run_image(void *source_buffer, efi_uintn_t source_size);

> > > > > >    efi_status_t efi_init_variables(void);

> > > > > >    /* Notify ExitBootServices() is called */

> > > > > >    void efi_variables_boot_exit_notify(void);

> > > > > > +/* Measure efi application invocation */

> > > > > > +efi_status_t EFIAPI efi_tcg2_measure_efi_app_invocation(void);

> > > > > > +/* Measure efi application exit */

> > > > > > +efi_status_t EFIAPI efi_tcg2_measure_efi_app_exit(void);

> > > > > >    /* Called by bootefi to initialize root node */

> > > > > >    efi_status_t efi_root_node_register(void);

> > > > > >    /* Called by bootefi to initialize runtime */

> > > > > > diff --git a/include/tpm-v2.h b/include/tpm-v2.h

> > > > > > index 3e48e35861..8a7b7f1874 100644

> > > > > > --- a/include/tpm-v2.h

> > > > > > +++ b/include/tpm-v2.h

> > > > > > @@ -73,7 +73,7 @@ struct udevice;

> > > > > >    /*

> > > > > >     * event types, cf.

> > > > > >     * "TCG PC Client Platform Firmware Profile Specification", Family "2.0"

> > > > > > - * rev 1.04, June 3, 2019

> > > > > > + * Level 00 Version 1.05 Revision 23, May 7, 2021

> > > > > >     */

> > > > > >    #define EV_EFI_EVENT_BASE                   ((u32)0x80000000)

> > > > > >    #define EV_EFI_VARIABLE_DRIVER_CONFIG               ((u32)0x80000001)

> > > > > > @@ -85,8 +85,24 @@ struct udevice;

> > > > > >    #define EV_EFI_ACTION                               ((u32)0x80000007)

> > > > > >    #define EV_EFI_PLATFORM_FIRMWARE_BLOB               ((u32)0x80000008)

> > > > > >    #define EV_EFI_HANDOFF_TABLES                       ((u32)0x80000009)

> > > > > > +#define EV_EFI_PLATFORM_FIRMWARE_BLOB2               ((u32)0x8000000A)

> > > > > > +#define EV_EFI_HANDOFF_TABLES2                       ((u32)0x8000000B)

> > > > > > +#define EV_EFI_VARIABLE_BOOT2                        ((u32)0x8000000C)

> > > > > >    #define EV_EFI_HCRTM_EVENT                  ((u32)0x80000010)

> > > > > >    #define EV_EFI_VARIABLE_AUTHORITY           ((u32)0x800000E0)

> > > > > > +#define EV_EFI_SPDM_FIRMWARE_BLOB            ((u32)0x800000E1)

> > > > > > +#define EV_EFI_SPDM_FIRMWARE_CONFIG          ((u32)0x800000E2)

> > > > > > +

> > > > > > +#define EFI_CALLING_EFI_APPLICATION         \

> > > > > > +     "Calling EFI Application from Boot Option"

> > > > > > +#define EFI_RETURNING_FROM_EFI_APPLICATION  \

> > > > > > +     "Returning from EFI Application from Boot Option"

> > > > > > +#define EFI_EXIT_BOOT_SERVICES_INVOCATION   \

> > > > > > +     "Exit Boot Services Invocation"

> > > > > > +#define EFI_EXIT_BOOT_SERVICES_FAILED       \

> > > > > > +     "Exit Boot Services Returned with Failure"

> > > > > > +#define EFI_EXIT_BOOT_SERVICES_SUCCEEDED    \

> > > > > > +     "Exit Boot Services Returned with Success"

> > > > >

> > > > > Which spec defines if the string in the event log shall be utf-8 or utf-16?

> > > >

> > > > TCG PC Client PFP spec does not clearly define the character encoding.

> > > > In my understanding, the string derived from UEFI spec such as

> > > > UEFI variable name uses utf-16(CHAR16).

> > > > Other strings like "Calling EFI Application from Boot Option" defind in TCG PC

> > > > Client spec use 1 byte ASCII encoding.

> > > >

> > > > EDK2 implementation also uses 1 byte ASCII encoding for these strings,

> > > > and tpm2-tools::tpm2_eventlog command can handles properly.

> > > >

> > > > Thanks,

> > > > Masahisa Kojima

> > > >

> > > > >

> > > > > Best regards

> > > > >

> > > > > Heinrich

> > > > >

> > > > > >

> > > > > >    /* TPMS_TAGGED_PROPERTY Structure */

> > > > > >    struct tpms_tagged_property {

> > > > > > diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c

> > > > > > index f6d5ba05e3..2914800c56 100644

> > > > > > --- a/lib/efi_loader/efi_boottime.c

> > > > > > +++ b/lib/efi_loader/efi_boottime.c

> > > > > > @@ -2993,6 +2993,16 @@ efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle,

> > > > > >        image_obj->exit_status = &exit_status;

> > > > > >        image_obj->exit_jmp = &exit_jmp;

> > > > > >

> > > > > > +     if (IS_ENABLED(CONFIG_EFI_TCG2_PROTOCOL)) {

> > > > > > +             if (image_obj->image_type == IMAGE_SUBSYSTEM_EFI_APPLICATION) {

> > > > > > +                     ret = efi_tcg2_measure_efi_app_invocation();

> > > > > > +                     if (ret != EFI_SUCCESS) {

> > > > > > +                             EFI_PRINT("tcg2 measurement fails(0x%lx)\n",

> > > > > > +                                       ret);

> > > > > > +                     }

> > > > > > +             }

> > > > > > +     }

> > > > > > +

> > > > > >        /* call the image! */

> > > > > >        if (setjmp(&exit_jmp)) {

> > > > > >                /*

> > > > > > @@ -3251,6 +3261,16 @@ static efi_status_t EFIAPI efi_exit(efi_handle_t image_handle,

> > > > > >            exit_status != EFI_SUCCESS)

> > > > > >                efi_delete_image(image_obj, loaded_image_protocol);

> > > > > >

> > > > > > +     if (IS_ENABLED(CONFIG_EFI_TCG2_PROTOCOL)) {

> > > > > > +             if (image_obj->image_type == IMAGE_SUBSYSTEM_EFI_APPLICATION) {

> > > > > > +                     ret = efi_tcg2_measure_efi_app_exit();

> > > > > > +                     if (ret != EFI_SUCCESS) {

> > > > > > +                             EFI_PRINT("tcg2 measurement fails(0x%lx)\n",

> > > > > > +                                       ret);

> > > > > > +                     }

> > > > > > +             }

> > > > > > +     }

> > > > > > +

> > > > > >        /* Make sure entry/exit counts for EFI world cross-overs match */

> > > > > >        EFI_EXIT(exit_status);

> > > > > >

> > > > > > diff --git a/lib/efi_loader/efi_tcg2.c b/lib/efi_loader/efi_tcg2.c

> > > > > > index 2a248bd62a..6e903e3cb3 100644

> > > > > > --- a/lib/efi_loader/efi_tcg2.c

> > > > > > +++ b/lib/efi_loader/efi_tcg2.c

> > > > > > @@ -35,6 +35,7 @@ struct event_log_buffer {

> > > > > >    };

> > > > > >

> > > > > >    static struct event_log_buffer event_log;

> > > > > > +static bool tcg2_efi_app_invoked;

> > > > > >    /*

> > > > > >     * When requesting TPM2_CAP_TPM_PROPERTIES the value is on a standard offset.

> > > > > >     * Since the current tpm2_get_capability() response buffers starts at

> > > > > > @@ -1383,6 +1384,128 @@ static efi_status_t tcg2_measure_variable(struct udevice *dev, u32 pcr_index,

> > > > > >        return ret;

> > > > > >    }

> > > > > >

> > > > > > +/**

> > > > > > + * tcg2_measure_boot_variable() - measure boot variables

> > > > > > + *

> > > > > > + * @dev:     TPM device

> > > > > > + *

> > > > > > + * Return:   status code

> > > > > > + */

> > > > > > +static efi_status_t tcg2_measure_boot_variable(struct udevice *dev)

> > > > > > +{

> > > > > > +     u16 *boot_order;

> > > > > > +     u16 var_name[] = L"BootOrder";

> > > > > > +     u16 boot_name[] = L"Boot0000";

> > > > > > +     u16 hexmap[] = L"0123456789ABCDEF";

> > > > > > +     u8 *bootvar;

> > > > > > +     efi_uintn_t var_data_size;

> > > > > > +     u32 count, i;

> > > > > > +     efi_status_t ret;

> > > > > > +

> > > > > > +     boot_order = efi_get_var(var_name, &efi_global_variable_guid,

> > > > > > +                              &var_data_size);

> > > > > > +     if (!boot_order) {

> > > > > > +             log_info("BootOrder not defined\n");

> > > > > > +             ret = EFI_NOT_FOUND;

> > > > > > +             goto error;

> > > > > > +     }

> > > > > > +

> > > > > > +     ret = tcg2_measure_variable(dev, 1, EV_EFI_VARIABLE_BOOT2, var_name,

> > > > > > +                                 &efi_global_variable_guid, var_data_size,

> > > > > > +                                 (u8 *)boot_order);

> > > > > > +     if (ret != EFI_SUCCESS)

> > > > > > +             goto error;

> > > > > > +

> > > > > > +     count = var_data_size / sizeof(*boot_order);

> > > > > > +     for (i = 0; i < count; i++) {

> > > > > > +             boot_name[4] = hexmap[(boot_order[i] & 0xf000) >> 12];

> > > > > > +             boot_name[5] = hexmap[(boot_order[i] & 0x0f00) >> 8];

> > > > > > +             boot_name[6] = hexmap[(boot_order[i] & 0x00f0) >> 4];

> > > > > > +             boot_name[7] = hexmap[(boot_order[i] & 0x000f)];

> > > > > > +

> > > > > > +             bootvar = efi_get_var(boot_name, &efi_global_variable_guid,

> > > > > > +                                   &var_data_size);

> > > > > > +

> > > > > > +             if (!bootvar) {

> > > > > > +                     log_info("%ls not found\n", boot_name);

> > > > > > +                     continue;

> > > > > > +             }

> > > > > > +

> > > > > > +             ret = tcg2_measure_variable(dev, 1, EV_EFI_VARIABLE_BOOT2,

> > > > > > +                                         boot_name,

> > > > > > +                                         &efi_global_variable_guid,

> > > > > > +                                         var_data_size, bootvar);

> > > > > > +             free(bootvar);

> > > > > > +             if (ret != EFI_SUCCESS)

> > > > > > +                     goto error;

> > > > > > +     }

> > > > > > +

> > > > > > +error:

> > > > > > +     free(boot_order);

> > > > > > +     return ret;

> > > > > > +}

> > > > > > +

> > > > > > +/**

> > > > > > + * efi_tcg2_measure_efi_app_invocation() - measure efi app invocation

> > > > > > + *

> > > > > > + * Return:   status code

> > > > > > + */

> > > > > > +efi_status_t EFIAPI efi_tcg2_measure_efi_app_invocation(void)

> > > > > > +{

> > > > > > +     efi_status_t ret;

> > > > > > +     u32 pcr_index;

> > > > > > +     struct udevice *dev;

> > > > > > +     u32 event = 0;

> > > > > > +

> > > > > > +     if (tcg2_efi_app_invoked)

> > > > > > +             return EFI_SUCCESS;

> > > > > > +

> > > > > > +     ret = platform_get_tpm2_device(&dev);

> > > > > > +     if (ret != EFI_SUCCESS)

> > > > > > +             return ret;

> > > > > > +

> > > > > > +     ret = tcg2_measure_boot_variable(dev);

> > > > > > +     if (ret != EFI_SUCCESS)

> > > > > > +             goto out;

> > > > > > +

> > > > > > +     ret = tcg2_measure_event(dev, 4, EV_EFI_ACTION,

> > > > > > +                              strlen(EFI_CALLING_EFI_APPLICATION),

> > > > > > +                              (u8 *)EFI_CALLING_EFI_APPLICATION);

> > > > > > +     if (ret != EFI_SUCCESS)

> > > > > > +             goto out;

> > > > > > +

> > > > > > +     for (pcr_index = 0; pcr_index <= 7; pcr_index++) {

> > > > > > +             ret = tcg2_measure_event(dev, pcr_index, EV_SEPARATOR,

> > > > > > +                                      sizeof(event), (u8 *)&event);

> > > > > > +             if (ret != EFI_SUCCESS)

> > > > > > +                     goto out;

> > > > > > +     }

> > > > > > +

> > > > > > +     tcg2_efi_app_invoked = true;

> > > > > > +out:

> > > > > > +     return ret;

> > > > > > +}

> > > > > > +

> > > > > > +/**

> > > > > > + * efi_tcg2_measure_efi_app_exit() - measure efi app exit

> > > > > > + *

> > > > > > + * Return:   status code

> > > > > > + */

> > > > > > +efi_status_t EFIAPI efi_tcg2_measure_efi_app_exit(void)

> > > > > > +{

> > > > > > +     efi_status_t ret;

> > > > > > +     struct udevice *dev;

> > > > > > +

> > > > > > +     ret = platform_get_tpm2_device(&dev);

> > > > > > +     if (ret != EFI_SUCCESS)

> > > > > > +             return ret;

> > > > > > +

> > > > > > +     ret = tcg2_measure_event(dev, 4, EV_EFI_ACTION,

> > > > > > +                              strlen(EFI_RETURNING_FROM_EFI_APPLICATION),

> > > > > > +                              (u8 *)EFI_RETURNING_FROM_EFI_APPLICATION);

> > > > > > +     return ret;

> > > > > > +}

> > > > > > +

> > > > > >    /**

> > > > > >     * tcg2_measure_secure_boot_variable() - measure secure boot variables

> > > > > >     *

> > > > > >

> > > > >
diff mbox series

Patch

diff --git a/include/efi_loader.h b/include/efi_loader.h
index 0a9c82a257..281ffff30f 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -407,6 +407,10 @@  efi_status_t efi_run_image(void *source_buffer, efi_uintn_t source_size);
 efi_status_t efi_init_variables(void);
 /* Notify ExitBootServices() is called */
 void efi_variables_boot_exit_notify(void);
+/* Measure efi application invocation */
+efi_status_t EFIAPI efi_tcg2_measure_efi_app_invocation(void);
+/* Measure efi application exit */
+efi_status_t EFIAPI efi_tcg2_measure_efi_app_exit(void);
 /* Called by bootefi to initialize root node */
 efi_status_t efi_root_node_register(void);
 /* Called by bootefi to initialize runtime */
diff --git a/include/tpm-v2.h b/include/tpm-v2.h
index 3e48e35861..8a7b7f1874 100644
--- a/include/tpm-v2.h
+++ b/include/tpm-v2.h
@@ -73,7 +73,7 @@  struct udevice;
 /*
  * event types, cf.
  * "TCG PC Client Platform Firmware Profile Specification", Family "2.0"
- * rev 1.04, June 3, 2019
+ * Level 00 Version 1.05 Revision 23, May 7, 2021
  */
 #define EV_EFI_EVENT_BASE			((u32)0x80000000)
 #define EV_EFI_VARIABLE_DRIVER_CONFIG		((u32)0x80000001)
@@ -85,8 +85,24 @@  struct udevice;
 #define EV_EFI_ACTION				((u32)0x80000007)
 #define EV_EFI_PLATFORM_FIRMWARE_BLOB		((u32)0x80000008)
 #define EV_EFI_HANDOFF_TABLES			((u32)0x80000009)
+#define EV_EFI_PLATFORM_FIRMWARE_BLOB2		((u32)0x8000000A)
+#define EV_EFI_HANDOFF_TABLES2			((u32)0x8000000B)
+#define EV_EFI_VARIABLE_BOOT2			((u32)0x8000000C)
 #define EV_EFI_HCRTM_EVENT			((u32)0x80000010)
 #define EV_EFI_VARIABLE_AUTHORITY		((u32)0x800000E0)
+#define EV_EFI_SPDM_FIRMWARE_BLOB		((u32)0x800000E1)
+#define EV_EFI_SPDM_FIRMWARE_CONFIG		((u32)0x800000E2)
+
+#define EFI_CALLING_EFI_APPLICATION         \
+	"Calling EFI Application from Boot Option"
+#define EFI_RETURNING_FROM_EFI_APPLICATION  \
+	"Returning from EFI Application from Boot Option"
+#define EFI_EXIT_BOOT_SERVICES_INVOCATION   \
+	"Exit Boot Services Invocation"
+#define EFI_EXIT_BOOT_SERVICES_FAILED       \
+	"Exit Boot Services Returned with Failure"
+#define EFI_EXIT_BOOT_SERVICES_SUCCEEDED    \
+	"Exit Boot Services Returned with Success"
 
 /* TPMS_TAGGED_PROPERTY Structure */
 struct tpms_tagged_property {
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
index f6d5ba05e3..2914800c56 100644
--- a/lib/efi_loader/efi_boottime.c
+++ b/lib/efi_loader/efi_boottime.c
@@ -2993,6 +2993,16 @@  efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle,
 	image_obj->exit_status = &exit_status;
 	image_obj->exit_jmp = &exit_jmp;
 
+	if (IS_ENABLED(CONFIG_EFI_TCG2_PROTOCOL)) {
+		if (image_obj->image_type == IMAGE_SUBSYSTEM_EFI_APPLICATION) {
+			ret = efi_tcg2_measure_efi_app_invocation();
+			if (ret != EFI_SUCCESS) {
+				EFI_PRINT("tcg2 measurement fails(0x%lx)\n",
+					  ret);
+			}
+		}
+	}
+
 	/* call the image! */
 	if (setjmp(&exit_jmp)) {
 		/*
@@ -3251,6 +3261,16 @@  static efi_status_t EFIAPI efi_exit(efi_handle_t image_handle,
 	    exit_status != EFI_SUCCESS)
 		efi_delete_image(image_obj, loaded_image_protocol);
 
+	if (IS_ENABLED(CONFIG_EFI_TCG2_PROTOCOL)) {
+		if (image_obj->image_type == IMAGE_SUBSYSTEM_EFI_APPLICATION) {
+			ret = efi_tcg2_measure_efi_app_exit();
+			if (ret != EFI_SUCCESS) {
+				EFI_PRINT("tcg2 measurement fails(0x%lx)\n",
+					  ret);
+			}
+		}
+	}
+
 	/* Make sure entry/exit counts for EFI world cross-overs match */
 	EFI_EXIT(exit_status);
 
diff --git a/lib/efi_loader/efi_tcg2.c b/lib/efi_loader/efi_tcg2.c
index 2a248bd62a..6e903e3cb3 100644
--- a/lib/efi_loader/efi_tcg2.c
+++ b/lib/efi_loader/efi_tcg2.c
@@ -35,6 +35,7 @@  struct event_log_buffer {
 };
 
 static struct event_log_buffer event_log;
+static bool tcg2_efi_app_invoked;
 /*
  * When requesting TPM2_CAP_TPM_PROPERTIES the value is on a standard offset.
  * Since the current tpm2_get_capability() response buffers starts at
@@ -1383,6 +1384,128 @@  static efi_status_t tcg2_measure_variable(struct udevice *dev, u32 pcr_index,
 	return ret;
 }
 
+/**
+ * tcg2_measure_boot_variable() - measure boot variables
+ *
+ * @dev:	TPM device
+ *
+ * Return:	status code
+ */
+static efi_status_t tcg2_measure_boot_variable(struct udevice *dev)
+{
+	u16 *boot_order;
+	u16 var_name[] = L"BootOrder";
+	u16 boot_name[] = L"Boot0000";
+	u16 hexmap[] = L"0123456789ABCDEF";
+	u8 *bootvar;
+	efi_uintn_t var_data_size;
+	u32 count, i;
+	efi_status_t ret;
+
+	boot_order = efi_get_var(var_name, &efi_global_variable_guid,
+				 &var_data_size);
+	if (!boot_order) {
+		log_info("BootOrder not defined\n");
+		ret = EFI_NOT_FOUND;
+		goto error;
+	}
+
+	ret = tcg2_measure_variable(dev, 1, EV_EFI_VARIABLE_BOOT2, var_name,
+				    &efi_global_variable_guid, var_data_size,
+				    (u8 *)boot_order);
+	if (ret != EFI_SUCCESS)
+		goto error;
+
+	count = var_data_size / sizeof(*boot_order);
+	for (i = 0; i < count; i++) {
+		boot_name[4] = hexmap[(boot_order[i] & 0xf000) >> 12];
+		boot_name[5] = hexmap[(boot_order[i] & 0x0f00) >> 8];
+		boot_name[6] = hexmap[(boot_order[i] & 0x00f0) >> 4];
+		boot_name[7] = hexmap[(boot_order[i] & 0x000f)];
+
+		bootvar = efi_get_var(boot_name, &efi_global_variable_guid,
+				      &var_data_size);
+
+		if (!bootvar) {
+			log_info("%ls not found\n", boot_name);
+			continue;
+		}
+
+		ret = tcg2_measure_variable(dev, 1, EV_EFI_VARIABLE_BOOT2,
+					    boot_name,
+					    &efi_global_variable_guid,
+					    var_data_size, bootvar);
+		free(bootvar);
+		if (ret != EFI_SUCCESS)
+			goto error;
+	}
+
+error:
+	free(boot_order);
+	return ret;
+}
+
+/**
+ * efi_tcg2_measure_efi_app_invocation() - measure efi app invocation
+ *
+ * Return:	status code
+ */
+efi_status_t EFIAPI efi_tcg2_measure_efi_app_invocation(void)
+{
+	efi_status_t ret;
+	u32 pcr_index;
+	struct udevice *dev;
+	u32 event = 0;
+
+	if (tcg2_efi_app_invoked)
+		return EFI_SUCCESS;
+
+	ret = platform_get_tpm2_device(&dev);
+	if (ret != EFI_SUCCESS)
+		return ret;
+
+	ret = tcg2_measure_boot_variable(dev);
+	if (ret != EFI_SUCCESS)
+		goto out;
+
+	ret = tcg2_measure_event(dev, 4, EV_EFI_ACTION,
+				 strlen(EFI_CALLING_EFI_APPLICATION),
+				 (u8 *)EFI_CALLING_EFI_APPLICATION);
+	if (ret != EFI_SUCCESS)
+		goto out;
+
+	for (pcr_index = 0; pcr_index <= 7; pcr_index++) {
+		ret = tcg2_measure_event(dev, pcr_index, EV_SEPARATOR,
+					 sizeof(event), (u8 *)&event);
+		if (ret != EFI_SUCCESS)
+			goto out;
+	}
+
+	tcg2_efi_app_invoked = true;
+out:
+	return ret;
+}
+
+/**
+ * efi_tcg2_measure_efi_app_exit() - measure efi app exit
+ *
+ * Return:	status code
+ */
+efi_status_t EFIAPI efi_tcg2_measure_efi_app_exit(void)
+{
+	efi_status_t ret;
+	struct udevice *dev;
+
+	ret = platform_get_tpm2_device(&dev);
+	if (ret != EFI_SUCCESS)
+		return ret;
+
+	ret = tcg2_measure_event(dev, 4, EV_EFI_ACTION,
+				 strlen(EFI_RETURNING_FROM_EFI_APPLICATION),
+				 (u8 *)EFI_RETURNING_FROM_EFI_APPLICATION);
+	return ret;
+}
+
 /**
  * tcg2_measure_secure_boot_variable() - measure secure boot variables
  *