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