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