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