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