From d463e3c5a341ece638a7a2067406fab7c03f30de Mon Sep 17 00:00:00 2001 From: Matthew Fioravante Date: Fri, 18 Jan 2013 10:55:42 +0000 Subject: add vtpm-stubdom code Add the code base for vtpm-stubdom to the stubdom heirarchy. Makefile changes in later patch. Signed-off-by: Matthew Fioravante Acked-by: Ian Campbell Committed-by: Ian Campbell --- stubdom/vtpm/Makefile | 37 +++++ stubdom/vtpm/minios.cfg | 14 ++ stubdom/vtpm/vtpm.c | 404 +++++++++++++++++++++++++++++++++++++++++++++++ stubdom/vtpm/vtpm.h | 36 +++++ stubdom/vtpm/vtpm_cmd.c | 256 ++++++++++++++++++++++++++++++ stubdom/vtpm/vtpm_cmd.h | 31 ++++ stubdom/vtpm/vtpm_pcrs.c | 43 +++++ stubdom/vtpm/vtpm_pcrs.h | 53 +++++++ stubdom/vtpm/vtpmblk.c | 307 +++++++++++++++++++++++++++++++++++ stubdom/vtpm/vtpmblk.h | 31 ++++ 10 files changed, 1212 insertions(+) create mode 100644 stubdom/vtpm/Makefile create mode 100644 stubdom/vtpm/minios.cfg create mode 100644 stubdom/vtpm/vtpm.c create mode 100644 stubdom/vtpm/vtpm.h create mode 100644 stubdom/vtpm/vtpm_cmd.c create mode 100644 stubdom/vtpm/vtpm_cmd.h create mode 100644 stubdom/vtpm/vtpm_pcrs.c create mode 100644 stubdom/vtpm/vtpm_pcrs.h create mode 100644 stubdom/vtpm/vtpmblk.c create mode 100644 stubdom/vtpm/vtpmblk.h (limited to 'stubdom') diff --git a/stubdom/vtpm/Makefile b/stubdom/vtpm/Makefile new file mode 100644 index 0000000000..686c0eab84 --- /dev/null +++ b/stubdom/vtpm/Makefile @@ -0,0 +1,37 @@ +# 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. +# + +XEN_ROOT=../.. + +PSSL_DIR=../polarssl-$(XEN_TARGET_ARCH)/library +PSSL_OBJS=aes.o sha1.o entropy.o ctr_drbg.o sha4.o + +TARGET=vtpm.a +OBJS=vtpm.o vtpm_cmd.o vtpmblk.o vtpm_pcrs.o + + +CPPFLAGS+=-I../tpm_emulator-$(XEN_TARGET_ARCH)/build +CPPFLAGS+=-I../tpm_emulator-$(XEN_TARGET_ARCH)/tpm +CPPFLAGS+=-I../tpm_emulator-$(XEN_TARGET_ARCH)/crypto +CPPFLAGS+=-I../tpm_emulator-$(XEN_TARGET_ARCH) + +$(TARGET): $(OBJS) + ar -cr $@ $(OBJS) $(TPMEMU_OBJS) $(foreach obj,$(PSSL_OBJS),$(PSSL_DIR)/$(obj)) + +$(OBJS): vtpm_manager.h + +vtpm_manager.h: + ln -s ../vtpmmgr/vtpm_manager.h vtpm_manager.h + +clean: + -rm $(TARGET) $(OBJS) vtpm_manager.h + +.PHONY: clean diff --git a/stubdom/vtpm/minios.cfg b/stubdom/vtpm/minios.cfg new file mode 100644 index 0000000000..31652ee4f2 --- /dev/null +++ b/stubdom/vtpm/minios.cfg @@ -0,0 +1,14 @@ +CONFIG_TPMFRONT=y +CONFIG_TPM_TIS=n +CONFIG_TPMBACK=y +CONFIG_START_NETWORK=n +CONFIG_TEST=n +CONFIG_PCIFRONT=n +CONFIG_BLKFRONT=y +CONFIG_NETFRONT=n +CONFIG_FBFRONT=n +CONFIG_KBDFRONT=n +CONFIG_CONSFRONT=n +CONFIG_XENBUS=y +CONFIG_LWIP=n +CONFIG_XC=n diff --git a/stubdom/vtpm/vtpm.c b/stubdom/vtpm/vtpm.c new file mode 100644 index 0000000000..71aef78d17 --- /dev/null +++ b/stubdom/vtpm/vtpm.c @@ -0,0 +1,404 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "tpm/tpm_emulator_extern.h" +#include "tpm/tpm_marshalling.h" +#include "vtpm.h" +#include "vtpm_cmd.h" +#include "vtpm_pcrs.h" +#include "vtpmblk.h" + +#define TPM_LOG_INFO LOG_INFO +#define TPM_LOG_ERROR LOG_ERR +#define TPM_LOG_DEBUG LOG_DEBUG + +/* Global commandline options - default values */ +struct Opt_args opt_args = { + .startup = ST_CLEAR, + .loglevel = TPM_LOG_INFO, + .hwinitpcrs = VTPM_PCRNONE, + .tpmconf = 0, + .enable_maint_cmds = false, +}; + +static uint32_t badords[32]; +static unsigned int n_badords = 0; + +entropy_context entropy; +ctr_drbg_context ctr_drbg; + +struct tpmfront_dev* tpmfront_dev; + +void vtpm_get_extern_random_bytes(void *buf, size_t nbytes) +{ + ctr_drbg_random(&ctr_drbg, buf, nbytes); +} + +int vtpm_read_from_file(uint8_t **data, size_t *data_length) { + return read_vtpmblk(tpmfront_dev, data, data_length); +} + +int vtpm_write_to_file(uint8_t *data, size_t data_length) { + return write_vtpmblk(tpmfront_dev, data, data_length); +} + +int vtpm_extern_init_fake(void) { + return 0; +} + +void vtpm_extern_release_fake(void) { +} + + +void vtpm_log(int priority, const char *fmt, ...) +{ + if(opt_args.loglevel >= priority) { + va_list v; + va_start(v, fmt); + vprintf(fmt, v); + va_end(v); + } +} + +static uint64_t vtpm_get_ticks(void) +{ + static uint64_t old_t = 0; + uint64_t new_t, res_t; + struct timeval tv; + gettimeofday(&tv, NULL); + new_t = (uint64_t)tv.tv_sec * 1000000 + (uint64_t)tv.tv_usec; + res_t = (old_t > 0) ? new_t - old_t : 0; + old_t = new_t; + return res_t; +} + + +static int tpm_entropy_source(void* dummy, unsigned char* data, size_t len, size_t* olen) { + UINT32 sz = len; + TPM_RESULT rc = VTPM_GetRandom(tpmfront_dev, data, &sz); + *olen = sz; + return rc == TPM_SUCCESS ? 0 : POLARSSL_ERR_ENTROPY_SOURCE_FAILED; +} + +int init_random(void) { + /* Initialize the rng */ + entropy_init(&entropy); + entropy_add_source(&entropy, tpm_entropy_source, NULL, 0); + entropy_gather(&entropy); + ctr_drbg_init(&ctr_drbg, entropy_func, &entropy, NULL, 0); + ctr_drbg_set_prediction_resistance( &ctr_drbg, CTR_DRBG_PR_OFF ); + + return 0; +} + +int check_ordinal(tpmcmd_t* tpmcmd) { + TPM_COMMAND_CODE ord; + UINT32 len = 4; + BYTE* ptr; + unsigned int i; + + if(tpmcmd->req_len < 10) { + return true; + } + + ptr = tpmcmd->req + 6; + tpm_unmarshal_UINT32(&ptr, &len, &ord); + + for(i = 0; i < n_badords; ++i) { + if(ord == badords[i]) { + error("Disabled command ordinal (%" PRIu32") requested!\n"); + return false; + } + } + return true; +} + +static void main_loop(void) { + tpmcmd_t* tpmcmd = NULL; + domid_t domid; /* Domid of frontend */ + unsigned int handle; /* handle of frontend */ + int res = -1; + + info("VTPM Initializing\n"); + + /* Set required tpm config args */ + opt_args.tpmconf |= TPM_CONF_STRONG_PERSISTENCE; + opt_args.tpmconf &= ~TPM_CONF_USE_INTERNAL_PRNG; + opt_args.tpmconf |= TPM_CONF_GENERATE_EK; + opt_args.tpmconf |= TPM_CONF_GENERATE_SEED_DAA; + + /* Initialize the emulator */ + tpm_emulator_init(opt_args.startup, opt_args.tpmconf); + + /* Initialize any requested PCRs with hardware TPM values */ + if(vtpm_initialize_hw_pcrs(tpmfront_dev, opt_args.hwinitpcrs) != TPM_SUCCESS) { + error("Failed to initialize PCRs with hardware TPM values"); + goto abort_postpcrs; + } + + /* Wait for the frontend domain to connect */ + info("Waiting for frontend domain to connect.."); + if(tpmback_wait_for_frontend_connect(&domid, &handle) == 0) { + info("VTPM attached to Frontend %u/%u", (unsigned int) domid, handle); + } else { + error("Unable to attach to a frontend"); + } + + tpmcmd = tpmback_req(domid, handle); + while(tpmcmd) { + /* Handle the request */ + if(tpmcmd->req_len) { + tpmcmd->resp = NULL; + tpmcmd->resp_len = 0; + + /* First check for disabled ordinals */ + if(!check_ordinal(tpmcmd)) { + create_error_response(tpmcmd, TPM_BAD_ORDINAL); + } + /* If not disabled, do the command */ + else { + if((res = tpm_handle_command(tpmcmd->req, tpmcmd->req_len, &tpmcmd->resp, &tpmcmd->resp_len)) != 0) { + error("tpm_handle_command() failed"); + create_error_response(tpmcmd, TPM_FAIL); + } + } + } + + /* Send the response */ + tpmback_resp(tpmcmd); + + /* Wait for the next request */ + tpmcmd = tpmback_req(domid, handle); + + } + +abort_postpcrs: + info("VTPM Shutting down\n"); + + tpm_emulator_shutdown(); +} + +int parse_cmd_line(int argc, char** argv) +{ + char sval[25]; + char* logstr = NULL; + /* Parse the command strings */ + for(unsigned int i = 1; i < argc; ++i) { + if (sscanf(argv[i], "loglevel=%25s", sval) == 1){ + if (!strcmp(sval, "debug")) { + opt_args.loglevel = TPM_LOG_DEBUG; + logstr = "debug"; + } + else if (!strcmp(sval, "info")) { + logstr = "info"; + opt_args.loglevel = TPM_LOG_INFO; + } + else if (!strcmp(sval, "error")) { + logstr = "error"; + opt_args.loglevel = TPM_LOG_ERROR; + } + } + else if (!strcmp(argv[i], "clear")) { + opt_args.startup = ST_CLEAR; + } + else if (!strcmp(argv[i], "save")) { + opt_args.startup = ST_SAVE; + } + else if (!strcmp(argv[i], "deactivated")) { + opt_args.startup = ST_DEACTIVATED; + } + else if (!strncmp(argv[i], "maintcmds=", 10)) { + if(!strcmp(argv[i] + 10, "1")) { + opt_args.enable_maint_cmds = true; + } else if(!strcmp(argv[i] + 10, "0")) { + opt_args.enable_maint_cmds = false; + } + } + else if(!strncmp(argv[i], "hwinitpcr=", 10)) { + char *pch = argv[i] + 10; + unsigned int v1, v2; + pch = strtok(pch, ","); + while(pch != NULL) { + if(!strcmp(pch, "all")) { + //Set all + opt_args.hwinitpcrs = VTPM_PCRALL; + } else if(!strcmp(pch, "none")) { + //Set none + opt_args.hwinitpcrs = VTPM_PCRNONE; + } else if(sscanf(pch, "%u", &v1) == 1) { + //Set one + if(v1 >= TPM_NUM_PCR) { + error("hwinitpcr error: Invalid PCR index %u", v1); + return -1; + } + opt_args.hwinitpcrs |= (1 << v1); + } else if(sscanf(pch, "%u-%u", &v1, &v2) == 2) { + //Set range + if(v1 >= TPM_NUM_PCR) { + error("hwinitpcr error: Invalid PCR index %u", v1); + return -1; + } + if(v2 >= TPM_NUM_PCR) { + error("hwinitpcr error: Invalid PCR index %u", v1); + return -1; + } + if(v2 < v1) { + unsigned tp = v1; + v1 = v2; + v2 = tp; + } + for(unsigned int i = v1; i <= v2; ++i) { + opt_args.hwinitpcrs |= (1 << i); + } + } else { + error("hwintipcr error: Invalid PCR specification : %s", pch); + return -1; + } + pch = strtok(NULL, ","); + } + } + else { + error("Invalid command line option `%s'", argv[i]); + } + + } + + /* Check Errors and print results */ + switch(opt_args.startup) { + case ST_CLEAR: + info("Startup mode is `clear'"); + break; + case ST_SAVE: + info("Startup mode is `save'"); + break; + case ST_DEACTIVATED: + info("Startup mode is `deactivated'"); + break; + default: + error("Invalid startup mode %d", opt_args.startup); + return -1; + } + + if(opt_args.hwinitpcrs & (VTPM_PCRALL)) + { + char pcrstr[1024]; + char* ptr = pcrstr; + + pcrstr[0] = '\0'; + info("The following PCRs will be initialized with values from the hardware TPM:"); + for(unsigned int i = 0; i < TPM_NUM_PCR; ++i) { + if(opt_args.hwinitpcrs & (1 << i)) { + ptr += sprintf(ptr, "%u, ", i); + } + } + /* get rid of the last comma if any numbers were printed */ + *(ptr -2) = '\0'; + + info("\t%s", pcrstr); + } else { + info("All PCRs initialized to default values"); + } + + if(!opt_args.enable_maint_cmds) { + info("TPM Maintenance Commands disabled"); + badords[n_badords++] = TPM_ORD_CreateMaintenanceArchive; + badords[n_badords++] = TPM_ORD_LoadMaintenanceArchive; + badords[n_badords++] = TPM_ORD_KillMaintenanceFeature; + badords[n_badords++] = TPM_ORD_LoadManuMaintPub; + badords[n_badords++] = TPM_ORD_ReadManuMaintPub; + } else { + info("TPM Maintenance Commands enabled"); + } + + info("Log level set to %s", logstr); + + return 0; +} + +void cleanup_opt_args(void) { +} + +int main(int argc, char **argv) +{ + //FIXME: initializing blkfront without this sleep causes the domain to crash on boot + sleep(2); + + /* Setup extern function pointers */ + tpm_extern_init = vtpm_extern_init_fake; + tpm_extern_release = vtpm_extern_release_fake; + tpm_malloc = malloc; + tpm_free = free; + tpm_log = vtpm_log; + tpm_get_ticks = vtpm_get_ticks; + tpm_get_extern_random_bytes = vtpm_get_extern_random_bytes; + tpm_write_to_storage = vtpm_write_to_file; + tpm_read_from_storage = vtpm_read_from_file; + + info("starting TPM Emulator (1.2.%d.%d-%d)", VERSION_MAJOR, VERSION_MINOR, VERSION_BUILD); + if(parse_cmd_line(argc, argv)) { + error("Error parsing commandline\n"); + return -1; + } + + /* Initialize devices */ + init_tpmback(); + if((tpmfront_dev = init_tpmfront(NULL)) == NULL) { + error("Unable to initialize tpmfront device"); + goto abort_posttpmfront; + } + + /* Seed the RNG with entropy from hardware TPM */ + if(init_random()) { + error("Unable to initialize RNG"); + goto abort_postrng; + } + + /* Initialize blkfront device */ + if(init_vtpmblk(tpmfront_dev)) { + error("Unable to initialize Blkfront persistent storage"); + goto abort_postvtpmblk; + } + + /* Run main loop */ + main_loop(); + + /* Shutdown blkfront */ + shutdown_vtpmblk(); +abort_postvtpmblk: +abort_postrng: + + /* Close devices */ + shutdown_tpmfront(tpmfront_dev); +abort_posttpmfront: + shutdown_tpmback(); + + cleanup_opt_args(); + + return 0; +} diff --git a/stubdom/vtpm/vtpm.h b/stubdom/vtpm/vtpm.h new file mode 100644 index 0000000000..5919e44fbd --- /dev/null +++ b/stubdom/vtpm/vtpm.h @@ -0,0 +1,36 @@ +/* + * 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. + */ + +#ifndef VTPM_H +#define VTPM_H + +#include + +/* For testing */ +#define VERS_CMD "\x00\xC1\x00\x00\x00\x16\x00\x00\x00\x65\x00\x00\x00\x05\x00\x00\x00\x04\x00\x00\x01\x03" +#define VERS_CMD_LEN 22 + +/* Global commandline options */ +struct Opt_args { + enum StartUp { + ST_CLEAR = 1, + ST_SAVE = 2, + ST_DEACTIVATED = 3 + } startup; + unsigned long hwinitpcrs; + int loglevel; + uint32_t tpmconf; + bool enable_maint_cmds; +}; +extern struct Opt_args opt_args; + +#endif 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 +#include +#include +#include +#include "tpm/tpm_marshalling.h" +#include "vtpm_manager.h" +#include "vtpm_cmd.h" +#include + +#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; + +} diff --git a/stubdom/vtpm/vtpm_cmd.h b/stubdom/vtpm/vtpm_cmd.h new file mode 100644 index 0000000000..b0bfa22897 --- /dev/null +++ b/stubdom/vtpm/vtpm_cmd.h @@ -0,0 +1,31 @@ +/* + * 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. + */ + +#ifndef MANAGER_H +#define MANAGER_H + +#include +#include +#include "tpm/tpm_structures.h" + +/* Create a command response error header */ +int create_error_response(tpmcmd_t* tpmcmd, TPM_RESULT errorcode); +/* Request random bytes from hardware tpm, returns 0 on success */ +TPM_RESULT VTPM_GetRandom(struct tpmfront_dev* tpmfront_dev, BYTE* bytes, UINT32* numbytes); +/* Retreive 256 bit AES encryption key from manager */ +TPM_RESULT VTPM_LoadHashKey(struct tpmfront_dev* tpmfront_dev, uint8_t** data, size_t* data_length); +/* Manager securely saves our 256 bit AES encryption key */ +TPM_RESULT VTPM_SaveHashKey(struct tpmfront_dev* tpmfront_dev, uint8_t* data, size_t data_length); +/* Send a TPM_PCRRead command passthrough the manager to the hw tpm */ +TPM_RESULT VTPM_PCRRead(struct tpmfront_dev* tpmfront_dev, UINT32 pcrIndex, BYTE* outDigest); + +#endif diff --git a/stubdom/vtpm/vtpm_pcrs.c b/stubdom/vtpm/vtpm_pcrs.c new file mode 100644 index 0000000000..22a6cef50d --- /dev/null +++ b/stubdom/vtpm/vtpm_pcrs.c @@ -0,0 +1,43 @@ +/* + * 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 "vtpm_pcrs.h" +#include "vtpm_cmd.h" +#include "tpm/tpm_data.h" + +#define PCR_VALUE tpmData.permanent.data.pcrValue + +static int write_pcr_direct(unsigned int pcrIndex, uint8_t* val) { + if(pcrIndex > TPM_NUM_PCR) { + return TPM_BADINDEX; + } + memcpy(&PCR_VALUE[pcrIndex], val, sizeof(TPM_PCRVALUE)); + return TPM_SUCCESS; +} + +TPM_RESULT vtpm_initialize_hw_pcrs(struct tpmfront_dev* tpmfront_dev, unsigned long pcrs) +{ + TPM_RESULT rc = TPM_SUCCESS; + uint8_t digest[sizeof(TPM_PCRVALUE)]; + + for(unsigned int i = 0; i < TPM_NUM_PCR; ++i) { + if(pcrs & 1 << i) { + if((rc = VTPM_PCRRead(tpmfront_dev, i, digest)) != TPM_SUCCESS) { + error("TPM_PCRRead failed with error : %d", rc); + return rc; + } + write_pcr_direct(i, digest); + } + } + + return rc; +} diff --git a/stubdom/vtpm/vtpm_pcrs.h b/stubdom/vtpm/vtpm_pcrs.h new file mode 100644 index 0000000000..11835f9e94 --- /dev/null +++ b/stubdom/vtpm/vtpm_pcrs.h @@ -0,0 +1,53 @@ +/* + * 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. + */ + +#ifndef VTPM_PCRS_H +#define VTPM_PCRS_H + +#include "tpm/tpm_structures.h" + +#define VTPM_PCR0 1 +#define VTPM_PCR1 1 << 1 +#define VTPM_PCR2 1 << 2 +#define VTPM_PCR3 1 << 3 +#define VTPM_PCR4 1 << 4 +#define VTPM_PCR5 1 << 5 +#define VTPM_PCR6 1 << 6 +#define VTPM_PCR7 1 << 7 +#define VTPM_PCR8 1 << 8 +#define VTPM_PCR9 1 << 9 +#define VTPM_PCR10 1 << 10 +#define VTPM_PCR11 1 << 11 +#define VTPM_PCR12 1 << 12 +#define VTPM_PCR13 1 << 13 +#define VTPM_PCR14 1 << 14 +#define VTPM_PCR15 1 << 15 +#define VTPM_PCR16 1 << 16 +#define VTPM_PCR17 1 << 17 +#define VTPM_PCR18 1 << 18 +#define VTPM_PCR19 1 << 19 +#define VTPM_PCR20 1 << 20 +#define VTPM_PCR21 1 << 21 +#define VTPM_PCR22 1 << 22 +#define VTPM_PCR23 1 << 23 + +#define VTPM_PCRALL (1 << TPM_NUM_PCR) - 1 +#define VTPM_PCRNONE 0 + +#define VTPM_NUMPCRS 24 + +struct tpmfront_dev; + +TPM_RESULT vtpm_initialize_hw_pcrs(struct tpmfront_dev* tpmfront_dev, unsigned long pcrs); + + +#endif diff --git a/stubdom/vtpm/vtpmblk.c b/stubdom/vtpm/vtpmblk.c new file mode 100644 index 0000000000..b343bd84b2 --- /dev/null +++ b/stubdom/vtpm/vtpmblk.c @@ -0,0 +1,307 @@ +/* + * 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 +#include "vtpmblk.h" +#include "tpm/tpm_marshalling.h" +#include "vtpm_cmd.h" +#include "polarssl/aes.h" +#include "polarssl/sha1.h" +#include +#include +#include +#include + +/*Encryption key and block sizes */ +#define BLKSZ 16 + +static struct blkfront_dev* blkdev = NULL; +static int blkfront_fd = -1; + +int init_vtpmblk(struct tpmfront_dev* tpmfront_dev) +{ + struct blkfront_info blkinfo; + info("Initializing persistent NVM storage\n"); + + if((blkdev = init_blkfront(NULL, &blkinfo)) == NULL) { + error("BLKIO: ERROR Unable to initialize blkfront"); + return -1; + } + if (blkinfo.info & VDISK_READONLY || blkinfo.mode != O_RDWR) { + error("BLKIO: ERROR block device is read only!"); + goto error; + } + if((blkfront_fd = blkfront_open(blkdev)) == -1) { + error("Unable to open blkfront file descriptor!"); + goto error; + } + + return 0; +error: + shutdown_blkfront(blkdev); + blkdev = NULL; + return -1; +} + +void shutdown_vtpmblk(void) +{ + close(blkfront_fd); + blkfront_fd = -1; + blkdev = NULL; +} + +int write_vtpmblk_raw(uint8_t *data, size_t data_length) +{ + int rc; + uint32_t lenbuf; + debug("Begin Write data=%p len=%u", data, data_length); + + lenbuf = cpu_to_be32((uint32_t)data_length); + + lseek(blkfront_fd, 0, SEEK_SET); + if((rc = write(blkfront_fd, (uint8_t*)&lenbuf, 4)) != 4) { + error("write(length) failed! error was %s", strerror(errno)); + return -1; + } + if((rc = write(blkfront_fd, data, data_length)) != data_length) { + error("write(data) failed! error was %s", strerror(errno)); + return -1; + } + + info("Wrote %u bytes to NVM persistent storage", data_length); + + return 0; +} + +int read_vtpmblk_raw(uint8_t **data, size_t *data_length) +{ + int rc; + uint32_t lenbuf; + + lseek(blkfront_fd, 0, SEEK_SET); + if(( rc = read(blkfront_fd, (uint8_t*)&lenbuf, 4)) != 4) { + error("read(length) failed! error was %s", strerror(errno)); + return -1; + } + *data_length = (size_t) cpu_to_be32(lenbuf); + if(*data_length == 0) { + error("read 0 data_length for NVM"); + return -1; + } + + *data = tpm_malloc(*data_length); + if((rc = read(blkfront_fd, *data, *data_length)) != *data_length) { + error("read(data) failed! error was %s", strerror(errno)); + return -1; + } + + info("Read %u bytes from NVM persistent storage", *data_length); + return 0; +} + +int encrypt_vtpmblk(uint8_t* clear, size_t clear_len, uint8_t** cipher, size_t* cipher_len, uint8_t* symkey) +{ + int rc = 0; + uint8_t iv[BLKSZ]; + aes_context aes_ctx; + UINT32 temp; + int mod; + + uint8_t* clbuf = NULL; + + uint8_t* ivptr; + int ivlen; + + uint8_t* cptr; //Cipher block pointer + int clen; //Cipher block length + + /*Create a new 256 bit encryption key */ + if(symkey == NULL) { + rc = -1; + goto abort_egress; + } + tpm_get_extern_random_bytes(symkey, NVMKEYSZ); + + /*Setup initialization vector - random bits and then 4 bytes clear text size at the end*/ + temp = sizeof(UINT32); + ivlen = BLKSZ - temp; + tpm_get_extern_random_bytes(iv, ivlen); + ivptr = iv + ivlen; + tpm_marshal_UINT32(&ivptr, &temp, (UINT32) clear_len); + + /*The clear text needs to be padded out to a multiple of BLKSZ */ + mod = clear_len % BLKSZ; + clen = mod ? clear_len + BLKSZ - mod : clear_len; + clbuf = malloc(clen); + if (clbuf == NULL) { + rc = -1; + goto abort_egress; + } + memcpy(clbuf, clear, clear_len); + /* zero out the padding bits - FIXME: better / more secure way to handle these? */ + if(clen - clear_len) { + memset(clbuf + clear_len, 0, clen - clear_len); + } + + /* Setup the ciphertext buffer */ + *cipher_len = BLKSZ + clen; /*iv + ciphertext */ + cptr = *cipher = malloc(*cipher_len); + if (*cipher == NULL) { + rc = -1; + goto abort_egress; + } + + /* Copy the IV to cipher text blob*/ + memcpy(cptr, iv, BLKSZ); + cptr += BLKSZ; + + /* Setup encryption */ + aes_setkey_enc(&aes_ctx, symkey, 256); + + /* Do encryption now */ + aes_crypt_cbc(&aes_ctx, AES_ENCRYPT, clen, iv, clbuf, cptr); + + goto egress; +abort_egress: +egress: + free(clbuf); + return rc; +} +int decrypt_vtpmblk(uint8_t* cipher, size_t cipher_len, uint8_t** clear, size_t* clear_len, uint8_t* symkey) +{ + int rc = 0; + uint8_t iv[BLKSZ]; + uint8_t* ivptr; + UINT32 u32, temp; + aes_context aes_ctx; + + uint8_t* cptr = cipher; //cipher block pointer + int clen = cipher_len; //cipher block length + + /* Pull out the initialization vector */ + memcpy(iv, cipher, BLKSZ); + cptr += BLKSZ; + clen -= BLKSZ; + + /* Setup the clear text buffer */ + if((*clear = malloc(clen)) == NULL) { + rc = -1; + goto abort_egress; + } + + /* Get the length of clear text from last 4 bytes of iv */ + temp = sizeof(UINT32); + ivptr = iv + BLKSZ - temp; + tpm_unmarshal_UINT32(&ivptr, &temp, &u32); + *clear_len = u32; + + /* Setup decryption */ + aes_setkey_dec(&aes_ctx, symkey, 256); + + /* Do decryption now */ + if ((clen % BLKSZ) != 0) { + error("Decryption Error: Cipher block size was not a multiple of %u", BLKSZ); + rc = -1; + goto abort_egress; + } + aes_crypt_cbc(&aes_ctx, AES_DECRYPT, clen, iv, cptr, *clear); + + goto egress; +abort_egress: +egress: + return rc; +} + +int write_vtpmblk(struct tpmfront_dev* tpmfront_dev, uint8_t* data, size_t data_length) { + int rc; + uint8_t* cipher = NULL; + size_t cipher_len = 0; + uint8_t hashkey[HASHKEYSZ]; + uint8_t* symkey = hashkey + HASHSZ; + + /* Encrypt the data */ + if((rc = encrypt_vtpmblk(data, data_length, &cipher, &cipher_len, symkey))) { + goto abort_egress; + } + /* Write to disk */ + if((rc = write_vtpmblk_raw(cipher, cipher_len))) { + goto abort_egress; + } + /* Get sha1 hash of data */ + sha1(cipher, cipher_len, hashkey); + + /* Send hash and key to manager */ + if((rc = VTPM_SaveHashKey(tpmfront_dev, hashkey, HASHKEYSZ)) != TPM_SUCCESS) { + goto abort_egress; + } + goto egress; +abort_egress: +egress: + free(cipher); + return rc; +} + +int read_vtpmblk(struct tpmfront_dev* tpmfront_dev, uint8_t** data, size_t *data_length) { + int rc; + uint8_t* cipher = NULL; + size_t cipher_len = 0; + size_t keysize; + uint8_t* hashkey = NULL; + uint8_t hash[HASHSZ]; + uint8_t* symkey; + + /* Retreive the hash and the key from the manager */ + if((rc = VTPM_LoadHashKey(tpmfront_dev, &hashkey, &keysize)) != TPM_SUCCESS) { + goto abort_egress; + } + if(keysize != HASHKEYSZ) { + error("Manager returned a hashkey of invalid size! expected %d, actual %d", NVMKEYSZ, keysize); + rc = -1; + goto abort_egress; + } + symkey = hashkey + HASHSZ; + + /* Read from disk now */ + if((rc = read_vtpmblk_raw(&cipher, &cipher_len))) { + goto abort_egress; + } + + /* Compute the hash of the cipher text and compare */ + sha1(cipher, cipher_len, hash); + if(memcmp(hash, hashkey, HASHSZ)) { + int i; + error("NVM Storage Checksum failed!"); + printf("Expected: "); + for(i = 0; i < HASHSZ; ++i) { + printf("%02hhX ", hashkey[i]); + } + printf("\n"); + printf("Actual: "); + for(i = 0; i < HASHSZ; ++i) { + printf("%02hhX ", hash[i]); + } + printf("\n"); + rc = -1; + goto abort_egress; + } + + /* Decrypt the blob */ + if((rc = decrypt_vtpmblk(cipher, cipher_len, data, data_length, symkey))) { + goto abort_egress; + } + goto egress; +abort_egress: +egress: + free(cipher); + free(hashkey); + return rc; +} diff --git a/stubdom/vtpm/vtpmblk.h b/stubdom/vtpm/vtpmblk.h new file mode 100644 index 0000000000..282ce6a9bc --- /dev/null +++ b/stubdom/vtpm/vtpmblk.h @@ -0,0 +1,31 @@ +/* + * 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. + */ + +#ifndef NVM_H +#define NVM_H +#include +#include +#include + +#define NVMKEYSZ 32 +#define HASHSZ 20 +#define HASHKEYSZ (NVMKEYSZ + HASHSZ) + +int init_vtpmblk(struct tpmfront_dev* tpmfront_dev); +void shutdown_vtpmblk(void); + +/* Encrypts and writes data to blk device */ +int write_vtpmblk(struct tpmfront_dev* tpmfront_dev, uint8_t *data, size_t data_length); +/* Reads, Decrypts, and returns data from blk device */ +int read_vtpmblk(struct tpmfront_dev* tpmfront_dev, uint8_t **data, size_t *data_length); + +#endif -- cgit v1.2.3