]> git.proxmox.com Git - mirror_edk2.git/blame - SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/AuthService.c
Change IPF version AuthVariable driver to support multiple-platform feature.
[mirror_edk2.git] / SecurityPkg / VariableAuthenticated / EsalVariableDxeSal / 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
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
9http://opensource.org/licenses/bsd-license.php\r
10\r
11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
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
21///\r
22UINT32 mPubKeyNumber;\r
23UINT32 mPlatformMode;\r
24EFI_GUID mSignatureSupport[SIGSUPPORT_NUM] = {EFI_CERT_RSA2048_SHA256_GUID, EFI_CERT_RSA2048_SHA1_GUID};\r
25//\r
26// Public Exponent of RSA Key.\r
27//\r
28CONST UINT8 mRsaE[] = { 0x01, 0x00, 0x01 };\r
29\r
30/**\r
31 Initializes for authenticated varibale service.\r
32\r
33 @retval EFI_SUCCESS The function successfully executed.\r
34 @retval EFI_OUT_OF_RESOURCES Failed to allocate enough memory resources.\r
35\r
36**/\r
37EFI_STATUS\r
38AutenticatedVariableServiceInitialize (\r
39 VOID\r
40 )\r
41{\r
42 EFI_STATUS Status;\r
43 VARIABLE_POINTER_TRACK Variable;\r
44 UINT8 VarValue;\r
45 UINT32 VarAttr;\r
46 UINTN DataSize;\r
47 UINTN CtxSize;\r
48 VARIABLE_HEADER VariableHeader;\r
49 BOOLEAN Valid;\r
50\r
51 mVariableModuleGlobal->AuthenticatedVariableGuid[Physical] = &gEfiAuthenticatedVariableGuid;\r
52 mVariableModuleGlobal->CertRsa2048Sha256Guid[Physical] = &gEfiCertRsa2048Sha256Guid;\r
53 mVariableModuleGlobal->ImageSecurityDatabaseGuid[Physical] = &gEfiImageSecurityDatabaseGuid;\r
54\r
55 //\r
56 // Initialize hash context.\r
57 //\r
58 CtxSize = Sha256GetContextSize ();\r
59 mVariableModuleGlobal->HashContext[Physical] = AllocateRuntimePool (CtxSize);\r
60 ASSERT (mVariableModuleGlobal->HashContext[Physical] != NULL);\r
61 //\r
62 // Check "AuthVarKeyDatabase" variable's existence. \r
63 // If it doesn't exist, create a new one with initial value of 0 and EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set. \r
64 //\r
65 Status = FindVariable (\r
66 mVariableModuleGlobal->VariableName[Physical][VAR_AUTH_KEY_DB], \r
67 &gEfiAuthenticatedVariableGuid, \r
68 &Variable, \r
69 &mVariableModuleGlobal->VariableGlobal[Physical],\r
70 mVariableModuleGlobal->FvbInstance\r
71 );\r
72\r
73 if (Variable.CurrPtr == 0x0) {\r
74 VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;\r
75 VarValue = 0;\r
76 mPubKeyNumber = 0;\r
77 Status = UpdateVariable (\r
78 mVariableModuleGlobal->VariableName[Physical][VAR_AUTH_KEY_DB],\r
79 &gEfiAuthenticatedVariableGuid,\r
80 &VarValue,\r
81 sizeof(UINT8),\r
82 VarAttr,\r
83 0,\r
84 0,\r
85 FALSE,\r
86 mVariableModuleGlobal,\r
87 &Variable\r
88 );\r
89 if (EFI_ERROR (Status)) {\r
90 return Status;\r
91 }\r
92 } else {\r
93 //\r
94 // Load database in global variable for cache.\r
95 //\r
96 Valid = IsValidVariableHeader (\r
97 Variable.CurrPtr, \r
98 Variable.Volatile, \r
99 &mVariableModuleGlobal->VariableGlobal[Physical], \r
100 mVariableModuleGlobal->FvbInstance, \r
101 &VariableHeader\r
102 );\r
103 ASSERT (Valid);\r
104\r
105 DataSize = DataSizeOfVariable (&VariableHeader);\r
106 ASSERT (DataSize <= MAX_KEYDB_SIZE);\r
107 GetVariableDataPtr (\r
108 Variable.CurrPtr,\r
109 Variable.Volatile,\r
110 &mVariableModuleGlobal->VariableGlobal[Physical],\r
111 mVariableModuleGlobal->FvbInstance,\r
112 (CHAR16 *) mVariableModuleGlobal->PubKeyStore\r
113 );\r
114\r
115 mPubKeyNumber = (UINT32) (DataSize / EFI_CERT_TYPE_RSA2048_SIZE);\r
116 }\r
117 //\r
118 // Check "SetupMode" variable's existence. \r
119 // If it doesn't exist, check PK database's existence to determine the value.\r
120 // Then create a new one with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set. \r
121 //\r
122 Status = FindVariable (\r
123 mVariableModuleGlobal->VariableName[Physical][VAR_SETUP_MODE], \r
124 &gEfiGlobalVariableGuid, \r
125 &Variable, \r
126 &mVariableModuleGlobal->VariableGlobal[Physical],\r
127 mVariableModuleGlobal->FvbInstance\r
128 );\r
129\r
130 if (Variable.CurrPtr == 0x0) {\r
131 Status = FindVariable (\r
132 mVariableModuleGlobal->VariableName[Physical][VAR_PLATFORM_KEY], \r
133 &gEfiGlobalVariableGuid, \r
134 &Variable, \r
135 &mVariableModuleGlobal->VariableGlobal[Physical],\r
136 mVariableModuleGlobal->FvbInstance\r
137 );\r
138 if (Variable.CurrPtr == 0x0) {\r
139 mPlatformMode = SETUP_MODE;\r
140 } else {\r
141 mPlatformMode = USER_MODE;\r
142 }\r
143\r
144 VarAttr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;\r
145 Status = UpdateVariable (\r
146 mVariableModuleGlobal->VariableName[Physical][VAR_SETUP_MODE],\r
147 &gEfiGlobalVariableGuid,\r
148 &mPlatformMode,\r
149 sizeof(UINT8),\r
150 VarAttr,\r
151 0,\r
152 0,\r
153 FALSE,\r
154 mVariableModuleGlobal,\r
155 &Variable\r
156 );\r
157 if (EFI_ERROR (Status)) {\r
158 return Status;\r
159 }\r
160 } else {\r
161 GetVariableDataPtr (\r
162 Variable.CurrPtr,\r
163 Variable.Volatile,\r
164 &mVariableModuleGlobal->VariableGlobal[Physical],\r
165 mVariableModuleGlobal->FvbInstance,\r
166 (CHAR16 *) &mPlatformMode\r
167 );\r
168 }\r
169 //\r
170 // Check "SignatureSupport" variable's existence. \r
171 // If it doesn't exist, then create a new one with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set. \r
172 //\r
173 Status = FindVariable (\r
174 EFI_SIGNATURE_SUPPORT_NAME, \r
175 &gEfiGlobalVariableGuid, \r
176 &Variable, \r
177 &mVariableModuleGlobal->VariableGlobal[Physical],\r
178 mVariableModuleGlobal->FvbInstance\r
179 );\r
180\r
181 if (Variable.CurrPtr == 0x0) {\r
182 VarAttr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;\r
183 Status = UpdateVariable (\r
184 EFI_SIGNATURE_SUPPORT_NAME,\r
185 &gEfiGlobalVariableGuid,\r
186 mSignatureSupport,\r
187 SIGSUPPORT_NUM * sizeof(EFI_GUID),\r
188 VarAttr,\r
189 0,\r
190 0,\r
191 FALSE,\r
192 mVariableModuleGlobal,\r
193 &Variable\r
194 );\r
195 }\r
196\r
197 return Status;\r
198}\r
199\r
200/**\r
201 Add public key in store and return its index.\r
202\r
203 @param[in] VirtualMode The current calling mode for this function.\r
204 @param[in] Global The context of this Extended SAL Variable Services Class call.\r
205 @param[in] PubKey The input pointer to Public Key data.\r
206\r
207 @return The index of new added item.\r
208\r
209**/\r
210UINT32\r
211AddPubKeyInStore (\r
212 IN BOOLEAN VirtualMode,\r
213 IN ESAL_VARIABLE_GLOBAL *Global,\r
214 IN UINT8 *PubKey\r
215 )\r
216{\r
217 EFI_STATUS Status;\r
218 BOOLEAN IsFound;\r
219 UINT32 Index;\r
220 VARIABLE_POINTER_TRACK Variable;\r
221 UINT8 *Ptr;\r
222\r
223 if (PubKey == NULL) {\r
224 return 0;\r
225 }\r
226\r
227 Status = FindVariable (\r
228 Global->VariableName[VirtualMode][VAR_AUTH_KEY_DB],\r
229 Global->AuthenticatedVariableGuid[VirtualMode],\r
230 &Variable,\r
231 &Global->VariableGlobal[VirtualMode],\r
232 Global->FvbInstance\r
233 );\r
234 ASSERT_EFI_ERROR (Status);\r
235 //\r
236 // Check whether the public key entry does exist.\r
237 //\r
238 IsFound = FALSE;\r
239 for (Ptr = Global->PubKeyStore, Index = 1; Index <= mPubKeyNumber; Index++) {\r
240 if (CompareMem (Ptr, PubKey, EFI_CERT_TYPE_RSA2048_SIZE) == 0) {\r
241 IsFound = TRUE;\r
242 break;\r
243 }\r
244 Ptr += EFI_CERT_TYPE_RSA2048_SIZE;\r
245 }\r
246\r
247 if (!IsFound) {\r
248 //\r
249 // Add public key in database.\r
250 //\r
251 if (mPubKeyNumber == MAX_KEY_NUM) {\r
252 //\r
253 // Notes: Database is full, need enhancement here, currently just return 0.\r
254 //\r
255 return 0;\r
256 }\r
257\r
258 CopyMem (Global->PubKeyStore + mPubKeyNumber * EFI_CERT_TYPE_RSA2048_SIZE, PubKey, EFI_CERT_TYPE_RSA2048_SIZE);\r
259 Index = ++mPubKeyNumber;\r
260 //\r
261 // Update public key database variable.\r
262 //\r
263 Status = UpdateVariable (\r
264 Global->VariableName[VirtualMode][VAR_AUTH_KEY_DB],\r
265 Global->AuthenticatedVariableGuid[VirtualMode],\r
266 Global->PubKeyStore,\r
267 mPubKeyNumber * EFI_CERT_TYPE_RSA2048_SIZE,\r
268 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS,\r
269 0,\r
270 0,\r
271 VirtualMode,\r
272 Global,\r
273 &Variable\r
274 );\r
275 ASSERT_EFI_ERROR (Status);\r
276 }\r
277\r
278 return Index;\r
279}\r
280\r
281/**\r
282 Verify data payload with AuthInfo in EFI_CERT_TYPE_RSA2048_SHA256 type.\r
283 Follow the steps in UEFI2.2.\r
284\r
285 @param[in] VirtualMode The current calling mode for this function.\r
286 @param[in] Global The context of this Extended SAL Variable Services Class call.\r
287 @param[in] Data The pointer to data with AuthInfo.\r
288 @param[in] DataSize The size of Data.\r
289 @param[in] PubKey The public key used for verification.\r
290\r
291 @retval EFI_INVALID_PARAMETER Invalid parameter.\r
292 @retval EFI_SECURITY_VIOLATION Authentication failed.\r
293 @retval EFI_SUCCESS Authentication successful.\r
294\r
295**/\r
296EFI_STATUS\r
297VerifyDataPayload (\r
298 IN BOOLEAN VirtualMode,\r
299 IN ESAL_VARIABLE_GLOBAL *Global,\r
300 IN UINT8 *Data,\r
301 IN UINTN DataSize,\r
302 IN UINT8 *PubKey\r
303 )\r
304{\r
305 BOOLEAN Status;\r
306 EFI_VARIABLE_AUTHENTICATION *CertData;\r
307 EFI_CERT_BLOCK_RSA_2048_SHA256 *CertBlock;\r
308 UINT8 Digest[SHA256_DIGEST_SIZE];\r
309 VOID *Rsa;\r
310 VOID *HashContext;\r
311\r
312 Rsa = NULL;\r
313 CertData = NULL;\r
314 CertBlock = NULL;\r
315\r
316 if (Data == NULL || PubKey == NULL) {\r
317 return EFI_INVALID_PARAMETER;\r
318 }\r
319\r
320 CertData = (EFI_VARIABLE_AUTHENTICATION *) Data;\r
321 CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData);\r
322\r
323 //\r
324 // wCertificateType should be WIN_CERT_TYPE_EFI_GUID.\r
325 // Cert type should be EFI_CERT_TYPE_RSA2048_SHA256.\r
326 //\r
327 if ((CertData->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID) ||\r
328 !CompareGuid (&CertData->AuthInfo.CertType, Global->CertRsa2048Sha256Guid[VirtualMode])\r
329 ) {\r
330 //\r
331 // Invalid AuthInfo type, return EFI_SECURITY_VIOLATION.\r
332 //\r
333 return EFI_SECURITY_VIOLATION;\r
334 }\r
335\r
336 //\r
337 // Hash data payload with SHA256.\r
338 //\r
339 ZeroMem (Digest, SHA256_DIGEST_SIZE);\r
340 HashContext = Global->HashContext[VirtualMode];\r
341 Status = Sha256Init (HashContext);\r
342 if (!Status) {\r
343 goto Done;\r
344 }\r
345 Status = Sha256Update (HashContext, Data + AUTHINFO_SIZE, (UINTN) (DataSize - AUTHINFO_SIZE));\r
346 if (!Status) {\r
347 goto Done;\r
348 }\r
349 //\r
350 // Hash Monotonic Count.\r
351 //\r
352 Status = Sha256Update (HashContext, &CertData->MonotonicCount, sizeof (UINT64));\r
353 if (!Status) {\r
354 goto Done;\r
355 }\r
356 Status = Sha256Final (HashContext, Digest);\r
357 if (!Status) {\r
358 goto Done;\r
359 }\r
360 //\r
361 // Generate & Initialize RSA Context.\r
362 //\r
363 Rsa = RsaNew ();\r
364 ASSERT (Rsa != NULL);\r
365 // \r
366 // Set RSA Key Components.\r
367 // NOTE: Only N and E are needed to be set as RSA public key for signature verification.\r
368 //\r
369 Status = RsaSetKey (Rsa, RsaKeyN, PubKey, EFI_CERT_TYPE_RSA2048_SIZE);\r
370 if (!Status) {\r
371 goto Done;\r
372 }\r
373 Status = RsaSetKey (Rsa, RsaKeyE, mRsaE, sizeof (mRsaE));\r
374 if (!Status) {\r
375 goto Done;\r
376 }\r
377 //\r
378 // Verify the signature.\r
379 //\r
380 Status = RsaPkcs1Verify (\r
381 Rsa, \r
382 Digest, \r
383 SHA256_DIGEST_SIZE, \r
384 CertBlock->Signature, \r
385 EFI_CERT_TYPE_RSA2048_SHA256_SIZE\r
386 );\r
387\r
388Done:\r
389 if (Rsa != NULL) {\r
390 RsaFree (Rsa);\r
391 }\r
392 if (Status) {\r
393 return EFI_SUCCESS;\r
394 } else {\r
395 return EFI_SECURITY_VIOLATION;\r
396 }\r
397}\r
398\r
399\r
400/**\r
401 Update platform mode.\r
402\r
403 @param[in] VirtualMode The current calling mode for this function.\r
404 @param[in] Global The context of this Extended SAL Variable Services Class call.\r
405 @param[in] Mode SETUP_MODE or USER_MODE.\r
406\r
407**/\r
408VOID\r
409UpdatePlatformMode (\r
410 IN BOOLEAN VirtualMode,\r
411 IN ESAL_VARIABLE_GLOBAL *Global,\r
412 IN UINT32 Mode\r
413 )\r
414{\r
415 EFI_STATUS Status;\r
416 VARIABLE_POINTER_TRACK Variable;\r
417 UINT32 VarAttr;\r
418\r
419 Status = FindVariable (\r
420 Global->VariableName[VirtualMode][VAR_SETUP_MODE], \r
421 Global->GlobalVariableGuid[VirtualMode], \r
422 &Variable, \r
423 &Global->VariableGlobal[VirtualMode],\r
424 Global->FvbInstance\r
425 );\r
426 ASSERT_EFI_ERROR (Status);\r
427\r
428 mPlatformMode = Mode;\r
429 VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;\r
430 Status = UpdateVariable (\r
431 Global->VariableName[VirtualMode][VAR_SETUP_MODE],\r
432 Global->GlobalVariableGuid[VirtualMode],\r
433 &mPlatformMode,\r
434 sizeof(UINT8),\r
435 VarAttr,\r
436 0,\r
437 0,\r
438 VirtualMode,\r
439 Global,\r
440 &Variable\r
441 );\r
442 ASSERT_EFI_ERROR (Status);\r
443}\r
444\r
445/**\r
446 Process variable with platform key for verification.\r
447\r
448 @param[in] VariableName The name of Variable to be found.\r
449 @param[in] VendorGuid The variable vendor GUID.\r
450 @param[in] Data The data pointer.\r
451 @param[in] DataSize The size of Data found. If size is less than the\r
452 data, this value contains the required size.\r
453 @param[in] VirtualMode The current calling mode for this function.\r
454 @param[in] Global The context of this Extended SAL Variable Services Class call.\r
455 @param[in] Variable The variable information which is used to keep track of variable usage.\r
456 @param[in] Attributes The attribute value of the variable.\r
457 @param[in] IsPk Indicates whether to process pk.\r
458\r
459 @retval EFI_INVALID_PARAMETER Invalid parameter.\r
460 @retval EFI_SECURITY_VIOLATION The variable does NOT pass the validation \r
461 check carried out by the firmware. \r
462 @retval EFI_SUCCESS The variable passed validation successfully.\r
463\r
464**/\r
465EFI_STATUS\r
466ProcessVarWithPk (\r
467 IN CHAR16 *VariableName,\r
468 IN EFI_GUID *VendorGuid,\r
469 IN VOID *Data,\r
470 IN UINTN DataSize,\r
471 IN BOOLEAN VirtualMode,\r
472 IN ESAL_VARIABLE_GLOBAL *Global,\r
473 IN VARIABLE_POINTER_TRACK *Variable,\r
474 IN UINT32 Attributes OPTIONAL,\r
475 IN BOOLEAN IsPk\r
476 )\r
477{\r
478 EFI_STATUS Status;\r
479 VARIABLE_POINTER_TRACK PkVariable;\r
480 EFI_SIGNATURE_LIST *OldPkList;\r
481 EFI_SIGNATURE_DATA *OldPkData;\r
482 EFI_VARIABLE_AUTHENTICATION *CertData;\r
483 VARIABLE_HEADER VariableHeader;\r
484 BOOLEAN Valid;\r
485\r
486 OldPkList = NULL;\r
487\r
488 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {\r
489 //\r
490 // PK and KEK should set EFI_VARIABLE_NON_VOLATILE attribute.\r
491 //\r
492 return EFI_INVALID_PARAMETER;\r
493 }\r
494\r
495 if (mPlatformMode == USER_MODE) {\r
496 if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == 0) {\r
497 //\r
498 // In user mode, PK and KEK should set EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute.\r
499 //\r
500 return EFI_INVALID_PARAMETER;\r
501 }\r
502\r
503 CertData = (EFI_VARIABLE_AUTHENTICATION *) Data;\r
504\r
505 if (Variable->CurrPtr != 0x0) {\r
506 Valid = IsValidVariableHeader (\r
507 Variable->CurrPtr, \r
508 Variable->Volatile, \r
509 &Global->VariableGlobal[VirtualMode], \r
510 Global->FvbInstance, \r
511 &VariableHeader\r
512 );\r
513 ASSERT (Valid);\r
514\r
515 if (CertData->MonotonicCount <= VariableHeader.MonotonicCount) {\r
516 //\r
517 // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.\r
518 //\r
519 return EFI_SECURITY_VIOLATION;\r
520 }\r
521 }\r
522 //\r
523 // Get platform key from variable.\r
524 //\r
525 Status = FindVariable (\r
526 Global->VariableName[VirtualMode][VAR_PLATFORM_KEY], \r
527 Global->GlobalVariableGuid[VirtualMode], \r
528 &PkVariable, \r
529 &Global->VariableGlobal[VirtualMode],\r
530 Global->FvbInstance\r
531 );\r
532 ASSERT_EFI_ERROR (Status);\r
533\r
534 ZeroMem (Global->KeyList, MAX_KEYDB_SIZE);\r
535 GetVariableDataPtr (\r
536 PkVariable.CurrPtr,\r
537 PkVariable.Volatile,\r
538 &Global->VariableGlobal[VirtualMode],\r
539 Global->FvbInstance,\r
540 (CHAR16 *) Global->KeyList\r
541 );\r
542\r
543 OldPkList = (EFI_SIGNATURE_LIST *) Global->KeyList;\r
544 OldPkData = (EFI_SIGNATURE_DATA *) ((UINT8 *) OldPkList + sizeof (EFI_SIGNATURE_LIST) + OldPkList->SignatureHeaderSize);\r
545 Status = VerifyDataPayload (VirtualMode, Global, Data, DataSize, OldPkData->SignatureData);\r
546 if (!EFI_ERROR (Status)) {\r
547 Status = UpdateVariable (\r
548 VariableName, \r
549 VendorGuid, \r
550 (UINT8*)Data + AUTHINFO_SIZE, \r
551 DataSize - AUTHINFO_SIZE, \r
552 Attributes, \r
553 0, \r
554 CertData->MonotonicCount, \r
555 VirtualMode, \r
556 Global,\r
557 Variable\r
558 );\r
559\r
560 if (!EFI_ERROR (Status)) {\r
561 //\r
562 // If delete PK in user mode, need change to setup mode.\r
563 //\r
564 if ((DataSize == AUTHINFO_SIZE) && IsPk) {\r
565 UpdatePlatformMode (VirtualMode, Global, SETUP_MODE);\r
566 }\r
567 }\r
568 }\r
569 } else {\r
570 Status = UpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes, 0, 0, VirtualMode, Global, Variable);\r
571 //\r
572 // If enroll PK in setup mode, need change to user mode.\r
573 //\r
574 if ((DataSize != 0) && IsPk) {\r
575 UpdatePlatformMode (VirtualMode, Global, USER_MODE);\r
576 }\r
577 }\r
578\r
579 return Status;\r
580}\r
581\r
582/**\r
583 Process variable with key exchange key for verification.\r
584\r
585 @param[in] VariableName The name of Variable to be found.\r
586 @param[in] VendorGuid The variable vendor GUID.\r
587 @param[in] Data The data pointer.\r
588 @param[in] DataSize The size of Data found. If size is less than the\r
589 data, this value contains the required size.\r
590 @param[in] VirtualMode The current calling mode for this function.\r
591 @param[in] Global The context of this Extended SAL Variable Services Class call.\r
592 @param[in] Variable The variable information which is used to keep track of variable usage.\r
593 @param[in] Attributes The attribute value of the variable.\r
594\r
595 @retval EFI_INVALID_PARAMETER Invalid parameter.\r
596 @retval EFI_SECURITY_VIOLATION The variable did NOT pass the validation \r
597 check carried out by the firmware. \r
598 @retval EFI_SUCCESS The variable passed validation successfully.\r
599\r
600**/\r
601EFI_STATUS\r
602ProcessVarWithKek (\r
603 IN CHAR16 *VariableName,\r
604 IN EFI_GUID *VendorGuid,\r
605 IN VOID *Data,\r
606 IN UINTN DataSize,\r
607 IN BOOLEAN VirtualMode,\r
608 IN ESAL_VARIABLE_GLOBAL *Global,\r
609 IN VARIABLE_POINTER_TRACK *Variable,\r
610 IN UINT32 Attributes OPTIONAL\r
611 )\r
612{\r
613 EFI_STATUS Status;\r
614 VARIABLE_POINTER_TRACK KekVariable;\r
615 EFI_SIGNATURE_LIST *KekList;\r
616 EFI_SIGNATURE_DATA *KekItem;\r
617 UINT32 KekCount;\r
618 EFI_VARIABLE_AUTHENTICATION *CertData;\r
619 EFI_CERT_BLOCK_RSA_2048_SHA256 *CertBlock;\r
620 BOOLEAN IsFound;\r
621 UINT32 Index;\r
622 VARIABLE_HEADER VariableHeader;\r
623 BOOLEAN Valid;\r
624\r
625 KekList = NULL;\r
626\r
627 if (mPlatformMode == USER_MODE) {\r
628 if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == 0) {\r
629 //\r
630 // In user mode, should set EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute.\r
631 //\r
632 return EFI_INVALID_PARAMETER;\r
633 }\r
634\r
635 CertData = (EFI_VARIABLE_AUTHENTICATION *) Data;\r
636 CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData);\r
637 if (Variable->CurrPtr != 0x0) {\r
638 Valid = IsValidVariableHeader (\r
639 Variable->CurrPtr, \r
640 Variable->Volatile, \r
641 &Global->VariableGlobal[VirtualMode], \r
642 Global->FvbInstance, \r
643 &VariableHeader\r
644 );\r
645 ASSERT (Valid);\r
646\r
647 if (CertData->MonotonicCount <= VariableHeader.MonotonicCount) {\r
648 //\r
649 // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.\r
650 //\r
651 return EFI_SECURITY_VIOLATION;\r
652 }\r
653 }\r
654 //\r
655 // Get KEK database from variable.\r
656 //\r
657 Status = FindVariable (\r
658 Global->VariableName[VirtualMode][VAR_KEY_EXCHANGE_KEY], \r
659 Global->GlobalVariableGuid[VirtualMode], \r
660 &KekVariable, \r
661 &Global->VariableGlobal[VirtualMode],\r
662 Global->FvbInstance\r
663 );\r
664 ASSERT_EFI_ERROR (Status);\r
665\r
666 ZeroMem (Global->KeyList, MAX_KEYDB_SIZE);\r
667 GetVariableDataPtr (\r
668 KekVariable.CurrPtr,\r
669 KekVariable.Volatile,\r
670 &Global->VariableGlobal[VirtualMode],\r
671 Global->FvbInstance,\r
672 (CHAR16 *) Global->KeyList\r
673 );\r
674 //\r
675 // Enumerate all Kek items in this list to verify the variable certificate data.\r
676 // If anyone is authenticated successfully, it means the variable is correct!\r
677 //\r
678 KekList = (EFI_SIGNATURE_LIST *) Global->KeyList;\r
679 IsFound = FALSE;\r
680 KekCount = (KekList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - KekList->SignatureHeaderSize) / KekList->SignatureSize;\r
681 KekItem = (EFI_SIGNATURE_DATA *) ((UINT8 *) KekList + sizeof (EFI_SIGNATURE_LIST) + KekList->SignatureHeaderSize);\r
682 for (Index = 0; Index < KekCount; Index++) {\r
683 if (CompareMem (KekItem->SignatureData, CertBlock->PublicKey, EFI_CERT_TYPE_RSA2048_SIZE) == 0) {\r
684 IsFound = TRUE;\r
685 break;\r
686 }\r
687 KekItem = (EFI_SIGNATURE_DATA *) ((UINT8 *) KekItem + KekList->SignatureSize);\r
688 }\r
689\r
690 if (!IsFound) {\r
691 return EFI_SECURITY_VIOLATION;\r
692 }\r
693\r
694 Status = VerifyDataPayload (VirtualMode, Global, Data, DataSize, CertBlock->PublicKey);\r
695 if (!EFI_ERROR (Status)) {\r
696 Status = UpdateVariable (\r
697 VariableName, \r
698 VendorGuid, \r
699 (UINT8*)Data + AUTHINFO_SIZE, \r
700 DataSize - AUTHINFO_SIZE, \r
701 Attributes, \r
702 0, \r
703 CertData->MonotonicCount, \r
704 VirtualMode,\r
705 Global,\r
706 Variable\r
707 );\r
708 }\r
709 } else {\r
710 //\r
711 // If in setup mode, no authentication needed.\r
712 //\r
713 Status = UpdateVariable (\r
714 VariableName, \r
715 VendorGuid, \r
716 Data, \r
717 DataSize, \r
718 Attributes, \r
719 0, \r
720 0, \r
721 VirtualMode,\r
722 Global,\r
723 Variable\r
724 );\r
725 }\r
726\r
727 return Status;\r
728}\r
729\r
730/**\r
731 Process variable with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set, and return the index of associated public key.\r
732\r
733 @param[in] Data The data pointer.\r
734 @param[in] DataSize The size of Data found. If size is less than the\r
735 data, this value contains the required size.\r
736 @param[in] VirtualMode The current calling mode for this function.\r
737 @param[in] Global The context of this Extended SAL Variable Services Class call.\r
738 @param[in] Variable The variable information which is used to keep track of variable usage.\r
739 @param[in] Attributes The attribute value of the variable.\r
740 @param[out] KeyIndex The output index of corresponding public key in database.\r
741 @param[out] MonotonicCount The output value of corresponding Monotonic Count.\r
742\r
743 @retval EFI_INVALID_PARAMETER Invalid parameter.\r
744 @retval EFI_WRITE_PROTECTED The variable is write-protected and needs authentication with\r
745 EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.\r
746 @retval EFI_SECURITY_VIOLATION The variable is with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS\r
747 set, but the AuthInfo does NOT pass the validation \r
748 check carried out by the firmware. \r
749 @retval EFI_SUCCESS The variable is not write-protected, or passed validation successfully.\r
750\r
751**/\r
752EFI_STATUS\r
753VerifyVariable (\r
754 IN VOID *Data,\r
755 IN UINTN DataSize,\r
756 IN BOOLEAN VirtualMode,\r
757 IN ESAL_VARIABLE_GLOBAL *Global,\r
758 IN VARIABLE_POINTER_TRACK *Variable,\r
759 IN UINT32 Attributes OPTIONAL,\r
760 OUT UINT32 *KeyIndex OPTIONAL,\r
761 OUT UINT64 *MonotonicCount OPTIONAL\r
762 )\r
763{\r
764 EFI_STATUS Status;\r
765 BOOLEAN IsDeletion;\r
766 BOOLEAN IsFirstTime;\r
767 UINT8 *PubKey;\r
768 EFI_VARIABLE_AUTHENTICATION *CertData;\r
769 EFI_CERT_BLOCK_RSA_2048_SHA256 *CertBlock;\r
770 VARIABLE_HEADER VariableHeader;\r
771 BOOLEAN Valid;\r
772\r
773 CertData = NULL;\r
774 CertBlock = NULL;\r
775 PubKey = NULL;\r
776 IsDeletion = FALSE;\r
777 Valid = FALSE;\r
778\r
779 if (KeyIndex != NULL) {\r
780 *KeyIndex = 0;\r
781 }\r
782 //\r
783 // Determine if first time SetVariable with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS.\r
784 //\r
785 ZeroMem (&VariableHeader, sizeof (VARIABLE_HEADER));\r
786 if (Variable->CurrPtr != 0x0) {\r
787 Valid = IsValidVariableHeader (\r
788 Variable->CurrPtr, \r
789 Variable->Volatile, \r
790 &Global->VariableGlobal[VirtualMode], \r
791 Global->FvbInstance, \r
792 &VariableHeader\r
793 );\r
794 ASSERT (Valid);\r
795 }\r
796\r
797 if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
798 if (KeyIndex == NULL) {\r
799 return EFI_INVALID_PARAMETER;\r
800 }\r
801\r
802 //\r
803 // Determine current operation type.\r
804 //\r
805 if (DataSize == AUTHINFO_SIZE) {\r
806 IsDeletion = TRUE;\r
807 }\r
808 //\r
809 // Determine whether this is the first time with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.\r
810 //\r
811 if (Variable->CurrPtr == 0x0) {\r
812 IsFirstTime = TRUE;\r
813 } else if (Valid &&(VariableHeader.Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == 0) {\r
814 IsFirstTime = TRUE;\r
815 } else {\r
816 *KeyIndex = VariableHeader.PubKeyIndex;\r
817 IsFirstTime = FALSE;\r
818 }\r
819 } else if (Valid && (VariableHeader.Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) { \r
820 //\r
821 // If the variable is already write-protected, it always needs authentication before update.\r
822 //\r
823 return EFI_WRITE_PROTECTED;\r
824 } else {\r
825 //\r
826 // If without EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, set and attributes collision.\r
827 // That means it is not authenticated variable, just return EFI_SUCCESS.\r
828 //\r
829 return EFI_SUCCESS;\r
830 }\r
831\r
832 //\r
833 // Get PubKey and check Monotonic Count value corresponding to the variable.\r
834 //\r
835 CertData = (EFI_VARIABLE_AUTHENTICATION *) Data;\r
836 CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData);\r
837 PubKey = CertBlock->PublicKey;\r
838\r
839 if (MonotonicCount != NULL) {\r
840 //\r
841 // Update Monotonic Count value.\r
842 //\r
843 *MonotonicCount = CertData->MonotonicCount;\r
844 }\r
845\r
846 if (!IsFirstTime) {\r
847 //\r
848 // Check input PubKey.\r
849 //\r
850 if (CompareMem (PubKey, Global->PubKeyStore + (*KeyIndex - 1) * EFI_CERT_TYPE_RSA2048_SIZE, EFI_CERT_TYPE_RSA2048_SIZE) != 0) {\r
851 return EFI_SECURITY_VIOLATION;\r
852 }\r
853 //\r
854 // Compare the current monotonic count and ensure that it is greater than the last SetVariable\r
855 // operation with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute set.\r
856 //\r
857 if (CertData->MonotonicCount <= VariableHeader.MonotonicCount) {\r
858 //\r
859 // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.\r
860 //\r
861 return EFI_SECURITY_VIOLATION;\r
862 }\r
863 } \r
864 //\r
865 // Verify the certificate in Data payload.\r
866 //\r
867 Status = VerifyDataPayload (VirtualMode, Global, Data, DataSize, PubKey);\r
868 if (!EFI_ERROR (Status)) {\r
869 //\r
870 // Now, the signature has been verified!\r
871 //\r
872 if (IsFirstTime && !IsDeletion) {\r
873 //\r
874 // Update public key database variable if need and return the index.\r
875 //\r
876 *KeyIndex = AddPubKeyInStore (VirtualMode, Global, PubKey);\r
877 }\r
878 }\r
879\r
880 return Status;\r
881}\r
882\r