1 // SPDX-License-Identifier: BSD-2-Clause-Patent
3 * Copyright 2012 <James.Bottomley@HansenPartnership.com>
5 * Portions of this file are a direct cut and paste from Tianocore
6 * (http://tianocore.sf.net)
8 * SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigImpl.c
10 * Copyright (c) 2011 - 2012, Intel Corporation. All rights reserved.<BR>
16 fill_esl(const EFI_SIGNATURE_DATA
*first_sig
, const size_t howmany
,
17 const EFI_GUID
*type
, const UINT32 sig_size
,
18 uint8_t *out
, size_t *outlen
)
20 EFI_SIGNATURE_LIST
*sl
;
21 EFI_SIGNATURE_DATA
*sd
;
23 size_t data_len
= howmany
* sig_size
;
25 dprint(L
"fill_esl: first_sig=0x%llx, data_len=%lu\n", first_sig
, data_len
);
27 if ((out
&& !first_sig
) || !howmany
|| !type
|| !sig_size
|| !outlen
)
28 return EFI_INVALID_PARAMETER
;
30 if (howmany
> (UINT32_MAX
- sizeof(EFI_SIGNATURE_LIST
)) / sig_size
)
31 return EFI_INVALID_PARAMETER
;
33 needed
= sizeof(EFI_SIGNATURE_LIST
) + data_len
;
34 if (!out
|| *outlen
< needed
) {
36 return EFI_BUFFER_TOO_SMALL
;
40 sl
= (EFI_SIGNATURE_LIST
*)out
;
42 sl
->SignatureHeaderSize
= 0;
43 sl
->SignatureType
= *type
;
44 sl
->SignatureSize
= sig_size
;
45 sl
->SignatureListSize
= needed
;
47 sd
= (EFI_SIGNATURE_DATA
*)(out
+ sizeof(EFI_SIGNATURE_LIST
));
48 CopyMem(sd
, first_sig
, data_len
);
54 fill_esl_with_one_signature(const uint8_t *data
, const uint32_t data_len
,
55 const EFI_GUID
*type
, const EFI_GUID
*owner
,
56 uint8_t *out
, size_t *outlen
)
58 EFI_STATUS efi_status
;
59 EFI_SIGNATURE_DATA
*sd
= NULL
;
60 UINT32 sig_size
= sizeof(EFI_SIGNATURE_DATA
) - 1 + data_len
;
62 if (data_len
> UINT32_MAX
- sizeof(EFI_SIGNATURE_DATA
) + 1)
63 return EFI_INVALID_PARAMETER
;
66 sd
= AllocateZeroPool(sig_size
);
68 CopyMem(sd
, owner
, sizeof(EFI_GUID
));
69 CopyMem(sd
->SignatureData
, data
, data_len
);
72 efi_status
= fill_esl(sd
, 1, type
, sig_size
, out
, outlen
);
80 variable_create_esl(const EFI_SIGNATURE_DATA
*first_sig
, const size_t howmany
,
81 const EFI_GUID
*type
, const UINT32 sig_size
,
82 uint8_t **out
, size_t *outlen
)
84 EFI_STATUS efi_status
;
87 efi_status
= fill_esl(first_sig
, howmany
, type
, sig_size
, NULL
, outlen
);
88 if (efi_status
!= EFI_BUFFER_TOO_SMALL
)
91 *out
= AllocateZeroPool(*outlen
);
93 return EFI_OUT_OF_RESOURCES
;
95 return fill_esl(first_sig
, howmany
, type
, sig_size
, *out
, outlen
);
99 variable_create_esl_with_one_signature(const uint8_t* data
, const size_t data_len
,
100 const EFI_GUID
*type
, const EFI_GUID
*owner
,
101 uint8_t **out
, size_t *outlen
)
103 EFI_STATUS efi_status
;
106 efi_status
= fill_esl_with_one_signature(data
, data_len
, type
, owner
,
108 if (efi_status
!= EFI_BUFFER_TOO_SMALL
)
111 *out
= AllocateZeroPool(*outlen
);
113 return EFI_OUT_OF_RESOURCES
;
115 return fill_esl_with_one_signature(data
, data_len
, type
, owner
, *out
,
120 CreateTimeBasedPayload(IN OUT UINTN
* DataSize
, IN OUT UINT8
** Data
)
122 EFI_STATUS efi_status
;
126 EFI_VARIABLE_AUTHENTICATION_2
*DescriptorData
;
127 UINTN DescriptorSize
;
130 if (Data
== NULL
|| DataSize
== NULL
) {
131 return EFI_INVALID_PARAMETER
;
134 * In Setup mode or Custom mode, the variable does not need to be
136 * parameters to the SetVariable() call still need to be prepared as
137 * authenticated variable. So we create EFI_VARIABLE_AUTHENTICATED_2
138 * descriptor without certificate data in it.
141 PayloadSize
= *DataSize
;
143 DescriptorSize
= offsetof(EFI_VARIABLE_AUTHENTICATION_2
, AuthInfo
)
144 + offsetof(WIN_CERTIFICATE_UEFI_GUID
, CertData
);
145 NewData
= (UINT8
*) AllocateZeroPool(DescriptorSize
+ PayloadSize
);
146 if (NewData
== NULL
) {
147 return EFI_OUT_OF_RESOURCES
;
150 if ((Payload
!= NULL
) && (PayloadSize
!= 0)) {
151 CopyMem(NewData
+ DescriptorSize
, Payload
, PayloadSize
);
154 DescriptorData
= (EFI_VARIABLE_AUTHENTICATION_2
*) (NewData
);
156 ZeroMem(&Time
, sizeof(EFI_TIME
));
157 efi_status
= gRT
->GetTime(&Time
, NULL
);
158 if (EFI_ERROR(efi_status
)) {
167 CopyMem(&DescriptorData
->TimeStamp
, &Time
, sizeof(EFI_TIME
));
169 DescriptorData
->AuthInfo
.Hdr
.dwLength
=
170 offsetof(WIN_CERTIFICATE_UEFI_GUID
, CertData
);
171 DescriptorData
->AuthInfo
.Hdr
.wRevision
= 0x0200;
172 DescriptorData
->AuthInfo
.Hdr
.wCertificateType
= WIN_CERT_TYPE_EFI_GUID
;
173 DescriptorData
->AuthInfo
.CertType
= EFI_CERT_TYPE_PKCS7_GUID
;
176 * we're expecting an EFI signature list, so don't free the input
177 * since it might not be in a pool
180 if (Payload
!= NULL
) {
185 *DataSize
= DescriptorSize
+ PayloadSize
;
191 SetSecureVariable(const CHAR16
* const var
, UINT8
*Data
, UINTN len
,
192 EFI_GUID owner
, UINT32 options
, int createtimebased
)
194 EFI_SIGNATURE_LIST
*Cert
;
196 EFI_STATUS efi_status
;
198 /* Microsoft request: Bugs in some UEFI platforms mean that PK or any
199 * other secure variable can be updated or deleted programmatically,
201 if (!variable_is_setupmode(1))
202 return EFI_SECURITY_VIOLATION
;
204 if (createtimebased
) {
206 efi_status
= variable_create_esl_with_one_signature(
207 Data
, len
, &X509_GUID
, NULL
,
208 (uint8_t **)&Cert
, &ds
);
209 if (EFI_ERROR(efi_status
)) {
210 console_print(L
"Failed to create %s certificate %d\n",
217 /* we expect an efi signature list rather than creating it */
218 Cert
= (EFI_SIGNATURE_LIST
*)Data
;
221 efi_status
= CreateTimeBasedPayload(&DataSize
, (UINT8
**)&Cert
);
222 if (EFI_ERROR(efi_status
)) {
223 console_print(L
"Failed to create time based payload %d\n",
228 efi_status
= gRT
->SetVariable((CHAR16
*)var
, &owner
,
229 EFI_VARIABLE_NON_VOLATILE
|
230 EFI_VARIABLE_RUNTIME_ACCESS
|
231 EFI_VARIABLE_BOOTSERVICE_ACCESS
|
232 EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
|
233 options
, DataSize
, Cert
);
238 GetOSIndications(void)
241 UINTN DataSize
= sizeof(indications
);
242 EFI_STATUS efi_status
;
244 efi_status
= gRT
->GetVariable(L
"OsIndicationsSupported", &GV_GUID
,
245 NULL
, &DataSize
, &indications
);
246 if (EFI_ERROR(efi_status
))
253 SETOSIndicationsAndReboot(UINT64 indications
)
255 UINTN DataSize
= sizeof(indications
);
256 EFI_STATUS efi_status
;
258 efi_status
= gRT
->SetVariable(L
"OsIndications", &GV_GUID
,
259 EFI_VARIABLE_NON_VOLATILE
|
260 EFI_VARIABLE_RUNTIME_ACCESS
|
261 EFI_VARIABLE_BOOTSERVICE_ACCESS
,
262 DataSize
, &indications
);
263 if (EFI_ERROR(efi_status
))
266 gRT
->ResetSystem(EfiResetWarm
, EFI_SUCCESS
, 0, NULL
);
267 /* does not return */
273 get_variable_attr(const CHAR16
* const var
, UINT8
**data
, UINTN
*len
,
274 EFI_GUID owner
, UINT32
*attributes
)
276 EFI_STATUS efi_status
;
279 return EFI_INVALID_PARAMETER
;
283 efi_status
= gRT
->GetVariable((CHAR16
*)var
, &owner
, NULL
, len
, NULL
);
284 if (efi_status
!= EFI_BUFFER_TOO_SMALL
) {
285 if (!EFI_ERROR(efi_status
)) /* this should never happen */
286 return EFI_PROTOCOL_ERROR
;
291 return EFI_INVALID_PARAMETER
;
294 * Add three zero pad bytes; at least one correctly aligned UCS-2
297 *data
= AllocateZeroPool(*len
+ 3);
299 return EFI_OUT_OF_RESOURCES
;
301 efi_status
= gRT
->GetVariable((CHAR16
*)var
, &owner
, attributes
, len
, *data
);
302 if (EFI_ERROR(efi_status
)) {
311 get_variable(const CHAR16
* const var
, UINT8
**data
, UINTN
*len
, EFI_GUID owner
)
313 return get_variable_attr(var
, data
, len
, owner
, NULL
);
317 get_variable_size(const CHAR16
* const var
, EFI_GUID owner
, UINTN
*lenp
)
320 EFI_STATUS efi_status
;
322 efi_status
= get_variable_attr(var
, NULL
, &len
, owner
, NULL
);
323 if (EFI_ERROR(efi_status
)) {
324 if (efi_status
== EFI_BUFFER_TOO_SMALL
) {
327 } else if (efi_status
== EFI_NOT_FOUND
) {
334 * who knows what this means, but...
341 set_variable(CHAR16
*var
, EFI_GUID owner
, UINT32 attributes
,
342 UINTN datasize
, void *data
)
344 return gRT
->SetVariable(var
, &owner
, attributes
, datasize
, data
);
348 del_variable(CHAR16
*var
, EFI_GUID owner
)
350 return set_variable(var
, owner
, 0, 0, "");
354 find_in_esl(UINT8
*Data
, UINTN DataSize
, UINT8
*key
, UINTN keylen
)
356 EFI_SIGNATURE_LIST
*CertList
;
358 certlist_for_each_certentry(CertList
, Data
, DataSize
, DataSize
) {
359 if (CertList
->SignatureSize
!= keylen
+ sizeof(EFI_GUID
))
361 EFI_SIGNATURE_DATA
*Cert
;
363 certentry_for_each_cert(Cert
, CertList
)
364 if (CompareMem (Cert
->SignatureData
, key
, keylen
) == 0)
367 return EFI_NOT_FOUND
;
371 find_in_variable_esl(const CHAR16
* const var
, EFI_GUID owner
, UINT8
*key
,
376 EFI_STATUS efi_status
;
378 efi_status
= get_variable(var
, &Data
, &DataSize
, owner
);
379 if (EFI_ERROR(efi_status
))
382 efi_status
= find_in_esl(Data
, DataSize
, key
, keylen
);
390 variable_is_setupmode(int default_return
)
392 /* set to 1 because we return true if SetupMode doesn't exist */
393 UINT8 SetupMode
= default_return
;
394 UINTN DataSize
= sizeof(SetupMode
);
395 EFI_STATUS efi_status
;
397 efi_status
= gRT
->GetVariable(L
"SetupMode", &GV_GUID
, NULL
,
398 &DataSize
, &SetupMode
);
399 if (EFI_ERROR(efi_status
))
400 return default_return
;
406 variable_is_secureboot(void)
408 /* return false if variable doesn't exist */
409 UINT8 SecureBoot
= 0;
411 EFI_STATUS efi_status
;
413 DataSize
= sizeof(SecureBoot
);
414 efi_status
= gRT
->GetVariable(L
"SecureBoot", &GV_GUID
, NULL
,
415 &DataSize
, &SecureBoot
);
416 if (EFI_ERROR(efi_status
))
423 variable_enroll_hash(const CHAR16
* const var
, EFI_GUID owner
,
424 UINT8 hash
[SHA256_DIGEST_SIZE
])
426 EFI_STATUS efi_status
;
428 efi_status
= find_in_variable_esl(var
, owner
, hash
, SHA256_DIGEST_SIZE
);
429 if (!EFI_ERROR(efi_status
))
430 /* hash already present */
431 return EFI_ALREADY_STARTED
;
433 UINT8 sig
[sizeof(EFI_SIGNATURE_LIST
)
434 + sizeof(EFI_SIGNATURE_DATA
) - 1 + SHA256_DIGEST_SIZE
];
435 EFI_SIGNATURE_LIST
*l
= (void *)sig
;
436 EFI_SIGNATURE_DATA
*d
= (void *)sig
+ sizeof(EFI_SIGNATURE_LIST
);
437 SetMem(sig
, 0, sizeof(sig
));
438 l
->SignatureType
= EFI_CERT_SHA256_GUID
;
439 l
->SignatureListSize
= sizeof(sig
);
440 l
->SignatureSize
= 16 +32; /* UEFI defined */
441 CopyMem(&d
->SignatureData
, hash
, SHA256_DIGEST_SIZE
);
442 d
->SignatureOwner
= SHIM_LOCK_GUID
;
444 if (CompareGuid(&owner
, &SIG_DB
) == 0)
445 efi_status
= SetSecureVariable(var
, sig
, sizeof(sig
), owner
,
446 EFI_VARIABLE_APPEND_WRITE
, 0);
448 efi_status
= gRT
->SetVariable((CHAR16
*)var
, &owner
,
449 EFI_VARIABLE_NON_VOLATILE
|
450 EFI_VARIABLE_BOOTSERVICE_ACCESS
|
451 EFI_VARIABLE_APPEND_WRITE
,