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