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