Based on this V2 patch about AuthVariableLib update.

Seemingly, you have forgotten partial of previous 2) and 5) comments.
2. Remove IsPkExist fields from SECURE_BOOT_MODE
structure since only any place to use them.
5. Suggest to update  EFI_SECURE_MODE_NAME and gEfiSecureBootModeGuid
to like  EDKII_SECURE_BOOT_MODE_NAME and gEdkiiSecureBootModeGuid
to reduce confusion.

New minor comments below.
1. Move mSecureBootMode to AuthService.c.
2. Add return status check after InitSecureBootVariables().
3. Remove the trailing white space for " // SetupMode is always RO. Skip IsSetupModeRO; " in AuthServiceInternal.h.

With that, you can have my
Reviewed-by: Star Zeng <star.z...@intel.com>


Thanks,
Star

On 2015/12/3 15:55, Zhang, Chao B wrote:
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Zhang, Chao <chao.b.zh...@intel.com>
---
  SecurityPkg/Library/AuthVariableLib/AuthService.c  | 1404 +++++++++++++++++---
  .../Library/AuthVariableLib/AuthServiceInternal.h  |   73 +
  .../Library/AuthVariableLib/AuthVariableLib.c      |  110 +-
  .../Library/AuthVariableLib/AuthVariableLib.inf    |    4 +
  .../DxeImageVerificationLib.c                      |  670 +++++++++-
  5 files changed, 1935 insertions(+), 326 deletions(-)

diff --git a/SecurityPkg/Library/AuthVariableLib/AuthService.c 
b/SecurityPkg/Library/AuthVariableLib/AuthService.c
index 1f9ba15..86ea04b 100644
--- a/SecurityPkg/Library/AuthVariableLib/AuthService.c
+++ b/SecurityPkg/Library/AuthVariableLib/AuthService.c
@@ -56,6 +56,56 @@ EFI_SIGNATURE_ITEM mSupportSigItem[] = {
    {EFI_CERT_X509_SHA512_GUID,     0,               80           }
  };

