From 9dd05ddec35a4c6d010dcd122d9a715d40d88d9c Mon Sep 17 00:00:00 2001 From: Eric Dong Date: Tue, 29 Mar 2016 14:42:13 +0800 Subject: [PATCH] SecurityPkg: TcgStorageOpalLib: Add TCG storage opal library. Library APIs used to create commands defined by TCG storage opal spec. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Eric Dong Reviewed-by: Feng Tian --- .../Include/Library/TcgStorageOpalLib.h | 831 +++++++++ .../TcgStorageOpalLib/TcgStorageOpalCore.c | 1653 +++++++++++++++++ .../TcgStorageOpalLib/TcgStorageOpalLib.inf | 50 + .../TcgStorageOpalLib/TcgStorageOpalUtil.c | 913 +++++++++ 4 files changed, 3447 insertions(+) create mode 100644 SecurityPkg/Include/Library/TcgStorageOpalLib.h create mode 100644 SecurityPkg/Library/TcgStorageOpalLib/TcgStorageOpalCore.c create mode 100644 SecurityPkg/Library/TcgStorageOpalLib/TcgStorageOpalLib.inf create mode 100644 SecurityPkg/Library/TcgStorageOpalLib/TcgStorageOpalUtil.c diff --git a/SecurityPkg/Include/Library/TcgStorageOpalLib.h b/SecurityPkg/Include/Library/TcgStorageOpalLib.h new file mode 100644 index 0000000000..a9b4f2fe6e --- /dev/null +++ b/SecurityPkg/Include/Library/TcgStorageOpalLib.h @@ -0,0 +1,831 @@ +/** @file + Public API for Opal Core 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_CORE_H_ +#define _OPAL_CORE_H_ + +#include + +#include +#include + +#pragma pack(1) + +typedef struct { + // + // Opal SSC 1 support (0 - not supported, 1 - supported) + // + UINT32 OpalSsc1 : 1; + + // + // Opal SSC 2support (0 - not supported, 1 - supported) + // + UINT32 OpalSsc2 : 1; + + // + // Opal SSC Lite support (0 - not supported, 1 - supported) + // + UINT32 OpalSscLite : 1; + + // + // Pyrite SSC support (0 - not supported, 1 - supported) + // + UINT32 PyriteSsc : 1; + + // + // Security protocol 1 support (0 - not supported, 1 - supported) + // + UINT32 Sp1 : 1; + + // + // Security protocol 2 support (0 - not supported, 1 - supported) + // + UINT32 Sp2 : 1; + + // + // Security protocol IEEE1667 support (0 - not supported, 1 - supported) + // + UINT32 SpIeee1667 : 1; + + // + // Media encryption supported (0 - not supported, 1 - supported) + // + UINT32 MediaEncryption : 1; + + // + // Initial C_PIN_SID PIN Indicator + // 0 - The initial C_PIN_SID PIN value is NOT equal to the C_PIN_MSID PIN value + // 1 - The initial C_PIN_SID PIN value is equal to the C_PIN_MSID PIN value + // + UINT32 InitCpinIndicator : 1; + + // + // Behavior of C_PIN_SID PIN upon TPer Revert + // 0 - The initial C_PIN_SID PIN value is NOT equal to the C_PIN_MSID PIN value + // 1 - The initial C_PIN_SID PIN value is equal to the C_PIN_MSID PIN value + // + UINT32 CpinUponRevert : 1; +} OPAL_DISK_SUPPORT_ATTRIBUTE; + +// +// Opal device ownership type +// The type indicates who was the determined owner of the device. +// +typedef enum { + // + // Represents the device ownership is unknown because starting a session as the SID authority with the ADMIN SP + //was unsuccessful with the provided PIN + // + OpalOwnershipUnknown, + + // + // Represents that the ADMIN SP SID authority contains the same PIN as the MSID PIN + // + OpalOwnershipNobody, +} OPAL_OWNER_SHIP; + +// +// Structure that is used to represent an Opal session. +// The structure must be initialized by calling OpalStartSession before being used as a parameter +// for any other Opal function. +// This structure should NOT be directly modified by the client of this library. +// +// +typedef struct { + UINT32 HostSessionId; + UINT32 TperSessionId; + UINT16 ComIdExtension; + + UINT16 OpalBaseComId; + + EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *Sscp; + UINT32 MediaId; +} OPAL_SESSION; +#pragma pack() + +/** + + The function fills in the provided Buffer with the supported protocol list + of the device specified. + + @param[in] Session OPAL_SESSION data. + @param[in] BufferSize Size of Buffer provided (in bytes) + @param[in] BuffAddress Buffer address to fill with security protocol list + +**/ +TCG_RESULT +EFIAPI +OpalRetrieveSupportedProtocolList( + OPAL_SESSION *Session, + UINTN BufferSize, + VOID *BuffAddress + ); + +/** + + The function fills in the provided Buffer with the level 0 discovery Header + of the device specified. + + @param[in] Session OPAL_SESSION data. + @param[in] BufferSize Size of Buffer provided (in bytes) + @param[in] BuffAddress Buffer address to fill with Level 0 Discovery response + +**/ +TCG_RESULT +EFIAPI +OpalRetrieveLevel0DiscoveryHeader( + OPAL_SESSION *Session, + UINTN BufferSize, + VOID *BuffAddress + ); + +/** + Starts a session with a security provider (SP). + + If a session is started successfully, the caller must end the session with OpalEndSession when finished + performing Opal actions. + + @param[in/out] Session OPAL_SESSION to initialize. + @param[in] SpId Security provider ID to start the session with. + @param[in] Write Whether the session should be read-only (FALSE) or read/write (TRUE). + @param[in] HostChallengeLength Length of the host challenge. Length should be 0 if hostChallenge is NULL + @param[in] HostChallenge Host challenge for Host Signing Authority. If NULL, then no Host Challenge will be sent. + @param[in] HostSigningAuthority Host Signing Authority used for start session. If NULL, then no Host Signing Authority will be sent. + @param[in/out] MethodStatus Status of the StartSession method; only valid if TcgResultSuccess is returned. + + @return TcgResultSuccess indicates that the function completed without any internal errors. + The caller must inspect the MethodStatus field to determine whether the method completed successfully. + +**/ +TCG_RESULT +EFIAPI +OpalStartSession( + OPAL_SESSION *Session, + TCG_UID SpId, + BOOLEAN Write, + UINT32 HostChallengeLength, + const VOID *HostChallenge, + TCG_UID HostSigningAuthority, + UINT8 *MethodStatus + ); + +/** + Close a session opened with OpalStartSession. + + @param[in/out] Session OPAL_SESSION to end. + +**/ +TCG_RESULT +EFIAPI +OpalEndSession( + OPAL_SESSION *Session + ); + +/** + + Reverts device using Admin SP Revert method. + + @param[in] AdminSpSession OPAL_SESSION with OPAL_UID_ADMIN_SP as OPAL_ADMIN_SP_PSID_AUTHORITY to perform PSID revert. + +**/ +TCG_RESULT +EFIAPI +OpalPsidRevert( + OPAL_SESSION *AdminSpSession + ); + + +/** + + The function retrieves the MSID from the device specified + + @param[in] AdminSpSession OPAL_SESSION with OPAL_UID_ADMIN_SP as OPAL_ADMIN_SP_PSID_AUTHORITY to perform PSID revert. + @param[in] MsidBufferSize Allocated buffer size (in bytes) for MSID allocated by caller + @param[in] Msid Variable length byte sequence representing MSID of device + @param[in] MsidLength Actual length of MSID retrieved from device + +**/ +TCG_RESULT +EFIAPI +OpalGetMsid( + OPAL_SESSION *AdminSpSession, + UINT32 MsidBufferSize, + UINT8 *Msid, + UINT32 *MsidLength + ); + +/** + + The function activates the Locking SP. + Once activated, per Opal spec, the ADMIN SP SID PIN is copied over to the ADMIN1 LOCKING SP PIN. + If the Locking SP is already enabled, then TcgResultSuccess is returned and no action occurs. + + @param[in] AdminSpSession OPAL_SESSION with OPAL_UID_ADMIN_SP as OPAL_ADMIN_SP_SID_AUTHORITY to activate Locking SP + @param[in/out] MethodStatus Method status of last action performed. If action succeeded, it should be TCG_METHOD_STATUS_CODE_SUCCESS. + +**/ +TCG_RESULT +EFIAPI +OpalActivateLockingSp( + OPAL_SESSION *AdminSpSession, + UINT8 *MethodStatus + ); + + +/** + + The function sets the PIN column of the specified cpinRowUid (authority) with the newPin value. + + @param[in/out] Session OPAL_SESSION to set password + @param[in] CpinRowUid UID of row (authority) to update PIN column + @param[in] NewPin New Pin to set for cpinRowUid specified + @param[in] NewPinLength Length in bytes of newPin + @param[in/out] MethodStatus Method status of last action performed. If action succeeded, it should be TCG_METHOD_STATUS_CODE_SUCCESS. + +**/ +TCG_RESULT +EFIAPI +OpalSetPassword( + OPAL_SESSION *Session, + TCG_UID CpinRowUid, + const VOID *NewPin, + UINT32 NewPinLength, + UINT8 *MethodStatus + ); + +/** + + The function retrieves the active key of the global locking range + and calls the GenKey method on the active key retrieved. + + @param[in] LockingSpSession OPAL_SESSION with OPAL_UID_LOCKING_SP to generate key + @param[in/out] MethodStatus Method status of last action performed. If action succeeded, it should be TCG_METHOD_STATUS_CODE_SUCCESS. + +**/ +TCG_RESULT +EFIAPI +OpalGlobalLockingRangeGenKey( + OPAL_SESSION *LockingSpSession, + UINT8 *MethodStatus + ); + + +/** + + The function updates the ReadLocked and WriteLocked columns of the Global Locking Range. + This funciton is required for a user1 authority, since a user1 authority shall only have access to ReadLocked and WriteLocked columns + (not ReadLockEnabled and WriteLockEnabled columns). + + @param[in] LockingSpSession OPAL_SESSION with OPAL_UID_LOCKING_SP to generate key + @param[in] ReadLocked Value to set ReadLocked column for Global Locking Range + @param[in] WriteLocked Value to set WriteLocked column for Global Locking Range + @param[in/out] MethodStatus Method status of last action performed. If action succeeded, it should be TCG_METHOD_STATUS_CODE_SUCCESS. + +**/ +TCG_RESULT +EFIAPI +OpalUpdateGlobalLockingRange( + OPAL_SESSION *LockingSpSession, + BOOLEAN ReadLocked, + BOOLEAN WriteLocked, + UINT8 *MethodStatus + ); + + +/** + + The function updates the RangeStart, RangeLength, ReadLockedEnabled, WriteLockedEnabled, ReadLocked and WriteLocked columns + of the specified Locking Range. This function requires admin authority of a locking SP session. + + @param[in] LockingSpSession OPAL_SESSION with OPAL_UID_LOCKING_SP to generate key + @param[in] LockingRangeUid Locking range UID to set values + @param[in] RangeStart Value to set RangeStart column for Locking Range + @param[in] RangeLength Value to set RangeLength column for Locking Range + @param[in] ReadLockEnabled Value to set readLockEnabled column for Locking Range + @param[in] WriteLockEnabled Value to set writeLockEnabled column for Locking Range + @param[in] ReadLocked Value to set ReadLocked column for Locking Range + @param[in] WriteLocked Value to set WriteLocked column for Locking Range + @param[in/out] MethodStatus Method status of last action performed. If action succeeded, it should be TCG_METHOD_STATUS_CODE_SUCCESS. + +**/ +TCG_RESULT +EFIAPI +OpalSetLockingRange( + OPAL_SESSION *LockingSpSession, + TCG_UID LockingRangeUid, + UINT64 RangeStart, + UINT64 RangeLength, + BOOLEAN ReadLockEnabled, + BOOLEAN WriteLockEnabled, + BOOLEAN ReadLocked, + BOOLEAN WriteLocked, + UINT8 *MethodStatus + ); + +/** + + The function sets the Enabled column to TRUE for the authorityUid provided and updates the PIN column for the cpinRowUid provided + using the newPin provided. AuthorityUid and cpinRowUid should describe the same authority. + + @param[in] LockingSpSession OPAL_SESSION with OPAL_UID_LOCKING_SP as OPAL_LOCKING_SP_ADMIN1_AUTHORITY to update + @param[in] CpinRowUid Row UID of C_PIN table of Locking SP to update PIN + @param[in] AuthorityUid UID of Locking SP authority to update Pin column with + @param[in] NewPin New Password used to set Pin column + @param[in] NewPinLength Length in bytes of new password + @param[in/out] MethodStatus Method status of last action performed. If action succeeded, it should be TCG_METHOD_STATUS_CODE_SUCCESS. + +**/ +TCG_RESULT +EFIAPI +OpalSetLockingSpAuthorityEnabledAndPin( + OPAL_SESSION *LockingSpSession, + TCG_UID CpinRowUid, + TCG_UID AuthorityUid, + const VOID *NewPin, + UINT32 NewPinLength, + UINT8 *MethodStatus + ); + + +/** + + The function sets the Enabled column to FALSE for the USER1 authority. + + @param[in] LockingSpSession OPAL_SESSION with OPAL_UID_LOCKING_SP as OPAL_LOCKING_SP_ADMIN1_AUTHORITY to disable User1 + @param[in/out] MethodStatus Method status of last action performed. If action succeeded, it should be TCG_METHOD_STATUS_CODE_SUCCESS. + +**/ +TCG_RESULT +EFIAPI +OpalDisableUser( + OPAL_SESSION *LockingSpSession, + UINT8 *MethodStatus + ); + + +/** + + The function calls the Admin SP RevertSP method on the Locking SP. If KeepUserData is True, then the optional parameter + to keep the user data is set to True, otherwise the optional parameter is not provided. + + @param[in] LockingSpSession OPAL_SESSION with OPAL_UID_LOCKING_SP as OPAL_LOCKING_SP_ADMIN1_AUTHORITY to revertSP + @param[in] KeepUserData Specifies whether or not to keep user data when performing RevertSP action. True = keeps user data. + @param[in/out] MethodStatus Method status of last action performed. If action succeeded, it should be TCG_METHOD_STATUS_CODE_SUCCESS. + +**/ +TCG_RESULT +EFIAPI +OpalAdminRevert( + OPAL_SESSION *LockingSpSession, + BOOLEAN KeepUserData, + UINT8 *MethodStatus + ); + + +/** + + The function retrieves the TryLimit column for the specified rowUid (authority). + + @param[in] LockingSpSession OPAL_SESSION with OPAL_UID_LOCKING_SP to retrieve try limit + @param[in] RowUid Row UID of the Locking SP C_PIN table to retrieve TryLimit column + @param[in/out] TryLimit Value from TryLimit column + +**/ +TCG_RESULT +EFIAPI +OpalGetTryLimit( + OPAL_SESSION *LockingSpSession, + TCG_UID RowUid, + UINT32 *TryLimit + ); + + +/** + + The function populates the CreateStruct with a payload that will retrieve the global locking range active key. + It is intended to be called with a session that is already started with a valid credential. + The function does not send the payload. + + @param[in] Session OPAL_SESSION to populate command for, needs comId + @param[in/out] CreateStruct Structure to populate with encoded TCG command + @param[in/out] Size Size in bytes of the command created. + +**/ +TCG_RESULT +EFIAPI +OpalCreateRetrieveGlobalLockingRangeActiveKey( + const OPAL_SESSION *Session, + TCG_CREATE_STRUCT *CreateStruct, + UINT32 *Size + ); + + +/** + + The function acquires the activeKey specified for the Global Locking Range from the parseStruct. + + @param[in] ParseStruct Structure that contains the device's response with the activekey + @param[in/out] ActiveKey The UID of the active key retrieved + +**/ +TCG_RESULT +EFIAPI +OpalParseRetrieveGlobalLockingRangeActiveKey( + TCG_PARSE_STRUCT *ParseStruct, + TCG_UID *ActiveKey + ); + +/** + + Get the support attribute info. + + @param[in] Session OPAL_SESSION with OPAL_UID_LOCKING_SP to retrieve info. + @param[in/out] LockingFeature Return the Locking info. + +**/ +TCG_RESULT +EFIAPI +OpalGetLockingInfo( + OPAL_SESSION *Session, + TCG_LOCKING_FEATURE_DESCRIPTOR *LockingFeature + ); + +/** + + The function determines whether or not all of the requirements for the Opal Feature (not full specification) + are met by the specified device. + + @param[in] SupportedAttributes Opal device attribute. + +**/ +BOOLEAN +EFIAPI +OpalFeatureSupported( + OPAL_DISK_SUPPORT_ATTRIBUTE *SupportedAttributes + ); + +/** + + The function returns whether or not the device is Opal Enabled. + TRUE means that the device is partially or fully locked. + This will perform a Level 0 Discovery and parse the locking feature descriptor + + @param[in] SupportedAttributes Opal device attribute. + @param[in] LockingFeature Opal device locking status. + + +**/ +BOOLEAN +EFIAPI +OpalFeatureEnabled( + OPAL_DISK_SUPPORT_ATTRIBUTE *SupportedAttributes, + TCG_LOCKING_FEATURE_DESCRIPTOR *LockingFeature + ); + +/** + + The function returns whether or not the device is Opal Locked. + TRUE means that the device is partially or fully locked. + This will perform a Level 0 Discovery and parse the locking feature descriptor + + @param[in] SupportedAttributes Opal device attribute. + @param[in] LockingFeature Opal device locking status. + +**/ +BOOLEAN +OpalDeviceLocked( + OPAL_DISK_SUPPORT_ATTRIBUTE *SupportedAttributes, + TCG_LOCKING_FEATURE_DESCRIPTOR *LockingFeature + ); + +/** + Trig the block sid action. + + @param[in] Session OPAL_SESSION to populate command for, needs comId + @param[in] HardwareReset Whether need to do hardware reset. + +**/ +TCG_RESULT +EFIAPI +OpalBlockSid( + OPAL_SESSION *Session, + BOOLEAN HardwareReset + ); + +/** + + Get the support attribute info. + + @param[in] Session OPAL_SESSION with OPAL_UID_LOCKING_SP to retrieve info. + @param[in/out] SupportedAttributes Return the support attribute info. + @param[out] OpalBaseComId Return the base com id info. + +**/ +TCG_RESULT +EFIAPI +OpalGetSupportedAttributesInfo( + OPAL_SESSION *Session, + OPAL_DISK_SUPPORT_ATTRIBUTE *SupportedAttributes, + UINT16 *OpalBaseComId + ); + +/** + Creates a session with OPAL_UID_ADMIN_SP as OPAL_ADMIN_SP_PSID_AUTHORITY, then reverts device using Admin SP Revert method. + + @param[in] AdminSpSession OPAL_SESSION to populate command for, needs comId + @param[in] Psid PSID of device to revert. + @param[in] PsidLength Length of PSID in bytes. + +**/ +TCG_RESULT +EFIAPI +OpalUtilPsidRevert( + OPAL_SESSION *AdminSpSession, + const VOID *Psid, + UINT32 PsidLength + ); + +/** + Opens a session with OPAL_UID_ADMIN_SP as OPAL_ADMIN_SP_SID_AUTHORITY, + sets the OPAL_UID_ADMIN_SP_C_PIN_SID column with the new password, + and activates the locking SP to copy SID PIN to Admin1 Locking SP PIN. + + @param[in] AdminSpSession OPAL_SESSION to populate command for, needs comId + @param[in] GeneratedSid Generated SID of disk + @param[in] SidLength Length of generatedSid in bytes + @param[in] Password New admin password to set + @param[in] PassLength Length of password in bytes + +**/ +TCG_RESULT +EFIAPI +OpalUtilSetAdminPasswordAsSid( + OPAL_SESSION *AdminSpSession, + const VOID *GeneratedSid, + UINT32 SidLength, + const VOID *Password, + UINT32 PassLength + ); + +/** + + Opens a session with OPAL_UID_LOCKING_SP as OPAL_LOCKING_SP_ADMIN1_AUTHORITY, + and updates the specified locking range with the provided column values. + + @param[in] LockingSpSession OPAL_SESSION to populate command for, needs comId + @param[in] Password New admin password to set + @param[in] PassLength Length of password in bytes + @param[in] LockingRangeUid Locking range UID to set values + @param[in] RangeStart Value to set RangeStart column for Locking Range + @param[in] RangeLength Value to set RangeLength column for Locking Range + @param[in] ReadLockEnabled Value to set readLockEnabled column for Locking Range + @param[in] WriteLockEnabled Value to set writeLockEnabled column for Locking Range + @param[in] ReadLocked Value to set ReadLocked column for Locking Range + @param[in] WriteLocked Value to set WriteLocked column for Locking Range + +**/ +TCG_RESULT +EFIAPI +OpalUtilSetOpalLockingRange( + OPAL_SESSION *LockingSpSession, + const VOID *Password, + UINT32 PassLength, + TCG_UID LockingRangeUid, + UINT64 RangeStart, + UINT64 RangeLength, + BOOLEAN ReadLockEnabled, + BOOLEAN WriteLockEnabled, + BOOLEAN ReadLocked, + BOOLEAN WriteLocked + ); + +/** + 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] AdminSpSession OPAL_SESSION to populate command for, needs comId + @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 + +**/ +TCG_RESULT +EFIAPI +OpalUtilSetAdminPassword( + OPAL_SESSION *AdminSpSession, + const VOID *OldPassword, + UINT32 OldPasswordLength, + const VOID *NewPassword, + UINT32 NewPasswordLength + ); + +/** + Starts a session with OPAL_UID_LOCKING_SP as OPAL_LOCKING_SP_USER1_AUTHORITY or OPAL_LOCKING_SP_ADMIN1_AUTHORITY + and sets the User1 SP authority to enabled and sets the User1 password. + + @param[in] LockingSpSession OPAL_SESSION to populate command for, needs comId + @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 + +**/ +TCG_RESULT +EFIAPI +OpalUtilSetUserPassword( + OPAL_SESSION *LockingSpSession, + const VOID *OldPassword, + UINT32 OldPasswordLength, + const VOID *NewPassword, + UINT32 NewPasswordLength + ); + +/** + Verify whether user input the correct password. + + @param[in] LockingSpSession OPAL_SESSION to populate command for, needs comId + @param[in] Password Admin password + @param[in] PasswordLength Length of password in bytes + @param[in/out] HostSigningAuthority Use the Host signing authority type. + +**/ +TCG_RESULT +EFIAPI +OpalUtilVerifyPassword ( + OPAL_SESSION *LockingSpSession, + const VOID *Password, + UINT32 PasswordLength, + TCG_UID HostSigningAuthority + ); + +/** + Starts a session with OPAL_UID_LOCKING_SP as OPAL_LOCKING_SP_USER1_AUTHORITY or OPAL_LOCKING_SP_ADMIN1_AUTHORITY + and generates a new global locking range key to erase the Data. + + @param[in] LockingSpSession OPAL_SESSION to populate command for, needs comId + @param[in] Password Admin or user password + @param[in] PasswordLength Length of password in bytes + @param[in/out] PasswordFailed indicates if password failed (start session didn't work) + +**/ +TCG_RESULT +EFIAPI +OpalUtilSecureErase( + OPAL_SESSION *LockingSpSession, + const VOID *Password, + UINT32 PasswordLength, + BOOLEAN *PasswordFailed + ); + +/** + Starts a session with OPAL_UID_LOCKING_SP as OPAL_LOCKING_SP_ADMIN1_AUTHORITY and disables the User1 authority. + + @param[in] LockingSpSession OPAL_SESSION to populate command for, needs comId + @param[in] Password Admin password + @param[in] PasswordLength Length of password in bytes + @param[in/out] PasswordFailed indicates if password failed (start session didn't work) + +**/ +TCG_RESULT +EFIAPI +OpalUtilDisableUser( + OPAL_SESSION *LockingSpSession, + const VOID *Password, + UINT32 PasswordLength, + BOOLEAN *PasswordFailed + ); + +/** + Opens a session with OPAL_UID_ADMIN_SP as OPAL_ADMIN_SP_PSID_AUTHORITY, then reverts the device using the RevertSP method. + + @param[in] LockingSpSession OPAL_SESSION to populate command for, needs comId + @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/out] PasswordFailed indicates if password failed (start session didn't work) + @param[in] Msid Input Msid info. + @param[in] MsidLength Input Msid info length. + +**/ +TCG_RESULT +EFIAPI +OpalUtilRevert( + OPAL_SESSION *LockingSpSession, + BOOLEAN KeepUserData, + const VOID *Password, + UINT32 PasswordLength, + BOOLEAN *PasswordFailed, + UINT8 *Msid, + UINT32 MsidLength + ); + +/** + After revert success, set SID to MSID. + + @param[in] AdminSpSession OPAL_SESSION to populate command for, needs comId + @param Password, Input password info. + @param PasswordLength, Input password length. + @param[in] Msid Input Msid info. + @param[in] MsidLength Input Msid info length. + +**/ +TCG_RESULT +EFIAPI +OpalUtilSetSIDtoMSID ( + OPAL_SESSION *AdminSpSession, + const VOID *Password, + UINT32 PasswordLength, + UINT8 *Msid, + UINT32 MsidLength + ); + +/** + Update global locking range. + + @param[in] LockingSpSession OPAL_SESSION to populate command for, needs comId + @param Password, Input password info. + @param PasswordLength, Input password length. + @param ReadLocked, Read lock info. + @param WriteLocked write lock info. + +**/ +TCG_RESULT +EFIAPI +OpalUtilUpdateGlobalLockingRange( + OPAL_SESSION *LockingSpSession, + const VOID *Password, + UINT32 PasswordLength, + BOOLEAN ReadLocked, + BOOLEAN WriteLocked + ); + +/** + Update global locking range. + + @param Session, The session info for one opal device. + @param Msid, The data buffer to save Msid info. + @param MsidBufferLength, The data buffer length for Msid. + @param MsidLength, The actual data length for Msid. + +**/ +TCG_RESULT +EFIAPI +OpalUtilGetMsid( + OPAL_SESSION *Session, + UINT8 *Msid, + UINT32 MsidBufferLength, + UINT32 *MsidLength + ); + +/** + + The function determines who owns the device by attempting to start a session with different credentials. + If the SID PIN matches the MSID PIN, the no one owns the device. + If the SID PIN matches the ourSidPin, then "Us" owns the device. Otherwise it is unknown. + + + @param[in] Session The session info for one opal device. + @param Msid, The Msid info. + @param MsidLength, The data length for Msid. + +**/ +OPAL_OWNER_SHIP +EFIAPI +OpalUtilDetermineOwnership( + OPAL_SESSION *Session, + UINT8 *Msid, + UINT32 MsidLength + ); + +/** + + The function returns if admin password exists. + + @param[in] OwnerShip The owner ship of the opal device. + @param[in] LockingFeature The locking info of the opal device. + + @retval TRUE Admin password existed. + @retval FALSE Admin password not existed. + +**/ +BOOLEAN +EFIAPI +OpalUtilAdminPasswordExists( + IN UINT16 OwnerShip, + IN TCG_LOCKING_FEATURE_DESCRIPTOR *LockingFeature + ); + +#endif // _OPAL_CORE_H_ diff --git a/SecurityPkg/Library/TcgStorageOpalLib/TcgStorageOpalCore.c b/SecurityPkg/Library/TcgStorageOpalLib/TcgStorageOpalCore.c new file mode 100644 index 0000000000..234909b13b --- /dev/null +++ b/SecurityPkg/Library/TcgStorageOpalLib/TcgStorageOpalCore.c @@ -0,0 +1,1653 @@ +/** @file + Public API for Opal Core 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 +#include +#include +#include +#include +#include + +#pragma pack(1) +typedef struct { + UINT8 HardwareReset : 1; + UINT8 Reserved : 7; +} TCG_BLOCK_SID_CLEAR_EVENTS; +#pragma pack() + +#define TRUSTED_COMMAND_TIMEOUT_NS ((UINT64) 5 * ((UINT64)(1000000)) * 1000) // 5 seconds +#define BUFFER_SIZE 512 + +/** + The function performs a Trusted Send of a Buffer containing a TCG_COM_PACKET. + + @param[in] Sscp The input Ssc Protocol. + @param[in] MediaId The input Media id info used by Ssc Protocol. + @param[in] SecurityProtocol Security Protocol + @param[in] SpSpecific Security Protocol Specific + @param[in] TransferLength Transfer Length of Buffer (in bytes) - always a multiple of 512 + @param[in] Buffer Address of Data to transfer + @param[in] BufferSize Full Size of Buffer, including space that may be used for padding. + +**/ +TCG_RESULT +OpalTrustedSend( + EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *Sscp, + UINT32 MediaId, + UINT8 SecurityProtocol, + UINT16 SpSpecific, + UINTN TransferLength, + VOID *Buffer, + UINTN BufferSize + ) +{ + UINTN TransferLength512; + EFI_STATUS Status; + + // + // Round transferLength up to a 512-byte multiple + // + TransferLength512 = (TransferLength + 511) & ~(UINTN)511; + + if (TransferLength512 > BufferSize) { + return TcgResultFailureBufferTooSmall; + } + + ZeroMem((UINT8*)Buffer + TransferLength, TransferLength512 - TransferLength); + + Status = Sscp->SendData( + Sscp, + MediaId, + TRUSTED_COMMAND_TIMEOUT_NS, + SecurityProtocol, + SwapBytes16(SpSpecific), + TransferLength512, + Buffer + ); + + return Status == EFI_SUCCESS ? TcgResultSuccess : TcgResultFailure; +} + +/** + + The function performs a Trusted Receive of a Buffer containing a TCG_COM_PACKET. + + @param[in] Sscp The input Ssc Protocol. + @param[in] MediaId The input Media id info used by Ssc Protocol. + @param[in] SecurityProtocol Security Protocol + @param[in] SpSpecific Security Protocol Specific + @param[in] Buffer Address of Data to transfer + @param[in] BufferSize Full Size of Buffer, including space that may be used for padding. + +**/ +TCG_RESULT +OpalTrustedRecv( + EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *Sscp, + UINT32 MediaId, + UINT8 SecurityProtocol, + UINT16 SpSpecific, + VOID *Buffer, + UINTN BufferSize + ) +{ + + UINTN TransferLength512; + UINT32 Tries; + TCG_COM_PACKET *ComPacket; + UINT32 Length; + UINT32 OutstandingData; + EFI_STATUS Status; + UINTN TransferSize; + + // + // Round Buffer Size down to a 512-byte multiple + // + TransferLength512 = BufferSize & ~(UINTN)511; + Tries = 0; + ComPacket = NULL; + Length = 0; + OutstandingData = 0; + + if (TransferLength512 < sizeof(TCG_COM_PACKET)) { + DEBUG ((DEBUG_INFO, "transferLength %u too small for ComPacket\n", TransferLength512)); + return TcgResultFailureBufferTooSmall; + } + + // + // Some devices respond with Length = 0 and OutstandingData = 1 to indicate that processing is not yet completed, + // so we need to retry the IF-RECV to get the actual Data. + // See TCG Core Spec v2 Table 45 IF-RECV ComPacket Field Values Summary + // This is an arbitrary number of retries, not from the spec. + // have a max timeout of 10 seconds, 5000 tries * 2ms = 10s + // + Tries = 5000; + while ((Tries--) > 0) { + ZeroMem( Buffer, BufferSize ); + TransferSize = 0; + + Status = Sscp->ReceiveData( + Sscp, + MediaId, + TRUSTED_COMMAND_TIMEOUT_NS, + SecurityProtocol, + SwapBytes16(SpSpecific), + TransferLength512, + Buffer, + &TransferSize + ); + + if (EFI_ERROR (Status)) { + return TcgResultFailure; + } + + if (SecurityProtocol != TCG_OPAL_SECURITY_PROTOCOL_1 && SecurityProtocol != TCG_OPAL_SECURITY_PROTOCOL_2) { + return TcgResultSuccess; + } + + if (SpSpecific == TCG_SP_SPECIFIC_PROTOCOL_LEVEL0_DISCOVERY) { + return TcgResultSuccess; + } + + ComPacket = (TCG_COM_PACKET*) Buffer; + Length = SwapBytes32(ComPacket->LengthBE); + OutstandingData = SwapBytes32( ComPacket->OutstandingDataBE ); + + if (Length != 0 && OutstandingData == 0) { + return TcgResultSuccess; + } + + // + // Delay for 2 ms + // + MicroSecondDelay (2000); + } + + return TcgResultFailure; +} + +/** + The function performs send, recv, check comIDs, check method status action. + + @param[in] Session OPAL_SESSION related to this method.. + @param[in] SendSize Transfer Length of Buffer (in bytes) - always a multiple of 512 + @param[in] Buffer Address of Data to transfer + @param[in] BufferSize Full Size of Buffer, including space that may be used for padding. + @param[in] ParseStruct Structure used to parse received TCG response. + @param[in] MethodStatus Method status of last action performed. If action succeeded, it should be TCG_METHOD_STATUS_CODE_SUCCESS. + +**/ +TCG_RESULT +EFIAPI +OpalPerformMethod( + OPAL_SESSION *Session, + UINT32 SendSize, + VOID *Buffer, + UINT32 BufferSize, + TCG_PARSE_STRUCT *ParseStruct, + UINT8 *MethodStatus + ) +{ + NULL_CHECK(Session); + NULL_CHECK(MethodStatus); + + ERROR_CHECK(OpalTrustedSend( + Session->Sscp, + Session->MediaId, + TCG_OPAL_SECURITY_PROTOCOL_1, + Session->OpalBaseComId, + SendSize, + Buffer, + BufferSize + )); + + ERROR_CHECK(OpalTrustedRecv( + Session->Sscp, + Session->MediaId, + TCG_OPAL_SECURITY_PROTOCOL_1, + Session->OpalBaseComId, + Buffer, + BufferSize + )); + + ERROR_CHECK(TcgInitTcgParseStruct(ParseStruct, Buffer, BufferSize)); + ERROR_CHECK(TcgCheckComIds(ParseStruct, Session->OpalBaseComId, Session->ComIdExtension)); + ERROR_CHECK(TcgGetMethodStatus(ParseStruct, MethodStatus)); + + return TcgResultSuccess; +} + +/** + Trig the block sid action. + + @param[in] Session OPAL_SESSION related to this method.. + @param[in] HardwareReset Whether need to do hardware reset. + +**/ +TCG_RESULT +EFIAPI +OpalBlockSid( + OPAL_SESSION *Session, + BOOLEAN HardwareReset + ) +{ + UINT8 Buffer[BUFFER_SIZE]; + TCG_BLOCK_SID_CLEAR_EVENTS *ClearEvents; + + NULL_CHECK(Session); + + // + // Set Hardware Reset bit + // + ClearEvents = (TCG_BLOCK_SID_CLEAR_EVENTS *) &Buffer[0]; + + ClearEvents->Reserved = 0; + ClearEvents->HardwareReset = HardwareReset; + + return(OpalTrustedSend( + Session->Sscp, + Session->MediaId, + TCG_OPAL_SECURITY_PROTOCOL_2, + Session->OpalBaseComId, + 1, + Buffer, + BUFFER_SIZE + )); +} + +/** + + Reverts device using Admin SP Revert method. + + @param[in] AdminSpSession OPAL_SESSION with OPAL_UID_ADMIN_SP as OPAL_ADMIN_SP_PSID_AUTHORITY to perform PSID revert. + +**/ +TCG_RESULT +EFIAPI +OpalPsidRevert( + OPAL_SESSION *AdminSpSession + ) +{ + // + // Now that base comid is known, start Session + // we'll attempt to start Session as PSID authority + // verify PSID Authority is defined in ADMIN SP authority table... is this possible? + // + TCG_CREATE_STRUCT CreateStruct; + TCG_PARSE_STRUCT ParseStruct; + UINT32 Size; + UINT8 Buffer[BUFFER_SIZE]; + UINT8 MethodStatus; + + NULL_CHECK(AdminSpSession); + + // + // Send Revert action on Admin SP + // + ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buffer, BUFFER_SIZE)); + ERROR_CHECK(TcgStartComPacket(&CreateStruct, AdminSpSession->OpalBaseComId, AdminSpSession->ComIdExtension)); + ERROR_CHECK(TcgStartPacket(&CreateStruct, AdminSpSession->TperSessionId, AdminSpSession->HostSessionId, 0x0, 0x0, 0x0)); + ERROR_CHECK(TcgStartSubPacket(&CreateStruct, 0x0)); + ERROR_CHECK(TcgStartMethodCall(&CreateStruct, OPAL_UID_ADMIN_SP, OPAL_ADMIN_SP_REVERT_METHOD)); + ERROR_CHECK(TcgStartParameters(&CreateStruct)); + ERROR_CHECK(TcgEndParameters(&CreateStruct)); + ERROR_CHECK(TcgEndMethodCall(&CreateStruct)); + ERROR_CHECK(TcgEndSubPacket(&CreateStruct)); + ERROR_CHECK(TcgEndPacket(&CreateStruct)); + ERROR_CHECK(TcgEndComPacket(&CreateStruct, &Size)); + + // + // Send Revert Method Call + // + ERROR_CHECK(OpalPerformMethod(AdminSpSession, Size, Buffer, BUFFER_SIZE, &ParseStruct, &MethodStatus)); + METHOD_STATUS_ERROR_CHECK(MethodStatus, TcgResultFailure); + + return TcgResultSuccess; +} + +/** + + The function fills in the provided Buffer with the level 0 discovery Header + of the device specified. + + @param[in] Session OPAL_SESSION data. + @param[in] BufferSize Size of Buffer provided (in bytes) + @param[in] BuffAddress Buffer address to fill with Level 0 Discovery response + +**/ +TCG_RESULT +EFIAPI +OpalRetrieveLevel0DiscoveryHeader( + OPAL_SESSION *Session, + UINTN BufferSize, + VOID *BuffAddress + ) +{ + return (OpalTrustedRecv( + Session->Sscp, + Session->MediaId, + TCG_OPAL_SECURITY_PROTOCOL_1, // SP + TCG_SP_SPECIFIC_PROTOCOL_LEVEL0_DISCOVERY, // SP_Specific + BuffAddress, + BufferSize + )); +} + +/** + + The function fills in the provided Buffer with the supported protocol list + of the device specified. + + @param[in] Session OPAL_SESSION data. + @param[in] BufferSize Size of Buffer provided (in bytes) + @param[in] BuffAddress Buffer address to fill with security protocol list + +**/ +TCG_RESULT +EFIAPI +OpalRetrieveSupportedProtocolList( + OPAL_SESSION *Session, + UINTN BufferSize, + VOID *BuffAddress + ) +{ + return (OpalTrustedRecv( + Session->Sscp, + Session->MediaId, + TCG_SECURITY_PROTOCOL_INFO, // SP + TCG_SP_SPECIFIC_PROTOCOL_LIST, // SP_Specific + BuffAddress, + BufferSize + )); +} + +/** + Starts a session with a security provider (SP). + + If a session is started successfully, the caller must end the session with OpalEndSession when finished + performing Opal actions. + + @param[in/out] Session OPAL_SESSION to initialize. + @param[in] SpId Security provider ID to start the session with. + @param[in] Write Whether the session should be read-only (FALSE) or read/write (TRUE). + @param[in] HostChallengeLength Length of the host challenge. Length should be 0 if hostChallenge is NULL + @param[in] HostChallenge Host challenge for Host Signing Authority. If NULL, then no Host Challenge will be sent. + @param[in] HostSigningAuthority Host Signing Authority used for start session. If NULL, then no Host Signing Authority will be sent. + @param[in/out] MethodStatus Status of the StartSession method; only valid if TcgResultSuccess is returned. + + @return TcgResultSuccess indicates that the function completed without any internal errors. + The caller must inspect the MethodStatus field to determine whether the method completed successfully. + +**/ +TCG_RESULT +EFIAPI +OpalStartSession( + OPAL_SESSION *Session, + TCG_UID SpId, + BOOLEAN Write, + UINT32 HostChallengeLength, + const VOID *HostChallenge, + TCG_UID HostSigningAuthority, + UINT8 *MethodStatus + ) +{ + TCG_CREATE_STRUCT CreateStruct; + TCG_PARSE_STRUCT ParseStruct; + UINT32 Size; + UINT8 Buf[BUFFER_SIZE]; + UINT16 ComIdExtension; + UINT32 HostSessionId; + + ComIdExtension = 0; + HostSessionId = 1; + + NULL_CHECK(Session); + NULL_CHECK(MethodStatus); + + Session->ComIdExtension = ComIdExtension; + Session->HostSessionId = HostSessionId; + + ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buf, sizeof(Buf))); + ERROR_CHECK(TcgCreateStartSession( + &CreateStruct, + &Size, + Session->OpalBaseComId, + ComIdExtension, + HostSessionId, + SpId, + Write, + HostChallengeLength, + HostChallenge, + HostSigningAuthority + )); + ERROR_CHECK(OpalPerformMethod(Session, Size, Buf, sizeof(Buf), &ParseStruct, MethodStatus)); + if (*MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { + return TcgResultSuccess; // return early if method failed - user must check MethodStatus + } + + if (TcgParseSyncSession(&ParseStruct, Session->OpalBaseComId, ComIdExtension, HostSessionId, &Session->TperSessionId) != TcgResultSuccess) { + OpalEndSession(Session); + return TcgResultFailure; + } + + return TcgResultSuccess; +} + +/** + Close a session opened with OpalStartSession. + + @param[in/out] Session OPAL_SESSION to end. + +**/ +TCG_RESULT +EFIAPI +OpalEndSession( + OPAL_SESSION *Session + ) +{ + UINT8 Buffer[BUFFER_SIZE]; + TCG_CREATE_STRUCT CreateStruct; + UINT32 Size; + TCG_PARSE_STRUCT ParseStruct; + + NULL_CHECK(Session); + ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buffer, sizeof(Buffer))); + ERROR_CHECK(TcgCreateEndSession( + &CreateStruct, + &Size, + Session->OpalBaseComId, + Session->ComIdExtension, + Session->HostSessionId, + Session->TperSessionId + )); + + ERROR_CHECK(OpalTrustedSend( + Session->Sscp, + Session->MediaId, + TCG_OPAL_SECURITY_PROTOCOL_1, + Session->OpalBaseComId, + Size, + Buffer, + sizeof(Buffer) + )); + + ERROR_CHECK(OpalTrustedRecv( + Session->Sscp, + Session->MediaId, + TCG_OPAL_SECURITY_PROTOCOL_1, + Session->OpalBaseComId, + Buffer, + sizeof(Buffer) + )); + + ERROR_CHECK(TcgInitTcgParseStruct(&ParseStruct, Buffer, sizeof(Buffer))); + ERROR_CHECK(TcgCheckComIds(&ParseStruct, Session->OpalBaseComId, Session->ComIdExtension)); + + ERROR_CHECK(TcgGetNextEndOfSession(&ParseStruct)); + return TcgResultSuccess; +} + +/** + + The function retrieves the MSID from the device specified + + @param[in] AdminSpSession OPAL_SESSION with OPAL_UID_ADMIN_SP as OPAL_ADMIN_SP_PSID_AUTHORITY to perform PSID revert. + @param[in] MsidBufferSize Allocated Buffer Size (in bytes) for MSID allocated by caller + @param[in] Msid Variable Length byte sequence representing MSID of device + @param[in] MsidLength Actual Length of MSID retrieved from device + +**/ +TCG_RESULT +EFIAPI +OpalGetMsid( + OPAL_SESSION *AdminSpSession, + UINT32 MsidBufferSize, + UINT8 *Msid, + UINT32 *MsidLength + ) +{ + // + // now that base comid is known, start Session + // we'll attempt to start Session as PSID authority + // verify PSID Authority is defined in ADMIN SP authority table... is this possible? + // + TCG_CREATE_STRUCT CreateStruct; + TCG_PARSE_STRUCT ParseStruct; + UINT32 Size; + UINT8 MethodStatus; + UINT32 Col; + const VOID *RecvMsid; + UINT8 Buffer[BUFFER_SIZE]; + + NULL_CHECK(AdminSpSession); + NULL_CHECK(Msid); + NULL_CHECK(MsidLength); + + ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buffer, BUFFER_SIZE)); + ERROR_CHECK(TcgStartComPacket(&CreateStruct, AdminSpSession->OpalBaseComId, AdminSpSession->ComIdExtension)); + ERROR_CHECK(TcgStartPacket(&CreateStruct, AdminSpSession->TperSessionId, AdminSpSession->HostSessionId, 0x0, 0x0, 0x0)); + ERROR_CHECK(TcgStartSubPacket(&CreateStruct, 0x0)); + ERROR_CHECK(TcgStartMethodCall(&CreateStruct, OPAL_UID_ADMIN_SP_C_PIN_MSID, TCG_UID_METHOD_GET)); + ERROR_CHECK(TcgStartParameters(&CreateStruct)); + ERROR_CHECK(TcgAddStartList(&CreateStruct)); + ERROR_CHECK(TcgAddStartName(&CreateStruct)); + ERROR_CHECK(TcgAddUINT8(&CreateStruct, TCG_CELL_BLOCK_START_COLUMN_NAME)); + ERROR_CHECK(TcgAddUINT8(&CreateStruct, OPAL_ADMIN_SP_PIN_COL)); + ERROR_CHECK(TcgAddEndName(&CreateStruct)); + ERROR_CHECK(TcgAddStartName(&CreateStruct)); + ERROR_CHECK(TcgAddUINT8(&CreateStruct, TCG_CELL_BLOCK_END_COLUMN_NAME)); + ERROR_CHECK(TcgAddUINT8(&CreateStruct, OPAL_ADMIN_SP_PIN_COL)); + ERROR_CHECK(TcgAddEndName(&CreateStruct)); + ERROR_CHECK(TcgAddEndList(&CreateStruct)); + ERROR_CHECK(TcgEndParameters(&CreateStruct)); + ERROR_CHECK(TcgEndMethodCall(&CreateStruct)); + ERROR_CHECK(TcgEndSubPacket(&CreateStruct)); + ERROR_CHECK(TcgEndPacket(&CreateStruct)); + ERROR_CHECK(TcgEndComPacket(&CreateStruct, &Size)); + + // + // Send MSID Method Call + // + ERROR_CHECK(OpalPerformMethod(AdminSpSession, Size, Buffer, BUFFER_SIZE, &ParseStruct, &MethodStatus)); + METHOD_STATUS_ERROR_CHECK(MethodStatus, TcgResultFailure); + + ERROR_CHECK(TcgGetNextStartList(&ParseStruct)); + ERROR_CHECK(TcgGetNextStartList(&ParseStruct)); + ERROR_CHECK(TcgGetNextStartName(&ParseStruct)); + ERROR_CHECK(TcgGetNextUINT32(&ParseStruct, &Col)); + ERROR_CHECK(TcgGetNextByteSequence(&ParseStruct, &RecvMsid, MsidLength)); + ERROR_CHECK(TcgGetNextEndName(&ParseStruct)); + ERROR_CHECK(TcgGetNextEndList(&ParseStruct)); + ERROR_CHECK(TcgGetNextEndList(&ParseStruct)); + ERROR_CHECK(TcgGetNextEndOfData(&ParseStruct)); + + if (Col != OPAL_ADMIN_SP_PIN_COL) { + DEBUG ((DEBUG_INFO, "ERROR: got col %u, expected %u\n", Col, OPAL_ADMIN_SP_PIN_COL)); + return TcgResultFailure; + } + + if (RecvMsid == NULL) { + return TcgResultFailure; + } + + if (MsidBufferSize < *MsidLength) { + DEBUG ((DEBUG_INFO, "Buffer too small MsidBufferSize: %d MsidLength: %d\n", MsidBufferSize, *MsidLength)); + return TcgResultFailureBufferTooSmall; + } + + // + // copy msid into Buffer + // + CopyMem(Msid, RecvMsid, *MsidLength); + return TcgResultSuccess; +} + +/** + + The function calls the Admin SP RevertSP method on the Locking SP. If KeepUserData is True, then the optional parameter + to keep the user Data is set to True, otherwise the optional parameter is not provided. + + @param[in] LockingSpSession OPAL_SESSION with OPAL_UID_LOCKING_SP as OPAL_LOCKING_SP_ADMIN1_AUTHORITY to revertSP + @param[in] KeepUserData Specifies whether or not to keep user Data when performing RevertSP action. True = keeps user Data. + @param[in/out] MethodStatus Method status of last action performed. If action succeeded, it should be TCG_METHOD_STATUS_CODE_SUCCESS. + +**/ +TCG_RESULT +EFIAPI +OpalAdminRevert( + OPAL_SESSION *LockingSpSession, + BOOLEAN KeepUserData, + UINT8 *MethodStatus + ) +{ + UINT8 Buf[BUFFER_SIZE]; + TCG_CREATE_STRUCT CreateStruct; + UINT32 Size; + TCG_PARSE_STRUCT ParseStruct; + TCG_RESULT Ret; + + NULL_CHECK(LockingSpSession); + NULL_CHECK(MethodStatus); + + // + // ReadLocked or WriteLocked must be False (per Opal spec) to guarantee revertSP can keep user Data + // + if (KeepUserData) { + // + // set readlocked and writelocked to false + // + Ret = OpalUpdateGlobalLockingRange( + LockingSpSession, + FALSE, + FALSE, + MethodStatus); + + if (Ret != TcgResultSuccess || *MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { + // + // bail out + // + return Ret; + } + } + + ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buf, sizeof(Buf))); + ERROR_CHECK(TcgStartComPacket(&CreateStruct, LockingSpSession->OpalBaseComId, LockingSpSession->ComIdExtension)); + ERROR_CHECK(TcgStartPacket(&CreateStruct, LockingSpSession->TperSessionId, LockingSpSession->HostSessionId, 0x0, 0x0, 0x0)); + ERROR_CHECK(TcgStartSubPacket(&CreateStruct, 0x0)); + ERROR_CHECK(TcgStartMethodCall(&CreateStruct, TCG_UID_THIS_SP, OPAL_LOCKING_SP_REVERTSP_METHOD)); + ERROR_CHECK(TcgStartParameters(&CreateStruct)); + + if (KeepUserData) { + // + // optional parameter to keep Data after revert + // + ERROR_CHECK(TcgAddStartName(&CreateStruct)); + ERROR_CHECK(TcgAddUINT32(&CreateStruct, 0x060000)); // weird Value but that's what spec says + ERROR_CHECK(TcgAddBOOLEAN(&CreateStruct, KeepUserData)); + ERROR_CHECK(TcgAddEndName(&CreateStruct)); + } + + ERROR_CHECK(TcgEndParameters(&CreateStruct)); + ERROR_CHECK(TcgEndMethodCall(&CreateStruct)); + ERROR_CHECK(TcgEndSubPacket(&CreateStruct)); + ERROR_CHECK(TcgEndPacket(&CreateStruct)); + ERROR_CHECK(TcgEndComPacket(&CreateStruct, &Size)); + + // + // Send RevertSP method call + // + ERROR_CHECK(OpalPerformMethod(LockingSpSession, Size, Buf, sizeof(Buf), &ParseStruct, MethodStatus)); + + // + // Session is immediately ended by device after successful revertsp, so no need to end Session + // + if (*MethodStatus == TCG_METHOD_STATUS_CODE_SUCCESS) { + // + // Caller should take ownership again + // + return TcgResultSuccess; + } else { + // + // End Session + // + METHOD_STATUS_ERROR_CHECK(*MethodStatus, TcgResultSuccess); // exit with success on method failure - user must inspect MethodStatus + } + + return TcgResultSuccess; +} + +/** + + The function activates the Locking SP. + Once activated, per Opal spec, the ADMIN SP SID PIN is copied over to the ADMIN1 LOCKING SP PIN. + If the Locking SP is already enabled, then TcgResultSuccess is returned and no action occurs. + + @param[in] AdminSpSession OPAL_SESSION with OPAL_UID_ADMIN_SP as OPAL_ADMIN_SP_SID_AUTHORITY to activate Locking SP + @param[in/out] MethodStatus Method status of last action performed. If action succeeded, it should be TCG_METHOD_STATUS_CODE_SUCCESS. + +**/ +TCG_RESULT +EFIAPI +OpalActivateLockingSp( + OPAL_SESSION *AdminSpSession, + UINT8 *MethodStatus + ) +{ + UINT8 Buf[BUFFER_SIZE]; + TCG_CREATE_STRUCT CreateStruct; + UINT32 Size; + TCG_PARSE_STRUCT ParseStruct; + + NULL_CHECK(AdminSpSession); + NULL_CHECK(MethodStatus); + + // + // Call Activate method on Locking SP + // + ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buf, sizeof(Buf))); + ERROR_CHECK(TcgStartComPacket(&CreateStruct, AdminSpSession->OpalBaseComId, AdminSpSession->ComIdExtension)); + ERROR_CHECK(TcgStartPacket(&CreateStruct, AdminSpSession->TperSessionId, AdminSpSession->HostSessionId, 0x0, 0x0, 0x0)); + ERROR_CHECK(TcgStartSubPacket(&CreateStruct, 0x0)); + ERROR_CHECK(TcgStartMethodCall(&CreateStruct, OPAL_UID_LOCKING_SP, OPAL_ADMIN_SP_ACTIVATE_METHOD)); + ERROR_CHECK(TcgStartParameters(&CreateStruct)); + ERROR_CHECK(TcgEndParameters(&CreateStruct)); + ERROR_CHECK(TcgEndMethodCall(&CreateStruct)); + ERROR_CHECK(TcgEndSubPacket(&CreateStruct)); + ERROR_CHECK(TcgEndPacket(&CreateStruct)); + ERROR_CHECK(TcgEndComPacket(&CreateStruct, &Size)); + + // + // Send Activate method call + // + ERROR_CHECK(OpalPerformMethod(AdminSpSession, Size, Buf, sizeof(Buf), &ParseStruct, MethodStatus)); + METHOD_STATUS_ERROR_CHECK(*MethodStatus, TcgResultSuccess); // exit with success on method failure - user must inspect MethodStatus + + return TcgResultSuccess; +} + +/** + + The function sets the PIN column of the specified cpinRowUid (authority) with the newPin Value. + + @param[in/out] Session OPAL_SESSION to set password + @param[in] CpinRowUid UID of row (authority) to update PIN column + @param[in] NewPin New Pin to set for cpinRowUid specified + @param[in] NewPinLength Length in bytes of newPin + @param[in/out] MethodStatus Method status of last action performed. If action succeeded, it should be TCG_METHOD_STATUS_CODE_SUCCESS. + +**/ +TCG_RESULT +EFIAPI +OpalSetPassword( + OPAL_SESSION *Session, + TCG_UID CpinRowUid, + const VOID *NewPin, + UINT32 NewPinLength, + UINT8 *MethodStatus + ) +{ + UINT8 Buf[BUFFER_SIZE]; + TCG_CREATE_STRUCT CreateStruct; + TCG_PARSE_STRUCT ParseStruct; + UINT32 Size; + + NULL_CHECK(Session); + NULL_CHECK(NewPin); + NULL_CHECK(MethodStatus); + + ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buf, sizeof(Buf))); + ERROR_CHECK(TcgCreateSetCPin( + &CreateStruct, + &Size, + Session->OpalBaseComId, + Session->ComIdExtension, + Session->TperSessionId, + Session->HostSessionId, + CpinRowUid, + NewPin, + NewPinLength + )); + + ERROR_CHECK(OpalPerformMethod(Session, Size, Buf, sizeof(Buf), &ParseStruct, MethodStatus)); + // exit with success on method failure - user must inspect MethodStatus + METHOD_STATUS_ERROR_CHECK(*MethodStatus, TcgResultSuccess); + + return TcgResultSuccess; +} + +/** + + The function sets the Enabled column to TRUE for the authorityUid provided and updates the PIN column for the cpinRowUid provided + using the newPin provided. AuthorityUid and cpinRowUid should describe the same authority. + + @param[in] LockingSpSession OPAL_SESSION with OPAL_UID_LOCKING_SP as OPAL_LOCKING_SP_ADMIN1_AUTHORITY to update + @param[in] CpinRowUid Row UID of C_PIN table of Locking SP to update PIN + @param[in] AuthorityUid UID of Locking SP authority to update Pin column with + @param[in] NewPin New Password used to set Pin column + @param[in] NewPinLength Length in bytes of new password + @param[in/out] MethodStatus Method status of last action performed. If action succeeded, it should be TCG_METHOD_STATUS_CODE_SUCCESS. + +**/ +TCG_RESULT +EFIAPI +OpalSetLockingSpAuthorityEnabledAndPin( + OPAL_SESSION *LockingSpSession, + TCG_UID CpinRowUid, + TCG_UID AuthorityUid, + const VOID *NewPin, + UINT32 NewPinLength, + UINT8 *MethodStatus + ) +{ + UINT8 Buf[BUFFER_SIZE]; + TCG_CREATE_STRUCT CreateStruct; + TCG_PARSE_STRUCT ParseStruct; + UINT32 Size; + TCG_UID ActiveKey; + + NULL_CHECK(LockingSpSession); + NULL_CHECK(NewPin); + NULL_CHECK(MethodStatus); + + ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buf, sizeof(Buf))); + ERROR_CHECK(TcgSetAuthorityEnabled( + &CreateStruct, + &Size, + LockingSpSession->OpalBaseComId, + LockingSpSession->ComIdExtension, + LockingSpSession->TperSessionId, + LockingSpSession->HostSessionId, + AuthorityUid, + TRUE)); + + ERROR_CHECK(OpalPerformMethod(LockingSpSession, Size, Buf, sizeof(Buf), &ParseStruct, MethodStatus)); + + if (*MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { + DEBUG ((DEBUG_INFO, "Send Set Authority error\n")); + return TcgResultFailure; + } + + ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buf, sizeof(Buf))); + + ERROR_CHECK(TcgCreateSetCPin( + &CreateStruct, + &Size, + LockingSpSession->OpalBaseComId, + LockingSpSession->ComIdExtension, + LockingSpSession->TperSessionId, + LockingSpSession->HostSessionId, + CpinRowUid, + NewPin, + NewPinLength)); + + ERROR_CHECK(OpalPerformMethod(LockingSpSession, Size, Buf, sizeof(Buf), &ParseStruct, MethodStatus)); + + // + // allow user1 to set global range to unlocked/locked by modifying ACE_Locking_GlobalRange_SetRdLocked/SetWrLocked + // + ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buf, sizeof(Buf))); + ERROR_CHECK(TcgCreateSetAce( + &CreateStruct, + &Size, + LockingSpSession->OpalBaseComId, + LockingSpSession->ComIdExtension, + LockingSpSession->TperSessionId, + LockingSpSession->HostSessionId, + OPAL_LOCKING_SP_ACE_LOCKING_GLOBALRANGE_SET_RDLOCKED, + OPAL_LOCKING_SP_USER1_AUTHORITY, + TCG_ACE_EXPRESSION_OR, + OPAL_LOCKING_SP_ADMINS_AUTHORITY + )); + + ERROR_CHECK(OpalPerformMethod(LockingSpSession, Size, Buf, sizeof(Buf), &ParseStruct, MethodStatus)); + + if (*MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { + DEBUG ((DEBUG_INFO, "Update ACE for RDLOCKED failed\n")); + return TcgResultFailure; + } + + ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buf, sizeof(Buf))); + ERROR_CHECK(TcgCreateSetAce( + &CreateStruct, + &Size, + LockingSpSession->OpalBaseComId, + LockingSpSession->ComIdExtension, + LockingSpSession->TperSessionId, + LockingSpSession->HostSessionId, + OPAL_LOCKING_SP_ACE_LOCKING_GLOBALRANGE_SET_WRLOCKED, + OPAL_LOCKING_SP_USER1_AUTHORITY, + TCG_ACE_EXPRESSION_OR, + OPAL_LOCKING_SP_ADMINS_AUTHORITY + )); + + ERROR_CHECK(OpalPerformMethod(LockingSpSession, Size, Buf, sizeof(Buf), &ParseStruct, MethodStatus)); + + if (*MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { + DEBUG ((DEBUG_INFO, "Update ACE for WRLOCKED failed\n")); + return TcgResultFailure; + } + + ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buf, sizeof(Buf))); + ERROR_CHECK(OpalCreateRetrieveGlobalLockingRangeActiveKey(LockingSpSession, &CreateStruct, &Size)); + ERROR_CHECK(OpalPerformMethod(LockingSpSession, Size, Buf, sizeof(Buf), &ParseStruct, MethodStatus)); + + ERROR_CHECK(OpalParseRetrieveGlobalLockingRangeActiveKey(&ParseStruct, &ActiveKey)); + + ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buf, sizeof(Buf))); + ERROR_CHECK(TcgCreateSetAce( + &CreateStruct, + &Size, + LockingSpSession->OpalBaseComId, + LockingSpSession->ComIdExtension, + LockingSpSession->TperSessionId, + LockingSpSession->HostSessionId, + (ActiveKey == OPAL_LOCKING_SP_K_AES_256_GLOBALRANGE_KEY) ? OPAL_LOCKING_SP_ACE_K_AES_256_GLOBALRANGE_GENKEY : OPAL_LOCKING_SP_ACE_K_AES_128_GLOBALRANGE_GENKEY, + OPAL_LOCKING_SP_USER1_AUTHORITY, + TCG_ACE_EXPRESSION_OR, + OPAL_LOCKING_SP_ADMINS_AUTHORITY + )); + + ERROR_CHECK(OpalPerformMethod(LockingSpSession, Size, Buf, sizeof(Buf), &ParseStruct, MethodStatus)); + + if (*MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { + DEBUG ((DEBUG_INFO, "Update ACE for GLOBALRANGE_GENKEY failed\n")); + // + //TODO do we want to disable user1 if all permissions are not granted + // + return TcgResultFailure; + } + + ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buf, sizeof(Buf))); + ERROR_CHECK(TcgCreateSetAce( + &CreateStruct, + &Size, + LockingSpSession->OpalBaseComId, + LockingSpSession->ComIdExtension, + LockingSpSession->TperSessionId, + LockingSpSession->HostSessionId, + OPAL_LOCKING_SP_ACE_LOCKING_GLOBALRANGE_GET_ALL, + OPAL_LOCKING_SP_USER1_AUTHORITY, + TCG_ACE_EXPRESSION_OR, + OPAL_LOCKING_SP_ADMINS_AUTHORITY + )); + + ERROR_CHECK(OpalPerformMethod(LockingSpSession, Size, Buf, sizeof(Buf), &ParseStruct, MethodStatus)); + + if (*MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { + DEBUG ((DEBUG_INFO, "Update ACE for OPAL_LOCKING_SP_ACE_LOCKING_GLOBALRANGE_GET_ALL failed\n")); + return TcgResultFailure; + } + + return TcgResultSuccess; +} + +/** + + The function sets the Enabled column to FALSE for the USER1 authority. + + @param[in] LockingSpSession OPAL_SESSION with OPAL_UID_LOCKING_SP as OPAL_LOCKING_SP_ADMIN1_AUTHORITY to disable User1 + @param[in/out] MethodStatus Method status of last action performed. If action succeeded, it should be TCG_METHOD_STATUS_CODE_SUCCESS. + +**/ +TCG_RESULT +EFIAPI +OpalDisableUser( + OPAL_SESSION *LockingSpSession, + UINT8 *MethodStatus + ) +{ + UINT8 Buf[BUFFER_SIZE]; + TCG_CREATE_STRUCT CreateStruct; + TCG_PARSE_STRUCT ParseStruct; + UINT32 Size; + + NULL_CHECK(LockingSpSession); + NULL_CHECK(MethodStatus); + + ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buf, sizeof(Buf))); + ERROR_CHECK(TcgSetAuthorityEnabled( + &CreateStruct, + &Size, + LockingSpSession->OpalBaseComId, + LockingSpSession->ComIdExtension, + LockingSpSession->TperSessionId, + LockingSpSession->HostSessionId, + OPAL_LOCKING_SP_USER1_AUTHORITY, + FALSE)); + + ERROR_CHECK(OpalPerformMethod(LockingSpSession, Size, Buf, sizeof(Buf), &ParseStruct, MethodStatus)); + + return TcgResultSuccess; +} + +/** + + The function retrieves the active key of the global locking range + and calls the GenKey method on the active key retrieved. + + @param[in] LockingSpSession OPAL_SESSION with OPAL_UID_LOCKING_SP to generate key + @param[in/out] MethodStatus Method status of last action performed. If action succeeded, it should be TCG_METHOD_STATUS_CODE_SUCCESS. + +**/ +TCG_RESULT +EFIAPI +OpalGlobalLockingRangeGenKey( + OPAL_SESSION *LockingSpSession, + UINT8 *MethodStatus + ) +{ + UINT8 Buf[BUFFER_SIZE]; + TCG_CREATE_STRUCT CreateStruct; + TCG_PARSE_STRUCT ParseStruct; + UINT32 Size; + TCG_UID ActiveKey; + + NULL_CHECK(LockingSpSession); + NULL_CHECK(MethodStatus); + + ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buf, sizeof(Buf))); + // + // retrieve the activekey in order to know which globalrange key to generate + // + ERROR_CHECK(OpalCreateRetrieveGlobalLockingRangeActiveKey(LockingSpSession, &CreateStruct, &Size)); + ERROR_CHECK(OpalPerformMethod(LockingSpSession, Size, Buf, sizeof(Buf), &ParseStruct, MethodStatus)); + + METHOD_STATUS_ERROR_CHECK(*MethodStatus, TcgResultSuccess); + + ERROR_CHECK(OpalParseRetrieveGlobalLockingRangeActiveKey(&ParseStruct, &ActiveKey)); + + // + // call genkey on ActiveKey UID + // + ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buf, sizeof(Buf))); + ERROR_CHECK(TcgStartComPacket(&CreateStruct, LockingSpSession->OpalBaseComId, LockingSpSession->ComIdExtension)); + ERROR_CHECK(TcgStartPacket(&CreateStruct, LockingSpSession->TperSessionId, LockingSpSession->HostSessionId, 0x0, 0x0, 0x0)); + ERROR_CHECK(TcgStartSubPacket(&CreateStruct, 0x0)); + ERROR_CHECK(TcgStartMethodCall(&CreateStruct, ActiveKey, TCG_UID_METHOD_GEN_KEY)); + ERROR_CHECK(TcgStartParameters(&CreateStruct)); + ERROR_CHECK(TcgEndParameters(&CreateStruct)); + ERROR_CHECK(TcgEndMethodCall(&CreateStruct)); + ERROR_CHECK(TcgEndSubPacket(&CreateStruct)); + ERROR_CHECK(TcgEndPacket(&CreateStruct)); + ERROR_CHECK(TcgEndComPacket(&CreateStruct, &Size)); + + ERROR_CHECK(OpalPerformMethod(LockingSpSession, Size, Buf, sizeof(Buf), &ParseStruct, MethodStatus)); + + return TcgResultSuccess; +} + +/** + + The function updates the ReadLocked and WriteLocked columns of the Global Locking Range. + This funciton is required for a user1 authority, since a user1 authority shall only have access to ReadLocked and WriteLocked columns + (not ReadLockEnabled and WriteLockEnabled columns). + + @param[in] LockingSpSession OPAL_SESSION with OPAL_UID_LOCKING_SP to generate key + @param[in] ReadLocked Value to set ReadLocked column for Global Locking Range + @param[in] WriteLocked Value to set WriteLocked column for Global Locking Range + @param[in/out] MethodStatus Method status of last action performed. If action succeeded, it should be TCG_METHOD_STATUS_CODE_SUCCESS. + +**/ +TCG_RESULT +EFIAPI +OpalUpdateGlobalLockingRange( + OPAL_SESSION *LockingSpSession, + BOOLEAN ReadLocked, + BOOLEAN WriteLocked, + UINT8 *MethodStatus + ) +{ + UINT8 Buf[BUFFER_SIZE]; + TCG_CREATE_STRUCT CreateStruct; + TCG_PARSE_STRUCT ParseStruct; + UINT32 Size; + + NULL_CHECK(LockingSpSession); + NULL_CHECK(MethodStatus); + + ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buf, sizeof(Buf))); + + // + // set global locking range values + // + ERROR_CHECK(TcgStartComPacket(&CreateStruct, LockingSpSession->OpalBaseComId, LockingSpSession->ComIdExtension)); + ERROR_CHECK(TcgStartPacket(&CreateStruct, LockingSpSession->TperSessionId, LockingSpSession->HostSessionId, 0x0, 0x0, 0x0)); + ERROR_CHECK(TcgStartSubPacket(&CreateStruct, 0x0)); + ERROR_CHECK(TcgStartMethodCall(&CreateStruct, OPAL_LOCKING_SP_LOCKING_GLOBALRANGE, TCG_UID_METHOD_SET)); + ERROR_CHECK(TcgStartParameters(&CreateStruct)); + ERROR_CHECK(TcgAddStartName(&CreateStruct)); + ERROR_CHECK(TcgAddUINT8(&CreateStruct, 0x01)); // "Values" + ERROR_CHECK(TcgAddStartList(&CreateStruct)); + + ERROR_CHECK(TcgAddStartName(&CreateStruct)); + ERROR_CHECK(TcgAddUINT8(&CreateStruct, 0x07)); // "ReadLocked" + ERROR_CHECK(TcgAddBOOLEAN(&CreateStruct, ReadLocked)); + ERROR_CHECK(TcgAddEndName(&CreateStruct)); + + ERROR_CHECK(TcgAddStartName(&CreateStruct)); + ERROR_CHECK(TcgAddUINT8(&CreateStruct, 0x08)); // "WriteLocked" + ERROR_CHECK(TcgAddBOOLEAN(&CreateStruct, WriteLocked)); + ERROR_CHECK(TcgAddEndName(&CreateStruct)); + + ERROR_CHECK(TcgAddEndList(&CreateStruct)); + ERROR_CHECK(TcgAddEndName(&CreateStruct)); + ERROR_CHECK(TcgEndParameters(&CreateStruct)); + ERROR_CHECK(TcgEndMethodCall(&CreateStruct)); + ERROR_CHECK(TcgEndSubPacket(&CreateStruct)); + ERROR_CHECK(TcgEndPacket(&CreateStruct)); + ERROR_CHECK(TcgEndComPacket(&CreateStruct, &Size)); + + ERROR_CHECK(OpalPerformMethod(LockingSpSession, Size, Buf, sizeof(Buf), &ParseStruct, MethodStatus)); + METHOD_STATUS_ERROR_CHECK(*MethodStatus, TcgResultSuccess); + + return TcgResultSuccess; +} + +/** + + The function updates the RangeStart, RangeLength, ReadLockedEnabled, WriteLockedEnabled, ReadLocked and WriteLocked columns + of the specified Locking Range. This function requires admin authority of a locking SP session. + + @param[in] LockingSpSession OPAL_SESSION with OPAL_UID_LOCKING_SP to generate key + @param[in] LockingRangeUid Locking range UID to set values + @param[in] RangeStart Value to set RangeStart column for Locking Range + @param[in] RangeLength Value to set RangeLength column for Locking Range + @param[in] ReadLockEnabled Value to set readLockEnabled column for Locking Range + @param[in] WriteLockEnabled Value to set writeLockEnabled column for Locking Range + @param[in] ReadLocked Value to set ReadLocked column for Locking Range + @param[in] WriteLocked Value to set WriteLocked column for Locking Range + @param[in/out] MethodStatus Method status of last action performed. If action succeeded, it should be TCG_METHOD_STATUS_CODE_SUCCESS. + +**/ +TCG_RESULT +EFIAPI +OpalSetLockingRange( + OPAL_SESSION *LockingSpSession, + TCG_UID LockingRangeUid, + UINT64 RangeStart, + UINT64 RangeLength, + BOOLEAN ReadLockEnabled, + BOOLEAN WriteLockEnabled, + BOOLEAN ReadLocked, + BOOLEAN WriteLocked, + UINT8 *MethodStatus + ) +{ + UINT8 Buf[BUFFER_SIZE]; + TCG_CREATE_STRUCT CreateStruct; + TCG_PARSE_STRUCT ParseStruct; + UINT32 Size; + + NULL_CHECK(LockingSpSession); + NULL_CHECK(MethodStatus); + + ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buf, sizeof(Buf))); + + // + // set locking range values + // + ERROR_CHECK(TcgStartComPacket(&CreateStruct, LockingSpSession->OpalBaseComId, LockingSpSession->ComIdExtension)); + ERROR_CHECK(TcgStartPacket(&CreateStruct, LockingSpSession->TperSessionId, LockingSpSession->HostSessionId, 0x0, 0x0, 0x0)); + ERROR_CHECK(TcgStartSubPacket(&CreateStruct, 0x0)); + ERROR_CHECK(TcgStartMethodCall(&CreateStruct, LockingRangeUid, TCG_UID_METHOD_SET)); + ERROR_CHECK(TcgStartParameters(&CreateStruct)); + ERROR_CHECK(TcgAddStartName(&CreateStruct)); + ERROR_CHECK(TcgAddUINT8(&CreateStruct, 0x01)); // "Values" + ERROR_CHECK(TcgAddStartList(&CreateStruct)); + + // + // range start and range Length only apply to non-global locking ranges + // + if (LockingRangeUid != OPAL_LOCKING_SP_LOCKING_GLOBALRANGE) { + ERROR_CHECK(TcgAddStartName(&CreateStruct)); + ERROR_CHECK(TcgAddUINT8(&CreateStruct, 0x03)); // "RangeStart" + ERROR_CHECK(TcgAddUINT64(&CreateStruct, RangeStart)); + ERROR_CHECK(TcgAddEndName(&CreateStruct)); + + ERROR_CHECK(TcgAddStartName(&CreateStruct)); + ERROR_CHECK(TcgAddUINT8(&CreateStruct, 0x04)); // "RangeLength" + ERROR_CHECK(TcgAddUINT64(&CreateStruct, RangeLength)); + ERROR_CHECK(TcgAddEndName(&CreateStruct)); + } + + ERROR_CHECK(TcgAddStartName(&CreateStruct)); + ERROR_CHECK(TcgAddUINT8(&CreateStruct, 0x05)); // "ReadLockEnabled" + ERROR_CHECK(TcgAddBOOLEAN(&CreateStruct, ReadLockEnabled)); + ERROR_CHECK(TcgAddEndName(&CreateStruct)); + + ERROR_CHECK(TcgAddStartName(&CreateStruct)); + ERROR_CHECK(TcgAddUINT8(&CreateStruct, 0x06)); // "WriteLockEnabled" + ERROR_CHECK(TcgAddBOOLEAN(&CreateStruct, WriteLockEnabled)); + ERROR_CHECK(TcgAddEndName(&CreateStruct)); + + ERROR_CHECK(TcgAddStartName(&CreateStruct)); + ERROR_CHECK(TcgAddUINT8(&CreateStruct, 0x07)); // "ReadLocked" + ERROR_CHECK(TcgAddBOOLEAN(&CreateStruct, ReadLocked)); + ERROR_CHECK(TcgAddEndName(&CreateStruct)); + + ERROR_CHECK(TcgAddStartName(&CreateStruct)); + ERROR_CHECK(TcgAddUINT8(&CreateStruct, 0x08)); // "WriteLocked" + ERROR_CHECK(TcgAddBOOLEAN(&CreateStruct, WriteLocked)); + ERROR_CHECK(TcgAddEndName(&CreateStruct)); + + ERROR_CHECK(TcgAddEndList(&CreateStruct)); + ERROR_CHECK(TcgAddEndName(&CreateStruct)); + ERROR_CHECK(TcgEndParameters(&CreateStruct)); + ERROR_CHECK(TcgEndMethodCall(&CreateStruct)); + ERROR_CHECK(TcgEndSubPacket(&CreateStruct)); + ERROR_CHECK(TcgEndPacket(&CreateStruct)); + ERROR_CHECK(TcgEndComPacket(&CreateStruct, &Size)); + + ERROR_CHECK(OpalPerformMethod(LockingSpSession, Size, Buf, sizeof(Buf), &ParseStruct, MethodStatus)); + // Exit with success on method failure - user must inspect MethodStatus + METHOD_STATUS_ERROR_CHECK(*MethodStatus, TcgResultSuccess); + + return TcgResultSuccess; +} + +/** + + The function populates the CreateStruct with a payload that will retrieve the global locking range active key. + It is intended to be called with a session that is already started with a valid credential. + The function does not send the payload. + + @param[in] Session OPAL_SESSION to populate command for, needs ComId + @param[in/out] CreateStruct Structure to populate with encoded TCG command + @param[in/out] Size Size in bytes of the command created. + +**/ +TCG_RESULT +EFIAPI +OpalCreateRetrieveGlobalLockingRangeActiveKey( + const OPAL_SESSION *Session, + TCG_CREATE_STRUCT *CreateStruct, + UINT32 *Size + ) +{ + NULL_CHECK(Session); + NULL_CHECK(CreateStruct); + NULL_CHECK(Size); + + // Retrieve the activekey in order to know which globalrange key to generate + ERROR_CHECK(TcgStartComPacket(CreateStruct, Session->OpalBaseComId, Session->ComIdExtension)); + ERROR_CHECK(TcgStartPacket(CreateStruct, Session->TperSessionId, Session->HostSessionId, 0x0, 0x0, 0x0)); + ERROR_CHECK(TcgStartSubPacket(CreateStruct, 0x0)); + ERROR_CHECK(TcgStartMethodCall(CreateStruct, OPAL_LOCKING_SP_LOCKING_GLOBALRANGE, TCG_UID_METHOD_GET)); + ERROR_CHECK(TcgStartParameters(CreateStruct)); + ERROR_CHECK(TcgAddStartList(CreateStruct)); + ERROR_CHECK(TcgAddStartName(CreateStruct)); + ERROR_CHECK(TcgAddUINT8(CreateStruct, TCG_CELL_BLOCK_START_COLUMN_NAME)); + ERROR_CHECK(TcgAddUINT8(CreateStruct, 0x0A)); // ActiveKey + ERROR_CHECK(TcgAddEndName(CreateStruct)); + ERROR_CHECK(TcgAddStartName(CreateStruct)); + ERROR_CHECK(TcgAddUINT8(CreateStruct, TCG_CELL_BLOCK_END_COLUMN_NAME)); + ERROR_CHECK(TcgAddUINT8(CreateStruct, 0x0A)); + ERROR_CHECK(TcgAddEndName(CreateStruct)); + ERROR_CHECK(TcgAddEndList(CreateStruct)); + ERROR_CHECK(TcgEndParameters(CreateStruct)); + ERROR_CHECK(TcgEndMethodCall(CreateStruct)); + ERROR_CHECK(TcgEndSubPacket(CreateStruct)); + ERROR_CHECK(TcgEndPacket(CreateStruct)); + ERROR_CHECK(TcgEndComPacket(CreateStruct, Size)); + + return TcgResultSuccess; +} + +/** + + The function acquires the activeKey specified for the Global Locking Range from the ParseStruct. + + @param[in] ParseStruct Structure that contains the device's response with the activekey + @param[in/out] ActiveKey The UID of the active key retrieved + +**/ +TCG_RESULT +EFIAPI +OpalParseRetrieveGlobalLockingRangeActiveKey( + TCG_PARSE_STRUCT *ParseStruct, + TCG_UID *ActiveKey + ) +{ + UINT32 ColumnName; + + NULL_CHECK(ParseStruct); + NULL_CHECK(ActiveKey); + + // parse response + ERROR_CHECK(TcgGetNextStartList(ParseStruct)); + ERROR_CHECK(TcgGetNextStartList(ParseStruct)); + ERROR_CHECK(TcgGetNextStartName(ParseStruct)); + ERROR_CHECK(TcgGetNextUINT32(ParseStruct, &ColumnName)); + ERROR_CHECK(TcgGetNextTcgUid(ParseStruct, ActiveKey)); + ERROR_CHECK(TcgGetNextEndName(ParseStruct)); + ERROR_CHECK(TcgGetNextEndList(ParseStruct)); + ERROR_CHECK(TcgGetNextEndList(ParseStruct)); + ERROR_CHECK(TcgGetNextEndOfData(ParseStruct)); + + if (ColumnName != 0x0A) { + DEBUG ((DEBUG_INFO, "Unexpected column name %u (exp 0x0A)\n", ColumnName)); + return TcgResultFailure; + } + + if (*ActiveKey != OPAL_LOCKING_SP_K_AES_256_GLOBALRANGE_KEY && *ActiveKey != OPAL_LOCKING_SP_K_AES_128_GLOBALRANGE_KEY) { + DEBUG ((DEBUG_INFO, "Unexpected gen key %u (exp %u or %u)\n", *ActiveKey, OPAL_LOCKING_SP_K_AES_256_GLOBALRANGE_KEY, OPAL_LOCKING_SP_K_AES_128_GLOBALRANGE_KEY)); + return TcgResultFailure; + } + + return TcgResultSuccess; +} + +/** + + The function retrieves the TryLimit column for the specified rowUid (authority). + + @param[in] LockingSpSession OPAL_SESSION with OPAL_UID_LOCKING_SP to retrieve try limit + @param[in] RowUid Row UID of the Locking SP C_PIN table to retrieve TryLimit column + @param[in/out] TryLimit Value from TryLimit column + +**/ +TCG_RESULT +EFIAPI +OpalGetTryLimit( + OPAL_SESSION *LockingSpSession, + TCG_UID RowUid, + UINT32 *TryLimit + ) +{ + TCG_CREATE_STRUCT CreateStruct; + TCG_PARSE_STRUCT ParseStruct; + UINT32 Size; + UINT8 MethodStatus; + UINT8 Buf[BUFFER_SIZE]; + UINT32 Col; + + NULL_CHECK(LockingSpSession); + NULL_CHECK(TryLimit); + + ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buf, sizeof(Buf))); + ERROR_CHECK(TcgStartComPacket(&CreateStruct, LockingSpSession->OpalBaseComId, LockingSpSession->ComIdExtension)); + ERROR_CHECK(TcgStartPacket(&CreateStruct, LockingSpSession->TperSessionId, LockingSpSession->HostSessionId, 0x0, 0x0, 0x0)); + ERROR_CHECK(TcgStartSubPacket(&CreateStruct, 0x0)); + ERROR_CHECK(TcgStartMethodCall(&CreateStruct, RowUid, TCG_UID_METHOD_GET)); + ERROR_CHECK(TcgStartParameters(&CreateStruct)); + ERROR_CHECK(TcgAddStartList(&CreateStruct)); + ERROR_CHECK(TcgAddStartName(&CreateStruct)); + ERROR_CHECK(TcgAddUINT8(&CreateStruct, TCG_CELL_BLOCK_START_COLUMN_NAME)); + ERROR_CHECK(TcgAddUINT8(&CreateStruct, OPAL_LOCKING_SP_C_PIN_TRYLIMIT_COL)); + ERROR_CHECK(TcgAddEndName(&CreateStruct)); + ERROR_CHECK(TcgAddStartName(&CreateStruct)); + ERROR_CHECK(TcgAddUINT8(&CreateStruct, TCG_CELL_BLOCK_END_COLUMN_NAME)); + ERROR_CHECK(TcgAddUINT8(&CreateStruct, OPAL_LOCKING_SP_C_PIN_TRYLIMIT_COL)); + ERROR_CHECK(TcgAddEndName(&CreateStruct)); + ERROR_CHECK(TcgAddEndList(&CreateStruct)); + ERROR_CHECK(TcgEndParameters(&CreateStruct)); + ERROR_CHECK(TcgEndMethodCall(&CreateStruct)); + ERROR_CHECK(TcgEndSubPacket(&CreateStruct)); + ERROR_CHECK(TcgEndPacket(&CreateStruct)); + ERROR_CHECK(TcgEndComPacket(&CreateStruct, &Size)); + + ERROR_CHECK(OpalPerformMethod(LockingSpSession, Size, Buf, sizeof(Buf), &ParseStruct, &MethodStatus)); + METHOD_STATUS_ERROR_CHECK(MethodStatus, TcgResultFailure); + + ERROR_CHECK(TcgGetNextStartList(&ParseStruct)); + ERROR_CHECK(TcgGetNextStartList(&ParseStruct)); + ERROR_CHECK(TcgGetNextStartName(&ParseStruct)); + ERROR_CHECK(TcgGetNextUINT32(&ParseStruct, &Col)); + ERROR_CHECK(TcgGetNextUINT32(&ParseStruct, TryLimit)); + ERROR_CHECK(TcgGetNextEndName(&ParseStruct)); + ERROR_CHECK(TcgGetNextEndList(&ParseStruct)); + ERROR_CHECK(TcgGetNextEndList(&ParseStruct)); + ERROR_CHECK(TcgGetNextEndOfData(&ParseStruct)); + + if (Col != OPAL_LOCKING_SP_C_PIN_TRYLIMIT_COL) { + DEBUG ((DEBUG_INFO, "ERROR: got col %u, expected %u\n", Col, OPAL_LOCKING_SP_C_PIN_TRYLIMIT_COL)); + return TcgResultFailure; + } + + return TcgResultSuccess; +} + +/** + + Get the support attribute info. + + @param[in] Session OPAL_SESSION with OPAL_UID_LOCKING_SP to retrieve info. + @param[out] SupportedAttributes Return the support attribute info. + @param[out] OpalBaseComId Return the base com id info. + +**/ +TCG_RESULT +EFIAPI +OpalGetSupportedAttributesInfo( + IN OPAL_SESSION *Session, + OUT OPAL_DISK_SUPPORT_ATTRIBUTE *SupportedAttributes, + OUT UINT16 *OpalBaseComId + ) +{ + UINT8 Buffer[BUFFER_SIZE]; + TCG_SUPPORTED_SECURITY_PROTOCOLS *SupportedProtocols; + TCG_LEVEL0_DISCOVERY_HEADER *DiscoveryHeader; + OPAL_LEVEL0_FEATURE_DESCRIPTOR *Feat; + UINTN Size; + + NULL_CHECK(Session); + NULL_CHECK(SupportedAttributes); + NULL_CHECK(OpalBaseComId); + + ZeroMem(Buffer, BUFFER_SIZE); + ASSERT(sizeof(Buffer) >= sizeof(TCG_SUPPORTED_SECURITY_PROTOCOLS)); + + // + // Retrieve supported protocols verify security protocol 1 is supported + // + SupportedProtocols = (TCG_SUPPORTED_SECURITY_PROTOCOLS*) Buffer; + + // + // Get list of supported protocols + // + if (OpalRetrieveSupportedProtocolList (Session, sizeof(TCG_SUPPORTED_SECURITY_PROTOCOLS), SupportedProtocols) == TcgResultFailure) { + DEBUG ((DEBUG_INFO, "OpalRetrieveSupportedProtocolList failed\n")); + return TcgResultFailure; + } + + SupportedAttributes->Sp1 = TcgIsProtocolSupported (SupportedProtocols, TCG_OPAL_SECURITY_PROTOCOL_1); + SupportedAttributes->Sp2 = TcgIsProtocolSupported (SupportedProtocols, TCG_OPAL_SECURITY_PROTOCOL_2); + SupportedAttributes->SpIeee1667 = TcgIsProtocolSupported (SupportedProtocols, TCG_SECURITY_PROTOCOL_IEEE_1667); + + DEBUG ((DEBUG_INFO, "Supported Protocols: Sp1 %d Sp2: %d SpIeee1667 %d \n", + SupportedAttributes->Sp1, + SupportedAttributes->Sp2, + SupportedAttributes->SpIeee1667 + )); + + // + // Perform level 0 discovery and assign desired feature info to Opal Disk structure + // + ZeroMem (Buffer, BUFFER_SIZE); + if (OpalRetrieveLevel0DiscoveryHeader (Session, BUFFER_SIZE, Buffer) == TcgResultFailure) { + DEBUG ((DEBUG_INFO, "OpalRetrieveLevel0DiscoveryHeader failed\n")); + return TcgResultFailure; + } + + // + // Check for required feature descriptors + // + DiscoveryHeader = (TCG_LEVEL0_DISCOVERY_HEADER*) Buffer; + + Size = 0; + Feat = (OPAL_LEVEL0_FEATURE_DESCRIPTOR*) TcgGetFeature (DiscoveryHeader, TCG_FEATURE_OPAL_SSC_V2_0_0, &Size); + SupportedAttributes->OpalSsc2 = (Feat != NULL); + + *OpalBaseComId = TCG_RESERVED_COMID; + + // + // Check Opal SCC V2 has valid settings for SID C_PIN on revert + // + if (SupportedAttributes->OpalSsc2 && Size >= sizeof (OPAL_SSCV2_FEATURE_DESCRIPTOR)) { + // + // Want opposite polarity b/c Value is greater than a bit, but we only care about non-zero vs zero + // + SupportedAttributes->InitCpinIndicator = (Feat->OpalSscV2.InitialCPINSIDPIN == 0); + SupportedAttributes->CpinUponRevert = (Feat->OpalSscV2.CPINSIDPINRevertBehavior == 0); + DEBUG ((DEBUG_INFO, "Opal SSC V2 InitCpinIndicator %d CpinUponRevert %d \n", + SupportedAttributes->InitCpinIndicator, + SupportedAttributes->CpinUponRevert + )); + *OpalBaseComId = SwapBytes16 (Feat->OpalSscV2.BaseComdIdBE); + } + + Size = 0; + Feat = (OPAL_LEVEL0_FEATURE_DESCRIPTOR*) TcgGetFeature (DiscoveryHeader, TCG_FEATURE_OPAL_SSC_LITE, &Size); + SupportedAttributes->OpalSscLite = (Feat != NULL); + + if (Feat != NULL && Size >= sizeof (OPAL_SSCLITE_FEATURE_DESCRIPTOR)) { + if (*OpalBaseComId == TCG_RESERVED_COMID) { + // + // Pin values used always match up with ComId used + // + *OpalBaseComId = SwapBytes16 (Feat->OpalSscLite.BaseComdIdBE); + SupportedAttributes->InitCpinIndicator = (Feat->OpalSscV2.InitialCPINSIDPIN == 0); + SupportedAttributes->CpinUponRevert = (Feat->OpalSscV2.CPINSIDPINRevertBehavior == 0); + DEBUG ((DEBUG_INFO, "Opal SSC Lite InitCpinIndicator %d CpinUponRevert %d \n", + SupportedAttributes->InitCpinIndicator, + SupportedAttributes->CpinUponRevert + )); + } + } + + Size = 0; + Feat = (OPAL_LEVEL0_FEATURE_DESCRIPTOR*) TcgGetFeature (DiscoveryHeader, TCG_FEATURE_PYRITE_SSC, &Size); + SupportedAttributes->PyriteSsc = (Feat != NULL); + if (Feat != NULL && Size >= sizeof (PYRITE_SSC_FEATURE_DESCRIPTOR)) { + if (*OpalBaseComId == TCG_RESERVED_COMID) { + *OpalBaseComId = SwapBytes16 (Feat->PyriteSsc.BaseComdIdBE); + SupportedAttributes->InitCpinIndicator = (Feat->PyriteSsc.InitialCPINSIDPIN == 0); + SupportedAttributes->CpinUponRevert = (Feat->PyriteSsc.CPINSIDPINRevertBehavior == 0); + DEBUG ((DEBUG_INFO, "Pyrite SSC InitCpinIndicator %d CpinUponRevert %d \n", + SupportedAttributes->InitCpinIndicator, + SupportedAttributes->CpinUponRevert + )); + } + } + + Size = 0; + Feat = (OPAL_LEVEL0_FEATURE_DESCRIPTOR*) TcgGetFeature (DiscoveryHeader, TCG_FEATURE_OPAL_SSC_V1_0_0, &Size); + SupportedAttributes->OpalSsc1 = (Feat != NULL); + if (Feat != NULL && Size >= sizeof (OPAL_SSCV1_FEATURE_DESCRIPTOR)) { + if (*OpalBaseComId == TCG_RESERVED_COMID) { + *OpalBaseComId = SwapBytes16 (Feat->OpalSscV1.BaseComdIdBE); + } + } + + Size = 0; + Feat = (OPAL_LEVEL0_FEATURE_DESCRIPTOR*) TcgGetFeature (DiscoveryHeader, TCG_FEATURE_LOCKING, &Size); + if (Feat != NULL && Size >= sizeof (TCG_LOCKING_FEATURE_DESCRIPTOR)) { + SupportedAttributes->MediaEncryption = Feat->Locking.MediaEncryption; + } + + DEBUG ((DEBUG_INFO, "Base COMID 0x%04X \n", *OpalBaseComId)); + + + return TcgResultSuccess; +} + +/** + + Get the support attribute info. + + @param[in] Session OPAL_SESSION with OPAL_UID_LOCKING_SP to retrieve info. + @param[in/out] LockingFeature Return the Locking info. + +**/ +TCG_RESULT +EFIAPI +OpalGetLockingInfo( + OPAL_SESSION *Session, + TCG_LOCKING_FEATURE_DESCRIPTOR *LockingFeature + ) +{ + UINT8 Buffer[BUFFER_SIZE]; + TCG_LEVEL0_DISCOVERY_HEADER *DiscoveryHeader; + OPAL_LEVEL0_FEATURE_DESCRIPTOR *Feat; + UINTN Size; + + NULL_CHECK(Session); + NULL_CHECK(LockingFeature); + + ZeroMem(Buffer, BUFFER_SIZE); + ASSERT(sizeof(Buffer) >= sizeof(TCG_SUPPORTED_SECURITY_PROTOCOLS)); + + if (OpalRetrieveLevel0DiscoveryHeader (Session, BUFFER_SIZE, Buffer) == TcgResultFailure) { + DEBUG ((DEBUG_INFO, "OpalRetrieveLevel0DiscoveryHeader failed\n")); + return TcgResultFailure; + } + DiscoveryHeader = (TCG_LEVEL0_DISCOVERY_HEADER*) Buffer; + + Size = 0; + Feat = (OPAL_LEVEL0_FEATURE_DESCRIPTOR*) TcgGetFeature (DiscoveryHeader, TCG_FEATURE_LOCKING, &Size); + if (Feat != NULL && Size >= sizeof (TCG_LOCKING_FEATURE_DESCRIPTOR)) { + CopyMem (LockingFeature, &Feat->Locking, sizeof (TCG_LOCKING_FEATURE_DESCRIPTOR)); + } + + return TcgResultSuccess; +} + +/** + + The function determines whether or not all of the requirements for the Opal Feature (not full specification) + are met by the specified device. + + @param[in] SupportedAttributes Opal device attribute. + +**/ +BOOLEAN +EFIAPI +OpalFeatureSupported( + OPAL_DISK_SUPPORT_ATTRIBUTE *SupportedAttributes + ) +{ + NULL_CHECK(SupportedAttributes); + + if (SupportedAttributes->Sp1 == 0) { + return FALSE; + } + + if (SupportedAttributes->OpalSscLite == 0 && + SupportedAttributes->OpalSsc1 == 0 && + SupportedAttributes->OpalSsc2 == 0 && + SupportedAttributes->PyriteSsc == 0 + ) { + return FALSE; + } + + return TRUE; +} + +/** + + The function returns whether or not the device is Opal Enabled. + TRUE means that the device is partially or fully locked. + This will perform a Level 0 Discovery and parse the locking feature descriptor + + @param[in] SupportedAttributes Opal device attribute. + @param[in] LockingFeature Opal device locking status. + + +**/ +BOOLEAN +EFIAPI +OpalFeatureEnabled( + OPAL_DISK_SUPPORT_ATTRIBUTE *SupportedAttributes, + TCG_LOCKING_FEATURE_DESCRIPTOR *LockingFeature + ) +{ + NULL_CHECK(SupportedAttributes); + NULL_CHECK(LockingFeature); + + if (!OpalFeatureSupported (SupportedAttributes)) { + return FALSE; + } + + if (LockingFeature->LockingSupported && LockingFeature->LockingEnabled) { + return TRUE; + } + + return FALSE; +} + +/** + + The function returns whether or not the device is Opal Locked. + TRUE means that the device is partially or fully locked. + This will perform a Level 0 Discovery and parse the locking feature descriptor + + @param[in] SupportedAttributes Opal device attribute. + @param[in] LockingFeature Opal device locking status. + +**/ +BOOLEAN +OpalDeviceLocked( + OPAL_DISK_SUPPORT_ATTRIBUTE *SupportedAttributes, + TCG_LOCKING_FEATURE_DESCRIPTOR *LockingFeature + ) +{ + NULL_CHECK(SupportedAttributes); + NULL_CHECK(LockingFeature); + + if (!OpalFeatureEnabled (SupportedAttributes, LockingFeature)) { + return FALSE; + } + + return LockingFeature->Locked; +} + diff --git a/SecurityPkg/Library/TcgStorageOpalLib/TcgStorageOpalLib.inf b/SecurityPkg/Library/TcgStorageOpalLib/TcgStorageOpalLib.inf new file mode 100644 index 0000000000..b4589d94d4 --- /dev/null +++ b/SecurityPkg/Library/TcgStorageOpalLib/TcgStorageOpalLib.inf @@ -0,0 +1,50 @@ +## @file +# This is a Tcg storage Opal 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 = TcgStorageOpalLib + FILE_GUID = F8B56221-FD5D-4215-B578-C3574AD1E253 + VERSION_STRING = 1.0 + MODULE_TYPE = BASE + LIBRARY_CLASS = TcgStorageOpalLib|DXE_DRIVER DXE_CORE DXE_SMM_DRIVER + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + TcgStorageOpalCore.c + TcgStorageOpalUtil.c + +[LibraryClasses] + BaseLib + BaseMemoryLib + PrintLib + DebugLib + TimerLib + TcgStorageCoreLib + UefiLib + +[Packages] + MdePkg/MdePkg.dec + SecurityPkg/SecurityPkg.dec + +[Protocols] + gEfiStorageSecurityCommandProtocolGuid ## CONSUMES + +[BuildOptions] + MSFT:*_*_*_CC_FLAGS = /Od /GL- diff --git a/SecurityPkg/Library/TcgStorageOpalLib/TcgStorageOpalUtil.c b/SecurityPkg/Library/TcgStorageOpalLib/TcgStorageOpalUtil.c new file mode 100644 index 0000000000..2d3ecb474c --- /dev/null +++ b/SecurityPkg/Library/TcgStorageOpalLib/TcgStorageOpalUtil.c @@ -0,0 +1,913 @@ +/** @file + Public API for Opal Core 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 +#include +#include +#include + + +/** + 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 session info for one opal device. + @param[in] Psid PSID of device to revert. + @param[in] PsidLength Length of PSID in bytes. + +**/ +TCG_RESULT +EFIAPI +OpalUtilPsidRevert( + OPAL_SESSION *Session, + const VOID *Psid, + UINT32 PsidLength + ) +{ + UINT8 MethodStatus; + TCG_RESULT Ret; + + NULL_CHECK(Session); + NULL_CHECK(Psid); + + Ret = OpalStartSession( + Session, + OPAL_UID_ADMIN_SP, + TRUE, + PsidLength, + Psid, + OPAL_ADMIN_SP_PSID_AUTHORITY, + &MethodStatus); + if (Ret == TcgResultSuccess && MethodStatus == TCG_METHOD_STATUS_CODE_SUCCESS) { + Ret = OpalPsidRevert(Session); + if (Ret != TcgResultSuccess) { + // + // If revert was successful, session was already ended by TPer, so only end session on failure + // + OpalEndSession(Session); + } + } + + if (MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { + Ret = TcgResultFailure; + } + + return Ret; +} + +/** + Opens a session with OPAL_UID_ADMIN_SP as OPAL_ADMIN_SP_SID_AUTHORITY, + sets the OPAL_UID_ADMIN_SP_C_PIN_SID column with the new password, + and activates the locking SP to copy SID PIN to Admin1 Locking SP PIN + + @param[in] Session, The session info for one opal device. + @param[in] GeneratedSid Generated SID of disk + @param[in] SidLength Length of generatedSid in bytes + @param[in] Password New admin password to set + @param[in] PassLength Length of password in bytes + +**/ +TCG_RESULT +EFIAPI +OpalUtilSetAdminPasswordAsSid( + OPAL_SESSION *Session, + const VOID *GeneratedSid, + UINT32 SidLength, + const VOID *Password, + UINT32 PassLength + ) +{ + UINT8 MethodStatus; + TCG_RESULT Ret; + + NULL_CHECK(Session); + NULL_CHECK(GeneratedSid); + NULL_CHECK(Password); + + Ret = OpalStartSession( + Session, + OPAL_UID_ADMIN_SP, + TRUE, + SidLength, + GeneratedSid, + OPAL_ADMIN_SP_SID_AUTHORITY, + &MethodStatus + ); + if (Ret != TcgResultSuccess || MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { + DEBUG ((DEBUG_INFO, "start session with admin SP as SID authority failed: Ret=%d MethodStatus=%u\n", Ret, MethodStatus)); + goto done; + } + + // + // 1. Update SID = new Password + // + Ret = OpalSetPassword( + Session, + OPAL_UID_ADMIN_SP_C_PIN_SID, + Password, + PassLength, + &MethodStatus + ); + + if (Ret != TcgResultSuccess || MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { + OpalEndSession(Session); + DEBUG ((DEBUG_INFO, "set Password failed: Ret=%d MethodStatus=%u\n", Ret, MethodStatus)); + goto done; + } + + // + // 2. Activate locking SP + // + Ret = OpalActivateLockingSp(Session, &MethodStatus); + OpalEndSession(Session); + if (Ret != TcgResultSuccess || MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { + DEBUG ((DEBUG_INFO, "activate locking SP failed: Ret=%d MethodStatus=%u\n", Ret, MethodStatus)); + goto done; + } + +done: + if (MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { + Ret = TcgResultFailure; + } + return Ret; +} + +/** + + Opens a session with OPAL_UID_LOCKING_SP as OPAL_LOCKING_SP_ADMIN1_AUTHORITY, + and updates the specified locking range with the provided column values + + @param[in] Session, The session info for one opal device. + @param[in] Password New admin password to set + @param[in] PassLength Length of password in bytes + @param[in] LockingRangeUid Locking range UID to set values + @param[in] RangeStart Value to set RangeStart column for Locking Range + @param[in] RangeLength Value to set RangeLength column for Locking Range + @param[in] ReadLockEnabled Value to set readLockEnabled column for Locking Range + @param[in] WriteLockEnabled Value to set writeLockEnabled column for Locking Range + @param[in] ReadLocked Value to set ReadLocked column for Locking Range + @param[in] WriteLocked Value to set WriteLocked column for Locking Range + +**/ +TCG_RESULT +EFIAPI +OpalUtilSetOpalLockingRange( + OPAL_SESSION *Session, + const VOID *Password, + UINT32 PassLength, + TCG_UID LockingRangeUid, + UINT64 RangeStart, + UINT64 RangeLength, + BOOLEAN ReadLockEnabled, + BOOLEAN WriteLockEnabled, + BOOLEAN ReadLocked, + BOOLEAN WriteLocked + ) +{ + UINT8 MethodStatus; + TCG_RESULT Ret; + + NULL_CHECK(Session); + NULL_CHECK(Password); + + // + // Start session with Locking SP using current admin Password + // + Ret = OpalStartSession( + Session, + OPAL_UID_LOCKING_SP, + TRUE, + PassLength, + Password, + OPAL_LOCKING_SP_ADMIN1_AUTHORITY, + &MethodStatus); + if ((Ret != TcgResultSuccess) || (MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS)) { + DEBUG ((DEBUG_INFO, "start session with locking SP failed: Ret=%d MethodStatus=%u\n", Ret, MethodStatus)); + goto done; + } + + // + // Enable locking range + // + Ret = OpalSetLockingRange( + Session, + LockingRangeUid, + RangeStart, + RangeLength, + ReadLockEnabled, + WriteLockEnabled, + ReadLocked, + WriteLocked, + &MethodStatus); + + OpalEndSession(Session); + if (Ret != TcgResultSuccess || MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { + DEBUG ((DEBUG_INFO, "set locking range failed: Ret=%d MethodStatus=0x%x\n", Ret, MethodStatus)); + } + +done: + if (MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { + Ret = TcgResultFailure; + } + 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 session info for one 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 + +**/ +TCG_RESULT +EFIAPI +OpalUtilSetAdminPassword( + OPAL_SESSION *Session, + const VOID *OldPassword, + UINT32 OldPasswordLength, + const VOID *NewPassword, + UINT32 NewPasswordLength + ) +{ + TCG_RESULT Ret; + UINT8 MethodStatus; + + NULL_CHECK(Session); + NULL_CHECK(OldPassword); + NULL_CHECK(NewPassword); + + // + // Unknown ownership + // + Ret = OpalStartSession( + Session, + OPAL_UID_ADMIN_SP, + TRUE, + OldPasswordLength, + OldPassword, + OPAL_ADMIN_SP_SID_AUTHORITY, + &MethodStatus + ); + if (Ret != TcgResultSuccess || MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { + DEBUG ((DEBUG_INFO, "start session with admin SP using old Password failed\n")); + goto done; + } + + // + // Update SID = new pw + // + Ret = OpalSetPassword(Session, OPAL_UID_ADMIN_SP_C_PIN_SID, NewPassword, NewPasswordLength, &MethodStatus); + OpalEndSession(Session); + if (Ret != TcgResultSuccess || MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { + DEBUG ((DEBUG_INFO, "set new admin SP Password failed\n")); + goto done; + } + + Ret = OpalStartSession( + Session, + OPAL_UID_LOCKING_SP, + TRUE, + OldPasswordLength, + OldPassword, + OPAL_LOCKING_SP_ADMIN1_AUTHORITY, + &MethodStatus + ); + if (Ret != TcgResultSuccess || MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { + DEBUG ((DEBUG_INFO, "start session with locking SP using old Password failed\n")); + goto done; + } + + // + // Update admin locking SP to new pw + // + Ret = OpalSetPassword(Session, OPAL_LOCKING_SP_C_PIN_ADMIN1, NewPassword, NewPasswordLength, &MethodStatus); + OpalEndSession(Session); + if (Ret != TcgResultSuccess || MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { + DEBUG ((DEBUG_INFO, "set new locking SP Password failed\n")); + goto done; + } + +done: + if (MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { + Ret = TcgResultFailure; + } + return Ret; +} + +/** + Starts a session with OPAL_UID_LOCKING_SP as OPAL_LOCKING_SP_USER1_AUTHORITY or OPAL_LOCKING_SP_ADMIN1_AUTHORITY + and sets the User1 SP authority to enabled and sets the User1 password. + + @param[in] Session, The session info for one 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 + +**/ +TCG_RESULT +EFIAPI +OpalUtilSetUserPassword( + OPAL_SESSION *Session, + const VOID *OldPassword, + UINT32 OldPasswordLength, + const VOID *NewPassword, + UINT32 NewPasswordLength + ) +{ + UINT8 MethodStatus; + TCG_RESULT Ret; + + NULL_CHECK(Session); + NULL_CHECK(OldPassword); + NULL_CHECK(NewPassword); + + // + // See if updating user1 authority + // + Ret = OpalStartSession( + Session, + OPAL_UID_LOCKING_SP, + TRUE, + OldPasswordLength, + OldPassword, + OPAL_LOCKING_SP_USER1_AUTHORITY, + &MethodStatus + ); + if (Ret == TcgResultSuccess && MethodStatus == TCG_METHOD_STATUS_CODE_SUCCESS) { + Ret = OpalSetPassword( + Session, + OPAL_LOCKING_SP_C_PIN_USER1, + NewPassword, + NewPasswordLength, + &MethodStatus + ); + OpalEndSession(Session); + if (Ret == TcgResultSuccess && MethodStatus == TCG_METHOD_STATUS_CODE_SUCCESS) { + return Ret; + } + } + + // + // Setting Password for first time or setting Password as admin + // + + // + // Start session with Locking SP using current admin Password + // + Ret = OpalStartSession( + Session, + OPAL_UID_LOCKING_SP, + TRUE, + OldPasswordLength, + OldPassword, + OPAL_LOCKING_SP_ADMIN1_AUTHORITY, + &MethodStatus + ); + if (Ret != TcgResultSuccess || MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { + DEBUG ((DEBUG_INFO, "StartSession with locking SP as admin1 authority failed\n")); + goto done; + } + + // + // Enable User1 and set its PIN + // + Ret = OpalSetLockingSpAuthorityEnabledAndPin( + Session, + OPAL_LOCKING_SP_C_PIN_USER1, + OPAL_LOCKING_SP_USER1_AUTHORITY, + NewPassword, + NewPasswordLength, + &MethodStatus + ); + OpalEndSession(Session); + if (Ret != TcgResultSuccess || MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { + DEBUG ((DEBUG_INFO, "OpalSetLockingSpAuthorityEnabledAndPin failed\n")); + goto done; + } + +done: + if (MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { + Ret = TcgResultFailure; + } + return Ret; +} + +/** + Verify whether user input the correct password. + + @param[in] Session, The session info for one opal device. + @param[in] Password Admin password + @param[in] PasswordLength Length of password in bytes + @param[in/out] HostSigningAuthority Use the Host signing authority type. + +**/ +TCG_RESULT +EFIAPI +OpalUtilVerifyPassword ( + OPAL_SESSION *Session, + const VOID *Password, + UINT32 PasswordLength, + TCG_UID HostSigningAuthority + ) +{ + TCG_RESULT Ret; + UINT8 MethodStatus; + + NULL_CHECK(Session); + NULL_CHECK(Password); + + Ret = OpalStartSession( + Session, + OPAL_UID_LOCKING_SP, + TRUE, + PasswordLength, + Password, + HostSigningAuthority, + &MethodStatus); + if (Ret == TcgResultSuccess && MethodStatus == TCG_METHOD_STATUS_CODE_SUCCESS) { + OpalEndSession(Session); + return TcgResultSuccess; + } + + return TcgResultFailure; +} + +/** + Starts a session with OPAL_UID_LOCKING_SP as OPAL_LOCKING_SP_USER1_AUTHORITY or OPAL_LOCKING_SP_ADMIN1_AUTHORITY + and generates a new global locking range key to erase the Data. + + @param[in] Session, The session info for one opal device. + @param[in] Password Admin or user password + @param[in] PasswordLength Length of password in bytes + @param[in/out] PasswordFailed indicates if password failed (start session didn't work) + +**/ +TCG_RESULT +EFIAPI +OpalUtilSecureErase( + OPAL_SESSION *Session, + const VOID *Password, + UINT32 PasswordLength, + BOOLEAN *PasswordFailed + ) +{ + UINT8 MethodStatus; + TCG_RESULT Ret; + + NULL_CHECK(Session); + NULL_CHECK(Password); + NULL_CHECK(PasswordFailed); + + // + // Try to generate a new key with admin1 + // + Ret = OpalStartSession( + Session, + OPAL_UID_LOCKING_SP, + TRUE, + PasswordLength, + Password, + OPAL_LOCKING_SP_ADMIN1_AUTHORITY, + &MethodStatus + ); + + if (Ret == TcgResultSuccess && MethodStatus == TCG_METHOD_STATUS_CODE_SUCCESS) { + Ret = OpalGlobalLockingRangeGenKey(Session, &MethodStatus); + *PasswordFailed = FALSE; + OpalEndSession(Session); + } else { + // + // Try to generate a new key with user1 + // + Ret = OpalStartSession( + Session, + OPAL_UID_LOCKING_SP, + TRUE, + PasswordLength, + Password, + OPAL_LOCKING_SP_USER1_AUTHORITY, + &MethodStatus + ); + + if (Ret == TcgResultSuccess && MethodStatus == TCG_METHOD_STATUS_CODE_SUCCESS) { + Ret = OpalGlobalLockingRangeGenKey(Session, &MethodStatus); + *PasswordFailed = FALSE; + OpalEndSession(Session); + } else { + *PasswordFailed = TRUE; + } + } + + if (MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { + Ret = TcgResultFailure; + } + 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 session info for one opal device. + @param[in] Password Admin password + @param[in] PasswordLength Length of password in bytes + @param[in/out] PasswordFailed indicates if password failed (start session didn't work) + +**/ +TCG_RESULT +EFIAPI +OpalUtilDisableUser( + OPAL_SESSION *Session, + const VOID *Password, + UINT32 PasswordLength, + BOOLEAN *PasswordFailed + ) +{ + UINT8 MethodStatus; + TCG_RESULT Ret; + + NULL_CHECK(Session); + NULL_CHECK(Password); + NULL_CHECK(PasswordFailed); + + // + // Start session with Locking SP using current admin Password + // + Ret = OpalStartSession( + Session, + OPAL_UID_LOCKING_SP, + TRUE, + PasswordLength, + Password, + OPAL_LOCKING_SP_ADMIN1_AUTHORITY, + &MethodStatus + ); + if (Ret != TcgResultSuccess || MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { + DEBUG ((DEBUG_INFO, "StartSession with Locking SP as Admin1 failed\n")); + *PasswordFailed = TRUE; + goto done; + } + + *PasswordFailed = FALSE; + Ret = OpalDisableUser(Session, &MethodStatus); + OpalEndSession(Session); + +done: + if (MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { + Ret = TcgResultFailure; + } + 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 session info for one 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/out] PasswordFailed indicates if password failed (start session didn't work) + @param[in] Msid Msid info. + @param[in] MsidLength Msid data length. + +**/ +TCG_RESULT +EFIAPI +OpalUtilRevert( + OPAL_SESSION *Session, + BOOLEAN KeepUserData, + const VOID *Password, + UINT32 PasswordLength, + BOOLEAN *PasswordFailed, + UINT8 *Msid, + UINT32 MsidLength + ) +{ + UINT8 MethodStatus; + TCG_RESULT Ret; + + NULL_CHECK(Session); + NULL_CHECK(Msid); + NULL_CHECK(Password); + NULL_CHECK(PasswordFailed); + + Ret = OpalStartSession( + Session, + OPAL_UID_LOCKING_SP, + TRUE, + PasswordLength, + Password, + OPAL_LOCKING_SP_ADMIN1_AUTHORITY, + &MethodStatus + ); + + if (Ret != TcgResultSuccess || MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { + DEBUG ((DEBUG_INFO, "error starting session: Ret=%d, MethodStatus=%u\n", Ret, MethodStatus)); + *PasswordFailed = TRUE; + goto done; + } + + *PasswordFailed = FALSE; + // + // Try to revert with admin1 + // + Ret = OpalAdminRevert(Session, KeepUserData, &MethodStatus); + if (Ret != TcgResultSuccess || MethodStatus == TCG_METHOD_STATUS_CODE_SUCCESS) { + // + // Device ends the session on successful revert, so only call OpalEndSession when fail. + // + DEBUG ((DEBUG_INFO, "OpalAdminRevert as admin failed\n")); + OpalEndSession(Session); + } + + Ret = OpalUtilSetSIDtoMSID (Session, Password, PasswordLength, Msid, MsidLength); + +done: + if (MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { + Ret = TcgResultFailure; + } + return Ret; +} + +/** + After revert success, set SID to MSID. + + @param Session, The session info for one opal device. + @param Password, Input password info. + @param PasswordLength, Input password length. + @param Msid Msid info. + @param MsidLength Msid data length. + +**/ +TCG_RESULT +EFIAPI +OpalUtilSetSIDtoMSID ( + OPAL_SESSION *Session, + const VOID *Password, + UINT32 PasswordLength, + UINT8 *Msid, + UINT32 MsidLength + ) +{ + TCG_RESULT Ret; + UINT8 MethodStatus; + + NULL_CHECK(Session); + NULL_CHECK(Msid); + NULL_CHECK(Password); + + // + // Start session with admin sp to update SID to MSID + // + Ret = OpalStartSession( + Session, + OPAL_UID_ADMIN_SP, + TRUE, + PasswordLength, + Password, + OPAL_ADMIN_SP_SID_AUTHORITY, + &MethodStatus + ); + if (Ret != TcgResultSuccess || MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { + goto done; + } + + // + // Update SID pin + // + Ret = OpalSetPassword(Session, OPAL_UID_ADMIN_SP_C_PIN_SID, Msid, MsidLength, &MethodStatus); + OpalEndSession(Session); + +done: + if (MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { + Ret = TcgResultFailure; + } + + return Ret; +} + +/** + Update global locking range. + + @param Session, The session info for one opal device. + @param Password, Input password info. + @param PasswordLength, Input password length. + @param ReadLocked, Read lock info. + @param WriteLocked write lock info. + +**/ +TCG_RESULT +EFIAPI +OpalUtilUpdateGlobalLockingRange( + OPAL_SESSION *Session, + const VOID *Password, + UINT32 PasswordLength, + BOOLEAN ReadLocked, + BOOLEAN WriteLocked + ) +{ + UINT8 MethodStatus; + TCG_RESULT Ret; + + NULL_CHECK(Session); + NULL_CHECK(Password); + + // + // Try to start session with Locking SP as admin1 authority + // + Ret = OpalStartSession( + Session, + OPAL_UID_LOCKING_SP, + TRUE, + PasswordLength, + Password, + OPAL_LOCKING_SP_ADMIN1_AUTHORITY, + &MethodStatus + ); + if (Ret == TcgResultSuccess && MethodStatus == TCG_METHOD_STATUS_CODE_SUCCESS) { + Ret = OpalUpdateGlobalLockingRange( + Session, + ReadLocked, + WriteLocked, + &MethodStatus + ); + OpalEndSession(Session); + if (Ret == TcgResultSuccess && MethodStatus == TCG_METHOD_STATUS_CODE_SUCCESS) { + goto done; + } + } + + if (MethodStatus == TCG_METHOD_STATUS_CODE_AUTHORITY_LOCKED_OUT) { + DEBUG ((DEBUG_INFO, "unlock as admin failed with AUTHORITY_LOCKED_OUT\n")); + goto done; + } + + // + // Try user1 authority + // + Ret = OpalStartSession( + Session, + OPAL_UID_LOCKING_SP, + TRUE, + PasswordLength, + Password, + OPAL_LOCKING_SP_USER1_AUTHORITY, + &MethodStatus + ); + if (Ret != TcgResultSuccess || MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { + DEBUG ((DEBUG_INFO, "StartSession with Locking SP as User1 failed\n")); + goto done; + } + + Ret = OpalUpdateGlobalLockingRange(Session, ReadLocked, WriteLocked, &MethodStatus); + OpalEndSession(Session); + +done: + if (MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { + Ret = TcgResultFailure; + } + return Ret; +} + +/** + Update global locking range. + + @param Session, The session info for one opal device. + @param Msid, The data buffer to save Msid info. + @param MsidBufferLength, The data buffer length for Msid. + @param MsidLength, The actual data length for Msid. + +**/ +TCG_RESULT +EFIAPI +OpalUtilGetMsid( + OPAL_SESSION *Session, + UINT8 *Msid, + UINT32 MsidBufferLength, + UINT32 *MsidLength + ) +{ + UINT8 MethodStatus; + TCG_RESULT Ret; + + NULL_CHECK(Session); + NULL_CHECK(Msid); + NULL_CHECK(MsidLength); + + Ret = OpalStartSession( + Session, + OPAL_UID_ADMIN_SP, + TRUE, + 0, + NULL, + TCG_UID_NULL, + &MethodStatus + ); + if ((Ret == TcgResultSuccess) && (MethodStatus == TCG_METHOD_STATUS_CODE_SUCCESS)) { + Ret = OpalGetMsid (Session, MsidBufferLength, Msid, MsidLength); + OpalEndSession (Session); + } + + if (MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { + Ret = TcgResultFailure; + } + + return Ret; +} + +/** + + The function determines who owns the device by attempting to start a session with different credentials. + If the SID PIN matches the MSID PIN, the no one owns the device. + If the SID PIN matches the ourSidPin, then "Us" owns the device. Otherwise it is unknown. + + + @param[in] Session The session info for one opal device. + @param Msid, The Msid info. + @param MsidLength, The data length for Msid. + +**/ +OPAL_OWNER_SHIP +EFIAPI +OpalUtilDetermineOwnership( + OPAL_SESSION *Session, + UINT8 *Msid, + UINT32 MsidLength + ) +{ + UINT8 MethodStatus; + TCG_RESULT Ret; + OPAL_OWNER_SHIP Owner; + + NULL_CHECK(Session); + NULL_CHECK(Msid); + + Owner = OpalOwnershipUnknown; + // + // Start Session as SID_UID with ADMIN_SP using MSID PIN + // + Ret = OpalStartSession( + Session, + OPAL_UID_ADMIN_SP, + TRUE, + MsidLength, + Msid, + OPAL_ADMIN_SP_SID_AUTHORITY, + &MethodStatus); + if ((Ret == TcgResultSuccess) && (MethodStatus == TCG_METHOD_STATUS_CODE_SUCCESS)) { + // + // now we know that SID PIN == MSID PIN + // + Owner = OpalOwnershipNobody; + + OpalEndSession(Session); + } + + return Owner; +} + +/** + + The function returns if admin password exists. + + @param[in] OwnerShip The owner ship of the opal device. + @param[in] LockingFeature The locking info of the opal device. + + @retval TRUE Admin password existed. + @retval FALSE Admin password not existed. + +**/ +BOOLEAN +EFIAPI +OpalUtilAdminPasswordExists( + IN UINT16 OwnerShip, + IN TCG_LOCKING_FEATURE_DESCRIPTOR *LockingFeature + ) +{ + NULL_CHECK(LockingFeature); + + // if it is Unknown who owns the device + // then someone has set password previously through our UI + // because the SID would no longer match the generated SID (ownership us) + // or someone has set password using 3rd party software + + // + // Locking sp enabled is checked b/c it must be enabled to change the PIN of the Admin1. + // + return (OwnerShip == OpalOwnershipUnknown && LockingFeature->LockingEnabled); +} + -- 2.39.2