]> git.proxmox.com Git - mirror_edk2.git/blob - SecurityPkg/Library/SecureBootVariableLib/SecureBootVariableLib.c
e0d137666e0e157e34f859bbe40666f7cc2e2c66
[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 KeyIndex = 0;
146 EfiSig = NULL;
147 *SigListsSize = 0;
148 while (1) {
149 Status = GetSectionFromAnyFv (
150 KeyFileGuid,
151 EFI_SECTION_RAW,
152 KeyIndex,
153 &Buffer,
154 &Size
155 );
156
157 if (Status == EFI_SUCCESS) {
158 RsaPubKey = NULL;
159 if (RsaGetPublicKeyFromX509 (Buffer, Size, &RsaPubKey) == FALSE) {
160 DEBUG ((DEBUG_ERROR, "%a: Invalid key format: %d\n", __FUNCTION__, KeyIndex));
161 if (EfiSig != NULL) {
162 FreePool (EfiSig);
163 }
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 }
187
188 if (Status == EFI_NOT_FOUND) {
189 break;
190 }
191 }
192
193 if (KeyIndex == 0) {
194 return EFI_NOT_FOUND;
195 }
196
197 *SigListOut = EfiSig;
198
199 return EFI_SUCCESS;
200 }
201
202 /**
203 Create a time based data payload by concatenating the EFI_VARIABLE_AUTHENTICATION_2
204 descriptor with the input data. NO authentication is required in this function.
205
206 @param[in, out] DataSize On input, the size of Data buffer in bytes.
207 On output, the size of data returned in Data
208 buffer in bytes.
209 @param[in, out] Data On input, Pointer to data buffer to be wrapped or
210 pointer to NULL to wrap an empty payload.
211 On output, Pointer to the new payload date buffer allocated from pool,
212 it's caller's responsibility to free the memory when finish using it.
213
214 @retval EFI_SUCCESS Create time based payload successfully.
215 @retval EFI_OUT_OF_RESOURCES There are not enough memory resources to create time based payload.
216 @retval EFI_INVALID_PARAMETER The parameter is invalid.
217 @retval Others Unexpected error happens.
218
219 **/
220 EFI_STATUS
221 CreateTimeBasedPayload (
222 IN OUT UINTN *DataSize,
223 IN OUT UINT8 **Data
224 )
225 {
226 EFI_STATUS Status;
227 UINT8 *NewData;
228 UINT8 *Payload;
229 UINTN PayloadSize;
230 EFI_VARIABLE_AUTHENTICATION_2 *DescriptorData;
231 UINTN DescriptorSize;
232 EFI_TIME Time;
233
234 if ((Data == NULL) || (DataSize == NULL)) {
235 return EFI_INVALID_PARAMETER;
236 }
237
238 //
239 // In Setup mode or Custom mode, the variable does not need to be signed but the
240 // parameters to the SetVariable() call still need to be prepared as authenticated
241 // variable. So we create EFI_VARIABLE_AUTHENTICATED_2 descriptor without certificate
242 // data in it.
243 //
244 Payload = *Data;
245 PayloadSize = *DataSize;
246
247 DescriptorSize = OFFSET_OF (EFI_VARIABLE_AUTHENTICATION_2, AuthInfo) + OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData);
248 NewData = (UINT8 *)AllocateZeroPool (DescriptorSize + PayloadSize);
249 if (NewData == NULL) {
250 return EFI_OUT_OF_RESOURCES;
251 }
252
253 if ((Payload != NULL) && (PayloadSize != 0)) {
254 CopyMem (NewData + DescriptorSize, Payload, PayloadSize);
255 }
256
257 DescriptorData = (EFI_VARIABLE_AUTHENTICATION_2 *)(NewData);
258
259 ZeroMem (&Time, sizeof (EFI_TIME));
260 Status = gRT->GetTime (&Time, NULL);
261 if (EFI_ERROR (Status)) {
262 FreePool (NewData);
263 return Status;
264 }
265
266 Time.Pad1 = 0;
267 Time.Nanosecond = 0;
268 Time.TimeZone = 0;
269 Time.Daylight = 0;
270 Time.Pad2 = 0;
271 CopyMem (&DescriptorData->TimeStamp, &Time, sizeof (EFI_TIME));
272
273 DescriptorData->AuthInfo.Hdr.dwLength = OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData);
274 DescriptorData->AuthInfo.Hdr.wRevision = 0x0200;
275 DescriptorData->AuthInfo.Hdr.wCertificateType = WIN_CERT_TYPE_EFI_GUID;
276 CopyGuid (&DescriptorData->AuthInfo.CertType, &gEfiCertPkcs7Guid);
277
278 if (Payload != NULL) {
279 FreePool (Payload);
280 }
281
282 *DataSize = DescriptorSize + PayloadSize;
283 *Data = NewData;
284 return EFI_SUCCESS;
285 }
286
287 /**
288 Internal helper function to delete a Variable given its name and GUID, NO authentication
289 required.
290
291 @param[in] VariableName Name of the Variable.
292 @param[in] VendorGuid GUID of the Variable.
293
294 @retval EFI_SUCCESS Variable deleted successfully.
295 @retval Others The driver failed to start the device.
296
297 **/
298 EFI_STATUS
299 DeleteVariable (
300 IN CHAR16 *VariableName,
301 IN EFI_GUID *VendorGuid
302 )
303 {
304 EFI_STATUS Status;
305 VOID *Variable;
306 UINT8 *Data;
307 UINTN DataSize;
308 UINT32 Attr;
309
310 GetVariable2 (VariableName, VendorGuid, &Variable, NULL);
311 if (Variable == NULL) {
312 return EFI_SUCCESS;
313 }
314
315 FreePool (Variable);
316
317 Data = NULL;
318 DataSize = 0;
319 Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS
320 | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
321
322 Status = CreateTimeBasedPayload (&DataSize, &Data);
323 if (EFI_ERROR (Status)) {
324 DEBUG ((DEBUG_ERROR, "Fail to create time-based data payload: %r", Status));
325 return Status;
326 }
327
328 Status = gRT->SetVariable (
329 VariableName,
330 VendorGuid,
331 Attr,
332 DataSize,
333 Data
334 );
335 if (Data != NULL) {
336 FreePool (Data);
337 }
338
339 return Status;
340 }
341
342 /**
343
344 Set the platform secure boot mode into "Custom" or "Standard" mode.
345
346 @param[in] SecureBootMode New secure boot mode: STANDARD_SECURE_BOOT_MODE or
347 CUSTOM_SECURE_BOOT_MODE.
348
349 @return EFI_SUCCESS The platform has switched to the special mode successfully.
350 @return other Fail to operate the secure boot mode.
351
352 **/
353 EFI_STATUS
354 SetSecureBootMode (
355 IN UINT8 SecureBootMode
356 )
357 {
358 return gRT->SetVariable (
359 EFI_CUSTOM_MODE_NAME,
360 &gEfiCustomModeEnableGuid,
361 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
362 sizeof (UINT8),
363 &SecureBootMode
364 );
365 }
366
367 /**
368 Fetches the value of SetupMode variable.
369
370 @param[out] SetupMode Pointer to UINT8 for SetupMode output
371
372 @retval other Retval from GetVariable.
373 **/
374 EFI_STATUS
375 EFIAPI
376 GetSetupMode (
377 OUT UINT8 *SetupMode
378 )
379 {
380 UINTN Size;
381 EFI_STATUS Status;
382
383 Size = sizeof (*SetupMode);
384 Status = gRT->GetVariable (
385 EFI_SETUP_MODE_NAME,
386 &gEfiGlobalVariableGuid,
387 NULL,
388 &Size,
389 SetupMode
390 );
391 if (EFI_ERROR (Status)) {
392 return Status;
393 }
394
395 return EFI_SUCCESS;
396 }
397
398 /**
399 Clears the content of the 'db' variable.
400
401 @retval EFI_OUT_OF_RESOURCES If memory allocation for EFI_VARIABLE_AUTHENTICATION_2 fails
402 while VendorGuid is NULL.
403 @retval other Errors from GetVariable2 (), GetTime () and SetVariable ()
404 **/
405 EFI_STATUS
406 EFIAPI
407 DeleteDb (
408 VOID
409 )
410 {
411 EFI_STATUS Status;
412
413 Status = DeleteVariable (
414 EFI_IMAGE_SECURITY_DATABASE,
415 &gEfiImageSecurityDatabaseGuid
416 );
417
418 return Status;
419 }
420
421 /**
422 Clears the content of the 'dbx' variable.
423
424 @retval EFI_OUT_OF_RESOURCES If memory allocation for EFI_VARIABLE_AUTHENTICATION_2 fails
425 while VendorGuid is NULL.
426 @retval other Errors from GetVariable2 (), GetTime () and SetVariable ()
427 **/
428 EFI_STATUS
429 EFIAPI
430 DeleteDbx (
431 VOID
432 )
433 {
434 EFI_STATUS Status;
435
436 Status = DeleteVariable (
437 EFI_IMAGE_SECURITY_DATABASE1,
438 &gEfiImageSecurityDatabaseGuid
439 );
440
441 return Status;
442 }
443
444 /**
445 Clears the content of the 'dbt' variable.
446
447 @retval EFI_OUT_OF_RESOURCES If memory allocation for EFI_VARIABLE_AUTHENTICATION_2 fails
448 while VendorGuid is NULL.
449 @retval other Errors from GetVariable2 (), GetTime () and SetVariable ()
450 **/
451 EFI_STATUS
452 EFIAPI
453 DeleteDbt (
454 VOID
455 )
456 {
457 EFI_STATUS Status;
458
459 Status = DeleteVariable (
460 EFI_IMAGE_SECURITY_DATABASE2,
461 &gEfiImageSecurityDatabaseGuid
462 );
463
464 return Status;
465 }
466
467 /**
468 Clears the content of the 'KEK' variable.
469
470 @retval EFI_OUT_OF_RESOURCES If memory allocation for EFI_VARIABLE_AUTHENTICATION_2 fails
471 while VendorGuid is NULL.
472 @retval other Errors from GetVariable2 (), GetTime () and SetVariable ()
473 **/
474 EFI_STATUS
475 EFIAPI
476 DeleteKEK (
477 VOID
478 )
479 {
480 EFI_STATUS Status;
481
482 Status = DeleteVariable (
483 EFI_KEY_EXCHANGE_KEY_NAME,
484 &gEfiGlobalVariableGuid
485 );
486
487 return Status;
488 }
489
490 /**
491 Remove the PK variable.
492
493 @retval EFI_SUCCESS Delete PK successfully.
494 @retval Others Could not allow to delete PK.
495
496 **/
497 EFI_STATUS
498 EFIAPI
499 DeletePlatformKey (
500 VOID
501 )
502 {
503 EFI_STATUS Status;
504
505 Status = SetSecureBootMode (CUSTOM_SECURE_BOOT_MODE);
506 if (EFI_ERROR (Status)) {
507 return Status;
508 }
509
510 Status = DeleteVariable (
511 EFI_PLATFORM_KEY_NAME,
512 &gEfiGlobalVariableGuid
513 );
514 return Status;
515 }