]> git.proxmox.com Git - mirror_edk2.git/blame - SecurityPkg/VariableAuthenticated/RuntimeDxe/AuthService.c
Add pointer check for NULL before dereference it.
[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
5Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
2d3fb919 6This program and the accompanying materials\r
7are licensed and made available under the terms and conditions of the BSD License\r
8which accompanies this distribution. The full text of the license may be found at\r
0c18794e 9http://opensource.org/licenses/bsd-license.php\r
10\r
2d3fb919 11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
0c18794e 12WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13\r
14**/\r
15\r
16#include "Variable.h"\r
17#include "AuthService.h"\r
18\r
19///\r
20/// Global database array for scratch\r
2d3fb919 21///\r
0c18794e 22UINT8 mPubKeyStore[MAX_KEYDB_SIZE];\r
23UINT32 mPubKeyNumber;\r
24UINT32 mPlatformMode;\r
25EFI_GUID mSignatureSupport[SIGSUPPORT_NUM] = {EFI_CERT_RSA2048_SHA256_GUID, EFI_CERT_RSA2048_SHA1_GUID};\r
26//\r
27// Public Exponent of RSA Key.\r
28//\r
29CONST UINT8 mRsaE[] = { 0x01, 0x00, 0x01 };\r
30//\r
31// Hash context pointer\r
32//\r
33VOID *mHashCtx = NULL;\r
34\r
0c18794e 35//\r
2d3fb919 36// Pointer to runtime buffer.\r
37// For "Append" operation to an existing variable, a read/modify/write operation\r
38// is supported by firmware internally. Reserve runtime buffer to cache previous\r
0c18794e 39// variable data in runtime phase because memory allocation is forbidden in virtual mode.\r
40//\r
41VOID *mStorageArea = NULL;\r
42\r
2d3fb919 43//\r
44// The serialization of the values of the VariableName, VendorGuid and Attributes\r
45// parameters of the SetVariable() call and the TimeStamp component of the\r
46// EFI_VARIABLE_AUTHENTICATION_2 descriptor followed by the variable's new value\r
47// i.e. (VariableName, VendorGuid, Attributes, TimeStamp, Data)\r
48//\r
49UINT8 *mSerializationRuntimeBuffer = NULL;\r
50\r
0c18794e 51/**\r
2d3fb919 52 Internal function to delete a Variable given its name and GUID, no authentication\r
53 required.\r
0c18794e 54\r
2d3fb919 55 @param[in] VariableName Name of the Variable.\r
56 @param[in] VendorGuid GUID of the Variable.\r
0c18794e 57\r
2d3fb919 58 @retval EFI_SUCCESS Variable deleted successfully.\r
59 @retval Others The driver failded to start the device.\r
0c18794e 60\r
61**/\r
62EFI_STATUS\r
2d3fb919 63DeleteVariable (\r
64 IN CHAR16 *VariableName,\r
65 IN EFI_GUID *VendorGuid\r
66 )\r
67{\r
68 EFI_STATUS Status;\r
69 VARIABLE_POINTER_TRACK Variable;\r
70\r
71 Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal);\r
72 if (EFI_ERROR (Status)) {\r
73 return EFI_SUCCESS;\r
74 }\r
75\r
76 ASSERT (Variable.CurrPtr != NULL);\r
77 return UpdateVariable (VariableName, VendorGuid, NULL, 0, 0, 0, 0, &Variable, NULL);\r
78}\r
0c18794e 79\r
80/**\r
81 Initializes for authenticated varibale service.\r
82\r
83 @retval EFI_SUCCESS Function successfully executed.\r
84 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resources.\r
85\r
86**/\r
87EFI_STATUS\r
88AutenticatedVariableServiceInitialize (\r
89 VOID\r
90 )\r
91{\r
92 EFI_STATUS Status;\r
93 VARIABLE_POINTER_TRACK Variable;\r
7aaf2fd6 94 VARIABLE_POINTER_TRACK PkVariable;\r
0c18794e 95 UINT8 VarValue;\r
96 UINT32 VarAttr;\r
97 UINT8 *Data;\r
98 UINTN DataSize;\r
99 UINTN CtxSize;\r
beda2356 100 UINT8 SecureBootMode;\r
101 UINT8 SecureBootEnable;\r
2d3fb919 102\r
0c18794e 103 //\r
104 // Initialize hash context.\r
105 //\r
106 CtxSize = Sha256GetContextSize ();\r
107 mHashCtx = AllocateRuntimePool (CtxSize);\r
108 if (mHashCtx == NULL) {\r
109 return EFI_OUT_OF_RESOURCES;\r
110 }\r
111\r
112 //\r
113 // Reserved runtime buffer for "Append" operation in virtual mode.\r
114 //\r
2d3fb919 115 mStorageArea = AllocateRuntimePool (PcdGet32 (PcdMaxVariableSize));\r
0c18794e 116 if (mStorageArea == NULL) {\r
117 return EFI_OUT_OF_RESOURCES;\r
118 }\r
119\r
120 //\r
2d3fb919 121 // Prepare runtime buffer for serialized data of time-based authenticated\r
122 // Variable, i.e. (VariableName, VendorGuid, Attributes, TimeStamp, Data).\r
123 //\r
124 mSerializationRuntimeBuffer = AllocateRuntimePool (PcdGet32 (PcdMaxVariableSize) + sizeof (EFI_GUID) + sizeof (UINT32) + sizeof (EFI_TIME));\r
125 if (mSerializationRuntimeBuffer == NULL) {\r
126 return EFI_OUT_OF_RESOURCES;\r
127 }\r
128\r
129 //\r
130 // Check "AuthVarKeyDatabase" variable's existence.\r
131 // If it doesn't exist, create a new one with initial value of 0 and EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.\r
0c18794e 132 //\r
133 Status = FindVariable (\r
2d3fb919 134 AUTHVAR_KEYDB_NAME,\r
135 &gEfiAuthenticatedVariableGuid,\r
136 &Variable,\r
0c18794e 137 &mVariableModuleGlobal->VariableGlobal\r
138 );\r
139\r
140 if (Variable.CurrPtr == NULL) {\r
141 VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;\r
142 VarValue = 0;\r
143 mPubKeyNumber = 0;\r
144 Status = UpdateVariable (\r
145 AUTHVAR_KEYDB_NAME,\r
146 &gEfiAuthenticatedVariableGuid,\r
147 &VarValue,\r
148 sizeof(UINT8),\r
149 VarAttr,\r
150 0,\r
151 0,\r
152 &Variable,\r
153 NULL\r
154 );\r
155 if (EFI_ERROR (Status)) {\r
156 return Status;\r
157 }\r
158 } else {\r
159 //\r
160 // Load database in global variable for cache.\r
161 //\r
162 DataSize = DataSizeOfVariable (Variable.CurrPtr);\r
163 Data = GetVariableDataPtr (Variable.CurrPtr);\r
164 ASSERT ((DataSize != 0) && (Data != NULL));\r
165 CopyMem (mPubKeyStore, (UINT8 *) Data, DataSize);\r
166 mPubKeyNumber = (UINT32) (DataSize / EFI_CERT_TYPE_RSA2048_SIZE);\r
167 }\r
7aaf2fd6 168\r
169 FindVariable (EFI_PLATFORM_KEY_NAME, &gEfiGlobalVariableGuid, &PkVariable, &mVariableModuleGlobal->VariableGlobal);\r
170 if (PkVariable.CurrPtr == NULL) {\r
171 DEBUG ((EFI_D_INFO, "Variable %s does not exist.\n", EFI_PLATFORM_KEY_NAME));\r
172 } else {\r
173 DEBUG ((EFI_D_INFO, "Variable %s exists.\n", EFI_PLATFORM_KEY_NAME));\r
174 }\r
175 \r
0c18794e 176 //\r
2d3fb919 177 // Check "SetupMode" variable's existence.\r
0c18794e 178 // If it doesn't exist, check PK database's existence to determine the value.\r
2d3fb919 179 // Then create a new one with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.\r
0c18794e 180 //\r
181 Status = FindVariable (\r
2d3fb919 182 EFI_SETUP_MODE_NAME,\r
183 &gEfiGlobalVariableGuid,\r
184 &Variable,\r
0c18794e 185 &mVariableModuleGlobal->VariableGlobal\r
186 );\r
187\r
188 if (Variable.CurrPtr == NULL) {\r
7aaf2fd6 189 if (PkVariable.CurrPtr == NULL) {\r
0c18794e 190 mPlatformMode = SETUP_MODE;\r
191 } else {\r
192 mPlatformMode = USER_MODE;\r
193 }\r
194\r
2d3fb919 195 VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;\r
0c18794e 196 Status = UpdateVariable (\r
197 EFI_SETUP_MODE_NAME,\r
198 &gEfiGlobalVariableGuid,\r
199 &mPlatformMode,\r
200 sizeof(UINT8),\r
201 VarAttr,\r
202 0,\r
203 0,\r
204 &Variable,\r
205 NULL\r
206 );\r
207 if (EFI_ERROR (Status)) {\r
208 return Status;\r
209 }\r
210 } else {\r
211 mPlatformMode = *(GetVariableDataPtr (Variable.CurrPtr));\r
212 }\r
213 //\r
2d3fb919 214 // Check "SignatureSupport" variable's existence.\r
215 // If it doesn't exist, then create a new one with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.\r
0c18794e 216 //\r
217 Status = FindVariable (\r
2d3fb919 218 EFI_SIGNATURE_SUPPORT_NAME,\r
219 &gEfiGlobalVariableGuid,\r
220 &Variable,\r
0c18794e 221 &mVariableModuleGlobal->VariableGlobal\r
222 );\r
223\r
224 if (Variable.CurrPtr == NULL) {\r
225 VarAttr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;\r
226 Status = UpdateVariable (\r
227 EFI_SIGNATURE_SUPPORT_NAME,\r
228 &gEfiGlobalVariableGuid,\r
229 mSignatureSupport,\r
230 SIGSUPPORT_NUM * sizeof(EFI_GUID),\r
231 VarAttr,\r
232 0,\r
233 0,\r
234 &Variable,\r
235 NULL\r
236 );\r
237 }\r
beda2356 238\r
239 //\r
240 // If "SecureBootEnable" variable exists, then update "SecureBoot" variable.\r
2d3fb919 241 // If "SecureBootEnable" variable is SECURE_BOOT_ENABLE and in USER_MODE, Set "SecureBoot" variable to SECURE_BOOT_MODE_ENABLE.\r
beda2356 242 // If "SecureBootEnable" variable is SECURE_BOOT_DISABLE, Set "SecureBoot" variable to SECURE_BOOT_MODE_DISABLE.\r
243 //\r
2d3fb919 244 SecureBootEnable = SECURE_BOOT_MODE_DISABLE;\r
beda2356 245 FindVariable (EFI_SECURE_BOOT_ENABLE_NAME, &gEfiSecureBootEnableDisableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal);\r
246 if (Variable.CurrPtr != NULL) {\r
247 SecureBootEnable = *(GetVariableDataPtr (Variable.CurrPtr));\r
2d3fb919 248 } else if (mPlatformMode == USER_MODE) {\r
249 //\r
250 // "SecureBootEnable" not exist, initialize it in USER_MODE.\r
251 //\r
252 SecureBootEnable = SECURE_BOOT_MODE_ENABLE;\r
beda2356 253 Status = UpdateVariable (\r
2d3fb919 254 EFI_SECURE_BOOT_ENABLE_NAME,\r
255 &gEfiSecureBootEnableDisableGuid,\r
256 &SecureBootEnable,\r
257 sizeof (UINT8),\r
258 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
259 0,\r
260 0,\r
beda2356 261 &Variable,\r
262 NULL\r
263 );\r
264 if (EFI_ERROR (Status)) {\r
265 return Status;\r
266 }\r
267 }\r
268\r
2d3fb919 269 if (SecureBootEnable == SECURE_BOOT_ENABLE && mPlatformMode == USER_MODE) {\r
270 SecureBootMode = SECURE_BOOT_MODE_ENABLE;\r
271 } else {\r
272 SecureBootMode = SECURE_BOOT_MODE_DISABLE;\r
273 }\r
274 FindVariable (EFI_SECURE_BOOT_MODE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal);\r
275 Status = UpdateVariable (\r
276 EFI_SECURE_BOOT_MODE_NAME,\r
277 &gEfiGlobalVariableGuid,\r
278 &SecureBootMode,\r
279 sizeof (UINT8),\r
280 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS,\r
281 0,\r
282 0,\r
283 &Variable,\r
284 NULL\r
285 );\r
286 if (EFI_ERROR (Status)) {\r
287 return Status;\r
288 }\r
289\r
7aaf2fd6 290 DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_SETUP_MODE_NAME, mPlatformMode));\r
291 DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_SECURE_BOOT_MODE_NAME, SecureBootMode));\r
292 DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_SECURE_BOOT_ENABLE_NAME, SecureBootEnable));\r
293\r
0c18794e 294 //\r
295 // Detect whether a secure platform-specific method to clear PK(Platform Key)\r
2d3fb919 296 // is configured by platform owner. This method is provided for users force to clear PK\r
0c18794e 297 // in case incorrect enrollment mis-haps.\r
298 //\r
299 if (ForceClearPK ()) {\r
7aaf2fd6 300 DEBUG ((EFI_D_INFO, "Variable PK/KEK/DB/DBX will be cleared in clear PK mode.\n"));\r
301\r
0c18794e 302 //\r
2d3fb919 303 // 1. Clear PK.\r
0c18794e 304 //\r
2d3fb919 305 Status = DeleteVariable (EFI_PLATFORM_KEY_NAME, &gEfiGlobalVariableGuid);\r
306 if (EFI_ERROR (Status)) {\r
307 return Status;\r
0c18794e 308 }\r
309\r
310 //\r
2d3fb919 311 // 2. Update "SetupMode" variable to SETUP_MODE.\r
0c18794e 312 //\r
313 UpdatePlatformMode (SETUP_MODE);\r
2d3fb919 314\r
315 //\r
316 // 3. Clear KEK, DB and DBX.\r
317 //\r
318 DeleteVariable (EFI_KEY_EXCHANGE_KEY_NAME, &gEfiGlobalVariableGuid);\r
319 DeleteVariable (EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid);\r
320 DeleteVariable (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid);\r
0c18794e 321 }\r
2d3fb919 322\r
0c18794e 323 return Status;\r
324}\r
325\r
326/**\r
327 Add public key in store and return its index.\r
328\r
329 @param[in] PubKey Input pointer to Public Key data\r
330\r
331 @return Index of new added item\r
332\r
333**/\r
334UINT32\r
335AddPubKeyInStore (\r
336 IN UINT8 *PubKey\r
337 )\r
338{\r
339 EFI_STATUS Status;\r
340 BOOLEAN IsFound;\r
341 UINT32 Index;\r
342 VARIABLE_POINTER_TRACK Variable;\r
343 UINT8 *Ptr;\r
344\r
345 if (PubKey == NULL) {\r
346 return 0;\r
347 }\r
348\r
349 Status = FindVariable (\r
350 AUTHVAR_KEYDB_NAME,\r
351 &gEfiAuthenticatedVariableGuid,\r
352 &Variable,\r
353 &mVariableModuleGlobal->VariableGlobal\r
354 );\r
355 ASSERT_EFI_ERROR (Status);\r
356 //\r
357 // Check whether the public key entry does exist.\r
358 //\r
359 IsFound = FALSE;\r
360 for (Ptr = mPubKeyStore, Index = 1; Index <= mPubKeyNumber; Index++) {\r
361 if (CompareMem (Ptr, PubKey, EFI_CERT_TYPE_RSA2048_SIZE) == 0) {\r
362 IsFound = TRUE;\r
363 break;\r
364 }\r
365 Ptr += EFI_CERT_TYPE_RSA2048_SIZE;\r
366 }\r
367\r
368 if (!IsFound) {\r
369 //\r
370 // Add public key in database.\r
371 //\r
372 if (mPubKeyNumber == MAX_KEY_NUM) {\r
373 //\r
374 // Notes: Database is full, need enhancement here, currently just return 0.\r
375 //\r
376 return 0;\r
377 }\r
378\r
379 CopyMem (mPubKeyStore + mPubKeyNumber * EFI_CERT_TYPE_RSA2048_SIZE, PubKey, EFI_CERT_TYPE_RSA2048_SIZE);\r
380 Index = ++mPubKeyNumber;\r
381 //\r
382 // Update public key database variable.\r
383 //\r
384 Status = UpdateVariable (\r
385 AUTHVAR_KEYDB_NAME,\r
386 &gEfiAuthenticatedVariableGuid,\r
387 mPubKeyStore,\r
388 mPubKeyNumber * EFI_CERT_TYPE_RSA2048_SIZE,\r
389 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS,\r
390 0,\r
391 0,\r
392 &Variable,\r
393 NULL\r
394 );\r
395 ASSERT_EFI_ERROR (Status);\r
396 }\r
397\r
398 return Index;\r
399}\r
400\r
401/**\r
402 Verify data payload with AuthInfo in EFI_CERT_TYPE_RSA2048_SHA256 type.\r
403 Follow the steps in UEFI2.2.\r
404\r
405 @param[in] Data Pointer to data with AuthInfo.\r
406 @param[in] DataSize Size of Data.\r
407 @param[in] PubKey Public key used for verification.\r
408\r
2d3fb919 409 @retval EFI_INVALID_PARAMETER Invalid parameter.\r
0c18794e 410 @retval EFI_SECURITY_VIOLATION If authentication failed.\r
2d3fb919 411 @retval EFI_SUCCESS Authentication successful.\r
0c18794e 412\r
413**/\r
414EFI_STATUS\r
415VerifyCounterBasedPayload (\r
416 IN UINT8 *Data,\r
417 IN UINTN DataSize,\r
418 IN UINT8 *PubKey\r
419 )\r
420{\r
421 BOOLEAN Status;\r
422 EFI_VARIABLE_AUTHENTICATION *CertData;\r
423 EFI_CERT_BLOCK_RSA_2048_SHA256 *CertBlock;\r
424 UINT8 Digest[SHA256_DIGEST_SIZE];\r
425 VOID *Rsa;\r
426\r
427 Rsa = NULL;\r
428 CertData = NULL;\r
429 CertBlock = NULL;\r
430\r
431 if (Data == NULL || PubKey == NULL) {\r
432 return EFI_INVALID_PARAMETER;\r
433 }\r
434\r
435 CertData = (EFI_VARIABLE_AUTHENTICATION *) Data;\r
436 CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData);\r
437\r
438 //\r
439 // wCertificateType should be WIN_CERT_TYPE_EFI_GUID.\r
440 // Cert type should be EFI_CERT_TYPE_RSA2048_SHA256.\r
441 //\r
442 if ((CertData->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID) ||\r
443 !CompareGuid (&CertData->AuthInfo.CertType, &gEfiCertRsa2048Sha256Guid)\r
444 ) {\r
445 //\r
446 // Invalid AuthInfo type, return EFI_SECURITY_VIOLATION.\r
447 //\r
448 return EFI_SECURITY_VIOLATION;\r
449 }\r
450 //\r
451 // Hash data payload with SHA256.\r
452 //\r
453 ZeroMem (Digest, SHA256_DIGEST_SIZE);\r
454 Status = Sha256Init (mHashCtx);\r
455 if (!Status) {\r
456 goto Done;\r
457 }\r
458 Status = Sha256Update (mHashCtx, Data + AUTHINFO_SIZE, (UINTN) (DataSize - AUTHINFO_SIZE));\r
459 if (!Status) {\r
460 goto Done;\r
461 }\r
462 //\r
463 // Hash Monotonic Count.\r
464 //\r
465 Status = Sha256Update (mHashCtx, &CertData->MonotonicCount, sizeof (UINT64));\r
466 if (!Status) {\r
467 goto Done;\r
468 }\r
469 Status = Sha256Final (mHashCtx, Digest);\r
470 if (!Status) {\r
471 goto Done;\r
472 }\r
473 //\r
474 // Generate & Initialize RSA Context.\r
475 //\r
476 Rsa = RsaNew ();\r
477 ASSERT (Rsa != NULL);\r
2d3fb919 478 //\r
0c18794e 479 // Set RSA Key Components.\r
480 // NOTE: Only N and E are needed to be set as RSA public key for signature verification.\r
481 //\r
482 Status = RsaSetKey (Rsa, RsaKeyN, PubKey, EFI_CERT_TYPE_RSA2048_SIZE);\r
483 if (!Status) {\r
484 goto Done;\r
485 }\r
486 Status = RsaSetKey (Rsa, RsaKeyE, mRsaE, sizeof (mRsaE));\r
487 if (!Status) {\r
488 goto Done;\r
489 }\r
490 //\r
491 // Verify the signature.\r
492 //\r
493 Status = RsaPkcs1Verify (\r
2d3fb919 494 Rsa,\r
495 Digest,\r
496 SHA256_DIGEST_SIZE,\r
497 CertBlock->Signature,\r
0c18794e 498 EFI_CERT_TYPE_RSA2048_SHA256_SIZE\r
499 );\r
500\r
501Done:\r
502 if (Rsa != NULL) {\r
503 RsaFree (Rsa);\r
504 }\r
505 if (Status) {\r
506 return EFI_SUCCESS;\r
507 } else {\r
508 return EFI_SECURITY_VIOLATION;\r
509 }\r
510}\r
511\r
0c18794e 512/**\r
513 Update platform mode.\r
514\r
515 @param[in] Mode SETUP_MODE or USER_MODE.\r
516\r
517 @return EFI_INVALID_PARAMETER Invalid parameter.\r
518 @return EFI_SUCCESS Update platform mode successfully.\r
519\r
520**/\r
521EFI_STATUS\r
522UpdatePlatformMode (\r
523 IN UINT32 Mode\r
524 )\r
525{\r
526 EFI_STATUS Status;\r
527 VARIABLE_POINTER_TRACK Variable;\r
528 UINT32 VarAttr;\r
529 UINT8 SecureBootMode;\r
beda2356 530 UINT8 SecureBootEnable;\r
531 UINTN VariableDataSize;\r
2d3fb919 532\r
0c18794e 533 Status = FindVariable (\r
2d3fb919 534 EFI_SETUP_MODE_NAME,\r
535 &gEfiGlobalVariableGuid,\r
536 &Variable,\r
0c18794e 537 &mVariableModuleGlobal->VariableGlobal\r
538 );\r
539 if (EFI_ERROR (Status)) {\r
540 return Status;\r
541 }\r
542\r
543 mPlatformMode = Mode;\r
2d3fb919 544 VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;\r
0c18794e 545 Status = UpdateVariable (\r
546 EFI_SETUP_MODE_NAME,\r
547 &gEfiGlobalVariableGuid,\r
548 &mPlatformMode,\r
549 sizeof(UINT8),\r
550 VarAttr,\r
551 0,\r
552 0,\r
553 &Variable,\r
554 NULL\r
555 );\r
556 if (EFI_ERROR (Status)) {\r
557 return Status;\r
558 }\r
559\r
2d3fb919 560 if (AtRuntime ()) {\r
561 //\r
562 // SecureBoot Variable indicates whether the platform firmware is operating\r
563 // in Secure boot mode (1) or not (0), so we should not change SecureBoot\r
564 // Variable in runtime.\r
565 //\r
566 return Status;\r
567 }\r
568\r
0c18794e 569 //\r
570 // Check "SecureBoot" variable's existence.\r
571 // If it doesn't exist, firmware has no capability to perform driver signing verification,\r
572 // then set "SecureBoot" to 0.\r
573 //\r
574 Status = FindVariable (\r
2d3fb919 575 EFI_SECURE_BOOT_MODE_NAME,\r
576 &gEfiGlobalVariableGuid,\r
577 &Variable,\r
0c18794e 578 &mVariableModuleGlobal->VariableGlobal\r
579 );\r
580 //\r
581 // If "SecureBoot" variable exists, then check "SetupMode" variable update.\r
582 // If "SetupMode" variable is USER_MODE, "SecureBoot" variable is set to 1.\r
583 // If "SetupMode" variable is SETUP_MODE, "SecureBoot" variable is set to 0.\r
584 //\r
585 if (Variable.CurrPtr == NULL) {\r
586 SecureBootMode = SECURE_BOOT_MODE_DISABLE;\r
587 } else {\r
588 if (mPlatformMode == USER_MODE) {\r
589 SecureBootMode = SECURE_BOOT_MODE_ENABLE;\r
590 } else if (mPlatformMode == SETUP_MODE) {\r
591 SecureBootMode = SECURE_BOOT_MODE_DISABLE;\r
592 } else {\r
593 return EFI_NOT_FOUND;\r
594 }\r
595 }\r
596\r
2d3fb919 597 VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;\r
beda2356 598 Status = UpdateVariable (\r
0c18794e 599 EFI_SECURE_BOOT_MODE_NAME,\r
600 &gEfiGlobalVariableGuid,\r
601 &SecureBootMode,\r
602 sizeof(UINT8),\r
603 VarAttr,\r
604 0,\r
605 0,\r
606 &Variable,\r
607 NULL\r
608 );\r
beda2356 609 if (EFI_ERROR (Status)) {\r
610 return Status;\r
611 }\r
612\r
613 //\r
614 // Check "SecureBootEnable" variable's existence. It can enable/disable secure boot feature.\r
615 //\r
616 Status = FindVariable (\r
2d3fb919 617 EFI_SECURE_BOOT_ENABLE_NAME,\r
618 &gEfiSecureBootEnableDisableGuid,\r
619 &Variable,\r
beda2356 620 &mVariableModuleGlobal->VariableGlobal\r
621 );\r
2d3fb919 622\r
beda2356 623 if (SecureBootMode == SECURE_BOOT_MODE_ENABLE) {\r
624 //\r
625 // Create the "SecureBootEnable" variable as secure boot is enabled.\r
626 //\r
627 SecureBootEnable = SECURE_BOOT_ENABLE;\r
628 VariableDataSize = sizeof (SecureBootEnable);\r
629 } else {\r
630 //\r
2d3fb919 631 // Delete the "SecureBootEnable" variable if this variable exist as "SecureBoot"\r
beda2356 632 // variable is not in secure boot state.\r
633 //\r
634 if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {\r
635 return EFI_SUCCESS;\r
636 }\r
637 SecureBootEnable = SECURE_BOOT_DISABLE;\r
638 VariableDataSize = 0;\r
639 }\r
2d3fb919 640\r
beda2356 641 Status = UpdateVariable (\r
2d3fb919 642 EFI_SECURE_BOOT_ENABLE_NAME,\r
643 &gEfiSecureBootEnableDisableGuid,\r
644 &SecureBootEnable,\r
645 VariableDataSize,\r
646 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
647 0,\r
648 0,\r
beda2356 649 &Variable,\r
650 NULL\r
651 );\r
652 return Status;\r
0c18794e 653}\r
654\r
655/**\r
656 Process variable with platform key for verification.\r
657\r
658 @param[in] VariableName Name of Variable to be found.\r
659 @param[in] VendorGuid Variable vendor GUID.\r
660 @param[in] Data Data pointer.\r
661 @param[in] DataSize Size of Data found. If size is less than the\r
662 data, this value contains the required size.\r
663 @param[in] Variable The variable information which is used to keep track of variable usage.\r
664 @param[in] Attributes Attribute value of the variable\r
665 @param[in] IsPk Indicate whether it is to process pk.\r
666\r
667 @return EFI_INVALID_PARAMETER Invalid parameter.\r
2d3fb919 668 @return EFI_SECURITY_VIOLATION The variable does NOT pass the validation.\r
669 check carried out by the firmware.\r
0c18794e 670 @return EFI_SUCCESS Variable passed validation successfully.\r
671\r
672**/\r
673EFI_STATUS\r
674ProcessVarWithPk (\r
675 IN CHAR16 *VariableName,\r
676 IN EFI_GUID *VendorGuid,\r
677 IN VOID *Data,\r
678 IN UINTN DataSize,\r
679 IN VARIABLE_POINTER_TRACK *Variable,\r
680 IN UINT32 Attributes OPTIONAL,\r
681 IN BOOLEAN IsPk\r
682 )\r
683{\r
684 EFI_STATUS Status;\r
685 VARIABLE_POINTER_TRACK PkVariable;\r
686 EFI_SIGNATURE_LIST *OldPkList;\r
687 EFI_SIGNATURE_DATA *OldPkData;\r
688 EFI_VARIABLE_AUTHENTICATION *CertData;\r
689 BOOLEAN TimeBase;\r
690 BOOLEAN Del;\r
2d3fb919 691 UINT8 *Payload;\r
692 UINTN PayloadSize;\r
693 UINT64 MonotonicCount;\r
694 EFI_TIME *TimeStamp;\r
0c18794e 695\r
696 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {\r
697 //\r
698 // PK and KEK should set EFI_VARIABLE_NON_VOLATILE attribute.\r
699 //\r
700 return EFI_INVALID_PARAMETER;\r
701 }\r
702\r
703 if (mPlatformMode == USER_MODE) {\r
704\r
705 if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
706 //\r
707 // EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute means time-based X509 Cert PK.\r
708 //\r
709 TimeBase = TRUE;\r
710 } else if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
711 //\r
712 // EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute means counter-based RSA-2048 Cert PK.\r
713 //\r
714 TimeBase = FALSE;\r
715 } else {\r
716 return EFI_INVALID_PARAMETER;\r
717 }\r
718\r
719 if (TimeBase) {\r
720 //\r
721 // Verify against X509 Cert PK.\r
722 //\r
723 Del = FALSE;\r
724 Status = VerifyTimeBasedPayload (VariableName, VendorGuid, Data, DataSize, Variable, Attributes, TRUE, &Del);\r
725 if (!EFI_ERROR (Status)) {\r
726 //\r
727 // If delete PK in user mode, need change to setup mode.\r
728 //\r
729 if (Del && IsPk) {\r
730 Status = UpdatePlatformMode (SETUP_MODE);\r
731 }\r
732 }\r
733 return Status;\r
734 } else {\r
735 //\r
736 // Verify against RSA2048 Cert PK.\r
737 //\r
738 CertData = (EFI_VARIABLE_AUTHENTICATION *) Data;\r
739 if ((Variable->CurrPtr != NULL) && (CertData->MonotonicCount <= Variable->CurrPtr->MonotonicCount)) {\r
740 //\r
741 // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.\r
742 //\r
743 return EFI_SECURITY_VIOLATION;\r
744 }\r
745 //\r
746 // Get platform key from variable.\r
747 //\r
748 Status = FindVariable (\r
2d3fb919 749 EFI_PLATFORM_KEY_NAME,\r
750 &gEfiGlobalVariableGuid,\r
751 &PkVariable,\r
0c18794e 752 &mVariableModuleGlobal->VariableGlobal\r
753 );\r
754 ASSERT_EFI_ERROR (Status);\r
2d3fb919 755\r
0c18794e 756 OldPkList = (EFI_SIGNATURE_LIST *) GetVariableDataPtr (PkVariable.CurrPtr);\r
757 OldPkData = (EFI_SIGNATURE_DATA *) ((UINT8 *) OldPkList + sizeof (EFI_SIGNATURE_LIST) + OldPkList->SignatureHeaderSize);\r
758 Status = VerifyCounterBasedPayload (Data, DataSize, OldPkData->SignatureData);\r
759 if (!EFI_ERROR (Status)) {\r
760 Status = UpdateVariable (\r
2d3fb919 761 VariableName,\r
762 VendorGuid,\r
763 (UINT8*)Data + AUTHINFO_SIZE,\r
764 DataSize - AUTHINFO_SIZE,\r
765 Attributes,\r
766 0,\r
767 CertData->MonotonicCount,\r
0c18794e 768 Variable,\r
769 NULL\r
770 );\r
2d3fb919 771\r
0c18794e 772 if (!EFI_ERROR (Status)) {\r
773 //\r
774 // If delete PK in user mode, need change to setup mode.\r
775 //\r
776 if ((DataSize == AUTHINFO_SIZE) && IsPk) {\r
777 Status = UpdatePlatformMode (SETUP_MODE);\r
778 }\r
779 }\r
780 }\r
781 }\r
782 } else {\r
2d3fb919 783 //\r
784 // Process PK or KEK in Setup mode.\r
785 //\r
786 if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
787 //\r
788 // Time-based Authentication descriptor.\r
789 //\r
790 MonotonicCount = 0;\r
791 TimeStamp = &((EFI_VARIABLE_AUTHENTICATION_2 *) Data)->TimeStamp;\r
792 Payload = (UINT8 *) Data + AUTHINFO2_SIZE (Data);\r
793 PayloadSize = DataSize - AUTHINFO2_SIZE (Data);\r
794 } else if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
795 //\r
796 // Counter-based Authentication descriptor.\r
797 //\r
798 MonotonicCount = ((EFI_VARIABLE_AUTHENTICATION *) Data)->MonotonicCount;\r
799 TimeStamp = NULL;\r
800 Payload = (UINT8*) Data + AUTHINFO_SIZE;\r
801 PayloadSize = DataSize - AUTHINFO_SIZE;\r
802 } else {\r
803 //\r
804 // No Authentication descriptor.\r
805 //\r
806 MonotonicCount = 0;\r
807 TimeStamp = NULL;\r
808 Payload = Data;\r
809 PayloadSize = DataSize;\r
810 }\r
811\r
812 Status = UpdateVariable (\r
813 VariableName,\r
814 VendorGuid,\r
815 Payload,\r
816 PayloadSize,\r
817 Attributes,\r
818 0,\r
819 MonotonicCount,\r
820 Variable,\r
821 TimeStamp\r
822 );\r
0c18794e 823 //\r
824 // If enroll PK in setup mode, need change to user mode.\r
825 //\r
826 if ((DataSize != 0) && IsPk) {\r
827 Status = UpdatePlatformMode (USER_MODE);\r
828 }\r
829 }\r
830\r
831 return Status;\r
832}\r
833\r
834/**\r
835 Process variable with key exchange key for verification.\r
836\r
837 @param[in] VariableName Name of Variable to be found.\r
838 @param[in] VendorGuid Variable vendor GUID.\r
839 @param[in] Data Data pointer.\r
840 @param[in] DataSize Size of Data found. If size is less than the\r
841 data, this value contains the required size.\r
842 @param[in] Variable The variable information which is used to keep track of variable usage.\r
843 @param[in] Attributes Attribute value of the variable.\r
844\r
845 @return EFI_INVALID_PARAMETER Invalid parameter.\r
2d3fb919 846 @return EFI_SECURITY_VIOLATION The variable does NOT pass the validation\r
847 check carried out by the firmware.\r
0c18794e 848 @return EFI_SUCCESS Variable pass validation successfully.\r
849\r
850**/\r
851EFI_STATUS\r
852ProcessVarWithKek (\r
853 IN CHAR16 *VariableName,\r
854 IN EFI_GUID *VendorGuid,\r
855 IN VOID *Data,\r
856 IN UINTN DataSize,\r
857 IN VARIABLE_POINTER_TRACK *Variable,\r
858 IN UINT32 Attributes OPTIONAL\r
859 )\r
860{\r
861 EFI_STATUS Status;\r
862 VARIABLE_POINTER_TRACK KekVariable;\r
863 EFI_SIGNATURE_LIST *KekList;\r
864 EFI_SIGNATURE_DATA *KekItem;\r
865 UINT32 KekCount;\r
866 EFI_VARIABLE_AUTHENTICATION *CertData;\r
867 EFI_CERT_BLOCK_RSA_2048_SHA256 *CertBlock;\r
868 BOOLEAN IsFound;\r
869 UINT32 Index;\r
870 UINT32 KekDataSize;\r
2d3fb919 871 UINT8 *Payload;\r
872 UINTN PayloadSize;\r
873 UINT64 MonotonicCount;\r
0c18794e 874\r
875 if (mPlatformMode == USER_MODE) {\r
876 if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == 0) {\r
877 //\r
878 // In user mode, should set EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute.\r
879 //\r
880 return EFI_INVALID_PARAMETER;\r
881 }\r
882\r
883 CertData = (EFI_VARIABLE_AUTHENTICATION *) Data;\r
884 CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData);\r
885 if ((Variable->CurrPtr != NULL) && (CertData->MonotonicCount <= Variable->CurrPtr->MonotonicCount)) {\r
886 //\r
887 // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.\r
888 //\r
889 return EFI_SECURITY_VIOLATION;\r
890 }\r
891 //\r
892 // Get KEK database from variable.\r
893 //\r
894 Status = FindVariable (\r
2d3fb919 895 EFI_KEY_EXCHANGE_KEY_NAME,\r
896 &gEfiGlobalVariableGuid,\r
897 &KekVariable,\r
0c18794e 898 &mVariableModuleGlobal->VariableGlobal\r
899 );\r
900 ASSERT_EFI_ERROR (Status);\r
901\r
902 KekDataSize = KekVariable.CurrPtr->DataSize;\r
903 KekList = (EFI_SIGNATURE_LIST *) GetVariableDataPtr (KekVariable.CurrPtr);\r
904\r
905 //\r
906 // Enumerate all Kek items in this list to verify the variable certificate data.\r
907 // If anyone is authenticated successfully, it means the variable is correct!\r
908 //\r
909 IsFound = FALSE;\r
910 while ((KekDataSize > 0) && (KekDataSize >= KekList->SignatureListSize)) {\r
911 if (CompareGuid (&KekList->SignatureType, &gEfiCertRsa2048Guid)) {\r
912 KekItem = (EFI_SIGNATURE_DATA *) ((UINT8 *) KekList + sizeof (EFI_SIGNATURE_LIST) + KekList->SignatureHeaderSize);\r
913 KekCount = (KekList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - KekList->SignatureHeaderSize) / KekList->SignatureSize;\r
914 for (Index = 0; Index < KekCount; Index++) {\r
915 if (CompareMem (KekItem->SignatureData, CertBlock->PublicKey, EFI_CERT_TYPE_RSA2048_SIZE) == 0) {\r
916 IsFound = TRUE;\r
917 break;\r
918 }\r
919 KekItem = (EFI_SIGNATURE_DATA *) ((UINT8 *) KekItem + KekList->SignatureSize);\r
920 }\r
921 }\r
922 KekDataSize -= KekList->SignatureListSize;\r
923 KekList = (EFI_SIGNATURE_LIST *) ((UINT8 *) KekList + KekList->SignatureListSize);\r
924 }\r
2d3fb919 925\r
0c18794e 926 if (!IsFound) {\r
927 return EFI_SECURITY_VIOLATION;\r
928 }\r
929\r
930 Status = VerifyCounterBasedPayload (Data, DataSize, CertBlock->PublicKey);\r
931 if (!EFI_ERROR (Status)) {\r
932 Status = UpdateVariable (\r
2d3fb919 933 VariableName,\r
934 VendorGuid,\r
935 (UINT8*)Data + AUTHINFO_SIZE,\r
936 DataSize - AUTHINFO_SIZE,\r
937 Attributes,\r
938 0,\r
939 CertData->MonotonicCount,\r
0c18794e 940 Variable,\r
941 NULL\r
942 );\r
943 }\r
944 } else {\r
945 //\r
946 // If in setup mode, no authentication needed.\r
947 //\r
2d3fb919 948 if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
949 //\r
950 // Counter-based Authentication descriptor.\r
951 //\r
952 MonotonicCount = ((EFI_VARIABLE_AUTHENTICATION *) Data)->MonotonicCount;\r
953 Payload = (UINT8*) Data + AUTHINFO_SIZE;\r
954 PayloadSize = DataSize - AUTHINFO_SIZE;\r
955 } else {\r
956 //\r
957 // No Authentication descriptor.\r
958 //\r
959 MonotonicCount = 0;\r
960 Payload = Data;\r
961 PayloadSize = DataSize;\r
962 }\r
963\r
0c18794e 964 Status = UpdateVariable (\r
2d3fb919 965 VariableName,\r
966 VendorGuid,\r
967 Payload,\r
968 PayloadSize,\r
969 Attributes,\r
970 0,\r
971 MonotonicCount,\r
0c18794e 972 Variable,\r
973 NULL\r
974 );\r
975 }\r
976\r
977 return Status;\r
978}\r
979\r
980/**\r
981 Process variable with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS/EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set\r
982\r
983 @param[in] VariableName Name of Variable to be found.\r
984 @param[in] VendorGuid Variable vendor GUID.\r
985\r
986 @param[in] Data Data pointer.\r
987 @param[in] DataSize Size of Data found. If size is less than the\r
988 data, this value contains the required size.\r
989 @param[in] Variable The variable information which is used to keep track of variable usage.\r
990 @param[in] Attributes Attribute value of the variable.\r
991\r
992 @return EFI_INVALID_PARAMETER Invalid parameter.\r
993 @return EFI_WRITE_PROTECTED Variable is write-protected and needs authentication with\r
994 EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.\r
995 @return EFI_SECURITY_VIOLATION The variable is with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS\r
2d3fb919 996 set, but the AuthInfo does NOT pass the validation\r
997 check carried out by the firmware.\r
0c18794e 998 @return EFI_SUCCESS Variable is not write-protected or pass validation successfully.\r
999\r
1000**/\r
1001EFI_STATUS\r
1002ProcessVariable (\r
1003 IN CHAR16 *VariableName,\r
1004 IN EFI_GUID *VendorGuid,\r
1005 IN VOID *Data,\r
1006 IN UINTN DataSize,\r
1007 IN VARIABLE_POINTER_TRACK *Variable,\r
1008 IN UINT32 Attributes\r
1009 )\r
1010{\r
1011 EFI_STATUS Status;\r
1012 BOOLEAN IsDeletion;\r
1013 BOOLEAN IsFirstTime;\r
1014 UINT8 *PubKey;\r
1015 EFI_VARIABLE_AUTHENTICATION *CertData;\r
1016 EFI_CERT_BLOCK_RSA_2048_SHA256 *CertBlock;\r
1017 UINT32 KeyIndex;\r
1018 UINT64 MonotonicCount;\r
1019\r
2d3fb919 1020 KeyIndex = 0;\r
0c18794e 1021 CertData = NULL;\r
1022 CertBlock = NULL;\r
1023 PubKey = NULL;\r
1024 IsDeletion = FALSE;\r
1025\r
1026 //\r
1027 // Process Time-based Authenticated variable.\r
1028 //\r
1029 if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
1030 return VerifyTimeBasedPayload (VariableName, VendorGuid, Data, DataSize, Variable, Attributes, FALSE, NULL);\r
1031 }\r
2d3fb919 1032\r
0c18794e 1033 //\r
1034 // Determine if first time SetVariable with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS.\r
1035 //\r
1036 if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
1037 //\r
1038 // Determine current operation type.\r
1039 //\r
1040 if (DataSize == AUTHINFO_SIZE) {\r
1041 IsDeletion = TRUE;\r
1042 }\r
1043 //\r
1044 // Determine whether this is the first time with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.\r
1045 //\r
1046 if (Variable->CurrPtr == NULL) {\r
1047 IsFirstTime = TRUE;\r
1048 } else if ((Variable->CurrPtr->Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == 0) {\r
1049 IsFirstTime = TRUE;\r
1050 } else {\r
1051 KeyIndex = Variable->CurrPtr->PubKeyIndex;\r
1052 IsFirstTime = FALSE;\r
1053 }\r
1054 } else if ((Variable->CurrPtr != NULL) &&\r
1055 (Variable->CurrPtr->Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0\r
1056 ) {\r
1057 //\r
1058 // If the variable is already write-protected, it always needs authentication before update.\r
1059 //\r
1060 return EFI_WRITE_PROTECTED;\r
1061 } else {\r
1062 //\r
1063 // If without EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, set and attributes collision.\r
1064 // That means it is not authenticated variable, just update variable as usual.\r
1065 //\r
1066 Status = UpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes, 0, 0, Variable, NULL);\r
1067 return Status;\r
1068 }\r
1069\r
1070 //\r
1071 // Get PubKey and check Monotonic Count value corresponding to the variable.\r
1072 //\r
1073 CertData = (EFI_VARIABLE_AUTHENTICATION *) Data;\r
1074 CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData);\r
1075 PubKey = CertBlock->PublicKey;\r
1076\r
1077 //\r
1078 // Update Monotonic Count value.\r
1079 //\r
1080 MonotonicCount = CertData->MonotonicCount;\r
1081\r
1082 if (!IsFirstTime) {\r
1083 //\r
1084 // Check input PubKey.\r
1085 //\r
1086 if (CompareMem (PubKey, mPubKeyStore + (KeyIndex - 1) * EFI_CERT_TYPE_RSA2048_SIZE, EFI_CERT_TYPE_RSA2048_SIZE) != 0) {\r
1087 return EFI_SECURITY_VIOLATION;\r
1088 }\r
1089 //\r
1090 // Compare the current monotonic count and ensure that it is greater than the last SetVariable\r
1091 // operation with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute set.\r
1092 //\r
1093 if (CertData->MonotonicCount <= Variable->CurrPtr->MonotonicCount) {\r
1094 //\r
1095 // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.\r
1096 //\r
1097 return EFI_SECURITY_VIOLATION;\r
1098 }\r
2d3fb919 1099 }\r
0c18794e 1100 //\r
1101 // Verify the certificate in Data payload.\r
1102 //\r
1103 Status = VerifyCounterBasedPayload (Data, DataSize, PubKey);\r
1104 if (EFI_ERROR (Status)) {\r
1105 return Status;\r
1106 }\r
2d3fb919 1107\r
0c18794e 1108 //\r
1109 // Now, the signature has been verified!\r
1110 //\r
1111 if (IsFirstTime && !IsDeletion) {\r
1112 //\r
1113 // Update public key database variable if need.\r
1114 //\r
1115 KeyIndex = AddPubKeyInStore (PubKey);\r
1116 }\r
1117\r
1118 //\r
1119 // Verification pass.\r
1120 //\r
1121 return UpdateVariable (VariableName, VendorGuid, (UINT8*)Data + AUTHINFO_SIZE, DataSize - AUTHINFO_SIZE, Attributes, KeyIndex, MonotonicCount, Variable, NULL);\r
1122}\r
1123\r
2d3fb919 1124/**\r
1125 Merge two buffers which formatted as EFI_SIGNATURE_LIST. Only the new EFI_SIGNATURE_DATA\r
1126 will be appended to the original EFI_SIGNATURE_LIST, duplicate EFI_SIGNATURE_DATA\r
1127 will be ignored.\r
1128\r
1129 @param[in, out] Data Pointer to original EFI_SIGNATURE_LIST.\r
1130 @param[in] DataSize Size of Data buffer.\r
1131 @param[in] NewData Pointer to new EFI_SIGNATURE_LIST to be appended.\r
1132 @param[in] NewDataSize Size of NewData buffer.\r
1133\r
1134 @return Size of the merged buffer.\r
1135\r
1136**/\r
1137UINTN\r
1138AppendSignatureList (\r
1139 IN OUT VOID *Data,\r
1140 IN UINTN DataSize,\r
1141 IN VOID *NewData,\r
1142 IN UINTN NewDataSize\r
1143 )\r
1144{\r
1145 EFI_SIGNATURE_LIST *CertList;\r
1146 EFI_SIGNATURE_DATA *Cert;\r
1147 UINTN CertCount;\r
1148 EFI_SIGNATURE_LIST *NewCertList;\r
1149 EFI_SIGNATURE_DATA *NewCert;\r
1150 UINTN NewCertCount;\r
1151 UINTN Index;\r
1152 UINTN Index2;\r
1153 UINTN Size;\r
1154 UINT8 *Tail;\r
1155 UINTN CopiedCount;\r
1156 UINTN SignatureListSize;\r
1157 BOOLEAN IsNewCert;\r
1158\r
1159 Tail = (UINT8 *) Data + DataSize;\r
1160\r
1161 NewCertList = (EFI_SIGNATURE_LIST *) NewData;\r
1162 while ((NewDataSize > 0) && (NewDataSize >= NewCertList->SignatureListSize)) {\r
1163 NewCert = (EFI_SIGNATURE_DATA *) ((UINT8 *) NewCertList + sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize);\r
1164 NewCertCount = (NewCertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - NewCertList->SignatureHeaderSize) / NewCertList->SignatureSize;\r
1165\r
1166 CopiedCount = 0;\r
1167 for (Index = 0; Index < NewCertCount; Index++) {\r
1168 IsNewCert = TRUE;\r
1169\r
1170 Size = DataSize;\r
1171 CertList = (EFI_SIGNATURE_LIST *) Data;\r
1172 while ((Size > 0) && (Size >= CertList->SignatureListSize)) {\r
1173 if (CompareGuid (&CertList->SignatureType, &NewCertList->SignatureType) &&\r
1174 (CertList->SignatureSize == NewCertList->SignatureSize)) {\r
1175 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);\r
1176 CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;\r
1177 for (Index2 = 0; Index2 < CertCount; Index2++) {\r
1178 //\r
1179 // Iterate each Signature Data in this Signature List.\r
1180 //\r
1181 if (CompareMem (NewCert, Cert, CertList->SignatureSize) == 0) {\r
1182 IsNewCert = FALSE;\r
1183 break;\r
1184 }\r
1185 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);\r
1186 }\r
1187 }\r
1188\r
1189 if (!IsNewCert) {\r
1190 break;\r
1191 }\r
1192 Size -= CertList->SignatureListSize;\r
1193 CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);\r
1194 }\r
1195\r
1196 if (IsNewCert) {\r
1197 //\r
1198 // New EFI_SIGNATURE_DATA, append it.\r
1199 //\r
1200 if (CopiedCount == 0) {\r
1201 //\r
1202 // Copy EFI_SIGNATURE_LIST header for only once.\r
1203 //\r
1204 CopyMem (Tail, NewCertList, sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize);\r
1205 Tail = Tail + sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize;\r
1206 }\r
1207\r
1208 CopyMem (Tail, NewCert, NewCertList->SignatureSize);\r
1209 Tail += NewCertList->SignatureSize;\r
1210 CopiedCount++;\r
1211 }\r
1212\r
1213 NewCert = (EFI_SIGNATURE_DATA *) ((UINT8 *) NewCert + NewCertList->SignatureSize);\r
1214 }\r
1215\r
1216 //\r
1217 // Update SignatureListSize in newly appended EFI_SIGNATURE_LIST.\r
1218 //\r
1219 if (CopiedCount != 0) {\r
1220 SignatureListSize = sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize + (CopiedCount * NewCertList->SignatureSize);\r
1221 CertList = (EFI_SIGNATURE_LIST *) (Tail - SignatureListSize);\r
1222 CertList->SignatureListSize = (UINT32) SignatureListSize;\r
1223 }\r
1224\r
1225 NewDataSize -= NewCertList->SignatureListSize;\r
1226 NewCertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) NewCertList + NewCertList->SignatureListSize);\r
1227 }\r
1228\r
1229 return (Tail - (UINT8 *) Data);\r
1230}\r
1231\r
0c18794e 1232/**\r
1233 Compare two EFI_TIME data.\r
1234\r
1235\r
1236 @param FirstTime A pointer to the first EFI_TIME data.\r
1237 @param SecondTime A pointer to the second EFI_TIME data.\r
1238\r
1239 @retval TRUE The FirstTime is not later than the SecondTime.\r
1240 @retval FALSE The FirstTime is later than the SecondTime.\r
1241\r
1242**/\r
1243BOOLEAN\r
1244CompareTimeStamp (\r
1245 IN EFI_TIME *FirstTime,\r
1246 IN EFI_TIME *SecondTime\r
1247 )\r
1248{\r
1249 if (FirstTime->Year != SecondTime->Year) {\r
1250 return (BOOLEAN) (FirstTime->Year < SecondTime->Year);\r
1251 } else if (FirstTime->Month != SecondTime->Month) {\r
1252 return (BOOLEAN) (FirstTime->Month < SecondTime->Month);\r
1253 } else if (FirstTime->Day != SecondTime->Day) {\r
1254 return (BOOLEAN) (FirstTime->Day < SecondTime->Day);\r
1255 } else if (FirstTime->Hour != SecondTime->Hour) {\r
1256 return (BOOLEAN) (FirstTime->Hour < SecondTime->Hour);\r
1257 } else if (FirstTime->Minute != SecondTime->Minute) {\r
1258 return (BOOLEAN) (FirstTime->Minute < FirstTime->Minute);\r
2d3fb919 1259 }\r
0c18794e 1260\r
1261 return (BOOLEAN) (FirstTime->Second <= SecondTime->Second);\r
1262}\r
1263\r
1264/**\r
1265 Process variable with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set\r
1266\r
1267 @param[in] VariableName Name of Variable to be found.\r
1268 @param[in] VendorGuid Variable vendor GUID.\r
1269 @param[in] Data Data pointer.\r
1270 @param[in] DataSize Size of Data found. If size is less than the\r
1271 data, this value contains the required size.\r
1272 @param[in] Variable The variable information which is used to keep track of variable usage.\r
1273 @param[in] Attributes Attribute value of the variable.\r
1274 @param[in] Pk Verify against PK or KEK database.\r
1275 @param[out] VarDel Delete the variable or not.\r
1276\r
1277 @retval EFI_INVALID_PARAMETER Invalid parameter.\r
2d3fb919 1278 @retval EFI_SECURITY_VIOLATION The variable does NOT pass the validation\r
1279 check carried out by the firmware.\r
0c18794e 1280 @retval EFI_OUT_OF_RESOURCES Failed to process variable due to lack\r
1281 of resources.\r
1282 @retval EFI_SUCCESS Variable pass validation successfully.\r
1283\r
1284**/\r
1285EFI_STATUS\r
1286VerifyTimeBasedPayload (\r
1287 IN CHAR16 *VariableName,\r
1288 IN EFI_GUID *VendorGuid,\r
1289 IN VOID *Data,\r
1290 IN UINTN DataSize,\r
1291 IN VARIABLE_POINTER_TRACK *Variable,\r
1292 IN UINT32 Attributes,\r
1293 IN BOOLEAN Pk,\r
1294 OUT BOOLEAN *VarDel\r
1295 )\r
1296{\r
1297 UINT8 *RootCert;\r
1298 UINT8 *SigData;\r
2d3fb919 1299 UINT8 *PayloadPtr;\r
0c18794e 1300 UINTN RootCertSize;\r
1301 UINTN Index;\r
2d3fb919 1302 UINTN CertCount;\r
1303 UINTN PayloadSize;\r
0c18794e 1304 UINT32 Attr;\r
1305 UINT32 SigDataSize;\r
1306 UINT32 KekDataSize;\r
1307 BOOLEAN Result;\r
1308 BOOLEAN VerifyStatus;\r
1309 EFI_STATUS Status;\r
1310 EFI_SIGNATURE_LIST *CertList;\r
1311 EFI_SIGNATURE_DATA *Cert;\r
1312 VARIABLE_POINTER_TRACK KekVariable;\r
1313 EFI_VARIABLE_AUTHENTICATION_2 *CertData;\r
1314 UINT8 *NewData;\r
1315 UINTN NewDataSize;\r
1316 VARIABLE_POINTER_TRACK PkVariable;\r
2d3fb919 1317 UINT8 *Buffer;\r
1318 UINTN Length;\r
0c18794e 1319\r
1320 Result = FALSE;\r
1321 VerifyStatus = FALSE;\r
1322 CertData = NULL;\r
1323 NewData = NULL;\r
1324 Attr = Attributes;\r
1325\r
1326 //\r
2d3fb919 1327 // When the attribute EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS is\r
0c18794e 1328 // set, then the Data buffer shall begin with an instance of a complete (and serialized)\r
2d3fb919 1329 // EFI_VARIABLE_AUTHENTICATION_2 descriptor. The descriptor shall be followed by the new\r
1330 // variable value and DataSize shall reflect the combined size of the descriptor and the new\r
1331 // variable value. The authentication descriptor is not part of the variable data and is not\r
0c18794e 1332 // returned by subsequent calls to GetVariable().\r
1333 //\r
1334 CertData = (EFI_VARIABLE_AUTHENTICATION_2 *) Data;\r
2d3fb919 1335\r
1336 //\r
1337 // Verify that Pad1, Nanosecond, TimeZone, Daylight and Pad2 components of the\r
1338 // TimeStamp value are set to zero.\r
1339 //\r
1340 if ((CertData->TimeStamp.Pad1 != 0) ||\r
1341 (CertData->TimeStamp.Nanosecond != 0) ||\r
1342 (CertData->TimeStamp.TimeZone != 0) ||\r
1343 (CertData->TimeStamp.Daylight != 0) ||\r
1344 (CertData->TimeStamp.Pad2 != 0)) {\r
1345 return EFI_INVALID_PARAMETER;\r
1346 }\r
1347\r
0c18794e 1348 if ((Variable->CurrPtr != NULL) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0)) {\r
1349 if (CompareTimeStamp (&CertData->TimeStamp, &Variable->CurrPtr->TimeStamp)) {\r
1350 //\r
1351 // TimeStamp check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.\r
1352 //\r
1353 return EFI_SECURITY_VIOLATION;\r
1354 }\r
1355 }\r
1356\r
1357 //\r
1358 // wCertificateType should be WIN_CERT_TYPE_EFI_GUID.\r
1359 // Cert type should be EFI_CERT_TYPE_PKCS7_GUID.\r
1360 //\r
1361 if ((CertData->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID) ||\r
2d3fb919 1362 !CompareGuid (&CertData->AuthInfo.CertType, &gEfiCertPkcs7Guid)) {\r
0c18794e 1363 //\r
1364 // Invalid AuthInfo type, return EFI_SECURITY_VIOLATION.\r
1365 //\r
1366 return EFI_SECURITY_VIOLATION;\r
1367 }\r
2d3fb919 1368\r
0c18794e 1369 //\r
1370 // Find out Pkcs7 SignedData which follows the EFI_VARIABLE_AUTHENTICATION_2 descriptor.\r
1371 // AuthInfo.Hdr.dwLength is the length of the entire certificate, including the length of the header.\r
1372 //\r
2d3fb919 1373 SigData = CertData->AuthInfo.CertData;\r
1374 SigDataSize = CertData->AuthInfo.Hdr.dwLength - (UINT32) (OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData));\r
648f98d1 1375\r
0c18794e 1376 //\r
1377 // Find out the new data payload which follows Pkcs7 SignedData directly.\r
1378 //\r
2d3fb919 1379 PayloadPtr = SigData + SigDataSize;\r
1380 PayloadSize = DataSize - OFFSET_OF_AUTHINFO2_CERT_DATA - (UINTN) SigDataSize;\r
0c18794e 1381\r
1382 //\r
1383 // Construct a buffer to fill with (VariableName, VendorGuid, Attributes, TimeStamp, Data).\r
1384 //\r
2d3fb919 1385 NewDataSize = PayloadSize + sizeof (EFI_TIME) + sizeof (UINT32) +\r
1386 sizeof (EFI_GUID) + StrSize (VariableName) - sizeof (CHAR16);\r
1387 NewData = mSerializationRuntimeBuffer;\r
0c18794e 1388\r
2d3fb919 1389 Buffer = NewData;\r
1390 Length = StrLen (VariableName) * sizeof (CHAR16);\r
1391 CopyMem (Buffer, VariableName, Length);\r
1392 Buffer += Length;\r
0c18794e 1393\r
2d3fb919 1394 Length = sizeof (EFI_GUID);\r
1395 CopyMem (Buffer, VendorGuid, Length);\r
1396 Buffer += Length;\r
0c18794e 1397\r
2d3fb919 1398 Length = sizeof (UINT32);\r
1399 CopyMem (Buffer, &Attr, Length);\r
1400 Buffer += Length;\r
0c18794e 1401\r
2d3fb919 1402 Length = sizeof (EFI_TIME);\r
1403 CopyMem (Buffer, &CertData->TimeStamp, Length);\r
1404 Buffer += Length;\r
0c18794e 1405\r
2d3fb919 1406 CopyMem (Buffer, PayloadPtr, PayloadSize);\r
0c18794e 1407\r
1408 if (Pk) {\r
1409 //\r
1410 // Get platform key from variable.\r
1411 //\r
1412 Status = FindVariable (\r
2d3fb919 1413 EFI_PLATFORM_KEY_NAME,\r
1414 &gEfiGlobalVariableGuid,\r
1415 &PkVariable,\r
0c18794e 1416 &mVariableModuleGlobal->VariableGlobal\r
1417 );\r
1418 if (EFI_ERROR (Status)) {\r
1419 return Status;\r
1420 }\r
1421\r
1422 CertList = (EFI_SIGNATURE_LIST *) GetVariableDataPtr (PkVariable.CurrPtr);\r
1423 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);\r
1424 RootCert = Cert->SignatureData;\r
1425 RootCertSize = CertList->SignatureSize;\r
1426\r
1427\r
1428 //\r
1429 // Verify Pkcs7 SignedData via Pkcs7Verify library.\r
1430 //\r
1431 VerifyStatus = Pkcs7Verify (\r
1432 SigData,\r
1433 SigDataSize,\r
1434 RootCert,\r
1435 RootCertSize,\r
1436 NewData,\r
1437 NewDataSize\r
1438 );\r
1439\r
1440 } else {\r
2d3fb919 1441\r
0c18794e 1442 //\r
1443 // Get KEK database from variable.\r
1444 //\r
1445 Status = FindVariable (\r
2d3fb919 1446 EFI_KEY_EXCHANGE_KEY_NAME,\r
1447 &gEfiGlobalVariableGuid,\r
1448 &KekVariable,\r
0c18794e 1449 &mVariableModuleGlobal->VariableGlobal\r
1450 );\r
1451 if (EFI_ERROR (Status)) {\r
1452 return Status;\r
1453 }\r
1454\r
1455 //\r
1456 // Ready to verify Pkcs7 SignedData. Go through KEK Signature Database to find out X.509 CertList.\r
2d3fb919 1457 //\r
0c18794e 1458 KekDataSize = KekVariable.CurrPtr->DataSize;\r
1459 CertList = (EFI_SIGNATURE_LIST *) GetVariableDataPtr (KekVariable.CurrPtr);\r
1460 while ((KekDataSize > 0) && (KekDataSize >= CertList->SignatureListSize)) {\r
1461 if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) {\r
1462 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);\r
1463 CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;\r
1464 for (Index = 0; Index < CertCount; Index++) {\r
1465 //\r
1466 // Iterate each Signature Data Node within this CertList for a verify\r
1467 //\r
1468 RootCert = Cert->SignatureData;\r
1469 RootCertSize = CertList->SignatureSize;\r
2d3fb919 1470\r
0c18794e 1471 //\r
1472 // Verify Pkcs7 SignedData via Pkcs7Verify library.\r
1473 //\r
1474 VerifyStatus = Pkcs7Verify (\r
1475 SigData,\r
1476 SigDataSize,\r
1477 RootCert,\r
1478 RootCertSize,\r
1479 NewData,\r
1480 NewDataSize\r
1481 );\r
1482 if (VerifyStatus) {\r
1483 goto Exit;\r
1484 }\r
1485 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);\r
1486 }\r
1487 }\r
1488 KekDataSize -= CertList->SignatureListSize;\r
1489 CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);\r
1490 }\r
1491 }\r
1492\r
1493Exit:\r
1494\r
0c18794e 1495 if (!VerifyStatus) {\r
1496 return EFI_SECURITY_VIOLATION;\r
1497 }\r
1498\r
2d3fb919 1499 if ((PayloadSize == 0) && (VarDel != NULL)) {\r
0c18794e 1500 *VarDel = TRUE;\r
1501 }\r
2d3fb919 1502\r
0c18794e 1503 //\r
1504 // Final step: Update/Append Variable if it pass Pkcs7Verify\r
1505 //\r
1506 return UpdateVariable (\r
2d3fb919 1507 VariableName,\r
1508 VendorGuid,\r
1509 PayloadPtr,\r
1510 PayloadSize,\r
1511 Attributes,\r
1512 0,\r
1513 0,\r
0c18794e 1514 Variable,\r
1515 &CertData->TimeStamp\r
1516 );\r
1517}\r