]> git.proxmox.com Git - mirror_edk2.git/blame - SecurityPkg/VariableAuthenticated/RuntimeDxe/AuthService.c
Return EFI_UNSUPPORTED if READY_TO_BOOT function is invoked at SMM runtime.
[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
dc204d5a
JY
5 Caution: This module requires additional review when modified.\r
6 This driver will have external input - variable data. It may be input in SMM mode.\r
7 This external input must be validated carefully to avoid security issue like\r
8 buffer overflow, integer overflow.\r
9 Variable attribute should also be checked to avoid authentication bypass.\r
10\r
11 ProcessVarWithPk(), ProcessVarWithKek() and ProcessVariable() are the function to do\r
12 variable authentication.\r
13\r
14 VerifyTimeBasedPayload() and VerifyCounterBasedPayload() are sub function to do verification.\r
15 They will do basic validation for authentication data structure, then call crypto library\r
16 to verify the signature.\r
17\r
ecc722ad 18Copyright (c) 2009 - 2012, Intel Corporation. All rights reserved.<BR>\r
2d3fb919 19This program and the accompanying materials\r
20are licensed and made available under the terms and conditions of the BSD License\r
21which accompanies this distribution. The full text of the license may be found at\r
0c18794e 22http://opensource.org/licenses/bsd-license.php\r
23\r
2d3fb919 24THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
0c18794e 25WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
26\r
27**/\r
28\r
29#include "Variable.h"\r
30#include "AuthService.h"\r
31\r
32///\r
33/// Global database array for scratch\r
2d3fb919 34///\r
0c18794e 35UINT8 mPubKeyStore[MAX_KEYDB_SIZE];\r
36UINT32 mPubKeyNumber;\r
37UINT32 mPlatformMode;\r
ae09f979 38EFI_GUID mSignatureSupport[] = {EFI_CERT_SHA1_GUID, EFI_CERT_SHA256_GUID, EFI_CERT_RSA2048_GUID, EFI_CERT_X509_GUID};\r
0c18794e 39//\r
40// Public Exponent of RSA Key.\r
41//\r
42CONST UINT8 mRsaE[] = { 0x01, 0x00, 0x01 };\r
43//\r
44// Hash context pointer\r
45//\r
46VOID *mHashCtx = NULL;\r
47\r
0c18794e 48//\r
2d3fb919 49// Pointer to runtime buffer.\r
50// For "Append" operation to an existing variable, a read/modify/write operation\r
51// is supported by firmware internally. Reserve runtime buffer to cache previous\r
0c18794e 52// variable data in runtime phase because memory allocation is forbidden in virtual mode.\r
53//\r
54VOID *mStorageArea = NULL;\r
55\r
2d3fb919 56//\r
57// The serialization of the values of the VariableName, VendorGuid and Attributes\r
58// parameters of the SetVariable() call and the TimeStamp component of the\r
59// EFI_VARIABLE_AUTHENTICATION_2 descriptor followed by the variable's new value\r
60// i.e. (VariableName, VendorGuid, Attributes, TimeStamp, Data)\r
61//\r
62UINT8 *mSerializationRuntimeBuffer = NULL;\r
63\r
d912bad7 64//\r
65// Requirement for different signature type which have been defined in UEFI spec.\r
66// These data are used to peform SignatureList format check while setting PK/KEK variable.\r
67//\r
68EFI_SIGNATURE_ITEM mSupportSigItem[] = {\r
69//{SigType, SigHeaderSize, SigDataSize }\r
70 {EFI_CERT_SHA256_GUID, 0, 32 },\r
71 {EFI_CERT_RSA2048_GUID, 0, 256 },\r
72 {EFI_CERT_RSA2048_SHA256_GUID, 0, 256 },\r
73 {EFI_CERT_SHA1_GUID, 0, 20 },\r
74 {EFI_CERT_RSA2048_SHA1_GUID, 0, 256 },\r
75 {EFI_CERT_X509_GUID, 0, ((UINT32) ~0)},\r
76 {EFI_CERT_SHA224_GUID, 0, 28 },\r
77 {EFI_CERT_SHA384_GUID, 0, 48 },\r
78 {EFI_CERT_SHA512_GUID, 0, 64 }\r
79};\r
80\r
ecc722ad 81/**\r
82 Determine whether this operation needs a physical present user.\r
83\r
84 @param[in] VariableName Name of the Variable.\r
85 @param[in] VendorGuid GUID of the Variable.\r
86\r
87 @retval TRUE This variable is protected, only a physical present user could set this variable.\r
88 @retval FALSE This variable is not protected.\r
89 \r
90**/\r
91BOOLEAN\r
92NeedPhysicallyPresent(\r
93 IN CHAR16 *VariableName,\r
94 IN EFI_GUID *VendorGuid\r
95 )\r
96{\r
97 if ((CompareGuid (VendorGuid, &gEfiSecureBootEnableDisableGuid) && (StrCmp (VariableName, EFI_SECURE_BOOT_ENABLE_NAME) == 0))\r
98 || (CompareGuid (VendorGuid, &gEfiCustomModeEnableGuid) && (StrCmp (VariableName, EFI_CUSTOM_MODE_NAME) == 0))) {\r
99 return TRUE;\r
100 }\r
101 \r
102 return FALSE;\r
103}\r
104\r
105/**\r
106 Determine whether the platform is operating in Custom Secure Boot mode.\r
107\r
108 @retval TRUE The platform is operating in Custom mode.\r
109 @retval FALSE The platform is operating in Standard mode.\r
110\r
111**/\r
112BOOLEAN\r
113InCustomMode (\r
114 VOID\r
115 )\r
116{\r
117 VARIABLE_POINTER_TRACK Variable;\r
118\r
119 FindVariable (EFI_CUSTOM_MODE_NAME, &gEfiCustomModeEnableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
120 if (Variable.CurrPtr != NULL && *(GetVariableDataPtr (Variable.CurrPtr)) == CUSTOM_SECURE_BOOT_MODE) {\r
121 return TRUE;\r
122 }\r
123 \r
124 return FALSE;\r
125}\r
126\r
127\r
0c18794e 128/**\r
2d3fb919 129 Internal function to delete a Variable given its name and GUID, no authentication\r
130 required.\r
0c18794e 131\r
2d3fb919 132 @param[in] VariableName Name of the Variable.\r
133 @param[in] VendorGuid GUID of the Variable.\r
0c18794e 134\r
2d3fb919 135 @retval EFI_SUCCESS Variable deleted successfully.\r
136 @retval Others The driver failded to start the device.\r
0c18794e 137\r
138**/\r
139EFI_STATUS\r
2d3fb919 140DeleteVariable (\r
141 IN CHAR16 *VariableName,\r
142 IN EFI_GUID *VendorGuid\r
143 )\r
144{\r
145 EFI_STATUS Status;\r
146 VARIABLE_POINTER_TRACK Variable;\r
147\r
ecc722ad 148 Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
2d3fb919 149 if (EFI_ERROR (Status)) {\r
150 return EFI_SUCCESS;\r
151 }\r
152\r
153 ASSERT (Variable.CurrPtr != NULL);\r
154 return UpdateVariable (VariableName, VendorGuid, NULL, 0, 0, 0, 0, &Variable, NULL);\r
155}\r
0c18794e 156\r
157/**\r
158 Initializes for authenticated varibale service.\r
159\r
160 @retval EFI_SUCCESS Function successfully executed.\r
161 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resources.\r
162\r
163**/\r
164EFI_STATUS\r
165AutenticatedVariableServiceInitialize (\r
166 VOID\r
167 )\r
168{\r
169 EFI_STATUS Status;\r
170 VARIABLE_POINTER_TRACK Variable;\r
7aaf2fd6 171 VARIABLE_POINTER_TRACK PkVariable;\r
0c18794e 172 UINT8 VarValue;\r
173 UINT32 VarAttr;\r
174 UINT8 *Data;\r
175 UINTN DataSize;\r
176 UINTN CtxSize;\r
beda2356 177 UINT8 SecureBootMode;\r
178 UINT8 SecureBootEnable;\r
ecc722ad 179 UINT8 CustomMode;\r
ed47ae02 180 UINT32 ListSize;\r
2d3fb919 181\r
0c18794e 182 //\r
183 // Initialize hash context.\r
184 //\r
185 CtxSize = Sha256GetContextSize ();\r
186 mHashCtx = AllocateRuntimePool (CtxSize);\r
187 if (mHashCtx == NULL) {\r
188 return EFI_OUT_OF_RESOURCES;\r
189 }\r
190\r
191 //\r
192 // Reserved runtime buffer for "Append" operation in virtual mode.\r
193 //\r
2d3fb919 194 mStorageArea = AllocateRuntimePool (PcdGet32 (PcdMaxVariableSize));\r
0c18794e 195 if (mStorageArea == NULL) {\r
196 return EFI_OUT_OF_RESOURCES;\r
197 }\r
198\r
199 //\r
2d3fb919 200 // Prepare runtime buffer for serialized data of time-based authenticated\r
201 // Variable, i.e. (VariableName, VendorGuid, Attributes, TimeStamp, Data).\r
202 //\r
203 mSerializationRuntimeBuffer = AllocateRuntimePool (PcdGet32 (PcdMaxVariableSize) + sizeof (EFI_GUID) + sizeof (UINT32) + sizeof (EFI_TIME));\r
204 if (mSerializationRuntimeBuffer == NULL) {\r
205 return EFI_OUT_OF_RESOURCES;\r
206 }\r
207\r
208 //\r
209 // Check "AuthVarKeyDatabase" variable's existence.\r
210 // If it doesn't exist, create a new one with initial value of 0 and EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.\r
0c18794e 211 //\r
212 Status = FindVariable (\r
2d3fb919 213 AUTHVAR_KEYDB_NAME,\r
214 &gEfiAuthenticatedVariableGuid,\r
215 &Variable,\r
ecc722ad 216 &mVariableModuleGlobal->VariableGlobal,\r
217 FALSE\r
0c18794e 218 );\r
219\r
220 if (Variable.CurrPtr == NULL) {\r
221 VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;\r
222 VarValue = 0;\r
223 mPubKeyNumber = 0;\r
224 Status = UpdateVariable (\r
225 AUTHVAR_KEYDB_NAME,\r
226 &gEfiAuthenticatedVariableGuid,\r
227 &VarValue,\r
228 sizeof(UINT8),\r
229 VarAttr,\r
230 0,\r
231 0,\r
232 &Variable,\r
233 NULL\r
234 );\r
235 if (EFI_ERROR (Status)) {\r
236 return Status;\r
237 }\r
238 } else {\r
239 //\r
240 // Load database in global variable for cache.\r
241 //\r
242 DataSize = DataSizeOfVariable (Variable.CurrPtr);\r
243 Data = GetVariableDataPtr (Variable.CurrPtr);\r
244 ASSERT ((DataSize != 0) && (Data != NULL));\r
245 CopyMem (mPubKeyStore, (UINT8 *) Data, DataSize);\r
246 mPubKeyNumber = (UINT32) (DataSize / EFI_CERT_TYPE_RSA2048_SIZE);\r
247 }\r
7aaf2fd6 248\r
ecc722ad 249 FindVariable (EFI_PLATFORM_KEY_NAME, &gEfiGlobalVariableGuid, &PkVariable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
7aaf2fd6 250 if (PkVariable.CurrPtr == NULL) {\r
251 DEBUG ((EFI_D_INFO, "Variable %s does not exist.\n", EFI_PLATFORM_KEY_NAME));\r
252 } else {\r
253 DEBUG ((EFI_D_INFO, "Variable %s exists.\n", EFI_PLATFORM_KEY_NAME));\r
254 }\r
255 \r
0c18794e 256 //\r
2d3fb919 257 // Check "SetupMode" variable's existence.\r
0c18794e 258 // If it doesn't exist, check PK database's existence to determine the value.\r
2d3fb919 259 // Then create a new one with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.\r
0c18794e 260 //\r
261 Status = FindVariable (\r
2d3fb919 262 EFI_SETUP_MODE_NAME,\r
263 &gEfiGlobalVariableGuid,\r
264 &Variable,\r
ecc722ad 265 &mVariableModuleGlobal->VariableGlobal,\r
266 FALSE\r
0c18794e 267 );\r
268\r
269 if (Variable.CurrPtr == NULL) {\r
7aaf2fd6 270 if (PkVariable.CurrPtr == NULL) {\r
0c18794e 271 mPlatformMode = SETUP_MODE;\r
272 } else {\r
273 mPlatformMode = USER_MODE;\r
274 }\r
275\r
2d3fb919 276 VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;\r
0c18794e 277 Status = UpdateVariable (\r
278 EFI_SETUP_MODE_NAME,\r
279 &gEfiGlobalVariableGuid,\r
280 &mPlatformMode,\r
281 sizeof(UINT8),\r
282 VarAttr,\r
283 0,\r
284 0,\r
285 &Variable,\r
286 NULL\r
287 );\r
288 if (EFI_ERROR (Status)) {\r
289 return Status;\r
290 }\r
291 } else {\r
292 mPlatformMode = *(GetVariableDataPtr (Variable.CurrPtr));\r
293 }\r
294 //\r
2d3fb919 295 // Check "SignatureSupport" variable's existence.\r
296 // If it doesn't exist, then create a new one with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.\r
0c18794e 297 //\r
298 Status = FindVariable (\r
2d3fb919 299 EFI_SIGNATURE_SUPPORT_NAME,\r
300 &gEfiGlobalVariableGuid,\r
301 &Variable,\r
ecc722ad 302 &mVariableModuleGlobal->VariableGlobal,\r
303 FALSE\r
0c18794e 304 );\r
305\r
306 if (Variable.CurrPtr == NULL) {\r
307 VarAttr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;\r
308 Status = UpdateVariable (\r
309 EFI_SIGNATURE_SUPPORT_NAME,\r
310 &gEfiGlobalVariableGuid,\r
311 mSignatureSupport,\r
ae09f979 312 sizeof(mSignatureSupport),\r
0c18794e 313 VarAttr,\r
314 0,\r
315 0,\r
316 &Variable,\r
317 NULL\r
318 );\r
319 }\r
beda2356 320\r
321 //\r
322 // If "SecureBootEnable" variable exists, then update "SecureBoot" variable.\r
2d3fb919 323 // If "SecureBootEnable" variable is SECURE_BOOT_ENABLE and in USER_MODE, Set "SecureBoot" variable to SECURE_BOOT_MODE_ENABLE.\r
beda2356 324 // If "SecureBootEnable" variable is SECURE_BOOT_DISABLE, Set "SecureBoot" variable to SECURE_BOOT_MODE_DISABLE.\r
325 //\r
8f8ca22e 326 SecureBootEnable = SECURE_BOOT_DISABLE;\r
ecc722ad 327 FindVariable (EFI_SECURE_BOOT_ENABLE_NAME, &gEfiSecureBootEnableDisableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
beda2356 328 if (Variable.CurrPtr != NULL) {\r
329 SecureBootEnable = *(GetVariableDataPtr (Variable.CurrPtr));\r
2d3fb919 330 } else if (mPlatformMode == USER_MODE) {\r
331 //\r
332 // "SecureBootEnable" not exist, initialize it in USER_MODE.\r
333 //\r
8f8ca22e 334 SecureBootEnable = SECURE_BOOT_ENABLE;\r
beda2356 335 Status = UpdateVariable (\r
2d3fb919 336 EFI_SECURE_BOOT_ENABLE_NAME,\r
337 &gEfiSecureBootEnableDisableGuid,\r
338 &SecureBootEnable,\r
339 sizeof (UINT8),\r
340 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
341 0,\r
342 0,\r
beda2356 343 &Variable,\r
344 NULL\r
345 );\r
346 if (EFI_ERROR (Status)) {\r
347 return Status;\r
348 }\r
349 }\r
350\r
2d3fb919 351 if (SecureBootEnable == SECURE_BOOT_ENABLE && mPlatformMode == USER_MODE) {\r
352 SecureBootMode = SECURE_BOOT_MODE_ENABLE;\r
353 } else {\r
354 SecureBootMode = SECURE_BOOT_MODE_DISABLE;\r
355 }\r
ecc722ad 356 FindVariable (EFI_SECURE_BOOT_MODE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
2d3fb919 357 Status = UpdateVariable (\r
358 EFI_SECURE_BOOT_MODE_NAME,\r
359 &gEfiGlobalVariableGuid,\r
360 &SecureBootMode,\r
361 sizeof (UINT8),\r
362 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS,\r
363 0,\r
364 0,\r
365 &Variable,\r
366 NULL\r
367 );\r
368 if (EFI_ERROR (Status)) {\r
369 return Status;\r
370 }\r
371\r
7aaf2fd6 372 DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_SETUP_MODE_NAME, mPlatformMode));\r
373 DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_SECURE_BOOT_MODE_NAME, SecureBootMode));\r
374 DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_SECURE_BOOT_ENABLE_NAME, SecureBootEnable));\r
375\r
0c18794e 376 //\r
ecc722ad 377 // Check "CustomMode" variable's existence.\r
0c18794e 378 //\r
ecc722ad 379 FindVariable (EFI_CUSTOM_MODE_NAME, &gEfiCustomModeEnableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
380 if (Variable.CurrPtr != NULL) {\r
381 CustomMode = *(GetVariableDataPtr (Variable.CurrPtr));\r
382 } else {\r
0c18794e 383 //\r
ecc722ad 384 // "CustomMode" not exist, initialize it in STANDARD_SECURE_BOOT_MODE.\r
0c18794e 385 //\r
ecc722ad 386 CustomMode = STANDARD_SECURE_BOOT_MODE;\r
387 Status = UpdateVariable (\r
388 EFI_CUSTOM_MODE_NAME,\r
389 &gEfiCustomModeEnableGuid,\r
390 &CustomMode,\r
391 sizeof (UINT8),\r
392 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
393 0,\r
394 0,\r
395 &Variable,\r
396 NULL\r
397 );\r
2d3fb919 398 if (EFI_ERROR (Status)) {\r
399 return Status;\r
0c18794e 400 }\r
0c18794e 401 }\r
ecc722ad 402 \r
403 DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_CUSTOM_MODE_NAME, CustomMode));\r
2d3fb919 404\r
ed47ae02 405 //\r
406 // Check "certdb" variable's existence.\r
407 // If it doesn't exist, then create a new one with \r
408 // EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set.\r
409 //\r
410 Status = FindVariable (\r
411 EFI_CERT_DB_NAME,\r
412 &gEfiCertDbGuid,\r
413 &Variable,\r
414 &mVariableModuleGlobal->VariableGlobal,\r
415 FALSE\r
416 );\r
417\r
418 if (Variable.CurrPtr == NULL) {\r
419 VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;\r
420 ListSize = 0;\r
421 Status = UpdateVariable (\r
422 EFI_CERT_DB_NAME,\r
423 &gEfiCertDbGuid,\r
424 &ListSize,\r
425 sizeof (UINT32),\r
426 VarAttr,\r
427 0,\r
428 0,\r
429 &Variable,\r
430 NULL\r
431 );\r
432\r
433 } \r
434\r
0c18794e 435 return Status;\r
436}\r
437\r
438/**\r
439 Add public key in store and return its index.\r
440\r
441 @param[in] PubKey Input pointer to Public Key data\r
442\r
443 @return Index of new added item\r
444\r
445**/\r
446UINT32\r
447AddPubKeyInStore (\r
448 IN UINT8 *PubKey\r
449 )\r
450{\r
451 EFI_STATUS Status;\r
452 BOOLEAN IsFound;\r
453 UINT32 Index;\r
454 VARIABLE_POINTER_TRACK Variable;\r
455 UINT8 *Ptr;\r
456\r
457 if (PubKey == NULL) {\r
458 return 0;\r
459 }\r
460\r
461 Status = FindVariable (\r
462 AUTHVAR_KEYDB_NAME,\r
463 &gEfiAuthenticatedVariableGuid,\r
464 &Variable,\r
ecc722ad 465 &mVariableModuleGlobal->VariableGlobal,\r
466 FALSE\r
0c18794e 467 );\r
468 ASSERT_EFI_ERROR (Status);\r
469 //\r
470 // Check whether the public key entry does exist.\r
471 //\r
472 IsFound = FALSE;\r
473 for (Ptr = mPubKeyStore, Index = 1; Index <= mPubKeyNumber; Index++) {\r
474 if (CompareMem (Ptr, PubKey, EFI_CERT_TYPE_RSA2048_SIZE) == 0) {\r
475 IsFound = TRUE;\r
476 break;\r
477 }\r
478 Ptr += EFI_CERT_TYPE_RSA2048_SIZE;\r
479 }\r
480\r
481 if (!IsFound) {\r
482 //\r
483 // Add public key in database.\r
484 //\r
485 if (mPubKeyNumber == MAX_KEY_NUM) {\r
486 //\r
487 // Notes: Database is full, need enhancement here, currently just return 0.\r
488 //\r
489 return 0;\r
490 }\r
491\r
492 CopyMem (mPubKeyStore + mPubKeyNumber * EFI_CERT_TYPE_RSA2048_SIZE, PubKey, EFI_CERT_TYPE_RSA2048_SIZE);\r
493 Index = ++mPubKeyNumber;\r
494 //\r
495 // Update public key database variable.\r
496 //\r
497 Status = UpdateVariable (\r
498 AUTHVAR_KEYDB_NAME,\r
499 &gEfiAuthenticatedVariableGuid,\r
500 mPubKeyStore,\r
501 mPubKeyNumber * EFI_CERT_TYPE_RSA2048_SIZE,\r
502 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS,\r
503 0,\r
504 0,\r
505 &Variable,\r
506 NULL\r
507 );\r
508 ASSERT_EFI_ERROR (Status);\r
509 }\r
510\r
511 return Index;\r
512}\r
513\r
514/**\r
85560919 515 Verify data payload with AuthInfo in EFI_CERT_TYPE_RSA2048_SHA256_GUID type.\r
0c18794e 516 Follow the steps in UEFI2.2.\r
517\r
dc204d5a
JY
518 Caution: This function may receive untrusted input.\r
519 This function may be invoked in SMM mode, and datasize and data are external input.\r
520 This function will do basic validation, before parse the data.\r
521 This function will parse the authentication carefully to avoid security issues, like\r
522 buffer overflow, integer overflow.\r
523\r
0c18794e 524 @param[in] Data Pointer to data with AuthInfo.\r
525 @param[in] DataSize Size of Data.\r
526 @param[in] PubKey Public key used for verification.\r
527\r
2d3fb919 528 @retval EFI_INVALID_PARAMETER Invalid parameter.\r
0c18794e 529 @retval EFI_SECURITY_VIOLATION If authentication failed.\r
2d3fb919 530 @retval EFI_SUCCESS Authentication successful.\r
0c18794e 531\r
532**/\r
533EFI_STATUS\r
534VerifyCounterBasedPayload (\r
535 IN UINT8 *Data,\r
536 IN UINTN DataSize,\r
537 IN UINT8 *PubKey\r
538 )\r
539{\r
540 BOOLEAN Status;\r
541 EFI_VARIABLE_AUTHENTICATION *CertData;\r
542 EFI_CERT_BLOCK_RSA_2048_SHA256 *CertBlock;\r
543 UINT8 Digest[SHA256_DIGEST_SIZE];\r
544 VOID *Rsa;\r
545\r
546 Rsa = NULL;\r
547 CertData = NULL;\r
548 CertBlock = NULL;\r
549\r
550 if (Data == NULL || PubKey == NULL) {\r
551 return EFI_INVALID_PARAMETER;\r
552 }\r
553\r
554 CertData = (EFI_VARIABLE_AUTHENTICATION *) Data;\r
555 CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData);\r
556\r
557 //\r
558 // wCertificateType should be WIN_CERT_TYPE_EFI_GUID.\r
85560919 559 // Cert type should be EFI_CERT_TYPE_RSA2048_SHA256_GUID.\r
0c18794e 560 //\r
561 if ((CertData->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID) ||\r
85560919 562 !CompareGuid (&CertData->AuthInfo.CertType, &gEfiCertTypeRsa2048Sha256Guid)\r
0c18794e 563 ) {\r
564 //\r
565 // Invalid AuthInfo type, return EFI_SECURITY_VIOLATION.\r
566 //\r
567 return EFI_SECURITY_VIOLATION;\r
568 }\r
569 //\r
570 // Hash data payload with SHA256.\r
571 //\r
572 ZeroMem (Digest, SHA256_DIGEST_SIZE);\r
573 Status = Sha256Init (mHashCtx);\r
574 if (!Status) {\r
575 goto Done;\r
576 }\r
577 Status = Sha256Update (mHashCtx, Data + AUTHINFO_SIZE, (UINTN) (DataSize - AUTHINFO_SIZE));\r
578 if (!Status) {\r
579 goto Done;\r
580 }\r
581 //\r
582 // Hash Monotonic Count.\r
583 //\r
584 Status = Sha256Update (mHashCtx, &CertData->MonotonicCount, sizeof (UINT64));\r
585 if (!Status) {\r
586 goto Done;\r
587 }\r
588 Status = Sha256Final (mHashCtx, Digest);\r
589 if (!Status) {\r
590 goto Done;\r
591 }\r
592 //\r
593 // Generate & Initialize RSA Context.\r
594 //\r
595 Rsa = RsaNew ();\r
596 ASSERT (Rsa != NULL);\r
2d3fb919 597 //\r
0c18794e 598 // Set RSA Key Components.\r
599 // NOTE: Only N and E are needed to be set as RSA public key for signature verification.\r
600 //\r
601 Status = RsaSetKey (Rsa, RsaKeyN, PubKey, EFI_CERT_TYPE_RSA2048_SIZE);\r
602 if (!Status) {\r
603 goto Done;\r
604 }\r
605 Status = RsaSetKey (Rsa, RsaKeyE, mRsaE, sizeof (mRsaE));\r
606 if (!Status) {\r
607 goto Done;\r
608 }\r
609 //\r
610 // Verify the signature.\r
611 //\r
612 Status = RsaPkcs1Verify (\r
2d3fb919 613 Rsa,\r
614 Digest,\r
615 SHA256_DIGEST_SIZE,\r
616 CertBlock->Signature,\r
0c18794e 617 EFI_CERT_TYPE_RSA2048_SHA256_SIZE\r
618 );\r
619\r
620Done:\r
621 if (Rsa != NULL) {\r
622 RsaFree (Rsa);\r
623 }\r
624 if (Status) {\r
625 return EFI_SUCCESS;\r
626 } else {\r
627 return EFI_SECURITY_VIOLATION;\r
628 }\r
629}\r
630\r
0c18794e 631/**\r
632 Update platform mode.\r
633\r
634 @param[in] Mode SETUP_MODE or USER_MODE.\r
635\r
636 @return EFI_INVALID_PARAMETER Invalid parameter.\r
637 @return EFI_SUCCESS Update platform mode successfully.\r
638\r
639**/\r
640EFI_STATUS\r
641UpdatePlatformMode (\r
642 IN UINT32 Mode\r
643 )\r
644{\r
645 EFI_STATUS Status;\r
646 VARIABLE_POINTER_TRACK Variable;\r
647 UINT32 VarAttr;\r
648 UINT8 SecureBootMode;\r
beda2356 649 UINT8 SecureBootEnable;\r
650 UINTN VariableDataSize;\r
2d3fb919 651\r
0c18794e 652 Status = FindVariable (\r
2d3fb919 653 EFI_SETUP_MODE_NAME,\r
654 &gEfiGlobalVariableGuid,\r
655 &Variable,\r
ecc722ad 656 &mVariableModuleGlobal->VariableGlobal,\r
657 FALSE\r
0c18794e 658 );\r
659 if (EFI_ERROR (Status)) {\r
660 return Status;\r
661 }\r
662\r
663 mPlatformMode = Mode;\r
2d3fb919 664 VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;\r
0c18794e 665 Status = UpdateVariable (\r
666 EFI_SETUP_MODE_NAME,\r
667 &gEfiGlobalVariableGuid,\r
668 &mPlatformMode,\r
669 sizeof(UINT8),\r
670 VarAttr,\r
671 0,\r
672 0,\r
673 &Variable,\r
674 NULL\r
675 );\r
676 if (EFI_ERROR (Status)) {\r
677 return Status;\r
678 }\r
679\r
2d3fb919 680 if (AtRuntime ()) {\r
681 //\r
682 // SecureBoot Variable indicates whether the platform firmware is operating\r
683 // in Secure boot mode (1) or not (0), so we should not change SecureBoot\r
684 // Variable in runtime.\r
685 //\r
686 return Status;\r
687 }\r
688\r
0c18794e 689 //\r
690 // Check "SecureBoot" variable's existence.\r
691 // If it doesn't exist, firmware has no capability to perform driver signing verification,\r
692 // then set "SecureBoot" to 0.\r
693 //\r
694 Status = FindVariable (\r
2d3fb919 695 EFI_SECURE_BOOT_MODE_NAME,\r
696 &gEfiGlobalVariableGuid,\r
697 &Variable,\r
ecc722ad 698 &mVariableModuleGlobal->VariableGlobal,\r
699 FALSE\r
0c18794e 700 );\r
701 //\r
702 // If "SecureBoot" variable exists, then check "SetupMode" variable update.\r
703 // If "SetupMode" variable is USER_MODE, "SecureBoot" variable is set to 1.\r
704 // If "SetupMode" variable is SETUP_MODE, "SecureBoot" variable is set to 0.\r
705 //\r
706 if (Variable.CurrPtr == NULL) {\r
707 SecureBootMode = SECURE_BOOT_MODE_DISABLE;\r
708 } else {\r
709 if (mPlatformMode == USER_MODE) {\r
710 SecureBootMode = SECURE_BOOT_MODE_ENABLE;\r
711 } else if (mPlatformMode == SETUP_MODE) {\r
712 SecureBootMode = SECURE_BOOT_MODE_DISABLE;\r
713 } else {\r
714 return EFI_NOT_FOUND;\r
715 }\r
716 }\r
717\r
2d3fb919 718 VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;\r
beda2356 719 Status = UpdateVariable (\r
0c18794e 720 EFI_SECURE_BOOT_MODE_NAME,\r
721 &gEfiGlobalVariableGuid,\r
722 &SecureBootMode,\r
723 sizeof(UINT8),\r
724 VarAttr,\r
725 0,\r
726 0,\r
727 &Variable,\r
728 NULL\r
729 );\r
beda2356 730 if (EFI_ERROR (Status)) {\r
731 return Status;\r
732 }\r
733\r
734 //\r
735 // Check "SecureBootEnable" variable's existence. It can enable/disable secure boot feature.\r
736 //\r
737 Status = FindVariable (\r
2d3fb919 738 EFI_SECURE_BOOT_ENABLE_NAME,\r
739 &gEfiSecureBootEnableDisableGuid,\r
740 &Variable,\r
ecc722ad 741 &mVariableModuleGlobal->VariableGlobal,\r
742 FALSE\r
beda2356 743 );\r
2d3fb919 744\r
beda2356 745 if (SecureBootMode == SECURE_BOOT_MODE_ENABLE) {\r
746 //\r
747 // Create the "SecureBootEnable" variable as secure boot is enabled.\r
748 //\r
749 SecureBootEnable = SECURE_BOOT_ENABLE;\r
750 VariableDataSize = sizeof (SecureBootEnable);\r
751 } else {\r
752 //\r
2d3fb919 753 // Delete the "SecureBootEnable" variable if this variable exist as "SecureBoot"\r
beda2356 754 // variable is not in secure boot state.\r
755 //\r
756 if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {\r
757 return EFI_SUCCESS;\r
758 }\r
759 SecureBootEnable = SECURE_BOOT_DISABLE;\r
760 VariableDataSize = 0;\r
761 }\r
2d3fb919 762\r
beda2356 763 Status = UpdateVariable (\r
2d3fb919 764 EFI_SECURE_BOOT_ENABLE_NAME,\r
765 &gEfiSecureBootEnableDisableGuid,\r
766 &SecureBootEnable,\r
767 VariableDataSize,\r
768 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
769 0,\r
770 0,\r
beda2356 771 &Variable,\r
772 NULL\r
773 );\r
774 return Status;\r
0c18794e 775}\r
776\r
d912bad7 777/**\r
778 Check input data form to make sure it is a valid EFI_SIGNATURE_LIST for PK/KEK variable.\r
779\r
780 @param[in] VariableName Name of Variable to be check.\r
781 @param[in] VendorGuid Variable vendor GUID.\r
782 @param[in] Data Point to the variable data to be checked.\r
783 @param[in] DataSize Size of Data.\r
784\r
785 @return EFI_INVALID_PARAMETER Invalid signature list format.\r
786 @return EFI_SUCCESS Passed signature list format check successfully.\r
787 \r
788**/\r
789EFI_STATUS\r
790CheckSignatureListFormat(\r
791 IN CHAR16 *VariableName,\r
792 IN EFI_GUID *VendorGuid,\r
793 IN VOID *Data,\r
794 IN UINTN DataSize\r
795 )\r
796{\r
797 EFI_SIGNATURE_LIST *SigList;\r
798 UINTN SigDataSize;\r
799 UINT32 Index;\r
800 UINT32 SigCount;\r
801 BOOLEAN IsPk;\r
802\r
803 if (DataSize == 0) {\r
804 return EFI_SUCCESS;\r
805 }\r
806\r
807 ASSERT (VariableName != NULL && VendorGuid != NULL && Data != NULL);\r
808\r
809 if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_PLATFORM_KEY_NAME) == 0)){\r
810 IsPk = TRUE;\r
811 } else if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_KEY_EXCHANGE_KEY_NAME) == 0)) {\r
812 IsPk = FALSE;\r
813 } else {\r
814 return EFI_SUCCESS;\r
815 }\r
816\r
817 SigCount = 0;\r
818 SigList = (EFI_SIGNATURE_LIST *) Data;\r
819 SigDataSize = DataSize;\r
820\r
821 //\r
822 // Walk throuth the input signature list and check the data format.\r
823 // If any signature is incorrectly formed, the whole check will fail.\r
824 //\r
825 while ((SigDataSize > 0) && (SigDataSize >= SigList->SignatureListSize)) {\r
826 for (Index = 0; Index < (sizeof (mSupportSigItem) / sizeof (EFI_SIGNATURE_ITEM)); Index++ ) {\r
827 if (CompareGuid (&SigList->SignatureType, &mSupportSigItem[Index].SigType)) {\r
828 //\r
829 // The value of SignatureSize should always be 16 (size of SignatureOwner \r
830 // component) add the data length according to signature type.\r
831 //\r
832 if (mSupportSigItem[Index].SigDataSize != ((UINT32) ~0) && \r
833 (SigList->SignatureSize - sizeof (EFI_GUID)) != mSupportSigItem[Index].SigDataSize) {\r
834 return EFI_INVALID_PARAMETER;\r
835 }\r
836 if (mSupportSigItem[Index].SigHeaderSize != ((UINTN) ~0) &&\r
837 SigList->SignatureHeaderSize != mSupportSigItem[Index].SigHeaderSize) {\r
838 return EFI_INVALID_PARAMETER;\r
839 }\r
840 break;\r
841 }\r
842 }\r
843\r
844 if (Index == (sizeof (mSupportSigItem) / sizeof (EFI_SIGNATURE_ITEM))) {\r
845 //\r
846 // Undefined signature type.\r
847 //\r
848 return EFI_INVALID_PARAMETER;\r
849 }\r
850\r
851 if ((SigList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - SigList->SignatureHeaderSize) % SigList->SignatureSize != 0) {\r
852 return EFI_INVALID_PARAMETER;\r
853 }\r
854 SigCount += (SigList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - SigList->SignatureHeaderSize) / SigList->SignatureSize;\r
855 \r
856 SigDataSize -= SigList->SignatureListSize;\r
857 SigList = (EFI_SIGNATURE_LIST *) ((UINT8 *) SigList + SigList->SignatureListSize);\r
858 }\r
859\r
860 if (((UINTN) SigList - (UINTN) Data) != DataSize) {\r
861 return EFI_INVALID_PARAMETER;\r
862 }\r
863\r
864 if (IsPk && SigCount > 1) {\r
865 return EFI_INVALID_PARAMETER;\r
866 }\r
867\r
868 return EFI_SUCCESS;\r
869}\r
870\r
0c18794e 871/**\r
872 Process variable with platform key for verification.\r
873\r
dc204d5a
JY
874 Caution: This function may receive untrusted input.\r
875 This function may be invoked in SMM mode, and datasize and data are external input.\r
876 This function will do basic validation, before parse the data.\r
877 This function will parse the authentication carefully to avoid security issues, like\r
878 buffer overflow, integer overflow.\r
879 This function will check attribute carefully to avoid authentication bypass.\r
880\r
0c18794e 881 @param[in] VariableName Name of Variable to be found.\r
882 @param[in] VendorGuid Variable vendor GUID.\r
883 @param[in] Data Data pointer.\r
884 @param[in] DataSize Size of Data found. If size is less than the\r
885 data, this value contains the required size.\r
886 @param[in] Variable The variable information which is used to keep track of variable usage.\r
887 @param[in] Attributes Attribute value of the variable\r
888 @param[in] IsPk Indicate whether it is to process pk.\r
889\r
890 @return EFI_INVALID_PARAMETER Invalid parameter.\r
2d3fb919 891 @return EFI_SECURITY_VIOLATION The variable does NOT pass the validation.\r
892 check carried out by the firmware.\r
0c18794e 893 @return EFI_SUCCESS Variable passed validation successfully.\r
894\r
895**/\r
896EFI_STATUS\r
897ProcessVarWithPk (\r
898 IN CHAR16 *VariableName,\r
899 IN EFI_GUID *VendorGuid,\r
900 IN VOID *Data,\r
901 IN UINTN DataSize,\r
902 IN VARIABLE_POINTER_TRACK *Variable,\r
903 IN UINT32 Attributes OPTIONAL,\r
904 IN BOOLEAN IsPk\r
905 )\r
906{\r
907 EFI_STATUS Status;\r
0c18794e 908 BOOLEAN Del;\r
2d3fb919 909 UINT8 *Payload;\r
910 UINTN PayloadSize;\r
0c18794e 911\r
8c1babfd 912 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0 || \r
913 (Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == 0) {\r
0c18794e 914 //\r
8c1babfd 915 // PK and KEK should set EFI_VARIABLE_NON_VOLATILE attribute and should be a time-based\r
916 // authenticated variable.\r
0c18794e 917 //\r
918 return EFI_INVALID_PARAMETER;\r
919 }\r
920\r
785d84ea 921 Del = FALSE;\r
922 if ((InCustomMode() && UserPhysicalPresent()) || (mPlatformMode == SETUP_MODE && !IsPk)) {\r
8c1babfd 923 Payload = (UINT8 *) Data + AUTHINFO2_SIZE (Data);\r
924 PayloadSize = DataSize - AUTHINFO2_SIZE (Data);\r
785d84ea 925 if (PayloadSize == 0) {\r
926 Del = TRUE;\r
927 }\r
2d3fb919 928\r
d912bad7 929 Status = CheckSignatureListFormat(VariableName, VendorGuid, Payload, PayloadSize);\r
930 if (EFI_ERROR (Status)) {\r
931 return Status;\r
932 }\r
933\r
2d3fb919 934 Status = UpdateVariable (\r
935 VariableName,\r
936 VendorGuid,\r
937 Payload,\r
938 PayloadSize,\r
939 Attributes,\r
940 0,\r
8c1babfd 941 0,\r
2d3fb919 942 Variable,\r
8c1babfd 943 &((EFI_VARIABLE_AUTHENTICATION_2 *) Data)->TimeStamp\r
2d3fb919 944 );\r
785d84ea 945 } else if (mPlatformMode == USER_MODE) {\r
946 //\r
947 // Verify against X509 Cert in PK database.\r
948 //\r
949 Status = VerifyTimeBasedPayload (\r
950 VariableName,\r
951 VendorGuid,\r
952 Data,\r
953 DataSize,\r
954 Variable,\r
955 Attributes,\r
956 AuthVarTypePk,\r
957 &Del\r
958 );\r
959 } else {\r
960 //\r
961 // Verify against the certificate in data payload.\r
962 //\r
963 Status = VerifyTimeBasedPayload (\r
964 VariableName,\r
965 VendorGuid,\r
966 Data,\r
967 DataSize,\r
968 Variable,\r
969 Attributes,\r
970 AuthVarTypePayload,\r
971 &Del\r
972 );\r
973 }\r
ecc722ad 974\r
785d84ea 975 if (!EFI_ERROR(Status) && IsPk) {\r
976 if (mPlatformMode == SETUP_MODE && !Del) {\r
977 //\r
978 // If enroll PK in setup mode, need change to user mode.\r
979 //\r
980 Status = UpdatePlatformMode (USER_MODE);\r
981 } else if (mPlatformMode == USER_MODE && Del){\r
982 //\r
983 // If delete PK in user mode, need change to setup mode.\r
984 //\r
985 Status = UpdatePlatformMode (SETUP_MODE);\r
986 }\r
0c18794e 987 }\r
988\r
989 return Status;\r
990}\r
991\r
992/**\r
993 Process variable with key exchange key for verification.\r
994\r
dc204d5a
JY
995 Caution: This function may receive untrusted input.\r
996 This function may be invoked in SMM mode, and datasize and data are external input.\r
997 This function will do basic validation, before parse the data.\r
998 This function will parse the authentication carefully to avoid security issues, like\r
999 buffer overflow, integer overflow.\r
1000 This function will check attribute carefully to avoid authentication bypass.\r
1001\r
0c18794e 1002 @param[in] VariableName Name of Variable to be found.\r
1003 @param[in] VendorGuid Variable vendor GUID.\r
1004 @param[in] Data Data pointer.\r
1005 @param[in] DataSize Size of Data found. If size is less than the\r
1006 data, this value contains the required size.\r
1007 @param[in] Variable The variable information which is used to keep track of variable usage.\r
1008 @param[in] Attributes Attribute value of the variable.\r
1009\r
1010 @return EFI_INVALID_PARAMETER Invalid parameter.\r
2d3fb919 1011 @return EFI_SECURITY_VIOLATION The variable does NOT pass the validation\r
1012 check carried out by the firmware.\r
0c18794e 1013 @return EFI_SUCCESS Variable pass validation successfully.\r
1014\r
1015**/\r
1016EFI_STATUS\r
1017ProcessVarWithKek (\r
1018 IN CHAR16 *VariableName,\r
1019 IN EFI_GUID *VendorGuid,\r
1020 IN VOID *Data,\r
1021 IN UINTN DataSize,\r
1022 IN VARIABLE_POINTER_TRACK *Variable,\r
1023 IN UINT32 Attributes OPTIONAL\r
1024 )\r
1025{\r
1026 EFI_STATUS Status;\r
2d3fb919 1027 UINT8 *Payload;\r
1028 UINTN PayloadSize;\r
ecc722ad 1029\r
8c1babfd 1030 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0 ||\r
1031 (Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == 0) {\r
ecc722ad 1032 //\r
8c1babfd 1033 // DB and DBX should set EFI_VARIABLE_NON_VOLATILE attribute and should be a time-based\r
1034 // authenticated variable.\r
ecc722ad 1035 //\r
1036 return EFI_INVALID_PARAMETER;\r
1037 }\r
0c18794e 1038\r
ecc722ad 1039 Status = EFI_SUCCESS;\r
1040 if (mPlatformMode == USER_MODE && !(InCustomMode() && UserPhysicalPresent())) {\r
8c1babfd 1041 //\r
1042 // Time-based, verify against X509 Cert KEK.\r
1043 //\r
1044 return VerifyTimeBasedPayload (\r
1045 VariableName,\r
1046 VendorGuid,\r
1047 Data,\r
1048 DataSize,\r
1049 Variable,\r
1050 Attributes,\r
1051 AuthVarTypeKek,\r
1052 NULL\r
1053 );\r
0c18794e 1054 } else {\r
1055 //\r
ecc722ad 1056 // If in setup mode or custom secure boot mode, no authentication needed.\r
0c18794e 1057 //\r
8c1babfd 1058 Payload = (UINT8 *) Data + AUTHINFO2_SIZE (Data);\r
1059 PayloadSize = DataSize - AUTHINFO2_SIZE (Data);\r
2d3fb919 1060\r
0c18794e 1061 Status = UpdateVariable (\r
2d3fb919 1062 VariableName,\r
1063 VendorGuid,\r
1064 Payload,\r
1065 PayloadSize,\r
1066 Attributes,\r
1067 0,\r
8c1babfd 1068 0,\r
0c18794e 1069 Variable,\r
8c1babfd 1070 &((EFI_VARIABLE_AUTHENTICATION_2 *) Data)->TimeStamp\r
0c18794e 1071 );\r
1072 }\r
1073\r
1074 return Status;\r
1075}\r
1076\r
1077/**\r
1078 Process variable with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS/EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set\r
1079\r
dc204d5a
JY
1080 Caution: This function may receive untrusted input.\r
1081 This function may be invoked in SMM mode, and datasize and data are external input.\r
1082 This function will do basic validation, before parse the data.\r
1083 This function will parse the authentication carefully to avoid security issues, like\r
1084 buffer overflow, integer overflow.\r
1085 This function will check attribute carefully to avoid authentication bypass.\r
1086\r
0c18794e 1087 @param[in] VariableName Name of Variable to be found.\r
1088 @param[in] VendorGuid Variable vendor GUID.\r
1089\r
1090 @param[in] Data Data pointer.\r
1091 @param[in] DataSize Size of Data found. If size is less than the\r
1092 data, this value contains the required size.\r
1093 @param[in] Variable The variable information which is used to keep track of variable usage.\r
1094 @param[in] Attributes Attribute value of the variable.\r
1095\r
1096 @return EFI_INVALID_PARAMETER Invalid parameter.\r
1097 @return EFI_WRITE_PROTECTED Variable is write-protected and needs authentication with\r
1098 EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.\r
1099 @return EFI_SECURITY_VIOLATION The variable is with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS\r
2d3fb919 1100 set, but the AuthInfo does NOT pass the validation\r
1101 check carried out by the firmware.\r
0c18794e 1102 @return EFI_SUCCESS Variable is not write-protected or pass validation successfully.\r
1103\r
1104**/\r
1105EFI_STATUS\r
1106ProcessVariable (\r
1107 IN CHAR16 *VariableName,\r
1108 IN EFI_GUID *VendorGuid,\r
1109 IN VOID *Data,\r
1110 IN UINTN DataSize,\r
1111 IN VARIABLE_POINTER_TRACK *Variable,\r
1112 IN UINT32 Attributes\r
1113 )\r
1114{\r
1115 EFI_STATUS Status;\r
1116 BOOLEAN IsDeletion;\r
1117 BOOLEAN IsFirstTime;\r
1118 UINT8 *PubKey;\r
1119 EFI_VARIABLE_AUTHENTICATION *CertData;\r
1120 EFI_CERT_BLOCK_RSA_2048_SHA256 *CertBlock;\r
1121 UINT32 KeyIndex;\r
1122 UINT64 MonotonicCount;\r
1123\r
2d3fb919 1124 KeyIndex = 0;\r
0c18794e 1125 CertData = NULL;\r
1126 CertBlock = NULL;\r
1127 PubKey = NULL;\r
1128 IsDeletion = FALSE;\r
1129\r
ecc722ad 1130 if (NeedPhysicallyPresent(VariableName, VendorGuid) && !UserPhysicalPresent()) {\r
1131 //\r
1132 // This variable is protected, only physical present user could modify its value.\r
1133 //\r
1134 return EFI_SECURITY_VIOLATION;\r
1135 }\r
1136 \r
0c18794e 1137 //\r
1138 // Process Time-based Authenticated variable.\r
1139 //\r
1140 if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
ed47ae02 1141 return VerifyTimeBasedPayload (\r
1142 VariableName,\r
1143 VendorGuid,\r
1144 Data,\r
1145 DataSize,\r
1146 Variable,\r
1147 Attributes,\r
1148 AuthVarTypePriv,\r
1149 NULL\r
1150 );\r
0c18794e 1151 }\r
2d3fb919 1152\r
0c18794e 1153 //\r
1154 // Determine if first time SetVariable with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS.\r
1155 //\r
1156 if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
1157 //\r
1158 // Determine current operation type.\r
1159 //\r
1160 if (DataSize == AUTHINFO_SIZE) {\r
1161 IsDeletion = TRUE;\r
1162 }\r
1163 //\r
1164 // Determine whether this is the first time with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.\r
1165 //\r
1166 if (Variable->CurrPtr == NULL) {\r
1167 IsFirstTime = TRUE;\r
1168 } else if ((Variable->CurrPtr->Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == 0) {\r
1169 IsFirstTime = TRUE;\r
1170 } else {\r
1171 KeyIndex = Variable->CurrPtr->PubKeyIndex;\r
1172 IsFirstTime = FALSE;\r
1173 }\r
389c8779 1174 } else if ((Variable->CurrPtr != NULL) && \r
1175 ((Variable->CurrPtr->Attributes & (EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)) != 0)\r
1176 ) {\r
0c18794e 1177 //\r
1178 // If the variable is already write-protected, it always needs authentication before update.\r
1179 //\r
1180 return EFI_WRITE_PROTECTED;\r
1181 } else {\r
1182 //\r
1183 // If without EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, set and attributes collision.\r
1184 // That means it is not authenticated variable, just update variable as usual.\r
1185 //\r
1186 Status = UpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes, 0, 0, Variable, NULL);\r
1187 return Status;\r
1188 }\r
1189\r
1190 //\r
1191 // Get PubKey and check Monotonic Count value corresponding to the variable.\r
1192 //\r
1193 CertData = (EFI_VARIABLE_AUTHENTICATION *) Data;\r
1194 CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData);\r
1195 PubKey = CertBlock->PublicKey;\r
1196\r
1197 //\r
1198 // Update Monotonic Count value.\r
1199 //\r
1200 MonotonicCount = CertData->MonotonicCount;\r
1201\r
1202 if (!IsFirstTime) {\r
1203 //\r
1204 // Check input PubKey.\r
1205 //\r
1206 if (CompareMem (PubKey, mPubKeyStore + (KeyIndex - 1) * EFI_CERT_TYPE_RSA2048_SIZE, EFI_CERT_TYPE_RSA2048_SIZE) != 0) {\r
1207 return EFI_SECURITY_VIOLATION;\r
1208 }\r
1209 //\r
1210 // Compare the current monotonic count and ensure that it is greater than the last SetVariable\r
1211 // operation with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute set.\r
1212 //\r
1213 if (CertData->MonotonicCount <= Variable->CurrPtr->MonotonicCount) {\r
1214 //\r
1215 // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.\r
1216 //\r
1217 return EFI_SECURITY_VIOLATION;\r
1218 }\r
2d3fb919 1219 }\r
0c18794e 1220 //\r
1221 // Verify the certificate in Data payload.\r
1222 //\r
1223 Status = VerifyCounterBasedPayload (Data, DataSize, PubKey);\r
1224 if (EFI_ERROR (Status)) {\r
1225 return Status;\r
1226 }\r
2d3fb919 1227\r
0c18794e 1228 //\r
1229 // Now, the signature has been verified!\r
1230 //\r
1231 if (IsFirstTime && !IsDeletion) {\r
1232 //\r
1233 // Update public key database variable if need.\r
1234 //\r
1235 KeyIndex = AddPubKeyInStore (PubKey);\r
4e33001c 1236 if (KeyIndex == 0) {\r
1237 return EFI_SECURITY_VIOLATION;\r
1238 }\r
0c18794e 1239 }\r
1240\r
1241 //\r
1242 // Verification pass.\r
1243 //\r
1244 return UpdateVariable (VariableName, VendorGuid, (UINT8*)Data + AUTHINFO_SIZE, DataSize - AUTHINFO_SIZE, Attributes, KeyIndex, MonotonicCount, Variable, NULL);\r
1245}\r
1246\r
2d3fb919 1247/**\r
1248 Merge two buffers which formatted as EFI_SIGNATURE_LIST. Only the new EFI_SIGNATURE_DATA\r
1249 will be appended to the original EFI_SIGNATURE_LIST, duplicate EFI_SIGNATURE_DATA\r
1250 will be ignored.\r
1251\r
1252 @param[in, out] Data Pointer to original EFI_SIGNATURE_LIST.\r
1253 @param[in] DataSize Size of Data buffer.\r
1254 @param[in] NewData Pointer to new EFI_SIGNATURE_LIST to be appended.\r
1255 @param[in] NewDataSize Size of NewData buffer.\r
1256\r
1257 @return Size of the merged buffer.\r
1258\r
1259**/\r
1260UINTN\r
1261AppendSignatureList (\r
1262 IN OUT VOID *Data,\r
1263 IN UINTN DataSize,\r
1264 IN VOID *NewData,\r
1265 IN UINTN NewDataSize\r
1266 )\r
1267{\r
1268 EFI_SIGNATURE_LIST *CertList;\r
1269 EFI_SIGNATURE_DATA *Cert;\r
1270 UINTN CertCount;\r
1271 EFI_SIGNATURE_LIST *NewCertList;\r
1272 EFI_SIGNATURE_DATA *NewCert;\r
1273 UINTN NewCertCount;\r
1274 UINTN Index;\r
1275 UINTN Index2;\r
1276 UINTN Size;\r
1277 UINT8 *Tail;\r
1278 UINTN CopiedCount;\r
1279 UINTN SignatureListSize;\r
1280 BOOLEAN IsNewCert;\r
1281\r
1282 Tail = (UINT8 *) Data + DataSize;\r
1283\r
1284 NewCertList = (EFI_SIGNATURE_LIST *) NewData;\r
1285 while ((NewDataSize > 0) && (NewDataSize >= NewCertList->SignatureListSize)) {\r
1286 NewCert = (EFI_SIGNATURE_DATA *) ((UINT8 *) NewCertList + sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize);\r
1287 NewCertCount = (NewCertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - NewCertList->SignatureHeaderSize) / NewCertList->SignatureSize;\r
1288\r
1289 CopiedCount = 0;\r
1290 for (Index = 0; Index < NewCertCount; Index++) {\r
1291 IsNewCert = TRUE;\r
1292\r
1293 Size = DataSize;\r
1294 CertList = (EFI_SIGNATURE_LIST *) Data;\r
1295 while ((Size > 0) && (Size >= CertList->SignatureListSize)) {\r
1296 if (CompareGuid (&CertList->SignatureType, &NewCertList->SignatureType) &&\r
1297 (CertList->SignatureSize == NewCertList->SignatureSize)) {\r
1298 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);\r
1299 CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;\r
1300 for (Index2 = 0; Index2 < CertCount; Index2++) {\r
1301 //\r
1302 // Iterate each Signature Data in this Signature List.\r
1303 //\r
1304 if (CompareMem (NewCert, Cert, CertList->SignatureSize) == 0) {\r
1305 IsNewCert = FALSE;\r
1306 break;\r
1307 }\r
1308 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);\r
1309 }\r
1310 }\r
1311\r
1312 if (!IsNewCert) {\r
1313 break;\r
1314 }\r
1315 Size -= CertList->SignatureListSize;\r
1316 CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);\r
1317 }\r
1318\r
1319 if (IsNewCert) {\r
1320 //\r
1321 // New EFI_SIGNATURE_DATA, append it.\r
1322 //\r
1323 if (CopiedCount == 0) {\r
1324 //\r
1325 // Copy EFI_SIGNATURE_LIST header for only once.\r
1326 //\r
1327 CopyMem (Tail, NewCertList, sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize);\r
1328 Tail = Tail + sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize;\r
1329 }\r
1330\r
1331 CopyMem (Tail, NewCert, NewCertList->SignatureSize);\r
1332 Tail += NewCertList->SignatureSize;\r
1333 CopiedCount++;\r
1334 }\r
1335\r
1336 NewCert = (EFI_SIGNATURE_DATA *) ((UINT8 *) NewCert + NewCertList->SignatureSize);\r
1337 }\r
1338\r
1339 //\r
1340 // Update SignatureListSize in newly appended EFI_SIGNATURE_LIST.\r
1341 //\r
1342 if (CopiedCount != 0) {\r
1343 SignatureListSize = sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize + (CopiedCount * NewCertList->SignatureSize);\r
1344 CertList = (EFI_SIGNATURE_LIST *) (Tail - SignatureListSize);\r
1345 CertList->SignatureListSize = (UINT32) SignatureListSize;\r
1346 }\r
1347\r
1348 NewDataSize -= NewCertList->SignatureListSize;\r
1349 NewCertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) NewCertList + NewCertList->SignatureListSize);\r
1350 }\r
1351\r
1352 return (Tail - (UINT8 *) Data);\r
1353}\r
1354\r
0c18794e 1355/**\r
1356 Compare two EFI_TIME data.\r
1357\r
1358\r
1359 @param FirstTime A pointer to the first EFI_TIME data.\r
1360 @param SecondTime A pointer to the second EFI_TIME data.\r
1361\r
1362 @retval TRUE The FirstTime is not later than the SecondTime.\r
1363 @retval FALSE The FirstTime is later than the SecondTime.\r
1364\r
1365**/\r
1366BOOLEAN\r
1367CompareTimeStamp (\r
1368 IN EFI_TIME *FirstTime,\r
1369 IN EFI_TIME *SecondTime\r
1370 )\r
1371{\r
1372 if (FirstTime->Year != SecondTime->Year) {\r
1373 return (BOOLEAN) (FirstTime->Year < SecondTime->Year);\r
1374 } else if (FirstTime->Month != SecondTime->Month) {\r
1375 return (BOOLEAN) (FirstTime->Month < SecondTime->Month);\r
1376 } else if (FirstTime->Day != SecondTime->Day) {\r
1377 return (BOOLEAN) (FirstTime->Day < SecondTime->Day);\r
1378 } else if (FirstTime->Hour != SecondTime->Hour) {\r
1379 return (BOOLEAN) (FirstTime->Hour < SecondTime->Hour);\r
1380 } else if (FirstTime->Minute != SecondTime->Minute) {\r
1381 return (BOOLEAN) (FirstTime->Minute < FirstTime->Minute);\r
2d3fb919 1382 }\r
0c18794e 1383\r
1384 return (BOOLEAN) (FirstTime->Second <= SecondTime->Second);\r
1385}\r
1386\r
ed47ae02 1387/**\r
1388 Find matching signer's certificates for common authenticated variable\r
1389 by corresponding VariableName and VendorGuid from "certdb".\r
1390\r
1391 The data format of "certdb":\r
1392 //\r
1393 // UINT32 CertDbListSize;\r
1394 // /// AUTH_CERT_DB_DATA Certs1[];\r
1395 // /// AUTH_CERT_DB_DATA Certs2[];\r
1396 // /// ...\r
1397 // /// AUTH_CERT_DB_DATA Certsn[];\r
1398 //\r
1399\r
1400 @param[in] VariableName Name of authenticated Variable.\r
1401 @param[in] VendorGuid Vendor GUID of authenticated Variable.\r
1402 @param[in] Data Pointer to variable "certdb".\r
1403 @param[in] DataSize Size of variable "certdb".\r
1404 @param[out] CertOffset Offset of matching CertData, from starting of Data.\r
1405 @param[out] CertDataSize Length of CertData in bytes.\r
1406 @param[out] CertNodeOffset Offset of matching AUTH_CERT_DB_DATA , from\r
1407 starting of Data.\r
1408 @param[out] CertNodeSize Length of AUTH_CERT_DB_DATA in bytes.\r
1409\r
1410 @retval EFI_INVALID_PARAMETER Any input parameter is invalid.\r
1411 @retval EFI_NOT_FOUND Fail to find matching certs.\r
1412 @retval EFI_SUCCESS Find matching certs and output parameters.\r
1413\r
1414**/\r
1415EFI_STATUS\r
1416FindCertsFromDb (\r
1417 IN CHAR16 *VariableName,\r
1418 IN EFI_GUID *VendorGuid,\r
1419 IN UINT8 *Data,\r
1420 IN UINTN DataSize,\r
1421 OUT UINT32 *CertOffset, OPTIONAL\r
1422 OUT UINT32 *CertDataSize, OPTIONAL\r
1423 OUT UINT32 *CertNodeOffset,OPTIONAL\r
1424 OUT UINT32 *CertNodeSize OPTIONAL\r
1425 )\r
1426{\r
1427 UINT32 Offset;\r
1428 AUTH_CERT_DB_DATA *Ptr;\r
1429 UINT32 CertSize;\r
1430 UINT32 NameSize;\r
1431 UINT32 NodeSize;\r
1432 UINT32 CertDbListSize;\r
1433\r
1434 if ((VariableName == NULL) || (VendorGuid == NULL) || (Data == NULL)) {\r
1435 return EFI_INVALID_PARAMETER;\r
1436 }\r
1437\r
1438 //\r
1439 // Check whether DataSize matches recorded CertDbListSize.\r
1440 //\r
1441 if (DataSize < sizeof (UINT32)) {\r
1442 return EFI_INVALID_PARAMETER;\r
1443 }\r
1444\r
1445 CertDbListSize = ReadUnaligned32 ((UINT32 *) Data);\r
1446\r
1447 if (CertDbListSize != (UINT32) DataSize) {\r
1448 return EFI_INVALID_PARAMETER;\r
1449 }\r
1450\r
1451 Offset = sizeof (UINT32);\r
1452\r
1453 //\r
1454 // Get corresponding certificates by VendorGuid and VariableName.\r
1455 //\r
1456 while (Offset < (UINT32) DataSize) {\r
1457 Ptr = (AUTH_CERT_DB_DATA *) (Data + Offset);\r
1458 //\r
1459 // Check whether VendorGuid matches.\r
1460 //\r
1461 if (CompareGuid (&Ptr->VendorGuid, VendorGuid)) {\r
1462 NodeSize = ReadUnaligned32 (&Ptr->CertNodeSize);\r
1463 NameSize = ReadUnaligned32 (&Ptr->NameSize);\r
1464 CertSize = ReadUnaligned32 (&Ptr->CertDataSize);\r
1465\r
1466 if (NodeSize != sizeof (EFI_GUID) + sizeof (UINT32) * 3 + CertSize +\r
1467 sizeof (CHAR16) * NameSize) {\r
1468 return EFI_INVALID_PARAMETER;\r
1469 }\r
1470\r
1471 Offset = Offset + sizeof (EFI_GUID) + sizeof (UINT32) * 3;\r
1472 //\r
1473 // Check whether VariableName matches.\r
1474 //\r
1475 if ((NameSize == StrLen (VariableName)) && \r
1476 (CompareMem (Data + Offset, VariableName, NameSize * sizeof (CHAR16)) == 0)) {\r
1477 Offset = Offset + NameSize * sizeof (CHAR16);\r
1478\r
1479 if (CertOffset != NULL) {\r
1480 *CertOffset = Offset;\r
1481 }\r
1482\r
1483 if (CertDataSize != NULL) {\r
1484 *CertDataSize = CertSize; \r
1485 }\r
1486\r
1487 if (CertNodeOffset != NULL) {\r
1488 *CertNodeOffset = (UINT32) ((UINT8 *) Ptr - Data);\r
1489 }\r
1490\r
1491 if (CertNodeSize != NULL) {\r
1492 *CertNodeSize = NodeSize;\r
1493 }\r
1494\r
1495 return EFI_SUCCESS;\r
1496 } else {\r
1497 Offset = Offset + NameSize * sizeof (CHAR16) + CertSize;\r
1498 }\r
1499 } else {\r
1500 NodeSize = ReadUnaligned32 (&Ptr->CertNodeSize);\r
1501 Offset = Offset + NodeSize;\r
1502 }\r
1503 }\r
1504\r
1505 return EFI_NOT_FOUND; \r
1506}\r
1507\r
1508/**\r
1509 Retrieve signer's certificates for common authenticated variable\r
1510 by corresponding VariableName and VendorGuid from "certdb".\r
1511\r
1512 @param[in] VariableName Name of authenticated Variable.\r
1513 @param[in] VendorGuid Vendor GUID of authenticated Variable.\r
1514 @param[out] CertData Pointer to signer's certificates.\r
1515 @param[out] CertDataSize Length of CertData in bytes.\r
1516\r
1517 @retval EFI_INVALID_PARAMETER Any input parameter is invalid.\r
1518 @retval EFI_NOT_FOUND Fail to find "certdb" or matching certs.\r
1519 @retval EFI_SUCCESS Get signer's certificates successfully.\r
1520\r
1521**/\r
1522EFI_STATUS\r
1523GetCertsFromDb (\r
1524 IN CHAR16 *VariableName,\r
1525 IN EFI_GUID *VendorGuid,\r
1526 OUT UINT8 **CertData,\r
1527 OUT UINT32 *CertDataSize\r
1528 )\r
1529{\r
1530 VARIABLE_POINTER_TRACK CertDbVariable;\r
1531 EFI_STATUS Status;\r
1532 UINT8 *Data;\r
1533 UINTN DataSize;\r
1534 UINT32 CertOffset;\r
1535\r
1536 if ((VariableName == NULL) || (VendorGuid == NULL) || (CertData == NULL) || (CertDataSize == NULL)) {\r
1537 return EFI_INVALID_PARAMETER;\r
1538 }\r
1539 \r
1540 //\r
1541 // Get variable "certdb".\r
1542 //\r
1543 Status = FindVariable (\r
1544 EFI_CERT_DB_NAME,\r
1545 &gEfiCertDbGuid,\r
1546 &CertDbVariable,\r
1547 &mVariableModuleGlobal->VariableGlobal,\r
1548 FALSE\r
1549 ); \r
1550 if (EFI_ERROR (Status)) {\r
1551 return Status;\r
1552 }\r
1553\r
1554 DataSize = DataSizeOfVariable (CertDbVariable.CurrPtr);\r
1555 Data = GetVariableDataPtr (CertDbVariable.CurrPtr);\r
1556 if ((DataSize == 0) || (Data == NULL)) {\r
1557 ASSERT (FALSE);\r
1558 return EFI_NOT_FOUND;\r
1559 }\r
1560\r
1561 Status = FindCertsFromDb (\r
1562 VariableName,\r
1563 VendorGuid,\r
1564 Data,\r
1565 DataSize,\r
1566 &CertOffset,\r
1567 CertDataSize,\r
1568 NULL,\r
1569 NULL\r
1570 );\r
1571\r
1572 if (EFI_ERROR (Status)) {\r
1573 return Status;\r
1574 }\r
1575\r
1576 *CertData = Data + CertOffset;\r
1577 return EFI_SUCCESS;\r
1578}\r
1579\r
1580/**\r
1581 Delete matching signer's certificates when deleting common authenticated\r
1582 variable by corresponding VariableName and VendorGuid from "certdb".\r
1583\r
1584 @param[in] VariableName Name of authenticated Variable.\r
1585 @param[in] VendorGuid Vendor GUID of authenticated Variable.\r
1586\r
1587 @retval EFI_INVALID_PARAMETER Any input parameter is invalid.\r
1588 @retval EFI_NOT_FOUND Fail to find "certdb" or matching certs.\r
1589 @retval EFI_OUT_OF_RESOURCES The operation is failed due to lack of resources.\r
1590 @retval EFI_SUCCESS The operation is completed successfully.\r
1591\r
1592**/\r
1593EFI_STATUS\r
1594DeleteCertsFromDb (\r
1595 IN CHAR16 *VariableName,\r
1596 IN EFI_GUID *VendorGuid\r
1597 )\r
1598{\r
1599 VARIABLE_POINTER_TRACK CertDbVariable;\r
1600 EFI_STATUS Status;\r
1601 UINT8 *Data;\r
1602 UINTN DataSize;\r
1603 UINT32 VarAttr;\r
1604 UINT32 CertNodeOffset;\r
1605 UINT32 CertNodeSize;\r
1606 UINT8 *NewCertDb;\r
1607 UINT32 NewCertDbSize;\r
1608\r
1609 if ((VariableName == NULL) || (VendorGuid == NULL)) {\r
1610 return EFI_INVALID_PARAMETER;\r
1611 }\r
1612 \r
1613 //\r
1614 // Get variable "certdb".\r
1615 //\r
1616 Status = FindVariable (\r
1617 EFI_CERT_DB_NAME,\r
1618 &gEfiCertDbGuid,\r
1619 &CertDbVariable,\r
1620 &mVariableModuleGlobal->VariableGlobal,\r
1621 FALSE\r
1622 ); \r
1623 if (EFI_ERROR (Status)) {\r
1624 return Status;\r
1625 }\r
1626\r
1627 DataSize = DataSizeOfVariable (CertDbVariable.CurrPtr);\r
1628 Data = GetVariableDataPtr (CertDbVariable.CurrPtr);\r
1629 if ((DataSize == 0) || (Data == NULL)) {\r
1630 ASSERT (FALSE);\r
1631 return EFI_NOT_FOUND;\r
1632 }\r
1633\r
1634 if (DataSize == sizeof (UINT32)) {\r
1635 //\r
1636 // There is no certs in certdb.\r
1637 //\r
1638 return EFI_SUCCESS;\r
1639 }\r
1640\r
1641 //\r
1642 // Get corresponding cert node from certdb.\r
1643 //\r
1644 Status = FindCertsFromDb (\r
1645 VariableName,\r
1646 VendorGuid,\r
1647 Data,\r
1648 DataSize,\r
1649 NULL,\r
1650 NULL,\r
1651 &CertNodeOffset,\r
1652 &CertNodeSize\r
1653 );\r
1654\r
1655 if (EFI_ERROR (Status)) {\r
1656 return Status;\r
1657 }\r
1658\r
1659 if (DataSize < (CertNodeOffset + CertNodeSize)) {\r
1660 return EFI_NOT_FOUND;\r
1661 }\r
1662\r
1663 //\r
1664 // Construct new data content of variable "certdb".\r
1665 //\r
1666 NewCertDbSize = (UINT32) DataSize - CertNodeSize;\r
1667 NewCertDb = AllocateZeroPool (NewCertDbSize);\r
1668 if (NewCertDb == NULL) {\r
1669 return EFI_OUT_OF_RESOURCES;\r
1670 }\r
1671\r
1672 //\r
1673 // Copy the DB entries before deleting node.\r
1674 //\r
1675 CopyMem (NewCertDb, Data, CertNodeOffset);\r
1676 //\r
1677 // Update CertDbListSize.\r
1678 //\r
1679 CopyMem (NewCertDb, &NewCertDbSize, sizeof (UINT32));\r
1680 //\r
1681 // Copy the DB entries after deleting node.\r
1682 //\r
1683 if (DataSize > (CertNodeOffset + CertNodeSize)) {\r
1684 CopyMem (\r
1685 NewCertDb + CertNodeOffset,\r
1686 Data + CertNodeOffset + CertNodeSize,\r
1687 DataSize - CertNodeOffset - CertNodeSize\r
1688 );\r
1689 }\r
1690\r
1691 //\r
1692 // Set "certdb".\r
1693 // \r
1694 VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS; \r
1695 Status = UpdateVariable (\r
1696 EFI_CERT_DB_NAME,\r
1697 &gEfiCertDbGuid,\r
1698 NewCertDb,\r
1699 NewCertDbSize,\r
1700 VarAttr,\r
1701 0,\r
1702 0,\r
1703 &CertDbVariable,\r
1704 NULL\r
1705 );\r
1706\r
1707 FreePool (NewCertDb);\r
1708 return Status;\r
1709}\r
1710\r
1711/**\r
1712 Insert signer's certificates for common authenticated variable with VariableName\r
1713 and VendorGuid in AUTH_CERT_DB_DATA to "certdb".\r
1714\r
1715 @param[in] VariableName Name of authenticated Variable.\r
1716 @param[in] VendorGuid Vendor GUID of authenticated Variable.\r
1717 @param[in] CertData Pointer to signer's certificates.\r
1718 @param[in] CertDataSize Length of CertData in bytes.\r
1719\r
1720 @retval EFI_INVALID_PARAMETER Any input parameter is invalid.\r
1721 @retval EFI_ACCESS_DENIED An AUTH_CERT_DB_DATA entry with same VariableName\r
1722 and VendorGuid already exists.\r
1723 @retval EFI_OUT_OF_RESOURCES The operation is failed due to lack of resources.\r
1724 @retval EFI_SUCCESS Insert an AUTH_CERT_DB_DATA entry to "certdb"\r
1725\r
1726**/\r
1727EFI_STATUS\r
1728InsertCertsToDb (\r
1729 IN CHAR16 *VariableName,\r
1730 IN EFI_GUID *VendorGuid,\r
1731 IN UINT8 *CertData,\r
1732 IN UINTN CertDataSize\r
1733 )\r
1734{\r
1735 VARIABLE_POINTER_TRACK CertDbVariable;\r
1736 EFI_STATUS Status;\r
1737 UINT8 *Data;\r
1738 UINTN DataSize;\r
1739 UINT32 VarAttr;\r
1740 UINT8 *NewCertDb;\r
1741 UINT32 NewCertDbSize;\r
1742 UINT32 CertNodeSize;\r
1743 UINT32 NameSize;\r
1744 AUTH_CERT_DB_DATA *Ptr;\r
1745\r
1746 if ((VariableName == NULL) || (VendorGuid == NULL) || (CertData == NULL)) {\r
1747 return EFI_INVALID_PARAMETER;\r
1748 }\r
1749 \r
1750 //\r
1751 // Get variable "certdb".\r
1752 //\r
1753 Status = FindVariable (\r
1754 EFI_CERT_DB_NAME,\r
1755 &gEfiCertDbGuid,\r
1756 &CertDbVariable,\r
1757 &mVariableModuleGlobal->VariableGlobal,\r
1758 FALSE\r
1759 ); \r
1760 if (EFI_ERROR (Status)) {\r
1761 return Status;\r
1762 }\r
1763\r
1764 DataSize = DataSizeOfVariable (CertDbVariable.CurrPtr);\r
1765 Data = GetVariableDataPtr (CertDbVariable.CurrPtr);\r
1766 if ((DataSize == 0) || (Data == NULL)) {\r
1767 ASSERT (FALSE);\r
1768 return EFI_NOT_FOUND;\r
1769 }\r
1770\r
1771 //\r
1772 // Find whether matching cert node already exists in "certdb".\r
1773 // If yes return error.\r
1774 //\r
1775 Status = FindCertsFromDb (\r
1776 VariableName,\r
1777 VendorGuid,\r
1778 Data,\r
1779 DataSize,\r
1780 NULL,\r
1781 NULL,\r
1782 NULL,\r
1783 NULL\r
1784 );\r
1785\r
1786 if (!EFI_ERROR (Status)) {\r
1787 ASSERT (FALSE);\r
1788 return EFI_ACCESS_DENIED;\r
1789 }\r
1790\r
1791 //\r
1792 // Construct new data content of variable "certdb".\r
1793 //\r
1794 NameSize = (UINT32) StrLen (VariableName);\r
1795 CertNodeSize = sizeof (AUTH_CERT_DB_DATA) + (UINT32) CertDataSize + NameSize * sizeof (CHAR16); \r
1796 NewCertDbSize = (UINT32) DataSize + CertNodeSize; \r
1797 NewCertDb = AllocateZeroPool (NewCertDbSize);\r
1798 if (NewCertDb == NULL) {\r
1799 return EFI_OUT_OF_RESOURCES;\r
1800 }\r
1801\r
1802 //\r
1803 // Copy the DB entries before deleting node.\r
1804 //\r
1805 CopyMem (NewCertDb, Data, DataSize);\r
1806 //\r
1807 // Update CertDbListSize.\r
1808 //\r
1809 CopyMem (NewCertDb, &NewCertDbSize, sizeof (UINT32));\r
1810 //\r
1811 // Construct new cert node.\r
1812 //\r
1813 Ptr = (AUTH_CERT_DB_DATA *) (NewCertDb + DataSize);\r
1814 CopyGuid (&Ptr->VendorGuid, VendorGuid);\r
1815 CopyMem (&Ptr->CertNodeSize, &CertNodeSize, sizeof (UINT32));\r
1816 CopyMem (&Ptr->NameSize, &NameSize, sizeof (UINT32));\r
1817 CopyMem (&Ptr->CertDataSize, &CertDataSize, sizeof (UINT32));\r
1818 \r
1819 CopyMem (\r
1820 (UINT8 *) Ptr + sizeof (AUTH_CERT_DB_DATA),\r
1821 VariableName,\r
1822 NameSize * sizeof (CHAR16)\r
1823 );\r
1824\r
1825 CopyMem (\r
1826 (UINT8 *) Ptr + sizeof (AUTH_CERT_DB_DATA) + NameSize * sizeof (CHAR16),\r
1827 CertData,\r
1828 CertDataSize\r
1829 );\r
1830 \r
1831 //\r
1832 // Set "certdb".\r
1833 // \r
1834 VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS; \r
1835 Status = UpdateVariable (\r
1836 EFI_CERT_DB_NAME,\r
1837 &gEfiCertDbGuid,\r
1838 NewCertDb,\r
1839 NewCertDbSize,\r
1840 VarAttr,\r
1841 0,\r
1842 0,\r
1843 &CertDbVariable,\r
1844 NULL\r
1845 );\r
1846\r
1847 FreePool (NewCertDb);\r
1848 return Status;\r
1849}\r
1850\r
0c18794e 1851/**\r
1852 Process variable with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set\r
1853\r
dc204d5a
JY
1854 Caution: This function may receive untrusted input.\r
1855 This function may be invoked in SMM mode, and datasize and data are external input.\r
1856 This function will do basic validation, before parse the data.\r
1857 This function will parse the authentication carefully to avoid security issues, like\r
1858 buffer overflow, integer overflow.\r
1859\r
0c18794e 1860 @param[in] VariableName Name of Variable to be found.\r
1861 @param[in] VendorGuid Variable vendor GUID.\r
1862 @param[in] Data Data pointer.\r
1863 @param[in] DataSize Size of Data found. If size is less than the\r
1864 data, this value contains the required size.\r
1865 @param[in] Variable The variable information which is used to keep track of variable usage.\r
1866 @param[in] Attributes Attribute value of the variable.\r
785d84ea 1867 @param[in] AuthVarType Verify against PK, KEK database, private database or certificate in data payload.\r
0c18794e 1868 @param[out] VarDel Delete the variable or not.\r
1869\r
1870 @retval EFI_INVALID_PARAMETER Invalid parameter.\r
2d3fb919 1871 @retval EFI_SECURITY_VIOLATION The variable does NOT pass the validation\r
1872 check carried out by the firmware.\r
0c18794e 1873 @retval EFI_OUT_OF_RESOURCES Failed to process variable due to lack\r
1874 of resources.\r
1875 @retval EFI_SUCCESS Variable pass validation successfully.\r
1876\r
1877**/\r
1878EFI_STATUS\r
1879VerifyTimeBasedPayload (\r
1880 IN CHAR16 *VariableName,\r
1881 IN EFI_GUID *VendorGuid,\r
1882 IN VOID *Data,\r
1883 IN UINTN DataSize,\r
1884 IN VARIABLE_POINTER_TRACK *Variable,\r
1885 IN UINT32 Attributes,\r
ed47ae02 1886 IN AUTHVAR_TYPE AuthVarType,\r
0c18794e 1887 OUT BOOLEAN *VarDel\r
1888 )\r
1889{\r
1890 UINT8 *RootCert;\r
1891 UINT8 *SigData;\r
2d3fb919 1892 UINT8 *PayloadPtr;\r
0c18794e 1893 UINTN RootCertSize;\r
1894 UINTN Index;\r
2d3fb919 1895 UINTN CertCount;\r
1896 UINTN PayloadSize;\r
0c18794e 1897 UINT32 Attr;\r
1898 UINT32 SigDataSize;\r
1899 UINT32 KekDataSize;\r
0c18794e 1900 BOOLEAN VerifyStatus;\r
1901 EFI_STATUS Status;\r
1902 EFI_SIGNATURE_LIST *CertList;\r
1903 EFI_SIGNATURE_DATA *Cert;\r
1904 VARIABLE_POINTER_TRACK KekVariable;\r
1905 EFI_VARIABLE_AUTHENTICATION_2 *CertData;\r
1906 UINT8 *NewData;\r
1907 UINTN NewDataSize;\r
1908 VARIABLE_POINTER_TRACK PkVariable;\r
2d3fb919 1909 UINT8 *Buffer;\r
1910 UINTN Length;\r
ed47ae02 1911 UINT8 *SignerCerts;\r
1912 UINT8 *WrapSigData;\r
1913 UINTN CertStackSize;\r
1914 UINT8 *CertsInCertDb;\r
1915 UINT32 CertsSizeinDb;\r
0c18794e 1916\r
0c18794e 1917 VerifyStatus = FALSE;\r
1918 CertData = NULL;\r
1919 NewData = NULL;\r
1920 Attr = Attributes;\r
ed47ae02 1921 WrapSigData = NULL;\r
1922 SignerCerts = NULL;\r
1923 RootCert = NULL;\r
0c18794e 1924\r
1925 //\r
2d3fb919 1926 // When the attribute EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS is\r
0c18794e 1927 // set, then the Data buffer shall begin with an instance of a complete (and serialized)\r
2d3fb919 1928 // EFI_VARIABLE_AUTHENTICATION_2 descriptor. The descriptor shall be followed by the new\r
1929 // variable value and DataSize shall reflect the combined size of the descriptor and the new\r
1930 // variable value. The authentication descriptor is not part of the variable data and is not\r
0c18794e 1931 // returned by subsequent calls to GetVariable().\r
1932 //\r
1933 CertData = (EFI_VARIABLE_AUTHENTICATION_2 *) Data;\r
2d3fb919 1934\r
1935 //\r
1936 // Verify that Pad1, Nanosecond, TimeZone, Daylight and Pad2 components of the\r
1937 // TimeStamp value are set to zero.\r
1938 //\r
1939 if ((CertData->TimeStamp.Pad1 != 0) ||\r
1940 (CertData->TimeStamp.Nanosecond != 0) ||\r
1941 (CertData->TimeStamp.TimeZone != 0) ||\r
1942 (CertData->TimeStamp.Daylight != 0) ||\r
1943 (CertData->TimeStamp.Pad2 != 0)) {\r
2e24814a 1944 return EFI_SECURITY_VIOLATION;\r
2d3fb919 1945 }\r
1946\r
0c18794e 1947 if ((Variable->CurrPtr != NULL) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0)) {\r
1948 if (CompareTimeStamp (&CertData->TimeStamp, &Variable->CurrPtr->TimeStamp)) {\r
1949 //\r
1950 // TimeStamp check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.\r
1951 //\r
1952 return EFI_SECURITY_VIOLATION;\r
1953 }\r
1954 }\r
1955\r
1956 //\r
1957 // wCertificateType should be WIN_CERT_TYPE_EFI_GUID.\r
1958 // Cert type should be EFI_CERT_TYPE_PKCS7_GUID.\r
1959 //\r
1960 if ((CertData->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID) ||\r
2d3fb919 1961 !CompareGuid (&CertData->AuthInfo.CertType, &gEfiCertPkcs7Guid)) {\r
0c18794e 1962 //\r
1963 // Invalid AuthInfo type, return EFI_SECURITY_VIOLATION.\r
1964 //\r
1965 return EFI_SECURITY_VIOLATION;\r
1966 }\r
2d3fb919 1967\r
0c18794e 1968 //\r
1969 // Find out Pkcs7 SignedData which follows the EFI_VARIABLE_AUTHENTICATION_2 descriptor.\r
1970 // AuthInfo.Hdr.dwLength is the length of the entire certificate, including the length of the header.\r
1971 //\r
2d3fb919 1972 SigData = CertData->AuthInfo.CertData;\r
1973 SigDataSize = CertData->AuthInfo.Hdr.dwLength - (UINT32) (OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData));\r
648f98d1 1974\r
0c18794e 1975 //\r
1976 // Find out the new data payload which follows Pkcs7 SignedData directly.\r
1977 //\r
2d3fb919 1978 PayloadPtr = SigData + SigDataSize;\r
1979 PayloadSize = DataSize - OFFSET_OF_AUTHINFO2_CERT_DATA - (UINTN) SigDataSize;\r
0c18794e 1980\r
1981 //\r
1982 // Construct a buffer to fill with (VariableName, VendorGuid, Attributes, TimeStamp, Data).\r
1983 //\r
2d3fb919 1984 NewDataSize = PayloadSize + sizeof (EFI_TIME) + sizeof (UINT32) +\r
1985 sizeof (EFI_GUID) + StrSize (VariableName) - sizeof (CHAR16);\r
1986 NewData = mSerializationRuntimeBuffer;\r
0c18794e 1987\r
2d3fb919 1988 Buffer = NewData;\r
1989 Length = StrLen (VariableName) * sizeof (CHAR16);\r
1990 CopyMem (Buffer, VariableName, Length);\r
1991 Buffer += Length;\r
0c18794e 1992\r
2d3fb919 1993 Length = sizeof (EFI_GUID);\r
1994 CopyMem (Buffer, VendorGuid, Length);\r
1995 Buffer += Length;\r
0c18794e 1996\r
2d3fb919 1997 Length = sizeof (UINT32);\r
1998 CopyMem (Buffer, &Attr, Length);\r
1999 Buffer += Length;\r
0c18794e 2000\r
2d3fb919 2001 Length = sizeof (EFI_TIME);\r
2002 CopyMem (Buffer, &CertData->TimeStamp, Length);\r
2003 Buffer += Length;\r
0c18794e 2004\r
2d3fb919 2005 CopyMem (Buffer, PayloadPtr, PayloadSize);\r
0c18794e 2006\r
ed47ae02 2007 if (AuthVarType == AuthVarTypePk) {\r
0c18794e 2008 //\r
2009 // Get platform key from variable.\r
2010 //\r
2011 Status = FindVariable (\r
2d3fb919 2012 EFI_PLATFORM_KEY_NAME,\r
2013 &gEfiGlobalVariableGuid,\r
2014 &PkVariable,\r
ecc722ad 2015 &mVariableModuleGlobal->VariableGlobal,\r
2016 FALSE\r
0c18794e 2017 );\r
2018 if (EFI_ERROR (Status)) {\r
2019 return Status;\r
2020 }\r
2021\r
2022 CertList = (EFI_SIGNATURE_LIST *) GetVariableDataPtr (PkVariable.CurrPtr);\r
2023 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);\r
2024 RootCert = Cert->SignatureData;\r
4e33001c 2025 RootCertSize = CertList->SignatureSize - (sizeof (EFI_SIGNATURE_DATA) - 1);\r
0c18794e 2026\r
2027\r
2028 //\r
2029 // Verify Pkcs7 SignedData via Pkcs7Verify library.\r
2030 //\r
2031 VerifyStatus = Pkcs7Verify (\r
2032 SigData,\r
2033 SigDataSize,\r
2034 RootCert,\r
2035 RootCertSize,\r
2036 NewData,\r
2037 NewDataSize\r
2038 );\r
2039\r
ed47ae02 2040 } else if (AuthVarType == AuthVarTypeKek) {\r
2d3fb919 2041\r
0c18794e 2042 //\r
2043 // Get KEK database from variable.\r
2044 //\r
2045 Status = FindVariable (\r
2d3fb919 2046 EFI_KEY_EXCHANGE_KEY_NAME,\r
2047 &gEfiGlobalVariableGuid,\r
2048 &KekVariable,\r
ecc722ad 2049 &mVariableModuleGlobal->VariableGlobal,\r
2050 FALSE\r
0c18794e 2051 );\r
2052 if (EFI_ERROR (Status)) {\r
2053 return Status;\r
2054 }\r
2055\r
2056 //\r
2057 // Ready to verify Pkcs7 SignedData. Go through KEK Signature Database to find out X.509 CertList.\r
2d3fb919 2058 //\r
0c18794e 2059 KekDataSize = KekVariable.CurrPtr->DataSize;\r
2060 CertList = (EFI_SIGNATURE_LIST *) GetVariableDataPtr (KekVariable.CurrPtr);\r
2061 while ((KekDataSize > 0) && (KekDataSize >= CertList->SignatureListSize)) {\r
2062 if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) {\r
2063 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);\r
2064 CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;\r
2065 for (Index = 0; Index < CertCount; Index++) {\r
2066 //\r
2067 // Iterate each Signature Data Node within this CertList for a verify\r
2068 //\r
2069 RootCert = Cert->SignatureData;\r
4e33001c 2070 RootCertSize = CertList->SignatureSize - (sizeof (EFI_SIGNATURE_DATA) - 1);\r
2d3fb919 2071\r
0c18794e 2072 //\r
2073 // Verify Pkcs7 SignedData via Pkcs7Verify library.\r
2074 //\r
2075 VerifyStatus = Pkcs7Verify (\r
2076 SigData,\r
2077 SigDataSize,\r
2078 RootCert,\r
2079 RootCertSize,\r
2080 NewData,\r
2081 NewDataSize\r
2082 );\r
2083 if (VerifyStatus) {\r
2084 goto Exit;\r
2085 }\r
2086 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);\r
2087 }\r
2088 }\r
2089 KekDataSize -= CertList->SignatureListSize;\r
2090 CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);\r
2091 }\r
ed47ae02 2092 } else if (AuthVarType == AuthVarTypePriv) {\r
2093\r
2094 //\r
2095 // Process common authenticated variable except PK/KEK/DB/DBX.\r
2096 // Get signer's certificates from SignedData.\r
2097 //\r
2098 VerifyStatus = Pkcs7GetSigners (\r
2099 SigData,\r
2100 SigDataSize,\r
2101 &SignerCerts,\r
2102 &CertStackSize,\r
2103 &RootCert,\r
2104 &RootCertSize\r
2105 );\r
2106 if (!VerifyStatus) {\r
2107 goto Exit;\r
2108 }\r
2109\r
2110 //\r
2111 // Get previously stored signer's certificates from certdb for existing\r
2112 // variable. Check whether they are identical with signer's certificates\r
2113 // in SignedData. If not, return error immediately.\r
2114 //\r
2115 if ((Variable->CurrPtr != NULL)) {\r
2116 VerifyStatus = FALSE;\r
2117\r
2118 Status = GetCertsFromDb (VariableName, VendorGuid, &CertsInCertDb, &CertsSizeinDb);\r
2119 if (EFI_ERROR (Status)) {\r
2120 goto Exit;\r
2121 }\r
2122 \r
2123 if ((CertStackSize != CertsSizeinDb) ||\r
2124 (CompareMem (SignerCerts, CertsInCertDb, CertsSizeinDb) != 0)) {\r
2125 goto Exit;\r
2126 }\r
2127 }\r
2128\r
2129 VerifyStatus = Pkcs7Verify (\r
2130 SigData,\r
2131 SigDataSize,\r
2132 RootCert,\r
2133 RootCertSize,\r
2134 NewData,\r
2135 NewDataSize\r
2136 );\r
2137 if (!VerifyStatus) {\r
2138 goto Exit;\r
2139 }\r
2140\r
2141 //\r
2142 // Delete signer's certificates when delete the common authenticated variable.\r
2143 //\r
2144 if ((PayloadSize == 0) && (Variable->CurrPtr != NULL)) {\r
2145 Status = DeleteCertsFromDb (VariableName, VendorGuid);\r
2146 if (EFI_ERROR (Status)) {\r
2147 VerifyStatus = FALSE;\r
2148 goto Exit;\r
2149 }\r
2150 } else if (Variable->CurrPtr == NULL) {\r
2151 //\r
2152 // Insert signer's certificates when adding a new common authenticated variable.\r
2153 //\r
2154 Status = InsertCertsToDb (VariableName, VendorGuid, SignerCerts, CertStackSize);\r
2155 if (EFI_ERROR (Status)) {\r
2156 VerifyStatus = FALSE;\r
2157 goto Exit;\r
2158 }\r
2159 }\r
785d84ea 2160 } else if (AuthVarType == AuthVarTypePayload) {\r
2161 CertList = (EFI_SIGNATURE_LIST *) PayloadPtr;\r
2162 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);\r
2163 RootCert = Cert->SignatureData;\r
2164 RootCertSize = CertList->SignatureSize - (sizeof (EFI_SIGNATURE_DATA) - 1);\r
2165 \r
2166 // Verify Pkcs7 SignedData via Pkcs7Verify library.\r
2167 //\r
2168 VerifyStatus = Pkcs7Verify (\r
2169 SigData,\r
2170 SigDataSize,\r
2171 RootCert,\r
2172 RootCertSize,\r
2173 NewData,\r
2174 NewDataSize\r
2175 );\r
ed47ae02 2176 } else {\r
2177 return EFI_SECURITY_VIOLATION;\r
0c18794e 2178 }\r
2179\r
2180Exit:\r
2181\r
ed47ae02 2182 if (AuthVarType == AuthVarTypePriv) {\r
2183 Pkcs7FreeSigners (RootCert);\r
2184 Pkcs7FreeSigners (SignerCerts);\r
2185 }\r
2186\r
0c18794e 2187 if (!VerifyStatus) {\r
2188 return EFI_SECURITY_VIOLATION;\r
2189 }\r
2190\r
d912bad7 2191 Status = CheckSignatureListFormat(VariableName, VendorGuid, PayloadPtr, PayloadSize);\r
2192 if (EFI_ERROR (Status)) {\r
2193 return Status;\r
2194 }\r
2195\r
2d3fb919 2196 if ((PayloadSize == 0) && (VarDel != NULL)) {\r
0c18794e 2197 *VarDel = TRUE;\r
2198 }\r
2d3fb919 2199\r
0c18794e 2200 //\r
2201 // Final step: Update/Append Variable if it pass Pkcs7Verify\r
2202 //\r
ed47ae02 2203 return UpdateVariable (\r
2204 VariableName,\r
2205 VendorGuid,\r
2206 PayloadPtr,\r
2207 PayloadSize,\r
2208 Attributes,\r
2209 0,\r
2210 0,\r
2211 Variable,\r
2212 &CertData->TimeStamp\r
2213 );\r
0c18794e 2214}\r
ed47ae02 2215\r