diff -Naur xen-unstable-trp-sdp-pristine/stubdom/vtpmmgr/Makefile xen-unstable-trp-sdp/stubdom/vtpmmgr/Makefile --- xen-unstable-trp-sdp-pristine/stubdom/vtpmmgr/Makefile 1969-12-31 19:00:00.000000000 -0500 +++ xen-unstable-trp-sdp/stubdom/vtpmmgr/Makefile 2011-02-23 19:40:48.000000000 -0500 @@ -0,0 +1,51 @@ +# LICENSE AND DISCLAIMER +# +# Copyright © 2011 The Johns Hopkins University/Applied Physics +# Laboratory + +# This software was developed at The Johns Hopkins University/Applied +# Physics Laboratory (“JHU/APL”) that is the author thereof under the +# “work made for hire” provisions of the copyright law. Permission is +# hereby granted, free of charge, to any person obtaining a copy of this +# software and associated documentation (the “Software”), to use the +# Software without restriction, including without limitation the rights to +# copy, modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit others to do so, subject to the following +# conditions: + +# 1. This LICENSE AND DISCLAIMER, including the copyright notice, shall +# be included in all copies of the Software, including copies of +# substantial portions of the Software; + +# 2. JHU/APL assumes no obligation to provide support of any kind with +# regard to the Software. This includes no obligation to provide assistance +# in using the Software nor to provide updated versions of the Software; and + +# 3. THE 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. USERS ARE ADVISED TO +# TEST THE SOFTWARE THOROUGHLY BEFORE RELYING ON IT. IN NO EVENT SHALL THE +# JOHNS HOPKINS UNIVERSITY BE LIABLE FOR ANY DAMAGES WHATSOEVER, INCLUDING, +# WITHOUT LIMITATION, ANY LOST PROFITS, LOST SAVINGS OR OTHER INCIDENTAL OR +# CONSEQUENTIAL DAMAGES, ARISING OUT OF THE USE OR INABILITY TO USE THE +# SOFTWARE. + +XEN_ROOT=../.. + +TARGET=vtpmmgr.a +OBJS=vtpmmgr.o vtpm_cmd_handler.o vtpm_storage.o + +CFLAGS+=-Werror + +build: $(TARGET) +$(TARGET): $(OBJS) + ar -rcs $@ $^ + +clean: + rm -f $(TARGET) $(OBJS) + +distclean: clean + +.PHONY: compat clean-compat clean distclean diff -Naur xen-unstable-trp-sdp-pristine/stubdom/vtpmmgr/vtpm_cmd_handler.c xen-unstable-trp-sdp/stubdom/vtpmmgr/vtpm_cmd_handler.c --- xen-unstable-trp-sdp-pristine/stubdom/vtpmmgr/vtpm_cmd_handler.c 1969-12-31 19:00:00.000000000 -0500 +++ xen-unstable-trp-sdp/stubdom/vtpmmgr/vtpm_cmd_handler.c 2011-02-23 19:40:48.000000000 -0500 @@ -0,0 +1,174 @@ +/* LICENSE AND DISCLAIMER + * + * Copyright © 2011 The Johns Hopkins University/Applied Physics + * Laboratory + + * This software was developed at The Johns Hopkins University/Applied + * Physics Laboratory (“JHU/APL”) that is the author thereof under the + * “work made for hire” provisions of the copyright law. Permission is + * hereby granted, free of charge, to any person obtaining a copy of this + * software and associated documentation (the “Software”), to use the + * Software without restriction, including without limitation the rights to + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit others to do so, subject to the following + * conditions: + + * 1. This LICENSE AND DISCLAIMER, including the copyright notice, shall + * be included in all copies of the Software, including copies of + * substantial portions of the Software; + + * 2. JHU/APL assumes no obligation to provide support of any kind with + * regard to the Software. This includes no obligation to provide assistance + * in using the Software nor to provide updated versions of the Software; and + + * 3. THE 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. USERS ARE ADVISED TO + * TEST THE SOFTWARE THOROUGHLY BEFORE RELYING ON IT. IN NO EVENT SHALL THE + * JOHNS HOPKINS UNIVERSITY BE LIABLE FOR ANY DAMAGES WHATSOEVER, INCLUDING, + * WITHOUT LIMITATION, ANY LOST PROFITS, LOST SAVINGS OR OTHER INCIDENTAL OR + * CONSEQUENTIAL DAMAGES, ARISING OUT OF THE USE OR INABILITY TO USE THE + * SOFTWARE. + */ +#include "vtpm_cmd_handler.h" + +#include +#include +#include +#include +#include +#include + +#include "vtpm_storage.h" +#include "vtpmmgr.h" + +static TPM_RESULT make_vtpm_resp_buf(buffer_t* resbuf, TPM_TAG tag, TPM_RESULT status, int size) { + UINT32 sz = VTPM_COMMAND_HEADER_SIZE_CLT + size; + TPM_TAG restag; + + switch(tag) { + case TPM_TAG_RQU_COMMAND: + restag = TPM_TAG_RSP_COMMAND; + break; + case TPM_TAG_RQU_AUTH1_COMMAND: + restag = TPM_TAG_RSP_AUTH1_COMMAND; + break; + case TPM_TAG_RQU_AUTH2_COMMAND: + restag = TPM_TAG_RSP_AUTH2_COMMAND; + break; + case VTPM_TAG_REQ: + restag = VTPM_TAG_RSP; + break; + default: + restag = tag; + } + + buffer_init(resbuf, sz, NULL); + BSG_PackList(resbuf->bytes, 3, + BSG_TPM_TAG, (BYTE*) &restag, + BSG_TYPE_UINT32, (BYTE*) &sz, + BSG_TPM_RESULT, (BYTE*) &status); + + return status; +} + +TPM_RESULT vtpmmgr_tpmpass(char* uuid, buffer_t* cmdbuf, buffer_t* resbuf) { + TPM_RESULT status = TPM_SUCCESS; + + TPM_TAG tag; + UINT32 insz; + TPM_COMMAND_CODE ord; + + BSG_UnpackList(cmdbuf->bytes, 3, + BSG_TPM_TAG, &tag, + BSG_TYPE_UINT32, &insz, + BSG_TPM_COMMAND_CODE, &ord); + + switch(ord) { + /*This should be a list of allowed ordinals, right now only 1 is allowed */ + case TPM_ORD_GetRandom: + vtpmloginfo(VTPM_LOG_VTPM, "TPM Command Passthrough ord=%" PRIu32 "\n", ord); + TPMTRY(TPM_IOERROR, VTSP_RawTransmit(vtpm_globals->manager_tcs_handle, cmdbuf, resbuf)); + + break; + default: + status = TPM_DISABLED_CMD; + vtpmlogerror(VTPM_LOG_VTPM, "TPM Command passthrough failed: command not allowed! ord = %" PRIu32 "\n", ord); + } + goto egress; +abort_egress: +egress: + return status; +} + +TPM_RESULT vtpmmgr_handle_cmd(char* uuid, buffer_t* cmdbuf, buffer_t* resbuf) +{ + TPM_RESULT status = TPM_SUCCESS; + TPM_TAG tag; + UINT32 insz; + TPM_COMMAND_CODE ord; + + /* Unpack the header fields */ + BSG_UnpackList(cmdbuf->bytes, 3, + BSG_TPM_TAG, &tag, + BSG_TYPE_UINT32, &insz, + BSG_TPM_COMMAND_CODE, &ord); + + /* Handle the command now */ + if(tag == VTPM_TAG_REQ) { + //This is a vTPM command + buffer_t inbuf; + buffer_init_alias_convert(&inbuf, buffer_len(cmdbuf) - VTPM_COMMAND_HEADER_SIZE_CLT, cmdbuf->bytes + VTPM_COMMAND_HEADER_SIZE_CLT); + switch(ord) { + case VTPM_ORD_TPMCOMMAND: + /* Forward raw tpm command embedded inside */ + TPMTRYRETURN(vtpmmgr_tpmpass(uuid, &inbuf, resbuf)); + break; + case VTPM_ORD_GET_MIG_KEY: + /* Get migration key */ + vtpmlogerror(VTPM_LOG_VTPM,"VTPM_ORD_GET_MIG_KEY: Not Implemented!\n"); + status = TPM_FAIL; + goto abort_egress; + break; + case VTPM_ORD_LOAD_MIG_KEY: + /* Load Migration key */ + vtpmlogerror(VTPM_LOG_VTPM, "VTPM_ORD_LOAD_MIG_KEY: Not Implemented!\n"); + status = TPM_FAIL; + goto abort_egress; + break; + case VTPM_ORD_SAVEHASHKEY: + /* Save Storage Key and hash */ + TPMTRYRETURN(vtpm_storage_SaveHashKey(uuid, &inbuf)); + make_vtpm_resp_buf(resbuf, tag, status, 0); + break; + case VTPM_ORD_LOADHASHKEY: + /* Load storage key and hash */ + { + /* Try to load key from storage */ + buffer_t keybuf = NULL_BUF; + TPMTRYRETURN(vtpm_storage_LoadHashKey(uuid, &keybuf)); + + /* pack the key data into a tpm response */ + make_vtpm_resp_buf(resbuf, tag, status, buffer_len(&keybuf)); + memcpy(resbuf->bytes + VTPM_COMMAND_HEADER_SIZE_CLT, keybuf.bytes, buffer_len(&keybuf)); + buffer_free(&keybuf); + } + break; + default: + vtpmlogerror(VTPM_LOG_VTPM, "Invalid vTPM Ordinal %" PRIu32 "\n", ord); + status = TPM_BAD_ORDINAL; + goto abort_egress; + } + } else { + //This is not a vTPM command, forward to tpm + TPMTRYRETURN(vtpmmgr_tpmpass(uuid, cmdbuf, resbuf)); + } + goto egress; +abort_egress: + make_vtpm_resp_buf(resbuf, tag, status, 0); +egress: + return status; +} + diff -Naur xen-unstable-trp-sdp-pristine/stubdom/vtpmmgr/vtpm_cmd_handler.h xen-unstable-trp-sdp/stubdom/vtpmmgr/vtpm_cmd_handler.h --- xen-unstable-trp-sdp-pristine/stubdom/vtpmmgr/vtpm_cmd_handler.h 1969-12-31 19:00:00.000000000 -0500 +++ xen-unstable-trp-sdp/stubdom/vtpmmgr/vtpm_cmd_handler.h 2011-02-23 19:40:48.000000000 -0500 @@ -0,0 +1,42 @@ +/* LICENSE AND DISCLAIMER + * + * Copyright © 2011 The Johns Hopkins University/Applied Physics + * Laboratory + + * This software was developed at The Johns Hopkins University/Applied + * Physics Laboratory (“JHU/APL”) that is the author thereof under the + * “work made for hire” provisions of the copyright law. Permission is + * hereby granted, free of charge, to any person obtaining a copy of this + * software and associated documentation (the “Software”), to use the + * Software without restriction, including without limitation the rights to + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit others to do so, subject to the following + * conditions: + + * 1. This LICENSE AND DISCLAIMER, including the copyright notice, shall + * be included in all copies of the Software, including copies of + * substantial portions of the Software; + + * 2. JHU/APL assumes no obligation to provide support of any kind with + * regard to the Software. This includes no obligation to provide assistance + * in using the Software nor to provide updated versions of the Software; and + + * 3. THE 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. USERS ARE ADVISED TO + * TEST THE SOFTWARE THOROUGHLY BEFORE RELYING ON IT. IN NO EVENT SHALL THE + * JOHNS HOPKINS UNIVERSITY BE LIABLE FOR ANY DAMAGES WHATSOEVER, INCLUDING, + * WITHOUT LIMITATION, ANY LOST PROFITS, LOST SAVINGS OR OTHER INCIDENTAL OR + * CONSEQUENTIAL DAMAGES, ARISING OUT OF THE USE OR INABILITY TO USE THE + * SOFTWARE. + */ +#ifndef VTPMMGR_CMD_HANDLER_H +#define VTPMMGR_CMD_HANDLER_H + +#include + +TPM_RESULT vtpmmgr_handle_cmd(char* uuid, buffer_t* cmdbuf, buffer_t* resbuf); + +#endif diff -Naur xen-unstable-trp-sdp-pristine/stubdom/vtpmmgr/vtpmmgr.c xen-unstable-trp-sdp/stubdom/vtpmmgr/vtpmmgr.c --- xen-unstable-trp-sdp-pristine/stubdom/vtpmmgr/vtpmmgr.c 1969-12-31 19:00:00.000000000 -0500 +++ xen-unstable-trp-sdp/stubdom/vtpmmgr/vtpmmgr.c 2011-02-23 19:40:48.000000000 -0500 @@ -0,0 +1,466 @@ +/* LICENSE AND DISCLAIMER + * + * Copyright © 2011 The Johns Hopkins University/Applied Physics + * Laboratory + + * This software was developed at The Johns Hopkins University/Applied + * Physics Laboratory (“JHU/APL”) that is the author thereof under the + * “work made for hire” provisions of the copyright law. Permission is + * hereby granted, free of charge, to any person obtaining a copy of this + * software and associated documentation (the “Software”), to use the + * Software without restriction, including without limitation the rights to + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit others to do so, subject to the following + * conditions: + + * 1. This LICENSE AND DISCLAIMER, including the copyright notice, shall + * be included in all copies of the Software, including copies of + * substantial portions of the Software; + + * 2. JHU/APL assumes no obligation to provide support of any kind with + * regard to the Software. This includes no obligation to provide assistance + * in using the Software nor to provide updated versions of the Software; and + + * 3. THE 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. USERS ARE ADVISED TO + * TEST THE SOFTWARE THOROUGHLY BEFORE RELYING ON IT. IN NO EVENT SHALL THE + * JOHNS HOPKINS UNIVERSITY BE LIABLE FOR ANY DAMAGES WHATSOEVER, INCLUDING, + * WITHOUT LIMITATION, ANY LOST PROFITS, LOST SAVINGS OR OTHER INCIDENTAL OR + * CONSEQUENTIAL DAMAGES, ARISING OUT OF THE USE OR INABILITY TO USE THE + * SOFTWARE. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "vtpm_cmd_handler.h" +#include "vtpm_storage.h" +#include "vtpmmgr.h" + +#include + +VTPM_GLOBALS *vtpm_globals=NULL; + +// --------------------------- Well Known Auths -------------------------- +const TPM_AUTHDATA WELLKNOWN_SRK_AUTH = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +const TPM_AUTHDATA WELLKNOWN_OWNER_AUTH = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + +int hwtpm_fd = -1; + +/* Default commandline options */ +struct Opts opts = +{ + .seal = 1, + .tpmdriver = TPMDRV_TPM_TIS, + .tpmiomem = TPM_BASEADDR, + .tpmirq = 0, + .tpmlocality = 0, +}; + +TPM_RESULT vtpmmgr_create(void) { + TPM_RESULT status = TPM_SUCCESS; + CRYPTO_INFO ek_cryptoInfo; + TCS_AUTH osap; + TPM_AUTHDATA sharedsecret; + TPM_AUTHDATA bootKeyWrapAuth; + + + // Generate Auth for Owner + memcpy(vtpm_globals->owner_usage_auth, opts.ownerauth, sizeof(TPM_AUTHDATA)); + + // Take Owership of TPM + + // If we can read PubEK then there is no owner and we should take it. + // We use the abilty to read the pubEK to flag that the TPM is owned. + // FIXME: Change to just trying to take ownership and react to the status + if(VTSP_ReadPubek(vtpm_globals->manager_tcs_handle, &ek_cryptoInfo) == TPM_SUCCESS) { + TPMTRYRETURN(VTSP_TakeOwnership(vtpm_globals->manager_tcs_handle, + (const TPM_AUTHDATA*)&vtpm_globals->owner_usage_auth, + (const TPM_AUTHDATA*)&opts.srkauth, + &ek_cryptoInfo, + &vtpm_globals->keyAuth)); + + TPMTRYRETURN(VTSP_DisablePubekRead(vtpm_globals->manager_tcs_handle, + (const TPM_AUTHDATA*)&vtpm_globals->owner_usage_auth, + &vtpm_globals->keyAuth)); + Crypto_RSACryptoInfoFree(&ek_cryptoInfo); + } else { + vtpmloginfo(VTPM_LOG_VTPM, "Failed to readEK meaning TPM has an owner. Creating Keys off existing SRK.\n"); + } + + // Generate storage key's auth + Crypto_GetRandom( &vtpm_globals->storage_key_usage_auth, + sizeof(TPM_AUTHDATA) ); + + + TPMTRYRETURN( VTSP_OSAP(vtpm_globals->manager_tcs_handle, + TPM_ET_KEYHANDLE, + TPM_SRK_KEYHANDLE, + (const TPM_AUTHDATA*)&opts.srkauth, + &sharedsecret, + &osap) ); + + osap.fContinueAuthSession = FALSE; + + TPMTRYRETURN( VTSP_CreateWrapKey( vtpm_globals->manager_tcs_handle, + TPM_KEY_BIND, + (const TPM_AUTHDATA*)&vtpm_globals->storage_key_usage_auth, + TPM_SRK_KEYHANDLE, + (const TPM_AUTHDATA*)&sharedsecret, + &vtpm_globals->storageKeyWrap, + &osap) ); + + // Generate boot key's auth + memset(&bootKeyWrapAuth, 0, sizeof(bootKeyWrapAuth)); + + TPMTRYRETURN( VTSP_OSAP(vtpm_globals->manager_tcs_handle, + TPM_ET_KEYHANDLE, + TPM_SRK_KEYHANDLE, + (const TPM_AUTHDATA*)&opts.srkauth, + &sharedsecret, + &osap) ); + + osap.fContinueAuthSession = FALSE; + + // FIXME: This key protects the global secrets on disk. It should use TPM + // PCR bindings to limit its use to legit configurations. + // Current binds are open, implying a Trusted VM contains this code. + // If this VM is not Trusted, use measurement and PCR bindings. + TPMTRYRETURN( VTSP_CreateWrapKey( vtpm_globals->manager_tcs_handle, + TPM_KEY_BIND, + (const TPM_AUTHDATA*)&bootKeyWrapAuth, + TPM_SRK_KEYHANDLE, + (const TPM_AUTHDATA*)&sharedsecret, + &vtpm_globals->bootKeyWrap, + &osap) ); + + // Populate CRYPTO_INFO vtpm_globals->bootKey. This does not load it into the TPM + TPMTRYRETURN( VTSP_LoadKey( vtpm_globals->manager_tcs_handle, + TPM_SRK_KEYHANDLE, + &vtpm_globals->bootKeyWrap, + NULL, + NULL, + NULL, + &vtpm_globals->bootKey, + TRUE ) ); + + TPMTRYRETURN( VTSP_SaveState(vtpm_globals->manager_tcs_handle) ); + + goto egress; +abort_egress: +egress: + vtpmloginfo(VTPM_LOG_VTPM, "Finished initialized new VTPM manager\n"); + + return status; +} + +TPM_RESULT vtpmmgr_init(void) { + TPM_RESULT status = TPM_SUCCESS; + BYTE *randomseed = NULL; + UINT32 randomsize=256; + + if ((vtpm_globals = (VTPM_GLOBALS *) malloc(sizeof(VTPM_GLOBALS))) == NULL){ + status = TPM_FAIL; + goto abort_egress; + } + memset(vtpm_globals, 0, sizeof(VTPM_GLOBALS)); + + // Create new TCS Object + vtpm_globals->manager_tcs_handle = 0; + TPMTRYRETURN(TDDL_Open_use_fd(hwtpm_fd)); + TPMTRYRETURN(TCS_create()); + + // Blow away all stale handles left in the tpm + if(TDDL_FlushAllResources() != TPM_SUCCESS) { + vtpmlogerror(VTPM_LOG_VTPM, "VTPM_FlushResources failed, continuing anyway..\n"); + } + + // Create TCS Context for service + TPMTRYRETURN( TCS_OpenContext(&vtpm_globals->manager_tcs_handle ) ); + TPMTRYRETURN( TCSP_GetRandom(vtpm_globals->manager_tcs_handle, + &randomsize, + &randomseed)); + + RAND_seed(randomseed, randomsize); + /* Initialize the crypto system */ + Crypto_Init(randomseed, randomsize); + + // Create OIAP session for service's authorized commands + TPMTRYRETURN( VTSP_OIAP( vtpm_globals->manager_tcs_handle, + &vtpm_globals->keyAuth) ); + vtpm_globals->keyAuth.fContinueAuthSession = TRUE; + + /* Load the Manager data, if it fails create a new manager */ + if (vtpm_storage_LoadManagerData() != TPM_SUCCESS) { + vtpmloginfo(VTPM_LOG_VTPM, "Failed to read manager file. Assuming first time initialization.\n"); + TPMTRYRETURN( vtpmmgr_create() ); + TPMTRYRETURN( vtpm_storage_SaveManagerData() ); + } + + //Load Storage Key + TPMTRYRETURN( VTSP_LoadKey( vtpm_globals->manager_tcs_handle, + TPM_SRK_KEYHANDLE, + &vtpm_globals->storageKeyWrap, + (const TPM_AUTHDATA*)&opts.srkauth, + &vtpm_globals->storageKeyHandle, + &vtpm_globals->keyAuth, + &vtpm_globals->storageKey, + FALSE ) ); + + /* Load the uuid and key data header */ + TPMTRYRETURN(vtpm_storage_LoadKeyMeta()); + + goto egress; +abort_egress: +egress: + TCS_FreeMemory (vtpm_globals->manager_tcs_handle, randomseed); + return status; +} + +void vtpmmgr_shutdown(void) +{ + /*Save Data to disk */ + if ( vtpm_storage_SaveManagerData() != TPM_SUCCESS ) + vtpmlogerror(VTPM_LOG_VTPM, "Unable to save manager data.\n"); + + /* Shutdown TCS context */ + TCS_CloseContext(vtpm_globals->manager_tcs_handle); + TCS_destroy(); + + /* Cleanup resources */ + Crypto_RSACryptoInfoFree(&vtpm_globals->bootKey); + Crypto_RSACryptoInfoFree(&vtpm_globals->storageKey); + buffer_free(&vtpm_globals->bootKeyWrap); + buffer_free(&vtpm_globals->storageKeyWrap); + free(vtpm_globals); + + /* Close crypto system */ + Crypto_Exit(); + + vtpmloginfo(VTPM_LOG_VTPM, "VTPM Manager stopped.\n"); +} + +void main_loop(void) { + tpmcmd_t* tpmcmd; + buffer_t cmdbuf; + buffer_t resbuf; + + while(1) { + /* Wait for requests from a vtpm */ + vtpmloginfo(VTPM_LOG_VTPM, "Waiting for commands from vTPM's:\n"); + if((tpmcmd = tpmback_req_any()) == NULL) { + vtpmlogerror(VTPM_LOG_VTPM, "NULL tpmcmd\n"); + continue; + } + + /* setup buffers */ + buffer_init_alias_convert(&cmdbuf, tpmcmd->req_len, tpmcmd->req); + buffer_init(&resbuf, 0, NULL); + + /* Now process the command */ + vtpmmgr_handle_cmd(tpmcmd->uuid, &cmdbuf, &resbuf); + + /* Send response */ + tpmcmd->resp = resbuf.bytes; + tpmcmd->resp_len = buffer_len(&resbuf); + tpmback_resp(tpmcmd); + + /* Cleanup */ + buffer_free(&cmdbuf); + buffer_free(&resbuf); + } +} + +int parse_auth_string(char* authstr, BYTE* target, const TPM_AUTHDATA wellknown, int allowrandom) { + int rc; + /* well known owner auth */ + if(!strcmp(authstr, "well-known")) { + memcpy(target, wellknown, sizeof(TPM_AUTHDATA)); + } + /* Create a randomly generated owner auth */ + else if(allowrandom && !strcmp(authstr, "random")) { + Crypto_GetRandom(target, sizeof(TPM_AUTHDATA)); + } + /* owner auth is a raw hash */ + else if(!strncmp(authstr, "hash:", 5)) { + authstr += 5; + if((rc = strlen(authstr)) != 40) { + vtpmlogerror(VTPM_LOG_VTPM, "Supplied owner auth hex string `%s' must be exactly 40 characters (20 bytes) long, length=%d\n", authstr, rc); + return -1; + } + for(int j = 0; j < 20; ++j) { + if(sscanf(authstr, "%hhX", target + j) != 1) { + vtpmlogerror(VTPM_LOG_VTPM, "Supplied owner auth string `%s' is not a valid hex string\n", authstr); + return -1; + } + authstr += 2; + } + } + /* owner auth is a string that will be hashed */ + else if(!strncmp(authstr, "text:", 5)) { + authstr += 5; + Crypto_SHA1Full((BYTE*) authstr, strlen(authstr), target); + } + else { + vtpmlogerror(VTPM_LOG_VTPM, "Invalid auth string %s\n", authstr); + return -1; + } + + return 0; +} + +int parse_cmdline_opts(int argc, char** argv) +{ + int rc; + int i; + + //Set defaults + memcpy(opts.ownerauth, WELLKNOWN_OWNER_AUTH, sizeof(TPM_AUTHDATA)); + memcpy(opts.srkauth, WELLKNOWN_SRK_AUTH, sizeof(TPM_AUTHDATA)); + + for(i = 1; i < argc; ++i) { + if(!strcmp(argv[i], "seal")) { + opts.seal = 1; + } else if(!strcmp(argv[i], "noseal")) { + opts.seal = 0; + } + else if(!strncmp(argv[i], "ownerauth:", 10)) { + if((rc = parse_auth_string(argv[i] + 10, opts.ownerauth, WELLKNOWN_OWNER_AUTH, 1)) != 0) { + goto err_invalid; + } + } + else if(!strncmp(argv[i], "srkauth:", 8)) { + if((rc = parse_auth_string(argv[i] + 8, opts.srkauth, WELLKNOWN_SRK_AUTH, 0)) != 0) { + goto err_invalid; + } + } + else if(!strncmp(argv[i], "tpmdriver=", 10)) { + if(!strcmp(argv[i] + 10, "tpm_tis")) { + opts.tpmdriver = TPMDRV_TPM_TIS; + } else if(!strcmp(argv[i] + 10, "tpmfront")) { + opts.tpmdriver = TPMDRV_TPMFRONT; + } else { + goto err_invalid; + } + } + else if(!strncmp(argv[i], "tpmiomem=",9)) { + if(sscanf(argv[i] + 9, "0x%lX", &opts.tpmiomem) != 1) { + goto err_invalid; + } + } + else if(!strncmp(argv[i], "tpmirq=",7)) { + if(!strcmp(argv[i] + 7, "probe")) { + opts.tpmirq = TPM_PROBE_IRQ; + } else if( sscanf(argv[i] + 7, "%u", &opts.tpmirq) != 1) { + goto err_invalid; + } + } + else if(!strncmp(argv[i], "tpmlocality=",12)) { + if(sscanf(argv[i] + 12, "%u", &opts.tpmlocality) != 1 || opts.tpmlocality > 4) { + goto err_invalid; + } + } + } + + if(opts.seal) { + vtpmloginfo(VTPM_LOG_VTPM, "Option: Sealed Storage Enabled\n"); + } else { + vtpmloginfo(VTPM_LOG_VTPM, "Option: Sealed Storage Disabled\n"); + } + switch(opts.tpmdriver) { + case TPMDRV_TPM_TIS: + vtpmloginfo(VTPM_LOG_VTPM, "Option: Using tpm_tis driver\n"); + break; + case TPMDRV_TPMFRONT: + vtpmloginfo(VTPM_LOG_VTPM, "Option: Using tpmfront driver\n"); + break; + } + + return 0; +err_invalid: + vtpmlogerror(VTPM_LOG_VTPM, "Invalid Option %s\n", argv[i]); + return -1; +} + +int main(int argc, char** argv) +{ + sleep(2); + vtpmloginfo(VTPM_LOG_VTPM, "Starting vTPM manager domain\n"); + + if(parse_cmdline_opts(argc, argv) != 0) { + vtpmlogerror(VTPM_LOG_VTPM, "Command line parsing failed! exiting..\n"); + goto exit_postcmd; + } + + //Setup storage system + if(vtpm_storage_init() != 0) { + vtpmlogerror(VTPM_LOG_VTPM, "Unable to initialize storage subsystem!\n"); + goto exit_poststorage; + } + + //Setup tpmback device + init_tpmback(NULL); + + //Setup tpm access + switch(opts.tpmdriver) { + case TPMDRV_TPM_TIS: + { + struct tpm_chip* tpm; + if((tpm = init_tpm_tis(opts.tpmiomem, TPM_TIS_LOCL_INT_TO_FLAG(opts.tpmlocality), opts.tpmirq)) == NULL) { + vtpmlogerror(VTPM_LOG_VTPM, "Unable to initialize tpmfront device\n"); + goto exit_posttpmfront; + } + hwtpm_fd = tpm_tis_open(tpm); + tpm_tis_request_locality(tpm, opts.tpmlocality); + } + break; + case TPMDRV_TPMFRONT: + { + struct tpmfront_dev* tpmfront_dev; + if((tpmfront_dev = init_tpmfront(NULL)) == NULL) { + vtpmlogerror(VTPM_LOG_VTPM, "Unable to initialize tpmfront device\n"); + goto exit_posttpmfront; + } + hwtpm_fd = tpmfront_open(tpmfront_dev); + } + break; + } + + /* Initialize the vtpm manager */ + if(vtpmmgr_init() != TPM_SUCCESS) { + vtpmlogerror(VTPM_LOG_VTPM, "Unable to initialize vtpmmgr domain!\n"); + goto exit_postmgrinit; + } + + main_loop(); + + vtpmloginfo(VTPM_LOG_VTPM, "vTPM Manager shutting down...\n"); + +exit_postmgrinit: + vtpmmgr_shutdown(); + /* tpmfront will be shutdown by manager destroying TCS Context */ +exit_posttpmfront: + shutdown_tpmback(); + vtpm_storage_shutdown(); +exit_poststorage: +exit_postcmd: + + return 0; + +} diff -Naur xen-unstable-trp-sdp-pristine/stubdom/vtpmmgr/vtpmmgr.h xen-unstable-trp-sdp/stubdom/vtpmmgr/vtpmmgr.h --- xen-unstable-trp-sdp-pristine/stubdom/vtpmmgr/vtpmmgr.h 1969-12-31 19:00:00.000000000 -0500 +++ xen-unstable-trp-sdp/stubdom/vtpmmgr/vtpmmgr.h 2011-02-23 19:40:48.000000000 -0500 @@ -0,0 +1,79 @@ +/* LICENSE AND DISCLAIMER + * + * Copyright © 2011 The Johns Hopkins University/Applied Physics + * Laboratory + + * This software was developed at The Johns Hopkins University/Applied + * Physics Laboratory (“JHU/APL”) that is the author thereof under the + * “work made for hire” provisions of the copyright law. Permission is + * hereby granted, free of charge, to any person obtaining a copy of this + * software and associated documentation (the “Software”), to use the + * Software without restriction, including without limitation the rights to + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit others to do so, subject to the following + * conditions: + + * 1. This LICENSE AND DISCLAIMER, including the copyright notice, shall + * be included in all copies of the Software, including copies of + * substantial portions of the Software; + + * 2. JHU/APL assumes no obligation to provide support of any kind with + * regard to the Software. This includes no obligation to provide assistance + * in using the Software nor to provide updated versions of the Software; and + + * 3. THE 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. USERS ARE ADVISED TO + * TEST THE SOFTWARE THOROUGHLY BEFORE RELYING ON IT. IN NO EVENT SHALL THE + * JOHNS HOPKINS UNIVERSITY BE LIABLE FOR ANY DAMAGES WHATSOEVER, INCLUDING, + * WITHOUT LIMITATION, ANY LOST PROFITS, LOST SAVINGS OR OTHER INCIDENTAL OR + * CONSEQUENTIAL DAMAGES, ARISING OUT OF THE USE OR INABILITY TO USE THE + * SOFTWARE. + */ +#ifndef VTPMMGR_H +#define VTPMMGR_H + +#include +#include + +struct Opts { + int seal; + TPM_AUTHDATA ownerauth; + TPM_AUTHDATA srkauth; + enum { + TPMDRV_TPM_TIS, + TPMDRV_TPMFRONT, + } tpmdriver; + unsigned long tpmiomem; + unsigned int tpmirq; + unsigned int tpmlocality; +}; + +extern struct Opts opts; + +#define VTPM_MANAGER_GEN 2 // This is incremented when the manager's table + // is changed. It's used for backwards compatability + +typedef struct tdVTPM_GLOBALS { + TCS_CONTEXT_HANDLE manager_tcs_handle; // TCS Handle used by manager + TPM_HANDLE storageKeyHandle; // Key used by persistent store + CRYPTO_INFO storageKey; // For software encryption + CRYPTO_INFO bootKey; // For saving table + TCS_AUTH keyAuth; // OIAP session for storageKey + + // Persistent Data + TPM_AUTHDATA owner_usage_auth; // OwnerAuth of real TPM + buffer_t storageKeyWrap; // Wrapped copy of storageKey + TPM_AUTHDATA srk_usage_auth; + TPM_AUTHDATA storage_key_usage_auth; + + buffer_t bootKeyWrap; // Wrapped copy of boot key + +}VTPM_GLOBALS; + +// --------------------------- Global Values -------------------------- +extern VTPM_GLOBALS *vtpm_globals; // Key info and DMI states + +#endif diff -Naur xen-unstable-trp-sdp-pristine/stubdom/vtpmmgr/vtpm_storage.c xen-unstable-trp-sdp/stubdom/vtpmmgr/vtpm_storage.c --- xen-unstable-trp-sdp-pristine/stubdom/vtpmmgr/vtpm_storage.c 1969-12-31 19:00:00.000000000 -0500 +++ xen-unstable-trp-sdp/stubdom/vtpmmgr/vtpm_storage.c 2011-02-23 19:40:48.000000000 -0500 @@ -0,0 +1,1348 @@ +/* LICENSE AND DISCLAIMER + * + * Copyright © 2011 The Johns Hopkins University/Applied Physics + * Laboratory + + * This software was developed at The Johns Hopkins University/Applied + * Physics Laboratory (“JHU/APL”) that is the author thereof under the + * “work made for hire” provisions of the copyright law. Permission is + * hereby granted, free of charge, to any person obtaining a copy of this + * software and associated documentation (the “Software”), to use the + * Software without restriction, including without limitation the rights to + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit others to do so, subject to the following + * conditions: + + * 1. This LICENSE AND DISCLAIMER, including the copyright notice, shall + * be included in all copies of the Software, including copies of + * substantial portions of the Software; + + * 2. JHU/APL assumes no obligation to provide support of any kind with + * regard to the Software. This includes no obligation to provide assistance + * in using the Software nor to provide updated versions of the Software; and + + * 3. THE 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. USERS ARE ADVISED TO + * TEST THE SOFTWARE THOROUGHLY BEFORE RELYING ON IT. IN NO EVENT SHALL THE + * JOHNS HOPKINS UNIVERSITY BE LIABLE FOR ANY DAMAGES WHATSOEVER, INCLUDING, + * WITHOUT LIMITATION, ANY LOST PROFITS, LOST SAVINGS OR OTHER INCIDENTAL OR + * CONSEQUENTIAL DAMAGES, ARISING OUT OF THE USE OR INABILITY TO USE THE + * SOFTWARE. + */ + +/*************************************************************** + * DISK IMAGE LAYOUT + * ************************************************************* + * All data is stored in BIG ENDIAN format + * ************************************************************* + * Section 1: Header (fixed size = 38 bytes) + * + * 10 bytes id ID String "VTPMMGRDOM" + * uint32_t version Disk Image version number (current == 1) + * uint32_t off_mgrdata Manager Data Section Offset + * uint32_t sz_mgrdata Manager Data Size + * uint32_t off_uuiddata Uuid Data Section Offset + * uint32_t sz_uuiddata Uuid Data Size (may be zero which indicates no uuid data is present) + * uint32_t off_keydata Key Data Section Offset + * uint32_t sz_keys Key Data Section Size (may be zero which indicates no key data is present) + * + * ************************************************************* + * Section 2: VTPM Manager Data + * + * see vtpm_manager.h + * + * ************************************************************* + * Section 3: Uuid Data + * + * This section contains a bunch of null terminated (0 byte) + * strings. One for each vtpm Uuid we are storing keys for. + * Each null terminated string is followed by a 32 bit integer + * index telling where its data is located in the key section. + * The end of the section is marked by an empty string. + * + * Example: ("foo\0bar\0baz\0\0") + * + * This entire section is encrypted with the vTPM storage key + * + * ************************************************************* + * Section 4: Key Data Table + * + * This section has a header: + * uint32_t sz_key Encrypted size of each table entry + * uint32_t num_keys Number of keys in this section + * + * Each table entry in the key data section is as follows: + * 20 bytes hash Sha1 hash of vTPM's data, supplied by vTPM + * 256 bytes key AES-256 Encryption Key, supplied by vTPM + * + * This data is encrypted, which may increase the total size of + * the key data entry. The encrypted size of each key data entry is given by sz_key + * in the header. The total size of this section is sz_key * num_keys. + * + * ************************************************************* + */ +#define DISKVERS 1 +#define HEADERSZ 38 +#define KEYHDRSZ 8 +#define IDSTR "VTPMMGRDOM" +#define IDSTRLEN 10 +#define DEFALLOC 16 +#define SECTIONBDD 512 + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "vtpmmgr.h" +#include "vtpm_storage.h" + +#define MAX(a,b) ( ((a) > (b)) ? (a) : (b) ) +#define MIN(a,b) ( ((a) < (b)) ? (a) : (b) ) + +/* blkfront device objets */ +static struct blkfront_dev* blkdev = NULL; +static int blkfront_fd = -1; + +/* In memory copy of the disk image contents */ +struct VtpmHeader { + uint32_t version; + uint32_t off_mgrdata; + uint32_t sz_mgrdata; + uint32_t off_uuids; + uint32_t sz_uuids; + uint32_t off_keys; + uint32_t sz_keys; +}; +struct UuidPair { + char* uuid; + uint32_t index; +}; +struct UuidData { + int num_alloc; + int num_uuids; + struct UuidPair* uuids; +}; +struct KeyData { + uint32_t sz_key; + uint32_t num_keys; +}; +struct SecureStorage { + struct VtpmHeader hdr; + struct UuidData uuiddata; + struct KeyData keydata; +}; +static struct SecureStorage storage = +{ + .hdr = + { + .version = DISKVERS, + .off_mgrdata = 0, + .sz_mgrdata = 0, + .off_uuids = 0, + .sz_uuids = 0, + .off_keys = 0, + .sz_keys = 0, + }, + .uuiddata = + { + .num_alloc = 0, + .num_uuids = 0, + .uuids = NULL, + }, + .keydata = + { + .sz_key = 0, + .num_keys = 0, + }, +}; + + + +/******************************************* + * INTERNAL HELPERS + * *************************************/ + +/* move sz bytes at location st offset bytes */ +TPM_RESULT block_move(uint32_t st, uint32_t sz, int offset) { + TPM_RESULT status = TPM_SUCCESS; + buffer_t buf = NULL_BUF; + int rc; + + buffer_init(&buf, sz, NULL); + + /* Read data */ + lseek(blkfront_fd, st, SEEK_SET); + if((rc = read(blkfront_fd, buf.bytes, sz)) != sz) { + vtpmlogerror(VTPM_LOG_VTPM, "Block Move Read Failure : offset=%" PRIu32 " size=%" PRIu32 " return %d, error=`%s'\n", st, sz, rc, strerror(errno)); + status = TPM_IOERROR; + goto abort_egress; + } + + /* Write data */ + lseek(blkfront_fd, st + offset, SEEK_SET); + if((rc = write(blkfront_fd, buf.bytes, sz)) != sz) { + vtpmlogerror(VTPM_LOG_VTPM, "Block Move Write Failure : offset=%" PRIu32 " size=%" PRIu32 " return %d, error=`%s'\n", st + offset, sz, rc, strerror(errno)); + status = TPM_IOERROR; + goto abort_egress; + } + + goto egress; +abort_egress: +egress: + buffer_free(&buf); + return status; +} + +enum SecType { + SEC_MGRDATA, + SEC_UUIDDATA, + SEC_KEYDATA +}; + +/* ENCRYPTION FUNCTIONS */ +TPM_RESULT envelope_encrypt(const buffer_t *inbuf, + CRYPTO_INFO *asymkey, + buffer_t *sealed_data) { + TPM_RESULT status = TPM_SUCCESS; + symkey_t *symkey; + buffer_t data_cipher = NULL_BUF, + symkey_cipher = NULL_BUF; + + UINT32 i; + struct pack_constbuf_t symkey_cipher32, data_cipher32; + + vtpmloginfo(VTPM_LOG_VTPM_DEEP, "Enveloping Input[%d]: 0x", buffer_len(inbuf)); + for (i=0; i< buffer_len(inbuf); i++) + vtpmloginfomore(VTPM_LOG_VTPM_DEEP, "%x ", inbuf->bytes[i]); + vtpmloginfomore(VTPM_LOG_VTPM_DEEP, "\n"); + + // Generate a sym key and encrypt state with it + TPMTRY(TPM_ENCRYPT_ERROR, Crypto_symcrypto_genkey (&symkey) ); + TPMTRY(TPM_ENCRYPT_ERROR, Crypto_symcrypto_encrypt (symkey, inbuf, &data_cipher) ); + + // Encrypt symmetric key + TPMTRYRETURN( VTSP_Bind( asymkey, + Crypto_symkey_getkey(symkey), + &symkey_cipher) ); + + // Create output blob: symkey_size + symkey_cipher + state_cipher_size + state_cipher + + symkey_cipher32.size = buffer_len(&symkey_cipher); + symkey_cipher32.data = symkey_cipher.bytes; + + data_cipher32.size = buffer_len(&data_cipher); + data_cipher32.data = data_cipher.bytes; + + TPMTRYRETURN( buffer_init(sealed_data, 2 * sizeof(UINT32) + symkey_cipher32.size + data_cipher32.size, NULL)); + memset(sealed_data->bytes, 0, sealed_data->size); + + BSG_PackList(sealed_data->bytes, 2, + BSG_TPM_SIZE32_DATA, &symkey_cipher32, + BSG_TPM_SIZE32_DATA, &data_cipher32); + + vtpmloginfo(VTPM_LOG_VTPM, "Saved %d bytes of E(symkey) + %d bytes of E(data)\n", buffer_len(&symkey_cipher), buffer_len(&data_cipher)); + + vtpmloginfo(VTPM_LOG_VTPM_DEEP, "Enveloping Output[%d]: 0x", buffer_len(sealed_data)); + for (i=0; i< buffer_len(sealed_data); i++) + vtpmloginfomore(VTPM_LOG_VTPM_DEEP, "%x ", sealed_data->bytes[i]); + vtpmloginfomore(VTPM_LOG_VTPM_DEEP, "\n"); + + goto egress; + + abort_egress: + vtpmlogerror(VTPM_LOG_VTPM, "Failed to envelope encrypt\n."); + + egress: + + buffer_free ( &data_cipher); + buffer_free ( &symkey_cipher); + Crypto_symcrypto_freekey (symkey); + + return status; +} + +TPM_RESULT symkey_encrypt(const buffer_t *inbuf, + CRYPTO_INFO *asymkey, + buffer_t *sealed_key) { + buffer_t symkey_cipher = NULL_BUF; + struct pack_constbuf_t symkey_cipher32; + TPM_RESULT status = TPM_SUCCESS; + + // Encrypt symmetric key + TPMTRYRETURN( VTSP_Bind( asymkey, + inbuf, + &symkey_cipher)); + + symkey_cipher32.size = buffer_len(&symkey_cipher); + symkey_cipher32.data = symkey_cipher.bytes; + + TPMTRYRETURN( buffer_init(sealed_key, sizeof(UINT32) + symkey_cipher32.size, NULL)); + BSG_PackList(sealed_key->bytes, 1, + BSG_TPM_SIZE32_DATA, &symkey_cipher32); + goto egress; +abort_egress: +egress: + buffer_free( &symkey_cipher); + return status; +} + +TPM_RESULT envelope_decrypt(const buffer_t *cipher, + TCS_CONTEXT_HANDLE TCSContext, + TPM_HANDLE keyHandle, + const TPM_AUTHDATA *key_usage_auth, + buffer_t *unsealed_data) { + + TPM_RESULT status = TPM_SUCCESS; + symkey_t *symkey; + buffer_t data_cipher = NULL_BUF, + symkey_clear = NULL_BUF, + symkey_cipher = NULL_BUF; + struct pack_buf_t symkey_cipher32 = NULL_PACK_BUF, data_cipher32 = NULL_PACK_BUF; + int i; + + vtpmloginfo(VTPM_LOG_VTPM_DEEP, "Envelope Decrypt Input[%d]: 0x", buffer_len(cipher) ); + for (i=0; i< buffer_len(cipher); i++) + vtpmloginfomore(VTPM_LOG_VTPM_DEEP, "%x ", cipher->bytes[i]); + vtpmloginfomore(VTPM_LOG_VTPM_DEEP, "\n"); + + BSG_UnpackList(cipher->bytes, 2, + BSG_TPM_SIZE32_DATA, &symkey_cipher32, + BSG_TPM_SIZE32_DATA, &data_cipher32); + + TPMTRYRETURN( buffer_init_alias_convert (&symkey_cipher, + symkey_cipher32.size, + symkey_cipher32.data) ); + + TPMTRYRETURN( buffer_init_alias_convert (&data_cipher, + data_cipher32.size, + data_cipher32.data) ); + + // Decrypt Symmetric Key + TPMTRYRETURN( VTSP_Unbind( TCSContext, + keyHandle, + &symkey_cipher, + key_usage_auth, + &symkey_clear, + &(vtpm_globals->keyAuth) ) ); + + // create symmetric key using saved bits + Crypto_symcrypto_initkey (&symkey, &symkey_clear); + + // Decrypt State + TPMTRY(TPM_DECRYPT_ERROR, Crypto_symcrypto_decrypt (symkey, &data_cipher, unsealed_data) ); + + vtpmloginfo(VTPM_LOG_VTPM_DEEP, "Envelope Decrypte Output[%d]: 0x", buffer_len(unsealed_data)); + for (i=0; i< buffer_len(unsealed_data); i++) + vtpmloginfomore(VTPM_LOG_VTPM_DEEP, "%x ", unsealed_data->bytes[i]); + vtpmloginfomore(VTPM_LOG_VTPM_DEEP, "\n"); + + goto egress; + + abort_egress: + vtpmlogerror(VTPM_LOG_VTPM, "Failed to envelope decrypt data\n."); + + egress: + buffer_free ( &data_cipher); + buffer_free ( &symkey_clear); + buffer_free ( &symkey_cipher); + BSG_Destroy(BSG_TPM_SIZE32_DATA, &symkey_cipher32); + BSG_Destroy(BSG_TPM_SIZE32_DATA, &data_cipher32); + Crypto_symcrypto_freekey (symkey); + + + return status; +} + +TPM_RESULT symkey_decrypt(const buffer_t *cipher, + TCS_CONTEXT_HANDLE TCSContext, + TPM_HANDLE keyHandle, + const TPM_AUTHDATA *key_usage_auth, + buffer_t *symkey_clear) { + + TPM_RESULT status = TPM_SUCCESS; + buffer_t symkey_cipher = NULL_BUF; + struct pack_buf_t symkey_cipher32 = NULL_PACK_BUF; + + BSG_UnpackList(cipher->bytes, 1, + BSG_TPM_SIZE32_DATA, &symkey_cipher32); + + TPMTRYRETURN( buffer_init_alias_convert (&symkey_cipher, + symkey_cipher32.size, + symkey_cipher32.data) ); + + // Decrypt Symmetric Key + TPMTRYRETURN( VTSP_Unbind( TCSContext, + keyHandle, + &symkey_cipher, + key_usage_auth, + symkey_clear, + &(vtpm_globals->keyAuth) ) ); + + goto egress; + abort_egress: + vtpmlogerror(VTPM_LOG_VTPM, "Failed to decrypt symmetric key status=%d\n.", status); + + egress: + BSG_Destroy(BSG_TPM_SIZE32_DATA, &symkey_cipher32); + return status; +} + +/* HEADER DATA FUNCTIONS */ + +#define HEADERSANE(COND, MSG) if(COND) { \ + vtpmlogerror(VTPM_LOG_VTPM, "Corrupted Header: " MSG "\n");\ + status = TPM_FAIL;\ + goto abort_egress;\ +} + +TPM_RESULT HeaderLoad(void) +{ + TPM_RESULT status = TPM_SUCCESS; + buffer_t headerbuf = NULL_BUF; + int rc; + + buffer_init(&headerbuf, HEADERSZ, NULL); + + /* Read the header from disk */ + lseek(blkfront_fd, 0, SEEK_SET); + if((rc = read(blkfront_fd, headerbuf.bytes, HEADERSZ)) != HEADERSZ) { + vtpmlogerror(VTPM_LOG_VTPM, "Failed to read vtpm header section : return=%d error=`%s'\n", rc, strerror(errno)); + status = TPM_IOERROR; + goto abort_egress; + } + + /* Verify the ID string */ + if(strncmp((char*)headerbuf.bytes, IDSTR, IDSTRLEN)) { + vtpmlogerror(VTPM_LOG_VTPM, "Invalid ID string in disk image!\n"); + status = TPM_FAIL; + goto abort_egress; + } + + /* Unpack the header */ + BSG_UnpackList(headerbuf.bytes + IDSTRLEN, 7, + BSG_TYPE_UINT32, &storage.hdr.version, + BSG_TYPE_UINT32, &storage.hdr.off_mgrdata, + BSG_TYPE_UINT32, &storage.hdr.sz_mgrdata, + BSG_TYPE_UINT32, &storage.hdr.off_uuids, + BSG_TYPE_UINT32, &storage.hdr.sz_uuids, + BSG_TYPE_UINT32, &storage.hdr.off_keys, + BSG_TYPE_UINT32, &storage.hdr.sz_keys + ); + + /* Verify the version */ + if(storage.hdr.version != DISKVERS) { + vtpmlogerror(VTPM_LOG_VTPM, "Unsupported disk image version number %" PRIu32 "\n", storage.hdr.version); + status = TPM_FAIL; + goto abort_egress; + } + + /* Sanity Check Manager data offsets */ + HEADERSANE((storage.hdr.off_mgrdata == 0 || storage.hdr.sz_mgrdata == 0), "Manager Data Section is not present"); + HEADERSANE((storage.hdr.off_mgrdata < HEADERSZ), "Manager Data collides with Header"); + HEADERSANE(((storage.hdr.off_mgrdata < storage.hdr.off_uuids && storage.hdr.off_mgrdata + storage.hdr.sz_mgrdata > storage.hdr.off_uuids) + || (storage.hdr.off_mgrdata >= storage.hdr.off_uuids && storage.hdr.off_mgrdata < storage.hdr.off_uuids + storage.hdr.sz_uuids)), "Manager Data collides with Uuid Data"); + HEADERSANE(((storage.hdr.off_mgrdata < storage.hdr.off_keys && storage.hdr.off_mgrdata + storage.hdr.sz_mgrdata > storage.hdr.off_keys) + || (storage.hdr.off_mgrdata >= storage.hdr.off_keys && storage.hdr.off_mgrdata < storage.hdr.off_keys + storage.hdr.sz_keys)), "Manager Data collides with Key Data"); + + /* Sanity Check Uuid data offsets - may not be present */ + if(storage.hdr.off_uuids != 0 && storage.hdr.sz_uuids != 0) { + HEADERSANE((storage.hdr.off_uuids < HEADERSZ), "Uuid Data collides with Header"); + HEADERSANE(((storage.hdr.off_uuids < storage.hdr.off_keys && storage.hdr.off_uuids + storage.hdr.sz_uuids > storage.hdr.off_keys) + || (storage.hdr.off_uuids >= storage.hdr.off_keys && storage.hdr.off_uuids < storage.hdr.off_keys + storage.hdr.sz_keys)), "Uuid Data collides with Key Data"); + } + /* Sanity Check Key data offsets - may not be present */ + if(storage.hdr.off_keys != 0 && storage.hdr.sz_keys != 0) { + HEADERSANE((storage.hdr.off_keys < HEADERSZ), "Key Data collides with Header"); + } + goto egress; +abort_egress: +egress: + buffer_free(&headerbuf); + return status; + +} + +TPM_RESULT HeaderSave(void) +{ + TPM_RESULT status = TPM_SUCCESS; + buffer_t headerbuf = NULL_BUF; + int rc; + + buffer_init(&headerbuf, HEADERSZ, NULL); + + /*Copy the ID string */ + memcpy(headerbuf.bytes, IDSTR, IDSTRLEN); + + /*Pack the header into the buffer */ + BSG_PackList(headerbuf.bytes + IDSTRLEN, 7, + BSG_TYPE_UINT32, &storage.hdr.version, + BSG_TYPE_UINT32, &storage.hdr.off_mgrdata, + BSG_TYPE_UINT32, &storage.hdr.sz_mgrdata, + BSG_TYPE_UINT32, &storage.hdr.off_uuids, + BSG_TYPE_UINT32, &storage.hdr.sz_uuids, + BSG_TYPE_UINT32, &storage.hdr.off_keys, + BSG_TYPE_UINT32, &storage.hdr.sz_keys + ); + + /* Write the header to disk */ + lseek(blkfront_fd, 0, SEEK_SET); + if((rc = write(blkfront_fd, headerbuf.bytes, HEADERSZ)) != HEADERSZ) { + vtpmlogerror(VTPM_LOG_VTPM, "Failed to write vtpm header section : return=%d error=`%s'\n", rc, strerror(errno)); + status = TPM_IOERROR; + goto abort_egress; + } + + goto egress; +abort_egress: +egress: + buffer_free(&headerbuf); + return status; +} + +/* DISK RELOCATION FUNCTION */ + +/* Checks if we need to relocate any sections on the disk to make + * room for the current section + * + * @sectype - Section type enum + * @size - size of the updated section + * @writehdr - if 1, update the header on disk with the new offsets + * + * */ +TPM_RESULT relocate_section(int sectype , uint32_t size, int writehdr) +{ + TPM_RESULT status = TPM_SUCCESS; + int diff = 0; + uint32_t st, end; + uint32_t mvst = 0; + uint32_t mvsz = 0; + + /* Store the current state of all the offsets and sizes */ + struct VtpmHeader backuphdr; + memcpy(&backuphdr, &storage.hdr, sizeof(backuphdr)); + + switch(sectype) { + case SEC_MGRDATA: + st = storage.hdr.off_mgrdata = (HEADERSZ / SECTIONBDD + 1) * SECTIONBDD; + storage.hdr.sz_mgrdata = size; + end = st + storage.hdr.sz_mgrdata; + + /* Find out if our new section will overlap */ + if(storage.hdr.sz_uuids != 0 && end >= storage.hdr.off_uuids) { + diff = end - storage.hdr.off_uuids + 1; + mvst = storage.hdr.off_uuids; + } + if(storage.hdr.sz_keys != 0 && end >= storage.hdr.off_keys) { + diff = MAX(diff, end - storage.hdr.off_keys + 1); + mvst = mvst != 0 ? MIN(mvst, storage.hdr.off_keys) : storage.hdr.off_keys; + } + + if(diff != 0) { + /* Move the rest of the data to make room */ + mvsz = MAX(storage.hdr.off_uuids + storage.hdr.sz_uuids, storage.hdr.off_keys + storage.hdr.sz_keys) - mvst; + + TPMTRYRETURN(block_move(mvst, mvsz, diff)); + if(storage.hdr.sz_uuids != 0) { + storage.hdr.off_uuids += diff; + } + if(storage.hdr.sz_keys != 0) { + storage.hdr.off_keys += diff; + } + } + break; + case SEC_UUIDDATA: + /* Make sure the manager data is in the right place */ + relocate_section(SEC_MGRDATA, storage.hdr.sz_mgrdata, 0); + + /* Put the Uuid Data after the Manager data */ + st = storage.hdr.off_uuids = ((storage.hdr.off_mgrdata + storage.hdr.sz_mgrdata) / SECTIONBDD + 1) * SECTIONBDD; + storage.hdr.sz_uuids = size; + end = st + storage.hdr.sz_uuids; + + /* Find out if our new section will overlap the key data */ + if(end >= storage.hdr.off_keys) { + diff = end - storage.hdr.off_keys + 1; + + mvst = storage.hdr.off_keys; + mvsz = storage.hdr.sz_keys; + + TPMTRYRETURN(block_move(mvst, mvsz, diff)); + storage.hdr.off_keys += diff; + } + break; + case SEC_KEYDATA: + /* Make sure the uuid data (and manager data) are in the right place */ + relocate_section(SEC_UUIDDATA, storage.hdr.sz_uuids, 0); + + /* Put the Key Data after the Uuid data */ + st = storage.hdr.off_keys = ((storage.hdr.off_uuids + storage.hdr.sz_uuids) / SECTIONBDD + 1) * SECTIONBDD; + storage.hdr.sz_keys = size; + end = st + storage.hdr.sz_keys; + + break; + } + + /* Update the header on disk if anything changed */ + if(writehdr && memcmp(&storage.hdr, &backuphdr, sizeof(backuphdr))) { + HeaderSave(); + } + + goto egress; +abort_egress: +egress: + return status; +} + +/* MANAGER DATA FUNCTIONS */ + +TPM_RESULT MgrDataLoad(void) +{ + TPM_RESULT status=TPM_SUCCESS; + long step_size; + int rc; + buffer_t unsealed_data = NULL_BUF; + buffer_t enc_table_abuf; + struct pack_buf_t storage_key_pack = NULL_PACK_BUF, boot_key_pack = NULL_PACK_BUF; + UINT32 enc_size; + BYTE* flat_table = NULL; + BYTE vtpm_manager_gen; + + TPM_HANDLE boot_key_handle; + TPM_AUTHDATA boot_usage_auth; + memset(&boot_usage_auth, 0, sizeof(TPM_AUTHDATA)); + + /* Check offsets */ + if(storage.hdr.off_mgrdata == 0 || storage.hdr.sz_mgrdata == 0) { + vtpmlogerror(VTPM_LOG_VTPM, "Invalid Manager Data offset and/or size\n"); + status = TPM_FAIL; + goto abort_egress; + } + + flat_table = malloc(storage.hdr.sz_mgrdata); + + /* Read Data from Disk */ + lseek(blkfront_fd, storage.hdr.off_mgrdata, SEEK_SET); + if((rc = read(blkfront_fd, flat_table, storage.hdr.sz_mgrdata)) != storage.hdr.sz_mgrdata) { + vtpmlogerror(VTPM_LOG_VTPM, "Failed to read vtpm manager data section : return=%d, error=`%s'\n", rc, strerror(errno)); + status = TPM_IOERROR; + goto abort_egress; + } + + // Read Boot Key + step_size = BSG_UnpackList( flat_table, 2, + BSG_TPM_SIZE32_DATA, &boot_key_pack, + BSG_TYPE_UINT32, &enc_size); + + TPMTRYRETURN(buffer_init_alias_convert(&enc_table_abuf, enc_size, flat_table + step_size) ); + TPMTRYRETURN(buffer_init(&vtpm_globals->bootKeyWrap, boot_key_pack.size, boot_key_pack.data) ); + + + //Load Boot Key + TPMTRYRETURN( VTSP_LoadKey( vtpm_globals->manager_tcs_handle, + TPM_SRK_KEYHANDLE, + &vtpm_globals->bootKeyWrap, + (const TPM_AUTHDATA*)&opts.srkauth, + &boot_key_handle, + &vtpm_globals->keyAuth, + &vtpm_globals->bootKey, + FALSE) ); + + TPMTRYRETURN( envelope_decrypt(&enc_table_abuf, + vtpm_globals->manager_tcs_handle, + boot_key_handle, + (const TPM_AUTHDATA*) &boot_usage_auth, + &unsealed_data) ); + step_size += enc_size; + + if (*unsealed_data.bytes != VTPM_MANAGER_GEN) { + // Once there is more than one gen, this will include some compatability stuff + vtpmlogerror(VTPM_LOG_VTPM, "Warning: Manager Data file is gen %d, while this manager is gen %d.\n", vtpm_manager_gen, VTPM_MANAGER_GEN); + } + + // Global Values needing to be saved + BSG_UnpackList( unsealed_data.bytes, 4, + BSG_TYPE_BYTE, &vtpm_manager_gen, + BSG_TPM_AUTHDATA, &vtpm_globals->owner_usage_auth, + BSG_TPM_SECRET, &vtpm_globals->storage_key_usage_auth, + BSG_TPM_SIZE32_DATA, &storage_key_pack); + + TPMTRYRETURN(buffer_init(&vtpm_globals->storageKeyWrap, storage_key_pack.size, storage_key_pack.data) ); + + goto egress; + +abort_egress: + vtpmlogerror(VTPM_LOG_VTPM, "Failed to load service data with error = %s\n", tpm_get_error_name(status)); +egress: + BSG_Destroy(BSG_TPM_SIZE32_DATA, &boot_key_pack); + BSG_Destroy(BSG_TPM_SIZE32_DATA, &storage_key_pack); + + buffer_free(&unsealed_data); + free(flat_table); + + // TODO: Could be nice and evict BootKey. (Need to add EvictKey to VTSP. + + return status; + +} + +TPM_RESULT MgrDataSave(void) +{ + TPM_RESULT status=TPM_SUCCESS; + + int datasz; + + BYTE *flat_boot_key=NULL; + BYTE flat_enc_len[sizeof(UINT32)]; + buffer_t clear_flat_global=NULL_BUF, enc_flat_global=NULL_BUF; + UINT32 storageKeySize = buffer_len(&vtpm_globals->storageKeyWrap); + UINT32 bootKeySize = buffer_len(&vtpm_globals->bootKeyWrap); + struct pack_buf_t storage_key_pack = {storageKeySize, vtpm_globals->storageKeyWrap.bytes}; + struct pack_buf_t boot_key_pack = {bootKeySize, vtpm_globals->bootKeyWrap.bytes}; + BYTE vtpm_manager_gen = VTPM_MANAGER_GEN; + + UINT32 boot_key_size = 0; + + // Initially fill these with buffer sizes for each data type. Later fill + // in actual size, once flattened. + boot_key_size = sizeof(UINT32) + // bootkeysize + bootKeySize; // boot key + + TPMTRYRETURN(buffer_init(&clear_flat_global,sizeof(BYTE) + // manager version + 3*sizeof(TPM_DIGEST) + // Auths + sizeof(UINT32) +// storagekeysize + storageKeySize, NULL) ); // storage key + + + flat_boot_key = (BYTE *) malloc( boot_key_size ); + + boot_key_size = BSG_PackList(flat_boot_key, 1, + BSG_TPM_SIZE32_DATA, &boot_key_pack); + + BSG_PackList(clear_flat_global.bytes, 4, + BSG_TYPE_BYTE, &vtpm_manager_gen, + BSG_TPM_AUTHDATA, &vtpm_globals->owner_usage_auth, + BSG_TPM_SECRET, &vtpm_globals->storage_key_usage_auth, + BSG_TPM_SIZE32_DATA, &storage_key_pack); + + TPMTRYRETURN(envelope_encrypt(&clear_flat_global, + &vtpm_globals->bootKey, + &enc_flat_global) ); + + BSG_PackConst(buffer_len(&enc_flat_global), 4, flat_enc_len); + + /* Prepare the disk image for the new manager data */ + datasz = boot_key_size + sizeof(UINT32) + buffer_len(&enc_flat_global); + relocate_section(SEC_MGRDATA, datasz, 1); + + /* Write the manager data */ + lseek(blkfront_fd, storage.hdr.off_mgrdata, SEEK_SET); + if ( ( write(blkfront_fd, flat_boot_key, boot_key_size) != boot_key_size ) || + ( write(blkfront_fd, flat_enc_len, sizeof(UINT32)) != sizeof(UINT32) ) || + ( write(blkfront_fd, enc_flat_global.bytes, buffer_len(&enc_flat_global)) != buffer_len(&enc_flat_global) )) { + vtpmlogerror(VTPM_LOG_VTPM, "Failed to completely write service data.\n"); + status = TPM_IOERROR; + goto abort_egress; + } + + goto egress; + +abort_egress: +egress: + + free(flat_boot_key); + buffer_free(&clear_flat_global); + buffer_free(&enc_flat_global); + + vtpmloginfo(VTPM_LOG_VTPM, "Saved VTPM Manager state (status = %d)\n", (int) status); + return status; +} + +/* UUID DATA FUNCTIONS */ + +int intcmp(const void* a, const void* b) { + printf("KEY INT CMP %d - %d = %d\n", *(int*)a, *(int*)b, *(int*)a - *(int*)b); + return *(int*)a - *(int*)b; +} +static uint32_t UuidGetFreeIndex(void) +{ + int i; + uint32_t index = 0; + + //FIXME: Why doesn't qsort work? Instead just always find a larget number + for(i = 0; i < storage.uuiddata.num_uuids; ++i) { + if(index <= storage.uuiddata.uuids[i].index) { + index = storage.uuiddata.uuids[i].index +1; + } + } +#if 0 + int* list; + /* Create a sorted list of all the used indices */ + list = malloc(sizeof(int) * storage.uuiddata.num_uuids); + for(i = 0; i < storage.uuiddata.num_uuids; ++i) { + list[i] = storage.uuiddata.uuids[i].index; +printf("LIST KEY %d / %" PRIu32 "\n", list[i], storage.uuiddata.num_uuids); + } + + qsort(list, storage.uuiddata.num_uuids, sizeof(int), intcmp); + for(i = 0; i < storage.uuiddata.num_uuids; ++i) { + list[i] = storage.uuiddata.uuids[i].index; +printf("SORTED LIST KEY %d / %" PRIu32 "\n", list[i], storage.uuiddata.num_uuids); + } + + /* Find the lowest free index available */ + for(i = 0; i < storage.uuiddata.num_uuids; ++i) { + if(index < list[i]) { + break; + } + index = list[i] + 1; + } + free(list); +#endif + + return index; +} + +static int __get_index(char* uuid, int st, int sz) { + int i = st + (sz / 2); + int cmp; + + if(sz <= 0) { + return -1; + } + + cmp = strcmp(uuid, storage.uuiddata.uuids[i].uuid); + + if(cmp == 0) { + return storage.uuiddata.uuids[i].index; + } else if (cmp < 0) { + return __get_index(uuid, st, sz/2); + } else { + return __get_index(uuid, i + 1, sz/2 - ((sz + 1) % 2)); + } + +} + +static int UuidGetIndex(char* uuid) { + return __get_index(uuid, 0, storage.uuiddata.num_uuids); +} + +static int UuidAdd(char* uuid, int len, int newindex) { + + int i, j; + + /* Get a new index */ + if(newindex < 0) { + newindex = UuidGetFreeIndex(); + } + + /* Allocate memory on first add */ + if(storage.uuiddata.num_alloc == 0) { + storage.uuiddata.num_alloc = DEFALLOC; + storage.uuiddata.uuids = malloc(sizeof(struct UuidPair) * storage.uuiddata.num_alloc); + for(i = 0; i < storage.uuiddata.num_alloc; ++i) { + storage.uuiddata.uuids[i].uuid = NULL; + storage.uuiddata.uuids[i].index = 0; + } + } + /* Resize the array if we need to */ + if(storage.uuiddata.num_uuids >= storage.uuiddata.num_alloc) { + storage.uuiddata.num_alloc *= 2; + storage.uuiddata.uuids = realloc(storage.uuiddata.uuids, sizeof(struct UuidPair) * storage.uuiddata.num_alloc); + for(i = storage.uuiddata.num_alloc / 2; i < storage.uuiddata.num_alloc; ++i) { + storage.uuiddata.uuids[i].uuid = NULL; + storage.uuiddata.uuids[i].index = 0; + } + } + /* calculate the length of the string if it hasn't been given */ + if(len < 0) { + len = strlen(uuid); + } + /* Find the location to put the new string */ + for(i = 0; i < storage.uuiddata.num_uuids; ++i) { + if(strcmp(uuid, storage.uuiddata.uuids[i].uuid) < 0) { + break; + } + } + /* Shift everything after the new uuid by 1*/ + for(j = storage.uuiddata.num_uuids; j > i; --j) { + storage.uuiddata.uuids[j] = storage.uuiddata.uuids[j-1]; + } + + /* Allocate and copy the uuid string */ + storage.uuiddata.uuids[i].uuid = malloc(sizeof(char) * (len +1)); + strcpy(storage.uuiddata.uuids[i].uuid, uuid); + + /* Set the index */ + storage.uuiddata.uuids[i].index = newindex; + + ++storage.uuiddata.num_uuids; + + return storage.uuiddata.uuids[i].index; +} + +static void UuidClear(void) +{ + int i; + if(storage.uuiddata.uuids != NULL) { + for(i = 0; i < storage.uuiddata.num_uuids; ++i) { + free(storage.uuiddata.uuids[i].uuid); + } + free(storage.uuiddata.uuids); + } + storage.uuiddata.num_uuids = storage.uuiddata.num_alloc = 0; +} + + +TPM_RESULT UuidDataLoad(void) +{ + TPM_RESULT status = TPM_SUCCESS; + buffer_t uuiddata = NULL_BUF; + buffer_t sealed = NULL_BUF; + int rc; + uint8_t* ptr; + int len; + uint32_t index; + + /* If there is no uuid section, silently set everything to zero and exit */ + if(storage.hdr.sz_uuids == 0) { + storage.uuiddata.num_uuids = storage.uuiddata.num_alloc = 0; + goto egress; + } + + buffer_init(&sealed, storage.hdr.sz_uuids, NULL); + + /* Read uuid data from disk */ + lseek(blkfront_fd, storage.hdr.off_uuids, SEEK_SET); + if((rc = read(blkfront_fd, sealed.bytes, storage.hdr.sz_uuids)) != storage.hdr.sz_uuids) { + vtpmlogerror(VTPM_LOG_VTPM, "Failed to read uuid data section : return %d, error=`%s'\n", rc, strerror(errno)); + status = TPM_IOERROR; + goto abort_egress; + } + + /* Decrypt uuid data */ + if(opts.seal) { + TPMTRYRETURN( envelope_decrypt(&sealed, + vtpm_globals->manager_tcs_handle, + vtpm_globals->storageKeyHandle, + (const TPM_AUTHDATA*)&vtpm_globals->storage_key_usage_auth, + &uuiddata) ); + } else { + buffer_init_alias(&uuiddata, &sealed, 0, 0); + } + + /* Wipe out any current uuid data */ + UuidClear(); + + /* Prevent possible buffer overruns later */ + uuiddata.bytes[buffer_len(&uuiddata) - 1] = '\0'; + + /*Load uuids into the memory array*/ + ptr = uuiddata.bytes; + len = strlen((char*)ptr); + while(len != 0) { + /* Sanity check - before we read a 4 byte int make sure there is room left for at least the final null terminator*/ + if(ptr + len + 1 + sizeof(uint32_t) >= uuiddata.bytes + buffer_len(&uuiddata)) { + vtpmlogerror(VTPM_LOG_VTPM, "Corrupted uuid data section!\n"); + status = TPM_FAIL; + goto abort_egress; + } + + /* Get the index value */ + BSG_UnpackList(ptr + len + 1, 1, + BSG_TYPE_UINT32, &index); + + /* Add the new Uuid to the list */ + UuidAdd((char*)ptr, len, index); + + /* Jump to the next string */ + ptr += len + 1 + sizeof(uint32_t); + len = strlen((char*)ptr); + } + + + goto egress; +abort_egress: + UuidClear(); +egress: + buffer_free(&uuiddata); + buffer_free(&sealed); + return status; +} + +TPM_RESULT UuidDataSave(void) +{ + TPM_RESULT status = TPM_SUCCESS; + buffer_t uuiddata = NULL_BUF; + buffer_t sealed = NULL_BUF; + int rc; + int bufsz; + int* lenuuids = NULL; + uint8_t* ptr; + int i; + + /* If there are no UUIDs then we are just a NOP */ + if(storage.uuiddata.num_uuids == 0) { + goto egress; + } + + lenuuids = malloc(sizeof(int) * storage.uuiddata.num_uuids); + + /* Get the lengths of the uuids and the entire buffer */ + bufsz = 0; + for(i = 0; i < storage.uuiddata.num_uuids; ++i) { + lenuuids[i] = strlen(storage.uuiddata.uuids[i].uuid); + bufsz += lenuuids[i] + 1 + sizeof(uint32_t); + } + ++bufsz; /* Final null terminator */ + + /*Create and write the buffer */ + buffer_init(&uuiddata, bufsz, NULL); + ptr = uuiddata.bytes; + for(i = 0; i < storage.uuiddata.num_uuids; ++i) { + /* Copy uuid string with its null terminator*/ + memcpy(ptr, storage.uuiddata.uuids[i].uuid, lenuuids[i] + 1); + ptr += lenuuids[i] + 1; + + /* Copy 4 byte index */ + BSG_PackList(ptr, 1, BSG_TYPE_UINT32, &storage.uuiddata.uuids[i].index); + ptr += sizeof(uint32_t); + } + /* Last entry has a second null terminator */ + *ptr = '\0'; + + /* Encrypt the data */ + if(opts.seal) { + TPMTRYRETURN( envelope_encrypt(&uuiddata, + &vtpm_globals->storageKey, + &sealed) ); + } else { + buffer_init_alias(&sealed, &uuiddata, 0, 0); + } + + /* Prepare the disk for our new uuid data */ + TPMTRYRETURN(relocate_section(SEC_UUIDDATA, buffer_len(&sealed), 1)); + + /* Write uuid data to disk */ + lseek(blkfront_fd, storage.hdr.off_uuids, SEEK_SET); + if((rc = write(blkfront_fd, sealed.bytes, storage.hdr.sz_uuids)) != storage.hdr.sz_uuids) { + vtpmlogerror(VTPM_LOG_VTPM, "Failed to write uuid data section : return %d, error=`%s'\n", rc, strerror(errno)); + status = TPM_IOERROR; + goto abort_egress; + } + + + goto egress; +abort_egress: +egress: + buffer_free(&uuiddata); + buffer_free(&sealed); + free(lenuuids); + return status; +} + +/* KEY DATA SECTION FUNCTIONS */ + +#define GetKeyOffset(index) (storage.hdr.off_keys + KEYHDRSZ + (storage.keydata.sz_key * index)) + +TPM_RESULT KeyDataHeaderLoad(void) +{ + TPM_RESULT status = TPM_SUCCESS; + buffer_t keydata = NULL_BUF; + int rc; + + /* If there are no keys then we set everything to zero and exit silently */ + if(storage.hdr.sz_keys == 0) { + storage.keydata.sz_key = storage.keydata.num_keys = 0; + goto egress; + } + + buffer_init(&keydata, KEYHDRSZ, NULL); + + /* Read the key header from the disk */ + lseek(blkfront_fd, storage.hdr.off_keys, SEEK_SET); + if((rc = read(blkfront_fd, keydata.bytes, KEYHDRSZ)) != KEYHDRSZ) { + vtpmlogerror(VTPM_LOG_VTPM, "Failed to read vtpm key header : return=%d error=`%s'\n", rc, strerror(errno)); + status = TPM_IOERROR; + goto abort_egress; + } + + /* Unpack the header values */ + BSG_UnpackList(keydata.bytes, 2, + BSG_TYPE_UINT32, &storage.keydata.sz_key, + BSG_TYPE_UINT32, &storage.keydata.num_keys); + + + /* Verify the sanity of header values */ + if(storage.keydata.sz_key * storage.keydata.num_keys > storage.hdr.sz_keys + || storage.keydata.sz_key < HASHKEYSZ) { + vtpmlogerror(VTPM_LOG_VTPM, "Corrupted key data section!\n"); + status = TPM_FAIL; + goto abort_egress; + } + + goto egress; +abort_egress: + storage.keydata.num_keys = storage.keydata.sz_key = 0; +egress: + buffer_free(&keydata); + + return status; +} + +TPM_RESULT KeyDataHeaderSave(void) +{ + TPM_RESULT status = TPM_SUCCESS; + buffer_t keydata = NULL_BUF; + int rc; + + /* if there was no key section before make one */ + if(storage.hdr.sz_keys == 0) { + relocate_section(SEC_KEYDATA, KEYHDRSZ, 1); + } + + buffer_init(&keydata, KEYHDRSZ, NULL); + + /* Unpack the header values */ + BSG_PackList(keydata.bytes, 2, + BSG_TYPE_UINT32, &storage.keydata.sz_key, + BSG_TYPE_UINT32, &storage.keydata.num_keys); + + /* Write the key header to the disk */ + lseek(blkfront_fd, storage.hdr.off_keys, SEEK_SET); + if((rc = write(blkfront_fd, keydata.bytes, KEYHDRSZ)) != KEYHDRSZ) { + vtpmlogerror(VTPM_LOG_VTPM, "Failed to write vtpm key data header : return=%d error=`%s'\n", rc, strerror(errno)); + status = TPM_IOERROR; + goto abort_egress; + } + + goto egress; +abort_egress: +egress: + buffer_free(&keydata); + + return status; +} + +/* OTHER HELPERS */ + +static void reset_storage(void) { + UuidClear(); + memset(&storage, 0, sizeof(storage)); + storage.hdr.version = DISKVERS; +} + + + +/************************************** + * PUBLIC FUNCTIONS + * ***********************************/ + +int vtpm_storage_init(void) { + struct blkfront_info info; + if((blkdev = init_blkfront(NULL, &info)) == NULL) { + return -1; + } + if((blkfront_fd = blkfront_open(blkdev)) < 0) { + return -1; + } + return 0; +} + +void vtpm_storage_shutdown(void) { + close(blkfront_fd); +} + +TPM_RESULT vtpm_storage_LoadHashKey(char* uuid, buffer_t* outbuf) +{ + TPM_RESULT status = TPM_SUCCESS; + buffer_t sealed_key = NULL_BUF; + int rc; + int key_num; + + + /* Sanity check the key header */ + if(storage.keydata.sz_key == 0 || storage.keydata.num_keys == 0) { + vtpmlogerror(VTPM_LOG_VTPM, "Loadkey failure: Invalid header!\n"); + status = TPM_FAIL; + goto abort_egress; + } + + /* Determine which key index we are using */ + if((key_num = UuidGetIndex(uuid)) < 0) { + vtpmlogerror(VTPM_LOG_VTPM, "LoadKey failure: Unrecognized uuid!\n"); + status = TPM_FAIL; + goto abort_egress; + } + printk("KEY NUM = %d\n", key_num); + + /* Sanity check the key index */ + if(key_num >= storage.keydata.num_keys) { + vtpmlogerror(VTPM_LOG_VTPM, "LoadKey failure: Invalid index (%d) into key table size of %" PRIu32 "\n", key_num, storage.keydata.num_keys); + status = TPM_FAIL; + goto abort_egress; + } + + buffer_init(&sealed_key, storage.keydata.sz_key, NULL); + + /* Read key data from disk */ + lseek(blkfront_fd, GetKeyOffset(key_num), SEEK_SET); + if((rc = read(blkfront_fd, sealed_key.bytes, storage.keydata.sz_key)) != storage.keydata.sz_key) { + vtpmlogerror(VTPM_LOG_VTPM, "Failed to read key data : key number %d, return %d, error=`%s'\n", key_num, rc, strerror(errno)); + status = TPM_IOERROR; + goto abort_egress; + } + + /*Decrypt key data */ + if(opts.seal) { + TPMTRYRETURN( symkey_decrypt(&sealed_key, + vtpm_globals->manager_tcs_handle, + vtpm_globals->storageKeyHandle, + (const TPM_AUTHDATA*)&vtpm_globals->storage_key_usage_auth, + outbuf) ); + } else { + buffer_init_alias(outbuf, &sealed_key, 0, 0); + outbuf->is_owner = TRUE; + sealed_key.is_owner = FALSE; + } + + /* Chop off any padding bits from encryption*/ + TPMTRYRETURN(buffer_truncate(outbuf, HASHKEYSZ)); + + goto egress; +abort_egress: + vtpmlogerror(VTPM_LOG_VTPM, "Failed to load key\n"); +egress: + buffer_free(&sealed_key); + return status; + +} +TPM_RESULT vtpm_storage_SaveHashKey(char* uuid, buffer_t* inbuf) +{ + TPM_RESULT status = TPM_SUCCESS; + buffer_t sealed_key = NULL_BUF; + int key_num; + int rc; + + /* Sanity check the input */ + if(buffer_len(inbuf) != HASHKEYSZ) { + vtpmlogerror(VTPM_LOG_VTPM, "SaveKey failure : invalid input buffer size %lu\n", (unsigned long) buffer_len(inbuf)); + status = TPM_FAIL; + goto abort_egress; + } + + /* Encrypt the key */ + if(opts.seal) { + TPMTRYRETURN( symkey_encrypt(inbuf, + &vtpm_globals->storageKey, + &sealed_key) ); + } else { + buffer_init_alias(&sealed_key, inbuf, 0, 0); + } + + /* Get the uuid index, or create one if this is new */ + if((key_num = UuidGetIndex(uuid)) < 0) { + /* Create new uuid->key position mapping and save the updated data */ + key_num = UuidAdd(uuid, -1, -1); + TPMTRYRETURN(UuidDataSave()); + } + + /* Create the key data section if it does not already exist */ + if(storage.hdr.sz_keys == 0) { + storage.keydata.sz_key = buffer_len(&sealed_key); + storage.keydata.num_keys = 0; + /* No need to save the key header yet, it'll get triggered on the next if statement */ + } + /* If it does exist, sanity check the encrypted data size */ + else { + if(buffer_len(&sealed_key) != storage.keydata.sz_key) { + /* this should never happen, unless the user doing something dumb like disabling encryption on encrypted data */ + vtpmlogerror(VTPM_LOG_VTPM, "SaveKey failure : Invalid encrypted data size??\n"); + status = TPM_FAIL; + goto abort_egress; + } + } + + /* Grow the key data section if needed */ + if(key_num >= storage.keydata.num_keys) { + storage.keydata.num_keys = key_num +1; + KeyDataHeaderSave(); + } + + /* Prepare the disk for the key section */ + relocate_section(SEC_KEYDATA, KEYHDRSZ + (storage.keydata.sz_key * storage.keydata.num_keys), 1); + + /* Write the key data to disk */ + lseek(blkfront_fd, GetKeyOffset(key_num), SEEK_SET); + if((rc = write(blkfront_fd, sealed_key.bytes, storage.keydata.sz_key)) != storage.keydata.sz_key) { + vtpmlogerror(VTPM_LOG_VTPM, "Failed to write key data : key number %d, return %d, error=`%s'\n", key_num, rc, strerror(errno)); + status = TPM_IOERROR; + goto abort_egress; + } + + goto egress; +abort_egress: + vtpmlogerror(VTPM_LOG_VTPM, "Failed to save key\n"); +egress: + buffer_free(&sealed_key); + return status; +} + +TPM_RESULT vtpm_storage_LoadManagerData(void) +{ + TPM_RESULT status = TPM_SUCCESS; + + reset_storage(); + + TPMTRYRETURN(HeaderLoad()); + TPMTRYRETURN(MgrDataLoad()); + + goto egress; +abort_egress: + vtpmlogerror(VTPM_LOG_VTPM, "vTPM LoadManagerData failed\n") + reset_storage(); +egress: + return status; +} + +TPM_RESULT vtpm_storage_LoadKeyMeta(void) +{ + TPM_RESULT status = TPM_SUCCESS; + + TPMTRYRETURN(UuidDataLoad()); + TPMTRYRETURN(KeyDataHeaderLoad()); + + goto egress; +abort_egress: + vtpmlogerror(VTPM_LOG_VTPM, "vTPM LoadKeyMeta failed\n"); +egress: + return status; +} + +TPM_RESULT vtpm_storage_SaveManagerData(void) +{ + TPM_RESULT status = TPM_SUCCESS; + + TPMTRYRETURN(HeaderSave()); + TPMTRYRETURN(MgrDataSave()); + /* Uuid and Key data get saved automatically during use */ + + goto egress; +abort_egress: + vtpmlogerror(VTPM_LOG_VTPM, "vTPM SaveManagerData failed\n") +egress: + return status; + +} + diff -Naur xen-unstable-trp-sdp-pristine/stubdom/vtpmmgr/vtpm_storage.h xen-unstable-trp-sdp/stubdom/vtpmmgr/vtpm_storage.h --- xen-unstable-trp-sdp-pristine/stubdom/vtpmmgr/vtpm_storage.h 1969-12-31 19:00:00.000000000 -0500 +++ xen-unstable-trp-sdp/stubdom/vtpmmgr/vtpm_storage.h 2011-02-23 19:40:48.000000000 -0500 @@ -0,0 +1,69 @@ +/* LICENSE AND DISCLAIMER + * + * Copyright © 2011 The Johns Hopkins University/Applied Physics + * Laboratory + + * This software was developed at The Johns Hopkins University/Applied + * Physics Laboratory (“JHU/APL”) that is the author thereof under the + * “work made for hire” provisions of the copyright law. Permission is + * hereby granted, free of charge, to any person obtaining a copy of this + * software and associated documentation (the “Software”), to use the + * Software without restriction, including without limitation the rights to + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit others to do so, subject to the following + * conditions: + + * 1. This LICENSE AND DISCLAIMER, including the copyright notice, shall + * be included in all copies of the Software, including copies of + * substantial portions of the Software; + + * 2. JHU/APL assumes no obligation to provide support of any kind with + * regard to the Software. This includes no obligation to provide assistance + * in using the Software nor to provide updated versions of the Software; and + + * 3. THE 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. USERS ARE ADVISED TO + * TEST THE SOFTWARE THOROUGHLY BEFORE RELYING ON IT. IN NO EVENT SHALL THE + * JOHNS HOPKINS UNIVERSITY BE LIABLE FOR ANY DAMAGES WHATSOEVER, INCLUDING, + * WITHOUT LIMITATION, ANY LOST PROFITS, LOST SAVINGS OR OTHER INCIDENTAL OR + * CONSEQUENTIAL DAMAGES, ARISING OUT OF THE USE OR INABILITY TO USE THE + * SOFTWARE. + */ +#ifndef VTPM_STORAGE_H +#define VTPM_STORAGE_h + +#include + +#define VTPM_NVMKEY_SIZE 32 +#define HASHKEYSZ (sizeof(TPM_DIGEST) + VTPM_NVMKEY_SIZE) + +/* Initialize the storage system and its virtual disk */ +int vtpm_storage_init(void); + +/* Shutdown the storage system and its virtual disk */ +void vtpm_storage_shutdown(void); + +/* Loads Sha1 hash and 256 bit AES key from disk and stores them + * packed together in outbuf. outbuf must be freed + * by the caller using buffer_free() + */ +TPM_RESULT vtpm_storage_LoadHashKey(char* uuid, buffer_t* outbuf); + +/* inbuf must contain a sha1 hash followed by a 256 bit AES key. + * Encrypts and stores the hash and key to disk */ +TPM_RESULT vtpm_storage_SaveHashKey(char* uuid, buffer_t* inbuf); + +/* Load the vtpm manager data - call this on startup */ +TPM_RESULT vtpm_storage_LoadManagerData(void); + +/* Load the uuid and key header data - call after loading the storage key */ +TPM_RESULT vtpm_storage_LoadKeyMeta(void); + +/* Saves the vtpm manager data - call this on shutdown */ +TPM_RESULT vtpm_storage_SaveManagerData(void); + + +#endif