mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 10:11:27 +01:00
Argument parsing only matches to before ':' and then the string with leading ':' is passed to parse_auth_string which fails to parse. Extend the length to include the seperator in the match. While here, switch the seperator to "=". The man page documented "=" and the other tpm.* arguments already use "=". Since it didn't work before, we don't need to worry about backwards compatibility. Signed-off-by: Jason Andryuk <jandryuk@gmail.com> Reviewed-by: Samuel Thibault <samuel.thibault@ens-lyon.org> Reviewed-by: Daniel P. Smith <dpsmith@apertussolutions.com>
808 lines
25 KiB
C
808 lines
25 KiB
C
/*
|
|
* Copyright (c) 2010-2012 United States Government, as represented by
|
|
* the Secretary of Defense. All rights reserved.
|
|
*
|
|
* based off of the original tools/vtpm_manager code base which is:
|
|
* Copyright (c) 2005, Intel Corp.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
*
|
|
* * Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* * Redistributions in binary form must reproduce the above
|
|
* copyright notice, this list of conditions and the following
|
|
* disclaimer in the documentation and/or other materials provided
|
|
* with the distribution.
|
|
* * Neither the name of Intel Corporation nor the names of its
|
|
* contributors may be used to endorse or promote products derived
|
|
* from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
|
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
|
|
#include <xen/xen.h>
|
|
#include <mini-os/tpmback.h>
|
|
#include <mini-os/tpmfront.h>
|
|
#include <mini-os/tpm_tis.h>
|
|
#include <unistd.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <polarssl/sha1.h>
|
|
|
|
#include "log.h"
|
|
#include "vtpmmgr.h"
|
|
#include "vtpm_disk.h"
|
|
#include "tpm.h"
|
|
#include "marshal.h"
|
|
#include "tpm2_marshal.h"
|
|
#include "tpm2.h"
|
|
|
|
struct Opts {
|
|
enum {
|
|
TPMDRV_TPM_TIS,
|
|
TPMDRV_TPMFRONT,
|
|
} tpmdriver;
|
|
unsigned long tpmiomem;
|
|
unsigned int tpmirq;
|
|
unsigned int tpmlocality;
|
|
int gen_owner_auth;
|
|
};
|
|
|
|
// --------------------------- Well Known Auths --------------------------
|
|
const TPM_AUTHDATA WELLKNOWN_AUTH = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
|
|
|
struct vtpm_globals vtpm_globals = {
|
|
.tpm_fd = -1,
|
|
.oiap = { .AuthHandle = 0 },
|
|
.hw_locality = 0
|
|
};
|
|
|
|
static int tpm_entropy_source(void* dummy, unsigned char* data, size_t len, size_t* olen) {
|
|
UINT32 sz = len;
|
|
TPM_RESULT rc = TPM_GetRandom(&sz, data);
|
|
*olen = sz;
|
|
return rc == TPM_SUCCESS ? 0 : POLARSSL_ERR_ENTROPY_SOURCE_FAILED;
|
|
}
|
|
|
|
static TPM_RESULT check_tpm_version(void) {
|
|
TPM_RESULT status;
|
|
UINT32 rsize;
|
|
BYTE* res = NULL;
|
|
TPM_CAP_VERSION_INFO vinfo;
|
|
|
|
TPMTRYRETURN(TPM_GetCapability(
|
|
TPM_CAP_VERSION_VAL,
|
|
0,
|
|
NULL,
|
|
&rsize,
|
|
&res));
|
|
if(rsize < 4) {
|
|
vtpmlogerror(VTPM_LOG_VTPM, "Invalid size returned by GetCapability!\n");
|
|
status = TPM_BAD_PARAMETER;
|
|
goto abort_egress;
|
|
}
|
|
|
|
unpack_TPM_CAP_VERSION_INFO(res, &vinfo, UNPACK_ALIAS);
|
|
|
|
vtpmloginfo(VTPM_LOG_VTPM, "Hardware TPM:\n");
|
|
vtpmloginfo(VTPM_LOG_VTPM, " version: %hhd %hhd %hhd %hhd\n",
|
|
vinfo.version.major, vinfo.version.minor, vinfo.version.revMajor, vinfo.version.revMinor);
|
|
vtpmloginfo(VTPM_LOG_VTPM, " specLevel: %hd\n", vinfo.specLevel);
|
|
vtpmloginfo(VTPM_LOG_VTPM, " errataRev: %hhd\n", vinfo.errataRev);
|
|
vtpmloginfo(VTPM_LOG_VTPM, " vendorID: %c%c%c%c\n",
|
|
vinfo.tpmVendorID[0], vinfo.tpmVendorID[1],
|
|
vinfo.tpmVendorID[2], vinfo.tpmVendorID[3]);
|
|
vtpmloginfo(VTPM_LOG_VTPM, " vendorSpecificSize: %hd\n", vinfo.vendorSpecificSize);
|
|
vtpmloginfo(VTPM_LOG_VTPM, " vendorSpecific: ");
|
|
for(int i = 0; i < vinfo.vendorSpecificSize; ++i) {
|
|
vtpmloginfomore(VTPM_LOG_VTPM, "%02hhx", vinfo.vendorSpecific[i]);
|
|
}
|
|
vtpmloginfomore(VTPM_LOG_VTPM, "\n");
|
|
|
|
abort_egress:
|
|
free(res);
|
|
return status;
|
|
}
|
|
|
|
static TPM_RESULT flush_tpm(void) {
|
|
TPM_RESULT status = TPM_SUCCESS;
|
|
const TPM_RESOURCE_TYPE reslist[] = { TPM_RT_KEY, TPM_RT_AUTH, TPM_RT_TRANS, TPM_RT_COUNTER, TPM_RT_DAA_TPM, TPM_RT_CONTEXT };
|
|
BYTE* keylist = NULL;
|
|
UINT32 keylistSize;
|
|
BYTE* ptr;
|
|
|
|
//Iterate through each resource type and flush all handles
|
|
for(int i = 0; i < sizeof(reslist) / sizeof(TPM_RESOURCE_TYPE); ++i) {
|
|
TPM_RESOURCE_TYPE beres = cpu_to_be32(reslist[i]);
|
|
UINT16 size;
|
|
TPMTRYRETURN(TPM_GetCapability(
|
|
TPM_CAP_HANDLE,
|
|
sizeof(TPM_RESOURCE_TYPE),
|
|
(BYTE*)(&beres),
|
|
&keylistSize,
|
|
&keylist));
|
|
|
|
ptr = keylist;
|
|
ptr = unpack_UINT16(ptr, &size);
|
|
|
|
//Flush each handle
|
|
if(size) {
|
|
vtpmloginfo(VTPM_LOG_VTPM, "Flushing %u handle(s) of type %lu\n", size, (unsigned long) reslist[i]);
|
|
for(int j = 0; j < size; ++j) {
|
|
TPM_HANDLE h;
|
|
ptr = unpack_TPM_HANDLE(ptr, &h);
|
|
TPMTRYRETURN(TPM_FlushSpecific(h, reslist[i]));
|
|
}
|
|
}
|
|
|
|
free(keylist);
|
|
keylist = NULL;
|
|
}
|
|
|
|
goto egress;
|
|
abort_egress:
|
|
free(keylist);
|
|
egress:
|
|
return status;
|
|
}
|
|
|
|
|
|
static TPM_RESULT try_take_ownership(void) {
|
|
TPM_RESULT status = TPM_SUCCESS;
|
|
TPM_PUBKEY pubEK = TPM_PUBKEY_INIT;
|
|
|
|
// If we can read PubEK then there is no owner and we should take it.
|
|
status = TPM_ReadPubek(&pubEK);
|
|
|
|
switch(status) {
|
|
case TPM_DISABLED_CMD:
|
|
//Cannot read ek? TPM has owner
|
|
vtpmloginfo(VTPM_LOG_VTPM, "Failed to readEK meaning TPM has an owner. Creating Keys off existing SRK.\n");
|
|
status = TPM_SUCCESS;
|
|
break;
|
|
case TPM_NO_ENDORSEMENT:
|
|
{
|
|
//If theres no ek, we have to create one
|
|
TPM_KEY_PARMS keyInfo = {
|
|
.algorithmID = TPM_ALG_RSA,
|
|
.encScheme = TPM_ES_RSAESOAEP_SHA1_MGF1,
|
|
.sigScheme = TPM_SS_NONE,
|
|
.parmSize = 12,
|
|
.parms.rsa = {
|
|
.keyLength = RSA_KEY_SIZE,
|
|
.numPrimes = 2,
|
|
.exponentSize = 0,
|
|
.exponent = NULL,
|
|
},
|
|
};
|
|
TPMTRYRETURN(TPM_CreateEndorsementKeyPair(&keyInfo, &pubEK));
|
|
}
|
|
//fall through to take ownership
|
|
case TPM_SUCCESS:
|
|
{
|
|
//Construct the Srk
|
|
TPM_KEY srk = {
|
|
.ver = TPM_STRUCT_VER_1_1,
|
|
.keyUsage = TPM_KEY_STORAGE,
|
|
.keyFlags = 0x00,
|
|
.authDataUsage = TPM_AUTH_ALWAYS,
|
|
.algorithmParms = {
|
|
.algorithmID = TPM_ALG_RSA,
|
|
.encScheme = TPM_ES_RSAESOAEP_SHA1_MGF1,
|
|
.sigScheme = TPM_SS_NONE,
|
|
.parmSize = 12,
|
|
.parms.rsa = {
|
|
.keyLength = RSA_KEY_SIZE,
|
|
.numPrimes = 2,
|
|
.exponentSize = 0,
|
|
.exponent = NULL,
|
|
},
|
|
},
|
|
.PCRInfoSize = 0,
|
|
.pubKey = {
|
|
.keyLength = 0,
|
|
.key = NULL,
|
|
},
|
|
.encDataSize = 0,
|
|
};
|
|
|
|
TPMTRYRETURN(TPM_TakeOwnership(
|
|
&pubEK,
|
|
(const TPM_AUTHDATA*)&vtpm_globals.owner_auth,
|
|
(const TPM_AUTHDATA*)&vtpm_globals.srk_auth,
|
|
&srk,
|
|
NULL,
|
|
&vtpm_globals.oiap));
|
|
|
|
TPMTRYRETURN(TPM_DisablePubekRead(
|
|
(const TPM_AUTHDATA*)&vtpm_globals.owner_auth,
|
|
&vtpm_globals.oiap));
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
abort_egress:
|
|
free_TPM_PUBKEY(&pubEK);
|
|
return status;
|
|
}
|
|
|
|
static int parse_auth_string(char* authstr, BYTE* target) {
|
|
int rc;
|
|
/* well known owner auth */
|
|
if(!strcmp(authstr, "well-known")) {
|
|
return 0;
|
|
}
|
|
/* 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;
|
|
sha1((const unsigned char*)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, struct Opts* opts)
|
|
{
|
|
int rc;
|
|
int i;
|
|
|
|
//Set defaults
|
|
memcpy(vtpm_globals.owner_auth, WELLKNOWN_AUTH, sizeof(TPM_AUTHDATA));
|
|
memcpy(vtpm_globals.srk_auth, WELLKNOWN_AUTH, sizeof(TPM_AUTHDATA));
|
|
|
|
for(i = 1; i < argc; ++i) {
|
|
if(!strncmp(argv[i], "owner_auth=", 11)) {
|
|
if((rc = parse_auth_string(argv[i] + 11, vtpm_globals.owner_auth)) < 0) {
|
|
goto err_invalid;
|
|
}
|
|
if(rc == 1) {
|
|
opts->gen_owner_auth = 1;
|
|
}
|
|
}
|
|
else if(!strncmp(argv[i], "srk_auth=", 9)) {
|
|
if((rc = parse_auth_string(argv[i] + 9, vtpm_globals.srk_auth)) != 0) {
|
|
goto err_invalid;
|
|
}
|
|
}
|
|
else if(!strncmp(argv[i], "srk_handle=", 11)) {
|
|
if(sscanf(argv[i] + 11, "%x", &vtpm_globals.srk_handle) != 1) {
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
|
|
static TPM_RESULT vtpmmgr_create(void) {
|
|
TPM_RESULT status = TPM_SUCCESS;
|
|
TPM_AUTH_SESSION osap = TPM_AUTH_SESSION_INIT;
|
|
TPM_AUTHDATA sharedsecret;
|
|
|
|
// Take ownership if TPM is unowned
|
|
TPMTRYRETURN(try_take_ownership());
|
|
|
|
// Generate storage key's auth
|
|
TPMTRYRETURN( TPM_OSAP(
|
|
TPM_ET_KEYHANDLE,
|
|
TPM_SRK_KEYHANDLE,
|
|
(const TPM_AUTHDATA*)&vtpm_globals.srk_auth,
|
|
&sharedsecret,
|
|
&osap) );
|
|
|
|
//Make sure TPM has commited changes
|
|
TPMTRYRETURN( TPM_SaveState() );
|
|
|
|
//Create new disk image
|
|
TPMTRYRETURN(vtpm_new_disk());
|
|
|
|
goto egress;
|
|
abort_egress:
|
|
egress:
|
|
vtpmloginfo(VTPM_LOG_VTPM, "Finished initialized new VTPM manager\n");
|
|
|
|
//End the OSAP session
|
|
if(osap.AuthHandle) {
|
|
TPM_TerminateHandle(osap.AuthHandle);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
static void set_opaque(domid_t domid, unsigned int handle)
|
|
{
|
|
struct tpm_opaque* opq;
|
|
|
|
opq = calloc(1, sizeof(*opq));
|
|
opq->uuid = (uuid_t*)tpmback_get_uuid(domid, handle);
|
|
opq->domid = domid;
|
|
opq->handle = handle;
|
|
tpmback_set_opaque(domid, handle, opq);
|
|
}
|
|
|
|
static void free_opaque(domid_t domid, unsigned int handle)
|
|
{
|
|
struct tpm_opaque* opq = tpmback_get_opaque(domid, handle);
|
|
if (opq && opq->vtpm)
|
|
opq->vtpm->flags &= ~VTPM_FLAG_OPEN;
|
|
free(opq);
|
|
}
|
|
|
|
TPM_RESULT vtpmmgr_init(int argc, char** argv) {
|
|
TPM_RESULT status = TPM_SUCCESS;
|
|
|
|
/* Default commandline options */
|
|
struct Opts opts = {
|
|
.tpmdriver = TPMDRV_TPM_TIS,
|
|
.tpmiomem = TPM_BASEADDR,
|
|
.tpmirq = 0,
|
|
.tpmlocality = 0,
|
|
.gen_owner_auth = 0,
|
|
};
|
|
|
|
if(parse_cmdline_opts(argc, argv, &opts) != 0) {
|
|
vtpmlogerror(VTPM_LOG_VTPM, "Command line parsing failed! exiting..\n");
|
|
status = TPM_BAD_PARAMETER;
|
|
goto abort_egress;
|
|
}
|
|
|
|
//Setup storage system
|
|
if(vtpm_storage_init() != 0) {
|
|
vtpmlogerror(VTPM_LOG_VTPM, "Unable to initialize storage subsystem!\n");
|
|
status = TPM_IOERROR;
|
|
goto abort_egress;
|
|
}
|
|
|
|
//Setup tpmback device
|
|
init_tpmback(set_opaque, free_opaque);
|
|
|
|
//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");
|
|
status = TPM_IOERROR;
|
|
goto abort_egress;
|
|
}
|
|
vtpm_globals.tpm_fd = tpm_tis_open(tpm);
|
|
tpm_tis_request_locality(tpm, opts.tpmlocality);
|
|
vtpm_globals.hw_locality = 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");
|
|
status = TPM_IOERROR;
|
|
goto abort_egress;
|
|
}
|
|
vtpm_globals.tpm_fd = tpmfront_open(tpmfront_dev);
|
|
}
|
|
break;
|
|
}
|
|
|
|
//Get the version of the tpm
|
|
TPMTRYRETURN(check_tpm_version());
|
|
|
|
// Blow away all stale handles left in the tpm
|
|
if(flush_tpm() != TPM_SUCCESS) {
|
|
vtpmlogerror(VTPM_LOG_VTPM, "VTPM_FlushResources failed, continuing anyway..\n");
|
|
}
|
|
|
|
/* Initialize the rng */
|
|
entropy_init(&vtpm_globals.entropy);
|
|
entropy_add_source(&vtpm_globals.entropy, tpm_entropy_source, NULL, 0);
|
|
entropy_gather(&vtpm_globals.entropy);
|
|
ctr_drbg_init(&vtpm_globals.ctr_drbg, entropy_func, &vtpm_globals.entropy, NULL, 0);
|
|
ctr_drbg_set_prediction_resistance( &vtpm_globals.ctr_drbg, CTR_DRBG_PR_OFF );
|
|
|
|
// Generate Auth for Owner
|
|
if(opts.gen_owner_auth) {
|
|
vtpmmgr_rand(vtpm_globals.owner_auth, sizeof(TPM_AUTHDATA));
|
|
}
|
|
|
|
// Create OIAP session for service's authorized commands
|
|
TPMTRYRETURN( TPM_OIAP(&vtpm_globals.oiap) );
|
|
|
|
/* Load the Manager data, if it fails create a new manager */
|
|
// TODO handle upgrade recovery of auth0
|
|
if (vtpm_load_disk()) {
|
|
/* If the OIAP session was closed by an error, create a new one */
|
|
if(vtpm_globals.oiap.AuthHandle == 0) {
|
|
TPMTRYRETURN( TPM_OIAP(&vtpm_globals.oiap) );
|
|
}
|
|
vtpmloginfo(VTPM_LOG_VTPM, "Failed to read manager file. Assuming first time initialization.\n");
|
|
TPMTRYRETURN( vtpmmgr_create() );
|
|
}
|
|
|
|
goto egress;
|
|
abort_egress:
|
|
vtpmmgr_shutdown();
|
|
egress:
|
|
return status;
|
|
}
|
|
|
|
/* TPM 2.0 */
|
|
|
|
static void tpm2_AuthArea_ctor(const char *authValue, UINT32 authLen,
|
|
TPM_AuthArea *auth)
|
|
{
|
|
auth->sessionHandle = TPM_RS_PW;
|
|
auth->nonce.size = 0;
|
|
auth->sessionAttributes = 1;
|
|
auth->auth.size = authLen;
|
|
memcpy(auth->auth.buffer, authValue, authLen);
|
|
auth->size = 9 + authLen;
|
|
}
|
|
|
|
TPM_RC tpm2_take_ownership(void)
|
|
{
|
|
TPM_RC status = TPM_SUCCESS;
|
|
|
|
tpm2_AuthArea_ctor(NULL, 0, &vtpm_globals.pw_auth);
|
|
|
|
/* create SRK */
|
|
TPM2_CreatePrimary_Params_in in = {
|
|
.inSensitive = {
|
|
.size = 4,
|
|
.sensitive = {
|
|
.userAuth.size = 0,
|
|
.userAuth.buffer = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
|
|
.data.size = 0,
|
|
},
|
|
},
|
|
.inPublic = {
|
|
.size = 60,
|
|
.publicArea = {
|
|
.type = TPM2_ALG_RSA,
|
|
.nameAlg = TPM2_ALG_SHA256,
|
|
#define SRK_OBJ_ATTR (fixedTPM | fixedParent | userWithAuth | \
|
|
sensitiveDataOrigin | restricted | decrypt)
|
|
.objectAttributes = SRK_OBJ_ATTR,
|
|
.authPolicy.size = 0,
|
|
.parameters.rsaDetail = {
|
|
.symmetric = {
|
|
.algorithm = TPM2_ALG_AES,
|
|
.keyBits.aes = AES_KEY_SIZES_BITS,
|
|
.mode.aes = TPM2_ALG_CFB,
|
|
},
|
|
.scheme = { TPM2_ALG_NULL },
|
|
.keyBits = RSA_KEY_SIZES_BITS,
|
|
.exponent = 0,
|
|
},
|
|
.unique.rsa.size = 0,
|
|
},
|
|
},
|
|
.outsideInfo.size = 0,
|
|
.creationPCR.count = 0,
|
|
};
|
|
|
|
TPMTRYRETURN(TPM2_CreatePrimary(TPM_RH_OWNER,&in,
|
|
&vtpm_globals.srk_handle, NULL));
|
|
vtpmloginfo(VTPM_LOG_VTPM, "SRK handle: 0x%X\n", vtpm_globals.srk_handle);
|
|
{
|
|
const char data[20] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
|
tpm2_AuthArea_ctor(data, 20, &vtpm_globals.srk_auth_area);
|
|
}
|
|
/*end create SRK*/
|
|
|
|
abort_egress:
|
|
return status;
|
|
}
|
|
|
|
TPM_RESULT vtpmmgr2_create(void)
|
|
{
|
|
TPM_RESULT status = TPM_SUCCESS;
|
|
|
|
if ( vtpm_globals.srk_handle == 0 ) {
|
|
TPMTRYRETURN(tpm2_take_ownership());
|
|
} else {
|
|
tpm2_AuthArea_ctor(NULL, 0, &vtpm_globals.srk_auth_area);
|
|
}
|
|
|
|
/* create SK */
|
|
TPM2_Create_Params_out out;
|
|
TPM2_Create_Params_in in = {
|
|
.inSensitive = {
|
|
.size = 4 + 20,
|
|
.sensitive = {
|
|
.userAuth.size = 20,
|
|
.userAuth.buffer = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
|
|
.data.size = 0,
|
|
},
|
|
},
|
|
.inPublic = {
|
|
.size = (60),
|
|
.publicArea = {
|
|
.type = TPM2_ALG_RSA,
|
|
.nameAlg = TPM2_ALG_SHA256,
|
|
#define SK_OBJ_ATTR (fixedTPM | fixedParent | userWithAuth |\
|
|
sensitiveDataOrigin |decrypt)
|
|
.objectAttributes = SK_OBJ_ATTR,
|
|
.authPolicy.size = 0,
|
|
.parameters.rsaDetail = {
|
|
.symmetric = {
|
|
.algorithm = TPM2_ALG_NULL,
|
|
},
|
|
.scheme = {
|
|
TPM2_ALG_OAEP,
|
|
.details.oaep.hashAlg = TPM2_ALG_SHA256,
|
|
},
|
|
.keyBits = RSA_KEY_SIZES_BITS,
|
|
.exponent = 0,
|
|
},
|
|
.unique.rsa.size = 0,
|
|
},
|
|
},
|
|
.outsideInfo.size = 0,
|
|
.creationPCR.count = 0,
|
|
};/*end in */
|
|
|
|
TPMTRYRETURN(TPM2_Create(vtpm_globals.srk_handle, &in, &out));
|
|
TPMTRYRETURN(TPM2_Load(vtpm_globals.srk_handle,
|
|
&vtpm_globals.tpm2_storage_key.Private,
|
|
&vtpm_globals.tpm2_storage_key.Public,
|
|
&vtpm_globals.sk_handle,
|
|
&vtpm_globals.sk_name));
|
|
|
|
vtpmloginfo(VTPM_LOG_VTPM, "SK HANDLE: 0x%X\n", vtpm_globals.sk_handle);
|
|
|
|
/*Create new disk image*/
|
|
TPMTRYRETURN(vtpm_new_disk());
|
|
|
|
goto egress;
|
|
|
|
abort_egress:
|
|
egress:
|
|
vtpmloginfo(VTPM_LOG_VTPM, "Finished initialized new VTPM manager\n");
|
|
return status;
|
|
}
|
|
|
|
static int tpm2_entropy_source(void* dummy, unsigned char* data,
|
|
size_t len, size_t* olen)
|
|
{
|
|
UINT32 sz = len;
|
|
TPM_RESULT rc = TPM2_GetRandom(&sz, data);
|
|
*olen = sz;
|
|
return rc == TPM_SUCCESS ? 0 : POLARSSL_ERR_ENTROPY_SOURCE_FAILED;
|
|
}
|
|
|
|
/*TPM 2.0 Objects flush */
|
|
static TPM_RC flush_tpm2(void)
|
|
{
|
|
int i;
|
|
|
|
for (i = TRANSIENT_FIRST; i <= TRANSIENT_LAST; i++)
|
|
TPM2_FlushContext(i);
|
|
|
|
return TPM_SUCCESS;
|
|
}
|
|
|
|
TPM_RESULT vtpmmgr2_init(int argc, char** argv)
|
|
{
|
|
TPM_RESULT status = TPM_SUCCESS;
|
|
|
|
/* Default commandline options */
|
|
struct Opts opts = {
|
|
.tpmdriver = TPMDRV_TPM_TIS,
|
|
.tpmiomem = TPM_BASEADDR,
|
|
.tpmirq = 0,
|
|
.tpmlocality = 0,
|
|
.gen_owner_auth = 0,
|
|
};
|
|
|
|
if (parse_cmdline_opts(argc, argv, &opts) != 0) {
|
|
vtpmlogerror(VTPM_LOG_VTPM, "Command line parsing failed! exiting..\n");
|
|
status = TPM_BAD_PARAMETER;
|
|
goto abort_egress;
|
|
}
|
|
|
|
/*Setup storage system*/
|
|
if (vtpm_storage_init() != 0) {
|
|
vtpmlogerror(VTPM_LOG_VTPM, "Unable to initialize storage subsystem!\n");
|
|
status = TPM_IOERROR;
|
|
goto abort_egress;
|
|
}
|
|
|
|
/*Setup tpmback device*/
|
|
init_tpmback(set_opaque, free_opaque);
|
|
|
|
/*Setup tpm access*/
|
|
switch(opts.tpmdriver) {
|
|
case TPMDRV_TPM_TIS:
|
|
{
|
|
struct tpm_chip* tpm;
|
|
if ((tpm = init_tpm2_tis(opts.tpmiomem, TPM_TIS_LOCL_INT_TO_FLAG(opts.tpmlocality),
|
|
opts.tpmirq)) == NULL) {
|
|
vtpmlogerror(VTPM_LOG_VTPM, "Unable to initialize tpmfront device\n");
|
|
status = TPM_IOERROR;
|
|
goto abort_egress;
|
|
}
|
|
printk("init_tpm2_tis() ...ok\n");
|
|
vtpm_globals.tpm_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");
|
|
status = TPM_IOERROR;
|
|
goto abort_egress;
|
|
}
|
|
vtpm_globals.tpm_fd = tpmfront_open(tpmfront_dev);
|
|
}
|
|
break;
|
|
}
|
|
printk("TPM 2.0 access ...ok\n");
|
|
/* Blow away all stale handles left in the tpm*/
|
|
if (flush_tpm2() != TPM_SUCCESS) {
|
|
vtpmlogerror(VTPM_LOG_VTPM, "VTPM_FlushResources failed, continuing anyway..\n");
|
|
}
|
|
|
|
/* Initialize the rng */
|
|
entropy_init(&vtpm_globals.entropy);
|
|
entropy_add_source(&vtpm_globals.entropy, tpm2_entropy_source, NULL, 0);
|
|
entropy_gather(&vtpm_globals.entropy);
|
|
ctr_drbg_init(&vtpm_globals.ctr_drbg, entropy_func, &vtpm_globals.entropy, NULL, 0);
|
|
ctr_drbg_set_prediction_resistance( &vtpm_globals.ctr_drbg, CTR_DRBG_PR_OFF );
|
|
|
|
/* Generate Auth for Owner*/
|
|
if (opts.gen_owner_auth) {
|
|
vtpmmgr_rand(vtpm_globals.owner_auth, sizeof(TPM_AUTHDATA));
|
|
}
|
|
|
|
/* Load the Manager data, if it fails create a new manager */
|
|
if (vtpm_load_disk()) {
|
|
vtpmloginfo(VTPM_LOG_VTPM, "Assuming first time initialization.\n");
|
|
TPMTRYRETURN(vtpmmgr2_create());
|
|
}
|
|
|
|
goto egress;
|
|
|
|
abort_egress:
|
|
vtpmmgr_shutdown();
|
|
egress:
|
|
return status;
|
|
}
|
|
|
|
TPM_RC tpm2_pcr_read(int index, uint8_t *buf)
|
|
{
|
|
TPM_RESULT status = TPM_SUCCESS;
|
|
TPML_PCR_SELECTION pcrSelectionIn = {
|
|
.count = 1,};
|
|
|
|
TPMS_PCR_SELECTION tpms_pcr_selection = {
|
|
.hash = TPM2_ALG_SHA1,
|
|
.sizeofSelect = PCR_SELECT_MAX,};
|
|
|
|
UINT32 pcrUpdateCounter;
|
|
TPML_PCR_SELECTION pcrSelectionOut;
|
|
TPML_DIGEST pcrValues;
|
|
TPM2B_DIGEST tpm2b_digest;
|
|
|
|
tpms_pcr_selection.pcrSelect[PCR_SELECT_NUM(index)] = PCR_SELECT_VALUE(index);
|
|
memcpy(&pcrSelectionIn.pcrSelections[0], &tpms_pcr_selection,
|
|
sizeof(TPMS_PCR_SELECTION));
|
|
|
|
TPMTRYRETURN(TPM2_PCR_Read(pcrSelectionIn, &pcrUpdateCounter,
|
|
&pcrSelectionOut, &pcrValues));
|
|
|
|
if (pcrValues.count < 1)
|
|
goto egress;
|
|
|
|
unpack_TPM2B_DIGEST((uint8_t *) &pcrValues, &tpm2b_digest);
|
|
memcpy(buf, tpm2b_digest.buffer, SHA1_DIGEST_SIZE);
|
|
|
|
abort_egress:
|
|
egress:
|
|
return status;
|
|
}
|
|
|
|
void vtpmmgr_shutdown(void)
|
|
{
|
|
/* Cleanup TPM resources */
|
|
TPM_TerminateHandle(vtpm_globals.oiap.AuthHandle);
|
|
|
|
/* Close tpmback */
|
|
shutdown_tpmback();
|
|
|
|
if (hw_is_tpm2()) {
|
|
/* Blow away all stale handles left in the tpm*/
|
|
if (flush_tpm2() != TPM_SUCCESS) {
|
|
vtpmlogerror(VTPM_LOG_TPM,
|
|
"TPM2_FlushResources failed, continuing shutdown..\n");
|
|
}
|
|
}
|
|
|
|
/* Close tpmfront/tpm_tis */
|
|
close(vtpm_globals.tpm_fd);
|
|
|
|
vtpmloginfo(VTPM_LOG_VTPM, "VTPM Manager stopped.\n");
|
|
}
|