[edk2] [PATCH V2 5/6] SecurityPkg/Password: Add Password based UserAuthentication modules.

Jiewen Yao posted 6 patches 7 years, 8 months ago
[edk2] [PATCH V2 5/6] SecurityPkg/Password: Add Password based UserAuthentication modules.
Posted by Jiewen Yao 7 years, 8 months ago
This password based user authentication is to verify user when a user
wants to enter BIOS setup page.

The DXE driver registers report status code listener.
When it gets (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_PC_USER_SETUP) progress
code, it will let the user input password.
If and only if the user inputs the right password, the status code handler
will return and let the setup driver continue running.
If the user inputs the wrong password, the status code handler will let
user try again.
If the user inputs the wrong password 3 times, the status code handler will
reset the system.

The DXE driver also register a setup page in setup browser, so that
user may update the password.

The DXE driver uses SMI to let SMM driver do the password verification
and management.

The SMM driver registers SMI handler to perform the request from DXE.
The password must meet below criteria:
1) Length >= 8 char
2) It must include lower case, upper case, number and symbol.
3) It must not duplicate with 5 previous password.
If above criteria is met, the password will be saved to a read only UEFI
variable. The format is password hash+salt, which is generated by
Pkcs5HashPassword algorithm (SHA256+1000 iteration).

If the SMM driver gets wrong password 3 times, the interface is locked
and does not accept more request.

If the SMM driver will detect IsPasswordCleared() at the entry point and
clear the password if IsPasswordCleared() is TRUE. This can be used when
the user forgets the password.

Cc: Qin Long <qin.long@intel.com>
Cc: Chao Zhang <chao.b.zhang@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jiewen Yao <jiewen.yao@intel.com>
---
 SecurityPkg/Password/UserAuthentication/KeyService.c                     | 210 ++++++
 SecurityPkg/Password/UserAuthentication/KeyService.h                     | 122 ++++
 SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.c          | 718 ++++++++++++++++++++
 SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.h          | 115 ++++
 SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.inf        |  79 +++
 SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.uni        |  22 +
 SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeExtra.uni   |  20 +
 SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeFormset.h   |  30 +
 SecurityPkg/Password/UserAuthentication/UserAuthenticationDxePassword.c  | 301 ++++++++
 SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeStrings.uni |  29 +
 SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeVfr.vfr     |  38 ++
 SecurityPkg/Password/UserAuthentication/UserAuthenticationGuid.h         |  65 ++
 SecurityPkg/Password/UserAuthentication/UserAuthenticationSmm.c          | 672 ++++++++++++++++++
 SecurityPkg/Password/UserAuthentication/UserAuthenticationSmm.inf        |  70 ++
 SecurityPkg/Password/UserAuthentication/UserAuthenticationSmm.uni        |  22 +
 SecurityPkg/Password/UserAuthentication/UserAuthenticationSmmExtra.uni   |  20 +
 16 files changed, 2533 insertions(+)

diff --git a/SecurityPkg/Password/UserAuthentication/KeyService.c b/SecurityPkg/Password/UserAuthentication/KeyService.c
new file mode 100644
index 0000000..81aa2f9
--- /dev/null
+++ b/SecurityPkg/Password/UserAuthentication/KeyService.c
@@ -0,0 +1,210 @@
+/** @file
+  Password key service.
+
+Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Uefi.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseCryptLib.h>
+#include "KeyService.h"
+
+#define DEFAULT_AES_KEY_BIT_SIZE       256
+#define DEFAULT_PBKDF2_ITERATION_COUNT 1000
+
+/**
+  Compares the contents of two buffers with slow algorithm
+
+  This function compares Length bytes of SourceBuffer to Length bytes of DestinationBuffer.
+  If all Length bytes of the two buffers are identical, then 0 is returned.  Otherwise, the
+  value returned is the first mismatched byte in SourceBuffer subtracted from the first
+  mismatched byte in DestinationBuffer.
+
+  If Length > 0 and DestinationBuffer is NULL, then ASSERT().
+  If Length > 0 and SourceBuffer is NULL, then ASSERT().
+  If Length is greater than (MAX_ADDRESS - DestinationBuffer + 1), then ASSERT().
+  If Length is greater than (MAX_ADDRESS - SourceBuffer + 1), then ASSERT().
+
+  @param  DestinationBuffer The pointer to the destination buffer to compare.
+  @param  SourceBuffer      The pointer to the source buffer to compare.
+  @param  Length            The number of bytes to compare.
+
+  @return 0                 All Length bytes of the two buffers are identical.
+  @retval -1                The SourceBuffer is not identical to DestinationBuffer.
+
+**/
+INTN
+EFIAPI
+KeyLibSlowCompareMem (
+  IN CONST VOID  *DestinationBuffer,
+  IN CONST VOID  *SourceBuffer,
+  IN UINTN       Length
+  )
+{
+  UINT8  Delta;
+  UINTN  Index;
+  UINT8  *Destination;
+  UINT8  *Source;
+
+  Destination = (UINT8 *)DestinationBuffer;
+  Source = (UINT8 *)SourceBuffer;
+  Delta = 0;
+  for (Index = 0; Index < Length; Index++) {
+    Delta |= Destination[Index] ^ Source[Index];
+  }
+  if (Delta == 0) {
+    return 0;
+  } else {
+    return -1;
+  }
+}
+
+/**
+  Generate Salt value.
+
+  @param[in, out]   SaltValue           Points to the salt buffer
+  @param[in]        SaltSize            Size of the salt buffer
+
+  @retval      TRUE           Salt is generated.
+  @retval      FALSE          Salt is not generated.
+**/
+BOOLEAN
+EFIAPI
+KeyLibGenerateSalt (
+  IN OUT UINT8  *SaltValue,
+  IN UINTN      SaltSize
+  )
+{
+  if (SaltValue == NULL) {
+    return FALSE;
+  }
+  RandomSeed(NULL, 0);
+  RandomBytes(SaltValue, SaltSize);
+  return TRUE;
+}
+
+/**
+  Hash the data.
+
+  @param[in]   HashType         Hash type
+  @param[in]   Key              Points to the key buffer
+  @param[in]   KeySize          Key buffer size
+  @param[in]   SaltValue        Points to the salt buffer
+  @param[in]   SaltSize         Size of the salt buffer
+  @param[out]  KeyHash          Points to the hashed result
+  @param[in]   KeyHashSize      Size of the hash buffer
+
+  @retval      TRUE           Hash the data successfully.
+  @retval      FALSE          Failed to hash the data.
+
+**/
+BOOLEAN
+EFIAPI
+KeyLibGenerateHash(
+  IN   UINT32              HashType,
+  IN   VOID                *Key,
+  IN   UINTN               KeySize,
+  IN   UINT8               *SaltValue,
+  IN   UINTN               SaltSize,
+  OUT  UINT8               *KeyHash,
+  IN   UINTN               KeyHashSize
+  )
+{
+  BOOLEAN                     Status;
+  UINTN                       HashSize;
+  VOID                        *HashContext;
+
+  if (HashType != HASH_TYPE_SHA256) {
+    return FALSE;
+  }
+  if (KeyHashSize != SHA256_DIGEST_SIZE) {
+    return FALSE;
+  }
+
+  if ((Key == NULL) || (SaltValue == NULL) || (KeyHash == NULL)) {
+    return FALSE;
+  }
+
+  HashSize    = Sha256GetContextSize ();
+  HashContext = AllocateZeroPool (HashSize);
+  if (HashContext == NULL) {
+    return FALSE;
+  }
+
+  Status = Sha256Init(HashContext);
+  if (!Status) {
+    goto Done;
+  }
+
+  Status = Sha256Update(HashContext, SaltValue, SaltSize);
+  if (!Status) {
+    goto Done;
+  }
+  Status = Sha256Update(HashContext, Key, KeySize);
+  if (!Status) {
+    goto Done;
+  }
+
+  Status = Sha256Final(HashContext, KeyHash);
+Done:
+  FreePool (HashContext);
+  return Status;
+}
+
+/**
+  Hash the password with PBKDF2.
+
+  @param[in]   HashType         Hash type
+  @param[in]   Key              Points to the key buffer
+  @param[in]   KeySize          Key buffer size
+  @param[in]   SaltValue        Points to the salt buffer
+  @param[in]   SaltSize         Size of the salt buffer
+  @param[out]  KeyHash          Points to the hashed result
+  @param[in]   KeyHashSize      Size of the hash buffer
+
+  @retval      TRUE           Hash the data successfully.
+  @retval      FALSE          Failed to hash the data.
+
+**/
+BOOLEAN
+EFIAPI
+KeyLibGeneratePBKDF2Hash (
+  IN   UINT32              HashType,
+  IN   VOID                *Key,
+  IN   UINTN               KeySize,
+  IN   UINT8               *SaltValue,
+  IN   UINTN               SaltSize,
+  OUT  UINT8               *KeyHash,
+  IN   UINTN               KeyHashSize
+  )
+{
+  BOOLEAN  Result;
+
+  if (HashType != HASH_TYPE_SHA256) {
+    return FALSE;
+  }
+  if (KeyHashSize != SHA256_DIGEST_SIZE) {
+    return FALSE;
+  }
+
+  Result = Pkcs5HashPassword (
+             KeySize,
+             Key,
+             SaltSize,
+             SaltValue,
+             DEFAULT_PBKDF2_ITERATION_COUNT,
+             SHA256_DIGEST_SIZE,
+             KeyHashSize,
+             KeyHash
+             );
+  return Result;
+}
diff --git a/SecurityPkg/Password/UserAuthentication/KeyService.h b/SecurityPkg/Password/UserAuthentication/KeyService.h
new file mode 100644
index 0000000..f287953
--- /dev/null
+++ b/SecurityPkg/Password/UserAuthentication/KeyService.h
@@ -0,0 +1,122 @@
+/** @file
+  Header file for key service.
+
+  Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+  This program and the accompanying materials
+  are licensed and made available under the terms and conditions of the BSD License
+  which accompanies this distribution.  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __KEY_LIB_H__
+#define __KEY_LIB_H__
+
+/**
+  Compares the contents of two buffers with slow algorithm
+
+  This function compares Length bytes of SourceBuffer to Length bytes of DestinationBuffer.
+  If all Length bytes of the two buffers are identical, then 0 is returned.  Otherwise, the
+  value returned is the first mismatched byte in SourceBuffer subtracted from the first
+  mismatched byte in DestinationBuffer.
+
+  If Length > 0 and DestinationBuffer is NULL, then ASSERT().
+  If Length > 0 and SourceBuffer is NULL, then ASSERT().
+  If Length is greater than (MAX_ADDRESS - DestinationBuffer + 1), then ASSERT().
+  If Length is greater than (MAX_ADDRESS - SourceBuffer + 1), then ASSERT().
+
+  @param  DestinationBuffer The pointer to the destination buffer to compare.
+  @param  SourceBuffer      The pointer to the source buffer to compare.
+  @param  Length            The number of bytes to compare.
+
+  @return 0                 All Length bytes of the two buffers are identical.
+  @retval -1                The SourceBuffer is not identical to DestinationBuffer.
+
+**/
+INTN
+EFIAPI
+KeyLibSlowCompareMem (
+  IN CONST VOID  *DestinationBuffer,
+  IN CONST VOID  *SourceBuffer,
+  IN UINTN       Length
+  );
+
+/**
+  Generate Salt value.
+
+  @param[in, out]   SaltValue           Points to the salt buffer
+  @param[in]        SaltSize            Size of the salt buffer
+
+  @retval      TRUE           Salt is generated.
+  @retval      FALSE          Salt is not generated.
+**/
+BOOLEAN
+EFIAPI
+KeyLibGenerateSalt(
+  IN OUT UINT8  *SaltValue,
+  IN UINTN      SaltSize
+  );
+
+#define HASH_TYPE_SHA256  0x000B
+
+#define SHA256_DIGEST_SIZE 32
+
+/**
+  Hash the data.
+
+  @param[in]   HashType         Hash type
+  @param[in]   Key              Points to the key buffer
+  @param[in]   KeySize          Key buffer size
+  @param[in]   SaltValue        Points to the salt buffer
+  @param[in]   SaltSize         Size of the salt buffer
+  @param[out]  KeyHash          Points to the hashed result
+  @param[in]   KeyHashSize      Size of the hash buffer
+
+  @retval      TRUE           Hash the data successfully.
+  @retval      FALSE          Failed to hash the data.
+
+**/
+BOOLEAN
+EFIAPI
+KeyLibGenerateHash(
+  IN   UINT32              HashType,
+  IN   VOID                *Key,
+  IN   UINTN               KeySize,
+  IN   UINT8               *SaltValue,
+  IN   UINTN               SaltSize,
+  OUT  UINT8               *KeyHash,
+  IN   UINTN               KeyHashSize
+  );
+
+/**
+  Hash the password with PBKDF2.
+
+  @param[in]   HashType         Hash type
+  @param[in]   Key              Points to the key buffer
+  @param[in]   KeySize          Key buffer size
+  @param[in]   SaltValue        Points to the salt buffer
+  @param[in]   SaltSize         Size of the salt buffer
+  @param[out]  KeyHash          Points to the hashed result
+  @param[in]   KeyHashSize      Size of the hash buffer
+
+  @retval      TRUE           Hash the data successfully.
+  @retval      FALSE          Failed to hash the data.
+
+**/
+BOOLEAN
+EFIAPI
+KeyLibGeneratePBKDF2Hash (
+  IN   UINT32              HashType,
+  IN   VOID                *Key,
+  IN   UINTN               KeySize,
+  IN   UINT8               *SaltValue,
+  IN   UINTN               SaltSize,
+  OUT  UINT8               *KeyHash,
+  IN   UINTN               KeyHashSize
+  );
+
+#endif
+
diff --git a/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.c b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.c
new file mode 100644
index 0000000..3836eac
--- /dev/null
+++ b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.c
@@ -0,0 +1,718 @@
+/** @file
+  This Driver mainly do user authentication before entering Setup.
+
+Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "UserAuthenticationDxe.h"
+
+EFI_EVENT                           mExitBootServicesEvent  = NULL;
+EFI_RSC_HANDLER_PROTOCOL           *mRscHandlerProtocol     = NULL;
+USER_AUTHENTICATION_PRIVATE_DATA   *mUserAuthenticationData = NULL;
+
+UINTN  mAdminPasswordTryCount;
+
+EFI_GUID gAdminAuthenticationGuid = ADMIN_AUTHENTICATION_GUID;
+
+HII_VENDOR_DEVICE_PATH  mHiiVendorDevicePath = {
+  {
+    {
+      HARDWARE_DEVICE_PATH,
+      HW_VENDOR_DP,
+      {
+        (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
+        (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
+      }
+    },
+    USER_AUTHENTICATION_FORMSET_GUID
+  },
+  {
+    END_DEVICE_PATH_TYPE,
+    END_ENTIRE_DEVICE_PATH_SUBTYPE,
+    {
+      (UINT8) (END_DEVICE_PATH_LENGTH),
+      (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
+    }
+  }
+};
+
+/**
+  Get a user input string.
+
+  @param[in]       PopUpString      A popup string to inform user.
+  @param[in, out]  UserInput        The user input string
+  @param[in]       UserInputMaxLen  The max unicode count of the UserInput without NULL terminator.
+**/
+EFI_STATUS
+GetUserInput (
+  IN     CHAR16      *PopUpString,
+  IN OUT CHAR16      *UserInput,
+  IN     UINTN       UserInputMaxLen
+  )
+{
+  EFI_INPUT_KEY                InputKey;
+  UINTN                        InputLength;
+  CHAR16                       *Mask;
+
+  UserInput[0] = 0;
+  Mask = AllocateZeroPool ((UserInputMaxLen + 1) * sizeof(CHAR16));
+  if (Mask == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  InputLength = 0;
+
+  while (TRUE) {
+    Mask[InputLength] = L'_';
+    CreatePopUp (
+      EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
+      &InputKey,
+      PopUpString,
+      L"---------------------",
+      Mask,
+      NULL
+      );
+    if (InputKey.ScanCode == SCAN_NULL) {
+      //
+      // Check whether finish inputing password.
+      //
+      if (InputKey.UnicodeChar == CHAR_CARRIAGE_RETURN && InputLength > 0) {
+        //
+        // Add the null terminator.
+        //
+        UserInput[InputLength] = 0;
+        break;
+      } else if ((InputKey.UnicodeChar == CHAR_NULL) ||
+                 (InputKey.UnicodeChar == CHAR_TAB) ||
+                 (InputKey.UnicodeChar == CHAR_LINEFEED) ||
+                 (InputKey.UnicodeChar == CHAR_CARRIAGE_RETURN)
+                ) {
+        continue;
+      } else {
+        //
+        // delete last key entered
+        //
+        if (InputKey.UnicodeChar == CHAR_BACKSPACE) {
+          if (InputLength > 0) {
+            UserInput[InputLength] = 0;
+            Mask[InputLength] = 0;
+            InputLength--;
+          }
+        } else {
+          //
+          // add Next key entry
+          //
+          UserInput[InputLength] = InputKey.UnicodeChar;
+          Mask[InputLength] = L'*';
+          InputLength++;
+          if (InputLength == UserInputMaxLen) {
+            //
+            // Add the null terminator.
+            //
+            UserInput[InputLength] = 0;
+            Mask[InputLength] = 0;
+            break;
+          }
+        }
+      }
+    }
+  }
+  FreePool (Mask);
+  return EFI_SUCCESS;
+}
+
+/**
+  Display a message box to end user.
+
+  @param[in] DisplayString   The string in message box.
+**/
+VOID
+MessageBox (
+  IN CHAR16  *DisplayString
+  )
+{
+  EFI_INPUT_KEY  Key;
+
+  do {
+    CreatePopUp (
+      EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
+      &Key,
+      L"",
+      DisplayString,
+      L"Press ENTER to continue ...",
+      L"",
+      NULL
+      );
+  } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
+}
+
+/**
+  Force system reset.
+**/
+VOID
+ForceSystemReset (
+  VOID
+  )
+{
+  MessageBox (L"Password retry count reach, reset system!");
+  gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);
+  CpuDeadLoop();
+}
+
+/**
+  Display message for set password.
+
+  @param[in]  ReturnStatus   The return status for set password.
+**/
+VOID
+PrintPasswordStatus (
+  IN EFI_STATUS  ReturnStatus
+  )
+{
+  CHAR16         *DisplayString;
+
+  if (ReturnStatus == EFI_SUCCESS) {
+    DisplayString = L"New password is updated successfully!";
+  } else if (ReturnStatus == EFI_UNSUPPORTED) {
+    DisplayString = L"New password is not strong enough!";
+  } else if (ReturnStatus == EFI_ALREADY_STARTED) {
+    DisplayString = L"New password is found in history!";
+  } else {
+    DisplayString = L"New password update fails!";
+  }
+
+  MessageBox (DisplayString);
+}
+
+/**
+  Require user input password.
+
+  @param[in]  UserGuid               The user GUID of the password.
+
+  @retval TRUE   User input correct password successfully.
+  @retval FALSE  The password is not set.
+**/
+BOOLEAN
+RequireUserPassword (
+  IN   EFI_GUID     *UserGuid
+  )
+{
+  EFI_STATUS                   Status;
+  CHAR16                       UserInputPw[MAX_PASSWORD_LEN + 1];
+  CHAR16                       TmpPassword[MAX_PASSWORD_LEN + 1];
+  CHAR16                       *PopUpString;
+  UINTN                        *PasswordTryCount;
+
+  Status = EFI_SUCCESS;
+  ZeroMem(UserInputPw, sizeof(UserInputPw));
+  ZeroMem(TmpPassword, sizeof(TmpPassword));
+
+  if (!IsPasswordSet(UserGuid)) {
+    return FALSE;
+  }
+
+  if (CompareGuid (UserGuid, &gAdminAuthenticationGuid)) {
+    PopUpString = L"Please input admin password";
+    PasswordTryCount = &mAdminPasswordTryCount;
+  } else {
+    DEBUG ((DEBUG_ERROR, "Invalid User Guid - %g\n", UserGuid));
+    return FALSE;
+  }
+
+  while (TRUE) {
+    gST->ConOut->ClearScreen(gST->ConOut);
+    GetUserInput (PopUpString, UserInputPw, MAX_PASSWORD_LEN);
+
+    CopyGuid (UserGuid, &gAdminAuthenticationGuid);
+    Status = ValidatePassword (UserGuid, UserInputPw, StrSize(UserInputPw));
+    if (!EFI_ERROR(Status)) {
+      break;
+    }
+    *PasswordTryCount = *PasswordTryCount + 1;
+    if (*PasswordTryCount >= PASSWORD_MAX_TRY_COUNT) {
+      ForceSystemReset ();
+    }
+    MessageBox (L"Incorrect password!");
+  }
+  *PasswordTryCount = 0;
+
+  ZeroMem(UserInputPw, sizeof(UserInputPw));
+  ZeroMem(TmpPassword, sizeof(TmpPassword));
+
+  gST->ConOut->ClearScreen(gST->ConOut);
+
+  return TRUE;
+}
+
+/**
+  Set user password.
+
+  @param[in]  UserGuid               The user GUID of the password.
+
+  @retval TRUE   The password is set.
+  @retval FALSE  The password is not set.
+**/
+BOOLEAN
+SetUserPassword (
+  IN   EFI_GUID     *UserGuid
+  )
+{
+  EFI_STATUS                   Status;
+  CHAR16                       UserInputPw[MAX_PASSWORD_LEN + 1];
+  CHAR16                       TmpPassword[MAX_PASSWORD_LEN + 1];
+  CHAR16                       *PopUpString;
+  CHAR16                       *PopUpString2;
+
+  Status = EFI_SUCCESS;
+  ZeroMem(UserInputPw, sizeof(UserInputPw));
+  ZeroMem(TmpPassword, sizeof(TmpPassword));
+
+  if (CompareGuid (UserGuid, &gAdminAuthenticationGuid)) {
+    PopUpString = L"Please set admin password";
+  } else {
+    DEBUG ((DEBUG_ERROR, "Invalid User Guid - %g\n", UserGuid));
+    return FALSE;
+  }
+
+  while (TRUE) {
+    gST->ConOut->ClearScreen(gST->ConOut);
+    GetUserInput (PopUpString, UserInputPw, MAX_PASSWORD_LEN);
+
+    PopUpString2 = L"Please confirm your new password";
+    gST->ConOut->ClearScreen(gST->ConOut);
+    GetUserInput (PopUpString2, TmpPassword, MAX_PASSWORD_LEN);
+    if (StrCmp (TmpPassword, UserInputPw) != 0) {
+      MessageBox (L"Password are not the same!");
+      continue;
+    }
+
+    Status = SetPassword (UserGuid, UserInputPw, StrSize(UserInputPw), NULL, 0);
+    PrintPasswordStatus (Status);
+    if (!EFI_ERROR(Status)) {
+      break;
+    }
+  }
+
+  ZeroMem(UserInputPw, sizeof(UserInputPw));
+  ZeroMem(TmpPassword, sizeof(TmpPassword));
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Check password before entering into setup.
+
+  @param  CodeType      Indicates the type of status code being reported.  Type EFI_STATUS_CODE_TYPE is defined in "Related Definitions" below.
+
+  @param  Value         Describes the current status of a hardware or software entity.
+                        This included information about the class and subclass that is used to classify the entity
+                        as well as an operation.  For progress codes, the operation is the current activity.
+                        For error codes, it is the exception.  For debug codes, it is not defined at this time.
+                        Type EFI_STATUS_CODE_VALUE is defined in "Related Definitions" below.
+                        Specific values are discussed in the Intel? Platform Innovation Framework for EFI Status Code Specification.
+
+  @param  Instance      The enumeration of a hardware or software entity within the system.
+                        A system may contain multiple entities that match a class/subclass pairing.
+                        The instance differentiates between them.  An instance of 0 indicates that instance information is unavailable,
+                        not meaningful, or not relevant.  Valid instance numbers start with 1.
+
+
+  @param  CallerId      This optional parameter may be used to identify the caller.
+                        This parameter allows the status code driver to apply different rules to different callers.
+                        Type EFI_GUID is defined in InstallProtocolInterface() in the UEFI 2.0 Specification.
+
+
+  @param  Data          This optional parameter may be used to pass additional data
+
+  @retval EFI_SUCCESS             Status code is what we expected.
+  @retval EFI_UNSUPPORTED         Status code not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+CheckForPassword (
+  IN EFI_STATUS_CODE_TYPE     CodeType,
+  IN EFI_STATUS_CODE_VALUE    Value,
+  IN UINT32                   Instance,
+  IN EFI_GUID                 *CallerId, OPTIONAL
+  IN EFI_STATUS_CODE_DATA     *Data      OPTIONAL
+  )
+{
+  BOOLEAN   PasswordSet;
+
+  if (((CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_PROGRESS_CODE) &&
+      (Value == (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_PC_USER_SETUP))) {
+    //
+    // Check whether enter setup page.
+    //
+    PasswordSet = RequireUserPassword (&gAdminAuthenticationGuid);
+    if (PasswordSet) {
+      DEBUG ((DEBUG_INFO, "Welcome Admin!\n"));
+    } else {
+      DEBUG ((DEBUG_INFO, "Admin password is not set!\n"));
+      if (NeedEnrollPassword()) {
+        SetUserPassword (&gAdminAuthenticationGuid);
+      }
+    }
+
+    return EFI_SUCCESS;
+  } else{
+    return EFI_UNSUPPORTED;
+  }
+}
+
+/**
+  This function allows a caller to extract the current configuration for one
+  or more named elements from the target driver.
+
+  @param  This                   Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+  @param  Request                A null-terminated Unicode string in
+                                 <ConfigRequest> format.
+  @param  Progress               On return, points to a character in the Request
+                                 string. Points to the string's null terminator if
+                                 request was successful. Points to the most recent
+                                 '&' before the first failing name/value pair (or
+                                 the beginning of the string if the failure is in
+                                 the first name/value pair) if the request was not
+                                 successful.
+  @param  Results                A null-terminated Unicode string in
+                                 <ConfigAltResp> format which has all values filled
+                                 in for the names in the Request string. String to
+                                 be allocated by the called function.
+
+  @retval EFI_SUCCESS            The Results is filled with the requested values.
+  @retval EFI_OUT_OF_RESOURCES   Not enough memory to store the results.
+  @retval EFI_INVALID_PARAMETER  Request is illegal syntax, or unknown name.
+  @retval EFI_NOT_FOUND          Routing data doesn't match any storage in this
+                                 driver.
+
+**/
+EFI_STATUS
+EFIAPI
+ExtractConfig (
+  IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
+  IN  CONST EFI_STRING                       Request,
+  OUT EFI_STRING                             *Progress,
+  OUT EFI_STRING                             *Results
+  )
+{
+  if (Progress == NULL || Results == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+  *Progress = Request;
+  return EFI_NOT_FOUND;
+}
+
+
+/**
+  This function processes the results of changes in configuration.
+
+  @param  This                   Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+  @param  Configuration          A null-terminated Unicode string in <ConfigResp>
+                                 format.
+  @param  Progress               A pointer to a string filled in with the offset of
+                                 the most recent '&' before the first failing
+                                 name/value pair (or the beginning of the string if
+                                 the failure is in the first name/value pair) or
+                                 the terminating NULL if all was successful.
+
+  @retval EFI_SUCCESS            The Results is processed successfully.
+  @retval EFI_INVALID_PARAMETER  Configuration is NULL.
+  @retval EFI_NOT_FOUND          Routing data doesn't match any storage in this
+                                 driver.
+
+**/
+EFI_STATUS
+EFIAPI
+RouteConfig (
+  IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
+  IN  CONST EFI_STRING                       Configuration,
+  OUT EFI_STRING                             *Progress
+  )
+{
+  if (Configuration == NULL || Progress == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  *Progress = Configuration;
+
+  return EFI_NOT_FOUND;
+}
+
+/**
+  This function processes the results of changes in configuration.
+
+  @param  This                   Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+  @param  Action                 Specifies the type of action taken by the browser.
+  @param  QuestionId             A unique value which is sent to the original
+                                 exporting driver so that it can identify the type
+                                 of data to expect.
+  @param  Type                   The type of value for the question.
+  @param  Value                  A pointer to the data being sent to the original
+                                 exporting driver.
+  @param  ActionRequest          On return, points to the action requested by the
+                                 callback function.
+
+  @retval EFI_SUCCESS            The callback successfully handled the action.
+  @retval EFI_OUT_OF_RESOURCES   Not enough storage is available to hold the
+                                 variable and its data.
+  @retval EFI_DEVICE_ERROR       The variable could not be saved.
+  @retval EFI_UNSUPPORTED        The specified Action is not supported by the
+                                 callback.
+
+**/
+EFI_STATUS
+EFIAPI
+UserAuthenticationCallback (
+  IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
+  IN  EFI_BROWSER_ACTION                     Action,
+  IN  EFI_QUESTION_ID                        QuestionId,
+  IN  UINT8                                  Type,
+  IN  EFI_IFR_TYPE_VALUE                     *Value,
+  OUT EFI_BROWSER_ACTION_REQUEST             *ActionRequest
+  )
+{
+  EFI_STATUS  Status;
+  CHAR16      *UserInputPassword;
+  EFI_GUID    *UserGuid;
+  UINTN       *PasswordTryCount;
+
+  Status = EFI_SUCCESS;
+
+  if (((Value == NULL) && (Action != EFI_BROWSER_ACTION_FORM_OPEN) && (Action != EFI_BROWSER_ACTION_FORM_CLOSE))||
+      (ActionRequest == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  switch (Action) {
+  case EFI_BROWSER_ACTION_CHANGING:
+    {
+      switch (QuestionId) {
+      case ADMIN_PASSWORD_KEY_ID:
+        UserGuid = &gAdminAuthenticationGuid;
+        PasswordTryCount = &mAdminPasswordTryCount;
+        if ((Type == EFI_IFR_TYPE_STRING) && (Value->string == 0) &&
+            (mUserAuthenticationData->PasswordState == BROWSER_STATE_SET_PASSWORD)) {
+          mUserAuthenticationData->PasswordState = BROWSER_STATE_VALIDATE_PASSWORD;
+          ZeroMem (mUserAuthenticationData->OldPassword, sizeof(mUserAuthenticationData->OldPassword));
+          return EFI_INVALID_PARAMETER;
+        }
+        //
+        // The Callback is responsible for validating old password input by user,
+        // If Callback return EFI_SUCCESS, it indicates validation pass.
+        //
+        switch (mUserAuthenticationData->PasswordState) {
+        case BROWSER_STATE_VALIDATE_PASSWORD:
+          UserInputPassword = HiiGetString (mUserAuthenticationData->HiiHandle, Value->string, NULL);
+          if ((StrLen (UserInputPassword) >= PASSWORD_MAX_SIZE) || (UserInputPassword[0] == 0)) {
+            Status = EFI_NOT_READY;
+            break;
+          }
+          Status = ValidatePassword (UserGuid, UserInputPassword, StrSize (UserInputPassword));
+          if (Status == EFI_SUCCESS) {
+            mUserAuthenticationData->PasswordState = BROWSER_STATE_SET_PASSWORD;
+            StrCpyS (
+              mUserAuthenticationData->OldPassword,
+              sizeof(mUserAuthenticationData->OldPassword)/sizeof(CHAR16),
+              UserInputPassword
+              );
+            *PasswordTryCount = 0;
+          } else {
+            //
+            // Old password mismatch, return EFI_NOT_READY to prompt for error message.
+            //
+            Status = EFI_NOT_READY;
+            *PasswordTryCount = *PasswordTryCount + 1;
+            if (*PasswordTryCount >= PASSWORD_MAX_TRY_COUNT) {
+              ForceSystemReset ();
+            }
+          }
+          break;
+
+        case BROWSER_STATE_SET_PASSWORD:
+          UserInputPassword = HiiGetString (mUserAuthenticationData->HiiHandle, Value->string, NULL);
+          if ((StrLen (UserInputPassword) >= PASSWORD_MAX_SIZE) || (UserInputPassword[0] == 0)) {
+            Status = EFI_NOT_READY;
+            break;
+          }
+          Status = SetPassword (UserGuid, UserInputPassword, StrSize (UserInputPassword), mUserAuthenticationData->OldPassword, StrSize(mUserAuthenticationData->OldPassword));
+          PrintPasswordStatus (Status);
+          ZeroMem (mUserAuthenticationData->OldPassword, sizeof(mUserAuthenticationData->OldPassword));
+          mUserAuthenticationData->PasswordState = BROWSER_STATE_VALIDATE_PASSWORD;
+          break;
+
+        default:
+          break;
+        }
+      default:
+        break;
+      }
+    }
+  default:
+    break;
+  }
+  return Status;
+}
+
+/**
+  Unregister status code callback functions.
+
+  @param  Event         Event whose notification function is being invoked.
+  @param  Context       Pointer to the notification function's context, which is
+                        always zero in current implementation.
+
+**/
+VOID
+EFIAPI
+UnregisterBootTimeHandlers (
+  IN EFI_EVENT        Event,
+  IN VOID             *Context
+  )
+{
+  mRscHandlerProtocol->Unregister (CheckForPassword);
+}
+
+/**
+  User Authentication entry point.
+
+  @param ImageHandle     The image handle.
+  @param SystemTable     The system table.
+
+  @retval EFI_SUCCESS    The entry point is executed successfully.
+  @return  other         Contain some other errors.
+
+**/
+EFI_STATUS
+EFIAPI
+UserAuthenticationEntry (
+  IN EFI_HANDLE           ImageHandle,
+  IN EFI_SYSTEM_TABLE     *SystemTable
+  )
+{
+  EFI_STATUS        Status;
+  EFI_HANDLE        DriverHandle;
+  EFI_HII_HANDLE    HiiHandle;
+
+  DriverHandle  = NULL;
+
+  mUserAuthenticationData = AllocateZeroPool (sizeof (USER_AUTHENTICATION_PRIVATE_DATA));
+  if (mUserAuthenticationData == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  mUserAuthenticationData->ConfigAccess.ExtractConfig = ExtractConfig;
+  mUserAuthenticationData->ConfigAccess.RouteConfig = RouteConfig;
+  mUserAuthenticationData->ConfigAccess.Callback = UserAuthenticationCallback;
+  mUserAuthenticationData->PasswordState = BROWSER_STATE_VALIDATE_PASSWORD;
+
+  //
+  // Install Config Access protocol to driver handle.
+  //
+  Status = gBS->InstallMultipleProtocolInterfaces (
+                  &DriverHandle,
+                  &gEfiDevicePathProtocolGuid,
+                  &mHiiVendorDevicePath,
+                  &gEfiHiiConfigAccessProtocolGuid,
+                  &mUserAuthenticationData->ConfigAccess,
+                  NULL
+                  );
+  ASSERT_EFI_ERROR (Status);
+  mUserAuthenticationData->DriverHandle = DriverHandle;
+
+  //
+  // Add HII data to database.
+  //
+  HiiHandle = HiiAddPackages (
+                   &gAdminAuthenticationGuid,
+                   DriverHandle,
+                   UserAuthenticationDxeStrings,
+                   UserAuthenticationDxeVfrBin,
+                   NULL
+                   );
+  if (HiiHandle == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+  mUserAuthenticationData->HiiHandle = HiiHandle;
+
+  //
+  // Locate report status code protocol.
+  //
+  Status = gBS->LocateProtocol (
+                  &gEfiRscHandlerProtocolGuid,
+                  NULL,
+                  (VOID **) &mRscHandlerProtocol
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  //
+  //Register the callback function for ReportStatusCode() notification.
+  //
+  mRscHandlerProtocol->Register (CheckForPassword, TPL_HIGH_LEVEL);
+
+  //
+  // Unregister boot time report status code listener at ExitBootService Event.
+  //
+  Status = gBS->CreateEventEx (
+                  EVT_NOTIFY_SIGNAL,
+                  TPL_NOTIFY,
+                  UnregisterBootTimeHandlers,
+                  NULL,
+                  &gEfiEventExitBootServicesGuid,
+                  &mExitBootServicesEvent
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Unloads the application and its installed protocol.
+
+  @param[in]  ImageHandle       Handle that identifies the image to be unloaded.
+
+  @retval EFI_SUCCESS           The image has been unloaded.
+**/
+EFI_STATUS
+EFIAPI
+UserAuthenticationUnload (
+  IN EFI_HANDLE  ImageHandle
+  )
+{
+  ASSERT (mUserAuthenticationData != NULL);
+
+  //
+  // Uninstall Config Access Protocol.
+  //
+  if (mUserAuthenticationData->DriverHandle != NULL) {
+    gBS->UninstallMultipleProtocolInterfaces (
+           mUserAuthenticationData->DriverHandle,
+           &gEfiDevicePathProtocolGuid,
+           &mHiiVendorDevicePath,
+           &gEfiHiiConfigAccessProtocolGuid,
+           &mUserAuthenticationData->ConfigAccess,
+           NULL
+           );
+    mUserAuthenticationData->DriverHandle = NULL;
+  }
+
+  //
+  // Remove Hii Data.
+  //
+  if (mUserAuthenticationData->HiiHandle != NULL) {
+    HiiRemovePackages (mUserAuthenticationData->HiiHandle);
+  }
+
+  FreePool (mUserAuthenticationData);
+  mUserAuthenticationData = NULL;
+
+  return EFI_SUCCESS;
+}
+
diff --git a/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.h b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.h
new file mode 100644
index 0000000..1bcc2a7
--- /dev/null
+++ b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.h
@@ -0,0 +1,115 @@
+/** @file
+  Header file for UserAuthenticationDxe.
+
+Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+
+**/
+
+#ifndef _USER_AUTHENTICATION_DXE_H_
+#define _USER_AUTHENTICATION_DXE_H_
+
+
+#include <Protocol/ReportStatusCodeHandler.h>
+#include <Protocol/HiiConfigAccess.h>
+
+#include <Guid/MdeModuleHii.h>
+#include <Guid/HiiPlatformSetupFormset.h>
+
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/BaseLib.h>
+#include <Library/UefiLib.h>
+#include <Library/HiiLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PlatformPasswordLib.h>
+#include "UserAuthenticationGuid.h"
+#include "UserAuthenticationDxeFormset.h"
+
+extern UINT8  UserAuthenticationDxeVfrBin[];
+extern UINT8  UserAuthenticationDxeStrings[];
+
+typedef struct {
+  EFI_HII_CONFIG_ACCESS_PROTOCOL       ConfigAccess;
+  EFI_HANDLE                           DriverHandle;
+  EFI_HII_HANDLE                       HiiHandle;
+  UINT8                                PasswordState;
+  CHAR16                               OldPassword[PASSWORD_MAX_SIZE];
+} USER_AUTHENTICATION_PRIVATE_DATA;
+
+#pragma pack(1)
+///
+/// HII specific Vendor Device Path definition.
+///
+typedef struct {
+  VENDOR_DEVICE_PATH             VendorDevicePath;
+  EFI_DEVICE_PATH_PROTOCOL       End;
+} HII_VENDOR_DEVICE_PATH;
+#pragma pack()
+
+/**
+  Validata if the password is correct.
+
+  @param[in]  UserGuid               The user GUID of the password.
+  @param[in]  Password               The user input password.
+  @param[in]  PasswordSize           The size of Password in byte.
+
+  @retval EFI_SUCCESS              The password is correct.
+  @retval EFI_SECURITY_VIOLATION   The password is incorrect.
+**/
+EFI_STATUS
+ValidatePassword (
+  IN   EFI_GUID     *UserGuid,
+  IN   CHAR16       *Password,
+  IN   UINTN        PasswordSize
+  );
+
+/**
+  Set a new password.
+
+  @param[in]  UserGuid               The user GUID of the password.
+  @param[in]  NewPassword            The user input new password.
+                                     NULL means clear password.
+  @param[in]  NewPasswordSize        The size of NewPassword in byte.
+  @param[in]  OldPassword            The user input old password.
+                                     NULL means no old password.
+  @param[in]  OldPasswordSize        The size of OldPassword in byte.
+
+  @retval EFI_SUCCESS              The password is correct.
+  @retval EFI_SECURITY_VIOLATION   The password is incorrect.
+  @retval EFI_OUT_OF_RESOURCES     Insufficient resources to set the password.
+**/
+EFI_STATUS
+SetPassword (
+  IN   EFI_GUID     *UserGuid,
+  IN   CHAR16       *NewPassword,     OPTIONAL
+  IN   UINTN        NewPasswordSize,
+  IN   CHAR16       *OldPassword,     OPTIONAL
+  IN   UINTN        OldPasswordSize
+  );
+
+/**
+  Return if the password is set.
+
+  @param[in]  UserGuid               The user GUID of the password.
+
+  @retval TRUE    The password is set.
+  @retval FALSE   The password is not set.
+**/
+BOOLEAN
+IsPasswordSet (
+  IN   EFI_GUID     *UserGuid
+  );
+
+#endif
diff --git a/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.inf b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.inf
new file mode 100644
index 0000000..75a8076
--- /dev/null
+++ b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.inf
@@ -0,0 +1,79 @@
+## @file
+#  User Authentication Dxe Driver.
+#
+#  This Driver mainly does user authentication before entering Setup.
+#
+# Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+#
+#  This program and the accompanying materials
+#  are licensed and made available under the terms and conditions of the BSD License
+#  which accompanies this distribution. The full text of the license may be found at
+#  http://opensource.org/licenses/bsd-license.php
+#
+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = UserAuthenticationDxe
+  MODULE_UNI_FILE                = UserAuthenticationDxe.uni
+  FILE_GUID                      = 0683FB88-664C-4BA6-9ED4-1C0916EE43A4
+  MODULE_TYPE                    = DXE_DRIVER
+  VERSION_STRING                 = 2.0
+  ENTRY_POINT                    = UserAuthenticationEntry
+  ENTRY_POINT                    = PasswordDxeInit
+  UNLOAD_IMAGE                   = UserAuthenticationUnload
+
+
+[Sources]
+  UserAuthenticationDxe.c
+  UserAuthenticationDxe.h
+  UserAuthenticationDxePassword.c
+  UserAuthenticationDxeFormset.h
+  UserAuthenticationGuid.h
+  UserAuthenticationDxeVfr.vfr
+  UserAuthenticationDxeStrings.uni
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  SecurityPkg/SecurityPkg.dec
+
+[LibraryClasses]
+  BaseLib
+  UefiBootServicesTableLib
+  UefiDriverEntryPoint
+  UefiRuntimeServicesTableLib
+  BaseMemoryLib
+  DebugLib
+  UefiLib
+  HiiLib
+  DevicePathLib
+  MemoryAllocationLib
+  PlatformPasswordLib
+
+[Guids]
+  gEfiEventExitBootServicesGuid                 ## CONSUMES  ## Event
+  gEdkiiPiSmmCommunicationRegionTableGuid       ## CONSUMES  ## SystemTable
+
+[Protocols]
+  gEfiRscHandlerProtocolGuid                    ## CONSUMES
+  gEfiDevicePathProtocolGuid                    ## PRODUCES
+  gEfiHiiConfigAccessProtocolGuid               ## PRODUCES
+  gEfiSmmCommunicationProtocolGuid              ## CONSUMES
+
+[Depex]
+  gEfiSimpleTextOutProtocolGuid      AND
+  gEfiHiiDatabaseProtocolGuid        AND
+  gEfiSmmCommunicationProtocolGuid   AND
+  gEfiVariableArchProtocolGuid       AND
+  gEfiVariableWriteArchProtocolGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+  UserAuthenticationDxeExtra.uni
+
+
+
diff --git a/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.uni b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.uni
new file mode 100644
index 0000000..6b2d292
--- /dev/null
+++ b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.uni
@@ -0,0 +1,22 @@
+// /** @file
+// User Authentication Dxe Driver.
+//
+// This driver mainly does the user authentication before entering Setup.
+//
+// Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+//
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT             #language en-US "User Authentication Dxe Driver."
+
+#string STR_MODULE_DESCRIPTION          #language en-US "This driver mainly does user authentication before entering Setup."
+
diff --git a/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeExtra.uni b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeExtra.uni
new file mode 100644
index 0000000..86c5c9b
--- /dev/null
+++ b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeExtra.uni
@@ -0,0 +1,20 @@
+// /** @file
+// User Authentication Dxe Driver.
+//
+// Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+//
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"User Authentication DXE Driver"
+
+
diff --git a/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeFormset.h b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeFormset.h
new file mode 100644
index 0000000..4d29a5d
--- /dev/null
+++ b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeFormset.h
@@ -0,0 +1,30 @@
+/** @file
+  Header file for UserAuthentication formset.
+
+Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+
+**/
+
+#ifndef _USER_AUTHENTICATION_DXE_FORMSET_H_
+#define _USER_AUTHENTICATION_DXE_FORMSET_H_
+
+//
+// Vendor GUID of the formset
+//
+#define USER_AUTHENTICATION_FORMSET_GUID \
+  { 0x760e3022, 0xf149, 0x4560, {0x9c, 0x6f, 0x33, 0xaa, 0x7d, 0x48, 0x75, 0xfa} }
+
+#define ADMIN_PASSWORD_KEY_ID   0x2001
+
+#define MAX_PASSWORD_LEN  20
+#define MIN_PASSWORD_LEN  8
+
+#endif
diff --git a/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxePassword.c b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxePassword.c
new file mode 100644
index 0000000..00b051a
--- /dev/null
+++ b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxePassword.c
@@ -0,0 +1,301 @@
+/** @file
+  UserAuthentication DXE password wrapper.
+
+Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "UserAuthenticationDxe.h"
+#include <Guid/PiSmmCommunicationRegionTable.h>
+#include <Protocol/SmmCommunication.h>
+
+EFI_SMM_COMMUNICATION_PROTOCOL *mSmmCommunication = NULL;
+
+/**
+  Initialize the communicate buffer using DataSize and Function.
+
+  @param[out]      DataPtr          Points to the data in the communicate buffer.
+  @param[in]       DataSize         The data size to send to SMM.
+  @param[in]       Function         The function number to initialize the communicate header.
+  @param[in]       UserGuid         The user GUID of the password.
+
+  @retval EFI_INVALID_PARAMETER     The data size is too big.
+  @retval EFI_SUCCESS               Find the specified variable.
+**/
+VOID*
+InitCommunicateBuffer (
+  OUT     VOID                              **DataPtr OPTIONAL,
+  IN      UINTN                             DataSize,
+  IN      UINTN                             Function,
+  IN      EFI_GUID                          *UserGuid
+  )
+{
+  EFI_SMM_COMMUNICATE_HEADER                *SmmCommunicateHeader;
+  SMM_PASSWORD_COMMUNICATE_HEADER           *SmmPasswordFunctionHeader;
+  VOID                                      *Buffer;
+  EDKII_PI_SMM_COMMUNICATION_REGION_TABLE   *SmmCommRegionTable;
+  EFI_MEMORY_DESCRIPTOR                     *SmmCommMemRegion;
+  UINTN                                     Index;
+  UINTN                                     Size;
+  EFI_STATUS                                Status;
+
+  Buffer = NULL;
+  Status = EfiGetSystemConfigurationTable (
+             &gEdkiiPiSmmCommunicationRegionTableGuid,
+             (VOID **) &SmmCommRegionTable
+             );
+  if (EFI_ERROR (Status)) {
+    return NULL;
+  }
+  ASSERT (SmmCommRegionTable != NULL);
+  SmmCommMemRegion = (EFI_MEMORY_DESCRIPTOR *) (SmmCommRegionTable + 1);
+  Size = 0;
+  for (Index = 0; Index < SmmCommRegionTable->NumberOfEntries; Index++) {
+    if (SmmCommMemRegion->Type == EfiConventionalMemory) {
+      Size = EFI_PAGES_TO_SIZE ((UINTN) SmmCommMemRegion->NumberOfPages);
+      if (Size >= (DataSize + OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data) + sizeof (SMM_PASSWORD_COMMUNICATE_HEADER))) {
+        break;
+      }
+    }
+    SmmCommMemRegion = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) SmmCommMemRegion + SmmCommRegionTable->DescriptorSize);
+  }
+  ASSERT (Index < SmmCommRegionTable->NumberOfEntries);
+
+  Buffer = (VOID*)(UINTN)SmmCommMemRegion->PhysicalStart;
+  ASSERT (Buffer != NULL);
+  SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) Buffer;
+  CopyGuid (&SmmCommunicateHeader->HeaderGuid, UserGuid);
+  SmmCommunicateHeader->MessageLength = DataSize + sizeof (SMM_PASSWORD_COMMUNICATE_HEADER);
+
+  SmmPasswordFunctionHeader = (SMM_PASSWORD_COMMUNICATE_HEADER *) SmmCommunicateHeader->Data;
+  ZeroMem (SmmPasswordFunctionHeader, DataSize + sizeof (SMM_PASSWORD_COMMUNICATE_HEADER));
+  SmmPasswordFunctionHeader->Function = Function;
+  CopyGuid (&SmmPasswordFunctionHeader->UserGuid, UserGuid);
+  if (DataPtr != NULL) {
+    *DataPtr = SmmPasswordFunctionHeader + 1;
+  }
+
+  return Buffer;
+}
+
+/**
+  Send the data in communicate buffer to SMM.
+
+  @param[in]   Buffer                 Points to the data in the communicate buffer.
+  @param[in]   DataSize               This size of the function header and the data.
+
+  @retval      EFI_SUCCESS            Success is returned from the functin in SMM.
+  @retval      Others                 Failure is returned from the function in SMM.
+
+**/
+EFI_STATUS
+SendCommunicateBuffer (
+  IN      VOID                              *Buffer,
+  IN      UINTN                             DataSize
+  )
+{
+  EFI_STATUS                                Status;
+  UINTN                                     CommSize;
+  EFI_SMM_COMMUNICATE_HEADER                *SmmCommunicateHeader;
+  SMM_PASSWORD_COMMUNICATE_HEADER           *SmmPasswordFunctionHeader;
+
+  CommSize = DataSize + OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data) + sizeof (SMM_PASSWORD_COMMUNICATE_HEADER);
+
+  Status = mSmmCommunication->Communicate (mSmmCommunication, Buffer, &CommSize);
+  ASSERT_EFI_ERROR (Status);
+
+  SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) Buffer;
+  SmmPasswordFunctionHeader = (SMM_PASSWORD_COMMUNICATE_HEADER *)SmmCommunicateHeader->Data;
+  return  SmmPasswordFunctionHeader->ReturnStatus;
+}
+
+/**
+  Validata if the password is correct.
+
+  @param[in]  UserGuid               The user GUID of the password.
+  @param[in]  Password               The user input password.
+  @param[in]  PasswordSize           The size of Password in byte.
+
+  @retval EFI_SUCCESS              The password is correct.
+  @retval EFI_SECURITY_VIOLATION   The password is incorrect.
+**/
+EFI_STATUS
+ValidatePassword (
+  IN   EFI_GUID     *UserGuid,
+  IN   CHAR16       *Password,
+  IN   UINTN        PasswordSize
+  )
+{
+  EFI_STATUS                                Status;
+  VOID                                      *Buffer;
+  SMM_PASSWORD_COMMUNICATE_VERIFY_PASSWORD  *VerifyPassword;
+
+  ASSERT (Password != NULL);
+
+  if (PasswordSize > sizeof(VerifyPassword->Password) * sizeof(CHAR16)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Buffer = InitCommunicateBuffer (
+             (VOID**)&VerifyPassword,
+             sizeof(*VerifyPassword),
+             SMM_PASSWORD_FUNCTION_VERIFY_PASSWORD,
+             UserGuid
+             );
+  if (Buffer == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  Status = UnicodeStrToAsciiStrS (Password, VerifyPassword->Password, sizeof(VerifyPassword->Password));
+  if (EFI_ERROR(Status)) {
+    return Status;
+  }
+
+  Status = SendCommunicateBuffer (Buffer, sizeof(*VerifyPassword));
+  if (EFI_ERROR (Status)) {
+    goto EXIT;
+  }
+
+EXIT:
+  ZeroMem (VerifyPassword, sizeof(*VerifyPassword));
+  return Status;
+}
+
+/**
+  Set a new password.
+
+  @param[in]  UserGuid               The user GUID of the password.
+  @param[in]  NewPassword            The user input new password.
+                                     NULL means clear password.
+  @param[in]  NewPasswordSize        The size of NewPassword in byte.
+  @param[in]  OldPassword            The user input old password.
+                                     NULL means no old password.
+  @param[in]  OldPasswordSize        The size of OldPassword in byte.
+
+  @retval EFI_SUCCESS              The password is correct.
+  @retval EFI_SECURITY_VIOLATION   The password is incorrect.
+  @retval EFI_OUT_OF_RESOURCES     Insufficient resources to set the password.
+**/
+EFI_STATUS
+SetPassword (
+  IN   EFI_GUID     *UserGuid,
+  IN   CHAR16       *NewPassword,     OPTIONAL
+  IN   UINTN        NewPasswordSize,
+  IN   CHAR16       *OldPassword,     OPTIONAL
+  IN   UINTN        OldPasswordSize
+  )
+{
+  EFI_STATUS                                Status;
+  VOID                                      *Buffer;
+  SMM_PASSWORD_COMMUNICATE_SET_PASSWORD     *SetPassword;
+
+  if (NewPasswordSize > sizeof(SetPassword->NewPassword) * sizeof(CHAR16)) {
+    return EFI_INVALID_PARAMETER;
+  }
+  if (OldPasswordSize > sizeof(SetPassword->OldPassword) * sizeof(CHAR16)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Buffer = InitCommunicateBuffer (
+             (VOID**)&SetPassword,
+             sizeof(*SetPassword),
+             SMM_PASSWORD_FUNCTION_SET_PASSWORD,
+             UserGuid
+             );
+  if (Buffer == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  if (NewPassword != NULL) {
+    Status = UnicodeStrToAsciiStrS (NewPassword, SetPassword->NewPassword, sizeof(SetPassword->NewPassword));
+    if (EFI_ERROR(Status)) {
+      return Status;
+    }
+  } else {
+    SetPassword->NewPassword[0] = 0;
+  }
+
+  if (OldPassword != NULL) {
+    Status = UnicodeStrToAsciiStrS (OldPassword, SetPassword->OldPassword, sizeof(SetPassword->OldPassword));
+    if (EFI_ERROR(Status)) {
+      return Status;
+    }
+  } else {
+    SetPassword->OldPassword[0] = 0;
+  }
+
+  Status = SendCommunicateBuffer (Buffer, sizeof(*SetPassword));
+  if (EFI_ERROR (Status)) {
+    goto EXIT;
+  }
+
+EXIT:
+  ZeroMem (SetPassword, sizeof(*SetPassword));
+  return Status;
+}
+
+/**
+  Return if the password is set.
+
+  @param[in]  UserGuid               The user GUID of the password.
+
+  @retval TRUE    The password is set.
+  @retval FALSE   The password is not set.
+**/
+BOOLEAN
+IsPasswordSet (
+  IN   EFI_GUID     *UserGuid
+  )
+{
+  EFI_STATUS                                Status;
+  VOID                                      *Buffer;
+
+  Buffer = InitCommunicateBuffer (
+             NULL,
+             0,
+             SMM_PASSWORD_FUNCTION_IS_PASSWORD_SET,
+             UserGuid
+             );
+  if (Buffer == NULL) {
+    return FALSE;
+  }
+
+  Status = SendCommunicateBuffer (Buffer, 0);
+  if (EFI_ERROR (Status)) {
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+/**
+  Main entry for this driver.
+
+  @param ImageHandle     Image handle this driver.
+  @param SystemTable     Pointer to SystemTable.
+
+  @retval EFI_SUCESS     This function always complete successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+PasswordDxeInit (
+  IN EFI_HANDLE                         ImageHandle,
+  IN EFI_SYSTEM_TABLE                   *SystemTable
+  )
+{
+  EFI_STATUS                     Status;
+
+  Status = gBS->LocateProtocol (&gEfiSmmCommunicationProtocolGuid, NULL, (VOID **) &mSmmCommunication);
+  ASSERT_EFI_ERROR (Status);
+
+  return EFI_SUCCESS;
+}
+
diff --git a/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeStrings.uni b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeStrings.uni
new file mode 100644
index 0000000..86fde22
--- /dev/null
+++ b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeStrings.uni
@@ -0,0 +1,29 @@
+/** @file
+// String definitions for User Authentication formset.
+
+// Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution.  The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#langdef en-US  "English"
+#langdef fr-FR  "Francais"
+
+
+#string STR_FORM_SET_TITLE             #language en-US "User Password Management"
+                                       #language fr-FR "User Password Management"
+#string STR_FORM_SET_TITLE_HELP        #language en-US "This Driver mainly handle user's password"
+                                       #language fr-FR "This Driver mainly handle user's password"
+#string STR_FORM_TITLE                 #language en-US "Password Management Form"
+                                       #language fr-FR "Password Management Form"
+#string STR_ADMIN_PASSWORD_PROMPT      #language en-US "Change Admin Password"
+                                       #language fr-FR "Change Admin Password"
+#string STR_ADMIN_PASSWORD_HELP        #language en-US "Input old admin password, then you can change the password to a new one. After the change action, you need input the new password when you enter UI. The new password must be at least 8 char and include lowercase, uppercase alphabetic, numbers, and symbols."
+                                       #language fr-FR "Input old admin password, then you can change the password to a new one. After the change action, you need input the new password when you enter UI. The new password must be at least 8 char and include lowercase, uppercase alphabetic, numbers, and symbols."
+
diff --git a/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeVfr.vfr b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeVfr.vfr
new file mode 100644
index 0000000..4741fe3
--- /dev/null
+++ b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeVfr.vfr
@@ -0,0 +1,38 @@
+///** @file
+// UserAuthentication formset.
+//
+// Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution.  The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+//
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+//**/
+
+#include <Guid/HiiPlatformSetupFormset.h>
+#include "UserAuthenticationDxeFormset.h"
+
+formset
+  guid      = USER_AUTHENTICATION_FORMSET_GUID,
+  title     = STRING_TOKEN(STR_FORM_SET_TITLE),
+  help      = STRING_TOKEN(STR_FORM_SET_TITLE_HELP),
+  classguid = EFI_HII_PLATFORM_SETUP_FORMSET_GUID,
+
+  form formid = 1,
+      title  = STRING_TOKEN(STR_FORM_TITLE);
+
+      password
+          prompt   = STRING_TOKEN(STR_ADMIN_PASSWORD_PROMPT),
+          help     = STRING_TOKEN(STR_ADMIN_PASSWORD_HELP),
+          flags    = INTERACTIVE,
+          key      = ADMIN_PASSWORD_KEY_ID,
+          minsize = MIN_PASSWORD_LEN,
+          maxsize = MAX_PASSWORD_LEN,
+      endpassword;
+
+  endform;
+
+endformset;
diff --git a/SecurityPkg/Password/UserAuthentication/UserAuthenticationGuid.h b/SecurityPkg/Password/UserAuthentication/UserAuthenticationGuid.h
new file mode 100644
index 0000000..0a4df01
--- /dev/null
+++ b/SecurityPkg/Password/UserAuthentication/UserAuthenticationGuid.h
@@ -0,0 +1,65 @@
+/** @file
+  GUID is for UserPassword variable.
+
+Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __USER_AUTHENTICATION_GUID_H__
+#define __USER_AUTHENTICATION_GUID_H__
+
+#define PASSWORD_MIN_SIZE    9  // MIN number of char of password, including NULL
+#define PASSWORD_MAX_SIZE    32 // MAX number of char of password, including NULL
+#define PASSWORD_SALT_SIZE   32
+#define PASSWORD_HASH_SIZE   32 // SHA256_DIGEST_SIZE
+
+#define PASSWORD_MAX_TRY_COUNT  3
+#define PASSWORD_HISTORY_CHECK_COUNT  5
+
+//
+// Vendor GUID of the variable
+//
+#define ADMIN_AUTHENTICATION_GUID \
+  { 0xee24a7f7, 0x606b, 0x4724, { 0xb3, 0xc9, 0xf5, 0xae, 0x4a, 0x3b, 0x81, 0x65} }
+
+//
+// Name of the variable
+//
+#define USER_AUTHENTICATION_VAR_NAME L"Password"
+#define USER_AUTHENTICATION_HISTORY_LAST_VAR_NAME L"PasswordLast"
+
+//
+// Variable storage
+//
+typedef struct {
+  UINT8        PasswordHash[PASSWORD_HASH_SIZE];
+  UINT8        PasswordSalt[PASSWORD_SALT_SIZE];
+} USER_PASSWORD_VAR_STRUCT;
+
+typedef struct {
+  UINTN       Function;
+  EFI_STATUS  ReturnStatus;
+  EFI_GUID    UserGuid;
+} SMM_PASSWORD_COMMUNICATE_HEADER;
+
+#define SMM_PASSWORD_FUNCTION_IS_PASSWORD_SET     1
+#define SMM_PASSWORD_FUNCTION_SET_PASSWORD        2
+#define SMM_PASSWORD_FUNCTION_VERIFY_PASSWORD     3
+
+typedef struct {
+  CHAR8                                 NewPassword[PASSWORD_MAX_SIZE];
+  CHAR8                                 OldPassword[PASSWORD_MAX_SIZE];
+} SMM_PASSWORD_COMMUNICATE_SET_PASSWORD;
+
+typedef struct {
+  CHAR8                                 Password[PASSWORD_MAX_SIZE];
+} SMM_PASSWORD_COMMUNICATE_VERIFY_PASSWORD;
+
+#endif
diff --git a/SecurityPkg/Password/UserAuthentication/UserAuthenticationSmm.c b/SecurityPkg/Password/UserAuthentication/UserAuthenticationSmm.c
new file mode 100644
index 0000000..ffc3d81
--- /dev/null
+++ b/SecurityPkg/Password/UserAuthentication/UserAuthenticationSmm.c
@@ -0,0 +1,672 @@
+/** @file
+
+Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiSmm.h>
+#include <Protocol/SmmVariable.h>
+#include <Protocol/VariableLock.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PrintLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/SmmServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/SmmServicesTableLib.h>
+#include <Library/PlatformPasswordLib.h>
+#include "KeyService.h"
+#include "UserAuthenticationGuid.h"
+
+EFI_GUID gAdminAuthenticationGuid = ADMIN_AUTHENTICATION_GUID;
+
+EFI_SMM_VARIABLE_PROTOCOL         *mSmmVariable;
+
+UINTN  mAdminPasswordTryCount;
+
+/**
+  Verify if the password is correct.
+
+  @param[in]  Password               The user input password.
+  @param[in]  PasswordSize           The size of Password in byte.
+  @param[in]  UserPasswordVarStruct  The storage of password in variable.
+
+  @retval EFI_SUCCESS              The password is correct.
+  @retval EFI_SECURITY_VIOLATION   The password is incorrect.
+**/
+EFI_STATUS
+VerifyPassword (
+  IN CHAR8                          *Password,
+  IN UINTN                          PasswordSize,
+  IN USER_PASSWORD_VAR_STRUCT       *UserPasswordVarStruct
+  )
+{
+  BOOLEAN  HashOk;
+  UINT8    HashData[PASSWORD_HASH_SIZE];
+
+  HashOk = KeyLibGeneratePBKDF2Hash (
+             HASH_TYPE_SHA256,
+             (UINT8 *)Password,
+             PasswordSize,
+             UserPasswordVarStruct->PasswordSalt,
+             sizeof(UserPasswordVarStruct->PasswordSalt),
+             HashData,
+             sizeof(HashData)
+             );
+  if (!HashOk) {
+    return EFI_DEVICE_ERROR;
+  }
+  if (KeyLibSlowCompareMem (UserPasswordVarStruct->PasswordHash, HashData, PASSWORD_HASH_SIZE) == 0) {
+    return EFI_SUCCESS;
+  } else {
+    return EFI_SECURITY_VIOLATION;
+  }
+}
+
+/**
+  Get hash data of password from non-volatile variable region.
+
+  @param[in]   UserGuid               The user GUID of the password variable.
+  @param[in]   Index                  The index of the password.
+                                      0 means current password.
+                                      Non-0 means the password history.
+  @param[out]  UserPasswordVarStruct  The storage of password in variable.
+
+  @retval EFI_SUCCESS             The password hash is returned successfully.
+  @retval EFI_NOT_FOUND           The password hash is not found.
+**/
+EFI_STATUS
+GetPasswordHashFromVariable (
+  IN  EFI_GUID                       *UserGuid,
+  IN  UINTN                          Index,
+  OUT USER_PASSWORD_VAR_STRUCT       *UserPasswordVarStruct
+  )
+{
+  EFI_STATUS                        Status;
+  UINTN                             DataSize;
+  CHAR16                            PasswordName[sizeof(USER_AUTHENTICATION_VAR_NAME)/sizeof(CHAR16) + 4];
+
+  if (Index != 0) {
+    UnicodeSPrint (PasswordName, sizeof (PasswordName), L"%s%04x", USER_AUTHENTICATION_VAR_NAME, Index);
+  } else {
+    UnicodeSPrint (PasswordName, sizeof (PasswordName), L"%s", USER_AUTHENTICATION_VAR_NAME);
+  }
+
+  DataSize = sizeof(*UserPasswordVarStruct);
+  Status = mSmmVariable->SmmGetVariable (
+                           PasswordName,
+                           UserGuid,
+                           NULL,
+                           &DataSize,
+                           UserPasswordVarStruct
+                           );
+  if (EFI_ERROR(Status)) {
+    return Status;
+  }
+
+  return Status;
+}
+
+/**
+  Save password hash data to non-volatile variable region.
+
+  @param[in]   UserGuid               The user GUID of the password variable.
+  @param[in]   UserPasswordVarStruct  The storage of password in variable.
+
+  @retval EFI_SUCCESS             The password hash is saved successfully.
+  @retval EFI_OUT_OF_RESOURCES    Insufficient resources to save the password hash.
+**/
+EFI_STATUS
+SavePasswordHashToVariable (
+  IN EFI_GUID                       *UserGuid,
+  IN USER_PASSWORD_VAR_STRUCT       *UserPasswordVarStruct
+  )
+{
+  EFI_STATUS                        Status;
+
+  if (UserPasswordVarStruct == NULL) {
+    Status = mSmmVariable->SmmSetVariable (
+                             USER_AUTHENTICATION_VAR_NAME,
+                             UserGuid,
+                             EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+                             0,
+                             NULL
+                             );
+  } else {
+    Status = mSmmVariable->SmmSetVariable (
+                             USER_AUTHENTICATION_VAR_NAME,
+                             UserGuid,
+                             EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+                             sizeof(*UserPasswordVarStruct),
+                             UserPasswordVarStruct
+                             );
+  }
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "SavePasswordHashToVariable fails with %r\n", Status));
+  }
+
+  return Status;
+}
+
+/**
+  Save old password hash data to non-volatile variable region as history.
+
+  The number of password history variable is limited.
+  If all the password history variables are used, the new password history
+  will override the oldest one.
+
+  @param[in]   UserGuid               The user GUID of the password variable.
+  @param[in]   UserPasswordVarStruct  The storage of password in variable.
+
+  @retval EFI_SUCCESS             The password hash is saved successfully.
+  @retval EFI_OUT_OF_RESOURCES    Insufficient resources to save the password hash.
+**/
+EFI_STATUS
+SaveOldPasswordToHistory (
+  IN EFI_GUID                       *UserGuid,
+  IN USER_PASSWORD_VAR_STRUCT       *UserPasswordVarStruct
+  )
+{
+  EFI_STATUS                        Status;
+  UINTN                             DataSize;
+  UINT32                            LastIndex;
+  CHAR16                            PasswordName[sizeof(USER_AUTHENTICATION_VAR_NAME)/sizeof(CHAR16) + 4];
+
+  DEBUG ((DEBUG_INFO, "SaveOldPasswordToHistory\n"));
+
+  DataSize = sizeof(LastIndex);
+  Status = mSmmVariable->SmmGetVariable (
+                           USER_AUTHENTICATION_HISTORY_LAST_VAR_NAME,
+                           UserGuid,
+                           NULL,
+                           &DataSize,
+                           &LastIndex
+                           );
+  if (EFI_ERROR(Status)) {
+    LastIndex = 0;
+  }
+  if (LastIndex >= PASSWORD_HISTORY_CHECK_COUNT) {
+    LastIndex = 0;
+  }
+
+  LastIndex ++;
+  UnicodeSPrint (PasswordName, sizeof (PasswordName), L"%s%04x", USER_AUTHENTICATION_VAR_NAME, LastIndex);
+
+
+  Status = mSmmVariable->SmmSetVariable (
+                           PasswordName,
+                           UserGuid,
+                           EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+                           sizeof(*UserPasswordVarStruct),
+                           UserPasswordVarStruct
+                           );
+  DEBUG ((DEBUG_INFO, "  -- to %s, %r\n", PasswordName, Status));
+  if (!EFI_ERROR(Status)) {
+    Status = mSmmVariable->SmmSetVariable (
+                             USER_AUTHENTICATION_HISTORY_LAST_VAR_NAME,
+                             UserGuid,
+                             EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+                             sizeof(LastIndex),
+                             &LastIndex
+                             );
+    DEBUG ((DEBUG_INFO, " LastIndex - 0x%04x, %r\n", LastIndex, Status));
+  }
+
+  return Status;
+}
+
+/**
+  Calculate password hash data and save it to non-volatile variable region.
+
+  @param[in]  UserGuid               The user GUID of the password variable.
+  @param[in]  Password               The user input password.
+                                     NULL means delete the password variable.
+  @param[in]  PasswordSize           The size of Password in byte.
+
+  @retval EFI_SUCCESS             The password hash is calculated and saved.
+  @retval EFI_OUT_OF_RESOURCES    Insufficient resources to save the password hash.
+**/
+EFI_STATUS
+SavePasswordToVariable (
+  IN  EFI_GUID                      *UserGuid,
+  IN  CHAR8                         *Password,  OPTIONAL
+  IN  UINTN                         PasswordSize
+  )
+{
+  EFI_STATUS                        Status;
+  USER_PASSWORD_VAR_STRUCT          UserPasswordVarStruct;
+  BOOLEAN                           HashOk;
+
+  //
+  // If password is NULL, it means we want to clean password field saved in variable region.
+  //
+  if (Password != NULL) {
+    KeyLibGenerateSalt (UserPasswordVarStruct.PasswordSalt, sizeof(UserPasswordVarStruct.PasswordSalt));
+    HashOk = KeyLibGeneratePBKDF2Hash (
+               HASH_TYPE_SHA256,
+               (UINT8 *)Password,
+               PasswordSize,
+               UserPasswordVarStruct.PasswordSalt,
+               sizeof(UserPasswordVarStruct.PasswordSalt),
+               UserPasswordVarStruct.PasswordHash,
+               sizeof(UserPasswordVarStruct.PasswordHash)
+               );
+    if (!HashOk) {
+      return EFI_DEVICE_ERROR;
+    }
+    Status = SavePasswordHashToVariable (UserGuid, &UserPasswordVarStruct);
+    //
+    // Save Password data to history variable
+    //
+    if (!EFI_ERROR(Status)) {
+      SaveOldPasswordToHistory (UserGuid, &UserPasswordVarStruct);
+    }
+  } else {
+    Status = SavePasswordHashToVariable (UserGuid, NULL);
+  }
+
+  return Status;
+}
+
+/**
+  Verify the password.
+  If the password variable does not exist, it passes the verification.
+  If the password variable exists, it does verification based upon password variable.
+
+  @param[in]  UserGuid               The user GUID of the password variable.
+  @param[in]  Password               The user input password.
+  @param[in]  PasswordSize           The size of Password in byte.
+
+  @retval TRUE    The verification passes.
+  @retval FALSE   The verification fails.
+**/
+BOOLEAN
+IsPasswordVerified (
+  IN EFI_GUID                       *UserGuid,
+  IN CHAR8                          *Password,
+  IN UINTN                          PasswordSize
+  )
+{
+  USER_PASSWORD_VAR_STRUCT          UserPasswordVarStruct;
+  EFI_STATUS                        Status;
+
+  Status = GetPasswordHashFromVariable (UserGuid, 0, &UserPasswordVarStruct);
+  if (EFI_ERROR(Status)) {
+    return TRUE;
+  }
+
+  //
+  // Old password exists
+  //
+  Status = VerifyPassword (Password, PasswordSize, &UserPasswordVarStruct);
+  if (EFI_ERROR(Status)) {
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+/**
+  Return if the password is set.
+
+  @param[in]  UserGuid               The user GUID of the password variable.
+
+  @retval TRUE    The password is set.
+  @retval FALSE   The password is not set.
+**/
+BOOLEAN
+IsPasswordSet (
+  IN EFI_GUID                       *UserGuid
+  )
+{
+  USER_PASSWORD_VAR_STRUCT          UserPasswordVarStruct;
+  EFI_STATUS                        Status;
+
+  Status = GetPasswordHashFromVariable(UserGuid, 0, &UserPasswordVarStruct);
+  if (EFI_ERROR(Status)) {
+    return FALSE;
+  }
+  return TRUE;
+}
+
+/**
+  Return if the password is strong.
+  Criteria:
+  1) length >= PASSWORD_MIN_SIZE
+  2) include lower case, upper case, number, symbol.
+
+  @param[in]  Password               The user input password.
+  @param[in]  PasswordSize           The size of Password in byte.
+
+  @retval TRUE    The password is strong.
+  @retval FALSE   The password is weak.
+**/
+BOOLEAN
+IsPasswordStrong (
+  IN CHAR8   *Password,
+  IN UINTN   PasswordSize
+  )
+{
+  UINTN   Index;
+  BOOLEAN HasLowerCase;
+  BOOLEAN HasUpperCase;
+  BOOLEAN HasNumber;
+  BOOLEAN HasSymbol;
+
+  if (PasswordSize < PASSWORD_MIN_SIZE) {
+    return FALSE;
+  }
+
+  HasLowerCase = FALSE;
+  HasUpperCase = FALSE;
+  HasNumber = FALSE;
+  HasSymbol = FALSE;
+  for (Index = 0; Index < PasswordSize - 1; Index++) {
+    if (Password[Index] >= 'a' && Password[Index] <= 'z') {
+      HasLowerCase = TRUE;
+    } else if (Password[Index] >= 'A' && Password[Index] <= 'Z') {
+      HasUpperCase = TRUE;
+    } else if (Password[Index] >= '0' && Password[Index] <= '9') {
+      HasNumber = TRUE;
+    } else {
+      HasSymbol = TRUE;
+    }
+  }
+  if ((!HasLowerCase) || (!HasUpperCase) || (!HasNumber) || (!HasSymbol)) {
+    return FALSE;
+  }
+  return TRUE;
+}
+
+/**
+  Return if the password is set before in PASSWORD_HISTORY_CHECK_COUNT.
+
+  @param[in]  UserGuid               The user GUID of the password variable.
+  @param[in]  Password               The user input password.
+  @param[in]  PasswordSize           The size of Password in byte.
+
+  @retval TRUE    The password is set before.
+  @retval FALSE   The password is not set before.
+**/
+BOOLEAN
+IsPasswordInHistory (
+  IN EFI_GUID                       *UserGuid,
+  IN CHAR8                          *Password,
+  IN UINTN                          PasswordSize
+  )
+{
+  EFI_STATUS                     Status;
+  USER_PASSWORD_VAR_STRUCT       UserPasswordVarStruct;
+  UINTN                          Index;
+
+  for (Index = 1; Index <= PASSWORD_HISTORY_CHECK_COUNT; Index++) {
+    Status = GetPasswordHashFromVariable (UserGuid, Index, &UserPasswordVarStruct);
+    if (!EFI_ERROR(Status)) {
+      Status = VerifyPassword (Password, PasswordSize, &UserPasswordVarStruct);
+      if (!EFI_ERROR(Status)) {
+        return TRUE;
+      }
+    }
+  }
+
+  return FALSE;
+}
+
+/**
+  Communication service SMI Handler entry.
+
+  This SMI handler provides services for password management.
+
+  @param[in]     DispatchHandle  The unique handle assigned to this handler by SmiHandlerRegister().
+  @param[in]     RegisterContext Points to an optional handler context which was specified when the
+                                 handler was registered.
+  @param[in, out] CommBuffer     A pointer to a collection of data in memory that will
+                                 be conveyed from a non-SMM environment into an SMM environment.
+  @param[in, out] CommBufferSize The size of the CommBuffer.
+
+  @retval EFI_SUCCESS                         The interrupt was handled and quiesced. No other handlers
+                                              should still be called.
+  @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED  The interrupt has been quiesced but other handlers should
+                                              still be called.
+  @retval EFI_WARN_INTERRUPT_SOURCE_PENDING   The interrupt is still pending and other handlers should still
+                                              be called.
+  @retval EFI_INTERRUPT_PENDING               The interrupt could not be quiesced.
+**/
+EFI_STATUS
+EFIAPI
+SmmPasswordHandler (
+  IN     EFI_HANDLE                 DispatchHandle,
+  IN     CONST VOID                 *RegisterContext,
+  IN OUT VOID                       *CommBuffer,
+  IN OUT UINTN                      *CommBufferSize
+  )
+{
+  EFI_STATUS                                Status;
+  SMM_PASSWORD_COMMUNICATE_HEADER           *SmmFunctionHeader;
+  UINTN                                     CommBufferPayloadSize;
+  UINTN                                     TempCommBufferSize;
+  SMM_PASSWORD_COMMUNICATE_SET_PASSWORD     SmmCommunicateSetPassword;
+  SMM_PASSWORD_COMMUNICATE_VERIFY_PASSWORD  SmmCommunicateVerifyPassword;
+  UINTN                                     PasswordLen;
+  EFI_GUID                                  UserGuid;
+  UINTN                                     *PasswordTryCount;
+
+  //
+  // If input is invalid, stop processing this SMI
+  //
+  if (CommBuffer == NULL || CommBufferSize == NULL) {
+    return EFI_SUCCESS;
+  }
+
+  TempCommBufferSize = *CommBufferSize;
+
+  if (TempCommBufferSize < sizeof (SMM_PASSWORD_COMMUNICATE_HEADER)) {
+    DEBUG ((DEBUG_ERROR, "SmmPasswordHandler: SMM communication buffer size invalid!\n"));
+    return EFI_SUCCESS;
+  }
+
+  CommBufferPayloadSize = TempCommBufferSize - sizeof (SMM_PASSWORD_COMMUNICATE_HEADER);
+
+  Status   = EFI_SUCCESS;
+  SmmFunctionHeader = (SMM_PASSWORD_COMMUNICATE_HEADER *)CommBuffer;
+  CopyGuid (&UserGuid, &SmmFunctionHeader->UserGuid);
+
+  if (CompareGuid (&UserGuid, &gAdminAuthenticationGuid)) {
+    PasswordTryCount = &mAdminPasswordTryCount;
+  } else {
+    DEBUG ((DEBUG_ERROR, "SmmPasswordHandler: Invalid UserGuid\n"));
+    PasswordTryCount = NULL;
+    Status = EFI_INVALID_PARAMETER;
+    goto EXIT;
+  }
+
+  switch (SmmFunctionHeader->Function) {
+  case SMM_PASSWORD_FUNCTION_IS_PASSWORD_SET:
+    PasswordTryCount = NULL;
+    if (CommBufferPayloadSize != 0) {
+      DEBUG ((DEBUG_ERROR, "SmmPasswordHandler: IS_PASSWORD_SET payload buffer invalid!\n"));
+      Status = EFI_INVALID_PARAMETER;
+      goto EXIT;
+    }
+    if (IsPasswordSet(&UserGuid)) {
+      Status = EFI_SUCCESS;
+    } else {
+      Status = EFI_NOT_FOUND;
+    }
+    break;
+  case SMM_PASSWORD_FUNCTION_SET_PASSWORD:
+    if (*PasswordTryCount >= PASSWORD_MAX_TRY_COUNT) {
+      DEBUG ((DEBUG_ERROR, "SmmPasswordHandler: SET_PASSWORD try count reach!\n"));
+      PasswordTryCount = NULL;
+      Status = EFI_INVALID_PARAMETER;
+      goto EXIT;
+    }
+    if (CommBufferPayloadSize != sizeof(SMM_PASSWORD_COMMUNICATE_SET_PASSWORD)) {
+      DEBUG ((DEBUG_ERROR, "SmmPasswordHandler: SET_PASSWORD payload buffer invalid!\n"));
+      Status = EFI_INVALID_PARAMETER;
+      goto EXIT;
+    }
+    CopyMem (&SmmCommunicateSetPassword, SmmFunctionHeader + 1, sizeof(SmmCommunicateSetPassword));
+
+    PasswordLen = AsciiStrnLenS(SmmCommunicateSetPassword.OldPassword, sizeof(SmmCommunicateSetPassword.OldPassword));
+    if (PasswordLen == sizeof(SmmCommunicateSetPassword.OldPassword)) {
+      DEBUG ((DEBUG_ERROR, "SmmPasswordHandler: OldPassword invalid!\n"));
+      Status = EFI_INVALID_PARAMETER;
+      goto EXIT;
+    }
+
+    if (!IsPasswordVerified (&UserGuid, SmmCommunicateSetPassword.OldPassword, PasswordLen + 1)) {
+      DEBUG ((DEBUG_ERROR, "SmmPasswordHandler: PasswordVerify - FAIL\n"));
+      Status = EFI_SECURITY_VIOLATION;
+      goto EXIT;
+    }
+
+    PasswordLen = AsciiStrnLenS(SmmCommunicateSetPassword.NewPassword, sizeof(SmmCommunicateSetPassword.NewPassword));
+    if (PasswordLen == sizeof(SmmCommunicateSetPassword.NewPassword)) {
+      DEBUG ((DEBUG_ERROR, "SmmPasswordHandler: NewPassword invalid!\n"));
+      Status = EFI_INVALID_PARAMETER;
+      goto EXIT;
+    }
+    if (!IsPasswordStrong (SmmCommunicateSetPassword.NewPassword, PasswordLen + 1)) {
+      DEBUG ((DEBUG_ERROR, "SmmPasswordHandler: NewPassword too weak!\n"));
+      Status = EFI_UNSUPPORTED;
+      goto EXIT;
+    }
+    if (IsPasswordInHistory (&UserGuid, SmmCommunicateSetPassword.NewPassword, PasswordLen + 1)) {
+      DEBUG ((DEBUG_ERROR, "SmmPasswordHandler: NewPassword in history!\n"));
+      Status = EFI_ALREADY_STARTED;
+      goto EXIT;
+    }
+
+    if (PasswordLen == 0) {
+      Status = SavePasswordToVariable (&UserGuid, NULL, 0);
+    } else {
+      Status = SavePasswordToVariable (&UserGuid, SmmCommunicateSetPassword.NewPassword, PasswordLen + 1);
+    }
+    break;
+
+  case SMM_PASSWORD_FUNCTION_VERIFY_PASSWORD:
+    if (*PasswordTryCount >= PASSWORD_MAX_TRY_COUNT) {
+      DEBUG ((DEBUG_ERROR, "SmmPasswordHandler: VERIFY_PASSWORD try count reach!\n"));
+      PasswordTryCount = NULL;
+      Status = EFI_INVALID_PARAMETER;
+      goto EXIT;
+    }
+    if (CommBufferPayloadSize != sizeof(SMM_PASSWORD_COMMUNICATE_VERIFY_PASSWORD)) {
+      DEBUG ((DEBUG_ERROR, "SmmPasswordHandler: VERIFY_PASSWORD payload buffer invalid!\n"));
+      Status = EFI_INVALID_PARAMETER;
+      goto EXIT;
+    }
+    CopyMem (&SmmCommunicateVerifyPassword, SmmFunctionHeader + 1, sizeof(SmmCommunicateVerifyPassword));
+
+    PasswordLen = AsciiStrnLenS(SmmCommunicateVerifyPassword.Password, sizeof(SmmCommunicateVerifyPassword.Password));
+    if (PasswordLen == sizeof(SmmCommunicateVerifyPassword.Password)) {
+      DEBUG ((DEBUG_ERROR, "SmmPasswordHandler: Password invalid!\n"));
+      Status = EFI_INVALID_PARAMETER;
+      goto EXIT;
+    }
+    if (!IsPasswordVerified (&UserGuid, SmmCommunicateVerifyPassword.Password, PasswordLen + 1)) {
+      DEBUG ((DEBUG_ERROR, "SmmPasswordHandler: PasswordVerify - FAIL\n"));
+      Status = EFI_SECURITY_VIOLATION;
+      goto EXIT;
+    }
+    Status = EFI_SUCCESS;
+    break;
+
+  default:
+    PasswordTryCount = NULL;
+    Status = EFI_UNSUPPORTED;
+    break;
+  }
+
+EXIT:
+  if (PasswordTryCount != NULL) {
+    if (Status == EFI_SUCCESS) {
+      *PasswordTryCount = 0;
+    } else {
+      *PasswordTryCount = *PasswordTryCount + 1;
+    }
+  }
+  SmmFunctionHeader->ReturnStatus = Status;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Main entry for this driver.
+
+  @param ImageHandle     Image handle this driver.
+  @param SystemTable     Pointer to SystemTable.
+
+  @retval EFI_SUCESS     This function always complete successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+PasswordSmmInit (
+  IN EFI_HANDLE                         ImageHandle,
+  IN EFI_SYSTEM_TABLE                   *SystemTable
+  )
+{
+  EFI_STATUS                            Status;
+  EFI_HANDLE                            SmmHandle;
+  EDKII_VARIABLE_LOCK_PROTOCOL          *VariableLock;
+  CHAR16                                PasswordHistoryName[sizeof(USER_AUTHENTICATION_VAR_NAME)/sizeof(CHAR16) + 4];
+  UINTN                                 Index;
+
+  ASSERT (PASSWORD_HASH_SIZE == SHA256_DIGEST_SIZE);
+  ASSERT (PASSWORD_HISTORY_CHECK_COUNT < 0xFFFF);
+
+  Status = gSmst->SmmLocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID**)&mSmmVariable);
+  ASSERT_EFI_ERROR (Status);
+
+  SmmHandle          = NULL;
+
+  //
+  // Make "HddPassword" varible read-only for DXE driver for security concern.
+  //
+  Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **) &VariableLock);
+  if (!EFI_ERROR (Status)) {
+    Status = VariableLock->RequestToLock (VariableLock, USER_AUTHENTICATION_VAR_NAME, &gAdminAuthenticationGuid);
+    ASSERT_EFI_ERROR (Status);
+
+    for (Index = 1; Index <= PASSWORD_HISTORY_CHECK_COUNT; Index++) {
+      UnicodeSPrint (PasswordHistoryName, sizeof (PasswordHistoryName), L"%s%04x", USER_AUTHENTICATION_VAR_NAME, Index);
+      Status = VariableLock->RequestToLock (VariableLock, PasswordHistoryName, &gAdminAuthenticationGuid);
+      ASSERT_EFI_ERROR (Status);
+    }
+    Status = VariableLock->RequestToLock (VariableLock, USER_AUTHENTICATION_HISTORY_LAST_VAR_NAME, &gAdminAuthenticationGuid);
+    ASSERT_EFI_ERROR (Status);
+  }
+
+  SmmHandle = NULL;
+  Status    = gSmst->SmiHandlerRegister (SmmPasswordHandler, &gAdminAuthenticationGuid, &SmmHandle);
+  ASSERT_EFI_ERROR (Status);
+  if (EFI_ERROR (Status)) {
+    Status = EFI_OUT_OF_RESOURCES;
+    goto EXIT;
+  }
+
+  if (IsPasswordCleared()) {
+    DEBUG ((DEBUG_INFO, "IsPasswordCleared\n"));
+    SavePasswordToVariable (&gAdminAuthenticationGuid, NULL, 0);
+  }
+
+  return EFI_SUCCESS;
+
+EXIT:
+  if (SmmHandle != NULL) {
+    gSmst->SmiHandlerUnRegister (SmmHandle);
+  }
+
+  return Status;
+}
+
diff --git a/SecurityPkg/Password/UserAuthentication/UserAuthenticationSmm.inf b/SecurityPkg/Password/UserAuthentication/UserAuthenticationSmm.inf
new file mode 100644
index 0000000..460809b
--- /dev/null
+++ b/SecurityPkg/Password/UserAuthentication/UserAuthenticationSmm.inf
@@ -0,0 +1,70 @@
+## @file
+#  User Authentication Smm Driver.
+#
+#  This driver provides SMM services for DXE user authentication module.
+#
+# Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+#
+#  This program and the accompanying materials
+#  are licensed and made available under the terms and conditions of the BSD License
+#  which accompanies this distribution. The full text of the license may be found at
+#  http://opensource.org/licenses/bsd-license.php
+#
+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = UserAuthenticationSmm
+  MODULE_UNI_FILE                = UserAuthenticationSmm.uni
+  FILE_GUID                      = 458B03ED-6E53-414f-9F07-3A829C990641
+  MODULE_TYPE                    = DXE_SMM_DRIVER
+  VERSION_STRING                 = 1.0
+  PI_SPECIFICATION_VERSION       = 0x0001000A
+  ENTRY_POINT                    = PasswordSmmInit
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC
+#
+
+[Sources]
+  UserAuthenticationSmm.c
+  UserAuthenticationGuid.h
+  KeyService.c
+  KeyService.h
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  CryptoPkg/CryptoPkg.dec
+  SecurityPkg/SecurityPkg.dec
+
+[LibraryClasses]
+  UefiBootServicesTableLib
+  UefiDriverEntryPoint
+  DebugLib
+  BaseLib
+  BaseMemoryLib
+  PrintLib
+  SmmServicesTableLib
+  MemoryAllocationLib
+  UefiLib
+  BaseCryptLib
+  PlatformPasswordLib
+
+[Protocols]
+  gEdkiiVariableLockProtocolGuid                ## CONSUMES
+  gEfiSmmVariableProtocolGuid                   ## CONSUMES
+
+[Depex]
+  gEfiSmmVariableProtocolGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+  UserAuthenticationDxeExtra.uni
+
+
diff --git a/SecurityPkg/Password/UserAuthentication/UserAuthenticationSmm.uni b/SecurityPkg/Password/UserAuthentication/UserAuthenticationSmm.uni
new file mode 100644
index 0000000..470c75c
--- /dev/null
+++ b/SecurityPkg/Password/UserAuthentication/UserAuthenticationSmm.uni
@@ -0,0 +1,22 @@
+// /** @file
+// User Authentication Smm Driver.
+//
+// This driver provides SMM services for DXE user authentication module.
+//
+// Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+//
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT             #language en-US "SMM services for DXE user authentication module."
+
+#string STR_MODULE_DESCRIPTION          #language en-US "This driver provides SMM services for DXE user authentication module."
+
diff --git a/SecurityPkg/Password/UserAuthentication/UserAuthenticationSmmExtra.uni b/SecurityPkg/Password/UserAuthentication/UserAuthenticationSmmExtra.uni
new file mode 100644
index 0000000..5e338fe
--- /dev/null
+++ b/SecurityPkg/Password/UserAuthentication/UserAuthenticationSmmExtra.uni
@@ -0,0 +1,20 @@
+// /** @file
+// User Authentication Smm Driver.
+//
+// Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+//
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"User Authentication SMM Driver"
+
+
-- 
2.7.4.windows.1

_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel
Re: [edk2] [PATCH V2 5/6] SecurityPkg/Password: Add Password based UserAuthentication modules.
Posted by Long, Qin 7 years, 8 months ago
Some comments:
1. I didn't see any usage of KeyLibGenerateLib interface. Remove or just designed for future usage?
2. Why need one extra KeyLibSlowCompareMem? Instead of using one in BaseMemoryLib?
     And if necessary, please add extra ASSERT handling as the comments.

Reviewed-by: Qin Long <qin.long@intel.com>

Best Regards & Thanks,
LONG, Qin


> -----Original Message-----
> From: Yao, Jiewen
> Sent: Tuesday, February 7, 2017 12:24 AM
> To: edk2-devel@lists.01.org
> Cc: Long, Qin <qin.long@intel.com>; Zhang, Chao B
> <chao.b.zhang@intel.com>
> Subject: [PATCH V2 5/6] SecurityPkg/Password: Add Password based
> UserAuthentication modules.
> 
> This password based user authentication is to verify user when a user
> wants to enter BIOS setup page.
> 
> The DXE driver registers report status code listener.
> When it gets (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_PC_USER_SETUP)
> progress
> code, it will let the user input password.
> If and only if the user inputs the right password, the status code handler
> will return and let the setup driver continue running.
> If the user inputs the wrong password, the status code handler will let
> user try again.
> If the user inputs the wrong password 3 times, the status code handler will
> reset the system.
> 
> The DXE driver also register a setup page in setup browser, so that
> user may update the password.
> 
> The DXE driver uses SMI to let SMM driver do the password verification
> and management.
> 
> The SMM driver registers SMI handler to perform the request from DXE.
> The password must meet below criteria:
> 1) Length >= 8 char
> 2) It must include lower case, upper case, number and symbol.
> 3) It must not duplicate with 5 previous password.
> If above criteria is met, the password will be saved to a read only UEFI
> variable. The format is password hash+salt, which is generated by
> Pkcs5HashPassword algorithm (SHA256+1000 iteration).
> 
> If the SMM driver gets wrong password 3 times, the interface is locked
> and does not accept more request.
> 
> If the SMM driver will detect IsPasswordCleared() at the entry point and
> clear the password if IsPasswordCleared() is TRUE. This can be used when
> the user forgets the password.
> 
> Cc: Qin Long <qin.long@intel.com>
> Cc: Chao Zhang <chao.b.zhang@intel.com>
> Contributed-under: TianoCore Contribution Agreement 1.0
> Signed-off-by: Jiewen Yao <jiewen.yao@intel.com>
> ---
>  SecurityPkg/Password/UserAuthentication/KeyService.c                     | 210
> ++++++
>  SecurityPkg/Password/UserAuthentication/KeyService.h                     | 122
> ++++
>  SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.c          |
> 718 ++++++++++++++++++++
>  SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.h          |
> 115 ++++
>  SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.inf        |
> 79 +++
>  SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.uni        |
> 22 +
>  SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeExtra.uni
> |  20 +
> 
> SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeFormset.
> h   |  30 +
> 
> SecurityPkg/Password/UserAuthentication/UserAuthenticationDxePasswor
> d.c  | 301 ++++++++
> 
> SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeStrings.u
> ni |  29 +
>  SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeVfr.vfr
> |  38 ++
>  SecurityPkg/Password/UserAuthentication/UserAuthenticationGuid.h         |
> 65 ++
>  SecurityPkg/Password/UserAuthentication/UserAuthenticationSmm.c          |
> 672 ++++++++++++++++++
>  SecurityPkg/Password/UserAuthentication/UserAuthenticationSmm.inf
> |  70 ++
>  SecurityPkg/Password/UserAuthentication/UserAuthenticationSmm.uni
> |  22 +
> 
> SecurityPkg/Password/UserAuthentication/UserAuthenticationSmmExtra.un
> i   |  20 +
>  16 files changed, 2533 insertions(+)
> 
> diff --git a/SecurityPkg/Password/UserAuthentication/KeyService.c
> b/SecurityPkg/Password/UserAuthentication/KeyService.c
> new file mode 100644
> index 0000000..81aa2f9
> --- /dev/null
> +++ b/SecurityPkg/Password/UserAuthentication/KeyService.c
> @@ -0,0 +1,210 @@
> +/** @file
> +  Password key service.
> +
> +Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
> +This program and the accompanying materials
> +are licensed and made available under the terms and conditions of the BSD
> License
> +which accompanies this distribution.  The full text of the license may be
> found at
> +http://opensource.org/licenses/bsd-license.php
> +
> +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +
> +**/
> +
> +#include <Uefi.h>
> +#include <Library/DebugLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/BaseCryptLib.h>
> +#include "KeyService.h"
> +
> +#define DEFAULT_AES_KEY_BIT_SIZE       256
> +#define DEFAULT_PBKDF2_ITERATION_COUNT 1000
> +
> +/**
> +  Compares the contents of two buffers with slow algorithm
> +
> +  This function compares Length bytes of SourceBuffer to Length bytes of
> DestinationBuffer.
> +  If all Length bytes of the two buffers are identical, then 0 is returned.
> Otherwise, the
> +  value returned is the first mismatched byte in SourceBuffer subtracted
> from the first
> +  mismatched byte in DestinationBuffer.
> +
> +  If Length > 0 and DestinationBuffer is NULL, then ASSERT().
> +  If Length > 0 and SourceBuffer is NULL, then ASSERT().
> +  If Length is greater than (MAX_ADDRESS - DestinationBuffer + 1), then
> ASSERT().
> +  If Length is greater than (MAX_ADDRESS - SourceBuffer + 1), then
> ASSERT().
> +
> +  @param  DestinationBuffer The pointer to the destination buffer to
> compare.
> +  @param  SourceBuffer      The pointer to the source buffer to compare.
> +  @param  Length            The number of bytes to compare.
> +
> +  @return 0                 All Length bytes of the two buffers are identical.
> +  @retval -1                The SourceBuffer is not identical to DestinationBuffer.
> +
> +**/
> +INTN
> +EFIAPI
> +KeyLibSlowCompareMem (
> +  IN CONST VOID  *DestinationBuffer,
> +  IN CONST VOID  *SourceBuffer,
> +  IN UINTN       Length
> +  )
> +{
> +  UINT8  Delta;
> +  UINTN  Index;
> +  UINT8  *Destination;
> +  UINT8  *Source;
> +
> +  Destination = (UINT8 *)DestinationBuffer;
> +  Source = (UINT8 *)SourceBuffer;
> +  Delta = 0;
> +  for (Index = 0; Index < Length; Index++) {
> +    Delta |= Destination[Index] ^ Source[Index];
> +  }
> +  if (Delta == 0) {
> +    return 0;
> +  } else {
> +    return -1;
> +  }
> +}
> +
> +/**
> +  Generate Salt value.
> +
> +  @param[in, out]   SaltValue           Points to the salt buffer
> +  @param[in]        SaltSize            Size of the salt buffer
> +
> +  @retval      TRUE           Salt is generated.
> +  @retval      FALSE          Salt is not generated.
> +**/
> +BOOLEAN
> +EFIAPI
> +KeyLibGenerateSalt (
> +  IN OUT UINT8  *SaltValue,
> +  IN UINTN      SaltSize
> +  )
> +{
> +  if (SaltValue == NULL) {
> +    return FALSE;
> +  }
> +  RandomSeed(NULL, 0);
> +  RandomBytes(SaltValue, SaltSize);
> +  return TRUE;
> +}
> +
> +/**
> +  Hash the data.
> +
> +  @param[in]   HashType         Hash type
> +  @param[in]   Key              Points to the key buffer
> +  @param[in]   KeySize          Key buffer size
> +  @param[in]   SaltValue        Points to the salt buffer
> +  @param[in]   SaltSize         Size of the salt buffer
> +  @param[out]  KeyHash          Points to the hashed result
> +  @param[in]   KeyHashSize      Size of the hash buffer
> +
> +  @retval      TRUE           Hash the data successfully.
> +  @retval      FALSE          Failed to hash the data.
> +
> +**/
> +BOOLEAN
> +EFIAPI
> +KeyLibGenerateHash(
> +  IN   UINT32              HashType,
> +  IN   VOID                *Key,
> +  IN   UINTN               KeySize,
> +  IN   UINT8               *SaltValue,
> +  IN   UINTN               SaltSize,
> +  OUT  UINT8               *KeyHash,
> +  IN   UINTN               KeyHashSize
> +  )
> +{
> +  BOOLEAN                     Status;
> +  UINTN                       HashSize;
> +  VOID                        *HashContext;
> +
> +  if (HashType != HASH_TYPE_SHA256) {
> +    return FALSE;
> +  }
> +  if (KeyHashSize != SHA256_DIGEST_SIZE) {
> +    return FALSE;
> +  }
> +
> +  if ((Key == NULL) || (SaltValue == NULL) || (KeyHash == NULL)) {
> +    return FALSE;
> +  }
> +
> +  HashSize    = Sha256GetContextSize ();
> +  HashContext = AllocateZeroPool (HashSize);
> +  if (HashContext == NULL) {
> +    return FALSE;
> +  }
> +
> +  Status = Sha256Init(HashContext);
> +  if (!Status) {
> +    goto Done;
> +  }
> +
> +  Status = Sha256Update(HashContext, SaltValue, SaltSize);
> +  if (!Status) {
> +    goto Done;
> +  }
> +  Status = Sha256Update(HashContext, Key, KeySize);
> +  if (!Status) {
> +    goto Done;
> +  }
> +
> +  Status = Sha256Final(HashContext, KeyHash);
> +Done:
> +  FreePool (HashContext);
> +  return Status;
> +}
> +
> +/**
> +  Hash the password with PBKDF2.
> +
> +  @param[in]   HashType         Hash type
> +  @param[in]   Key              Points to the key buffer
> +  @param[in]   KeySize          Key buffer size
> +  @param[in]   SaltValue        Points to the salt buffer
> +  @param[in]   SaltSize         Size of the salt buffer
> +  @param[out]  KeyHash          Points to the hashed result
> +  @param[in]   KeyHashSize      Size of the hash buffer
> +
> +  @retval      TRUE           Hash the data successfully.
> +  @retval      FALSE          Failed to hash the data.
> +
> +**/
> +BOOLEAN
> +EFIAPI
> +KeyLibGeneratePBKDF2Hash (
> +  IN   UINT32              HashType,
> +  IN   VOID                *Key,
> +  IN   UINTN               KeySize,
> +  IN   UINT8               *SaltValue,
> +  IN   UINTN               SaltSize,
> +  OUT  UINT8               *KeyHash,
> +  IN   UINTN               KeyHashSize
> +  )
> +{
> +  BOOLEAN  Result;
> +
> +  if (HashType != HASH_TYPE_SHA256) {
> +    return FALSE;
> +  }
> +  if (KeyHashSize != SHA256_DIGEST_SIZE) {
> +    return FALSE;
> +  }
> +
> +  Result = Pkcs5HashPassword (
> +             KeySize,
> +             Key,
> +             SaltSize,
> +             SaltValue,
> +             DEFAULT_PBKDF2_ITERATION_COUNT,
> +             SHA256_DIGEST_SIZE,
> +             KeyHashSize,
> +             KeyHash
> +             );
> +  return Result;
> +}
> diff --git a/SecurityPkg/Password/UserAuthentication/KeyService.h
> b/SecurityPkg/Password/UserAuthentication/KeyService.h
> new file mode 100644
> index 0000000..f287953
> --- /dev/null
> +++ b/SecurityPkg/Password/UserAuthentication/KeyService.h
> @@ -0,0 +1,122 @@
> +/** @file
> +  Header file for key service.
> +
> +  Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
> +  This program and the accompanying materials
> +  are licensed and made available under the terms and conditions of the BSD
> License
> +  which accompanies this distribution.  The full text of the license may be
> found at
> +  http://opensource.org/licenses/bsd-license.php
> +
> +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +
> +**/
> +
> +#ifndef __KEY_LIB_H__
> +#define __KEY_LIB_H__
> +
> +/**
> +  Compares the contents of two buffers with slow algorithm
> +
> +  This function compares Length bytes of SourceBuffer to Length bytes of
> DestinationBuffer.
> +  If all Length bytes of the two buffers are identical, then 0 is returned.
> Otherwise, the
> +  value returned is the first mismatched byte in SourceBuffer subtracted
> from the first
> +  mismatched byte in DestinationBuffer.
> +
> +  If Length > 0 and DestinationBuffer is NULL, then ASSERT().
> +  If Length > 0 and SourceBuffer is NULL, then ASSERT().
> +  If Length is greater than (MAX_ADDRESS - DestinationBuffer + 1), then
> ASSERT().
> +  If Length is greater than (MAX_ADDRESS - SourceBuffer + 1), then
> ASSERT().
> +
> +  @param  DestinationBuffer The pointer to the destination buffer to
> compare.
> +  @param  SourceBuffer      The pointer to the source buffer to compare.
> +  @param  Length            The number of bytes to compare.
> +
> +  @return 0                 All Length bytes of the two buffers are identical.
> +  @retval -1                The SourceBuffer is not identical to DestinationBuffer.
> +
> +**/
> +INTN
> +EFIAPI
> +KeyLibSlowCompareMem (
> +  IN CONST VOID  *DestinationBuffer,
> +  IN CONST VOID  *SourceBuffer,
> +  IN UINTN       Length
> +  );
> +
> +/**
> +  Generate Salt value.
> +
> +  @param[in, out]   SaltValue           Points to the salt buffer
> +  @param[in]        SaltSize            Size of the salt buffer
> +
> +  @retval      TRUE           Salt is generated.
> +  @retval      FALSE          Salt is not generated.
> +**/
> +BOOLEAN
> +EFIAPI
> +KeyLibGenerateSalt(
> +  IN OUT UINT8  *SaltValue,
> +  IN UINTN      SaltSize
> +  );
> +
> +#define HASH_TYPE_SHA256  0x000B
> +
> +#define SHA256_DIGEST_SIZE 32
> +
> +/**
> +  Hash the data.
> +
> +  @param[in]   HashType         Hash type
> +  @param[in]   Key              Points to the key buffer
> +  @param[in]   KeySize          Key buffer size
> +  @param[in]   SaltValue        Points to the salt buffer
> +  @param[in]   SaltSize         Size of the salt buffer
> +  @param[out]  KeyHash          Points to the hashed result
> +  @param[in]   KeyHashSize      Size of the hash buffer
> +
> +  @retval      TRUE           Hash the data successfully.
> +  @retval      FALSE          Failed to hash the data.
> +
> +**/
> +BOOLEAN
> +EFIAPI
> +KeyLibGenerateHash(
> +  IN   UINT32              HashType,
> +  IN   VOID                *Key,
> +  IN   UINTN               KeySize,
> +  IN   UINT8               *SaltValue,
> +  IN   UINTN               SaltSize,
> +  OUT  UINT8               *KeyHash,
> +  IN   UINTN               KeyHashSize
> +  );
> +
> +/**
> +  Hash the password with PBKDF2.
> +
> +  @param[in]   HashType         Hash type
> +  @param[in]   Key              Points to the key buffer
> +  @param[in]   KeySize          Key buffer size
> +  @param[in]   SaltValue        Points to the salt buffer
> +  @param[in]   SaltSize         Size of the salt buffer
> +  @param[out]  KeyHash          Points to the hashed result
> +  @param[in]   KeyHashSize      Size of the hash buffer
> +
> +  @retval      TRUE           Hash the data successfully.
> +  @retval      FALSE          Failed to hash the data.
> +
> +**/
> +BOOLEAN
> +EFIAPI
> +KeyLibGeneratePBKDF2Hash (
> +  IN   UINT32              HashType,
> +  IN   VOID                *Key,
> +  IN   UINTN               KeySize,
> +  IN   UINT8               *SaltValue,
> +  IN   UINTN               SaltSize,
> +  OUT  UINT8               *KeyHash,
> +  IN   UINTN               KeyHashSize
> +  );
> +
> +#endif
> +
> diff --git
> a/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.c
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.c
> new file mode 100644
> index 0000000..3836eac
> --- /dev/null
> +++ b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.c
> @@ -0,0 +1,718 @@
> +/** @file
> +  This Driver mainly do user authentication before entering Setup.
> +
> +Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
> +This program and the accompanying materials
> +are licensed and made available under the terms and conditions of the BSD
> License
> +which accompanies this distribution.  The full text of the license may be
> found at
> +http://opensource.org/licenses/bsd-license.php
> +
> +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +
> +**/
> +
> +#include "UserAuthenticationDxe.h"
> +
> +EFI_EVENT                           mExitBootServicesEvent  = NULL;
> +EFI_RSC_HANDLER_PROTOCOL           *mRscHandlerProtocol     = NULL;
> +USER_AUTHENTICATION_PRIVATE_DATA   *mUserAuthenticationData =
> NULL;
> +
> +UINTN  mAdminPasswordTryCount;
> +
> +EFI_GUID gAdminAuthenticationGuid = ADMIN_AUTHENTICATION_GUID;
> +
> +HII_VENDOR_DEVICE_PATH  mHiiVendorDevicePath = {
> +  {
> +    {
> +      HARDWARE_DEVICE_PATH,
> +      HW_VENDOR_DP,
> +      {
> +        (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
> +        (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
> +      }
> +    },
> +    USER_AUTHENTICATION_FORMSET_GUID
> +  },
> +  {
> +    END_DEVICE_PATH_TYPE,
> +    END_ENTIRE_DEVICE_PATH_SUBTYPE,
> +    {
> +      (UINT8) (END_DEVICE_PATH_LENGTH),
> +      (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
> +    }
> +  }
> +};
> +
> +/**
> +  Get a user input string.
> +
> +  @param[in]       PopUpString      A popup string to inform user.
> +  @param[in, out]  UserInput        The user input string
> +  @param[in]       UserInputMaxLen  The max unicode count of the
> UserInput without NULL terminator.
> +**/
> +EFI_STATUS
> +GetUserInput (
> +  IN     CHAR16      *PopUpString,
> +  IN OUT CHAR16      *UserInput,
> +  IN     UINTN       UserInputMaxLen
> +  )
> +{
> +  EFI_INPUT_KEY                InputKey;
> +  UINTN                        InputLength;
> +  CHAR16                       *Mask;
> +
> +  UserInput[0] = 0;
> +  Mask = AllocateZeroPool ((UserInputMaxLen + 1) * sizeof(CHAR16));
> +  if (Mask == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  InputLength = 0;
> +
> +  while (TRUE) {
> +    Mask[InputLength] = L'_';
> +    CreatePopUp (
> +      EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
> +      &InputKey,
> +      PopUpString,
> +      L"---------------------",
> +      Mask,
> +      NULL
> +      );
> +    if (InputKey.ScanCode == SCAN_NULL) {
> +      //
> +      // Check whether finish inputing password.
> +      //
> +      if (InputKey.UnicodeChar == CHAR_CARRIAGE_RETURN && InputLength >
> 0) {
> +        //
> +        // Add the null terminator.
> +        //
> +        UserInput[InputLength] = 0;
> +        break;
> +      } else if ((InputKey.UnicodeChar == CHAR_NULL) ||
> +                 (InputKey.UnicodeChar == CHAR_TAB) ||
> +                 (InputKey.UnicodeChar == CHAR_LINEFEED) ||
> +                 (InputKey.UnicodeChar == CHAR_CARRIAGE_RETURN)
> +                ) {
> +        continue;
> +      } else {
> +        //
> +        // delete last key entered
> +        //
> +        if (InputKey.UnicodeChar == CHAR_BACKSPACE) {
> +          if (InputLength > 0) {
> +            UserInput[InputLength] = 0;
> +            Mask[InputLength] = 0;
> +            InputLength--;
> +          }
> +        } else {
> +          //
> +          // add Next key entry
> +          //
> +          UserInput[InputLength] = InputKey.UnicodeChar;
> +          Mask[InputLength] = L'*';
> +          InputLength++;
> +          if (InputLength == UserInputMaxLen) {
> +            //
> +            // Add the null terminator.
> +            //
> +            UserInput[InputLength] = 0;
> +            Mask[InputLength] = 0;
> +            break;
> +          }
> +        }
> +      }
> +    }
> +  }
> +  FreePool (Mask);
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Display a message box to end user.
> +
> +  @param[in] DisplayString   The string in message box.
> +**/
> +VOID
> +MessageBox (
> +  IN CHAR16  *DisplayString
> +  )
> +{
> +  EFI_INPUT_KEY  Key;
> +
> +  do {
> +    CreatePopUp (
> +      EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
> +      &Key,
> +      L"",
> +      DisplayString,
> +      L"Press ENTER to continue ...",
> +      L"",
> +      NULL
> +      );
> +  } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
> +}
> +
> +/**
> +  Force system reset.
> +**/
> +VOID
> +ForceSystemReset (
> +  VOID
> +  )
> +{
> +  MessageBox (L"Password retry count reach, reset system!");
> +  gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);
> +  CpuDeadLoop();
> +}
> +
> +/**
> +  Display message for set password.
> +
> +  @param[in]  ReturnStatus   The return status for set password.
> +**/
> +VOID
> +PrintPasswordStatus (
> +  IN EFI_STATUS  ReturnStatus
> +  )
> +{
> +  CHAR16         *DisplayString;
> +
> +  if (ReturnStatus == EFI_SUCCESS) {
> +    DisplayString = L"New password is updated successfully!";
> +  } else if (ReturnStatus == EFI_UNSUPPORTED) {
> +    DisplayString = L"New password is not strong enough!";
> +  } else if (ReturnStatus == EFI_ALREADY_STARTED) {
> +    DisplayString = L"New password is found in history!";
> +  } else {
> +    DisplayString = L"New password update fails!";
> +  }
> +
> +  MessageBox (DisplayString);
> +}
> +
> +/**
> +  Require user input password.
> +
> +  @param[in]  UserGuid               The user GUID of the password.
> +
> +  @retval TRUE   User input correct password successfully.
> +  @retval FALSE  The password is not set.
> +**/
> +BOOLEAN
> +RequireUserPassword (
> +  IN   EFI_GUID     *UserGuid
> +  )
> +{
> +  EFI_STATUS                   Status;
> +  CHAR16                       UserInputPw[MAX_PASSWORD_LEN + 1];
> +  CHAR16                       TmpPassword[MAX_PASSWORD_LEN + 1];
> +  CHAR16                       *PopUpString;
> +  UINTN                        *PasswordTryCount;
> +
> +  Status = EFI_SUCCESS;
> +  ZeroMem(UserInputPw, sizeof(UserInputPw));
> +  ZeroMem(TmpPassword, sizeof(TmpPassword));
> +
> +  if (!IsPasswordSet(UserGuid)) {
> +    return FALSE;
> +  }
> +
> +  if (CompareGuid (UserGuid, &gAdminAuthenticationGuid)) {
> +    PopUpString = L"Please input admin password";
> +    PasswordTryCount = &mAdminPasswordTryCount;
> +  } else {
> +    DEBUG ((DEBUG_ERROR, "Invalid User Guid - %g\n", UserGuid));
> +    return FALSE;
> +  }
> +
> +  while (TRUE) {
> +    gST->ConOut->ClearScreen(gST->ConOut);
> +    GetUserInput (PopUpString, UserInputPw, MAX_PASSWORD_LEN);
> +
> +    CopyGuid (UserGuid, &gAdminAuthenticationGuid);
> +    Status = ValidatePassword (UserGuid, UserInputPw,
> StrSize(UserInputPw));
> +    if (!EFI_ERROR(Status)) {
> +      break;
> +    }
> +    *PasswordTryCount = *PasswordTryCount + 1;
> +    if (*PasswordTryCount >= PASSWORD_MAX_TRY_COUNT) {
> +      ForceSystemReset ();
> +    }
> +    MessageBox (L"Incorrect password!");
> +  }
> +  *PasswordTryCount = 0;
> +
> +  ZeroMem(UserInputPw, sizeof(UserInputPw));
> +  ZeroMem(TmpPassword, sizeof(TmpPassword));
> +
> +  gST->ConOut->ClearScreen(gST->ConOut);
> +
> +  return TRUE;
> +}
> +
> +/**
> +  Set user password.
> +
> +  @param[in]  UserGuid               The user GUID of the password.
> +
> +  @retval TRUE   The password is set.
> +  @retval FALSE  The password is not set.
> +**/
> +BOOLEAN
> +SetUserPassword (
> +  IN   EFI_GUID     *UserGuid
> +  )
> +{
> +  EFI_STATUS                   Status;
> +  CHAR16                       UserInputPw[MAX_PASSWORD_LEN + 1];
> +  CHAR16                       TmpPassword[MAX_PASSWORD_LEN + 1];
> +  CHAR16                       *PopUpString;
> +  CHAR16                       *PopUpString2;
> +
> +  Status = EFI_SUCCESS;
> +  ZeroMem(UserInputPw, sizeof(UserInputPw));
> +  ZeroMem(TmpPassword, sizeof(TmpPassword));
> +
> +  if (CompareGuid (UserGuid, &gAdminAuthenticationGuid)) {
> +    PopUpString = L"Please set admin password";
> +  } else {
> +    DEBUG ((DEBUG_ERROR, "Invalid User Guid - %g\n", UserGuid));
> +    return FALSE;
> +  }
> +
> +  while (TRUE) {
> +    gST->ConOut->ClearScreen(gST->ConOut);
> +    GetUserInput (PopUpString, UserInputPw, MAX_PASSWORD_LEN);
> +
> +    PopUpString2 = L"Please confirm your new password";
> +    gST->ConOut->ClearScreen(gST->ConOut);
> +    GetUserInput (PopUpString2, TmpPassword, MAX_PASSWORD_LEN);
> +    if (StrCmp (TmpPassword, UserInputPw) != 0) {
> +      MessageBox (L"Password are not the same!");
> +      continue;
> +    }
> +
> +    Status = SetPassword (UserGuid, UserInputPw, StrSize(UserInputPw),
> NULL, 0);
> +    PrintPasswordStatus (Status);
> +    if (!EFI_ERROR(Status)) {
> +      break;
> +    }
> +  }
> +
> +  ZeroMem(UserInputPw, sizeof(UserInputPw));
> +  ZeroMem(TmpPassword, sizeof(TmpPassword));
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Check password before entering into setup.
> +
> +  @param  CodeType      Indicates the type of status code being reported.
> Type EFI_STATUS_CODE_TYPE is defined in "Related Definitions" below.
> +
> +  @param  Value         Describes the current status of a hardware or software
> entity.
> +                        This included information about the class and subclass that is
> used to classify the entity
> +                        as well as an operation.  For progress codes, the operation is the
> current activity.
> +                        For error codes, it is the exception.  For debug codes, it is not
> defined at this time.
> +                        Type EFI_STATUS_CODE_VALUE is defined in "Related
> Definitions" below.
> +                        Specific values are discussed in the Intel? Platform Innovation
> Framework for EFI Status Code Specification.
> +
> +  @param  Instance      The enumeration of a hardware or software entity
> within the system.
> +                        A system may contain multiple entities that match a
> class/subclass pairing.
> +                        The instance differentiates between them.  An instance of 0
> indicates that instance information is unavailable,
> +                        not meaningful, or not relevant.  Valid instance numbers start
> with 1.
> +
> +
> +  @param  CallerId      This optional parameter may be used to identify the
> caller.
> +                        This parameter allows the status code driver to apply different
> rules to different callers.
> +                        Type EFI_GUID is defined in InstallProtocolInterface() in the
> UEFI 2.0 Specification.
> +
> +
> +  @param  Data          This optional parameter may be used to pass additional
> data
> +
> +  @retval EFI_SUCCESS             Status code is what we expected.
> +  @retval EFI_UNSUPPORTED         Status code not supported.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +CheckForPassword (
> +  IN EFI_STATUS_CODE_TYPE     CodeType,
> +  IN EFI_STATUS_CODE_VALUE    Value,
> +  IN UINT32                   Instance,
> +  IN EFI_GUID                 *CallerId, OPTIONAL
> +  IN EFI_STATUS_CODE_DATA     *Data      OPTIONAL
> +  )
> +{
> +  BOOLEAN   PasswordSet;
> +
> +  if (((CodeType & EFI_STATUS_CODE_TYPE_MASK) ==
> EFI_PROGRESS_CODE) &&
> +      (Value == (EFI_SOFTWARE_DXE_BS_DRIVER |
> EFI_SW_PC_USER_SETUP))) {
> +    //
> +    // Check whether enter setup page.
> +    //
> +    PasswordSet = RequireUserPassword (&gAdminAuthenticationGuid);
> +    if (PasswordSet) {
> +      DEBUG ((DEBUG_INFO, "Welcome Admin!\n"));
> +    } else {
> +      DEBUG ((DEBUG_INFO, "Admin password is not set!\n"));
> +      if (NeedEnrollPassword()) {
> +        SetUserPassword (&gAdminAuthenticationGuid);
> +      }
> +    }
> +
> +    return EFI_SUCCESS;
> +  } else{
> +    return EFI_UNSUPPORTED;
> +  }
> +}
> +
> +/**
> +  This function allows a caller to extract the current configuration for one
> +  or more named elements from the target driver.
> +
> +  @param  This                   Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
> +  @param  Request                A null-terminated Unicode string in
> +                                 <ConfigRequest> format.
> +  @param  Progress               On return, points to a character in the Request
> +                                 string. Points to the string's null terminator if
> +                                 request was successful. Points to the most recent
> +                                 '&' before the first failing name/value pair (or
> +                                 the beginning of the string if the failure is in
> +                                 the first name/value pair) if the request was not
> +                                 successful.
> +  @param  Results                A null-terminated Unicode string in
> +                                 <ConfigAltResp> format which has all values filled
> +                                 in for the names in the Request string. String to
> +                                 be allocated by the called function.
> +
> +  @retval EFI_SUCCESS            The Results is filled with the requested values.
> +  @retval EFI_OUT_OF_RESOURCES   Not enough memory to store the
> results.
> +  @retval EFI_INVALID_PARAMETER  Request is illegal syntax, or unknown
> name.
> +  @retval EFI_NOT_FOUND          Routing data doesn't match any storage in
> this
> +                                 driver.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ExtractConfig (
> +  IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
> +  IN  CONST EFI_STRING                       Request,
> +  OUT EFI_STRING                             *Progress,
> +  OUT EFI_STRING                             *Results
> +  )
> +{
> +  if (Progress == NULL || Results == NULL) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +  *Progress = Request;
> +  return EFI_NOT_FOUND;
> +}
> +
> +
> +/**
> +  This function processes the results of changes in configuration.
> +
> +  @param  This                   Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
> +  @param  Configuration          A null-terminated Unicode string in
> <ConfigResp>
> +                                 format.
> +  @param  Progress               A pointer to a string filled in with the offset of
> +                                 the most recent '&' before the first failing
> +                                 name/value pair (or the beginning of the string if
> +                                 the failure is in the first name/value pair) or
> +                                 the terminating NULL if all was successful.
> +
> +  @retval EFI_SUCCESS            The Results is processed successfully.
> +  @retval EFI_INVALID_PARAMETER  Configuration is NULL.
> +  @retval EFI_NOT_FOUND          Routing data doesn't match any storage in
> this
> +                                 driver.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RouteConfig (
> +  IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
> +  IN  CONST EFI_STRING                       Configuration,
> +  OUT EFI_STRING                             *Progress
> +  )
> +{
> +  if (Configuration == NULL || Progress == NULL) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  *Progress = Configuration;
> +
> +  return EFI_NOT_FOUND;
> +}
> +
> +/**
> +  This function processes the results of changes in configuration.
> +
> +  @param  This                   Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
> +  @param  Action                 Specifies the type of action taken by the browser.
> +  @param  QuestionId             A unique value which is sent to the original
> +                                 exporting driver so that it can identify the type
> +                                 of data to expect.
> +  @param  Type                   The type of value for the question.
> +  @param  Value                  A pointer to the data being sent to the original
> +                                 exporting driver.
> +  @param  ActionRequest          On return, points to the action requested by
> the
> +                                 callback function.
> +
> +  @retval EFI_SUCCESS            The callback successfully handled the action.
> +  @retval EFI_OUT_OF_RESOURCES   Not enough storage is available to hold
> the
> +                                 variable and its data.
> +  @retval EFI_DEVICE_ERROR       The variable could not be saved.
> +  @retval EFI_UNSUPPORTED        The specified Action is not supported by
> the
> +                                 callback.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +UserAuthenticationCallback (
> +  IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
> +  IN  EFI_BROWSER_ACTION                     Action,
> +  IN  EFI_QUESTION_ID                        QuestionId,
> +  IN  UINT8                                  Type,
> +  IN  EFI_IFR_TYPE_VALUE                     *Value,
> +  OUT EFI_BROWSER_ACTION_REQUEST             *ActionRequest
> +  )
> +{
> +  EFI_STATUS  Status;
> +  CHAR16      *UserInputPassword;
> +  EFI_GUID    *UserGuid;
> +  UINTN       *PasswordTryCount;
> +
> +  Status = EFI_SUCCESS;
> +
> +  if (((Value == NULL) && (Action != EFI_BROWSER_ACTION_FORM_OPEN)
> && (Action != EFI_BROWSER_ACTION_FORM_CLOSE))||
> +      (ActionRequest == NULL)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  switch (Action) {
> +  case EFI_BROWSER_ACTION_CHANGING:
> +    {
> +      switch (QuestionId) {
> +      case ADMIN_PASSWORD_KEY_ID:
> +        UserGuid = &gAdminAuthenticationGuid;
> +        PasswordTryCount = &mAdminPasswordTryCount;
> +        if ((Type == EFI_IFR_TYPE_STRING) && (Value->string == 0) &&
> +            (mUserAuthenticationData->PasswordState ==
> BROWSER_STATE_SET_PASSWORD)) {
> +          mUserAuthenticationData->PasswordState =
> BROWSER_STATE_VALIDATE_PASSWORD;
> +          ZeroMem (mUserAuthenticationData->OldPassword,
> sizeof(mUserAuthenticationData->OldPassword));
> +          return EFI_INVALID_PARAMETER;
> +        }
> +        //
> +        // The Callback is responsible for validating old password input by user,
> +        // If Callback return EFI_SUCCESS, it indicates validation pass.
> +        //
> +        switch (mUserAuthenticationData->PasswordState) {
> +        case BROWSER_STATE_VALIDATE_PASSWORD:
> +          UserInputPassword = HiiGetString (mUserAuthenticationData-
> >HiiHandle, Value->string, NULL);
> +          if ((StrLen (UserInputPassword) >= PASSWORD_MAX_SIZE) ||
> (UserInputPassword[0] == 0)) {
> +            Status = EFI_NOT_READY;
> +            break;
> +          }
> +          Status = ValidatePassword (UserGuid, UserInputPassword, StrSize
> (UserInputPassword));
> +          if (Status == EFI_SUCCESS) {
> +            mUserAuthenticationData->PasswordState =
> BROWSER_STATE_SET_PASSWORD;
> +            StrCpyS (
> +              mUserAuthenticationData->OldPassword,
> +              sizeof(mUserAuthenticationData->OldPassword)/sizeof(CHAR16),
> +              UserInputPassword
> +              );
> +            *PasswordTryCount = 0;
> +          } else {
> +            //
> +            // Old password mismatch, return EFI_NOT_READY to prompt for
> error message.
> +            //
> +            Status = EFI_NOT_READY;
> +            *PasswordTryCount = *PasswordTryCount + 1;
> +            if (*PasswordTryCount >= PASSWORD_MAX_TRY_COUNT) {
> +              ForceSystemReset ();
> +            }
> +          }
> +          break;
> +
> +        case BROWSER_STATE_SET_PASSWORD:
> +          UserInputPassword = HiiGetString (mUserAuthenticationData-
> >HiiHandle, Value->string, NULL);
> +          if ((StrLen (UserInputPassword) >= PASSWORD_MAX_SIZE) ||
> (UserInputPassword[0] == 0)) {
> +            Status = EFI_NOT_READY;
> +            break;
> +          }
> +          Status = SetPassword (UserGuid, UserInputPassword, StrSize
> (UserInputPassword), mUserAuthenticationData->OldPassword,
> StrSize(mUserAuthenticationData->OldPassword));
> +          PrintPasswordStatus (Status);
> +          ZeroMem (mUserAuthenticationData->OldPassword,
> sizeof(mUserAuthenticationData->OldPassword));
> +          mUserAuthenticationData->PasswordState =
> BROWSER_STATE_VALIDATE_PASSWORD;
> +          break;
> +
> +        default:
> +          break;
> +        }
> +      default:
> +        break;
> +      }
> +    }
> +  default:
> +    break;
> +  }
> +  return Status;
> +}
> +
> +/**
> +  Unregister status code callback functions.
> +
> +  @param  Event         Event whose notification function is being invoked.
> +  @param  Context       Pointer to the notification function's context, which is
> +                        always zero in current implementation.
> +
> +**/
> +VOID
> +EFIAPI
> +UnregisterBootTimeHandlers (
> +  IN EFI_EVENT        Event,
> +  IN VOID             *Context
> +  )
> +{
> +  mRscHandlerProtocol->Unregister (CheckForPassword);
> +}
> +
> +/**
> +  User Authentication entry point.
> +
> +  @param ImageHandle     The image handle.
> +  @param SystemTable     The system table.
> +
> +  @retval EFI_SUCCESS    The entry point is executed successfully.
> +  @return  other         Contain some other errors.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +UserAuthenticationEntry (
> +  IN EFI_HANDLE           ImageHandle,
> +  IN EFI_SYSTEM_TABLE     *SystemTable
> +  )
> +{
> +  EFI_STATUS        Status;
> +  EFI_HANDLE        DriverHandle;
> +  EFI_HII_HANDLE    HiiHandle;
> +
> +  DriverHandle  = NULL;
> +
> +  mUserAuthenticationData = AllocateZeroPool (sizeof
> (USER_AUTHENTICATION_PRIVATE_DATA));
> +  if (mUserAuthenticationData == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  mUserAuthenticationData->ConfigAccess.ExtractConfig = ExtractConfig;
> +  mUserAuthenticationData->ConfigAccess.RouteConfig = RouteConfig;
> +  mUserAuthenticationData->ConfigAccess.Callback =
> UserAuthenticationCallback;
> +  mUserAuthenticationData->PasswordState =
> BROWSER_STATE_VALIDATE_PASSWORD;
> +
> +  //
> +  // Install Config Access protocol to driver handle.
> +  //
> +  Status = gBS->InstallMultipleProtocolInterfaces (
> +                  &DriverHandle,
> +                  &gEfiDevicePathProtocolGuid,
> +                  &mHiiVendorDevicePath,
> +                  &gEfiHiiConfigAccessProtocolGuid,
> +                  &mUserAuthenticationData->ConfigAccess,
> +                  NULL
> +                  );
> +  ASSERT_EFI_ERROR (Status);
> +  mUserAuthenticationData->DriverHandle = DriverHandle;
> +
> +  //
> +  // Add HII data to database.
> +  //
> +  HiiHandle = HiiAddPackages (
> +                   &gAdminAuthenticationGuid,
> +                   DriverHandle,
> +                   UserAuthenticationDxeStrings,
> +                   UserAuthenticationDxeVfrBin,
> +                   NULL
> +                   );
> +  if (HiiHandle == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +  mUserAuthenticationData->HiiHandle = HiiHandle;
> +
> +  //
> +  // Locate report status code protocol.
> +  //
> +  Status = gBS->LocateProtocol (
> +                  &gEfiRscHandlerProtocolGuid,
> +                  NULL,
> +                  (VOID **) &mRscHandlerProtocol
> +                  );
> +  ASSERT_EFI_ERROR (Status);
> +
> +  //
> +  //Register the callback function for ReportStatusCode() notification.
> +  //
> +  mRscHandlerProtocol->Register (CheckForPassword, TPL_HIGH_LEVEL);
> +
> +  //
> +  // Unregister boot time report status code listener at ExitBootService
> Event.
> +  //
> +  Status = gBS->CreateEventEx (
> +                  EVT_NOTIFY_SIGNAL,
> +                  TPL_NOTIFY,
> +                  UnregisterBootTimeHandlers,
> +                  NULL,
> +                  &gEfiEventExitBootServicesGuid,
> +                  &mExitBootServicesEvent
> +                  );
> +  ASSERT_EFI_ERROR (Status);
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Unloads the application and its installed protocol.
> +
> +  @param[in]  ImageHandle       Handle that identifies the image to be
> unloaded.
> +
> +  @retval EFI_SUCCESS           The image has been unloaded.
> +**/
> +EFI_STATUS
> +EFIAPI
> +UserAuthenticationUnload (
> +  IN EFI_HANDLE  ImageHandle
> +  )
> +{
> +  ASSERT (mUserAuthenticationData != NULL);
> +
> +  //
> +  // Uninstall Config Access Protocol.
> +  //
> +  if (mUserAuthenticationData->DriverHandle != NULL) {
> +    gBS->UninstallMultipleProtocolInterfaces (
> +           mUserAuthenticationData->DriverHandle,
> +           &gEfiDevicePathProtocolGuid,
> +           &mHiiVendorDevicePath,
> +           &gEfiHiiConfigAccessProtocolGuid,
> +           &mUserAuthenticationData->ConfigAccess,
> +           NULL
> +           );
> +    mUserAuthenticationData->DriverHandle = NULL;
> +  }
> +
> +  //
> +  // Remove Hii Data.
> +  //
> +  if (mUserAuthenticationData->HiiHandle != NULL) {
> +    HiiRemovePackages (mUserAuthenticationData->HiiHandle);
> +  }
> +
> +  FreePool (mUserAuthenticationData);
> +  mUserAuthenticationData = NULL;
> +
> +  return EFI_SUCCESS;
> +}
> +
> diff --git
> a/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.h
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.h
> new file mode 100644
> index 0000000..1bcc2a7
> --- /dev/null
> +++ b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.h
> @@ -0,0 +1,115 @@
> +/** @file
> +  Header file for UserAuthenticationDxe.
> +
> +Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
> +This program and the accompanying materials
> +are licensed and made available under the terms and conditions of the BSD
> License
> +which accompanies this distribution.  The full text of the license may be
> found at
> +http://opensource.org/licenses/bsd-license.php
> +
> +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +
> +
> +**/
> +
> +#ifndef _USER_AUTHENTICATION_DXE_H_
> +#define _USER_AUTHENTICATION_DXE_H_
> +
> +
> +#include <Protocol/ReportStatusCodeHandler.h>
> +#include <Protocol/HiiConfigAccess.h>
> +
> +#include <Guid/MdeModuleHii.h>
> +#include <Guid/HiiPlatformSetupFormset.h>
> +
> +#include <Library/DebugLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/UefiRuntimeServicesTableLib.h>
> +#include <Library/UefiDriverEntryPoint.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +#include <Library/BaseLib.h>
> +#include <Library/UefiLib.h>
> +#include <Library/HiiLib.h>
> +#include <Library/DevicePathLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/PlatformPasswordLib.h>
> +#include "UserAuthenticationGuid.h"
> +#include "UserAuthenticationDxeFormset.h"
> +
> +extern UINT8  UserAuthenticationDxeVfrBin[];
> +extern UINT8  UserAuthenticationDxeStrings[];
> +
> +typedef struct {
> +  EFI_HII_CONFIG_ACCESS_PROTOCOL       ConfigAccess;
> +  EFI_HANDLE                           DriverHandle;
> +  EFI_HII_HANDLE                       HiiHandle;
> +  UINT8                                PasswordState;
> +  CHAR16                               OldPassword[PASSWORD_MAX_SIZE];
> +} USER_AUTHENTICATION_PRIVATE_DATA;
> +
> +#pragma pack(1)
> +///
> +/// HII specific Vendor Device Path definition.
> +///
> +typedef struct {
> +  VENDOR_DEVICE_PATH             VendorDevicePath;
> +  EFI_DEVICE_PATH_PROTOCOL       End;
> +} HII_VENDOR_DEVICE_PATH;
> +#pragma pack()
> +
> +/**
> +  Validata if the password is correct.
> +
> +  @param[in]  UserGuid               The user GUID of the password.
> +  @param[in]  Password               The user input password.
> +  @param[in]  PasswordSize           The size of Password in byte.
> +
> +  @retval EFI_SUCCESS              The password is correct.
> +  @retval EFI_SECURITY_VIOLATION   The password is incorrect.
> +**/
> +EFI_STATUS
> +ValidatePassword (
> +  IN   EFI_GUID     *UserGuid,
> +  IN   CHAR16       *Password,
> +  IN   UINTN        PasswordSize
> +  );
> +
> +/**
> +  Set a new password.
> +
> +  @param[in]  UserGuid               The user GUID of the password.
> +  @param[in]  NewPassword            The user input new password.
> +                                     NULL means clear password.
> +  @param[in]  NewPasswordSize        The size of NewPassword in byte.
> +  @param[in]  OldPassword            The user input old password.
> +                                     NULL means no old password.
> +  @param[in]  OldPasswordSize        The size of OldPassword in byte.
> +
> +  @retval EFI_SUCCESS              The password is correct.
> +  @retval EFI_SECURITY_VIOLATION   The password is incorrect.
> +  @retval EFI_OUT_OF_RESOURCES     Insufficient resources to set the
> password.
> +**/
> +EFI_STATUS
> +SetPassword (
> +  IN   EFI_GUID     *UserGuid,
> +  IN   CHAR16       *NewPassword,     OPTIONAL
> +  IN   UINTN        NewPasswordSize,
> +  IN   CHAR16       *OldPassword,     OPTIONAL
> +  IN   UINTN        OldPasswordSize
> +  );
> +
> +/**
> +  Return if the password is set.
> +
> +  @param[in]  UserGuid               The user GUID of the password.
> +
> +  @retval TRUE    The password is set.
> +  @retval FALSE   The password is not set.
> +**/
> +BOOLEAN
> +IsPasswordSet (
> +  IN   EFI_GUID     *UserGuid
> +  );
> +
> +#endif
> diff --git
> a/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.inf
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.inf
> new file mode 100644
> index 0000000..75a8076
> --- /dev/null
> +++
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.inf
> @@ -0,0 +1,79 @@
> +## @file
> +#  User Authentication Dxe Driver.
> +#
> +#  This Driver mainly does user authentication before entering Setup.
> +#
> +# Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
> +#
> +#  This program and the accompanying materials
> +#  are licensed and made available under the terms and conditions of the
> BSD License
> +#  which accompanies this distribution. The full text of the license may be
> found at
> +#  http://opensource.org/licenses/bsd-license.php
> +#
> +#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +#
> +#
> +##
> +
> +[Defines]
> +  INF_VERSION                    = 0x00010005
> +  BASE_NAME                      = UserAuthenticationDxe
> +  MODULE_UNI_FILE                = UserAuthenticationDxe.uni
> +  FILE_GUID                      = 0683FB88-664C-4BA6-9ED4-1C0916EE43A4
> +  MODULE_TYPE                    = DXE_DRIVER
> +  VERSION_STRING                 = 2.0
> +  ENTRY_POINT                    = UserAuthenticationEntry
> +  ENTRY_POINT                    = PasswordDxeInit
> +  UNLOAD_IMAGE                   = UserAuthenticationUnload
> +
> +
> +[Sources]
> +  UserAuthenticationDxe.c
> +  UserAuthenticationDxe.h
> +  UserAuthenticationDxePassword.c
> +  UserAuthenticationDxeFormset.h
> +  UserAuthenticationGuid.h
> +  UserAuthenticationDxeVfr.vfr
> +  UserAuthenticationDxeStrings.uni
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +  MdeModulePkg/MdeModulePkg.dec
> +  SecurityPkg/SecurityPkg.dec
> +
> +[LibraryClasses]
> +  BaseLib
> +  UefiBootServicesTableLib
> +  UefiDriverEntryPoint
> +  UefiRuntimeServicesTableLib
> +  BaseMemoryLib
> +  DebugLib
> +  UefiLib
> +  HiiLib
> +  DevicePathLib
> +  MemoryAllocationLib
> +  PlatformPasswordLib
> +
> +[Guids]
> +  gEfiEventExitBootServicesGuid                 ## CONSUMES  ## Event
> +  gEdkiiPiSmmCommunicationRegionTableGuid       ## CONSUMES  ##
> SystemTable
> +
> +[Protocols]
> +  gEfiRscHandlerProtocolGuid                    ## CONSUMES
> +  gEfiDevicePathProtocolGuid                    ## PRODUCES
> +  gEfiHiiConfigAccessProtocolGuid               ## PRODUCES
> +  gEfiSmmCommunicationProtocolGuid              ## CONSUMES
> +
> +[Depex]
> +  gEfiSimpleTextOutProtocolGuid      AND
> +  gEfiHiiDatabaseProtocolGuid        AND
> +  gEfiSmmCommunicationProtocolGuid   AND
> +  gEfiVariableArchProtocolGuid       AND
> +  gEfiVariableWriteArchProtocolGuid
> +
> +[UserExtensions.TianoCore."ExtraFiles"]
> +  UserAuthenticationDxeExtra.uni
> +
> +
> +
> diff --git
> a/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.uni
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.uni
> new file mode 100644
> index 0000000..6b2d292
> --- /dev/null
> +++
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.uni
> @@ -0,0 +1,22 @@
> +// /** @file
> +// User Authentication Dxe Driver.
> +//
> +// This driver mainly does the user authentication before entering Setup.
> +//
> +// Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
> +//
> +// This program and the accompanying materials
> +// are licensed and made available under the terms and conditions of the
> BSD License
> +// which accompanies this distribution. The full text of the license may be
> found at
> +// http://opensource.org/licenses/bsd-license.php
> +//
> +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +//
> +// **/
> +
> +
> +#string STR_MODULE_ABSTRACT             #language en-US "User
> Authentication Dxe Driver."
> +
> +#string STR_MODULE_DESCRIPTION          #language en-US "This driver
> mainly does user authentication before entering Setup."
> +
> diff --git
> a/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeExtra.u
> ni
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeExtra.u
> ni
> new file mode 100644
> index 0000000..86c5c9b
> --- /dev/null
> +++
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeExtra.u
> ni
> @@ -0,0 +1,20 @@
> +// /** @file
> +// User Authentication Dxe Driver.
> +//
> +// Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
> +//
> +// This program and the accompanying materials
> +// are licensed and made available under the terms and conditions of the
> BSD License
> +// which accompanies this distribution. The full text of the license may be
> found at
> +// http://opensource.org/licenses/bsd-license.php
> +//
> +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +//
> +// **/
> +
> +#string STR_PROPERTIES_MODULE_NAME
> +#language en-US
> +"User Authentication DXE Driver"
> +
> +
> diff --git
> a/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeForms
> et.h
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeForms
> et.h
> new file mode 100644
> index 0000000..4d29a5d
> --- /dev/null
> +++
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeForms
> et.h
> @@ -0,0 +1,30 @@
> +/** @file
> +  Header file for UserAuthentication formset.
> +
> +Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
> +This program and the accompanying materials
> +are licensed and made available under the terms and conditions of the BSD
> License
> +which accompanies this distribution.  The full text of the license may be
> found at
> +http://opensource.org/licenses/bsd-license.php
> +
> +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +
> +
> +**/
> +
> +#ifndef _USER_AUTHENTICATION_DXE_FORMSET_H_
> +#define _USER_AUTHENTICATION_DXE_FORMSET_H_
> +
> +//
> +// Vendor GUID of the formset
> +//
> +#define USER_AUTHENTICATION_FORMSET_GUID \
> +  { 0x760e3022, 0xf149, 0x4560, {0x9c, 0x6f, 0x33, 0xaa, 0x7d, 0x48, 0x75,
> 0xfa} }
> +
> +#define ADMIN_PASSWORD_KEY_ID   0x2001
> +
> +#define MAX_PASSWORD_LEN  20
> +#define MIN_PASSWORD_LEN  8
> +
> +#endif
> diff --git
> a/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxePassw
> ord.c
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxePassw
> ord.c
> new file mode 100644
> index 0000000..00b051a
> --- /dev/null
> +++
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxePassw
> ord.c
> @@ -0,0 +1,301 @@
> +/** @file
> +  UserAuthentication DXE password wrapper.
> +
> +Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
> +This program and the accompanying materials
> +are licensed and made available under the terms and conditions of the BSD
> License
> +which accompanies this distribution.  The full text of the license may be
> found at
> +http://opensource.org/licenses/bsd-license.php
> +
> +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +
> +**/
> +
> +#include "UserAuthenticationDxe.h"
> +#include <Guid/PiSmmCommunicationRegionTable.h>
> +#include <Protocol/SmmCommunication.h>
> +
> +EFI_SMM_COMMUNICATION_PROTOCOL *mSmmCommunication = NULL;
> +
> +/**
> +  Initialize the communicate buffer using DataSize and Function.
> +
> +  @param[out]      DataPtr          Points to the data in the communicate buffer.
> +  @param[in]       DataSize         The data size to send to SMM.
> +  @param[in]       Function         The function number to initialize the
> communicate header.
> +  @param[in]       UserGuid         The user GUID of the password.
> +
> +  @retval EFI_INVALID_PARAMETER     The data size is too big.
> +  @retval EFI_SUCCESS               Find the specified variable.
> +**/
> +VOID*
> +InitCommunicateBuffer (
> +  OUT     VOID                              **DataPtr OPTIONAL,
> +  IN      UINTN                             DataSize,
> +  IN      UINTN                             Function,
> +  IN      EFI_GUID                          *UserGuid
> +  )
> +{
> +  EFI_SMM_COMMUNICATE_HEADER                *SmmCommunicateHeader;
> +  SMM_PASSWORD_COMMUNICATE_HEADER
> *SmmPasswordFunctionHeader;
> +  VOID                                      *Buffer;
> +  EDKII_PI_SMM_COMMUNICATION_REGION_TABLE
> *SmmCommRegionTable;
> +  EFI_MEMORY_DESCRIPTOR                     *SmmCommMemRegion;
> +  UINTN                                     Index;
> +  UINTN                                     Size;
> +  EFI_STATUS                                Status;
> +
> +  Buffer = NULL;
> +  Status = EfiGetSystemConfigurationTable (
> +             &gEdkiiPiSmmCommunicationRegionTableGuid,
> +             (VOID **) &SmmCommRegionTable
> +             );
> +  if (EFI_ERROR (Status)) {
> +    return NULL;
> +  }
> +  ASSERT (SmmCommRegionTable != NULL);
> +  SmmCommMemRegion = (EFI_MEMORY_DESCRIPTOR *)
> (SmmCommRegionTable + 1);
> +  Size = 0;
> +  for (Index = 0; Index < SmmCommRegionTable->NumberOfEntries;
> Index++) {
> +    if (SmmCommMemRegion->Type == EfiConventionalMemory) {
> +      Size = EFI_PAGES_TO_SIZE ((UINTN) SmmCommMemRegion-
> >NumberOfPages);
> +      if (Size >= (DataSize + OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER,
> Data) + sizeof (SMM_PASSWORD_COMMUNICATE_HEADER))) {
> +        break;
> +      }
> +    }
> +    SmmCommMemRegion = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *)
> SmmCommMemRegion + SmmCommRegionTable->DescriptorSize);
> +  }
> +  ASSERT (Index < SmmCommRegionTable->NumberOfEntries);
> +
> +  Buffer = (VOID*)(UINTN)SmmCommMemRegion->PhysicalStart;
> +  ASSERT (Buffer != NULL);
> +  SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *)
> Buffer;
> +  CopyGuid (&SmmCommunicateHeader->HeaderGuid, UserGuid);
> +  SmmCommunicateHeader->MessageLength = DataSize + sizeof
> (SMM_PASSWORD_COMMUNICATE_HEADER);
> +
> +  SmmPasswordFunctionHeader =
> (SMM_PASSWORD_COMMUNICATE_HEADER *) SmmCommunicateHeader-
> >Data;
> +  ZeroMem (SmmPasswordFunctionHeader, DataSize + sizeof
> (SMM_PASSWORD_COMMUNICATE_HEADER));
> +  SmmPasswordFunctionHeader->Function = Function;
> +  CopyGuid (&SmmPasswordFunctionHeader->UserGuid, UserGuid);
> +  if (DataPtr != NULL) {
> +    *DataPtr = SmmPasswordFunctionHeader + 1;
> +  }
> +
> +  return Buffer;
> +}
> +
> +/**
> +  Send the data in communicate buffer to SMM.
> +
> +  @param[in]   Buffer                 Points to the data in the communicate buffer.
> +  @param[in]   DataSize               This size of the function header and the data.
> +
> +  @retval      EFI_SUCCESS            Success is returned from the functin in SMM.
> +  @retval      Others                 Failure is returned from the function in SMM.
> +
> +**/
> +EFI_STATUS
> +SendCommunicateBuffer (
> +  IN      VOID                              *Buffer,
> +  IN      UINTN                             DataSize
> +  )
> +{
> +  EFI_STATUS                                Status;
> +  UINTN                                     CommSize;
> +  EFI_SMM_COMMUNICATE_HEADER                *SmmCommunicateHeader;
> +  SMM_PASSWORD_COMMUNICATE_HEADER
> *SmmPasswordFunctionHeader;
> +
> +  CommSize = DataSize + OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER,
> Data) + sizeof (SMM_PASSWORD_COMMUNICATE_HEADER);
> +
> +  Status = mSmmCommunication->Communicate (mSmmCommunication,
> Buffer, &CommSize);
> +  ASSERT_EFI_ERROR (Status);
> +
> +  SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *)
> Buffer;
> +  SmmPasswordFunctionHeader =
> (SMM_PASSWORD_COMMUNICATE_HEADER *)SmmCommunicateHeader-
> >Data;
> +  return  SmmPasswordFunctionHeader->ReturnStatus;
> +}
> +
> +/**
> +  Validata if the password is correct.
> +
> +  @param[in]  UserGuid               The user GUID of the password.
> +  @param[in]  Password               The user input password.
> +  @param[in]  PasswordSize           The size of Password in byte.
> +
> +  @retval EFI_SUCCESS              The password is correct.
> +  @retval EFI_SECURITY_VIOLATION   The password is incorrect.
> +**/
> +EFI_STATUS
> +ValidatePassword (
> +  IN   EFI_GUID     *UserGuid,
> +  IN   CHAR16       *Password,
> +  IN   UINTN        PasswordSize
> +  )
> +{
> +  EFI_STATUS                                Status;
> +  VOID                                      *Buffer;
> +  SMM_PASSWORD_COMMUNICATE_VERIFY_PASSWORD
> *VerifyPassword;
> +
> +  ASSERT (Password != NULL);
> +
> +  if (PasswordSize > sizeof(VerifyPassword->Password) * sizeof(CHAR16)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  Buffer = InitCommunicateBuffer (
> +             (VOID**)&VerifyPassword,
> +             sizeof(*VerifyPassword),
> +             SMM_PASSWORD_FUNCTION_VERIFY_PASSWORD,
> +             UserGuid
> +             );
> +  if (Buffer == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  Status = UnicodeStrToAsciiStrS (Password, VerifyPassword->Password,
> sizeof(VerifyPassword->Password));
> +  if (EFI_ERROR(Status)) {
> +    return Status;
> +  }
> +
> +  Status = SendCommunicateBuffer (Buffer, sizeof(*VerifyPassword));
> +  if (EFI_ERROR (Status)) {
> +    goto EXIT;
> +  }
> +
> +EXIT:
> +  ZeroMem (VerifyPassword, sizeof(*VerifyPassword));
> +  return Status;
> +}
> +
> +/**
> +  Set a new password.
> +
> +  @param[in]  UserGuid               The user GUID of the password.
> +  @param[in]  NewPassword            The user input new password.
> +                                     NULL means clear password.
> +  @param[in]  NewPasswordSize        The size of NewPassword in byte.
> +  @param[in]  OldPassword            The user input old password.
> +                                     NULL means no old password.
> +  @param[in]  OldPasswordSize        The size of OldPassword in byte.
> +
> +  @retval EFI_SUCCESS              The password is correct.
> +  @retval EFI_SECURITY_VIOLATION   The password is incorrect.
> +  @retval EFI_OUT_OF_RESOURCES     Insufficient resources to set the
> password.
> +**/
> +EFI_STATUS
> +SetPassword (
> +  IN   EFI_GUID     *UserGuid,
> +  IN   CHAR16       *NewPassword,     OPTIONAL
> +  IN   UINTN        NewPasswordSize,
> +  IN   CHAR16       *OldPassword,     OPTIONAL
> +  IN   UINTN        OldPasswordSize
> +  )
> +{
> +  EFI_STATUS                                Status;
> +  VOID                                      *Buffer;
> +  SMM_PASSWORD_COMMUNICATE_SET_PASSWORD     *SetPassword;
> +
> +  if (NewPasswordSize > sizeof(SetPassword->NewPassword) *
> sizeof(CHAR16)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +  if (OldPasswordSize > sizeof(SetPassword->OldPassword) *
> sizeof(CHAR16)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  Buffer = InitCommunicateBuffer (
> +             (VOID**)&SetPassword,
> +             sizeof(*SetPassword),
> +             SMM_PASSWORD_FUNCTION_SET_PASSWORD,
> +             UserGuid
> +             );
> +  if (Buffer == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  if (NewPassword != NULL) {
> +    Status = UnicodeStrToAsciiStrS (NewPassword, SetPassword-
> >NewPassword, sizeof(SetPassword->NewPassword));
> +    if (EFI_ERROR(Status)) {
> +      return Status;
> +    }
> +  } else {
> +    SetPassword->NewPassword[0] = 0;
> +  }
> +
> +  if (OldPassword != NULL) {
> +    Status = UnicodeStrToAsciiStrS (OldPassword, SetPassword-
> >OldPassword, sizeof(SetPassword->OldPassword));
> +    if (EFI_ERROR(Status)) {
> +      return Status;
> +    }
> +  } else {
> +    SetPassword->OldPassword[0] = 0;
> +  }
> +
> +  Status = SendCommunicateBuffer (Buffer, sizeof(*SetPassword));
> +  if (EFI_ERROR (Status)) {
> +    goto EXIT;
> +  }
> +
> +EXIT:
> +  ZeroMem (SetPassword, sizeof(*SetPassword));
> +  return Status;
> +}
> +
> +/**
> +  Return if the password is set.
> +
> +  @param[in]  UserGuid               The user GUID of the password.
> +
> +  @retval TRUE    The password is set.
> +  @retval FALSE   The password is not set.
> +**/
> +BOOLEAN
> +IsPasswordSet (
> +  IN   EFI_GUID     *UserGuid
> +  )
> +{
> +  EFI_STATUS                                Status;
> +  VOID                                      *Buffer;
> +
> +  Buffer = InitCommunicateBuffer (
> +             NULL,
> +             0,
> +             SMM_PASSWORD_FUNCTION_IS_PASSWORD_SET,
> +             UserGuid
> +             );
> +  if (Buffer == NULL) {
> +    return FALSE;
> +  }
> +
> +  Status = SendCommunicateBuffer (Buffer, 0);
> +  if (EFI_ERROR (Status)) {
> +    return FALSE;
> +  }
> +
> +  return TRUE;
> +}
> +
> +/**
> +  Main entry for this driver.
> +
> +  @param ImageHandle     Image handle this driver.
> +  @param SystemTable     Pointer to SystemTable.
> +
> +  @retval EFI_SUCESS     This function always complete successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PasswordDxeInit (
> +  IN EFI_HANDLE                         ImageHandle,
> +  IN EFI_SYSTEM_TABLE                   *SystemTable
> +  )
> +{
> +  EFI_STATUS                     Status;
> +
> +  Status = gBS->LocateProtocol (&gEfiSmmCommunicationProtocolGuid,
> NULL, (VOID **) &mSmmCommunication);
> +  ASSERT_EFI_ERROR (Status);
> +
> +  return EFI_SUCCESS;
> +}
> +
> diff --git
> a/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeStrings.
> uni
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeStrings
> .uni
> new file mode 100644
> index 0000000..86fde22
> --- /dev/null
> +++
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeStrings
> .uni
> @@ -0,0 +1,29 @@
> +/** @file
> +// String definitions for User Authentication formset.
> +
> +// Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
> +// This program and the accompanying materials
> +// are licensed and made available under the terms and conditions of the
> BSD License
> +// which accompanies this distribution.  The full text of the license may be
> found at
> +// http://opensource.org/licenses/bsd-license.php
> +
> +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +
> +**/
> +
> +#langdef en-US  "English"
> +#langdef fr-FR  "Francais"
> +
> +
> +#string STR_FORM_SET_TITLE             #language en-US "User Password
> Management"
> +                                       #language fr-FR "User Password Management"
> +#string STR_FORM_SET_TITLE_HELP        #language en-US "This Driver
> mainly handle user's password"
> +                                       #language fr-FR "This Driver mainly handle user's
> password"
> +#string STR_FORM_TITLE                 #language en-US "Password Management
> Form"
> +                                       #language fr-FR "Password Management Form"
> +#string STR_ADMIN_PASSWORD_PROMPT      #language en-US "Change
> Admin Password"
> +                                       #language fr-FR "Change Admin Password"
> +#string STR_ADMIN_PASSWORD_HELP        #language en-US "Input old
> admin password, then you can change the password to a new one. After the
> change action, you need input the new password when you enter UI. The
> new password must be at least 8 char and include lowercase, uppercase
> alphabetic, numbers, and symbols."
> +                                       #language fr-FR "Input old admin password, then you
> can change the password to a new one. After the change action, you need
> input the new password when you enter UI. The new password must be at
> least 8 char and include lowercase, uppercase alphabetic, numbers, and
> symbols."
> +
> diff --git
> a/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeVfr.vfr
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeVfr.vfr
> new file mode 100644
> index 0000000..4741fe3
> --- /dev/null
> +++
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeVfr.vfr
> @@ -0,0 +1,38 @@
> +///** @file
> +// UserAuthentication formset.
> +//
> +// Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
> +// This program and the accompanying materials
> +// are licensed and made available under the terms and conditions of the
> BSD License
> +// which accompanies this distribution.  The full text of the license may be
> found at
> +// http://opensource.org/licenses/bsd-license.php
> +//
> +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +
> +//**/
> +
> +#include <Guid/HiiPlatformSetupFormset.h>
> +#include "UserAuthenticationDxeFormset.h"
> +
> +formset
> +  guid      = USER_AUTHENTICATION_FORMSET_GUID,
> +  title     = STRING_TOKEN(STR_FORM_SET_TITLE),
> +  help      = STRING_TOKEN(STR_FORM_SET_TITLE_HELP),
> +  classguid = EFI_HII_PLATFORM_SETUP_FORMSET_GUID,
> +
> +  form formid = 1,
> +      title  = STRING_TOKEN(STR_FORM_TITLE);
> +
> +      password
> +          prompt   = STRING_TOKEN(STR_ADMIN_PASSWORD_PROMPT),
> +          help     = STRING_TOKEN(STR_ADMIN_PASSWORD_HELP),
> +          flags    = INTERACTIVE,
> +          key      = ADMIN_PASSWORD_KEY_ID,
> +          minsize = MIN_PASSWORD_LEN,
> +          maxsize = MAX_PASSWORD_LEN,
> +      endpassword;
> +
> +  endform;
> +
> +endformset;
> diff --git
> a/SecurityPkg/Password/UserAuthentication/UserAuthenticationGuid.h
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationGuid.h
> new file mode 100644
> index 0000000..0a4df01
> --- /dev/null
> +++ b/SecurityPkg/Password/UserAuthentication/UserAuthenticationGuid.h
> @@ -0,0 +1,65 @@
> +/** @file
> +  GUID is for UserPassword variable.
> +
> +Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
> +This program and the accompanying materials are licensed and made
> available under
> +the terms and conditions of the BSD License that accompanies this
> distribution.
> +The full text of the license may be found at
> +http://opensource.org/licenses/bsd-license.php.
> +
> +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +
> +**/
> +
> +#ifndef __USER_AUTHENTICATION_GUID_H__
> +#define __USER_AUTHENTICATION_GUID_H__
> +
> +#define PASSWORD_MIN_SIZE    9  // MIN number of char of password,
> including NULL
> +#define PASSWORD_MAX_SIZE    32 // MAX number of char of password,
> including NULL
> +#define PASSWORD_SALT_SIZE   32
> +#define PASSWORD_HASH_SIZE   32 // SHA256_DIGEST_SIZE
> +
> +#define PASSWORD_MAX_TRY_COUNT  3
> +#define PASSWORD_HISTORY_CHECK_COUNT  5
> +
> +//
> +// Vendor GUID of the variable
> +//
> +#define ADMIN_AUTHENTICATION_GUID \
> +  { 0xee24a7f7, 0x606b, 0x4724, { 0xb3, 0xc9, 0xf5, 0xae, 0x4a, 0x3b, 0x81,
> 0x65} }
> +
> +//
> +// Name of the variable
> +//
> +#define USER_AUTHENTICATION_VAR_NAME L"Password"
> +#define USER_AUTHENTICATION_HISTORY_LAST_VAR_NAME
> L"PasswordLast"
> +
> +//
> +// Variable storage
> +//
> +typedef struct {
> +  UINT8        PasswordHash[PASSWORD_HASH_SIZE];
> +  UINT8        PasswordSalt[PASSWORD_SALT_SIZE];
> +} USER_PASSWORD_VAR_STRUCT;
> +
> +typedef struct {
> +  UINTN       Function;
> +  EFI_STATUS  ReturnStatus;
> +  EFI_GUID    UserGuid;
> +} SMM_PASSWORD_COMMUNICATE_HEADER;
> +
> +#define SMM_PASSWORD_FUNCTION_IS_PASSWORD_SET     1
> +#define SMM_PASSWORD_FUNCTION_SET_PASSWORD        2
> +#define SMM_PASSWORD_FUNCTION_VERIFY_PASSWORD     3
> +
> +typedef struct {
> +  CHAR8                                 NewPassword[PASSWORD_MAX_SIZE];
> +  CHAR8                                 OldPassword[PASSWORD_MAX_SIZE];
> +} SMM_PASSWORD_COMMUNICATE_SET_PASSWORD;
> +
> +typedef struct {
> +  CHAR8                                 Password[PASSWORD_MAX_SIZE];
> +} SMM_PASSWORD_COMMUNICATE_VERIFY_PASSWORD;
> +
> +#endif
> diff --git
> a/SecurityPkg/Password/UserAuthentication/UserAuthenticationSmm.c
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationSmm.c
> new file mode 100644
> index 0000000..ffc3d81
> --- /dev/null
> +++ b/SecurityPkg/Password/UserAuthentication/UserAuthenticationSmm.c
> @@ -0,0 +1,672 @@
> +/** @file
> +
> +Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
> +This program and the accompanying materials
> +are licensed and made available under the terms and conditions of the BSD
> License
> +which accompanies this distribution.  The full text of the license may be
> found at
> +http://opensource.org/licenses/bsd-license.php
> +
> +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +
> +**/
> +
> +#include <PiSmm.h>
> +#include <Protocol/SmmVariable.h>
> +#include <Protocol/VariableLock.h>
> +#include <Library/DebugLib.h>
> +#include <Library/BaseLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/PrintLib.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +#include <Library/SmmServicesTableLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/SmmServicesTableLib.h>
> +#include <Library/PlatformPasswordLib.h>
> +#include "KeyService.h"
> +#include "UserAuthenticationGuid.h"
> +
> +EFI_GUID gAdminAuthenticationGuid = ADMIN_AUTHENTICATION_GUID;
> +
> +EFI_SMM_VARIABLE_PROTOCOL         *mSmmVariable;
> +
> +UINTN  mAdminPasswordTryCount;
> +
> +/**
> +  Verify if the password is correct.
> +
> +  @param[in]  Password               The user input password.
> +  @param[in]  PasswordSize           The size of Password in byte.
> +  @param[in]  UserPasswordVarStruct  The storage of password in variable.
> +
> +  @retval EFI_SUCCESS              The password is correct.
> +  @retval EFI_SECURITY_VIOLATION   The password is incorrect.
> +**/
> +EFI_STATUS
> +VerifyPassword (
> +  IN CHAR8                          *Password,
> +  IN UINTN                          PasswordSize,
> +  IN USER_PASSWORD_VAR_STRUCT       *UserPasswordVarStruct
> +  )
> +{
> +  BOOLEAN  HashOk;
> +  UINT8    HashData[PASSWORD_HASH_SIZE];
> +
> +  HashOk = KeyLibGeneratePBKDF2Hash (
> +             HASH_TYPE_SHA256,
> +             (UINT8 *)Password,
> +             PasswordSize,
> +             UserPasswordVarStruct->PasswordSalt,
> +             sizeof(UserPasswordVarStruct->PasswordSalt),
> +             HashData,
> +             sizeof(HashData)
> +             );
> +  if (!HashOk) {
> +    return EFI_DEVICE_ERROR;
> +  }
> +  if (KeyLibSlowCompareMem (UserPasswordVarStruct->PasswordHash,
> HashData, PASSWORD_HASH_SIZE) == 0) {
> +    return EFI_SUCCESS;
> +  } else {
> +    return EFI_SECURITY_VIOLATION;
> +  }
> +}
> +
> +/**
> +  Get hash data of password from non-volatile variable region.
> +
> +  @param[in]   UserGuid               The user GUID of the password variable.
> +  @param[in]   Index                  The index of the password.
> +                                      0 means current password.
> +                                      Non-0 means the password history.
> +  @param[out]  UserPasswordVarStruct  The storage of password in variable.
> +
> +  @retval EFI_SUCCESS             The password hash is returned successfully.
> +  @retval EFI_NOT_FOUND           The password hash is not found.
> +**/
> +EFI_STATUS
> +GetPasswordHashFromVariable (
> +  IN  EFI_GUID                       *UserGuid,
> +  IN  UINTN                          Index,
> +  OUT USER_PASSWORD_VAR_STRUCT       *UserPasswordVarStruct
> +  )
> +{
> +  EFI_STATUS                        Status;
> +  UINTN                             DataSize;
> +  CHAR16
> PasswordName[sizeof(USER_AUTHENTICATION_VAR_NAME)/sizeof(CHAR1
> 6) + 4];
> +
> +  if (Index != 0) {
> +    UnicodeSPrint (PasswordName, sizeof (PasswordName), L"%s%04x",
> USER_AUTHENTICATION_VAR_NAME, Index);
> +  } else {
> +    UnicodeSPrint (PasswordName, sizeof (PasswordName), L"%s",
> USER_AUTHENTICATION_VAR_NAME);
> +  }
> +
> +  DataSize = sizeof(*UserPasswordVarStruct);
> +  Status = mSmmVariable->SmmGetVariable (
> +                           PasswordName,
> +                           UserGuid,
> +                           NULL,
> +                           &DataSize,
> +                           UserPasswordVarStruct
> +                           );
> +  if (EFI_ERROR(Status)) {
> +    return Status;
> +  }
> +
> +  return Status;
> +}
> +
> +/**
> +  Save password hash data to non-volatile variable region.
> +
> +  @param[in]   UserGuid               The user GUID of the password variable.
> +  @param[in]   UserPasswordVarStruct  The storage of password in variable.
> +
> +  @retval EFI_SUCCESS             The password hash is saved successfully.
> +  @retval EFI_OUT_OF_RESOURCES    Insufficient resources to save the
> password hash.
> +**/
> +EFI_STATUS
> +SavePasswordHashToVariable (
> +  IN EFI_GUID                       *UserGuid,
> +  IN USER_PASSWORD_VAR_STRUCT       *UserPasswordVarStruct
> +  )
> +{
> +  EFI_STATUS                        Status;
> +
> +  if (UserPasswordVarStruct == NULL) {
> +    Status = mSmmVariable->SmmSetVariable (
> +                             USER_AUTHENTICATION_VAR_NAME,
> +                             UserGuid,
> +                             EFI_VARIABLE_BOOTSERVICE_ACCESS |
> EFI_VARIABLE_NON_VOLATILE,
> +                             0,
> +                             NULL
> +                             );
> +  } else {
> +    Status = mSmmVariable->SmmSetVariable (
> +                             USER_AUTHENTICATION_VAR_NAME,
> +                             UserGuid,
> +                             EFI_VARIABLE_BOOTSERVICE_ACCESS |
> EFI_VARIABLE_NON_VOLATILE,
> +                             sizeof(*UserPasswordVarStruct),
> +                             UserPasswordVarStruct
> +                             );
> +  }
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "SavePasswordHashToVariable fails with %r\n",
> Status));
> +  }
> +
> +  return Status;
> +}
> +
> +/**
> +  Save old password hash data to non-volatile variable region as history.
> +
> +  The number of password history variable is limited.
> +  If all the password history variables are used, the new password history
> +  will override the oldest one.
> +
> +  @param[in]   UserGuid               The user GUID of the password variable.
> +  @param[in]   UserPasswordVarStruct  The storage of password in variable.
> +
> +  @retval EFI_SUCCESS             The password hash is saved successfully.
> +  @retval EFI_OUT_OF_RESOURCES    Insufficient resources to save the
> password hash.
> +**/
> +EFI_STATUS
> +SaveOldPasswordToHistory (
> +  IN EFI_GUID                       *UserGuid,
> +  IN USER_PASSWORD_VAR_STRUCT       *UserPasswordVarStruct
> +  )
> +{
> +  EFI_STATUS                        Status;
> +  UINTN                             DataSize;
> +  UINT32                            LastIndex;
> +  CHAR16
> PasswordName[sizeof(USER_AUTHENTICATION_VAR_NAME)/sizeof(CHAR1
> 6) + 4];
> +
> +  DEBUG ((DEBUG_INFO, "SaveOldPasswordToHistory\n"));
> +
> +  DataSize = sizeof(LastIndex);
> +  Status = mSmmVariable->SmmGetVariable (
> +                           USER_AUTHENTICATION_HISTORY_LAST_VAR_NAME,
> +                           UserGuid,
> +                           NULL,
> +                           &DataSize,
> +                           &LastIndex
> +                           );
> +  if (EFI_ERROR(Status)) {
> +    LastIndex = 0;
> +  }
> +  if (LastIndex >= PASSWORD_HISTORY_CHECK_COUNT) {
> +    LastIndex = 0;
> +  }
> +
> +  LastIndex ++;
> +  UnicodeSPrint (PasswordName, sizeof (PasswordName), L"%s%04x",
> USER_AUTHENTICATION_VAR_NAME, LastIndex);
> +
> +
> +  Status = mSmmVariable->SmmSetVariable (
> +                           PasswordName,
> +                           UserGuid,
> +                           EFI_VARIABLE_BOOTSERVICE_ACCESS |
> EFI_VARIABLE_NON_VOLATILE,
> +                           sizeof(*UserPasswordVarStruct),
> +                           UserPasswordVarStruct
> +                           );
> +  DEBUG ((DEBUG_INFO, "  -- to %s, %r\n", PasswordName, Status));
> +  if (!EFI_ERROR(Status)) {
> +    Status = mSmmVariable->SmmSetVariable (
> +                             USER_AUTHENTICATION_HISTORY_LAST_VAR_NAME,
> +                             UserGuid,
> +                             EFI_VARIABLE_BOOTSERVICE_ACCESS |
> EFI_VARIABLE_NON_VOLATILE,
> +                             sizeof(LastIndex),
> +                             &LastIndex
> +                             );
> +    DEBUG ((DEBUG_INFO, " LastIndex - 0x%04x, %r\n", LastIndex, Status));
> +  }
> +
> +  return Status;
> +}
> +
> +/**
> +  Calculate password hash data and save it to non-volatile variable region.
> +
> +  @param[in]  UserGuid               The user GUID of the password variable.
> +  @param[in]  Password               The user input password.
> +                                     NULL means delete the password variable.
> +  @param[in]  PasswordSize           The size of Password in byte.
> +
> +  @retval EFI_SUCCESS             The password hash is calculated and saved.
> +  @retval EFI_OUT_OF_RESOURCES    Insufficient resources to save the
> password hash.
> +**/
> +EFI_STATUS
> +SavePasswordToVariable (
> +  IN  EFI_GUID                      *UserGuid,
> +  IN  CHAR8                         *Password,  OPTIONAL
> +  IN  UINTN                         PasswordSize
> +  )
> +{
> +  EFI_STATUS                        Status;
> +  USER_PASSWORD_VAR_STRUCT          UserPasswordVarStruct;
> +  BOOLEAN                           HashOk;
> +
> +  //
> +  // If password is NULL, it means we want to clean password field saved in
> variable region.
> +  //
> +  if (Password != NULL) {
> +    KeyLibGenerateSalt (UserPasswordVarStruct.PasswordSalt,
> sizeof(UserPasswordVarStruct.PasswordSalt));
> +    HashOk = KeyLibGeneratePBKDF2Hash (
> +               HASH_TYPE_SHA256,
> +               (UINT8 *)Password,
> +               PasswordSize,
> +               UserPasswordVarStruct.PasswordSalt,
> +               sizeof(UserPasswordVarStruct.PasswordSalt),
> +               UserPasswordVarStruct.PasswordHash,
> +               sizeof(UserPasswordVarStruct.PasswordHash)
> +               );
> +    if (!HashOk) {
> +      return EFI_DEVICE_ERROR;
> +    }
> +    Status = SavePasswordHashToVariable (UserGuid,
> &UserPasswordVarStruct);
> +    //
> +    // Save Password data to history variable
> +    //
> +    if (!EFI_ERROR(Status)) {
> +      SaveOldPasswordToHistory (UserGuid, &UserPasswordVarStruct);
> +    }
> +  } else {
> +    Status = SavePasswordHashToVariable (UserGuid, NULL);
> +  }
> +
> +  return Status;
> +}
> +
> +/**
> +  Verify the password.
> +  If the password variable does not exist, it passes the verification.
> +  If the password variable exists, it does verification based upon password
> variable.
> +
> +  @param[in]  UserGuid               The user GUID of the password variable.
> +  @param[in]  Password               The user input password.
> +  @param[in]  PasswordSize           The size of Password in byte.
> +
> +  @retval TRUE    The verification passes.
> +  @retval FALSE   The verification fails.
> +**/
> +BOOLEAN
> +IsPasswordVerified (
> +  IN EFI_GUID                       *UserGuid,
> +  IN CHAR8                          *Password,
> +  IN UINTN                          PasswordSize
> +  )
> +{
> +  USER_PASSWORD_VAR_STRUCT          UserPasswordVarStruct;
> +  EFI_STATUS                        Status;
> +
> +  Status = GetPasswordHashFromVariable (UserGuid, 0,
> &UserPasswordVarStruct);
> +  if (EFI_ERROR(Status)) {
> +    return TRUE;
> +  }
> +
> +  //
> +  // Old password exists
> +  //
> +  Status = VerifyPassword (Password, PasswordSize,
> &UserPasswordVarStruct);
> +  if (EFI_ERROR(Status)) {
> +    return FALSE;
> +  }
> +
> +  return TRUE;
> +}
> +
> +/**
> +  Return if the password is set.
> +
> +  @param[in]  UserGuid               The user GUID of the password variable.
> +
> +  @retval TRUE    The password is set.
> +  @retval FALSE   The password is not set.
> +**/
> +BOOLEAN
> +IsPasswordSet (
> +  IN EFI_GUID                       *UserGuid
> +  )
> +{
> +  USER_PASSWORD_VAR_STRUCT          UserPasswordVarStruct;
> +  EFI_STATUS                        Status;
> +
> +  Status = GetPasswordHashFromVariable(UserGuid, 0,
> &UserPasswordVarStruct);
> +  if (EFI_ERROR(Status)) {
> +    return FALSE;
> +  }
> +  return TRUE;
> +}
> +
> +/**
> +  Return if the password is strong.
> +  Criteria:
> +  1) length >= PASSWORD_MIN_SIZE
> +  2) include lower case, upper case, number, symbol.
> +
> +  @param[in]  Password               The user input password.
> +  @param[in]  PasswordSize           The size of Password in byte.
> +
> +  @retval TRUE    The password is strong.
> +  @retval FALSE   The password is weak.
> +**/
> +BOOLEAN
> +IsPasswordStrong (
> +  IN CHAR8   *Password,
> +  IN UINTN   PasswordSize
> +  )
> +{
> +  UINTN   Index;
> +  BOOLEAN HasLowerCase;
> +  BOOLEAN HasUpperCase;
> +  BOOLEAN HasNumber;
> +  BOOLEAN HasSymbol;
> +
> +  if (PasswordSize < PASSWORD_MIN_SIZE) {
> +    return FALSE;
> +  }
> +
> +  HasLowerCase = FALSE;
> +  HasUpperCase = FALSE;
> +  HasNumber = FALSE;
> +  HasSymbol = FALSE;
> +  for (Index = 0; Index < PasswordSize - 1; Index++) {
> +    if (Password[Index] >= 'a' && Password[Index] <= 'z') {
> +      HasLowerCase = TRUE;
> +    } else if (Password[Index] >= 'A' && Password[Index] <= 'Z') {
> +      HasUpperCase = TRUE;
> +    } else if (Password[Index] >= '0' && Password[Index] <= '9') {
> +      HasNumber = TRUE;
> +    } else {
> +      HasSymbol = TRUE;
> +    }
> +  }
> +  if ((!HasLowerCase) || (!HasUpperCase) || (!HasNumber) || (!HasSymbol))
> {
> +    return FALSE;
> +  }
> +  return TRUE;
> +}
> +
> +/**
> +  Return if the password is set before in
> PASSWORD_HISTORY_CHECK_COUNT.
> +
> +  @param[in]  UserGuid               The user GUID of the password variable.
> +  @param[in]  Password               The user input password.
> +  @param[in]  PasswordSize           The size of Password in byte.
> +
> +  @retval TRUE    The password is set before.
> +  @retval FALSE   The password is not set before.
> +**/
> +BOOLEAN
> +IsPasswordInHistory (
> +  IN EFI_GUID                       *UserGuid,
> +  IN CHAR8                          *Password,
> +  IN UINTN                          PasswordSize
> +  )
> +{
> +  EFI_STATUS                     Status;
> +  USER_PASSWORD_VAR_STRUCT       UserPasswordVarStruct;
> +  UINTN                          Index;
> +
> +  for (Index = 1; Index <= PASSWORD_HISTORY_CHECK_COUNT; Index++) {
> +    Status = GetPasswordHashFromVariable (UserGuid, Index,
> &UserPasswordVarStruct);
> +    if (!EFI_ERROR(Status)) {
> +      Status = VerifyPassword (Password, PasswordSize,
> &UserPasswordVarStruct);
> +      if (!EFI_ERROR(Status)) {
> +        return TRUE;
> +      }
> +    }
> +  }
> +
> +  return FALSE;
> +}
> +
> +/**
> +  Communication service SMI Handler entry.
> +
> +  This SMI handler provides services for password management.
> +
> +  @param[in]     DispatchHandle  The unique handle assigned to this handler
> by SmiHandlerRegister().
> +  @param[in]     RegisterContext Points to an optional handler context which
> was specified when the
> +                                 handler was registered.
> +  @param[in, out] CommBuffer     A pointer to a collection of data in
> memory that will
> +                                 be conveyed from a non-SMM environment into an SMM
> environment.
> +  @param[in, out] CommBufferSize The size of the CommBuffer.
> +
> +  @retval EFI_SUCCESS                         The interrupt was handled and quiesced.
> No other handlers
> +                                              should still be called.
> +  @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED  The interrupt has
> been quiesced but other handlers should
> +                                              still be called.
> +  @retval EFI_WARN_INTERRUPT_SOURCE_PENDING   The interrupt is still
> pending and other handlers should still
> +                                              be called.
> +  @retval EFI_INTERRUPT_PENDING               The interrupt could not be
> quiesced.
> +**/
> +EFI_STATUS
> +EFIAPI
> +SmmPasswordHandler (
> +  IN     EFI_HANDLE                 DispatchHandle,
> +  IN     CONST VOID                 *RegisterContext,
> +  IN OUT VOID                       *CommBuffer,
> +  IN OUT UINTN                      *CommBufferSize
> +  )
> +{
> +  EFI_STATUS                                Status;
> +  SMM_PASSWORD_COMMUNICATE_HEADER           *SmmFunctionHeader;
> +  UINTN                                     CommBufferPayloadSize;
> +  UINTN                                     TempCommBufferSize;
> +  SMM_PASSWORD_COMMUNICATE_SET_PASSWORD
> SmmCommunicateSetPassword;
> +  SMM_PASSWORD_COMMUNICATE_VERIFY_PASSWORD
> SmmCommunicateVerifyPassword;
> +  UINTN                                     PasswordLen;
> +  EFI_GUID                                  UserGuid;
> +  UINTN                                     *PasswordTryCount;
> +
> +  //
> +  // If input is invalid, stop processing this SMI
> +  //
> +  if (CommBuffer == NULL || CommBufferSize == NULL) {
> +    return EFI_SUCCESS;
> +  }
> +
> +  TempCommBufferSize = *CommBufferSize;
> +
> +  if (TempCommBufferSize < sizeof
> (SMM_PASSWORD_COMMUNICATE_HEADER)) {
> +    DEBUG ((DEBUG_ERROR, "SmmPasswordHandler: SMM communication
> buffer size invalid!\n"));
> +    return EFI_SUCCESS;
> +  }
> +
> +  CommBufferPayloadSize = TempCommBufferSize - sizeof
> (SMM_PASSWORD_COMMUNICATE_HEADER);
> +
> +  Status   = EFI_SUCCESS;
> +  SmmFunctionHeader = (SMM_PASSWORD_COMMUNICATE_HEADER
> *)CommBuffer;
> +  CopyGuid (&UserGuid, &SmmFunctionHeader->UserGuid);
> +
> +  if (CompareGuid (&UserGuid, &gAdminAuthenticationGuid)) {
> +    PasswordTryCount = &mAdminPasswordTryCount;
> +  } else {
> +    DEBUG ((DEBUG_ERROR, "SmmPasswordHandler: Invalid UserGuid\n"));
> +    PasswordTryCount = NULL;
> +    Status = EFI_INVALID_PARAMETER;
> +    goto EXIT;
> +  }
> +
> +  switch (SmmFunctionHeader->Function) {
> +  case SMM_PASSWORD_FUNCTION_IS_PASSWORD_SET:
> +    PasswordTryCount = NULL;
> +    if (CommBufferPayloadSize != 0) {
> +      DEBUG ((DEBUG_ERROR, "SmmPasswordHandler: IS_PASSWORD_SET
> payload buffer invalid!\n"));
> +      Status = EFI_INVALID_PARAMETER;
> +      goto EXIT;
> +    }
> +    if (IsPasswordSet(&UserGuid)) {
> +      Status = EFI_SUCCESS;
> +    } else {
> +      Status = EFI_NOT_FOUND;
> +    }
> +    break;
> +  case SMM_PASSWORD_FUNCTION_SET_PASSWORD:
> +    if (*PasswordTryCount >= PASSWORD_MAX_TRY_COUNT) {
> +      DEBUG ((DEBUG_ERROR, "SmmPasswordHandler: SET_PASSWORD try
> count reach!\n"));
> +      PasswordTryCount = NULL;
> +      Status = EFI_INVALID_PARAMETER;
> +      goto EXIT;
> +    }
> +    if (CommBufferPayloadSize !=
> sizeof(SMM_PASSWORD_COMMUNICATE_SET_PASSWORD)) {
> +      DEBUG ((DEBUG_ERROR, "SmmPasswordHandler: SET_PASSWORD
> payload buffer invalid!\n"));
> +      Status = EFI_INVALID_PARAMETER;
> +      goto EXIT;
> +    }
> +    CopyMem (&SmmCommunicateSetPassword, SmmFunctionHeader + 1,
> sizeof(SmmCommunicateSetPassword));
> +
> +    PasswordLen =
> AsciiStrnLenS(SmmCommunicateSetPassword.OldPassword,
> sizeof(SmmCommunicateSetPassword.OldPassword));
> +    if (PasswordLen == sizeof(SmmCommunicateSetPassword.OldPassword))
> {
> +      DEBUG ((DEBUG_ERROR, "SmmPasswordHandler: OldPassword
> invalid!\n"));
> +      Status = EFI_INVALID_PARAMETER;
> +      goto EXIT;
> +    }
> +
> +    if (!IsPasswordVerified (&UserGuid,
> SmmCommunicateSetPassword.OldPassword, PasswordLen + 1)) {
> +      DEBUG ((DEBUG_ERROR, "SmmPasswordHandler: PasswordVerify -
> FAIL\n"));
> +      Status = EFI_SECURITY_VIOLATION;
> +      goto EXIT;
> +    }
> +
> +    PasswordLen =
> AsciiStrnLenS(SmmCommunicateSetPassword.NewPassword,
> sizeof(SmmCommunicateSetPassword.NewPassword));
> +    if (PasswordLen ==
> sizeof(SmmCommunicateSetPassword.NewPassword)) {
> +      DEBUG ((DEBUG_ERROR, "SmmPasswordHandler: NewPassword
> invalid!\n"));
> +      Status = EFI_INVALID_PARAMETER;
> +      goto EXIT;
> +    }
> +    if (!IsPasswordStrong (SmmCommunicateSetPassword.NewPassword,
> PasswordLen + 1)) {
> +      DEBUG ((DEBUG_ERROR, "SmmPasswordHandler: NewPassword too
> weak!\n"));
> +      Status = EFI_UNSUPPORTED;
> +      goto EXIT;
> +    }
> +    if (IsPasswordInHistory (&UserGuid,
> SmmCommunicateSetPassword.NewPassword, PasswordLen + 1)) {
> +      DEBUG ((DEBUG_ERROR, "SmmPasswordHandler: NewPassword in
> history!\n"));
> +      Status = EFI_ALREADY_STARTED;
> +      goto EXIT;
> +    }
> +
> +    if (PasswordLen == 0) {
> +      Status = SavePasswordToVariable (&UserGuid, NULL, 0);
> +    } else {
> +      Status = SavePasswordToVariable (&UserGuid,
> SmmCommunicateSetPassword.NewPassword, PasswordLen + 1);
> +    }
> +    break;
> +
> +  case SMM_PASSWORD_FUNCTION_VERIFY_PASSWORD:
> +    if (*PasswordTryCount >= PASSWORD_MAX_TRY_COUNT) {
> +      DEBUG ((DEBUG_ERROR, "SmmPasswordHandler: VERIFY_PASSWORD
> try count reach!\n"));
> +      PasswordTryCount = NULL;
> +      Status = EFI_INVALID_PARAMETER;
> +      goto EXIT;
> +    }
> +    if (CommBufferPayloadSize !=
> sizeof(SMM_PASSWORD_COMMUNICATE_VERIFY_PASSWORD)) {
> +      DEBUG ((DEBUG_ERROR, "SmmPasswordHandler: VERIFY_PASSWORD
> payload buffer invalid!\n"));
> +      Status = EFI_INVALID_PARAMETER;
> +      goto EXIT;
> +    }
> +    CopyMem (&SmmCommunicateVerifyPassword, SmmFunctionHeader +
> 1, sizeof(SmmCommunicateVerifyPassword));
> +
> +    PasswordLen =
> AsciiStrnLenS(SmmCommunicateVerifyPassword.Password,
> sizeof(SmmCommunicateVerifyPassword.Password));
> +    if (PasswordLen == sizeof(SmmCommunicateVerifyPassword.Password))
> {
> +      DEBUG ((DEBUG_ERROR, "SmmPasswordHandler: Password invalid!\n"));
> +      Status = EFI_INVALID_PARAMETER;
> +      goto EXIT;
> +    }
> +    if (!IsPasswordVerified (&UserGuid,
> SmmCommunicateVerifyPassword.Password, PasswordLen + 1)) {
> +      DEBUG ((DEBUG_ERROR, "SmmPasswordHandler: PasswordVerify -
> FAIL\n"));
> +      Status = EFI_SECURITY_VIOLATION;
> +      goto EXIT;
> +    }
> +    Status = EFI_SUCCESS;
> +    break;
> +
> +  default:
> +    PasswordTryCount = NULL;
> +    Status = EFI_UNSUPPORTED;
> +    break;
> +  }
> +
> +EXIT:
> +  if (PasswordTryCount != NULL) {
> +    if (Status == EFI_SUCCESS) {
> +      *PasswordTryCount = 0;
> +    } else {
> +      *PasswordTryCount = *PasswordTryCount + 1;
> +    }
> +  }
> +  SmmFunctionHeader->ReturnStatus = Status;
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Main entry for this driver.
> +
> +  @param ImageHandle     Image handle this driver.
> +  @param SystemTable     Pointer to SystemTable.
> +
> +  @retval EFI_SUCESS     This function always complete successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PasswordSmmInit (
> +  IN EFI_HANDLE                         ImageHandle,
> +  IN EFI_SYSTEM_TABLE                   *SystemTable
> +  )
> +{
> +  EFI_STATUS                            Status;
> +  EFI_HANDLE                            SmmHandle;
> +  EDKII_VARIABLE_LOCK_PROTOCOL          *VariableLock;
> +  CHAR16
> PasswordHistoryName[sizeof(USER_AUTHENTICATION_VAR_NAME)/sizeof(
> CHAR16) + 4];
> +  UINTN                                 Index;
> +
> +  ASSERT (PASSWORD_HASH_SIZE == SHA256_DIGEST_SIZE);
> +  ASSERT (PASSWORD_HISTORY_CHECK_COUNT < 0xFFFF);
> +
> +  Status = gSmst->SmmLocateProtocol (&gEfiSmmVariableProtocolGuid,
> NULL, (VOID**)&mSmmVariable);
> +  ASSERT_EFI_ERROR (Status);
> +
> +  SmmHandle          = NULL;
> +
> +  //
> +  // Make "HddPassword" varible read-only for DXE driver for security
> concern.
> +  //
> +  Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL,
> (VOID **) &VariableLock);
> +  if (!EFI_ERROR (Status)) {
> +    Status = VariableLock->RequestToLock (VariableLock,
> USER_AUTHENTICATION_VAR_NAME, &gAdminAuthenticationGuid);
> +    ASSERT_EFI_ERROR (Status);
> +
> +    for (Index = 1; Index <= PASSWORD_HISTORY_CHECK_COUNT; Index++) {
> +      UnicodeSPrint (PasswordHistoryName, sizeof (PasswordHistoryName),
> L"%s%04x", USER_AUTHENTICATION_VAR_NAME, Index);
> +      Status = VariableLock->RequestToLock (VariableLock,
> PasswordHistoryName, &gAdminAuthenticationGuid);
> +      ASSERT_EFI_ERROR (Status);
> +    }
> +    Status = VariableLock->RequestToLock (VariableLock,
> USER_AUTHENTICATION_HISTORY_LAST_VAR_NAME,
> &gAdminAuthenticationGuid);
> +    ASSERT_EFI_ERROR (Status);
> +  }
> +
> +  SmmHandle = NULL;
> +  Status    = gSmst->SmiHandlerRegister (SmmPasswordHandler,
> &gAdminAuthenticationGuid, &SmmHandle);
> +  ASSERT_EFI_ERROR (Status);
> +  if (EFI_ERROR (Status)) {
> +    Status = EFI_OUT_OF_RESOURCES;
> +    goto EXIT;
> +  }
> +
> +  if (IsPasswordCleared()) {
> +    DEBUG ((DEBUG_INFO, "IsPasswordCleared\n"));
> +    SavePasswordToVariable (&gAdminAuthenticationGuid, NULL, 0);
> +  }
> +
> +  return EFI_SUCCESS;
> +
> +EXIT:
> +  if (SmmHandle != NULL) {
> +    gSmst->SmiHandlerUnRegister (SmmHandle);
> +  }
> +
> +  return Status;
> +}
> +
> diff --git
> a/SecurityPkg/Password/UserAuthentication/UserAuthenticationSmm.inf
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationSmm.inf
> new file mode 100644
> index 0000000..460809b
> --- /dev/null
> +++
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationSmm.inf
> @@ -0,0 +1,70 @@
> +## @file
> +#  User Authentication Smm Driver.
> +#
> +#  This driver provides SMM services for DXE user authentication module.
> +#
> +# Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
> +#
> +#  This program and the accompanying materials
> +#  are licensed and made available under the terms and conditions of the
> BSD License
> +#  which accompanies this distribution. The full text of the license may be
> found at
> +#  http://opensource.org/licenses/bsd-license.php
> +#
> +#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +#
> +#
> +##
> +
> +[Defines]
> +  INF_VERSION                    = 0x00010005
> +  BASE_NAME                      = UserAuthenticationSmm
> +  MODULE_UNI_FILE                = UserAuthenticationSmm.uni
> +  FILE_GUID                      = 458B03ED-6E53-414f-9F07-3A829C990641
> +  MODULE_TYPE                    = DXE_SMM_DRIVER
> +  VERSION_STRING                 = 1.0
> +  PI_SPECIFICATION_VERSION       = 0x0001000A
> +  ENTRY_POINT                    = PasswordSmmInit
> +
> +#
> +# The following information is for reference only and not required by the
> build tools.
> +#
> +#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC
> +#
> +
> +[Sources]
> +  UserAuthenticationSmm.c
> +  UserAuthenticationGuid.h
> +  KeyService.c
> +  KeyService.h
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +  MdeModulePkg/MdeModulePkg.dec
> +  CryptoPkg/CryptoPkg.dec
> +  SecurityPkg/SecurityPkg.dec
> +
> +[LibraryClasses]
> +  UefiBootServicesTableLib
> +  UefiDriverEntryPoint
> +  DebugLib
> +  BaseLib
> +  BaseMemoryLib
> +  PrintLib
> +  SmmServicesTableLib
> +  MemoryAllocationLib
> +  UefiLib
> +  BaseCryptLib
> +  PlatformPasswordLib
> +
> +[Protocols]
> +  gEdkiiVariableLockProtocolGuid                ## CONSUMES
> +  gEfiSmmVariableProtocolGuid                   ## CONSUMES
> +
> +[Depex]
> +  gEfiSmmVariableProtocolGuid
> +
> +[UserExtensions.TianoCore."ExtraFiles"]
> +  UserAuthenticationDxeExtra.uni
> +
> +
> diff --git
> a/SecurityPkg/Password/UserAuthentication/UserAuthenticationSmm.uni
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationSmm.uni
> new file mode 100644
> index 0000000..470c75c
> --- /dev/null
> +++
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationSmm.uni
> @@ -0,0 +1,22 @@
> +// /** @file
> +// User Authentication Smm Driver.
> +//
> +// This driver provides SMM services for DXE user authentication module.
> +//
> +// Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
> +//
> +// This program and the accompanying materials
> +// are licensed and made available under the terms and conditions of the
> BSD License
> +// which accompanies this distribution. The full text of the license may be
> found at
> +// http://opensource.org/licenses/bsd-license.php
> +//
> +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +//
> +// **/
> +
> +
> +#string STR_MODULE_ABSTRACT             #language en-US "SMM services for
> DXE user authentication module."
> +
> +#string STR_MODULE_DESCRIPTION          #language en-US "This driver
> provides SMM services for DXE user authentication module."
> +
> diff --git
> a/SecurityPkg/Password/UserAuthentication/UserAuthenticationSmmExtra.
> uni
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationSmmExtra.
> uni
> new file mode 100644
> index 0000000..5e338fe
> --- /dev/null
> +++
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationSmmExtra.
> uni
> @@ -0,0 +1,20 @@
> +// /** @file
> +// User Authentication Smm Driver.
> +//
> +// Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
> +//
> +// This program and the accompanying materials
> +// are licensed and made available under the terms and conditions of the
> BSD License
> +// which accompanies this distribution. The full text of the license may be
> found at
> +// http://opensource.org/licenses/bsd-license.php
> +//
> +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +//
> +// **/
> +
> +#string STR_PROPERTIES_MODULE_NAME
> +#language en-US
> +"User Authentication SMM Driver"
> +
> +
> --
> 2.7.4.windows.1

_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel
Re: [edk2] [PATCH V2 5/6] SecurityPkg/Password: Add Password based UserAuthentication modules.
Posted by Yao, Jiewen 7 years, 8 months ago
Good question.
1) I will remove the unused code.

2) If BaseMemoryLib is used, the malicious code may guess which byte is incorrect by analyzing time on error returned - technically.

The SlowCompareMem is designed to mitigate time-attack for comparison. It always compare the full memory even the first byte is different.



Thank you
Yao Jiewen

From: Long, Qin
Sent: Wednesday, February 8, 2017 4:49 PM
To: Yao, Jiewen <jiewen.yao@intel.com>; edk2-devel@lists.01.org
Cc: Zhang, Chao B <chao.b.zhang@intel.com>
Subject: RE: [PATCH V2 5/6] SecurityPkg/Password: Add Password based UserAuthentication modules.

Some comments:
1. I didn't see any usage of KeyLibGenerateLib interface. Remove or just designed for future usage?
2. Why need one extra KeyLibSlowCompareMem? Instead of using one in BaseMemoryLib?
     And if necessary, please add extra ASSERT handling as the comments.

Reviewed-by: Qin Long <qin.long@intel.com<mailto:qin.long@intel.com>>

Best Regards & Thanks,
LONG, Qin


> -----Original Message-----
> From: Yao, Jiewen
> Sent: Tuesday, February 7, 2017 12:24 AM
> To: edk2-devel@lists.01.org<mailto:edk2-devel@lists.01.org>
> Cc: Long, Qin <qin.long@intel.com<mailto:qin.long@intel.com>>; Zhang, Chao B
> <chao.b.zhang@intel.com<mailto:chao.b.zhang@intel.com>>
> Subject: [PATCH V2 5/6] SecurityPkg/Password: Add Password based
> UserAuthentication modules.
>
> This password based user authentication is to verify user when a user
> wants to enter BIOS setup page.
>
> The DXE driver registers report status code listener.
> When it gets (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_PC_USER_SETUP)
> progress
> code, it will let the user input password.
> If and only if the user inputs the right password, the status code handler
> will return and let the setup driver continue running.
> If the user inputs the wrong password, the status code handler will let
> user try again.
> If the user inputs the wrong password 3 times, the status code handler will
> reset the system.
>
> The DXE driver also register a setup page in setup browser, so that
> user may update the password.
>
> The DXE driver uses SMI to let SMM driver do the password verification
> and management.
>
> The SMM driver registers SMI handler to perform the request from DXE.
> The password must meet below criteria:
> 1) Length >= 8 char
> 2) It must include lower case, upper case, number and symbol.
> 3) It must not duplicate with 5 previous password.
> If above criteria is met, the password will be saved to a read only UEFI
> variable. The format is password hash+salt, which is generated by
> Pkcs5HashPassword algorithm (SHA256+1000 iteration).
>
> If the SMM driver gets wrong password 3 times, the interface is locked
> and does not accept more request.
>
> If the SMM driver will detect IsPasswordCleared() at the entry point and
> clear the password if IsPasswordCleared() is TRUE. This can be used when
> the user forgets the password.
>
> Cc: Qin Long <qin.long@intel.com<mailto:qin.long@intel.com>>
> Cc: Chao Zhang <chao.b.zhang@intel.com<mailto:chao.b.zhang@intel.com>>
> Contributed-under: TianoCore Contribution Agreement 1.0
> Signed-off-by: Jiewen Yao <jiewen.yao@intel.com<mailto:jiewen.yao@intel.com>>
> ---
>  SecurityPkg/Password/UserAuthentication/KeyService.c                     | 210
> ++++++
>  SecurityPkg/Password/UserAuthentication/KeyService.h                     | 122
> ++++
>  SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.c          |
> 718 ++++++++++++++++++++
>  SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.h          |
> 115 ++++
>  SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.inf        |
> 79 +++
>  SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.uni        |
> 22 +
>  SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeExtra.uni
> |  20 +
>
> SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeFormset.
> h   |  30 +
>
> SecurityPkg/Password/UserAuthentication/UserAuthenticationDxePasswor
> d.c  | 301 ++++++++
>
> SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeStrings.u
> ni |  29 +
>  SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeVfr.vfr
> |  38 ++
>  SecurityPkg/Password/UserAuthentication/UserAuthenticationGuid.h         |
> 65 ++
>  SecurityPkg/Password/UserAuthentication/UserAuthenticationSmm.c          |
> 672 ++++++++++++++++++
>  SecurityPkg/Password/UserAuthentication/UserAuthenticationSmm.inf
> |  70 ++
>  SecurityPkg/Password/UserAuthentication/UserAuthenticationSmm.uni
> |  22 +
>
> SecurityPkg/Password/UserAuthentication/UserAuthenticationSmmExtra.un
> i   |  20 +
>  16 files changed, 2533 insertions(+)
>
> diff --git a/SecurityPkg/Password/UserAuthentication/KeyService.c
> b/SecurityPkg/Password/UserAuthentication/KeyService.c
> new file mode 100644
> index 0000000..81aa2f9
> --- /dev/null
> +++ b/SecurityPkg/Password/UserAuthentication/KeyService.c
> @@ -0,0 +1,210 @@
> +/** @file
> +  Password key service.
> +
> +Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
> +This program and the accompanying materials
> +are licensed and made available under the terms and conditions of the BSD
> License
> +which accompanies this distribution.  The full text of the license may be
> found at
> +http://opensource.org/licenses/bsd-license.php
> +
> +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +
> +**/
> +
> +#include <Uefi.h>
> +#include <Library/DebugLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/BaseCryptLib.h>
> +#include "KeyService.h"
> +
> +#define DEFAULT_AES_KEY_BIT_SIZE       256
> +#define DEFAULT_PBKDF2_ITERATION_COUNT 1000
> +
> +/**
> +  Compares the contents of two buffers with slow algorithm
> +
> +  This function compares Length bytes of SourceBuffer to Length bytes of
> DestinationBuffer.
> +  If all Length bytes of the two buffers are identical, then 0 is returned.
> Otherwise, the
> +  value returned is the first mismatched byte in SourceBuffer subtracted
> from the first
> +  mismatched byte in DestinationBuffer.
> +
> +  If Length > 0 and DestinationBuffer is NULL, then ASSERT().
> +  If Length > 0 and SourceBuffer is NULL, then ASSERT().
> +  If Length is greater than (MAX_ADDRESS - DestinationBuffer + 1), then
> ASSERT().
> +  If Length is greater than (MAX_ADDRESS - SourceBuffer + 1), then
> ASSERT().
> +
> +  @param  DestinationBuffer The pointer to the destination buffer to
> compare.
> +  @param  SourceBuffer      The pointer to the source buffer to compare.
> +  @param  Length            The number of bytes to compare.
> +
> +  @return 0                 All Length bytes of the two buffers are identical.
> +  @retval -1                The SourceBuffer is not identical to DestinationBuffer.
> +
> +**/
> +INTN
> +EFIAPI
> +KeyLibSlowCompareMem (
> +  IN CONST VOID  *DestinationBuffer,
> +  IN CONST VOID  *SourceBuffer,
> +  IN UINTN       Length
> +  )
> +{
> +  UINT8  Delta;
> +  UINTN  Index;
> +  UINT8  *Destination;
> +  UINT8  *Source;
> +
> +  Destination = (UINT8 *)DestinationBuffer;
> +  Source = (UINT8 *)SourceBuffer;
> +  Delta = 0;
> +  for (Index = 0; Index < Length; Index++) {
> +    Delta |= Destination[Index] ^ Source[Index];
> +  }
> +  if (Delta == 0) {
> +    return 0;
> +  } else {
> +    return -1;
> +  }
> +}
> +
> +/**
> +  Generate Salt value.
> +
> +  @param[in, out]   SaltValue           Points to the salt buffer
> +  @param[in]        SaltSize            Size of the salt buffer
> +
> +  @retval      TRUE           Salt is generated.
> +  @retval      FALSE          Salt is not generated.
> +**/
> +BOOLEAN
> +EFIAPI
> +KeyLibGenerateSalt (
> +  IN OUT UINT8  *SaltValue,
> +  IN UINTN      SaltSize
> +  )
> +{
> +  if (SaltValue == NULL) {
> +    return FALSE;
> +  }
> +  RandomSeed(NULL, 0);
> +  RandomBytes(SaltValue, SaltSize);
> +  return TRUE;
> +}
> +
> +/**
> +  Hash the data.
> +
> +  @param[in]   HashType         Hash type
> +  @param[in]   Key              Points to the key buffer
> +  @param[in]   KeySize          Key buffer size
> +  @param[in]   SaltValue        Points to the salt buffer
> +  @param[in]   SaltSize         Size of the salt buffer
> +  @param[out]  KeyHash          Points to the hashed result
> +  @param[in]   KeyHashSize      Size of the hash buffer
> +
> +  @retval      TRUE           Hash the data successfully.
> +  @retval      FALSE          Failed to hash the data.
> +
> +**/
> +BOOLEAN
> +EFIAPI
> +KeyLibGenerateHash(
> +  IN   UINT32              HashType,
> +  IN   VOID                *Key,
> +  IN   UINTN               KeySize,
> +  IN   UINT8               *SaltValue,
> +  IN   UINTN               SaltSize,
> +  OUT  UINT8               *KeyHash,
> +  IN   UINTN               KeyHashSize
> +  )
> +{
> +  BOOLEAN                     Status;
> +  UINTN                       HashSize;
> +  VOID                        *HashContext;
> +
> +  if (HashType != HASH_TYPE_SHA256) {
> +    return FALSE;
> +  }
> +  if (KeyHashSize != SHA256_DIGEST_SIZE) {
> +    return FALSE;
> +  }
> +
> +  if ((Key == NULL) || (SaltValue == NULL) || (KeyHash == NULL)) {
> +    return FALSE;
> +  }
> +
> +  HashSize    = Sha256GetContextSize ();
> +  HashContext = AllocateZeroPool (HashSize);
> +  if (HashContext == NULL) {
> +    return FALSE;
> +  }
> +
> +  Status = Sha256Init(HashContext);
> +  if (!Status) {
> +    goto Done;
> +  }
> +
> +  Status = Sha256Update(HashContext, SaltValue, SaltSize);
> +  if (!Status) {
> +    goto Done;
> +  }
> +  Status = Sha256Update(HashContext, Key, KeySize);
> +  if (!Status) {
> +    goto Done;
> +  }
> +
> +  Status = Sha256Final(HashContext, KeyHash);
> +Done:
> +  FreePool (HashContext);
> +  return Status;
> +}
> +
> +/**
> +  Hash the password with PBKDF2.
> +
> +  @param[in]   HashType         Hash type
> +  @param[in]   Key              Points to the key buffer
> +  @param[in]   KeySize          Key buffer size
> +  @param[in]   SaltValue        Points to the salt buffer
> +  @param[in]   SaltSize         Size of the salt buffer
> +  @param[out]  KeyHash          Points to the hashed result
> +  @param[in]   KeyHashSize      Size of the hash buffer
> +
> +  @retval      TRUE           Hash the data successfully.
> +  @retval      FALSE          Failed to hash the data.
> +
> +**/
> +BOOLEAN
> +EFIAPI
> +KeyLibGeneratePBKDF2Hash (
> +  IN   UINT32              HashType,
> +  IN   VOID                *Key,
> +  IN   UINTN               KeySize,
> +  IN   UINT8               *SaltValue,
> +  IN   UINTN               SaltSize,
> +  OUT  UINT8               *KeyHash,
> +  IN   UINTN               KeyHashSize
> +  )
> +{
> +  BOOLEAN  Result;
> +
> +  if (HashType != HASH_TYPE_SHA256) {
> +    return FALSE;
> +  }
> +  if (KeyHashSize != SHA256_DIGEST_SIZE) {
> +    return FALSE;
> +  }
> +
> +  Result = Pkcs5HashPassword (
> +             KeySize,
> +             Key,
> +             SaltSize,
> +             SaltValue,
> +             DEFAULT_PBKDF2_ITERATION_COUNT,
> +             SHA256_DIGEST_SIZE,
> +             KeyHashSize,
> +             KeyHash
> +             );
> +  return Result;
> +}
> diff --git a/SecurityPkg/Password/UserAuthentication/KeyService.h
> b/SecurityPkg/Password/UserAuthentication/KeyService.h
> new file mode 100644
> index 0000000..f287953
> --- /dev/null
> +++ b/SecurityPkg/Password/UserAuthentication/KeyService.h
> @@ -0,0 +1,122 @@
> +/** @file
> +  Header file for key service.
> +
> +  Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
> +  This program and the accompanying materials
> +  are licensed and made available under the terms and conditions of the BSD
> License
> +  which accompanies this distribution.  The full text of the license may be
> found at
> +  http://opensource.org/licenses/bsd-license.php
> +
> +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +
> +**/
> +
> +#ifndef __KEY_LIB_H__
> +#define __KEY_LIB_H__
> +
> +/**
> +  Compares the contents of two buffers with slow algorithm
> +
> +  This function compares Length bytes of SourceBuffer to Length bytes of
> DestinationBuffer.
> +  If all Length bytes of the two buffers are identical, then 0 is returned.
> Otherwise, the
> +  value returned is the first mismatched byte in SourceBuffer subtracted
> from the first
> +  mismatched byte in DestinationBuffer.
> +
> +  If Length > 0 and DestinationBuffer is NULL, then ASSERT().
> +  If Length > 0 and SourceBuffer is NULL, then ASSERT().
> +  If Length is greater than (MAX_ADDRESS - DestinationBuffer + 1), then
> ASSERT().
> +  If Length is greater than (MAX_ADDRESS - SourceBuffer + 1), then
> ASSERT().
> +
> +  @param  DestinationBuffer The pointer to the destination buffer to
> compare.
> +  @param  SourceBuffer      The pointer to the source buffer to compare.
> +  @param  Length            The number of bytes to compare.
> +
> +  @return 0                 All Length bytes of the two buffers are identical.
> +  @retval -1                The SourceBuffer is not identical to DestinationBuffer.
> +
> +**/
> +INTN
> +EFIAPI
> +KeyLibSlowCompareMem (
> +  IN CONST VOID  *DestinationBuffer,
> +  IN CONST VOID  *SourceBuffer,
> +  IN UINTN       Length
> +  );
> +
> +/**
> +  Generate Salt value.
> +
> +  @param[in, out]   SaltValue           Points to the salt buffer
> +  @param[in]        SaltSize            Size of the salt buffer
> +
> +  @retval      TRUE           Salt is generated.
> +  @retval      FALSE          Salt is not generated.
> +**/
> +BOOLEAN
> +EFIAPI
> +KeyLibGenerateSalt(
> +  IN OUT UINT8  *SaltValue,
> +  IN UINTN      SaltSize
> +  );
> +
> +#define HASH_TYPE_SHA256  0x000B
> +
> +#define SHA256_DIGEST_SIZE 32
> +
> +/**
> +  Hash the data.
> +
> +  @param[in]   HashType         Hash type
> +  @param[in]   Key              Points to the key buffer
> +  @param[in]   KeySize          Key buffer size
> +  @param[in]   SaltValue        Points to the salt buffer
> +  @param[in]   SaltSize         Size of the salt buffer
> +  @param[out]  KeyHash          Points to the hashed result
> +  @param[in]   KeyHashSize      Size of the hash buffer
> +
> +  @retval      TRUE           Hash the data successfully.
> +  @retval      FALSE          Failed to hash the data.
> +
> +**/
> +BOOLEAN
> +EFIAPI
> +KeyLibGenerateHash(
> +  IN   UINT32              HashType,
> +  IN   VOID                *Key,
> +  IN   UINTN               KeySize,
> +  IN   UINT8               *SaltValue,
> +  IN   UINTN               SaltSize,
> +  OUT  UINT8               *KeyHash,
> +  IN   UINTN               KeyHashSize
> +  );
> +
> +/**
> +  Hash the password with PBKDF2.
> +
> +  @param[in]   HashType         Hash type
> +  @param[in]   Key              Points to the key buffer
> +  @param[in]   KeySize          Key buffer size
> +  @param[in]   SaltValue        Points to the salt buffer
> +  @param[in]   SaltSize         Size of the salt buffer
> +  @param[out]  KeyHash          Points to the hashed result
> +  @param[in]   KeyHashSize      Size of the hash buffer
> +
> +  @retval      TRUE           Hash the data successfully.
> +  @retval      FALSE          Failed to hash the data.
> +
> +**/
> +BOOLEAN
> +EFIAPI
> +KeyLibGeneratePBKDF2Hash (
> +  IN   UINT32              HashType,
> +  IN   VOID                *Key,
> +  IN   UINTN               KeySize,
> +  IN   UINT8               *SaltValue,
> +  IN   UINTN               SaltSize,
> +  OUT  UINT8               *KeyHash,
> +  IN   UINTN               KeyHashSize
> +  );
> +
> +#endif
> +
> diff --git
> a/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.c
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.c
> new file mode 100644
> index 0000000..3836eac
> --- /dev/null
> +++ b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.c
> @@ -0,0 +1,718 @@
> +/** @file
> +  This Driver mainly do user authentication before entering Setup.
> +
> +Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
> +This program and the accompanying materials
> +are licensed and made available under the terms and conditions of the BSD
> License
> +which accompanies this distribution.  The full text of the license may be
> found at
> +http://opensource.org/licenses/bsd-license.php
> +
> +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +
> +**/
> +
> +#include "UserAuthenticationDxe.h"
> +
> +EFI_EVENT                           mExitBootServicesEvent  = NULL;
> +EFI_RSC_HANDLER_PROTOCOL           *mRscHandlerProtocol     = NULL;
> +USER_AUTHENTICATION_PRIVATE_DATA   *mUserAuthenticationData =
> NULL;
> +
> +UINTN  mAdminPasswordTryCount;
> +
> +EFI_GUID gAdminAuthenticationGuid = ADMIN_AUTHENTICATION_GUID;
> +
> +HII_VENDOR_DEVICE_PATH  mHiiVendorDevicePath = {
> +  {
> +    {
> +      HARDWARE_DEVICE_PATH,
> +      HW_VENDOR_DP,
> +      {
> +        (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
> +        (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
> +      }
> +    },
> +    USER_AUTHENTICATION_FORMSET_GUID
> +  },
> +  {
> +    END_DEVICE_PATH_TYPE,
> +    END_ENTIRE_DEVICE_PATH_SUBTYPE,
> +    {
> +      (UINT8) (END_DEVICE_PATH_LENGTH),
> +      (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
> +    }
> +  }
> +};
> +
> +/**
> +  Get a user input string.
> +
> +  @param[in]       PopUpString      A popup string to inform user.
> +  @param[in, out]  UserInput        The user input string
> +  @param[in]       UserInputMaxLen  The max unicode count of the
> UserInput without NULL terminator.
> +**/
> +EFI_STATUS
> +GetUserInput (
> +  IN     CHAR16      *PopUpString,
> +  IN OUT CHAR16      *UserInput,
> +  IN     UINTN       UserInputMaxLen
> +  )
> +{
> +  EFI_INPUT_KEY                InputKey;
> +  UINTN                        InputLength;
> +  CHAR16                       *Mask;
> +
> +  UserInput[0] = 0;
> +  Mask = AllocateZeroPool ((UserInputMaxLen + 1) * sizeof(CHAR16));
> +  if (Mask == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  InputLength = 0;
> +
> +  while (TRUE) {
> +    Mask[InputLength] = L'_';
> +    CreatePopUp (
> +      EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
> +      &InputKey,
> +      PopUpString,
> +      L"---------------------",
> +      Mask,
> +      NULL
> +      );
> +    if (InputKey.ScanCode == SCAN_NULL) {
> +      //
> +      // Check whether finish inputing password.
> +      //
> +      if (InputKey.UnicodeChar == CHAR_CARRIAGE_RETURN && InputLength >
> 0) {
> +        //
> +        // Add the null terminator.
> +        //
> +        UserInput[InputLength] = 0;
> +        break;
> +      } else if ((InputKey.UnicodeChar == CHAR_NULL) ||
> +                 (InputKey.UnicodeChar == CHAR_TAB) ||
> +                 (InputKey.UnicodeChar == CHAR_LINEFEED) ||
> +                 (InputKey.UnicodeChar == CHAR_CARRIAGE_RETURN)
> +                ) {
> +        continue;
> +      } else {
> +        //
> +        // delete last key entered
> +        //
> +        if (InputKey.UnicodeChar == CHAR_BACKSPACE) {
> +          if (InputLength > 0) {
> +            UserInput[InputLength] = 0;
> +            Mask[InputLength] = 0;
> +            InputLength--;
> +          }
> +        } else {
> +          //
> +          // add Next key entry
> +          //
> +          UserInput[InputLength] = InputKey.UnicodeChar;
> +          Mask[InputLength] = L'*';
> +          InputLength++;
> +          if (InputLength == UserInputMaxLen) {
> +            //
> +            // Add the null terminator.
> +            //
> +            UserInput[InputLength] = 0;
> +            Mask[InputLength] = 0;
> +            break;
> +          }
> +        }
> +      }
> +    }
> +  }
> +  FreePool (Mask);
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Display a message box to end user.
> +
> +  @param[in] DisplayString   The string in message box.
> +**/
> +VOID
> +MessageBox (
> +  IN CHAR16  *DisplayString
> +  )
> +{
> +  EFI_INPUT_KEY  Key;
> +
> +  do {
> +    CreatePopUp (
> +      EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
> +      &Key,
> +      L"",
> +      DisplayString,
> +      L"Press ENTER to continue ...",
> +      L"",
> +      NULL
> +      );
> +  } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
> +}
> +
> +/**
> +  Force system reset.
> +**/
> +VOID
> +ForceSystemReset (
> +  VOID
> +  )
> +{
> +  MessageBox (L"Password retry count reach, reset system!");
> +  gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);
> +  CpuDeadLoop();
> +}
> +
> +/**
> +  Display message for set password.
> +
> +  @param[in]  ReturnStatus   The return status for set password.
> +**/
> +VOID
> +PrintPasswordStatus (
> +  IN EFI_STATUS  ReturnStatus
> +  )
> +{
> +  CHAR16         *DisplayString;
> +
> +  if (ReturnStatus == EFI_SUCCESS) {
> +    DisplayString = L"New password is updated successfully!";
> +  } else if (ReturnStatus == EFI_UNSUPPORTED) {
> +    DisplayString = L"New password is not strong enough!";
> +  } else if (ReturnStatus == EFI_ALREADY_STARTED) {
> +    DisplayString = L"New password is found in history!";
> +  } else {
> +    DisplayString = L"New password update fails!";
> +  }
> +
> +  MessageBox (DisplayString);
> +}
> +
> +/**
> +  Require user input password.
> +
> +  @param[in]  UserGuid               The user GUID of the password.
> +
> +  @retval TRUE   User input correct password successfully.
> +  @retval FALSE  The password is not set.
> +**/
> +BOOLEAN
> +RequireUserPassword (
> +  IN   EFI_GUID     *UserGuid
> +  )
> +{
> +  EFI_STATUS                   Status;
> +  CHAR16                       UserInputPw[MAX_PASSWORD_LEN + 1];
> +  CHAR16                       TmpPassword[MAX_PASSWORD_LEN + 1];
> +  CHAR16                       *PopUpString;
> +  UINTN                        *PasswordTryCount;
> +
> +  Status = EFI_SUCCESS;
> +  ZeroMem(UserInputPw, sizeof(UserInputPw));
> +  ZeroMem(TmpPassword, sizeof(TmpPassword));
> +
> +  if (!IsPasswordSet(UserGuid)) {
> +    return FALSE;
> +  }
> +
> +  if (CompareGuid (UserGuid, &gAdminAuthenticationGuid)) {
> +    PopUpString = L"Please input admin password";
> +    PasswordTryCount = &mAdminPasswordTryCount;
> +  } else {
> +    DEBUG ((DEBUG_ERROR, "Invalid User Guid - %g\n", UserGuid));
> +    return FALSE;
> +  }
> +
> +  while (TRUE) {
> +    gST->ConOut->ClearScreen(gST->ConOut);
> +    GetUserInput (PopUpString, UserInputPw, MAX_PASSWORD_LEN);
> +
> +    CopyGuid (UserGuid, &gAdminAuthenticationGuid);
> +    Status = ValidatePassword (UserGuid, UserInputPw,
> StrSize(UserInputPw));
> +    if (!EFI_ERROR(Status)) {
> +      break;
> +    }
> +    *PasswordTryCount = *PasswordTryCount + 1;
> +    if (*PasswordTryCount >= PASSWORD_MAX_TRY_COUNT) {
> +      ForceSystemReset ();
> +    }
> +    MessageBox (L"Incorrect password!");
> +  }
> +  *PasswordTryCount = 0;
> +
> +  ZeroMem(UserInputPw, sizeof(UserInputPw));
> +  ZeroMem(TmpPassword, sizeof(TmpPassword));
> +
> +  gST->ConOut->ClearScreen(gST->ConOut);
> +
> +  return TRUE;
> +}
> +
> +/**
> +  Set user password.
> +
> +  @param[in]  UserGuid               The user GUID of the password.
> +
> +  @retval TRUE   The password is set.
> +  @retval FALSE  The password is not set.
> +**/
> +BOOLEAN
> +SetUserPassword (
> +  IN   EFI_GUID     *UserGuid
> +  )
> +{
> +  EFI_STATUS                   Status;
> +  CHAR16                       UserInputPw[MAX_PASSWORD_LEN + 1];
> +  CHAR16                       TmpPassword[MAX_PASSWORD_LEN + 1];
> +  CHAR16                       *PopUpString;
> +  CHAR16                       *PopUpString2;
> +
> +  Status = EFI_SUCCESS;
> +  ZeroMem(UserInputPw, sizeof(UserInputPw));
> +  ZeroMem(TmpPassword, sizeof(TmpPassword));
> +
> +  if (CompareGuid (UserGuid, &gAdminAuthenticationGuid)) {
> +    PopUpString = L"Please set admin password";
> +  } else {
> +    DEBUG ((DEBUG_ERROR, "Invalid User Guid - %g\n", UserGuid));
> +    return FALSE;
> +  }
> +
> +  while (TRUE) {
> +    gST->ConOut->ClearScreen(gST->ConOut);
> +    GetUserInput (PopUpString, UserInputPw, MAX_PASSWORD_LEN);
> +
> +    PopUpString2 = L"Please confirm your new password";
> +    gST->ConOut->ClearScreen(gST->ConOut);
> +    GetUserInput (PopUpString2, TmpPassword, MAX_PASSWORD_LEN);
> +    if (StrCmp (TmpPassword, UserInputPw) != 0) {
> +      MessageBox (L"Password are not the same!");
> +      continue;
> +    }
> +
> +    Status = SetPassword (UserGuid, UserInputPw, StrSize(UserInputPw),
> NULL, 0);
> +    PrintPasswordStatus (Status);
> +    if (!EFI_ERROR(Status)) {
> +      break;
> +    }
> +  }
> +
> +  ZeroMem(UserInputPw, sizeof(UserInputPw));
> +  ZeroMem(TmpPassword, sizeof(TmpPassword));
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Check password before entering into setup.
> +
> +  @param  CodeType      Indicates the type of status code being reported.
> Type EFI_STATUS_CODE_TYPE is defined in "Related Definitions" below.
> +
> +  @param  Value         Describes the current status of a hardware or software
> entity.
> +                        This included information about the class and subclass that is
> used to classify the entity
> +                        as well as an operation.  For progress codes, the operation is the
> current activity.
> +                        For error codes, it is the exception.  For debug codes, it is not
> defined at this time.
> +                        Type EFI_STATUS_CODE_VALUE is defined in "Related
> Definitions" below.
> +                        Specific values are discussed in the Intel? Platform Innovation
> Framework for EFI Status Code Specification.
> +
> +  @param  Instance      The enumeration of a hardware or software entity
> within the system.
> +                        A system may contain multiple entities that match a
> class/subclass pairing.
> +                        The instance differentiates between them.  An instance of 0
> indicates that instance information is unavailable,
> +                        not meaningful, or not relevant.  Valid instance numbers start
> with 1.
> +
> +
> +  @param  CallerId      This optional parameter may be used to identify the
> caller.
> +                        This parameter allows the status code driver to apply different
> rules to different callers.
> +                        Type EFI_GUID is defined in InstallProtocolInterface() in the
> UEFI 2.0 Specification.
> +
> +
> +  @param  Data          This optional parameter may be used to pass additional
> data
> +
> +  @retval EFI_SUCCESS             Status code is what we expected.
> +  @retval EFI_UNSUPPORTED         Status code not supported.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +CheckForPassword (
> +  IN EFI_STATUS_CODE_TYPE     CodeType,
> +  IN EFI_STATUS_CODE_VALUE    Value,
> +  IN UINT32                   Instance,
> +  IN EFI_GUID                 *CallerId, OPTIONAL
> +  IN EFI_STATUS_CODE_DATA     *Data      OPTIONAL
> +  )
> +{
> +  BOOLEAN   PasswordSet;
> +
> +  if (((CodeType & EFI_STATUS_CODE_TYPE_MASK) ==
> EFI_PROGRESS_CODE) &&
> +      (Value == (EFI_SOFTWARE_DXE_BS_DRIVER |
> EFI_SW_PC_USER_SETUP))) {
> +    //
> +    // Check whether enter setup page.
> +    //
> +    PasswordSet = RequireUserPassword (&gAdminAuthenticationGuid);
> +    if (PasswordSet) {
> +      DEBUG ((DEBUG_INFO, "Welcome Admin!\n"));
> +    } else {
> +      DEBUG ((DEBUG_INFO, "Admin password is not set!\n"));
> +      if (NeedEnrollPassword()) {
> +        SetUserPassword (&gAdminAuthenticationGuid);
> +      }
> +    }
> +
> +    return EFI_SUCCESS;
> +  } else{
> +    return EFI_UNSUPPORTED;
> +  }
> +}
> +
> +/**
> +  This function allows a caller to extract the current configuration for one
> +  or more named elements from the target driver.
> +
> +  @param  This                   Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
> +  @param  Request                A null-terminated Unicode string in
> +                                 <ConfigRequest> format.
> +  @param  Progress               On return, points to a character in the Request
> +                                 string. Points to the string's null terminator if
> +                                 request was successful. Points to the most recent
> +                                 '&' before the first failing name/value pair (or
> +                                 the beginning of the string if the failure is in
> +                                 the first name/value pair) if the request was not
> +                                 successful.
> +  @param  Results                A null-terminated Unicode string in
> +                                 <ConfigAltResp> format which has all values filled
> +                                 in for the names in the Request string. String to
> +                                 be allocated by the called function.
> +
> +  @retval EFI_SUCCESS            The Results is filled with the requested values.
> +  @retval EFI_OUT_OF_RESOURCES   Not enough memory to store the
> results.
> +  @retval EFI_INVALID_PARAMETER  Request is illegal syntax, or unknown
> name.
> +  @retval EFI_NOT_FOUND          Routing data doesn't match any storage in
> this
> +                                 driver.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ExtractConfig (
> +  IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
> +  IN  CONST EFI_STRING                       Request,
> +  OUT EFI_STRING                             *Progress,
> +  OUT EFI_STRING                             *Results
> +  )
> +{
> +  if (Progress == NULL || Results == NULL) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +  *Progress = Request;
> +  return EFI_NOT_FOUND;
> +}
> +
> +
> +/**
> +  This function processes the results of changes in configuration.
> +
> +  @param  This                   Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
> +  @param  Configuration          A null-terminated Unicode string in
> <ConfigResp>
> +                                 format.
> +  @param  Progress               A pointer to a string filled in with the offset of
> +                                 the most recent '&' before the first failing
> +                                 name/value pair (or the beginning of the string if
> +                                 the failure is in the first name/value pair) or
> +                                 the terminating NULL if all was successful.
> +
> +  @retval EFI_SUCCESS            The Results is processed successfully.
> +  @retval EFI_INVALID_PARAMETER  Configuration is NULL.
> +  @retval EFI_NOT_FOUND          Routing data doesn't match any storage in
> this
> +                                 driver.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RouteConfig (
> +  IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
> +  IN  CONST EFI_STRING                       Configuration,
> +  OUT EFI_STRING                             *Progress
> +  )
> +{
> +  if (Configuration == NULL || Progress == NULL) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  *Progress = Configuration;
> +
> +  return EFI_NOT_FOUND;
> +}
> +
> +/**
> +  This function processes the results of changes in configuration.
> +
> +  @param  This                   Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
> +  @param  Action                 Specifies the type of action taken by the browser.
> +  @param  QuestionId             A unique value which is sent to the original
> +                                 exporting driver so that it can identify the type
> +                                 of data to expect.
> +  @param  Type                   The type of value for the question.
> +  @param  Value                  A pointer to the data being sent to the original
> +                                 exporting driver.
> +  @param  ActionRequest          On return, points to the action requested by
> the
> +                                 callback function.
> +
> +  @retval EFI_SUCCESS            The callback successfully handled the action.
> +  @retval EFI_OUT_OF_RESOURCES   Not enough storage is available to hold
> the
> +                                 variable and its data.
> +  @retval EFI_DEVICE_ERROR       The variable could not be saved.
> +  @retval EFI_UNSUPPORTED        The specified Action is not supported by
> the
> +                                 callback.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +UserAuthenticationCallback (
> +  IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
> +  IN  EFI_BROWSER_ACTION                     Action,
> +  IN  EFI_QUESTION_ID                        QuestionId,
> +  IN  UINT8                                  Type,
> +  IN  EFI_IFR_TYPE_VALUE                     *Value,
> +  OUT EFI_BROWSER_ACTION_REQUEST             *ActionRequest
> +  )
> +{
> +  EFI_STATUS  Status;
> +  CHAR16      *UserInputPassword;
> +  EFI_GUID    *UserGuid;
> +  UINTN       *PasswordTryCount;
> +
> +  Status = EFI_SUCCESS;
> +
> +  if (((Value == NULL) && (Action != EFI_BROWSER_ACTION_FORM_OPEN)
> && (Action != EFI_BROWSER_ACTION_FORM_CLOSE))||
> +      (ActionRequest == NULL)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  switch (Action) {
> +  case EFI_BROWSER_ACTION_CHANGING:
> +    {
> +      switch (QuestionId) {
> +      case ADMIN_PASSWORD_KEY_ID:
> +        UserGuid = &gAdminAuthenticationGuid;
> +        PasswordTryCount = &mAdminPasswordTryCount;
> +        if ((Type == EFI_IFR_TYPE_STRING) && (Value->string == 0) &&
> +            (mUserAuthenticationData->PasswordState ==
> BROWSER_STATE_SET_PASSWORD)) {
> +          mUserAuthenticationData->PasswordState =
> BROWSER_STATE_VALIDATE_PASSWORD;
> +          ZeroMem (mUserAuthenticationData->OldPassword,
> sizeof(mUserAuthenticationData->OldPassword));
> +          return EFI_INVALID_PARAMETER;
> +        }
> +        //
> +        // The Callback is responsible for validating old password input by user,
> +        // If Callback return EFI_SUCCESS, it indicates validation pass.
> +        //
> +        switch (mUserAuthenticationData->PasswordState) {
> +        case BROWSER_STATE_VALIDATE_PASSWORD:
> +          UserInputPassword = HiiGetString (mUserAuthenticationData-
> >HiiHandle, Value->string, NULL);
> +          if ((StrLen (UserInputPassword) >= PASSWORD_MAX_SIZE) ||
> (UserInputPassword[0] == 0)) {
> +            Status = EFI_NOT_READY;
> +            break;
> +          }
> +          Status = ValidatePassword (UserGuid, UserInputPassword, StrSize
> (UserInputPassword));
> +          if (Status == EFI_SUCCESS) {
> +            mUserAuthenticationData->PasswordState =
> BROWSER_STATE_SET_PASSWORD;
> +            StrCpyS (
> +              mUserAuthenticationData->OldPassword,
> +              sizeof(mUserAuthenticationData->OldPassword)/sizeof(CHAR16),
> +              UserInputPassword
> +              );
> +            *PasswordTryCount = 0;
> +          } else {
> +            //
> +            // Old password mismatch, return EFI_NOT_READY to prompt for
> error message.
> +            //
> +            Status = EFI_NOT_READY;
> +            *PasswordTryCount = *PasswordTryCount + 1;
> +            if (*PasswordTryCount >= PASSWORD_MAX_TRY_COUNT) {
> +              ForceSystemReset ();
> +            }
> +          }
> +          break;
> +
> +        case BROWSER_STATE_SET_PASSWORD:
> +          UserInputPassword = HiiGetString (mUserAuthenticationData-
> >HiiHandle, Value->string, NULL);
> +          if ((StrLen (UserInputPassword) >= PASSWORD_MAX_SIZE) ||
> (UserInputPassword[0] == 0)) {
> +            Status = EFI_NOT_READY;
> +            break;
> +          }
> +          Status = SetPassword (UserGuid, UserInputPassword, StrSize
> (UserInputPassword), mUserAuthenticationData->OldPassword,
> StrSize(mUserAuthenticationData->OldPassword));
> +          PrintPasswordStatus (Status);
> +          ZeroMem (mUserAuthenticationData->OldPassword,
> sizeof(mUserAuthenticationData->OldPassword));
> +          mUserAuthenticationData->PasswordState =
> BROWSER_STATE_VALIDATE_PASSWORD;
> +          break;
> +
> +        default:
> +          break;
> +        }
> +      default:
> +        break;
> +      }
> +    }
> +  default:
> +    break;
> +  }
> +  return Status;
> +}
> +
> +/**
> +  Unregister status code callback functions.
> +
> +  @param  Event         Event whose notification function is being invoked.
> +  @param  Context       Pointer to the notification function's context, which is
> +                        always zero in current implementation.
> +
> +**/
> +VOID
> +EFIAPI
> +UnregisterBootTimeHandlers (
> +  IN EFI_EVENT        Event,
> +  IN VOID             *Context
> +  )
> +{
> +  mRscHandlerProtocol->Unregister (CheckForPassword);
> +}
> +
> +/**
> +  User Authentication entry point.
> +
> +  @param ImageHandle     The image handle.
> +  @param SystemTable     The system table.
> +
> +  @retval EFI_SUCCESS    The entry point is executed successfully.
> +  @return  other         Contain some other errors.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +UserAuthenticationEntry (
> +  IN EFI_HANDLE           ImageHandle,
> +  IN EFI_SYSTEM_TABLE     *SystemTable
> +  )
> +{
> +  EFI_STATUS        Status;
> +  EFI_HANDLE        DriverHandle;
> +  EFI_HII_HANDLE    HiiHandle;
> +
> +  DriverHandle  = NULL;
> +
> +  mUserAuthenticationData = AllocateZeroPool (sizeof
> (USER_AUTHENTICATION_PRIVATE_DATA));
> +  if (mUserAuthenticationData == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  mUserAuthenticationData->ConfigAccess.ExtractConfig = ExtractConfig;
> +  mUserAuthenticationData->ConfigAccess.RouteConfig = RouteConfig;
> +  mUserAuthenticationData->ConfigAccess.Callback =
> UserAuthenticationCallback;
> +  mUserAuthenticationData->PasswordState =
> BROWSER_STATE_VALIDATE_PASSWORD;
> +
> +  //
> +  // Install Config Access protocol to driver handle.
> +  //
> +  Status = gBS->InstallMultipleProtocolInterfaces (
> +                  &DriverHandle,
> +                  &gEfiDevicePathProtocolGuid,
> +                  &mHiiVendorDevicePath,
> +                  &gEfiHiiConfigAccessProtocolGuid,
> +                  &mUserAuthenticationData->ConfigAccess,
> +                  NULL
> +                  );
> +  ASSERT_EFI_ERROR (Status);
> +  mUserAuthenticationData->DriverHandle = DriverHandle;
> +
> +  //
> +  // Add HII data to database.
> +  //
> +  HiiHandle = HiiAddPackages (
> +                   &gAdminAuthenticationGuid,
> +                   DriverHandle,
> +                   UserAuthenticationDxeStrings,
> +                   UserAuthenticationDxeVfrBin,
> +                   NULL
> +                   );
> +  if (HiiHandle == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +  mUserAuthenticationData->HiiHandle = HiiHandle;
> +
> +  //
> +  // Locate report status code protocol.
> +  //
> +  Status = gBS->LocateProtocol (
> +                  &gEfiRscHandlerProtocolGuid,
> +                  NULL,
> +                  (VOID **) &mRscHandlerProtocol
> +                  );
> +  ASSERT_EFI_ERROR (Status);
> +
> +  //
> +  //Register the callback function for ReportStatusCode() notification.
> +  //
> +  mRscHandlerProtocol->Register (CheckForPassword, TPL_HIGH_LEVEL);
> +
> +  //
> +  // Unregister boot time report status code listener at ExitBootService
> Event.
> +  //
> +  Status = gBS->CreateEventEx (
> +                  EVT_NOTIFY_SIGNAL,
> +                  TPL_NOTIFY,
> +                  UnregisterBootTimeHandlers,
> +                  NULL,
> +                  &gEfiEventExitBootServicesGuid,
> +                  &mExitBootServicesEvent
> +                  );
> +  ASSERT_EFI_ERROR (Status);
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Unloads the application and its installed protocol.
> +
> +  @param[in]  ImageHandle       Handle that identifies the image to be
> unloaded.
> +
> +  @retval EFI_SUCCESS           The image has been unloaded.
> +**/
> +EFI_STATUS
> +EFIAPI
> +UserAuthenticationUnload (
> +  IN EFI_HANDLE  ImageHandle
> +  )
> +{
> +  ASSERT (mUserAuthenticationData != NULL);
> +
> +  //
> +  // Uninstall Config Access Protocol.
> +  //
> +  if (mUserAuthenticationData->DriverHandle != NULL) {
> +    gBS->UninstallMultipleProtocolInterfaces (
> +           mUserAuthenticationData->DriverHandle,
> +           &gEfiDevicePathProtocolGuid,
> +           &mHiiVendorDevicePath,
> +           &gEfiHiiConfigAccessProtocolGuid,
> +           &mUserAuthenticationData->ConfigAccess,
> +           NULL
> +           );
> +    mUserAuthenticationData->DriverHandle = NULL;
> +  }
> +
> +  //
> +  // Remove Hii Data.
> +  //
> +  if (mUserAuthenticationData->HiiHandle != NULL) {
> +    HiiRemovePackages (mUserAuthenticationData->HiiHandle);
> +  }
> +
> +  FreePool (mUserAuthenticationData);
> +  mUserAuthenticationData = NULL;
> +
> +  return EFI_SUCCESS;
> +}
> +
> diff --git
> a/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.h
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.h
> new file mode 100644
> index 0000000..1bcc2a7
> --- /dev/null
> +++ b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.h
> @@ -0,0 +1,115 @@
> +/** @file
> +  Header file for UserAuthenticationDxe.
> +
> +Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
> +This program and the accompanying materials
> +are licensed and made available under the terms and conditions of the BSD
> License
> +which accompanies this distribution.  The full text of the license may be
> found at
> +http://opensource.org/licenses/bsd-license.php
> +
> +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +
> +
> +**/
> +
> +#ifndef _USER_AUTHENTICATION_DXE_H_
> +#define _USER_AUTHENTICATION_DXE_H_
> +
> +
> +#include <Protocol/ReportStatusCodeHandler.h>
> +#include <Protocol/HiiConfigAccess.h>
> +
> +#include <Guid/MdeModuleHii.h>
> +#include <Guid/HiiPlatformSetupFormset.h>
> +
> +#include <Library/DebugLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/UefiRuntimeServicesTableLib.h>
> +#include <Library/UefiDriverEntryPoint.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +#include <Library/BaseLib.h>
> +#include <Library/UefiLib.h>
> +#include <Library/HiiLib.h>
> +#include <Library/DevicePathLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/PlatformPasswordLib.h>
> +#include "UserAuthenticationGuid.h"
> +#include "UserAuthenticationDxeFormset.h"
> +
> +extern UINT8  UserAuthenticationDxeVfrBin[];
> +extern UINT8  UserAuthenticationDxeStrings[];
> +
> +typedef struct {
> +  EFI_HII_CONFIG_ACCESS_PROTOCOL       ConfigAccess;
> +  EFI_HANDLE                           DriverHandle;
> +  EFI_HII_HANDLE                       HiiHandle;
> +  UINT8                                PasswordState;
> +  CHAR16                               OldPassword[PASSWORD_MAX_SIZE];
> +} USER_AUTHENTICATION_PRIVATE_DATA;
> +
> +#pragma pack(1)
> +///
> +/// HII specific Vendor Device Path definition.
> +///
> +typedef struct {
> +  VENDOR_DEVICE_PATH             VendorDevicePath;
> +  EFI_DEVICE_PATH_PROTOCOL       End;
> +} HII_VENDOR_DEVICE_PATH;
> +#pragma pack()
> +
> +/**
> +  Validata if the password is correct.
> +
> +  @param[in]  UserGuid               The user GUID of the password.
> +  @param[in]  Password               The user input password.
> +  @param[in]  PasswordSize           The size of Password in byte.
> +
> +  @retval EFI_SUCCESS              The password is correct.
> +  @retval EFI_SECURITY_VIOLATION   The password is incorrect.
> +**/
> +EFI_STATUS
> +ValidatePassword (
> +  IN   EFI_GUID     *UserGuid,
> +  IN   CHAR16       *Password,
> +  IN   UINTN        PasswordSize
> +  );
> +
> +/**
> +  Set a new password.
> +
> +  @param[in]  UserGuid               The user GUID of the password.
> +  @param[in]  NewPassword            The user input new password.
> +                                     NULL means clear password.
> +  @param[in]  NewPasswordSize        The size of NewPassword in byte.
> +  @param[in]  OldPassword            The user input old password.
> +                                     NULL means no old password.
> +  @param[in]  OldPasswordSize        The size of OldPassword in byte.
> +
> +  @retval EFI_SUCCESS              The password is correct.
> +  @retval EFI_SECURITY_VIOLATION   The password is incorrect.
> +  @retval EFI_OUT_OF_RESOURCES     Insufficient resources to set the
> password.
> +**/
> +EFI_STATUS
> +SetPassword (
> +  IN   EFI_GUID     *UserGuid,
> +  IN   CHAR16       *NewPassword,     OPTIONAL
> +  IN   UINTN        NewPasswordSize,
> +  IN   CHAR16       *OldPassword,     OPTIONAL
> +  IN   UINTN        OldPasswordSize
> +  );
> +
> +/**
> +  Return if the password is set.
> +
> +  @param[in]  UserGuid               The user GUID of the password.
> +
> +  @retval TRUE    The password is set.
> +  @retval FALSE   The password is not set.
> +**/
> +BOOLEAN
> +IsPasswordSet (
> +  IN   EFI_GUID     *UserGuid
> +  );
> +
> +#endif
> diff --git
> a/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.inf
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.inf
> new file mode 100644
> index 0000000..75a8076
> --- /dev/null
> +++
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.inf
> @@ -0,0 +1,79 @@
> +## @file
> +#  User Authentication Dxe Driver.
> +#
> +#  This Driver mainly does user authentication before entering Setup.
> +#
> +# Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
> +#
> +#  This program and the accompanying materials
> +#  are licensed and made available under the terms and conditions of the
> BSD License
> +#  which accompanies this distribution. The full text of the license may be
> found at
> +#  http://opensource.org/licenses/bsd-license.php
> +#
> +#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +#
> +#
> +##
> +
> +[Defines]
> +  INF_VERSION                    = 0x00010005
> +  BASE_NAME                      = UserAuthenticationDxe
> +  MODULE_UNI_FILE                = UserAuthenticationDxe.uni
> +  FILE_GUID                      = 0683FB88-664C-4BA6-9ED4-1C0916EE43A4
> +  MODULE_TYPE                    = DXE_DRIVER
> +  VERSION_STRING                 = 2.0
> +  ENTRY_POINT                    = UserAuthenticationEntry
> +  ENTRY_POINT                    = PasswordDxeInit
> +  UNLOAD_IMAGE                   = UserAuthenticationUnload
> +
> +
> +[Sources]
> +  UserAuthenticationDxe.c
> +  UserAuthenticationDxe.h
> +  UserAuthenticationDxePassword.c
> +  UserAuthenticationDxeFormset.h
> +  UserAuthenticationGuid.h
> +  UserAuthenticationDxeVfr.vfr
> +  UserAuthenticationDxeStrings.uni
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +  MdeModulePkg/MdeModulePkg.dec
> +  SecurityPkg/SecurityPkg.dec
> +
> +[LibraryClasses]
> +  BaseLib
> +  UefiBootServicesTableLib
> +  UefiDriverEntryPoint
> +  UefiRuntimeServicesTableLib
> +  BaseMemoryLib
> +  DebugLib
> +  UefiLib
> +  HiiLib
> +  DevicePathLib
> +  MemoryAllocationLib
> +  PlatformPasswordLib
> +
> +[Guids]
> +  gEfiEventExitBootServicesGuid                 ## CONSUMES  ## Event
> +  gEdkiiPiSmmCommunicationRegionTableGuid       ## CONSUMES  ##
> SystemTable
> +
> +[Protocols]
> +  gEfiRscHandlerProtocolGuid                    ## CONSUMES
> +  gEfiDevicePathProtocolGuid                    ## PRODUCES
> +  gEfiHiiConfigAccessProtocolGuid               ## PRODUCES
> +  gEfiSmmCommunicationProtocolGuid              ## CONSUMES
> +
> +[Depex]
> +  gEfiSimpleTextOutProtocolGuid      AND
> +  gEfiHiiDatabaseProtocolGuid        AND
> +  gEfiSmmCommunicationProtocolGuid   AND
> +  gEfiVariableArchProtocolGuid       AND
> +  gEfiVariableWriteArchProtocolGuid
> +
> +[UserExtensions.TianoCore."ExtraFiles"]
> +  UserAuthenticationDxeExtra.uni
> +
> +
> +
> diff --git
> a/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.uni
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.uni
> new file mode 100644
> index 0000000..6b2d292
> --- /dev/null
> +++
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.uni
> @@ -0,0 +1,22 @@
> +// /** @file
> +// User Authentication Dxe Driver.
> +//
> +// This driver mainly does the user authentication before entering Setup.
> +//
> +// Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
> +//
> +// This program and the accompanying materials
> +// are licensed and made available under the terms and conditions of the
> BSD License
> +// which accompanies this distribution. The full text of the license may be
> found at
> +// http://opensource.org/licenses/bsd-license.php
> +//
> +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +//
> +// **/
> +
> +
> +#string STR_MODULE_ABSTRACT             #language en-US "User
> Authentication Dxe Driver."
> +
> +#string STR_MODULE_DESCRIPTION          #language en-US "This driver
> mainly does user authentication before entering Setup."
> +
> diff --git
> a/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeExtra.u
> ni
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeExtra.u
> ni
> new file mode 100644
> index 0000000..86c5c9b
> --- /dev/null
> +++
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeExtra.u
> ni
> @@ -0,0 +1,20 @@
> +// /** @file
> +// User Authentication Dxe Driver.
> +//
> +// Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
> +//
> +// This program and the accompanying materials
> +// are licensed and made available under the terms and conditions of the
> BSD License
> +// which accompanies this distribution. The full text of the license may be
> found at
> +// http://opensource.org/licenses/bsd-license.php
> +//
> +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +//
> +// **/
> +
> +#string STR_PROPERTIES_MODULE_NAME
> +#language en-US
> +"User Authentication DXE Driver"
> +
> +
> diff --git
> a/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeForms
> et.h
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeForms
> et.h
> new file mode 100644
> index 0000000..4d29a5d
> --- /dev/null
> +++
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeForms
> et.h
> @@ -0,0 +1,30 @@
> +/** @file
> +  Header file for UserAuthentication formset.
> +
> +Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
> +This program and the accompanying materials
> +are licensed and made available under the terms and conditions of the BSD
> License
> +which accompanies this distribution.  The full text of the license may be
> found at
> +http://opensource.org/licenses/bsd-license.php
> +
> +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +
> +
> +**/
> +
> +#ifndef _USER_AUTHENTICATION_DXE_FORMSET_H_
> +#define _USER_AUTHENTICATION_DXE_FORMSET_H_
> +
> +//
> +// Vendor GUID of the formset
> +//
> +#define USER_AUTHENTICATION_FORMSET_GUID \
> +  { 0x760e3022, 0xf149, 0x4560, {0x9c, 0x6f, 0x33, 0xaa, 0x7d, 0x48, 0x75,
> 0xfa} }
> +
> +#define ADMIN_PASSWORD_KEY_ID   0x2001
> +
> +#define MAX_PASSWORD_LEN  20
> +#define MIN_PASSWORD_LEN  8
> +
> +#endif
> diff --git
> a/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxePassw
> ord.c
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxePassw
> ord.c
> new file mode 100644
> index 0000000..00b051a
> --- /dev/null
> +++
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxePassw
> ord.c
> @@ -0,0 +1,301 @@
> +/** @file
> +  UserAuthentication DXE password wrapper.
> +
> +Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
> +This program and the accompanying materials
> +are licensed and made available under the terms and conditions of the BSD
> License
> +which accompanies this distribution.  The full text of the license may be
> found at
> +http://opensource.org/licenses/bsd-license.php
> +
> +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +
> +**/
> +
> +#include "UserAuthenticationDxe.h"
> +#include <Guid/PiSmmCommunicationRegionTable.h>
> +#include <Protocol/SmmCommunication.h>
> +
> +EFI_SMM_COMMUNICATION_PROTOCOL *mSmmCommunication = NULL;
> +
> +/**
> +  Initialize the communicate buffer using DataSize and Function.
> +
> +  @param[out]      DataPtr          Points to the data in the communicate buffer.
> +  @param[in]       DataSize         The data size to send to SMM.
> +  @param[in]       Function         The function number to initialize the
> communicate header.
> +  @param[in]       UserGuid         The user GUID of the password.
> +
> +  @retval EFI_INVALID_PARAMETER     The data size is too big.
> +  @retval EFI_SUCCESS               Find the specified variable.
> +**/
> +VOID*
> +InitCommunicateBuffer (
> +  OUT     VOID                              **DataPtr OPTIONAL,
> +  IN      UINTN                             DataSize,
> +  IN      UINTN                             Function,
> +  IN      EFI_GUID                          *UserGuid
> +  )
> +{
> +  EFI_SMM_COMMUNICATE_HEADER                *SmmCommunicateHeader;
> +  SMM_PASSWORD_COMMUNICATE_HEADER
> *SmmPasswordFunctionHeader;
> +  VOID                                      *Buffer;
> +  EDKII_PI_SMM_COMMUNICATION_REGION_TABLE
> *SmmCommRegionTable;
> +  EFI_MEMORY_DESCRIPTOR                     *SmmCommMemRegion;
> +  UINTN                                     Index;
> +  UINTN                                     Size;
> +  EFI_STATUS                                Status;
> +
> +  Buffer = NULL;
> +  Status = EfiGetSystemConfigurationTable (
> +             &gEdkiiPiSmmCommunicationRegionTableGuid,
> +             (VOID **) &SmmCommRegionTable
> +             );
> +  if (EFI_ERROR (Status)) {
> +    return NULL;
> +  }
> +  ASSERT (SmmCommRegionTable != NULL);
> +  SmmCommMemRegion = (EFI_MEMORY_DESCRIPTOR *)
> (SmmCommRegionTable + 1);
> +  Size = 0;
> +  for (Index = 0; Index < SmmCommRegionTable->NumberOfEntries;
> Index++) {
> +    if (SmmCommMemRegion->Type == EfiConventionalMemory) {
> +      Size = EFI_PAGES_TO_SIZE ((UINTN) SmmCommMemRegion-
> >NumberOfPages);
> +      if (Size >= (DataSize + OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER,
> Data) + sizeof (SMM_PASSWORD_COMMUNICATE_HEADER))) {
> +        break;
> +      }
> +    }
> +    SmmCommMemRegion = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *)
> SmmCommMemRegion + SmmCommRegionTable->DescriptorSize);
> +  }
> +  ASSERT (Index < SmmCommRegionTable->NumberOfEntries);
> +
> +  Buffer = (VOID*)(UINTN)SmmCommMemRegion->PhysicalStart;
> +  ASSERT (Buffer != NULL);
> +  SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *)
> Buffer;
> +  CopyGuid (&SmmCommunicateHeader->HeaderGuid, UserGuid);
> +  SmmCommunicateHeader->MessageLength = DataSize + sizeof
> (SMM_PASSWORD_COMMUNICATE_HEADER);
> +
> +  SmmPasswordFunctionHeader =
> (SMM_PASSWORD_COMMUNICATE_HEADER *) SmmCommunicateHeader-
> >Data;
> +  ZeroMem (SmmPasswordFunctionHeader, DataSize + sizeof
> (SMM_PASSWORD_COMMUNICATE_HEADER));
> +  SmmPasswordFunctionHeader->Function = Function;
> +  CopyGuid (&SmmPasswordFunctionHeader->UserGuid, UserGuid);
> +  if (DataPtr != NULL) {
> +    *DataPtr = SmmPasswordFunctionHeader + 1;
> +  }
> +
> +  return Buffer;
> +}
> +
> +/**
> +  Send the data in communicate buffer to SMM.
> +
> +  @param[in]   Buffer                 Points to the data in the communicate buffer.
> +  @param[in]   DataSize               This size of the function header and the data.
> +
> +  @retval      EFI_SUCCESS            Success is returned from the functin in SMM.
> +  @retval      Others                 Failure is returned from the function in SMM.
> +
> +**/
> +EFI_STATUS
> +SendCommunicateBuffer (
> +  IN      VOID                              *Buffer,
> +  IN      UINTN                             DataSize
> +  )
> +{
> +  EFI_STATUS                                Status;
> +  UINTN                                     CommSize;
> +  EFI_SMM_COMMUNICATE_HEADER                *SmmCommunicateHeader;
> +  SMM_PASSWORD_COMMUNICATE_HEADER
> *SmmPasswordFunctionHeader;
> +
> +  CommSize = DataSize + OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER,
> Data) + sizeof (SMM_PASSWORD_COMMUNICATE_HEADER);
> +
> +  Status = mSmmCommunication->Communicate (mSmmCommunication,
> Buffer, &CommSize);
> +  ASSERT_EFI_ERROR (Status);
> +
> +  SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *)
> Buffer;
> +  SmmPasswordFunctionHeader =
> (SMM_PASSWORD_COMMUNICATE_HEADER *)SmmCommunicateHeader-
> >Data;
> +  return  SmmPasswordFunctionHeader->ReturnStatus;
> +}
> +
> +/**
> +  Validata if the password is correct.
> +
> +  @param[in]  UserGuid               The user GUID of the password.
> +  @param[in]  Password               The user input password.
> +  @param[in]  PasswordSize           The size of Password in byte.
> +
> +  @retval EFI_SUCCESS              The password is correct.
> +  @retval EFI_SECURITY_VIOLATION   The password is incorrect.
> +**/
> +EFI_STATUS
> +ValidatePassword (
> +  IN   EFI_GUID     *UserGuid,
> +  IN   CHAR16       *Password,
> +  IN   UINTN        PasswordSize
> +  )
> +{
> +  EFI_STATUS                                Status;
> +  VOID                                      *Buffer;
> +  SMM_PASSWORD_COMMUNICATE_VERIFY_PASSWORD
> *VerifyPassword;
> +
> +  ASSERT (Password != NULL);
> +
> +  if (PasswordSize > sizeof(VerifyPassword->Password) * sizeof(CHAR16)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  Buffer = InitCommunicateBuffer (
> +             (VOID**)&VerifyPassword,
> +             sizeof(*VerifyPassword),
> +             SMM_PASSWORD_FUNCTION_VERIFY_PASSWORD,
> +             UserGuid
> +             );
> +  if (Buffer == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  Status = UnicodeStrToAsciiStrS (Password, VerifyPassword->Password,
> sizeof(VerifyPassword->Password));
> +  if (EFI_ERROR(Status)) {
> +    return Status;
> +  }
> +
> +  Status = SendCommunicateBuffer (Buffer, sizeof(*VerifyPassword));
> +  if (EFI_ERROR (Status)) {
> +    goto EXIT;
> +  }
> +
> +EXIT:
> +  ZeroMem (VerifyPassword, sizeof(*VerifyPassword));
> +  return Status;
> +}
> +
> +/**
> +  Set a new password.
> +
> +  @param[in]  UserGuid               The user GUID of the password.
> +  @param[in]  NewPassword            The user input new password.
> +                                     NULL means clear password.
> +  @param[in]  NewPasswordSize        The size of NewPassword in byte.
> +  @param[in]  OldPassword            The user input old password.
> +                                     NULL means no old password.
> +  @param[in]  OldPasswordSize        The size of OldPassword in byte.
> +
> +  @retval EFI_SUCCESS              The password is correct.
> +  @retval EFI_SECURITY_VIOLATION   The password is incorrect.
> +  @retval EFI_OUT_OF_RESOURCES     Insufficient resources to set the
> password.
> +**/
> +EFI_STATUS
> +SetPassword (
> +  IN   EFI_GUID     *UserGuid,
> +  IN   CHAR16       *NewPassword,     OPTIONAL
> +  IN   UINTN        NewPasswordSize,
> +  IN   CHAR16       *OldPassword,     OPTIONAL
> +  IN   UINTN        OldPasswordSize
> +  )
> +{
> +  EFI_STATUS                                Status;
> +  VOID                                      *Buffer;
> +  SMM_PASSWORD_COMMUNICATE_SET_PASSWORD     *SetPassword;
> +
> +  if (NewPasswordSize > sizeof(SetPassword->NewPassword) *
> sizeof(CHAR16)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +  if (OldPasswordSize > sizeof(SetPassword->OldPassword) *
> sizeof(CHAR16)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  Buffer = InitCommunicateBuffer (
> +             (VOID**)&SetPassword,
> +             sizeof(*SetPassword),
> +             SMM_PASSWORD_FUNCTION_SET_PASSWORD,
> +             UserGuid
> +             );
> +  if (Buffer == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  if (NewPassword != NULL) {
> +    Status = UnicodeStrToAsciiStrS (NewPassword, SetPassword-
> >NewPassword, sizeof(SetPassword->NewPassword));
> +    if (EFI_ERROR(Status)) {
> +      return Status;
> +    }
> +  } else {
> +    SetPassword->NewPassword[0] = 0;
> +  }
> +
> +  if (OldPassword != NULL) {
> +    Status = UnicodeStrToAsciiStrS (OldPassword, SetPassword-
> >OldPassword, sizeof(SetPassword->OldPassword));
> +    if (EFI_ERROR(Status)) {
> +      return Status;
> +    }
> +  } else {
> +    SetPassword->OldPassword[0] = 0;
> +  }
> +
> +  Status = SendCommunicateBuffer (Buffer, sizeof(*SetPassword));
> +  if (EFI_ERROR (Status)) {
> +    goto EXIT;
> +  }
> +
> +EXIT:
> +  ZeroMem (SetPassword, sizeof(*SetPassword));
> +  return Status;
> +}
> +
> +/**
> +  Return if the password is set.
> +
> +  @param[in]  UserGuid               The user GUID of the password.
> +
> +  @retval TRUE    The password is set.
> +  @retval FALSE   The password is not set.
> +**/
> +BOOLEAN
> +IsPasswordSet (
> +  IN   EFI_GUID     *UserGuid
> +  )
> +{
> +  EFI_STATUS                                Status;
> +  VOID                                      *Buffer;
> +
> +  Buffer = InitCommunicateBuffer (
> +             NULL,
> +             0,
> +             SMM_PASSWORD_FUNCTION_IS_PASSWORD_SET,
> +             UserGuid
> +             );
> +  if (Buffer == NULL) {
> +    return FALSE;
> +  }
> +
> +  Status = SendCommunicateBuffer (Buffer, 0);
> +  if (EFI_ERROR (Status)) {
> +    return FALSE;
> +  }
> +
> +  return TRUE;
> +}
> +
> +/**
> +  Main entry for this driver.
> +
> +  @param ImageHandle     Image handle this driver.
> +  @param SystemTable     Pointer to SystemTable.
> +
> +  @retval EFI_SUCESS     This function always complete successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PasswordDxeInit (
> +  IN EFI_HANDLE                         ImageHandle,
> +  IN EFI_SYSTEM_TABLE                   *SystemTable
> +  )
> +{
> +  EFI_STATUS                     Status;
> +
> +  Status = gBS->LocateProtocol (&gEfiSmmCommunicationProtocolGuid,
> NULL, (VOID **) &mSmmCommunication);
> +  ASSERT_EFI_ERROR (Status);
> +
> +  return EFI_SUCCESS;
> +}
> +
> diff --git
> a/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeStrings.
> uni
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeStrings
> .uni
> new file mode 100644
> index 0000000..86fde22
> --- /dev/null
> +++
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeStrings
> .uni
> @@ -0,0 +1,29 @@
> +/** @file
> +// String definitions for User Authentication formset.
> +
> +// Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
> +// This program and the accompanying materials
> +// are licensed and made available under the terms and conditions of the
> BSD License
> +// which accompanies this distribution.  The full text of the license may be
> found at
> +// http://opensource.org/licenses/bsd-license.php
> +
> +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +
> +**/
> +
> +#langdef en-US  "English"
> +#langdef fr-FR  "Francais"
> +
> +
> +#string STR_FORM_SET_TITLE             #language en-US "User Password
> Management"
> +                                       #language fr-FR "User Password Management"
> +#string STR_FORM_SET_TITLE_HELP        #language en-US "This Driver
> mainly handle user's password"
> +                                       #language fr-FR "This Driver mainly handle user's
> password"
> +#string STR_FORM_TITLE                 #language en-US "Password Management
> Form"
> +                                       #language fr-FR "Password Management Form"
> +#string STR_ADMIN_PASSWORD_PROMPT      #language en-US "Change
> Admin Password"
> +                                       #language fr-FR "Change Admin Password"
> +#string STR_ADMIN_PASSWORD_HELP        #language en-US "Input old
> admin password, then you can change the password to a new one. After the
> change action, you need input the new password when you enter UI. The
> new password must be at least 8 char and include lowercase, uppercase
> alphabetic, numbers, and symbols."
> +                                       #language fr-FR "Input old admin password, then you
> can change the password to a new one. After the change action, you need
> input the new password when you enter UI. The new password must be at
> least 8 char and include lowercase, uppercase alphabetic, numbers, and
> symbols."
> +
> diff --git
> a/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeVfr.vfr
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeVfr.vfr
> new file mode 100644
> index 0000000..4741fe3
> --- /dev/null
> +++
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeVfr.vfr
> @@ -0,0 +1,38 @@
> +///** @file
> +// UserAuthentication formset.
> +//
> +// Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
> +// This program and the accompanying materials
> +// are licensed and made available under the terms and conditions of the
> BSD License
> +// which accompanies this distribution.  The full text of the license may be
> found at
> +// http://opensource.org/licenses/bsd-license.php
> +//
> +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +
> +//**/
> +
> +#include <Guid/HiiPlatformSetupFormset.h>
> +#include "UserAuthenticationDxeFormset.h"
> +
> +formset
> +  guid      = USER_AUTHENTICATION_FORMSET_GUID,
> +  title     = STRING_TOKEN(STR_FORM_SET_TITLE),
> +  help      = STRING_TOKEN(STR_FORM_SET_TITLE_HELP),
> +  classguid = EFI_HII_PLATFORM_SETUP_FORMSET_GUID,
> +
> +  form formid = 1,
> +      title  = STRING_TOKEN(STR_FORM_TITLE);
> +
> +      password
> +          prompt   = STRING_TOKEN(STR_ADMIN_PASSWORD_PROMPT),
> +          help     = STRING_TOKEN(STR_ADMIN_PASSWORD_HELP),
> +          flags    = INTERACTIVE,
> +          key      = ADMIN_PASSWORD_KEY_ID,
> +          minsize = MIN_PASSWORD_LEN,
> +          maxsize = MAX_PASSWORD_LEN,
> +      endpassword;
> +
> +  endform;
> +
> +endformset;
> diff --git
> a/SecurityPkg/Password/UserAuthentication/UserAuthenticationGuid.h
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationGuid.h
> new file mode 100644
> index 0000000..0a4df01
> --- /dev/null
> +++ b/SecurityPkg/Password/UserAuthentication/UserAuthenticationGuid.h
> @@ -0,0 +1,65 @@
> +/** @file
> +  GUID is for UserPassword variable.
> +
> +Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
> +This program and the accompanying materials are licensed and made
> available under
> +the terms and conditions of the BSD License that accompanies this
> distribution.
> +The full text of the license may be found at
> +http://opensource.org/licenses/bsd-license.php.
> +
> +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +
> +**/
> +
> +#ifndef __USER_AUTHENTICATION_GUID_H__
> +#define __USER_AUTHENTICATION_GUID_H__
> +
> +#define PASSWORD_MIN_SIZE    9  // MIN number of char of password,
> including NULL
> +#define PASSWORD_MAX_SIZE    32 // MAX number of char of password,
> including NULL
> +#define PASSWORD_SALT_SIZE   32
> +#define PASSWORD_HASH_SIZE   32 // SHA256_DIGEST_SIZE
> +
> +#define PASSWORD_MAX_TRY_COUNT  3
> +#define PASSWORD_HISTORY_CHECK_COUNT  5
> +
> +//
> +// Vendor GUID of the variable
> +//
> +#define ADMIN_AUTHENTICATION_GUID \
> +  { 0xee24a7f7, 0x606b, 0x4724, { 0xb3, 0xc9, 0xf5, 0xae, 0x4a, 0x3b, 0x81,
> 0x65} }
> +
> +//
> +// Name of the variable
> +//
> +#define USER_AUTHENTICATION_VAR_NAME L"Password"
> +#define USER_AUTHENTICATION_HISTORY_LAST_VAR_NAME
> L"PasswordLast"
> +
> +//
> +// Variable storage
> +//
> +typedef struct {
> +  UINT8        PasswordHash[PASSWORD_HASH_SIZE];
> +  UINT8        PasswordSalt[PASSWORD_SALT_SIZE];
> +} USER_PASSWORD_VAR_STRUCT;
> +
> +typedef struct {
> +  UINTN       Function;
> +  EFI_STATUS  ReturnStatus;
> +  EFI_GUID    UserGuid;
> +} SMM_PASSWORD_COMMUNICATE_HEADER;
> +
> +#define SMM_PASSWORD_FUNCTION_IS_PASSWORD_SET     1
> +#define SMM_PASSWORD_FUNCTION_SET_PASSWORD        2
> +#define SMM_PASSWORD_FUNCTION_VERIFY_PASSWORD     3
> +
> +typedef struct {
> +  CHAR8                                 NewPassword[PASSWORD_MAX_SIZE];
> +  CHAR8                                 OldPassword[PASSWORD_MAX_SIZE];
> +} SMM_PASSWORD_COMMUNICATE_SET_PASSWORD;
> +
> +typedef struct {
> +  CHAR8                                 Password[PASSWORD_MAX_SIZE];
> +} SMM_PASSWORD_COMMUNICATE_VERIFY_PASSWORD;
> +
> +#endif
> diff --git
> a/SecurityPkg/Password/UserAuthentication/UserAuthenticationSmm.c
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationSmm.c
> new file mode 100644
> index 0000000..ffc3d81
> --- /dev/null
> +++ b/SecurityPkg/Password/UserAuthentication/UserAuthenticationSmm.c
> @@ -0,0 +1,672 @@
> +/** @file
> +
> +Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
> +This program and the accompanying materials
> +are licensed and made available under the terms and conditions of the BSD
> License
> +which accompanies this distribution.  The full text of the license may be
> found at
> +http://opensource.org/licenses/bsd-license.php
> +
> +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +
> +**/
> +
> +#include <PiSmm.h>
> +#include <Protocol/SmmVariable.h>
> +#include <Protocol/VariableLock.h>
> +#include <Library/DebugLib.h>
> +#include <Library/BaseLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/PrintLib.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +#include <Library/SmmServicesTableLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/SmmServicesTableLib.h>
> +#include <Library/PlatformPasswordLib.h>
> +#include "KeyService.h"
> +#include "UserAuthenticationGuid.h"
> +
> +EFI_GUID gAdminAuthenticationGuid = ADMIN_AUTHENTICATION_GUID;
> +
> +EFI_SMM_VARIABLE_PROTOCOL         *mSmmVariable;
> +
> +UINTN  mAdminPasswordTryCount;
> +
> +/**
> +  Verify if the password is correct.
> +
> +  @param[in]  Password               The user input password.
> +  @param[in]  PasswordSize           The size of Password in byte.
> +  @param[in]  UserPasswordVarStruct  The storage of password in variable.
> +
> +  @retval EFI_SUCCESS              The password is correct.
> +  @retval EFI_SECURITY_VIOLATION   The password is incorrect.
> +**/
> +EFI_STATUS
> +VerifyPassword (
> +  IN CHAR8                          *Password,
> +  IN UINTN                          PasswordSize,
> +  IN USER_PASSWORD_VAR_STRUCT       *UserPasswordVarStruct
> +  )
> +{
> +  BOOLEAN  HashOk;
> +  UINT8    HashData[PASSWORD_HASH_SIZE];
> +
> +  HashOk = KeyLibGeneratePBKDF2Hash (
> +             HASH_TYPE_SHA256,
> +             (UINT8 *)Password,
> +             PasswordSize,
> +             UserPasswordVarStruct->PasswordSalt,
> +             sizeof(UserPasswordVarStruct->PasswordSalt),
> +             HashData,
> +             sizeof(HashData)
> +             );
> +  if (!HashOk) {
> +    return EFI_DEVICE_ERROR;
> +  }
> +  if (KeyLibSlowCompareMem (UserPasswordVarStruct->PasswordHash,
> HashData, PASSWORD_HASH_SIZE) == 0) {
> +    return EFI_SUCCESS;
> +  } else {
> +    return EFI_SECURITY_VIOLATION;
> +  }
> +}
> +
> +/**
> +  Get hash data of password from non-volatile variable region.
> +
> +  @param[in]   UserGuid               The user GUID of the password variable.
> +  @param[in]   Index                  The index of the password.
> +                                      0 means current password.
> +                                      Non-0 means the password history.
> +  @param[out]  UserPasswordVarStruct  The storage of password in variable.
> +
> +  @retval EFI_SUCCESS             The password hash is returned successfully.
> +  @retval EFI_NOT_FOUND           The password hash is not found.
> +**/
> +EFI_STATUS
> +GetPasswordHashFromVariable (
> +  IN  EFI_GUID                       *UserGuid,
> +  IN  UINTN                          Index,
> +  OUT USER_PASSWORD_VAR_STRUCT       *UserPasswordVarStruct
> +  )
> +{
> +  EFI_STATUS                        Status;
> +  UINTN                             DataSize;
> +  CHAR16
> PasswordName[sizeof(USER_AUTHENTICATION_VAR_NAME)/sizeof(CHAR1
> 6) + 4];
> +
> +  if (Index != 0) {
> +    UnicodeSPrint (PasswordName, sizeof (PasswordName), L"%s%04x",
> USER_AUTHENTICATION_VAR_NAME, Index);
> +  } else {
> +    UnicodeSPrint (PasswordName, sizeof (PasswordName), L"%s",
> USER_AUTHENTICATION_VAR_NAME);
> +  }
> +
> +  DataSize = sizeof(*UserPasswordVarStruct);
> +  Status = mSmmVariable->SmmGetVariable (
> +                           PasswordName,
> +                           UserGuid,
> +                           NULL,
> +                           &DataSize,
> +                           UserPasswordVarStruct
> +                           );
> +  if (EFI_ERROR(Status)) {
> +    return Status;
> +  }
> +
> +  return Status;
> +}
> +
> +/**
> +  Save password hash data to non-volatile variable region.
> +
> +  @param[in]   UserGuid               The user GUID of the password variable.
> +  @param[in]   UserPasswordVarStruct  The storage of password in variable.
> +
> +  @retval EFI_SUCCESS             The password hash is saved successfully.
> +  @retval EFI_OUT_OF_RESOURCES    Insufficient resources to save the
> password hash.
> +**/
> +EFI_STATUS
> +SavePasswordHashToVariable (
> +  IN EFI_GUID                       *UserGuid,
> +  IN USER_PASSWORD_VAR_STRUCT       *UserPasswordVarStruct
> +  )
> +{
> +  EFI_STATUS                        Status;
> +
> +  if (UserPasswordVarStruct == NULL) {
> +    Status = mSmmVariable->SmmSetVariable (
> +                             USER_AUTHENTICATION_VAR_NAME,
> +                             UserGuid,
> +                             EFI_VARIABLE_BOOTSERVICE_ACCESS |
> EFI_VARIABLE_NON_VOLATILE,
> +                             0,
> +                             NULL
> +                             );
> +  } else {
> +    Status = mSmmVariable->SmmSetVariable (
> +                             USER_AUTHENTICATION_VAR_NAME,
> +                             UserGuid,
> +                             EFI_VARIABLE_BOOTSERVICE_ACCESS |
> EFI_VARIABLE_NON_VOLATILE,
> +                             sizeof(*UserPasswordVarStruct),
> +                             UserPasswordVarStruct
> +                             );
> +  }
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "SavePasswordHashToVariable fails with %r\n",
> Status));
> +  }
> +
> +  return Status;
> +}
> +
> +/**
> +  Save old password hash data to non-volatile variable region as history.
> +
> +  The number of password history variable is limited.
> +  If all the password history variables are used, the new password history
> +  will override the oldest one.
> +
> +  @param[in]   UserGuid               The user GUID of the password variable.
> +  @param[in]   UserPasswordVarStruct  The storage of password in variable.
> +
> +  @retval EFI_SUCCESS             The password hash is saved successfully.
> +  @retval EFI_OUT_OF_RESOURCES    Insufficient resources to save the
> password hash.
> +**/
> +EFI_STATUS
> +SaveOldPasswordToHistory (
> +  IN EFI_GUID                       *UserGuid,
> +  IN USER_PASSWORD_VAR_STRUCT       *UserPasswordVarStruct
> +  )
> +{
> +  EFI_STATUS                        Status;
> +  UINTN                             DataSize;
> +  UINT32                            LastIndex;
> +  CHAR16
> PasswordName[sizeof(USER_AUTHENTICATION_VAR_NAME)/sizeof(CHAR1
> 6) + 4];
> +
> +  DEBUG ((DEBUG_INFO, "SaveOldPasswordToHistory\n"));
> +
> +  DataSize = sizeof(LastIndex);
> +  Status = mSmmVariable->SmmGetVariable (
> +                           USER_AUTHENTICATION_HISTORY_LAST_VAR_NAME,
> +                           UserGuid,
> +                           NULL,
> +                           &DataSize,
> +                           &LastIndex
> +                           );
> +  if (EFI_ERROR(Status)) {
> +    LastIndex = 0;
> +  }
> +  if (LastIndex >= PASSWORD_HISTORY_CHECK_COUNT) {
> +    LastIndex = 0;
> +  }
> +
> +  LastIndex ++;
> +  UnicodeSPrint (PasswordName, sizeof (PasswordName), L"%s%04x",
> USER_AUTHENTICATION_VAR_NAME, LastIndex);
> +
> +
> +  Status = mSmmVariable->SmmSetVariable (
> +                           PasswordName,
> +                           UserGuid,
> +                           EFI_VARIABLE_BOOTSERVICE_ACCESS |
> EFI_VARIABLE_NON_VOLATILE,
> +                           sizeof(*UserPasswordVarStruct),
> +                           UserPasswordVarStruct
> +                           );
> +  DEBUG ((DEBUG_INFO, "  -- to %s, %r\n", PasswordName, Status));
> +  if (!EFI_ERROR(Status)) {
> +    Status = mSmmVariable->SmmSetVariable (
> +                             USER_AUTHENTICATION_HISTORY_LAST_VAR_NAME,
> +                             UserGuid,
> +                             EFI_VARIABLE_BOOTSERVICE_ACCESS |
> EFI_VARIABLE_NON_VOLATILE,
> +                             sizeof(LastIndex),
> +                             &LastIndex
> +                             );
> +    DEBUG ((DEBUG_INFO, " LastIndex - 0x%04x, %r\n", LastIndex, Status));
> +  }
> +
> +  return Status;
> +}
> +
> +/**
> +  Calculate password hash data and save it to non-volatile variable region.
> +
> +  @param[in]  UserGuid               The user GUID of the password variable.
> +  @param[in]  Password               The user input password.
> +                                     NULL means delete the password variable.
> +  @param[in]  PasswordSize           The size of Password in byte.
> +
> +  @retval EFI_SUCCESS             The password hash is calculated and saved.
> +  @retval EFI_OUT_OF_RESOURCES    Insufficient resources to save the
> password hash.
> +**/
> +EFI_STATUS
> +SavePasswordToVariable (
> +  IN  EFI_GUID                      *UserGuid,
> +  IN  CHAR8                         *Password,  OPTIONAL
> +  IN  UINTN                         PasswordSize
> +  )
> +{
> +  EFI_STATUS                        Status;
> +  USER_PASSWORD_VAR_STRUCT          UserPasswordVarStruct;
> +  BOOLEAN                           HashOk;
> +
> +  //
> +  // If password is NULL, it means we want to clean password field saved in
> variable region.
> +  //
> +  if (Password != NULL) {
> +    KeyLibGenerateSalt (UserPasswordVarStruct.PasswordSalt,
> sizeof(UserPasswordVarStruct.PasswordSalt));
> +    HashOk = KeyLibGeneratePBKDF2Hash (
> +               HASH_TYPE_SHA256,
> +               (UINT8 *)Password,
> +               PasswordSize,
> +               UserPasswordVarStruct.PasswordSalt,
> +               sizeof(UserPasswordVarStruct.PasswordSalt),
> +               UserPasswordVarStruct.PasswordHash,
> +               sizeof(UserPasswordVarStruct.PasswordHash)
> +               );
> +    if (!HashOk) {
> +      return EFI_DEVICE_ERROR;
> +    }
> +    Status = SavePasswordHashToVariable (UserGuid,
> &UserPasswordVarStruct);
> +    //
> +    // Save Password data to history variable
> +    //
> +    if (!EFI_ERROR(Status)) {
> +      SaveOldPasswordToHistory (UserGuid, &UserPasswordVarStruct);
> +    }
> +  } else {
> +    Status = SavePasswordHashToVariable (UserGuid, NULL);
> +  }
> +
> +  return Status;
> +}
> +
> +/**
> +  Verify the password.
> +  If the password variable does not exist, it passes the verification.
> +  If the password variable exists, it does verification based upon password
> variable.
> +
> +  @param[in]  UserGuid               The user GUID of the password variable.
> +  @param[in]  Password               The user input password.
> +  @param[in]  PasswordSize           The size of Password in byte.
> +
> +  @retval TRUE    The verification passes.
> +  @retval FALSE   The verification fails.
> +**/
> +BOOLEAN
> +IsPasswordVerified (
> +  IN EFI_GUID                       *UserGuid,
> +  IN CHAR8                          *Password,
> +  IN UINTN                          PasswordSize
> +  )
> +{
> +  USER_PASSWORD_VAR_STRUCT          UserPasswordVarStruct;
> +  EFI_STATUS                        Status;
> +
> +  Status = GetPasswordHashFromVariable (UserGuid, 0,
> &UserPasswordVarStruct);
> +  if (EFI_ERROR(Status)) {
> +    return TRUE;
> +  }
> +
> +  //
> +  // Old password exists
> +  //
> +  Status = VerifyPassword (Password, PasswordSize,
> &UserPasswordVarStruct);
> +  if (EFI_ERROR(Status)) {
> +    return FALSE;
> +  }
> +
> +  return TRUE;
> +}
> +
> +/**
> +  Return if the password is set.
> +
> +  @param[in]  UserGuid               The user GUID of the password variable.
> +
> +  @retval TRUE    The password is set.
> +  @retval FALSE   The password is not set.
> +**/
> +BOOLEAN
> +IsPasswordSet (
> +  IN EFI_GUID                       *UserGuid
> +  )
> +{
> +  USER_PASSWORD_VAR_STRUCT          UserPasswordVarStruct;
> +  EFI_STATUS                        Status;
> +
> +  Status = GetPasswordHashFromVariable(UserGuid, 0,
> &UserPasswordVarStruct);
> +  if (EFI_ERROR(Status)) {
> +    return FALSE;
> +  }
> +  return TRUE;
> +}
> +
> +/**
> +  Return if the password is strong.
> +  Criteria:
> +  1) length >= PASSWORD_MIN_SIZE
> +  2) include lower case, upper case, number, symbol.
> +
> +  @param[in]  Password               The user input password.
> +  @param[in]  PasswordSize           The size of Password in byte.
> +
> +  @retval TRUE    The password is strong.
> +  @retval FALSE   The password is weak.
> +**/
> +BOOLEAN
> +IsPasswordStrong (
> +  IN CHAR8   *Password,
> +  IN UINTN   PasswordSize
> +  )
> +{
> +  UINTN   Index;
> +  BOOLEAN HasLowerCase;
> +  BOOLEAN HasUpperCase;
> +  BOOLEAN HasNumber;
> +  BOOLEAN HasSymbol;
> +
> +  if (PasswordSize < PASSWORD_MIN_SIZE) {
> +    return FALSE;
> +  }
> +
> +  HasLowerCase = FALSE;
> +  HasUpperCase = FALSE;
> +  HasNumber = FALSE;
> +  HasSymbol = FALSE;
> +  for (Index = 0; Index < PasswordSize - 1; Index++) {
> +    if (Password[Index] >= 'a' && Password[Index] <= 'z') {
> +      HasLowerCase = TRUE;
> +    } else if (Password[Index] >= 'A' && Password[Index] <= 'Z') {
> +      HasUpperCase = TRUE;
> +    } else if (Password[Index] >= '0' && Password[Index] <= '9') {
> +      HasNumber = TRUE;
> +    } else {
> +      HasSymbol = TRUE;
> +    }
> +  }
> +  if ((!HasLowerCase) || (!HasUpperCase) || (!HasNumber) || (!HasSymbol))
> {
> +    return FALSE;
> +  }
> +  return TRUE;
> +}
> +
> +/**
> +  Return if the password is set before in
> PASSWORD_HISTORY_CHECK_COUNT.
> +
> +  @param[in]  UserGuid               The user GUID of the password variable.
> +  @param[in]  Password               The user input password.
> +  @param[in]  PasswordSize           The size of Password in byte.
> +
> +  @retval TRUE    The password is set before.
> +  @retval FALSE   The password is not set before.
> +**/
> +BOOLEAN
> +IsPasswordInHistory (
> +  IN EFI_GUID                       *UserGuid,
> +  IN CHAR8                          *Password,
> +  IN UINTN                          PasswordSize
> +  )
> +{
> +  EFI_STATUS                     Status;
> +  USER_PASSWORD_VAR_STRUCT       UserPasswordVarStruct;
> +  UINTN                          Index;
> +
> +  for (Index = 1; Index <= PASSWORD_HISTORY_CHECK_COUNT; Index++) {
> +    Status = GetPasswordHashFromVariable (UserGuid, Index,
> &UserPasswordVarStruct);
> +    if (!EFI_ERROR(Status)) {
> +      Status = VerifyPassword (Password, PasswordSize,
> &UserPasswordVarStruct);
> +      if (!EFI_ERROR(Status)) {
> +        return TRUE;
> +      }
> +    }
> +  }
> +
> +  return FALSE;
> +}
> +
> +/**
> +  Communication service SMI Handler entry.
> +
> +  This SMI handler provides services for password management.
> +
> +  @param[in]     DispatchHandle  The unique handle assigned to this handler
> by SmiHandlerRegister().
> +  @param[in]     RegisterContext Points to an optional handler context which
> was specified when the
> +                                 handler was registered.
> +  @param[in, out] CommBuffer     A pointer to a collection of data in
> memory that will
> +                                 be conveyed from a non-SMM environment into an SMM
> environment.
> +  @param[in, out] CommBufferSize The size of the CommBuffer.
> +
> +  @retval EFI_SUCCESS                         The interrupt was handled and quiesced.
> No other handlers
> +                                              should still be called.
> +  @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED  The interrupt has
> been quiesced but other handlers should
> +                                              still be called.
> +  @retval EFI_WARN_INTERRUPT_SOURCE_PENDING   The interrupt is still
> pending and other handlers should still
> +                                              be called.
> +  @retval EFI_INTERRUPT_PENDING               The interrupt could not be
> quiesced.
> +**/
> +EFI_STATUS
> +EFIAPI
> +SmmPasswordHandler (
> +  IN     EFI_HANDLE                 DispatchHandle,
> +  IN     CONST VOID                 *RegisterContext,
> +  IN OUT VOID                       *CommBuffer,
> +  IN OUT UINTN                      *CommBufferSize
> +  )
> +{
> +  EFI_STATUS                                Status;
> +  SMM_PASSWORD_COMMUNICATE_HEADER           *SmmFunctionHeader;
> +  UINTN                                     CommBufferPayloadSize;
> +  UINTN                                     TempCommBufferSize;
> +  SMM_PASSWORD_COMMUNICATE_SET_PASSWORD
> SmmCommunicateSetPassword;
> +  SMM_PASSWORD_COMMUNICATE_VERIFY_PASSWORD
> SmmCommunicateVerifyPassword;
> +  UINTN                                     PasswordLen;
> +  EFI_GUID                                  UserGuid;
> +  UINTN                                     *PasswordTryCount;
> +
> +  //
> +  // If input is invalid, stop processing this SMI
> +  //
> +  if (CommBuffer == NULL || CommBufferSize == NULL) {
> +    return EFI_SUCCESS;
> +  }
> +
> +  TempCommBufferSize = *CommBufferSize;
> +
> +  if (TempCommBufferSize < sizeof
> (SMM_PASSWORD_COMMUNICATE_HEADER)) {
> +    DEBUG ((DEBUG_ERROR, "SmmPasswordHandler: SMM communication
> buffer size invalid!\n"));
> +    return EFI_SUCCESS;
> +  }
> +
> +  CommBufferPayloadSize = TempCommBufferSize - sizeof
> (SMM_PASSWORD_COMMUNICATE_HEADER);
> +
> +  Status   = EFI_SUCCESS;
> +  SmmFunctionHeader = (SMM_PASSWORD_COMMUNICATE_HEADER
> *)CommBuffer;
> +  CopyGuid (&UserGuid, &SmmFunctionHeader->UserGuid);
> +
> +  if (CompareGuid (&UserGuid, &gAdminAuthenticationGuid)) {
> +    PasswordTryCount = &mAdminPasswordTryCount;
> +  } else {
> +    DEBUG ((DEBUG_ERROR, "SmmPasswordHandler: Invalid UserGuid\n"));
> +    PasswordTryCount = NULL;
> +    Status = EFI_INVALID_PARAMETER;
> +    goto EXIT;
> +  }
> +
> +  switch (SmmFunctionHeader->Function) {
> +  case SMM_PASSWORD_FUNCTION_IS_PASSWORD_SET:
> +    PasswordTryCount = NULL;
> +    if (CommBufferPayloadSize != 0) {
> +      DEBUG ((DEBUG_ERROR, "SmmPasswordHandler: IS_PASSWORD_SET
> payload buffer invalid!\n"));
> +      Status = EFI_INVALID_PARAMETER;
> +      goto EXIT;
> +    }
> +    if (IsPasswordSet(&UserGuid)) {
> +      Status = EFI_SUCCESS;
> +    } else {
> +      Status = EFI_NOT_FOUND;
> +    }
> +    break;
> +  case SMM_PASSWORD_FUNCTION_SET_PASSWORD:
> +    if (*PasswordTryCount >= PASSWORD_MAX_TRY_COUNT) {
> +      DEBUG ((DEBUG_ERROR, "SmmPasswordHandler: SET_PASSWORD try
> count reach!\n"));
> +      PasswordTryCount = NULL;
> +      Status = EFI_INVALID_PARAMETER;
> +      goto EXIT;
> +    }
> +    if (CommBufferPayloadSize !=
> sizeof(SMM_PASSWORD_COMMUNICATE_SET_PASSWORD)) {
> +      DEBUG ((DEBUG_ERROR, "SmmPasswordHandler: SET_PASSWORD
> payload buffer invalid!\n"));
> +      Status = EFI_INVALID_PARAMETER;
> +      goto EXIT;
> +    }
> +    CopyMem (&SmmCommunicateSetPassword, SmmFunctionHeader + 1,
> sizeof(SmmCommunicateSetPassword));
> +
> +    PasswordLen =
> AsciiStrnLenS(SmmCommunicateSetPassword.OldPassword,
> sizeof(SmmCommunicateSetPassword.OldPassword));
> +    if (PasswordLen == sizeof(SmmCommunicateSetPassword.OldPassword))
> {
> +      DEBUG ((DEBUG_ERROR, "SmmPasswordHandler: OldPassword
> invalid!\n"));
> +      Status = EFI_INVALID_PARAMETER;
> +      goto EXIT;
> +    }
> +
> +    if (!IsPasswordVerified (&UserGuid,
> SmmCommunicateSetPassword.OldPassword, PasswordLen + 1)) {
> +      DEBUG ((DEBUG_ERROR, "SmmPasswordHandler: PasswordVerify -
> FAIL\n"));
> +      Status = EFI_SECURITY_VIOLATION;
> +      goto EXIT;
> +    }
> +
> +    PasswordLen =
> AsciiStrnLenS(SmmCommunicateSetPassword.NewPassword,
> sizeof(SmmCommunicateSetPassword.NewPassword));
> +    if (PasswordLen ==
> sizeof(SmmCommunicateSetPassword.NewPassword)) {
> +      DEBUG ((DEBUG_ERROR, "SmmPasswordHandler: NewPassword
> invalid!\n"));
> +      Status = EFI_INVALID_PARAMETER;
> +      goto EXIT;
> +    }
> +    if (!IsPasswordStrong (SmmCommunicateSetPassword.NewPassword,
> PasswordLen + 1)) {
> +      DEBUG ((DEBUG_ERROR, "SmmPasswordHandler: NewPassword too
> weak!\n"));
> +      Status = EFI_UNSUPPORTED;
> +      goto EXIT;
> +    }
> +    if (IsPasswordInHistory (&UserGuid,
> SmmCommunicateSetPassword.NewPassword, PasswordLen + 1)) {
> +      DEBUG ((DEBUG_ERROR, "SmmPasswordHandler: NewPassword in
> history!\n"));
> +      Status = EFI_ALREADY_STARTED;
> +      goto EXIT;
> +    }
> +
> +    if (PasswordLen == 0) {
> +      Status = SavePasswordToVariable (&UserGuid, NULL, 0);
> +    } else {
> +      Status = SavePasswordToVariable (&UserGuid,
> SmmCommunicateSetPassword.NewPassword, PasswordLen + 1);
> +    }
> +    break;
> +
> +  case SMM_PASSWORD_FUNCTION_VERIFY_PASSWORD:
> +    if (*PasswordTryCount >= PASSWORD_MAX_TRY_COUNT) {
> +      DEBUG ((DEBUG_ERROR, "SmmPasswordHandler: VERIFY_PASSWORD
> try count reach!\n"));
> +      PasswordTryCount = NULL;
> +      Status = EFI_INVALID_PARAMETER;
> +      goto EXIT;
> +    }
> +    if (CommBufferPayloadSize !=
> sizeof(SMM_PASSWORD_COMMUNICATE_VERIFY_PASSWORD)) {
> +      DEBUG ((DEBUG_ERROR, "SmmPasswordHandler: VERIFY_PASSWORD
> payload buffer invalid!\n"));
> +      Status = EFI_INVALID_PARAMETER;
> +      goto EXIT;
> +    }
> +    CopyMem (&SmmCommunicateVerifyPassword, SmmFunctionHeader +
> 1, sizeof(SmmCommunicateVerifyPassword));
> +
> +    PasswordLen =
> AsciiStrnLenS(SmmCommunicateVerifyPassword.Password,
> sizeof(SmmCommunicateVerifyPassword.Password));
> +    if (PasswordLen == sizeof(SmmCommunicateVerifyPassword.Password))
> {
> +      DEBUG ((DEBUG_ERROR, "SmmPasswordHandler: Password invalid!\n"));
> +      Status = EFI_INVALID_PARAMETER;
> +      goto EXIT;
> +    }
> +    if (!IsPasswordVerified (&UserGuid,
> SmmCommunicateVerifyPassword.Password, PasswordLen + 1)) {
> +      DEBUG ((DEBUG_ERROR, "SmmPasswordHandler: PasswordVerify -
> FAIL\n"));
> +      Status = EFI_SECURITY_VIOLATION;
> +      goto EXIT;
> +    }
> +    Status = EFI_SUCCESS;
> +    break;
> +
> +  default:
> +    PasswordTryCount = NULL;
> +    Status = EFI_UNSUPPORTED;
> +    break;
> +  }
> +
> +EXIT:
> +  if (PasswordTryCount != NULL) {
> +    if (Status == EFI_SUCCESS) {
> +      *PasswordTryCount = 0;
> +    } else {
> +      *PasswordTryCount = *PasswordTryCount + 1;
> +    }
> +  }
> +  SmmFunctionHeader->ReturnStatus = Status;
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Main entry for this driver.
> +
> +  @param ImageHandle     Image handle this driver.
> +  @param SystemTable     Pointer to SystemTable.
> +
> +  @retval EFI_SUCESS     This function always complete successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PasswordSmmInit (
> +  IN EFI_HANDLE                         ImageHandle,
> +  IN EFI_SYSTEM_TABLE                   *SystemTable
> +  )
> +{
> +  EFI_STATUS                            Status;
> +  EFI_HANDLE                            SmmHandle;
> +  EDKII_VARIABLE_LOCK_PROTOCOL          *VariableLock;
> +  CHAR16
> PasswordHistoryName[sizeof(USER_AUTHENTICATION_VAR_NAME)/sizeof(
> CHAR16) + 4];
> +  UINTN                                 Index;
> +
> +  ASSERT (PASSWORD_HASH_SIZE == SHA256_DIGEST_SIZE);
> +  ASSERT (PASSWORD_HISTORY_CHECK_COUNT < 0xFFFF);
> +
> +  Status = gSmst->SmmLocateProtocol (&gEfiSmmVariableProtocolGuid,
> NULL, (VOID**)&mSmmVariable);
> +  ASSERT_EFI_ERROR (Status);
> +
> +  SmmHandle          = NULL;
> +
> +  //
> +  // Make "HddPassword" varible read-only for DXE driver for security
> concern.
> +  //
> +  Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL,
> (VOID **) &VariableLock);
> +  if (!EFI_ERROR (Status)) {
> +    Status = VariableLock->RequestToLock (VariableLock,
> USER_AUTHENTICATION_VAR_NAME, &gAdminAuthenticationGuid);
> +    ASSERT_EFI_ERROR (Status);
> +
> +    for (Index = 1; Index <= PASSWORD_HISTORY_CHECK_COUNT; Index++) {
> +      UnicodeSPrint (PasswordHistoryName, sizeof (PasswordHistoryName),
> L"%s%04x", USER_AUTHENTICATION_VAR_NAME, Index);
> +      Status = VariableLock->RequestToLock (VariableLock,
> PasswordHistoryName, &gAdminAuthenticationGuid);
> +      ASSERT_EFI_ERROR (Status);
> +    }
> +    Status = VariableLock->RequestToLock (VariableLock,
> USER_AUTHENTICATION_HISTORY_LAST_VAR_NAME,
> &gAdminAuthenticationGuid);
> +    ASSERT_EFI_ERROR (Status);
> +  }
> +
> +  SmmHandle = NULL;
> +  Status    = gSmst->SmiHandlerRegister (SmmPasswordHandler,
> &gAdminAuthenticationGuid, &SmmHandle);
> +  ASSERT_EFI_ERROR (Status);
> +  if (EFI_ERROR (Status)) {
> +    Status = EFI_OUT_OF_RESOURCES;
> +    goto EXIT;
> +  }
> +
> +  if (IsPasswordCleared()) {
> +    DEBUG ((DEBUG_INFO, "IsPasswordCleared\n"));
> +    SavePasswordToVariable (&gAdminAuthenticationGuid, NULL, 0);
> +  }
> +
> +  return EFI_SUCCESS;
> +
> +EXIT:
> +  if (SmmHandle != NULL) {
> +    gSmst->SmiHandlerUnRegister (SmmHandle);
> +  }
> +
> +  return Status;
> +}
> +
> diff --git
> a/SecurityPkg/Password/UserAuthentication/UserAuthenticationSmm.inf
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationSmm.inf
> new file mode 100644
> index 0000000..460809b
> --- /dev/null
> +++
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationSmm.inf
> @@ -0,0 +1,70 @@
> +## @file
> +#  User Authentication Smm Driver.
> +#
> +#  This driver provides SMM services for DXE user authentication module.
> +#
> +# Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
> +#
> +#  This program and the accompanying materials
> +#  are licensed and made available under the terms and conditions of the
> BSD License
> +#  which accompanies this distribution. The full text of the license may be
> found at
> +#  http://opensource.org/licenses/bsd-license.php
> +#
> +#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +#
> +#
> +##
> +
> +[Defines]
> +  INF_VERSION                    = 0x00010005
> +  BASE_NAME                      = UserAuthenticationSmm
> +  MODULE_UNI_FILE                = UserAuthenticationSmm.uni
> +  FILE_GUID                      = 458B03ED-6E53-414f-9F07-3A829C990641
> +  MODULE_TYPE                    = DXE_SMM_DRIVER
> +  VERSION_STRING                 = 1.0
> +  PI_SPECIFICATION_VERSION       = 0x0001000A
> +  ENTRY_POINT                    = PasswordSmmInit
> +
> +#
> +# The following information is for reference only and not required by the
> build tools.
> +#
> +#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC
> +#
> +
> +[Sources]
> +  UserAuthenticationSmm.c
> +  UserAuthenticationGuid.h
> +  KeyService.c
> +  KeyService.h
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +  MdeModulePkg/MdeModulePkg.dec
> +  CryptoPkg/CryptoPkg.dec
> +  SecurityPkg/SecurityPkg.dec
> +
> +[LibraryClasses]
> +  UefiBootServicesTableLib
> +  UefiDriverEntryPoint
> +  DebugLib
> +  BaseLib
> +  BaseMemoryLib
> +  PrintLib
> +  SmmServicesTableLib
> +  MemoryAllocationLib
> +  UefiLib
> +  BaseCryptLib
> +  PlatformPasswordLib
> +
> +[Protocols]
> +  gEdkiiVariableLockProtocolGuid                ## CONSUMES
> +  gEfiSmmVariableProtocolGuid                   ## CONSUMES
> +
> +[Depex]
> +  gEfiSmmVariableProtocolGuid
> +
> +[UserExtensions.TianoCore."ExtraFiles"]
> +  UserAuthenticationDxeExtra.uni
> +
> +
> diff --git
> a/SecurityPkg/Password/UserAuthentication/UserAuthenticationSmm.uni
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationSmm.uni
> new file mode 100644
> index 0000000..470c75c
> --- /dev/null
> +++
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationSmm.uni
> @@ -0,0 +1,22 @@
> +// /** @file
> +// User Authentication Smm Driver.
> +//
> +// This driver provides SMM services for DXE user authentication module.
> +//
> +// Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
> +//
> +// This program and the accompanying materials
> +// are licensed and made available under the terms and conditions of the
> BSD License
> +// which accompanies this distribution. The full text of the license may be
> found at
> +// http://opensource.org/licenses/bsd-license.php
> +//
> +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +//
> +// **/
> +
> +
> +#string STR_MODULE_ABSTRACT             #language en-US "SMM services for
> DXE user authentication module."
> +
> +#string STR_MODULE_DESCRIPTION          #language en-US "This driver
> provides SMM services for DXE user authentication module."
> +
> diff --git
> a/SecurityPkg/Password/UserAuthentication/UserAuthenticationSmmExtra.
> uni
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationSmmExtra.
> uni
> new file mode 100644
> index 0000000..5e338fe
> --- /dev/null
> +++
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationSmmExtra.
> uni
> @@ -0,0 +1,20 @@
> +// /** @file
> +// User Authentication Smm Driver.
> +//
> +// Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
> +//
> +// This program and the accompanying materials
> +// are licensed and made available under the terms and conditions of the
> BSD License
> +// which accompanies this distribution. The full text of the license may be
> found at
> +// http://opensource.org/licenses/bsd-license.php
> +//
> +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +//
> +// **/
> +
> +#string STR_PROPERTIES_MODULE_NAME
> +#language en-US
> +"User Authentication SMM Driver"
> +
> +
> --
> 2.7.4.windows.1
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel
Re: [edk2] [PATCH V2 5/6] SecurityPkg/Password: Add Password based UserAuthentication modules.
Posted by Long, Qin 7 years, 8 months ago
Good thoughts, though the time attack looks just theoretical in here (the hash result comparison in here can nearly ignored on CPU overhead.) :)
In general, time-based attack was possible if the attacker is capable of adjust some parameters to collect more CPU usage or power for clearer measurement, e.g. iteration numbers in PBKDF2.

Anyway, it is good thought here to use this SlowCompareMem function with a fixed CPU time cost. Just remember to add some ASSERT operations as the comment states.


Best Regards & Thanks,
LONG, Qin


From: Yao, Jiewen
Sent: Wednesday, February 8, 2017 5:04 PM
To: Long, Qin <qin.long@intel.com>; edk2-devel@lists.01.org
Cc: Zhang, Chao B <chao.b.zhang@intel.com>
Subject: RE: [PATCH V2 5/6] SecurityPkg/Password: Add Password based UserAuthentication modules.

Good question.
1) I will remove the unused code.

2) If BaseMemoryLib is used, the malicious code may guess which byte is incorrect by analyzing time on error returned - technically.

The SlowCompareMem is designed to mitigate time-attack for comparison. It always compare the full memory even the first byte is different.



Thank you
Yao Jiewen

From: Long, Qin
Sent: Wednesday, February 8, 2017 4:49 PM
To: Yao, Jiewen <jiewen.yao@intel.com<mailto:jiewen.yao@intel.com>>; edk2-devel@lists.01.org<mailto:edk2-devel@lists.01.org>
Cc: Zhang, Chao B <chao.b.zhang@intel.com<mailto:chao.b.zhang@intel.com>>
Subject: RE: [PATCH V2 5/6] SecurityPkg/Password: Add Password based UserAuthentication modules.

Some comments:
1. I didn't see any usage of KeyLibGenerateLib interface. Remove or just designed for future usage?
2. Why need one extra KeyLibSlowCompareMem? Instead of using one in BaseMemoryLib?
     And if necessary, please add extra ASSERT handling as the comments.

Reviewed-by: Qin Long <qin.long@intel.com<mailto:qin.long@intel.com>>

Best Regards & Thanks,
LONG, Qin


> -----Original Message-----
> From: Yao, Jiewen
> Sent: Tuesday, February 7, 2017 12:24 AM
> To: edk2-devel@lists.01.org<mailto:edk2-devel@lists.01.org>
> Cc: Long, Qin <qin.long@intel.com<mailto:qin.long@intel.com>>; Zhang, Chao B
> <chao.b.zhang@intel.com<mailto:chao.b.zhang@intel.com>>
> Subject: [PATCH V2 5/6] SecurityPkg/Password: Add Password based
> UserAuthentication modules.
>
> This password based user authentication is to verify user when a user
> wants to enter BIOS setup page.
>
> The DXE driver registers report status code listener.
> When it gets (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_PC_USER_SETUP)
> progress
> code, it will let the user input password.
> If and only if the user inputs the right password, the status code handler
> will return and let the setup driver continue running.
> If the user inputs the wrong password, the status code handler will let
> user try again.
> If the user inputs the wrong password 3 times, the status code handler will
> reset the system.
>
> The DXE driver also register a setup page in setup browser, so that
> user may update the password.
>
> The DXE driver uses SMI to let SMM driver do the password verification
> and management.
>
> The SMM driver registers SMI handler to perform the request from DXE.
> The password must meet below criteria:
> 1) Length >= 8 char
> 2) It must include lower case, upper case, number and symbol.
> 3) It must not duplicate with 5 previous password.
> If above criteria is met, the password will be saved to a read only UEFI
> variable. The format is password hash+salt, which is generated by
> Pkcs5HashPassword algorithm (SHA256+1000 iteration).
>
> If the SMM driver gets wrong password 3 times, the interface is locked
> and does not accept more request.
>
> If the SMM driver will detect IsPasswordCleared() at the entry point and
> clear the password if IsPasswordCleared() is TRUE. This can be used when
> the user forgets the password.
>
> Cc: Qin Long <qin.long@intel.com<mailto:qin.long@intel.com>>
> Cc: Chao Zhang <chao.b.zhang@intel.com<mailto:chao.b.zhang@intel.com>>
> Contributed-under: TianoCore Contribution Agreement 1.0
> Signed-off-by: Jiewen Yao <jiewen.yao@intel.com<mailto:jiewen.yao@intel.com>>
> ---
>  SecurityPkg/Password/UserAuthentication/KeyService.c                     | 210
> ++++++
>  SecurityPkg/Password/UserAuthentication/KeyService.h                     | 122
> ++++
>  SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.c          |
> 718 ++++++++++++++++++++
>  SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.h          |
> 115 ++++
>  SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.inf        |
> 79 +++
>  SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.uni        |
> 22 +
>  SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeExtra.uni
> |  20 +
>
> SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeFormset.
> h   |  30 +
>
> SecurityPkg/Password/UserAuthentication/UserAuthenticationDxePasswor
> d.c  | 301 ++++++++
>
> SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeStrings.u
> ni |  29 +
>  SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeVfr.vfr
> |  38 ++
>  SecurityPkg/Password/UserAuthentication/UserAuthenticationGuid.h         |
> 65 ++
>  SecurityPkg/Password/UserAuthentication/UserAuthenticationSmm.c          |
> 672 ++++++++++++++++++
>  SecurityPkg/Password/UserAuthentication/UserAuthenticationSmm.inf
> |  70 ++
>  SecurityPkg/Password/UserAuthentication/UserAuthenticationSmm.uni
> |  22 +
>
> SecurityPkg/Password/UserAuthentication/UserAuthenticationSmmExtra.un
> i   |  20 +
>  16 files changed, 2533 insertions(+)
>
> diff --git a/SecurityPkg/Password/UserAuthentication/KeyService.c
> b/SecurityPkg/Password/UserAuthentication/KeyService.c
> new file mode 100644
> index 0000000..81aa2f9
> --- /dev/null
> +++ b/SecurityPkg/Password/UserAuthentication/KeyService.c
> @@ -0,0 +1,210 @@
> +/** @file
> +  Password key service.
> +
> +Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
> +This program and the accompanying materials
> +are licensed and made available under the terms and conditions of the BSD
> License
> +which accompanies this distribution.  The full text of the license may be
> found at
> +http://opensource.org/licenses/bsd-license.php
> +
> +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +
> +**/
> +
> +#include <Uefi.h>
> +#include <Library/DebugLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/BaseCryptLib.h>
> +#include "KeyService.h"
> +
> +#define DEFAULT_AES_KEY_BIT_SIZE       256
> +#define DEFAULT_PBKDF2_ITERATION_COUNT 1000
> +
> +/**
> +  Compares the contents of two buffers with slow algorithm
> +
> +  This function compares Length bytes of SourceBuffer to Length bytes of
> DestinationBuffer.
> +  If all Length bytes of the two buffers are identical, then 0 is returned.
> Otherwise, the
> +  value returned is the first mismatched byte in SourceBuffer subtracted
> from the first
> +  mismatched byte in DestinationBuffer.
> +
> +  If Length > 0 and DestinationBuffer is NULL, then ASSERT().
> +  If Length > 0 and SourceBuffer is NULL, then ASSERT().
> +  If Length is greater than (MAX_ADDRESS - DestinationBuffer + 1), then
> ASSERT().
> +  If Length is greater than (MAX_ADDRESS - SourceBuffer + 1), then
> ASSERT().
> +
> +  @param  DestinationBuffer The pointer to the destination buffer to
> compare.
> +  @param  SourceBuffer      The pointer to the source buffer to compare.
> +  @param  Length            The number of bytes to compare.
> +
> +  @return 0                 All Length bytes of the two buffers are identical.
> +  @retval -1                The SourceBuffer is not identical to DestinationBuffer.
> +
> +**/
> +INTN
> +EFIAPI
> +KeyLibSlowCompareMem (
> +  IN CONST VOID  *DestinationBuffer,
> +  IN CONST VOID  *SourceBuffer,
> +  IN UINTN       Length
> +  )
> +{
> +  UINT8  Delta;
> +  UINTN  Index;
> +  UINT8  *Destination;
> +  UINT8  *Source;
> +
> +  Destination = (UINT8 *)DestinationBuffer;
> +  Source = (UINT8 *)SourceBuffer;
> +  Delta = 0;
> +  for (Index = 0; Index < Length; Index++) {
> +    Delta |= Destination[Index] ^ Source[Index];
> +  }
> +  if (Delta == 0) {
> +    return 0;
> +  } else {
> +    return -1;
> +  }
> +}
> +
> +/**
> +  Generate Salt value.
> +
> +  @param[in, out]   SaltValue           Points to the salt buffer
> +  @param[in]        SaltSize            Size of the salt buffer
> +
> +  @retval      TRUE           Salt is generated.
> +  @retval      FALSE          Salt is not generated.
> +**/
> +BOOLEAN
> +EFIAPI
> +KeyLibGenerateSalt (
> +  IN OUT UINT8  *SaltValue,
> +  IN UINTN      SaltSize
> +  )
> +{
> +  if (SaltValue == NULL) {
> +    return FALSE;
> +  }
> +  RandomSeed(NULL, 0);
> +  RandomBytes(SaltValue, SaltSize);
> +  return TRUE;
> +}
> +
> +/**
> +  Hash the data.
> +
> +  @param[in]   HashType         Hash type
> +  @param[in]   Key              Points to the key buffer
> +  @param[in]   KeySize          Key buffer size
> +  @param[in]   SaltValue        Points to the salt buffer
> +  @param[in]   SaltSize         Size of the salt buffer
> +  @param[out]  KeyHash          Points to the hashed result
> +  @param[in]   KeyHashSize      Size of the hash buffer
> +
> +  @retval      TRUE           Hash the data successfully.
> +  @retval      FALSE          Failed to hash the data.
> +
> +**/
> +BOOLEAN
> +EFIAPI
> +KeyLibGenerateHash(
> +  IN   UINT32              HashType,
> +  IN   VOID                *Key,
> +  IN   UINTN               KeySize,
> +  IN   UINT8               *SaltValue,
> +  IN   UINTN               SaltSize,
> +  OUT  UINT8               *KeyHash,
> +  IN   UINTN               KeyHashSize
> +  )
> +{
> +  BOOLEAN                     Status;
> +  UINTN                       HashSize;
> +  VOID                        *HashContext;
> +
> +  if (HashType != HASH_TYPE_SHA256) {
> +    return FALSE;
> +  }
> +  if (KeyHashSize != SHA256_DIGEST_SIZE) {
> +    return FALSE;
> +  }
> +
> +  if ((Key == NULL) || (SaltValue == NULL) || (KeyHash == NULL)) {
> +    return FALSE;
> +  }
> +
> +  HashSize    = Sha256GetContextSize ();
> +  HashContext = AllocateZeroPool (HashSize);
> +  if (HashContext == NULL) {
> +    return FALSE;
> +  }
> +
> +  Status = Sha256Init(HashContext);
> +  if (!Status) {
> +    goto Done;
> +  }
> +
> +  Status = Sha256Update(HashContext, SaltValue, SaltSize);
> +  if (!Status) {
> +    goto Done;
> +  }
> +  Status = Sha256Update(HashContext, Key, KeySize);
> +  if (!Status) {
> +    goto Done;
> +  }
> +
> +  Status = Sha256Final(HashContext, KeyHash);
> +Done:
> +  FreePool (HashContext);
> +  return Status;
> +}
> +
> +/**
> +  Hash the password with PBKDF2.
> +
> +  @param[in]   HashType         Hash type
> +  @param[in]   Key              Points to the key buffer
> +  @param[in]   KeySize          Key buffer size
> +  @param[in]   SaltValue        Points to the salt buffer
> +  @param[in]   SaltSize         Size of the salt buffer
> +  @param[out]  KeyHash          Points to the hashed result
> +  @param[in]   KeyHashSize      Size of the hash buffer
> +
> +  @retval      TRUE           Hash the data successfully.
> +  @retval      FALSE          Failed to hash the data.
> +
> +**/
> +BOOLEAN
> +EFIAPI
> +KeyLibGeneratePBKDF2Hash (
> +  IN   UINT32              HashType,
> +  IN   VOID                *Key,
> +  IN   UINTN               KeySize,
> +  IN   UINT8               *SaltValue,
> +  IN   UINTN               SaltSize,
> +  OUT  UINT8               *KeyHash,
> +  IN   UINTN               KeyHashSize
> +  )
> +{
> +  BOOLEAN  Result;
> +
> +  if (HashType != HASH_TYPE_SHA256) {
> +    return FALSE;
> +  }
> +  if (KeyHashSize != SHA256_DIGEST_SIZE) {
> +    return FALSE;
> +  }
> +
> +  Result = Pkcs5HashPassword (
> +             KeySize,
> +             Key,
> +             SaltSize,
> +             SaltValue,
> +             DEFAULT_PBKDF2_ITERATION_COUNT,
> +             SHA256_DIGEST_SIZE,
> +             KeyHashSize,
> +             KeyHash
> +             );
> +  return Result;
> +}
> diff --git a/SecurityPkg/Password/UserAuthentication/KeyService.h
> b/SecurityPkg/Password/UserAuthentication/KeyService.h
> new file mode 100644
> index 0000000..f287953
> --- /dev/null
> +++ b/SecurityPkg/Password/UserAuthentication/KeyService.h
> @@ -0,0 +1,122 @@
> +/** @file
> +  Header file for key service.
> +
> +  Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
> +  This program and the accompanying materials
> +  are licensed and made available under the terms and conditions of the BSD
> License
> +  which accompanies this distribution.  The full text of the license may be
> found at
> +  http://opensource.org/licenses/bsd-license.php
> +
> +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +
> +**/
> +
> +#ifndef __KEY_LIB_H__
> +#define __KEY_LIB_H__
> +
> +/**
> +  Compares the contents of two buffers with slow algorithm
> +
> +  This function compares Length bytes of SourceBuffer to Length bytes of
> DestinationBuffer.
> +  If all Length bytes of the two buffers are identical, then 0 is returned.
> Otherwise, the
> +  value returned is the first mismatched byte in SourceBuffer subtracted
> from the first
> +  mismatched byte in DestinationBuffer.
> +
> +  If Length > 0 and DestinationBuffer is NULL, then ASSERT().
> +  If Length > 0 and SourceBuffer is NULL, then ASSERT().
> +  If Length is greater than (MAX_ADDRESS - DestinationBuffer + 1), then
> ASSERT().
> +  If Length is greater than (MAX_ADDRESS - SourceBuffer + 1), then
> ASSERT().
> +
> +  @param  DestinationBuffer The pointer to the destination buffer to
> compare.
> +  @param  SourceBuffer      The pointer to the source buffer to compare.
> +  @param  Length            The number of bytes to compare.
> +
> +  @return 0                 All Length bytes of the two buffers are identical.
> +  @retval -1                The SourceBuffer is not identical to DestinationBuffer.
> +
> +**/
> +INTN
> +EFIAPI
> +KeyLibSlowCompareMem (
> +  IN CONST VOID  *DestinationBuffer,
> +  IN CONST VOID  *SourceBuffer,
> +  IN UINTN       Length
> +  );
> +
> +/**
> +  Generate Salt value.
> +
> +  @param[in, out]   SaltValue           Points to the salt buffer
> +  @param[in]        SaltSize            Size of the salt buffer
> +
> +  @retval      TRUE           Salt is generated.
> +  @retval      FALSE          Salt is not generated.
> +**/
> +BOOLEAN
> +EFIAPI
> +KeyLibGenerateSalt(
> +  IN OUT UINT8  *SaltValue,
> +  IN UINTN      SaltSize
> +  );
> +
> +#define HASH_TYPE_SHA256  0x000B
> +
> +#define SHA256_DIGEST_SIZE 32
> +
> +/**
> +  Hash the data.
> +
> +  @param[in]   HashType         Hash type
> +  @param[in]   Key              Points to the key buffer
> +  @param[in]   KeySize          Key buffer size
> +  @param[in]   SaltValue        Points to the salt buffer
> +  @param[in]   SaltSize         Size of the salt buffer
> +  @param[out]  KeyHash          Points to the hashed result
> +  @param[in]   KeyHashSize      Size of the hash buffer
> +
> +  @retval      TRUE           Hash the data successfully.
> +  @retval      FALSE          Failed to hash the data.
> +
> +**/
> +BOOLEAN
> +EFIAPI
> +KeyLibGenerateHash(
> +  IN   UINT32              HashType,
> +  IN   VOID                *Key,
> +  IN   UINTN               KeySize,
> +  IN   UINT8               *SaltValue,
> +  IN   UINTN               SaltSize,
> +  OUT  UINT8               *KeyHash,
> +  IN   UINTN               KeyHashSize
> +  );
> +
> +/**
> +  Hash the password with PBKDF2.
> +
> +  @param[in]   HashType         Hash type
> +  @param[in]   Key              Points to the key buffer
> +  @param[in]   KeySize          Key buffer size
> +  @param[in]   SaltValue        Points to the salt buffer
> +  @param[in]   SaltSize         Size of the salt buffer
> +  @param[out]  KeyHash          Points to the hashed result
> +  @param[in]   KeyHashSize      Size of the hash buffer
> +
> +  @retval      TRUE           Hash the data successfully.
> +  @retval      FALSE          Failed to hash the data.
> +
> +**/
> +BOOLEAN
> +EFIAPI
> +KeyLibGeneratePBKDF2Hash (
> +  IN   UINT32              HashType,
> +  IN   VOID                *Key,
> +  IN   UINTN               KeySize,
> +  IN   UINT8               *SaltValue,
> +  IN   UINTN               SaltSize,
> +  OUT  UINT8               *KeyHash,
> +  IN   UINTN               KeyHashSize
> +  );
> +
> +#endif
> +
> diff --git
> a/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.c
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.c
> new file mode 100644
> index 0000000..3836eac
> --- /dev/null
> +++ b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.c
> @@ -0,0 +1,718 @@
> +/** @file
> +  This Driver mainly do user authentication before entering Setup.
> +
> +Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
> +This program and the accompanying materials
> +are licensed and made available under the terms and conditions of the BSD
> License
> +which accompanies this distribution.  The full text of the license may be
> found at
> +http://opensource.org/licenses/bsd-license.php
> +
> +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +
> +**/
> +
> +#include "UserAuthenticationDxe.h"
> +
> +EFI_EVENT                           mExitBootServicesEvent  = NULL;
> +EFI_RSC_HANDLER_PROTOCOL           *mRscHandlerProtocol     = NULL;
> +USER_AUTHENTICATION_PRIVATE_DATA   *mUserAuthenticationData =
> NULL;
> +
> +UINTN  mAdminPasswordTryCount;
> +
> +EFI_GUID gAdminAuthenticationGuid = ADMIN_AUTHENTICATION_GUID;
> +
> +HII_VENDOR_DEVICE_PATH  mHiiVendorDevicePath = {
> +  {
> +    {
> +      HARDWARE_DEVICE_PATH,
> +      HW_VENDOR_DP,
> +      {
> +        (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
> +        (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
> +      }
> +    },
> +    USER_AUTHENTICATION_FORMSET_GUID
> +  },
> +  {
> +    END_DEVICE_PATH_TYPE,
> +    END_ENTIRE_DEVICE_PATH_SUBTYPE,
> +    {
> +      (UINT8) (END_DEVICE_PATH_LENGTH),
> +      (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
> +    }
> +  }
> +};
> +
> +/**
> +  Get a user input string.
> +
> +  @param[in]       PopUpString      A popup string to inform user.
> +  @param[in, out]  UserInput        The user input string
> +  @param[in]       UserInputMaxLen  The max unicode count of the
> UserInput without NULL terminator.
> +**/
> +EFI_STATUS
> +GetUserInput (
> +  IN     CHAR16      *PopUpString,
> +  IN OUT CHAR16      *UserInput,
> +  IN     UINTN       UserInputMaxLen
> +  )
> +{
> +  EFI_INPUT_KEY                InputKey;
> +  UINTN                        InputLength;
> +  CHAR16                       *Mask;
> +
> +  UserInput[0] = 0;
> +  Mask = AllocateZeroPool ((UserInputMaxLen + 1) * sizeof(CHAR16));
> +  if (Mask == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  InputLength = 0;
> +
> +  while (TRUE) {
> +    Mask[InputLength] = L'_';
> +    CreatePopUp (
> +      EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
> +      &InputKey,
> +      PopUpString,
> +      L"---------------------",
> +      Mask,
> +      NULL
> +      );
> +    if (InputKey.ScanCode == SCAN_NULL) {
> +      //
> +      // Check whether finish inputing password.
> +      //
> +      if (InputKey.UnicodeChar == CHAR_CARRIAGE_RETURN && InputLength >
> 0) {
> +        //
> +        // Add the null terminator.
> +        //
> +        UserInput[InputLength] = 0;
> +        break;
> +      } else if ((InputKey.UnicodeChar == CHAR_NULL) ||
> +                 (InputKey.UnicodeChar == CHAR_TAB) ||
> +                 (InputKey.UnicodeChar == CHAR_LINEFEED) ||
> +                 (InputKey.UnicodeChar == CHAR_CARRIAGE_RETURN)
> +                ) {
> +        continue;
> +      } else {
> +        //
> +        // delete last key entered
> +        //
> +        if (InputKey.UnicodeChar == CHAR_BACKSPACE) {
> +          if (InputLength > 0) {
> +            UserInput[InputLength] = 0;
> +            Mask[InputLength] = 0;
> +            InputLength--;
> +          }
> +        } else {
> +          //
> +          // add Next key entry
> +          //
> +          UserInput[InputLength] = InputKey.UnicodeChar;
> +          Mask[InputLength] = L'*';
> +          InputLength++;
> +          if (InputLength == UserInputMaxLen) {
> +            //
> +            // Add the null terminator.
> +            //
> +            UserInput[InputLength] = 0;
> +            Mask[InputLength] = 0;
> +            break;
> +          }
> +        }
> +      }
> +    }
> +  }
> +  FreePool (Mask);
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Display a message box to end user.
> +
> +  @param[in] DisplayString   The string in message box.
> +**/
> +VOID
> +MessageBox (
> +  IN CHAR16  *DisplayString
> +  )
> +{
> +  EFI_INPUT_KEY  Key;
> +
> +  do {
> +    CreatePopUp (
> +      EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
> +      &Key,
> +      L"",
> +      DisplayString,
> +      L"Press ENTER to continue ...",
> +      L"",
> +      NULL
> +      );
> +  } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
> +}
> +
> +/**
> +  Force system reset.
> +**/
> +VOID
> +ForceSystemReset (
> +  VOID
> +  )
> +{
> +  MessageBox (L"Password retry count reach, reset system!");
> +  gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);
> +  CpuDeadLoop();
> +}
> +
> +/**
> +  Display message for set password.
> +
> +  @param[in]  ReturnStatus   The return status for set password.
> +**/
> +VOID
> +PrintPasswordStatus (
> +  IN EFI_STATUS  ReturnStatus
> +  )
> +{
> +  CHAR16         *DisplayString;
> +
> +  if (ReturnStatus == EFI_SUCCESS) {
> +    DisplayString = L"New password is updated successfully!";
> +  } else if (ReturnStatus == EFI_UNSUPPORTED) {
> +    DisplayString = L"New password is not strong enough!";
> +  } else if (ReturnStatus == EFI_ALREADY_STARTED) {
> +    DisplayString = L"New password is found in history!";
> +  } else {
> +    DisplayString = L"New password update fails!";
> +  }
> +
> +  MessageBox (DisplayString);
> +}
> +
> +/**
> +  Require user input password.
> +
> +  @param[in]  UserGuid               The user GUID of the password.
> +
> +  @retval TRUE   User input correct password successfully.
> +  @retval FALSE  The password is not set.
> +**/
> +BOOLEAN
> +RequireUserPassword (
> +  IN   EFI_GUID     *UserGuid
> +  )
> +{
> +  EFI_STATUS                   Status;
> +  CHAR16                       UserInputPw[MAX_PASSWORD_LEN + 1];
> +  CHAR16                       TmpPassword[MAX_PASSWORD_LEN + 1];
> +  CHAR16                       *PopUpString;
> +  UINTN                        *PasswordTryCount;
> +
> +  Status = EFI_SUCCESS;
> +  ZeroMem(UserInputPw, sizeof(UserInputPw));
> +  ZeroMem(TmpPassword, sizeof(TmpPassword));
> +
> +  if (!IsPasswordSet(UserGuid)) {
> +    return FALSE;
> +  }
> +
> +  if (CompareGuid (UserGuid, &gAdminAuthenticationGuid)) {
> +    PopUpString = L"Please input admin password";
> +    PasswordTryCount = &mAdminPasswordTryCount;
> +  } else {
> +    DEBUG ((DEBUG_ERROR, "Invalid User Guid - %g\n", UserGuid));
> +    return FALSE;
> +  }
> +
> +  while (TRUE) {
> +    gST->ConOut->ClearScreen(gST->ConOut);
> +    GetUserInput (PopUpString, UserInputPw, MAX_PASSWORD_LEN);
> +
> +    CopyGuid (UserGuid, &gAdminAuthenticationGuid);
> +    Status = ValidatePassword (UserGuid, UserInputPw,
> StrSize(UserInputPw));
> +    if (!EFI_ERROR(Status)) {
> +      break;
> +    }
> +    *PasswordTryCount = *PasswordTryCount + 1;
> +    if (*PasswordTryCount >= PASSWORD_MAX_TRY_COUNT) {
> +      ForceSystemReset ();
> +    }
> +    MessageBox (L"Incorrect password!");
> +  }
> +  *PasswordTryCount = 0;
> +
> +  ZeroMem(UserInputPw, sizeof(UserInputPw));
> +  ZeroMem(TmpPassword, sizeof(TmpPassword));
> +
> +  gST->ConOut->ClearScreen(gST->ConOut);
> +
> +  return TRUE;
> +}
> +
> +/**
> +  Set user password.
> +
> +  @param[in]  UserGuid               The user GUID of the password.
> +
> +  @retval TRUE   The password is set.
> +  @retval FALSE  The password is not set.
> +**/
> +BOOLEAN
> +SetUserPassword (
> +  IN   EFI_GUID     *UserGuid
> +  )
> +{
> +  EFI_STATUS                   Status;
> +  CHAR16                       UserInputPw[MAX_PASSWORD_LEN + 1];
> +  CHAR16                       TmpPassword[MAX_PASSWORD_LEN + 1];
> +  CHAR16                       *PopUpString;
> +  CHAR16                       *PopUpString2;
> +
> +  Status = EFI_SUCCESS;
> +  ZeroMem(UserInputPw, sizeof(UserInputPw));
> +  ZeroMem(TmpPassword, sizeof(TmpPassword));
> +
> +  if (CompareGuid (UserGuid, &gAdminAuthenticationGuid)) {
> +    PopUpString = L"Please set admin password";
> +  } else {
> +    DEBUG ((DEBUG_ERROR, "Invalid User Guid - %g\n", UserGuid));
> +    return FALSE;
> +  }
> +
> +  while (TRUE) {
> +    gST->ConOut->ClearScreen(gST->ConOut);
> +    GetUserInput (PopUpString, UserInputPw, MAX_PASSWORD_LEN);
> +
> +    PopUpString2 = L"Please confirm your new password";
> +    gST->ConOut->ClearScreen(gST->ConOut);
> +    GetUserInput (PopUpString2, TmpPassword, MAX_PASSWORD_LEN);
> +    if (StrCmp (TmpPassword, UserInputPw) != 0) {
> +      MessageBox (L"Password are not the same!");
> +      continue;
> +    }
> +
> +    Status = SetPassword (UserGuid, UserInputPw, StrSize(UserInputPw),
> NULL, 0);
> +    PrintPasswordStatus (Status);
> +    if (!EFI_ERROR(Status)) {
> +      break;
> +    }
> +  }
> +
> +  ZeroMem(UserInputPw, sizeof(UserInputPw));
> +  ZeroMem(TmpPassword, sizeof(TmpPassword));
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Check password before entering into setup.
> +
> +  @param  CodeType      Indicates the type of status code being reported.
> Type EFI_STATUS_CODE_TYPE is defined in "Related Definitions" below.
> +
> +  @param  Value         Describes the current status of a hardware or software
> entity.
> +                        This included information about the class and subclass that is
> used to classify the entity
> +                        as well as an operation.  For progress codes, the operation is the
> current activity.
> +                        For error codes, it is the exception.  For debug codes, it is not
> defined at this time.
> +                        Type EFI_STATUS_CODE_VALUE is defined in "Related
> Definitions" below.
> +                        Specific values are discussed in the Intel? Platform Innovation
> Framework for EFI Status Code Specification.
> +
> +  @param  Instance      The enumeration of a hardware or software entity
> within the system.
> +                        A system may contain multiple entities that match a
> class/subclass pairing.
> +                        The instance differentiates between them.  An instance of 0
> indicates that instance information is unavailable,
> +                        not meaningful, or not relevant.  Valid instance numbers start
> with 1.
> +
> +
> +  @param  CallerId      This optional parameter may be used to identify the
> caller.
> +                        This parameter allows the status code driver to apply different
> rules to different callers.
> +                        Type EFI_GUID is defined in InstallProtocolInterface() in the
> UEFI 2.0 Specification.
> +
> +
> +  @param  Data          This optional parameter may be used to pass additional
> data
> +
> +  @retval EFI_SUCCESS             Status code is what we expected.
> +  @retval EFI_UNSUPPORTED         Status code not supported.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +CheckForPassword (
> +  IN EFI_STATUS_CODE_TYPE     CodeType,
> +  IN EFI_STATUS_CODE_VALUE    Value,
> +  IN UINT32                   Instance,
> +  IN EFI_GUID                 *CallerId, OPTIONAL
> +  IN EFI_STATUS_CODE_DATA     *Data      OPTIONAL
> +  )
> +{
> +  BOOLEAN   PasswordSet;
> +
> +  if (((CodeType & EFI_STATUS_CODE_TYPE_MASK) ==
> EFI_PROGRESS_CODE) &&
> +      (Value == (EFI_SOFTWARE_DXE_BS_DRIVER |
> EFI_SW_PC_USER_SETUP))) {
> +    //
> +    // Check whether enter setup page.
> +    //
> +    PasswordSet = RequireUserPassword (&gAdminAuthenticationGuid);
> +    if (PasswordSet) {
> +      DEBUG ((DEBUG_INFO, "Welcome Admin!\n"));
> +    } else {
> +      DEBUG ((DEBUG_INFO, "Admin password is not set!\n"));
> +      if (NeedEnrollPassword()) {
> +        SetUserPassword (&gAdminAuthenticationGuid);
> +      }
> +    }
> +
> +    return EFI_SUCCESS;
> +  } else{
> +    return EFI_UNSUPPORTED;
> +  }
> +}
> +
> +/**
> +  This function allows a caller to extract the current configuration for one
> +  or more named elements from the target driver.
> +
> +  @param  This                   Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
> +  @param  Request                A null-terminated Unicode string in
> +                                 <ConfigRequest> format.
> +  @param  Progress               On return, points to a character in the Request
> +                                 string. Points to the string's null terminator if
> +                                 request was successful. Points to the most recent
> +                                 '&' before the first failing name/value pair (or
> +                                 the beginning of the string if the failure is in
> +                                 the first name/value pair) if the request was not
> +                                 successful.
> +  @param  Results                A null-terminated Unicode string in
> +                                 <ConfigAltResp> format which has all values filled
> +                                 in for the names in the Request string. String to
> +                                 be allocated by the called function.
> +
> +  @retval EFI_SUCCESS            The Results is filled with the requested values.
> +  @retval EFI_OUT_OF_RESOURCES   Not enough memory to store the
> results.
> +  @retval EFI_INVALID_PARAMETER  Request is illegal syntax, or unknown
> name.
> +  @retval EFI_NOT_FOUND          Routing data doesn't match any storage in
> this
> +                                 driver.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ExtractConfig (
> +  IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
> +  IN  CONST EFI_STRING                       Request,
> +  OUT EFI_STRING                             *Progress,
> +  OUT EFI_STRING                             *Results
> +  )
> +{
> +  if (Progress == NULL || Results == NULL) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +  *Progress = Request;
> +  return EFI_NOT_FOUND;
> +}
> +
> +
> +/**
> +  This function processes the results of changes in configuration.
> +
> +  @param  This                   Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
> +  @param  Configuration          A null-terminated Unicode string in
> <ConfigResp>
> +                                 format.
> +  @param  Progress               A pointer to a string filled in with the offset of
> +                                 the most recent '&' before the first failing
> +                                 name/value pair (or the beginning of the string if
> +                                 the failure is in the first name/value pair) or
> +                                 the terminating NULL if all was successful.
> +
> +  @retval EFI_SUCCESS            The Results is processed successfully.
> +  @retval EFI_INVALID_PARAMETER  Configuration is NULL.
> +  @retval EFI_NOT_FOUND          Routing data doesn't match any storage in
> this
> +                                 driver.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +RouteConfig (
> +  IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
> +  IN  CONST EFI_STRING                       Configuration,
> +  OUT EFI_STRING                             *Progress
> +  )
> +{
> +  if (Configuration == NULL || Progress == NULL) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  *Progress = Configuration;
> +
> +  return EFI_NOT_FOUND;
> +}
> +
> +/**
> +  This function processes the results of changes in configuration.
> +
> +  @param  This                   Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
> +  @param  Action                 Specifies the type of action taken by the browser.
> +  @param  QuestionId             A unique value which is sent to the original
> +                                 exporting driver so that it can identify the type
> +                                 of data to expect.
> +  @param  Type                   The type of value for the question.
> +  @param  Value                  A pointer to the data being sent to the original
> +                                 exporting driver.
> +  @param  ActionRequest          On return, points to the action requested by
> the
> +                                 callback function.
> +
> +  @retval EFI_SUCCESS            The callback successfully handled the action.
> +  @retval EFI_OUT_OF_RESOURCES   Not enough storage is available to hold
> the
> +                                 variable and its data.
> +  @retval EFI_DEVICE_ERROR       The variable could not be saved.
> +  @retval EFI_UNSUPPORTED        The specified Action is not supported by
> the
> +                                 callback.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +UserAuthenticationCallback (
> +  IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
> +  IN  EFI_BROWSER_ACTION                     Action,
> +  IN  EFI_QUESTION_ID                        QuestionId,
> +  IN  UINT8                                  Type,
> +  IN  EFI_IFR_TYPE_VALUE                     *Value,
> +  OUT EFI_BROWSER_ACTION_REQUEST             *ActionRequest
> +  )
> +{
> +  EFI_STATUS  Status;
> +  CHAR16      *UserInputPassword;
> +  EFI_GUID    *UserGuid;
> +  UINTN       *PasswordTryCount;
> +
> +  Status = EFI_SUCCESS;
> +
> +  if (((Value == NULL) && (Action != EFI_BROWSER_ACTION_FORM_OPEN)
> && (Action != EFI_BROWSER_ACTION_FORM_CLOSE))||
> +      (ActionRequest == NULL)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  switch (Action) {
> +  case EFI_BROWSER_ACTION_CHANGING:
> +    {
> +      switch (QuestionId) {
> +      case ADMIN_PASSWORD_KEY_ID:
> +        UserGuid = &gAdminAuthenticationGuid;
> +        PasswordTryCount = &mAdminPasswordTryCount;
> +        if ((Type == EFI_IFR_TYPE_STRING) && (Value->string == 0) &&
> +            (mUserAuthenticationData->PasswordState ==
> BROWSER_STATE_SET_PASSWORD)) {
> +          mUserAuthenticationData->PasswordState =
> BROWSER_STATE_VALIDATE_PASSWORD;
> +          ZeroMem (mUserAuthenticationData->OldPassword,
> sizeof(mUserAuthenticationData->OldPassword));
> +          return EFI_INVALID_PARAMETER;
> +        }
> +        //
> +        // The Callback is responsible for validating old password input by user,
> +        // If Callback return EFI_SUCCESS, it indicates validation pass.
> +        //
> +        switch (mUserAuthenticationData->PasswordState) {
> +        case BROWSER_STATE_VALIDATE_PASSWORD:
> +          UserInputPassword = HiiGetString (mUserAuthenticationData-
> >HiiHandle, Value->string, NULL);
> +          if ((StrLen (UserInputPassword) >= PASSWORD_MAX_SIZE) ||
> (UserInputPassword[0] == 0)) {
> +            Status = EFI_NOT_READY;
> +            break;
> +          }
> +          Status = ValidatePassword (UserGuid, UserInputPassword, StrSize
> (UserInputPassword));
> +          if (Status == EFI_SUCCESS) {
> +            mUserAuthenticationData->PasswordState =
> BROWSER_STATE_SET_PASSWORD;
> +            StrCpyS (
> +              mUserAuthenticationData->OldPassword,
> +              sizeof(mUserAuthenticationData->OldPassword)/sizeof(CHAR16),
> +              UserInputPassword
> +              );
> +            *PasswordTryCount = 0;
> +          } else {
> +            //
> +            // Old password mismatch, return EFI_NOT_READY to prompt for
> error message.
> +            //
> +            Status = EFI_NOT_READY;
> +            *PasswordTryCount = *PasswordTryCount + 1;
> +            if (*PasswordTryCount >= PASSWORD_MAX_TRY_COUNT) {
> +              ForceSystemReset ();
> +            }
> +          }
> +          break;
> +
> +        case BROWSER_STATE_SET_PASSWORD:
> +          UserInputPassword = HiiGetString (mUserAuthenticationData-
> >HiiHandle, Value->string, NULL);
> +          if ((StrLen (UserInputPassword) >= PASSWORD_MAX_SIZE) ||
> (UserInputPassword[0] == 0)) {
> +            Status = EFI_NOT_READY;
> +            break;
> +          }
> +          Status = SetPassword (UserGuid, UserInputPassword, StrSize
> (UserInputPassword), mUserAuthenticationData->OldPassword,
> StrSize(mUserAuthenticationData->OldPassword));
> +          PrintPasswordStatus (Status);
> +          ZeroMem (mUserAuthenticationData->OldPassword,
> sizeof(mUserAuthenticationData->OldPassword));
> +          mUserAuthenticationData->PasswordState =
> BROWSER_STATE_VALIDATE_PASSWORD;
> +          break;
> +
> +        default:
> +          break;
> +        }
> +      default:
> +        break;
> +      }
> +    }
> +  default:
> +    break;
> +  }
> +  return Status;
> +}
> +
> +/**
> +  Unregister status code callback functions.
> +
> +  @param  Event         Event whose notification function is being invoked.
> +  @param  Context       Pointer to the notification function's context, which is
> +                        always zero in current implementation.
> +
> +**/
> +VOID
> +EFIAPI
> +UnregisterBootTimeHandlers (
> +  IN EFI_EVENT        Event,
> +  IN VOID             *Context
> +  )
> +{
> +  mRscHandlerProtocol->Unregister (CheckForPassword);
> +}
> +
> +/**
> +  User Authentication entry point.
> +
> +  @param ImageHandle     The image handle.
> +  @param SystemTable     The system table.
> +
> +  @retval EFI_SUCCESS    The entry point is executed successfully.
> +  @return  other         Contain some other errors.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +UserAuthenticationEntry (
> +  IN EFI_HANDLE           ImageHandle,
> +  IN EFI_SYSTEM_TABLE     *SystemTable
> +  )
> +{
> +  EFI_STATUS        Status;
> +  EFI_HANDLE        DriverHandle;
> +  EFI_HII_HANDLE    HiiHandle;
> +
> +  DriverHandle  = NULL;
> +
> +  mUserAuthenticationData = AllocateZeroPool (sizeof
> (USER_AUTHENTICATION_PRIVATE_DATA));
> +  if (mUserAuthenticationData == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  mUserAuthenticationData->ConfigAccess.ExtractConfig = ExtractConfig;
> +  mUserAuthenticationData->ConfigAccess.RouteConfig = RouteConfig;
> +  mUserAuthenticationData->ConfigAccess.Callback =
> UserAuthenticationCallback;
> +  mUserAuthenticationData->PasswordState =
> BROWSER_STATE_VALIDATE_PASSWORD;
> +
> +  //
> +  // Install Config Access protocol to driver handle.
> +  //
> +  Status = gBS->InstallMultipleProtocolInterfaces (
> +                  &DriverHandle,
> +                  &gEfiDevicePathProtocolGuid,
> +                  &mHiiVendorDevicePath,
> +                  &gEfiHiiConfigAccessProtocolGuid,
> +                  &mUserAuthenticationData->ConfigAccess,
> +                  NULL
> +                  );
> +  ASSERT_EFI_ERROR (Status);
> +  mUserAuthenticationData->DriverHandle = DriverHandle;
> +
> +  //
> +  // Add HII data to database.
> +  //
> +  HiiHandle = HiiAddPackages (
> +                   &gAdminAuthenticationGuid,
> +                   DriverHandle,
> +                   UserAuthenticationDxeStrings,
> +                   UserAuthenticationDxeVfrBin,
> +                   NULL
> +                   );
> +  if (HiiHandle == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +  mUserAuthenticationData->HiiHandle = HiiHandle;
> +
> +  //
> +  // Locate report status code protocol.
> +  //
> +  Status = gBS->LocateProtocol (
> +                  &gEfiRscHandlerProtocolGuid,
> +                  NULL,
> +                  (VOID **) &mRscHandlerProtocol
> +                  );
> +  ASSERT_EFI_ERROR (Status);
> +
> +  //
> +  //Register the callback function for ReportStatusCode() notification.
> +  //
> +  mRscHandlerProtocol->Register (CheckForPassword, TPL_HIGH_LEVEL);
> +
> +  //
> +  // Unregister boot time report status code listener at ExitBootService
> Event.
> +  //
> +  Status = gBS->CreateEventEx (
> +                  EVT_NOTIFY_SIGNAL,
> +                  TPL_NOTIFY,
> +                  UnregisterBootTimeHandlers,
> +                  NULL,
> +                  &gEfiEventExitBootServicesGuid,
> +                  &mExitBootServicesEvent
> +                  );
> +  ASSERT_EFI_ERROR (Status);
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Unloads the application and its installed protocol.
> +
> +  @param[in]  ImageHandle       Handle that identifies the image to be
> unloaded.
> +
> +  @retval EFI_SUCCESS           The image has been unloaded.
> +**/
> +EFI_STATUS
> +EFIAPI
> +UserAuthenticationUnload (
> +  IN EFI_HANDLE  ImageHandle
> +  )
> +{
> +  ASSERT (mUserAuthenticationData != NULL);
> +
> +  //
> +  // Uninstall Config Access Protocol.
> +  //
> +  if (mUserAuthenticationData->DriverHandle != NULL) {
> +    gBS->UninstallMultipleProtocolInterfaces (
> +           mUserAuthenticationData->DriverHandle,
> +           &gEfiDevicePathProtocolGuid,
> +           &mHiiVendorDevicePath,
> +           &gEfiHiiConfigAccessProtocolGuid,
> +           &mUserAuthenticationData->ConfigAccess,
> +           NULL
> +           );
> +    mUserAuthenticationData->DriverHandle = NULL;
> +  }
> +
> +  //
> +  // Remove Hii Data.
> +  //
> +  if (mUserAuthenticationData->HiiHandle != NULL) {
> +    HiiRemovePackages (mUserAuthenticationData->HiiHandle);
> +  }
> +
> +  FreePool (mUserAuthenticationData);
> +  mUserAuthenticationData = NULL;
> +
> +  return EFI_SUCCESS;
> +}
> +
> diff --git
> a/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.h
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.h
> new file mode 100644
> index 0000000..1bcc2a7
> --- /dev/null
> +++ b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.h
> @@ -0,0 +1,115 @@
> +/** @file
> +  Header file for UserAuthenticationDxe.
> +
> +Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
> +This program and the accompanying materials
> +are licensed and made available under the terms and conditions of the BSD
> License
> +which accompanies this distribution.  The full text of the license may be
> found at
> +http://opensource.org/licenses/bsd-license.php
> +
> +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +
> +
> +**/
> +
> +#ifndef _USER_AUTHENTICATION_DXE_H_
> +#define _USER_AUTHENTICATION_DXE_H_
> +
> +
> +#include <Protocol/ReportStatusCodeHandler.h>
> +#include <Protocol/HiiConfigAccess.h>
> +
> +#include <Guid/MdeModuleHii.h>
> +#include <Guid/HiiPlatformSetupFormset.h>
> +
> +#include <Library/DebugLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/UefiRuntimeServicesTableLib.h>
> +#include <Library/UefiDriverEntryPoint.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +#include <Library/BaseLib.h>
> +#include <Library/UefiLib.h>
> +#include <Library/HiiLib.h>
> +#include <Library/DevicePathLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/PlatformPasswordLib.h>
> +#include "UserAuthenticationGuid.h"
> +#include "UserAuthenticationDxeFormset.h"
> +
> +extern UINT8  UserAuthenticationDxeVfrBin[];
> +extern UINT8  UserAuthenticationDxeStrings[];
> +
> +typedef struct {
> +  EFI_HII_CONFIG_ACCESS_PROTOCOL       ConfigAccess;
> +  EFI_HANDLE                           DriverHandle;
> +  EFI_HII_HANDLE                       HiiHandle;
> +  UINT8                                PasswordState;
> +  CHAR16                               OldPassword[PASSWORD_MAX_SIZE];
> +} USER_AUTHENTICATION_PRIVATE_DATA;
> +
> +#pragma pack(1)
> +///
> +/// HII specific Vendor Device Path definition.
> +///
> +typedef struct {
> +  VENDOR_DEVICE_PATH             VendorDevicePath;
> +  EFI_DEVICE_PATH_PROTOCOL       End;
> +} HII_VENDOR_DEVICE_PATH;
> +#pragma pack()
> +
> +/**
> +  Validata if the password is correct.
> +
> +  @param[in]  UserGuid               The user GUID of the password.
> +  @param[in]  Password               The user input password.
> +  @param[in]  PasswordSize           The size of Password in byte.
> +
> +  @retval EFI_SUCCESS              The password is correct.
> +  @retval EFI_SECURITY_VIOLATION   The password is incorrect.
> +**/
> +EFI_STATUS
> +ValidatePassword (
> +  IN   EFI_GUID     *UserGuid,
> +  IN   CHAR16       *Password,
> +  IN   UINTN        PasswordSize
> +  );
> +
> +/**
> +  Set a new password.
> +
> +  @param[in]  UserGuid               The user GUID of the password.
> +  @param[in]  NewPassword            The user input new password.
> +                                     NULL means clear password.
> +  @param[in]  NewPasswordSize        The size of NewPassword in byte.
> +  @param[in]  OldPassword            The user input old password.
> +                                     NULL means no old password.
> +  @param[in]  OldPasswordSize        The size of OldPassword in byte.
> +
> +  @retval EFI_SUCCESS              The password is correct.
> +  @retval EFI_SECURITY_VIOLATION   The password is incorrect.
> +  @retval EFI_OUT_OF_RESOURCES     Insufficient resources to set the
> password.
> +**/
> +EFI_STATUS
> +SetPassword (
> +  IN   EFI_GUID     *UserGuid,
> +  IN   CHAR16       *NewPassword,     OPTIONAL
> +  IN   UINTN        NewPasswordSize,
> +  IN   CHAR16       *OldPassword,     OPTIONAL
> +  IN   UINTN        OldPasswordSize
> +  );
> +
> +/**
> +  Return if the password is set.
> +
> +  @param[in]  UserGuid               The user GUID of the password.
> +
> +  @retval TRUE    The password is set.
> +  @retval FALSE   The password is not set.
> +**/
> +BOOLEAN
> +IsPasswordSet (
> +  IN   EFI_GUID     *UserGuid
> +  );
> +
> +#endif
> diff --git
> a/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.inf
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.inf
> new file mode 100644
> index 0000000..75a8076
> --- /dev/null
> +++
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.inf
> @@ -0,0 +1,79 @@
> +## @file
> +#  User Authentication Dxe Driver.
> +#
> +#  This Driver mainly does user authentication before entering Setup.
> +#
> +# Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
> +#
> +#  This program and the accompanying materials
> +#  are licensed and made available under the terms and conditions of the
> BSD License
> +#  which accompanies this distribution. The full text of the license may be
> found at
> +#  http://opensource.org/licenses/bsd-license.php
> +#
> +#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +#
> +#
> +##
> +
> +[Defines]
> +  INF_VERSION                    = 0x00010005
> +  BASE_NAME                      = UserAuthenticationDxe
> +  MODULE_UNI_FILE                = UserAuthenticationDxe.uni
> +  FILE_GUID                      = 0683FB88-664C-4BA6-9ED4-1C0916EE43A4
> +  MODULE_TYPE                    = DXE_DRIVER
> +  VERSION_STRING                 = 2.0
> +  ENTRY_POINT                    = UserAuthenticationEntry
> +  ENTRY_POINT                    = PasswordDxeInit
> +  UNLOAD_IMAGE                   = UserAuthenticationUnload
> +
> +
> +[Sources]
> +  UserAuthenticationDxe.c
> +  UserAuthenticationDxe.h
> +  UserAuthenticationDxePassword.c
> +  UserAuthenticationDxeFormset.h
> +  UserAuthenticationGuid.h
> +  UserAuthenticationDxeVfr.vfr
> +  UserAuthenticationDxeStrings.uni
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +  MdeModulePkg/MdeModulePkg.dec
> +  SecurityPkg/SecurityPkg.dec
> +
> +[LibraryClasses]
> +  BaseLib
> +  UefiBootServicesTableLib
> +  UefiDriverEntryPoint
> +  UefiRuntimeServicesTableLib
> +  BaseMemoryLib
> +  DebugLib
> +  UefiLib
> +  HiiLib
> +  DevicePathLib
> +  MemoryAllocationLib
> +  PlatformPasswordLib
> +
> +[Guids]
> +  gEfiEventExitBootServicesGuid                 ## CONSUMES  ## Event
> +  gEdkiiPiSmmCommunicationRegionTableGuid       ## CONSUMES  ##
> SystemTable
> +
> +[Protocols]
> +  gEfiRscHandlerProtocolGuid                    ## CONSUMES
> +  gEfiDevicePathProtocolGuid                    ## PRODUCES
> +  gEfiHiiConfigAccessProtocolGuid               ## PRODUCES
> +  gEfiSmmCommunicationProtocolGuid              ## CONSUMES
> +
> +[Depex]
> +  gEfiSimpleTextOutProtocolGuid      AND
> +  gEfiHiiDatabaseProtocolGuid        AND
> +  gEfiSmmCommunicationProtocolGuid   AND
> +  gEfiVariableArchProtocolGuid       AND
> +  gEfiVariableWriteArchProtocolGuid
> +
> +[UserExtensions.TianoCore."ExtraFiles"]
> +  UserAuthenticationDxeExtra.uni
> +
> +
> +
> diff --git
> a/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.uni
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.uni
> new file mode 100644
> index 0000000..6b2d292
> --- /dev/null
> +++
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.uni
> @@ -0,0 +1,22 @@
> +// /** @file
> +// User Authentication Dxe Driver.
> +//
> +// This driver mainly does the user authentication before entering Setup.
> +//
> +// Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
> +//
> +// This program and the accompanying materials
> +// are licensed and made available under the terms and conditions of the
> BSD License
> +// which accompanies this distribution. The full text of the license may be
> found at
> +// http://opensource.org/licenses/bsd-license.php
> +//
> +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +//
> +// **/
> +
> +
> +#string STR_MODULE_ABSTRACT             #language en-US "User
> Authentication Dxe Driver."
> +
> +#string STR_MODULE_DESCRIPTION          #language en-US "This driver
> mainly does user authentication before entering Setup."
> +
> diff --git
> a/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeExtra.u
> ni
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeExtra.u
> ni
> new file mode 100644
> index 0000000..86c5c9b
> --- /dev/null
> +++
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeExtra.u
> ni
> @@ -0,0 +1,20 @@
> +// /** @file
> +// User Authentication Dxe Driver.
> +//
> +// Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
> +//
> +// This program and the accompanying materials
> +// are licensed and made available under the terms and conditions of the
> BSD License
> +// which accompanies this distribution. The full text of the license may be
> found at
> +// http://opensource.org/licenses/bsd-license.php
> +//
> +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +//
> +// **/
> +
> +#string STR_PROPERTIES_MODULE_NAME
> +#language en-US
> +"User Authentication DXE Driver"
> +
> +
> diff --git
> a/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeForms
> et.h
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeForms
> et.h
> new file mode 100644
> index 0000000..4d29a5d
> --- /dev/null
> +++
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeForms
> et.h
> @@ -0,0 +1,30 @@
> +/** @file
> +  Header file for UserAuthentication formset.
> +
> +Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
> +This program and the accompanying materials
> +are licensed and made available under the terms and conditions of the BSD
> License
> +which accompanies this distribution.  The full text of the license may be
> found at
> +http://opensource.org/licenses/bsd-license.php
> +
> +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +
> +
> +**/
> +
> +#ifndef _USER_AUTHENTICATION_DXE_FORMSET_H_
> +#define _USER_AUTHENTICATION_DXE_FORMSET_H_
> +
> +//
> +// Vendor GUID of the formset
> +//
> +#define USER_AUTHENTICATION_FORMSET_GUID \
> +  { 0x760e3022, 0xf149, 0x4560, {0x9c, 0x6f, 0x33, 0xaa, 0x7d, 0x48, 0x75,
> 0xfa} }
> +
> +#define ADMIN_PASSWORD_KEY_ID   0x2001
> +
> +#define MAX_PASSWORD_LEN  20
> +#define MIN_PASSWORD_LEN  8
> +
> +#endif
> diff --git
> a/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxePassw
> ord.c
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxePassw
> ord.c
> new file mode 100644
> index 0000000..00b051a
> --- /dev/null
> +++
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxePassw
> ord.c
> @@ -0,0 +1,301 @@
> +/** @file
> +  UserAuthentication DXE password wrapper.
> +
> +Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
> +This program and the accompanying materials
> +are licensed and made available under the terms and conditions of the BSD
> License
> +which accompanies this distribution.  The full text of the license may be
> found at
> +http://opensource.org/licenses/bsd-license.php
> +
> +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +
> +**/
> +
> +#include "UserAuthenticationDxe.h"
> +#include <Guid/PiSmmCommunicationRegionTable.h>
> +#include <Protocol/SmmCommunication.h>
> +
> +EFI_SMM_COMMUNICATION_PROTOCOL *mSmmCommunication = NULL;
> +
> +/**
> +  Initialize the communicate buffer using DataSize and Function.
> +
> +  @param[out]      DataPtr          Points to the data in the communicate buffer.
> +  @param[in]       DataSize         The data size to send to SMM.
> +  @param[in]       Function         The function number to initialize the
> communicate header.
> +  @param[in]       UserGuid         The user GUID of the password.
> +
> +  @retval EFI_INVALID_PARAMETER     The data size is too big.
> +  @retval EFI_SUCCESS               Find the specified variable.
> +**/
> +VOID*
> +InitCommunicateBuffer (
> +  OUT     VOID                              **DataPtr OPTIONAL,
> +  IN      UINTN                             DataSize,
> +  IN      UINTN                             Function,
> +  IN      EFI_GUID                          *UserGuid
> +  )
> +{
> +  EFI_SMM_COMMUNICATE_HEADER                *SmmCommunicateHeader;
> +  SMM_PASSWORD_COMMUNICATE_HEADER
> *SmmPasswordFunctionHeader;
> +  VOID                                      *Buffer;
> +  EDKII_PI_SMM_COMMUNICATION_REGION_TABLE
> *SmmCommRegionTable;
> +  EFI_MEMORY_DESCRIPTOR                     *SmmCommMemRegion;
> +  UINTN                                     Index;
> +  UINTN                                     Size;
> +  EFI_STATUS                                Status;
> +
> +  Buffer = NULL;
> +  Status = EfiGetSystemConfigurationTable (
> +             &gEdkiiPiSmmCommunicationRegionTableGuid,
> +             (VOID **) &SmmCommRegionTable
> +             );
> +  if (EFI_ERROR (Status)) {
> +    return NULL;
> +  }
> +  ASSERT (SmmCommRegionTable != NULL);
> +  SmmCommMemRegion = (EFI_MEMORY_DESCRIPTOR *)
> (SmmCommRegionTable + 1);
> +  Size = 0;
> +  for (Index = 0; Index < SmmCommRegionTable->NumberOfEntries;
> Index++) {
> +    if (SmmCommMemRegion->Type == EfiConventionalMemory) {
> +      Size = EFI_PAGES_TO_SIZE ((UINTN) SmmCommMemRegion-
> >NumberOfPages);
> +      if (Size >= (DataSize + OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER,
> Data) + sizeof (SMM_PASSWORD_COMMUNICATE_HEADER))) {
> +        break;
> +      }
> +    }
> +    SmmCommMemRegion = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *)
> SmmCommMemRegion + SmmCommRegionTable->DescriptorSize);
> +  }
> +  ASSERT (Index < SmmCommRegionTable->NumberOfEntries);
> +
> +  Buffer = (VOID*)(UINTN)SmmCommMemRegion->PhysicalStart;
> +  ASSERT (Buffer != NULL);
> +  SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *)
> Buffer;
> +  CopyGuid (&SmmCommunicateHeader->HeaderGuid, UserGuid);
> +  SmmCommunicateHeader->MessageLength = DataSize + sizeof
> (SMM_PASSWORD_COMMUNICATE_HEADER);
> +
> +  SmmPasswordFunctionHeader =
> (SMM_PASSWORD_COMMUNICATE_HEADER *) SmmCommunicateHeader-
> >Data;
> +  ZeroMem (SmmPasswordFunctionHeader, DataSize + sizeof
> (SMM_PASSWORD_COMMUNICATE_HEADER));
> +  SmmPasswordFunctionHeader->Function = Function;
> +  CopyGuid (&SmmPasswordFunctionHeader->UserGuid, UserGuid);
> +  if (DataPtr != NULL) {
> +    *DataPtr = SmmPasswordFunctionHeader + 1;
> +  }
> +
> +  return Buffer;
> +}
> +
> +/**
> +  Send the data in communicate buffer to SMM.
> +
> +  @param[in]   Buffer                 Points to the data in the communicate buffer.
> +  @param[in]   DataSize               This size of the function header and the data.
> +
> +  @retval      EFI_SUCCESS            Success is returned from the functin in SMM.
> +  @retval      Others                 Failure is returned from the function in SMM.
> +
> +**/
> +EFI_STATUS
> +SendCommunicateBuffer (
> +  IN      VOID                              *Buffer,
> +  IN      UINTN                             DataSize
> +  )
> +{
> +  EFI_STATUS                                Status;
> +  UINTN                                     CommSize;
> +  EFI_SMM_COMMUNICATE_HEADER                *SmmCommunicateHeader;
> +  SMM_PASSWORD_COMMUNICATE_HEADER
> *SmmPasswordFunctionHeader;
> +
> +  CommSize = DataSize + OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER,
> Data) + sizeof (SMM_PASSWORD_COMMUNICATE_HEADER);
> +
> +  Status = mSmmCommunication->Communicate (mSmmCommunication,
> Buffer, &CommSize);
> +  ASSERT_EFI_ERROR (Status);
> +
> +  SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *)
> Buffer;
> +  SmmPasswordFunctionHeader =
> (SMM_PASSWORD_COMMUNICATE_HEADER *)SmmCommunicateHeader-
> >Data;
> +  return  SmmPasswordFunctionHeader->ReturnStatus;
> +}
> +
> +/**
> +  Validata if the password is correct.
> +
> +  @param[in]  UserGuid               The user GUID of the password.
> +  @param[in]  Password               The user input password.
> +  @param[in]  PasswordSize           The size of Password in byte.
> +
> +  @retval EFI_SUCCESS              The password is correct.
> +  @retval EFI_SECURITY_VIOLATION   The password is incorrect.
> +**/
> +EFI_STATUS
> +ValidatePassword (
> +  IN   EFI_GUID     *UserGuid,
> +  IN   CHAR16       *Password,
> +  IN   UINTN        PasswordSize
> +  )
> +{
> +  EFI_STATUS                                Status;
> +  VOID                                      *Buffer;
> +  SMM_PASSWORD_COMMUNICATE_VERIFY_PASSWORD
> *VerifyPassword;
> +
> +  ASSERT (Password != NULL);
> +
> +  if (PasswordSize > sizeof(VerifyPassword->Password) * sizeof(CHAR16)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  Buffer = InitCommunicateBuffer (
> +             (VOID**)&VerifyPassword,
> +             sizeof(*VerifyPassword),
> +             SMM_PASSWORD_FUNCTION_VERIFY_PASSWORD,
> +             UserGuid
> +             );
> +  if (Buffer == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  Status = UnicodeStrToAsciiStrS (Password, VerifyPassword->Password,
> sizeof(VerifyPassword->Password));
> +  if (EFI_ERROR(Status)) {
> +    return Status;
> +  }
> +
> +  Status = SendCommunicateBuffer (Buffer, sizeof(*VerifyPassword));
> +  if (EFI_ERROR (Status)) {
> +    goto EXIT;
> +  }
> +
> +EXIT:
> +  ZeroMem (VerifyPassword, sizeof(*VerifyPassword));
> +  return Status;
> +}
> +
> +/**
> +  Set a new password.
> +
> +  @param[in]  UserGuid               The user GUID of the password.
> +  @param[in]  NewPassword            The user input new password.
> +                                     NULL means clear password.
> +  @param[in]  NewPasswordSize        The size of NewPassword in byte.
> +  @param[in]  OldPassword            The user input old password.
> +                                     NULL means no old password.
> +  @param[in]  OldPasswordSize        The size of OldPassword in byte.
> +
> +  @retval EFI_SUCCESS              The password is correct.
> +  @retval EFI_SECURITY_VIOLATION   The password is incorrect.
> +  @retval EFI_OUT_OF_RESOURCES     Insufficient resources to set the
> password.
> +**/
> +EFI_STATUS
> +SetPassword (
> +  IN   EFI_GUID     *UserGuid,
> +  IN   CHAR16       *NewPassword,     OPTIONAL
> +  IN   UINTN        NewPasswordSize,
> +  IN   CHAR16       *OldPassword,     OPTIONAL
> +  IN   UINTN        OldPasswordSize
> +  )
> +{
> +  EFI_STATUS                                Status;
> +  VOID                                      *Buffer;
> +  SMM_PASSWORD_COMMUNICATE_SET_PASSWORD     *SetPassword;
> +
> +  if (NewPasswordSize > sizeof(SetPassword->NewPassword) *
> sizeof(CHAR16)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +  if (OldPasswordSize > sizeof(SetPassword->OldPassword) *
> sizeof(CHAR16)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  Buffer = InitCommunicateBuffer (
> +             (VOID**)&SetPassword,
> +             sizeof(*SetPassword),
> +             SMM_PASSWORD_FUNCTION_SET_PASSWORD,
> +             UserGuid
> +             );
> +  if (Buffer == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  if (NewPassword != NULL) {
> +    Status = UnicodeStrToAsciiStrS (NewPassword, SetPassword-
> >NewPassword, sizeof(SetPassword->NewPassword));
> +    if (EFI_ERROR(Status)) {
> +      return Status;
> +    }
> +  } else {
> +    SetPassword->NewPassword[0] = 0;
> +  }
> +
> +  if (OldPassword != NULL) {
> +    Status = UnicodeStrToAsciiStrS (OldPassword, SetPassword-
> >OldPassword, sizeof(SetPassword->OldPassword));
> +    if (EFI_ERROR(Status)) {
> +      return Status;
> +    }
> +  } else {
> +    SetPassword->OldPassword[0] = 0;
> +  }
> +
> +  Status = SendCommunicateBuffer (Buffer, sizeof(*SetPassword));
> +  if (EFI_ERROR (Status)) {
> +    goto EXIT;
> +  }
> +
> +EXIT:
> +  ZeroMem (SetPassword, sizeof(*SetPassword));
> +  return Status;
> +}
> +
> +/**
> +  Return if the password is set.
> +
> +  @param[in]  UserGuid               The user GUID of the password.
> +
> +  @retval TRUE    The password is set.
> +  @retval FALSE   The password is not set.
> +**/
> +BOOLEAN
> +IsPasswordSet (
> +  IN   EFI_GUID     *UserGuid
> +  )
> +{
> +  EFI_STATUS                                Status;
> +  VOID                                      *Buffer;
> +
> +  Buffer = InitCommunicateBuffer (
> +             NULL,
> +             0,
> +             SMM_PASSWORD_FUNCTION_IS_PASSWORD_SET,
> +             UserGuid
> +             );
> +  if (Buffer == NULL) {
> +    return FALSE;
> +  }
> +
> +  Status = SendCommunicateBuffer (Buffer, 0);
> +  if (EFI_ERROR (Status)) {
> +    return FALSE;
> +  }
> +
> +  return TRUE;
> +}
> +
> +/**
> +  Main entry for this driver.
> +
> +  @param ImageHandle     Image handle this driver.
> +  @param SystemTable     Pointer to SystemTable.
> +
> +  @retval EFI_SUCESS     This function always complete successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PasswordDxeInit (
> +  IN EFI_HANDLE                         ImageHandle,
> +  IN EFI_SYSTEM_TABLE                   *SystemTable
> +  )
> +{
> +  EFI_STATUS                     Status;
> +
> +  Status = gBS->LocateProtocol (&gEfiSmmCommunicationProtocolGuid,
> NULL, (VOID **) &mSmmCommunication);
> +  ASSERT_EFI_ERROR (Status);
> +
> +  return EFI_SUCCESS;
> +}
> +
> diff --git
> a/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeStrings.
> uni
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeStrings
> .uni
> new file mode 100644
> index 0000000..86fde22
> --- /dev/null
> +++
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeStrings
> .uni
> @@ -0,0 +1,29 @@
> +/** @file
> +// String definitions for User Authentication formset.
> +
> +// Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
> +// This program and the accompanying materials
> +// are licensed and made available under the terms and conditions of the
> BSD License
> +// which accompanies this distribution.  The full text of the license may be
> found at
> +// http://opensource.org/licenses/bsd-license.php
> +
> +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +
> +**/
> +
> +#langdef en-US  "English"
> +#langdef fr-FR  "Francais"
> +
> +
> +#string STR_FORM_SET_TITLE             #language en-US "User Password
> Management"
> +                                       #language fr-FR "User Password Management"
> +#string STR_FORM_SET_TITLE_HELP        #language en-US "This Driver
> mainly handle user's password"
> +                                       #language fr-FR "This Driver mainly handle user's
> password"
> +#string STR_FORM_TITLE                 #language en-US "Password Management
> Form"
> +                                       #language fr-FR "Password Management Form"
> +#string STR_ADMIN_PASSWORD_PROMPT      #language en-US "Change
> Admin Password"
> +                                       #language fr-FR "Change Admin Password"
> +#string STR_ADMIN_PASSWORD_HELP        #language en-US "Input old
> admin password, then you can change the password to a new one. After the
> change action, you need input the new password when you enter UI. The
> new password must be at least 8 char and include lowercase, uppercase
> alphabetic, numbers, and symbols."
> +                                       #language fr-FR "Input old admin password, then you
> can change the password to a new one. After the change action, you need
> input the new password when you enter UI. The new password must be at
> least 8 char and include lowercase, uppercase alphabetic, numbers, and
> symbols."
> +
> diff --git
> a/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeVfr.vfr
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeVfr.vfr
> new file mode 100644
> index 0000000..4741fe3
> --- /dev/null
> +++
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeVfr.vfr
> @@ -0,0 +1,38 @@
> +///** @file
> +// UserAuthentication formset.
> +//
> +// Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
> +// This program and the accompanying materials
> +// are licensed and made available under the terms and conditions of the
> BSD License
> +// which accompanies this distribution.  The full text of the license may be
> found at
> +// http://opensource.org/licenses/bsd-license.php
> +//
> +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +
> +//**/
> +
> +#include <Guid/HiiPlatformSetupFormset.h>
> +#include "UserAuthenticationDxeFormset.h"
> +
> +formset
> +  guid      = USER_AUTHENTICATION_FORMSET_GUID,
> +  title     = STRING_TOKEN(STR_FORM_SET_TITLE),
> +  help      = STRING_TOKEN(STR_FORM_SET_TITLE_HELP),
> +  classguid = EFI_HII_PLATFORM_SETUP_FORMSET_GUID,
> +
> +  form formid = 1,
> +      title  = STRING_TOKEN(STR_FORM_TITLE);
> +
> +      password
> +          prompt   = STRING_TOKEN(STR_ADMIN_PASSWORD_PROMPT),
> +          help     = STRING_TOKEN(STR_ADMIN_PASSWORD_HELP),
> +          flags    = INTERACTIVE,
> +          key      = ADMIN_PASSWORD_KEY_ID,
> +          minsize = MIN_PASSWORD_LEN,
> +          maxsize = MAX_PASSWORD_LEN,
> +      endpassword;
> +
> +  endform;
> +
> +endformset;
> diff --git
> a/SecurityPkg/Password/UserAuthentication/UserAuthenticationGuid.h
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationGuid.h
> new file mode 100644
> index 0000000..0a4df01
> --- /dev/null
> +++ b/SecurityPkg/Password/UserAuthentication/UserAuthenticationGuid.h
> @@ -0,0 +1,65 @@
> +/** @file
> +  GUID is for UserPassword variable.
> +
> +Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
> +This program and the accompanying materials are licensed and made
> available under
> +the terms and conditions of the BSD License that accompanies this
> distribution.
> +The full text of the license may be found at
> +http://opensource.org/licenses/bsd-license.php.
> +
> +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +
> +**/
> +
> +#ifndef __USER_AUTHENTICATION_GUID_H__
> +#define __USER_AUTHENTICATION_GUID_H__
> +
> +#define PASSWORD_MIN_SIZE    9  // MIN number of char of password,
> including NULL
> +#define PASSWORD_MAX_SIZE    32 // MAX number of char of password,
> including NULL
> +#define PASSWORD_SALT_SIZE   32
> +#define PASSWORD_HASH_SIZE   32 // SHA256_DIGEST_SIZE
> +
> +#define PASSWORD_MAX_TRY_COUNT  3
> +#define PASSWORD_HISTORY_CHECK_COUNT  5
> +
> +//
> +// Vendor GUID of the variable
> +//
> +#define ADMIN_AUTHENTICATION_GUID \
> +  { 0xee24a7f7, 0x606b, 0x4724, { 0xb3, 0xc9, 0xf5, 0xae, 0x4a, 0x3b, 0x81,
> 0x65} }
> +
> +//
> +// Name of the variable
> +//
> +#define USER_AUTHENTICATION_VAR_NAME L"Password"
> +#define USER_AUTHENTICATION_HISTORY_LAST_VAR_NAME
> L"PasswordLast"
> +
> +//
> +// Variable storage
> +//
> +typedef struct {
> +  UINT8        PasswordHash[PASSWORD_HASH_SIZE];
> +  UINT8        PasswordSalt[PASSWORD_SALT_SIZE];
> +} USER_PASSWORD_VAR_STRUCT;
> +
> +typedef struct {
> +  UINTN       Function;
> +  EFI_STATUS  ReturnStatus;
> +  EFI_GUID    UserGuid;
> +} SMM_PASSWORD_COMMUNICATE_HEADER;
> +
> +#define SMM_PASSWORD_FUNCTION_IS_PASSWORD_SET     1
> +#define SMM_PASSWORD_FUNCTION_SET_PASSWORD        2
> +#define SMM_PASSWORD_FUNCTION_VERIFY_PASSWORD     3
> +
> +typedef struct {
> +  CHAR8                                 NewPassword[PASSWORD_MAX_SIZE];
> +  CHAR8                                 OldPassword[PASSWORD_MAX_SIZE];
> +} SMM_PASSWORD_COMMUNICATE_SET_PASSWORD;
> +
> +typedef struct {
> +  CHAR8                                 Password[PASSWORD_MAX_SIZE];
> +} SMM_PASSWORD_COMMUNICATE_VERIFY_PASSWORD;
> +
> +#endif
> diff --git
> a/SecurityPkg/Password/UserAuthentication/UserAuthenticationSmm.c
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationSmm.c
> new file mode 100644
> index 0000000..ffc3d81
> --- /dev/null
> +++ b/SecurityPkg/Password/UserAuthentication/UserAuthenticationSmm.c
> @@ -0,0 +1,672 @@
> +/** @file
> +
> +Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
> +This program and the accompanying materials
> +are licensed and made available under the terms and conditions of the BSD
> License
> +which accompanies this distribution.  The full text of the license may be
> found at
> +http://opensource.org/licenses/bsd-license.php
> +
> +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +
> +**/
> +
> +#include <PiSmm.h>
> +#include <Protocol/SmmVariable.h>
> +#include <Protocol/VariableLock.h>
> +#include <Library/DebugLib.h>
> +#include <Library/BaseLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/PrintLib.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +#include <Library/SmmServicesTableLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/SmmServicesTableLib.h>
> +#include <Library/PlatformPasswordLib.h>
> +#include "KeyService.h"
> +#include "UserAuthenticationGuid.h"
> +
> +EFI_GUID gAdminAuthenticationGuid = ADMIN_AUTHENTICATION_GUID;
> +
> +EFI_SMM_VARIABLE_PROTOCOL         *mSmmVariable;
> +
> +UINTN  mAdminPasswordTryCount;
> +
> +/**
> +  Verify if the password is correct.
> +
> +  @param[in]  Password               The user input password.
> +  @param[in]  PasswordSize           The size of Password in byte.
> +  @param[in]  UserPasswordVarStruct  The storage of password in variable.
> +
> +  @retval EFI_SUCCESS              The password is correct.
> +  @retval EFI_SECURITY_VIOLATION   The password is incorrect.
> +**/
> +EFI_STATUS
> +VerifyPassword (
> +  IN CHAR8                          *Password,
> +  IN UINTN                          PasswordSize,
> +  IN USER_PASSWORD_VAR_STRUCT       *UserPasswordVarStruct
> +  )
> +{
> +  BOOLEAN  HashOk;
> +  UINT8    HashData[PASSWORD_HASH_SIZE];
> +
> +  HashOk = KeyLibGeneratePBKDF2Hash (
> +             HASH_TYPE_SHA256,
> +             (UINT8 *)Password,
> +             PasswordSize,
> +             UserPasswordVarStruct->PasswordSalt,
> +             sizeof(UserPasswordVarStruct->PasswordSalt),
> +             HashData,
> +             sizeof(HashData)
> +             );
> +  if (!HashOk) {
> +    return EFI_DEVICE_ERROR;
> +  }
> +  if (KeyLibSlowCompareMem (UserPasswordVarStruct->PasswordHash,
> HashData, PASSWORD_HASH_SIZE) == 0) {
> +    return EFI_SUCCESS;
> +  } else {
> +    return EFI_SECURITY_VIOLATION;
> +  }
> +}
> +
> +/**
> +  Get hash data of password from non-volatile variable region.
> +
> +  @param[in]   UserGuid               The user GUID of the password variable.
> +  @param[in]   Index                  The index of the password.
> +                                      0 means current password.
> +                                      Non-0 means the password history.
> +  @param[out]  UserPasswordVarStruct  The storage of password in variable.
> +
> +  @retval EFI_SUCCESS             The password hash is returned successfully.
> +  @retval EFI_NOT_FOUND           The password hash is not found.
> +**/
> +EFI_STATUS
> +GetPasswordHashFromVariable (
> +  IN  EFI_GUID                       *UserGuid,
> +  IN  UINTN                          Index,
> +  OUT USER_PASSWORD_VAR_STRUCT       *UserPasswordVarStruct
> +  )
> +{
> +  EFI_STATUS                        Status;
> +  UINTN                             DataSize;
> +  CHAR16
> PasswordName[sizeof(USER_AUTHENTICATION_VAR_NAME)/sizeof(CHAR1
> 6) + 4];
> +
> +  if (Index != 0) {
> +    UnicodeSPrint (PasswordName, sizeof (PasswordName), L"%s%04x",
> USER_AUTHENTICATION_VAR_NAME, Index);
> +  } else {
> +    UnicodeSPrint (PasswordName, sizeof (PasswordName), L"%s",
> USER_AUTHENTICATION_VAR_NAME);
> +  }
> +
> +  DataSize = sizeof(*UserPasswordVarStruct);
> +  Status = mSmmVariable->SmmGetVariable (
> +                           PasswordName,
> +                           UserGuid,
> +                           NULL,
> +                           &DataSize,
> +                           UserPasswordVarStruct
> +                           );
> +  if (EFI_ERROR(Status)) {
> +    return Status;
> +  }
> +
> +  return Status;
> +}
> +
> +/**
> +  Save password hash data to non-volatile variable region.
> +
> +  @param[in]   UserGuid               The user GUID of the password variable.
> +  @param[in]   UserPasswordVarStruct  The storage of password in variable.
> +
> +  @retval EFI_SUCCESS             The password hash is saved successfully.
> +  @retval EFI_OUT_OF_RESOURCES    Insufficient resources to save the
> password hash.
> +**/
> +EFI_STATUS
> +SavePasswordHashToVariable (
> +  IN EFI_GUID                       *UserGuid,
> +  IN USER_PASSWORD_VAR_STRUCT       *UserPasswordVarStruct
> +  )
> +{
> +  EFI_STATUS                        Status;
> +
> +  if (UserPasswordVarStruct == NULL) {
> +    Status = mSmmVariable->SmmSetVariable (
> +                             USER_AUTHENTICATION_VAR_NAME,
> +                             UserGuid,
> +                             EFI_VARIABLE_BOOTSERVICE_ACCESS |
> EFI_VARIABLE_NON_VOLATILE,
> +                             0,
> +                             NULL
> +                             );
> +  } else {
> +    Status = mSmmVariable->SmmSetVariable (
> +                             USER_AUTHENTICATION_VAR_NAME,
> +                             UserGuid,
> +                             EFI_VARIABLE_BOOTSERVICE_ACCESS |
> EFI_VARIABLE_NON_VOLATILE,
> +                             sizeof(*UserPasswordVarStruct),
> +                             UserPasswordVarStruct
> +                             );
> +  }
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "SavePasswordHashToVariable fails with %r\n",
> Status));
> +  }
> +
> +  return Status;
> +}
> +
> +/**
> +  Save old password hash data to non-volatile variable region as history.
> +
> +  The number of password history variable is limited.
> +  If all the password history variables are used, the new password history
> +  will override the oldest one.
> +
> +  @param[in]   UserGuid               The user GUID of the password variable.
> +  @param[in]   UserPasswordVarStruct  The storage of password in variable.
> +
> +  @retval EFI_SUCCESS             The password hash is saved successfully.
> +  @retval EFI_OUT_OF_RESOURCES    Insufficient resources to save the
> password hash.
> +**/
> +EFI_STATUS
> +SaveOldPasswordToHistory (
> +  IN EFI_GUID                       *UserGuid,
> +  IN USER_PASSWORD_VAR_STRUCT       *UserPasswordVarStruct
> +  )
> +{
> +  EFI_STATUS                        Status;
> +  UINTN                             DataSize;
> +  UINT32                            LastIndex;
> +  CHAR16
> PasswordName[sizeof(USER_AUTHENTICATION_VAR_NAME)/sizeof(CHAR1
> 6) + 4];
> +
> +  DEBUG ((DEBUG_INFO, "SaveOldPasswordToHistory\n"));
> +
> +  DataSize = sizeof(LastIndex);
> +  Status = mSmmVariable->SmmGetVariable (
> +                           USER_AUTHENTICATION_HISTORY_LAST_VAR_NAME,
> +                           UserGuid,
> +                           NULL,
> +                           &DataSize,
> +                           &LastIndex
> +                           );
> +  if (EFI_ERROR(Status)) {
> +    LastIndex = 0;
> +  }
> +  if (LastIndex >= PASSWORD_HISTORY_CHECK_COUNT) {
> +    LastIndex = 0;
> +  }
> +
> +  LastIndex ++;
> +  UnicodeSPrint (PasswordName, sizeof (PasswordName), L"%s%04x",
> USER_AUTHENTICATION_VAR_NAME, LastIndex);
> +
> +
> +  Status = mSmmVariable->SmmSetVariable (
> +                           PasswordName,
> +                           UserGuid,
> +                           EFI_VARIABLE_BOOTSERVICE_ACCESS |
> EFI_VARIABLE_NON_VOLATILE,
> +                           sizeof(*UserPasswordVarStruct),
> +                           UserPasswordVarStruct
> +                           );
> +  DEBUG ((DEBUG_INFO, "  -- to %s, %r\n", PasswordName, Status));
> +  if (!EFI_ERROR(Status)) {
> +    Status = mSmmVariable->SmmSetVariable (
> +                             USER_AUTHENTICATION_HISTORY_LAST_VAR_NAME,
> +                             UserGuid,
> +                             EFI_VARIABLE_BOOTSERVICE_ACCESS |
> EFI_VARIABLE_NON_VOLATILE,
> +                             sizeof(LastIndex),
> +                             &LastIndex
> +                             );
> +    DEBUG ((DEBUG_INFO, " LastIndex - 0x%04x, %r\n", LastIndex, Status));
> +  }
> +
> +  return Status;
> +}
> +
> +/**
> +  Calculate password hash data and save it to non-volatile variable region.
> +
> +  @param[in]  UserGuid               The user GUID of the password variable.
> +  @param[in]  Password               The user input password.
> +                                     NULL means delete the password variable.
> +  @param[in]  PasswordSize           The size of Password in byte.
> +
> +  @retval EFI_SUCCESS             The password hash is calculated and saved.
> +  @retval EFI_OUT_OF_RESOURCES    Insufficient resources to save the
> password hash.
> +**/
> +EFI_STATUS
> +SavePasswordToVariable (
> +  IN  EFI_GUID                      *UserGuid,
> +  IN  CHAR8                         *Password,  OPTIONAL
> +  IN  UINTN                         PasswordSize
> +  )
> +{
> +  EFI_STATUS                        Status;
> +  USER_PASSWORD_VAR_STRUCT          UserPasswordVarStruct;
> +  BOOLEAN                           HashOk;
> +
> +  //
> +  // If password is NULL, it means we want to clean password field saved in
> variable region.
> +  //
> +  if (Password != NULL) {
> +    KeyLibGenerateSalt (UserPasswordVarStruct.PasswordSalt,
> sizeof(UserPasswordVarStruct.PasswordSalt));
> +    HashOk = KeyLibGeneratePBKDF2Hash (
> +               HASH_TYPE_SHA256,
> +               (UINT8 *)Password,
> +               PasswordSize,
> +               UserPasswordVarStruct.PasswordSalt,
> +               sizeof(UserPasswordVarStruct.PasswordSalt),
> +               UserPasswordVarStruct.PasswordHash,
> +               sizeof(UserPasswordVarStruct.PasswordHash)
> +               );
> +    if (!HashOk) {
> +      return EFI_DEVICE_ERROR;
> +    }
> +    Status = SavePasswordHashToVariable (UserGuid,
> &UserPasswordVarStruct);
> +    //
> +    // Save Password data to history variable
> +    //
> +    if (!EFI_ERROR(Status)) {
> +      SaveOldPasswordToHistory (UserGuid, &UserPasswordVarStruct);
> +    }
> +  } else {
> +    Status = SavePasswordHashToVariable (UserGuid, NULL);
> +  }
> +
> +  return Status;
> +}
> +
> +/**
> +  Verify the password.
> +  If the password variable does not exist, it passes the verification.
> +  If the password variable exists, it does verification based upon password
> variable.
> +
> +  @param[in]  UserGuid               The user GUID of the password variable.
> +  @param[in]  Password               The user input password.
> +  @param[in]  PasswordSize           The size of Password in byte.
> +
> +  @retval TRUE    The verification passes.
> +  @retval FALSE   The verification fails.
> +**/
> +BOOLEAN
> +IsPasswordVerified (
> +  IN EFI_GUID                       *UserGuid,
> +  IN CHAR8                          *Password,
> +  IN UINTN                          PasswordSize
> +  )
> +{
> +  USER_PASSWORD_VAR_STRUCT          UserPasswordVarStruct;
> +  EFI_STATUS                        Status;
> +
> +  Status = GetPasswordHashFromVariable (UserGuid, 0,
> &UserPasswordVarStruct);
> +  if (EFI_ERROR(Status)) {
> +    return TRUE;
> +  }
> +
> +  //
> +  // Old password exists
> +  //
> +  Status = VerifyPassword (Password, PasswordSize,
> &UserPasswordVarStruct);
> +  if (EFI_ERROR(Status)) {
> +    return FALSE;
> +  }
> +
> +  return TRUE;
> +}
> +
> +/**
> +  Return if the password is set.
> +
> +  @param[in]  UserGuid               The user GUID of the password variable.
> +
> +  @retval TRUE    The password is set.
> +  @retval FALSE   The password is not set.
> +**/
> +BOOLEAN
> +IsPasswordSet (
> +  IN EFI_GUID                       *UserGuid
> +  )
> +{
> +  USER_PASSWORD_VAR_STRUCT          UserPasswordVarStruct;
> +  EFI_STATUS                        Status;
> +
> +  Status = GetPasswordHashFromVariable(UserGuid, 0,
> &UserPasswordVarStruct);
> +  if (EFI_ERROR(Status)) {
> +    return FALSE;
> +  }
> +  return TRUE;
> +}
> +
> +/**
> +  Return if the password is strong.
> +  Criteria:
> +  1) length >= PASSWORD_MIN_SIZE
> +  2) include lower case, upper case, number, symbol.
> +
> +  @param[in]  Password               The user input password.
> +  @param[in]  PasswordSize           The size of Password in byte.
> +
> +  @retval TRUE    The password is strong.
> +  @retval FALSE   The password is weak.
> +**/
> +BOOLEAN
> +IsPasswordStrong (
> +  IN CHAR8   *Password,
> +  IN UINTN   PasswordSize
> +  )
> +{
> +  UINTN   Index;
> +  BOOLEAN HasLowerCase;
> +  BOOLEAN HasUpperCase;
> +  BOOLEAN HasNumber;
> +  BOOLEAN HasSymbol;
> +
> +  if (PasswordSize < PASSWORD_MIN_SIZE) {
> +    return FALSE;
> +  }
> +
> +  HasLowerCase = FALSE;
> +  HasUpperCase = FALSE;
> +  HasNumber = FALSE;
> +  HasSymbol = FALSE;
> +  for (Index = 0; Index < PasswordSize - 1; Index++) {
> +    if (Password[Index] >= 'a' && Password[Index] <= 'z') {
> +      HasLowerCase = TRUE;
> +    } else if (Password[Index] >= 'A' && Password[Index] <= 'Z') {
> +      HasUpperCase = TRUE;
> +    } else if (Password[Index] >= '0' && Password[Index] <= '9') {
> +      HasNumber = TRUE;
> +    } else {
> +      HasSymbol = TRUE;
> +    }
> +  }
> +  if ((!HasLowerCase) || (!HasUpperCase) || (!HasNumber) || (!HasSymbol))
> {
> +    return FALSE;
> +  }
> +  return TRUE;
> +}
> +
> +/**
> +  Return if the password is set before in
> PASSWORD_HISTORY_CHECK_COUNT.
> +
> +  @param[in]  UserGuid               The user GUID of the password variable.
> +  @param[in]  Password               The user input password.
> +  @param[in]  PasswordSize           The size of Password in byte.
> +
> +  @retval TRUE    The password is set before.
> +  @retval FALSE   The password is not set before.
> +**/
> +BOOLEAN
> +IsPasswordInHistory (
> +  IN EFI_GUID                       *UserGuid,
> +  IN CHAR8                          *Password,
> +  IN UINTN                          PasswordSize
> +  )
> +{
> +  EFI_STATUS                     Status;
> +  USER_PASSWORD_VAR_STRUCT       UserPasswordVarStruct;
> +  UINTN                          Index;
> +
> +  for (Index = 1; Index <= PASSWORD_HISTORY_CHECK_COUNT; Index++) {
> +    Status = GetPasswordHashFromVariable (UserGuid, Index,
> &UserPasswordVarStruct);
> +    if (!EFI_ERROR(Status)) {
> +      Status = VerifyPassword (Password, PasswordSize,
> &UserPasswordVarStruct);
> +      if (!EFI_ERROR(Status)) {
> +        return TRUE;
> +      }
> +    }
> +  }
> +
> +  return FALSE;
> +}
> +
> +/**
> +  Communication service SMI Handler entry.
> +
> +  This SMI handler provides services for password management.
> +
> +  @param[in]     DispatchHandle  The unique handle assigned to this handler
> by SmiHandlerRegister().
> +  @param[in]     RegisterContext Points to an optional handler context which
> was specified when the
> +                                 handler was registered.
> +  @param[in, out] CommBuffer     A pointer to a collection of data in
> memory that will
> +                                 be conveyed from a non-SMM environment into an SMM
> environment.
> +  @param[in, out] CommBufferSize The size of the CommBuffer.
> +
> +  @retval EFI_SUCCESS                         The interrupt was handled and quiesced.
> No other handlers
> +                                              should still be called.
> +  @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED  The interrupt has
> been quiesced but other handlers should
> +                                              still be called.
> +  @retval EFI_WARN_INTERRUPT_SOURCE_PENDING   The interrupt is still
> pending and other handlers should still
> +                                              be called.
> +  @retval EFI_INTERRUPT_PENDING               The interrupt could not be
> quiesced.
> +**/
> +EFI_STATUS
> +EFIAPI
> +SmmPasswordHandler (
> +  IN     EFI_HANDLE                 DispatchHandle,
> +  IN     CONST VOID                 *RegisterContext,
> +  IN OUT VOID                       *CommBuffer,
> +  IN OUT UINTN                      *CommBufferSize
> +  )
> +{
> +  EFI_STATUS                                Status;
> +  SMM_PASSWORD_COMMUNICATE_HEADER           *SmmFunctionHeader;
> +  UINTN                                     CommBufferPayloadSize;
> +  UINTN                                     TempCommBufferSize;
> +  SMM_PASSWORD_COMMUNICATE_SET_PASSWORD
> SmmCommunicateSetPassword;
> +  SMM_PASSWORD_COMMUNICATE_VERIFY_PASSWORD
> SmmCommunicateVerifyPassword;
> +  UINTN                                     PasswordLen;
> +  EFI_GUID                                  UserGuid;
> +  UINTN                                     *PasswordTryCount;
> +
> +  //
> +  // If input is invalid, stop processing this SMI
> +  //
> +  if (CommBuffer == NULL || CommBufferSize == NULL) {
> +    return EFI_SUCCESS;
> +  }
> +
> +  TempCommBufferSize = *CommBufferSize;
> +
> +  if (TempCommBufferSize < sizeof
> (SMM_PASSWORD_COMMUNICATE_HEADER)) {
> +    DEBUG ((DEBUG_ERROR, "SmmPasswordHandler: SMM communication
> buffer size invalid!\n"));
> +    return EFI_SUCCESS;
> +  }
> +
> +  CommBufferPayloadSize = TempCommBufferSize - sizeof
> (SMM_PASSWORD_COMMUNICATE_HEADER);
> +
> +  Status   = EFI_SUCCESS;
> +  SmmFunctionHeader = (SMM_PASSWORD_COMMUNICATE_HEADER
> *)CommBuffer;
> +  CopyGuid (&UserGuid, &SmmFunctionHeader->UserGuid);
> +
> +  if (CompareGuid (&UserGuid, &gAdminAuthenticationGuid)) {
> +    PasswordTryCount = &mAdminPasswordTryCount;
> +  } else {
> +    DEBUG ((DEBUG_ERROR, "SmmPasswordHandler: Invalid UserGuid\n"));
> +    PasswordTryCount = NULL;
> +    Status = EFI_INVALID_PARAMETER;
> +    goto EXIT;
> +  }
> +
> +  switch (SmmFunctionHeader->Function) {
> +  case SMM_PASSWORD_FUNCTION_IS_PASSWORD_SET:
> +    PasswordTryCount = NULL;
> +    if (CommBufferPayloadSize != 0) {
> +      DEBUG ((DEBUG_ERROR, "SmmPasswordHandler: IS_PASSWORD_SET
> payload buffer invalid!\n"));
> +      Status = EFI_INVALID_PARAMETER;
> +      goto EXIT;
> +    }
> +    if (IsPasswordSet(&UserGuid)) {
> +      Status = EFI_SUCCESS;
> +    } else {
> +      Status = EFI_NOT_FOUND;
> +    }
> +    break;
> +  case SMM_PASSWORD_FUNCTION_SET_PASSWORD:
> +    if (*PasswordTryCount >= PASSWORD_MAX_TRY_COUNT) {
> +      DEBUG ((DEBUG_ERROR, "SmmPasswordHandler: SET_PASSWORD try
> count reach!\n"));
> +      PasswordTryCount = NULL;
> +      Status = EFI_INVALID_PARAMETER;
> +      goto EXIT;
> +    }
> +    if (CommBufferPayloadSize !=
> sizeof(SMM_PASSWORD_COMMUNICATE_SET_PASSWORD)) {
> +      DEBUG ((DEBUG_ERROR, "SmmPasswordHandler: SET_PASSWORD
> payload buffer invalid!\n"));
> +      Status = EFI_INVALID_PARAMETER;
> +      goto EXIT;
> +    }
> +    CopyMem (&SmmCommunicateSetPassword, SmmFunctionHeader + 1,
> sizeof(SmmCommunicateSetPassword));
> +
> +    PasswordLen =
> AsciiStrnLenS(SmmCommunicateSetPassword.OldPassword,
> sizeof(SmmCommunicateSetPassword.OldPassword));
> +    if (PasswordLen == sizeof(SmmCommunicateSetPassword.OldPassword))
> {
> +      DEBUG ((DEBUG_ERROR, "SmmPasswordHandler: OldPassword
> invalid!\n"));
> +      Status = EFI_INVALID_PARAMETER;
> +      goto EXIT;
> +    }
> +
> +    if (!IsPasswordVerified (&UserGuid,
> SmmCommunicateSetPassword.OldPassword, PasswordLen + 1)) {
> +      DEBUG ((DEBUG_ERROR, "SmmPasswordHandler: PasswordVerify -
> FAIL\n"));
> +      Status = EFI_SECURITY_VIOLATION;
> +      goto EXIT;
> +    }
> +
> +    PasswordLen =
> AsciiStrnLenS(SmmCommunicateSetPassword.NewPassword,
> sizeof(SmmCommunicateSetPassword.NewPassword));
> +    if (PasswordLen ==
> sizeof(SmmCommunicateSetPassword.NewPassword)) {
> +      DEBUG ((DEBUG_ERROR, "SmmPasswordHandler: NewPassword
> invalid!\n"));
> +      Status = EFI_INVALID_PARAMETER;
> +      goto EXIT;
> +    }
> +    if (!IsPasswordStrong (SmmCommunicateSetPassword.NewPassword,
> PasswordLen + 1)) {
> +      DEBUG ((DEBUG_ERROR, "SmmPasswordHandler: NewPassword too
> weak!\n"));
> +      Status = EFI_UNSUPPORTED;
> +      goto EXIT;
> +    }
> +    if (IsPasswordInHistory (&UserGuid,
> SmmCommunicateSetPassword.NewPassword, PasswordLen + 1)) {
> +      DEBUG ((DEBUG_ERROR, "SmmPasswordHandler: NewPassword in
> history!\n"));
> +      Status = EFI_ALREADY_STARTED;
> +      goto EXIT;
> +    }
> +
> +    if (PasswordLen == 0) {
> +      Status = SavePasswordToVariable (&UserGuid, NULL, 0);
> +    } else {
> +      Status = SavePasswordToVariable (&UserGuid,
> SmmCommunicateSetPassword.NewPassword, PasswordLen + 1);
> +    }
> +    break;
> +
> +  case SMM_PASSWORD_FUNCTION_VERIFY_PASSWORD:
> +    if (*PasswordTryCount >= PASSWORD_MAX_TRY_COUNT) {
> +      DEBUG ((DEBUG_ERROR, "SmmPasswordHandler: VERIFY_PASSWORD
> try count reach!\n"));
> +      PasswordTryCount = NULL;
> +      Status = EFI_INVALID_PARAMETER;
> +      goto EXIT;
> +    }
> +    if (CommBufferPayloadSize !=
> sizeof(SMM_PASSWORD_COMMUNICATE_VERIFY_PASSWORD)) {
> +      DEBUG ((DEBUG_ERROR, "SmmPasswordHandler: VERIFY_PASSWORD
> payload buffer invalid!\n"));
> +      Status = EFI_INVALID_PARAMETER;
> +      goto EXIT;
> +    }
> +    CopyMem (&SmmCommunicateVerifyPassword, SmmFunctionHeader +
> 1, sizeof(SmmCommunicateVerifyPassword));
> +
> +    PasswordLen =
> AsciiStrnLenS(SmmCommunicateVerifyPassword.Password,
> sizeof(SmmCommunicateVerifyPassword.Password));
> +    if (PasswordLen == sizeof(SmmCommunicateVerifyPassword.Password))
> {
> +      DEBUG ((DEBUG_ERROR, "SmmPasswordHandler: Password invalid!\n"));
> +      Status = EFI_INVALID_PARAMETER;
> +      goto EXIT;
> +    }
> +    if (!IsPasswordVerified (&UserGuid,
> SmmCommunicateVerifyPassword.Password, PasswordLen + 1)) {
> +      DEBUG ((DEBUG_ERROR, "SmmPasswordHandler: PasswordVerify -
> FAIL\n"));
> +      Status = EFI_SECURITY_VIOLATION;
> +      goto EXIT;
> +    }
> +    Status = EFI_SUCCESS;
> +    break;
> +
> +  default:
> +    PasswordTryCount = NULL;
> +    Status = EFI_UNSUPPORTED;
> +    break;
> +  }
> +
> +EXIT:
> +  if (PasswordTryCount != NULL) {
> +    if (Status == EFI_SUCCESS) {
> +      *PasswordTryCount = 0;
> +    } else {
> +      *PasswordTryCount = *PasswordTryCount + 1;
> +    }
> +  }
> +  SmmFunctionHeader->ReturnStatus = Status;
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Main entry for this driver.
> +
> +  @param ImageHandle     Image handle this driver.
> +  @param SystemTable     Pointer to SystemTable.
> +
> +  @retval EFI_SUCESS     This function always complete successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PasswordSmmInit (
> +  IN EFI_HANDLE                         ImageHandle,
> +  IN EFI_SYSTEM_TABLE                   *SystemTable
> +  )
> +{
> +  EFI_STATUS                            Status;
> +  EFI_HANDLE                            SmmHandle;
> +  EDKII_VARIABLE_LOCK_PROTOCOL          *VariableLock;
> +  CHAR16
> PasswordHistoryName[sizeof(USER_AUTHENTICATION_VAR_NAME)/sizeof(
> CHAR16) + 4];
> +  UINTN                                 Index;
> +
> +  ASSERT (PASSWORD_HASH_SIZE == SHA256_DIGEST_SIZE);
> +  ASSERT (PASSWORD_HISTORY_CHECK_COUNT < 0xFFFF);
> +
> +  Status = gSmst->SmmLocateProtocol (&gEfiSmmVariableProtocolGuid,
> NULL, (VOID**)&mSmmVariable);
> +  ASSERT_EFI_ERROR (Status);
> +
> +  SmmHandle          = NULL;
> +
> +  //
> +  // Make "HddPassword" varible read-only for DXE driver for security
> concern.
> +  //
> +  Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL,
> (VOID **) &VariableLock);
> +  if (!EFI_ERROR (Status)) {
> +    Status = VariableLock->RequestToLock (VariableLock,
> USER_AUTHENTICATION_VAR_NAME, &gAdminAuthenticationGuid);
> +    ASSERT_EFI_ERROR (Status);
> +
> +    for (Index = 1; Index <= PASSWORD_HISTORY_CHECK_COUNT; Index++) {
> +      UnicodeSPrint (PasswordHistoryName, sizeof (PasswordHistoryName),
> L"%s%04x", USER_AUTHENTICATION_VAR_NAME, Index);
> +      Status = VariableLock->RequestToLock (VariableLock,
> PasswordHistoryName, &gAdminAuthenticationGuid);
> +      ASSERT_EFI_ERROR (Status);
> +    }
> +    Status = VariableLock->RequestToLock (VariableLock,
> USER_AUTHENTICATION_HISTORY_LAST_VAR_NAME,
> &gAdminAuthenticationGuid);
> +    ASSERT_EFI_ERROR (Status);
> +  }
> +
> +  SmmHandle = NULL;
> +  Status    = gSmst->SmiHandlerRegister (SmmPasswordHandler,
> &gAdminAuthenticationGuid, &SmmHandle);
> +  ASSERT_EFI_ERROR (Status);
> +  if (EFI_ERROR (Status)) {
> +    Status = EFI_OUT_OF_RESOURCES;
> +    goto EXIT;
> +  }
> +
> +  if (IsPasswordCleared()) {
> +    DEBUG ((DEBUG_INFO, "IsPasswordCleared\n"));
> +    SavePasswordToVariable (&gAdminAuthenticationGuid, NULL, 0);
> +  }
> +
> +  return EFI_SUCCESS;
> +
> +EXIT:
> +  if (SmmHandle != NULL) {
> +    gSmst->SmiHandlerUnRegister (SmmHandle);
> +  }
> +
> +  return Status;
> +}
> +
> diff --git
> a/SecurityPkg/Password/UserAuthentication/UserAuthenticationSmm.inf
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationSmm.inf
> new file mode 100644
> index 0000000..460809b
> --- /dev/null
> +++
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationSmm.inf
> @@ -0,0 +1,70 @@
> +## @file
> +#  User Authentication Smm Driver.
> +#
> +#  This driver provides SMM services for DXE user authentication module.
> +#
> +# Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
> +#
> +#  This program and the accompanying materials
> +#  are licensed and made available under the terms and conditions of the
> BSD License
> +#  which accompanies this distribution. The full text of the license may be
> found at
> +#  http://opensource.org/licenses/bsd-license.php
> +#
> +#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +#
> +#
> +##
> +
> +[Defines]
> +  INF_VERSION                    = 0x00010005
> +  BASE_NAME                      = UserAuthenticationSmm
> +  MODULE_UNI_FILE                = UserAuthenticationSmm.uni
> +  FILE_GUID                      = 458B03ED-6E53-414f-9F07-3A829C990641
> +  MODULE_TYPE                    = DXE_SMM_DRIVER
> +  VERSION_STRING                 = 1.0
> +  PI_SPECIFICATION_VERSION       = 0x0001000A
> +  ENTRY_POINT                    = PasswordSmmInit
> +
> +#
> +# The following information is for reference only and not required by the
> build tools.
> +#
> +#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC
> +#
> +
> +[Sources]
> +  UserAuthenticationSmm.c
> +  UserAuthenticationGuid.h
> +  KeyService.c
> +  KeyService.h
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +  MdeModulePkg/MdeModulePkg.dec
> +  CryptoPkg/CryptoPkg.dec
> +  SecurityPkg/SecurityPkg.dec
> +
> +[LibraryClasses]
> +  UefiBootServicesTableLib
> +  UefiDriverEntryPoint
> +  DebugLib
> +  BaseLib
> +  BaseMemoryLib
> +  PrintLib
> +  SmmServicesTableLib
> +  MemoryAllocationLib
> +  UefiLib
> +  BaseCryptLib
> +  PlatformPasswordLib
> +
> +[Protocols]
> +  gEdkiiVariableLockProtocolGuid                ## CONSUMES
> +  gEfiSmmVariableProtocolGuid                   ## CONSUMES
> +
> +[Depex]
> +  gEfiSmmVariableProtocolGuid
> +
> +[UserExtensions.TianoCore."ExtraFiles"]
> +  UserAuthenticationDxeExtra.uni
> +
> +
> diff --git
> a/SecurityPkg/Password/UserAuthentication/UserAuthenticationSmm.uni
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationSmm.uni
> new file mode 100644
> index 0000000..470c75c
> --- /dev/null
> +++
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationSmm.uni
> @@ -0,0 +1,22 @@
> +// /** @file
> +// User Authentication Smm Driver.
> +//
> +// This driver provides SMM services for DXE user authentication module.
> +//
> +// Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
> +//
> +// This program and the accompanying materials
> +// are licensed and made available under the terms and conditions of the
> BSD License
> +// which accompanies this distribution. The full text of the license may be
> found at
> +// http://opensource.org/licenses/bsd-license.php
> +//
> +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +//
> +// **/
> +
> +
> +#string STR_MODULE_ABSTRACT             #language en-US "SMM services for
> DXE user authentication module."
> +
> +#string STR_MODULE_DESCRIPTION          #language en-US "This driver
> provides SMM services for DXE user authentication module."
> +
> diff --git
> a/SecurityPkg/Password/UserAuthentication/UserAuthenticationSmmExtra.
> uni
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationSmmExtra.
> uni
> new file mode 100644
> index 0000000..5e338fe
> --- /dev/null
> +++
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationSmmExtra.
> uni
> @@ -0,0 +1,20 @@
> +// /** @file
> +// User Authentication Smm Driver.
> +//
> +// Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
> +//
> +// This program and the accompanying materials
> +// are licensed and made available under the terms and conditions of the
> BSD License
> +// which accompanies this distribution. The full text of the license may be
> found at
> +// http://opensource.org/licenses/bsd-license.php
> +//
> +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +//
> +// **/
> +
> +#string STR_PROPERTIES_MODULE_NAME
> +#language en-US
> +"User Authentication SMM Driver"
> +
> +
> --
> 2.7.4.windows.1
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel