]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - SecurityPkg/Library/SecureBootVariableLib/SecureBootVariableLib.c
SecurityPkg: SecureBootVariableLib: Updated signature list creator
[mirror_edk2.git] / SecurityPkg / Library / SecureBootVariableLib / SecureBootVariableLib.c
... / ...
CommitLineData
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
9 Copyright (c) Microsoft Corporation.\r
10 SPDX-License-Identifier: BSD-2-Clause-Patent\r
11**/\r
12#include <Uefi.h>\r
13#include <UefiSecureBoot.h>\r
14#include <Guid/GlobalVariable.h>\r
15#include <Guid/AuthenticatedVariableFormat.h>\r
16#include <Guid/ImageAuthentication.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\r
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
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
52 IN VOID *Data,\r
53 IN UINTN Size,\r
54 OUT EFI_SIGNATURE_LIST **SigList\r
55 )\r
56{\r
57 UINTN SigListSize;\r
58 EFI_SIGNATURE_LIST *TmpSigList;\r
59 EFI_SIGNATURE_DATA *SigData;\r
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
65 TmpSigList = (EFI_SIGNATURE_LIST *)AllocateZeroPool (SigListSize);\r
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
73 TmpSigList->SignatureListSize = (UINT32)SigListSize;\r
74 TmpSigList->SignatureSize = (UINT32)(sizeof (EFI_SIGNATURE_DATA) - 1 + Size);\r
75 TmpSigList->SignatureHeaderSize = 0;\r
76 CopyGuid (&TmpSigList->SignatureType, &gEfiCertX509Guid);\r
77\r
78 //\r
79 // Copy key data\r
80 //\r
81 SigData = (EFI_SIGNATURE_DATA *)(TmpSigList + 1);\r
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
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
108{\r
109 EFI_SIGNATURE_LIST *TmpSigList;\r
110 UINT8 *Offset;\r
111 UINTN NewSigListsSize;\r
112\r
113 NewSigListsSize = *SigListsSize + SigListAppend->SignatureListSize;\r
114\r
115 TmpSigList = (EFI_SIGNATURE_LIST *)AllocateZeroPool (NewSigListsSize);\r
116 if (TmpSigList == NULL) {\r
117 return EFI_OUT_OF_RESOURCES;\r
118 }\r
119\r
120 CopyMem (TmpSigList, SigLists, *SigListsSize);\r
121\r
122 Offset = (UINT8 *)TmpSigList;\r
123 Offset += *SigListsSize;\r
124 CopyMem ((VOID *)Offset, SigListAppend, SigListAppend->SignatureListSize);\r
125\r
126 *SigListsSize = NewSigListsSize;\r
127 *SigListOut = TmpSigList;\r
128 return EFI_SUCCESS;\r
129}\r
130\r
131/**\r
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
135\r
136 @param[out] SigListsSize A pointer to size of signature list\r
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
141\r
142 @retval EFI_SUCCESS Created signature list from payload successfully.\r
143 @retval EFI_NOT_FOUND Section with key has not been found.\r
144 @retval EFI_INVALID_PARAMETER Embedded key has a wrong format or input pointers are NULL.\r
145 @retval Others Unexpected error happens.\r
146\r
147**/\r
148EFI_STATUS\r
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
155 )\r
156{\r
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
162 UINTN Size;\r
163 UINTN InputIndex;\r
164 UINTN KeyIndex;\r
165\r
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
175 KeyIndex = 0;\r
176 EfiSig = NULL;\r
177 *SigListsSize = 0;\r
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
183 if (EfiSig != NULL) {\r
184 FreePool (EfiSig);\r
185 }\r
186\r
187 return EFI_OUT_OF_RESOURCES;\r
188 }\r
189\r
190 Status = CreateSigList (Buffer, Size, &TmpEfiSig);\r
191\r
192 if (EFI_ERROR (Status)) {\r
193 FreePool (Buffer);\r
194 break;\r
195 }\r
196\r
197 //\r
198 // Concatenate lists if more than one section found\r
199 //\r
200 if (KeyIndex == 0) {\r
201 EfiSig = TmpEfiSig;\r
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
212 }\r
213\r
214 InputIndex++;\r
215 }\r
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
237 @param[in] Time Pointer to time information to created time based payload.\r
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
244--*/\r
245EFI_STATUS\r
246EFIAPI\r
247CreateTimeBasedPayload (\r
248 IN OUT UINTN *DataSize,\r
249 IN OUT UINT8 **Data,\r
250 IN EFI_TIME *Time\r
251 )\r
252{\r
253 UINT8 *NewData;\r
254 UINT8 *Payload;\r
255 UINTN PayloadSize;\r
256 EFI_VARIABLE_AUTHENTICATION_2 *DescriptorData;\r
257 UINTN DescriptorSize;\r
258\r
259 if ((Data == NULL) || (DataSize == NULL) || (Time == NULL)) {\r
260 DEBUG ((DEBUG_ERROR, "%a(), invalid arg\n", __FUNCTION__));\r
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
273 DescriptorSize = OFFSET_OF (EFI_VARIABLE_AUTHENTICATION_2, AuthInfo) + OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData);\r
274 NewData = (UINT8 *)AllocateZeroPool (DescriptorSize + PayloadSize);\r
275 if (NewData == NULL) {\r
276 DEBUG ((DEBUG_ERROR, "%a() Out of resources.\n", __FUNCTION__));\r
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
284 DescriptorData = (EFI_VARIABLE_AUTHENTICATION_2 *)(NewData);\r
285\r
286 CopyMem (&DescriptorData->TimeStamp, Time, sizeof (EFI_TIME));\r
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
294 FreePool (Payload);\r
295 Payload = NULL;\r
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
315EFIAPI\r
316DeleteVariable (\r
317 IN CHAR16 *VariableName,\r
318 IN EFI_GUID *VendorGuid\r
319 )\r
320{\r
321 EFI_STATUS Status;\r
322 VOID *Variable;\r
323 UINT8 *Data;\r
324 UINTN DataSize;\r
325 UINT32 Attr;\r
326\r
327 GetVariable2 (VariableName, VendorGuid, &Variable, NULL);\r
328 if (Variable == NULL) {\r
329 return EFI_SUCCESS;\r
330 }\r
331\r
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
339 Status = CreateTimeBasedPayload (&DataSize, &Data, &mMaxTimestamp);\r
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
355\r
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
371EFIAPI\r
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
395 OUT UINT8 *SetupMode\r
396 )\r
397{\r
398 UINTN Size;\r
399 EFI_STATUS Status;\r
400\r
401 Size = sizeof (*SetupMode);\r
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
427 )\r
428{\r
429 EFI_STATUS Status;\r
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
450 )\r
451{\r
452 EFI_STATUS Status;\r
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
473 )\r
474{\r
475 EFI_STATUS Status;\r
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
496 )\r
497{\r
498 EFI_STATUS Status;\r
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
519 )\r
520{\r
521 EFI_STATUS Status;\r
522\r
523 Status = SetSecureBootMode (CUSTOM_SECURE_BOOT_MODE);\r
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