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