aboutsummaryrefslogtreecommitdiffstats
path: root/stubdom/vtpm/vtpm_cmd.c
diff options
context:
space:
mode:
Diffstat (limited to 'stubdom/vtpm/vtpm_cmd.c')
-rw-r--r--stubdom/vtpm/vtpm_cmd.c256
1 files changed, 256 insertions, 0 deletions
diff --git a/stubdom/vtpm/vtpm_cmd.c b/stubdom/vtpm/vtpm_cmd.c
new file mode 100644
index 0000000000..7eae98b54a
--- /dev/null
+++ b/stubdom/vtpm/vtpm_cmd.c
@@ -0,0 +1,256 @@
+/*
+ * Copyright (c) 2010-2012 United States Government, as represented by
+ * the Secretary of Defense. All rights reserved.
+ *
+ * THIS SOFTWARE AND ITS DOCUMENTATION ARE PROVIDED AS IS AND WITHOUT
+ * ANY EXPRESS OR IMPLIED WARRANTIES WHATSOEVER. ALL WARRANTIES
+ * INCLUDING, BUT NOT LIMITED TO, PERFORMANCE, MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT ARE HEREBY
+ * DISCLAIMED. USERS ASSUME THE ENTIRE RISK AND LIABILITY OF USING THE
+ * SOFTWARE.
+ */
+
+#include <types.h>
+#include <xen/xen.h>
+#include <mm.h>
+#include <gnttab.h>
+#include "tpm/tpm_marshalling.h"
+#include "vtpm_manager.h"
+#include "vtpm_cmd.h"
+#include <tpmback.h>
+
+#define TRYFAILGOTO(C) \
+ if((C)) { \
+ status = TPM_FAIL; \
+ goto abort_egress; \
+ }
+#define TRYFAILGOTOMSG(C, msg) \
+ if((C)) { \
+ status = TPM_FAIL; \
+ error(msg); \
+ goto abort_egress; \
+ }
+#define CHECKSTATUSGOTO(ret, fname) \
+ if((ret) != TPM_SUCCESS) { \
+ error("%s failed with error code (%lu)", fname, (unsigned long) ret); \
+ status = ord; \
+ goto abort_egress; \
+ }
+
+#define ERR_MALFORMED "Malformed response from backend"
+#define ERR_TPMFRONT "Error sending command through frontend device"
+
+struct shpage {
+ void* page;
+ grant_ref_t grantref;
+};
+
+typedef struct shpage shpage_t;
+
+static inline int pack_header(uint8_t** bptr, UINT32* len, TPM_TAG tag, UINT32 size, TPM_COMMAND_CODE ord)
+{
+ return *bptr == NULL ||
+ tpm_marshal_UINT16(bptr, len, tag) ||
+ tpm_marshal_UINT32(bptr, len, size) ||
+ tpm_marshal_UINT32(bptr, len, ord);
+}
+
+static inline int unpack_header(uint8_t** bptr, UINT32* len, TPM_TAG* tag, UINT32* size, TPM_COMMAND_CODE* ord)
+{
+ return *bptr == NULL ||
+ tpm_unmarshal_UINT16(bptr, len, tag) ||
+ tpm_unmarshal_UINT32(bptr, len, size) ||
+ tpm_unmarshal_UINT32(bptr, len, ord);
+}
+
+int create_error_response(tpmcmd_t* tpmcmd, TPM_RESULT errorcode)
+{
+ TPM_TAG tag;
+ UINT32 len = tpmcmd->req_len;
+ uint8_t* respptr;
+ uint8_t* cmdptr = tpmcmd->req;
+
+ if(!tpm_unmarshal_UINT16(&cmdptr, &len, &tag)) {
+ switch (tag) {
+ case TPM_TAG_RQU_COMMAND:
+ tag = TPM_TAG_RSP_COMMAND;
+ break;
+ case TPM_TAG_RQU_AUTH1_COMMAND:
+ tag = TPM_TAG_RQU_AUTH2_COMMAND;
+ break;
+ case TPM_TAG_RQU_AUTH2_COMMAND:
+ tag = TPM_TAG_RQU_AUTH2_COMMAND;
+ break;
+ }
+ } else {
+ tag = TPM_TAG_RSP_COMMAND;
+ }
+
+ tpmcmd->resp_len = len = 10;
+ tpmcmd->resp = respptr = tpm_malloc(tpmcmd->resp_len);
+
+ return pack_header(&respptr, &len, tag, len, errorcode);
+}
+
+TPM_RESULT VTPM_GetRandom(struct tpmfront_dev* tpmfront_dev, BYTE* bytes, UINT32 *numbytes) {
+ TPM_RESULT status = TPM_SUCCESS;
+ uint8_t* cmdbuf, *resp, *bptr;
+ size_t resplen = 0;
+ UINT32 len;
+
+ /*Ask the real tpm for random bytes for the seed */
+ TPM_TAG tag = TPM_TAG_RQU_COMMAND;
+ UINT32 size;
+ TPM_COMMAND_CODE ord = TPM_ORD_GetRandom;
+ len = size = sizeof(TPM_TAG) + sizeof(UINT32) + sizeof(TPM_COMMAND_CODE) + sizeof(UINT32);
+
+ /*Create the raw tpm command */
+ bptr = cmdbuf = malloc(size);
+ TRYFAILGOTO(pack_header(&bptr, &len, tag, size, ord));
+ TRYFAILGOTO(tpm_marshal_UINT32(&bptr, &len, *numbytes));
+
+ /* Send cmd, wait for response */
+ TRYFAILGOTOMSG(tpmfront_cmd(tpmfront_dev, cmdbuf, size, &resp, &resplen),
+ ERR_TPMFRONT);
+
+ bptr = resp; len = resplen;
+ TRYFAILGOTOMSG(unpack_header(&bptr, &len, &tag, &size, &ord), ERR_MALFORMED);
+
+ //Check return status of command
+ CHECKSTATUSGOTO(ord, "TPM_GetRandom()");
+
+ // Get the number of random bytes in the response
+ TRYFAILGOTOMSG(tpm_unmarshal_UINT32(&bptr, &len, &size), ERR_MALFORMED);
+ *numbytes = size;
+
+ //Get the random bytes out, tpm may give us less bytes than what we wanrt
+ TRYFAILGOTOMSG(tpm_unmarshal_BYTE_ARRAY(&bptr, &len, bytes, *numbytes), ERR_MALFORMED);
+
+ goto egress;
+abort_egress:
+egress:
+ free(cmdbuf);
+ return status;
+
+}
+
+TPM_RESULT VTPM_LoadHashKey(struct tpmfront_dev* tpmfront_dev, uint8_t** data, size_t* data_length)
+{
+ TPM_RESULT status = TPM_SUCCESS;
+ uint8_t* bptr, *resp;
+ uint8_t* cmdbuf = NULL;
+ size_t resplen = 0;
+ UINT32 len;
+
+ TPM_TAG tag = VTPM_TAG_REQ;
+ UINT32 size;
+ TPM_COMMAND_CODE ord = VTPM_ORD_LOADHASHKEY;
+
+ /*Create the command*/
+ len = size = VTPM_COMMAND_HEADER_SIZE;
+ bptr = cmdbuf = malloc(size);
+ TRYFAILGOTO(pack_header(&bptr, &len, tag, size, ord));
+
+ /* Send the command to vtpm_manager */
+ info("Requesting Encryption key from backend");
+ TRYFAILGOTOMSG(tpmfront_cmd(tpmfront_dev, cmdbuf, size, &resp, &resplen), ERR_TPMFRONT);
+
+ /* Unpack response header */
+ bptr = resp;
+ len = resplen;
+ TRYFAILGOTOMSG(unpack_header(&bptr, &len, &tag, &size, &ord), ERR_MALFORMED);
+
+ /* Check return code */
+ CHECKSTATUSGOTO(ord, "VTPM_LoadHashKey()");
+
+ /* Get the size of the key */
+ *data_length = size - VTPM_COMMAND_HEADER_SIZE;
+
+ /* Copy the key bits */
+ *data = malloc(*data_length);
+ memcpy(*data, bptr, *data_length);
+
+ goto egress;
+abort_egress:
+ error("VTPM_LoadHashKey failed");
+egress:
+ free(cmdbuf);
+ return status;
+}
+
+TPM_RESULT VTPM_SaveHashKey(struct tpmfront_dev* tpmfront_dev, uint8_t* data, size_t data_length)
+{
+ TPM_RESULT status = TPM_SUCCESS;
+ uint8_t* bptr, *resp;
+ uint8_t* cmdbuf = NULL;
+ size_t resplen = 0;
+ UINT32 len;
+
+ TPM_TAG tag = VTPM_TAG_REQ;
+ UINT32 size;
+ TPM_COMMAND_CODE ord = VTPM_ORD_SAVEHASHKEY;
+
+ /*Create the command*/
+ len = size = VTPM_COMMAND_HEADER_SIZE + data_length;
+ bptr = cmdbuf = malloc(size);
+ TRYFAILGOTO(pack_header(&bptr, &len, tag, size, ord));
+ memcpy(bptr, data, data_length);
+ bptr += data_length;
+
+ /* Send the command to vtpm_manager */
+ info("Sending encryption key to backend");
+ TRYFAILGOTOMSG(tpmfront_cmd(tpmfront_dev, cmdbuf, size, &resp, &resplen), ERR_TPMFRONT);
+
+ /* Unpack response header */
+ bptr = resp;
+ len = resplen;
+ TRYFAILGOTOMSG(unpack_header(&bptr, &len, &tag, &size, &ord), ERR_MALFORMED);
+
+ /* Check return code */
+ CHECKSTATUSGOTO(ord, "VTPM_SaveHashKey()");
+
+ goto egress;
+abort_egress:
+ error("VTPM_SaveHashKey failed");
+egress:
+ free(cmdbuf);
+ return status;
+}
+
+TPM_RESULT VTPM_PCRRead(struct tpmfront_dev* tpmfront_dev, UINT32 pcrIndex, BYTE* outDigest)
+{
+ TPM_RESULT status = TPM_SUCCESS;
+ uint8_t *cmdbuf, *resp, *bptr;
+ size_t resplen = 0;
+ UINT32 len;
+
+ /*Just send a TPM_PCRRead Command to the HW tpm */
+ TPM_TAG tag = TPM_TAG_RQU_COMMAND;
+ UINT32 size;
+ TPM_COMMAND_CODE ord = TPM_ORD_PCRRead;
+ len = size = sizeof(TPM_TAG) + sizeof(UINT32) + sizeof(TPM_COMMAND_CODE) + sizeof(UINT32);
+
+ /*Create the raw tpm cmd */
+ bptr = cmdbuf = malloc(size);
+ TRYFAILGOTO(pack_header(&bptr, &len, tag, size, ord));
+ TRYFAILGOTO(tpm_marshal_UINT32(&bptr, &len, pcrIndex));
+
+ /*Send Cmd wait for response */
+ TRYFAILGOTOMSG(tpmfront_cmd(tpmfront_dev, cmdbuf, size, &resp, &resplen), ERR_TPMFRONT);
+
+ bptr = resp; len = resplen;
+ TRYFAILGOTOMSG(unpack_header(&bptr, &len, &tag, &size, &ord), ERR_MALFORMED);
+
+ //Check return status of command
+ CHECKSTATUSGOTO(ord, "TPM_PCRRead");
+
+ //Get the ptr value
+ memcpy(outDigest, bptr, sizeof(TPM_PCRVALUE));
+
+ goto egress;
+abort_egress:
+egress:
+ free(cmdbuf);
+ return status;
+
+}