diff options
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/TcgStorageOpalLib/TcgStorageOpalUtil.c')
-rw-r--r-- | src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/TcgStorageOpalLib/TcgStorageOpalUtil.c | 1123 |
1 files changed, 1123 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/TcgStorageOpalLib/TcgStorageOpalUtil.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/TcgStorageOpalLib/TcgStorageOpalUtil.c new file mode 100644 index 00000000..a3444441 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/TcgStorageOpalLib/TcgStorageOpalUtil.c @@ -0,0 +1,1123 @@ +/** @file + Public API for Opal Core library. + +Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#include <Uefi.h> +#include <Library/BaseLib.h> +#include <Library/DebugLib.h> +#include <Library/TcgStorageOpalLib.h> +#include "TcgStorageOpalLibInternal.h" + +#define OPAL_MSID_LENGTH 128 + +/** + 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; + UINT32 RemovalTimeOut; + + NULL_CHECK(Session); + NULL_CHECK(Psid); + + RemovalTimeOut = GetRevertTimeOut (Session); + DEBUG ((DEBUG_INFO, "OpalUtilPsidRevert: Timeout value = %d\n", RemovalTimeOut)); + + 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 = OpalPyrite2PsidRevert(Session, RemovalTimeOut); + 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; + UINT32 RemovalTimeOut; + + NULL_CHECK(Session); + NULL_CHECK(Msid); + NULL_CHECK(Password); + NULL_CHECK(PasswordFailed); + + RemovalTimeOut = GetRevertTimeOut (Session); + DEBUG ((DEBUG_INFO, "OpalUtilRevert: Timeout value = %d\n", RemovalTimeOut)); + + 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 = OpalPyrite2AdminRevert(Session, KeepUserData, &MethodStatus, RemovalTimeOut); + 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")); + } + + // + // 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) { + if (MethodStatus == TCG_METHOD_STATUS_CODE_AUTHORITY_LOCKED_OUT) { + // + // Caller need to know this special error, but return status not has type for it. + // so here use TcgResultFailureInvalidType as an replacement. + // + Ret = TcgResultFailureInvalidType; + } else { + 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; + + if ((Session == NULL) || (Msid == NULL)) { + return OpalOwnershipUnknown; + } + + 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); +} + +/** + Get Active Data Removal Mechanism Value. + + @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[out] ActiveDataRemovalMechanism Return the active data removal mechanism. + +**/ +TCG_RESULT +EFIAPI +OpalUtilGetActiveDataRemovalMechanism ( + OPAL_SESSION *Session, + const VOID *GeneratedSid, + UINT32 SidLength, + UINT8 *ActiveDataRemovalMechanism + ) +{ + TCG_RESULT Ret; + UINT8 MethodStatus; + + NULL_CHECK(Session); + NULL_CHECK(GeneratedSid); + NULL_CHECK(ActiveDataRemovalMechanism); + + Ret = OpalStartSession( + Session, + OPAL_UID_ADMIN_SP, + TRUE, + SidLength, + GeneratedSid, + OPAL_ADMIN_SP_ANYBODY_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)); + if (MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { + Ret = TcgResultFailure; + } + return Ret; + } + + Ret = OpalPyrite2GetActiveDataRemovalMechanism ( + Session, + ActiveDataRemovalMechanism + ); + + if (Ret != TcgResultSuccess) { + DEBUG ((DEBUG_INFO, "Pyrite2 Get Active Data Removal Mechanism failed: Ret=%d\n", Ret)); + } + + OpalEndSession(Session); + + return Ret; +} + +/** + Calculate the estimated time. + + @param[in] IsMinute Whether the input time value is minute type or second type. + @param[in] Time The input time value. + +**/ +UINT32 +CalculateDataRemovalTime ( + IN BOOLEAN IsMinute, + IN UINT16 Time + ) +{ + if (IsMinute) { + return Time * 2 * 60; + } else { + return Time * 2; + } +} + +/** + Return the estimated time for specific type. + + @param[in] Index The input data removal type. + @param[in] Descriptor DATA_REMOVAL_FEATURE_DESCRIPTOR + +**/ +UINT32 +GetDataRemovalTime ( + IN UINT8 Index, + IN DATA_REMOVAL_FEATURE_DESCRIPTOR *Descriptor + ) +{ + switch (Index) { + case OverwriteDataErase: + return CalculateDataRemovalTime (Descriptor->FormatBit0, SwapBytes16 (Descriptor->TimeBit0)); + + case BlockErase: + return CalculateDataRemovalTime (Descriptor->FormatBit1, SwapBytes16 (Descriptor->TimeBit1)); + + case CryptoErase: + return CalculateDataRemovalTime (Descriptor->FormatBit2, SwapBytes16 (Descriptor->TimeBit2)); + + case Unmap: + return CalculateDataRemovalTime (Descriptor->FormatBit3, SwapBytes16 (Descriptor->TimeBit3)); + + case ResetWritePointers: + return CalculateDataRemovalTime (Descriptor->FormatBit4, SwapBytes16 (Descriptor->TimeBit4)); + + case VendorSpecificErase: + return CalculateDataRemovalTime (Descriptor->FormatBit5, SwapBytes16 (Descriptor->TimeBit5)); + + default: + return 0; + } +} + +/** + Get the supported Data Removal Mechanism list. + + @param[in] Session The session info for one opal device. + @param[out] RemovalMechanismLists Return the supported data removal mechanism lists. + +**/ +TCG_RESULT +EFIAPI +OpalUtilGetDataRemovalMechanismLists ( + IN OPAL_SESSION *Session, + OUT UINT32 *RemovalMechanismLists + ) +{ + TCG_RESULT Ret; + UINTN DataSize; + DATA_REMOVAL_FEATURE_DESCRIPTOR Descriptor; + UINT8 Index; + UINT8 BitValue; + + NULL_CHECK(Session); + NULL_CHECK(RemovalMechanismLists); + + DataSize = sizeof (Descriptor); + Ret = OpalGetFeatureDescriptor (Session, TCG_FEATURE_DATA_REMOVAL, &DataSize, &Descriptor); + if (Ret != TcgResultSuccess) { + return TcgResultFailure; + } + + ASSERT (Descriptor.RemovalMechanism != 0); + + for (Index = 0; Index < ResearvedMechanism; Index ++) { + BitValue = (BOOLEAN) BitFieldRead8 (Descriptor.RemovalMechanism, Index, Index); + + if (BitValue == 0) { + RemovalMechanismLists[Index] = 0; + } else { + RemovalMechanismLists[Index] = GetDataRemovalTime (Index, &Descriptor); + } + } + + return TcgResultSuccess; +} + +/** + Get revert timeout value. + + @param[in] Session The session info for one opal device. + +**/ +UINT32 +GetRevertTimeOut ( + IN OPAL_SESSION *Session + ) +{ + TCG_RESULT TcgResult; + OPAL_DISK_SUPPORT_ATTRIBUTE SupportedAttributes; + UINT16 BaseComId; + UINT32 MsidLength; + UINT8 Msid[OPAL_MSID_LENGTH]; + UINT32 RemovalMechanishLists[ResearvedMechanism]; + UINT8 ActiveDataRemovalMechanism; + + TcgResult = OpalGetSupportedAttributesInfo (Session, &SupportedAttributes, &BaseComId); + if (TcgResult != TcgResultSuccess || SupportedAttributes.DataRemoval == 0) { + return 0; + } + + TcgResult = OpalUtilGetMsid (Session, Msid, OPAL_MSID_LENGTH, &MsidLength); + if (TcgResult != TcgResultSuccess) { + return 0; + } + + TcgResult = OpalUtilGetDataRemovalMechanismLists (Session, RemovalMechanishLists); + if (TcgResult != TcgResultSuccess) { + return 0; + } + + TcgResult = OpalUtilGetActiveDataRemovalMechanism (Session, Msid, MsidLength, &ActiveDataRemovalMechanism); + if (TcgResult != TcgResultSuccess) { + return 0; + } + + return RemovalMechanishLists[ActiveDataRemovalMechanism]; +} |