diff options
Diffstat (limited to 'SecurityPkg/Library')
3 files changed, 2616 insertions, 0 deletions
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.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <uefi.h>
+#include <Library/BaseLib.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/TcgStorageOpalLib.h>
+
+#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.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+[Defines]
+ INF_VERSION = 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.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+#include <uefi.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/TcgStorageOpalLib.h>
+
+
+/**
+ 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);
+}
+
|