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