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