1/** @file
2  Measure TrEE required variable.
3
4Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
5This program and the accompanying materials
6are licensed and made available under the terms and conditions of the BSD License
7which accompanies this distribution.  The full text of the license may be found at
8http://opensource.org/licenses/bsd-license.php
9
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13**/
14
15#include <PiDxe.h>
16#include <Guid/ImageAuthentication.h>
17#include <IndustryStandard/UefiTcgPlatform.h>
18#include <Protocol/TrEEProtocol.h>
19
20#include <Library/UefiBootServicesTableLib.h>
21#include <Library/UefiRuntimeServicesTableLib.h>
22#include <Library/MemoryAllocationLib.h>
23#include <Library/BaseMemoryLib.h>
24#include <Library/DebugLib.h>
25#include <Library/BaseLib.h>
26#include <Library/TpmMeasurementLib.h>
27
28typedef struct {
29  CHAR16                                 *VariableName;
30  EFI_GUID                               *VendorGuid;
31} VARIABLE_TYPE;
32
33typedef struct {
34  CHAR16                                 *VariableName;
35  EFI_GUID                               *VendorGuid;
36  VOID                                   *Data;
37  UINTN                                  Size;
38} VARIABLE_RECORD;
39
40#define  MEASURED_AUTHORITY_COUNT_MAX  0x100
41
42UINTN            mMeasuredAuthorityCount    = 0;
43UINTN            mMeasuredAuthorityCountMax = 0;
44VARIABLE_RECORD  *mMeasuredAuthorityList    = NULL;
45
46VARIABLE_TYPE  mVariableType[] = {
47  {EFI_IMAGE_SECURITY_DATABASE,  &gEfiImageSecurityDatabaseGuid},
48};
49
50/**
51  This function will check if VarName should be recorded and return the address of VarName if it is needed.
52
53  @param[in]  VarName           A Null-terminated string that is the name of the vendor's variable.
54
55  @return the address of VarName.
56**/
57CHAR16 *
58AssignVarName (
59  IN      CHAR16                    *VarName
60  )
61{
62  UINTN  Index;
63
64  for (Index = 0; Index < sizeof(mVariableType)/sizeof(mVariableType[0]); Index++) {
65    if (StrCmp (VarName, mVariableType[Index].VariableName) == 0) {
66      return mVariableType[Index].VariableName;
67    }
68  }
69
70  return NULL;
71}
72
73/**
74  This function will check if VendorGuid should be recorded and return the address of VendorGuid if it is needed.
75
76  @param[in]  VendorGuid        A unique identifier for the vendor.
77
78  @return the address of VendorGuid.
79**/
80EFI_GUID *
81AssignVendorGuid (
82  IN      EFI_GUID                  *VendorGuid
83  )
84{
85  UINTN  Index;
86
87  for (Index = 0; Index < sizeof(mVariableType)/sizeof(mVariableType[0]); Index++) {
88    if (CompareGuid (VendorGuid, mVariableType[Index].VendorGuid)) {
89      return mVariableType[Index].VendorGuid;
90    }
91  }
92
93  return NULL;
94}
95
96/**
97  This function will add variable information to MeasuredAuthorityList.
98
99  @param[in]  VarName           A Null-terminated string that is the name of the vendor's variable.
100  @param[in]  VendorGuid        A unique identifier for the vendor.
101  @param[in]  VarData           The content of the variable data.
102  @param[in]  VarSize           The size of the variable data.
103
104  @retval EFI_SUCCESS           Operation completed successfully.
105  @retval EFI_OUT_OF_RESOURCES  Out of memory.
106**/
107EFI_STATUS
108AddDataMeasured (
109  IN      CHAR16                    *VarName,
110  IN      EFI_GUID                  *VendorGuid,
111  IN      VOID                      *Data,
112  IN      UINTN                     Size
113  )
114{
115  VARIABLE_RECORD  *NewMeasuredAuthorityList;
116
117  ASSERT (mMeasuredAuthorityCount <= mMeasuredAuthorityCountMax);
118  if (mMeasuredAuthorityCount == mMeasuredAuthorityCountMax) {
119    //
120    // Need enlarge
121    //
122    NewMeasuredAuthorityList = AllocateZeroPool (sizeof(VARIABLE_RECORD) * (mMeasuredAuthorityCountMax + MEASURED_AUTHORITY_COUNT_MAX));
123    if (NewMeasuredAuthorityList == NULL) {
124      return EFI_OUT_OF_RESOURCES;
125    }
126    if (mMeasuredAuthorityList != NULL) {
127      CopyMem (NewMeasuredAuthorityList, mMeasuredAuthorityList, sizeof(VARIABLE_RECORD) * mMeasuredAuthorityCount);
128      FreePool (mMeasuredAuthorityList);
129    }
130    mMeasuredAuthorityList     = NewMeasuredAuthorityList;
131    mMeasuredAuthorityCountMax += MEASURED_AUTHORITY_COUNT_MAX;
132  }
133
134  //
135  // Add new entry
136  //
137  mMeasuredAuthorityList[mMeasuredAuthorityCount].VariableName = AssignVarName (VarName);
138  mMeasuredAuthorityList[mMeasuredAuthorityCount].VendorGuid   = AssignVendorGuid (VendorGuid);
139  mMeasuredAuthorityList[mMeasuredAuthorityCount].Size         = Size;
140  mMeasuredAuthorityList[mMeasuredAuthorityCount].Data         = AllocatePool (Size);
141  if (mMeasuredAuthorityList[mMeasuredAuthorityCount].Data == NULL) {
142    return EFI_OUT_OF_RESOURCES;
143  }
144  CopyMem (mMeasuredAuthorityList[mMeasuredAuthorityCount].Data, Data, Size);
145  mMeasuredAuthorityCount++;
146
147  return EFI_SUCCESS;
148}
149
150/**
151  This function will return if this variable is already measured.
152
153  @param[in]  VarName           A Null-terminated string that is the name of the vendor's variable.
154  @param[in]  VendorGuid        A unique identifier for the vendor.
155  @param[in]  VarData           The content of the variable data.
156  @param[in]  VarSize           The size of the variable data.
157
158  @retval TRUE  The data is already measured.
159  @retval FALSE The data is not measured yet.
160**/
161BOOLEAN
162IsDataMeasured (
163  IN      CHAR16                    *VarName,
164  IN      EFI_GUID                  *VendorGuid,
165  IN      VOID                      *Data,
166  IN      UINTN                     Size
167  )
168{
169  UINTN  Index;
170
171  for (Index = 0; Index < mMeasuredAuthorityCount; Index++) {
172    if ((StrCmp (VarName, mMeasuredAuthorityList[Index].VariableName) == 0) &&
173        (CompareGuid (VendorGuid, mMeasuredAuthorityList[Index].VendorGuid)) &&
174        (CompareMem (Data, mMeasuredAuthorityList[Index].Data, Size) == 0) &&
175        (Size == mMeasuredAuthorityList[Index].Size)) {
176      return TRUE;
177    }
178  }
179
180  return FALSE;
181}
182
183/**
184  This function will return if this variable is SecureAuthority Variable.
185
186  @param[in]  VariableName      A Null-terminated string that is the name of the vendor's variable.
187  @param[in]  VendorGuid        A unique identifier for the vendor.
188
189  @retval TRUE  This is SecureAuthority Variable
190  @retval FALSE This is not SecureAuthority Variable
191**/
192BOOLEAN
193IsSecureAuthorityVariable (
194  IN CHAR16                                 *VariableName,
195  IN EFI_GUID                               *VendorGuid
196  )
197{
198  UINTN   Index;
199
200  for (Index = 0; Index < sizeof(mVariableType)/sizeof(mVariableType[0]); Index++) {
201    if ((StrCmp (VariableName, mVariableType[Index].VariableName) == 0) &&
202        (CompareGuid (VendorGuid, mVariableType[Index].VendorGuid))) {
203      return TRUE;
204    }
205  }
206  return FALSE;
207}
208
209/**
210  Measure and log an EFI variable, and extend the measurement result into a specific PCR.
211
212  @param[in]  VarName           A Null-terminated string that is the name of the vendor's variable.
213  @param[in]  VendorGuid        A unique identifier for the vendor.
214  @param[in]  VarData           The content of the variable data.
215  @param[in]  VarSize           The size of the variable data.
216
217  @retval EFI_SUCCESS           Operation completed successfully.
218  @retval EFI_OUT_OF_RESOURCES  Out of memory.
219  @retval EFI_DEVICE_ERROR      The operation was unsuccessful.
220
221**/
222EFI_STATUS
223EFIAPI
224MeasureVariable (
225  IN      CHAR16                    *VarName,
226  IN      EFI_GUID                  *VendorGuid,
227  IN      VOID                      *VarData,
228  IN      UINTN                     VarSize
229  )
230{
231  EFI_STATUS                        Status;
232  UINTN                             VarNameLength;
233  EFI_VARIABLE_DATA_TREE            *VarLog;
234  UINT32                            VarLogSize;
235
236  //
237  // The EFI_VARIABLE_DATA_TREE.VariableData value shall be the EFI_SIGNATURE_DATA value
238  // from the EFI_SIGNATURE_LIST that contained the authority that was used to validate the image
239  //
240  VarNameLength      = StrLen (VarName);
241  VarLogSize = (UINT32)(sizeof (*VarLog) + VarNameLength * sizeof (*VarName) + VarSize
242                        - sizeof (VarLog->UnicodeName) - sizeof (VarLog->VariableData));
243
244  VarLog = (EFI_VARIABLE_DATA_TREE *) AllocateZeroPool (VarLogSize);
245  if (VarLog == NULL) {
246    return EFI_OUT_OF_RESOURCES;
247  }
248
249  CopyMem (&VarLog->VariableName, VendorGuid, sizeof(VarLog->VariableName));
250  VarLog->UnicodeNameLength  = VarNameLength;
251  VarLog->VariableDataLength = VarSize;
252  CopyMem (
253     VarLog->UnicodeName,
254     VarName,
255     VarNameLength * sizeof (*VarName)
256     );
257  CopyMem (
258     (CHAR16 *)VarLog->UnicodeName + VarNameLength,
259     VarData,
260     VarSize
261     );
262
263  DEBUG ((EFI_D_INFO, "DxeImageVerification: MeasureVariable (Pcr - %x, EventType - %x, ", (UINTN)7, (UINTN)EV_EFI_VARIABLE_AUTHORITY));
264  DEBUG ((EFI_D_INFO, "VariableName - %s, VendorGuid - %g)\n", VarName, VendorGuid));
265
266  Status = TpmMeasureAndLogData (
267             7,
268             EV_EFI_VARIABLE_AUTHORITY,
269             VarLog,
270             VarLogSize,
271             VarLog,
272             VarLogSize
273             );
274  FreePool (VarLog);
275
276  return Status;
277}
278
279/**
280  SecureBoot Hook for processing image verification.
281
282  @param[in] VariableName                 Name of Variable to be found.
283  @param[in] VendorGuid                   Variable vendor GUID.
284  @param[in] DataSize                     Size of Data found. If size is less than the
285                                          data, this value contains the required size.
286  @param[in] Data                         Data pointer.
287
288**/
289VOID
290EFIAPI
291SecureBootHook (
292  IN CHAR16                                 *VariableName,
293  IN EFI_GUID                               *VendorGuid,
294  IN UINTN                                  DataSize,
295  IN VOID                                   *Data
296  )
297{
298  EFI_STATUS                        Status;
299
300  if (!IsSecureAuthorityVariable (VariableName, VendorGuid)) {
301    return ;
302  }
303
304  if (IsDataMeasured (VariableName, VendorGuid, Data, DataSize)) {
305    DEBUG ((EFI_D_ERROR, "MeasureSecureAuthorityVariable - IsDataMeasured\n"));
306    return ;
307  }
308
309  Status = MeasureVariable (
310             VariableName,
311             VendorGuid,
312             Data,
313             DataSize
314             );
315  DEBUG ((EFI_D_INFO, "MeasureBootPolicyVariable - %r\n", Status));
316
317  if (!EFI_ERROR (Status)) {
318    AddDataMeasured (VariableName, VendorGuid, Data, DataSize);
319  }
320
321  return ;
322}
323