* [PATCH 0/6] Add password support @ 2017-01-26 11:50 Jiewen Yao 2017-01-26 11:50 ` [PATCH 1/6] CryptoPkg:SmmCryptLib: Add real Pkcs5Pbkdf2.c Jiewen Yao ` (5 more replies) 0 siblings, 6 replies; 9+ messages in thread From: Jiewen Yao @ 2017-01-26 11:50 UTC (permalink / raw) To: edk2-devel; +Cc: Qin Long, Chao Zhang This series patch adds password support in EDKII. This password based user authentication is to verify user when a user wants to enter BIOS setup page. The detail information is added in [PATCH 5/6]. 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> Jiewen Yao (6): CryptoPkg:SmmCryptLib: Add real Pkcs5Pbkdf2.c. SecurityPkg/dec: Add PcdPasswordCleared. SecurityPkg/include: Add PlatformPasswordLib lib class. SecurityPkg/PlatformPasswordLibNull: Add PlatformPasswordLib instance. SecurityPkg/Password: Add Password based UserAuthentication modules. SecurityPkg/dsc: add Password authentication module. CryptoPkg/Library/BaseCryptLib/SmmCryptLib.inf | 2 +- SecurityPkg/Include/Library/PlatformPasswordLib.h | 54 ++ SecurityPkg/Library/PlatformPasswordLibNull/PlatformPasswordLibNull.c | 84 +++ SecurityPkg/Library/PlatformPasswordLibNull/PlatformPasswordLibNull.inf | 44 ++ SecurityPkg/Library/PlatformPasswordLibNull/PlatformPasswordLibNull.uni | 24 + 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 + SecurityPkg/SecurityPkg.dec | 10 + SecurityPkg/SecurityPkg.dsc | 7 + SecurityPkg/SecurityPkg.uni | 10 + 23 files changed, 2741 insertions(+), 1 deletion(-) create mode 100644 SecurityPkg/Include/Library/PlatformPasswordLib.h create mode 100644 SecurityPkg/Library/PlatformPasswordLibNull/PlatformPasswordLibNull.c create mode 100644 SecurityPkg/Library/PlatformPasswordLibNull/PlatformPasswordLibNull.inf create mode 100644 SecurityPkg/Library/PlatformPasswordLibNull/PlatformPasswordLibNull.uni create mode 100644 SecurityPkg/Password/UserAuthentication/KeyLib.c create mode 100644 SecurityPkg/Password/UserAuthentication/KeyLib.h create mode 100644 SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.c create mode 100644 SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.h create mode 100644 SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.inf create mode 100644 SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.uni create mode 100644 SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeExtra.uni create mode 100644 SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeFormset.h create mode 100644 SecurityPkg/Password/UserAuthentication/UserAuthenticationDxePassword.c create mode 100644 SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeStrings.uni create mode 100644 SecurityPkg/Password/UserAuthentication/UserAuthenticationDxeVfr.vfr create mode 100644 SecurityPkg/Password/UserAuthentication/UserAuthenticationGuid.h create mode 100644 SecurityPkg/Password/UserAuthentication/UserAuthenticationSmm.c create mode 100644 SecurityPkg/Password/UserAuthentication/UserAuthenticationSmm.inf create mode 100644 SecurityPkg/Password/UserAuthentication/UserAuthenticationSmmExtra.uni -- 2.7.4.windows.1 ^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 1/6] CryptoPkg:SmmCryptLib: Add real Pkcs5Pbkdf2.c. 2017-01-26 11:50 [PATCH 0/6] Add password support Jiewen Yao @ 2017-01-26 11:50 ` Jiewen Yao 2017-01-26 11:50 ` [PATCH 2/6] SecurityPkg/dec: Add PcdPasswordCleared Jiewen Yao ` (4 subsequent siblings) 5 siblings, 0 replies; 9+ messages in thread From: Jiewen Yao @ 2017-01-26 11:50 UTC (permalink / raw) To: edk2-devel; +Cc: Qin Long Cc: Qin Long <qin.long@intel.com> Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jiewen Yao <jiewen.yao@intel.com> --- CryptoPkg/Library/BaseCryptLib/SmmCryptLib.inf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CryptoPkg/Library/BaseCryptLib/SmmCryptLib.inf b/CryptoPkg/Library/BaseCryptLib/SmmCryptLib.inf index df44184..2a0f02f 100644 --- a/CryptoPkg/Library/BaseCryptLib/SmmCryptLib.inf +++ b/CryptoPkg/Library/BaseCryptLib/SmmCryptLib.inf @@ -52,7 +52,7 @@ Cipher/CryptArc4Null.c Pk/CryptRsaBasic.c Pk/CryptRsaExtNull.c - Pk/CryptPkcs5Pbkdf2Null.c + Pk/CryptPkcs5Pbkdf2.c Pk/CryptPkcs7SignNull.c Pk/CryptPkcs7Verify.c Pk/CryptDhNull.c -- 2.7.4.windows.1 ^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 2/6] SecurityPkg/dec: Add PcdPasswordCleared. 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 ` Jiewen Yao 2017-01-26 11:50 ` [PATCH 3/6] SecurityPkg/include: Add PlatformPasswordLib lib class Jiewen Yao ` (3 subsequent siblings) 5 siblings, 0 replies; 9+ messages in thread From: Jiewen Yao @ 2017-01-26 11:50 UTC (permalink / raw) To: edk2-devel; +Cc: Qin Long, Chao Zhang This PCD is to indicate if the password is cleared. 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/SecurityPkg.dec | 6 ++++++ SecurityPkg/SecurityPkg.uni | 10 ++++++++++ 2 files changed, 16 insertions(+) diff --git a/SecurityPkg/SecurityPkg.dec b/SecurityPkg/SecurityPkg.dec index b556fb6..da2f84f 100644 --- a/SecurityPkg/SecurityPkg.dec +++ b/SecurityPkg/SecurityPkg.dec @@ -446,6 +446,12 @@ # @Prompt Initial setting of TCG2 Persistent Firmware Management Flags gEfiSecurityPkgTokenSpaceGuid.PcdTcg2PhysicalPresenceFlags|0x300E2|UINT32|0x0001001B + ## Indicate whether the password is cleared. + # When it is configured to Dynamic or DynamicEx, it can be set through detection using + # a platform-specific method (e.g. Board Jumper set) in a actual platform in early boot phase.<BR><BR> + # @Prompt The passowrd clear status + gEfiSecurityPkgTokenSpaceGuid.PcdPasswordCleared|FALSE|BOOLEAN|0x0001001C + [PcdsDynamic, PcdsDynamicEx] ## This PCD indicates Hash mask for TPM 2.0.<BR><BR> diff --git a/SecurityPkg/SecurityPkg.uni b/SecurityPkg/SecurityPkg.uni index 17d36c0..ffc097e 100644 --- a/SecurityPkg/SecurityPkg.uni +++ b/SecurityPkg/SecurityPkg.uni @@ -219,6 +219,16 @@ "When it is configured to Dynamic or DynamicEx, it can be set through detection using " "a platform-specific method (e.g. Button pressed) in a actual platform in early boot phase.<BR><BR>" +#string STR_gEfiSecurityPkgTokenSpaceGuid_PcdPasswordCleared_PROMPT +#language en-US +"The passowrd clear status" + +#string STR_gEfiSecurityPkgTokenSpaceGuid_PcdPasswordCleared_HELP +#language en-US +"Indicate whether the password is cleared. " +"When it is configured to Dynamic or DynamicEx, it can be set through detection using " +"a platform-specific method (e.g. Board Jumper set) in a actual platform in early boot phase.<BR><BR>" + #string STR_gEfiSecurityPkgTokenSpaceGuid_PcdPkcs7CertBuffer_PROMPT #language en-US "One PKCS7 cert used to verify Recovery and Capsule Update images" #string STR_gEfiSecurityPkgTokenSpaceGuid_PcdPkcs7CertBuffer_HELP #language en-US "Provides one PKCS7 cert used to verify Recovery and Capsule Update images\n" -- 2.7.4.windows.1 ^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 3/6] SecurityPkg/include: Add PlatformPasswordLib lib class. 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 ` Jiewen Yao 2017-01-26 11:50 ` [PATCH 4/6] SecurityPkg/PlatformPasswordLibNull: Add PlatformPasswordLib instance Jiewen Yao ` (2 subsequent siblings) 5 siblings, 0 replies; 9+ messages in thread From: Jiewen Yao @ 2017-01-26 11:50 UTC (permalink / raw) To: edk2-devel; +Cc: Qin Long, Chao Zhang This lib is to indicate if the password is cleared. 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/Include/Library/PlatformPasswordLib.h | 54 ++++++++++++++++++++ SecurityPkg/SecurityPkg.dec | 4 ++ 2 files changed, 58 insertions(+) diff --git a/SecurityPkg/Include/Library/PlatformPasswordLib.h b/SecurityPkg/Include/Library/PlatformPasswordLib.h new file mode 100644 index 0000000..a1cad50 --- /dev/null +++ b/SecurityPkg/Include/Library/PlatformPasswordLib.h @@ -0,0 +1,54 @@ +/** @file + Provides a platform-specific method to return password policy. + +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 __PLATFORM_PASSWORD_LIB_H__ +#define __PLATFORM_PASSWORD_LIB_H__ + +/** + This function is called at password driver entrypoint. + This function should be called only once, to clear the password. + + This function provides a way to reset the password, just in case + the platform owner forgets the password. + The platform should provide a secure way to make sure + only the platform owner is allowed to clear password. + + Once the password is cleared, the platform should provide a way + to set a new password. + + @retval TRUE There is a platform request to clear the password. + @retval FALSE There is no platform request to clear the password. +**/ +BOOLEAN +EFIAPI +IsPasswordCleared ( + VOID + ); + +/** + This function is called if the password driver finds that the password is not enrolled, + when the password is required to input. + + This function should return the action accroding to platform policy. + + @retval TRUE The caller should force the user to enroll the password. + @retval FALSE The caller may skip the password enroll. +**/ +BOOLEAN +EFIAPI +NeedEnrollPassword ( + VOID + ); + +#endif diff --git a/SecurityPkg/SecurityPkg.dec b/SecurityPkg/SecurityPkg.dec index da2f84f..7050d3e 100644 --- a/SecurityPkg/SecurityPkg.dec +++ b/SecurityPkg/SecurityPkg.dec @@ -93,6 +93,10 @@ # OpalPasswordSupportLib|Include/Library/OpalPasswordSupportLib.h + ## @libraryclass Provides a platform-specific method to return password policy. + # + PlatformPasswordLib|Include/Library/PlatformPasswordLib.h + [Guids] ## Security package token space guid. # Include/Guid/SecurityPkgTokenSpace.h -- 2.7.4.windows.1 ^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 4/6] SecurityPkg/PlatformPasswordLibNull: Add PlatformPasswordLib instance. 2017-01-26 11:50 [PATCH 0/6] Add password support Jiewen Yao ` (2 preceding siblings ...) 2017-01-26 11:50 ` [PATCH 3/6] SecurityPkg/include: Add PlatformPasswordLib lib class Jiewen Yao @ 2017-01-26 11:50 ` Jiewen Yao 2017-01-26 11:50 ` [PATCH 5/6] SecurityPkg/Password: Add Password based UserAuthentication modules Jiewen Yao 2017-01-26 11:50 ` [PATCH 6/6] SecurityPkg/dsc: add Password authentication module Jiewen Yao 5 siblings, 0 replies; 9+ messages in thread From: Jiewen Yao @ 2017-01-26 11:50 UTC (permalink / raw) To: edk2-devel; +Cc: Qin Long, Chao Zhang This lib instance is to return if the password is cleared based upon PCD. 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/Library/PlatformPasswordLibNull/PlatformPasswordLibNull.c | 84 ++++++++++++++++++++ SecurityPkg/Library/PlatformPasswordLibNull/PlatformPasswordLibNull.inf | 44 ++++++++++ SecurityPkg/Library/PlatformPasswordLibNull/PlatformPasswordLibNull.uni | 24 ++++++ 3 files changed, 152 insertions(+) diff --git a/SecurityPkg/Library/PlatformPasswordLibNull/PlatformPasswordLibNull.c b/SecurityPkg/Library/PlatformPasswordLibNull/PlatformPasswordLibNull.c new file mode 100644 index 0000000..ebfe35a --- /dev/null +++ b/SecurityPkg/Library/PlatformPasswordLibNull/PlatformPasswordLibNull.c @@ -0,0 +1,84 @@ +/** @file + NULL PlatformPasswordLib instance does NOT really detect whether the password is cleared + but returns the PCD value directly. This instance can be used to verify security + related features during platform enabling and development. It should be replaced + by a platform-specific method(e.g. Button pressed) in a real platform for product. + +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. + +**/ + +BOOLEAN mPasswordCleared = FALSE; + +/** + This function is called at password driver entrypoint. + This function should be called only once, to clear the password. + + This function provides a way to reset the password, just in case + the platform owner forgets the password. + The platform should provide a secure way to make sure + only the platform owner is allowed to clear password. + + Once the password is cleared, the platform should provide a way + to set a new password. + + @retval TRUE There is a platform request to clear the password. + @retval FALSE There is no platform request to clear the password. +**/ +BOOLEAN +EFIAPI +IsPasswordCleared ( + VOID + ) +{ + return mPasswordCleared; +} + +/** + This function is called if the password driver finds that the password is not enrolled, + when the password is required to input. + + This function should return the action accroding to platform policy. + + @retval TRUE The caller should force the user to enroll the password. + @retval FALSE The caller may skip the password enroll. +**/ +BOOLEAN +EFIAPI +NeedEnrollPassword ( + VOID + ) +{ + return FALSE; +} + + +/** + Save password clear state from a PCD to mPasswordCleared. + + @param ImageHandle ImageHandle of the loaded driver. + @param SystemTable Pointer to the EFI System Table. + + @retval EFI_SUCCESS PcdPasswordCleared is got successfully. + +**/ +EFI_STATUS +EFIAPI +PlatformPasswordLibNullConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + + mPasswordCleared = PcdGetBool(PcdPasswordCleared); + + return EFI_SUCCESS; +} + diff --git a/SecurityPkg/Library/PlatformPasswordLibNull/PlatformPasswordLibNull.inf b/SecurityPkg/Library/PlatformPasswordLibNull/PlatformPasswordLibNull.inf new file mode 100644 index 0000000..d071565 --- /dev/null +++ b/SecurityPkg/Library/PlatformPasswordLibNull/PlatformPasswordLibNull.inf @@ -0,0 +1,44 @@ +## @file +# NULL platform password library instance that returns the password clear state based upon PCD. +# +# NULL PlatformPasswordLib instance does NOT really detect whether the password is cleared +# but returns the PCD value directly. This instance can be used to verify security +# related features during platform enabling and development. It should be replaced +# by a platform-specific method(e.g. Button pressed) in a real platform for product. +# +# 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 = 0x00010006 + BASE_NAME = PlatformPasswordLibNull + MODULE_UNI_FILE = PlatformPasswordLibNull.uni + FILE_GUID = 27417BCA-0CCD-4089-9711-AD069A33C555 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = PlatformPasswordLib|DXE_RUNTIME_DRIVER DXE_SMM_DRIVER DXE_DRIVER + CONSTRUCTOR = PlatformPasswordLibNullConstructor + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources] + PlatformPasswordLibNull.c + +[Packages] + MdePkg/MdePkg.dec + SecurityPkg/SecurityPkg.dec + +[Pcd] + gEfiSecurityPkgTokenSpaceGuid.PcdPasswordCleared ## CONSUMES + diff --git a/SecurityPkg/Library/PlatformPasswordLibNull/PlatformPasswordLibNull.uni b/SecurityPkg/Library/PlatformPasswordLibNull/PlatformPasswordLibNull.uni new file mode 100644 index 0000000..bbedef6 --- /dev/null +++ b/SecurityPkg/Library/PlatformPasswordLibNull/PlatformPasswordLibNull.uni @@ -0,0 +1,24 @@ +// /** @file +// NULL platform password library instance that returns the password clear state based upon PCD. +// +// NULL PlatformPasswordLib instance does NOT really detect whether the password is cleared +// but returns the PCD value directly. This instance can be used to verify security +// related features during platform enabling and development. It should be replaced +// by a platform-specific method(e.g. Button pressed) in a real platform for product. +// +// 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 "NULL platform password library instance that returns the password clear state based upon PCD." + +#string STR_MODULE_DESCRIPTION #language en-US "NULL PlatformPasswordLib instance does NOT really detect whether the password is cleared but returns the PCD value directly. This instance can be used to verify security related features during platform enabling and development. It should be replaced by a platform-specific method(e.g. Button pressed) in a real platform for product." + -- 2.7.4.windows.1 ^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 5/6] SecurityPkg/Password: Add Password based UserAuthentication modules. 2017-01-26 11:50 [PATCH 0/6] Add password support Jiewen Yao ` (3 preceding siblings ...) 2017-01-26 11:50 ` [PATCH 4/6] SecurityPkg/PlatformPasswordLibNull: Add PlatformPasswordLib instance Jiewen Yao @ 2017-01-26 11:50 ` Jiewen Yao 2017-02-04 3:05 ` Zhang, Chao B 2017-01-26 11:50 ` [PATCH 6/6] SecurityPkg/dsc: add Password authentication module Jiewen Yao 5 siblings, 1 reply; 9+ messages in thread From: Jiewen Yao @ 2017-01-26 11:50 UTC (permalink / raw) To: edk2-devel; +Cc: Qin Long, Chao Zhang 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(CHAR16) + 4]; + UINTN Index; + + ASSERT (PASSWORD_HASH_SIZE == SHA256_DIGEST_SIZE); + ASSERT (PASSWORD_HISTORY_CHECK_COUNT < 0xFFFF); + + Status = gSmst->SmmLocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID**)&mSmmVariable); + ASSERT_EFI_ERROR (Status); + + SmmHandle = NULL; + + // + // Make "HddPassword" varible read-only for DXE driver for security concern. + // + Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **) &VariableLock); + if (!EFI_ERROR (Status)) { + Status = VariableLock->RequestToLock (VariableLock, USER_AUTHENTICATION_VAR_NAME, &gAdminAuthenticationGuid); + ASSERT_EFI_ERROR (Status); + + for (Index = 1; Index <= PASSWORD_HISTORY_CHECK_COUNT; Index++) { + UnicodeSPrint (PasswordHistoryName, sizeof (PasswordHistoryName), L"%s%04x", USER_AUTHENTICATION_VAR_NAME, Index); + Status = VariableLock->RequestToLock (VariableLock, PasswordHistoryName, &gAdminAuthenticationGuid); + ASSERT_EFI_ERROR (Status); + } + Status = VariableLock->RequestToLock (VariableLock, USER_AUTHENTICATION_HISTORY_LAST_VAR_NAME, &gAdminAuthenticationGuid); + ASSERT_EFI_ERROR (Status); + } + + SmmHandle = NULL; + Status = gSmst->SmiHandlerRegister (SmmPasswordHandler, &gAdminAuthenticationGuid, &SmmHandle); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + Status = EFI_OUT_OF_RESOURCES; + goto EXIT; + } + + if (IsPasswordCleared()) { + DEBUG ((DEBUG_INFO, "IsPasswordCleared\n")); + SavePasswordToVariable (&gAdminAuthenticationGuid, NULL, 0); + } + + return EFI_SUCCESS; + +EXIT: + if (SmmHandle != NULL) { + gSmst->SmiHandlerUnRegister (SmmHandle); + } + + return Status; +} + diff --git a/SecurityPkg/Password/UserAuthentication/UserAuthenticationSmm.inf b/SecurityPkg/Password/UserAuthentication/UserAuthenticationSmm.inf new file mode 100644 index 0000000..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 ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH 5/6] SecurityPkg/Password: Add Password based UserAuthentication modules. 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 0 siblings, 1 reply; 9+ messages in thread From: Zhang, Chao B @ 2017-02-04 3:05 UTC (permalink / raw) To: Yao, Jiewen, edk2-devel@lists.01.org; +Cc: Long, Qin 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(CHAR16) + 4]; + UINTN Index; + + ASSERT (PASSWORD_HASH_SIZE == SHA256_DIGEST_SIZE); + ASSERT (PASSWORD_HISTORY_CHECK_COUNT < 0xFFFF); + + Status = gSmst->SmmLocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID**)&mSmmVariable); + ASSERT_EFI_ERROR (Status); + + SmmHandle = NULL; + + // + // Make "HddPassword" varible read-only for DXE driver for security concern. + // + Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **) &VariableLock); + if (!EFI_ERROR (Status)) { + Status = VariableLock->RequestToLock (VariableLock, USER_AUTHENTICATION_VAR_NAME, &gAdminAuthenticationGuid); + ASSERT_EFI_ERROR (Status); + + for (Index = 1; Index <= PASSWORD_HISTORY_CHECK_COUNT; Index++) { + UnicodeSPrint (PasswordHistoryName, sizeof (PasswordHistoryName), L"%s%04x", USER_AUTHENTICATION_VAR_NAME, Index); + Status = VariableLock->RequestToLock (VariableLock, PasswordHistoryName, &gAdminAuthenticationGuid); + ASSERT_EFI_ERROR (Status); + } + Status = VariableLock->RequestToLock (VariableLock, USER_AUTHENTICATION_HISTORY_LAST_VAR_NAME, &gAdminAuthenticationGuid); + ASSERT_EFI_ERROR (Status); + } + + SmmHandle = NULL; + Status = gSmst->SmiHandlerRegister (SmmPasswordHandler, &gAdminAuthenticationGuid, &SmmHandle); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + Status = EFI_OUT_OF_RESOURCES; + goto EXIT; + } + + if (IsPasswordCleared()) { + DEBUG ((DEBUG_INFO, "IsPasswordCleared\n")); + SavePasswordToVariable (&gAdminAuthenticationGuid, NULL, 0); + } + + return EFI_SUCCESS; + +EXIT: + if (SmmHandle != NULL) { + gSmst->SmiHandlerUnRegister (SmmHandle); + } + + return Status; +} + diff --git a/SecurityPkg/Password/UserAuthentication/UserAuthenticationSmm.inf b/SecurityPkg/Password/UserAuthentication/UserAuthenticationSmm.inf new file mode 100644 index 0000000..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 ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH 5/6] SecurityPkg/Password: Add Password based UserAuthentication modules. 2017-02-04 3:05 ` Zhang, Chao B @ 2017-02-04 3:07 ` Yao, Jiewen 0 siblings, 0 replies; 9+ messages in thread From: Yao, Jiewen @ 2017-02-04 3:07 UTC (permalink / raw) To: Zhang, Chao B, edk2-devel@lists.01.org; +Cc: Long, Qin 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 ^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 6/6] SecurityPkg/dsc: add Password authentication module. 2017-01-26 11:50 [PATCH 0/6] Add password support Jiewen Yao ` (4 preceding siblings ...) 2017-01-26 11:50 ` [PATCH 5/6] SecurityPkg/Password: Add Password based UserAuthentication modules Jiewen Yao @ 2017-01-26 11:50 ` Jiewen Yao 5 siblings, 0 replies; 9+ messages in thread From: Jiewen Yao @ 2017-01-26 11:50 UTC (permalink / raw) To: edk2-devel; +Cc: Qin Long, Chao Zhang 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/SecurityPkg.dsc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/SecurityPkg/SecurityPkg.dsc b/SecurityPkg/SecurityPkg.dsc index dee9241..d337a26 100644 --- a/SecurityPkg/SecurityPkg.dsc +++ b/SecurityPkg/SecurityPkg.dsc @@ -75,6 +75,7 @@ TcgStorageOpalLib|SecurityPkg/Library/TcgStorageOpalLib/TcgStorageOpalLib.inf OpalPasswordSupportLib|SecurityPkg/Library/OpalPasswordSupportLib/OpalPasswordSupportLib.inf ResetSystemLib|MdeModulePkg/Library/BaseResetSystemLibNull/BaseResetSystemLibNull.inf + PlatformPasswordLib|SecurityPkg/Library/PlatformPasswordLibNull/PlatformPasswordLibNull.inf [LibraryClasses.common.PEIM] PeimEntryPoint|MdePkg/Library/PeimEntryPoint/PeimEntryPoint.inf @@ -328,6 +329,12 @@ SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalPasswordDxe.inf SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalPasswordSmm.inf + # + # Password + # + SecurityPkg/Password/UserAuthentication/UserAuthenticationDxe.inf + SecurityPkg/Password/UserAuthentication/UserAuthenticationSmm.inf + [Components.IPF] SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/EsalVariableDxeSal.inf -- 2.7.4.windows.1 ^ permalink raw reply related [flat|nested] 9+ messages in thread
end of thread, other threads:[~2017-02-04 3:07 UTC | newest] Thread overview: 9+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 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 2017-01-26 11:50 ` [PATCH 6/6] SecurityPkg/dsc: add Password authentication module Jiewen Yao
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox