]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - SecurityPkg/Library/AuthVariableLib/AuthService.c
SecurityPkg: AuthVariableLib & SecureBootConfigDxe: Fix SecureBootEnable & PK inconsi...
[mirror_edk2.git] / SecurityPkg / Library / AuthVariableLib / AuthService.c
... / ...
CommitLineData
1/** @file\r
2 Implement authentication services for the authenticated variables.\r
3\r
4 Caution: This module requires additional review when modified.\r
5 This driver will have external input - variable data. It may be input in SMM mode.\r
6 This external input must be validated carefully to avoid security issue like\r
7 buffer overflow, integer overflow.\r
8 Variable attribute should also be checked to avoid authentication bypass.\r
9 The whole SMM authentication variable design relies on the integrity of flash part and SMM.\r
10 which is assumed to be protected by platform. All variable code and metadata in flash/SMM Memory\r
11 may not be modified without authorization. If platform fails to protect these resources,\r
12 the authentication service provided in this driver will be broken, and the behavior is undefined.\r
13\r
14 ProcessVarWithPk(), ProcessVarWithKek() and ProcessVariable() are the function to do\r
15 variable authentication.\r
16\r
17 VerifyTimeBasedPayloadAndUpdate() and VerifyCounterBasedPayload() are sub function to do verification.\r
18 They will do basic validation for authentication data structure, then call crypto library\r
19 to verify the signature.\r
20\r
21Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>\r
22This program and the accompanying materials\r
23are licensed and made available under the terms and conditions of the BSD License\r
24which accompanies this distribution. The full text of the license may be found at\r
25http://opensource.org/licenses/bsd-license.php\r
26\r
27THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
28WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
29\r
30**/\r
31\r
32#include "AuthServiceInternal.h"\r
33\r
34//\r
35// Public Exponent of RSA Key.\r
36//\r
37CONST UINT8 mRsaE[] = { 0x01, 0x00, 0x01 };\r
38\r
39//\r
40// Requirement for different signature type which have been defined in UEFI spec.\r
41// These data are used to perform SignatureList format check while setting PK/KEK variable.\r
42//\r
43EFI_SIGNATURE_ITEM mSupportSigItem[] = {\r
44//{SigType, SigHeaderSize, SigDataSize }\r
45 {EFI_CERT_SHA256_GUID, 0, 32 },\r
46 {EFI_CERT_RSA2048_GUID, 0, 256 },\r
47 {EFI_CERT_RSA2048_SHA256_GUID, 0, 256 },\r
48 {EFI_CERT_SHA1_GUID, 0, 20 },\r
49 {EFI_CERT_RSA2048_SHA1_GUID, 0, 256 },\r
50 {EFI_CERT_X509_GUID, 0, ((UINT32) ~0)},\r
51 {EFI_CERT_SHA224_GUID, 0, 28 },\r
52 {EFI_CERT_SHA384_GUID, 0, 48 },\r
53 {EFI_CERT_SHA512_GUID, 0, 64 },\r
54 {EFI_CERT_X509_SHA256_GUID, 0, 48 },\r
55 {EFI_CERT_X509_SHA384_GUID, 0, 64 },\r
56 {EFI_CERT_X509_SHA512_GUID, 0, 80 }\r
57};\r
58\r
59//\r
60// Secure Boot Mode state machine\r
61//\r
62SECURE_BOOT_MODE mSecureBootState[SecureBootModeTypeMax] = {\r
63 // USER MODE\r
64 {\r
65 AUDIT_MODE_DISABLE, // AuditMode\r
66 FALSE, // IsAuditModeRO, AuditMode is RW\r
67 DEPLOYED_MODE_DISABLE, // DeployedMode\r
68 FALSE, // IsDeployedModeRO, DeployedMode is RW\r
69 SETUP_MODE_DISABLE, // SetupMode\r
70 // SetupMode is always RO\r
71 SECURE_BOOT_MODE_ENABLE // SecureBoot\r
72 },\r
73 // SETUP MODE\r
74 {\r
75 AUDIT_MODE_DISABLE, // AuditMode\r
76 FALSE, // IsAuditModeRO, AuditMode is RW\r
77 DEPLOYED_MODE_DISABLE, // DeployedMode\r
78 TRUE, // IsDeployedModeRO, DeployedMode is RO\r
79 SETUP_MODE_ENABLE, // SetupMode\r
80 // SetupMode is always RO\r
81 SECURE_BOOT_MODE_DISABLE // SecureBoot\r
82 },\r
83 // AUDIT MODE\r
84 {\r
85 AUDIT_MODE_ENABLE, // AuditMode\r
86 TRUE, // AuditModeValAttr RO, AuditMode is RO\r
87 DEPLOYED_MODE_DISABLE, // DeployedMode\r
88 TRUE, // DeployedModeValAttr RO, DeployedMode is RO\r
89 SETUP_MODE_ENABLE, // SetupMode\r
90 // SetupMode is always RO\r
91 SECURE_BOOT_MODE_DISABLE // SecureBoot\r
92 },\r
93 // DEPLOYED MODE\r
94 {\r
95 AUDIT_MODE_DISABLE, // AuditMode, AuditMode is RO\r
96 TRUE, // AuditModeValAttr RO\r
97 DEPLOYED_MODE_ENABLE, // DeployedMode\r
98 TRUE, // DeployedModeValAttr RO, DeployedMode is RO\r
99 SETUP_MODE_DISABLE, // SetupMode\r
100 // SetupMode is always RO\r
101 SECURE_BOOT_MODE_ENABLE // SecureBoot\r
102 }\r
103};\r
104\r
105SECURE_BOOT_MODE_TYPE mSecureBootMode;\r
106\r
107/**\r
108 Finds variable in storage blocks of volatile and non-volatile storage areas.\r
109\r
110 This code finds variable in storage blocks of volatile and non-volatile storage areas.\r
111 If VariableName is an empty string, then we just return the first\r
112 qualified variable without comparing VariableName and VendorGuid.\r
113\r
114 @param[in] VariableName Name of the variable to be found.\r
115 @param[in] VendorGuid Variable vendor GUID to be found.\r
116 @param[out] Data Pointer to data address.\r
117 @param[out] DataSize Pointer to data size.\r
118\r
119 @retval EFI_INVALID_PARAMETER If VariableName is not an empty string,\r
120 while VendorGuid is NULL.\r
121 @retval EFI_SUCCESS Variable successfully found.\r
122 @retval EFI_NOT_FOUND Variable not found\r
123\r
124**/\r
125EFI_STATUS\r
126AuthServiceInternalFindVariable (\r
127 IN CHAR16 *VariableName,\r
128 IN EFI_GUID *VendorGuid,\r
129 OUT VOID **Data,\r
130 OUT UINTN *DataSize\r
131 )\r
132{\r
133 EFI_STATUS Status;\r
134 AUTH_VARIABLE_INFO AuthVariableInfo;\r
135\r
136 ZeroMem (&AuthVariableInfo, sizeof (AuthVariableInfo));\r
137 Status = mAuthVarLibContextIn->FindVariable (\r
138 VariableName,\r
139 VendorGuid,\r
140 &AuthVariableInfo\r
141 );\r
142 *Data = AuthVariableInfo.Data;\r
143 *DataSize = AuthVariableInfo.DataSize;\r
144 return Status;\r
145}\r
146\r
147/**\r
148 Update the variable region with Variable information.\r
149\r
150 @param[in] VariableName Name of variable.\r
151 @param[in] VendorGuid Guid of variable.\r
152 @param[in] Data Data pointer.\r
153 @param[in] DataSize Size of Data.\r
154 @param[in] Attributes Attribute value of the variable.\r
155\r
156 @retval EFI_SUCCESS The update operation is success.\r
157 @retval EFI_INVALID_PARAMETER Invalid parameter.\r
158 @retval EFI_WRITE_PROTECTED Variable is write-protected.\r
159 @retval EFI_OUT_OF_RESOURCES There is not enough resource.\r
160\r
161**/\r
162EFI_STATUS\r
163AuthServiceInternalUpdateVariable (\r
164 IN CHAR16 *VariableName,\r
165 IN EFI_GUID *VendorGuid,\r
166 IN VOID *Data,\r
167 IN UINTN DataSize,\r
168 IN UINT32 Attributes\r
169 )\r
170{\r
171 AUTH_VARIABLE_INFO AuthVariableInfo;\r
172\r
173 ZeroMem (&AuthVariableInfo, sizeof (AuthVariableInfo));\r
174 AuthVariableInfo.VariableName = VariableName;\r
175 AuthVariableInfo.VendorGuid = VendorGuid;\r
176 AuthVariableInfo.Data = Data;\r
177 AuthVariableInfo.DataSize = DataSize;\r
178 AuthVariableInfo.Attributes = Attributes;\r
179\r
180 return mAuthVarLibContextIn->UpdateVariable (\r
181 &AuthVariableInfo\r
182 );\r
183}\r
184\r
185/**\r
186 Update the variable region with Variable information.\r
187\r
188 @param[in] VariableName Name of variable.\r
189 @param[in] VendorGuid Guid of variable.\r
190 @param[in] Data Data pointer.\r
191 @param[in] DataSize Size of Data.\r
192 @param[in] Attributes Attribute value of the variable.\r
193 @param[in] KeyIndex Index of associated public key.\r
194 @param[in] MonotonicCount Value of associated monotonic count.\r
195\r
196 @retval EFI_SUCCESS The update operation is success.\r
197 @retval EFI_INVALID_PARAMETER Invalid parameter.\r
198 @retval EFI_WRITE_PROTECTED Variable is write-protected.\r
199 @retval EFI_OUT_OF_RESOURCES There is not enough resource.\r
200\r
201**/\r
202EFI_STATUS\r
203AuthServiceInternalUpdateVariableWithMonotonicCount (\r
204 IN CHAR16 *VariableName,\r
205 IN EFI_GUID *VendorGuid,\r
206 IN VOID *Data,\r
207 IN UINTN DataSize,\r
208 IN UINT32 Attributes,\r
209 IN UINT32 KeyIndex,\r
210 IN UINT64 MonotonicCount\r
211 )\r
212{\r
213 AUTH_VARIABLE_INFO AuthVariableInfo;\r
214\r
215 ZeroMem (&AuthVariableInfo, sizeof (AuthVariableInfo));\r
216 AuthVariableInfo.VariableName = VariableName;\r
217 AuthVariableInfo.VendorGuid = VendorGuid;\r
218 AuthVariableInfo.Data = Data;\r
219 AuthVariableInfo.DataSize = DataSize;\r
220 AuthVariableInfo.Attributes = Attributes;\r
221 AuthVariableInfo.PubKeyIndex = KeyIndex;\r
222 AuthVariableInfo.MonotonicCount = MonotonicCount;\r
223\r
224 return mAuthVarLibContextIn->UpdateVariable (\r
225 &AuthVariableInfo\r
226 );\r
227}\r
228\r
229/**\r
230 Update the variable region with Variable information.\r
231\r
232 @param[in] VariableName Name of variable.\r
233 @param[in] VendorGuid Guid of variable.\r
234 @param[in] Data Data pointer.\r
235 @param[in] DataSize Size of Data.\r
236 @param[in] Attributes Attribute value of the variable.\r
237 @param[in] TimeStamp Value of associated TimeStamp.\r
238\r
239 @retval EFI_SUCCESS The update operation is success.\r
240 @retval EFI_INVALID_PARAMETER Invalid parameter.\r
241 @retval EFI_WRITE_PROTECTED Variable is write-protected.\r
242 @retval EFI_OUT_OF_RESOURCES There is not enough resource.\r
243\r
244**/\r
245EFI_STATUS\r
246AuthServiceInternalUpdateVariableWithTimeStamp (\r
247 IN CHAR16 *VariableName,\r
248 IN EFI_GUID *VendorGuid,\r
249 IN VOID *Data,\r
250 IN UINTN DataSize,\r
251 IN UINT32 Attributes,\r
252 IN EFI_TIME *TimeStamp\r
253 )\r
254{\r
255 EFI_STATUS FindStatus;\r
256 VOID *OrgData;\r
257 UINTN OrgDataSize;\r
258 AUTH_VARIABLE_INFO AuthVariableInfo;\r
259\r
260 FindStatus = AuthServiceInternalFindVariable (\r
261 VariableName,\r
262 VendorGuid,\r
263 &OrgData,\r
264 &OrgDataSize\r
265 );\r
266\r
267 //\r
268 // EFI_VARIABLE_APPEND_WRITE attribute only effects for existing variable\r
269 //\r
270 if (!EFI_ERROR (FindStatus) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) != 0)) {\r
271 if ((CompareGuid (VendorGuid, &gEfiImageSecurityDatabaseGuid) &&\r
272 ((StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE) == 0) || (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE1) == 0) ||\r
273 (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE2) == 0))) ||\r
274 (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_KEY_EXCHANGE_KEY_NAME) == 0))) {\r
275 //\r
276 // For variables with formatted as EFI_SIGNATURE_LIST, the driver shall not perform an append of\r
277 // EFI_SIGNATURE_DATA values that are already part of the existing variable value.\r
278 //\r
279 FilterSignatureList (\r
280 OrgData,\r
281 OrgDataSize,\r
282 Data,\r
283 &DataSize\r
284 );\r
285 }\r
286 }\r
287\r
288 ZeroMem (&AuthVariableInfo, sizeof (AuthVariableInfo));\r
289 AuthVariableInfo.VariableName = VariableName;\r
290 AuthVariableInfo.VendorGuid = VendorGuid;\r
291 AuthVariableInfo.Data = Data;\r
292 AuthVariableInfo.DataSize = DataSize;\r
293 AuthVariableInfo.Attributes = Attributes;\r
294 AuthVariableInfo.TimeStamp = TimeStamp;\r
295 return mAuthVarLibContextIn->UpdateVariable (\r
296 &AuthVariableInfo\r
297 );\r
298}\r
299\r
300/**\r
301 Initialize Secure Boot variables.\r
302\r
303 @retval EFI_SUCCESS The initialization operation is successful.\r
304 @retval EFI_OUT_OF_RESOURCES There is not enough resource.\r
305\r
306**/\r
307EFI_STATUS\r
308InitSecureBootVariables (\r
309 VOID\r
310 )\r
311{\r
312 EFI_STATUS Status;\r
313 UINT8 *Data;\r
314 UINTN DataSize;\r
315 UINT32 SecureBoot;\r
316 UINT8 SecureBootEnable;\r
317 SECURE_BOOT_MODE_TYPE SecureBootMode;\r
318 BOOLEAN IsPkPresent;\r
319\r
320 //\r
321 // Find "PK" variable\r
322 //\r
323 Status = AuthServiceInternalFindVariable (EFI_PLATFORM_KEY_NAME, &gEfiGlobalVariableGuid, (VOID **) &Data, &DataSize);\r
324 if (EFI_ERROR (Status)) {\r
325 IsPkPresent = FALSE;\r
326 DEBUG ((EFI_D_INFO, "Variable %s does not exist.\n", EFI_PLATFORM_KEY_NAME));\r
327 } else {\r
328 IsPkPresent = TRUE;\r
329 DEBUG ((EFI_D_INFO, "Variable %s exists.\n", EFI_PLATFORM_KEY_NAME));\r
330 }\r
331\r
332 //\r
333 // Init "SecureBootMode" variable.\r
334 // Initial case\r
335 // SecureBootMode doesn't exist. Init it with PK state\r
336 // 3 inconsistency cases need to sync\r
337 // 1.1 Add PK -> system break -> update SecureBootMode Var\r
338 // 1.2 Delete PK -> system break -> update SecureBootMode Var\r
339 // 1.3 Set AuditMode ->Delete PK -> system break -> Update SecureBootMode Var\r
340 //\r
341 Status = AuthServiceInternalFindVariable (EDKII_SECURE_BOOT_MODE_NAME, &gEdkiiSecureBootModeGuid, (VOID **)&Data, &DataSize);\r
342 if (EFI_ERROR(Status)) {\r
343 //\r
344 // Variable driver Initial Case\r
345 //\r
346 if (IsPkPresent) {\r
347 SecureBootMode = SecureBootModeTypeUserMode;\r
348 } else {\r
349 SecureBootMode = SecureBootModeTypeSetupMode;\r
350 }\r
351 } else {\r
352 //\r
353 // 3 inconsistency cases need to sync\r
354 //\r
355 SecureBootMode = (SECURE_BOOT_MODE_TYPE)*Data;\r
356 ASSERT(SecureBootMode < SecureBootModeTypeMax);\r
357\r
358 if (IsPkPresent) {\r
359 //\r
360 // 3.1 Add PK -> system break -> update SecureBootMode Var\r
361 //\r
362 if (SecureBootMode == SecureBootModeTypeSetupMode) {\r
363 SecureBootMode = SecureBootModeTypeUserMode;\r
364 } else if (SecureBootMode == SecureBootModeTypeAuditMode) {\r
365 SecureBootMode = SecureBootModeTypeDeployedMode;\r
366 }\r
367 } else {\r
368 //\r
369 // 3.2 Delete PK -> system break -> update SecureBootMode Var\r
370 // 3.3 Set AuditMode ->Delete PK -> system break -> Update SecureBootMode Var. Reinit to be SetupMode\r
371 //\r
372 if ((SecureBootMode == SecureBootModeTypeUserMode) || (SecureBootMode == SecureBootModeTypeDeployedMode)) {\r
373 SecureBootMode = SecureBootModeTypeSetupMode;\r
374 }\r
375 }\r
376 }\r
377\r
378 if (EFI_ERROR(Status) || (SecureBootMode != (SECURE_BOOT_MODE_TYPE)*Data)) {\r
379 //\r
380 // Update SecureBootMode Var\r
381 //\r
382 Status = AuthServiceInternalUpdateVariable (\r
383 EDKII_SECURE_BOOT_MODE_NAME,\r
384 &gEdkiiSecureBootModeGuid,\r
385 &SecureBootMode,\r
386 sizeof (UINT8),\r
387 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS\r
388 );\r
389 if (EFI_ERROR(Status)) {\r
390 return Status;\r
391 }\r
392 }\r
393\r
394 //\r
395 // Init "AuditMode"\r
396 //\r
397 Status = AuthServiceInternalUpdateVariable (\r
398 EFI_AUDIT_MODE_NAME,\r
399 &gEfiGlobalVariableGuid,\r
400 &mSecureBootState[SecureBootMode].AuditMode,\r
401 sizeof(UINT8),\r
402 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS\r
403 );\r
404 if (EFI_ERROR(Status)) {\r
405 return Status;\r
406 }\r
407\r
408 //\r
409 // Init "DeployedMode"\r
410 //\r
411 Status = AuthServiceInternalUpdateVariable (\r
412 EFI_DEPLOYED_MODE_NAME,\r
413 &gEfiGlobalVariableGuid,\r
414 &mSecureBootState[SecureBootMode].DeployedMode,\r
415 sizeof(UINT8),\r
416 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS\r
417 );\r
418 if (EFI_ERROR(Status)) {\r
419 return Status;\r
420 }\r
421\r
422 //\r
423 // Init "SetupMode"\r
424 //\r
425 Status = AuthServiceInternalUpdateVariable (\r
426 EFI_SETUP_MODE_NAME,\r
427 &gEfiGlobalVariableGuid,\r
428 &mSecureBootState[SecureBootMode].SetupMode,\r
429 sizeof(UINT8),\r
430 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS\r
431 );\r
432 if (EFI_ERROR(Status)) {\r
433 return Status;\r
434 }\r
435\r
436 //\r
437 // If "SecureBootEnable" variable exists, then update "SecureBoot" variable.\r
438 // If "SecureBootEnable" variable is SECURE_BOOT_ENABLE and in User Mode or Deployed Mode, Set "SecureBoot" variable to SECURE_BOOT_MODE_ENABLE.\r
439 // If "SecureBootEnable" variable is SECURE_BOOT_DISABLE, Set "SecureBoot" variable to SECURE_BOOT_MODE_DISABLE.\r
440 //\r
441 SecureBootEnable = SECURE_BOOT_DISABLE;\r
442 Status = AuthServiceInternalFindVariable (EFI_SECURE_BOOT_ENABLE_NAME, &gEfiSecureBootEnableDisableGuid, (VOID **)&Data, &DataSize);\r
443 if (!EFI_ERROR(Status)) {\r
444 if (IsPkPresent) {\r
445 SecureBootEnable = *Data;\r
446 }\r
447 } else if ((SecureBootMode == SecureBootModeTypeUserMode) || (SecureBootMode == SecureBootModeTypeDeployedMode)) {\r
448 //\r
449 // "SecureBootEnable" not exist, initialize it in User Mode or Deployed Mode.\r
450 //\r
451 SecureBootEnable = SECURE_BOOT_ENABLE;\r
452 Status = AuthServiceInternalUpdateVariable (\r
453 EFI_SECURE_BOOT_ENABLE_NAME,\r
454 &gEfiSecureBootEnableDisableGuid,\r
455 &SecureBootEnable,\r
456 sizeof (UINT8),\r
457 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS\r
458 );\r
459 if (EFI_ERROR (Status)) {\r
460 return Status;\r
461 }\r
462 }\r
463\r
464 //\r
465 // Create "SecureBoot" variable with BS+RT attribute set.\r
466 //\r
467 if ((SecureBootEnable == SECURE_BOOT_ENABLE) \r
468 && ((SecureBootMode == SecureBootModeTypeUserMode) || (SecureBootMode == SecureBootModeTypeDeployedMode))) {\r
469 SecureBoot = SECURE_BOOT_MODE_ENABLE;\r
470 } else {\r
471 SecureBoot = SECURE_BOOT_MODE_DISABLE;\r
472 }\r
473 Status = AuthServiceInternalUpdateVariable (\r
474 EFI_SECURE_BOOT_MODE_NAME,\r
475 &gEfiGlobalVariableGuid,\r
476 &SecureBoot,\r
477 sizeof (UINT8),\r
478 EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS\r
479 );\r
480\r
481 DEBUG ((EFI_D_INFO, "SecureBootMode is %x\n", SecureBootMode));\r
482 DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_SECURE_BOOT_MODE_NAME, SecureBoot));\r
483 DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_SECURE_BOOT_ENABLE_NAME, SecureBootEnable));\r
484\r
485 //\r
486 // Save SecureBootMode in global space\r
487 //\r
488 mSecureBootMode = SecureBootMode;\r
489\r
490 return Status;\r
491}\r
492\r
493/**\r
494 Update SecureBootMode variable.\r
495\r
496 @param[in] NewMode New Secure Boot Mode.\r
497\r
498 @retval EFI_SUCCESS The initialization operation is successful.\r
499 @retval EFI_OUT_OF_RESOURCES There is not enough resource.\r
500\r
501**/\r
502EFI_STATUS\r
503UpdateSecureBootMode(\r
504 IN SECURE_BOOT_MODE_TYPE NewMode\r
505 )\r
506{\r
507 EFI_STATUS Status;\r
508\r
509 //\r
510 // Update "SecureBootMode" variable to new Secure Boot Mode\r
511 //\r
512 Status = AuthServiceInternalUpdateVariable (\r
513 EDKII_SECURE_BOOT_MODE_NAME,\r
514 &gEdkiiSecureBootModeGuid,\r
515 &NewMode,\r
516 sizeof (UINT8),\r
517 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS\r
518 );\r
519\r
520 if (!EFI_ERROR(Status)) {\r
521 DEBUG((EFI_D_INFO, "SecureBootMode Update to %x\n", NewMode));\r
522 mSecureBootMode = NewMode;\r
523 } else {\r
524 DEBUG((EFI_D_ERROR, "SecureBootMode Update failure %x\n", Status));\r
525 }\r
526\r
527 return Status;\r
528}\r
529\r
530/**\r
531 Current secure boot mode is AuditMode. This function performs secure boot mode transition\r
532 to a new mode.\r
533\r
534 @param[in] NewMode New Secure Boot Mode.\r
535\r
536 @retval EFI_SUCCESS The initialization operation is successful.\r
537 @retval EFI_OUT_OF_RESOURCES There is not enough resource.\r
538\r
539**/\r
540EFI_STATUS\r
541TransitionFromAuditMode(\r
542 IN SECURE_BOOT_MODE_TYPE NewMode\r
543 )\r
544{\r
545 EFI_STATUS Status;\r
546 VOID *AuditVarData;\r
547 VOID *DeployedVarData;\r
548 VOID *SetupVarData;\r
549 VOID *SecureBootVarData;\r
550 UINT8 SecureBootEnable;\r
551 UINTN DataSize;\r
552\r
553 //\r
554 // AuditMode/DeployedMode/SetupMode/SecureBoot are all NON_NV variable maintained by Variable driver\r
555 // they can be RW. but can't be deleted. so they can always be found.\r
556 //\r
557 Status = AuthServiceInternalFindVariable (\r
558 EFI_AUDIT_MODE_NAME,\r
559 &gEfiGlobalVariableGuid,\r
560 &AuditVarData,\r
561 &DataSize\r
562 );\r
563 if (EFI_ERROR (Status)) {\r
564 ASSERT(FALSE);\r
565 }\r
566\r
567 Status = AuthServiceInternalFindVariable (\r
568 EFI_DEPLOYED_MODE_NAME,\r
569 &gEfiGlobalVariableGuid,\r
570 &DeployedVarData,\r
571 &DataSize\r
572 );\r
573 if (EFI_ERROR (Status)) {\r
574 ASSERT(FALSE);\r
575 }\r
576\r
577 Status = AuthServiceInternalFindVariable (\r
578 EFI_SETUP_MODE_NAME,\r
579 &gEfiGlobalVariableGuid,\r
580 &SetupVarData,\r
581 &DataSize\r
582 );\r
583 if (EFI_ERROR (Status)) {\r
584 ASSERT(FALSE);\r
585 }\r
586\r
587 Status = AuthServiceInternalFindVariable (\r
588 EFI_SECURE_BOOT_MODE_NAME,\r
589 &gEfiGlobalVariableGuid,\r
590 &SecureBootVarData,\r
591 &DataSize\r
592 );\r
593 if (EFI_ERROR (Status)) {\r
594 ASSERT(FALSE);\r
595 }\r
596\r
597 //\r
598 // Make Secure Boot Mode transition ATOMIC\r
599 // Update Private NV SecureBootMode Variable first, because it may fail due to NV range overflow.\r
600 // other tranisition logic are all memory operations.\r
601 //\r
602 Status = UpdateSecureBootMode(NewMode);\r
603 if (EFI_ERROR(Status)) {\r
604 DEBUG((EFI_D_ERROR, "Update SecureBootMode Variable fail %x\n", Status));\r
605 }\r
606\r
607 if (NewMode == SecureBootModeTypeDeployedMode) {\r
608 //\r
609 // Since PK is enrolled, can't rollback, always update SecureBootMode in memory\r
610 //\r
611 mSecureBootMode = NewMode;\r
612 Status = EFI_SUCCESS;\r
613\r
614 //\r
615 // AuditMode ----> DeployedMode\r
616 // Side Effects\r
617 // AuditMode =: 0 / DeployedMode := 1 / SetupMode := 0\r
618 //\r
619 // Update the value of AuditMode variable by a simple mem copy, this could avoid possible\r
620 // variable storage reclaim at runtime.\r
621 //\r
622 CopyMem (AuditVarData, &mSecureBootState[NewMode].AuditMode, sizeof(UINT8));\r
623 //\r
624 // Update the value of DeployedMode variable by a simple mem copy, this could avoid possible\r
625 // variable storage reclaim at runtime.\r
626 //\r
627 CopyMem (DeployedVarData, &mSecureBootState[NewMode].DeployedMode, sizeof(UINT8));\r
628 //\r
629 // Update the value of SetupMode variable by a simple mem copy, this could avoid possible\r
630 // variable storage reclaim at runtime.\r
631 //\r
632 CopyMem (SetupVarData, &mSecureBootState[NewMode].SetupMode, sizeof(UINT8));\r
633\r
634 if (mAuthVarLibContextIn->AtRuntime ()) {\r
635 //\r
636 // SecureBoot Variable indicates whether the platform firmware is operating\r
637 // in Secure boot mode (1) or not (0), so we should not change SecureBoot\r
638 // Variable in runtime.\r
639 //\r
640 return Status;\r
641 }\r
642\r
643 //\r
644 // Update the value of SecureBoot variable by a simple mem copy, this could avoid possible\r
645 // variable storage reclaim at runtime.\r
646 //\r
647 CopyMem (SecureBootVarData, &mSecureBootState[NewMode].SecureBoot, sizeof(UINT8));\r
648\r
649 //\r
650 // Create "SecureBootEnable" variable as secure boot is enabled.\r
651 //\r
652 SecureBootEnable = SECURE_BOOT_ENABLE;\r
653 AuthServiceInternalUpdateVariable (\r
654 EFI_SECURE_BOOT_ENABLE_NAME,\r
655 &gEfiSecureBootEnableDisableGuid,\r
656 &SecureBootEnable,\r
657 sizeof (SecureBootEnable),\r
658 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS\r
659 );\r
660 } else {\r
661 DEBUG((EFI_D_ERROR, "Invalid state tranition from %x to %x\n", SecureBootModeTypeAuditMode, NewMode));\r
662 ASSERT(FALSE);\r
663 }\r
664\r
665 return Status;\r
666}\r
667\r
668/**\r
669 Current secure boot mode is DeployedMode. This function performs secure boot mode transition\r
670 to a new mode.\r
671\r
672 @param[in] NewMode New Secure Boot Mode.\r
673\r
674 @retval EFI_SUCCESS The initialization operation is successful.\r
675 @retval EFI_OUT_OF_RESOURCES There is not enough resource.\r
676\r
677**/\r
678EFI_STATUS\r
679TransitionFromDeployedMode(\r
680 IN SECURE_BOOT_MODE_TYPE NewMode\r
681 )\r
682{\r
683 EFI_STATUS Status;\r
684 VOID *DeployedVarData;\r
685 VOID *SetupVarData;\r
686 VOID *SecureBootVarData;\r
687 UINT8 SecureBootEnable;\r
688 UINTN DataSize;\r
689\r
690 //\r
691 // AuditMode/DeployedMode/SetupMode/SecureBoot are all NON_NV variable maintained by Variable driver\r
692 // they can be RW. but can't be deleted. so they can always be found.\r
693 //\r
694 Status = AuthServiceInternalFindVariable (\r
695 EFI_DEPLOYED_MODE_NAME,\r
696 &gEfiGlobalVariableGuid,\r
697 &DeployedVarData,\r
698 &DataSize\r
699 );\r
700 if (EFI_ERROR (Status)) {\r
701 ASSERT(FALSE);\r
702 }\r
703\r
704 Status = AuthServiceInternalFindVariable (\r
705 EFI_SETUP_MODE_NAME,\r
706 &gEfiGlobalVariableGuid,\r
707 &SetupVarData,\r
708 &DataSize\r
709 );\r
710 if (EFI_ERROR (Status)) {\r
711 ASSERT(FALSE);\r
712 }\r
713\r
714 Status = AuthServiceInternalFindVariable (\r
715 EFI_SECURE_BOOT_MODE_NAME,\r
716 &gEfiGlobalVariableGuid,\r
717 &SecureBootVarData,\r
718 &DataSize\r
719 );\r
720 if (EFI_ERROR (Status)) {\r
721 ASSERT(FALSE);\r
722 }\r
723\r
724 //\r
725 // Make Secure Boot Mode transition ATOMIC\r
726 // Update Private NV SecureBootMode Variable first, because it may fail due to NV range overflow.\r
727 // other tranisition logic are all memory operations.\r
728 //\r
729 Status = UpdateSecureBootMode(NewMode);\r
730 if (EFI_ERROR(Status)) {\r
731 DEBUG((EFI_D_ERROR, "Update SecureBootMode Variable fail %x\n", Status));\r
732 }\r
733\r
734 switch(NewMode) {\r
735 case SecureBootModeTypeUserMode:\r
736 //\r
737 // DeployedMode ----> UserMode\r
738 // Side Effects\r
739 // DeployedMode := 0\r
740 //\r
741 // Platform Specific DeployedMode clear. UpdateSecureBootMode fails and no other variables are updated before. rollback this transition\r
742 //\r
743 if (EFI_ERROR(Status)) {\r
744 return Status;\r
745 }\r
746 CopyMem (DeployedVarData, &mSecureBootState[NewMode].DeployedMode, sizeof(UINT8));\r
747\r
748 break;\r
749\r
750 case SecureBootModeTypeSetupMode:\r
751 //\r
752 // Since PK is processed before, can't rollback, still update SecureBootMode in memory\r
753 //\r
754 mSecureBootMode = NewMode;\r
755 Status = EFI_SUCCESS;\r
756\r
757 //\r
758 // DeployedMode ----> SetupMode\r
759 //\r
760 // Platform Specific PKpub clear or Delete Pkpub\r
761 // Side Effects\r
762 // DeployedMode := 0 / SetupMode := 1 / SecureBoot := 0\r
763 //\r
764 // Update the value of DeployedMode variable by a simple mem copy, this could avoid possible\r
765 // variable storage reclaim at runtime.\r
766 //\r
767 CopyMem (DeployedVarData, &mSecureBootState[NewMode].DeployedMode, sizeof(UINT8));\r
768 //\r
769 // Update the value of SetupMode variable by a simple mem copy, this could avoid possible\r
770 // variable storage reclaim at runtime.\r
771 //\r
772 CopyMem (SetupVarData, &mSecureBootState[NewMode].SetupMode, sizeof(UINT8));\r
773\r
774 if (mAuthVarLibContextIn->AtRuntime ()) {\r
775 //\r
776 // SecureBoot Variable indicates whether the platform firmware is operating\r
777 // in Secure boot mode (1) or not (0), so we should not change SecureBoot\r
778 // Variable in runtime.\r
779 //\r
780 return Status;\r
781 }\r
782\r
783 //\r
784 // Update the value of SecureBoot variable by a simple mem copy, this could avoid possible\r
785 // variable storage reclaim at runtime.\r
786 //\r
787 CopyMem (SecureBootVarData, &mSecureBootState[NewMode].SecureBoot, sizeof(UINT8));\r
788\r
789 //\r
790 // Delete the "SecureBootEnable" variable as secure boot is Disabled.\r
791 //\r
792 SecureBootEnable = SECURE_BOOT_DISABLE;\r
793 AuthServiceInternalUpdateVariable (\r
794 EFI_SECURE_BOOT_ENABLE_NAME,\r
795 &gEfiSecureBootEnableDisableGuid,\r
796 &SecureBootEnable,\r
797 0,\r
798 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS\r
799 );\r
800 break;\r
801\r
802 default:\r
803 DEBUG((EFI_D_ERROR, "Invalid state tranition from %x to %x\n", SecureBootModeTypeDeployedMode, NewMode));\r
804 ASSERT(FALSE);\r
805 }\r
806\r
807 return Status;\r
808}\r
809\r
810/**\r
811 Current secure boot mode is UserMode. This function performs secure boot mode transition\r
812 to a new mode.\r
813\r
814 @param[in] NewMode New Secure Boot Mode.\r
815\r
816 @retval EFI_SUCCESS The initialization operation is successful.\r
817 @retval EFI_OUT_OF_RESOURCES There is not enough resource.\r
818\r
819**/\r
820EFI_STATUS\r
821TransitionFromUserMode(\r
822 IN SECURE_BOOT_MODE_TYPE NewMode\r
823 )\r
824{\r
825 EFI_STATUS Status;\r
826 VOID *AuditVarData;\r
827 VOID *DeployedVarData;\r
828 VOID *SetupVarData;\r
829 VOID *PkVarData;\r
830 VOID *SecureBootVarData;\r
831 UINT8 SecureBootEnable;\r
832 UINTN DataSize;\r
833 VARIABLE_ENTRY_CONSISTENCY VariableEntry;\r
834\r
835 //\r
836 // AuditMode/DeployedMode/SetupMode/SecureBoot are all NON_NV variable maintained by Variable driver\r
837 // they can be RW. but can't be deleted. so they can always be found.\r
838 //\r
839 Status = AuthServiceInternalFindVariable (\r
840 EFI_AUDIT_MODE_NAME,\r
841 &gEfiGlobalVariableGuid,\r
842 &AuditVarData,\r
843 &DataSize\r
844 );\r
845 if (EFI_ERROR (Status)) {\r
846 ASSERT(FALSE);\r
847 }\r
848\r
849 Status = AuthServiceInternalFindVariable (\r
850 EFI_DEPLOYED_MODE_NAME,\r
851 &gEfiGlobalVariableGuid,\r
852 &DeployedVarData,\r
853 &DataSize\r
854 );\r
855 if (EFI_ERROR (Status)) {\r
856 ASSERT(FALSE);\r
857 }\r
858\r
859 Status = AuthServiceInternalFindVariable (\r
860 EFI_SETUP_MODE_NAME,\r
861 &gEfiGlobalVariableGuid,\r
862 &SetupVarData,\r
863 &DataSize\r
864 );\r
865 if (EFI_ERROR (Status)) {\r
866 ASSERT(FALSE);\r
867 }\r
868\r
869 Status = AuthServiceInternalFindVariable (\r
870 EFI_SECURE_BOOT_MODE_NAME,\r
871 &gEfiGlobalVariableGuid,\r
872 &SecureBootVarData,\r
873 &DataSize\r
874 );\r
875 if (EFI_ERROR (Status)) {\r
876 ASSERT(FALSE);\r
877 }\r
878\r
879 //\r
880 // Make Secure Boot Mode transition ATOMIC\r
881 // Update Private NV SecureBootMode Variable first, because it may fail due to NV range overflow. \r
882 // Other tranisition logic are all memory operations and PK delete is assumed to be always successful.\r
883 //\r
884 if (NewMode != SecureBootModeTypeAuditMode) {\r
885 Status = UpdateSecureBootMode(NewMode);\r
886 if (EFI_ERROR(Status)) {\r
887 DEBUG((EFI_D_ERROR, "Update SecureBootMode Variable fail %x\n", Status));\r
888 }\r
889 } else {\r
890 //\r
891 // UserMode -----> AuditMode. Check RemainingSpace for SecureBootMode var first.\r
892 // Will update SecureBootMode after DeletePK logic\r
893 //\r
894 VariableEntry.VariableSize = sizeof(UINT8);\r
895 VariableEntry.Guid = &gEdkiiSecureBootModeGuid;\r
896 VariableEntry.Name = EDKII_SECURE_BOOT_MODE_NAME;\r
897 if (!mAuthVarLibContextIn->CheckRemainingSpaceForConsistency (VARIABLE_ATTRIBUTE_NV_BS_RT, &VariableEntry, NULL)) {\r
898 return EFI_OUT_OF_RESOURCES;\r
899 }\r
900 }\r
901\r
902 switch(NewMode) {\r
903 case SecureBootModeTypeDeployedMode:\r
904 //\r
905 // UpdateSecureBootMode fails and no other variables are updated before. rollback this transition\r
906 //\r
907 if (EFI_ERROR(Status)) {\r
908 return Status;\r
909 }\r
910\r
911 //\r
912 // UserMode ----> DeployedMode\r
913 // Side Effects\r
914 // DeployedMode := 1\r
915 //\r
916 CopyMem (DeployedVarData, &mSecureBootState[NewMode].DeployedMode, sizeof(UINT8));\r
917 break;\r
918\r
919 case SecureBootModeTypeAuditMode:\r
920 //\r
921 // UserMode ----> AuditMode\r
922 // Side Effects\r
923 // Delete PKpub / SetupMode := 1 / SecureBoot := 0\r
924 //\r
925 // Delete PKpub without verification. Should always succeed.\r
926 //\r
927 PkVarData = NULL;\r
928 Status = AuthServiceInternalUpdateVariable (\r
929 EFI_PLATFORM_KEY_NAME,\r
930 &gEfiGlobalVariableGuid,\r
931 PkVarData,\r
932 0,\r
933 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS\r
934 );\r
935 if (EFI_ERROR(Status)) {\r
936 DEBUG((EFI_D_ERROR, "UserMode -> AuditMode. Delete PK fail %x\n", Status));\r
937 ASSERT(FALSE);\r
938 }\r
939\r
940 //\r
941 // Update Private NV SecureBootMode Variable\r
942 //\r
943 Status = UpdateSecureBootMode(NewMode);\r
944 if (EFI_ERROR(Status)) {\r
945 //\r
946 // Since PK is deleted successfully, Doesn't break, continue to update other variable.\r
947 //\r
948 DEBUG((EFI_D_ERROR, "Update SecureBootMode Variable fail %x\n", Status));\r
949 }\r
950 CopyMem (AuditVarData, &mSecureBootState[NewMode].AuditMode, sizeof(UINT8));\r
951\r
952 //\r
953 // Fall into SetupMode logic\r
954 //\r
955 case SecureBootModeTypeSetupMode:\r
956 //\r
957 // Since PK is deleted before , can't rollback, still update SecureBootMode in memory\r
958 //\r
959 mSecureBootMode = NewMode;\r
960 Status = EFI_SUCCESS;\r
961\r
962 //\r
963 // UserMode ----> SetupMode\r
964 // Side Effects\r
965 // DeployedMode :=0 / SetupMode :=1 / SecureBoot :=0\r
966 //\r
967 // Update the value of SetupMode variable by a simple mem copy, this could avoid possible\r
968 // variable storage reclaim at runtime.\r
969 //\r
970 CopyMem (SetupVarData, &mSecureBootState[NewMode].SetupMode, sizeof(UINT8));\r
971\r
972 if (mAuthVarLibContextIn->AtRuntime ()) {\r
973 //\r
974 // SecureBoot Variable indicates whether the platform firmware is operating\r
975 // in Secure boot mode (1) or not (0), so we should not change SecureBoot\r
976 // Variable in runtime.\r
977 //\r
978 return Status;\r
979 }\r
980\r
981 //\r
982 // Update the value of SecureBoot variable by a simple mem copy, this could avoid possible\r
983 // variable storage reclaim at runtime.\r
984 //\r
985 CopyMem (SecureBootVarData, &mSecureBootState[NewMode].SecureBoot, sizeof(UINT8));\r
986\r
987 //\r
988 // Delete the "SecureBootEnable" variable as secure boot is Disabled.\r
989 //\r
990 SecureBootEnable = SECURE_BOOT_DISABLE;\r
991 AuthServiceInternalUpdateVariable (\r
992 EFI_SECURE_BOOT_ENABLE_NAME,\r
993 &gEfiSecureBootEnableDisableGuid,\r
994 &SecureBootEnable,\r
995 0,\r
996 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS\r
997 );\r
998\r
999 break;\r
1000\r
1001 default:\r
1002 DEBUG((EFI_D_ERROR, "Invalid state tranition from %x to %x\n", SecureBootModeTypeUserMode, NewMode));\r
1003 ASSERT(FALSE);\r
1004 }\r
1005\r
1006 return Status;\r
1007}\r
1008\r
1009/**\r
1010 Current secure boot mode is SetupMode. This function performs secure boot mode transition\r
1011 to a new mode.\r
1012\r
1013 @param[in] NewMode New Secure Boot Mode.\r
1014\r
1015 @retval EFI_SUCCESS The initialization operation is successful.\r
1016 @retval EFI_OUT_OF_RESOURCES There is not enough resource.\r
1017\r
1018**/\r
1019EFI_STATUS\r
1020TransitionFromSetupMode(\r
1021 IN SECURE_BOOT_MODE_TYPE NewMode\r
1022 )\r
1023{\r
1024 EFI_STATUS Status;\r
1025 VOID *AuditVarData;\r
1026 VOID *SetupVarData;\r
1027 VOID *SecureBootVarData;\r
1028 UINT8 SecureBootEnable;\r
1029 UINTN DataSize;\r
1030\r
1031 //\r
1032 // AuditMode/DeployedMode/SetupMode/SecureBoot are all NON_NV variable maintained by Variable driver\r
1033 // they can be RW. but can't be deleted. so they can always be found.\r
1034 //\r
1035 Status = AuthServiceInternalFindVariable (\r
1036 EFI_AUDIT_MODE_NAME,\r
1037 &gEfiGlobalVariableGuid,\r
1038 &AuditVarData,\r
1039 &DataSize\r
1040 );\r
1041 if (EFI_ERROR (Status)) {\r
1042 ASSERT(FALSE);\r
1043 }\r
1044\r
1045 Status = AuthServiceInternalFindVariable (\r
1046 EFI_SETUP_MODE_NAME,\r
1047 &gEfiGlobalVariableGuid,\r
1048 &SetupVarData,\r
1049 &DataSize\r
1050 );\r
1051 if (EFI_ERROR (Status)) {\r
1052 ASSERT(FALSE);\r
1053 }\r
1054\r
1055 Status = AuthServiceInternalFindVariable (\r
1056 EFI_SECURE_BOOT_MODE_NAME,\r
1057 &gEfiGlobalVariableGuid,\r
1058 &SecureBootVarData,\r
1059 &DataSize\r
1060 );\r
1061 if (EFI_ERROR (Status)) {\r
1062 ASSERT(FALSE);\r
1063 }\r
1064\r
1065 //\r
1066 // Make Secure Boot Mode transition ATOMIC\r
1067 // Update Private NV SecureBootMode Variable first, because it may fail due to NV range overflow.\r
1068 // Other tranisition logic are all memory operations and PK delete is assumed to be always successful.\r
1069 //\r
1070 Status = UpdateSecureBootMode(NewMode);\r
1071 if (EFI_ERROR(Status)) {\r
1072 DEBUG((EFI_D_ERROR, "Update SecureBootMode Variable fail %x\n", Status));\r
1073 }\r
1074\r
1075 switch(NewMode) {\r
1076 case SecureBootModeTypeAuditMode:\r
1077 //\r
1078 // UpdateSecureBootMode fails and no other variables are updated before. rollback this transition\r
1079 //\r
1080 if (EFI_ERROR(Status)) {\r
1081 return Status;\r
1082 }\r
1083\r
1084 //\r
1085 // SetupMode ----> AuditMode\r
1086 // Side Effects\r
1087 // AuditMode := 1\r
1088 //\r
1089 // Update the value of AuditMode variable by a simple mem copy, this could avoid possible\r
1090 // variable storage reclaim at runtime.\r
1091 //\r
1092 CopyMem (AuditVarData, &mSecureBootState[NewMode].AuditMode, sizeof(UINT8));\r
1093 break;\r
1094\r
1095 case SecureBootModeTypeUserMode:\r
1096 //\r
1097 // Since PK is enrolled before, can't rollback, still update SecureBootMode in memory\r
1098 //\r
1099 mSecureBootMode = NewMode;\r
1100 Status = EFI_SUCCESS;\r
1101\r
1102 //\r
1103 // SetupMode ----> UserMode\r
1104 // Side Effects\r
1105 // SetupMode := 0 / SecureBoot := 1\r
1106 //\r
1107 // Update the value of AuditMode variable by a simple mem copy, this could avoid possible\r
1108 // variable storage reclaim at runtime.\r
1109 //\r
1110 CopyMem (SetupVarData, &mSecureBootState[NewMode].SetupMode, sizeof(UINT8));\r
1111\r
1112 if (mAuthVarLibContextIn->AtRuntime ()) {\r
1113 //\r
1114 // SecureBoot Variable indicates whether the platform firmware is operating\r
1115 // in Secure boot mode (1) or not (0), so we should not change SecureBoot\r
1116 // Variable in runtime.\r
1117 //\r
1118 return Status;\r
1119 }\r
1120\r
1121 //\r
1122 // Update the value of SecureBoot variable by a simple mem copy, this could avoid possible\r
1123 // variable storage reclaim at runtime.\r
1124 //\r
1125 CopyMem (SecureBootVarData, &mSecureBootState[NewMode].SecureBoot, sizeof(UINT8));\r
1126\r
1127 //\r
1128 // Create the "SecureBootEnable" variable as secure boot is enabled.\r
1129 //\r
1130 SecureBootEnable = SECURE_BOOT_ENABLE;\r
1131 AuthServiceInternalUpdateVariable (\r
1132 EFI_SECURE_BOOT_ENABLE_NAME,\r
1133 &gEfiSecureBootEnableDisableGuid,\r
1134 &SecureBootEnable,\r
1135 sizeof (SecureBootEnable),\r
1136 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS\r
1137 );\r
1138 break;\r
1139\r
1140 default:\r
1141 DEBUG((EFI_D_ERROR, "Invalid state tranition from %x to %x\n", SecureBootModeTypeSetupMode, NewMode));\r
1142 ASSERT(FALSE);\r
1143 }\r
1144\r
1145 return Status;\r
1146}\r
1147\r
1148/**\r
1149 This function performs main secure boot mode transition logic.\r
1150\r
1151 @param[in] CurMode Current Secure Boot Mode.\r
1152 @param[in] NewMode New Secure Boot Mode.\r
1153\r
1154 @retval EFI_SUCCESS The initialization operation is successful.\r
1155 @retval EFI_OUT_OF_RESOURCES There is not enough resource.\r
1156 @retval EFI_INVALID_PARAMETER The Current Secure Boot Mode is wrong.\r
1157\r
1158**/\r
1159EFI_STATUS\r
1160SecureBootModeTransition(\r
1161 IN SECURE_BOOT_MODE_TYPE CurMode,\r
1162 IN SECURE_BOOT_MODE_TYPE NewMode\r
1163 )\r
1164{\r
1165 EFI_STATUS Status;\r
1166\r
1167 //\r
1168 // SecureBootMode transition\r
1169 //\r
1170 switch (CurMode) {\r
1171 case SecureBootModeTypeUserMode:\r
1172 Status = TransitionFromUserMode(NewMode);\r
1173 break;\r
1174\r
1175 case SecureBootModeTypeSetupMode:\r
1176 Status = TransitionFromSetupMode(NewMode);\r
1177 break;\r
1178\r
1179 case SecureBootModeTypeAuditMode:\r
1180 Status = TransitionFromAuditMode(NewMode);\r
1181 break;\r
1182\r
1183 case SecureBootModeTypeDeployedMode:\r
1184 Status = TransitionFromDeployedMode(NewMode);\r
1185 break;\r
1186\r
1187 default:\r
1188 Status = EFI_INVALID_PARAMETER;\r
1189 ASSERT(FALSE);\r
1190 }\r
1191\r
1192 return Status;\r
1193\r
1194}\r
1195\r
1196/**\r
1197 Determine whether this operation needs a physical present user.\r
1198\r
1199 @param[in] VariableName Name of the Variable.\r
1200 @param[in] VendorGuid GUID of the Variable.\r
1201\r
1202 @retval TRUE This variable is protected, only a physical present user could set this variable.\r
1203 @retval FALSE This variable is not protected.\r
1204\r
1205**/\r
1206BOOLEAN\r
1207NeedPhysicallyPresent(\r
1208 IN CHAR16 *VariableName,\r
1209 IN EFI_GUID *VendorGuid\r
1210 )\r
1211{\r
1212 if ((CompareGuid (VendorGuid, &gEfiSecureBootEnableDisableGuid) && (StrCmp (VariableName, EFI_SECURE_BOOT_ENABLE_NAME) == 0))\r
1213 || (CompareGuid (VendorGuid, &gEfiCustomModeEnableGuid) && (StrCmp (VariableName, EFI_CUSTOM_MODE_NAME) == 0))) {\r
1214 return TRUE;\r
1215 }\r
1216\r
1217 return FALSE;\r
1218}\r
1219\r
1220/**\r
1221 Determine whether the platform is operating in Custom Secure Boot mode.\r
1222\r
1223 @retval TRUE The platform is operating in Custom mode.\r
1224 @retval FALSE The platform is operating in Standard mode.\r
1225\r
1226**/\r
1227BOOLEAN\r
1228InCustomMode (\r
1229 VOID\r
1230 )\r
1231{\r
1232 EFI_STATUS Status;\r
1233 VOID *Data;\r
1234 UINTN DataSize;\r
1235\r
1236 Status = AuthServiceInternalFindVariable (EFI_CUSTOM_MODE_NAME, &gEfiCustomModeEnableGuid, &Data, &DataSize);\r
1237 if (!EFI_ERROR (Status) && (*(UINT8 *) Data == CUSTOM_SECURE_BOOT_MODE)) {\r
1238 return TRUE;\r
1239 }\r
1240\r
1241 return FALSE;\r
1242}\r
1243\r
1244/**\r
1245 Get available public key index.\r
1246\r
1247 @param[in] PubKey Pointer to Public Key data.\r
1248\r
1249 @return Public key index, 0 if no any public key index available.\r
1250\r
1251**/\r
1252UINT32\r
1253GetAvailableKeyIndex (\r
1254 IN UINT8 *PubKey\r
1255 )\r
1256{\r
1257 EFI_STATUS Status;\r
1258 UINT8 *Data;\r
1259 UINTN DataSize;\r
1260 UINT8 *Ptr;\r
1261 UINT32 Index;\r
1262 BOOLEAN IsFound;\r
1263 EFI_GUID VendorGuid;\r
1264 CHAR16 Name[1];\r
1265 AUTH_VARIABLE_INFO AuthVariableInfo;\r
1266 UINT32 KeyIndex;\r
1267\r
1268 Status = AuthServiceInternalFindVariable (\r
1269 AUTHVAR_KEYDB_NAME,\r
1270 &gEfiAuthenticatedVariableGuid,\r
1271 (VOID **) &Data,\r
1272 &DataSize\r
1273 );\r
1274 if (EFI_ERROR (Status)) {\r
1275 DEBUG ((EFI_D_ERROR, "Get public key database variable failure, Status = %r\n", Status));\r
1276 return 0;\r
1277 }\r
1278\r
1279 if (mPubKeyNumber == mMaxKeyNumber) {\r
1280 Name[0] = 0;\r
1281 AuthVariableInfo.VariableName = Name;\r
1282 ZeroMem (&VendorGuid, sizeof (VendorGuid));\r
1283 AuthVariableInfo.VendorGuid = &VendorGuid;\r
1284 mPubKeyNumber = 0;\r
1285 //\r
1286 // Collect valid key data.\r
1287 //\r
1288 do {\r
1289 Status = mAuthVarLibContextIn->FindNextVariable (AuthVariableInfo.VariableName, AuthVariableInfo.VendorGuid, &AuthVariableInfo);\r
1290 if (!EFI_ERROR (Status)) {\r
1291 if (AuthVariableInfo.PubKeyIndex != 0) {\r
1292 for (Ptr = Data; Ptr < (Data + DataSize); Ptr += sizeof (AUTHVAR_KEY_DB_DATA)) {\r
1293 if (ReadUnaligned32 (&(((AUTHVAR_KEY_DB_DATA *) Ptr)->KeyIndex)) == AuthVariableInfo.PubKeyIndex) {\r
1294 //\r
1295 // Check if the key data has been collected.\r
1296 //\r
1297 for (Index = 0; Index < mPubKeyNumber; Index++) {\r
1298 if (ReadUnaligned32 (&(((AUTHVAR_KEY_DB_DATA *) mPubKeyStore + Index)->KeyIndex)) == AuthVariableInfo.PubKeyIndex) {\r
1299 break;\r
1300 }\r
1301 }\r
1302 if (Index == mPubKeyNumber) {\r
1303 //\r
1304 // New key data.\r
1305 //\r
1306 CopyMem ((AUTHVAR_KEY_DB_DATA *) mPubKeyStore + mPubKeyNumber, Ptr, sizeof (AUTHVAR_KEY_DB_DATA));\r
1307 mPubKeyNumber++;\r
1308 }\r
1309 break;\r
1310 }\r
1311 }\r
1312 }\r
1313 }\r
1314 } while (Status != EFI_NOT_FOUND);\r
1315\r
1316 //\r
1317 // No available space to add new public key.\r
1318 //\r
1319 if (mPubKeyNumber == mMaxKeyNumber) {\r
1320 return 0;\r
1321 }\r
1322 }\r
1323\r
1324 //\r
1325 // Find available public key index.\r
1326 //\r
1327 for (KeyIndex = 1; KeyIndex <= mMaxKeyNumber; KeyIndex++) {\r
1328 IsFound = FALSE;\r
1329 for (Ptr = mPubKeyStore; Ptr < (mPubKeyStore + mPubKeyNumber * sizeof (AUTHVAR_KEY_DB_DATA)); Ptr += sizeof (AUTHVAR_KEY_DB_DATA)) {\r
1330 if (ReadUnaligned32 (&(((AUTHVAR_KEY_DB_DATA *) Ptr)->KeyIndex)) == KeyIndex) {\r
1331 IsFound = TRUE;\r
1332 break;\r
1333 }\r
1334 }\r
1335 if (!IsFound) {\r
1336 break;\r
1337 }\r
1338 }\r
1339\r
1340 return KeyIndex;\r
1341}\r
1342\r
1343/**\r
1344 Add public key in store and return its index.\r
1345\r
1346 @param[in] PubKey Input pointer to Public Key data.\r
1347 @param[in] VariableDataEntry The variable data entry.\r
1348\r
1349 @return Index of new added public key.\r
1350\r
1351**/\r
1352UINT32\r
1353AddPubKeyInStore (\r
1354 IN UINT8 *PubKey,\r
1355 IN VARIABLE_ENTRY_CONSISTENCY *VariableDataEntry\r
1356 )\r
1357{\r
1358 EFI_STATUS Status;\r
1359 UINT32 Index;\r
1360 VARIABLE_ENTRY_CONSISTENCY PublicKeyEntry;\r
1361 UINT32 Attributes;\r
1362 UINT32 KeyIndex;\r
1363\r
1364 if (PubKey == NULL) {\r
1365 return 0;\r
1366 }\r
1367\r
1368 //\r
1369 // Check whether the public key entry does exist.\r
1370 //\r
1371 for (Index = 0; Index < mPubKeyNumber; Index++) {\r
1372 if (CompareMem (((AUTHVAR_KEY_DB_DATA *) mPubKeyStore + Index)->KeyData, PubKey, EFI_CERT_TYPE_RSA2048_SIZE) == 0) {\r
1373 return ReadUnaligned32 (&(((AUTHVAR_KEY_DB_DATA *) mPubKeyStore + Index)->KeyIndex));\r
1374 }\r
1375 }\r
1376\r
1377 KeyIndex = GetAvailableKeyIndex (PubKey);\r
1378 if (KeyIndex == 0) {\r
1379 return 0;\r
1380 }\r
1381\r
1382 //\r
1383 // Check the variable space for both public key and variable data.\r
1384 //\r
1385 PublicKeyEntry.VariableSize = (mPubKeyNumber + 1) * sizeof (AUTHVAR_KEY_DB_DATA);\r
1386 PublicKeyEntry.Guid = &gEfiAuthenticatedVariableGuid;\r
1387 PublicKeyEntry.Name = AUTHVAR_KEYDB_NAME;\r
1388 Attributes = VARIABLE_ATTRIBUTE_NV_BS_RT | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;\r
1389\r
1390 if (!mAuthVarLibContextIn->CheckRemainingSpaceForConsistency (Attributes, &PublicKeyEntry, VariableDataEntry, NULL)) {\r
1391 //\r
1392 // No enough variable space.\r
1393 //\r
1394 return 0;\r
1395 }\r
1396\r
1397 WriteUnaligned32 (&(((AUTHVAR_KEY_DB_DATA *) mPubKeyStore + mPubKeyNumber)->KeyIndex), KeyIndex);\r
1398 CopyMem (((AUTHVAR_KEY_DB_DATA *) mPubKeyStore + mPubKeyNumber)->KeyData, PubKey, EFI_CERT_TYPE_RSA2048_SIZE);\r
1399 mPubKeyNumber++;\r
1400\r
1401 //\r
1402 // Update public key database variable.\r
1403 //\r
1404 Status = AuthServiceInternalUpdateVariable (\r
1405 AUTHVAR_KEYDB_NAME,\r
1406 &gEfiAuthenticatedVariableGuid,\r
1407 mPubKeyStore,\r
1408 mPubKeyNumber * sizeof (AUTHVAR_KEY_DB_DATA),\r
1409 Attributes\r
1410 );\r
1411 if (EFI_ERROR (Status)) {\r
1412 DEBUG ((EFI_D_ERROR, "Update public key database variable failure, Status = %r\n", Status));\r
1413 return 0;\r
1414 }\r
1415\r
1416 return KeyIndex;\r
1417}\r
1418\r
1419/**\r
1420 Verify data payload with AuthInfo in EFI_CERT_TYPE_RSA2048_SHA256_GUID type.\r
1421 Follow the steps in UEFI2.2.\r
1422\r
1423 Caution: This function may receive untrusted input.\r
1424 This function may be invoked in SMM mode, and datasize and data are external input.\r
1425 This function will do basic validation, before parse the data.\r
1426 This function will parse the authentication carefully to avoid security issues, like\r
1427 buffer overflow, integer overflow.\r
1428\r
1429 @param[in] Data Pointer to data with AuthInfo.\r
1430 @param[in] DataSize Size of Data.\r
1431 @param[in] PubKey Public key used for verification.\r
1432\r
1433 @retval EFI_INVALID_PARAMETER Invalid parameter.\r
1434 @retval EFI_SECURITY_VIOLATION If authentication failed.\r
1435 @retval EFI_SUCCESS Authentication successful.\r
1436\r
1437**/\r
1438EFI_STATUS\r
1439VerifyCounterBasedPayload (\r
1440 IN UINT8 *Data,\r
1441 IN UINTN DataSize,\r
1442 IN UINT8 *PubKey\r
1443 )\r
1444{\r
1445 BOOLEAN Status;\r
1446 EFI_VARIABLE_AUTHENTICATION *CertData;\r
1447 EFI_CERT_BLOCK_RSA_2048_SHA256 *CertBlock;\r
1448 UINT8 Digest[SHA256_DIGEST_SIZE];\r
1449 VOID *Rsa;\r
1450 UINTN PayloadSize;\r
1451\r
1452 PayloadSize = DataSize - AUTHINFO_SIZE;\r
1453 Rsa = NULL;\r
1454 CertData = NULL;\r
1455 CertBlock = NULL;\r
1456\r
1457 if (Data == NULL || PubKey == NULL) {\r
1458 return EFI_INVALID_PARAMETER;\r
1459 }\r
1460\r
1461 CertData = (EFI_VARIABLE_AUTHENTICATION *) Data;\r
1462 CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData);\r
1463\r
1464 //\r
1465 // wCertificateType should be WIN_CERT_TYPE_EFI_GUID.\r
1466 // Cert type should be EFI_CERT_TYPE_RSA2048_SHA256_GUID.\r
1467 //\r
1468 if ((CertData->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID) ||\r
1469 !CompareGuid (&CertData->AuthInfo.CertType, &gEfiCertTypeRsa2048Sha256Guid)) {\r
1470 //\r
1471 // Invalid AuthInfo type, return EFI_SECURITY_VIOLATION.\r
1472 //\r
1473 return EFI_SECURITY_VIOLATION;\r
1474 }\r
1475 //\r
1476 // Hash data payload with SHA256.\r
1477 //\r
1478 ZeroMem (Digest, SHA256_DIGEST_SIZE);\r
1479 Status = Sha256Init (mHashCtx);\r
1480 if (!Status) {\r
1481 goto Done;\r
1482 }\r
1483 Status = Sha256Update (mHashCtx, Data + AUTHINFO_SIZE, PayloadSize);\r
1484 if (!Status) {\r
1485 goto Done;\r
1486 }\r
1487 //\r
1488 // Hash Size.\r
1489 //\r
1490 Status = Sha256Update (mHashCtx, &PayloadSize, sizeof (UINTN));\r
1491 if (!Status) {\r
1492 goto Done;\r
1493 }\r
1494 //\r
1495 // Hash Monotonic Count.\r
1496 //\r
1497 Status = Sha256Update (mHashCtx, &CertData->MonotonicCount, sizeof (UINT64));\r
1498 if (!Status) {\r
1499 goto Done;\r
1500 }\r
1501 Status = Sha256Final (mHashCtx, Digest);\r
1502 if (!Status) {\r
1503 goto Done;\r
1504 }\r
1505 //\r
1506 // Generate & Initialize RSA Context.\r
1507 //\r
1508 Rsa = RsaNew ();\r
1509 ASSERT (Rsa != NULL);\r
1510 //\r
1511 // Set RSA Key Components.\r
1512 // NOTE: Only N and E are needed to be set as RSA public key for signature verification.\r
1513 //\r
1514 Status = RsaSetKey (Rsa, RsaKeyN, PubKey, EFI_CERT_TYPE_RSA2048_SIZE);\r
1515 if (!Status) {\r
1516 goto Done;\r
1517 }\r
1518 Status = RsaSetKey (Rsa, RsaKeyE, mRsaE, sizeof (mRsaE));\r
1519 if (!Status) {\r
1520 goto Done;\r
1521 }\r
1522 //\r
1523 // Verify the signature.\r
1524 //\r
1525 Status = RsaPkcs1Verify (\r
1526 Rsa,\r
1527 Digest,\r
1528 SHA256_DIGEST_SIZE,\r
1529 CertBlock->Signature,\r
1530 EFI_CERT_TYPE_RSA2048_SHA256_SIZE\r
1531 );\r
1532\r
1533Done:\r
1534 if (Rsa != NULL) {\r
1535 RsaFree (Rsa);\r
1536 }\r
1537 if (Status) {\r
1538 return EFI_SUCCESS;\r
1539 } else {\r
1540 return EFI_SECURITY_VIOLATION;\r
1541 }\r
1542}\r
1543\r
1544\r
1545/**\r
1546 Check input data form to make sure it is a valid EFI_SIGNATURE_LIST for PK/KEK/db/dbx/dbt variable.\r
1547\r
1548 @param[in] VariableName Name of Variable to be check.\r
1549 @param[in] VendorGuid Variable vendor GUID.\r
1550 @param[in] Data Point to the variable data to be checked.\r
1551 @param[in] DataSize Size of Data.\r
1552\r
1553 @return EFI_INVALID_PARAMETER Invalid signature list format.\r
1554 @return EFI_SUCCESS Passed signature list format check successfully.\r
1555\r
1556**/\r
1557EFI_STATUS\r
1558CheckSignatureListFormat(\r
1559 IN CHAR16 *VariableName,\r
1560 IN EFI_GUID *VendorGuid,\r
1561 IN VOID *Data,\r
1562 IN UINTN DataSize\r
1563 )\r
1564{\r
1565 EFI_SIGNATURE_LIST *SigList;\r
1566 UINTN SigDataSize;\r
1567 UINT32 Index;\r
1568 UINT32 SigCount;\r
1569 BOOLEAN IsPk;\r
1570 VOID *RsaContext;\r
1571 EFI_SIGNATURE_DATA *CertData;\r
1572 UINTN CertLen;\r
1573\r
1574 if (DataSize == 0) {\r
1575 return EFI_SUCCESS;\r
1576 }\r
1577\r
1578 ASSERT (VariableName != NULL && VendorGuid != NULL && Data != NULL);\r
1579\r
1580 if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_PLATFORM_KEY_NAME) == 0)){\r
1581 IsPk = TRUE;\r
1582 } else if ((CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_KEY_EXCHANGE_KEY_NAME) == 0)) ||\r
1583 (CompareGuid (VendorGuid, &gEfiImageSecurityDatabaseGuid) &&\r
1584 ((StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE) == 0) || (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE1) == 0) ||\r
1585 (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE2) == 0)))) {\r
1586 IsPk = FALSE;\r
1587 } else {\r
1588 return EFI_SUCCESS;\r
1589 }\r
1590\r
1591 SigCount = 0;\r
1592 SigList = (EFI_SIGNATURE_LIST *) Data;\r
1593 SigDataSize = DataSize;\r
1594 RsaContext = NULL;\r
1595\r
1596 //\r
1597 // Walk throuth the input signature list and check the data format.\r
1598 // If any signature is incorrectly formed, the whole check will fail.\r
1599 //\r
1600 while ((SigDataSize > 0) && (SigDataSize >= SigList->SignatureListSize)) {\r
1601 for (Index = 0; Index < (sizeof (mSupportSigItem) / sizeof (EFI_SIGNATURE_ITEM)); Index++ ) {\r
1602 if (CompareGuid (&SigList->SignatureType, &mSupportSigItem[Index].SigType)) {\r
1603 //\r
1604 // The value of SignatureSize should always be 16 (size of SignatureOwner\r
1605 // component) add the data length according to signature type.\r
1606 //\r
1607 if (mSupportSigItem[Index].SigDataSize != ((UINT32) ~0) &&\r
1608 (SigList->SignatureSize - sizeof (EFI_GUID)) != mSupportSigItem[Index].SigDataSize) {\r
1609 return EFI_INVALID_PARAMETER;\r
1610 }\r
1611 if (mSupportSigItem[Index].SigHeaderSize != ((UINT32) ~0) &&\r
1612 SigList->SignatureHeaderSize != mSupportSigItem[Index].SigHeaderSize) {\r
1613 return EFI_INVALID_PARAMETER;\r
1614 }\r
1615 break;\r
1616 }\r
1617 }\r
1618\r
1619 if (Index == (sizeof (mSupportSigItem) / sizeof (EFI_SIGNATURE_ITEM))) {\r
1620 //\r
1621 // Undefined signature type.\r
1622 //\r
1623 return EFI_INVALID_PARAMETER;\r
1624 }\r
1625\r
1626 if (CompareGuid (&SigList->SignatureType, &gEfiCertX509Guid)) {\r
1627 //\r
1628 // Try to retrieve the RSA public key from the X.509 certificate.\r
1629 // If this operation fails, it's not a valid certificate.\r
1630 //\r
1631 RsaContext = RsaNew ();\r
1632 if (RsaContext == NULL) {\r
1633 return EFI_INVALID_PARAMETER;\r
1634 }\r
1635 CertData = (EFI_SIGNATURE_DATA *) ((UINT8 *) SigList + sizeof (EFI_SIGNATURE_LIST) + SigList->SignatureHeaderSize);\r
1636 CertLen = SigList->SignatureSize - sizeof (EFI_GUID);\r
1637 if (!RsaGetPublicKeyFromX509 (CertData->SignatureData, CertLen, &RsaContext)) {\r
1638 RsaFree (RsaContext);\r
1639 return EFI_INVALID_PARAMETER;\r
1640 }\r
1641 RsaFree (RsaContext);\r
1642 }\r
1643\r
1644 if ((SigList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - SigList->SignatureHeaderSize) % SigList->SignatureSize != 0) {\r
1645 return EFI_INVALID_PARAMETER;\r
1646 }\r
1647 SigCount += (SigList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - SigList->SignatureHeaderSize) / SigList->SignatureSize;\r
1648\r
1649 SigDataSize -= SigList->SignatureListSize;\r
1650 SigList = (EFI_SIGNATURE_LIST *) ((UINT8 *) SigList + SigList->SignatureListSize);\r
1651 }\r
1652\r
1653 if (((UINTN) SigList - (UINTN) Data) != DataSize) {\r
1654 return EFI_INVALID_PARAMETER;\r
1655 }\r
1656\r
1657 if (IsPk && SigCount > 1) {\r
1658 return EFI_INVALID_PARAMETER;\r
1659 }\r
1660\r
1661 return EFI_SUCCESS;\r
1662}\r
1663\r
1664/**\r
1665 Update "VendorKeys" variable to record the out of band secure boot key modification.\r
1666\r
1667 @return EFI_SUCCESS Variable is updated successfully.\r
1668 @return Others Failed to update variable.\r
1669\r
1670**/\r
1671EFI_STATUS\r
1672VendorKeyIsModified (\r
1673 VOID\r
1674 )\r
1675{\r
1676 EFI_STATUS Status;\r
1677\r
1678 if (mVendorKeyState == VENDOR_KEYS_MODIFIED) {\r
1679 return EFI_SUCCESS;\r
1680 }\r
1681 mVendorKeyState = VENDOR_KEYS_MODIFIED;\r
1682\r
1683 Status = AuthServiceInternalUpdateVariable (\r
1684 EFI_VENDOR_KEYS_NV_VARIABLE_NAME,\r
1685 &gEfiVendorKeysNvGuid,\r
1686 &mVendorKeyState,\r
1687 sizeof (UINT8),\r
1688 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS\r
1689 );\r
1690 if (EFI_ERROR (Status)) {\r
1691 return Status;\r
1692 }\r
1693\r
1694 return AuthServiceInternalUpdateVariable (\r
1695 EFI_VENDOR_KEYS_VARIABLE_NAME,\r
1696 &gEfiGlobalVariableGuid,\r
1697 &mVendorKeyState,\r
1698 sizeof (UINT8),\r
1699 EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS\r
1700 );\r
1701}\r
1702\r
1703/**\r
1704 Process Secure Boot Mode variable.\r
1705\r
1706 Caution: This function may receive untrusted input.\r
1707 This function may be invoked in SMM mode, and datasize and data are external input.\r
1708 This function will do basic validation, before parse the data.\r
1709 This function will parse the authentication carefully to avoid security issues, like\r
1710 buffer overflow, integer overflow.\r
1711 This function will check attribute carefully to avoid authentication bypass.\r
1712\r
1713 @param[in] VariableName Name of Variable to be found.\r
1714 @param[in] VendorGuid Variable vendor GUID.\r
1715 @param[in] Data Data pointer.\r
1716 @param[in] DataSize Size of Data found. If size is less than the\r
1717 data, this value contains the required size.\r
1718 @param[in] Attributes Attribute value of the variable\r
1719\r
1720 @return EFI_INVALID_PARAMETER Invalid parameter\r
1721 @return EFI_SECURITY_VIOLATION The variable does NOT pass the validation\r
1722 check carried out by the firmware.\r
1723 @return EFI_WRITE_PROTECTED Variable is Read-Only.\r
1724 @return EFI_SUCCESS Variable passed validation successfully.\r
1725\r
1726**/\r
1727EFI_STATUS\r
1728ProcessSecureBootModeVar (\r
1729 IN CHAR16 *VariableName,\r
1730 IN EFI_GUID *VendorGuid,\r
1731 IN VOID *Data,\r
1732 IN UINTN DataSize,\r
1733 IN UINT32 Attributes OPTIONAL\r
1734 )\r
1735{\r
1736 EFI_STATUS Status;\r
1737 VOID *VarData;\r
1738 UINTN VarDataSize;\r
1739\r
1740 //\r
1741 // Check "AuditMode", "DeployedMode" Variable ReadWrite Attributes\r
1742 // if in Runtime, Always RO\r
1743 // if in Boottime, Depends on current Secure Boot Mode\r
1744 //\r
1745 if (mAuthVarLibContextIn->AtRuntime()) {\r
1746 return EFI_WRITE_PROTECTED;\r
1747 }\r
1748\r
1749 //\r
1750 // Delete not OK\r
1751 //\r
1752 if ((DataSize != sizeof(UINT8)) || (Attributes == 0)) {\r
1753 return EFI_INVALID_PARAMETER;\r
1754 }\r
1755\r
1756 if (StrCmp (VariableName, EFI_AUDIT_MODE_NAME) == 0) {\r
1757 if(mSecureBootState[mSecureBootMode].IsAuditModeRO) {\r
1758 return EFI_WRITE_PROTECTED;\r
1759 }\r
1760 } else {\r
1761 //\r
1762 // Platform specific deployedMode clear. Set DeployedMode = RW\r
1763 //\r
1764 if (!InCustomMode() || !UserPhysicalPresent() || mSecureBootMode != SecureBootModeTypeDeployedMode) {\r
1765 if(mSecureBootState[mSecureBootMode].IsDeployedModeRO) {\r
1766 return EFI_WRITE_PROTECTED;\r
1767 }\r
1768 }\r
1769 }\r
1770\r
1771 if (*(UINT8 *)Data != 0 && *(UINT8 *)Data != 1) {\r
1772 return EFI_INVALID_PARAMETER;\r
1773 }\r
1774\r
1775 //\r
1776 // AuditMode/DeployedMode/SetupMode/SecureBoot are all NON_NV variable maintained by Variable driver\r
1777 // they can be RW. but can't be deleted. so they can always be found.\r
1778 //\r
1779 Status = AuthServiceInternalFindVariable (\r
1780 VariableName,\r
1781 VendorGuid,\r
1782 &VarData,\r
1783 &VarDataSize\r
1784 );\r
1785 if (EFI_ERROR(Status)) {\r
1786 ASSERT(FALSE);\r
1787 }\r
1788\r
1789 //\r
1790 // If AuditMode/DeployedMode is assigned same value. Simply return EFI_SUCCESS\r
1791 //\r
1792 if (*(UINT8 *)VarData == *(UINT8 *)Data) {\r
1793 return EFI_SUCCESS;\r
1794 }\r
1795\r
1796 //\r
1797 // Perform SecureBootMode transition\r
1798 //\r
1799 if (StrCmp (VariableName, EFI_AUDIT_MODE_NAME) == 0) {\r
1800 DEBUG((EFI_D_INFO, "Current SecureBootMode %x Transfer to SecureBootMode %x\n", mSecureBootMode, SecureBootModeTypeAuditMode));\r
1801 return SecureBootModeTransition(mSecureBootMode, SecureBootModeTypeAuditMode);\r
1802 } else if (StrCmp (VariableName, EFI_DEPLOYED_MODE_NAME) == 0) {\r
1803 if (mSecureBootMode == SecureBootModeTypeDeployedMode) {\r
1804 //\r
1805 // Platform specific DeployedMode clear. InCustomMode() && UserPhysicalPresent() is checked before\r
1806 //\r
1807 DEBUG((EFI_D_INFO, "Current SecureBootMode %x. Transfer to SecureBootMode %x\n", mSecureBootMode, SecureBootModeTypeUserMode));\r
1808 return SecureBootModeTransition(mSecureBootMode, SecureBootModeTypeUserMode);\r
1809 } else {\r
1810 DEBUG((EFI_D_INFO, "Current SecureBootMode %x. Transfer to SecureBootMode %x\n", mSecureBootMode, SecureBootModeTypeDeployedMode));\r
1811 return SecureBootModeTransition(mSecureBootMode, SecureBootModeTypeDeployedMode);\r
1812 }\r
1813 }\r
1814\r
1815 return EFI_INVALID_PARAMETER;\r
1816}\r
1817\r
1818/**\r
1819 Process variable with platform key for verification.\r
1820\r
1821 Caution: This function may receive untrusted input.\r
1822 This function may be invoked in SMM mode, and datasize and data are external input.\r
1823 This function will do basic validation, before parse the data.\r
1824 This function will parse the authentication carefully to avoid security issues, like\r
1825 buffer overflow, integer overflow.\r
1826 This function will check attribute carefully to avoid authentication bypass.\r
1827\r
1828 @param[in] VariableName Name of Variable to be found.\r
1829 @param[in] VendorGuid Variable vendor GUID.\r
1830 @param[in] Data Data pointer.\r
1831 @param[in] DataSize Size of Data found. If size is less than the\r
1832 data, this value contains the required size.\r
1833 @param[in] Attributes Attribute value of the variable\r
1834 @param[in] IsPk Indicate whether it is to process pk.\r
1835\r
1836 @return EFI_INVALID_PARAMETER Invalid parameter.\r
1837 @return EFI_SECURITY_VIOLATION The variable does NOT pass the validation.\r
1838 check carried out by the firmware.\r
1839 @return EFI_SUCCESS Variable passed validation successfully.\r
1840\r
1841**/\r
1842EFI_STATUS\r
1843ProcessVarWithPk (\r
1844 IN CHAR16 *VariableName,\r
1845 IN EFI_GUID *VendorGuid,\r
1846 IN VOID *Data,\r
1847 IN UINTN DataSize,\r
1848 IN UINT32 Attributes OPTIONAL,\r
1849 IN BOOLEAN IsPk\r
1850 )\r
1851{\r
1852 EFI_STATUS Status;\r
1853 BOOLEAN Del;\r
1854 UINT8 *Payload;\r
1855 UINTN PayloadSize;\r
1856 VARIABLE_ENTRY_CONSISTENCY VariableEntry[2];\r
1857\r
1858 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0 ||\r
1859 (Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == 0) {\r
1860 //\r
1861 // PK, KEK and db/dbx/dbt should set EFI_VARIABLE_NON_VOLATILE attribute and should be a time-based\r
1862 // authenticated variable.\r
1863 //\r
1864 return EFI_INVALID_PARAMETER;\r
1865 }\r
1866\r
1867 //\r
1868 // Init state of Del. State may change due to secure check\r
1869 //\r
1870 Del = FALSE;\r
1871 Payload = (UINT8 *) Data + AUTHINFO2_SIZE (Data);\r
1872 PayloadSize = DataSize - AUTHINFO2_SIZE (Data);\r
1873 if (PayloadSize == 0) {\r
1874 Del = TRUE;\r
1875 }\r
1876\r
1877 //\r
1878 // Check the variable space for both PKpub and SecureBootMode variable.\r
1879 //\r
1880 VariableEntry[0].VariableSize = PayloadSize;\r
1881 VariableEntry[0].Guid = &gEfiGlobalVariableGuid;\r
1882 VariableEntry[0].Name = EFI_PLATFORM_KEY_NAME;\r
1883\r
1884 VariableEntry[1].VariableSize = sizeof(UINT8);\r
1885 VariableEntry[1].Guid = &gEdkiiSecureBootModeGuid;\r
1886 VariableEntry[1].Name = EDKII_SECURE_BOOT_MODE_NAME;\r
1887\r
1888 if ((InCustomMode() && UserPhysicalPresent()) || \r
1889 (((mSecureBootMode == SecureBootModeTypeSetupMode) || (mSecureBootMode == SecureBootModeTypeAuditMode)) && !IsPk)) {\r
1890\r
1891 Status = CheckSignatureListFormat(VariableName, VendorGuid, Payload, PayloadSize);\r
1892 if (EFI_ERROR (Status)) {\r
1893 return Status;\r
1894 }\r
1895\r
1896 //\r
1897 // If delete PKpub, only check for "SecureBootMode" only\r
1898 // if update / add PKpub, check both NewPKpub & "SecureBootMode"\r
1899 //\r
1900 if (IsPk) {\r
1901 //\r
1902 // Delete PKpub\r
1903 //\r
1904 if (Del && ((mSecureBootMode == SecureBootModeTypeUserMode) || (mSecureBootMode == SecureBootModeTypeDeployedMode)) \r
1905 && !mAuthVarLibContextIn->CheckRemainingSpaceForConsistency (VARIABLE_ATTRIBUTE_NV_BS_RT, &VariableEntry[1], NULL)){\r
1906 return EFI_OUT_OF_RESOURCES;\r
1907 //\r
1908 // Add PKpub\r
1909 //\r
1910 } else if (!Del && ((mSecureBootMode == SecureBootModeTypeSetupMode) || (mSecureBootMode == SecureBootModeTypeAuditMode))\r
1911 && !mAuthVarLibContextIn->CheckRemainingSpaceForConsistency (VARIABLE_ATTRIBUTE_NV_BS_RT, &VariableEntry[0], &VariableEntry[1], NULL)) {\r
1912 return EFI_OUT_OF_RESOURCES;\r
1913 }\r
1914 }\r
1915\r
1916 Status = AuthServiceInternalUpdateVariableWithTimeStamp (\r
1917 VariableName,\r
1918 VendorGuid,\r
1919 Payload,\r
1920 PayloadSize,\r
1921 Attributes,\r
1922 &((EFI_VARIABLE_AUTHENTICATION_2 *) Data)->TimeStamp\r
1923 );\r
1924 if (EFI_ERROR(Status)) {\r
1925 return Status;\r
1926 }\r
1927\r
1928 if (((mSecureBootMode != SecureBootModeTypeSetupMode) && (mSecureBootMode != SecureBootModeTypeAuditMode)) || IsPk) {\r
1929 Status = VendorKeyIsModified ();\r
1930 }\r
1931 } else if (mSecureBootMode == SecureBootModeTypeUserMode || mSecureBootMode == SecureBootModeTypeDeployedMode) {\r
1932 //\r
1933 // If delete PKpub, check "SecureBootMode" only\r
1934 //\r
1935 if (IsPk && Del && !mAuthVarLibContextIn->CheckRemainingSpaceForConsistency (VARIABLE_ATTRIBUTE_NV_BS_RT, &VariableEntry[1], NULL)){\r
1936 return EFI_OUT_OF_RESOURCES;\r
1937 }\r
1938\r
1939 //\r
1940 // Verify against X509 Cert in PK database.\r
1941 //\r
1942 Status = VerifyTimeBasedPayloadAndUpdate (\r
1943 VariableName,\r
1944 VendorGuid,\r
1945 Data,\r
1946 DataSize,\r
1947 Attributes,\r
1948 AuthVarTypePk,\r
1949 &Del\r
1950 );\r
1951 } else {\r
1952 //\r
1953 // SetupMode or AuditMode to add PK\r
1954 // Verify against the certificate in data payload.\r
1955 //\r
1956 //\r
1957 // Check PKpub & SecureBootMode variable space consistency\r
1958 //\r
1959 if (!mAuthVarLibContextIn->CheckRemainingSpaceForConsistency (VARIABLE_ATTRIBUTE_NV_BS_RT, &VariableEntry[0], &VariableEntry[1], NULL)) {\r
1960 //\r
1961 // No enough variable space to set PK successfully.\r
1962 //\r
1963 return EFI_OUT_OF_RESOURCES;\r
1964 }\r
1965\r
1966 Status = VerifyTimeBasedPayloadAndUpdate (\r
1967 VariableName,\r
1968 VendorGuid,\r
1969 Data,\r
1970 DataSize,\r
1971 Attributes,\r
1972 AuthVarTypePayload,\r
1973 &Del\r
1974 );\r
1975 }\r
1976\r
1977 if (!EFI_ERROR(Status) && IsPk) {\r
1978 //\r
1979 // Delete or Enroll PK causes SecureBootMode change\r
1980 //\r
1981 if (!Del) {\r
1982 if (mSecureBootMode == SecureBootModeTypeSetupMode) {\r
1983 //\r
1984 // If enroll PK in setup mode, change to user mode.\r
1985 //\r
1986 Status = SecureBootModeTransition (mSecureBootMode, SecureBootModeTypeUserMode);\r
1987 } else if (mSecureBootMode == SecureBootModeTypeAuditMode) {\r
1988 //\r
1989 // If enroll PK in Audit mode, change to Deployed mode.\r
1990 //\r
1991 Status = SecureBootModeTransition (mSecureBootMode, SecureBootModeTypeDeployedMode);\r
1992 } else {\r
1993 DEBUG((EFI_D_INFO, "PK is updated in %x mode. No SecureBootMode change.\n", mSecureBootMode));\r
1994 }\r
1995 } else {\r
1996 if ((mSecureBootMode == SecureBootModeTypeUserMode) || (mSecureBootMode == SecureBootModeTypeDeployedMode)) {\r
1997 //\r
1998 // If delete PK in User Mode or DeployedMode, change to Setup Mode.\r
1999 //\r
2000 Status = SecureBootModeTransition (mSecureBootMode, SecureBootModeTypeSetupMode);\r
2001 }\r
2002 }\r
2003 }\r
2004\r
2005 return Status;\r
2006}\r
2007\r
2008/**\r
2009 Process variable with key exchange key for verification.\r
2010\r
2011 Caution: This function may receive untrusted input.\r
2012 This function may be invoked in SMM mode, and datasize and data are external input.\r
2013 This function will do basic validation, before parse the data.\r
2014 This function will parse the authentication carefully to avoid security issues, like\r
2015 buffer overflow, integer overflow.\r
2016 This function will check attribute carefully to avoid authentication bypass.\r
2017\r
2018 @param[in] VariableName Name of Variable to be found.\r
2019 @param[in] VendorGuid Variable vendor GUID.\r
2020 @param[in] Data Data pointer.\r
2021 @param[in] DataSize Size of Data found. If size is less than the\r
2022 data, this value contains the required size.\r
2023 @param[in] Attributes Attribute value of the variable.\r
2024\r
2025 @return EFI_INVALID_PARAMETER Invalid parameter.\r
2026 @return EFI_SECURITY_VIOLATION The variable does NOT pass the validation\r
2027 check carried out by the firmware.\r
2028 @return EFI_SUCCESS Variable pass validation successfully.\r
2029\r
2030**/\r
2031EFI_STATUS\r
2032ProcessVarWithKek (\r
2033 IN CHAR16 *VariableName,\r
2034 IN EFI_GUID *VendorGuid,\r
2035 IN VOID *Data,\r
2036 IN UINTN DataSize,\r
2037 IN UINT32 Attributes OPTIONAL\r
2038 )\r
2039{\r
2040 EFI_STATUS Status;\r
2041 UINT8 *Payload;\r
2042 UINTN PayloadSize;\r
2043\r
2044 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0 ||\r
2045 (Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == 0) {\r
2046 //\r
2047 // DB, DBX and DBT should set EFI_VARIABLE_NON_VOLATILE attribute and should be a time-based\r
2048 // authenticated variable.\r
2049 //\r
2050 return EFI_INVALID_PARAMETER;\r
2051 }\r
2052\r
2053 Status = EFI_SUCCESS;\r
2054 if ((mSecureBootMode == SecureBootModeTypeUserMode || mSecureBootMode == SecureBootModeTypeDeployedMode)\r
2055 && !(InCustomMode() && UserPhysicalPresent())) {\r
2056 //\r
2057 // Time-based, verify against X509 Cert KEK.\r
2058 //\r
2059 return VerifyTimeBasedPayloadAndUpdate (\r
2060 VariableName,\r
2061 VendorGuid,\r
2062 Data,\r
2063 DataSize,\r
2064 Attributes,\r
2065 AuthVarTypeKek,\r
2066 NULL\r
2067 );\r
2068 } else {\r
2069 //\r
2070 // If in setup mode or custom secure boot mode, no authentication needed.\r
2071 //\r
2072 Payload = (UINT8 *) Data + AUTHINFO2_SIZE (Data);\r
2073 PayloadSize = DataSize - AUTHINFO2_SIZE (Data);\r
2074\r
2075 Status = CheckSignatureListFormat(VariableName, VendorGuid, Payload, PayloadSize);\r
2076 if (EFI_ERROR (Status)) {\r
2077 return Status;\r
2078 }\r
2079\r
2080 Status = AuthServiceInternalUpdateVariableWithTimeStamp (\r
2081 VariableName,\r
2082 VendorGuid,\r
2083 Payload,\r
2084 PayloadSize,\r
2085 Attributes,\r
2086 &((EFI_VARIABLE_AUTHENTICATION_2 *) Data)->TimeStamp\r
2087 );\r
2088 if (EFI_ERROR (Status)) {\r
2089 return Status;\r
2090 }\r
2091\r
2092 if ((mSecureBootMode != SecureBootModeTypeSetupMode) && (mSecureBootMode != SecureBootModeTypeAuditMode)) {\r
2093 Status = VendorKeyIsModified ();\r
2094 }\r
2095 }\r
2096\r
2097 return Status;\r
2098}\r
2099\r
2100/**\r
2101 Check if it is to delete auth variable.\r
2102\r
2103 @param[in] OrgAttributes Original attribute value of the variable.\r
2104 @param[in] Data Data pointer.\r
2105 @param[in] DataSize Size of Data.\r
2106 @param[in] Attributes Attribute value of the variable.\r
2107\r
2108 @retval TRUE It is to delete auth variable.\r
2109 @retval FALSE It is not to delete auth variable.\r
2110\r
2111**/\r
2112BOOLEAN\r
2113IsDeleteAuthVariable (\r
2114 IN UINT32 OrgAttributes,\r
2115 IN VOID *Data,\r
2116 IN UINTN DataSize,\r
2117 IN UINT32 Attributes\r
2118 )\r
2119{\r
2120 BOOLEAN Del;\r
2121 UINTN PayloadSize;\r
2122\r
2123 Del = FALSE;\r
2124\r
2125 //\r
2126 // To delete a variable created with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS\r
2127 // or the EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute,\r
2128 // SetVariable must be used with attributes matching the existing variable\r
2129 // and the DataSize set to the size of the AuthInfo descriptor.\r
2130 //\r
2131 if ((Attributes == OrgAttributes) &&\r
2132 ((Attributes & (EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)) != 0)) {\r
2133 if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
2134 PayloadSize = DataSize - AUTHINFO2_SIZE (Data);\r
2135 if (PayloadSize == 0) {\r
2136 Del = TRUE;\r
2137 }\r
2138 } else {\r
2139 PayloadSize = DataSize - AUTHINFO_SIZE;\r
2140 if (PayloadSize == 0) {\r
2141 Del = TRUE;\r
2142 }\r
2143 }\r
2144 }\r
2145\r
2146 return Del;\r
2147}\r
2148\r
2149/**\r
2150 Process variable with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS/EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set\r
2151\r
2152 Caution: This function may receive untrusted input.\r
2153 This function may be invoked in SMM mode, and datasize and data are external input.\r
2154 This function will do basic validation, before parse the data.\r
2155 This function will parse the authentication carefully to avoid security issues, like\r
2156 buffer overflow, integer overflow.\r
2157 This function will check attribute carefully to avoid authentication bypass.\r
2158\r
2159 @param[in] VariableName Name of the variable.\r
2160 @param[in] VendorGuid Variable vendor GUID.\r
2161 @param[in] Data Data pointer.\r
2162 @param[in] DataSize Size of Data.\r
2163 @param[in] Attributes Attribute value of the variable.\r
2164\r
2165 @return EFI_INVALID_PARAMETER Invalid parameter.\r
2166 @return EFI_WRITE_PROTECTED Variable is write-protected and needs authentication with\r
2167 EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.\r
2168 @return EFI_OUT_OF_RESOURCES The Database to save the public key is full.\r
2169 @return EFI_SECURITY_VIOLATION The variable is with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS\r
2170 set, but the AuthInfo does NOT pass the validation\r
2171 check carried out by the firmware.\r
2172 @return EFI_SUCCESS Variable is not write-protected or pass validation successfully.\r
2173\r
2174**/\r
2175EFI_STATUS\r
2176ProcessVariable (\r
2177 IN CHAR16 *VariableName,\r
2178 IN EFI_GUID *VendorGuid,\r
2179 IN VOID *Data,\r
2180 IN UINTN DataSize,\r
2181 IN UINT32 Attributes\r
2182 )\r
2183{\r
2184 EFI_STATUS Status;\r
2185 BOOLEAN IsDeletion;\r
2186 BOOLEAN IsFirstTime;\r
2187 UINT8 *PubKey;\r
2188 EFI_VARIABLE_AUTHENTICATION *CertData;\r
2189 EFI_CERT_BLOCK_RSA_2048_SHA256 *CertBlock;\r
2190 UINT32 KeyIndex;\r
2191 UINT64 MonotonicCount;\r
2192 VARIABLE_ENTRY_CONSISTENCY VariableDataEntry;\r
2193 UINT32 Index;\r
2194 AUTH_VARIABLE_INFO OrgVariableInfo;\r
2195\r
2196 KeyIndex = 0;\r
2197 CertData = NULL;\r
2198 CertBlock = NULL;\r
2199 PubKey = NULL;\r
2200 IsDeletion = FALSE;\r
2201 Status = EFI_SUCCESS;\r
2202\r
2203 ZeroMem (&OrgVariableInfo, sizeof (OrgVariableInfo));\r
2204 Status = mAuthVarLibContextIn->FindVariable (\r
2205 VariableName,\r
2206 VendorGuid,\r
2207 &OrgVariableInfo\r
2208 );\r
2209\r
2210 if ((!EFI_ERROR (Status)) && IsDeleteAuthVariable (OrgVariableInfo.Attributes, Data, DataSize, Attributes) && UserPhysicalPresent()) {\r
2211 //\r
2212 // Allow the delete operation of common authenticated variable at user physical presence.\r
2213 //\r
2214 Status = AuthServiceInternalUpdateVariable (\r
2215 VariableName,\r
2216 VendorGuid,\r
2217 NULL,\r
2218 0,\r
2219 0\r
2220 );\r
2221 if (!EFI_ERROR (Status) && ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0)) {\r
2222 Status = DeleteCertsFromDb (VariableName, VendorGuid, Attributes);\r
2223 }\r
2224\r
2225 return Status;\r
2226 }\r
2227\r
2228 if (NeedPhysicallyPresent (VariableName, VendorGuid) && !UserPhysicalPresent()) {\r
2229 //\r
2230 // This variable is protected, only physical present user could modify its value.\r
2231 //\r
2232 return EFI_SECURITY_VIOLATION;\r
2233 }\r
2234\r
2235 //\r
2236 // A time-based authenticated variable and a count-based authenticated variable\r
2237 // can't be updated by each other.\r
2238 //\r
2239 if (OrgVariableInfo.Data != NULL) {\r
2240 if (((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) &&\r
2241 ((OrgVariableInfo.Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0)) {\r
2242 return EFI_SECURITY_VIOLATION;\r
2243 }\r
2244\r
2245 if (((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) &&\r
2246 ((OrgVariableInfo.Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0)) {\r
2247 return EFI_SECURITY_VIOLATION;\r
2248 }\r
2249 }\r
2250\r
2251 //\r
2252 // Process Time-based Authenticated variable.\r
2253 //\r
2254 if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
2255 return VerifyTimeBasedPayloadAndUpdate (\r
2256 VariableName,\r
2257 VendorGuid,\r
2258 Data,\r
2259 DataSize,\r
2260 Attributes,\r
2261 AuthVarTypePriv,\r
2262 NULL\r
2263 );\r
2264 }\r
2265\r
2266 //\r
2267 // Determine if first time SetVariable with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS.\r
2268 //\r
2269 if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
2270 //\r
2271 // Determine current operation type.\r
2272 //\r
2273 if (DataSize == AUTHINFO_SIZE) {\r
2274 IsDeletion = TRUE;\r
2275 }\r
2276 //\r
2277 // Determine whether this is the first time with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.\r
2278 //\r
2279 if (OrgVariableInfo.Data == NULL) {\r
2280 IsFirstTime = TRUE;\r
2281 } else if ((OrgVariableInfo.Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == 0) {\r
2282 IsFirstTime = TRUE;\r
2283 } else {\r
2284 KeyIndex = OrgVariableInfo.PubKeyIndex;\r
2285 IsFirstTime = FALSE;\r
2286 }\r
2287 } else if ((OrgVariableInfo.Data != NULL) &&\r
2288 ((OrgVariableInfo.Attributes & (EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)) != 0)\r
2289 ) {\r
2290 //\r
2291 // If the variable is already write-protected, it always needs authentication before update.\r
2292 //\r
2293 return EFI_WRITE_PROTECTED;\r
2294 } else {\r
2295 //\r
2296 // If without EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, set and attributes collision.\r
2297 // That means it is not authenticated variable, just update variable as usual.\r
2298 //\r
2299 Status = AuthServiceInternalUpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes);\r
2300 return Status;\r
2301 }\r
2302\r
2303 //\r
2304 // Get PubKey and check Monotonic Count value corresponding to the variable.\r
2305 //\r
2306 CertData = (EFI_VARIABLE_AUTHENTICATION *) Data;\r
2307 CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData);\r
2308 PubKey = CertBlock->PublicKey;\r
2309\r
2310 //\r
2311 // Update Monotonic Count value.\r
2312 //\r
2313 MonotonicCount = CertData->MonotonicCount;\r
2314\r
2315 if (!IsFirstTime) {\r
2316 //\r
2317 // 2 cases need to check here\r
2318 // 1. Internal PubKey variable. PubKeyIndex is always 0\r
2319 // 2. Other counter-based AuthVariable. Check input PubKey.\r
2320 //\r
2321 if (KeyIndex == 0) {\r
2322 return EFI_SECURITY_VIOLATION;\r
2323 }\r
2324 for (Index = 0; Index < mPubKeyNumber; Index++) {\r
2325 if (ReadUnaligned32 (&(((AUTHVAR_KEY_DB_DATA *) mPubKeyStore + Index)->KeyIndex)) == KeyIndex) {\r
2326 if (CompareMem (((AUTHVAR_KEY_DB_DATA *) mPubKeyStore + Index)->KeyData, PubKey, EFI_CERT_TYPE_RSA2048_SIZE) == 0) {\r
2327 break;\r
2328 } else {\r
2329 return EFI_SECURITY_VIOLATION;\r
2330 }\r
2331 }\r
2332 }\r
2333 if (Index == mPubKeyNumber) {\r
2334 return EFI_SECURITY_VIOLATION;\r
2335 }\r
2336\r
2337 //\r
2338 // Compare the current monotonic count and ensure that it is greater than the last SetVariable\r
2339 // operation with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute set.\r
2340 //\r
2341 if (MonotonicCount <= OrgVariableInfo.MonotonicCount) {\r
2342 //\r
2343 // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.\r
2344 //\r
2345 return EFI_SECURITY_VIOLATION;\r
2346 }\r
2347 }\r
2348 //\r
2349 // Verify the certificate in Data payload.\r
2350 //\r
2351 Status = VerifyCounterBasedPayload (Data, DataSize, PubKey);\r
2352 if (EFI_ERROR (Status)) {\r
2353 return Status;\r
2354 }\r
2355\r
2356 //\r
2357 // Now, the signature has been verified!\r
2358 //\r
2359 if (IsFirstTime && !IsDeletion) {\r
2360 VariableDataEntry.VariableSize = DataSize - AUTHINFO_SIZE;\r
2361 VariableDataEntry.Guid = VendorGuid;\r
2362 VariableDataEntry.Name = VariableName;\r
2363\r
2364 //\r
2365 // Update public key database variable if need.\r
2366 //\r
2367 KeyIndex = AddPubKeyInStore (PubKey, &VariableDataEntry);\r
2368 if (KeyIndex == 0) {\r
2369 return EFI_OUT_OF_RESOURCES;\r
2370 }\r
2371 }\r
2372\r
2373 //\r
2374 // Verification pass.\r
2375 //\r
2376 return AuthServiceInternalUpdateVariableWithMonotonicCount (VariableName, VendorGuid, (UINT8*)Data + AUTHINFO_SIZE, DataSize - AUTHINFO_SIZE, Attributes, KeyIndex, MonotonicCount);\r
2377}\r
2378\r
2379/**\r
2380 Filter out the duplicated EFI_SIGNATURE_DATA from the new data by comparing to the original data.\r
2381\r
2382 @param[in] Data Pointer to original EFI_SIGNATURE_LIST.\r
2383 @param[in] DataSize Size of Data buffer.\r
2384 @param[in, out] NewData Pointer to new EFI_SIGNATURE_LIST.\r
2385 @param[in, out] NewDataSize Size of NewData buffer.\r
2386\r
2387**/\r
2388EFI_STATUS\r
2389FilterSignatureList (\r
2390 IN VOID *Data,\r
2391 IN UINTN DataSize,\r
2392 IN OUT VOID *NewData,\r
2393 IN OUT UINTN *NewDataSize\r
2394 )\r
2395{\r
2396 EFI_SIGNATURE_LIST *CertList;\r
2397 EFI_SIGNATURE_DATA *Cert;\r
2398 UINTN CertCount;\r
2399 EFI_SIGNATURE_LIST *NewCertList;\r
2400 EFI_SIGNATURE_DATA *NewCert;\r
2401 UINTN NewCertCount;\r
2402 UINTN Index;\r
2403 UINTN Index2;\r
2404 UINTN Size;\r
2405 UINT8 *Tail;\r
2406 UINTN CopiedCount;\r
2407 UINTN SignatureListSize;\r
2408 BOOLEAN IsNewCert;\r
2409 UINT8 *TempData;\r
2410 UINTN TempDataSize;\r
2411 EFI_STATUS Status;\r
2412\r
2413 if (*NewDataSize == 0) {\r
2414 return EFI_SUCCESS;\r
2415 }\r
2416\r
2417 TempDataSize = *NewDataSize;\r
2418 Status = mAuthVarLibContextIn->GetScratchBuffer (&TempDataSize, (VOID **) &TempData);\r
2419 if (EFI_ERROR (Status)) {\r
2420 return EFI_OUT_OF_RESOURCES;\r
2421 }\r
2422\r
2423 Tail = TempData;\r
2424\r
2425 NewCertList = (EFI_SIGNATURE_LIST *) NewData;\r
2426 while ((*NewDataSize > 0) && (*NewDataSize >= NewCertList->SignatureListSize)) {\r
2427 NewCert = (EFI_SIGNATURE_DATA *) ((UINT8 *) NewCertList + sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize);\r
2428 NewCertCount = (NewCertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - NewCertList->SignatureHeaderSize) / NewCertList->SignatureSize;\r
2429\r
2430 CopiedCount = 0;\r
2431 for (Index = 0; Index < NewCertCount; Index++) {\r
2432 IsNewCert = TRUE;\r
2433\r
2434 Size = DataSize;\r
2435 CertList = (EFI_SIGNATURE_LIST *) Data;\r
2436 while ((Size > 0) && (Size >= CertList->SignatureListSize)) {\r
2437 if (CompareGuid (&CertList->SignatureType, &NewCertList->SignatureType) &&\r
2438 (CertList->SignatureSize == NewCertList->SignatureSize)) {\r
2439 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);\r
2440 CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;\r
2441 for (Index2 = 0; Index2 < CertCount; Index2++) {\r
2442 //\r
2443 // Iterate each Signature Data in this Signature List.\r
2444 //\r
2445 if (CompareMem (NewCert, Cert, CertList->SignatureSize) == 0) {\r
2446 IsNewCert = FALSE;\r
2447 break;\r
2448 }\r
2449 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);\r
2450 }\r
2451 }\r
2452\r
2453 if (!IsNewCert) {\r
2454 break;\r
2455 }\r
2456 Size -= CertList->SignatureListSize;\r
2457 CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);\r
2458 }\r
2459\r
2460 if (IsNewCert) {\r
2461 //\r
2462 // New EFI_SIGNATURE_DATA, keep it.\r
2463 //\r
2464 if (CopiedCount == 0) {\r
2465 //\r
2466 // Copy EFI_SIGNATURE_LIST header for only once.\r
2467 //\r
2468 CopyMem (Tail, NewCertList, sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize);\r
2469 Tail = Tail + sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize;\r
2470 }\r
2471\r
2472 CopyMem (Tail, NewCert, NewCertList->SignatureSize);\r
2473 Tail += NewCertList->SignatureSize;\r
2474 CopiedCount++;\r
2475 }\r
2476\r
2477 NewCert = (EFI_SIGNATURE_DATA *) ((UINT8 *) NewCert + NewCertList->SignatureSize);\r
2478 }\r
2479\r
2480 //\r
2481 // Update SignatureListSize in the kept EFI_SIGNATURE_LIST.\r
2482 //\r
2483 if (CopiedCount != 0) {\r
2484 SignatureListSize = sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize + (CopiedCount * NewCertList->SignatureSize);\r
2485 CertList = (EFI_SIGNATURE_LIST *) (Tail - SignatureListSize);\r
2486 CertList->SignatureListSize = (UINT32) SignatureListSize;\r
2487 }\r
2488\r
2489 *NewDataSize -= NewCertList->SignatureListSize;\r
2490 NewCertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) NewCertList + NewCertList->SignatureListSize);\r
2491 }\r
2492\r
2493 TempDataSize = (Tail - (UINT8 *) TempData);\r
2494\r
2495 CopyMem (NewData, TempData, TempDataSize);\r
2496 *NewDataSize = TempDataSize;\r
2497\r
2498 return EFI_SUCCESS;\r
2499}\r
2500\r
2501/**\r
2502 Compare two EFI_TIME data.\r
2503\r
2504\r
2505 @param FirstTime A pointer to the first EFI_TIME data.\r
2506 @param SecondTime A pointer to the second EFI_TIME data.\r
2507\r
2508 @retval TRUE The FirstTime is not later than the SecondTime.\r
2509 @retval FALSE The FirstTime is later than the SecondTime.\r
2510\r
2511**/\r
2512BOOLEAN\r
2513AuthServiceInternalCompareTimeStamp (\r
2514 IN EFI_TIME *FirstTime,\r
2515 IN EFI_TIME *SecondTime\r
2516 )\r
2517{\r
2518 if (FirstTime->Year != SecondTime->Year) {\r
2519 return (BOOLEAN) (FirstTime->Year < SecondTime->Year);\r
2520 } else if (FirstTime->Month != SecondTime->Month) {\r
2521 return (BOOLEAN) (FirstTime->Month < SecondTime->Month);\r
2522 } else if (FirstTime->Day != SecondTime->Day) {\r
2523 return (BOOLEAN) (FirstTime->Day < SecondTime->Day);\r
2524 } else if (FirstTime->Hour != SecondTime->Hour) {\r
2525 return (BOOLEAN) (FirstTime->Hour < SecondTime->Hour);\r
2526 } else if (FirstTime->Minute != SecondTime->Minute) {\r
2527 return (BOOLEAN) (FirstTime->Minute < SecondTime->Minute);\r
2528 }\r
2529\r
2530 return (BOOLEAN) (FirstTime->Second <= SecondTime->Second);\r
2531}\r
2532\r
2533/**\r
2534 Find matching signer's certificates for common authenticated variable\r
2535 by corresponding VariableName and VendorGuid from "certdb" or "certdbv".\r
2536\r
2537 The data format of "certdb" or "certdbv":\r
2538 //\r
2539 // UINT32 CertDbListSize;\r
2540 // /// AUTH_CERT_DB_DATA Certs1[];\r
2541 // /// AUTH_CERT_DB_DATA Certs2[];\r
2542 // /// ...\r
2543 // /// AUTH_CERT_DB_DATA Certsn[];\r
2544 //\r
2545\r
2546 @param[in] VariableName Name of authenticated Variable.\r
2547 @param[in] VendorGuid Vendor GUID of authenticated Variable.\r
2548 @param[in] Data Pointer to variable "certdb" or "certdbv".\r
2549 @param[in] DataSize Size of variable "certdb" or "certdbv".\r
2550 @param[out] CertOffset Offset of matching CertData, from starting of Data.\r
2551 @param[out] CertDataSize Length of CertData in bytes.\r
2552 @param[out] CertNodeOffset Offset of matching AUTH_CERT_DB_DATA , from\r
2553 starting of Data.\r
2554 @param[out] CertNodeSize Length of AUTH_CERT_DB_DATA in bytes.\r
2555\r
2556 @retval EFI_INVALID_PARAMETER Any input parameter is invalid.\r
2557 @retval EFI_NOT_FOUND Fail to find matching certs.\r
2558 @retval EFI_SUCCESS Find matching certs and output parameters.\r
2559\r
2560**/\r
2561EFI_STATUS\r
2562FindCertsFromDb (\r
2563 IN CHAR16 *VariableName,\r
2564 IN EFI_GUID *VendorGuid,\r
2565 IN UINT8 *Data,\r
2566 IN UINTN DataSize,\r
2567 OUT UINT32 *CertOffset, OPTIONAL\r
2568 OUT UINT32 *CertDataSize, OPTIONAL\r
2569 OUT UINT32 *CertNodeOffset,OPTIONAL\r
2570 OUT UINT32 *CertNodeSize OPTIONAL\r
2571 )\r
2572{\r
2573 UINT32 Offset;\r
2574 AUTH_CERT_DB_DATA *Ptr;\r
2575 UINT32 CertSize;\r
2576 UINT32 NameSize;\r
2577 UINT32 NodeSize;\r
2578 UINT32 CertDbListSize;\r
2579\r
2580 if ((VariableName == NULL) || (VendorGuid == NULL) || (Data == NULL)) {\r
2581 return EFI_INVALID_PARAMETER;\r
2582 }\r
2583\r
2584 //\r
2585 // Check whether DataSize matches recorded CertDbListSize.\r
2586 //\r
2587 if (DataSize < sizeof (UINT32)) {\r
2588 return EFI_INVALID_PARAMETER;\r
2589 }\r
2590\r
2591 CertDbListSize = ReadUnaligned32 ((UINT32 *) Data);\r
2592\r
2593 if (CertDbListSize != (UINT32) DataSize) {\r
2594 return EFI_INVALID_PARAMETER;\r
2595 }\r
2596\r
2597 Offset = sizeof (UINT32);\r
2598\r
2599 //\r
2600 // Get corresponding certificates by VendorGuid and VariableName.\r
2601 //\r
2602 while (Offset < (UINT32) DataSize) {\r
2603 Ptr = (AUTH_CERT_DB_DATA *) (Data + Offset);\r
2604 //\r
2605 // Check whether VendorGuid matches.\r
2606 //\r
2607 if (CompareGuid (&Ptr->VendorGuid, VendorGuid)) {\r
2608 NodeSize = ReadUnaligned32 (&Ptr->CertNodeSize);\r
2609 NameSize = ReadUnaligned32 (&Ptr->NameSize);\r
2610 CertSize = ReadUnaligned32 (&Ptr->CertDataSize);\r
2611\r
2612 if (NodeSize != sizeof (EFI_GUID) + sizeof (UINT32) * 3 + CertSize +\r
2613 sizeof (CHAR16) * NameSize) {\r
2614 return EFI_INVALID_PARAMETER;\r
2615 }\r
2616\r
2617 Offset = Offset + sizeof (EFI_GUID) + sizeof (UINT32) * 3;\r
2618 //\r
2619 // Check whether VariableName matches.\r
2620 //\r
2621 if ((NameSize == StrLen (VariableName)) &&\r
2622 (CompareMem (Data + Offset, VariableName, NameSize * sizeof (CHAR16)) == 0)) {\r
2623 Offset = Offset + NameSize * sizeof (CHAR16);\r
2624\r
2625 if (CertOffset != NULL) {\r
2626 *CertOffset = Offset;\r
2627 }\r
2628\r
2629 if (CertDataSize != NULL) {\r
2630 *CertDataSize = CertSize;\r
2631 }\r
2632\r
2633 if (CertNodeOffset != NULL) {\r
2634 *CertNodeOffset = (UINT32) ((UINT8 *) Ptr - Data);\r
2635 }\r
2636\r
2637 if (CertNodeSize != NULL) {\r
2638 *CertNodeSize = NodeSize;\r
2639 }\r
2640\r
2641 return EFI_SUCCESS;\r
2642 } else {\r
2643 Offset = Offset + NameSize * sizeof (CHAR16) + CertSize;\r
2644 }\r
2645 } else {\r
2646 NodeSize = ReadUnaligned32 (&Ptr->CertNodeSize);\r
2647 Offset = Offset + NodeSize;\r
2648 }\r
2649 }\r
2650\r
2651 return EFI_NOT_FOUND;\r
2652}\r
2653\r
2654/**\r
2655 Retrieve signer's certificates for common authenticated variable\r
2656 by corresponding VariableName and VendorGuid from "certdb"\r
2657 or "certdbv" according to authenticated variable attributes.\r
2658\r
2659 @param[in] VariableName Name of authenticated Variable.\r
2660 @param[in] VendorGuid Vendor GUID of authenticated Variable.\r
2661 @param[in] Attributes Attributes of authenticated variable.\r
2662 @param[out] CertData Pointer to signer's certificates.\r
2663 @param[out] CertDataSize Length of CertData in bytes.\r
2664\r
2665 @retval EFI_INVALID_PARAMETER Any input parameter is invalid.\r
2666 @retval EFI_NOT_FOUND Fail to find "certdb"/"certdbv" or matching certs.\r
2667 @retval EFI_SUCCESS Get signer's certificates successfully.\r
2668\r
2669**/\r
2670EFI_STATUS\r
2671GetCertsFromDb (\r
2672 IN CHAR16 *VariableName,\r
2673 IN EFI_GUID *VendorGuid,\r
2674 IN UINT32 Attributes,\r
2675 OUT UINT8 **CertData,\r
2676 OUT UINT32 *CertDataSize\r
2677 )\r
2678{\r
2679 EFI_STATUS Status;\r
2680 UINT8 *Data;\r
2681 UINTN DataSize;\r
2682 UINT32 CertOffset;\r
2683 CHAR16 *DbName;\r
2684\r
2685 if ((VariableName == NULL) || (VendorGuid == NULL) || (CertData == NULL) || (CertDataSize == NULL)) {\r
2686 return EFI_INVALID_PARAMETER;\r
2687 }\r
2688\r
2689 \r
2690 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {\r
2691 //\r
2692 // Get variable "certdb".\r
2693 //\r
2694 DbName = EFI_CERT_DB_NAME;\r
2695 } else {\r
2696 //\r
2697 // Get variable "certdbv".\r
2698 //\r
2699 DbName = EFI_CERT_DB_VOLATILE_NAME;\r
2700 }\r
2701\r
2702 //\r
2703 // Get variable "certdb" or "certdbv".\r
2704 //\r
2705 Status = AuthServiceInternalFindVariable (\r
2706 DbName,\r
2707 &gEfiCertDbGuid,\r
2708 (VOID **) &Data,\r
2709 &DataSize\r
2710 );\r
2711 if (EFI_ERROR (Status)) {\r
2712 return Status;\r
2713 }\r
2714\r
2715 if ((DataSize == 0) || (Data == NULL)) {\r
2716 ASSERT (FALSE);\r
2717 return EFI_NOT_FOUND;\r
2718 }\r
2719\r
2720 Status = FindCertsFromDb (\r
2721 VariableName,\r
2722 VendorGuid,\r
2723 Data,\r
2724 DataSize,\r
2725 &CertOffset,\r
2726 CertDataSize,\r
2727 NULL,\r
2728 NULL\r
2729 );\r
2730\r
2731 if (EFI_ERROR (Status)) {\r
2732 return Status;\r
2733 }\r
2734\r
2735 *CertData = Data + CertOffset;\r
2736 return EFI_SUCCESS;\r
2737}\r
2738\r
2739/**\r
2740 Delete matching signer's certificates when deleting common authenticated\r
2741 variable by corresponding VariableName and VendorGuid from "certdb" or \r
2742 "certdbv" according to authenticated variable attributes.\r
2743\r
2744 @param[in] VariableName Name of authenticated Variable.\r
2745 @param[in] VendorGuid Vendor GUID of authenticated Variable.\r
2746 @param[in] Attributes Attributes of authenticated variable.\r
2747\r
2748 @retval EFI_INVALID_PARAMETER Any input parameter is invalid.\r
2749 @retval EFI_NOT_FOUND Fail to find "certdb"/"certdbv" or matching certs.\r
2750 @retval EFI_OUT_OF_RESOURCES The operation is failed due to lack of resources.\r
2751 @retval EFI_SUCCESS The operation is completed successfully.\r
2752\r
2753**/\r
2754EFI_STATUS\r
2755DeleteCertsFromDb (\r
2756 IN CHAR16 *VariableName,\r
2757 IN EFI_GUID *VendorGuid,\r
2758 IN UINT32 Attributes\r
2759 )\r
2760{\r
2761 EFI_STATUS Status;\r
2762 UINT8 *Data;\r
2763 UINTN DataSize;\r
2764 UINT32 VarAttr;\r
2765 UINT32 CertNodeOffset;\r
2766 UINT32 CertNodeSize;\r
2767 UINT8 *NewCertDb;\r
2768 UINT32 NewCertDbSize;\r
2769 CHAR16 *DbName;\r
2770\r
2771 if ((VariableName == NULL) || (VendorGuid == NULL)) {\r
2772 return EFI_INVALID_PARAMETER;\r
2773 }\r
2774\r
2775 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {\r
2776 //\r
2777 // Get variable "certdb".\r
2778 //\r
2779 DbName = EFI_CERT_DB_NAME;\r
2780 VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;\r
2781 } else {\r
2782 //\r
2783 // Get variable "certdbv".\r
2784 //\r
2785 DbName = EFI_CERT_DB_VOLATILE_NAME;\r
2786 VarAttr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;\r
2787 }\r
2788\r
2789 Status = AuthServiceInternalFindVariable (\r
2790 DbName,\r
2791 &gEfiCertDbGuid,\r
2792 (VOID **) &Data,\r
2793 &DataSize\r
2794 );\r
2795\r
2796 if (EFI_ERROR (Status)) {\r
2797 return Status;\r
2798 }\r
2799\r
2800 if ((DataSize == 0) || (Data == NULL)) {\r
2801 ASSERT (FALSE);\r
2802 return EFI_NOT_FOUND;\r
2803 }\r
2804\r
2805 if (DataSize == sizeof (UINT32)) {\r
2806 //\r
2807 // There is no certs in "certdb" or "certdbv".\r
2808 //\r
2809 return EFI_SUCCESS;\r
2810 }\r
2811\r
2812 //\r
2813 // Get corresponding cert node from "certdb" or "certdbv".\r
2814 //\r
2815 Status = FindCertsFromDb (\r
2816 VariableName,\r
2817 VendorGuid,\r
2818 Data,\r
2819 DataSize,\r
2820 NULL,\r
2821 NULL,\r
2822 &CertNodeOffset,\r
2823 &CertNodeSize\r
2824 );\r
2825\r
2826 if (EFI_ERROR (Status)) {\r
2827 return Status;\r
2828 }\r
2829\r
2830 if (DataSize < (CertNodeOffset + CertNodeSize)) {\r
2831 return EFI_NOT_FOUND;\r
2832 }\r
2833\r
2834 //\r
2835 // Construct new data content of variable "certdb" or "certdbv".\r
2836 //\r
2837 NewCertDbSize = (UINT32) DataSize - CertNodeSize;\r
2838 NewCertDb = (UINT8*) mCertDbStore;\r
2839\r
2840 //\r
2841 // Copy the DB entries before deleting node.\r
2842 //\r
2843 CopyMem (NewCertDb, Data, CertNodeOffset);\r
2844 //\r
2845 // Update CertDbListSize.\r
2846 //\r
2847 CopyMem (NewCertDb, &NewCertDbSize, sizeof (UINT32));\r
2848 //\r
2849 // Copy the DB entries after deleting node.\r
2850 //\r
2851 if (DataSize > (CertNodeOffset + CertNodeSize)) {\r
2852 CopyMem (\r
2853 NewCertDb + CertNodeOffset,\r
2854 Data + CertNodeOffset + CertNodeSize,\r
2855 DataSize - CertNodeOffset - CertNodeSize\r
2856 );\r
2857 }\r
2858\r
2859 //\r
2860 // Set "certdb" or "certdbv".\r
2861 //\r
2862 Status = AuthServiceInternalUpdateVariable (\r
2863 DbName,\r
2864 &gEfiCertDbGuid,\r
2865 NewCertDb,\r
2866 NewCertDbSize,\r
2867 VarAttr\r
2868 );\r
2869\r
2870 return Status;\r
2871}\r
2872\r
2873/**\r
2874 Insert signer's certificates for common authenticated variable with VariableName\r
2875 and VendorGuid in AUTH_CERT_DB_DATA to "certdb" or "certdbv" according to\r
2876 time based authenticated variable attributes.\r
2877\r
2878 @param[in] VariableName Name of authenticated Variable.\r
2879 @param[in] VendorGuid Vendor GUID of authenticated Variable.\r
2880 @param[in] Attributes Attributes of authenticated variable.\r
2881 @param[in] CertData Pointer to signer's certificates.\r
2882 @param[in] CertDataSize Length of CertData in bytes.\r
2883\r
2884 @retval EFI_INVALID_PARAMETER Any input parameter is invalid.\r
2885 @retval EFI_ACCESS_DENIED An AUTH_CERT_DB_DATA entry with same VariableName\r
2886 and VendorGuid already exists.\r
2887 @retval EFI_OUT_OF_RESOURCES The operation is failed due to lack of resources.\r
2888 @retval EFI_SUCCESS Insert an AUTH_CERT_DB_DATA entry to "certdb" or "certdbv"\r
2889\r
2890**/\r
2891EFI_STATUS\r
2892InsertCertsToDb (\r
2893 IN CHAR16 *VariableName,\r
2894 IN EFI_GUID *VendorGuid,\r
2895 IN UINT32 Attributes,\r
2896 IN UINT8 *CertData,\r
2897 IN UINTN CertDataSize\r
2898 )\r
2899{\r
2900 EFI_STATUS Status;\r
2901 UINT8 *Data;\r
2902 UINTN DataSize;\r
2903 UINT32 VarAttr;\r
2904 UINT8 *NewCertDb;\r
2905 UINT32 NewCertDbSize;\r
2906 UINT32 CertNodeSize;\r
2907 UINT32 NameSize;\r
2908 AUTH_CERT_DB_DATA *Ptr;\r
2909 CHAR16 *DbName;\r
2910\r
2911 if ((VariableName == NULL) || (VendorGuid == NULL) || (CertData == NULL)) {\r
2912 return EFI_INVALID_PARAMETER;\r
2913 }\r
2914\r
2915 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {\r
2916 //\r
2917 // Get variable "certdb".\r
2918 //\r
2919 DbName = EFI_CERT_DB_NAME;\r
2920 VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;\r
2921 } else {\r
2922 //\r
2923 // Get variable "certdbv".\r
2924 //\r
2925 DbName = EFI_CERT_DB_VOLATILE_NAME;\r
2926 VarAttr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;\r
2927 }\r
2928\r
2929 //\r
2930 // Get variable "certdb" or "certdbv".\r
2931 //\r
2932 Status = AuthServiceInternalFindVariable (\r
2933 DbName,\r
2934 &gEfiCertDbGuid,\r
2935 (VOID **) &Data,\r
2936 &DataSize\r
2937 );\r
2938 if (EFI_ERROR (Status)) {\r
2939 return Status;\r
2940 }\r
2941\r
2942 if ((DataSize == 0) || (Data == NULL)) {\r
2943 ASSERT (FALSE);\r
2944 return EFI_NOT_FOUND;\r
2945 }\r
2946\r
2947 //\r
2948 // Find whether matching cert node already exists in "certdb" or "certdbv".\r
2949 // If yes return error.\r
2950 //\r
2951 Status = FindCertsFromDb (\r
2952 VariableName,\r
2953 VendorGuid,\r
2954 Data,\r
2955 DataSize,\r
2956 NULL,\r
2957 NULL,\r
2958 NULL,\r
2959 NULL\r
2960 );\r
2961\r
2962 if (!EFI_ERROR (Status)) {\r
2963 ASSERT (FALSE);\r
2964 return EFI_ACCESS_DENIED;\r
2965 }\r
2966\r
2967 //\r
2968 // Construct new data content of variable "certdb" or "certdbv".\r
2969 //\r
2970 NameSize = (UINT32) StrLen (VariableName);\r
2971 CertNodeSize = sizeof (AUTH_CERT_DB_DATA) + (UINT32) CertDataSize + NameSize * sizeof (CHAR16);\r
2972 NewCertDbSize = (UINT32) DataSize + CertNodeSize;\r
2973 if (NewCertDbSize > mMaxCertDbSize) {\r
2974 return EFI_OUT_OF_RESOURCES;\r
2975 }\r
2976 NewCertDb = (UINT8*) mCertDbStore;\r
2977\r
2978 //\r
2979 // Copy the DB entries before inserting node.\r
2980 //\r
2981 CopyMem (NewCertDb, Data, DataSize);\r
2982 //\r
2983 // Update CertDbListSize.\r
2984 //\r
2985 CopyMem (NewCertDb, &NewCertDbSize, sizeof (UINT32));\r
2986 //\r
2987 // Construct new cert node.\r
2988 //\r
2989 Ptr = (AUTH_CERT_DB_DATA *) (NewCertDb + DataSize);\r
2990 CopyGuid (&Ptr->VendorGuid, VendorGuid);\r
2991 CopyMem (&Ptr->CertNodeSize, &CertNodeSize, sizeof (UINT32));\r
2992 CopyMem (&Ptr->NameSize, &NameSize, sizeof (UINT32));\r
2993 CopyMem (&Ptr->CertDataSize, &CertDataSize, sizeof (UINT32));\r
2994\r
2995 CopyMem (\r
2996 (UINT8 *) Ptr + sizeof (AUTH_CERT_DB_DATA),\r
2997 VariableName,\r
2998 NameSize * sizeof (CHAR16)\r
2999 );\r
3000\r
3001 CopyMem (\r
3002 (UINT8 *) Ptr + sizeof (AUTH_CERT_DB_DATA) + NameSize * sizeof (CHAR16),\r
3003 CertData,\r
3004 CertDataSize\r
3005 );\r
3006\r
3007 //\r
3008 // Set "certdb" or "certdbv".\r
3009 //\r
3010 Status = AuthServiceInternalUpdateVariable (\r
3011 DbName,\r
3012 &gEfiCertDbGuid,\r
3013 NewCertDb,\r
3014 NewCertDbSize,\r
3015 VarAttr\r
3016 );\r
3017\r
3018 return Status;\r
3019}\r
3020\r
3021/**\r
3022 Clean up signer's certificates for common authenticated variable\r
3023 by corresponding VariableName and VendorGuid from "certdb".\r
3024 System may break down during Timebased Variable update & certdb update,\r
3025 make them inconsistent, this function is called in AuthVariable Init\r
3026 to ensure consistency.\r
3027\r
3028 @retval EFI_NOT_FOUND Fail to find variable "certdb".\r
3029 @retval EFI_OUT_OF_RESOURCES The operation is failed due to lack of resources.\r
3030 @retval EFI_SUCCESS The operation is completed successfully.\r
3031\r
3032**/\r
3033EFI_STATUS\r
3034CleanCertsFromDb (\r
3035 VOID\r
3036 )\r
3037{\r
3038 UINT32 Offset;\r
3039 AUTH_CERT_DB_DATA *Ptr;\r
3040 UINT32 NameSize;\r
3041 UINT32 NodeSize;\r
3042 CHAR16 *VariableName;\r
3043 EFI_STATUS Status;\r
3044 BOOLEAN CertCleaned;\r
3045 UINT8 *Data;\r
3046 UINTN DataSize;\r
3047 EFI_GUID AuthVarGuid;\r
3048 AUTH_VARIABLE_INFO AuthVariableInfo;\r
3049\r
3050 Status = EFI_SUCCESS;\r
3051\r
3052 //\r
3053 // Get corresponding certificates by VendorGuid and VariableName.\r
3054 //\r
3055 do {\r
3056 CertCleaned = FALSE;\r
3057\r
3058 //\r
3059 // Get latest variable "certdb"\r
3060 //\r
3061 Status = AuthServiceInternalFindVariable (\r
3062 EFI_CERT_DB_NAME,\r
3063 &gEfiCertDbGuid,\r
3064 (VOID **) &Data,\r
3065 &DataSize\r
3066 );\r
3067 if (EFI_ERROR (Status)) {\r
3068 return Status;\r
3069 }\r
3070\r
3071 if ((DataSize == 0) || (Data == NULL)) {\r
3072 ASSERT (FALSE);\r
3073 return EFI_NOT_FOUND;\r
3074 }\r
3075\r
3076 Offset = sizeof (UINT32);\r
3077\r
3078 while (Offset < (UINT32) DataSize) {\r
3079 Ptr = (AUTH_CERT_DB_DATA *) (Data + Offset);\r
3080 NodeSize = ReadUnaligned32 (&Ptr->CertNodeSize);\r
3081 NameSize = ReadUnaligned32 (&Ptr->NameSize);\r
3082\r
3083 //\r
3084 // Get VarName tailed with '\0'\r
3085 //\r
3086 VariableName = AllocateZeroPool((NameSize + 1) * sizeof(CHAR16));\r
3087 if (VariableName == NULL) {\r
3088 return EFI_OUT_OF_RESOURCES;\r
3089 }\r
3090 CopyMem (VariableName, (UINT8 *) Ptr + sizeof (AUTH_CERT_DB_DATA), NameSize * sizeof(CHAR16));\r
3091 //\r
3092 // Keep VarGuid aligned\r
3093 //\r
3094 CopyMem (&AuthVarGuid, &Ptr->VendorGuid, sizeof(EFI_GUID));\r
3095\r
3096 //\r
3097 // Find corresponding time auth variable\r
3098 //\r
3099 ZeroMem (&AuthVariableInfo, sizeof (AuthVariableInfo));\r
3100 Status = mAuthVarLibContextIn->FindVariable (\r
3101 VariableName,\r
3102 &AuthVarGuid,\r
3103 &AuthVariableInfo\r
3104 );\r
3105\r
3106 if (EFI_ERROR(Status)) {\r
3107 Status = DeleteCertsFromDb(\r
3108 VariableName,\r
3109 &AuthVarGuid,\r
3110 AuthVariableInfo.Attributes\r
3111 );\r
3112 CertCleaned = TRUE;\r
3113 DEBUG((EFI_D_INFO, "Recovery!! Cert for Auth Variable %s Guid %g is removed for consistency\n", VariableName, &AuthVarGuid));\r
3114 FreePool(VariableName);\r
3115 break;\r
3116 }\r
3117\r
3118 FreePool(VariableName);\r
3119 Offset = Offset + NodeSize;\r
3120 }\r
3121 } while (CertCleaned);\r
3122\r
3123 return Status;\r
3124}\r
3125\r
3126/**\r
3127 Process variable with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set\r
3128\r
3129 Caution: This function may receive untrusted input.\r
3130 This function may be invoked in SMM mode, and datasize and data are external input.\r
3131 This function will do basic validation, before parse the data.\r
3132 This function will parse the authentication carefully to avoid security issues, like\r
3133 buffer overflow, integer overflow.\r
3134\r
3135 @param[in] VariableName Name of Variable to be found.\r
3136 @param[in] VendorGuid Variable vendor GUID.\r
3137 @param[in] Data Data pointer.\r
3138 @param[in] DataSize Size of Data found. If size is less than the\r
3139 data, this value contains the required size.\r
3140 @param[in] Attributes Attribute value of the variable.\r
3141 @param[in] AuthVarType Verify against PK, KEK database, private database or certificate in data payload.\r
3142 @param[in] OrgTimeStamp Pointer to original time stamp,\r
3143 original variable is not found if NULL.\r
3144 @param[out] VarPayloadPtr Pointer to variable payload address.\r
3145 @param[out] VarPayloadSize Pointer to variable payload size.\r
3146\r
3147 @retval EFI_INVALID_PARAMETER Invalid parameter.\r
3148 @retval EFI_SECURITY_VIOLATION The variable does NOT pass the validation\r
3149 check carried out by the firmware.\r
3150 @retval EFI_OUT_OF_RESOURCES Failed to process variable due to lack\r
3151 of resources.\r
3152 @retval EFI_SUCCESS Variable pass validation successfully.\r
3153\r
3154**/\r
3155EFI_STATUS\r
3156VerifyTimeBasedPayload (\r
3157 IN CHAR16 *VariableName,\r
3158 IN EFI_GUID *VendorGuid,\r
3159 IN VOID *Data,\r
3160 IN UINTN DataSize,\r
3161 IN UINT32 Attributes,\r
3162 IN AUTHVAR_TYPE AuthVarType,\r
3163 IN EFI_TIME *OrgTimeStamp,\r
3164 OUT UINT8 **VarPayloadPtr,\r
3165 OUT UINTN *VarPayloadSize\r
3166 )\r
3167{\r
3168 EFI_VARIABLE_AUTHENTICATION_2 *CertData;\r
3169 UINT8 *SigData;\r
3170 UINT32 SigDataSize;\r
3171 UINT8 *PayloadPtr;\r
3172 UINTN PayloadSize;\r
3173 UINT32 Attr;\r
3174 BOOLEAN VerifyStatus;\r
3175 EFI_STATUS Status;\r
3176 EFI_SIGNATURE_LIST *CertList;\r
3177 EFI_SIGNATURE_DATA *Cert;\r
3178 UINTN Index;\r
3179 UINTN CertCount;\r
3180 UINT32 KekDataSize;\r
3181 UINT8 *NewData;\r
3182 UINTN NewDataSize;\r
3183 UINT8 *Buffer;\r
3184 UINTN Length;\r
3185 UINT8 *RootCert;\r
3186 UINTN RootCertSize;\r
3187 UINT8 *SignerCerts;\r
3188 UINTN CertStackSize;\r
3189 UINT8 *CertsInCertDb;\r
3190 UINT32 CertsSizeinDb;\r
3191\r
3192 VerifyStatus = FALSE;\r
3193 CertData = NULL;\r
3194 NewData = NULL;\r
3195 Attr = Attributes;\r
3196 SignerCerts = NULL;\r
3197 RootCert = NULL;\r
3198 CertsInCertDb = NULL;\r
3199\r
3200 //\r
3201 // When the attribute EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS is\r
3202 // set, then the Data buffer shall begin with an instance of a complete (and serialized)\r
3203 // EFI_VARIABLE_AUTHENTICATION_2 descriptor. The descriptor shall be followed by the new\r
3204 // variable value and DataSize shall reflect the combined size of the descriptor and the new\r
3205 // variable value. The authentication descriptor is not part of the variable data and is not\r
3206 // returned by subsequent calls to GetVariable().\r
3207 //\r
3208 CertData = (EFI_VARIABLE_AUTHENTICATION_2 *) Data;\r
3209\r
3210 //\r
3211 // Verify that Pad1, Nanosecond, TimeZone, Daylight and Pad2 components of the\r
3212 // TimeStamp value are set to zero.\r
3213 //\r
3214 if ((CertData->TimeStamp.Pad1 != 0) ||\r
3215 (CertData->TimeStamp.Nanosecond != 0) ||\r
3216 (CertData->TimeStamp.TimeZone != 0) ||\r
3217 (CertData->TimeStamp.Daylight != 0) ||\r
3218 (CertData->TimeStamp.Pad2 != 0)) {\r
3219 return EFI_SECURITY_VIOLATION;\r
3220 }\r
3221\r
3222 if ((OrgTimeStamp != NULL) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0)) {\r
3223 if (AuthServiceInternalCompareTimeStamp (&CertData->TimeStamp, OrgTimeStamp)) {\r
3224 //\r
3225 // TimeStamp check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.\r
3226 //\r
3227 return EFI_SECURITY_VIOLATION;\r
3228 }\r
3229 }\r
3230\r
3231 //\r
3232 // wCertificateType should be WIN_CERT_TYPE_EFI_GUID.\r
3233 // Cert type should be EFI_CERT_TYPE_PKCS7_GUID.\r
3234 //\r
3235 if ((CertData->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID) ||\r
3236 !CompareGuid (&CertData->AuthInfo.CertType, &gEfiCertPkcs7Guid)) {\r
3237 //\r
3238 // Invalid AuthInfo type, return EFI_SECURITY_VIOLATION.\r
3239 //\r
3240 return EFI_SECURITY_VIOLATION;\r
3241 }\r
3242\r
3243 //\r
3244 // Find out Pkcs7 SignedData which follows the EFI_VARIABLE_AUTHENTICATION_2 descriptor.\r
3245 // AuthInfo.Hdr.dwLength is the length of the entire certificate, including the length of the header.\r
3246 //\r
3247 SigData = CertData->AuthInfo.CertData;\r
3248 SigDataSize = CertData->AuthInfo.Hdr.dwLength - (UINT32) (OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData));\r
3249\r
3250 //\r
3251 // Find out the new data payload which follows Pkcs7 SignedData directly.\r
3252 //\r
3253 PayloadPtr = SigData + SigDataSize;\r
3254 PayloadSize = DataSize - OFFSET_OF_AUTHINFO2_CERT_DATA - (UINTN) SigDataSize;\r
3255\r
3256 //\r
3257 // Construct a serialization buffer of the values of the VariableName, VendorGuid and Attributes\r
3258 // parameters of the SetVariable() call and the TimeStamp component of the\r
3259 // EFI_VARIABLE_AUTHENTICATION_2 descriptor followed by the variable's new value\r
3260 // i.e. (VariableName, VendorGuid, Attributes, TimeStamp, Data)\r
3261 //\r
3262 NewDataSize = PayloadSize + sizeof (EFI_TIME) + sizeof (UINT32) +\r
3263 sizeof (EFI_GUID) + StrSize (VariableName) - sizeof (CHAR16);\r
3264\r
3265 //\r
3266 // Here is to reuse scratch data area(at the end of volatile variable store)\r
3267 // to reduce SMRAM consumption for SMM variable driver.\r
3268 // The scratch buffer is enough to hold the serialized data and safe to use,\r
3269 // because it is only used at here to do verification temporarily first\r
3270 // and then used in UpdateVariable() for a time based auth variable set.\r
3271 //\r
3272 Status = mAuthVarLibContextIn->GetScratchBuffer (&NewDataSize, (VOID **) &NewData);\r
3273 if (EFI_ERROR (Status)) {\r
3274 return EFI_OUT_OF_RESOURCES;\r
3275 }\r
3276\r
3277 Buffer = NewData;\r
3278 Length = StrLen (VariableName) * sizeof (CHAR16);\r
3279 CopyMem (Buffer, VariableName, Length);\r
3280 Buffer += Length;\r
3281\r
3282 Length = sizeof (EFI_GUID);\r
3283 CopyMem (Buffer, VendorGuid, Length);\r
3284 Buffer += Length;\r
3285\r
3286 Length = sizeof (UINT32);\r
3287 CopyMem (Buffer, &Attr, Length);\r
3288 Buffer += Length;\r
3289\r
3290 Length = sizeof (EFI_TIME);\r
3291 CopyMem (Buffer, &CertData->TimeStamp, Length);\r
3292 Buffer += Length;\r
3293\r
3294 CopyMem (Buffer, PayloadPtr, PayloadSize);\r
3295\r
3296 if (AuthVarType == AuthVarTypePk) {\r
3297 //\r
3298 // Verify that the signature has been made with the current Platform Key (no chaining for PK).\r
3299 // First, get signer's certificates from SignedData.\r
3300 //\r
3301 VerifyStatus = Pkcs7GetSigners (\r
3302 SigData,\r
3303 SigDataSize,\r
3304 &SignerCerts,\r
3305 &CertStackSize,\r
3306 &RootCert,\r
3307 &RootCertSize\r
3308 );\r
3309 if (!VerifyStatus) {\r
3310 goto Exit;\r
3311 }\r
3312\r
3313 //\r
3314 // Second, get the current platform key from variable. Check whether it's identical with signer's certificates\r
3315 // in SignedData. If not, return error immediately.\r
3316 //\r
3317 Status = AuthServiceInternalFindVariable (\r
3318 EFI_PLATFORM_KEY_NAME,\r
3319 &gEfiGlobalVariableGuid,\r
3320 &Data,\r
3321 &DataSize\r
3322 );\r
3323 if (EFI_ERROR (Status)) {\r
3324 VerifyStatus = FALSE;\r
3325 goto Exit;\r
3326 }\r
3327 CertList = (EFI_SIGNATURE_LIST *) Data;\r
3328 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);\r
3329 if ((RootCertSize != (CertList->SignatureSize - (sizeof (EFI_SIGNATURE_DATA) - 1))) ||\r
3330 (CompareMem (Cert->SignatureData, RootCert, RootCertSize) != 0)) {\r
3331 VerifyStatus = FALSE;\r
3332 goto Exit;\r
3333 }\r
3334\r
3335 //\r
3336 // Verify Pkcs7 SignedData via Pkcs7Verify library.\r
3337 //\r
3338 VerifyStatus = Pkcs7Verify (\r
3339 SigData,\r
3340 SigDataSize,\r
3341 RootCert,\r
3342 RootCertSize,\r
3343 NewData,\r
3344 NewDataSize\r
3345 );\r
3346\r
3347 } else if (AuthVarType == AuthVarTypeKek) {\r
3348\r
3349 //\r
3350 // Get KEK database from variable.\r
3351 //\r
3352 Status = AuthServiceInternalFindVariable (\r
3353 EFI_KEY_EXCHANGE_KEY_NAME,\r
3354 &gEfiGlobalVariableGuid,\r
3355 &Data,\r
3356 &DataSize\r
3357 );\r
3358 if (EFI_ERROR (Status)) {\r
3359 return Status;\r
3360 }\r
3361\r
3362 //\r
3363 // Ready to verify Pkcs7 SignedData. Go through KEK Signature Database to find out X.509 CertList.\r
3364 //\r
3365 KekDataSize = (UINT32) DataSize;\r
3366 CertList = (EFI_SIGNATURE_LIST *) Data;\r
3367 while ((KekDataSize > 0) && (KekDataSize >= CertList->SignatureListSize)) {\r
3368 if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) {\r
3369 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);\r
3370 CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;\r
3371 for (Index = 0; Index < CertCount; Index++) {\r
3372 //\r
3373 // Iterate each Signature Data Node within this CertList for a verify\r
3374 //\r
3375 RootCert = Cert->SignatureData;\r
3376 RootCertSize = CertList->SignatureSize - (sizeof (EFI_SIGNATURE_DATA) - 1);\r
3377\r
3378 //\r
3379 // Verify Pkcs7 SignedData via Pkcs7Verify library.\r
3380 //\r
3381 VerifyStatus = Pkcs7Verify (\r
3382 SigData,\r
3383 SigDataSize,\r
3384 RootCert,\r
3385 RootCertSize,\r
3386 NewData,\r
3387 NewDataSize\r
3388 );\r
3389 if (VerifyStatus) {\r
3390 goto Exit;\r
3391 }\r
3392 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);\r
3393 }\r
3394 }\r
3395 KekDataSize -= CertList->SignatureListSize;\r
3396 CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);\r
3397 }\r
3398 } else if (AuthVarType == AuthVarTypePriv) {\r
3399\r
3400 //\r
3401 // Process common authenticated variable except PK/KEK/DB/DBX/DBT.\r
3402 // Get signer's certificates from SignedData.\r
3403 //\r
3404 VerifyStatus = Pkcs7GetSigners (\r
3405 SigData,\r
3406 SigDataSize,\r
3407 &SignerCerts,\r
3408 &CertStackSize,\r
3409 &RootCert,\r
3410 &RootCertSize\r
3411 );\r
3412 if (!VerifyStatus) {\r
3413 goto Exit;\r
3414 }\r
3415\r
3416 //\r
3417 // Get previously stored signer's certificates from certdb or certdbv for existing\r
3418 // variable. Check whether they are identical with signer's certificates\r
3419 // in SignedData. If not, return error immediately.\r
3420 //\r
3421 if (OrgTimeStamp != NULL) {\r
3422 VerifyStatus = FALSE;\r
3423\r
3424 Status = GetCertsFromDb (VariableName, VendorGuid, Attributes, &CertsInCertDb, &CertsSizeinDb);\r
3425 if (EFI_ERROR (Status)) {\r
3426 goto Exit;\r
3427 }\r
3428\r
3429 if ((CertStackSize != CertsSizeinDb) ||\r
3430 (CompareMem (SignerCerts, CertsInCertDb, CertsSizeinDb) != 0)) {\r
3431 goto Exit;\r
3432 }\r
3433 }\r
3434\r
3435 VerifyStatus = Pkcs7Verify (\r
3436 SigData,\r
3437 SigDataSize,\r
3438 RootCert,\r
3439 RootCertSize,\r
3440 NewData,\r
3441 NewDataSize\r
3442 );\r
3443 if (!VerifyStatus) {\r
3444 goto Exit;\r
3445 }\r
3446\r
3447 if ((OrgTimeStamp == NULL) && (PayloadSize != 0)) {\r
3448 //\r
3449 // Insert signer's certificates when adding a new common authenticated variable.\r
3450 //\r
3451 Status = InsertCertsToDb (VariableName, VendorGuid, Attributes, SignerCerts, CertStackSize);\r
3452 if (EFI_ERROR (Status)) {\r
3453 VerifyStatus = FALSE;\r
3454 goto Exit;\r
3455 }\r
3456 }\r
3457 } else if (AuthVarType == AuthVarTypePayload) {\r
3458 CertList = (EFI_SIGNATURE_LIST *) PayloadPtr;\r
3459 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);\r
3460 RootCert = Cert->SignatureData;\r
3461 RootCertSize = CertList->SignatureSize - (sizeof (EFI_SIGNATURE_DATA) - 1);\r
3462 //\r
3463 // Verify Pkcs7 SignedData via Pkcs7Verify library.\r
3464 //\r
3465 VerifyStatus = Pkcs7Verify (\r
3466 SigData,\r
3467 SigDataSize,\r
3468 RootCert,\r
3469 RootCertSize,\r
3470 NewData,\r
3471 NewDataSize\r
3472 );\r
3473 } else {\r
3474 return EFI_SECURITY_VIOLATION;\r
3475 }\r
3476\r
3477Exit:\r
3478\r
3479 if (AuthVarType == AuthVarTypePk || AuthVarType == AuthVarTypePriv) {\r
3480 Pkcs7FreeSigners (RootCert);\r
3481 Pkcs7FreeSigners (SignerCerts);\r
3482 }\r
3483\r
3484 if (!VerifyStatus) {\r
3485 return EFI_SECURITY_VIOLATION;\r
3486 }\r
3487\r
3488 Status = CheckSignatureListFormat(VariableName, VendorGuid, PayloadPtr, PayloadSize);\r
3489 if (EFI_ERROR (Status)) {\r
3490 return Status;\r
3491 }\r
3492\r
3493 *VarPayloadPtr = PayloadPtr;\r
3494 *VarPayloadSize = PayloadSize;\r
3495\r
3496 return EFI_SUCCESS;\r
3497}\r
3498\r
3499/**\r
3500 Process variable with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set\r
3501\r
3502 Caution: This function may receive untrusted input.\r
3503 This function may be invoked in SMM mode, and datasize and data are external input.\r
3504 This function will do basic validation, before parse the data.\r
3505 This function will parse the authentication carefully to avoid security issues, like\r
3506 buffer overflow, integer overflow.\r
3507\r
3508 @param[in] VariableName Name of Variable to be found.\r
3509 @param[in] VendorGuid Variable vendor GUID.\r
3510 @param[in] Data Data pointer.\r
3511 @param[in] DataSize Size of Data found. If size is less than the\r
3512 data, this value contains the required size.\r
3513 @param[in] Attributes Attribute value of the variable.\r
3514 @param[in] AuthVarType Verify against PK, KEK database, private database or certificate in data payload.\r
3515 @param[out] VarDel Delete the variable or not.\r
3516\r
3517 @retval EFI_INVALID_PARAMETER Invalid parameter.\r
3518 @retval EFI_SECURITY_VIOLATION The variable does NOT pass the validation\r
3519 check carried out by the firmware.\r
3520 @retval EFI_OUT_OF_RESOURCES Failed to process variable due to lack\r
3521 of resources.\r
3522 @retval EFI_SUCCESS Variable pass validation successfully.\r
3523\r
3524**/\r
3525EFI_STATUS\r
3526VerifyTimeBasedPayloadAndUpdate (\r
3527 IN CHAR16 *VariableName,\r
3528 IN EFI_GUID *VendorGuid,\r
3529 IN VOID *Data,\r
3530 IN UINTN DataSize,\r
3531 IN UINT32 Attributes,\r
3532 IN AUTHVAR_TYPE AuthVarType,\r
3533 OUT BOOLEAN *VarDel\r
3534 )\r
3535{\r
3536 EFI_STATUS Status;\r
3537 EFI_STATUS FindStatus;\r
3538 UINT8 *PayloadPtr;\r
3539 UINTN PayloadSize;\r
3540 EFI_VARIABLE_AUTHENTICATION_2 *CertData;\r
3541 AUTH_VARIABLE_INFO OrgVariableInfo;\r
3542 BOOLEAN IsDel;\r
3543\r
3544 ZeroMem (&OrgVariableInfo, sizeof (OrgVariableInfo));\r
3545 FindStatus = mAuthVarLibContextIn->FindVariable (\r
3546 VariableName,\r
3547 VendorGuid,\r
3548 &OrgVariableInfo\r
3549 );\r
3550\r
3551 Status = VerifyTimeBasedPayload (\r
3552 VariableName,\r
3553 VendorGuid,\r
3554 Data,\r
3555 DataSize,\r
3556 Attributes,\r
3557 AuthVarType,\r
3558 (!EFI_ERROR (FindStatus)) ? OrgVariableInfo.TimeStamp : NULL,\r
3559 &PayloadPtr,\r
3560 &PayloadSize\r
3561 );\r
3562 if (EFI_ERROR (Status)) {\r
3563 return Status;\r
3564 }\r
3565\r
3566 if (!EFI_ERROR(FindStatus)\r
3567 && (PayloadSize == 0)\r
3568 && ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0)) {\r
3569 IsDel = TRUE;\r
3570 } else {\r
3571 IsDel = FALSE;\r
3572 }\r
3573\r
3574 CertData = (EFI_VARIABLE_AUTHENTICATION_2 *) Data;\r
3575\r
3576 //\r
3577 // Final step: Update/Append Variable if it pass Pkcs7Verify\r
3578 //\r
3579 Status = AuthServiceInternalUpdateVariableWithTimeStamp (\r
3580 VariableName,\r
3581 VendorGuid,\r
3582 PayloadPtr,\r
3583 PayloadSize,\r
3584 Attributes,\r
3585 &CertData->TimeStamp\r
3586 );\r
3587\r
3588 //\r
3589 // Delete signer's certificates when delete the common authenticated variable.\r
3590 //\r
3591 if (IsDel && AuthVarType == AuthVarTypePriv && !EFI_ERROR(Status) ) {\r
3592 Status = DeleteCertsFromDb (VariableName, VendorGuid, Attributes);\r
3593 }\r
3594\r
3595 if (VarDel != NULL) {\r
3596 if (IsDel && !EFI_ERROR(Status)) {\r
3597 *VarDel = TRUE;\r
3598 } else {\r
3599 *VarDel = FALSE;\r
3600 }\r
3601 }\r
3602\r
3603 return Status;\r
3604}\r