public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Yao, Jiewen" <jiewen.yao@intel.com>
To: "Zhang, Chao B" <chao.b.zhang@intel.com>,
	"edk2-devel@lists.01.org" <edk2-devel@lists.01.org>
Cc: "Long, Qin" <qin.long@intel.com>
Subject: Re: [PATCH 5/6] SecurityPkg/Password: Add Password based UserAuthentication modules.
Date: Sat, 4 Feb 2017 03:07:10 +0000	[thread overview]
Message-ID: <74D8A39837DF1E4DA445A8C0B3885C503A8E90DC@shsmsx102.ccr.corp.intel.com> (raw)
In-Reply-To: <FF72C7E4248F3C4E9BDF19D4918E90F2494FD5B0@shsmsx102.ccr.corp.intel.com>

Good catch. I will add it.

Thank you
Yao Jiewen


> -----Original Message-----
> From: Zhang, Chao B
> Sent: Saturday, February 4, 2017 11:05 AM
> To: Yao, Jiewen <jiewen.yao@intel.com>; edk2-devel@lists.01.org
> Cc: Long, Qin <qin.long@intel.com>
> Subject: RE: [PATCH 5/6] SecurityPkg/Password: Add Password based
> UserAuthentication modules.
> 
> Jiewen:
>   Why SmmCommunicationBufferProtocol is not placed in
> UserAuthenticationDxe [DEPEX]?
> 
> -----Original Message-----
> From: Yao, Jiewen
> Sent: Thursday, January 26, 2017 7:50 PM
> To: edk2-devel@lists.01.org
> Cc: Long, Qin <qin.long@intel.com>; Zhang, Chao B <chao.b.zhang@intel.com>
> Subject: [PATCH 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/KeyLib.c
> | 209 ++++++
>  SecurityPkg/Password/UserAuthentication/KeyLib.h
> | 121 ++++
>  SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.c
> | 718 ++++++++++++++++++++
>  SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.h
> | 115 ++++
>  SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.inf
> |  76 +++
>  SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.uni
> |  20 +
>  SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeExtra.uni
> |  20 +
>  SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeFormset.h
> |  30 +
>  SecurityPkg/Password/UserAuthentication/UserAuthenticationDxePassword.c
> | 300 ++++++++
>  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
> |  74 ++
>  SecurityPkg/Password/UserAuthentication/UserAuthenticationSmmExtra.uni
> |  20 +
>  15 files changed, 2507 insertions(+)
> 
> diff --git a/SecurityPkg/Password/UserAuthentication/KeyLib.c
> b/SecurityPkg/Password/UserAuthentication/KeyLib.c
> new file mode 100644
> index 0000000..295c73d
> --- /dev/null
> +++ b/SecurityPkg/Password/UserAuthentication/KeyLib.c
> @@ -0,0 +1,209 @@
> +/** @file
> +
> +Copyright (c) 2016, 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 "KeyLib.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/KeyLib.h
> b/SecurityPkg/Password/UserAuthentication/KeyLib.h
> new file mode 100644
> index 0000000..82886f0
> --- /dev/null
> +++ b/SecurityPkg/Password/UserAuthentication/KeyLib.h
> @@ -0,0 +1,121 @@
> +/** @file
> +
> +  Copyright (c) 2016, 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..90e2236
> --- /dev/null
> +++ b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.c
> @@ -0,0 +1,718 @@
> +/** @file
> +  This Driver mainly do user authentication before entering Setup.
> +
> +Copyright (c) 2016, 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..30c64fc
> --- /dev/null
> +++ b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.h
> @@ -0,0 +1,115 @@
> +/** @file
> +  Header file for UserAuthenticationDxe.
> +
> +Copyright (c) 2016, 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..8cb4c1a
> --- /dev/null
> +++ b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.inf
> @@ -0,0 +1,76 @@
> +## @file
> +#  This Driver mainly do user authentication before entering Setup.
> +#
> +# Copyright (c) 2016, 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
> +  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..a92788f
> --- /dev/null
> +++ b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.uni
> @@ -0,0 +1,20 @@
> +// /** @file
> +// This driver mainly do the user authentication before entering Setup.
> +//
> +// Copyright (c) 2016, 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 "This driver
> mainly do user authentication before entering Setup."
> +
> +#string STR_MODULE_DESCRIPTION          #language en-US "This driver
> mainly do 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..021a50a
> --- /dev/null
> +++
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeExtra.uni
> @@ -0,0 +1,20 @@
> +// /** @file
> +// User Authentication Dxe Driver.
> +//
> +// Copyright (c) 2016, 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..9b971bd
> --- /dev/null
> +++
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeFormset.h
> @@ -0,0 +1,30 @@
> +/** @file
> +  Header file for UserAuthenticationDxe.
> +
> +Copyright (c) 2016, 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..d30818b
> --- /dev/null
> +++
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxePassword.
> c
> @@ -0,0 +1,300 @@
> +/** @file
> +
> +Copyright (c) 2016, 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..91b46bc
> --- /dev/null
> +++
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeStrings.uni
> @@ -0,0 +1,29 @@
> +/** @file
> +// String definitions for User Authentication formset.
> +
> +// Copyright (c) 2016, 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..41ee8c2
> --- /dev/null
> +++ b/SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeVfr.vfr
> @@ -0,0 +1,38 @@
> +///** @file
> +// UserAuthentication formset.
> +//
> +// Copyright (c) 2016, 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..228a0fe
> --- /dev/null
> +++ b/SecurityPkg/Password/UserAuthentication/UserAuthenticationGuid.h
> @@ -0,0 +1,65 @@
> +/** @file
> +  GUID is for UserPassword variable.
> +
> +Copyright (c) 2016, 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..59f4bdc
> --- /dev/null
> +++ b/SecurityPkg/Password/UserAuthentication/UserAuthenticationSmm.c
> @@ -0,0 +1,672 @@
> +/** @file
> +
> +Copyright (c) 2016, 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 "KeyLib.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(CHA
> R16) + 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..e0a3b12
> --- /dev/null
> +++ b/SecurityPkg/Password/UserAuthentication/UserAuthenticationSmm.inf
> @@ -0,0 +1,74 @@
> +##
> +#  This file contains a 'Sample Driver' and is licensed as such
> +#  under the terms of your license agreement with Intel or your
> +#  vendor.  This file may be modified by the user, subject to
> +#  the additional terms of the license agreement
> +#
> +##
> +## @file
> +#  HddPassword Smm module which is used to provide HDD unlock interface
> for S3 resume path.
> +#
> +#  Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.<BR>
> +#
> +#  This software and associated documentation (if any) is furnished
> +#  under a license and may only be used or copied in accordance
> +#  with the terms of the license. Except as permitted by such
> +#  license, no part of this software or documentation may be
> +#  reproduced, stored in a retrieval system, or transmitted in any
> +#  form or by any means without the express written consent of
> +#  Intel Corporation.
> +#
> +#
> +##
> +
> +[Defines]
> +  INF_VERSION                    = 0x00010005
> +  BASE_NAME                      = UserAuthenticationSmm
> +  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
> +  KeyLib.c
> +  KeyLib.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/UserAuthenticationSmmExtra.uni
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationSmmExtra.uni
> new file mode 100644
> index 0000000..6011481
> --- /dev/null
> +++
> b/SecurityPkg/Password/UserAuthentication/UserAuthenticationSmmExtra.uni
> @@ -0,0 +1,20 @@
> +// /** @file
> +// User Authentication Smm Driver.
> +//
> +// Copyright (c) 2016, 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



  reply	other threads:[~2017-02-04  3:07 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-01-26 11:50 [PATCH 0/6] Add password support Jiewen Yao
2017-01-26 11:50 ` [PATCH 1/6] CryptoPkg:SmmCryptLib: Add real Pkcs5Pbkdf2.c Jiewen Yao
2017-01-26 11:50 ` [PATCH 2/6] SecurityPkg/dec: Add PcdPasswordCleared Jiewen Yao
2017-01-26 11:50 ` [PATCH 3/6] SecurityPkg/include: Add PlatformPasswordLib lib class Jiewen Yao
2017-01-26 11:50 ` [PATCH 4/6] SecurityPkg/PlatformPasswordLibNull: Add PlatformPasswordLib instance Jiewen Yao
2017-01-26 11:50 ` [PATCH 5/6] SecurityPkg/Password: Add Password based UserAuthentication modules Jiewen Yao
2017-02-04  3:05   ` Zhang, Chao B
2017-02-04  3:07     ` Yao, Jiewen [this message]
2017-01-26 11:50 ` [PATCH 6/6] SecurityPkg/dsc: add Password authentication module Jiewen Yao

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=74D8A39837DF1E4DA445A8C0B3885C503A8E90DC@shsmsx102.ccr.corp.intel.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox