/** @file Public API for Opal Core library. Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include #include #include #include #include #include #include "TcgStorageOpalLibInternal.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. @param[in] EstimateTimeCost Estimate the time needed. **/ TCG_RESULT OpalTrustedRecv( EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *Sscp, UINT32 MediaId, UINT8 SecurityProtocol, UINT16 SpSpecific, VOID *Buffer, UINTN BufferSize, UINT32 EstimateTimeCost ) { 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. // // if user input estimate time cost(second level) value bigger than 10s, base on user input value to wait. // Else, Use a max timeout of 10 seconds to wait, 5000 tries * 2ms = 10s // if (EstimateTimeCost > 10) { Tries = EstimateTimeCost * 500; // 500 = 1000 * 1000 / 2000; } else { 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. @param[in] EstimateTimeCost Estimate the time need to for the method. **/ TCG_RESULT EFIAPI OpalPerformMethod ( OPAL_SESSION *Session, UINT32 SendSize, VOID *Buffer, UINT32 BufferSize, TCG_PARSE_STRUCT *ParseStruct, UINT8 *MethodStatus, UINT32 EstimateTimeCost ) { 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, EstimateTimeCost )); 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, TCG_BLOCKSID_COMID, // hardcode ComID 0x0005 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, 0)); METHOD_STATUS_ERROR_CHECK(MethodStatus, TcgResultFailure); return TcgResultSuccess; } /** 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. @param[in] EstimateTimeCost Estimate the time needed. **/ TCG_RESULT OpalPyrite2PsidRevert( OPAL_SESSION *AdminSpSession, UINT32 EstimateTimeCost ) { // // 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, EstimateTimeCost)); 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, 0 )); } /** 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, 0 )); } /** 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, 0)); 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), 0 )); 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, 0)); 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 retrieves the MSID from the device specified @param[in] AdminSpSession OPAL_SESSION with OPAL_UID_ADMIN_SP as OPAL_ADMIN_SP_ANYBODY_AUTHORITY @param[out] ActiveDataRemovalMechanism Active Data Removal Mechanism that the device will use for Revert/RevertSP calls. **/ TCG_RESULT OpalPyrite2GetActiveDataRemovalMechanism ( IN OPAL_SESSION *AdminSpSession, OUT UINT8 *ActiveDataRemovalMechanism ) { TCG_CREATE_STRUCT CreateStruct; TCG_PARSE_STRUCT ParseStruct; UINT32 Size; UINT8 MethodStatus; UINT32 Col; UINT8 RecvActiveDataRemovalMechanism; UINT8 Buffer[BUFFER_SIZE]; NULL_CHECK(AdminSpSession); NULL_CHECK(ActiveDataRemovalMechanism); 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_DATA_REMOVAL_MECHANISM, 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_ACTIVE_DATA_REMOVAL_MECHANISM_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_ACTIVE_DATA_REMOVAL_MECHANISM_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 Get Active Data Removal Mechanism Method Call // ERROR_CHECK(OpalPerformMethod(AdminSpSession, Size, Buffer, BUFFER_SIZE, &ParseStruct, &MethodStatus, 0)); 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(TcgGetNextUINT8(&ParseStruct, &RecvActiveDataRemovalMechanism)); ERROR_CHECK(TcgGetNextEndName(&ParseStruct)); ERROR_CHECK(TcgGetNextEndList(&ParseStruct)); ERROR_CHECK(TcgGetNextEndList(&ParseStruct)); ERROR_CHECK(TcgGetNextEndOfData(&ParseStruct)); if (Col != OPAL_ADMIN_SP_ACTIVE_DATA_REMOVAL_MECHANISM_COL) { DEBUG ((DEBUG_INFO, "ERROR: got col %u, expected %u\n", Col, OPAL_ADMIN_SP_ACTIVE_DATA_REMOVAL_MECHANISM_COL)); return TcgResultFailure; } if (RecvActiveDataRemovalMechanism >= ResearvedMechanism) { return TcgResultFailure; } // // Copy active data removal mechanism into Buffer // CopyMem(ActiveDataRemovalMechanism, &RecvActiveDataRemovalMechanism, sizeof(RecvActiveDataRemovalMechanism)); 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, 0)); // // 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 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. @param[in] EstimateTimeCost Estimate the time needed. **/ TCG_RESULT OpalPyrite2AdminRevert( OPAL_SESSION *LockingSpSession, BOOLEAN KeepUserData, UINT8 *MethodStatus, UINT32 EstimateTimeCost ) { 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, EstimateTimeCost)); // // 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, 0)); 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, 0)); // 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; TCG_RESULT Ret; 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, 0)); 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, 0)); // // 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, 0)); 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, 0)); 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, 0)); // // For Pyrite type SSC, it not supports Active Key. // So here add check logic before enable it. // Ret = OpalParseRetrieveGlobalLockingRangeActiveKey(&ParseStruct, &ActiveKey); if (Ret == TcgResultSuccess) { 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, 0)); if (*MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { DEBUG ((DEBUG_INFO, "Update ACE for GLOBALRANGE_GENKEY failed\n")); // // 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, 0)); 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, 0)); 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, 0)); 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, 0)); return TcgResultSuccess; } /** The function updates the ReadLocked and WriteLocked columns of the Global Locking Range. This function 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, 0)); 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, 0)); // 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, 0)); 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; OPAL_LEVEL0_FEATURE_DESCRIPTOR *Feat2; UINTN Size; UINTN Size2; 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 )); } } // // For some pyrite 2.0 device, it contains both pyrite 1.0 and 2.0 feature data. // so here try to get data from pyrite 2.0 feature data first. // Size = 0; Feat = (OPAL_LEVEL0_FEATURE_DESCRIPTOR*) TcgGetFeature (DiscoveryHeader, TCG_FEATURE_PYRITE_SSC, &Size); Size2 = 0; Feat2 = (OPAL_LEVEL0_FEATURE_DESCRIPTOR*) TcgGetFeature (DiscoveryHeader, TCG_FEATURE_PYRITE_SSC_V2_0_0, &Size2); if (Feat2 != NULL && Size2 >= sizeof (PYRITE_SSCV2_FEATURE_DESCRIPTOR)) { SupportedAttributes->PyriteSscV2 = TRUE; if (*OpalBaseComId == TCG_RESERVED_COMID) { *OpalBaseComId = SwapBytes16 (Feat2->PyriteSscV2.BaseComdIdBE); SupportedAttributes->InitCpinIndicator = (Feat2->PyriteSscV2.InitialCPINSIDPIN == 0); SupportedAttributes->CpinUponRevert = (Feat2->PyriteSscV2.CPINSIDPINRevertBehavior == 0); DEBUG ((DEBUG_INFO, "Pyrite SSC V2 InitCpinIndicator %d CpinUponRevert %d \n", SupportedAttributes->InitCpinIndicator, SupportedAttributes->CpinUponRevert )); } } else { 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, "SupportedAttributes->MediaEncryption 0x%X \n", SupportedAttributes->MediaEncryption)); } Size = 0; Feat = (OPAL_LEVEL0_FEATURE_DESCRIPTOR*) TcgGetFeature (DiscoveryHeader, TCG_FEATURE_BLOCK_SID, &Size); if (Feat != NULL && Size >= sizeof (TCG_BLOCK_SID_FEATURE_DESCRIPTOR)) { SupportedAttributes->BlockSid = TRUE; DEBUG ((DEBUG_INFO, "BlockSid Supported!!! Current Status is 0x%X \n", Feat->BlockSid.SIDBlockedState)); } else { DEBUG ((DEBUG_INFO, "BlockSid Unsupported!!!")); } Size = 0; Feat = (OPAL_LEVEL0_FEATURE_DESCRIPTOR*) TcgGetFeature (DiscoveryHeader, TCG_FEATURE_DATA_REMOVAL, &Size); if (Feat != NULL && Size >= sizeof (DATA_REMOVAL_FEATURE_DESCRIPTOR)) { SupportedAttributes->DataRemoval = TRUE; DEBUG ((DEBUG_INFO, "DataRemoval Feature Supported!\n")); DEBUG ((DEBUG_INFO, "Operation Processing = 0x%x\n", Feat->DataRemoval.OperationProcessing)); DEBUG ((DEBUG_INFO, "RemovalMechanism = 0x%x\n", Feat->DataRemoval.RemovalMechanism)); DEBUG ((DEBUG_INFO, "BIT0 :: Format = 0x%x, Time = 0x%x\n", Feat->DataRemoval.FormatBit0, SwapBytes16 (Feat->DataRemoval.TimeBit0))); DEBUG ((DEBUG_INFO, "BIT1 :: Format = 0x%x, Time = 0x%x\n", Feat->DataRemoval.FormatBit1, SwapBytes16 (Feat->DataRemoval.TimeBit1))); DEBUG ((DEBUG_INFO, "BIT2 :: Format = 0x%x, Time = 0x%x\n", Feat->DataRemoval.FormatBit2, SwapBytes16 (Feat->DataRemoval.TimeBit2))); DEBUG ((DEBUG_INFO, "BIT3 :: Format = 0x%x, Time = 0x%x\n", Feat->DataRemoval.FormatBit3, SwapBytes16 (Feat->DataRemoval.TimeBit3))); DEBUG ((DEBUG_INFO, "BIT4 :: Format = 0x%x, Time = 0x%x\n", Feat->DataRemoval.FormatBit4, SwapBytes16 (Feat->DataRemoval.TimeBit4))); } 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; } /** Get the descriptor for the specific feature code. @param[in] Session OPAL_SESSION with OPAL_UID_LOCKING_SP to retrieve info. @param[in] FeatureCode The feature code user request. @param[in, out] DataSize The data size. @param[out] Data The data buffer used to save the feature descriptor. **/ TCG_RESULT OpalGetFeatureDescriptor ( IN OPAL_SESSION *Session, IN UINT16 FeatureCode, IN OUT UINTN *DataSize, OUT VOID *Data ) { UINT8 Buffer[BUFFER_SIZE]; TCG_LEVEL0_DISCOVERY_HEADER *DiscoveryHeader; OPAL_LEVEL0_FEATURE_DESCRIPTOR *Feat; UINTN Size; NULL_CHECK(Session); NULL_CHECK(DataSize); NULL_CHECK(Data); 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, FeatureCode, &Size); if (Feat != NULL) { if (Size > *DataSize) { *DataSize = Size; return TcgResultFailureBufferTooSmall; } *DataSize = Size; CopyMem (Data, Feat, Size); } 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 && SupportedAttributes->PyriteSscV2 == 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; }