]> git.proxmox.com Git - mirror_edk2.git/blame - SecurityPkg/VariableAuthenticated/RuntimeDxe/AuthService.c
Add security package to repository.
[mirror_edk2.git] / SecurityPkg / VariableAuthenticated / RuntimeDxe / AuthService.c
CommitLineData
0c18794e 1/** @file\r
2 Implement authentication services for the authenticated variable\r
3 service in UEFI2.2.\r
4\r
5Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
6This program and the accompanying materials \r
7are licensed and made available under the terms and conditions of the BSD License \r
8which accompanies this distribution. The full text of the license may be found at \r
9http://opensource.org/licenses/bsd-license.php\r
10\r
11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
12WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13\r
14**/\r
15\r
16#include "Variable.h"\r
17#include "AuthService.h"\r
18\r
19///\r
20/// Global database array for scratch\r
21/// \r
22UINT8 mPubKeyStore[MAX_KEYDB_SIZE];\r
23UINT32 mPubKeyNumber;\r
24UINT32 mPlatformMode;\r
25EFI_GUID mSignatureSupport[SIGSUPPORT_NUM] = {EFI_CERT_RSA2048_SHA256_GUID, EFI_CERT_RSA2048_SHA1_GUID};\r
26//\r
27// Public Exponent of RSA Key.\r
28//\r
29CONST UINT8 mRsaE[] = { 0x01, 0x00, 0x01 };\r
30//\r
31// Hash context pointer\r
32//\r
33VOID *mHashCtx = NULL;\r
34\r
35\r
36//\r
37// Pointer to runtime buffer. \r
38// For "Append" operation to an existing variable, a read/modify/write operation \r
39// is supported by firmware internally. Reserve runtime buffer to cache previous \r
40// variable data in runtime phase because memory allocation is forbidden in virtual mode.\r
41//\r
42VOID *mStorageArea = NULL;\r
43\r
44/**\r
45 Update platform mode.\r
46\r
47 @param[in] Mode SETUP_MODE or USER_MODE.\r
48\r
49 @return EFI_INVALID_PARAMETER Invalid parameter.\r
50 @return EFI_SUCCESS Update platform mode successfully.\r
51\r
52**/\r
53EFI_STATUS\r
54UpdatePlatformMode (\r
55 IN UINT32 Mode\r
56 );\r
57\r
58/**\r
59 Initializes for authenticated varibale service.\r
60\r
61 @retval EFI_SUCCESS Function successfully executed.\r
62 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resources.\r
63\r
64**/\r
65EFI_STATUS\r
66AutenticatedVariableServiceInitialize (\r
67 VOID\r
68 )\r
69{\r
70 EFI_STATUS Status;\r
71 VARIABLE_POINTER_TRACK Variable;\r
72 UINT8 VarValue;\r
73 UINT32 VarAttr;\r
74 UINT8 *Data;\r
75 UINTN DataSize;\r
76 UINTN CtxSize;\r
77 //\r
78 // Initialize hash context.\r
79 //\r
80 CtxSize = Sha256GetContextSize ();\r
81 mHashCtx = AllocateRuntimePool (CtxSize);\r
82 if (mHashCtx == NULL) {\r
83 return EFI_OUT_OF_RESOURCES;\r
84 }\r
85\r
86 //\r
87 // Reserved runtime buffer for "Append" operation in virtual mode.\r
88 //\r
89 mStorageArea = AllocateRuntimePool (PcdGet32 (PcdMaxAppendVariableSize));\r
90 if (mStorageArea == NULL) {\r
91 return EFI_OUT_OF_RESOURCES;\r
92 }\r
93\r
94 //\r
95 // Check "AuthVarKeyDatabase" variable's existence. \r
96 // If it doesn't exist, create a new one with initial value of 0 and EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set. \r
97 //\r
98 Status = FindVariable (\r
99 AUTHVAR_KEYDB_NAME, \r
100 &gEfiAuthenticatedVariableGuid, \r
101 &Variable, \r
102 &mVariableModuleGlobal->VariableGlobal\r
103 );\r
104\r
105 if (Variable.CurrPtr == NULL) {\r
106 VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;\r
107 VarValue = 0;\r
108 mPubKeyNumber = 0;\r
109 Status = UpdateVariable (\r
110 AUTHVAR_KEYDB_NAME,\r
111 &gEfiAuthenticatedVariableGuid,\r
112 &VarValue,\r
113 sizeof(UINT8),\r
114 VarAttr,\r
115 0,\r
116 0,\r
117 &Variable,\r
118 NULL\r
119 );\r
120 if (EFI_ERROR (Status)) {\r
121 return Status;\r
122 }\r
123 } else {\r
124 //\r
125 // Load database in global variable for cache.\r
126 //\r
127 DataSize = DataSizeOfVariable (Variable.CurrPtr);\r
128 Data = GetVariableDataPtr (Variable.CurrPtr);\r
129 ASSERT ((DataSize != 0) && (Data != NULL));\r
130 CopyMem (mPubKeyStore, (UINT8 *) Data, DataSize);\r
131 mPubKeyNumber = (UINT32) (DataSize / EFI_CERT_TYPE_RSA2048_SIZE);\r
132 }\r
133 //\r
134 // Check "SetupMode" variable's existence. \r
135 // If it doesn't exist, check PK database's existence to determine the value.\r
136 // Then create a new one with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set. \r
137 //\r
138 Status = FindVariable (\r
139 EFI_SETUP_MODE_NAME, \r
140 &gEfiGlobalVariableGuid, \r
141 &Variable, \r
142 &mVariableModuleGlobal->VariableGlobal\r
143 );\r
144\r
145 if (Variable.CurrPtr == NULL) {\r
146 Status = FindVariable (\r
147 EFI_PLATFORM_KEY_NAME, \r
148 &gEfiGlobalVariableGuid, \r
149 &Variable, \r
150 &mVariableModuleGlobal->VariableGlobal\r
151 );\r
152 if (Variable.CurrPtr == NULL) {\r
153 mPlatformMode = SETUP_MODE;\r
154 } else {\r
155 mPlatformMode = USER_MODE;\r
156 }\r
157\r
158 VarAttr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;\r
159 Status = UpdateVariable (\r
160 EFI_SETUP_MODE_NAME,\r
161 &gEfiGlobalVariableGuid,\r
162 &mPlatformMode,\r
163 sizeof(UINT8),\r
164 VarAttr,\r
165 0,\r
166 0,\r
167 &Variable,\r
168 NULL\r
169 );\r
170 if (EFI_ERROR (Status)) {\r
171 return Status;\r
172 }\r
173 } else {\r
174 mPlatformMode = *(GetVariableDataPtr (Variable.CurrPtr));\r
175 }\r
176 //\r
177 // Check "SignatureSupport" variable's existence. \r
178 // If it doesn't exist, then create a new one with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set. \r
179 //\r
180 Status = FindVariable (\r
181 EFI_SIGNATURE_SUPPORT_NAME, \r
182 &gEfiGlobalVariableGuid, \r
183 &Variable, \r
184 &mVariableModuleGlobal->VariableGlobal\r
185 );\r
186\r
187 if (Variable.CurrPtr == NULL) {\r
188 VarAttr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;\r
189 Status = UpdateVariable (\r
190 EFI_SIGNATURE_SUPPORT_NAME,\r
191 &gEfiGlobalVariableGuid,\r
192 mSignatureSupport,\r
193 SIGSUPPORT_NUM * sizeof(EFI_GUID),\r
194 VarAttr,\r
195 0,\r
196 0,\r
197 &Variable,\r
198 NULL\r
199 );\r
200 }\r
201 \r
202 //\r
203 // Detect whether a secure platform-specific method to clear PK(Platform Key)\r
204 // is configured by platform owner. This method is provided for users force to clear PK \r
205 // in case incorrect enrollment mis-haps.\r
206 //\r
207 if (ForceClearPK ()) {\r
208 //\r
209 // 1. Check whether PK is existing, and clear PK if existing\r
210 //\r
211 FindVariable (\r
212 EFI_PLATFORM_KEY_NAME, \r
213 &gEfiGlobalVariableGuid, \r
214 &Variable, \r
215 &mVariableModuleGlobal->VariableGlobal\r
216 );\r
217 if (Variable.CurrPtr != NULL) {\r
218 VarAttr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;\r
219 Status = UpdateVariable (\r
220 EFI_PLATFORM_KEY_NAME,\r
221 &gEfiGlobalVariableGuid,\r
222 NULL,\r
223 0,\r
224 VarAttr,\r
225 0,\r
226 0,\r
227 &Variable,\r
228 NULL\r
229 );\r
230 if (EFI_ERROR (Status)) {\r
231 return Status;\r
232 }\r
233 }\r
234\r
235 //\r
236 // 2. Update "SetupMode" variable to SETUP_MODE\r
237 //\r
238 UpdatePlatformMode (SETUP_MODE);\r
239 }\r
240 return Status;\r
241}\r
242\r
243/**\r
244 Add public key in store and return its index.\r
245\r
246 @param[in] PubKey Input pointer to Public Key data\r
247\r
248 @return Index of new added item\r
249\r
250**/\r
251UINT32\r
252AddPubKeyInStore (\r
253 IN UINT8 *PubKey\r
254 )\r
255{\r
256 EFI_STATUS Status;\r
257 BOOLEAN IsFound;\r
258 UINT32 Index;\r
259 VARIABLE_POINTER_TRACK Variable;\r
260 UINT8 *Ptr;\r
261\r
262 if (PubKey == NULL) {\r
263 return 0;\r
264 }\r
265\r
266 Status = FindVariable (\r
267 AUTHVAR_KEYDB_NAME,\r
268 &gEfiAuthenticatedVariableGuid,\r
269 &Variable,\r
270 &mVariableModuleGlobal->VariableGlobal\r
271 );\r
272 ASSERT_EFI_ERROR (Status);\r
273 //\r
274 // Check whether the public key entry does exist.\r
275 //\r
276 IsFound = FALSE;\r
277 for (Ptr = mPubKeyStore, Index = 1; Index <= mPubKeyNumber; Index++) {\r
278 if (CompareMem (Ptr, PubKey, EFI_CERT_TYPE_RSA2048_SIZE) == 0) {\r
279 IsFound = TRUE;\r
280 break;\r
281 }\r
282 Ptr += EFI_CERT_TYPE_RSA2048_SIZE;\r
283 }\r
284\r
285 if (!IsFound) {\r
286 //\r
287 // Add public key in database.\r
288 //\r
289 if (mPubKeyNumber == MAX_KEY_NUM) {\r
290 //\r
291 // Notes: Database is full, need enhancement here, currently just return 0.\r
292 //\r
293 return 0;\r
294 }\r
295\r
296 CopyMem (mPubKeyStore + mPubKeyNumber * EFI_CERT_TYPE_RSA2048_SIZE, PubKey, EFI_CERT_TYPE_RSA2048_SIZE);\r
297 Index = ++mPubKeyNumber;\r
298 //\r
299 // Update public key database variable.\r
300 //\r
301 Status = UpdateVariable (\r
302 AUTHVAR_KEYDB_NAME,\r
303 &gEfiAuthenticatedVariableGuid,\r
304 mPubKeyStore,\r
305 mPubKeyNumber * EFI_CERT_TYPE_RSA2048_SIZE,\r
306 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS,\r
307 0,\r
308 0,\r
309 &Variable,\r
310 NULL\r
311 );\r
312 ASSERT_EFI_ERROR (Status);\r
313 }\r
314\r
315 return Index;\r
316}\r
317\r
318/**\r
319 Verify data payload with AuthInfo in EFI_CERT_TYPE_RSA2048_SHA256 type.\r
320 Follow the steps in UEFI2.2.\r
321\r
322 @param[in] Data Pointer to data with AuthInfo.\r
323 @param[in] DataSize Size of Data.\r
324 @param[in] PubKey Public key used for verification.\r
325\r
326 @return EFI_INVALID_PARAMETER Invalid parameter.\r
327 @retval EFI_SECURITY_VIOLATION If authentication failed.\r
328 @return EFI_SUCCESS Authentication successful.\r
329\r
330**/\r
331EFI_STATUS\r
332VerifyCounterBasedPayload (\r
333 IN UINT8 *Data,\r
334 IN UINTN DataSize,\r
335 IN UINT8 *PubKey\r
336 )\r
337{\r
338 BOOLEAN Status;\r
339 EFI_VARIABLE_AUTHENTICATION *CertData;\r
340 EFI_CERT_BLOCK_RSA_2048_SHA256 *CertBlock;\r
341 UINT8 Digest[SHA256_DIGEST_SIZE];\r
342 VOID *Rsa;\r
343\r
344 Rsa = NULL;\r
345 CertData = NULL;\r
346 CertBlock = NULL;\r
347\r
348 if (Data == NULL || PubKey == NULL) {\r
349 return EFI_INVALID_PARAMETER;\r
350 }\r
351\r
352 CertData = (EFI_VARIABLE_AUTHENTICATION *) Data;\r
353 CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData);\r
354\r
355 //\r
356 // wCertificateType should be WIN_CERT_TYPE_EFI_GUID.\r
357 // Cert type should be EFI_CERT_TYPE_RSA2048_SHA256.\r
358 //\r
359 if ((CertData->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID) ||\r
360 !CompareGuid (&CertData->AuthInfo.CertType, &gEfiCertRsa2048Sha256Guid)\r
361 ) {\r
362 //\r
363 // Invalid AuthInfo type, return EFI_SECURITY_VIOLATION.\r
364 //\r
365 return EFI_SECURITY_VIOLATION;\r
366 }\r
367 //\r
368 // Hash data payload with SHA256.\r
369 //\r
370 ZeroMem (Digest, SHA256_DIGEST_SIZE);\r
371 Status = Sha256Init (mHashCtx);\r
372 if (!Status) {\r
373 goto Done;\r
374 }\r
375 Status = Sha256Update (mHashCtx, Data + AUTHINFO_SIZE, (UINTN) (DataSize - AUTHINFO_SIZE));\r
376 if (!Status) {\r
377 goto Done;\r
378 }\r
379 //\r
380 // Hash Monotonic Count.\r
381 //\r
382 Status = Sha256Update (mHashCtx, &CertData->MonotonicCount, sizeof (UINT64));\r
383 if (!Status) {\r
384 goto Done;\r
385 }\r
386 Status = Sha256Final (mHashCtx, Digest);\r
387 if (!Status) {\r
388 goto Done;\r
389 }\r
390 //\r
391 // Generate & Initialize RSA Context.\r
392 //\r
393 Rsa = RsaNew ();\r
394 ASSERT (Rsa != NULL);\r
395 // \r
396 // Set RSA Key Components.\r
397 // NOTE: Only N and E are needed to be set as RSA public key for signature verification.\r
398 //\r
399 Status = RsaSetKey (Rsa, RsaKeyN, PubKey, EFI_CERT_TYPE_RSA2048_SIZE);\r
400 if (!Status) {\r
401 goto Done;\r
402 }\r
403 Status = RsaSetKey (Rsa, RsaKeyE, mRsaE, sizeof (mRsaE));\r
404 if (!Status) {\r
405 goto Done;\r
406 }\r
407 //\r
408 // Verify the signature.\r
409 //\r
410 Status = RsaPkcs1Verify (\r
411 Rsa, \r
412 Digest, \r
413 SHA256_DIGEST_SIZE, \r
414 CertBlock->Signature, \r
415 EFI_CERT_TYPE_RSA2048_SHA256_SIZE\r
416 );\r
417\r
418Done:\r
419 if (Rsa != NULL) {\r
420 RsaFree (Rsa);\r
421 }\r
422 if (Status) {\r
423 return EFI_SUCCESS;\r
424 } else {\r
425 return EFI_SECURITY_VIOLATION;\r
426 }\r
427}\r
428\r
429\r
430/**\r
431 Update platform mode.\r
432\r
433 @param[in] Mode SETUP_MODE or USER_MODE.\r
434\r
435 @return EFI_INVALID_PARAMETER Invalid parameter.\r
436 @return EFI_SUCCESS Update platform mode successfully.\r
437\r
438**/\r
439EFI_STATUS\r
440UpdatePlatformMode (\r
441 IN UINT32 Mode\r
442 )\r
443{\r
444 EFI_STATUS Status;\r
445 VARIABLE_POINTER_TRACK Variable;\r
446 UINT32 VarAttr;\r
447 UINT8 SecureBootMode;\r
448\r
449 Status = FindVariable (\r
450 EFI_SETUP_MODE_NAME, \r
451 &gEfiGlobalVariableGuid, \r
452 &Variable, \r
453 &mVariableModuleGlobal->VariableGlobal\r
454 );\r
455 if (EFI_ERROR (Status)) {\r
456 return Status;\r
457 }\r
458\r
459 mPlatformMode = Mode;\r
460 VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;\r
461 Status = UpdateVariable (\r
462 EFI_SETUP_MODE_NAME,\r
463 &gEfiGlobalVariableGuid,\r
464 &mPlatformMode,\r
465 sizeof(UINT8),\r
466 VarAttr,\r
467 0,\r
468 0,\r
469 &Variable,\r
470 NULL\r
471 );\r
472 if (EFI_ERROR (Status)) {\r
473 return Status;\r
474 }\r
475\r
476 //\r
477 // Check "SecureBoot" variable's existence.\r
478 // If it doesn't exist, firmware has no capability to perform driver signing verification,\r
479 // then set "SecureBoot" to 0.\r
480 //\r
481 Status = FindVariable (\r
482 EFI_SECURE_BOOT_MODE_NAME, \r
483 &gEfiGlobalVariableGuid, \r
484 &Variable, \r
485 &mVariableModuleGlobal->VariableGlobal\r
486 );\r
487 //\r
488 // If "SecureBoot" variable exists, then check "SetupMode" variable update.\r
489 // If "SetupMode" variable is USER_MODE, "SecureBoot" variable is set to 1.\r
490 // If "SetupMode" variable is SETUP_MODE, "SecureBoot" variable is set to 0.\r
491 //\r
492 if (Variable.CurrPtr == NULL) {\r
493 SecureBootMode = SECURE_BOOT_MODE_DISABLE;\r
494 } else {\r
495 if (mPlatformMode == USER_MODE) {\r
496 SecureBootMode = SECURE_BOOT_MODE_ENABLE;\r
497 } else if (mPlatformMode == SETUP_MODE) {\r
498 SecureBootMode = SECURE_BOOT_MODE_DISABLE;\r
499 } else {\r
500 return EFI_NOT_FOUND;\r
501 }\r
502 }\r
503\r
504 VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;\r
505 return UpdateVariable (\r
506 EFI_SECURE_BOOT_MODE_NAME,\r
507 &gEfiGlobalVariableGuid,\r
508 &SecureBootMode,\r
509 sizeof(UINT8),\r
510 VarAttr,\r
511 0,\r
512 0,\r
513 &Variable,\r
514 NULL\r
515 );\r
516}\r
517\r
518/**\r
519 Process variable with platform key for verification.\r
520\r
521 @param[in] VariableName Name of Variable to be found.\r
522 @param[in] VendorGuid Variable vendor GUID.\r
523 @param[in] Data Data pointer.\r
524 @param[in] DataSize Size of Data found. If size is less than the\r
525 data, this value contains the required size.\r
526 @param[in] Variable The variable information which is used to keep track of variable usage.\r
527 @param[in] Attributes Attribute value of the variable\r
528 @param[in] IsPk Indicate whether it is to process pk.\r
529\r
530 @return EFI_INVALID_PARAMETER Invalid parameter.\r
531 @return EFI_SECURITY_VIOLATION The variable does NOT pass the validation. \r
532 check carried out by the firmware. \r
533 @return EFI_SUCCESS Variable passed validation successfully.\r
534\r
535**/\r
536EFI_STATUS\r
537ProcessVarWithPk (\r
538 IN CHAR16 *VariableName,\r
539 IN EFI_GUID *VendorGuid,\r
540 IN VOID *Data,\r
541 IN UINTN DataSize,\r
542 IN VARIABLE_POINTER_TRACK *Variable,\r
543 IN UINT32 Attributes OPTIONAL,\r
544 IN BOOLEAN IsPk\r
545 )\r
546{\r
547 EFI_STATUS Status;\r
548 VARIABLE_POINTER_TRACK PkVariable;\r
549 EFI_SIGNATURE_LIST *OldPkList;\r
550 EFI_SIGNATURE_DATA *OldPkData;\r
551 EFI_VARIABLE_AUTHENTICATION *CertData;\r
552 BOOLEAN TimeBase;\r
553 BOOLEAN Del;\r
554\r
555 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {\r
556 //\r
557 // PK and KEK should set EFI_VARIABLE_NON_VOLATILE attribute.\r
558 //\r
559 return EFI_INVALID_PARAMETER;\r
560 }\r
561\r
562 if (mPlatformMode == USER_MODE) {\r
563\r
564 if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
565 //\r
566 // EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute means time-based X509 Cert PK.\r
567 //\r
568 TimeBase = TRUE;\r
569 } else if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
570 //\r
571 // EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute means counter-based RSA-2048 Cert PK.\r
572 //\r
573 TimeBase = FALSE;\r
574 } else {\r
575 return EFI_INVALID_PARAMETER;\r
576 }\r
577\r
578 if (TimeBase) {\r
579 //\r
580 // Verify against X509 Cert PK.\r
581 //\r
582 Del = FALSE;\r
583 Status = VerifyTimeBasedPayload (VariableName, VendorGuid, Data, DataSize, Variable, Attributes, TRUE, &Del);\r
584 if (!EFI_ERROR (Status)) {\r
585 //\r
586 // If delete PK in user mode, need change to setup mode.\r
587 //\r
588 if (Del && IsPk) {\r
589 Status = UpdatePlatformMode (SETUP_MODE);\r
590 }\r
591 }\r
592 return Status;\r
593 } else {\r
594 //\r
595 // Verify against RSA2048 Cert PK.\r
596 //\r
597 CertData = (EFI_VARIABLE_AUTHENTICATION *) Data;\r
598 if ((Variable->CurrPtr != NULL) && (CertData->MonotonicCount <= Variable->CurrPtr->MonotonicCount)) {\r
599 //\r
600 // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.\r
601 //\r
602 return EFI_SECURITY_VIOLATION;\r
603 }\r
604 //\r
605 // Get platform key from variable.\r
606 //\r
607 Status = FindVariable (\r
608 EFI_PLATFORM_KEY_NAME, \r
609 &gEfiGlobalVariableGuid, \r
610 &PkVariable, \r
611 &mVariableModuleGlobal->VariableGlobal\r
612 );\r
613 ASSERT_EFI_ERROR (Status);\r
614 \r
615 OldPkList = (EFI_SIGNATURE_LIST *) GetVariableDataPtr (PkVariable.CurrPtr);\r
616 OldPkData = (EFI_SIGNATURE_DATA *) ((UINT8 *) OldPkList + sizeof (EFI_SIGNATURE_LIST) + OldPkList->SignatureHeaderSize);\r
617 Status = VerifyCounterBasedPayload (Data, DataSize, OldPkData->SignatureData);\r
618 if (!EFI_ERROR (Status)) {\r
619 Status = UpdateVariable (\r
620 VariableName, \r
621 VendorGuid, \r
622 (UINT8*)Data + AUTHINFO_SIZE, \r
623 DataSize - AUTHINFO_SIZE, \r
624 Attributes, \r
625 0, \r
626 CertData->MonotonicCount, \r
627 Variable,\r
628 NULL\r
629 );\r
630 \r
631 if (!EFI_ERROR (Status)) {\r
632 //\r
633 // If delete PK in user mode, need change to setup mode.\r
634 //\r
635 if ((DataSize == AUTHINFO_SIZE) && IsPk) {\r
636 Status = UpdatePlatformMode (SETUP_MODE);\r
637 }\r
638 }\r
639 }\r
640 }\r
641 } else {\r
642 Status = UpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes, 0, 0, Variable, NULL);\r
643 //\r
644 // If enroll PK in setup mode, need change to user mode.\r
645 //\r
646 if ((DataSize != 0) && IsPk) {\r
647 Status = UpdatePlatformMode (USER_MODE);\r
648 }\r
649 }\r
650\r
651 return Status;\r
652}\r
653\r
654/**\r
655 Process variable with key exchange key for verification.\r
656\r
657 @param[in] VariableName Name of Variable to be found.\r
658 @param[in] VendorGuid Variable vendor GUID.\r
659 @param[in] Data Data pointer.\r
660 @param[in] DataSize Size of Data found. If size is less than the\r
661 data, this value contains the required size.\r
662 @param[in] Variable The variable information which is used to keep track of variable usage.\r
663 @param[in] Attributes Attribute value of the variable.\r
664\r
665 @return EFI_INVALID_PARAMETER Invalid parameter.\r
666 @return EFI_SECURITY_VIOLATION The variable does NOT pass the validation \r
667 check carried out by the firmware. \r
668 @return EFI_SUCCESS Variable pass validation successfully.\r
669\r
670**/\r
671EFI_STATUS\r
672ProcessVarWithKek (\r
673 IN CHAR16 *VariableName,\r
674 IN EFI_GUID *VendorGuid,\r
675 IN VOID *Data,\r
676 IN UINTN DataSize,\r
677 IN VARIABLE_POINTER_TRACK *Variable,\r
678 IN UINT32 Attributes OPTIONAL\r
679 )\r
680{\r
681 EFI_STATUS Status;\r
682 VARIABLE_POINTER_TRACK KekVariable;\r
683 EFI_SIGNATURE_LIST *KekList;\r
684 EFI_SIGNATURE_DATA *KekItem;\r
685 UINT32 KekCount;\r
686 EFI_VARIABLE_AUTHENTICATION *CertData;\r
687 EFI_CERT_BLOCK_RSA_2048_SHA256 *CertBlock;\r
688 BOOLEAN IsFound;\r
689 UINT32 Index;\r
690 UINT32 KekDataSize;\r
691\r
692 if (mPlatformMode == USER_MODE) {\r
693 if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == 0) {\r
694 //\r
695 // In user mode, should set EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute.\r
696 //\r
697 return EFI_INVALID_PARAMETER;\r
698 }\r
699\r
700 CertData = (EFI_VARIABLE_AUTHENTICATION *) Data;\r
701 CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData);\r
702 if ((Variable->CurrPtr != NULL) && (CertData->MonotonicCount <= Variable->CurrPtr->MonotonicCount)) {\r
703 //\r
704 // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.\r
705 //\r
706 return EFI_SECURITY_VIOLATION;\r
707 }\r
708 //\r
709 // Get KEK database from variable.\r
710 //\r
711 Status = FindVariable (\r
712 EFI_KEY_EXCHANGE_KEY_NAME, \r
713 &gEfiGlobalVariableGuid, \r
714 &KekVariable, \r
715 &mVariableModuleGlobal->VariableGlobal\r
716 );\r
717 ASSERT_EFI_ERROR (Status);\r
718\r
719 KekDataSize = KekVariable.CurrPtr->DataSize;\r
720 KekList = (EFI_SIGNATURE_LIST *) GetVariableDataPtr (KekVariable.CurrPtr);\r
721\r
722 //\r
723 // Enumerate all Kek items in this list to verify the variable certificate data.\r
724 // If anyone is authenticated successfully, it means the variable is correct!\r
725 //\r
726 IsFound = FALSE;\r
727 while ((KekDataSize > 0) && (KekDataSize >= KekList->SignatureListSize)) {\r
728 if (CompareGuid (&KekList->SignatureType, &gEfiCertRsa2048Guid)) {\r
729 KekItem = (EFI_SIGNATURE_DATA *) ((UINT8 *) KekList + sizeof (EFI_SIGNATURE_LIST) + KekList->SignatureHeaderSize);\r
730 KekCount = (KekList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - KekList->SignatureHeaderSize) / KekList->SignatureSize;\r
731 for (Index = 0; Index < KekCount; Index++) {\r
732 if (CompareMem (KekItem->SignatureData, CertBlock->PublicKey, EFI_CERT_TYPE_RSA2048_SIZE) == 0) {\r
733 IsFound = TRUE;\r
734 break;\r
735 }\r
736 KekItem = (EFI_SIGNATURE_DATA *) ((UINT8 *) KekItem + KekList->SignatureSize);\r
737 }\r
738 }\r
739 KekDataSize -= KekList->SignatureListSize;\r
740 KekList = (EFI_SIGNATURE_LIST *) ((UINT8 *) KekList + KekList->SignatureListSize);\r
741 }\r
742 \r
743 if (!IsFound) {\r
744 return EFI_SECURITY_VIOLATION;\r
745 }\r
746\r
747 Status = VerifyCounterBasedPayload (Data, DataSize, CertBlock->PublicKey);\r
748 if (!EFI_ERROR (Status)) {\r
749 Status = UpdateVariable (\r
750 VariableName, \r
751 VendorGuid, \r
752 (UINT8*)Data + AUTHINFO_SIZE, \r
753 DataSize - AUTHINFO_SIZE, \r
754 Attributes, \r
755 0, \r
756 CertData->MonotonicCount, \r
757 Variable,\r
758 NULL\r
759 );\r
760 }\r
761 } else {\r
762 //\r
763 // If in setup mode, no authentication needed.\r
764 //\r
765 Status = UpdateVariable (\r
766 VariableName, \r
767 VendorGuid, \r
768 Data, \r
769 DataSize, \r
770 Attributes, \r
771 0, \r
772 0, \r
773 Variable,\r
774 NULL\r
775 );\r
776 }\r
777\r
778 return Status;\r
779}\r
780\r
781/**\r
782 Process variable with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS/EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set\r
783\r
784 @param[in] VariableName Name of Variable to be found.\r
785 @param[in] VendorGuid Variable vendor GUID.\r
786\r
787 @param[in] Data Data pointer.\r
788 @param[in] DataSize Size of Data found. If size is less than the\r
789 data, this value contains the required size.\r
790 @param[in] Variable The variable information which is used to keep track of variable usage.\r
791 @param[in] Attributes Attribute value of the variable.\r
792\r
793 @return EFI_INVALID_PARAMETER Invalid parameter.\r
794 @return EFI_WRITE_PROTECTED Variable is write-protected and needs authentication with\r
795 EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.\r
796 @return EFI_SECURITY_VIOLATION The variable is with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS\r
797 set, but the AuthInfo does NOT pass the validation \r
798 check carried out by the firmware. \r
799 @return EFI_SUCCESS Variable is not write-protected or pass validation successfully.\r
800\r
801**/\r
802EFI_STATUS\r
803ProcessVariable (\r
804 IN CHAR16 *VariableName,\r
805 IN EFI_GUID *VendorGuid,\r
806 IN VOID *Data,\r
807 IN UINTN DataSize,\r
808 IN VARIABLE_POINTER_TRACK *Variable,\r
809 IN UINT32 Attributes\r
810 )\r
811{\r
812 EFI_STATUS Status;\r
813 BOOLEAN IsDeletion;\r
814 BOOLEAN IsFirstTime;\r
815 UINT8 *PubKey;\r
816 EFI_VARIABLE_AUTHENTICATION *CertData;\r
817 EFI_CERT_BLOCK_RSA_2048_SHA256 *CertBlock;\r
818 UINT32 KeyIndex;\r
819 UINT64 MonotonicCount;\r
820\r
821 KeyIndex = 0; \r
822 CertData = NULL;\r
823 CertBlock = NULL;\r
824 PubKey = NULL;\r
825 IsDeletion = FALSE;\r
826\r
827 //\r
828 // Process Time-based Authenticated variable.\r
829 //\r
830 if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
831 return VerifyTimeBasedPayload (VariableName, VendorGuid, Data, DataSize, Variable, Attributes, FALSE, NULL);\r
832 }\r
833 \r
834 //\r
835 // Determine if first time SetVariable with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS.\r
836 //\r
837 if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
838 //\r
839 // Determine current operation type.\r
840 //\r
841 if (DataSize == AUTHINFO_SIZE) {\r
842 IsDeletion = TRUE;\r
843 }\r
844 //\r
845 // Determine whether this is the first time with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.\r
846 //\r
847 if (Variable->CurrPtr == NULL) {\r
848 IsFirstTime = TRUE;\r
849 } else if ((Variable->CurrPtr->Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == 0) {\r
850 IsFirstTime = TRUE;\r
851 } else {\r
852 KeyIndex = Variable->CurrPtr->PubKeyIndex;\r
853 IsFirstTime = FALSE;\r
854 }\r
855 } else if ((Variable->CurrPtr != NULL) &&\r
856 (Variable->CurrPtr->Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0\r
857 ) {\r
858 //\r
859 // If the variable is already write-protected, it always needs authentication before update.\r
860 //\r
861 return EFI_WRITE_PROTECTED;\r
862 } else {\r
863 //\r
864 // If without EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, set and attributes collision.\r
865 // That means it is not authenticated variable, just update variable as usual.\r
866 //\r
867 Status = UpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes, 0, 0, Variable, NULL);\r
868 return Status;\r
869 }\r
870\r
871 //\r
872 // Get PubKey and check Monotonic Count value corresponding to the variable.\r
873 //\r
874 CertData = (EFI_VARIABLE_AUTHENTICATION *) Data;\r
875 CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData);\r
876 PubKey = CertBlock->PublicKey;\r
877\r
878 //\r
879 // Update Monotonic Count value.\r
880 //\r
881 MonotonicCount = CertData->MonotonicCount;\r
882\r
883 if (!IsFirstTime) {\r
884 //\r
885 // Check input PubKey.\r
886 //\r
887 if (CompareMem (PubKey, mPubKeyStore + (KeyIndex - 1) * EFI_CERT_TYPE_RSA2048_SIZE, EFI_CERT_TYPE_RSA2048_SIZE) != 0) {\r
888 return EFI_SECURITY_VIOLATION;\r
889 }\r
890 //\r
891 // Compare the current monotonic count and ensure that it is greater than the last SetVariable\r
892 // operation with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute set.\r
893 //\r
894 if (CertData->MonotonicCount <= Variable->CurrPtr->MonotonicCount) {\r
895 //\r
896 // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.\r
897 //\r
898 return EFI_SECURITY_VIOLATION;\r
899 }\r
900 } \r
901 //\r
902 // Verify the certificate in Data payload.\r
903 //\r
904 Status = VerifyCounterBasedPayload (Data, DataSize, PubKey);\r
905 if (EFI_ERROR (Status)) {\r
906 return Status;\r
907 }\r
908 \r
909 //\r
910 // Now, the signature has been verified!\r
911 //\r
912 if (IsFirstTime && !IsDeletion) {\r
913 //\r
914 // Update public key database variable if need.\r
915 //\r
916 KeyIndex = AddPubKeyInStore (PubKey);\r
917 }\r
918\r
919 //\r
920 // Verification pass.\r
921 //\r
922 return UpdateVariable (VariableName, VendorGuid, (UINT8*)Data + AUTHINFO_SIZE, DataSize - AUTHINFO_SIZE, Attributes, KeyIndex, MonotonicCount, Variable, NULL);\r
923}\r
924\r
925/**\r
926 Compare two EFI_TIME data.\r
927\r
928\r
929 @param FirstTime A pointer to the first EFI_TIME data.\r
930 @param SecondTime A pointer to the second EFI_TIME data.\r
931\r
932 @retval TRUE The FirstTime is not later than the SecondTime.\r
933 @retval FALSE The FirstTime is later than the SecondTime.\r
934\r
935**/\r
936BOOLEAN\r
937CompareTimeStamp (\r
938 IN EFI_TIME *FirstTime,\r
939 IN EFI_TIME *SecondTime\r
940 )\r
941{\r
942 if (FirstTime->Year != SecondTime->Year) {\r
943 return (BOOLEAN) (FirstTime->Year < SecondTime->Year);\r
944 } else if (FirstTime->Month != SecondTime->Month) {\r
945 return (BOOLEAN) (FirstTime->Month < SecondTime->Month);\r
946 } else if (FirstTime->Day != SecondTime->Day) {\r
947 return (BOOLEAN) (FirstTime->Day < SecondTime->Day);\r
948 } else if (FirstTime->Hour != SecondTime->Hour) {\r
949 return (BOOLEAN) (FirstTime->Hour < SecondTime->Hour);\r
950 } else if (FirstTime->Minute != SecondTime->Minute) {\r
951 return (BOOLEAN) (FirstTime->Minute < FirstTime->Minute);\r
952 } \r
953\r
954 return (BOOLEAN) (FirstTime->Second <= SecondTime->Second);\r
955}\r
956\r
957/**\r
958 Process variable with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set\r
959\r
960 @param[in] VariableName Name of Variable to be found.\r
961 @param[in] VendorGuid Variable vendor GUID.\r
962 @param[in] Data Data pointer.\r
963 @param[in] DataSize Size of Data found. If size is less than the\r
964 data, this value contains the required size.\r
965 @param[in] Variable The variable information which is used to keep track of variable usage.\r
966 @param[in] Attributes Attribute value of the variable.\r
967 @param[in] Pk Verify against PK or KEK database.\r
968 @param[out] VarDel Delete the variable or not.\r
969\r
970 @retval EFI_INVALID_PARAMETER Invalid parameter.\r
971 @retval EFI_SECURITY_VIOLATION The variable does NOT pass the validation \r
972 check carried out by the firmware. \r
973 @retval EFI_OUT_OF_RESOURCES Failed to process variable due to lack\r
974 of resources.\r
975 @retval EFI_SUCCESS Variable pass validation successfully.\r
976\r
977**/\r
978EFI_STATUS\r
979VerifyTimeBasedPayload (\r
980 IN CHAR16 *VariableName,\r
981 IN EFI_GUID *VendorGuid,\r
982 IN VOID *Data,\r
983 IN UINTN DataSize,\r
984 IN VARIABLE_POINTER_TRACK *Variable,\r
985 IN UINT32 Attributes,\r
986 IN BOOLEAN Pk,\r
987 OUT BOOLEAN *VarDel\r
988 )\r
989{\r
990 UINT8 *RootCert;\r
991 UINT8 *SigData;\r
992 UINT8 *PayLoadPtr;\r
993 UINTN RootCertSize;\r
994 UINTN Index;\r
995 UINTN CertCount; \r
996 UINTN PayLoadSize; \r
997 UINT32 Attr;\r
998 UINT32 SigDataSize;\r
999 UINT32 KekDataSize;\r
1000 BOOLEAN Result;\r
1001 BOOLEAN VerifyStatus;\r
1002 EFI_STATUS Status;\r
1003 EFI_SIGNATURE_LIST *CertList;\r
1004 EFI_SIGNATURE_DATA *Cert;\r
1005 VARIABLE_POINTER_TRACK KekVariable;\r
1006 EFI_VARIABLE_AUTHENTICATION_2 *CertData;\r
1007 UINT8 *NewData;\r
1008 UINTN NewDataSize;\r
1009 VARIABLE_POINTER_TRACK PkVariable;\r
1010\r
1011\r
1012 Result = FALSE;\r
1013 VerifyStatus = FALSE;\r
1014 CertData = NULL;\r
1015 NewData = NULL;\r
1016 Attr = Attributes;\r
1017\r
1018 //\r
1019 // When the attribute EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS is \r
1020 // set, then the Data buffer shall begin with an instance of a complete (and serialized)\r
1021 // EFI_VARIABLE_AUTHENTICATION_2 descriptor. The descriptor shall be followed by the new \r
1022 // variable value and DataSize shall reflect the combined size of the descriptor and the new \r
1023 // variable value. The authentication descriptor is not part of the variable data and is not \r
1024 // returned by subsequent calls to GetVariable().\r
1025 //\r
1026 CertData = (EFI_VARIABLE_AUTHENTICATION_2 *) Data;\r
1027 \r
1028 if ((Variable->CurrPtr != NULL) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0)) {\r
1029 if (CompareTimeStamp (&CertData->TimeStamp, &Variable->CurrPtr->TimeStamp)) {\r
1030 //\r
1031 // TimeStamp check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.\r
1032 //\r
1033 return EFI_SECURITY_VIOLATION;\r
1034 }\r
1035 }\r
1036\r
1037 //\r
1038 // wCertificateType should be WIN_CERT_TYPE_EFI_GUID.\r
1039 // Cert type should be EFI_CERT_TYPE_PKCS7_GUID.\r
1040 //\r
1041 if ((CertData->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID) ||\r
1042 !CompareGuid (&CertData->AuthInfo.CertType, &gEfiCertPkcs7Guid)\r
1043 ) {\r
1044 //\r
1045 // Invalid AuthInfo type, return EFI_SECURITY_VIOLATION.\r
1046 //\r
1047 return EFI_SECURITY_VIOLATION;\r
1048 }\r
1049\r
1050 //\r
1051 // Find out Pkcs7 SignedData which follows the EFI_VARIABLE_AUTHENTICATION_2 descriptor.\r
1052 // AuthInfo.Hdr.dwLength is the length of the entire certificate, including the length of the header.\r
1053 //\r
1054 SigData = (UINT8*) ((UINTN)Data + (UINTN)(((EFI_VARIABLE_AUTHENTICATION_2 *) 0)->AuthInfo.CertData));\r
1055 SigDataSize = CertData->AuthInfo.Hdr.dwLength - (UINT32)(UINTN)(((WIN_CERTIFICATE_UEFI_GUID *) 0)->CertData);\r
1056 \r
1057 //\r
1058 // Find out the new data payload which follows Pkcs7 SignedData directly.\r
1059 //\r
1060 PayLoadPtr = (UINT8*) ((UINTN) SigData + (UINTN) SigDataSize);\r
1061 PayLoadSize = DataSize - (UINTN)(((EFI_VARIABLE_AUTHENTICATION_2 *) 0)->AuthInfo.CertData) - (UINTN) SigDataSize;\r
1062\r
1063\r
1064 //\r
1065 // Construct a buffer to fill with (VariableName, VendorGuid, Attributes, TimeStamp, Data).\r
1066 //\r
1067 NewDataSize = PayLoadSize + sizeof (EFI_TIME) + sizeof (UINT32) +\r
1068 sizeof (EFI_GUID) + StrSize (VariableName);\r
1069 NewData = (UINT8 *) AllocateZeroPool (NewDataSize);\r
1070\r
1071 if (NewData == NULL) {\r
1072 return EFI_OUT_OF_RESOURCES;\r
1073 }\r
1074\r
1075 CopyMem (NewData, VariableName, StrSize (VariableName));\r
1076\r
1077 CopyMem (NewData + StrSize (VariableName), VendorGuid, sizeof (EFI_GUID));\r
1078\r
1079 CopyMem (\r
1080 NewData + StrSize (VariableName) + sizeof (EFI_GUID),\r
1081 &Attr,\r
1082 sizeof (UINT32)\r
1083 );\r
1084\r
1085 CopyMem (\r
1086 NewData + StrSize (VariableName) + sizeof (EFI_GUID) + sizeof (UINT32),\r
1087 &CertData->TimeStamp,\r
1088 sizeof (EFI_TIME)\r
1089 );\r
1090\r
1091 CopyMem (NewData + (NewDataSize - PayLoadSize), PayLoadPtr, PayLoadSize);\r
1092\r
1093\r
1094 if (Pk) {\r
1095 //\r
1096 // Get platform key from variable.\r
1097 //\r
1098 Status = FindVariable (\r
1099 EFI_PLATFORM_KEY_NAME, \r
1100 &gEfiGlobalVariableGuid, \r
1101 &PkVariable, \r
1102 &mVariableModuleGlobal->VariableGlobal\r
1103 );\r
1104 if (EFI_ERROR (Status)) {\r
1105 return Status;\r
1106 }\r
1107\r
1108 CertList = (EFI_SIGNATURE_LIST *) GetVariableDataPtr (PkVariable.CurrPtr);\r
1109 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);\r
1110 RootCert = Cert->SignatureData;\r
1111 RootCertSize = CertList->SignatureSize;\r
1112\r
1113\r
1114 //\r
1115 // Verify Pkcs7 SignedData via Pkcs7Verify library.\r
1116 //\r
1117 VerifyStatus = Pkcs7Verify (\r
1118 SigData,\r
1119 SigDataSize,\r
1120 RootCert,\r
1121 RootCertSize,\r
1122 NewData,\r
1123 NewDataSize\r
1124 );\r
1125\r
1126 } else {\r
1127 \r
1128 //\r
1129 // Get KEK database from variable.\r
1130 //\r
1131 Status = FindVariable (\r
1132 EFI_KEY_EXCHANGE_KEY_NAME, \r
1133 &gEfiGlobalVariableGuid, \r
1134 &KekVariable, \r
1135 &mVariableModuleGlobal->VariableGlobal\r
1136 );\r
1137 if (EFI_ERROR (Status)) {\r
1138 return Status;\r
1139 }\r
1140\r
1141 //\r
1142 // Ready to verify Pkcs7 SignedData. Go through KEK Signature Database to find out X.509 CertList.\r
1143 // \r
1144 KekDataSize = KekVariable.CurrPtr->DataSize;\r
1145 CertList = (EFI_SIGNATURE_LIST *) GetVariableDataPtr (KekVariable.CurrPtr);\r
1146 while ((KekDataSize > 0) && (KekDataSize >= CertList->SignatureListSize)) {\r
1147 if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) {\r
1148 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);\r
1149 CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;\r
1150 for (Index = 0; Index < CertCount; Index++) {\r
1151 //\r
1152 // Iterate each Signature Data Node within this CertList for a verify\r
1153 //\r
1154 RootCert = Cert->SignatureData;\r
1155 RootCertSize = CertList->SignatureSize;\r
1156 \r
1157 //\r
1158 // Verify Pkcs7 SignedData via Pkcs7Verify library.\r
1159 //\r
1160 VerifyStatus = Pkcs7Verify (\r
1161 SigData,\r
1162 SigDataSize,\r
1163 RootCert,\r
1164 RootCertSize,\r
1165 NewData,\r
1166 NewDataSize\r
1167 );\r
1168 if (VerifyStatus) {\r
1169 goto Exit;\r
1170 }\r
1171 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);\r
1172 }\r
1173 }\r
1174 KekDataSize -= CertList->SignatureListSize;\r
1175 CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);\r
1176 }\r
1177 }\r
1178\r
1179Exit:\r
1180\r
1181 FreePool (NewData);\r
1182\r
1183 if (!VerifyStatus) {\r
1184 return EFI_SECURITY_VIOLATION;\r
1185 }\r
1186\r
1187 if ((PayLoadSize == 0) && (VarDel != NULL)) {\r
1188 *VarDel = TRUE;\r
1189 }\r
1190 \r
1191 //\r
1192 // Final step: Update/Append Variable if it pass Pkcs7Verify\r
1193 //\r
1194 return UpdateVariable (\r
1195 VariableName, \r
1196 VendorGuid, \r
1197 PayLoadPtr, \r
1198 PayLoadSize, \r
1199 Attributes, \r
1200 0, \r
1201 0, \r
1202 Variable,\r
1203 &CertData->TimeStamp\r
1204 );\r
1205}\r