+//
+// Secure Boot Mode state machine
+//
+SECURE_BOOT_MODE mSecureBootState[SecureBootModeTypeMax] = {
+  // USER MODE
+  {
+      TRUE,                                      // IsPkExist
+      AUDIT_MODE_DISABLE,                        // AuditMode
+      FALSE,                                     // IsAuditModeRO, AuditMode 
is RW
+      DEPLOYED_MODE_DISABLE,                     // DeployedMode
+      FALSE,                                     // IsDeployedModeRO, 
DeployedMode is RW
+      SETUP_MODE_DISABLE,                        // SetupMode
+                                                 // SetupMode is always RO
+      SECURE_BOOT_MODE_ENABLE                    // SecureBoot
+  },
+  // SETUP MODE
+  {
+      FALSE,                                     // IsPkExist
+      AUDIT_MODE_DISABLE,                        // AuditMode
+      FALSE,                                     // IsAuditModeRO, AuditMode 
is RW
+      DEPLOYED_MODE_DISABLE,                     // DeployedMode
+      TRUE,                                      // IsDeployedModeRO, 
DeployedMode is RO
+      SETUP_MODE_ENABLE,                         // SetupMode
+                                                 // SetupMode is always RO
+      SECURE_BOOT_MODE_DISABLE                   // SecureBoot
+  },
+  // AUDIT MODE
+  {
+      FALSE,                                     // IsPkExist
+      AUDIT_MODE_ENABLE,                         // AuditMode
+      TRUE,                                      // AuditModeValAttr RO, 
AuditMode is RO
+      DEPLOYED_MODE_DISABLE,                     // DeployedMode
+      TRUE,                                      // DeployedModeValAttr RO, 
DeployedMode is RO
+      SETUP_MODE_ENABLE,                         // SetupMode
+                                                 // SetupMode is always RO
+      SECURE_BOOT_MODE_DISABLE                   // SecureBoot
+  },
+  // DEPLOYED MODE
+  {
+      TRUE,                                      // IsPkExist
+      AUDIT_MODE_DISABLE,                        // AuditMode, AuditMode is RO
+      TRUE,                                      // AuditModeValAttr RO
+      DEPLOYED_MODE_ENABLE,                      // DeployedMode
+      TRUE,                                      // DeployedModeValAttr RO, 
DeployedMode is RO
+      SETUP_MODE_DISABLE,                        // SetupMode
+                                                 // SetupMode is always RO
+      SECURE_BOOT_MODE_ENABLE                    // SecureBoot
+  }
+};
+
  /**
    Finds variable in storage blocks of volatile and non-volatile storage areas.

@@ -173,80 +223,988 @@ AuthServiceInternalUpdateVariableWithMonotonicCount (
    AuthVariableInfo.PubKeyIndex = KeyIndex;
    AuthVariableInfo.MonotonicCount = MonotonicCount;

-  return mAuthVarLibContextIn->UpdateVariable (
-           &AuthVariableInfo
-           );
+  return mAuthVarLibContextIn->UpdateVariable (
+           &AuthVariableInfo
+           );
+}
+
+/**
+  Update the variable region with Variable information.
+
+  @param[in] VariableName           Name of variable.
+  @param[in] VendorGuid             Guid of variable.
+  @param[in] Data                   Data pointer.
+  @param[in] DataSize               Size of Data.
+  @param[in] Attributes             Attribute value of the variable.
+  @param[in] TimeStamp              Value of associated TimeStamp.
+
+  @retval EFI_SUCCESS               The update operation is success.
+  @retval EFI_INVALID_PARAMETER     Invalid parameter.
+  @retval EFI_WRITE_PROTECTED       Variable is write-protected.
+  @retval EFI_OUT_OF_RESOURCES      There is not enough resource.
+
+**/
+EFI_STATUS
+AuthServiceInternalUpdateVariableWithTimeStamp (
+  IN CHAR16             *VariableName,
+  IN EFI_GUID           *VendorGuid,
+  IN VOID               *Data,
+  IN UINTN              DataSize,
+  IN UINT32             Attributes,
+  IN EFI_TIME           *TimeStamp
+  )
+{
+  EFI_STATUS            FindStatus;
+  VOID                  *OrgData;
+  UINTN                 OrgDataSize;
+  AUTH_VARIABLE_INFO    AuthVariableInfo;
+
+  FindStatus = AuthServiceInternalFindVariable (
+                 VariableName,
+                 VendorGuid,
+                 &OrgData,
+                 &OrgDataSize
+                 );
+
+  //
+  // EFI_VARIABLE_APPEND_WRITE attribute only effects for existing variable
+  //
+  if (!EFI_ERROR (FindStatus) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) != 
0)) {
+    if ((CompareGuid (VendorGuid, &gEfiImageSecurityDatabaseGuid) &&
+        ((StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE) == 0) || (StrCmp 
(VariableName, EFI_IMAGE_SECURITY_DATABASE1) == 0) ||
+        (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE2) == 0))) ||
+        (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp 
(VariableName, EFI_KEY_EXCHANGE_KEY_NAME) == 0))) {
+      //
+      // For variables with formatted as EFI_SIGNATURE_LIST, the driver shall 
not perform an append of
+      // EFI_SIGNATURE_DATA values that are already part of the existing 
variable value.
+      //
+      FilterSignatureList (
+        OrgData,
+        OrgDataSize,
+        Data,
+        &DataSize
+        );
+    }
+  }
+
+  ZeroMem (&AuthVariableInfo, sizeof (AuthVariableInfo));
+  AuthVariableInfo.VariableName = VariableName;
+  AuthVariableInfo.VendorGuid = VendorGuid;
+  AuthVariableInfo.Data = Data;
+  AuthVariableInfo.DataSize = DataSize;
+  AuthVariableInfo.Attributes = Attributes;
+  AuthVariableInfo.TimeStamp = TimeStamp;
+  return mAuthVarLibContextIn->UpdateVariable (
+           &AuthVariableInfo
+           );
+}
+
+/**
+  Initialize Secure Boot variables.
+
+  @retval EFI_SUCCESS               The initialization operation is successful.
+  @retval EFI_OUT_OF_RESOURCES      There is not enough resource.
+
+**/
+EFI_STATUS
+InitSecureBootVariables (
+  VOID
+  )
+{
+  EFI_STATUS             Status;
+  UINT8                  *Data;
+  UINTN                  DataSize;
+  UINT32                 SecureBoot;
+  UINT8                  SecureBootEnable;
+  SECURE_BOOT_MODE_TYPE  SecureBootMode;
+  BOOLEAN                IsPkPresent;
+
+  //
+  // Find "PK" variable
+  //
+  Status = AuthServiceInternalFindVariable (EFI_PLATFORM_KEY_NAME, 
&gEfiGlobalVariableGuid, (VOID **) &Data, &DataSize);
+  if (EFI_ERROR (Status)) {
+    IsPkPresent = FALSE;
+    DEBUG ((EFI_D_INFO, "Variable %s does not exist.\n", 
EFI_PLATFORM_KEY_NAME));
+  } else {
+    IsPkPresent = TRUE;
+    DEBUG ((EFI_D_INFO, "Variable %s exists.\n", EFI_PLATFORM_KEY_NAME));
+  }
+
+  //
+  // Init "SecureBootMode" variable.
+  // Initial case
+  //   SecureBootMode doesn't exist. Init it with PK state
+  // 3 inconsistency cases need to sync
+  //   1.1 Add PK     -> system break -> update SecureBootMode Var
+  //   1.2 Delete PK  -> system break -> update SecureBootMode Var
+  //   1.3 Set AuditMode ->Delete PK  -> system break -> Update SecureBootMode 
Var
+  //
+  Status = AuthServiceInternalFindVariable (EFI_SECURE_MODE_NAME, 
&gEfiSecureBootModeGuid, (VOID **)&Data, &DataSize);
+  if (EFI_ERROR(Status)) {
+    //
+    // Variable driver Initial Case
+    //
+    if (IsPkPresent) {
+      SecureBootMode = SecureBootModeTypeUserMode;
+    } else {
+      SecureBootMode = SecureBootModeTypeSetupMode;
+    }
+  } else {
+    //
+    // 3 inconsistency cases need to sync
+    //
+    SecureBootMode = (SECURE_BOOT_MODE_TYPE)*Data;
+    ASSERT(SecureBootMode < SecureBootModeTypeMax);
+
+    if (IsPkPresent) {
+      //
+      // 3.1 Add PK     -> system break -> update SecureBootMode Var
+      //
+      if (SecureBootMode == SecureBootModeTypeSetupMode) {
+        SecureBootMode = SecureBootModeTypeUserMode;
+      } else if (SecureBootMode == SecureBootModeTypeAuditMode) {
+        SecureBootMode = SecureBootModeTypeDeployedMode;
+      }
+    } else {
+      //
+      // 3.2 Delete PK -> system break -> update SecureBootMode Var
+      // 3.3 Set AuditMode ->Delete PK  -> system break -> Update 
SecureBootMode Var. Reinit to be SetupMode
+      //
+      if ((SecureBootMode == SecureBootModeTypeUserMode) || (SecureBootMode == 
SecureBootModeTypeDeployedMode)) {
+        SecureBootMode = SecureBootModeTypeSetupMode;
+      }
+    }
+  }
+
+  if (EFI_ERROR(Status) || (SecureBootMode != (SECURE_BOOT_MODE_TYPE)*Data)) {
+    //
+    // Update SecureBootMode Var
+    //
+    Status = AuthServiceInternalUpdateVariable (
+               EFI_SECURE_MODE_NAME,
+               &gEfiSecureBootModeGuid,
+               &SecureBootMode,
+               sizeof (UINT8),
+               EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | 
EFI_VARIABLE_RUNTIME_ACCESS
+               );
+    if (EFI_ERROR(Status)) {
+      return Status;
+    }
+  }
+
+  //
+  // Init "AuditMode"
+  //
+  Status = AuthServiceInternalUpdateVariable (
+             EFI_AUDIT_MODE_NAME,
+             &gEfiGlobalVariableGuid,
+             &mSecureBootState[SecureBootMode].AuditMode,
+             sizeof(UINT8),
+             EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS
+             );
+  if (EFI_ERROR(Status)) {
+    return Status;
+  }
+
+  //
+  // Init "DeployedMode"
+  //
+  Status = AuthServiceInternalUpdateVariable (
+             EFI_DEPLOYED_MODE_NAME,
+             &gEfiGlobalVariableGuid,
+             &mSecureBootState[SecureBootMode].DeployedMode,
+             sizeof(UINT8),
+             EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS
+             );
+  if (EFI_ERROR(Status)) {
+    return Status;
+  }
+
+  //
+  // Init "SetupMode"
+  //
+  Status = AuthServiceInternalUpdateVariable (
+             EFI_SETUP_MODE_NAME,
+             &gEfiGlobalVariableGuid,
+             &mSecureBootState[SecureBootMode].SetupMode,
+             sizeof(UINT8),
+             EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS
+             );
+  if (EFI_ERROR(Status)) {
+    return Status;
+  }
+
+  //
+  // If "SecureBootEnable" variable exists, then update "SecureBoot" variable.
+  // If "SecureBootEnable" variable is SECURE_BOOT_ENABLE and in User Mode or Deployed 
Mode, Set "SecureBoot" variable to SECURE_BOOT_MODE_ENABLE.
+  // If "SecureBootEnable" variable is SECURE_BOOT_DISABLE, Set "SecureBoot" 
variable to SECURE_BOOT_MODE_DISABLE.
+  //
+  SecureBootEnable = SECURE_BOOT_DISABLE;
+  Status = AuthServiceInternalFindVariable (EFI_SECURE_BOOT_ENABLE_NAME, 
&gEfiSecureBootEnableDisableGuid, (VOID **)&Data, &DataSize);
+  if (!EFI_ERROR(Status)) {
+    if (!IsPkPresent) {
+      //
+      // PK is cleared in runtime. "SecureBootMode" is not updated before 
reboot
+      // Delete "SecureBootMode"
+      //
+      Status = AuthServiceInternalUpdateVariable (
+                 EFI_SECURE_BOOT_ENABLE_NAME,
+                 &gEfiSecureBootEnableDisableGuid,
+                 &SecureBootEnable,
+                 0,
+                 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS
+                 );
+    } else {
+      SecureBootEnable = *Data;
+    }
+  } else if ((SecureBootMode == SecureBootModeTypeUserMode) || (SecureBootMode 
== SecureBootModeTypeDeployedMode)) {
+    //
+    // "SecureBootEnable" not exist, initialize it in User Mode or Deployed 
Mode.
+    //
+    SecureBootEnable = SECURE_BOOT_ENABLE;
+    Status = AuthServiceInternalUpdateVariable (
+               EFI_SECURE_BOOT_ENABLE_NAME,
+               &gEfiSecureBootEnableDisableGuid,
+               &SecureBootEnable,
+               sizeof (UINT8),
+               EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS
+               );
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+  }
+
+  //
+  // Create "SecureBoot" variable with BS+RT attribute set.
+  //
+  if ((SecureBootEnable == SECURE_BOOT_ENABLE)
+  && ((SecureBootMode == SecureBootModeTypeUserMode) || (SecureBootMode == 
SecureBootModeTypeDeployedMode))) {
+    SecureBoot = SECURE_BOOT_MODE_ENABLE;
+  } else {
+    SecureBoot = SECURE_BOOT_MODE_DISABLE;
+  }
+  Status = AuthServiceInternalUpdateVariable (
+             EFI_SECURE_BOOT_MODE_NAME,
+             &gEfiGlobalVariableGuid,
+             &SecureBoot,
+             sizeof (UINT8),
+             EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS
+             );
+
+  DEBUG ((EFI_D_INFO, "SecureBootMode is %x\n", SecureBootMode));
+  DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_SECURE_BOOT_MODE_NAME, 
SecureBoot));
+  DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_SECURE_BOOT_ENABLE_NAME, 
SecureBootEnable));
+
+  //
+  // Save SecureBootMode in global space
+  //
+  mSecureBootMode = SecureBootMode;
+
+  return Status;
+}
+
+/**
+  Update SecureBootMode variable.
+
+  @param[in] NewMode                New Secure Boot Mode.
+
+  @retval EFI_SUCCESS               The initialization operation is successful.
+  @retval EFI_OUT_OF_RESOURCES      There is not enough resource.
+
+**/
+EFI_STATUS
+UpdateSecureBootMode(
+  IN  SECURE_BOOT_MODE_TYPE  NewMode
+  )
+{
+  EFI_STATUS              Status;
+
+  //
+  // Update "SecureBootMode" variable to new Secure Boot Mode
+  //
+  Status = AuthServiceInternalUpdateVariable (
+             EFI_SECURE_MODE_NAME,
+             &gEfiSecureBootModeGuid,
+             &NewMode,
+             sizeof (UINT8),
+             EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | 
EFI_VARIABLE_RUNTIME_ACCESS
+             );
+
+  if (!EFI_ERROR(Status)) {
+    DEBUG((EFI_D_INFO, "SecureBootMode Update to %x\n", NewMode));
+    mSecureBootMode = NewMode;
+  } else {
+    DEBUG((EFI_D_ERROR, "SecureBootMode Update failure %x\n", Status));
+  }
+
+  return Status;
+}
+
+/**
+  Current secure boot mode is AuditMode. This function performs secure boot 
mode transition
+  to a new mode.
+
+  @param[in] NewMode                New Secure Boot Mode.
+
+  @retval EFI_SUCCESS               The initialization operation is successful.
+  @retval EFI_OUT_OF_RESOURCES      There is not enough resource.
+
+**/
+EFI_STATUS
+TransitionFromAuditMode(
+  IN  SECURE_BOOT_MODE_TYPE               NewMode
+  )
+{
+  EFI_STATUS  Status;
+  UINT8       *AuditVarData;
+  UINT8       *DeployedVarData;
+  UINT8       *SetupVarData;
+  UINT8       *SecureBootVarData;
+  UINT8       SecureBootEnable;
+  UINTN       DataSize;
+
+  //
+  // AuditMode/DeployedMode/SetupMode/SecureBoot are all NON_NV variable 
maintained by Variable driver
+  // they can be RW. but can't be deleted. so they can always be found.
+  //
+  Status = AuthServiceInternalFindVariable (
+             EFI_AUDIT_MODE_NAME,
+             &gEfiGlobalVariableGuid,
+             &AuditVarData,
+             &DataSize
+             );
+  if (EFI_ERROR (Status)) {
+    ASSERT(FALSE);
+  }
+
+  Status = AuthServiceInternalFindVariable (
+             EFI_DEPLOYED_MODE_NAME,
+             &gEfiGlobalVariableGuid,
+             &DeployedVarData,
+             &DataSize
+             );
+  if (EFI_ERROR (Status)) {
+    ASSERT(FALSE);
+  }
+
+  Status = AuthServiceInternalFindVariable (
+             EFI_SETUP_MODE_NAME,
+             &gEfiGlobalVariableGuid,
+             &SetupVarData,
+             &DataSize
+             );
+  if (EFI_ERROR (Status)) {
+    ASSERT(FALSE);
+  }
+
+  Status = AuthServiceInternalFindVariable (
+             EFI_SECURE_BOOT_MODE_NAME,
+             &gEfiGlobalVariableGuid,
+             &SecureBootVarData,
+             &DataSize
+             );
+  if (EFI_ERROR (Status)) {
+    ASSERT(FALSE);
+  }
+
+  //
+  // Make Secure Boot Mode transition ATOMIC
+  // Update Private NV SecureBootMode Variable first, because it may fail due 
to NV range overflow.
+  // other tranisition logic are all memory operations.
+  //
+  Status = UpdateSecureBootMode(NewMode);
+  if (EFI_ERROR(Status)) {
+    DEBUG((EFI_D_ERROR, "Update SecureBootMode Variable fail %x\n", Status));
+  }
+
+  if (NewMode == SecureBootModeTypeDeployedMode) {
+    //
+    // Since PK is enrolled, can't rollback, always update SecureBootMode in 
memory
+    //
+    mSecureBootMode = NewMode;
+    Status          = EFI_SUCCESS;
+
+    //
+    // AuditMode ----> DeployedMode
+    // Side Effects
+    //   AuditMode =: 0 / DeployedMode := 1 / SetupMode := 0
+    //
+    // Update the value of AuditMode variable by a simple mem copy, this could 
avoid possible
+    // variable storage reclaim at runtime.
+    //
+    CopyMem (AuditVarData, &mSecureBootState[NewMode].AuditMode, 
sizeof(UINT8));
+    //
+    // Update the value of DeployedMode variable by a simple mem copy, this 
could avoid possible
+    // variable storage reclaim at runtime.
+    //
+    CopyMem (DeployedVarData, &mSecureBootState[NewMode].DeployedMode, 
sizeof(UINT8));
+    //
+    // Update the value of SetupMode variable by a simple mem copy, this could 
avoid possible
+    // variable storage reclaim at runtime.
+    //
+    CopyMem (SetupVarData, &mSecureBootState[NewMode].SetupMode, 
sizeof(UINT8));
+
+    if (mAuthVarLibContextIn->AtRuntime ()) {
+      //
+      // SecureBoot Variable indicates whether the platform firmware is 
operating
+      // in Secure boot mode (1) or not (0), so we should not change SecureBoot
+      // Variable in runtime.
+      //
+      return Status;
+    }
+
+    //
+    // Update the value of SecureBoot variable by a simple mem copy, this 
could avoid possible
+    // variable storage reclaim at runtime.
+    //
+    CopyMem (SecureBootVarData, &mSecureBootState[NewMode].SecureBoot, 
sizeof(UINT8));
+
+    //
+    // Create "SecureBootEnable" variable  as secure boot is enabled.
+    //
+    SecureBootEnable = SECURE_BOOT_ENABLE;
+    AuthServiceInternalUpdateVariable (
+      EFI_SECURE_BOOT_ENABLE_NAME,
+      &gEfiSecureBootEnableDisableGuid,
+      &SecureBootEnable,
+      sizeof (SecureBootEnable),
+      EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS
+      );
+  } else {
+    DEBUG((EFI_D_ERROR, "Invalid state tranition from %x to %x\n", 
SecureBootModeTypeAuditMode, NewMode));
+    ASSERT(FALSE);
+  }
+
+  return Status;
+}
+
+/**
+  Current secure boot mode is DeployedMode. This function performs secure boot 
mode transition
+  to a new mode.
+
+  @param[in] NewMode                New Secure Boot Mode.
+
+  @retval EFI_SUCCESS               The initialization operation is successful.
+  @retval EFI_OUT_OF_RESOURCES      There is not enough resource.
+
+**/
+EFI_STATUS
+TransitionFromDeployedMode(
+  IN  SECURE_BOOT_MODE_TYPE               NewMode
+  )
+{
+  EFI_STATUS  Status;
+  UINT8       *DeployedVarData;
+  UINT8       *SetupVarData;
+  UINT8       *SecureBootVarData;
+  UINT8       SecureBootEnable;
+  UINTN       DataSize;
+
+  //
+  // AuditMode/DeployedMode/SetupMode/SecureBoot are all NON_NV variable 
maintained by Variable driver
+  // they can be RW. but can't be deleted. so they can always be found.
+  //
+  Status = AuthServiceInternalFindVariable (
+             EFI_DEPLOYED_MODE_NAME,
+             &gEfiGlobalVariableGuid,
+             &DeployedVarData,
+             &DataSize
+             );
+  if (EFI_ERROR (Status)) {
+    ASSERT(FALSE);
+  }
+
+  Status = AuthServiceInternalFindVariable (
+             EFI_SETUP_MODE_NAME,
+             &gEfiGlobalVariableGuid,
+             &SetupVarData,
+             &DataSize
+             );
+  if (EFI_ERROR (Status)) {
+    ASSERT(FALSE);
+  }
+
+  Status = AuthServiceInternalFindVariable (
+             EFI_SECURE_BOOT_MODE_NAME,
+             &gEfiGlobalVariableGuid,
+             &SecureBootVarData,
+             &DataSize
+             );
+  if (EFI_ERROR (Status)) {
+    ASSERT(FALSE);
+  }
+
+  //
+  // Make Secure Boot Mode transition ATOMIC
+  // Update Private NV SecureBootMode Variable first, because it may fail due 
to NV range overflow.
+  // other tranisition logic are all memory operations.
+  //
+  Status = UpdateSecureBootMode(NewMode);
+  if (EFI_ERROR(Status)) {
+    DEBUG((EFI_D_ERROR, "Update SecureBootMode Variable fail %x\n", Status));
+  }
+
+  switch(NewMode) {
+    case SecureBootModeTypeUserMode:
+      //
+      // DeployedMode ----> UserMode
+      // Side Effects
+      //   DeployedMode := 0
+      //
+      // Platform Specific DeployedMode clear. UpdateSecureBootMode fails and 
no other variables are updated before. rollback this transition
+      //
+      if (EFI_ERROR(Status)) {
+        return Status;
+      }
+      CopyMem (DeployedVarData, &mSecureBootState[NewMode].DeployedMode, 
sizeof(UINT8));
+
+      break;
+
+    case SecureBootModeTypeSetupMode:
+      //
+      // Since PK is processed before, can't rollback, still update 
SecureBootMode in memory
+      //
+      mSecureBootMode = NewMode;
+      Status          = EFI_SUCCESS;
+
+      //
+      // DeployedMode ----> SetupMode
+      //
+      // Platform Specific PKpub clear or Delete Pkpub
+      // Side Effects
+      //   DeployedMode := 0 / SetupMode := 1 / SecureBoot := 0
+      //
+      // Update the value of DeployedMode variable by a simple mem copy, this 
could avoid possible
+      // variable storage reclaim at runtime.
+      //
+      CopyMem (DeployedVarData, &mSecureBootState[NewMode].DeployedMode, 
sizeof(UINT8));
+      //
+      // Update the value of SetupMode variable by a simple mem copy, this 
could avoid possible
+      // variable storage reclaim at runtime.
+      //
+      CopyMem (SetupVarData, &mSecureBootState[NewMode].SetupMode, 
sizeof(UINT8));
+
+      if (mAuthVarLibContextIn->AtRuntime ()) {
+        //
+        // SecureBoot Variable indicates whether the platform firmware is 
operating
+        // in Secure boot mode (1) or not (0), so we should not change 
SecureBoot
+        // Variable in runtime.
+        //
+        return Status;
+      }
+
+      //
+      // Update the value of SecureBoot variable by a simple mem copy, this 
could avoid possible
+      // variable storage reclaim at runtime.
+      //
+      CopyMem (SecureBootVarData, &mSecureBootState[NewMode].SecureBoot, 
sizeof(UINT8));
+
+      //
+      // Delete the "SecureBootEnable" variable as secure boot is Disabled.
+      //
+      SecureBootEnable = SECURE_BOOT_DISABLE;
+      AuthServiceInternalUpdateVariable (
+        EFI_SECURE_BOOT_ENABLE_NAME,
+        &gEfiSecureBootEnableDisableGuid,
+        &SecureBootEnable,
+        0,
+        EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS
+        );
+      break;
+
+    default:
+      DEBUG((EFI_D_ERROR, "Invalid state tranition from %x to %x\n", 
SecureBootModeTypeDeployedMode, NewMode));
+      ASSERT(FALSE);
+  }
+
+  return Status;
+}
+
+/**
+  Current secure boot mode is UserMode. This function performs secure boot 
mode transition
+  to a new mode.
+
+  @param[in] NewMode                New Secure Boot Mode.
+
+  @retval EFI_SUCCESS               The initialization operation is successful.
+  @retval EFI_OUT_OF_RESOURCES      There is not enough resource.
+
+**/
+EFI_STATUS
+TransitionFromUserMode(
+  IN  SECURE_BOOT_MODE_TYPE               NewMode
+  )
+{
+  EFI_STATUS   Status;
+  UINT8        *AuditVarData;
+  UINT8        *DeployedVarData;
+  UINT8        *SetupVarData;
+  UINT8        *PkVarData;
+  UINT8        *SecureBootVarData;
+  UINT8        SecureBootEnable;
+  UINTN        DataSize;
+  VARIABLE_ENTRY_CONSISTENCY  VariableEntry;
+
+  //
+  // AuditMode/DeployedMode/SetupMode/SecureBoot are all NON_NV variable 
maintained by Variable driver
+  // they can be RW. but can't be deleted. so they can always be found.
+  //
+  Status = AuthServiceInternalFindVariable (
+             EFI_AUDIT_MODE_NAME,
+             &gEfiGlobalVariableGuid,
+             &AuditVarData,
+             &DataSize
+             );
+  if (EFI_ERROR (Status)) {
+    ASSERT(FALSE);
+  }
+
+  Status = AuthServiceInternalFindVariable (
+             EFI_DEPLOYED_MODE_NAME,
+             &gEfiGlobalVariableGuid,
+             &DeployedVarData,
+             &DataSize
+             );
+  if (EFI_ERROR (Status)) {
+    ASSERT(FALSE);
+  }
+
+  Status = AuthServiceInternalFindVariable (
+             EFI_SETUP_MODE_NAME,
+             &gEfiGlobalVariableGuid,
+             &SetupVarData,
+             &DataSize
+             );
+  if (EFI_ERROR (Status)) {
+    ASSERT(FALSE);
+  }
+
+  Status = AuthServiceInternalFindVariable (
+             EFI_SECURE_BOOT_MODE_NAME,
+             &gEfiGlobalVariableGuid,
+             &SecureBootVarData,
+             &DataSize
+             );
+  if (EFI_ERROR (Status)) {
+    ASSERT(FALSE);
+  }
+
+  //
+  // Make Secure Boot Mode transition ATOMIC
+  // Update Private NV SecureBootMode Variable first, because it may fail due 
to NV range overflow.
+  // Other tranisition logic are all memory operations and PK delete is 
assumed to be always successful.
+  //
+  if (NewMode != SecureBootModeTypeAuditMode) {
+    Status = UpdateSecureBootMode(NewMode);
+    if (EFI_ERROR(Status)) {
+      DEBUG((EFI_D_ERROR, "Update SecureBootMode Variable fail %x\n", Status));
+    }
+  } else {
+    //
+    // UserMode -----> AuditMode. Check RemainingSpace for SecureBootMode var 
first.
+    // Will update SecureBootMode after DeletePK logic
+    //
+    VariableEntry.VariableSize = sizeof(UINT8);
+    VariableEntry.Guid         = &gEfiSecureBootModeGuid;
+    VariableEntry.Name         = EFI_SECURE_MODE_NAME;
+    if (!mAuthVarLibContextIn->CheckRemainingSpaceForConsistency 
(VARIABLE_ATTRIBUTE_NV_BS_RT, &VariableEntry, NULL)) {
+      return EFI_OUT_OF_RESOURCES;
+    }
+  }
+
+  switch(NewMode) {
+    case SecureBootModeTypeDeployedMode:
+      //
+      // UpdateSecureBootMode fails and no other variables are updated before. 
rollback this transition
+      //
+      if (EFI_ERROR(Status)) {
+        return Status;
+      }
+
+      //
+      // UserMode ----> DeployedMode
+      // Side Effects
+      //   DeployedMode := 1
+      //
+      CopyMem (DeployedVarData, &mSecureBootState[NewMode].DeployedMode, 
sizeof(UINT8));
+      break;
+
+    case SecureBootModeTypeAuditMode:
+      //
+      // UserMode ----> AuditMode
+      // Side Effects
+      //   Delete PKpub / SetupMode := 1 / SecureBoot := 0
+      //
+      // Delete PKpub without verification. Should always succeed.
+      //
+      PkVarData = NULL;
+      Status = AuthServiceInternalUpdateVariable (
+                 EFI_PLATFORM_KEY_NAME,
+                 &gEfiGlobalVariableGuid,
+                 PkVarData,
+                 0,
+                 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | 
EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
+                 );
+      if (EFI_ERROR(Status)) {
+        DEBUG((EFI_D_ERROR, "UserMode -> AuditMode. Delete PK fail %x\n", 
Status));
+        ASSERT(FALSE);
+      }
+
+      //
+      // Update Private NV SecureBootMode Variable
+      //
+      Status = UpdateSecureBootMode(NewMode);
+      if (EFI_ERROR(Status)) {
+        //
+        // Since PK is deleted successfully, Doesn't break, continue to update 
other variable.
+        //
+        DEBUG((EFI_D_ERROR, "Update SecureBootMode Variable fail %x\n", 
Status));
+      }
+      CopyMem (AuditVarData, &mSecureBootState[NewMode].AuditMode, 
sizeof(UINT8));
+
+      //
+      // Fall into SetupMode logic
+      //
+    case SecureBootModeTypeSetupMode:
+      //
+      // Since PK is deleted before , can't rollback, still update 
SecureBootMode in memory
+      //
+      mSecureBootMode = NewMode;
+      Status          = EFI_SUCCESS;
+
+      //
+      // UserMode ----> SetupMode
+      //  Side Effects
+      //    DeployedMode :=0 / SetupMode :=1 / SecureBoot :=0
+      //
+      // Update the value of SetupMode variable by a simple mem copy, this 
could avoid possible
+      // variable storage reclaim at runtime.
+      //
+      CopyMem (SetupVarData, &mSecureBootState[NewMode].SetupMode, 
sizeof(UINT8));
+
+      if (mAuthVarLibContextIn->AtRuntime ()) {
+        //
+        // SecureBoot Variable indicates whether the platform firmware is 
operating
+        // in Secure boot mode (1) or not (0), so we should not change 
SecureBoot
+        // Variable in runtime.
+        //
+        return Status;
+      }
+
+      //
+      // Update the value of SecureBoot variable by a simple mem copy, this 
could avoid possible
+      // variable storage reclaim at runtime.
+      //
+      CopyMem (SecureBootVarData, &mSecureBootState[NewMode].SecureBoot, 
sizeof(UINT8));
+
+      //
+      // Delete the "SecureBootEnable" variable as secure boot is Disabled.
+      //
+      SecureBootEnable = SECURE_BOOT_DISABLE;
+      AuthServiceInternalUpdateVariable (
+        EFI_SECURE_BOOT_ENABLE_NAME,
+        &gEfiSecureBootEnableDisableGuid,
+        &SecureBootEnable,
+        0,
+        EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS
+        );
+
+      break;
+
+    default:
+      DEBUG((EFI_D_ERROR, "Invalid state tranition from %x to %x\n", 
SecureBootModeTypeUserMode, NewMode));
+      ASSERT(FALSE);
+  }
+
+  return Status;
+}
+
+/**
+  Current secure boot mode is SetupMode. This function performs secure boot 
mode transition
+  to a new mode.
+
+  @param[in] NewMode                New Secure Boot Mode.
+
+  @retval EFI_SUCCESS               The initialization operation is successful.
+  @retval EFI_OUT_OF_RESOURCES      There is not enough resource.
+
+**/
+EFI_STATUS
+TransitionFromSetupMode(
+  IN  SECURE_BOOT_MODE_TYPE              NewMode
+  )
+{
+  EFI_STATUS   Status;
+  UINT8        *AuditVarData;
+  UINT8        *SetupVarData;
+  UINT8        *SecureBootVarData;
+  UINT8        SecureBootEnable;
+  UINTN        DataSize;
+
+  //
+  // AuditMode/DeployedMode/SetupMode/SecureBoot are all NON_NV variable 
maintained by Variable driver
+  // they can be RW. but can't be deleted. so they can always be found.
+  //
+  Status = AuthServiceInternalFindVariable (
+             EFI_AUDIT_MODE_NAME,
+             &gEfiGlobalVariableGuid,
+             &AuditVarData,
+             &DataSize
+             );
+  if (EFI_ERROR (Status)) {
+    ASSERT(FALSE);
+  }
+
+  Status = AuthServiceInternalFindVariable (
+             EFI_SETUP_MODE_NAME,
+             &gEfiGlobalVariableGuid,
+             &SetupVarData,
+             &DataSize
+             );
+  if (EFI_ERROR (Status)) {
+    ASSERT(FALSE);
+  }
+
+  Status = AuthServiceInternalFindVariable (
+             EFI_SECURE_BOOT_MODE_NAME,
+             &gEfiGlobalVariableGuid,
+             &SecureBootVarData,
+             &DataSize
+             );
+  if (EFI_ERROR (Status)) {
+    ASSERT(FALSE);
+  }
+
+  //
+  // Make Secure Boot Mode transition ATOMIC
+  // Update Private NV SecureBootMode Variable first, because it may fail due 
to NV range overflow.
+  // Other tranisition logic are all memory operations and PK delete is 
assumed to be always successful.
+  //
+  Status = UpdateSecureBootMode(NewMode);
+  if (EFI_ERROR(Status)) {
+    DEBUG((EFI_D_ERROR, "Update SecureBootMode Variable fail %x\n", Status));
+  }
+
+  switch(NewMode) {
+    case SecureBootModeTypeAuditMode:
+      //
+      // UpdateSecureBootMode fails and no other variables are updated before. 
rollback this transition
+      //
+      if (EFI_ERROR(Status)) {
+        return Status;
+      }
+
+      //
+      // SetupMode ----> AuditMode
+      // Side Effects
+      //   AuditMode := 1
+      //
+      // Update the value of AuditMode variable by a simple mem copy, this 
could avoid possible
+      // variable storage reclaim at runtime.
+      //
+      CopyMem (AuditVarData, &mSecureBootState[NewMode].AuditMode, 
sizeof(UINT8));
+      break;
+
+    case SecureBootModeTypeUserMode:
+      //
+      // Since PK is enrolled before, can't rollback, still update 
SecureBootMode in memory
+      //
+      mSecureBootMode = NewMode;
+      Status          = EFI_SUCCESS;
+
+      //
+      // SetupMode ----> UserMode
+      // Side Effects
+      //   SetupMode := 0 / SecureBoot := 1
+      //
+      // Update the value of AuditMode variable by a simple mem copy, this 
could avoid possible
+      // variable storage reclaim at runtime.
+      //
+      CopyMem (SetupVarData, &mSecureBootState[NewMode].SetupMode, 
sizeof(UINT8));
+
+      if (mAuthVarLibContextIn->AtRuntime ()) {
+        //
+        // SecureBoot Variable indicates whether the platform firmware is 
operating
+        // in Secure boot mode (1) or not (0), so we should not change 
SecureBoot
+        // Variable in runtime.
+        //
+        return Status;
+      }
+
+      //
+      // Update the value of SecureBoot variable by a simple mem copy, this 
could avoid possible
+      // variable storage reclaim at runtime.
+      //
+      CopyMem (SecureBootVarData, &mSecureBootState[NewMode].SecureBoot, 
sizeof(UINT8));
+
+      //
+      // Create the "SecureBootEnable" variable as secure boot is enabled.
+      //
+      SecureBootEnable = SECURE_BOOT_ENABLE;
+      AuthServiceInternalUpdateVariable (
+        EFI_SECURE_BOOT_ENABLE_NAME,
+        &gEfiSecureBootEnableDisableGuid,
+        &SecureBootEnable,
+        sizeof (SecureBootEnable),
+        EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS
+        );
+      break;
+
+    default:
+      DEBUG((EFI_D_ERROR, "Invalid state tranition from %x to %x\n", 
SecureBootModeTypeSetupMode, NewMode));
+      ASSERT(FALSE);
+  }
+
+  return Status;
  }

  /**
-  Update the variable region with Variable information.
+  This function performs main secure boot mode transition logic.

-  @param[in] VariableName           Name of variable.
-  @param[in] VendorGuid             Guid of variable.
-  @param[in] Data                   Data pointer.
-  @param[in] DataSize               Size of Data.
-  @param[in] Attributes             Attribute value of the variable.
-  @param[in] TimeStamp              Value of associated TimeStamp.
+  @param[in] CurMode                Current Secure Boot Mode.
+  @param[in] NewMode                New Secure Boot Mode.

-  @retval EFI_SUCCESS               The update operation is success.
-  @retval EFI_INVALID_PARAMETER     Invalid parameter.
-  @retval EFI_WRITE_PROTECTED       Variable is write-protected.
+  @retval EFI_SUCCESS               The initialization operation is successful.
    @retval EFI_OUT_OF_RESOURCES      There is not enough resource.
+  @retval EFI_INVALID_PARAMETER     The Current Secure Boot Mode is wrong.

  **/
  EFI_STATUS
