UEFI의 TPM2_GetCapability
TPM2_GetCapability의 매개변수
간단히 말해서, 우리는 Capability에서 원하는 정보의 종류를 지정합니다. [property:property+propertyCount] 범위의 결과를 요청합니다.
지정할 수 있는 기능 유형은 명령 설명에 나열되어 있습니다.
이 게시물에서는 TPM2_GetCapability를 사용하여 TPM_CAP_COMMANDS를 기능 매개 변수로 지정하여 지원되는 명령을 나열합니다.
구현
전체 코드는 다음과 같습니다.
#include <Uefi.h>
#include <Library/UefiLib.h>
#include <Protocol/Tcg2Protocol.h>
#include <IndustryStandard/Tpm20.h>
#pragma pack(1)
typedef struct {
TPM2_COMMAND_HEADER Header;
TPM_CAP capability;
UINT32 property;
UINT32 propertyCount;
} TPM2_GET_CAPABILITY_COMMAND;
typedef struct {
TPM2_RESPONSE_HEADER Header;
TPMI_YES_NO moreData;
TPMS_CAPABILITY_DATA capabilityData;
} TPM2_GET_CAPABILITY_RESPONSE;
#pragma pack()
EFI_STATUS EFIAPI UefiMain(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable) {
EFI_TCG2_PROTOCOL *Tcg2Protocol;
SystemTable->BootServices->LocateProtocol(&gEfiTcg2ProtocolGuid, NULL, (VOID**)&Tcg2Protocol);
TPM2_GET_CAPABILITY_COMMAND CmdBuffer;
UINT32 CmdBufferSize;
TPM2_GET_CAPABILITY_RESPONSE RecvBuffer;
UINT32 RecvBufferSize;
// set command parameters
CmdBuffer.Header.tag = SwapBytes16(TPM_ST_NO_SESSIONS);
CmdBuffer.Header.commandCode = SwapBytes32(TPM_CC_GetCapability);
CmdBuffer.capability = SwapBytes32(TPM_CAP_COMMANDS);
CmdBuffer.property = SwapBytes32(TPM_CAP_FIRST);
CmdBuffer.propertyCount = SwapBytes32(MAX_CAP_CC);
CmdBufferSize = sizeof(CmdBuffer.Header) + sizeof(CmdBuffer.capability) + sizeof(CmdBuffer.property) + sizeof(CmdBuffer.propertyCount);
CmdBuffer.Header.paramSize = SwapBytes32(CmdBufferSize);
// send TPM command
RecvBufferSize = sizeof(RecvBuffer);
EFI_STATUS stats = Tcg2Protocol->SubmitCommand(Tcg2Protocol, CmdBufferSize, (UINT8*)&CmdBuffer, RecvBufferSize, (UINT8*)&RecvBuffer);
if(stats==EFI_SUCCESS)
Print(L"SubmitCommand Success!\r\n");
else
Print(L"stats: 0x%x (EFI_DEVICE_ERROR:0x%x, EFI_INVALID_PARAMETER:0x%x, EFI_BUFFER_TOO_SMALL:0x%x)\r\n", stats, EFI_DEVICE_ERROR, EFI_INVALID_PARAMETER, EFI_BUFFER_TOO_SMALL);
// parse response
UINT16 res = SwapBytes32(RecvBuffer.Header.responseCode);
Print(L"ResponseCode is %d\r\n", res);
Print(L"moreData: %d\r\n", RecvBuffer.moreData);
UINT32 i;
UINT32 count = SwapBytes32(RecvBuffer.capabilityData.data.command.count);
Print(L"--- %d commands supported ---\r\n", count);
TPMA_CC* tpmacc = (TPMA_CC*)RecvBuffer.capabilityData.data.command.commandAttributes;
for(i=0; i<count; i++) {
union {
UINT32 tpma_cc_uint32;
TPMA_CC buf;
} castbuf;
castbuf.buf = tpmacc[i];
UINT32 tpmacc32 = SwapBytes32(castbuf.tpma_cc_uint32);
if((UINT16)tpmacc32 == TPM_CC_NV_DefineSpace) {
Print(L"TPM2_NV_DefineSpace is supported: %X\r\n", tpmacc32);
}
}
while(1);
return 0;
}
명령 매개변수 설명
다시 한 번 BigEndian의 데이터를 TPM으로 보내야 하므로
SwapBytes
가 많이 있습니다. TPM_CAP_COMMANDS 및 TPM_CAP_FIRST와 같은 매크로는 MdePkg/Include/IndustryStandard/Tpm20.h
에 있는 Tpm20.h에서 검색됩니다. MAX_CAP_CC를 propertyCount 매개변수로 요청하고 있으므로 응답에서 moreData 매개변수가 0이 될 것이라고 추측할 수 있습니다.응답 설명
구문 분석 응답은 이 문서의 주요 부분입니다.
Tpm20.h에서
typedef BYTE TPMI_YES_NO;
를 찾을 수 있으며 "YES_NO"라고 표시되어 있기 때문에 moreData가 값으로 1 또는 0을 취한다는 것을 쉽게 알 수 있습니다. 그러나 TPMS_CAPABILITY_DATA 유형이 있는 capabilityData 매개변수는 더 복잡합니다. Tpm20.h에서 찾아보면 TPMS_CAPABILITY_DATA 구조가 다음과 같다는 것을 알 수 있습니다.* [struct] TPMS_CAPABILITY_DATA
* [UINT32] TPM_CAP capability
* [union] TPMU_CAPABILITIES
* [struct] TPML_ALG_PROPERTY algorithms;
* [UINT32] UINT32 count
* [struct] TPMS_ALG_PROPERTY algProperties[MAX_CAP_ALGS];
* [UINT16] TPM_ALG_ID alg
* [UINT32(bitfield)] TPMA_ALGORITHM algProperties
* ...
이름 접두사 규칙
위의 TPM 매크로를 살펴보면 이름의 접두사에 몇 가지 규칙이 있음을 알 수 있습니다. 이름 접두사 규칙은 TCG 사양 Part2 4.16에 정의되어 있습니다. 여기에 그 일부가 있습니다.
알아야 할 접두사는 TPM2B_ 접두사입니다. 이 접두사가 있는 구조는 보유하고 있는 데이터에 따라 크기가 다릅니다. TPMS_CAPABILITY_DATA에는 아무것도 없지만, 이 구조가 포함되어 있으면 위의 코드에서 내가 하고 있는 것처럼 응답 구조를 정의하고 그 구조를 통해 액세스할 수 없습니다. 이것은 나중에 이것이 실제로 나타날 때 설명될 것이다. 지금은 접두사에서 어떤 유형의 데이터인지 알 수 있다는 것만 알면 충분합니다.
비트 필드를 UINT32로
이것은 TPM과 관련된 것은 아니지만 TPM 구조에서 비트 필드(TPMA_ 접두사가 있는 것)를 자주 볼 수 있습니다. TPM은 빅 엔디안으로 데이터를 처리하기 때문에 교환해야 하지만 SwapBytes32는 UINT32용이고 UINT32 비트필드용은 아닙니다. 따라서 먼저 UINT32로 변환해야 합니다. bitfield를 UINT32로 변환하기 위해서는 다음과 같이 union을 정의하면 됩니다.
union {
UINT32 tpma_cc_uint32;
TPMA_CC buf;
} castbuf;
castbuf.buf = /*TPMA_CC object*/;
Print(L"%d", SwapBytes32(castbuf.tpma_cc_uint32));
코드 실행
성공하면 이런 종류의 출력이 표시됩니다. 오류가 발생하면 오류를 평가하는 방법에 대한 이전 게시물을 확인할 수 있습니다.
0x240012A
는 00 0 0 001 0 0 1 000000 0000000100101010
이므로 TPM2_NV_DefineSpace에 대한 TPMA_CC 값은 다음과 같습니다.요약
Reference
이 문제에 관하여(UEFI의 TPM2_GetCapability), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/machinehunter/accessing-tpm20-from-uefi-module-tpm2getcapability-444p텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)