forked from rhboot/shim
-
Notifications
You must be signed in to change notification settings - Fork 0
/
tpm.c
152 lines (122 loc) · 3.98 KB
/
tpm.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#include <efi.h>
#include <efilib.h>
#include <string.h>
#include "tpm.h"
extern UINT8 in_protocol;
#define perror(fmt, ...) ({ \
UINTN __perror_ret = 0; \
if (!in_protocol) \
__perror_ret = Print((fmt), ##__VA_ARGS__); \
__perror_ret; \
})
EFI_GUID tpm_guid = EFI_TPM_GUID;
EFI_GUID tpm2_guid = EFI_TPM2_GUID;
static BOOLEAN tpm_present(efi_tpm_protocol_t *tpm)
{
EFI_STATUS status;
TCG_EFI_BOOT_SERVICE_CAPABILITY caps;
UINT32 flags;
EFI_PHYSICAL_ADDRESS eventlog, lastevent;
caps.Size = (UINT8)sizeof(caps);
status = uefi_call_wrapper(tpm->status_check, 5, tpm, &caps, &flags,
&eventlog, &lastevent);
if (status != EFI_SUCCESS || caps.TPMDeactivatedFlag
|| !caps.TPMPresentFlag)
return FALSE;
return TRUE;
}
static BOOLEAN tpm2_present(efi_tpm2_protocol_t *tpm)
{
EFI_STATUS status;
EFI_TCG2_BOOT_SERVICE_CAPABILITY caps;
EFI_TCG2_BOOT_SERVICE_CAPABILITY_1_0 *caps_1_0;
caps.Size = (UINT8)sizeof(caps);
status = uefi_call_wrapper(tpm->get_capability, 2, tpm, &caps);
if (status != EFI_SUCCESS)
return FALSE;
if (caps.StructureVersion.Major == 1 &&
caps.StructureVersion.Minor == 0) {
caps_1_0 = (EFI_TCG2_BOOT_SERVICE_CAPABILITY_1_0 *)∩︀
if (caps_1_0->TPMPresentFlag)
return TRUE;
} else {
if (caps.TPMPresentFlag)
return TRUE;
}
return FALSE;
}
/*
* According to TCG EFI Protocol Specification for TPM 2.0 family,
* all events generated after the invocation of EFI_TCG2_GET_EVENT_LOG
* shall be stored in an instance of an EFI_CONFIGURATION_TABLE aka
* EFI TCG 2.0 final events table. Hence, it is necessary to trigger the
* internal switch through calling get_event_log() in order to allow
* to retrieve the logs from OS runtime.
*/
static EFI_STATUS trigger_tcg2_final_events_table(efi_tpm2_protocol_t *tpm2)
{
EFI_PHYSICAL_ADDRESS start;
EFI_PHYSICAL_ADDRESS end;
BOOLEAN truncated;
return uefi_call_wrapper(tpm2->get_event_log, 5, tpm2,
EFI_TCG2_EVENT_LOG_FORMAT_TCG_2, &start,
&end, &truncated);
}
EFI_STATUS tpm_log_event(EFI_PHYSICAL_ADDRESS buf, UINTN size, UINT8 pcr,
const CHAR8 *description)
{
EFI_STATUS status;
efi_tpm_protocol_t *tpm;
efi_tpm2_protocol_t *tpm2;
status = LibLocateProtocol(&tpm2_guid, (VOID **)&tpm2);
/* TPM 2.0 */
if (status == EFI_SUCCESS) {
EFI_TCG2_EVENT *event;
if (!tpm2_present(tpm2))
return EFI_SUCCESS;
status = trigger_tcg2_final_events_table(tpm2);
if (EFI_ERROR(status)) {
perror(L"Unable to trigger tcg2 final events table: %r\n", status);
return status;
}
event = AllocatePool(sizeof(*event) + strlen(description) + 1);
if (!event) {
perror(L"Unable to allocate event structure\n");
return EFI_OUT_OF_RESOURCES;
}
event->Header.HeaderSize = sizeof(EFI_TCG2_EVENT_HEADER);
event->Header.HeaderVersion = 1;
event->Header.PCRIndex = pcr;
event->Header.EventType = 0x0d;
event->Size = sizeof(*event) - sizeof(event->Event) + strlen(description) + 1;
memcpy(event->Event, description, strlen(description) + 1);
status = uefi_call_wrapper(tpm2->hash_log_extend_event, 5, tpm2,
0, buf, (UINT64) size, event);
FreePool(event);
return status;
} else {
TCG_PCR_EVENT *event;
UINT32 algorithm, eventnum = 0;
EFI_PHYSICAL_ADDRESS lastevent;
status = LibLocateProtocol(&tpm_guid, (VOID **)&tpm);
if (status != EFI_SUCCESS)
return EFI_SUCCESS;
if (!tpm_present(tpm))
return EFI_SUCCESS;
event = AllocatePool(sizeof(*event) + strlen(description) + 1);
if (!event) {
perror(L"Unable to allocate event structure\n");
return EFI_OUT_OF_RESOURCES;
}
event->PCRIndex = pcr;
event->EventType = 0x0d;
event->EventSize = strlen(description) + 1;
algorithm = 0x00000004;
status = uefi_call_wrapper(tpm->log_extend_event, 7, tpm, buf,
(UINT64)size, algorithm, event,
&eventnum, &lastevent);
FreePool(event);
return status;
}
return EFI_SUCCESS;
}