blob: da4fd18ea8c28e45ef1451c044b4370d07f20bfb [file] [log] [blame] [raw]
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#if ENABLE_TPM
#include <efi.h>
#include <efilib.h>
#include "macro-fundamental.h"
#include "measure.h"
#include "missing_efi.h"
#include "util.h"
static EFI_STATUS tpm1_measure_to_pcr_and_event_log(
const EFI_TCG *tcg,
UINT32 pcrindex,
EFI_PHYSICAL_ADDRESS buffer,
UINTN buffer_size,
const CHAR16 *description) {
_cleanup_freepool_ TCG_PCR_EVENT *tcg_event = NULL;
EFI_PHYSICAL_ADDRESS event_log_last;
UINT32 event_number = 1;
UINTN desc_len;
assert(tcg);
assert(description);
desc_len = StrSize(description);
tcg_event = xallocate_zero_pool(offsetof(TCG_PCR_EVENT, Event) + desc_len);
*tcg_event = (TCG_PCR_EVENT) {
.EventSize = desc_len,
.PCRIndex = pcrindex,
.EventType = EV_IPL,
};
CopyMem(tcg_event->Event, description, desc_len);
return tcg->HashLogExtendEvent(
(EFI_TCG *) tcg,
buffer, buffer_size,
TCG_ALG_SHA,
tcg_event,
&event_number,
&event_log_last);
}
static EFI_STATUS tpm2_measure_to_pcr_and_event_log(
EFI_TCG2 *tcg,
UINT32 pcrindex,
EFI_PHYSICAL_ADDRESS buffer,
UINT64 buffer_size,
const CHAR16 *description) {
_cleanup_freepool_ EFI_TCG2_EVENT *tcg_event = NULL;
UINTN desc_len;
assert(tcg);
assert(description);
desc_len = StrSize(description);
tcg_event = xallocate_zero_pool(offsetof(EFI_TCG2_EVENT, Event) + desc_len);
*tcg_event = (EFI_TCG2_EVENT) {
.Size = offsetof(EFI_TCG2_EVENT, Event) + desc_len,
.Header.HeaderSize = sizeof(EFI_TCG2_EVENT_HEADER),
.Header.HeaderVersion = EFI_TCG2_EVENT_HEADER_VERSION,
.Header.PCRIndex = pcrindex,
.Header.EventType = EV_IPL,
};
CopyMem(tcg_event->Event, description, desc_len);
return tcg->HashLogExtendEvent(
tcg,
0,
buffer, buffer_size,
tcg_event);
}
static EFI_TCG *tcg1_interface_check(void) {
EFI_PHYSICAL_ADDRESS event_log_location, event_log_last_entry;
TCG_BOOT_SERVICE_CAPABILITY capability = {
.Size = sizeof(capability),
};
EFI_STATUS status;
UINT32 features;
EFI_TCG *tcg;
status = LibLocateProtocol((EFI_GUID*) EFI_TCG_GUID, (void **) &tcg);
if (EFI_ERROR(status))
return NULL;
status = tcg->StatusCheck(
tcg,
&capability,
&features,
&event_log_location,
&event_log_last_entry);
if (EFI_ERROR(status))
return NULL;
if (capability.TPMDeactivatedFlag)
return NULL;
if (!capability.TPMPresentFlag)
return NULL;
return tcg;
}
static EFI_TCG2 * tcg2_interface_check(void) {
EFI_TCG2_BOOT_SERVICE_CAPABILITY capability = {
.Size = sizeof(capability),
};
EFI_STATUS status;
EFI_TCG2 *tcg;
status = LibLocateProtocol((EFI_GUID*) EFI_TCG2_GUID, (void **) &tcg);
if (EFI_ERROR(status))
return NULL;
status = tcg->GetCapability(tcg, &capability);
if (EFI_ERROR(status))
return NULL;
if (capability.StructureVersion.Major == 1 &&
capability.StructureVersion.Minor == 0) {
TCG_BOOT_SERVICE_CAPABILITY *caps_1_0 =
(TCG_BOOT_SERVICE_CAPABILITY*) &capability;
if (caps_1_0->TPMPresentFlag)
return tcg;
}
if (!capability.TPMPresentFlag)
return NULL;
return tcg;
}
BOOLEAN tpm_present(void) {
return tcg2_interface_check() || tcg1_interface_check();
}
EFI_STATUS tpm_log_event(UINT32 pcrindex, EFI_PHYSICAL_ADDRESS buffer, UINTN buffer_size, const CHAR16 *description) {
EFI_TCG *tpm1;
EFI_TCG2 *tpm2;
assert(description);
/* PCR disabled */
if (pcrindex == UINT32_MAX)
return EFI_SUCCESS;
tpm2 = tcg2_interface_check();
if (tpm2)
return tpm2_measure_to_pcr_and_event_log(tpm2, pcrindex, buffer, buffer_size, description);
tpm1 = tcg1_interface_check();
if (tpm1)
return tpm1_measure_to_pcr_and_event_log(tpm1, pcrindex, buffer, buffer_size, description);
/* No active TPM found, so don't return an error */
return EFI_SUCCESS;
}
EFI_STATUS tpm_log_load_options(const CHAR16 *load_options) {
EFI_STATUS err;
/* Measures a load options string into the TPM2, i.e. the kernel command line */
for (UINTN i = 0; i < 2; i++) {
UINT32 pcr = i == 0 ? TPM_PCR_INDEX_KERNEL_PARAMETERS : TPM_PCR_INDEX_KERNEL_PARAMETERS_COMPAT;
err = tpm_log_event(pcr,
POINTER_TO_PHYSICAL_ADDRESS(load_options),
StrSize(load_options), load_options);
if (EFI_ERROR(err))
return log_error_status_stall(err, L"Unable to add load options (i.e. kernel command) line measurement to PCR %u: %r", pcr, err);
}
return EFI_SUCCESS;
}
#endif