]> git.proxmox.com Git - mirror_edk2.git/blame - SecurityPkg/VariableAuthenticated/RuntimeDxe/AuthService.c
Set the current view point to the breaking CPU if it meets breakpoint.
[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
2d3fb919 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
0c18794e 9http://opensource.org/licenses/bsd-license.php\r
10\r
2d3fb919 11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
0c18794e 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
2d3fb919 21///\r
0c18794e 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
0c18794e 35//\r
2d3fb919 36// Pointer to runtime buffer.\r
37// For "Append" operation to an existing variable, a read/modify/write operation\r
38// is supported by firmware internally. Reserve runtime buffer to cache previous\r
0c18794e 39// variable data in runtime phase because memory allocation is forbidden in virtual mode.\r
40//\r
41VOID *mStorageArea = NULL;\r
42\r
2d3fb919 43//\r
44// The serialization of the values of the VariableName, VendorGuid and Attributes\r
45// parameters of the SetVariable() call and the TimeStamp component of the\r
46// EFI_VARIABLE_AUTHENTICATION_2 descriptor followed by the variable's new value\r
47// i.e. (VariableName, VendorGuid, Attributes, TimeStamp, Data)\r
48//\r
49UINT8 *mSerializationRuntimeBuffer = NULL;\r
50\r
d912bad7 51//\r
52// Requirement for different signature type which have been defined in UEFI spec.\r
53// These data are used to peform SignatureList format check while setting PK/KEK variable.\r
54//\r
55EFI_SIGNATURE_ITEM mSupportSigItem[] = {\r
56//{SigType, SigHeaderSize, SigDataSize }\r
57 {EFI_CERT_SHA256_GUID, 0, 32 },\r
58 {EFI_CERT_RSA2048_GUID, 0, 256 },\r
59 {EFI_CERT_RSA2048_SHA256_GUID, 0, 256 },\r
60 {EFI_CERT_SHA1_GUID, 0, 20 },\r
61 {EFI_CERT_RSA2048_SHA1_GUID, 0, 256 },\r
62 {EFI_CERT_X509_GUID, 0, ((UINT32) ~0)},\r
63 {EFI_CERT_SHA224_GUID, 0, 28 },\r
64 {EFI_CERT_SHA384_GUID, 0, 48 },\r
65 {EFI_CERT_SHA512_GUID, 0, 64 }\r
66};\r
67\r
0c18794e 68/**\r
2d3fb919 69 Internal function to delete a Variable given its name and GUID, no authentication\r
70 required.\r
0c18794e 71\r
2d3fb919 72 @param[in] VariableName Name of the Variable.\r
73 @param[in] VendorGuid GUID of the Variable.\r
0c18794e 74\r
2d3fb919 75 @retval EFI_SUCCESS Variable deleted successfully.\r
76 @retval Others The driver failded to start the device.\r
0c18794e 77\r
78**/\r
79EFI_STATUS\r
2d3fb919 80DeleteVariable (\r
81 IN CHAR16 *VariableName,\r
82 IN EFI_GUID *VendorGuid\r
83 )\r
84{\r
85 EFI_STATUS Status;\r
86 VARIABLE_POINTER_TRACK Variable;\r
87\r
88 Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal);\r
89 if (EFI_ERROR (Status)) {\r
90 return EFI_SUCCESS;\r
91 }\r
92\r
93 ASSERT (Variable.CurrPtr != NULL);\r
94 return UpdateVariable (VariableName, VendorGuid, NULL, 0, 0, 0, 0, &Variable, NULL);\r
95}\r
0c18794e 96\r
97/**\r
98 Initializes for authenticated varibale service.\r
99\r
100 @retval EFI_SUCCESS Function successfully executed.\r
101 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resources.\r
102\r
103**/\r
104EFI_STATUS\r
105AutenticatedVariableServiceInitialize (\r
106 VOID\r
107 )\r
108{\r
109 EFI_STATUS Status;\r
110 VARIABLE_POINTER_TRACK Variable;\r
7aaf2fd6 111 VARIABLE_POINTER_TRACK PkVariable;\r
0c18794e 112 UINT8 VarValue;\r
113 UINT32 VarAttr;\r
114 UINT8 *Data;\r
115 UINTN DataSize;\r
116 UINTN CtxSize;\r
beda2356 117 UINT8 SecureBootMode;\r
118 UINT8 SecureBootEnable;\r
2d3fb919 119\r
0c18794e 120 //\r
121 // Initialize hash context.\r
122 //\r
123 CtxSize = Sha256GetContextSize ();\r
124 mHashCtx = AllocateRuntimePool (CtxSize);\r
125 if (mHashCtx == NULL) {\r
126 return EFI_OUT_OF_RESOURCES;\r
127 }\r
128\r
129 //\r
130 // Reserved runtime buffer for "Append" operation in virtual mode.\r
131 //\r
2d3fb919 132 mStorageArea = AllocateRuntimePool (PcdGet32 (PcdMaxVariableSize));\r
0c18794e 133 if (mStorageArea == NULL) {\r
134 return EFI_OUT_OF_RESOURCES;\r
135 }\r
136\r
137 //\r
2d3fb919 138 // Prepare runtime buffer for serialized data of time-based authenticated\r
139 // Variable, i.e. (VariableName, VendorGuid, Attributes, TimeStamp, Data).\r
140 //\r
141 mSerializationRuntimeBuffer = AllocateRuntimePool (PcdGet32 (PcdMaxVariableSize) + sizeof (EFI_GUID) + sizeof (UINT32) + sizeof (EFI_TIME));\r
142 if (mSerializationRuntimeBuffer == NULL) {\r
143 return EFI_OUT_OF_RESOURCES;\r
144 }\r
145\r
146 //\r
147 // Check "AuthVarKeyDatabase" variable's existence.\r
148 // If it doesn't exist, create a new one with initial value of 0 and EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.\r
0c18794e 149 //\r
150 Status = FindVariable (\r
2d3fb919 151 AUTHVAR_KEYDB_NAME,\r
152 &gEfiAuthenticatedVariableGuid,\r
153 &Variable,\r
0c18794e 154 &mVariableModuleGlobal->VariableGlobal\r
155 );\r
156\r
157 if (Variable.CurrPtr == NULL) {\r
158 VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;\r
159 VarValue = 0;\r
160 mPubKeyNumber = 0;\r
161 Status = UpdateVariable (\r
162 AUTHVAR_KEYDB_NAME,\r
163 &gEfiAuthenticatedVariableGuid,\r
164 &VarValue,\r
165 sizeof(UINT8),\r
166 VarAttr,\r
167 0,\r
168 0,\r
169 &Variable,\r
170 NULL\r
171 );\r
172 if (EFI_ERROR (Status)) {\r
173 return Status;\r
174 }\r
175 } else {\r
176 //\r
177 // Load database in global variable for cache.\r
178 //\r
179 DataSize = DataSizeOfVariable (Variable.CurrPtr);\r
180 Data = GetVariableDataPtr (Variable.CurrPtr);\r
181 ASSERT ((DataSize != 0) && (Data != NULL));\r
182 CopyMem (mPubKeyStore, (UINT8 *) Data, DataSize);\r
183 mPubKeyNumber = (UINT32) (DataSize / EFI_CERT_TYPE_RSA2048_SIZE);\r
184 }\r
7aaf2fd6 185\r
186 FindVariable (EFI_PLATFORM_KEY_NAME, &gEfiGlobalVariableGuid, &PkVariable, &mVariableModuleGlobal->VariableGlobal);\r
187 if (PkVariable.CurrPtr == NULL) {\r
188 DEBUG ((EFI_D_INFO, "Variable %s does not exist.\n", EFI_PLATFORM_KEY_NAME));\r
189 } else {\r
190 DEBUG ((EFI_D_INFO, "Variable %s exists.\n", EFI_PLATFORM_KEY_NAME));\r
191 }\r
192 \r
0c18794e 193 //\r
2d3fb919 194 // Check "SetupMode" variable's existence.\r
0c18794e 195 // If it doesn't exist, check PK database's existence to determine the value.\r
2d3fb919 196 // Then create a new one with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.\r
0c18794e 197 //\r
198 Status = FindVariable (\r
2d3fb919 199 EFI_SETUP_MODE_NAME,\r
200 &gEfiGlobalVariableGuid,\r
201 &Variable,\r
0c18794e 202 &mVariableModuleGlobal->VariableGlobal\r
203 );\r
204\r
205 if (Variable.CurrPtr == NULL) {\r
7aaf2fd6 206 if (PkVariable.CurrPtr == NULL) {\r
0c18794e 207 mPlatformMode = SETUP_MODE;\r
208 } else {\r
209 mPlatformMode = USER_MODE;\r
210 }\r
211\r
2d3fb919 212 VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;\r
0c18794e 213 Status = UpdateVariable (\r
214 EFI_SETUP_MODE_NAME,\r
215 &gEfiGlobalVariableGuid,\r
216 &mPlatformMode,\r
217 sizeof(UINT8),\r
218 VarAttr,\r
219 0,\r
220 0,\r
221 &Variable,\r
222 NULL\r
223 );\r
224 if (EFI_ERROR (Status)) {\r
225 return Status;\r
226 }\r
227 } else {\r
228 mPlatformMode = *(GetVariableDataPtr (Variable.CurrPtr));\r
229 }\r
230 //\r
2d3fb919 231 // Check "SignatureSupport" variable's existence.\r
232 // If it doesn't exist, then create a new one with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.\r
0c18794e 233 //\r
234 Status = FindVariable (\r
2d3fb919 235 EFI_SIGNATURE_SUPPORT_NAME,\r
236 &gEfiGlobalVariableGuid,\r
237 &Variable,\r
0c18794e 238 &mVariableModuleGlobal->VariableGlobal\r
239 );\r
240\r
241 if (Variable.CurrPtr == NULL) {\r
242 VarAttr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;\r
243 Status = UpdateVariable (\r
244 EFI_SIGNATURE_SUPPORT_NAME,\r
245 &gEfiGlobalVariableGuid,\r
246 mSignatureSupport,\r
247 SIGSUPPORT_NUM * sizeof(EFI_GUID),\r
248 VarAttr,\r
249 0,\r
250 0,\r
251 &Variable,\r
252 NULL\r
253 );\r
254 }\r
beda2356 255\r
256 //\r
257 // If "SecureBootEnable" variable exists, then update "SecureBoot" variable.\r
2d3fb919 258 // If "SecureBootEnable" variable is SECURE_BOOT_ENABLE and in USER_MODE, Set "SecureBoot" variable to SECURE_BOOT_MODE_ENABLE.\r
beda2356 259 // If "SecureBootEnable" variable is SECURE_BOOT_DISABLE, Set "SecureBoot" variable to SECURE_BOOT_MODE_DISABLE.\r
260 //\r
2d3fb919 261 SecureBootEnable = SECURE_BOOT_MODE_DISABLE;\r
beda2356 262 FindVariable (EFI_SECURE_BOOT_ENABLE_NAME, &gEfiSecureBootEnableDisableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal);\r
263 if (Variable.CurrPtr != NULL) {\r
264 SecureBootEnable = *(GetVariableDataPtr (Variable.CurrPtr));\r
2d3fb919 265 } else if (mPlatformMode == USER_MODE) {\r
266 //\r
267 // "SecureBootEnable" not exist, initialize it in USER_MODE.\r
268 //\r
269 SecureBootEnable = SECURE_BOOT_MODE_ENABLE;\r
beda2356 270 Status = UpdateVariable (\r
2d3fb919 271 EFI_SECURE_BOOT_ENABLE_NAME,\r
272 &gEfiSecureBootEnableDisableGuid,\r
273 &SecureBootEnable,\r
274 sizeof (UINT8),\r
275 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
276 0,\r
277 0,\r
beda2356 278 &Variable,\r
279 NULL\r
280 );\r
281 if (EFI_ERROR (Status)) {\r
282 return Status;\r
283 }\r
284 }\r
285\r
2d3fb919 286 if (SecureBootEnable == SECURE_BOOT_ENABLE && mPlatformMode == USER_MODE) {\r
287 SecureBootMode = SECURE_BOOT_MODE_ENABLE;\r
288 } else {\r
289 SecureBootMode = SECURE_BOOT_MODE_DISABLE;\r
290 }\r
291 FindVariable (EFI_SECURE_BOOT_MODE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal);\r
292 Status = UpdateVariable (\r
293 EFI_SECURE_BOOT_MODE_NAME,\r
294 &gEfiGlobalVariableGuid,\r
295 &SecureBootMode,\r
296 sizeof (UINT8),\r
297 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS,\r
298 0,\r
299 0,\r
300 &Variable,\r
301 NULL\r
302 );\r
303 if (EFI_ERROR (Status)) {\r
304 return Status;\r
305 }\r
306\r
7aaf2fd6 307 DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_SETUP_MODE_NAME, mPlatformMode));\r
308 DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_SECURE_BOOT_MODE_NAME, SecureBootMode));\r
309 DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_SECURE_BOOT_ENABLE_NAME, SecureBootEnable));\r
310\r
0c18794e 311 //\r
312 // Detect whether a secure platform-specific method to clear PK(Platform Key)\r
2d3fb919 313 // is configured by platform owner. This method is provided for users force to clear PK\r
0c18794e 314 // in case incorrect enrollment mis-haps.\r
315 //\r
316 if (ForceClearPK ()) {\r
7aaf2fd6 317 DEBUG ((EFI_D_INFO, "Variable PK/KEK/DB/DBX will be cleared in clear PK mode.\n"));\r
318\r
0c18794e 319 //\r
2d3fb919 320 // 1. Clear PK.\r
0c18794e 321 //\r
2d3fb919 322 Status = DeleteVariable (EFI_PLATFORM_KEY_NAME, &gEfiGlobalVariableGuid);\r
323 if (EFI_ERROR (Status)) {\r
324 return Status;\r
0c18794e 325 }\r
326\r
327 //\r
2d3fb919 328 // 2. Update "SetupMode" variable to SETUP_MODE.\r
0c18794e 329 //\r
330 UpdatePlatformMode (SETUP_MODE);\r
2d3fb919 331\r
332 //\r
333 // 3. Clear KEK, DB and DBX.\r
334 //\r
335 DeleteVariable (EFI_KEY_EXCHANGE_KEY_NAME, &gEfiGlobalVariableGuid);\r
336 DeleteVariable (EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid);\r
337 DeleteVariable (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid);\r
0c18794e 338 }\r
2d3fb919 339\r
0c18794e 340 return Status;\r
341}\r
342\r
343/**\r
344 Add public key in store and return its index.\r
345\r
346 @param[in] PubKey Input pointer to Public Key data\r
347\r
348 @return Index of new added item\r
349\r
350**/\r
351UINT32\r
352AddPubKeyInStore (\r
353 IN UINT8 *PubKey\r
354 )\r
355{\r
356 EFI_STATUS Status;\r
357 BOOLEAN IsFound;\r
358 UINT32 Index;\r
359 VARIABLE_POINTER_TRACK Variable;\r
360 UINT8 *Ptr;\r
361\r
362 if (PubKey == NULL) {\r
363 return 0;\r
364 }\r
365\r
366 Status = FindVariable (\r
367 AUTHVAR_KEYDB_NAME,\r
368 &gEfiAuthenticatedVariableGuid,\r
369 &Variable,\r
370 &mVariableModuleGlobal->VariableGlobal\r
371 );\r
372 ASSERT_EFI_ERROR (Status);\r
373 //\r
374 // Check whether the public key entry does exist.\r
375 //\r
376 IsFound = FALSE;\r
377 for (Ptr = mPubKeyStore, Index = 1; Index <= mPubKeyNumber; Index++) {\r
378 if (CompareMem (Ptr, PubKey, EFI_CERT_TYPE_RSA2048_SIZE) == 0) {\r
379 IsFound = TRUE;\r
380 break;\r
381 }\r
382 Ptr += EFI_CERT_TYPE_RSA2048_SIZE;\r
383 }\r
384\r
385 if (!IsFound) {\r
386 //\r
387 // Add public key in database.\r
388 //\r
389 if (mPubKeyNumber == MAX_KEY_NUM) {\r
390 //\r
391 // Notes: Database is full, need enhancement here, currently just return 0.\r
392 //\r
393 return 0;\r
394 }\r
395\r
396 CopyMem (mPubKeyStore + mPubKeyNumber * EFI_CERT_TYPE_RSA2048_SIZE, PubKey, EFI_CERT_TYPE_RSA2048_SIZE);\r
397 Index = ++mPubKeyNumber;\r
398 //\r
399 // Update public key database variable.\r
400 //\r
401 Status = UpdateVariable (\r
402 AUTHVAR_KEYDB_NAME,\r
403 &gEfiAuthenticatedVariableGuid,\r
404 mPubKeyStore,\r
405 mPubKeyNumber * EFI_CERT_TYPE_RSA2048_SIZE,\r
406 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS,\r
407 0,\r
408 0,\r
409 &Variable,\r
410 NULL\r
411 );\r
412 ASSERT_EFI_ERROR (Status);\r
413 }\r
414\r
415 return Index;\r
416}\r
417\r
418/**\r
419 Verify data payload with AuthInfo in EFI_CERT_TYPE_RSA2048_SHA256 type.\r
420 Follow the steps in UEFI2.2.\r
421\r
422 @param[in] Data Pointer to data with AuthInfo.\r
423 @param[in] DataSize Size of Data.\r
424 @param[in] PubKey Public key used for verification.\r
425\r
2d3fb919 426 @retval EFI_INVALID_PARAMETER Invalid parameter.\r
0c18794e 427 @retval EFI_SECURITY_VIOLATION If authentication failed.\r
2d3fb919 428 @retval EFI_SUCCESS Authentication successful.\r
0c18794e 429\r
430**/\r
431EFI_STATUS\r
432VerifyCounterBasedPayload (\r
433 IN UINT8 *Data,\r
434 IN UINTN DataSize,\r
435 IN UINT8 *PubKey\r
436 )\r
437{\r
438 BOOLEAN Status;\r
439 EFI_VARIABLE_AUTHENTICATION *CertData;\r
440 EFI_CERT_BLOCK_RSA_2048_SHA256 *CertBlock;\r
441 UINT8 Digest[SHA256_DIGEST_SIZE];\r
442 VOID *Rsa;\r
443\r
444 Rsa = NULL;\r
445 CertData = NULL;\r
446 CertBlock = NULL;\r
447\r
448 if (Data == NULL || PubKey == NULL) {\r
449 return EFI_INVALID_PARAMETER;\r
450 }\r
451\r
452 CertData = (EFI_VARIABLE_AUTHENTICATION *) Data;\r
453 CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData);\r
454\r
455 //\r
456 // wCertificateType should be WIN_CERT_TYPE_EFI_GUID.\r
457 // Cert type should be EFI_CERT_TYPE_RSA2048_SHA256.\r
458 //\r
459 if ((CertData->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID) ||\r
460 !CompareGuid (&CertData->AuthInfo.CertType, &gEfiCertRsa2048Sha256Guid)\r
461 ) {\r
462 //\r
463 // Invalid AuthInfo type, return EFI_SECURITY_VIOLATION.\r
464 //\r
465 return EFI_SECURITY_VIOLATION;\r
466 }\r
467 //\r
468 // Hash data payload with SHA256.\r
469 //\r
470 ZeroMem (Digest, SHA256_DIGEST_SIZE);\r
471 Status = Sha256Init (mHashCtx);\r
472 if (!Status) {\r
473 goto Done;\r
474 }\r
475 Status = Sha256Update (mHashCtx, Data + AUTHINFO_SIZE, (UINTN) (DataSize - AUTHINFO_SIZE));\r
476 if (!Status) {\r
477 goto Done;\r
478 }\r
479 //\r
480 // Hash Monotonic Count.\r
481 //\r
482 Status = Sha256Update (mHashCtx, &CertData->MonotonicCount, sizeof (UINT64));\r
483 if (!Status) {\r
484 goto Done;\r
485 }\r
486 Status = Sha256Final (mHashCtx, Digest);\r
487 if (!Status) {\r
488 goto Done;\r
489 }\r
490 //\r
491 // Generate & Initialize RSA Context.\r
492 //\r
493 Rsa = RsaNew ();\r
494 ASSERT (Rsa != NULL);\r
2d3fb919 495 //\r
0c18794e 496 // Set RSA Key Components.\r
497 // NOTE: Only N and E are needed to be set as RSA public key for signature verification.\r
498 //\r
499 Status = RsaSetKey (Rsa, RsaKeyN, PubKey, EFI_CERT_TYPE_RSA2048_SIZE);\r
500 if (!Status) {\r
501 goto Done;\r
502 }\r
503 Status = RsaSetKey (Rsa, RsaKeyE, mRsaE, sizeof (mRsaE));\r
504 if (!Status) {\r
505 goto Done;\r
506 }\r
507 //\r
508 // Verify the signature.\r
509 //\r
510 Status = RsaPkcs1Verify (\r
2d3fb919 511 Rsa,\r
512 Digest,\r
513 SHA256_DIGEST_SIZE,\r
514 CertBlock->Signature,\r
0c18794e 515 EFI_CERT_TYPE_RSA2048_SHA256_SIZE\r
516 );\r
517\r
518Done:\r
519 if (Rsa != NULL) {\r
520 RsaFree (Rsa);\r
521 }\r
522 if (Status) {\r
523 return EFI_SUCCESS;\r
524 } else {\r
525 return EFI_SECURITY_VIOLATION;\r
526 }\r
527}\r
528\r
0c18794e 529/**\r
530 Update platform mode.\r
531\r
532 @param[in] Mode SETUP_MODE or USER_MODE.\r
533\r
534 @return EFI_INVALID_PARAMETER Invalid parameter.\r
535 @return EFI_SUCCESS Update platform mode successfully.\r
536\r
537**/\r
538EFI_STATUS\r
539UpdatePlatformMode (\r
540 IN UINT32 Mode\r
541 )\r
542{\r
543 EFI_STATUS Status;\r
544 VARIABLE_POINTER_TRACK Variable;\r
545 UINT32 VarAttr;\r
546 UINT8 SecureBootMode;\r
beda2356 547 UINT8 SecureBootEnable;\r
548 UINTN VariableDataSize;\r
2d3fb919 549\r
0c18794e 550 Status = FindVariable (\r
2d3fb919 551 EFI_SETUP_MODE_NAME,\r
552 &gEfiGlobalVariableGuid,\r
553 &Variable,\r
0c18794e 554 &mVariableModuleGlobal->VariableGlobal\r
555 );\r
556 if (EFI_ERROR (Status)) {\r
557 return Status;\r
558 }\r
559\r
560 mPlatformMode = Mode;\r
2d3fb919 561 VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;\r
0c18794e 562 Status = UpdateVariable (\r
563 EFI_SETUP_MODE_NAME,\r
564 &gEfiGlobalVariableGuid,\r
565 &mPlatformMode,\r
566 sizeof(UINT8),\r
567 VarAttr,\r
568 0,\r
569 0,\r
570 &Variable,\r
571 NULL\r
572 );\r
573 if (EFI_ERROR (Status)) {\r
574 return Status;\r
575 }\r
576\r
2d3fb919 577 if (AtRuntime ()) {\r
578 //\r
579 // SecureBoot Variable indicates whether the platform firmware is operating\r
580 // in Secure boot mode (1) or not (0), so we should not change SecureBoot\r
581 // Variable in runtime.\r
582 //\r
583 return Status;\r
584 }\r
585\r
0c18794e 586 //\r
587 // Check "SecureBoot" variable's existence.\r
588 // If it doesn't exist, firmware has no capability to perform driver signing verification,\r
589 // then set "SecureBoot" to 0.\r
590 //\r
591 Status = FindVariable (\r
2d3fb919 592 EFI_SECURE_BOOT_MODE_NAME,\r
593 &gEfiGlobalVariableGuid,\r
594 &Variable,\r
0c18794e 595 &mVariableModuleGlobal->VariableGlobal\r
596 );\r
597 //\r
598 // If "SecureBoot" variable exists, then check "SetupMode" variable update.\r
599 // If "SetupMode" variable is USER_MODE, "SecureBoot" variable is set to 1.\r
600 // If "SetupMode" variable is SETUP_MODE, "SecureBoot" variable is set to 0.\r
601 //\r
602 if (Variable.CurrPtr == NULL) {\r
603 SecureBootMode = SECURE_BOOT_MODE_DISABLE;\r
604 } else {\r
605 if (mPlatformMode == USER_MODE) {\r
606 SecureBootMode = SECURE_BOOT_MODE_ENABLE;\r
607 } else if (mPlatformMode == SETUP_MODE) {\r
608 SecureBootMode = SECURE_BOOT_MODE_DISABLE;\r
609 } else {\r
610 return EFI_NOT_FOUND;\r
611 }\r
612 }\r
613\r
2d3fb919 614 VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;\r
beda2356 615 Status = UpdateVariable (\r
0c18794e 616 EFI_SECURE_BOOT_MODE_NAME,\r
617 &gEfiGlobalVariableGuid,\r
618 &SecureBootMode,\r
619 sizeof(UINT8),\r
620 VarAttr,\r
621 0,\r
622 0,\r
623 &Variable,\r
624 NULL\r
625 );\r
beda2356 626 if (EFI_ERROR (Status)) {\r
627 return Status;\r
628 }\r
629\r
630 //\r
631 // Check "SecureBootEnable" variable's existence. It can enable/disable secure boot feature.\r
632 //\r
633 Status = FindVariable (\r
2d3fb919 634 EFI_SECURE_BOOT_ENABLE_NAME,\r
635 &gEfiSecureBootEnableDisableGuid,\r
636 &Variable,\r
beda2356 637 &mVariableModuleGlobal->VariableGlobal\r
638 );\r
2d3fb919 639\r
beda2356 640 if (SecureBootMode == SECURE_BOOT_MODE_ENABLE) {\r
641 //\r
642 // Create the "SecureBootEnable" variable as secure boot is enabled.\r
643 //\r
644 SecureBootEnable = SECURE_BOOT_ENABLE;\r
645 VariableDataSize = sizeof (SecureBootEnable);\r
646 } else {\r
647 //\r
2d3fb919 648 // Delete the "SecureBootEnable" variable if this variable exist as "SecureBoot"\r
beda2356 649 // variable is not in secure boot state.\r
650 //\r
651 if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {\r
652 return EFI_SUCCESS;\r
653 }\r
654 SecureBootEnable = SECURE_BOOT_DISABLE;\r
655 VariableDataSize = 0;\r
656 }\r
2d3fb919 657\r
beda2356 658 Status = UpdateVariable (\r
2d3fb919 659 EFI_SECURE_BOOT_ENABLE_NAME,\r
660 &gEfiSecureBootEnableDisableGuid,\r
661 &SecureBootEnable,\r
662 VariableDataSize,\r
663 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
664 0,\r
665 0,\r
beda2356 666 &Variable,\r
667 NULL\r
668 );\r
669 return Status;\r
0c18794e 670}\r
671\r
d912bad7 672/**\r
673 Check input data form to make sure it is a valid EFI_SIGNATURE_LIST for PK/KEK variable.\r
674\r
675 @param[in] VariableName Name of Variable to be check.\r
676 @param[in] VendorGuid Variable vendor GUID.\r
677 @param[in] Data Point to the variable data to be checked.\r
678 @param[in] DataSize Size of Data.\r
679\r
680 @return EFI_INVALID_PARAMETER Invalid signature list format.\r
681 @return EFI_SUCCESS Passed signature list format check successfully.\r
682 \r
683**/\r
684EFI_STATUS\r
685CheckSignatureListFormat(\r
686 IN CHAR16 *VariableName,\r
687 IN EFI_GUID *VendorGuid,\r
688 IN VOID *Data,\r
689 IN UINTN DataSize\r
690 )\r
691{\r
692 EFI_SIGNATURE_LIST *SigList;\r
693 UINTN SigDataSize;\r
694 UINT32 Index;\r
695 UINT32 SigCount;\r
696 BOOLEAN IsPk;\r
697\r
698 if (DataSize == 0) {\r
699 return EFI_SUCCESS;\r
700 }\r
701\r
702 ASSERT (VariableName != NULL && VendorGuid != NULL && Data != NULL);\r
703\r
704 if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_PLATFORM_KEY_NAME) == 0)){\r
705 IsPk = TRUE;\r
706 } else if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_KEY_EXCHANGE_KEY_NAME) == 0)) {\r
707 IsPk = FALSE;\r
708 } else {\r
709 return EFI_SUCCESS;\r
710 }\r
711\r
712 SigCount = 0;\r
713 SigList = (EFI_SIGNATURE_LIST *) Data;\r
714 SigDataSize = DataSize;\r
715\r
716 //\r
717 // Walk throuth the input signature list and check the data format.\r
718 // If any signature is incorrectly formed, the whole check will fail.\r
719 //\r
720 while ((SigDataSize > 0) && (SigDataSize >= SigList->SignatureListSize)) {\r
721 for (Index = 0; Index < (sizeof (mSupportSigItem) / sizeof (EFI_SIGNATURE_ITEM)); Index++ ) {\r
722 if (CompareGuid (&SigList->SignatureType, &mSupportSigItem[Index].SigType)) {\r
723 //\r
724 // The value of SignatureSize should always be 16 (size of SignatureOwner \r
725 // component) add the data length according to signature type.\r
726 //\r
727 if (mSupportSigItem[Index].SigDataSize != ((UINT32) ~0) && \r
728 (SigList->SignatureSize - sizeof (EFI_GUID)) != mSupportSigItem[Index].SigDataSize) {\r
729 return EFI_INVALID_PARAMETER;\r
730 }\r
731 if (mSupportSigItem[Index].SigHeaderSize != ((UINTN) ~0) &&\r
732 SigList->SignatureHeaderSize != mSupportSigItem[Index].SigHeaderSize) {\r
733 return EFI_INVALID_PARAMETER;\r
734 }\r
735 break;\r
736 }\r
737 }\r
738\r
739 if (Index == (sizeof (mSupportSigItem) / sizeof (EFI_SIGNATURE_ITEM))) {\r
740 //\r
741 // Undefined signature type.\r
742 //\r
743 return EFI_INVALID_PARAMETER;\r
744 }\r
745\r
746 if ((SigList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - SigList->SignatureHeaderSize) % SigList->SignatureSize != 0) {\r
747 return EFI_INVALID_PARAMETER;\r
748 }\r
749 SigCount += (SigList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - SigList->SignatureHeaderSize) / SigList->SignatureSize;\r
750 \r
751 SigDataSize -= SigList->SignatureListSize;\r
752 SigList = (EFI_SIGNATURE_LIST *) ((UINT8 *) SigList + SigList->SignatureListSize);\r
753 }\r
754\r
755 if (((UINTN) SigList - (UINTN) Data) != DataSize) {\r
756 return EFI_INVALID_PARAMETER;\r
757 }\r
758\r
759 if (IsPk && SigCount > 1) {\r
760 return EFI_INVALID_PARAMETER;\r
761 }\r
762\r
763 return EFI_SUCCESS;\r
764}\r
765\r
0c18794e 766/**\r
767 Process variable with platform key for verification.\r
768\r
769 @param[in] VariableName Name of Variable to be found.\r
770 @param[in] VendorGuid Variable vendor GUID.\r
771 @param[in] Data Data pointer.\r
772 @param[in] DataSize Size of Data found. If size is less than the\r
773 data, this value contains the required size.\r
774 @param[in] Variable The variable information which is used to keep track of variable usage.\r
775 @param[in] Attributes Attribute value of the variable\r
776 @param[in] IsPk Indicate whether it is to process pk.\r
777\r
778 @return EFI_INVALID_PARAMETER Invalid parameter.\r
2d3fb919 779 @return EFI_SECURITY_VIOLATION The variable does NOT pass the validation.\r
780 check carried out by the firmware.\r
0c18794e 781 @return EFI_SUCCESS Variable passed validation successfully.\r
782\r
783**/\r
784EFI_STATUS\r
785ProcessVarWithPk (\r
786 IN CHAR16 *VariableName,\r
787 IN EFI_GUID *VendorGuid,\r
788 IN VOID *Data,\r
789 IN UINTN DataSize,\r
790 IN VARIABLE_POINTER_TRACK *Variable,\r
791 IN UINT32 Attributes OPTIONAL,\r
792 IN BOOLEAN IsPk\r
793 )\r
794{\r
795 EFI_STATUS Status;\r
796 VARIABLE_POINTER_TRACK PkVariable;\r
797 EFI_SIGNATURE_LIST *OldPkList;\r
798 EFI_SIGNATURE_DATA *OldPkData;\r
799 EFI_VARIABLE_AUTHENTICATION *CertData;\r
800 BOOLEAN TimeBase;\r
801 BOOLEAN Del;\r
2d3fb919 802 UINT8 *Payload;\r
803 UINTN PayloadSize;\r
804 UINT64 MonotonicCount;\r
805 EFI_TIME *TimeStamp;\r
0c18794e 806\r
807 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {\r
808 //\r
809 // PK and KEK should set EFI_VARIABLE_NON_VOLATILE attribute.\r
810 //\r
811 return EFI_INVALID_PARAMETER;\r
812 }\r
813\r
814 if (mPlatformMode == USER_MODE) {\r
815\r
816 if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
817 //\r
818 // EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute means time-based X509 Cert PK.\r
819 //\r
820 TimeBase = TRUE;\r
821 } else if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
822 //\r
823 // EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute means counter-based RSA-2048 Cert PK.\r
824 //\r
825 TimeBase = FALSE;\r
826 } else {\r
827 return EFI_INVALID_PARAMETER;\r
828 }\r
829\r
830 if (TimeBase) {\r
831 //\r
832 // Verify against X509 Cert PK.\r
833 //\r
834 Del = FALSE;\r
835 Status = VerifyTimeBasedPayload (VariableName, VendorGuid, Data, DataSize, Variable, Attributes, TRUE, &Del);\r
836 if (!EFI_ERROR (Status)) {\r
837 //\r
838 // If delete PK in user mode, need change to setup mode.\r
839 //\r
840 if (Del && IsPk) {\r
841 Status = UpdatePlatformMode (SETUP_MODE);\r
842 }\r
843 }\r
844 return Status;\r
845 } else {\r
846 //\r
847 // Verify against RSA2048 Cert PK.\r
848 //\r
849 CertData = (EFI_VARIABLE_AUTHENTICATION *) Data;\r
850 if ((Variable->CurrPtr != NULL) && (CertData->MonotonicCount <= Variable->CurrPtr->MonotonicCount)) {\r
851 //\r
852 // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.\r
853 //\r
854 return EFI_SECURITY_VIOLATION;\r
855 }\r
856 //\r
857 // Get platform key from variable.\r
858 //\r
859 Status = FindVariable (\r
2d3fb919 860 EFI_PLATFORM_KEY_NAME,\r
861 &gEfiGlobalVariableGuid,\r
862 &PkVariable,\r
0c18794e 863 &mVariableModuleGlobal->VariableGlobal\r
864 );\r
865 ASSERT_EFI_ERROR (Status);\r
2d3fb919 866\r
0c18794e 867 OldPkList = (EFI_SIGNATURE_LIST *) GetVariableDataPtr (PkVariable.CurrPtr);\r
868 OldPkData = (EFI_SIGNATURE_DATA *) ((UINT8 *) OldPkList + sizeof (EFI_SIGNATURE_LIST) + OldPkList->SignatureHeaderSize);\r
869 Status = VerifyCounterBasedPayload (Data, DataSize, OldPkData->SignatureData);\r
870 if (!EFI_ERROR (Status)) {\r
d912bad7 871 Status = CheckSignatureListFormat(\r
872 VariableName,\r
873 VendorGuid,\r
874 (UINT8*)Data + AUTHINFO_SIZE,\r
875 DataSize - AUTHINFO_SIZE);\r
876 if (EFI_ERROR (Status)) {\r
877 return Status;\r
878 }\r
879 \r
0c18794e 880 Status = UpdateVariable (\r
2d3fb919 881 VariableName,\r
882 VendorGuid,\r
883 (UINT8*)Data + AUTHINFO_SIZE,\r
884 DataSize - AUTHINFO_SIZE,\r
885 Attributes,\r
886 0,\r
887 CertData->MonotonicCount,\r
0c18794e 888 Variable,\r
889 NULL\r
890 );\r
2d3fb919 891\r
0c18794e 892 if (!EFI_ERROR (Status)) {\r
893 //\r
894 // If delete PK in user mode, need change to setup mode.\r
895 //\r
896 if ((DataSize == AUTHINFO_SIZE) && IsPk) {\r
897 Status = UpdatePlatformMode (SETUP_MODE);\r
898 }\r
899 }\r
900 }\r
901 }\r
902 } else {\r
2d3fb919 903 //\r
904 // Process PK or KEK in Setup mode.\r
905 //\r
906 if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
907 //\r
908 // Time-based Authentication descriptor.\r
909 //\r
910 MonotonicCount = 0;\r
911 TimeStamp = &((EFI_VARIABLE_AUTHENTICATION_2 *) Data)->TimeStamp;\r
912 Payload = (UINT8 *) Data + AUTHINFO2_SIZE (Data);\r
913 PayloadSize = DataSize - AUTHINFO2_SIZE (Data);\r
914 } else if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
915 //\r
916 // Counter-based Authentication descriptor.\r
917 //\r
918 MonotonicCount = ((EFI_VARIABLE_AUTHENTICATION *) Data)->MonotonicCount;\r
919 TimeStamp = NULL;\r
920 Payload = (UINT8*) Data + AUTHINFO_SIZE;\r
921 PayloadSize = DataSize - AUTHINFO_SIZE;\r
922 } else {\r
923 //\r
924 // No Authentication descriptor.\r
925 //\r
926 MonotonicCount = 0;\r
927 TimeStamp = NULL;\r
928 Payload = Data;\r
929 PayloadSize = DataSize;\r
930 }\r
931\r
d912bad7 932 Status = CheckSignatureListFormat(VariableName, VendorGuid, Payload, PayloadSize);\r
933 if (EFI_ERROR (Status)) {\r
934 return Status;\r
935 }\r
936\r
2d3fb919 937 Status = UpdateVariable (\r
938 VariableName,\r
939 VendorGuid,\r
940 Payload,\r
941 PayloadSize,\r
942 Attributes,\r
943 0,\r
944 MonotonicCount,\r
945 Variable,\r
946 TimeStamp\r
947 );\r
0c18794e 948 //\r
949 // If enroll PK in setup mode, need change to user mode.\r
950 //\r
951 if ((DataSize != 0) && IsPk) {\r
952 Status = UpdatePlatformMode (USER_MODE);\r
953 }\r
954 }\r
955\r
956 return Status;\r
957}\r
958\r
959/**\r
960 Process variable with key exchange key for verification.\r
961\r
962 @param[in] VariableName Name of Variable to be found.\r
963 @param[in] VendorGuid Variable vendor GUID.\r
964 @param[in] Data Data pointer.\r
965 @param[in] DataSize Size of Data found. If size is less than the\r
966 data, this value contains the required size.\r
967 @param[in] Variable The variable information which is used to keep track of variable usage.\r
968 @param[in] Attributes Attribute value of the variable.\r
969\r
970 @return EFI_INVALID_PARAMETER Invalid parameter.\r
2d3fb919 971 @return EFI_SECURITY_VIOLATION The variable does NOT pass the validation\r
972 check carried out by the firmware.\r
0c18794e 973 @return EFI_SUCCESS Variable pass validation successfully.\r
974\r
975**/\r
976EFI_STATUS\r
977ProcessVarWithKek (\r
978 IN CHAR16 *VariableName,\r
979 IN EFI_GUID *VendorGuid,\r
980 IN VOID *Data,\r
981 IN UINTN DataSize,\r
982 IN VARIABLE_POINTER_TRACK *Variable,\r
983 IN UINT32 Attributes OPTIONAL\r
984 )\r
985{\r
986 EFI_STATUS Status;\r
987 VARIABLE_POINTER_TRACK KekVariable;\r
988 EFI_SIGNATURE_LIST *KekList;\r
989 EFI_SIGNATURE_DATA *KekItem;\r
990 UINT32 KekCount;\r
991 EFI_VARIABLE_AUTHENTICATION *CertData;\r
992 EFI_CERT_BLOCK_RSA_2048_SHA256 *CertBlock;\r
993 BOOLEAN IsFound;\r
994 UINT32 Index;\r
995 UINT32 KekDataSize;\r
2d3fb919 996 UINT8 *Payload;\r
997 UINTN PayloadSize;\r
998 UINT64 MonotonicCount;\r
0c18794e 999\r
1000 if (mPlatformMode == USER_MODE) {\r
1001 if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == 0) {\r
1002 //\r
1003 // In user mode, should set EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute.\r
1004 //\r
1005 return EFI_INVALID_PARAMETER;\r
1006 }\r
1007\r
1008 CertData = (EFI_VARIABLE_AUTHENTICATION *) Data;\r
1009 CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData);\r
1010 if ((Variable->CurrPtr != NULL) && (CertData->MonotonicCount <= Variable->CurrPtr->MonotonicCount)) {\r
1011 //\r
1012 // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.\r
1013 //\r
1014 return EFI_SECURITY_VIOLATION;\r
1015 }\r
1016 //\r
1017 // Get KEK database from variable.\r
1018 //\r
1019 Status = FindVariable (\r
2d3fb919 1020 EFI_KEY_EXCHANGE_KEY_NAME,\r
1021 &gEfiGlobalVariableGuid,\r
1022 &KekVariable,\r
0c18794e 1023 &mVariableModuleGlobal->VariableGlobal\r
1024 );\r
1025 ASSERT_EFI_ERROR (Status);\r
1026\r
1027 KekDataSize = KekVariable.CurrPtr->DataSize;\r
1028 KekList = (EFI_SIGNATURE_LIST *) GetVariableDataPtr (KekVariable.CurrPtr);\r
1029\r
1030 //\r
1031 // Enumerate all Kek items in this list to verify the variable certificate data.\r
1032 // If anyone is authenticated successfully, it means the variable is correct!\r
1033 //\r
1034 IsFound = FALSE;\r
1035 while ((KekDataSize > 0) && (KekDataSize >= KekList->SignatureListSize)) {\r
1036 if (CompareGuid (&KekList->SignatureType, &gEfiCertRsa2048Guid)) {\r
1037 KekItem = (EFI_SIGNATURE_DATA *) ((UINT8 *) KekList + sizeof (EFI_SIGNATURE_LIST) + KekList->SignatureHeaderSize);\r
1038 KekCount = (KekList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - KekList->SignatureHeaderSize) / KekList->SignatureSize;\r
1039 for (Index = 0; Index < KekCount; Index++) {\r
1040 if (CompareMem (KekItem->SignatureData, CertBlock->PublicKey, EFI_CERT_TYPE_RSA2048_SIZE) == 0) {\r
1041 IsFound = TRUE;\r
1042 break;\r
1043 }\r
1044 KekItem = (EFI_SIGNATURE_DATA *) ((UINT8 *) KekItem + KekList->SignatureSize);\r
1045 }\r
1046 }\r
1047 KekDataSize -= KekList->SignatureListSize;\r
1048 KekList = (EFI_SIGNATURE_LIST *) ((UINT8 *) KekList + KekList->SignatureListSize);\r
1049 }\r
2d3fb919 1050\r
0c18794e 1051 if (!IsFound) {\r
1052 return EFI_SECURITY_VIOLATION;\r
1053 }\r
1054\r
1055 Status = VerifyCounterBasedPayload (Data, DataSize, CertBlock->PublicKey);\r
1056 if (!EFI_ERROR (Status)) {\r
1057 Status = UpdateVariable (\r
2d3fb919 1058 VariableName,\r
1059 VendorGuid,\r
1060 (UINT8*)Data + AUTHINFO_SIZE,\r
1061 DataSize - AUTHINFO_SIZE,\r
1062 Attributes,\r
1063 0,\r
1064 CertData->MonotonicCount,\r
0c18794e 1065 Variable,\r
1066 NULL\r
1067 );\r
1068 }\r
1069 } else {\r
1070 //\r
1071 // If in setup mode, no authentication needed.\r
1072 //\r
2d3fb919 1073 if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
1074 //\r
1075 // Counter-based Authentication descriptor.\r
1076 //\r
1077 MonotonicCount = ((EFI_VARIABLE_AUTHENTICATION *) Data)->MonotonicCount;\r
1078 Payload = (UINT8*) Data + AUTHINFO_SIZE;\r
1079 PayloadSize = DataSize - AUTHINFO_SIZE;\r
1080 } else {\r
1081 //\r
1082 // No Authentication descriptor.\r
1083 //\r
1084 MonotonicCount = 0;\r
1085 Payload = Data;\r
1086 PayloadSize = DataSize;\r
1087 }\r
1088\r
0c18794e 1089 Status = UpdateVariable (\r
2d3fb919 1090 VariableName,\r
1091 VendorGuid,\r
1092 Payload,\r
1093 PayloadSize,\r
1094 Attributes,\r
1095 0,\r
1096 MonotonicCount,\r
0c18794e 1097 Variable,\r
1098 NULL\r
1099 );\r
1100 }\r
1101\r
1102 return Status;\r
1103}\r
1104\r
1105/**\r
1106 Process variable with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS/EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set\r
1107\r
1108 @param[in] VariableName Name of Variable to be found.\r
1109 @param[in] VendorGuid Variable vendor GUID.\r
1110\r
1111 @param[in] Data Data pointer.\r
1112 @param[in] DataSize Size of Data found. If size is less than the\r
1113 data, this value contains the required size.\r
1114 @param[in] Variable The variable information which is used to keep track of variable usage.\r
1115 @param[in] Attributes Attribute value of the variable.\r
1116\r
1117 @return EFI_INVALID_PARAMETER Invalid parameter.\r
1118 @return EFI_WRITE_PROTECTED Variable is write-protected and needs authentication with\r
1119 EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.\r
1120 @return EFI_SECURITY_VIOLATION The variable is with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS\r
2d3fb919 1121 set, but the AuthInfo does NOT pass the validation\r
1122 check carried out by the firmware.\r
0c18794e 1123 @return EFI_SUCCESS Variable is not write-protected or pass validation successfully.\r
1124\r
1125**/\r
1126EFI_STATUS\r
1127ProcessVariable (\r
1128 IN CHAR16 *VariableName,\r
1129 IN EFI_GUID *VendorGuid,\r
1130 IN VOID *Data,\r
1131 IN UINTN DataSize,\r
1132 IN VARIABLE_POINTER_TRACK *Variable,\r
1133 IN UINT32 Attributes\r
1134 )\r
1135{\r
1136 EFI_STATUS Status;\r
1137 BOOLEAN IsDeletion;\r
1138 BOOLEAN IsFirstTime;\r
1139 UINT8 *PubKey;\r
1140 EFI_VARIABLE_AUTHENTICATION *CertData;\r
1141 EFI_CERT_BLOCK_RSA_2048_SHA256 *CertBlock;\r
1142 UINT32 KeyIndex;\r
1143 UINT64 MonotonicCount;\r
1144\r
2d3fb919 1145 KeyIndex = 0;\r
0c18794e 1146 CertData = NULL;\r
1147 CertBlock = NULL;\r
1148 PubKey = NULL;\r
1149 IsDeletion = FALSE;\r
1150\r
1151 //\r
1152 // Process Time-based Authenticated variable.\r
1153 //\r
1154 if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
1155 return VerifyTimeBasedPayload (VariableName, VendorGuid, Data, DataSize, Variable, Attributes, FALSE, NULL);\r
1156 }\r
2d3fb919 1157\r
0c18794e 1158 //\r
1159 // Determine if first time SetVariable with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS.\r
1160 //\r
1161 if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
1162 //\r
1163 // Determine current operation type.\r
1164 //\r
1165 if (DataSize == AUTHINFO_SIZE) {\r
1166 IsDeletion = TRUE;\r
1167 }\r
1168 //\r
1169 // Determine whether this is the first time with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.\r
1170 //\r
1171 if (Variable->CurrPtr == NULL) {\r
1172 IsFirstTime = TRUE;\r
1173 } else if ((Variable->CurrPtr->Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == 0) {\r
1174 IsFirstTime = TRUE;\r
1175 } else {\r
1176 KeyIndex = Variable->CurrPtr->PubKeyIndex;\r
1177 IsFirstTime = FALSE;\r
1178 }\r
1179 } else if ((Variable->CurrPtr != NULL) &&\r
1180 (Variable->CurrPtr->Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0\r
1181 ) {\r
1182 //\r
1183 // If the variable is already write-protected, it always needs authentication before update.\r
1184 //\r
1185 return EFI_WRITE_PROTECTED;\r
1186 } else {\r
1187 //\r
1188 // If without EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, set and attributes collision.\r
1189 // That means it is not authenticated variable, just update variable as usual.\r
1190 //\r
1191 Status = UpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes, 0, 0, Variable, NULL);\r
1192 return Status;\r
1193 }\r
1194\r
1195 //\r
1196 // Get PubKey and check Monotonic Count value corresponding to the variable.\r
1197 //\r
1198 CertData = (EFI_VARIABLE_AUTHENTICATION *) Data;\r
1199 CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData);\r
1200 PubKey = CertBlock->PublicKey;\r
1201\r
1202 //\r
1203 // Update Monotonic Count value.\r
1204 //\r
1205 MonotonicCount = CertData->MonotonicCount;\r
1206\r
1207 if (!IsFirstTime) {\r
1208 //\r
1209 // Check input PubKey.\r
1210 //\r
1211 if (CompareMem (PubKey, mPubKeyStore + (KeyIndex - 1) * EFI_CERT_TYPE_RSA2048_SIZE, EFI_CERT_TYPE_RSA2048_SIZE) != 0) {\r
1212 return EFI_SECURITY_VIOLATION;\r
1213 }\r
1214 //\r
1215 // Compare the current monotonic count and ensure that it is greater than the last SetVariable\r
1216 // operation with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute set.\r
1217 //\r
1218 if (CertData->MonotonicCount <= Variable->CurrPtr->MonotonicCount) {\r
1219 //\r
1220 // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.\r
1221 //\r
1222 return EFI_SECURITY_VIOLATION;\r
1223 }\r
2d3fb919 1224 }\r
0c18794e 1225 //\r
1226 // Verify the certificate in Data payload.\r
1227 //\r
1228 Status = VerifyCounterBasedPayload (Data, DataSize, PubKey);\r
1229 if (EFI_ERROR (Status)) {\r
1230 return Status;\r
1231 }\r
2d3fb919 1232\r
0c18794e 1233 //\r
1234 // Now, the signature has been verified!\r
1235 //\r
1236 if (IsFirstTime && !IsDeletion) {\r
1237 //\r
1238 // Update public key database variable if need.\r
1239 //\r
1240 KeyIndex = AddPubKeyInStore (PubKey);\r
1241 }\r
1242\r
1243 //\r
1244 // Verification pass.\r
1245 //\r
1246 return UpdateVariable (VariableName, VendorGuid, (UINT8*)Data + AUTHINFO_SIZE, DataSize - AUTHINFO_SIZE, Attributes, KeyIndex, MonotonicCount, Variable, NULL);\r
1247}\r
1248\r
2d3fb919 1249/**\r
1250 Merge two buffers which formatted as EFI_SIGNATURE_LIST. Only the new EFI_SIGNATURE_DATA\r
1251 will be appended to the original EFI_SIGNATURE_LIST, duplicate EFI_SIGNATURE_DATA\r
1252 will be ignored.\r
1253\r
1254 @param[in, out] Data Pointer to original EFI_SIGNATURE_LIST.\r
1255 @param[in] DataSize Size of Data buffer.\r
1256 @param[in] NewData Pointer to new EFI_SIGNATURE_LIST to be appended.\r
1257 @param[in] NewDataSize Size of NewData buffer.\r
1258\r
1259 @return Size of the merged buffer.\r
1260\r
1261**/\r
1262UINTN\r
1263AppendSignatureList (\r
1264 IN OUT VOID *Data,\r
1265 IN UINTN DataSize,\r
1266 IN VOID *NewData,\r
1267 IN UINTN NewDataSize\r
1268 )\r
1269{\r
1270 EFI_SIGNATURE_LIST *CertList;\r
1271 EFI_SIGNATURE_DATA *Cert;\r
1272 UINTN CertCount;\r
1273 EFI_SIGNATURE_LIST *NewCertList;\r
1274 EFI_SIGNATURE_DATA *NewCert;\r
1275 UINTN NewCertCount;\r
1276 UINTN Index;\r
1277 UINTN Index2;\r
1278 UINTN Size;\r
1279 UINT8 *Tail;\r
1280 UINTN CopiedCount;\r
1281 UINTN SignatureListSize;\r
1282 BOOLEAN IsNewCert;\r
1283\r
1284 Tail = (UINT8 *) Data + DataSize;\r
1285\r
1286 NewCertList = (EFI_SIGNATURE_LIST *) NewData;\r
1287 while ((NewDataSize > 0) && (NewDataSize >= NewCertList->SignatureListSize)) {\r
1288 NewCert = (EFI_SIGNATURE_DATA *) ((UINT8 *) NewCertList + sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize);\r
1289 NewCertCount = (NewCertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - NewCertList->SignatureHeaderSize) / NewCertList->SignatureSize;\r
1290\r
1291 CopiedCount = 0;\r
1292 for (Index = 0; Index < NewCertCount; Index++) {\r
1293 IsNewCert = TRUE;\r
1294\r
1295 Size = DataSize;\r
1296 CertList = (EFI_SIGNATURE_LIST *) Data;\r
1297 while ((Size > 0) && (Size >= CertList->SignatureListSize)) {\r
1298 if (CompareGuid (&CertList->SignatureType, &NewCertList->SignatureType) &&\r
1299 (CertList->SignatureSize == NewCertList->SignatureSize)) {\r
1300 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);\r
1301 CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;\r
1302 for (Index2 = 0; Index2 < CertCount; Index2++) {\r
1303 //\r
1304 // Iterate each Signature Data in this Signature List.\r
1305 //\r
1306 if (CompareMem (NewCert, Cert, CertList->SignatureSize) == 0) {\r
1307 IsNewCert = FALSE;\r
1308 break;\r
1309 }\r
1310 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);\r
1311 }\r
1312 }\r
1313\r
1314 if (!IsNewCert) {\r
1315 break;\r
1316 }\r
1317 Size -= CertList->SignatureListSize;\r
1318 CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);\r
1319 }\r
1320\r
1321 if (IsNewCert) {\r
1322 //\r
1323 // New EFI_SIGNATURE_DATA, append it.\r
1324 //\r
1325 if (CopiedCount == 0) {\r
1326 //\r
1327 // Copy EFI_SIGNATURE_LIST header for only once.\r
1328 //\r
1329 CopyMem (Tail, NewCertList, sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize);\r
1330 Tail = Tail + sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize;\r
1331 }\r
1332\r
1333 CopyMem (Tail, NewCert, NewCertList->SignatureSize);\r
1334 Tail += NewCertList->SignatureSize;\r
1335 CopiedCount++;\r
1336 }\r
1337\r
1338 NewCert = (EFI_SIGNATURE_DATA *) ((UINT8 *) NewCert + NewCertList->SignatureSize);\r
1339 }\r
1340\r
1341 //\r
1342 // Update SignatureListSize in newly appended EFI_SIGNATURE_LIST.\r
1343 //\r
1344 if (CopiedCount != 0) {\r
1345 SignatureListSize = sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize + (CopiedCount * NewCertList->SignatureSize);\r
1346 CertList = (EFI_SIGNATURE_LIST *) (Tail - SignatureListSize);\r
1347 CertList->SignatureListSize = (UINT32) SignatureListSize;\r
1348 }\r
1349\r
1350 NewDataSize -= NewCertList->SignatureListSize;\r
1351 NewCertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) NewCertList + NewCertList->SignatureListSize);\r
1352 }\r
1353\r
1354 return (Tail - (UINT8 *) Data);\r
1355}\r
1356\r
0c18794e 1357/**\r
1358 Compare two EFI_TIME data.\r
1359\r
1360\r
1361 @param FirstTime A pointer to the first EFI_TIME data.\r
1362 @param SecondTime A pointer to the second EFI_TIME data.\r
1363\r
1364 @retval TRUE The FirstTime is not later than the SecondTime.\r
1365 @retval FALSE The FirstTime is later than the SecondTime.\r
1366\r
1367**/\r
1368BOOLEAN\r
1369CompareTimeStamp (\r
1370 IN EFI_TIME *FirstTime,\r
1371 IN EFI_TIME *SecondTime\r
1372 )\r
1373{\r
1374 if (FirstTime->Year != SecondTime->Year) {\r
1375 return (BOOLEAN) (FirstTime->Year < SecondTime->Year);\r
1376 } else if (FirstTime->Month != SecondTime->Month) {\r
1377 return (BOOLEAN) (FirstTime->Month < SecondTime->Month);\r
1378 } else if (FirstTime->Day != SecondTime->Day) {\r
1379 return (BOOLEAN) (FirstTime->Day < SecondTime->Day);\r
1380 } else if (FirstTime->Hour != SecondTime->Hour) {\r
1381 return (BOOLEAN) (FirstTime->Hour < SecondTime->Hour);\r
1382 } else if (FirstTime->Minute != SecondTime->Minute) {\r
1383 return (BOOLEAN) (FirstTime->Minute < FirstTime->Minute);\r
2d3fb919 1384 }\r
0c18794e 1385\r
1386 return (BOOLEAN) (FirstTime->Second <= SecondTime->Second);\r
1387}\r
1388\r
1389/**\r
1390 Process variable with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set\r
1391\r
1392 @param[in] VariableName Name of Variable to be found.\r
1393 @param[in] VendorGuid Variable vendor GUID.\r
1394 @param[in] Data Data pointer.\r
1395 @param[in] DataSize Size of Data found. If size is less than the\r
1396 data, this value contains the required size.\r
1397 @param[in] Variable The variable information which is used to keep track of variable usage.\r
1398 @param[in] Attributes Attribute value of the variable.\r
1399 @param[in] Pk Verify against PK or KEK database.\r
1400 @param[out] VarDel Delete the variable or not.\r
1401\r
1402 @retval EFI_INVALID_PARAMETER Invalid parameter.\r
2d3fb919 1403 @retval EFI_SECURITY_VIOLATION The variable does NOT pass the validation\r
1404 check carried out by the firmware.\r
0c18794e 1405 @retval EFI_OUT_OF_RESOURCES Failed to process variable due to lack\r
1406 of resources.\r
1407 @retval EFI_SUCCESS Variable pass validation successfully.\r
1408\r
1409**/\r
1410EFI_STATUS\r
1411VerifyTimeBasedPayload (\r
1412 IN CHAR16 *VariableName,\r
1413 IN EFI_GUID *VendorGuid,\r
1414 IN VOID *Data,\r
1415 IN UINTN DataSize,\r
1416 IN VARIABLE_POINTER_TRACK *Variable,\r
1417 IN UINT32 Attributes,\r
1418 IN BOOLEAN Pk,\r
1419 OUT BOOLEAN *VarDel\r
1420 )\r
1421{\r
1422 UINT8 *RootCert;\r
1423 UINT8 *SigData;\r
2d3fb919 1424 UINT8 *PayloadPtr;\r
0c18794e 1425 UINTN RootCertSize;\r
1426 UINTN Index;\r
2d3fb919 1427 UINTN CertCount;\r
1428 UINTN PayloadSize;\r
0c18794e 1429 UINT32 Attr;\r
1430 UINT32 SigDataSize;\r
1431 UINT32 KekDataSize;\r
1432 BOOLEAN Result;\r
1433 BOOLEAN VerifyStatus;\r
1434 EFI_STATUS Status;\r
1435 EFI_SIGNATURE_LIST *CertList;\r
1436 EFI_SIGNATURE_DATA *Cert;\r
1437 VARIABLE_POINTER_TRACK KekVariable;\r
1438 EFI_VARIABLE_AUTHENTICATION_2 *CertData;\r
1439 UINT8 *NewData;\r
1440 UINTN NewDataSize;\r
1441 VARIABLE_POINTER_TRACK PkVariable;\r
2d3fb919 1442 UINT8 *Buffer;\r
1443 UINTN Length;\r
0c18794e 1444\r
1445 Result = FALSE;\r
1446 VerifyStatus = FALSE;\r
1447 CertData = NULL;\r
1448 NewData = NULL;\r
1449 Attr = Attributes;\r
1450\r
1451 //\r
2d3fb919 1452 // When the attribute EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS is\r
0c18794e 1453 // set, then the Data buffer shall begin with an instance of a complete (and serialized)\r
2d3fb919 1454 // EFI_VARIABLE_AUTHENTICATION_2 descriptor. The descriptor shall be followed by the new\r
1455 // variable value and DataSize shall reflect the combined size of the descriptor and the new\r
1456 // variable value. The authentication descriptor is not part of the variable data and is not\r
0c18794e 1457 // returned by subsequent calls to GetVariable().\r
1458 //\r
1459 CertData = (EFI_VARIABLE_AUTHENTICATION_2 *) Data;\r
2d3fb919 1460\r
1461 //\r
1462 // Verify that Pad1, Nanosecond, TimeZone, Daylight and Pad2 components of the\r
1463 // TimeStamp value are set to zero.\r
1464 //\r
1465 if ((CertData->TimeStamp.Pad1 != 0) ||\r
1466 (CertData->TimeStamp.Nanosecond != 0) ||\r
1467 (CertData->TimeStamp.TimeZone != 0) ||\r
1468 (CertData->TimeStamp.Daylight != 0) ||\r
1469 (CertData->TimeStamp.Pad2 != 0)) {\r
1470 return EFI_INVALID_PARAMETER;\r
1471 }\r
1472\r
0c18794e 1473 if ((Variable->CurrPtr != NULL) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0)) {\r
1474 if (CompareTimeStamp (&CertData->TimeStamp, &Variable->CurrPtr->TimeStamp)) {\r
1475 //\r
1476 // TimeStamp check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.\r
1477 //\r
1478 return EFI_SECURITY_VIOLATION;\r
1479 }\r
1480 }\r
1481\r
1482 //\r
1483 // wCertificateType should be WIN_CERT_TYPE_EFI_GUID.\r
1484 // Cert type should be EFI_CERT_TYPE_PKCS7_GUID.\r
1485 //\r
1486 if ((CertData->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID) ||\r
2d3fb919 1487 !CompareGuid (&CertData->AuthInfo.CertType, &gEfiCertPkcs7Guid)) {\r
0c18794e 1488 //\r
1489 // Invalid AuthInfo type, return EFI_SECURITY_VIOLATION.\r
1490 //\r
1491 return EFI_SECURITY_VIOLATION;\r
1492 }\r
2d3fb919 1493\r
0c18794e 1494 //\r
1495 // Find out Pkcs7 SignedData which follows the EFI_VARIABLE_AUTHENTICATION_2 descriptor.\r
1496 // AuthInfo.Hdr.dwLength is the length of the entire certificate, including the length of the header.\r
1497 //\r
2d3fb919 1498 SigData = CertData->AuthInfo.CertData;\r
1499 SigDataSize = CertData->AuthInfo.Hdr.dwLength - (UINT32) (OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData));\r
648f98d1 1500\r
0c18794e 1501 //\r
1502 // Find out the new data payload which follows Pkcs7 SignedData directly.\r
1503 //\r
2d3fb919 1504 PayloadPtr = SigData + SigDataSize;\r
1505 PayloadSize = DataSize - OFFSET_OF_AUTHINFO2_CERT_DATA - (UINTN) SigDataSize;\r
0c18794e 1506\r
1507 //\r
1508 // Construct a buffer to fill with (VariableName, VendorGuid, Attributes, TimeStamp, Data).\r
1509 //\r
2d3fb919 1510 NewDataSize = PayloadSize + sizeof (EFI_TIME) + sizeof (UINT32) +\r
1511 sizeof (EFI_GUID) + StrSize (VariableName) - sizeof (CHAR16);\r
1512 NewData = mSerializationRuntimeBuffer;\r
0c18794e 1513\r
2d3fb919 1514 Buffer = NewData;\r
1515 Length = StrLen (VariableName) * sizeof (CHAR16);\r
1516 CopyMem (Buffer, VariableName, Length);\r
1517 Buffer += Length;\r
0c18794e 1518\r
2d3fb919 1519 Length = sizeof (EFI_GUID);\r
1520 CopyMem (Buffer, VendorGuid, Length);\r
1521 Buffer += Length;\r
0c18794e 1522\r
2d3fb919 1523 Length = sizeof (UINT32);\r
1524 CopyMem (Buffer, &Attr, Length);\r
1525 Buffer += Length;\r
0c18794e 1526\r
2d3fb919 1527 Length = sizeof (EFI_TIME);\r
1528 CopyMem (Buffer, &CertData->TimeStamp, Length);\r
1529 Buffer += Length;\r
0c18794e 1530\r
2d3fb919 1531 CopyMem (Buffer, PayloadPtr, PayloadSize);\r
0c18794e 1532\r
1533 if (Pk) {\r
1534 //\r
1535 // Get platform key from variable.\r
1536 //\r
1537 Status = FindVariable (\r
2d3fb919 1538 EFI_PLATFORM_KEY_NAME,\r
1539 &gEfiGlobalVariableGuid,\r
1540 &PkVariable,\r
0c18794e 1541 &mVariableModuleGlobal->VariableGlobal\r
1542 );\r
1543 if (EFI_ERROR (Status)) {\r
1544 return Status;\r
1545 }\r
1546\r
1547 CertList = (EFI_SIGNATURE_LIST *) GetVariableDataPtr (PkVariable.CurrPtr);\r
1548 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);\r
1549 RootCert = Cert->SignatureData;\r
1550 RootCertSize = CertList->SignatureSize;\r
1551\r
1552\r
1553 //\r
1554 // Verify Pkcs7 SignedData via Pkcs7Verify library.\r
1555 //\r
1556 VerifyStatus = Pkcs7Verify (\r
1557 SigData,\r
1558 SigDataSize,\r
1559 RootCert,\r
1560 RootCertSize,\r
1561 NewData,\r
1562 NewDataSize\r
1563 );\r
1564\r
1565 } else {\r
2d3fb919 1566\r
0c18794e 1567 //\r
1568 // Get KEK database from variable.\r
1569 //\r
1570 Status = FindVariable (\r
2d3fb919 1571 EFI_KEY_EXCHANGE_KEY_NAME,\r
1572 &gEfiGlobalVariableGuid,\r
1573 &KekVariable,\r
0c18794e 1574 &mVariableModuleGlobal->VariableGlobal\r
1575 );\r
1576 if (EFI_ERROR (Status)) {\r
1577 return Status;\r
1578 }\r
1579\r
1580 //\r
1581 // Ready to verify Pkcs7 SignedData. Go through KEK Signature Database to find out X.509 CertList.\r
2d3fb919 1582 //\r
0c18794e 1583 KekDataSize = KekVariable.CurrPtr->DataSize;\r
1584 CertList = (EFI_SIGNATURE_LIST *) GetVariableDataPtr (KekVariable.CurrPtr);\r
1585 while ((KekDataSize > 0) && (KekDataSize >= CertList->SignatureListSize)) {\r
1586 if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) {\r
1587 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);\r
1588 CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;\r
1589 for (Index = 0; Index < CertCount; Index++) {\r
1590 //\r
1591 // Iterate each Signature Data Node within this CertList for a verify\r
1592 //\r
1593 RootCert = Cert->SignatureData;\r
1594 RootCertSize = CertList->SignatureSize;\r
2d3fb919 1595\r
0c18794e 1596 //\r
1597 // Verify Pkcs7 SignedData via Pkcs7Verify library.\r
1598 //\r
1599 VerifyStatus = Pkcs7Verify (\r
1600 SigData,\r
1601 SigDataSize,\r
1602 RootCert,\r
1603 RootCertSize,\r
1604 NewData,\r
1605 NewDataSize\r
1606 );\r
1607 if (VerifyStatus) {\r
1608 goto Exit;\r
1609 }\r
1610 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);\r
1611 }\r
1612 }\r
1613 KekDataSize -= CertList->SignatureListSize;\r
1614 CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);\r
1615 }\r
1616 }\r
1617\r
1618Exit:\r
1619\r
0c18794e 1620 if (!VerifyStatus) {\r
1621 return EFI_SECURITY_VIOLATION;\r
1622 }\r
1623\r
d912bad7 1624 Status = CheckSignatureListFormat(VariableName, VendorGuid, PayloadPtr, PayloadSize);\r
1625 if (EFI_ERROR (Status)) {\r
1626 return Status;\r
1627 }\r
1628\r
2d3fb919 1629 if ((PayloadSize == 0) && (VarDel != NULL)) {\r
0c18794e 1630 *VarDel = TRUE;\r
1631 }\r
2d3fb919 1632\r
0c18794e 1633 //\r
1634 // Final step: Update/Append Variable if it pass Pkcs7Verify\r
1635 //\r
1636 return UpdateVariable (\r
2d3fb919 1637 VariableName,\r
1638 VendorGuid,\r
1639 PayloadPtr,\r
1640 PayloadSize,\r
1641 Attributes,\r
1642 0,\r
1643 0,\r
0c18794e 1644 Variable,\r
1645 &CertData->TimeStamp\r
1646 );\r
1647}\r