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