From 3058711f8b12cf11585e0eda2a1b573f0d871667 Mon Sep 17 00:00:00 2001 From: kavsrf Date: Mon, 17 Apr 2017 23:30:06 +0300 Subject: TPM 2.0 --- Library/DcsCfgLib/DcsRandom.c | 9 +- Library/DcsTpmLib/DcsTpmLib.inf | 4 + Library/DcsTpmLib/Tpm12.c | 115 +++-- Library/DcsTpmLib/Tpm20.c | 906 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 994 insertions(+), 40 deletions(-) create mode 100644 Library/DcsTpmLib/Tpm20.c (limited to 'Library') diff --git a/Library/DcsCfgLib/DcsRandom.c b/Library/DcsCfgLib/DcsRandom.c index f4eb2e0..4362e6d 100644 --- a/Library/DcsCfgLib/DcsRandom.c +++ b/Library/DcsCfgLib/DcsRandom.c @@ -402,8 +402,8 @@ RndTpmPrepare( { UINT64 rndTmp; UINT32 sz = sizeof(rndTmp); - if (rnd != NULL && rnd->Type == RndTypeTpm) { - return Tpm12GetRandom(&sz, (UINT8*)&rndTmp); + if (rnd != NULL && rnd->Type == RndTypeTpm && !EFI_ERROR(GetTpm())) { + return gTpm->GetRandom(gTpm, sz, (UINT8*)&rndTmp); } return EFI_NOT_READY; } @@ -414,9 +414,8 @@ RndTpmGetBytes( OUT UINT8 *buf, IN UINTN len) { - UINT32 sz = (UINT32)len; - if (rnd != NULL && rnd->Type == RndTypeTpm) { - return Tpm12GetRandom(&sz, buf); + if (rnd != NULL && rnd->Type == RndTypeTpm && !EFI_ERROR(GetTpm())) { + return gTpm->GetRandom(gTpm, (UINT32)len, buf); } return EFI_NOT_READY; } diff --git a/Library/DcsTpmLib/DcsTpmLib.inf b/Library/DcsTpmLib/DcsTpmLib.inf index 79ea0f7..0661129 100644 --- a/Library/DcsTpmLib/DcsTpmLib.inf +++ b/Library/DcsTpmLib/DcsTpmLib.inf @@ -27,6 +27,7 @@ [Sources.common] Tpm12.c + Tpm20.c [Packages] MdePkg/MdePkg.dec @@ -39,10 +40,13 @@ UefiLib PrintLib Tpm12DeviceLib + Tpm2DeviceLib + Tpm2CommandLib BaseCryptLib [Protocols] gEfiTcgProtocolGuid + gEfiTcg2ProtocolGuid # [Guids] diff --git a/Library/DcsTpmLib/Tpm12.c b/Library/DcsTpmLib/Tpm12.c index 502677b..02c8dd8 100644 --- a/Library/DcsTpmLib/Tpm12.c +++ b/Library/DcsTpmLib/Tpm12.c @@ -66,7 +66,10 @@ Sha1Hash( if (ctx == NULL) return EFI_BUFFER_TOO_SMALL; Sha1Init(ctx); Sha1Update(ctx, data, dataSize); - if (!Sha1Final(ctx, hash)) return EFI_DEVICE_ERROR; + if (!Sha1Final(ctx, hash)) { + MEM_FREE(ctx); + return EFI_DEVICE_ERROR; + } return EFI_SUCCESS; } @@ -1104,9 +1107,6 @@ Tpm12GetRandom( ////////////////////////////////////////////////////////////////////////// // Protocol ////////////////////////////////////////////////////////////////////////// -#define DCS_TPM_NV_INDEX 0x0DC5B -#define DCS_TPM_NV_SIZE 128 -#define DCS_TPM_PCR_LOCK 8 typedef struct _Password Password; @@ -1172,7 +1172,6 @@ DcsTpm12IsConfigured( return TRUE; } -#define TPM_OWNER_PWD_MAX 64 VOID AskTpmOwnerPwd( OUT CHAR16* ownerPass @@ -1250,15 +1249,15 @@ ActionTpm12PrintPcrs( return res; } -PMENU_ITEM gTpmMenu = NULL; -BOOLEAN gTpmMenuContinue = TRUE; +PMENU_ITEM mTpm12Menu = NULL; +BOOLEAN mTpm12MenuContinue = TRUE; EFI_STATUS -ActionTpmExit( +ActionTpm12Exit( IN VOID *ctx ) { - gTpmMenuContinue = FALSE; + mTpm12MenuContinue = FALSE; return EFI_SUCCESS; } @@ -1270,10 +1269,10 @@ DcsTpm12Configure( PMENU_ITEM item = NULL; EFI_STATUS res; item = DcsMenuAppend(item, L"Update TPM secret", 'u', ActionTpm12Update, NULL); - gTpmMenu = item; + mTpm12Menu = item; item = DcsMenuAppend(item, L"Delete TPM secret", 'd', ActionTpm12Clean, NULL); item = DcsMenuAppend(item, L"Print PCRs", 'p', ActionTpm12PrintPcrs, NULL); - item = DcsMenuAppend(item, L"Exit", 'e', ActionTpmExit, NULL); + item = DcsMenuAppend(item, L"Exit", 'e', ActionTpm12Exit, NULL); do { EFI_INPUT_KEY key; OUT_PRINT(L"TPM "); @@ -1290,11 +1289,11 @@ DcsTpm12Configure( ERR_PRINT(L"not configured"); } OUT_PRINT(L"\n"); - DcsMenuPrint(gTpmMenu); + DcsMenuPrint(mTpm12Menu); item = NULL; key.UnicodeChar = 0; while (item == NULL) { - item = gTpmMenu; + item = mTpm12Menu; key = GetKey(); while (item != NULL) { if (item->Select == key.UnicodeChar) break; @@ -1306,39 +1305,85 @@ DcsTpm12Configure( if (EFI_ERROR(res)) { ERR_PRINT(L"%r(%x),line %d\n", res, Tpm12RespCode(gTpm12Io), gCELine); } - } while (gTpmMenuContinue); + } while (mTpm12MenuContinue); return EFI_SUCCESS; } -DCS_TPM_PROTOCOL* gTpm = (DCS_TPM_PROTOCOL*)NULL; - EFI_STATUS -GetTpm() { - EFI_STATUS res; - res = InitTpm12(); - if (EFI_ERROR(res)) { - return res; +DcsTpm12GetRandom( + IN DCS_TPM_PROTOCOL* tpm, + IN UINT32 DataSize, + OUT UINT8 *Data + ) +{ + UINT32 remains = DataSize; + UINT32 gotBytes = 0; + UINT8 *rnd = Data; + EFI_STATUS res = EFI_SUCCESS; + while (remains > 0) + { + gotBytes = remains; + res = Tpm12GetRandom(&gotBytes, rnd); + if (EFI_ERROR(res)) return res; + rnd += gotBytes; + remains -= gotBytes; } - gTpm = (DCS_TPM_PROTOCOL*)MEM_ALLOC(sizeof(DCS_TPM_PROTOCOL)); - if (gTpm == NULL) return EFI_BUFFER_TOO_SMALL; - gTpm->IsConfigured = DcsTpm12IsConfigured; - gTpm->IsOpen = DcsTpm12IsOpen; - gTpm->Configure = DcsTpm12Configure; - gTpm->Apply = DcsTpm12Apply; - gTpm->Lock = DcsTpm12Lock; - return EFI_SUCCESS; + return res; } -EFI_STATUS -TpmMeasure( - IN VOID* data, - IN UINTN dataSz - ) { +EFI_STATUS +DcsTpm12Measure( + DCS_TPM_PROTOCOL* tpm, + IN UINTN index, + IN UINTN dataSz, + IN VOID* data + ) +{ EFI_STATUS res; TPM_DIGEST hash; + if (index > 0x10000) { + index = DCS_TPM_PCR_LOCK; + } CE(Sha1Hash(data, dataSz, (UINT8*)&hash)); - CE(Tpm12PcrExtend(DCS_TPM_PCR_LOCK, sizeof(hash), &hash)); + CE(Tpm12PcrExtend((UINT32)index, sizeof(hash), &hash)); err: return res; } + +DCS_TPM_PROTOCOL* gTpm = (DCS_TPM_PROTOCOL*)NULL; + +VOID +DcsInitTpm12( + IN OUT DCS_TPM_PROTOCOL* Tpm) +{ + Tpm->TpmVersion = 0x102; + Tpm->IsConfigured = DcsTpm12IsConfigured; + Tpm->IsOpen = DcsTpm12IsOpen; + Tpm->Configure = DcsTpm12Configure; + Tpm->Apply = DcsTpm12Apply; + Tpm->Lock = DcsTpm12Lock; + Tpm->Measure = DcsTpm12Measure; + Tpm->GetRandom = DcsTpm12GetRandom; +} + +EFI_STATUS +GetTpm() { + EFI_STATUS res; + res = InitTpm12(); + if (!EFI_ERROR(res)) { + gTpm = (DCS_TPM_PROTOCOL*)MEM_ALLOC(sizeof(DCS_TPM_PROTOCOL)); + if (gTpm == NULL) return EFI_BUFFER_TOO_SMALL; + DcsInitTpm12(gTpm); + return EFI_SUCCESS; + } + res = InitTpm20(); + if (!EFI_ERROR(res)) { + gTpm = (DCS_TPM_PROTOCOL*)MEM_ALLOC(sizeof(DCS_TPM_PROTOCOL)); + if (gTpm == NULL) return EFI_BUFFER_TOO_SMALL; + DcsInitTpm20(gTpm); + return EFI_SUCCESS; + } + return res; +} + diff --git a/Library/DcsTpmLib/Tpm20.c b/Library/DcsTpmLib/Tpm20.c new file mode 100644 index 0000000..3ddc4df --- /dev/null +++ b/Library/DcsTpmLib/Tpm20.c @@ -0,0 +1,906 @@ +/** @file +EFI TPM 2.0 DCS protocol + +Copyright (c) 2016 Disk Cryptography Services for EFI (DCS), Alex Kolotnikov + +This program and the accompanying materials are licensed and made available +under the terms and conditions of the GNU Lesser General Public License, version 3.0 (LGPL-3.0). + +The full text of the license may be found at +https://opensource.org/licenses/LGPL-3.0 +**/ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include "Library/DcsCfgLib.h" +#include + +#define DCS_TPM2_NV_INDEX (0x1000000 | DCS_TPM_NV_INDEX) +#define DCS_TPM2_NV_INDEX_PCRS (0x1100000 | DCS_TPM_NV_INDEX) + +EFI_STATUS Tcg2Ready = EFI_NOT_READY; +extern EFI_TCG2_PROTOCOL *mTcg2Protocol; + +EFI_STATUS +InitTpm20() { + if (EFI_ERROR(Tcg2Ready)) { + Tcg2Ready = Tpm2RequestUseTpm(); + } + return Tcg2Ready; +} + +EFI_STATUS +Sha256Hash( + IN VOID *data, + IN UINTN dataSize, + OUT UINT8 *hash + ) +{ + UINTN ctxSize; + VOID *ctx; + ctxSize = Sha256GetContextSize(); + ctx = MEM_ALLOC(ctxSize); + if (ctx == NULL) return EFI_BUFFER_TOO_SMALL; + Sha256Init(ctx); + Sha256Update(ctx, data, dataSize); + if (!Sha256Final(ctx, hash)) { + MEM_FREE(ctx); + return EFI_DEVICE_ERROR; + } + return EFI_SUCCESS; +} + +////////////////////////////////////////////////////////////////////////// +// Tests +////////////////////////////////////////////////////////////////////////// +/* +EFI_STATUS +Tpm20AuthSesseion() +{ + EFI_STATUS res = EFI_SUCCESS; + TPMI_DH_OBJECT TpmKey = TPM_RH_NULL; + TPMI_DH_ENTITY Bind = TPM_RH_NULL; + TPM2B_NONCE NonceCaller; + TPM2B_ENCRYPTED_SECRET Salt; + TPM_SE SessionType = TPM_SE_POLICY; + TPMT_SYM_DEF Symmetric; + TPMI_ALG_HASH AuthHash = TPM_ALG_SHA256; + TPMI_SH_AUTH_SESSION SessionHandle; + TPM2B_NONCE NonceTPM; + + SetMem(&NonceCaller, sizeof(NonceCaller), 0); + NonceCaller.size = 0x20; + Salt.size = 0; + Symmetric.algorithm = TPM_ALG_XOR; + Symmetric.keyBits.xor = TPM_ALG_SHA256; + + res = Tpm2StartAuthSession( + TpmKey, + Bind, + &NonceCaller, + &Salt, + SessionType, + &Symmetric, + AuthHash, + OUT &SessionHandle, + OUT &NonceTPM + ); + + res = Tpm2FlushContext(SessionHandle); + + return res; +} + +EFI_STATUS +Tpm2NvDefine() +{ + EFI_STATUS res = EFI_SUCCESS; + TPMI_RH_PROVISION AuthHandle = TPM_RH_OWNER; + TPMI_RH_NV_INDEX NvIndex = 0x1000001; + TPMS_AUTH_COMMAND AuthSession; + TPM2B_AUTH Auth; + TPM2B_NV_PUBLIC NvPublic; + + SetMem(&AuthSession, sizeof(AuthSession), 0); + AuthSession.sessionHandle = TPM_RS_PW; + AuthSession.nonce.size = 0; + AuthSession.hmac.size = (UINT16)AsciiStrLen("tpmoPwd"); + AsciiStrCpy(AuthSession.hmac.buffer, "tpmoPwd"); + + Auth.size = (UINT16)AsciiStrLen("tpmnPwd"); + AsciiStrCpy(Auth.buffer, "tpmnPwd"); + NvPublic.size = 4 + 2 + 4 + 2 + SHA256_DIGEST_SIZE + 2; + NvPublic.nvPublic.nvIndex = NvIndex; + NvPublic.nvPublic.nameAlg = TPM_ALG_SHA256; + NvPublic.nvPublic.attributes.TPMA_NV_POLICYREAD = 1; + NvPublic.nvPublic.attributes.TPMA_NV_POLICYWRITE = 1; + NvPublic.nvPublic.attributes.TPMA_NV_OWNERREAD = 1; + NvPublic.nvPublic.attributes.TPMA_NV_OWNERWRITE = 1; + NvPublic.nvPublic.attributes.TPMA_NV_NO_DA = 1; + NvPublic.nvPublic.authPolicy.size = SHA256_DIGEST_SIZE; + CE(Tpm20MakePolicyPcr(0xf, &NvPublic.nvPublic.authPolicy.buffer[0])); + NvPublic.nvPublic.dataSize = 64; + + CE(Tpm2NvDefineSpace( + IN AuthHandle, + IN &AuthSession, OPTIONAL + IN &Auth, + IN &NvPublic + )); + + CE(Tpm2NvUndefineSpace( + IN AuthHandle, + IN NvIndex, + IN &AuthSession OPTIONAL + )); + + return res; +err: + ERR_PRINT(L"NvDefineSpace(%d): %r\n", gCELine, res); + return res; +} + +EFI_STATUS +Tpm20NVRead() +{ + EFI_STATUS res = EFI_SUCCESS; + TPMI_RH_NV_AUTH AuthHandle = TPM_RH_OWNER; + TPMI_RH_NV_INDEX NvIndex = 0x1000000; + TPMS_AUTH_COMMAND AuthSession; + TPM2B_MAX_BUFFER InData; + UINT16 Offset = 0; + UINT16 Size = 10; + TPM2B_MAX_BUFFER OutData; + + SetMem(&AuthSession, sizeof(AuthSession), 0); + AuthSession.sessionHandle = TPM_RS_PW; + AuthSession.nonce.size = 0; + AuthSession.hmac.size = (UINT16)AsciiStrLen("tpmoPwd"); + AsciiStrCpy(AuthSession.hmac.buffer, "tpmoPwd"); + // AuthSession.sessionAttributes = 0; + InData.size = 5; + AsciiStrCpy(InData.buffer, "54321"); + + res = Tpm2NvWrite( + IN AuthHandle, + IN NvIndex, + IN &AuthSession, OPTIONAL + IN &InData, + IN Offset + ); + + res = Tpm2NvRead( + IN AuthHandle, + IN NvIndex, + IN &AuthSession, OPTIONAL + IN Size, + IN Offset, + &OutData + ); + + return res; +} +*/ + +////////////////////////////////////////////////////////////////////////// +// TPM 2.0 Helpers +////////////////////////////////////////////////////////////////////////// +EFI_STATUS +DcsTpm2PcrRead( + IN UINT32 PcrIndex, + OUT void *PcrValue + ) +{ + EFI_STATUS res = EFI_SUCCESS; + TPML_PCR_SELECTION PcrSelectionIn = { 0 }; + UINT32 PcrUpdateCounter; + TPML_PCR_SELECTION PcrSelectionOut; + PcrSelectionIn.count = 1; + PcrSelectionIn.pcrSelections[0].hash = TPM_ALG_SHA256; + PcrSelectionIn.pcrSelections[0].sizeofSelect = 3; + PcrSelectionIn.pcrSelections[0].pcrSelect[0] = (PcrIndex < 8) ? 1 << PcrIndex : 0; + PcrSelectionIn.pcrSelections[0].pcrSelect[1] = (PcrIndex > 7) && (PcrIndex < 16) ? 1 << (PcrIndex - 8) : 0; + PcrSelectionIn.pcrSelections[0].pcrSelect[2] = (PcrIndex > 15) ? 1 << (PcrIndex - 16) : 0; + + res = Tpm2PcrRead(&PcrSelectionIn, &PcrUpdateCounter, &PcrSelectionOut, PcrValue); + return res; +} + +#pragma pack(1) +typedef struct { + UINT32 cmd; + UINT32 count; + TPM_ALG_ID hashType; + UINT8 pcrCount; + UINT8 pcrSelection[3]; + UINT8 hash[SHA256_DIGEST_SIZE]; +} TPM_CC_POLICYPCR; +#pragma pack() + +EFI_STATUS +Tpm2MakePolicyPcr( + IN UINT32 pcrMask, + OUT UINT8 *hash + ) +{ + EFI_STATUS res = EFI_SUCCESS; + TPML_DIGEST PcrValue; + UINTN ctxSize; + VOID *ctx; + UINT32 tmp; + UINTN i; + TPM_CC_POLICYPCR polycyPcr; + + polycyPcr.cmd = SwapBytes32(TPM_CC_PolicyPCR); + polycyPcr.count = SwapBytes32(1); + polycyPcr.hashType = SwapBytes16(TPM_ALG_SHA256); + polycyPcr.pcrCount = 3; + polycyPcr.pcrSelection[0] = pcrMask & 0xFF; + polycyPcr.pcrSelection[1] = (pcrMask >> 8) & 0xFF; + polycyPcr.pcrSelection[2] = (pcrMask >> 16) & 0xFF; + + ctxSize = Sha256GetContextSize(); + ctx = MEM_ALLOC(ctxSize); + if (ctx == NULL) return EFI_BUFFER_TOO_SMALL; + Sha256Init(ctx); + tmp = pcrMask; + for (i = 0; i < 32; ++i) { + if ((tmp & 1) == 1) { + CE(DcsTpm2PcrRead((UINT32)i, &PcrValue)); + Sha256Update(ctx, PcrValue.digests[0].buffer, SHA256_DIGEST_SIZE); + } + tmp >>= 1; + } + CE(Sha256Final(ctx, &polycyPcr.hash[0]) ? EFI_SUCCESS: EFI_DEVICE_ERROR); + Sha256Init(ctx); + SetMem(hash, SHA256_DIGEST_SIZE, 0); + Sha256Update(ctx, hash, SHA256_DIGEST_SIZE); + Sha256Update(ctx, &polycyPcr, sizeof(polycyPcr)); + CE(Sha256Final(ctx, &hash[0]) ? EFI_SUCCESS : EFI_DEVICE_ERROR); + +err: + MEM_FREE(ctx); + return res; +} + +#pragma pack(1) +typedef struct { + TPM2_COMMAND_HEADER Header; + UINT16 Size; +} TPM2_GET_RANDOM_COMMAND; + +typedef struct { + TPM2_RESPONSE_HEADER Header; + TPM2B_MAX_BUFFER Data; +} TPM2_GET_RANDOM_RESPONSE; +#pragma pack() + +EFI_STATUS +Tpm2GetRandom( + IN UINTN size, + OUT VOID* data) +{ + EFI_STATUS res = EFI_SUCCESS; + UINTN remains = size; + UINTN request; + UINTN gotBytes; + UINT8 *rnd = data; + TPM2_GET_RANDOM_COMMAND SendBuffer; + TPM2_GET_RANDOM_RESPONSE RecvBuffer; + UINT32 SendBufferSize; + UINT32 RecvBufferSize; + TPM_RC ResponseCode; + + SendBufferSize = (UINT32) sizeof(SendBuffer); + SendBuffer.Header.tag = SwapBytes16(TPM_ST_NO_SESSIONS); + SendBuffer.Header.commandCode = SwapBytes32(TPM_CC_GetRandom); + SendBuffer.Header.paramSize = SwapBytes32(SendBufferSize); + + while (remains > 0) { + request = (remains < sizeof(RecvBuffer.Data.buffer)) ? remains : sizeof(RecvBuffer.Data.buffer); + SendBuffer.Size = SwapBytes16((UINT16)request); + RecvBufferSize = (UINT32) sizeof(RecvBuffer); + + res = Tpm2SubmitCommand(SendBufferSize, (UINT8 *)&SendBuffer, &RecvBufferSize, (UINT8 *)&RecvBuffer); + if (EFI_ERROR(res)) { + return res; + } + + if (RecvBufferSize < sizeof(TPM2_RESPONSE_HEADER)) { + return EFI_DEVICE_ERROR; + } + ResponseCode = SwapBytes32(RecvBuffer.Header.responseCode); + if (ResponseCode != TPM_RC_SUCCESS) { + return EFI_DEVICE_ERROR; + } + gotBytes = SwapBytes16(RecvBuffer.Data.size); + CopyMem(rnd, &RecvBuffer.Data.buffer[0], gotBytes); + remains -= gotBytes; + rnd += gotBytes; + } + return res; +} + +EFI_STATUS +Tpm2Measure( + IN UINT32 index, + IN UINTN size, + IN VOID* data) +{ + EFI_STATUS res = EFI_SUCCESS; + TPMI_DH_PCR PcrHandle = index; + TPML_DIGEST_VALUES Digests; + + Digests.count = 2; + Digests.digests[0].hashAlg = TPM_ALG_SHA256; + Digests.digests[1].hashAlg = TPM_ALG_SHA1; + CE(Sha256Hash(data, size, &Digests.digests[0].digest.sha256[0])); + CE(Sha1Hash(data, size, &Digests.digests[1].digest.sha1[0])); + + CE(Tpm2PcrExtend(PcrHandle,&Digests)); + +err: + return res; +} + +EFI_STATUS +DcsTpm2NVReadPcrMask( + UINT32* mask + ) +{ + EFI_STATUS res = EFI_SUCCESS; + TPMI_RH_NV_AUTH AuthHandle = DCS_TPM2_NV_INDEX_PCRS; + TPMI_RH_NV_INDEX NvIndex = DCS_TPM2_NV_INDEX_PCRS; + TPMS_AUTH_COMMAND AuthSession; + UINT16 Offset = 0; + UINT16 Size = 4; + TPM2B_MAX_BUFFER OutData; + + SetMem(&AuthSession, sizeof(AuthSession), 0); + AuthSession.sessionHandle = TPM_RS_PW; + AuthSession.nonce.size = 0; + AuthSession.hmac.size = (UINT16)0; + + CE(Tpm2NvRead( + IN AuthHandle, + IN NvIndex, + IN &AuthSession, OPTIONAL + IN Size, + IN Offset, + &OutData + )); + CopyMem(mask, &OutData.buffer[0], 4); + *mask = SwapBytes32(*mask); + +err: + return res; +} + +VOID +Tpm2AuthSessionOwnerPrepare( + IN UINT8 *OwnerPwd, + IN UINT16 OwnerPwdSize, + OUT TPMS_AUTH_COMMAND *AuthSession + ) { + SetMem(AuthSession, sizeof(*AuthSession), 0); + AuthSession->sessionHandle = TPM_RS_PW; + AuthSession->nonce.size = 0; + AuthSession->hmac.size = (UINT16)OwnerPwdSize; + CopyMem(&AuthSession->hmac.buffer[0], OwnerPwd, OwnerPwdSize); +// AuthSession->hmac.size = (UINT16)AsciiStrLen("tpmoPwd"); +// AsciiStrCpy(AuthSession->hmac.buffer, "tpmoPwd"); + +} + +EFI_STATUS +DcsTpm2Clean( + UINT8 *OwnerPwd, + UINT16 OwnerPwdSize + ) +{ + EFI_STATUS res = EFI_SUCCESS; + TPMS_AUTH_COMMAND AuthSession; + + Tpm2AuthSessionOwnerPrepare(OwnerPwd, OwnerPwdSize, &AuthSession); + + res = Tpm2NvUndefineSpace( + TPM_RH_OWNER, + DCS_TPM2_NV_INDEX_PCRS, + IN &AuthSession OPTIONAL + ); + + CE(Tpm2NvUndefineSpace( + TPM_RH_OWNER, + DCS_TPM2_NV_INDEX, + IN &AuthSession OPTIONAL + )); + +err: + return res; +} + +EFI_STATUS +DcsTpm2NvDefine( + UINT8 *OwnerPwd, + UINT16 OwnerPwdSize, + UINT32 PcrMask, + UINT8 *Secret + ) +{ + EFI_STATUS res = EFI_SUCCESS; + TPMS_AUTH_COMMAND AuthSession; + TPM2B_AUTH Auth; + TPM2B_NV_PUBLIC NvPublic; + TPM2B_MAX_BUFFER InData; + + DcsTpm2Clean(OwnerPwd, OwnerPwdSize); + Tpm2AuthSessionOwnerPrepare(OwnerPwd, OwnerPwdSize, &AuthSession); + + SetMem(&NvPublic, sizeof(NvPublic), 0); + SetMem(&Auth, sizeof(Auth), 0); + Auth.size = (UINT16)0; + NvPublic.size = 4 + 2 + 4 + 2 + SHA256_DIGEST_SIZE + 2; + NvPublic.nvPublic.nvIndex = DCS_TPM2_NV_INDEX; + NvPublic.nvPublic.nameAlg = TPM_ALG_SHA256; + NvPublic.nvPublic.attributes.TPMA_NV_POLICYREAD = 1; + NvPublic.nvPublic.attributes.TPMA_NV_POLICYWRITE = 1; + NvPublic.nvPublic.attributes.TPMA_NV_OWNERREAD = 1; + NvPublic.nvPublic.attributes.TPMA_NV_OWNERWRITE = 1; + NvPublic.nvPublic.attributes.TPMA_NV_NO_DA = 1; + NvPublic.nvPublic.authPolicy.size = SHA256_DIGEST_SIZE; + CE(Tpm2MakePolicyPcr(PcrMask, &NvPublic.nvPublic.authPolicy.buffer[0])); + NvPublic.nvPublic.dataSize = DCS_TPM_NV_SIZE; + + CE(Tpm2NvDefineSpace( + IN TPM_RH_OWNER, + IN &AuthSession, OPTIONAL + IN &Auth, + IN &NvPublic + )); + + SetMem(&NvPublic, sizeof(NvPublic), 0); + SetMem(&Auth, sizeof(Auth), 0); + Auth.size = (UINT16)0; + NvPublic.size = 4 + 2 + 4 + 2 + 2; + NvPublic.nvPublic.nvIndex = DCS_TPM2_NV_INDEX_PCRS; + NvPublic.nvPublic.nameAlg = TPM_ALG_SHA256; + NvPublic.nvPublic.attributes.TPMA_NV_OWNERREAD = 1; + NvPublic.nvPublic.attributes.TPMA_NV_OWNERWRITE = 1; + NvPublic.nvPublic.attributes.TPMA_NV_AUTHREAD = 1; + NvPublic.nvPublic.attributes.TPMA_NV_NO_DA = 1; + NvPublic.nvPublic.authPolicy.size = 0; + NvPublic.nvPublic.dataSize = 4; + + CE(Tpm2NvDefineSpace( + IN TPM_RH_OWNER, + IN &AuthSession, OPTIONAL + IN &Auth, + IN &NvPublic + )); + + InData.size = DCS_TPM_NV_SIZE; + CopyMem(InData.buffer, Secret, DCS_TPM_NV_SIZE); + + CE(Tpm2NvWrite( + IN TPM_RH_OWNER, + IN DCS_TPM2_NV_INDEX, + IN &AuthSession, OPTIONAL + IN &InData, + IN 0 + )); + + InData.size = 4; + PcrMask = SwapBytes32(PcrMask); + CopyMem(InData.buffer, &PcrMask, 4); + + CE(Tpm2NvWrite( + IN TPM_RH_OWNER, + IN DCS_TPM2_NV_INDEX_PCRS, + IN &AuthSession, OPTIONAL + IN &InData, + IN 0 + )); + +err: + return res; +} + +#pragma pack(1) +typedef struct { + TPM2_COMMAND_HEADER Header; + UINT32 Handle; + UINT16 auth; + UINT32 count; + TPM_ALG_ID hashType; + UINT8 pcrCount; + UINT8 pcrSelection[3]; +} TPM2_POLICYPCR_COMMAND; + +typedef struct { + TPM2_RESPONSE_HEADER Header; +} TPM2_POLICYPCR_RESPONSE; +#pragma pack() + +EFI_STATUS +DcsTpm2NvRead( + UINT8 *Secret + ) +{ + EFI_STATUS res; + TPMI_SH_AUTH_SESSION SessionHandle = 0; + UINT32 PcrMask, + + CE(DcsTpm2NVReadPcrMask(&PcrMask)); + + { + TPMI_DH_OBJECT TpmKey = TPM_RH_NULL; + TPMI_DH_ENTITY Bind = TPM_RH_NULL; + TPM2B_NONCE NonceCaller; + TPM2B_ENCRYPTED_SECRET Salt; + TPM_SE SessionType = TPM_SE_POLICY; + TPMT_SYM_DEF Symmetric; + TPMI_ALG_HASH AuthHash = TPM_ALG_SHA256; + TPM2B_NONCE NonceTPM; + + SetMem(&NonceCaller, sizeof(NonceCaller), 0); + NonceCaller.size = 0x20; + Salt.size = 0; + Symmetric.algorithm = TPM_ALG_XOR; + Symmetric.keyBits.xor = TPM_ALG_SHA256; + + CE(Tpm2StartAuthSession( + TpmKey, + Bind, + &NonceCaller, + &Salt, + SessionType, + &Symmetric, + AuthHash, + OUT &SessionHandle, + OUT &NonceTPM + )); + + { + TPM2_POLICYPCR_COMMAND SendBuffer; + TPM2_POLICYPCR_RESPONSE RecvBuffer; + UINT32 SendBufferSize; + UINT32 RecvBufferSize; + TPM_RC ResponseCode; + TPMS_AUTH_COMMAND AuthSession; + TPM2B_MAX_BUFFER OutData; + + SetMem(&SendBuffer, sizeof(SendBuffer), 0); + SetMem(&RecvBuffer, sizeof(RecvBuffer), 0); + RecvBufferSize = (UINT32) sizeof(RecvBuffer); + SendBufferSize = (UINT32) sizeof(SendBuffer); + + SendBuffer.Header.tag = SwapBytes16(TPM_ST_NO_SESSIONS); + SendBuffer.Header.commandCode = SwapBytes32(TPM_CC_PolicyPCR); + SendBuffer.Header.paramSize = SwapBytes32(SendBufferSize); + SendBuffer.Handle = SwapBytes32(SessionHandle); + SendBuffer.auth = 0; + SendBuffer.hashType = SwapBytes16(TPM_ALG_SHA256); + SendBuffer.count = SwapBytes32(1); + SendBuffer.pcrCount = 3; + SendBuffer.pcrSelection[0] = (PcrMask) & 0xFF; + SendBuffer.pcrSelection[1] = ((PcrMask) >> 8) & 0xFF; + SendBuffer.pcrSelection[2] = ((PcrMask) >> 16) & 0xFF; + res = Tpm2SubmitCommand(SendBufferSize, (UINT8 *)&SendBuffer, &RecvBufferSize, (UINT8 *)&RecvBuffer); + if (EFI_ERROR(res)) { + return res; + } + + if (RecvBufferSize < sizeof(TPM2_RESPONSE_HEADER)) { + res = EFI_DEVICE_ERROR; + goto err; + } + ResponseCode = SwapBytes32(RecvBuffer.Header.responseCode); + if (ResponseCode != TPM_RC_SUCCESS) { + res = EFI_DEVICE_ERROR; + goto err; + } + + SetMem(&AuthSession, sizeof(AuthSession), 0); + AuthSession.sessionHandle = SessionHandle; + AuthSession.nonce.size = SHA256_DIGEST_SIZE; + AuthSession.hmac.size = 0; + + CE(Tpm2NvRead( + DCS_TPM2_NV_INDEX, + DCS_TPM2_NV_INDEX, + &AuthSession, + DCS_TPM_NV_SIZE, + 0, + OUT &OutData + )); + + CopyMem(Secret, &OutData.buffer[0], DCS_TPM_NV_SIZE); + SetMem(&OutData, sizeof(OutData), 0); + } + } +err: + if (SessionHandle != 0) { + Tpm2FlushContext(SessionHandle); + } + return res; +} + +////////////////////////////////////////////////////////////////////////// +// PCRs +////////////////////////////////////////////////////////////////////////// +EFI_STATUS +DcsTpm2PrintPCR( + IN UINT32 PcrIndex) +{ + TPML_DIGEST PcrValue; + EFI_STATUS Status; + OUT_PRINT(L"%HPCR%02d%N ", PcrIndex); + Status = DcsTpm2PcrRead(PcrIndex, &PcrValue); + if (EFI_ERROR(Status)) { + ERR_PRINT(L"%r(%x)\n", Status); // , Tpm12RespCode(gTpm12Io)); + return Status; + } + PrintBytes(PcrValue.digests[0].buffer, PcrValue.digests[0].size); + OUT_PRINT(L"\n"); + return EFI_SUCCESS; +} + +EFI_STATUS +DcsTpm2DumpPcrs( + IN UINT32 sPcr, + IN UINT32 ePcr) +{ + UINT32 i; + EFI_STATUS Status = EFI_SUCCESS; + for (i = sPcr; i <= ePcr; ++i) { + Status = DcsTpm2PrintPCR(i); + if (EFI_ERROR(Status)) { + return Status; + } + } + return Status; +} + +////////////////////////////////////////////////////////////////////////// +// DCS TPM 2.0 Protocol +////////////////////////////////////////////////////////////////////////// +BOOLEAN +DcsTpm2IsConfigured( + DCS_TPM_PROTOCOL *tpm + ) +{ + EFI_STATUS res = EFI_SUCCESS; + TPMI_RH_NV_INDEX NvIndex = 0x1000000 | DCS_TPM_NV_INDEX; + TPM2B_NV_PUBLIC NvPublic; + TPM2B_NAME NvName; + UINT32 PcrMask; + + if (EFI_ERROR(res = DcsTpm2NVReadPcrMask(&PcrMask)) || + EFI_ERROR(res = Tpm2NvReadPublic(NvIndex, &NvPublic, &NvName)) || + (NvPublic.nvPublic.dataSize != DCS_TPM_NV_SIZE) || + (NvPublic.nvPublic.attributes.TPMA_NV_WRITTEN == 0) + ) { + return FALSE; + } + + return TRUE; +} + +EFI_STATUS +DcsTpm2GetRandom( + IN DCS_TPM_PROTOCOL* tpm, + IN UINT32 DataSize, + OUT UINT8 *Data + ) +{ + return Tpm2GetRandom(DataSize, Data); +} + +EFI_STATUS +DcsTpm2Measure( + DCS_TPM_PROTOCOL* tpm, + IN UINTN index, + IN UINTN dataSz, + IN VOID* data + ) +{ + if (index > 0x10000) { + index = DCS_TPM_PCR_LOCK; + } + return Tpm2Measure((UINT32)index, dataSz, data); +} + +EFI_STATUS +DcsTpm2Lock( + DCS_TPM_PROTOCOL* tpm + ) +{ + UINT32 lock = 1; + return Tpm2Measure(DCS_TPM_PCR_LOCK, sizeof(lock), &lock); +} + +BOOLEAN +DcsTpm2IsOpen( + DCS_TPM_PROTOCOL *tpm + ) +{ + EFI_STATUS res = EFI_SUCCESS; + CHAR8 data[DCS_TPM_NV_SIZE]; + res = DcsTpm2NvRead(data); + ZeroMem(data, DCS_TPM_NV_SIZE); + return !EFI_ERROR(res); +} + +typedef struct _Password Password; +extern VOID +ApplyKeyFile( + IN OUT Password* password, + IN CHAR8* keyfileData, + IN UINTN keyfileDataSize + ); + +EFI_STATUS +DcsTpm2Apply( + DCS_TPM_PROTOCOL *tpm, + OUT VOID* pwd + ) +{ + EFI_STATUS res = EFI_SUCCESS; + CHAR8 data[DCS_TPM_NV_SIZE]; + res = DcsTpm2NvRead(data); + if (EFI_ERROR(res)) return res; + ApplyKeyFile(pwd, data, DCS_TPM_NV_SIZE); + ZeroMem(data, DCS_TPM_NV_SIZE); + return EFI_SUCCESS; +} + +EFI_STATUS +ActionTpm2PrintPcrs( + IN VOID *ctx + ) +{ + EFI_STATUS res = EFI_SUCCESS; + UINTN i; + UINT32 pcrMask = 0x1FF; + UINT32 tmp; + + DcsTpm2NVReadPcrMask(&pcrMask); + pcrMask = AskPcrsMask(pcrMask); + tmp = pcrMask; + for (i = 0; i < 32; ++i) { + if ((tmp & 1) == 1) { + DcsTpm2PrintPCR((UINT32)i); + } + tmp >>= 1; + } + return res; +} + +EFI_STATUS +ActionTpm2Clean( + IN VOID *ctx + ) +{ + EFI_STATUS res; + CHAR16 ownerPass[TPM_OWNER_PWD_MAX]; + AskTpmOwnerPwd(ownerPass); + CE(DcsTpm2Clean((UINT8*)ownerPass, (UINT16)StrLen(ownerPass) * 2)); +err: + return res; +} + +EFI_STATUS +ActionTpm2Update( + IN VOID *ctx + ) +{ + EFI_STATUS res; + CHAR16 ownerPass[TPM_OWNER_PWD_MAX]; + UINT32 pcrMask; + UINT8 data[DCS_TPM_NV_SIZE]; + UINT8 v_data[DCS_TPM_NV_SIZE]; + + CE(gRnd == NULL ? EFI_NOT_READY : EFI_SUCCESS); + CE(gRnd->GetBytes(gRnd, data, sizeof(data))); + + AskTpmOwnerPwd(ownerPass); + pcrMask = AskPcrsMask(0x137); + + res = DcsTpm2NvDefine((UINT8*)ownerPass, (UINT16)StrLen(ownerPass) * 2,pcrMask, data); + + res = DcsTpm2NvRead(v_data); + if (CompareMem(v_data, data, DCS_TPM_NV_SIZE) != 0) { + res = EFI_CRC_ERROR; + } + + ZeroMem(v_data, DCS_TPM_NV_SIZE); + ZeroMem(data, DCS_TPM_NV_SIZE); + +err: + return res; +} + +PMENU_ITEM mTpm2Menu = NULL; +BOOLEAN mTpm2MenuContinue = TRUE; + +EFI_STATUS +ActionTpm2Exit( + IN VOID *ctx + ) +{ + mTpm2MenuContinue = FALSE; + return EFI_SUCCESS; +} + + +EFI_STATUS +DcsTpm2Configure( + IN DCS_TPM_PROTOCOL* tpm + ) { + PMENU_ITEM item = NULL; + EFI_STATUS res; + item = DcsMenuAppend(item, L"Update TPM secret", 'u', ActionTpm2Update, NULL); + mTpm2Menu = item; + item = DcsMenuAppend(item, L"Delete TPM secret", 'd', ActionTpm2Clean, NULL); + item = DcsMenuAppend(item, L"Print PCRs", 'p', ActionTpm2PrintPcrs, NULL); + item = DcsMenuAppend(item, L"Exit", 'e', ActionTpm2Exit, NULL); + do { + EFI_INPUT_KEY key; + OUT_PRINT(L"TPM "); + if (tpm->IsConfigured(tpm)) { + OUT_PRINT(L"%Vconfigured%N, "); + if (tpm->IsOpen(tpm)) { + OUT_PRINT(L"%Vopen%N"); + } + else { + ERR_PRINT(L"locked"); + } + } + else { + ERR_PRINT(L"not configured"); + } + OUT_PRINT(L"\n"); + DcsMenuPrint(mTpm2Menu); + item = NULL; + key.UnicodeChar = 0; + while (item == NULL) { + item = mTpm2Menu; + key = GetKey(); + while (item != NULL) { + if (item->Select == key.UnicodeChar) break; + item = item->Next; + } + } + OUT_PRINT(L"%c\n", key.UnicodeChar); + res = item->Action(item->Context); + if (EFI_ERROR(res)) { + ERR_PRINT(L"%r,line %d\n", res, gCELine); + } + } while (mTpm2MenuContinue); + return EFI_SUCCESS; +} + +VOID +DcsInitTpm20( + IN OUT DCS_TPM_PROTOCOL* Tpm) +{ + Tpm->TpmVersion = 0x200; + Tpm->IsConfigured = DcsTpm2IsConfigured; + Tpm->IsOpen = DcsTpm2IsOpen; + Tpm->Configure = DcsTpm2Configure; + Tpm->Apply = DcsTpm2Apply; + Tpm->Lock = DcsTpm2Lock; + Tpm->Measure = DcsTpm2Measure; + Tpm->GetRandom = DcsTpm2GetRandom; +} -- cgit v1.2.3