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
next prev parent 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