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