]> git.proxmox.com Git - mirror_edk2.git/blame - SecurityPkg/Library/SecureBootVariableLib/SecureBootVariableLib.c
SecurityPkg: SecureBootVariableLib: Updated time based payload creator
[mirror_edk2.git] / SecurityPkg / Library / SecureBootVariableLib / SecureBootVariableLib.c
CommitLineData
bb806a6e
GB
1/** @file\r
2 This library provides helper functions to set/clear Secure Boot\r
3 keys and databases.\r
4\r
5 Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>\r
6 (C) Copyright 2018 Hewlett Packard Enterprise Development LP<BR>\r
7 Copyright (c) 2021, ARM Ltd. All rights reserved.<BR>\r
8 Copyright (c) 2021, Semihalf All rights reserved.<BR>\r
56c717aa 9 Copyright (c) Microsoft Corporation.\r
bb806a6e
GB
10 SPDX-License-Identifier: BSD-2-Clause-Patent\r
11**/\r
56c717aa 12#include <Uefi.h>\r
bb806a6e
GB
13#include <Guid/GlobalVariable.h>\r
14#include <Guid/AuthenticatedVariableFormat.h>\r
15#include <Guid/ImageAuthentication.h>\r
16#include <Library/BaseCryptLib.h>\r
17#include <Library/BaseLib.h>\r
18#include <Library/BaseMemoryLib.h>\r
19#include <Library/DebugLib.h>\r
20#include <Library/UefiLib.h>\r
21#include <Library/MemoryAllocationLib.h>\r
22#include <Library/UefiRuntimeServicesTableLib.h>\r
23#include <Library/SecureBootVariableLib.h>\r
24#include "Library/DxeServicesLib.h"\r
25\r
56c717aa
KQ
26// This time can be used when deleting variables, as it should be greater than any variable time.\r
27EFI_TIME mMaxTimestamp = {\r
28 0xFFFF, // Year\r
29 0xFF, // Month\r
30 0xFF, // Day\r
31 0xFF, // Hour\r
32 0xFF, // Minute\r
33 0xFF, // Second\r
34 0x00,\r
35 0x00000000, // Nanosecond\r
36 0,\r
37 0,\r
38 0x00\r
39};\r
40\r
bb806a6e
GB
41/** Creates EFI Signature List structure.\r
42\r
43 @param[in] Data A pointer to signature data.\r
44 @param[in] Size Size of signature data.\r
45 @param[out] SigList Created Signature List.\r
46\r
47 @retval EFI_SUCCESS Signature List was created successfully.\r
48 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
49**/\r
50STATIC\r
51EFI_STATUS\r
52CreateSigList (\r
c411b485
MK
53 IN VOID *Data,\r
54 IN UINTN Size,\r
55 OUT EFI_SIGNATURE_LIST **SigList\r
bb806a6e
GB
56 )\r
57{\r
c411b485
MK
58 UINTN SigListSize;\r
59 EFI_SIGNATURE_LIST *TmpSigList;\r
60 EFI_SIGNATURE_DATA *SigData;\r
bb806a6e
GB
61\r
62 //\r
63 // Allocate data for Signature Database\r
64 //\r
65 SigListSize = sizeof (EFI_SIGNATURE_LIST) + sizeof (EFI_SIGNATURE_DATA) - 1 + Size;\r
c411b485 66 TmpSigList = (EFI_SIGNATURE_LIST *)AllocateZeroPool (SigListSize);\r
bb806a6e
GB
67 if (TmpSigList == NULL) {\r
68 return EFI_OUT_OF_RESOURCES;\r
69 }\r
70\r
71 //\r
72 // Only gEfiCertX509Guid type is supported\r
73 //\r
c411b485
MK
74 TmpSigList->SignatureListSize = (UINT32)SigListSize;\r
75 TmpSigList->SignatureSize = (UINT32)(sizeof (EFI_SIGNATURE_DATA) - 1 + Size);\r
bb806a6e
GB
76 TmpSigList->SignatureHeaderSize = 0;\r
77 CopyGuid (&TmpSigList->SignatureType, &gEfiCertX509Guid);\r
78\r
79 //\r
80 // Copy key data\r
81 //\r
c411b485 82 SigData = (EFI_SIGNATURE_DATA *)(TmpSigList + 1);\r
bb806a6e
GB
83 CopyGuid (&SigData->SignatureOwner, &gEfiGlobalVariableGuid);\r
84 CopyMem (&SigData->SignatureData[0], Data, Size);\r
85\r
86 *SigList = TmpSigList;\r
87\r
88 return EFI_SUCCESS;\r
89}\r
90\r
91/** Adds new signature list to signature database.\r
92\r
93 @param[in] SigLists A pointer to signature database.\r
94 @param[in] SigListAppend A signature list to be added.\r
95 @param[out] *SigListOut Created signature database.\r
96 @param[in, out] SigListsSize A size of created signature database.\r
97\r
98 @retval EFI_SUCCESS Signature List was added successfully.\r
99 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
100**/\r
101STATIC\r
102EFI_STATUS\r
103ConcatenateSigList (\r
c411b485
MK
104 IN EFI_SIGNATURE_LIST *SigLists,\r
105 IN EFI_SIGNATURE_LIST *SigListAppend,\r
106 OUT EFI_SIGNATURE_LIST **SigListOut,\r
107 IN OUT UINTN *SigListsSize\r
108 )\r
bb806a6e 109{\r
c411b485
MK
110 EFI_SIGNATURE_LIST *TmpSigList;\r
111 UINT8 *Offset;\r
112 UINTN NewSigListsSize;\r
bb806a6e
GB
113\r
114 NewSigListsSize = *SigListsSize + SigListAppend->SignatureListSize;\r
115\r
c411b485 116 TmpSigList = (EFI_SIGNATURE_LIST *)AllocateZeroPool (NewSigListsSize);\r
bb806a6e
GB
117 if (TmpSigList == NULL) {\r
118 return EFI_OUT_OF_RESOURCES;\r
119 }\r
120\r
121 CopyMem (TmpSigList, SigLists, *SigListsSize);\r
122\r
c411b485 123 Offset = (UINT8 *)TmpSigList;\r
bb806a6e
GB
124 Offset += *SigListsSize;\r
125 CopyMem ((VOID *)Offset, SigListAppend, SigListAppend->SignatureListSize);\r
126\r
127 *SigListsSize = NewSigListsSize;\r
c411b485 128 *SigListOut = TmpSigList;\r
bb806a6e
GB
129 return EFI_SUCCESS;\r
130}\r
131\r
132/**\r
133 Create a EFI Signature List with data fetched from section specified as a argument.\r
134 Found keys are verified using RsaGetPublicKeyFromX509().\r
135\r
136 @param[in] KeyFileGuid A pointer to to the FFS filename GUID\r
137 @param[out] SigListsSize A pointer to size of signature list\r
56c717aa 138 @param[out] SigListsOut a pointer to a callee-allocated buffer with signature lists\r
bb806a6e
GB
139\r
140 @retval EFI_SUCCESS Create time based payload successfully.\r
141 @retval EFI_NOT_FOUND Section with key has not been found.\r
142 @retval EFI_INVALID_PARAMETER Embedded key has a wrong format.\r
143 @retval Others Unexpected error happens.\r
144\r
145**/\r
146EFI_STATUS\r
147SecureBootFetchData (\r
c411b485
MK
148 IN EFI_GUID *KeyFileGuid,\r
149 OUT UINTN *SigListsSize,\r
150 OUT EFI_SIGNATURE_LIST **SigListOut\r
151 )\r
bb806a6e 152{\r
c411b485
MK
153 EFI_SIGNATURE_LIST *EfiSig;\r
154 EFI_SIGNATURE_LIST *TmpEfiSig;\r
155 EFI_SIGNATURE_LIST *TmpEfiSig2;\r
156 EFI_STATUS Status;\r
157 VOID *Buffer;\r
158 VOID *RsaPubKey;\r
bb806a6e
GB
159 UINTN Size;\r
160 UINTN KeyIndex;\r
161\r
c411b485
MK
162 KeyIndex = 0;\r
163 EfiSig = NULL;\r
bb806a6e
GB
164 *SigListsSize = 0;\r
165 while (1) {\r
166 Status = GetSectionFromAnyFv (\r
167 KeyFileGuid,\r
168 EFI_SECTION_RAW,\r
169 KeyIndex,\r
170 &Buffer,\r
171 &Size\r
172 );\r
173\r
174 if (Status == EFI_SUCCESS) {\r
175 RsaPubKey = NULL;\r
176 if (RsaGetPublicKeyFromX509 (Buffer, Size, &RsaPubKey) == FALSE) {\r
177 DEBUG ((DEBUG_ERROR, "%a: Invalid key format: %d\n", __FUNCTION__, KeyIndex));\r
178 if (EfiSig != NULL) {\r
c411b485 179 FreePool (EfiSig);\r
bb806a6e 180 }\r
c411b485
MK
181\r
182 FreePool (Buffer);\r
bb806a6e
GB
183 return EFI_INVALID_PARAMETER;\r
184 }\r
185\r
186 Status = CreateSigList (Buffer, Size, &TmpEfiSig);\r
187\r
188 //\r
189 // Concatenate lists if more than one section found\r
190 //\r
191 if (KeyIndex == 0) {\r
c411b485 192 EfiSig = TmpEfiSig;\r
bb806a6e
GB
193 *SigListsSize = TmpEfiSig->SignatureListSize;\r
194 } else {\r
195 ConcatenateSigList (EfiSig, TmpEfiSig, &TmpEfiSig2, SigListsSize);\r
196 FreePool (EfiSig);\r
197 FreePool (TmpEfiSig);\r
198 EfiSig = TmpEfiSig2;\r
199 }\r
200\r
201 KeyIndex++;\r
202 FreePool (Buffer);\r
c411b485
MK
203 }\r
204\r
205 if (Status == EFI_NOT_FOUND) {\r
bb806a6e
GB
206 break;\r
207 }\r
c411b485 208 }\r
bb806a6e
GB
209\r
210 if (KeyIndex == 0) {\r
211 return EFI_NOT_FOUND;\r
212 }\r
213\r
214 *SigListOut = EfiSig;\r
215\r
216 return EFI_SUCCESS;\r
217}\r
218\r
219/**\r
220 Create a time based data payload by concatenating the EFI_VARIABLE_AUTHENTICATION_2\r
221 descriptor with the input data. NO authentication is required in this function.\r
222\r
223 @param[in, out] DataSize On input, the size of Data buffer in bytes.\r
224 On output, the size of data returned in Data\r
225 buffer in bytes.\r
226 @param[in, out] Data On input, Pointer to data buffer to be wrapped or\r
227 pointer to NULL to wrap an empty payload.\r
228 On output, Pointer to the new payload date buffer allocated from pool,\r
229 it's caller's responsibility to free the memory when finish using it.\r
56c717aa 230 @param[in] Time Pointer to time information to created time based payload.\r
bb806a6e
GB
231\r
232 @retval EFI_SUCCESS Create time based payload successfully.\r
233 @retval EFI_OUT_OF_RESOURCES There are not enough memory resources to create time based payload.\r
234 @retval EFI_INVALID_PARAMETER The parameter is invalid.\r
235 @retval Others Unexpected error happens.\r
236\r
56c717aa 237--*/\r
bb806a6e 238EFI_STATUS\r
56c717aa 239EFIAPI\r
bb806a6e 240CreateTimeBasedPayload (\r
56c717aa
KQ
241 IN OUT UINTN *DataSize,\r
242 IN OUT UINT8 **Data,\r
243 IN EFI_TIME *Time\r
bb806a6e
GB
244 )\r
245{\r
c411b485
MK
246 UINT8 *NewData;\r
247 UINT8 *Payload;\r
248 UINTN PayloadSize;\r
249 EFI_VARIABLE_AUTHENTICATION_2 *DescriptorData;\r
250 UINTN DescriptorSize;\r
c411b485 251\r
56c717aa
KQ
252 if ((Data == NULL) || (DataSize == NULL) || (Time == NULL)) {\r
253 DEBUG ((DEBUG_ERROR, "%a(), invalid arg\n", __FUNCTION__));\r
bb806a6e
GB
254 return EFI_INVALID_PARAMETER;\r
255 }\r
256\r
257 //\r
258 // In Setup mode or Custom mode, the variable does not need to be signed but the\r
259 // parameters to the SetVariable() call still need to be prepared as authenticated\r
260 // variable. So we create EFI_VARIABLE_AUTHENTICATED_2 descriptor without certificate\r
261 // data in it.\r
262 //\r
263 Payload = *Data;\r
264 PayloadSize = *DataSize;\r
265\r
c411b485
MK
266 DescriptorSize = OFFSET_OF (EFI_VARIABLE_AUTHENTICATION_2, AuthInfo) + OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData);\r
267 NewData = (UINT8 *)AllocateZeroPool (DescriptorSize + PayloadSize);\r
bb806a6e 268 if (NewData == NULL) {\r
56c717aa 269 DEBUG ((DEBUG_ERROR, "%a() Out of resources.\n", __FUNCTION__));\r
bb806a6e
GB
270 return EFI_OUT_OF_RESOURCES;\r
271 }\r
272\r
273 if ((Payload != NULL) && (PayloadSize != 0)) {\r
274 CopyMem (NewData + DescriptorSize, Payload, PayloadSize);\r
275 }\r
276\r
c411b485 277 DescriptorData = (EFI_VARIABLE_AUTHENTICATION_2 *)(NewData);\r
bb806a6e 278\r
56c717aa 279 CopyMem (&DescriptorData->TimeStamp, Time, sizeof (EFI_TIME));\r
bb806a6e
GB
280\r
281 DescriptorData->AuthInfo.Hdr.dwLength = OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData);\r
282 DescriptorData->AuthInfo.Hdr.wRevision = 0x0200;\r
283 DescriptorData->AuthInfo.Hdr.wCertificateType = WIN_CERT_TYPE_EFI_GUID;\r
284 CopyGuid (&DescriptorData->AuthInfo.CertType, &gEfiCertPkcs7Guid);\r
285\r
286 if (Payload != NULL) {\r
c411b485 287 FreePool (Payload);\r
56c717aa 288 Payload = NULL;\r
bb806a6e
GB
289 }\r
290\r
291 *DataSize = DescriptorSize + PayloadSize;\r
292 *Data = NewData;\r
293 return EFI_SUCCESS;\r
294}\r
295\r
296/**\r
297 Internal helper function to delete a Variable given its name and GUID, NO authentication\r
298 required.\r
299\r
300 @param[in] VariableName Name of the Variable.\r
301 @param[in] VendorGuid GUID of the Variable.\r
302\r
303 @retval EFI_SUCCESS Variable deleted successfully.\r
304 @retval Others The driver failed to start the device.\r
305\r
306**/\r
307EFI_STATUS\r
56c717aa 308EFIAPI\r
bb806a6e 309DeleteVariable (\r
c411b485
MK
310 IN CHAR16 *VariableName,\r
311 IN EFI_GUID *VendorGuid\r
bb806a6e
GB
312 )\r
313{\r
c411b485
MK
314 EFI_STATUS Status;\r
315 VOID *Variable;\r
316 UINT8 *Data;\r
317 UINTN DataSize;\r
318 UINT32 Attr;\r
bb806a6e
GB
319\r
320 GetVariable2 (VariableName, VendorGuid, &Variable, NULL);\r
321 if (Variable == NULL) {\r
322 return EFI_SUCCESS;\r
323 }\r
c411b485 324\r
bb806a6e
GB
325 FreePool (Variable);\r
326\r
327 Data = NULL;\r
328 DataSize = 0;\r
329 Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS\r
330 | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;\r
331\r
56c717aa 332 Status = CreateTimeBasedPayload (&DataSize, &Data, &mMaxTimestamp);\r
bb806a6e
GB
333 if (EFI_ERROR (Status)) {\r
334 DEBUG ((DEBUG_ERROR, "Fail to create time-based data payload: %r", Status));\r
335 return Status;\r
336 }\r
337\r
338 Status = gRT->SetVariable (\r
339 VariableName,\r
340 VendorGuid,\r
341 Attr,\r
342 DataSize,\r
343 Data\r
344 );\r
345 if (Data != NULL) {\r
346 FreePool (Data);\r
347 }\r
c411b485 348\r
bb806a6e
GB
349 return Status;\r
350}\r
351\r
352/**\r
353\r
354 Set the platform secure boot mode into "Custom" or "Standard" mode.\r
355\r
356 @param[in] SecureBootMode New secure boot mode: STANDARD_SECURE_BOOT_MODE or\r
357 CUSTOM_SECURE_BOOT_MODE.\r
358\r
359 @return EFI_SUCCESS The platform has switched to the special mode successfully.\r
360 @return other Fail to operate the secure boot mode.\r
361\r
362**/\r
363EFI_STATUS\r
56c717aa 364EFIAPI\r
bb806a6e
GB
365SetSecureBootMode (\r
366 IN UINT8 SecureBootMode\r
367 )\r
368{\r
369 return gRT->SetVariable (\r
370 EFI_CUSTOM_MODE_NAME,\r
371 &gEfiCustomModeEnableGuid,\r
372 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
373 sizeof (UINT8),\r
374 &SecureBootMode\r
375 );\r
376}\r
377\r
378/**\r
379 Fetches the value of SetupMode variable.\r
380\r
381 @param[out] SetupMode Pointer to UINT8 for SetupMode output\r
382\r
383 @retval other Retval from GetVariable.\r
384**/\r
385EFI_STATUS\r
386EFIAPI\r
387GetSetupMode (\r
c411b485
MK
388 OUT UINT8 *SetupMode\r
389 )\r
bb806a6e 390{\r
c411b485
MK
391 UINTN Size;\r
392 EFI_STATUS Status;\r
bb806a6e 393\r
c411b485 394 Size = sizeof (*SetupMode);\r
bb806a6e
GB
395 Status = gRT->GetVariable (\r
396 EFI_SETUP_MODE_NAME,\r
397 &gEfiGlobalVariableGuid,\r
398 NULL,\r
399 &Size,\r
400 SetupMode\r
401 );\r
402 if (EFI_ERROR (Status)) {\r
403 return Status;\r
404 }\r
405\r
406 return EFI_SUCCESS;\r
407}\r
408\r
409/**\r
410 Clears the content of the 'db' variable.\r
411\r
412 @retval EFI_OUT_OF_RESOURCES If memory allocation for EFI_VARIABLE_AUTHENTICATION_2 fails\r
413 while VendorGuid is NULL.\r
414 @retval other Errors from GetVariable2 (), GetTime () and SetVariable ()\r
415**/\r
416EFI_STATUS\r
417EFIAPI\r
418DeleteDb (\r
419 VOID\r
c411b485 420 )\r
bb806a6e 421{\r
c411b485 422 EFI_STATUS Status;\r
bb806a6e
GB
423\r
424 Status = DeleteVariable (\r
425 EFI_IMAGE_SECURITY_DATABASE,\r
426 &gEfiImageSecurityDatabaseGuid\r
427 );\r
428\r
429 return Status;\r
430}\r
431\r
432/**\r
433 Clears the content of the 'dbx' variable.\r
434\r
435 @retval EFI_OUT_OF_RESOURCES If memory allocation for EFI_VARIABLE_AUTHENTICATION_2 fails\r
436 while VendorGuid is NULL.\r
437 @retval other Errors from GetVariable2 (), GetTime () and SetVariable ()\r
438**/\r
439EFI_STATUS\r
440EFIAPI\r
441DeleteDbx (\r
442 VOID\r
c411b485 443 )\r
bb806a6e 444{\r
c411b485 445 EFI_STATUS Status;\r
bb806a6e
GB
446\r
447 Status = DeleteVariable (\r
448 EFI_IMAGE_SECURITY_DATABASE1,\r
449 &gEfiImageSecurityDatabaseGuid\r
450 );\r
451\r
452 return Status;\r
453}\r
454\r
455/**\r
456 Clears the content of the 'dbt' variable.\r
457\r
458 @retval EFI_OUT_OF_RESOURCES If memory allocation for EFI_VARIABLE_AUTHENTICATION_2 fails\r
459 while VendorGuid is NULL.\r
460 @retval other Errors from GetVariable2 (), GetTime () and SetVariable ()\r
461**/\r
462EFI_STATUS\r
463EFIAPI\r
464DeleteDbt (\r
465 VOID\r
c411b485 466 )\r
bb806a6e 467{\r
c411b485 468 EFI_STATUS Status;\r
bb806a6e
GB
469\r
470 Status = DeleteVariable (\r
471 EFI_IMAGE_SECURITY_DATABASE2,\r
472 &gEfiImageSecurityDatabaseGuid\r
473 );\r
474\r
475 return Status;\r
476}\r
477\r
478/**\r
479 Clears the content of the 'KEK' variable.\r
480\r
481 @retval EFI_OUT_OF_RESOURCES If memory allocation for EFI_VARIABLE_AUTHENTICATION_2 fails\r
482 while VendorGuid is NULL.\r
483 @retval other Errors from GetVariable2 (), GetTime () and SetVariable ()\r
484**/\r
485EFI_STATUS\r
486EFIAPI\r
487DeleteKEK (\r
488 VOID\r
c411b485 489 )\r
bb806a6e 490{\r
c411b485 491 EFI_STATUS Status;\r
bb806a6e
GB
492\r
493 Status = DeleteVariable (\r
494 EFI_KEY_EXCHANGE_KEY_NAME,\r
495 &gEfiGlobalVariableGuid\r
496 );\r
497\r
498 return Status;\r
499}\r
500\r
501/**\r
502 Remove the PK variable.\r
503\r
504 @retval EFI_SUCCESS Delete PK successfully.\r
505 @retval Others Could not allow to delete PK.\r
506\r
507**/\r
508EFI_STATUS\r
509EFIAPI\r
510DeletePlatformKey (\r
511 VOID\r
c411b485 512 )\r
bb806a6e 513{\r
c411b485 514 EFI_STATUS Status;\r
bb806a6e 515\r
c411b485 516 Status = SetSecureBootMode (CUSTOM_SECURE_BOOT_MODE);\r
bb806a6e
GB
517 if (EFI_ERROR (Status)) {\r
518 return Status;\r
519 }\r
520\r
521 Status = DeleteVariable (\r
522 EFI_PLATFORM_KEY_NAME,\r
523 &gEfiGlobalVariableGuid\r
524 );\r
525 return Status;\r
526}\r