/** @file
|
Public API for Opal Core library.
|
|
Copyright (c) 2016 - 2021, Intel Corporation. All rights reserved.<BR>
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
**/
|
|
#include <Uefi.h>
|
#include <Library/BaseLib.h>
|
#include <Library/TimerLib.h>
|
#include <Library/BaseMemoryLib.h>
|
#include <Library/DebugLib.h>
|
#include <Library/TcgStorageOpalLib.h>
|
|
#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);
|
ZeroMem(SupportedAttributes, sizeof(OPAL_DISK_SUPPORT_ATTRIBUTE));
|
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;
|
}
|
|