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