diff --git a/SecurityPkg/Include/Guid/OpalPasswordExtraInfoVariable.h b/SecurityPkg/Include/Guid/OpalPasswordExtraInfoVariable.h new file mode 100644 index 0000000000..f16d0a4ac3 --- /dev/null +++ b/SecurityPkg/Include/Guid/OpalPasswordExtraInfoVariable.h @@ -0,0 +1,27 @@ +/** @file + Defines Name GUIDs to represent an Opal device variable guid for Opal Security Feature. + +Copyright (c) 2016, Intel Corporation. All rights reserved.
+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 _OPAL_PASSWORD_EXTRA_INFO_VARIABLE_H_ +#define _OPAL_PASSWORD_EXTRA_INFO_VARIABLE_H_ + +#define OPAL_EXTRA_INFO_VAR_NAME L"OpalExtraInfo" + +typedef struct { + UINT8 EnableBlockSid; +} OPAL_EXTRA_INFO_VAR; + +extern EFI_GUID gOpalExtraInfoVariableGuid; + +#endif // _OPAL_PASSWORD_SECURITY_VARIABLE_H_ + diff --git a/SecurityPkg/Include/Library/OpalPasswordSupportLib.h b/SecurityPkg/Include/Library/OpalPasswordSupportLib.h new file mode 100644 index 0000000000..e616c763f0 --- /dev/null +++ b/SecurityPkg/Include/Library/OpalPasswordSupportLib.h @@ -0,0 +1,289 @@ +/** @file + Header file of Opal password support library. + +Copyright (c) 2016, Intel Corporation. All rights reserved.
+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 _OPAL_PASSWORD_SUPPORT_LIB_H_ +#define _OPAL_PASSWORD_SUPPORT_LIB_H_ + +#include +#include + + +#pragma pack(1) + +// +// Structure that is used to represent the available actions for an OpalDisk. +// The data can then be utilized to expose/hide certain actions available to an end user +// by the consumer of this library. +// +typedef struct { + // + // Indicates if the disk can support PSID Revert action. should verify disk supports PSID authority + // + UINT16 PsidRevert : 1; + + // + // Indicates if the disk can support Revert action + // + UINT16 Revert : 1; + + // + // Indicates if the user must keep data for revert action. It is true if no media encryption is supported. + // + UINT16 RevertKeepDataForced : 1; + + // + // Indicates if the disk can support set Admin password + // + UINT16 AdminPass : 1; + + // + // Indicates if the disk can support set User password. This action requires that a user + // password is first enabled. + // + UINT16 UserPass : 1; + + // + // Indicates if unlock action is available. Requires disk to be currently locked. + // + UINT16 Unlock : 1; + + // + // Indicates if Secure Erase action is available. Action requires admin credentials and media encryption support. + // + UINT16 SecureErase : 1; + + // + // Indicates if Disable User action is available. Action requires admin credentials. + // + UINT16 DisableUser : 1; +} OPAL_DISK_ACTIONS; + +// +// Structure that is used to represent the Opal device with password info. +// +typedef struct { + LIST_ENTRY Link; + + UINT8 Password[32]; + UINT8 PasswordLength; + + EFI_DEVICE_PATH_PROTOCOL OpalDevicePath; +} OPAL_DISK_AND_PASSWORD_INFO; + +#pragma pack() + +/** + + The function performs determines the available actions for the OPAL_DISK provided. + + @param[in] SupportedAttributes The support attribute for the device. + @param[in] LockingFeature The locking status for the device. + @param[in] OwnerShip The ownership for the device. + @param[out] AvalDiskActions Pointer to fill-out with appropriate disk actions. + +**/ +TCG_RESULT +EFIAPI +OpalSupportGetAvailableActions( + IN OPAL_DISK_SUPPORT_ATTRIBUTE *SupportedAttributes, + IN TCG_LOCKING_FEATURE_DESCRIPTOR *LockingFeature, + IN UINT16 OwnerShip, + OUT OPAL_DISK_ACTIONS *AvalDiskActions + ); + +/** + Enable Opal Feature for the input device. + + @param[in] Session The opal session for the opal device. + @param[in] Msid Msid + @param[in] MsidLength Msid Length + @param[in] Password Admin password + @param[in] PassLength Length of password in bytes + @param[in] DevicePath The device path for the opal devcie. + +**/ +TCG_RESULT +EFIAPI +OpalSupportEnableOpalFeature( + IN OPAL_SESSION *Session, + IN VOID *Msid, + IN UINT32 MsidLength, + IN VOID *Password, + IN UINT32 PassLength, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ); + +/** + Creates a session with OPAL_UID_ADMIN_SP as OPAL_ADMIN_SP_PSID_AUTHORITY, then reverts device using Admin SP Revert method. + + @param[in] Session The opal session for the opal device. + @param[in] Psid PSID of device to revert. + @param[in] PsidLength Length of PSID in bytes. + @param[in] DevicePath The device path for the opal devcie. + +**/ +TCG_RESULT +EFIAPI +OpalSupportPsidRevert( + IN OPAL_SESSION *Session, + IN VOID *Psid, + IN UINT32 PsidLength, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ); + +/** + Opens a session with OPAL_UID_ADMIN_SP as OPAL_ADMIN_SP_PSID_AUTHORITY, then reverts the device using the RevertSP method. + + @param[in] Session The opal session for the opal device. + @param[in] KeepUserData TRUE to keep existing Data on the disk, or FALSE to erase it + @param[in] Password Admin password + @param[in] PasswordLength Length of password in bytes + @param[in] Msid Msid + @param[in] MsidLength Msid Length + @param[out] PasswordFailed indicates if password failed (start session didn't work) + @param[in] DevicePath The device path for the opal devcie. + +**/ +TCG_RESULT +EFIAPI +OpalSupportRevert( + IN OPAL_SESSION *Session, + IN BOOLEAN KeepUserData, + IN VOID *Password, + IN UINT32 PasswordLength, + IN VOID *Msid, + IN UINT32 MsidLength, + OUT BOOLEAN *PasswordFailed, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ); + +/** + Set new password. + + @param[in] Session The opal session for the opal device. + @param[in] OldPassword Current admin password + @param[in] OldPasswordLength Length of current admin password in bytes + @param[in] NewPassword New admin password to set + @param[in] NewPasswordLength Length of new password in bytes + @param[in] DevicePath The device path for the opal devcie. + @param[in] SetAdmin Whether set admin password or user password. + TRUE for admin, FALSE for user. + +**/ +TCG_RESULT +EFIAPI +OpalSupportSetPassword( + IN OPAL_SESSION *Session, + IN VOID *OldPassword, + IN UINT32 OldPasswordLength, + IN VOID *NewPassword, + IN UINT32 NewPasswordLength, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + IN BOOLEAN SetAdmin + ); + +/** + Starts a session with OPAL_UID_LOCKING_SP as OPAL_LOCKING_SP_ADMIN1_AUTHORITY and disables the User1 authority. + + @param[in] Session The opal session for the opal device. + @param[in] Password Admin password + @param[in] PasswordLength Length of password in bytes + @param[out] PasswordFailed Indicates if password failed (start session didn't work) + @param[in] DevicePath The device path for the opal devcie. + +**/ +TCG_RESULT +EFIAPI +OpalSupportDisableUser( + IN OPAL_SESSION *Session, + IN VOID *Password, + IN UINT32 PasswordLength, + OUT BOOLEAN *PasswordFailed, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ); + +/** + Starts a session with OPAL_UID_LOCKING_SP as OPAL_LOCKING_SP_USER1_AUTHORITY or OPAL_LOCKING_SP_ADMIN1_AUTHORITY + and updates the global locking range ReadLocked and WriteLocked columns to FALSE. + + @param[in] Session The opal session for the opal device. + @param[in] Password Admin or user password + @param[in] PasswordLength Length of password in bytes + @param[in] DevicePath The device path for the opal devcie. + +**/ +TCG_RESULT +EFIAPI +OpalSupportUnlock( + IN OPAL_SESSION *Session, + IN VOID *Password, + IN UINT32 PasswordLength, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ); + +/** + Starts a session with OPAL_UID_LOCKING_SP as OPAL_LOCKING_SP_USER1_AUTHORITY or OPAL_LOCKING_SP_ADMIN1_AUTHORITY + and updates the global locking range ReadLocked and WriteLocked columns to TRUE. + + @param[in] Session The opal session for the opal device. + @param[in] Password Admin or user password + @param[in] PasswordLength Length of password in bytes + @param[in] DevicePath The device path for the opal devcie. + +**/ +TCG_RESULT +EFIAPI +OpalSupportLock( + IN OPAL_SESSION *Session, + IN VOID *Password, + IN UINT32 PasswordLength, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ); + +/** + Check if the password is full zero. + + @param[in] Password Points to the Data Buffer + + @retval TRUE This password string is full zero. + @retval FALSE This password string is not full zero. + +**/ +LIST_ENTRY * +EFIAPI +OpalSupportGetOpalDeviceList ( + VOID + ); + +/** + Transfer the password to the smm driver. + + @param[in] DevicePath The device path for the opal devcie. + @param PasswordLen The input password length. + @param Password Input password buffer. + + @retval EFI_SUCCESS Do the required action success. + @retval Others Error occured. + +**/ +EFI_STATUS +EFIAPI +OpalSupportSendPasword( + EFI_DEVICE_PATH_PROTOCOL *DevicePath, + UINTN PasswordLen, + VOID *Password + ); + +#endif // _OPAL_CORE_H_ diff --git a/SecurityPkg/Library/OpalPasswordSupportLib/OpalPasswordSupportLib.c b/SecurityPkg/Library/OpalPasswordSupportLib/OpalPasswordSupportLib.c new file mode 100644 index 0000000000..d3a93aa300 --- /dev/null +++ b/SecurityPkg/Library/OpalPasswordSupportLib/OpalPasswordSupportLib.c @@ -0,0 +1,754 @@ +/** @file + Implementation of Opal password support library. + +Copyright (c) 2016, Intel Corporation. All rights reserved.
+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 "OpalPasswordSupportNotify.h" + +#define OPAL_PASSWORD_MAX_LENGTH 32 + +LIST_ENTRY mDeviceList = INITIALIZE_LIST_HEAD_VARIABLE (mDeviceList); +BOOLEAN gInSmm = FALSE; +EFI_GUID gOpalPasswordNotifyProtocolGuid = OPAL_PASSWORD_NOTIFY_PROTOCOL_GUID; + +/** + + The function performs determines the available actions for the OPAL_DISK provided. + + @param[in] SupportedAttributes The support attribute for the device. + @param[in] LockingFeature The locking status for the device. + @param[in] OwnerShip The ownership for the device. + @param[out] AvalDiskActions Pointer to fill-out with appropriate disk actions. + +**/ +TCG_RESULT +EFIAPI +OpalSupportGetAvailableActions( + IN OPAL_DISK_SUPPORT_ATTRIBUTE *SupportedAttributes, + IN TCG_LOCKING_FEATURE_DESCRIPTOR *LockingFeature, + IN UINT16 OwnerShip, + OUT OPAL_DISK_ACTIONS *AvalDiskActions + ) +{ + BOOLEAN ExistingPassword; + + NULL_CHECK(AvalDiskActions); + + AvalDiskActions->AdminPass = 1; + AvalDiskActions->UserPass = 0; + AvalDiskActions->DisableUser = 0; + AvalDiskActions->Unlock = 0; + + // + // Revert is performed on locking sp, so only allow if locking sp is enabled + // + if (LockingFeature->LockingEnabled) { + AvalDiskActions->Revert = 1; + } + + // + // Psid revert is available for any device with media encryption support + // Revert is allowed for any device with media encryption support, however it requires + // + if (SupportedAttributes->MediaEncryption) { + + // + // Only allow psid revert if media encryption is enabled. + // Otherwise, someone who steals a disk can psid revert the disk and the user Data is still + // intact and accessible + // + AvalDiskActions->PsidRevert = 1; + AvalDiskActions->RevertKeepDataForced = 0; + + // + // Secure erase is performed by generating a new encryption key + // this is only available is encryption is supported + // + AvalDiskActions->SecureErase = 1; + } else { + AvalDiskActions->PsidRevert = 0; + AvalDiskActions->SecureErase = 0; + + // + // If no media encryption is supported, then a revert (using password) will not + // erase the Data (since you can't generate a new encryption key) + // + AvalDiskActions->RevertKeepDataForced = 1; + } + + if (LockingFeature->Locked) { + AvalDiskActions->Unlock = 1; + } else { + AvalDiskActions->Unlock = 0; + } + + // + // Only allow user to set password if an admin password exists + // + ExistingPassword = OpalUtilAdminPasswordExists(OwnerShip, LockingFeature); + AvalDiskActions->UserPass = ExistingPassword; + + // + // This will still show up even if there isn't a user, which is fine + // + AvalDiskActions->DisableUser = ExistingPassword; + + return TcgResultSuccess; +} + +/** + Creates a session with OPAL_UID_ADMIN_SP as OPAL_ADMIN_SP_PSID_AUTHORITY, then reverts device using Admin SP Revert method. + + @param[in] Session The opal session for the opal device. + @param[in] Psid PSID of device to revert. + @param[in] PsidLength Length of PSID in bytes. + @param[in] DevicePath The device path for the opal devcie. + +**/ +TCG_RESULT +EFIAPI +OpalSupportPsidRevert( + IN OPAL_SESSION *Session, + IN VOID *Psid, + IN UINT32 PsidLength, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +{ + TCG_RESULT Ret; + + NULL_CHECK(Session); + NULL_CHECK(Psid); + + Ret = OpalUtilPsidRevert (Session, Psid, PsidLength); + if (Ret == TcgResultSuccess && !gInSmm) { + OpalSupportSendPasword (DevicePath, 0, NULL); + } + + return Ret; +} + +/** + Opens a session with OPAL_UID_ADMIN_SP as OPAL_ADMIN_SP_SID_AUTHORITY, + sets OPAL_UID_ADMIN_SP_C_PIN_SID with the new password, + and sets OPAL_LOCKING_SP_C_PIN_ADMIN1 with the new password. + + @param[in] Session The opal session for the opal device. + @param[in] OldPassword Current admin password + @param[in] OldPasswordLength Length of current admin password in bytes + @param[in] NewPassword New admin password to set + @param[in] NewPasswordLength Length of new password in bytes + @param[in] DevicePath The device path for the opal devcie. + @param[in] SetAdmin Whether set admin password or user password. + TRUE for admin, FALSE for user. + +**/ +TCG_RESULT +EFIAPI +OpalSupportSetPassword( + IN OPAL_SESSION *Session, + IN VOID *OldPassword, + IN UINT32 OldPasswordLength, + IN VOID *NewPassword, + IN UINT32 NewPasswordLength, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + IN BOOLEAN SetAdmin + ) +{ + TCG_RESULT Ret; + + NULL_CHECK(Session); + NULL_CHECK(OldPassword); + NULL_CHECK(NewPassword); + + if (SetAdmin) { + Ret = OpalUtilSetAdminPassword(Session, OldPassword, OldPasswordLength, NewPassword, NewPasswordLength); + } else { + Ret = OpalUtilSetUserPassword(Session, OldPassword, OldPasswordLength, NewPassword, NewPasswordLength); + } + if (Ret == TcgResultSuccess && !gInSmm) { + OpalSupportSendPasword (DevicePath, NewPasswordLength, NewPassword); + } + + return Ret; +} + +/** + Starts a session with OPAL_UID_LOCKING_SP as OPAL_LOCKING_SP_ADMIN1_AUTHORITY and disables the User1 authority. + + @param[in] Session The opal session for the opal device. + @param[in] Password Admin password + @param[in] PasswordLength Length of password in bytes + @param[out] PasswordFailed Indicates if password failed (start session didn't work) + @param[in] DevicePath The device path for the opal devcie. + +**/ +TCG_RESULT +EFIAPI +OpalSupportDisableUser( + IN OPAL_SESSION *Session, + IN VOID *Password, + IN UINT32 PasswordLength, + OUT BOOLEAN *PasswordFailed, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +{ + TCG_RESULT Ret; + + NULL_CHECK(Session); + NULL_CHECK(Password); + NULL_CHECK(PasswordFailed); + + Ret = OpalUtilDisableUser(Session, Password, PasswordLength, PasswordFailed); + if (Ret == TcgResultSuccess && !gInSmm) { + OpalSupportSendPasword (DevicePath, PasswordLength, Password); + } + + return Ret; +} + +/** + Enable Opal Feature for the input device. + + @param[in] Session The opal session for the opal device. + @param[in] Msid Msid + @param[in] MsidLength Msid Length + @param[in] Password Admin password + @param[in] PassLength Length of password in bytes + @param[in] DevicePath The device path for the opal devcie. + +**/ +TCG_RESULT +EFIAPI +OpalSupportEnableOpalFeature ( + IN OPAL_SESSION *Session, + IN VOID *Msid, + IN UINT32 MsidLength, + IN VOID *Password, + IN UINT32 PassLength, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +{ + TCG_RESULT Ret; + + NULL_CHECK(Session); + NULL_CHECK(Msid); + NULL_CHECK(Password); + + Ret = OpalUtilSetAdminPasswordAsSid( + Session, + Msid, + MsidLength, + Password, + PassLength + ); + if (Ret == TcgResultSuccess) { + // + // Enable global locking range + // + Ret = OpalUtilSetOpalLockingRange( + Session, + Password, + PassLength, + OPAL_LOCKING_SP_LOCKING_GLOBALRANGE, + 0, + 0, + TRUE, + TRUE, + FALSE, + FALSE + ); + } + + if (Ret == TcgResultSuccess && !gInSmm) { + OpalSupportSendPasword (DevicePath, PassLength, Password); + } + + return Ret; +} + +/** + Opens a session with OPAL_UID_ADMIN_SP as OPAL_ADMIN_SP_PSID_AUTHORITY, then reverts the device using the RevertSP method. + + @param[in] Session The opal session for the opal device. + @param[in] KeepUserData TRUE to keep existing Data on the disk, or FALSE to erase it + @param[in] Password Admin password + @param[in] PasswordLength Length of password in bytes + @param[in] Msid Msid + @param[in] MsidLength Msid Length + @param[out] PasswordFailed indicates if password failed (start session didn't work) + @param[in] DevicePath The device path for the opal devcie. + +**/ +TCG_RESULT +EFIAPI +OpalSupportRevert( + IN OPAL_SESSION *Session, + IN BOOLEAN KeepUserData, + IN VOID *Password, + IN UINT32 PasswordLength, + IN VOID *Msid, + IN UINT32 MsidLength, + OUT BOOLEAN *PasswordFailed, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +{ + TCG_RESULT Ret; + + NULL_CHECK(Session); + NULL_CHECK(Password); + NULL_CHECK(Msid); + NULL_CHECK(PasswordFailed); + + Ret = OpalUtilRevert(Session, KeepUserData, Password, PasswordLength, PasswordFailed, Msid, MsidLength); + if (Ret == TcgResultSuccess && !gInSmm) { + OpalSupportSendPasword (DevicePath, 0, NULL); + } + + return Ret; +} + +/** + Starts a session with OPAL_UID_LOCKING_SP as OPAL_LOCKING_SP_USER1_AUTHORITY or OPAL_LOCKING_SP_ADMIN1_AUTHORITY + and updates the global locking range ReadLocked and WriteLocked columns to FALSE. + + @param[in] Session The opal session for the opal device. + @param[in] Password Admin or user password + @param[in] PasswordLength Length of password in bytes + @param[in] DevicePath The device path for the opal devcie. + +**/ +TCG_RESULT +EFIAPI +OpalSupportUnlock( + IN OPAL_SESSION *Session, + IN VOID *Password, + IN UINT32 PasswordLength, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +{ + TCG_RESULT Ret; + + NULL_CHECK(Session); + NULL_CHECK(Password); + + Ret = OpalUtilUpdateGlobalLockingRange(Session, Password, PasswordLength, FALSE, FALSE); + if (Ret == TcgResultSuccess && !gInSmm) { + OpalSupportSendPasword (DevicePath, PasswordLength, Password); + } + + return Ret; +} + +/** + Starts a session with OPAL_UID_LOCKING_SP as OPAL_LOCKING_SP_USER1_AUTHORITY or OPAL_LOCKING_SP_ADMIN1_AUTHORITY + and updates the global locking range ReadLocked and WriteLocked columns to TRUE. + + @param[in] Session The opal session for the opal device. + @param[in] Password Admin or user password + @param[in] PasswordLength Length of password in bytes + @param[in] DevicePath The device path for the opal devcie. + +**/ +TCG_RESULT +EFIAPI +OpalSupportLock( + IN OPAL_SESSION *Session, + IN VOID *Password, + IN UINT32 PasswordLength, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +{ + TCG_RESULT Ret; + + NULL_CHECK(Session); + NULL_CHECK(Password); + + Ret = OpalUtilUpdateGlobalLockingRange(Session, Password, PasswordLength, TRUE, TRUE); + if (Ret == TcgResultSuccess && !gInSmm) { + OpalSupportSendPasword (DevicePath, PasswordLength, Password); + } + + return Ret; +} + +/** + 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. + + @retval EFI_INVALID_PARAMETER The Data Size is too big. + @retval EFI_SUCCESS Find the specified variable. + +**/ +VOID* +OpalInitCommunicateBuffer ( + OUT VOID **DataPtr OPTIONAL, + IN UINTN DataSize, + IN UINTN Function + ) +{ + EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader; + OPAL_SMM_COMMUNICATE_HEADER *SmmFunctionHeader; + VOID *Buffer; + + Buffer = AllocateZeroPool (DataSize + OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data) + OFFSET_OF (OPAL_SMM_COMMUNICATE_HEADER, Data)); + ASSERT (Buffer != NULL); + + SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) Buffer; + CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gOpalPasswordNotifyProtocolGuid); + SmmCommunicateHeader->MessageLength = DataSize + OFFSET_OF (OPAL_SMM_COMMUNICATE_HEADER, Data); + + SmmFunctionHeader = (OPAL_SMM_COMMUNICATE_HEADER *) SmmCommunicateHeader->Data; + SmmFunctionHeader->Function = Function; + if (DataPtr != NULL) { + *DataPtr = SmmFunctionHeader->Data; + } + + 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 +OpalSendCommunicateBuffer ( + IN VOID *Buffer, + IN UINTN DataSize + ) +{ + EFI_STATUS Status; + UINTN CommSize; + EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader; + OPAL_SMM_COMMUNICATE_HEADER *SmmFunctionHeader; + EFI_SMM_COMMUNICATION_PROTOCOL *SmmCommunication; + + Status = gBS->LocateProtocol (&gEfiSmmCommunicationProtocolGuid, NULL, (VOID **) &SmmCommunication); + if (EFI_ERROR (Status)) { + return Status; + } + + CommSize = DataSize + OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data) + OFFSET_OF (OPAL_SMM_COMMUNICATE_HEADER, Data); + Status = SmmCommunication->Communicate (SmmCommunication, Buffer, &CommSize); + if (EFI_ERROR (Status)) { + return Status; + } + + SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) Buffer; + SmmFunctionHeader = (OPAL_SMM_COMMUNICATE_HEADER *)SmmCommunicateHeader->Data; + + return SmmFunctionHeader->ReturnStatus; +} + +/** + Transfer the password to the smm driver. + + @param[in] DevicePath The device path for the opal devcie. + @param PasswordLen The input password length. + @param Password Input password buffer. + + @retval EFI_SUCCESS Do the required action success. + @retval Others Error occured. + +**/ +EFI_STATUS +EFIAPI +OpalSupportSendPasword( + EFI_DEVICE_PATH_PROTOCOL *DevicePath, + UINTN PasswordLen, + VOID *Password + ) +{ + OPAL_COMM_DEVICE_LIST *Parameter; + VOID *Buffer; + UINTN Length; + EFI_STATUS Status; + UINTN DevicePathLen; + + Parameter = NULL; + Buffer = NULL; + + if (DevicePath == NULL) { + // + // Assume DevicePath == NULL only when library used by SMM driver + // and should not run to here, just return success. + // + return EFI_SUCCESS; + } + + DevicePathLen = GetDevicePathSize (DevicePath); + Length = OFFSET_OF (OPAL_COMM_DEVICE_LIST, OpalDevicePath) + DevicePathLen; + Buffer = OpalInitCommunicateBuffer((VOID**)&Parameter, Length, SMM_FUNCTION_SET_OPAL_PASSWORD); + if (Buffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + if (Password != NULL) { + CopyMem((VOID*)Parameter->Password, Password, PasswordLen); + Parameter->PasswordLength = (UINT8)PasswordLen; + } + CopyMem (&Parameter->OpalDevicePath, DevicePath, DevicePathLen); + + Status = OpalSendCommunicateBuffer(Buffer, Length); + if (EFI_ERROR(Status)) { + goto EXIT; + } + +EXIT: + ZeroMem(Parameter, Length); + FreePool(Buffer); + + return Status; +} + +/** + Get saved Opal device list. + + @retval return opal device list. + +**/ +LIST_ENTRY* +EFIAPI +OpalSupportGetOpalDeviceList ( + VOID + ) +{ + return &mDeviceList; +} + +/** + Check if the password is full zero. + + @param[in] Password Points to the Data Buffer + + @retval TRUE This password string is full zero. + @retval FALSE This password string is not full zero. + +**/ +BOOLEAN +OpalPasswordIsFullZero ( + IN UINT8 *Password + ) +{ + UINTN Index; + + for (Index = 0; Index < OPAL_PASSWORD_MAX_LENGTH; Index++) { + if (Password[Index] != 0) { + return FALSE; + } + } + + return TRUE; +} + +/** + Save hdd password to SMM. + + @param[in] DevicePath Input device path info for the device. + @param[in] Password The hdd password of attached ATA device. + @param[in] PasswordLength The hdd password length. + + @retval EFI_OUT_OF_RESOURCES Insufficient resources to create database record + @retval EFI_SUCCESS The function has been successfully executed. + +**/ +EFI_STATUS +OpalSavePasswordToSmm ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + IN UINT8 *Password, + IN UINT8 PasswordLength + ) +{ + OPAL_DISK_AND_PASSWORD_INFO *List; + OPAL_DISK_AND_PASSWORD_INFO *Dev; + LIST_ENTRY *Entry; + UINTN DevicePathLen; + + DevicePathLen = GetDevicePathSize (DevicePath); + + for (Entry = mDeviceList.ForwardLink; Entry != &mDeviceList; Entry = Entry->ForwardLink) { + List = BASE_CR (Entry, OPAL_DISK_AND_PASSWORD_INFO, Link); + if (CompareMem (&List->OpalDevicePath, DevicePath, DevicePathLen) == 0) { + CopyMem(List->Password, Password, OPAL_PASSWORD_MAX_LENGTH); + return EFI_SUCCESS; + } + } + + Dev = AllocateZeroPool (OFFSET_OF (OPAL_DISK_AND_PASSWORD_INFO, OpalDevicePath) + DevicePathLen); + if (Dev == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Dev->PasswordLength = PasswordLength; + CopyMem(&(Dev->Password), Password, OPAL_PASSWORD_MAX_LENGTH); + CopyMem(&(Dev->OpalDevicePath), DevicePath, DevicePathLen); + + InsertHeadList (&mDeviceList, &Dev->Link); + + return EFI_SUCCESS; +} + +/** + Communication service SMI Handler entry. + + This SMI handler provides services for saving HDD password and saving S3 boot script when ready to boot. + + @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 +SmmOpalPasswordHandler ( + IN EFI_HANDLE DispatchHandle, + IN CONST VOID *RegisterContext, + IN OUT VOID *CommBuffer, + IN OUT UINTN *CommBufferSize + ) +{ + EFI_STATUS Status; + OPAL_SMM_COMMUNICATE_HEADER *SmmFunctionHeader; + UINTN TempCommBufferSize; + UINT8 *NewPassword; + UINT8 PasswordLength; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + + if (CommBuffer == NULL || CommBufferSize == NULL) { + return EFI_SUCCESS; + } + + TempCommBufferSize = *CommBufferSize; + if (TempCommBufferSize < OFFSET_OF (OPAL_SMM_COMMUNICATE_HEADER, Data)) { + return EFI_SUCCESS; + } + + Status = EFI_SUCCESS; + SmmFunctionHeader = (OPAL_SMM_COMMUNICATE_HEADER *)CommBuffer; + + DevicePath = &((OPAL_COMM_DEVICE_LIST*)(SmmFunctionHeader->Data))->OpalDevicePath; + PasswordLength = ((OPAL_COMM_DEVICE_LIST*)(SmmFunctionHeader->Data))->PasswordLength; + NewPassword = ((OPAL_COMM_DEVICE_LIST*)(SmmFunctionHeader->Data))->Password; + + switch (SmmFunctionHeader->Function) { + case SMM_FUNCTION_SET_OPAL_PASSWORD: + if (OpalPasswordIsFullZero (NewPassword) || PasswordLength == 0) { + Status = EFI_INVALID_PARAMETER; + goto EXIT; + } + + Status = OpalSavePasswordToSmm (DevicePath, NewPassword, PasswordLength); + break; + + default: + Status = EFI_UNSUPPORTED; + break; + } + +EXIT: + SmmFunctionHeader->ReturnStatus = Status; + + // + // Return EFI_SUCCESS cause only one handler can be trigged. + // so return EFI_WARN_INTERRUPT_SOURCE_PENDING to make all handler can be trigged. + // + return EFI_WARN_INTERRUPT_SOURCE_PENDING; +} + +/** + The constructor function. + + Register SMI handler when link to SMM driver. + + @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS. + +**/ +EFI_STATUS +EFIAPI +OpalPasswordSupportLibConstructor ( + VOID + ) +{ + EFI_SMM_BASE2_PROTOCOL *SmmBase2; + EFI_SMM_SYSTEM_TABLE2 *Smst; + EFI_HANDLE SmmHandle; + EFI_STATUS Status; + + Status = gBS->LocateProtocol (&gEfiSmmBase2ProtocolGuid, NULL, (VOID**) &SmmBase2); + if (EFI_ERROR (Status)) { + return RETURN_SUCCESS; + } + Status = SmmBase2->InSmm (SmmBase2, &gInSmm); + if (EFI_ERROR (Status)) { + return RETURN_SUCCESS; + } + if (!gInSmm) { + return RETURN_SUCCESS; + } + + // + // Good, we are in SMM + // + Status = SmmBase2->GetSmstLocation (SmmBase2, &Smst); + if (EFI_ERROR (Status)) { + return RETURN_SUCCESS; + } + + SmmHandle = NULL; + Status = Smst->SmiHandlerRegister (SmmOpalPasswordHandler, &gOpalPasswordNotifyProtocolGuid, &SmmHandle); + ASSERT_EFI_ERROR (Status); + + return EFI_SUCCESS; +} + +/** + The Destructor function. + + Clean the saved opal device list. + + @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS. + +**/ +EFI_STATUS +EFIAPI +OpalPasswordSupportLibDestructor ( + VOID + ) +{ + OPAL_DISK_AND_PASSWORD_INFO *Device; + + while (!IsListEmpty (&mDeviceList)) { + Device = BASE_CR (mDeviceList.ForwardLink, OPAL_DISK_AND_PASSWORD_INFO, Link); + + RemoveEntryList (&Device->Link); + FreePool (Device); + } + + return EFI_SUCCESS; +} diff --git a/SecurityPkg/Library/OpalPasswordSupportLib/OpalPasswordSupportLib.inf b/SecurityPkg/Library/OpalPasswordSupportLib/OpalPasswordSupportLib.inf new file mode 100644 index 0000000000..461d7eaab6 --- /dev/null +++ b/SecurityPkg/Library/OpalPasswordSupportLib/OpalPasswordSupportLib.inf @@ -0,0 +1,54 @@ +## @file +# This is a OpalPassword support library. +# +# This module is used to provide API used by Opal password solution. +# +# Copyright (c) 2016, Intel Corporation. All rights reserved.
+# 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 = 0x00010017 + BASE_NAME = OpalPasswordSupportLib + FILE_GUID = 00F93D8C-00A6-42D0-9327-11CE309B944A + VERSION_STRING = 1.0 + MODULE_TYPE = BASE + LIBRARY_CLASS = OpalPasswordSupportLib|DXE_DRIVER DXE_CORE DXE_SMM_DRIVER + + CONSTRUCTOR = OpalPasswordSupportLibConstructor + DESTRUCTOR = OpalPasswordSupportLibDestructor +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + OpalPasswordSupportLib.c + OpalPasswordSupportNotify.h + +[LibraryClasses] + BaseLib + BaseMemoryLib + PrintLib + DebugLib + TimerLib + TcgStorageOpalLib + UefiLib + +[Packages] + MdePkg/MdePkg.dec + SecurityPkg/SecurityPkg.dec + +[Protocols] + gEfiStorageSecurityCommandProtocolGuid ## CONSUMES + gEfiSmmCommunicationProtocolGuid ## CONSUMES + gEfiSmmBase2ProtocolGuid + +[BuildOptions] + MSFT:*_*_*_CC_FLAGS = /Od /GL- diff --git a/SecurityPkg/Library/OpalPasswordSupportLib/OpalPasswordSupportNotify.h b/SecurityPkg/Library/OpalPasswordSupportLib/OpalPasswordSupportNotify.h new file mode 100644 index 0000000000..59c1214d8c --- /dev/null +++ b/SecurityPkg/Library/OpalPasswordSupportLib/OpalPasswordSupportNotify.h @@ -0,0 +1,56 @@ +/** @file + Implementation of Opal password support library. + +Copyright (c) 2016, Intel Corporation. All rights reserved.
+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 _DXE_OPAL_NOTIFY_H_ +#define _DXE_OPAL_NOTIFY_H_ + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +#pragma pack(1) + +typedef struct { + UINTN Function; + EFI_STATUS ReturnStatus; + UINT8 Data[1]; +} OPAL_SMM_COMMUNICATE_HEADER; + +typedef struct { + UINT8 Password[32]; + UINT8 PasswordLength; + + EFI_DEVICE_PATH_PROTOCOL OpalDevicePath; +} OPAL_COMM_DEVICE_LIST; + +#pragma pack() + +#define SMM_FUNCTION_SET_OPAL_PASSWORD 1 + +#define OPAL_PASSWORD_NOTIFY_PROTOCOL_GUID {0x0ff2ddd0, 0xefc9, 0x4f49, { 0x99, 0x7a, 0xcb, 0x59, 0x44, 0xe6, 0x97, 0xd3 } } + +#endif diff --git a/SecurityPkg/SecurityPkg.dec b/SecurityPkg/SecurityPkg.dec index b432c4459e..99cda26fd2 100644 --- a/SecurityPkg/SecurityPkg.dec +++ b/SecurityPkg/SecurityPkg.dec @@ -81,6 +81,18 @@ # Tcg2PhysicalPresenceLib|Include/Library/Tcg2PhysicalPresenceLib.h + ## @libraryclass Provides interfaces about TCG storage generic commond. + # + TcgStorageCoreLib|Include/Library/TcgStorageCoreLib.h + + ## @libraryclass Provides interfaces about TCG storage Opal generic commond. + # + TcgStorageOpalLib|Include/Library/TcgStorageOpalLib.h + + ## @libraryclass Provides interfaces about Opal commond special for Opal password solution. + # + OpalPasswordSupportLib|Include/Library/OpalPasswordSupportLib.h + [Guids] ## Security package token space guid. # Include/Guid/SecurityPkgTokenSpace.h @@ -190,6 +202,10 @@ # Include/Guid/TrEEConfigHii.h gTrEEConfigFormSetGuid = {0xc54b425f, 0xaa79, 0x48b4, { 0x98, 0x1f, 0x99, 0x8b, 0x3c, 0x4b, 0x64, 0x1c }} + ## Include/OpalPasswordExtraInfoVariable.h + gOpalExtraInfoVariableGuid = {0x44a2ad5d, 0x612c, 0x47b3, {0xb0, 0x6e, 0xc8, 0xf5, 0x0b, 0xfb, 0xf0, 0x7d}} + + [Ppis] ## The PPI GUID for that TPM physical presence should be locked. # Include/Ppi/LockPhysicalPresence.h