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