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