blob: 949e26350c783fc44490ee03e381647ea7e2e7cf [file] [log] [blame]
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#if ENABLE_TPM
#include <efi.h>
#include <efilib.h>
#include "tpm-pcr.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_t pcrindex,
EFI_PHYSICAL_ADDRESS buffer,
size_t buffer_size,
const char16_t *description) {
_cleanup_free_ TCG_PCR_EVENT *tcg_event = NULL;
EFI_PHYSICAL_ADDRESS event_log_last;
uint32_t event_number = 1;
size_t desc_len;
assert(tcg);
assert(description);
desc_len = strsize16(description);
tcg_event = xmalloc(offsetof(TCG_PCR_EVENT, Event) + desc_len);
memset(tcg_event, 0, offsetof(TCG_PCR_EVENT, Event) + desc_len);
*tcg_event = (TCG_PCR_EVENT) {
.EventSize = desc_len,
.PCRIndex = pcrindex,
.EventType = EV_IPL,
};
memcpy(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_t pcrindex,
EFI_PHYSICAL_ADDRESS buffer,
uint64_t buffer_size,
const char16_t *description) {
_cleanup_free_ EFI_TCG2_EVENT *tcg_event = NULL;
size_t desc_len;
assert(tcg);
assert(description);
desc_len = strsize16(description);
tcg_event = xmalloc(offsetof(EFI_TCG2_EVENT, Event) + desc_len);
memset(tcg_event, 0, 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,
};
memcpy(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 err;
uint32_t features;
EFI_TCG *tcg;
err = BS->LocateProtocol(MAKE_GUID_PTR(EFI_TCG), NULL, (void **) &tcg);
if (err != EFI_SUCCESS)
return NULL;
err = tcg->StatusCheck(
tcg,
&capability,
&features,
&event_log_location,
&event_log_last_entry);
if (err != EFI_SUCCESS)
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 err;
EFI_TCG2 *tcg;
err = BS->LocateProtocol(MAKE_GUID_PTR(EFI_TCG2), NULL, (void **) &tcg);
if (err != EFI_SUCCESS)
return NULL;
err = tcg->GetCapability(tcg, &capability);
if (err != EFI_SUCCESS)
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;
}
bool tpm_present(void) {
return tcg2_interface_check() || tcg1_interface_check();
}
EFI_STATUS tpm_log_event(uint32_t pcrindex, EFI_PHYSICAL_ADDRESS buffer, size_t buffer_size, const char16_t *description, bool *ret_measured) {
EFI_TCG2 *tpm2;
EFI_STATUS err;
assert(description || pcrindex == UINT32_MAX);
/* If EFI_SUCCESS is returned, will initialize ret_measured to true if we actually measured
* something, or false if measurement was turned off. */
if (pcrindex == UINT32_MAX) { /* PCR disabled? */
if (ret_measured)
*ret_measured = false;
return EFI_SUCCESS;
}
tpm2 = tcg2_interface_check();
if (tpm2)
err = tpm2_measure_to_pcr_and_event_log(tpm2, pcrindex, buffer, buffer_size, description);
else {
EFI_TCG *tpm1;
tpm1 = tcg1_interface_check();
if (tpm1)
err = tpm1_measure_to_pcr_and_event_log(tpm1, pcrindex, buffer, buffer_size, description);
else {
/* No active TPM found, so don't return an error */
if (ret_measured)
*ret_measured = false;
return EFI_SUCCESS;
}
}
if (err == EFI_SUCCESS && ret_measured)
*ret_measured = true;
return err;
}
EFI_STATUS tpm_log_event_ascii(uint32_t pcrindex, EFI_PHYSICAL_ADDRESS buffer, size_t buffer_size, const char *description, bool *ret_measured) {
_cleanup_free_ char16_t *c = NULL;
if (description)
c = xstr8_to_16(description);
return tpm_log_event(pcrindex, buffer, buffer_size, c, ret_measured);
}
EFI_STATUS tpm_log_load_options(const char16_t *load_options, bool *ret_measured) {
bool measured = false;
EFI_STATUS err;
/* Measures a load options string into the TPM2, i.e. the kernel command line */
err = tpm_log_event(
TPM_PCR_INDEX_KERNEL_PARAMETERS,
POINTER_TO_PHYSICAL_ADDRESS(load_options),
strsize16(load_options),
load_options,
&measured);
if (err != EFI_SUCCESS)
return log_error_status(
err,
"Unable to add load options (i.e. kernel command) line measurement to PCR %u: %m",
TPM_PCR_INDEX_KERNEL_PARAMETERS);
if (ret_measured)
*ret_measured = measured;
return EFI_SUCCESS;
}
#endif