-AuthServiceInternalUpdateVariableWithTimeStamp (
-  IN CHAR16             *VariableName,
-  IN EFI_GUID           *VendorGuid,
-  IN VOID               *Data,
-  IN UINTN              DataSize,
-  IN UINT32             Attributes,
-  IN EFI_TIME           *TimeStamp
+SecureBootModeTransition(
+  IN  SECURE_BOOT_MODE_TYPE  CurMode,
+  IN  SECURE_BOOT_MODE_TYPE  NewMode
    )
  {
-  EFI_STATUS            FindStatus;
-  VOID                  *OrgData;
-  UINTN                 OrgDataSize;
-  AUTH_VARIABLE_INFO    AuthVariableInfo;
-
-  FindStatus = AuthServiceInternalFindVariable (
-                 VariableName,
-                 VendorGuid,
-                 &OrgData,
-                 &OrgDataSize
-                 );
+  EFI_STATUS Status;

    //
-  // EFI_VARIABLE_APPEND_WRITE attribute only effects for existing variable
+  // SecureBootMode transition
    //
-  if (!EFI_ERROR (FindStatus) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) != 
0)) {
-    if ((CompareGuid (VendorGuid, &gEfiImageSecurityDatabaseGuid) &&
-        ((StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE) == 0) || (StrCmp 
(VariableName, EFI_IMAGE_SECURITY_DATABASE1) == 0) ||
-        (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE2) == 0))) ||
-        (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp 
(VariableName, EFI_KEY_EXCHANGE_KEY_NAME) == 0))) {
-      //
-      // For variables with formatted as EFI_SIGNATURE_LIST, the driver shall 
not perform an append of
-      // EFI_SIGNATURE_DATA values that are already part of the existing 
variable value.
-      //
-      FilterSignatureList (
-        OrgData,
-        OrgDataSize,
-        Data,
-        &DataSize
-        );
-    }
+  switch (CurMode) {
+    case SecureBootModeTypeUserMode:
+      Status = TransitionFromUserMode(NewMode);
+      break;
+
+    case SecureBootModeTypeSetupMode:
+      Status = TransitionFromSetupMode(NewMode);
+      break;
+
+    case SecureBootModeTypeAuditMode:
+      Status = TransitionFromAuditMode(NewMode);
+      break;
+
+    case SecureBootModeTypeDeployedMode:
+      Status = TransitionFromDeployedMode(NewMode);
+      break;
+
+    default:
+      Status = EFI_INVALID_PARAMETER;
+      ASSERT(FALSE);
    }

