]> git.proxmox.com Git - efi-boot-shim.git/blob - lib/variables.c
f606e248493dc4775f3044dd8bae75efccd9479d
[efi-boot-shim.git] / lib / variables.c
1 // SPDX-License-Identifier: BSD-2-Clause-Patent
2 /*
3 * Copyright 2012 <James.Bottomley@HansenPartnership.com>
4 *
5 * Portions of this file are a direct cut and paste from Tianocore
6 * (http://tianocore.sf.net)
7 *
8 * SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigImpl.c
9 *
10 * Copyright (c) 2011 - 2012, Intel Corporation. All rights reserved.<BR>
11 *
12 */
13 #include "shim.h"
14
15 EFI_STATUS
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)
19 {
20 EFI_SIGNATURE_LIST *sl;
21 EFI_SIGNATURE_DATA *sd;
22 size_t needed = 0;
23 size_t data_len = howmany * sig_size;
24
25 dprint(L"fill_esl: first_sig=0x%llx, data_len=%lu\n", first_sig, data_len);
26
27 if ((out && !first_sig) || !howmany || !type || !sig_size || !outlen)
28 return EFI_INVALID_PARAMETER;
29
30 if (howmany > (UINT32_MAX - sizeof(EFI_SIGNATURE_LIST)) / sig_size)
31 return EFI_INVALID_PARAMETER;
32
33 needed = sizeof(EFI_SIGNATURE_LIST) + data_len;
34 if (!out || *outlen < needed) {
35 *outlen = needed;
36 return EFI_BUFFER_TOO_SMALL;
37 }
38
39 *outlen = needed;
40 sl = (EFI_SIGNATURE_LIST *)out;
41
42 sl->SignatureHeaderSize = 0;
43 sl->SignatureType = *type;
44 sl->SignatureSize = sig_size;
45 sl->SignatureListSize = needed;
46
47 sd = (EFI_SIGNATURE_DATA *)(out + sizeof(EFI_SIGNATURE_LIST));
48 CopyMem(sd, first_sig, data_len);
49
50 return EFI_SUCCESS;
51 }
52
53 EFI_STATUS
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)
57 {
58 EFI_STATUS efi_status;
59 EFI_SIGNATURE_DATA *sd = NULL;
60 UINT32 sig_size = sizeof(EFI_SIGNATURE_DATA) - 1 + data_len;
61
62 if (data_len > UINT32_MAX - sizeof(EFI_SIGNATURE_DATA) + 1)
63 return EFI_INVALID_PARAMETER;
64
65 if (out) {
66 sd = AllocateZeroPool(sig_size);
67 if (owner)
68 CopyMem(sd, owner, sizeof(EFI_GUID));
69 CopyMem(sd->SignatureData, data, data_len);
70 }
71
72 efi_status = fill_esl(sd, 1, type, sig_size, out, outlen);
73
74 if (out)
75 FreePool(sd);
76 return efi_status;
77 }
78
79 EFI_STATUS
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)
83 {
84 EFI_STATUS efi_status;
85
86 *outlen = 0;
87 efi_status = fill_esl(first_sig, howmany, type, sig_size, NULL, outlen);
88 if (efi_status != EFI_BUFFER_TOO_SMALL)
89 return efi_status;
90
91 *out = AllocateZeroPool(*outlen);
92 if (!*out)
93 return EFI_OUT_OF_RESOURCES;
94
95 return fill_esl(first_sig, howmany, type, sig_size, *out, outlen);
96 }
97
98 EFI_STATUS
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)
102 {
103 EFI_STATUS efi_status;
104
105 *outlen = 0;
106 efi_status = fill_esl_with_one_signature(data, data_len, type, owner,
107 NULL, outlen);
108 if (efi_status != EFI_BUFFER_TOO_SMALL)
109 return efi_status;
110
111 *out = AllocateZeroPool(*outlen);
112 if (!*out)
113 return EFI_OUT_OF_RESOURCES;
114
115 return fill_esl_with_one_signature(data, data_len, type, owner, *out,
116 outlen);
117 }
118
119 EFI_STATUS
120 CreateTimeBasedPayload(IN OUT UINTN * DataSize, IN OUT UINT8 ** Data)
121 {
122 EFI_STATUS efi_status;
123 UINT8 *NewData;
124 UINT8 *Payload;
125 UINTN PayloadSize;
126 EFI_VARIABLE_AUTHENTICATION_2 *DescriptorData;
127 UINTN DescriptorSize;
128 EFI_TIME Time;
129
130 if (Data == NULL || DataSize == NULL) {
131 return EFI_INVALID_PARAMETER;
132 }
133 /*
134 * In Setup mode or Custom mode, the variable does not need to be
135 * signed but the
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.
139 */
140 Payload = *Data;
141 PayloadSize = *DataSize;
142
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;
148 }
149
150 if ((Payload != NULL) && (PayloadSize != 0)) {
151 CopyMem(NewData + DescriptorSize, Payload, PayloadSize);
152 }
153
154 DescriptorData = (EFI_VARIABLE_AUTHENTICATION_2 *) (NewData);
155
156 ZeroMem(&Time, sizeof(EFI_TIME));
157 efi_status = gRT->GetTime(&Time, NULL);
158 if (EFI_ERROR(efi_status)) {
159 FreePool(NewData);
160 return efi_status;
161 }
162 Time.Pad1 = 0;
163 Time.Nanosecond = 0;
164 Time.TimeZone = 0;
165 Time.Daylight = 0;
166 Time.Pad2 = 0;
167 CopyMem(&DescriptorData->TimeStamp, &Time, sizeof(EFI_TIME));
168
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;
174
175 /*
176 * we're expecting an EFI signature list, so don't free the input
177 * since it might not be in a pool
178 */
179 #if 0
180 if (Payload != NULL) {
181 FreePool(Payload);
182 }
183 #endif
184
185 *DataSize = DescriptorSize + PayloadSize;
186 *Data = NewData;
187 return EFI_SUCCESS;
188 }
189
190 EFI_STATUS
191 SetSecureVariable(const CHAR16 * const var, UINT8 *Data, UINTN len,
192 EFI_GUID owner, UINT32 options, int createtimebased)
193 {
194 EFI_SIGNATURE_LIST *Cert;
195 UINTN DataSize;
196 EFI_STATUS efi_status;
197
198 /* Microsoft request: Bugs in some UEFI platforms mean that PK or any
199 * other secure variable can be updated or deleted programmatically,
200 * so prevent */
201 if (!variable_is_setupmode(1))
202 return EFI_SECURITY_VIOLATION;
203
204 if (createtimebased) {
205 size_t ds;
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",
211 var, efi_status);
212 return efi_status;
213 }
214
215 DataSize = ds;
216 } else {
217 /* we expect an efi signature list rather than creating it */
218 Cert = (EFI_SIGNATURE_LIST *)Data;
219 DataSize = len;
220 }
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",
224 efi_status);
225 return efi_status;
226 }
227
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);
234 return efi_status;
235 }
236
237 UINT64
238 GetOSIndications(void)
239 {
240 UINT64 indications;
241 UINTN DataSize = sizeof(indications);
242 EFI_STATUS efi_status;
243
244 efi_status = gRT->GetVariable(L"OsIndicationsSupported", &GV_GUID,
245 NULL, &DataSize, &indications);
246 if (EFI_ERROR(efi_status))
247 return 0;
248
249 return indications;
250 }
251
252 EFI_STATUS
253 SETOSIndicationsAndReboot(UINT64 indications)
254 {
255 UINTN DataSize = sizeof(indications);
256 EFI_STATUS efi_status;
257
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))
264 return efi_status;
265
266 gRT->ResetSystem(EfiResetWarm, EFI_SUCCESS, 0, NULL);
267 /* does not return */
268
269 return EFI_SUCCESS;
270 }
271
272 EFI_STATUS
273 get_variable_attr(const CHAR16 * const var, UINT8 **data, UINTN *len,
274 EFI_GUID owner, UINT32 *attributes)
275 {
276 EFI_STATUS efi_status;
277
278 if (!len)
279 return EFI_INVALID_PARAMETER;
280
281 *len = 0;
282
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;
287 return efi_status;
288 }
289
290 if (!data)
291 return EFI_INVALID_PARAMETER;
292
293 /*
294 * Add three zero pad bytes; at least one correctly aligned UCS-2
295 * character.
296 */
297 *data = AllocateZeroPool(*len + 3);
298 if (!*data)
299 return EFI_OUT_OF_RESOURCES;
300
301 efi_status = gRT->GetVariable((CHAR16 *)var, &owner, attributes, len, *data);
302 if (EFI_ERROR(efi_status)) {
303 FreePool(*data);
304 *data = NULL;
305 }
306
307 return efi_status;
308 }
309
310 EFI_STATUS
311 get_variable(const CHAR16 * const var, UINT8 **data, UINTN *len, EFI_GUID owner)
312 {
313 return get_variable_attr(var, data, len, owner, NULL);
314 }
315
316 EFI_STATUS
317 get_variable_size(const CHAR16 * const var, EFI_GUID owner, UINTN *lenp)
318 {
319 UINTN len = 0;
320 EFI_STATUS efi_status;
321
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) {
325 *lenp = len;
326 return EFI_SUCCESS;
327 } else if (efi_status == EFI_NOT_FOUND) {
328 *lenp = 0;
329 return EFI_SUCCESS;
330 }
331 return efi_status;
332 }
333 /*
334 * who knows what this means, but...
335 */
336 *lenp = len;
337 return efi_status;
338 }
339
340 EFI_STATUS
341 set_variable(CHAR16 *var, EFI_GUID owner, UINT32 attributes,
342 UINTN datasize, void *data)
343 {
344 return gRT->SetVariable(var, &owner, attributes, datasize, data);
345 }
346
347 EFI_STATUS
348 del_variable(CHAR16 *var, EFI_GUID owner)
349 {
350 return set_variable(var, owner, 0, 0, "");
351 }
352
353 EFI_STATUS
354 find_in_esl(UINT8 *Data, UINTN DataSize, UINT8 *key, UINTN keylen)
355 {
356 EFI_SIGNATURE_LIST *CertList;
357
358 certlist_for_each_certentry(CertList, Data, DataSize, DataSize) {
359 if (CertList->SignatureSize != keylen + sizeof(EFI_GUID))
360 continue;
361 EFI_SIGNATURE_DATA *Cert;
362
363 certentry_for_each_cert(Cert, CertList)
364 if (CompareMem (Cert->SignatureData, key, keylen) == 0)
365 return EFI_SUCCESS;
366 }
367 return EFI_NOT_FOUND;
368 }
369
370 EFI_STATUS
371 find_in_variable_esl(const CHAR16 * const var, EFI_GUID owner, UINT8 *key,
372 UINTN keylen)
373 {
374 UINTN DataSize = 0;
375 UINT8 *Data = NULL;
376 EFI_STATUS efi_status;
377
378 efi_status = get_variable(var, &Data, &DataSize, owner);
379 if (EFI_ERROR(efi_status))
380 return efi_status;
381
382 efi_status = find_in_esl(Data, DataSize, key, keylen);
383
384 FreePool(Data);
385
386 return efi_status;
387 }
388
389 int
390 variable_is_setupmode(int default_return)
391 {
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;
396
397 efi_status = gRT->GetVariable(L"SetupMode", &GV_GUID, NULL,
398 &DataSize, &SetupMode);
399 if (EFI_ERROR(efi_status))
400 return default_return;
401
402 return SetupMode;
403 }
404
405 int
406 variable_is_secureboot(void)
407 {
408 /* return false if variable doesn't exist */
409 UINT8 SecureBoot = 0;
410 UINTN DataSize;
411 EFI_STATUS efi_status;
412
413 DataSize = sizeof(SecureBoot);
414 efi_status = gRT->GetVariable(L"SecureBoot", &GV_GUID, NULL,
415 &DataSize, &SecureBoot);
416 if (EFI_ERROR(efi_status))
417 return 0;
418
419 return SecureBoot;
420 }
421
422 EFI_STATUS
423 variable_enroll_hash(const CHAR16 * const var, EFI_GUID owner,
424 UINT8 hash[SHA256_DIGEST_SIZE])
425 {
426 EFI_STATUS efi_status;
427
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;
432
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;
443
444 if (CompareGuid(&owner, &SIG_DB) == 0)
445 efi_status = SetSecureVariable(var, sig, sizeof(sig), owner,
446 EFI_VARIABLE_APPEND_WRITE, 0);
447 else
448 efi_status = gRT->SetVariable((CHAR16 *)var, &owner,
449 EFI_VARIABLE_NON_VOLATILE |
450 EFI_VARIABLE_BOOTSERVICE_ACCESS |
451 EFI_VARIABLE_APPEND_WRITE,
452 sizeof(sig), sig);
453 return efi_status;
454 }