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