| diff --git a/tpm/tpm_cmd_handler.c b/tpm/tpm_cmd_handler.c |
| index 0fabf98..69511d1 100644 |
| --- a/tpm/tpm_cmd_handler.c |
| +++ b/tpm/tpm_cmd_handler.c |
| @@ -3343,6 +3343,39 @@ static TPM_RESULT execute_TPM_ParentSignEK(TPM_REQUEST *req, TPM_RESPONSE *rsp) |
| return res; |
| } |
| |
| +static TPM_RESULT execute_TPM_DeepQuote(TPM_REQUEST *req, TPM_RESPONSE *rsp) |
| +{ |
| + TPM_NONCE nonce; |
| + TPM_RESULT res; |
| + UINT32 sigSize; |
| + BYTE *sig; |
| + BYTE *ptr; |
| + UINT32 len; |
| + TPM_PCR_SELECTION myPCR; |
| + TPM_PCR_SELECTION ptPCR; |
| + |
| + tpm_compute_in_param_digest(req); |
| + |
| + ptr = req->param; |
| + len = req->paramSize; |
| + if (tpm_unmarshal_TPM_NONCE(&ptr, &len, &nonce) |
| + || tpm_unmarshal_TPM_PCR_SELECTION(&ptr, &len, &myPCR) |
| + || tpm_unmarshal_TPM_PCR_SELECTION(&ptr, &len, &ptPCR) |
| + || len != 0) return TPM_BAD_PARAMETER; |
| + |
| + res = TPM_DeepQuote(&nonce, &myPCR, &ptPCR, &req->auth1, &sigSize, &sig); |
| + if (res != TPM_SUCCESS) return res; |
| + rsp->paramSize = len = sigSize; |
| + rsp->param = ptr = tpm_malloc(len); |
| + if (ptr == NULL || tpm_marshal_BLOB(&ptr, &len, sig, sigSize)) { |
| + tpm_free(rsp->param); |
| + res = TPM_FAIL; |
| + } |
| + tpm_free(sig); |
| + |
| + return res; |
| +} |
| + |
| static void tpm_setup_rsp_auth(TPM_COMMAND_CODE ordinal, TPM_RESPONSE *rsp) |
| { |
| tpm_hmac_ctx_t hmac; |
| @@ -4098,6 +4131,11 @@ void tpm_execute_command(TPM_REQUEST *req, TPM_RESPONSE *rsp) |
| res = execute_TPM_ParentSignEK(req, rsp); |
| break; |
| |
| + case TPM_ORD_DeepQuote: |
| + debug("[TPM_ORD_DeepQuote]"); |
| + res = execute_TPM_DeepQuote(req, rsp); |
| + break; |
| + |
| default: |
| #ifdef MTM_EMULATOR |
| res = mtm_execute_command(req, rsp); |
| diff --git a/tpm/tpm_commands.h b/tpm/tpm_commands.h |
| index 7fef934..328d1be 100644 |
| --- a/tpm/tpm_commands.h |
| +++ b/tpm/tpm_commands.h |
| @@ -3071,6 +3071,25 @@ TPM_RESULT TPM_ParentSignEK( |
| BYTE **sig |
| ); |
| |
| +/** |
| + * TPM_DeepQuote - gets a hardware TPM quote of a vTPM's PCRs |
| + * @externalData: [in] AntiReplay nonce to prevent replay of messages |
| + * @myPCR: [in] PCR selection for the virtual TPM |
| + * @ptPCR: [in] PCR selection for the hardware TPM |
| + * @auth1: [in, out] Authorization protocol parameters |
| + * @sigSize: [out] The length of the returned digital signature |
| + * @sig: [out] The resulting digital signature and PCR values |
| + * Returns: TPM_SUCCESS on success, a TPM error code otherwise. |
| + */ |
| +TPM_RESULT TPM_DeepQuote( |
| + TPM_NONCE *externalData, |
| + TPM_PCR_SELECTION *myPCR, |
| + TPM_PCR_SELECTION *ptPCR, |
| + TPM_AUTH *auth1, |
| + UINT32 *sigSize, |
| + BYTE **sig |
| +); |
| + |
| /* |
| * Error handling |
| * [tpm_error.c] |
| diff --git a/tpm/tpm_credentials.c b/tpm/tpm_credentials.c |
| index 01f29e6..c0d62e7 100644 |
| --- a/tpm/tpm_credentials.c |
| +++ b/tpm/tpm_credentials.c |
| @@ -211,3 +211,49 @@ TPM_RESULT TPM_ParentSignEK(TPM_NONCE *externalData, TPM_PCR_SELECTION *sel, |
| free_TPM_PUBKEY(pubKey); |
| return res; |
| } |
| + |
| +static const BYTE dquot_hdr[] = { |
| + 0, 0, 0, 0, 'D', 'Q', 'U', 'T' |
| +}; |
| + |
| +TPM_RESULT TPM_DeepQuote(TPM_NONCE *externalData, TPM_PCR_SELECTION *myPCR, |
| + TPM_PCR_SELECTION *ptPCR, TPM_AUTH *auth1, |
| + UINT32 *sigSize, BYTE **sig) |
| +{ |
| + TPM_RESULT res; |
| + TPM_DIGEST hres; |
| + TPM_PCR_INFO_SHORT pcrData; |
| + tpm_sha1_ctx_t ctx; |
| + BYTE *buf, *ptr; |
| + UINT32 size, len; |
| + |
| + info("TPM_DeepQuote()"); |
| + |
| + res = tpm_verify_auth(auth1, tpmData.permanent.data.ownerAuth, TPM_KH_OWNER); |
| + if (res != TPM_SUCCESS) return res; |
| + |
| + res = tpm_compute_pcr_digest(myPCR, &pcrData.digestAtRelease, NULL); |
| + if (res != TPM_SUCCESS) return res; |
| + |
| + pcrData.pcrSelection.sizeOfSelect = myPCR->sizeOfSelect; |
| + memcpy(pcrData.pcrSelection.pcrSelect, myPCR->pcrSelect, myPCR->sizeOfSelect); |
| + pcrData.localityAtRelease = 1 << tpmData.stany.flags.localityModifier; |
| + |
| + size = len = sizeof_TPM_PCR_INFO_SHORT(pcrData); |
| + buf = ptr = tpm_malloc(size); |
| + if (buf == NULL) return TPM_NOSPACE; |
| + if (tpm_marshal_TPM_PCR_INFO_SHORT(&ptr, &len, &pcrData)) |
| + return TPM_FAIL; |
| + |
| + tpm_sha1_init(&ctx); |
| + tpm_sha1_update(&ctx, dquot_hdr, 8); |
| + tpm_sha1_update(&ctx, externalData->nonce, 20); |
| + tpm_sha1_update(&ctx, buf, size); |
| + tpm_sha1_final(&ctx, hres.digest); |
| + |
| + tpm_free(buf); |
| + |
| + res = VTPM_GetParentQuote(&hres, ptPCR, sigSize, sig); |
| + |
| + return res; |
| +} |
| diff --git a/tpm/tpm_structures.h b/tpm/tpm_structures.h |
| index b0f4625..dfb1894 100644 |
| --- a/tpm/tpm_structures.h |
| +++ b/tpm/tpm_structures.h |
| @@ -660,6 +660,42 @@ typedef struct tdTPM_CMK_MA_APPROVAL { |
| |
| /* VTPM-only commands: */ |
| /* |
| + * Deep Quote - Create quote of PCRs |
| + * Input: |
| + * TPM_TAG tag TPM_TAG_RQU_AUTH1_COMMAND |
| + * UINT32 paramSize Total size of request |
| + * TPM_COMMAND_CODE ordinal TPM_ORD_DeepQuote |
| + * TPM_NONCE externData 20 bytes of external data |
| + * TPM_PCR_SELECTION vtSel PCR selection for virtual TPM |
| + * TPM_PCR_SELECTION ptSel PCR selection for physical TPM |
| + * --- |
| + * UINT32 authHandle Owner authorization session (OIAP) |
| + * TPM_NONCE nonceOdd Nonce for authHandle |
| + * BOOL continueAuth Continue flag for authHandle |
| + * TPM_AUTHDATA privAuth Authorization digest for command |
| + * |
| + * Output: |
| + * TPM_TAG tag TPM_TAG_RSP_AUTH1_COMMAND |
| + * UINT32 paramSize Total size of response |
| + * TPM_RESULT returnCode Return code of the operation |
| + * BYTE[] sig Signature provided by physical TPM |
| + * TPM_PCRVALUE[] pcrValue Values of hardware PCRs used in the quote |
| + * --- |
| + * TPM_NONCE nonceEven Nonce for authHandle |
| + * BOOL continueAuth Continue flag for authHandle |
| + * TPM_AUTHDATA resAuth Authorization digest for response |
| + * |
| + * The values of the virutal TPM's PCRs are not included in the response. |
| + * The signature is a standard TPM_Quote response from the physical TPM; its |
| + * externalData is the SHA1 hash of the following structure: |
| + * TPM_STRUCT_VER version MUST be 0.0.0.0 |
| + * BYTE[4] fixed MUST be the string "DQUT" |
| + * TPM_NONCE externData From input to the deep quote |
| + * TPM_PCR_INFO_SHORT pcrData Virtual TPM's PCRs |
| + */ |
| +#define TPM_ORD_DeepQuote (TPM_VENDOR_COMMAND | TPM_ORD_Quote) |
| + |
| +/* |
| * ParentSignEK - Proof of fresh provisioning and EK value |
| * |
| * Input: |