]> git.proxmox.com Git - mirror_edk2.git/blame - SecurityPkg/Library/SecureBootVariableLib/SecureBootVariableLib.c
SecurityPkg: SecureBootVariableLib: Added newly supported interfaces
[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
6de7c084 13#include <UefiSecureBoot.h>\r
bb806a6e
GB
14#include <Guid/GlobalVariable.h>\r
15#include <Guid/AuthenticatedVariableFormat.h>\r
16#include <Guid/ImageAuthentication.h>\r
bb806a6e
GB
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
6eb40794 24#include <Library/PlatformPKProtectionLib.h>\r
bb806a6e 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
6eb40794 41//\r
42// This epoch time is the date that is used when creating SecureBoot default variables.\r
43// NOTE: This is a placeholder date that doesn't correspond to anything else.\r
44//\r
45EFI_TIME mDefaultPayloadTimestamp = {\r
46 1970, // Year (1970)\r
47 1, // Month (Jan)\r
48 1, // Day (1)\r
49 0, // Hour\r
50 0, // Minute\r
51 0, // Second\r
52 0, // Pad1\r
53 0, // Nanosecond\r
54 0, // Timezone (Dummy value)\r
55 0, // Daylight (Dummy value)\r
56 0 // Pad2\r
57};\r
58\r
bb806a6e
GB
59/** Creates EFI Signature List structure.\r
60\r
61 @param[in] Data A pointer to signature data.\r
62 @param[in] Size Size of signature data.\r
63 @param[out] SigList Created Signature List.\r
64\r
65 @retval EFI_SUCCESS Signature List was created successfully.\r
66 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
67**/\r
68STATIC\r
69EFI_STATUS\r
70CreateSigList (\r
c411b485
MK
71 IN VOID *Data,\r
72 IN UINTN Size,\r
73 OUT EFI_SIGNATURE_LIST **SigList\r
bb806a6e
GB
74 )\r
75{\r
c411b485
MK
76 UINTN SigListSize;\r
77 EFI_SIGNATURE_LIST *TmpSigList;\r
78 EFI_SIGNATURE_DATA *SigData;\r
bb806a6e
GB
79\r
80 //\r
81 // Allocate data for Signature Database\r
82 //\r
83 SigListSize = sizeof (EFI_SIGNATURE_LIST) + sizeof (EFI_SIGNATURE_DATA) - 1 + Size;\r
c411b485 84 TmpSigList = (EFI_SIGNATURE_LIST *)AllocateZeroPool (SigListSize);\r
bb806a6e
GB
85 if (TmpSigList == NULL) {\r
86 return EFI_OUT_OF_RESOURCES;\r
87 }\r
88\r
89 //\r
90 // Only gEfiCertX509Guid type is supported\r
91 //\r
c411b485
MK
92 TmpSigList->SignatureListSize = (UINT32)SigListSize;\r
93 TmpSigList->SignatureSize = (UINT32)(sizeof (EFI_SIGNATURE_DATA) - 1 + Size);\r
bb806a6e
GB
94 TmpSigList->SignatureHeaderSize = 0;\r
95 CopyGuid (&TmpSigList->SignatureType, &gEfiCertX509Guid);\r
96\r
97 //\r
98 // Copy key data\r
99 //\r
c411b485 100 SigData = (EFI_SIGNATURE_DATA *)(TmpSigList + 1);\r
bb806a6e
GB
101 CopyGuid (&SigData->SignatureOwner, &gEfiGlobalVariableGuid);\r
102 CopyMem (&SigData->SignatureData[0], Data, Size);\r
103\r
104 *SigList = TmpSigList;\r
105\r
106 return EFI_SUCCESS;\r
107}\r
108\r
109/** Adds new signature list to signature database.\r
110\r
111 @param[in] SigLists A pointer to signature database.\r
112 @param[in] SigListAppend A signature list to be added.\r
113 @param[out] *SigListOut Created signature database.\r
114 @param[in, out] SigListsSize A size of created signature database.\r
115\r
116 @retval EFI_SUCCESS Signature List was added successfully.\r
117 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
118**/\r
119STATIC\r
120EFI_STATUS\r
121ConcatenateSigList (\r
c411b485
MK
122 IN EFI_SIGNATURE_LIST *SigLists,\r
123 IN EFI_SIGNATURE_LIST *SigListAppend,\r
124 OUT EFI_SIGNATURE_LIST **SigListOut,\r
125 IN OUT UINTN *SigListsSize\r
126 )\r
bb806a6e 127{\r
c411b485
MK
128 EFI_SIGNATURE_LIST *TmpSigList;\r
129 UINT8 *Offset;\r
130 UINTN NewSigListsSize;\r
bb806a6e
GB
131\r
132 NewSigListsSize = *SigListsSize + SigListAppend->SignatureListSize;\r
133\r
c411b485 134 TmpSigList = (EFI_SIGNATURE_LIST *)AllocateZeroPool (NewSigListsSize);\r
bb806a6e
GB
135 if (TmpSigList == NULL) {\r
136 return EFI_OUT_OF_RESOURCES;\r
137 }\r
138\r
139 CopyMem (TmpSigList, SigLists, *SigListsSize);\r
140\r
c411b485 141 Offset = (UINT8 *)TmpSigList;\r
bb806a6e
GB
142 Offset += *SigListsSize;\r
143 CopyMem ((VOID *)Offset, SigListAppend, SigListAppend->SignatureListSize);\r
144\r
145 *SigListsSize = NewSigListsSize;\r
c411b485 146 *SigListOut = TmpSigList;\r
bb806a6e
GB
147 return EFI_SUCCESS;\r
148}\r
149\r
150/**\r
6de7c084 151 Create a EFI Signature List with data supplied from input argument.\r
152 The input certificates from KeyInfo parameter should be DER-encoded\r
153 format.\r
bb806a6e 154\r
bb806a6e 155 @param[out] SigListsSize A pointer to size of signature list\r
6de7c084 156 @param[out] SigListOut A pointer to a callee-allocated buffer with signature lists\r
157 @param[in] KeyInfoCount The number of certificate pointer and size pairs inside KeyInfo.\r
158 @param[in] KeyInfo A pointer to all certificates, in the format of DER-encoded,\r
159 to be concatenated into signature lists.\r
bb806a6e 160\r
6de7c084 161 @retval EFI_SUCCESS Created signature list from payload successfully.\r
bb806a6e 162 @retval EFI_NOT_FOUND Section with key has not been found.\r
6de7c084 163 @retval EFI_INVALID_PARAMETER Embedded key has a wrong format or input pointers are NULL.\r
bb806a6e
GB
164 @retval Others Unexpected error happens.\r
165\r
166**/\r
167EFI_STATUS\r
6de7c084 168EFIAPI\r
169SecureBootCreateDataFromInput (\r
170 OUT UINTN *SigListsSize,\r
171 OUT EFI_SIGNATURE_LIST **SigListOut,\r
172 IN UINTN KeyInfoCount,\r
173 IN CONST SECURE_BOOT_CERTIFICATE_INFO *KeyInfo\r
c411b485 174 )\r
bb806a6e 175{\r
c411b485
MK
176 EFI_SIGNATURE_LIST *EfiSig;\r
177 EFI_SIGNATURE_LIST *TmpEfiSig;\r
178 EFI_SIGNATURE_LIST *TmpEfiSig2;\r
179 EFI_STATUS Status;\r
180 VOID *Buffer;\r
bb806a6e 181 UINTN Size;\r
6de7c084 182 UINTN InputIndex;\r
bb806a6e
GB
183 UINTN KeyIndex;\r
184\r
6de7c084 185 if ((SigListOut == NULL) || (SigListsSize == NULL)) {\r
186 return EFI_INVALID_PARAMETER;\r
187 }\r
188\r
189 if ((KeyInfoCount == 0) || (KeyInfo == NULL)) {\r
190 return EFI_INVALID_PARAMETER;\r
191 }\r
192\r
193 InputIndex = 0;\r
c411b485
MK
194 KeyIndex = 0;\r
195 EfiSig = NULL;\r
bb806a6e 196 *SigListsSize = 0;\r
6de7c084 197 while (InputIndex < KeyInfoCount) {\r
198 if (KeyInfo[InputIndex].Data != NULL) {\r
199 Size = KeyInfo[InputIndex].DataSize;\r
200 Buffer = AllocateCopyPool (Size, KeyInfo[InputIndex].Data);\r
201 if (Buffer == NULL) {\r
bb806a6e 202 if (EfiSig != NULL) {\r
c411b485 203 FreePool (EfiSig);\r
bb806a6e 204 }\r
c411b485 205\r
6de7c084 206 return EFI_OUT_OF_RESOURCES;\r
bb806a6e
GB
207 }\r
208\r
209 Status = CreateSigList (Buffer, Size, &TmpEfiSig);\r
210\r
6de7c084 211 if (EFI_ERROR (Status)) {\r
212 FreePool (Buffer);\r
213 break;\r
214 }\r
215\r
bb806a6e
GB
216 //\r
217 // Concatenate lists if more than one section found\r
218 //\r
219 if (KeyIndex == 0) {\r
c411b485 220 EfiSig = TmpEfiSig;\r
bb806a6e
GB
221 *SigListsSize = TmpEfiSig->SignatureListSize;\r
222 } else {\r
223 ConcatenateSigList (EfiSig, TmpEfiSig, &TmpEfiSig2, SigListsSize);\r
224 FreePool (EfiSig);\r
225 FreePool (TmpEfiSig);\r
226 EfiSig = TmpEfiSig2;\r
227 }\r
228\r
229 KeyIndex++;\r
230 FreePool (Buffer);\r
c411b485
MK
231 }\r
232\r
6de7c084 233 InputIndex++;\r
c411b485 234 }\r
bb806a6e
GB
235\r
236 if (KeyIndex == 0) {\r
237 return EFI_NOT_FOUND;\r
238 }\r
239\r
240 *SigListOut = EfiSig;\r
241\r
242 return EFI_SUCCESS;\r
243}\r
244\r
245/**\r
246 Create a time based data payload by concatenating the EFI_VARIABLE_AUTHENTICATION_2\r
247 descriptor with the input data. NO authentication is required in this function.\r
248\r
249 @param[in, out] DataSize On input, the size of Data buffer in bytes.\r
250 On output, the size of data returned in Data\r
251 buffer in bytes.\r
252 @param[in, out] Data On input, Pointer to data buffer to be wrapped or\r
253 pointer to NULL to wrap an empty payload.\r
254 On output, Pointer to the new payload date buffer allocated from pool,\r
255 it's caller's responsibility to free the memory when finish using it.\r
56c717aa 256 @param[in] Time Pointer to time information to created time based payload.\r
bb806a6e
GB
257\r
258 @retval EFI_SUCCESS Create time based payload successfully.\r
259 @retval EFI_OUT_OF_RESOURCES There are not enough memory resources to create time based payload.\r
260 @retval EFI_INVALID_PARAMETER The parameter is invalid.\r
261 @retval Others Unexpected error happens.\r
262\r
56c717aa 263--*/\r
bb806a6e 264EFI_STATUS\r
56c717aa 265EFIAPI\r
bb806a6e 266CreateTimeBasedPayload (\r
56c717aa
KQ
267 IN OUT UINTN *DataSize,\r
268 IN OUT UINT8 **Data,\r
269 IN EFI_TIME *Time\r
bb806a6e
GB
270 )\r
271{\r
c411b485
MK
272 UINT8 *NewData;\r
273 UINT8 *Payload;\r
274 UINTN PayloadSize;\r
275 EFI_VARIABLE_AUTHENTICATION_2 *DescriptorData;\r
276 UINTN DescriptorSize;\r
c411b485 277\r
56c717aa
KQ
278 if ((Data == NULL) || (DataSize == NULL) || (Time == NULL)) {\r
279 DEBUG ((DEBUG_ERROR, "%a(), invalid arg\n", __FUNCTION__));\r
bb806a6e
GB
280 return EFI_INVALID_PARAMETER;\r
281 }\r
282\r
283 //\r
284 // In Setup mode or Custom mode, the variable does not need to be signed but the\r
285 // parameters to the SetVariable() call still need to be prepared as authenticated\r
286 // variable. So we create EFI_VARIABLE_AUTHENTICATED_2 descriptor without certificate\r
287 // data in it.\r
288 //\r
289 Payload = *Data;\r
290 PayloadSize = *DataSize;\r
291\r
c411b485
MK
292 DescriptorSize = OFFSET_OF (EFI_VARIABLE_AUTHENTICATION_2, AuthInfo) + OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData);\r
293 NewData = (UINT8 *)AllocateZeroPool (DescriptorSize + PayloadSize);\r
bb806a6e 294 if (NewData == NULL) {\r
56c717aa 295 DEBUG ((DEBUG_ERROR, "%a() Out of resources.\n", __FUNCTION__));\r
bb806a6e
GB
296 return EFI_OUT_OF_RESOURCES;\r
297 }\r
298\r
299 if ((Payload != NULL) && (PayloadSize != 0)) {\r
300 CopyMem (NewData + DescriptorSize, Payload, PayloadSize);\r
301 }\r
302\r
c411b485 303 DescriptorData = (EFI_VARIABLE_AUTHENTICATION_2 *)(NewData);\r
bb806a6e 304\r
56c717aa 305 CopyMem (&DescriptorData->TimeStamp, Time, sizeof (EFI_TIME));\r
bb806a6e
GB
306\r
307 DescriptorData->AuthInfo.Hdr.dwLength = OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData);\r
308 DescriptorData->AuthInfo.Hdr.wRevision = 0x0200;\r
309 DescriptorData->AuthInfo.Hdr.wCertificateType = WIN_CERT_TYPE_EFI_GUID;\r
310 CopyGuid (&DescriptorData->AuthInfo.CertType, &gEfiCertPkcs7Guid);\r
311\r
312 if (Payload != NULL) {\r
c411b485 313 FreePool (Payload);\r
56c717aa 314 Payload = NULL;\r
bb806a6e
GB
315 }\r
316\r
317 *DataSize = DescriptorSize + PayloadSize;\r
318 *Data = NewData;\r
319 return EFI_SUCCESS;\r
320}\r
321\r
322/**\r
323 Internal helper function to delete a Variable given its name and GUID, NO authentication\r
324 required.\r
325\r
326 @param[in] VariableName Name of the Variable.\r
327 @param[in] VendorGuid GUID of the Variable.\r
328\r
329 @retval EFI_SUCCESS Variable deleted successfully.\r
330 @retval Others The driver failed to start the device.\r
331\r
332**/\r
333EFI_STATUS\r
56c717aa 334EFIAPI\r
bb806a6e 335DeleteVariable (\r
c411b485
MK
336 IN CHAR16 *VariableName,\r
337 IN EFI_GUID *VendorGuid\r
bb806a6e
GB
338 )\r
339{\r
c411b485
MK
340 EFI_STATUS Status;\r
341 VOID *Variable;\r
342 UINT8 *Data;\r
343 UINTN DataSize;\r
344 UINT32 Attr;\r
bb806a6e
GB
345\r
346 GetVariable2 (VariableName, VendorGuid, &Variable, NULL);\r
347 if (Variable == NULL) {\r
348 return EFI_SUCCESS;\r
349 }\r
c411b485 350\r
bb806a6e
GB
351 FreePool (Variable);\r
352\r
353 Data = NULL;\r
354 DataSize = 0;\r
355 Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS\r
356 | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;\r
357\r
56c717aa 358 Status = CreateTimeBasedPayload (&DataSize, &Data, &mMaxTimestamp);\r
bb806a6e
GB
359 if (EFI_ERROR (Status)) {\r
360 DEBUG ((DEBUG_ERROR, "Fail to create time-based data payload: %r", Status));\r
361 return Status;\r
362 }\r
363\r
364 Status = gRT->SetVariable (\r
365 VariableName,\r
366 VendorGuid,\r
367 Attr,\r
368 DataSize,\r
369 Data\r
370 );\r
371 if (Data != NULL) {\r
372 FreePool (Data);\r
373 }\r
c411b485 374\r
bb806a6e
GB
375 return Status;\r
376}\r
377\r
378/**\r
379\r
380 Set the platform secure boot mode into "Custom" or "Standard" mode.\r
381\r
382 @param[in] SecureBootMode New secure boot mode: STANDARD_SECURE_BOOT_MODE or\r
383 CUSTOM_SECURE_BOOT_MODE.\r
384\r
385 @return EFI_SUCCESS The platform has switched to the special mode successfully.\r
386 @return other Fail to operate the secure boot mode.\r
387\r
388**/\r
389EFI_STATUS\r
56c717aa 390EFIAPI\r
bb806a6e
GB
391SetSecureBootMode (\r
392 IN UINT8 SecureBootMode\r
393 )\r
394{\r
395 return gRT->SetVariable (\r
396 EFI_CUSTOM_MODE_NAME,\r
397 &gEfiCustomModeEnableGuid,\r
398 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
399 sizeof (UINT8),\r
400 &SecureBootMode\r
401 );\r
402}\r
403\r
404/**\r
405 Fetches the value of SetupMode variable.\r
406\r
407 @param[out] SetupMode Pointer to UINT8 for SetupMode output\r
408\r
409 @retval other Retval from GetVariable.\r
410**/\r
411EFI_STATUS\r
412EFIAPI\r
413GetSetupMode (\r
c411b485
MK
414 OUT UINT8 *SetupMode\r
415 )\r
bb806a6e 416{\r
c411b485
MK
417 UINTN Size;\r
418 EFI_STATUS Status;\r
bb806a6e 419\r
c411b485 420 Size = sizeof (*SetupMode);\r
bb806a6e
GB
421 Status = gRT->GetVariable (\r
422 EFI_SETUP_MODE_NAME,\r
423 &gEfiGlobalVariableGuid,\r
424 NULL,\r
425 &Size,\r
426 SetupMode\r
427 );\r
428 if (EFI_ERROR (Status)) {\r
429 return Status;\r
430 }\r
431\r
432 return EFI_SUCCESS;\r
433}\r
434\r
6eb40794 435/**\r
436 Helper function to quickly determine whether SecureBoot is enabled.\r
437\r
438 @retval TRUE SecureBoot is verifiably enabled.\r
439 @retval FALSE SecureBoot is either disabled or an error prevented checking.\r
440\r
441**/\r
442BOOLEAN\r
443EFIAPI\r
444IsSecureBootEnabled (\r
445 VOID\r
446 )\r
447{\r
448 EFI_STATUS Status;\r
449 UINT8 *SecureBoot;\r
450\r
451 SecureBoot = NULL;\r
452\r
453 Status = GetEfiGlobalVariable2 (EFI_SECURE_BOOT_MODE_NAME, (VOID **)&SecureBoot, NULL);\r
454 //\r
455 // Skip verification if SecureBoot variable doesn't exist.\r
456 //\r
457 if (EFI_ERROR (Status)) {\r
458 DEBUG ((DEBUG_ERROR, "Cannot check SecureBoot variable %r \n ", Status));\r
459 return FALSE;\r
460 }\r
461\r
462 //\r
463 // Skip verification if SecureBoot is disabled but not AuditMode\r
464 //\r
465 if (*SecureBoot == SECURE_BOOT_MODE_DISABLE) {\r
466 FreePool (SecureBoot);\r
467 return FALSE;\r
468 } else {\r
469 return TRUE;\r
470 }\r
471}\r
472\r
bb806a6e
GB
473/**\r
474 Clears the content of the 'db' variable.\r
475\r
476 @retval EFI_OUT_OF_RESOURCES If memory allocation for EFI_VARIABLE_AUTHENTICATION_2 fails\r
477 while VendorGuid is NULL.\r
478 @retval other Errors from GetVariable2 (), GetTime () and SetVariable ()\r
479**/\r
480EFI_STATUS\r
481EFIAPI\r
482DeleteDb (\r
483 VOID\r
c411b485 484 )\r
bb806a6e 485{\r
c411b485 486 EFI_STATUS Status;\r
bb806a6e
GB
487\r
488 Status = DeleteVariable (\r
489 EFI_IMAGE_SECURITY_DATABASE,\r
490 &gEfiImageSecurityDatabaseGuid\r
491 );\r
492\r
493 return Status;\r
494}\r
495\r
496/**\r
497 Clears the content of the 'dbx' variable.\r
498\r
499 @retval EFI_OUT_OF_RESOURCES If memory allocation for EFI_VARIABLE_AUTHENTICATION_2 fails\r
500 while VendorGuid is NULL.\r
501 @retval other Errors from GetVariable2 (), GetTime () and SetVariable ()\r
502**/\r
503EFI_STATUS\r
504EFIAPI\r
505DeleteDbx (\r
506 VOID\r
c411b485 507 )\r
bb806a6e 508{\r
c411b485 509 EFI_STATUS Status;\r
bb806a6e
GB
510\r
511 Status = DeleteVariable (\r
512 EFI_IMAGE_SECURITY_DATABASE1,\r
513 &gEfiImageSecurityDatabaseGuid\r
514 );\r
515\r
516 return Status;\r
517}\r
518\r
519/**\r
520 Clears the content of the 'dbt' variable.\r
521\r
522 @retval EFI_OUT_OF_RESOURCES If memory allocation for EFI_VARIABLE_AUTHENTICATION_2 fails\r
523 while VendorGuid is NULL.\r
524 @retval other Errors from GetVariable2 (), GetTime () and SetVariable ()\r
525**/\r
526EFI_STATUS\r
527EFIAPI\r
528DeleteDbt (\r
529 VOID\r
c411b485 530 )\r
bb806a6e 531{\r
c411b485 532 EFI_STATUS Status;\r
bb806a6e
GB
533\r
534 Status = DeleteVariable (\r
535 EFI_IMAGE_SECURITY_DATABASE2,\r
536 &gEfiImageSecurityDatabaseGuid\r
537 );\r
538\r
539 return Status;\r
540}\r
541\r
542/**\r
543 Clears the content of the 'KEK' variable.\r
544\r
545 @retval EFI_OUT_OF_RESOURCES If memory allocation for EFI_VARIABLE_AUTHENTICATION_2 fails\r
546 while VendorGuid is NULL.\r
547 @retval other Errors from GetVariable2 (), GetTime () and SetVariable ()\r
548**/\r
549EFI_STATUS\r
550EFIAPI\r
551DeleteKEK (\r
552 VOID\r
c411b485 553 )\r
bb806a6e 554{\r
c411b485 555 EFI_STATUS Status;\r
bb806a6e
GB
556\r
557 Status = DeleteVariable (\r
558 EFI_KEY_EXCHANGE_KEY_NAME,\r
559 &gEfiGlobalVariableGuid\r
560 );\r
561\r
562 return Status;\r
563}\r
564\r
565/**\r
566 Remove the PK variable.\r
567\r
568 @retval EFI_SUCCESS Delete PK successfully.\r
569 @retval Others Could not allow to delete PK.\r
570\r
571**/\r
572EFI_STATUS\r
573EFIAPI\r
574DeletePlatformKey (\r
575 VOID\r
c411b485 576 )\r
bb806a6e 577{\r
c411b485 578 EFI_STATUS Status;\r
bb806a6e 579\r
c411b485 580 Status = SetSecureBootMode (CUSTOM_SECURE_BOOT_MODE);\r
bb806a6e
GB
581 if (EFI_ERROR (Status)) {\r
582 return Status;\r
583 }\r
584\r
585 Status = DeleteVariable (\r
586 EFI_PLATFORM_KEY_NAME,\r
587 &gEfiGlobalVariableGuid\r
588 );\r
589 return Status;\r
590}\r
6eb40794 591\r
592/**\r
593 This function will delete the secure boot keys, thus\r
594 disabling secure boot.\r
595\r
596 @return EFI_SUCCESS or underlying failure code.\r
597**/\r
598EFI_STATUS\r
599EFIAPI\r
600DeleteSecureBootVariables (\r
601 VOID\r
602 )\r
603{\r
604 EFI_STATUS Status, TempStatus;\r
605\r
606 DEBUG ((DEBUG_INFO, "%a - Attempting to delete the Secure Boot variables.\n", __FUNCTION__));\r
607\r
608 //\r
609 // Step 1: Notify that a PK update is coming shortly...\r
610 Status = DisablePKProtection ();\r
611 if (EFI_ERROR (Status)) {\r
612 DEBUG ((DEBUG_ERROR, "%a - Failed to signal PK update start! %r\n", __FUNCTION__, Status));\r
613 // Classify this as a PK deletion error.\r
614 Status = EFI_ABORTED;\r
615 }\r
616\r
617 //\r
618 // Step 2: Attempt to delete the PK.\r
619 // Let's try to nuke the PK, why not...\r
620 if (!EFI_ERROR (Status)) {\r
621 Status = DeletePlatformKey ();\r
622 DEBUG ((DEBUG_INFO, "%a - PK Delete = %r\n", __FUNCTION__, Status));\r
623 // If the PK is not found, then our work here is done.\r
624 if (Status == EFI_NOT_FOUND) {\r
625 Status = EFI_SUCCESS;\r
626 }\r
627 // If any other error occurred, let's inform the caller that the PK delete in particular failed.\r
628 else if (EFI_ERROR (Status)) {\r
629 Status = EFI_ABORTED;\r
630 }\r
631 }\r
632\r
633 //\r
634 // Step 3: Attempt to delete remaining keys/databases...\r
635 // Now that the PK is deleted (assuming Status == EFI_SUCCESS) the system is in SETUP_MODE.\r
636 // Arguably we could leave these variables in place and let them be deleted by whoever wants to\r
637 // update all the SecureBoot variables. However, for cleanliness sake, let's try to\r
638 // get rid of them here.\r
639 if (!EFI_ERROR (Status)) {\r
640 //\r
641 // If any of THESE steps have an error, report the error but attempt to delete all keys.\r
642 // Using TempStatus will prevent an error from being trampled by an EFI_SUCCESS.\r
643 // Overwrite Status ONLY if TempStatus is an error.\r
644 //\r
645 // If the error is EFI_NOT_FOUND, we can safely ignore it since we were trying to delete\r
646 // the variables anyway.\r
647 //\r
648 TempStatus = DeleteKEK ();\r
649 DEBUG ((DEBUG_INFO, "%a - KEK Delete = %r\n", __FUNCTION__, TempStatus));\r
650 if (EFI_ERROR (TempStatus) && (TempStatus != EFI_NOT_FOUND)) {\r
651 Status = EFI_ACCESS_DENIED;\r
652 }\r
653\r
654 TempStatus = DeleteDb ();\r
655 DEBUG ((DEBUG_INFO, "%a - db Delete = %r\n", __FUNCTION__, TempStatus));\r
656 if (EFI_ERROR (TempStatus) && (TempStatus != EFI_NOT_FOUND)) {\r
657 Status = EFI_ACCESS_DENIED;\r
658 }\r
659\r
660 TempStatus = DeleteDbx ();\r
661 DEBUG ((DEBUG_INFO, "%a - dbx Delete = %r\n", __FUNCTION__, TempStatus));\r
662 if (EFI_ERROR (TempStatus) && (TempStatus != EFI_NOT_FOUND)) {\r
663 Status = EFI_ACCESS_DENIED;\r
664 }\r
665\r
666 TempStatus = DeleteDbt ();\r
667 DEBUG ((DEBUG_INFO, "%a - dbt Delete = %r\n", __FUNCTION__, TempStatus));\r
668 if (EFI_ERROR (TempStatus) && (TempStatus != EFI_NOT_FOUND)) {\r
669 Status = EFI_ACCESS_DENIED;\r
670 }\r
671 }\r
672\r
673 return Status;\r
674}// DeleteSecureBootVariables()\r
675\r
676/**\r
677 A helper function to take in a variable payload, wrap it in the\r
678 proper authenticated variable structure, and install it in the\r
679 EFI variable space.\r
680\r
681 @param[in] VariableName The name of the key/database.\r
682 @param[in] VendorGuid The namespace (ie. vendor GUID) of the variable\r
683 @param[in] DataSize Size parameter for target secure boot variable.\r
684 @param[in] Data Pointer to signature list formatted secure boot variable content.\r
685\r
686 @retval EFI_SUCCESS The enrollment for authenticated variable was successful.\r
687 @retval EFI_OUT_OF_RESOURCES There are not enough memory resources to create time based payload.\r
688 @retval EFI_INVALID_PARAMETER The parameter is invalid.\r
689 @retval Others Unexpected error happens.\r
690**/\r
691EFI_STATUS\r
692EFIAPI\r
693EnrollFromInput (\r
694 IN CHAR16 *VariableName,\r
695 IN EFI_GUID *VendorGuid,\r
696 IN UINTN DataSize,\r
697 IN VOID *Data\r
698 )\r
699{\r
700 VOID *Payload;\r
701 UINTN PayloadSize;\r
702 EFI_STATUS Status;\r
703\r
704 Payload = NULL;\r
705\r
706 if ((VariableName == NULL) || (VendorGuid == 0)) {\r
707 DEBUG ((DEBUG_ERROR, "Input vendor variable invalid: %p and %p\n", VariableName, VendorGuid));\r
708 Status = EFI_INVALID_PARAMETER;\r
709 goto Exit;\r
710 }\r
711\r
712 if ((Data == NULL) || (DataSize == 0)) {\r
713 // You might as well just use DeleteVariable...\r
714 DEBUG ((DEBUG_ERROR, "Input argument invalid: %p: %x\n", Data, DataSize));\r
715 Status = EFI_INVALID_PARAMETER;\r
716 goto Exit;\r
717 }\r
718\r
719 // Bring in the noise...\r
720 PayloadSize = DataSize;\r
721 Payload = AllocateZeroPool (DataSize);\r
722 // Bring in the funk...\r
723 if (Payload == NULL) {\r
724 return EFI_OUT_OF_RESOURCES;\r
725 } else {\r
726 CopyMem (Payload, Data, DataSize);\r
727 }\r
728\r
729 Status = CreateTimeBasedPayload (&PayloadSize, (UINT8 **)&Payload, &mDefaultPayloadTimestamp);\r
730 if (EFI_ERROR (Status) || (Payload == NULL)) {\r
731 DEBUG ((DEBUG_ERROR, "Fail to create time-based data payload: %r\n", Status));\r
732 Payload = NULL;\r
733 Status = EFI_OUT_OF_RESOURCES;\r
734 goto Exit;\r
735 }\r
736\r
737 //\r
738 // Allocate memory for auth variable\r
739 //\r
740 Status = gRT->SetVariable (\r
741 VariableName,\r
742 VendorGuid,\r
743 (EFI_VARIABLE_NON_VOLATILE |\r
744 EFI_VARIABLE_BOOTSERVICE_ACCESS |\r
745 EFI_VARIABLE_RUNTIME_ACCESS |\r
746 EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS),\r
747 PayloadSize,\r
748 Payload\r
749 );\r
750\r
751 if (EFI_ERROR (Status)) {\r
752 DEBUG ((\r
753 DEBUG_ERROR,\r
754 "error: %a (\"%s\", %g): %r\n",\r
755 __FUNCTION__,\r
756 VariableName,\r
757 VendorGuid,\r
758 Status\r
759 ));\r
760 }\r
761\r
762Exit:\r
763 //\r
764 // Always Put Away Your Toys\r
765 // Payload will be reassigned by CreateTimeBasedPayload()...\r
766 if (Payload != NULL) {\r
767 FreePool (Payload);\r
768 Payload = NULL;\r
769 }\r
770\r
771 return Status;\r
772}\r
773\r
774/**\r
775 Similar to DeleteSecureBootVariables, this function is used to unilaterally\r
776 force the state of related SB variables (db, dbx, dbt, KEK, PK, etc.) to be\r
777 the built-in, hardcoded default vars.\r
778\r
779 @param[in] SecureBootPayload Payload information for secure boot related keys.\r
780\r
781 @retval EFI_SUCCESS SecureBoot keys are now set to defaults.\r
782 @retval EFI_ABORTED SecureBoot keys are not empty. Please delete keys first\r
783 or follow standard methods of altering keys (ie. use the signing system).\r
784 @retval EFI_SECURITY_VIOLATION Failed to create the PK.\r
785 @retval Others Something failed in one of the subfunctions.\r
786\r
787**/\r
788EFI_STATUS\r
789EFIAPI\r
790SetSecureBootVariablesToDefault (\r
791 IN CONST SECURE_BOOT_PAYLOAD_INFO *SecureBootPayload\r
792 )\r
793{\r
794 EFI_STATUS Status;\r
795 UINT8 *Data;\r
796 UINTN DataSize;\r
797\r
798 DEBUG ((DEBUG_INFO, "%a() Entry\n", __FUNCTION__));\r
799\r
800 if (SecureBootPayload == NULL) {\r
801 DEBUG ((DEBUG_ERROR, "%a - Invalid SecureBoot payload is supplied!\n", __FUNCTION__));\r
802 return EFI_INVALID_PARAMETER;\r
803 }\r
804\r
805 //\r
806 // Right off the bat, if SecureBoot is currently enabled, bail.\r
807 if (IsSecureBootEnabled ()) {\r
808 DEBUG ((DEBUG_ERROR, "%a - Cannot set default keys while SecureBoot is enabled!\n", __FUNCTION__));\r
809 return EFI_ABORTED;\r
810 }\r
811\r
812 DEBUG ((DEBUG_INFO, "%a - Setting up key %s!\n", __FUNCTION__, SecureBootPayload->SecureBootKeyName));\r
813\r
814 //\r
815 // Start running down the list, creating variables in our wake.\r
816 // dbx is a good place to start.\r
817 Data = (UINT8 *)SecureBootPayload->DbxPtr;\r
818 DataSize = SecureBootPayload->DbxSize;\r
819 Status = EnrollFromInput (\r
820 EFI_IMAGE_SECURITY_DATABASE1,\r
821 &gEfiImageSecurityDatabaseGuid,\r
822 DataSize,\r
823 Data\r
824 );\r
825\r
826 // If that went well, try the db (make sure to pick the right one!).\r
827 if (!EFI_ERROR (Status)) {\r
828 Data = (UINT8 *)SecureBootPayload->DbPtr;\r
829 DataSize = SecureBootPayload->DbSize;\r
830 Status = EnrollFromInput (\r
831 EFI_IMAGE_SECURITY_DATABASE,\r
832 &gEfiImageSecurityDatabaseGuid,\r
833 DataSize,\r
834 Data\r
835 );\r
836 if (EFI_ERROR (Status)) {\r
837 DEBUG ((DEBUG_ERROR, "%a - Failed to enroll DB %r!\n", __FUNCTION__, Status));\r
838 }\r
839 } else {\r
840 DEBUG ((DEBUG_ERROR, "%a - Failed to enroll DBX %r!\n", __FUNCTION__, Status));\r
841 }\r
842\r
843 // Keep it going. Keep it going. dbt if supplied...\r
844 if (!EFI_ERROR (Status) && (SecureBootPayload->DbtPtr != NULL)) {\r
845 Data = (UINT8 *)SecureBootPayload->DbtPtr;\r
846 DataSize = SecureBootPayload->DbtSize;\r
847 Status = EnrollFromInput (\r
848 EFI_IMAGE_SECURITY_DATABASE2,\r
849 &gEfiImageSecurityDatabaseGuid,\r
850 DataSize,\r
851 Data\r
852 );\r
853 if (EFI_ERROR (Status)) {\r
854 DEBUG ((DEBUG_ERROR, "%a - Failed to enroll DBT %r!\n", __FUNCTION__, Status));\r
855 }\r
856 }\r
857\r
858 // Keep it going. Keep it going. KEK...\r
859 if (!EFI_ERROR (Status)) {\r
860 Data = (UINT8 *)SecureBootPayload->KekPtr;\r
861 DataSize = SecureBootPayload->KekSize;\r
862 Status = EnrollFromInput (\r
863 EFI_KEY_EXCHANGE_KEY_NAME,\r
864 &gEfiGlobalVariableGuid,\r
865 DataSize,\r
866 Data\r
867 );\r
868 if (EFI_ERROR (Status)) {\r
869 DEBUG ((DEBUG_ERROR, "%a - Failed to enroll KEK %r!\n", __FUNCTION__, Status));\r
870 }\r
871 }\r
872\r
873 //\r
874 // Finally! The Big Daddy of them all.\r
875 // The PK!\r
876 //\r
877 if (!EFI_ERROR (Status)) {\r
878 //\r
879 // Finally, install the key.\r
880 Data = (UINT8 *)SecureBootPayload->PkPtr;\r
881 DataSize = SecureBootPayload->PkSize;\r
882 Status = EnrollFromInput (\r
883 EFI_PLATFORM_KEY_NAME,\r
884 &gEfiGlobalVariableGuid,\r
885 DataSize,\r
886 Data\r
887 );\r
888\r
889 //\r
890 // Report PK creation errors.\r
891 if (EFI_ERROR (Status)) {\r
892 DEBUG ((DEBUG_ERROR, "%a - Failed to update the PK! - %r\n", __FUNCTION__, Status));\r
893 Status = EFI_SECURITY_VIOLATION;\r
894 }\r
895 }\r
896\r
897 return Status;\r
898}\r