-  ZeroMem (&AuthVariableInfo, sizeof (AuthVariableInfo));
-  AuthVariableInfo.VariableName = VariableName;
-  AuthVariableInfo.VendorGuid = VendorGuid;
-  AuthVariableInfo.Data = Data;
-  AuthVariableInfo.DataSize = DataSize;
-  AuthVariableInfo.Attributes = Attributes;
-  AuthVariableInfo.TimeStamp = TimeStamp;
-  return mAuthVarLibContextIn->UpdateVariable (
-           &AuthVariableInfo
-           );
+  return Status;
+
  }

  /**
@@ -597,129 +1555,6 @@ Done:
    }
  }

-/**
-  Update platform mode.
-
-  @param[in]      Mode                    SETUP_MODE or USER_MODE.
-
-  @return EFI_INVALID_PARAMETER           Invalid parameter.
-  @return EFI_SUCCESS                     Update platform mode successfully.
-
-**/
-EFI_STATUS
-UpdatePlatformMode (
-  IN  UINT32                    Mode
-  )
-{
-  EFI_STATUS              Status;
-  VOID                    *Data;
-  UINTN                   DataSize;
-  UINT8                   SecureBootMode;
-  UINT8                   SecureBootEnable;
-  UINTN                   VariableDataSize;
-
-  Status = AuthServiceInternalFindVariable (
-             EFI_SETUP_MODE_NAME,
-             &gEfiGlobalVariableGuid,
-             &Data,
-             &DataSize
-             );
-  if (EFI_ERROR (Status)) {
-    return Status;
-  }
-
-  //
-  // Update the value of SetupMode variable by a simple mem copy, this could 
avoid possible
-  // variable storage reclaim at runtime.
-  //
-  mPlatformMode = (UINT8) Mode;
-  CopyMem (Data, &mPlatformMode, sizeof(UINT8));
-
-  if (mAuthVarLibContextIn->AtRuntime ()) {
-    //
-    // SecureBoot Variable indicates whether the platform firmware is operating
-    // in Secure boot mode (1) or not (0), so we should not change SecureBoot
-    // Variable in runtime.
-    //
-    return Status;
-  }
-
-  //
-  // Check "SecureBoot" variable's existence.
-  // If it doesn't exist, firmware has no capability to perform driver signing 
verification,
-  // then set "SecureBoot" to 0.
-  //
-  Status = AuthServiceInternalFindVariable (
-             EFI_SECURE_BOOT_MODE_NAME,
-             &gEfiGlobalVariableGuid,
-             &Data,
-             &DataSize
-             );
-  //
-  // If "SecureBoot" variable exists, then check "SetupMode" variable update.
-  // If "SetupMode" variable is USER_MODE, "SecureBoot" variable is set to 1.
-  // If "SetupMode" variable is SETUP_MODE, "SecureBoot" variable is set to 0.
-  //
-  if (EFI_ERROR (Status)) {
-    SecureBootMode = SECURE_BOOT_MODE_DISABLE;
-  } else {
-    if (mPlatformMode == USER_MODE) {
-      SecureBootMode = SECURE_BOOT_MODE_ENABLE;
-    } else if (mPlatformMode == SETUP_MODE) {
-      SecureBootMode = SECURE_BOOT_MODE_DISABLE;
-    } else {
-      return EFI_NOT_FOUND;
-    }
-  }
-
-  Status  = AuthServiceInternalUpdateVariable (
-              EFI_SECURE_BOOT_MODE_NAME,
-              &gEfiGlobalVariableGuid,
-              &SecureBootMode,
-              sizeof(UINT8),
-              EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS
-              );
-  if (EFI_ERROR (Status)) {
-    return Status;
-  }
-
-  //
-  // Check "SecureBootEnable" variable's existence. It can enable/disable 
secure boot feature.
-  //
-  Status = AuthServiceInternalFindVariable (
-             EFI_SECURE_BOOT_ENABLE_NAME,
-             &gEfiSecureBootEnableDisableGuid,
-             &Data,
-             &DataSize
-             );
-
-  if (SecureBootMode == SECURE_BOOT_MODE_ENABLE) {
-    //
-    // Create the "SecureBootEnable" variable as secure boot is enabled.
-    //
-    SecureBootEnable = SECURE_BOOT_ENABLE;
-    VariableDataSize = sizeof (SecureBootEnable);
-  } else {
-    //
-    // Delete the "SecureBootEnable" variable if this variable exist as 
"SecureBoot"
-    // variable is not in secure boot state.
-    //
-    if (EFI_ERROR (Status)) {
-      return EFI_SUCCESS;
-    }
-    SecureBootEnable = SECURE_BOOT_DISABLE;
-    VariableDataSize = 0;
-  }
-
-  Status = AuthServiceInternalUpdateVariable (
-             EFI_SECURE_BOOT_ENABLE_NAME,
-             &gEfiSecureBootEnableDisableGuid,
-             &SecureBootEnable,
-             VariableDataSize,
-             EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS
-             );
-  return Status;
-}

  /**
    Check input data form to make sure it is a valid EFI_SIGNATURE_LIST for 
PK/KEK/db/dbx/dbt variable.
@@ -880,6 +1715,121 @@ VendorKeyIsModified (
  }

  /**
+  Process Secure Boot Mode variable.
+
+  Caution: This function may receive untrusted input.
+  This function may be invoked in SMM mode, and datasize and data are external 
input.
+  This function will do basic validation, before parse the data.
+  This function will parse the authentication carefully to avoid security 
issues, like
+  buffer overflow, integer overflow.
+  This function will check attribute carefully to avoid authentication bypass.
+
+  @param[in]  VariableName                Name of Variable to be found.
+  @param[in]  VendorGuid                  Variable vendor GUID.
+  @param[in]  Data                        Data pointer.
+  @param[in]  DataSize                    Size of Data found. If size is less 
than the
+                                          data, this value contains the 
required size.
+  @param[in]  Attributes                  Attribute value of the variable
+
+  @return EFI_INVALID_PARAMETER           Invalid parameter
+  @return EFI_SECURITY_VIOLATION          The variable does NOT pass the 
validation
+                                          check carried out by the firmware.
+  @return EFI_WRITE_PROTECTED             Variable is Read-Only.
+  @return EFI_SUCCESS                     Variable passed validation 
successfully.
+
+**/
+EFI_STATUS
+ProcessSecureBootModeVar (
+  IN  CHAR16         *VariableName,
+  IN  EFI_GUID       *VendorGuid,
+  IN  VOID           *Data,
+  IN  UINTN          DataSize,
+  IN  UINT32         Attributes OPTIONAL
+  )
+{
+  EFI_STATUS    Status;
+  UINT8         *VarData;
+  UINTN         VarDataSize;
+
+  //
+  // Check "AuditMode", "DeployedMode" Variable ReadWrite Attributes
+  //  if in Runtime,  Always RO
+  //  if in Boottime, Depends on current Secure Boot Mode
+  //
+  if (mAuthVarLibContextIn->AtRuntime()) {
+    return EFI_WRITE_PROTECTED;
+  }
+
+  //
+  // Delete not OK
+  //
+  if ((DataSize != sizeof(UINT8)) || (Attributes == 0)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (StrCmp (VariableName, EFI_AUDIT_MODE_NAME) == 0) {
+    if(mSecureBootState[mSecureBootMode].IsAuditModeRO) {
+      return EFI_WRITE_PROTECTED;
+    }
+  } else {
+    //
+    // Platform specific deployedMode clear. Set DeployedMode = RW
+    //
+    if (!InCustomMode() || !UserPhysicalPresent() || mSecureBootMode != 
SecureBootModeTypeDeployedMode) {
+      if(mSecureBootState[mSecureBootMode].IsDeployedModeRO) {
+        return EFI_WRITE_PROTECTED;
+      }
+    }
+  }
+
+  if (*(UINT8 *)Data != 0 && *(UINT8 *)Data != 1) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // AuditMode/DeployedMode/SetupMode/SecureBoot are all NON_NV variable 
maintained by Variable driver
+  // they can be RW. but can't be deleted. so they can always be found.
+  //
+  Status = AuthServiceInternalFindVariable (
+             VariableName,
+             VendorGuid,
+             &VarData,
+             &VarDataSize
+             );
+  if (EFI_ERROR(Status)) {
+    ASSERT(FALSE);
+  }
+
+  //
+  // If AuditMode/DeployedMode is assigned same value. Simply return 
EFI_SUCCESS
+  //
+  if (*VarData == *(UINT8 *)Data) {
+    return EFI_SUCCESS;
+  }
+
+  //
+  // Perform SecureBootMode transition
+  //
+  if (StrCmp (VariableName, EFI_AUDIT_MODE_NAME) == 0) {
+    DEBUG((EFI_D_INFO, "Current SecureBootMode %x Transfer to SecureBootMode 
%x\n", mSecureBootMode, SecureBootModeTypeAuditMode));
+    return SecureBootModeTransition(mSecureBootMode, 
SecureBootModeTypeAuditMode);
+  } else if (StrCmp (VariableName, EFI_DEPLOYED_MODE_NAME) == 0) {
+    if (mSecureBootMode == SecureBootModeTypeDeployedMode) {
+      //
+      // Platform specific DeployedMode clear. InCustomMode() && 
UserPhysicalPresent() is checked before
+      //
+      DEBUG((EFI_D_INFO, "Current SecureBootMode %x. Transfer to SecureBootMode 
%x\n", mSecureBootMode, SecureBootModeTypeUserMode));
+      return SecureBootModeTransition(mSecureBootMode, 
SecureBootModeTypeUserMode);
+    } else {
+      DEBUG((EFI_D_INFO, "Current SecureBootMode %x. Transfer to SecureBootMode 
%x\n", mSecureBootMode, SecureBootModeTypeDeployedMode));
+      return SecureBootModeTransition(mSecureBootMode, 
SecureBootModeTypeDeployedMode);
+    }
+  }
+
+  return EFI_INVALID_PARAMETER;
+}
+
+/**
    Process variable with platform key for verification.

    Caution: This function may receive untrusted input.
@@ -917,6 +1867,7 @@ ProcessVarWithPk (
    BOOLEAN                     Del;
    UINT8                       *Payload;
    UINTN                       PayloadSize;
+  VARIABLE_ENTRY_CONSISTENCY  VariableEntry[2];

    if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0 ||
        (Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == 0) 
{
@@ -927,13 +1878,29 @@ ProcessVarWithPk (
      return EFI_INVALID_PARAMETER;
    }

+  //
+  // Init state of Del. State may change due to secure check
+  //
    Del = FALSE;
-  if ((InCustomMode() && UserPhysicalPresent()) || (mPlatformMode == SETUP_MODE 
&& !IsPk)) {
-    Payload = (UINT8 *) Data + AUTHINFO2_SIZE (Data);
-    PayloadSize = DataSize - AUTHINFO2_SIZE (Data);
-    if (PayloadSize == 0) {
-      Del = TRUE;
-    }
+  Payload = (UINT8 *) Data + AUTHINFO2_SIZE (Data);
+  PayloadSize = DataSize - AUTHINFO2_SIZE (Data);
+  if (PayloadSize == 0) {
+    Del = TRUE;
+  }
+
+  //
+  // Check the variable space for both PKpub and SecureBootMode variable.
+  //
+  VariableEntry[0].VariableSize = PayloadSize;
+  VariableEntry[0].Guid         = &gEfiGlobalVariableGuid;
+  VariableEntry[0].Name         = EFI_PLATFORM_KEY_NAME;
+
+  VariableEntry[1].VariableSize = sizeof(UINT8);
+  VariableEntry[1].Guid         = &gEfiSecureBootModeGuid;
+  VariableEntry[1].Name         = EFI_SECURE_MODE_NAME;
+
+  if ((InCustomMode() && UserPhysicalPresent()) ||
+      (((mSecureBootMode == SecureBootModeTypeSetupMode) || (mSecureBootMode == 
SecureBootModeTypeAuditMode)) && !IsPk)) {

      Status = CheckSignatureListFormat(VariableName, VendorGuid, Payload, 
PayloadSize);
      if (EFI_ERROR (Status)) {
@@ -952,10 +1919,19 @@ ProcessVarWithPk (
        return Status;
      }

-    if ((mPlatformMode != SETUP_MODE) || IsPk) {
+    if (((mSecureBootMode != SecureBootModeTypeSetupMode) && (mSecureBootMode 
!= SecureBootModeTypeAuditMode)) || IsPk) {
        Status = VendorKeyIsModified ();
      }
-  } else if (mPlatformMode == USER_MODE) {
+  } else if (mSecureBootMode == SecureBootModeTypeUserMode || mSecureBootMode 
== SecureBootModeTypeDeployedMode) {
+    //
+    // If delete PKpub, check "SecureBootMode" only
+    // if update / add PKub, check both NewPKpub & "SecureBootMode"
+    //
+    if ((IsPk && Del && !mAuthVarLibContextIn->CheckRemainingSpaceForConsistency 
(VARIABLE_ATTRIBUTE_NV_BS_RT, &VariableEntry[1], NULL))
+     || (IsPk && !Del && !mAuthVarLibContextIn->CheckRemainingSpaceForConsistency 
(VARIABLE_ATTRIBUTE_NV_BS_RT, &VariableEntry[0], &VariableEntry[1], NULL))) {
+      return EFI_OUT_OF_RESOURCES;
+    }
+
      //
      // Verify against X509 Cert in PK database.
      //
@@ -970,8 +1946,19 @@ ProcessVarWithPk (
                 );
    } else {
      //
+    // SetupMode or  AuditMode to add PK
      // Verify against the certificate in data payload.
      //
+    //
+    // Check PKpub & SecureBootMode variable space consistency
+    //
+    if (!mAuthVarLibContextIn->CheckRemainingSpaceForConsistency 
(VARIABLE_ATTRIBUTE_NV_BS_RT, &VariableEntry[0], &VariableEntry[1], NULL)) {
+      //
+      // No enough variable space to set PK successfully.
+      //
+      return EFI_OUT_OF_RESOURCES;
+    }
+
      Status = VerifyTimeBasedPayloadAndUpdate (
                 VariableName,
                 VendorGuid,
@@ -984,16 +1971,30 @@ ProcessVarWithPk (
    }

    if (!EFI_ERROR(Status) && IsPk) {
-    if (mPlatformMode == SETUP_MODE && !Del) {
-      //
-      // If enroll PK in setup mode, need change to user mode.
-      //
-      Status = UpdatePlatformMode (USER_MODE);
-    } else if (mPlatformMode == USER_MODE && Del){
-      //
-      // If delete PK in user mode, need change to setup mode.
-      //
-      Status = UpdatePlatformMode (SETUP_MODE);
+    //
+    // Delete or Enroll PK causes SecureBootMode change
+    //
+    if (!Del) {
+      if (mSecureBootMode == SecureBootModeTypeSetupMode) {
+        //
+        // If enroll PK in setup mode,  change to user mode.
+        //
+        Status = SecureBootModeTransition (mSecureBootMode, 
SecureBootModeTypeUserMode);
+      } else if (mSecureBootMode == SecureBootModeTypeAuditMode) {
+        //
+        // If enroll PK in Audit mode,  change to Deployed mode.
+        //
+        Status = SecureBootModeTransition (mSecureBootMode, 
SecureBootModeTypeDeployedMode);
+      } else {
+        DEBUG((EFI_D_INFO, "PK is updated in %x mode. No SecureBootMode 
change.\n", mSecureBootMode));
+      }
+    } else {
+      if ((mSecureBootMode == SecureBootModeTypeUserMode) || (mSecureBootMode 
== SecureBootModeTypeDeployedMode)) {
+        //
+        // If delete PK in User Mode or DeployedMode,  change to Setup Mode.
+        //
+        Status = SecureBootModeTransition (mSecureBootMode, 
SecureBootModeTypeSetupMode);
+      }
      }
    }

@@ -1046,7 +2047,8 @@ ProcessVarWithKek (
    }

    Status = EFI_SUCCESS;
-  if (mPlatformMode == USER_MODE && !(InCustomMode() && 
UserPhysicalPresent())) {
+  if ((mSecureBootMode == SecureBootModeTypeUserMode || mSecureBootMode == 
SecureBootModeTypeDeployedMode)
+   && !(InCustomMode() && UserPhysicalPresent())) {
      //
      // Time-based, verify against X509 Cert KEK.
      //
@@ -1083,7 +2085,7 @@ ProcessVarWithKek (
        return Status;
      }

-    if (mPlatformMode != SETUP_MODE) {
+    if ((mSecureBootMode != SecureBootModeTypeSetupMode) && (mSecureBootMode 
!= SecureBootModeTypeAuditMode)) {
        Status = VendorKeyIsModified ();
      }
    }
diff --git a/SecurityPkg/Library/AuthVariableLib/AuthServiceInternal.h 
b/SecurityPkg/Library/AuthVariableLib/AuthServiceInternal.h
index add05c2..88f3a99 100644
--- a/SecurityPkg/Library/AuthVariableLib/AuthServiceInternal.h
+++ b/SecurityPkg/Library/AuthVariableLib/AuthServiceInternal.h
@@ -117,6 +117,33 @@ typedef struct {
  } AUTH_CERT_DB_DATA;
  #pragma pack()

+///
+/// "SecureBootMode" variable stores current secure boot mode.
+/// The value type is SECURE_BOOT_MODE_TYPE.
+///
+#define EFI_SECURE_MODE_NAME    L"SecureBootMode"
+
+typedef enum {
+  SecureBootModeTypeUserMode,
+  SecureBootModeTypeSetupMode,
+  SecureBootModeTypeAuditMode,
+  SecureBootModeTypeDeployedMode,
+  SecureBootModeTypeMax
+} SECURE_BOOT_MODE_TYPE;
+
+typedef struct {
+   BOOLEAN IsPkExist;
+   UINT8   AuditMode;
+   BOOLEAN IsAuditModeRO;
+   UINT8   DeployedMode;
+   BOOLEAN IsDeployedModeRO;
+   UINT8   SetupMode;
+   //
+   // SetupMode is always RO. Skip IsSetupModeRO;
+   //
+   UINT8   SecureBoot;
+} SECURE_BOOT_MODE;
+
  extern UINT8    *mPubKeyStore;
  extern UINT32   mPubKeyNumber;
  extern UINT32   mMaxKeyNumber;
@@ -129,6 +156,19 @@ extern UINT8    mVendorKeyState;
  extern VOID     *mHashCtx;

  extern AUTH_VAR_LIB_CONTEXT_IN *mAuthVarLibContextIn;
+extern SECURE_BOOT_MODE_TYPE   mSecureBootMode;
+
+/**
+  Initialize Secure Boot variables.
+
+  @retval EFI_SUCCESS               The initialization operation is successful.
+  @retval EFI_OUT_OF_RESOURCES      There is not enough resource.
+
+**/
+EFI_STATUS
+InitSecureBootVariables (
+  VOID
+  );

  /**
    Process variable with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set
@@ -220,6 +260,39 @@ FilterSignatureList (
    );

  /**
+  Process Secure Boot Mode variable.
+
+  Caution: This function may receive untrusted input.
+  This function may be invoked in SMM mode, and datasize and data are external 
input.
+  This function will do basic validation, before parse the data.
+  This function will parse the authentication carefully to avoid security 
issues, like
+  buffer overflow, integer overflow.
+  This function will check attribute carefully to avoid authentication bypass.
+
+  @param[in]  VariableName                Name of Variable to be found.
+  @param[in]  VendorGuid                  Variable vendor GUID.
+  @param[in]  Data                        Data pointer.
+  @param[in]  DataSize                    Size of Data found. If size is less 
than the
+                                          data, this value contains the 
required size.
+  @param[in]  Attributes                  Attribute value of the variable
+
+  @return EFI_INVALID_PARAMETER           Invalid parameter
+  @return EFI_SECURITY_VIOLATION          The variable does NOT pass the 
validation
+                                          check carried out by the firmware.
+  @return EFI_WRITE_PROTECTED             Variable is Read-Only.
+  @return EFI_SUCCESS                     Variable passed validation 
successfully.
+
+**/
+EFI_STATUS
+ProcessSecureBootModeVar (
+  IN  CHAR16         *VariableName,
+  IN  EFI_GUID       *VendorGuid,
+  IN  VOID           *Data,
+  IN  UINTN          DataSize,
+  IN  UINT32         Attributes OPTIONAL
+  );
+
+/**
    Process variable with platform key for verification.

    Caution: This function may receive untrusted input.
diff --git a/SecurityPkg/Library/AuthVariableLib/AuthVariableLib.c 
b/SecurityPkg/Library/AuthVariableLib/AuthVariableLib.c
index a54eaaa..446b07c 100644
--- a/SecurityPkg/Library/AuthVariableLib/AuthVariableLib.c
+++ b/SecurityPkg/Library/AuthVariableLib/AuthVariableLib.c
@@ -33,8 +33,8 @@ UINT32   mMaxKeyNumber;
  UINT32   mMaxKeyDbSize;
  UINT8    *mCertDbStore;
  UINT32   mMaxCertDbSize;
-UINT32   mPlatformMode;
  UINT8    mVendorKeyState;
+SECURE_BOOT_MODE_TYPE  mSecureBootMode;

  EFI_GUID mSignatureSupport[] = {EFI_CERT_SHA1_GUID, EFI_CERT_SHA256_GUID, 
EFI_CERT_RSA2048_GUID, EFI_CERT_X509_GUID};

@@ -99,6 +99,17 @@ VARIABLE_ENTRY_PROPERTY mAuthVarEntry[] = {
        MAX_UINTN
      }
    },
+  {
+    &gEfiSecureBootModeGuid,
+    L"SecureBootMode",
+    {
+      VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+      VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY,
+      VARIABLE_ATTRIBUTE_NV_BS_RT,
+      sizeof (UINT8),
+      sizeof (UINT8)
+    }
+  }
  };

  VOID **mAuthVarAddressPointer[10];
@@ -132,8 +143,6 @@ AuthVariableLibInitialize (
    UINT8                 *Data;
    UINTN                 DataSize;
    UINTN                 CtxSize;
-  UINT8                 SecureBootMode;
-  UINT8                 SecureBootEnable;
    UINT8                 CustomMode;
    UINT32                ListSize;

@@ -208,31 +217,11 @@ AuthVariableLibInitialize (
      mPubKeyNumber = (UINT32) (DataSize / sizeof (AUTHVAR_KEY_DB_DATA));
    }

-  Status = AuthServiceInternalFindVariable (EFI_PLATFORM_KEY_NAME, 
&gEfiGlobalVariableGuid, (VOID **) &Data, &DataSize);
-  if (EFI_ERROR (Status)) {
-    DEBUG ((EFI_D_INFO, "Variable %s does not exist.\n", 
EFI_PLATFORM_KEY_NAME));
-  } else {
-    DEBUG ((EFI_D_INFO, "Variable %s exists.\n", EFI_PLATFORM_KEY_NAME));
-  }
-
    //
-  // Create "SetupMode" variable with BS+RT attribute set.
+  // Init Secure Boot variables
    //
-  if (EFI_ERROR (Status)) {
-    mPlatformMode = SETUP_MODE;
-  } else {
-    mPlatformMode = USER_MODE;
-  }
-  Status = AuthServiceInternalUpdateVariable (
-             EFI_SETUP_MODE_NAME,
-             &gEfiGlobalVariableGuid,
-             &mPlatformMode,
-             sizeof(UINT8),
-             EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS
-             );
-  if (EFI_ERROR (Status)) {
-    return Status;
-  }
+  Status = InitSecureBootVariables ();
+

    //
    // Create "SignatureSupport" variable with BS+RT attribute set.
@@ -249,69 +238,6 @@ AuthVariableLibInitialize (
    }

    //
-  // If "SecureBootEnable" variable exists, then update "SecureBoot" variable.
-  // If "SecureBootEnable" variable is SECURE_BOOT_ENABLE and in USER_MODE, Set 
"SecureBoot" variable to SECURE_BOOT_MODE_ENABLE.
-  // If "SecureBootEnable" variable is SECURE_BOOT_DISABLE, Set "SecureBoot" 
variable to SECURE_BOOT_MODE_DISABLE.
-  //
-  SecureBootEnable = SECURE_BOOT_DISABLE;
-  Status = AuthServiceInternalFindVariable (EFI_SECURE_BOOT_ENABLE_NAME, 
&gEfiSecureBootEnableDisableGuid, (VOID **) &Data, &DataSize);
-  if (!EFI_ERROR (Status)) {
-    if (mPlatformMode == SETUP_MODE){
-      //
-      // PK is cleared in runtime. "SecureBootMode" is not updated before 
reboot
-      // Delete "SecureBootMode" in SetupMode
-      //
-      Status = AuthServiceInternalUpdateVariable (
-                 EFI_SECURE_BOOT_ENABLE_NAME,
-                 &gEfiSecureBootEnableDisableGuid,
-                 &SecureBootEnable,
-                 0,
-                 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS
-                 );
-    } else {
-      SecureBootEnable = *(UINT8 *) Data;
-    }
-  } else if (mPlatformMode == USER_MODE) {
-    //
-    // "SecureBootEnable" not exist, initialize it in USER_MODE.
-    //
-    SecureBootEnable = SECURE_BOOT_ENABLE;
-    Status = AuthServiceInternalUpdateVariable (
-               EFI_SECURE_BOOT_ENABLE_NAME,
-               &gEfiSecureBootEnableDisableGuid,
-               &SecureBootEnable,
-               sizeof (UINT8),
-               EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS
-               );
-    if (EFI_ERROR (Status)) {
-      return Status;
-    }
-  }
-
-  //
-  // Create "SecureBoot" variable with BS+RT attribute set.
-  //
-  if (SecureBootEnable == SECURE_BOOT_ENABLE && mPlatformMode == USER_MODE) {
-    SecureBootMode = SECURE_BOOT_MODE_ENABLE;
-  } else {
-    SecureBootMode = SECURE_BOOT_MODE_DISABLE;
-  }
-  Status = AuthServiceInternalUpdateVariable (
-             EFI_SECURE_BOOT_MODE_NAME,
-             &gEfiGlobalVariableGuid,
-             &SecureBootMode,
-             sizeof (UINT8),
-             EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS
-             );
-  if (EFI_ERROR (Status)) {
-    return Status;
-  }
-
-  DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_SETUP_MODE_NAME, 
mPlatformMode));
-  DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_SECURE_BOOT_MODE_NAME, 
SecureBootMode));
-  DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_SECURE_BOOT_ENABLE_NAME, 
SecureBootEnable));
-
-  //
    // Initialize "CustomMode" in STANDARD_SECURE_BOOT_MODE state.
    //
    CustomMode = STANDARD_SECURE_BOOT_MODE;
@@ -455,10 +381,16 @@ AuthVariableLibProcessVariable (
  {
    EFI_STATUS        Status;

+  //
+  // Process PK, KEK, Sigdb, AuditMode, DeployedMode separately.
+  //
    if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp 
(VariableName, EFI_PLATFORM_KEY_NAME) == 0)){
      Status = ProcessVarWithPk (VariableName, VendorGuid, Data, DataSize, 
Attributes, TRUE);
    } else if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp 
(VariableName, EFI_KEY_EXCHANGE_KEY_NAME) == 0)) {
      Status = ProcessVarWithPk (VariableName, VendorGuid, Data, DataSize, 
Attributes, FALSE);
+  } else if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid)
+          && (StrCmp (VariableName, EFI_AUDIT_MODE_NAME) == 0 || StrCmp 
(VariableName, EFI_DEPLOYED_MODE_NAME) == 0)) {
+    Status = ProcessSecureBootModeVar(VariableName, VendorGuid, Data, 
DataSize, Attributes);
    } else if (CompareGuid (VendorGuid, &gEfiImageSecurityDatabaseGuid) &&
               ((StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE)  == 0) ||
                (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE1) == 0) ||
diff --git a/SecurityPkg/Library/AuthVariableLib/AuthVariableLib.inf 
b/SecurityPkg/Library/AuthVariableLib/AuthVariableLib.inf
index 3709f7b..3cf6582 100644
--- a/SecurityPkg/Library/AuthVariableLib/AuthVariableLib.inf
+++ b/SecurityPkg/Library/AuthVariableLib/AuthVariableLib.inf
@@ -85,6 +85,10 @@
    ## PRODUCES            ## Variable:L"AuthVarKeyDatabase"
    gEfiAuthenticatedVariableGuid

+  ## CONSUMES            ## Variable:L"SecureBootMode"
+  ## PRODUCES            ## Variable:L"SecureBootMode"
+  gEfiSecureBootModeGuid
+
    gEfiCertTypeRsa2048Sha256Guid  ## SOMETIMES_CONSUMES   ## GUID  # Unique ID 
for the type of the certificate.
    gEfiCertPkcs7Guid              ## SOMETIMES_CONSUMES   ## GUID  # Unique ID 
for the type of the certificate.
    gEfiCertX509Guid               ## SOMETIMES_CONSUMES   ## GUID  # Unique ID 
for the type of the signature.
diff --git 
a/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c 
b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c
index 5cb9f81..4b4d3bf 100644
--- a/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c
+++ b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c
@@ -712,6 +712,58 @@ GetImageExeInfoTableSize (
  }

  /**
+  Create signature list based on input signature data and certificate type 
GUID. Caller is reposible
+  to free new created SignatureList.
+
+  @param[in]   SignatureData           Signature data in SignatureList.
+  @param[in]   SignatureDataSize       Signature data size.
+  @param[in]   CertType                Certificate Type.
+  @param[out]  SignatureList           Created SignatureList.
+  @param[out]  SignatureListSize       Created SignatureListSize.
+
+  @return EFI_OUT_OF_RESOURCES         The operation is failed due to lack of 
resources.
+  @retval EFI_SUCCESS          Successfully create signature list.
+
+**/
+EFI_STATUS
+CreateSignatureList(
+  IN UINT8                *SignatureData,
+  IN UINTN                SignatureDataSize,
+  IN EFI_GUID             *CertType,
+  OUT EFI_SIGNATURE_LIST  **SignatureList,
+  OUT UINTN               *SignatureListSize
+  )
+{
+  EFI_SIGNATURE_LIST   *SignList;
+  UINTN                SignListSize;
+  EFI_SIGNATURE_DATA   *Signature;
+
+  SignList       = NULL;
+  *SignatureList = NULL;
+
+  SignListSize = sizeof (EFI_SIGNATURE_LIST) + sizeof (EFI_SIGNATURE_DATA) - 1 
+ SignatureDataSize;
+  SignList     = (EFI_SIGNATURE_LIST *) AllocateZeroPool (SignListSize);
+  if (SignList == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  SignList->SignatureHeaderSize = 0;
+  SignList->SignatureListSize   = (UINT32) SignListSize;
+  SignList->SignatureSize       = (UINT32) SignatureDataSize + sizeof 
(EFI_SIGNATURE_DATA) - 1;
+  CopyMem (&SignList->SignatureType, CertType, sizeof (EFI_GUID));
+
+  DEBUG((EFI_D_INFO, "SignatureDataSize %x\n", SignatureDataSize));
+  Signature = (EFI_SIGNATURE_DATA *) ((UINT8 *) SignList + sizeof 
(EFI_SIGNATURE_LIST));
+  CopyMem (Signature->SignatureData, SignatureData, SignatureDataSize);
+
+  *SignatureList     = SignList;
+  *SignatureListSize = SignListSize;
+
+  return EFI_SUCCESS;
+
+}
+
+/**
    Create an Image Execution Information Table entry and add it to system 
configuration table.

    @param[in]  Action          Describes the action taken by the firmware 
regarding this image.
@@ -737,11 +789,13 @@ AddImageExeInfo (
    UINTN                           NewImageExeInfoEntrySize;
    UINTN                           NameStringLen;
    UINTN                           DevicePathSize;
+  CHAR16                          *NameStr;

    ImageExeInfoTable     = NULL;
    NewImageExeInfoTable  = NULL;
    ImageExeInfoEntry     = NULL;
    NameStringLen         = 0;
+  NameStr               = NULL;

    if (DevicePath == NULL) {
      return ;
@@ -769,7 +823,12 @@ AddImageExeInfo (
    }

    DevicePathSize            = GetDevicePathSize (DevicePath);
-  NewImageExeInfoEntrySize  = sizeof (EFI_IMAGE_EXECUTION_INFO) + 
NameStringLen + DevicePathSize + SignatureSize;
+
+  //
+  // Signature size can be odd. Pad after signature to ensure next 
EXECUTION_INFO entry align
+  //
+  NewImageExeInfoEntrySize = sizeof (EFI_IMAGE_EXECUTION_INFO) + NameStringLen 
+ DevicePathSize + SignatureSize;
+
    NewImageExeInfoTable      = (EFI_IMAGE_EXECUTION_INFO_TABLE *) 
AllocateRuntimePool (ImageExeInfoTableSize + NewImageExeInfoEntrySize);
    if (NewImageExeInfoTable == NULL) {
      return ;
@@ -788,19 +847,21 @@ AddImageExeInfo (
    WriteUnaligned32 ((UINT32 *) ImageExeInfoEntry, Action);
    WriteUnaligned32 ((UINT32 *) ((UINT8 *) ImageExeInfoEntry + sizeof 
(EFI_IMAGE_EXECUTION_ACTION)), (UINT32) NewImageExeInfoEntrySize);

+  NameStr = (CHAR16 *)(ImageExeInfoEntry + 1);
    if (Name != NULL) {
-    CopyMem ((UINT8 *) ImageExeInfoEntry + sizeof (EFI_IMAGE_EXECUTION_ACTION) 
+ sizeof (UINT32), Name, NameStringLen);
+    CopyMem ((UINT8 *) NameStr, Name, NameStringLen);
    } else {
-    ZeroMem ((UINT8 *) ImageExeInfoEntry + sizeof (EFI_IMAGE_EXECUTION_ACTION) 
+ sizeof (UINT32), sizeof (CHAR16));
+    ZeroMem ((UINT8 *) NameStr, sizeof (CHAR16));
    }
+
    CopyMem (
-    (UINT8 *) ImageExeInfoEntry + sizeof (EFI_IMAGE_EXECUTION_ACTION) + sizeof 
(UINT32) + NameStringLen,
+    (UINT8 *) NameStr + NameStringLen,
      DevicePath,
      DevicePathSize
      );
    if (Signature != NULL) {
      CopyMem (
-      (UINT8 *) ImageExeInfoEntry + sizeof (EFI_IMAGE_EXECUTION_ACTION) + 
sizeof (UINT32) + NameStringLen + DevicePathSize,
+      (UINT8 *) NameStr + NameStringLen + DevicePathSize,
        Signature,
        SignatureSize
        );
@@ -1088,6 +1149,53 @@ IsTimeZero (
  }

  /**
+  Record multiple certificate list & verification state of a verified image to
+  IMAGE_EXECUTION_TABLE.
+
+  @param[in]  CertBuf              Certificate list buffer.
+  @param[in]  CertBufLength        Certificate list buffer.
+  @param[in]  Action               Certificate list action to be record.
+  @param[in]  ImageName            Image name.
+  @param[in]  ImageDevicePath      Image device path.
+
+**/
+VOID
+RecordCertListToImageExeuctionTable(
+  IN UINT8                          *CertBuf,
+  IN UINTN                           CertBufLength,
+  IN EFI_IMAGE_EXECUTION_ACTION      Action,
+  IN CHAR16                         *ImageName OPTIONAL,
+  IN CONST EFI_DEVICE_PATH_PROTOCOL *ImageDevicePath OPTIONAL
+  )
+{
+  UINT8               CertNumber;
+  UINT8               *CertPtr;
+  UINTN               Index;
+  UINT8               *Cert;
+  UINTN               CertSize;
+  EFI_STATUS          Status;
+  EFI_SIGNATURE_LIST  *SignatureList;
+  UINTN               SignatureListSize;
+
+  CertNumber = (UINT8) (*CertBuf);
+  CertPtr    = CertBuf + 1;
+  for (Index = 0; Index < CertNumber; Index++) {
+    CertSize = (UINTN) ReadUnaligned32 ((UINT32 *)CertPtr);
+    Cert     = (UINT8 *)CertPtr + sizeof (UINT32);
+
+    //
+    // Record all cert in cert chain to be passed
+    //
+    Status = CreateSignatureList(Cert, CertSize, &gEfiCertX509Guid, 
&SignatureList, &SignatureListSize);
+    if (!EFI_ERROR(Status)) {
+      AddImageExeInfo (Action, ImageName, ImageDevicePath, SignatureList, 
SignatureListSize);
+      FreePool (SignatureList);
+    }
+  }
+}
+
+
+/**
    Check whether the timestamp signature is valid and the signing time is also 
earlier than
    the revocation time.

@@ -1197,8 +1305,11 @@ Done:
    Check whether the image signature is forbidden by the forbidden database 
(dbx).
    The image is forbidden to load if any certificates for signing are revoked 
before signing time.

-  @param[in]  AuthData      Pointer to the Authenticode signature retrieved 
from the signed image.
-  @param[in]  AuthDataSize  Size of the Authenticode signature in bytes.
+  @param[in]  AuthData             Pointer to the Authenticode signature 
retrieved from the signed image.
+  @param[in]  AuthDataSize         Size of the Authenticode signature in bytes.
+  @param[in]  IsAuditMode          Whether system Secure Boot Mode is in 
AuditMode.
+  @param[in]  ImageName            Name of the image to verify.
+  @param[in]  ImageDevicePath      DevicePath of the image to verify.

    @retval TRUE              Image is forbidden by dbx.
    @retval FALSE             Image is not forbidden by dbx.
@@ -1206,8 +1317,11 @@ Done:
  **/
  BOOLEAN
  IsForbiddenByDbx (
-  IN UINT8                  *AuthData,
-  IN UINTN                  AuthDataSize
+  IN UINT8                          *AuthData,
+  IN UINTN                          AuthDataSize,
+  IN BOOLEAN                        IsAuditMode,
+  IN CHAR16                         *ImageName OPTIONAL,
+  IN CONST EFI_DEVICE_PATH_PROTOCOL *ImageDevicePath OPTIONAL
    )
  {
    EFI_STATUS                Status;
@@ -1230,7 +1344,10 @@ IsForbiddenByDbx (
    UINT8                     *Cert;
    UINTN                     CertSize;
    EFI_TIME                  RevocationTime;
-
+  UINT8                     *SignerCert;
+  UINTN                     SignerCertLength;
+  UINT8                     *UnchainCert;
+  UINTN                     UnchainCertLength;
    //
    // Variable Initialization
    //
@@ -1245,6 +1362,10 @@ IsForbiddenByDbx (
    BufferLength      = 0;
    TrustedCert       = NULL;
    TrustedCertLength = 0;
+  SignerCert        = NULL;
+  SignerCertLength  = 0;
+  UnchainCert       = NULL;
+  UnchainCertLength = 0;

    //
    // The image will not be forbidden if dbx can't be got.
@@ -1352,21 +1473,54 @@ IsForbiddenByDbx (
    }

  Done:
+  if (IsForbidden && IsAuditMode) {
+    Pkcs7GetCertificatesList(AuthData, AuthDataSize, &SignerCert, &SignerCertLength, 
&UnchainCert, &UnchainCertLength);
+
+    //
+    // Record all certs in image to be failed
+    //
+    if ((SignerCertLength != 0) && (SignerCert != NULL)) {
+      RecordCertListToImageExeuctionTable(
+        SignerCert,
+        SignerCertLength,
+        EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED | EFI_IMAGE_EXECUTION_INITIALIZED,
+        ImageName,
+        ImageDevicePath
+        );
+    }
+
+    if ((UnchainCertLength != 0) && (UnchainCert != NULL)) {
+      RecordCertListToImageExeuctionTable(
+        UnchainCert,
+        UnchainCertLength,
+        EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED | EFI_IMAGE_EXECUTION_INITIALIZED,
+        ImageName,
+        ImageDevicePath
+        );
+    }
+  }
+
    if (Data != NULL) {
      FreePool (Data);
    }

    Pkcs7FreeSigners (CertBuffer);
    Pkcs7FreeSigners (TrustedCert);
+  Pkcs7FreeSigners (SignerCert);
+  Pkcs7FreeSigners (UnchainCert);

    return IsForbidden;
  }

+
  /**
    Check whether the image signature can be verified by the trusted 
certificates in DB database.

-  @param[in]  AuthData      Pointer to the Authenticode signature retrieved 
from signed image.
-  @param[in]  AuthDataSize  Size of the Authenticode signature in bytes.
+  @param[in]  AuthData              Pointer to the Authenticode signature 
retrieved from signed image.
+  @param[in]  AuthDataSize          Size of the Authenticode signature in 
bytes.
+  @param[in]  IsAuditMode           Whether system Secure Boot Mode is in 
AuditMode.
+  @param[in]  ImageName             Name of the image to verify.
+  @param[in]  ImageDevicePath       DevicePath of the image to verify.

    @retval TRUE         Image passed verification using certificate in db.
    @retval FALSE        Image didn't pass verification using certificate in db.
@@ -1374,14 +1528,17 @@ Done:
  **/
  BOOLEAN
  IsAllowedByDb (
-  IN UINT8              *AuthData,
-  IN UINTN              AuthDataSize
+  IN UINT8                          *AuthData,
+  IN UINTN                          AuthDataSize,
+  IN BOOLEAN                        IsAuditMode,
+  IN CHAR16                         *ImageName OPTIONAL,
+  IN CONST EFI_DEVICE_PATH_PROTOCOL *ImageDevicePath OPTIONAL
    )
  {
    EFI_STATUS                Status;
    BOOLEAN                   VerifyStatus;
    EFI_SIGNATURE_LIST        *CertList;
-  EFI_SIGNATURE_DATA        *Cert;
+  EFI_SIGNATURE_DATA        *CertData;
    UINTN                     DataSize;
    UINT8                     *Data;
    UINT8                     *RootCert;
@@ -1391,14 +1548,22 @@ IsAllowedByDb (
    UINTN                     DbxDataSize;
    UINT8                     *DbxData;
    EFI_TIME                  RevocationTime;
+  UINT8                     *SignerCert;
+  UINTN                     SignerCertLength;
+  UINT8                     *UnchainCert;
+  UINTN                     UnchainCertLength;

-  Data         = NULL;
-  CertList     = NULL;
-  Cert         = NULL;
-  RootCert     = NULL;
-  DbxData      = NULL;
-  RootCertSize = 0;
-  VerifyStatus = FALSE;
+  Data              = NULL;
+  CertList          = NULL;
+  CertData          = NULL;
+  RootCert          = NULL;
+  DbxData           = NULL;
+  RootCertSize      = 0;
+  VerifyStatus      = FALSE;
+  SignerCert        = NULL;
+  SignerCertLength  = 0;
+  UnchainCert       = NULL;
+  UnchainCertLength = 0;

    DataSize = 0;
    Status   = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE, 
&gEfiImageSecurityDatabaseGuid, NULL, &DataSize, NULL);
@@ -1419,14 +1584,14 @@ IsAllowedByDb (
      CertList = (EFI_SIGNATURE_LIST *) Data;
      while ((DataSize > 0) && (DataSize >= CertList->SignatureListSize)) {
        if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) {
-        Cert       = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof 
(EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
-        CertCount  = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - 
CertList->SignatureHeaderSize) / CertList->SignatureSize;
+        CertData  = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof 
(EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
+        CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - 
CertList->SignatureHeaderSize) / CertList->SignatureSize;

          for (Index = 0; Index < CertCount; Index++) {
            //
            // Iterate each Signature Data Node within this CertList for verify.
            //
-          RootCert     = Cert->SignatureData;
+          RootCert     = CertData->SignatureData;
            RootCertSize = CertList->SignatureSize - sizeof (EFI_GUID);

            //
@@ -1468,7 +1633,7 @@ IsAllowedByDb (
              goto Done;
            }

-          Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + 
CertList->SignatureSize);
+          CertData = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertData + 
CertList->SignatureSize);
          }
        }

@@ -1478,10 +1643,67 @@ IsAllowedByDb (
    }

  Done:
+
    if (VerifyStatus) {
-    SecureBootHook (EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid, 
CertList->SignatureSize, Cert);
+    SecureBootHook (EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid, 
CertList->SignatureSize, CertData);
+  }
+
+  if (IsAuditMode) {
+
+    Pkcs7GetCertificatesList(AuthData, AuthDataSize, &SignerCert, &SignerCertLength, 
&UnchainCert, &UnchainCertLength);
+    if (VerifyStatus) {
+      if ((SignerCertLength != 0) && (SignerCert != NULL)) {
+        //
+        // Record all cert in signer's cert chain to be passed
+        //
+        RecordCertListToImageExeuctionTable(
+          SignerCert,
+          SignerCertLength,
+          EFI_IMAGE_EXECUTION_AUTH_SIG_PASSED | 
EFI_IMAGE_EXECUTION_INITIALIZED,
+          ImageName,
+          ImageDevicePath
+          );
+      }
+
+      if ((UnchainCertLength != 0) && (UnchainCert != NULL)) {
+        //
+        // Record all certs in unchained certificates lists to be failed
+        //
+        RecordCertListToImageExeuctionTable(
+          UnchainCert,
+          UnchainCertLength,
+          EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED | 
EFI_IMAGE_EXECUTION_INITIALIZED,
+          ImageName,
+          ImageDevicePath
+          );
+      }
+    } else {
+      //
+      // Record all certs in image to be failed
+      //
+      if ((SignerCertLength != 0) && (SignerCert != NULL)) {
+        RecordCertListToImageExeuctionTable(
+          SignerCert,
+          SignerCertLength,
+          EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED | 
EFI_IMAGE_EXECUTION_INITIALIZED,
+          ImageName,
+          ImageDevicePath
+          );
+      }
+
+      if ((UnchainCertLength != 0) && (UnchainCert != NULL)) {
+        RecordCertListToImageExeuctionTable(
+          UnchainCert,
+          UnchainCertLength,
+          EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED | 
EFI_IMAGE_EXECUTION_INITIALIZED,
+          ImageName,
+          ImageDevicePath
+          );
+      }
+    }
    }

+
    if (Data != NULL) {
      FreePool (Data);
    }
@@ -1489,10 +1711,370 @@ Done:
      FreePool (DbxData);
    }

+  Pkcs7FreeSigners (SignerCert);
+  Pkcs7FreeSigners (UnchainCert);
+
    return VerifyStatus;
  }

  /**
+  Provide verification service for signed images in AuditMode, which include 
both signature validation
+  and platform policy control. For signature types, both UEFI 
WIN_CERTIFICATE_UEFI_GUID and
+  MSFT Authenticode type signatures are supported.
+
+  In this implementation, only verify external executables when in AuditMode.
+  Executables from FV is bypass, so pass in AuthenticationStatus is ignored. 
Other authentication status
+  are record into IMAGE_EXECUTION_TABLE.
+
+  The image verification policy is:
+    If the image is signed,
+      At least one valid signature or at least one hash value of the image 
must match a record
+      in the security database "db", and no valid signature nor any hash value 
of the image may
+      be reflected in the security database "dbx".
+    Otherwise, the image is not signed,
+      The SHA256 hash value of the image must match a record in the security database 
"db", and
+      not be reflected in the security data base "dbx".
+
+  Caution: This function may receive untrusted input.
+  PE/COFF image is external input, so this function will validate its data 
structure
+  within this image buffer before use.
+
+  @param[in]    AuthenticationStatus
+                           This is the authentication status returned from the 
security
+                           measurement services for the input file.
+  @param[in]    File       This is a pointer to the device path of the file 
that is
+                           being dispatched. This will optionally be used for 
logging.
+  @param[in]    FileBuffer File buffer matches the input file device path.
+  @param[in]    FileSize   Size of File buffer matches the input file device 
path.
+  @param[in]    BootPolicy A boot policy that was used to call LoadImage() 
UEFI service.
+
+  @retval EFI_SUCCESS            The authenticate info is sucessfully stored 
for the file
+                                 specified by DevicePath and non-NULL 
FileBuffer
+  @retval EFI_ACCESS_DENIED      The file specified by File and FileBuffer did 
not
+                                 authenticate, and the platform policy 
dictates that the DXE
+                                 Foundation many not use File.
+
+**/
+EFI_STATUS
+EFIAPI
+ImageVerificationInAuditMode (
+  IN  UINT32                           AuthenticationStatus,
+  IN  CONST EFI_DEVICE_PATH_PROTOCOL   *File,
+  IN  VOID                             *FileBuffer,
+  IN  UINTN                            FileSize,
+  IN  BOOLEAN                          BootPolicy
+  )
+{
+  EFI_STATUS                           Status;
+  UINT16                               Magic;
+  EFI_IMAGE_DOS_HEADER                 *DosHdr;
+  EFI_SIGNATURE_LIST                   *SignatureList;
+  EFI_IMAGE_EXECUTION_ACTION           Action;
+  WIN_CERTIFICATE                      *WinCertificate;
+  UINT32                               Policy;
+  PE_COFF_LOADER_IMAGE_CONTEXT         ImageContext;
+  UINT32                               NumberOfRvaAndSizes;
+  WIN_CERTIFICATE_EFI_PKCS             *PkcsCertData;
+  WIN_CERTIFICATE_UEFI_GUID            *WinCertUefiGuid;
+  UINT8                                *AuthData;
+  UINTN                                AuthDataSize;
+  EFI_IMAGE_DATA_DIRECTORY             *SecDataDir;
+  UINT32                               OffSet;
+  CHAR16                               *FilePathStr;
+  UINTN                                SignatureListSize;
+
+  SignatureList     = NULL;
+  WinCertificate    = NULL;
+  SecDataDir        = NULL;
+  PkcsCertData      = NULL;
+  FilePathStr       = NULL;
+  Action            = EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED | 
EFI_IMAGE_EXECUTION_INITIALIZED;
+  Status            = EFI_ACCESS_DENIED;
+
+
+  //
+  // Check the image type and get policy setting.
+  //
+  switch (GetImageType (File)) {
+
+  case IMAGE_FROM_FV:
+    Policy = ALWAYS_EXECUTE;
+    break;
+
+  case IMAGE_FROM_OPTION_ROM:
+    Policy = PcdGet32 (PcdOptionRomImageVerificationPolicy);
+    break;
+
+  case IMAGE_FROM_REMOVABLE_MEDIA:
+    Policy = PcdGet32 (PcdRemovableMediaImageVerificationPolicy);
+    break;
+
+  case IMAGE_FROM_FIXED_MEDIA:
+    Policy = PcdGet32 (PcdFixedMediaImageVerificationPolicy);
+    break;
+
+  default:
+    Policy = DENY_EXECUTE_ON_SECURITY_VIOLATION;
+    break;
+  }
+
+  //
+  // If policy is always/never execute, return directly.
+  //
+  if (Policy == ALWAYS_EXECUTE) {
+    return EFI_SUCCESS;
+  }
+
+  //
+  // Get Image Device Path Str
+  //
+  FilePathStr = ConvertDevicePathToText (File, FALSE, TRUE);
+
+  //
+  // Authentication failed because of (unspecified) firmware security policy
+  //
+  if (Policy == NEVER_EXECUTE) {
+    //
+    // No signature, record FilePath/FilePathStr only
+    //
+    AddImageExeInfo (EFI_IMAGE_EXECUTION_POLICY_FAILED | 
EFI_IMAGE_EXECUTION_INITIALIZED, FilePathStr, File, NULL, 0);
+    goto END;
+  }
+
+  //
+  // The policy QUERY_USER_ON_SECURITY_VIOLATION and 
ALLOW_EXECUTE_ON_SECURITY_VIOLATION
+  // violates the UEFI spec and has been removed.
+  //
+  ASSERT (Policy != QUERY_USER_ON_SECURITY_VIOLATION && Policy != 
ALLOW_EXECUTE_ON_SECURITY_VIOLATION);
+  if (Policy == QUERY_USER_ON_SECURITY_VIOLATION || Policy == 
ALLOW_EXECUTE_ON_SECURITY_VIOLATION) {
+    CpuDeadLoop ();
+  }
+
+  //
+  // Read the Dos header.
+  //
+  if (FileBuffer == NULL) {
+    Status = EFI_INVALID_PARAMETER;
+    goto END;
+  }
+
+  mImageBase  = (UINT8 *) FileBuffer;
+  mImageSize  = FileSize;
+
+  ZeroMem (&ImageContext, sizeof (ImageContext));
+  ImageContext.Handle    = (VOID *) FileBuffer;
+  ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) 
DxeImageVerificationLibImageRead;
+
+  //
+  // Get information about the image being loaded
+  //
+  Status = PeCoffLoaderGetImageInfo (&ImageContext);
+  if (EFI_ERROR (Status)) {
+    //
+    // The information can't be got from the invalid PeImage
+    //
+    goto END;
+  }
+
+
+  DosHdr = (EFI_IMAGE_DOS_HEADER *) mImageBase;
+  if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
+    //
+    // DOS image header is present,
+    // so read the PE header after the DOS image header.
+    //
+    mPeCoffHeaderOffset = DosHdr->e_lfanew;
+  } else {
+    mPeCoffHeaderOffset = 0;
+  }
+
+  //
+  // Check PE/COFF image.
+  //
+  mNtHeader.Pe32 = (EFI_IMAGE_NT_HEADERS32 *) (mImageBase + 
mPeCoffHeaderOffset);
+  if (mNtHeader.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {
+    //
+    // It is not a valid Pe/Coff file.
+    //
+    Status = EFI_ACCESS_DENIED;
+    goto END;
+  }
+
+  if (mNtHeader.Pe32->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64 && 
mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+    //
+    // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic 
value
+    //       in the PE/COFF Header. If the MachineType is Itanium(IA64) and the
+    //       Magic value in the OptionalHeader is 
EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
+    //       then override the magic value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
+    //
+    Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;
+  } else {
+    //
+    // Get the magic value from the PE/COFF Optional Header
+    //
+    Magic = mNtHeader.Pe32->OptionalHeader.Magic;
+  }
+
+  if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+    //
+    // Use PE32 offset.
+    //
+    NumberOfRvaAndSizes = mNtHeader.Pe32->OptionalHeader.NumberOfRvaAndSizes;
+    if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {
+      SecDataDir = (EFI_IMAGE_DATA_DIRECTORY *) 
&mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];
+    }
+  } else {
+    //
+    // Use PE32+ offset.
+    //
+    NumberOfRvaAndSizes = 
mNtHeader.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
+    if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {
+      SecDataDir = (EFI_IMAGE_DATA_DIRECTORY *) 
&mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];
+    }
+  }
+
+  //
+  // Start Image Validation.
+  //
+  if (SecDataDir == NULL || SecDataDir->Size == 0) {
+    //
+    // This image is not signed. The SHA256 hash value of the image must match a record 
in the security database "db",
+    // and not be reflected in the security data base "dbx".
+    //
+    if (!HashPeImage (HASHALG_SHA256)) {
+      Status = EFI_ACCESS_DENIED;
+      goto END;
+    }
+
+    //
+    // Image Hash is in forbidden database (DBX).
+    //
+    if (!IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE1, mImageDigest, 
&mCertType, mImageDigestSize)) {
+      //
+      // Image Hash is in allowed database (DB).
+      //
+      if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE, mImageDigest, 
&mCertType, mImageDigestSize)) {
+        Action = EFI_IMAGE_EXECUTION_AUTH_SIG_PASSED | 
EFI_IMAGE_EXECUTION_INITIALIZED;
+      }
+    }
+
+    //
+    // Add HASH digest for image without signature
+    //
+    Status = CreateSignatureList(mImageDigest, mImageDigestSize, &mCertType, 
&SignatureList, &SignatureListSize);
+    if (!EFI_ERROR(Status)) {
+      AddImageExeInfo (Action, FilePathStr, File, SignatureList, 
SignatureListSize);
+      FreePool (SignatureList);
+    }
+    goto END;
+  }
+
+  //
+  // Verify the signature of the image, multiple signatures are allowed as per 
PE/COFF Section 4.7
+  // "Attribute Certificate Table".
+  // The first certificate starts at offset (SecDataDir->VirtualAddress) from 
the start of the file.
+  //
+  for (OffSet = SecDataDir->VirtualAddress;
+       OffSet < (SecDataDir->VirtualAddress + SecDataDir->Size);
+       OffSet += (WinCertificate->dwLength + ALIGN_SIZE 
(WinCertificate->dwLength))) {
+    WinCertificate = (WIN_CERTIFICATE *) (mImageBase + OffSet);
+    if ((SecDataDir->VirtualAddress + SecDataDir->Size - OffSet) <= sizeof 
(WIN_CERTIFICATE) ||
+        (SecDataDir->VirtualAddress + SecDataDir->Size - OffSet) < 
WinCertificate->dwLength) {
+      break;
+    }
+
+    //
+    // Verify the image's Authenticode signature, only DER-encoded PKCS#7 
signed data is supported.
+    //
+    if (WinCertificate->wCertificateType == WIN_CERT_TYPE_PKCS_SIGNED_DATA) {
+      //
+      // The certificate is formatted as WIN_CERTIFICATE_EFI_PKCS which is 
described in the
+      // Authenticode specification.
+      //
+      PkcsCertData = (WIN_CERTIFICATE_EFI_PKCS *) WinCertificate;
+      if (PkcsCertData->Hdr.dwLength <= sizeof (PkcsCertData->Hdr)) {
+        break;
+      }
+      AuthData   = PkcsCertData->CertData;
+      AuthDataSize = PkcsCertData->Hdr.dwLength - sizeof(PkcsCertData->Hdr);
+    } else if (WinCertificate->wCertificateType == WIN_CERT_TYPE_EFI_GUID) {
+      //
+      // The certificate is formatted as WIN_CERTIFICATE_UEFI_GUID which is 
described in UEFI Spec.
+      //
+      WinCertUefiGuid = (WIN_CERTIFICATE_UEFI_GUID *) WinCertificate;
+      if (WinCertUefiGuid->Hdr.dwLength <= 
OFFSET_OF(WIN_CERTIFICATE_UEFI_GUID, CertData)) {
+        break;
+      }
+      if (!CompareGuid (&WinCertUefiGuid->CertType, &gEfiCertPkcs7Guid)) {
+        continue;
+      }
+      AuthData = WinCertUefiGuid->CertData;
+      AuthDataSize = WinCertUefiGuid->Hdr.dwLength - 
OFFSET_OF(WIN_CERTIFICATE_UEFI_GUID, CertData);
+    } else {
+      if (WinCertificate->dwLength < sizeof (WIN_CERTIFICATE)) {
+        break;
+      }
+      continue;
+    }
+
+    Status = HashPeImageByType (AuthData, AuthDataSize);
+    if (EFI_ERROR (Status)) {
+      continue;
+    }
+
+    Action = EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED | 
EFI_IMAGE_EXECUTION_INITIALIZED;
+
+    //
+    // Check the digital signature against the revoked certificate in 
forbidden database (dbx).
+    // Check the digital signature against the valid certificate in allowed 
database (db).
+    //
+    if (!IsForbiddenByDbx (AuthData, AuthDataSize, TRUE, FilePathStr, File)) {
+      IsAllowedByDb (AuthData, AuthDataSize, TRUE, FilePathStr, File);
+    }
+
+    //
+    // Check the image's hash value.
+    //
+    if (!IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE1, mImageDigest, 
&mCertType, mImageDigestSize)) {
+      if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE, mImageDigest, 
&mCertType, mImageDigestSize)) {
+        Action = EFI_IMAGE_EXECUTION_AUTH_SIG_PASSED | 
EFI_IMAGE_EXECUTION_INITIALIZED;
+      }
+    }
+
+    //
+    // Add HASH digest for image with signature
+    //
+    Status = CreateSignatureList(mImageDigest, mImageDigestSize, &mCertType, 
&SignatureList, &SignatureListSize);
+
+    if (!EFI_ERROR(Status)) {
+      AddImageExeInfo (Action, FilePathStr, File, SignatureList, 
SignatureListSize);
+      FreePool (SignatureList);
+    } else {
+      goto END;
+    }
+  }
+
+
+  if (OffSet != (SecDataDir->VirtualAddress + SecDataDir->Size)) {
+    //
+    // The Size in Certificate Table or the attribute certicate table is 
corrupted.
+    //
+    Status = EFI_ACCESS_DENIED;
+  } else {
+    Status = EFI_SUCCESS;
+  }
+
+END:
+
+  if (FilePathStr != NULL) {
+    FreePool(FilePathStr);
+    FilePathStr = NULL;
+  }
+
+  return Status;
+}
+
+/**
    Provide verification service for signed images, which include both 
signature validation
    and platform policy control. For signature types, both UEFI 
WIN_CERTIFICATE_UEFI_GUID and
    MSFT Authenticode type signatures are supported.
@@ -1559,7 +2141,9 @@ DxeImageVerificationHandler (
    EFI_IMAGE_EXECUTION_ACTION           Action;
    WIN_CERTIFICATE                      *WinCertificate;
    UINT32                               Policy;
-  UINT8                                *SecureBoot;
+  UINT8                                *VarData;
+  UINT8                                SecureBoot;
+  UINT8                                AuditMode;
    PE_COFF_LOADER_IMAGE_CONTEXT         ImageContext;
    UINT32                               NumberOfRvaAndSizes;
    WIN_CERTIFICATE_EFI_PKCS             *PkcsCertData;
@@ -1579,6 +2163,20 @@ DxeImageVerificationHandler (
    Status            = EFI_ACCESS_DENIED;
    VerifyStatus      = EFI_ACCESS_DENIED;

+  GetEfiGlobalVariable2 (EFI_AUDIT_MODE_NAME, (VOID**)&VarData, NULL);
+  //
+  // Skip verification if AuditMode variable doesn't exist. AuditMode should 
always exist
+  //
+  if (VarData == NULL) {
+    return EFI_SUCCESS;
+  }
+  AuditMode = *VarData;
+  FreePool(VarData);
+
+  if (AuditMode == AUDIT_MODE_ENABLE) {
+    return ImageVerificationInAuditMode(AuthenticationStatus, File, 
FileBuffer, FileSize, BootPolicy);
+  }
+
    //
    // Check the image type and get policy setting.
    //
@@ -1622,22 +2220,22 @@ DxeImageVerificationHandler (
      CpuDeadLoop ();
    }

-  GetEfiGlobalVariable2 (EFI_SECURE_BOOT_MODE_NAME, (VOID**)&SecureBoot, NULL);
+  GetEfiGlobalVariable2 (EFI_SECURE_BOOT_MODE_NAME, (VOID**)&VarData, NULL);
    //
    // Skip verification if SecureBoot variable doesn't exist.
    //
-  if (SecureBoot == NULL) {
+  if (VarData == NULL) {
      return EFI_SUCCESS;
    }
+  SecureBoot = *VarData;
+  FreePool(VarData);

    //
-  // Skip verification if SecureBoot is disabled.
+  // Skip verification if SecureBoot is disabled but not AuditMode
    //
-  if (*SecureBoot == SECURE_BOOT_MODE_DISABLE) {
-    FreePool (SecureBoot);
+  if (SecureBoot == SECURE_BOOT_MODE_DISABLE) {
      return EFI_SUCCESS;
    }
-  FreePool (SecureBoot);

    //
    // Read the Dos header.
@@ -1808,7 +2406,7 @@ DxeImageVerificationHandler (
      //
      // Check the digital signature against the revoked certificate in 
forbidden database (dbx).
      //
-    if (IsForbiddenByDbx (AuthData, AuthDataSize)) {
+    if (IsForbiddenByDbx (AuthData, AuthDataSize, FALSE, NULL, NULL)) {
        Action = EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED;
        VerifyStatus = EFI_ACCESS_DENIED;
        break;
@@ -1818,7 +2416,7 @@ DxeImageVerificationHandler (
      // Check the digital signature against the valid certificate in allowed 
database (db).
      //
      if (EFI_ERROR (VerifyStatus)) {
-      if (IsAllowedByDb (AuthData, AuthDataSize)) {
+      if (IsAllowedByDb (AuthData, AuthDataSize, FALSE, NULL, NULL)) {
          VerifyStatus = EFI_SUCCESS;
        }
      }


_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel

Reply via email to