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