Files
xen/stubdom/vtpmmgr/vtpm_storage.c
T
Matthew Fioravante 095b0b7794 add stubdom/vtpmmgr code
Add the code base for vtpmmgrdom. Makefile changes
next patch.

Signed-off-by: Matthew Fioravante <matthew.fioravante@jhuapl.edu>
Acked-by: Ian Campbell <ian.campbell@citrix.com>
Committed-by: Ian Campbell <ian.campbell@citrix.com>
2013-01-18 10:55:43 +00:00

795 lines
23 KiB
C

/*
* Copyright (c) 2010-2012 United States Government, as represented by
* the Secretary of Defense. All rights reserved.
*
* THIS SOFTWARE AND ITS DOCUMENTATION ARE PROVIDED AS IS AND WITHOUT
* ANY EXPRESS OR IMPLIED WARRANTIES WHATSOEVER. ALL WARRANTIES
* INCLUDING, BUT NOT LIMITED TO, PERFORMANCE, MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT ARE HEREBY
* DISCLAIMED. USERS ASSUME THE ENTIRE RISK AND LIABILITY OF USING THE
* SOFTWARE.
*/
/***************************************************************
* DISK IMAGE LAYOUT
* *************************************************************
* All data is stored in BIG ENDIAN format
* *************************************************************
* Section 1: Header
*
* 10 bytes id ID String "VTPMMGRDOM"
* uint32_t version Disk Image version number (current == 1)
* uint32_t storage_key_len Length of the storage Key
* TPM_KEY storage_key Marshalled TPM_KEY structure (See TPM spec v2)
* RSA_BLOCK aes_crypto Encrypted aes key data (RSA_CIPHER_SIZE bytes), bound by the storage_key
* BYTE[32] aes_key Aes key for encrypting the uuid table
* uint32_t cipher_sz Encrypted size of the uuid table
*
* *************************************************************
* Section 2: Uuid Table
*
* This table is encrypted by the aes_key in the header. The cipher text size is just
* large enough to hold all of the entries plus required padding.
*
* Each entry is as follows
* BYTE[16] uuid Uuid of a vtpm that is stored on this disk
* uint32_t offset Disk offset where the vtpm data is stored
*
* *************************************************************
* Section 3: Vtpm Table
*
* The rest of the disk stores vtpms. Each vtpm is an RSA_BLOCK encrypted
* by the storage key. Each vtpm must exist on an RSA_BLOCK aligned boundary,
* starting at the first RSA_BLOCK aligned offset after the uuid table.
* As the uuid table grows, vtpms may be relocated.
*
* RSA_BLOCK vtpm_crypto Vtpm data encrypted by storage_key
* BYTE[20] hash Sha1 hash of vtpm encrypted data
* BYTE[16] vtpm_aes_key Encryption key for vtpm data
*
*************************************************************
*/
#define DISKVERS 1
#define IDSTR "VTPMMGRDOM"
#define IDSTRLEN 10
#define AES_BLOCK_SIZE 16
#define AES_KEY_BITS 256
#define AES_KEY_SIZE (AES_KEY_BITS/8)
#define BUF_SIZE 4096
#define UUID_TBL_ENT_SIZE (sizeof(uuid_t) + sizeof(uint32_t))
#define HEADERSZ (10 + 4 + 4)
#define TRY_READ(buf, size, msg) do {\
int rc; \
if((rc = read(blkfront_fd, buf, (size))) != (size)) { \
vtpmlogerror(VTPM_LOG_VTPM, "read() failed! " msg " : rc=(%d/%d), error=(%s)\n", rc, (int)(size), strerror(errno)); \
status = TPM_IOERROR;\
goto abort_egress;\
} \
} while(0)
#define TRY_WRITE(buf, size, msg) do {\
int rc; \
if((rc = write(blkfront_fd, buf, (size))) != (size)) { \
vtpmlogerror(VTPM_LOG_VTPM, "write() failed! " msg " : rc=(%d/%d), error=(%s)\n", rc, (int)(size), strerror(errno)); \
status = TPM_IOERROR;\
goto abort_egress;\
} \
} while(0)
#include <blkfront.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <inttypes.h>
#include <stdlib.h>
#include <stdbool.h>
#include <mini-os/byteorder.h>
#include <polarssl/aes.h>
#include "vtpm_manager.h"
#include "log.h"
#include "marshal.h"
#include "tpm.h"
#include "uuid.h"
#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;
struct Vtpm {
uuid_t uuid;
int offset;
};
struct Storage {
int aes_offset;
int uuid_offset;
int end_offset;
int num_vtpms;
int num_vtpms_alloced;
struct Vtpm* vtpms;
};
/* Global storage data */
static struct Storage g_store = {
.vtpms = NULL,
};
static int get_offset(void) {
return lseek(blkfront_fd, 0, SEEK_CUR);
}
static void reset_store(void) {
g_store.aes_offset = 0;
g_store.uuid_offset = 0;
g_store.end_offset = 0;
g_store.num_vtpms = 0;
g_store.num_vtpms_alloced = 0;
free(g_store.vtpms);
g_store.vtpms = NULL;
}
static int vtpm_get_index(const uuid_t uuid) {
int st = 0;
int ed = g_store.num_vtpms-1;
while(st <= ed) {
int mid = ((unsigned int)st + (unsigned int)ed) >> 1; //avoid overflow
int c = memcmp(uuid, &g_store.vtpms[mid].uuid, sizeof(uuid_t));
if(c == 0) {
return mid;
} else if(c > 0) {
st = mid + 1;
} else {
ed = mid - 1;
}
}
return -(st + 1);
}
static void vtpm_add(const uuid_t uuid, int offset, int index) {
/* Realloc more space if needed */
if(g_store.num_vtpms >= g_store.num_vtpms_alloced) {
g_store.num_vtpms_alloced += 16;
g_store.vtpms = realloc(
g_store.vtpms,
sizeof(struct Vtpm) * g_store.num_vtpms_alloced);
}
/* Move everybody after the new guy */
for(int i = g_store.num_vtpms; i > index; --i) {
g_store.vtpms[i] = g_store.vtpms[i-1];
}
vtpmloginfo(VTPM_LOG_VTPM, "Registered vtpm " UUID_FMT "\n", UUID_BYTES(uuid));
/* Finally add new one */
memcpy(g_store.vtpms[index].uuid, uuid, sizeof(uuid_t));
g_store.vtpms[index].offset = offset;
++g_store.num_vtpms;
}
#if 0
static void vtpm_remove(int index) {
for(i = index; i < g_store.num_vtpms; ++i) {
g_store.vtpms[i] = g_store.vtpms[i+1];
}
--g_store.num_vtpms;
}
#endif
static int pack_uuid_table(uint8_t* table, int size, int* nvtpms) {
uint8_t* ptr = table;
while(*nvtpms < g_store.num_vtpms && size >= 0)
{
/* Pack the uuid */
memcpy(ptr, (uint8_t*)g_store.vtpms[*nvtpms].uuid, sizeof(uuid_t));
ptr+= sizeof(uuid_t);
/* Pack the offset */
ptr = pack_UINT32(ptr, g_store.vtpms[*nvtpms].offset);
++*nvtpms;
size -= UUID_TBL_ENT_SIZE;
}
return ptr - table;
}
/* Extract the uuids */
static int extract_uuid_table(uint8_t* table, int size) {
uint8_t* ptr = table;
for(;size >= UUID_TBL_ENT_SIZE; size -= UUID_TBL_ENT_SIZE) {
int index;
uint32_t v32;
/*uuid_t is just an array of bytes, so we can do a direct cast here */
uint8_t* uuid = ptr;
ptr += sizeof(uuid_t);
/* Get the offset of the key */
ptr = unpack_UINT32(ptr, &v32);
/* Insert the new vtpm in sorted order */
if((index = vtpm_get_index(uuid)) >= 0) {
vtpmlogerror(VTPM_LOG_VTPM, "Vtpm (" UUID_FMT ") exists multiple times! ignoring...\n", UUID_BYTES(uuid));
continue;
}
index = -index -1;
vtpm_add(uuid, v32, index);
}
return ptr - table;
}
static void vtpm_decrypt_block(aes_context* aes,
uint8_t* iv,
uint8_t* cipher,
uint8_t* plain,
int cipher_sz,
int* overlap)
{
int bytes_ext;
/* Decrypt */
aes_crypt_cbc(aes, AES_DECRYPT,
cipher_sz,
iv, cipher, plain + *overlap);
/* Extract */
bytes_ext = extract_uuid_table(plain, cipher_sz + *overlap);
/* Copy left overs to the beginning */
*overlap = cipher_sz + *overlap - bytes_ext;
memcpy(plain, plain + bytes_ext, *overlap);
}
static int vtpm_encrypt_block(aes_context* aes,
uint8_t* iv,
uint8_t* plain,
uint8_t* cipher,
int block_sz,
int* overlap,
int* num_vtpms)
{
int bytes_to_crypt;
int bytes_packed;
/* Pack the uuid table */
bytes_packed = *overlap + pack_uuid_table(plain + *overlap, block_sz - *overlap, num_vtpms);
bytes_to_crypt = MIN(bytes_packed, block_sz);
/* Add padding if we aren't on a multiple of the block size */
if(bytes_to_crypt & (AES_BLOCK_SIZE-1)) {
int oldsz = bytes_to_crypt;
//add padding
bytes_to_crypt += AES_BLOCK_SIZE - (bytes_to_crypt & (AES_BLOCK_SIZE-1));
//fill padding with random bytes
vtpmmgr_rand(plain + oldsz, bytes_to_crypt - oldsz);
*overlap = 0;
} else {
*overlap = bytes_packed - bytes_to_crypt;
}
/* Encrypt this chunk */
aes_crypt_cbc(aes, AES_ENCRYPT,
bytes_to_crypt,
iv, plain, cipher);
/* Copy the left over partials to the beginning */
memcpy(plain, plain + bytes_to_crypt, *overlap);
return bytes_to_crypt;
}
static TPM_RESULT vtpm_storage_new_vtpm(const uuid_t uuid, int index) {
TPM_RESULT status = TPM_SUCCESS;
uint8_t plain[BUF_SIZE + AES_BLOCK_SIZE];
uint8_t buf[BUF_SIZE];
uint8_t* ptr;
int cipher_sz;
aes_context aes;
/* Add new vtpm to the table */
vtpm_add(uuid, g_store.end_offset, index);
g_store.end_offset += RSA_CIPHER_SIZE;
/* Compute the new end location of the encrypted uuid table */
cipher_sz = AES_BLOCK_SIZE; //IV
cipher_sz += g_store.num_vtpms * UUID_TBL_ENT_SIZE; //uuid table
cipher_sz += (AES_BLOCK_SIZE - (cipher_sz & (AES_BLOCK_SIZE -1))) & (AES_BLOCK_SIZE-1); //aes padding
/* Does this overlap any key data? If so they need to be relocated */
int uuid_end = (g_store.uuid_offset + cipher_sz + RSA_CIPHER_SIZE) & ~(RSA_CIPHER_SIZE -1);
for(int i = 0; i < g_store.num_vtpms; ++i) {
if(g_store.vtpms[i].offset < uuid_end) {
vtpmloginfo(VTPM_LOG_VTPM, "Relocating vtpm data\n");
//Read the hashkey cipher text
lseek(blkfront_fd, g_store.vtpms[i].offset, SEEK_SET);
TRY_READ(buf, RSA_CIPHER_SIZE, "vtpm hashkey relocate");
//Write the cipher text to new offset
lseek(blkfront_fd, g_store.end_offset, SEEK_SET);
TRY_WRITE(buf, RSA_CIPHER_SIZE, "vtpm hashkey relocate");
//Save new offset
g_store.vtpms[i].offset = g_store.end_offset;
g_store.end_offset += RSA_CIPHER_SIZE;
}
}
vtpmloginfo(VTPM_LOG_VTPM, "Generating a new symmetric key\n");
/* Generate an aes key */
TPMTRYRETURN(vtpmmgr_rand(plain, AES_KEY_SIZE));
aes_setkey_enc(&aes, plain, AES_KEY_BITS);
ptr = plain + AES_KEY_SIZE;
/* Pack the crypted size */
ptr = pack_UINT32(ptr, cipher_sz);
vtpmloginfo(VTPM_LOG_VTPM, "Binding encrypted key\n");
/* Seal the key and size */
TPMTRYRETURN(TPM_Bind(&vtpm_globals.storage_key,
plain,
ptr - plain,
buf));
/* Write the sealed key to disk */
lseek(blkfront_fd, g_store.aes_offset, SEEK_SET);
TRY_WRITE(buf, RSA_CIPHER_SIZE, "vtpm aes key");
/* ENCRYPT AND WRITE UUID TABLE */
vtpmloginfo(VTPM_LOG_VTPM, "Encrypting the uuid table\n");
int num_vtpms = 0;
int overlap = 0;
int bytes_crypted;
uint8_t iv[AES_BLOCK_SIZE];
/* Generate the iv for the first block */
TPMTRYRETURN(vtpmmgr_rand(iv, AES_BLOCK_SIZE));
/* Copy the iv to the cipher text buffer to be written to disk */
memcpy(buf, iv, AES_BLOCK_SIZE);
ptr = buf + AES_BLOCK_SIZE;
/* Encrypt the first block of the uuid table */
bytes_crypted = vtpm_encrypt_block(&aes,
iv, //iv
plain, //plaintext
ptr, //cipher text
BUF_SIZE - AES_BLOCK_SIZE,
&overlap,
&num_vtpms);
/* Write the iv followed by the crypted table*/
TRY_WRITE(buf, bytes_crypted + AES_BLOCK_SIZE, "vtpm uuid table");
/* Decrement the number of bytes encrypted */
cipher_sz -= bytes_crypted + AES_BLOCK_SIZE;
/* If there are more vtpms, encrypt and write them block by block */
while(cipher_sz > 0) {
/* Encrypt the next block of the uuid table */
bytes_crypted = vtpm_encrypt_block(&aes,
iv,
plain,
buf,
BUF_SIZE,
&overlap,
&num_vtpms);
/* Write the cipher text to disk */
TRY_WRITE(buf, bytes_crypted, "vtpm uuid table");
cipher_sz -= bytes_crypted;
}
goto egress;
abort_egress:
egress:
return status;
}
/**************************************
* 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) {
reset_store();
close(blkfront_fd);
}
TPM_RESULT vtpm_storage_load_hashkey(const uuid_t uuid, uint8_t hashkey[HASHKEYSZ])
{
TPM_RESULT status = TPM_SUCCESS;
int index;
uint8_t cipher[RSA_CIPHER_SIZE];
uint8_t clear[RSA_CIPHER_SIZE];
UINT32 clear_size;
/* Find the index of this uuid */
if((index = vtpm_get_index(uuid)) < 0) {
index = -index-1;
vtpmlogerror(VTPM_LOG_VTPM, "LoadKey failure: Unrecognized uuid! " UUID_FMT "\n", UUID_BYTES(uuid));
status = TPM_BAD_PARAMETER;
goto abort_egress;
}
/* Read the table entry */
lseek(blkfront_fd, g_store.vtpms[index].offset, SEEK_SET);
TRY_READ(cipher, RSA_CIPHER_SIZE, "vtpm hashkey data");
/* Decrypt the table entry */
TPMTRYRETURN(TPM_UnBind(
vtpm_globals.storage_key_handle,
RSA_CIPHER_SIZE,
cipher,
&clear_size,
clear,
(const TPM_AUTHDATA*)&vtpm_globals.storage_key_usage_auth,
&vtpm_globals.oiap));
if(clear_size < HASHKEYSZ) {
vtpmloginfo(VTPM_LOG_VTPM, "Decrypted Hash key size (%" PRIu32 ") was too small!\n", clear_size);
status = TPM_RESOURCES;
goto abort_egress;
}
memcpy(hashkey, clear, HASHKEYSZ);
vtpmloginfo(VTPM_LOG_VTPM, "Loaded hash and key for vtpm " UUID_FMT "\n", UUID_BYTES(uuid));
goto egress;
abort_egress:
vtpmlogerror(VTPM_LOG_VTPM, "Failed to load key\n");
egress:
return status;
}
TPM_RESULT vtpm_storage_save_hashkey(const uuid_t uuid, uint8_t hashkey[HASHKEYSZ])
{
TPM_RESULT status = TPM_SUCCESS;
int index;
uint8_t buf[RSA_CIPHER_SIZE];
/* Find the index of this uuid */
if((index = vtpm_get_index(uuid)) < 0) {
index = -index-1;
/* Create a new vtpm */
TPMTRYRETURN( vtpm_storage_new_vtpm(uuid, index) );
}
/* Encrypt the hash and key */
TPMTRYRETURN( TPM_Bind(&vtpm_globals.storage_key,
hashkey,
HASHKEYSZ,
buf));
/* Write to disk */
lseek(blkfront_fd, g_store.vtpms[index].offset, SEEK_SET);
TRY_WRITE(buf, RSA_CIPHER_SIZE, "vtpm hashkey data");
vtpmloginfo(VTPM_LOG_VTPM, "Saved hash and key for vtpm " UUID_FMT "\n", UUID_BYTES(uuid));
goto egress;
abort_egress:
vtpmlogerror(VTPM_LOG_VTPM, "Failed to save key\n");
egress:
return status;
}
TPM_RESULT vtpm_storage_new_header()
{
TPM_RESULT status = TPM_SUCCESS;
uint8_t buf[BUF_SIZE];
uint8_t keybuf[AES_KEY_SIZE + sizeof(uint32_t)];
uint8_t* ptr = buf;
uint8_t* sptr;
/* Clear everything first */
reset_store();
vtpmloginfo(VTPM_LOG_VTPM, "Creating new disk image header\n");
/*Copy the ID string */
memcpy(ptr, IDSTR, IDSTRLEN);
ptr += IDSTRLEN;
/*Copy the version */
ptr = pack_UINT32(ptr, DISKVERS);
/*Save the location of the key size */
sptr = ptr;
ptr += sizeof(UINT32);
vtpmloginfo(VTPM_LOG_VTPM, "Saving root storage key..\n");
/* Copy the storage key */
ptr = pack_TPM_KEY(ptr, &vtpm_globals.storage_key);
/* Now save the size */
pack_UINT32(sptr, ptr - (sptr + 4));
/* Create a fake aes key and set cipher text size to 0 */
memset(keybuf, 0, sizeof(keybuf));
vtpmloginfo(VTPM_LOG_VTPM, "Binding uuid table symmetric key..\n");
/* Save the location of the aes key */
g_store.aes_offset = ptr - buf;
/* Store the fake aes key and vtpm count */
TPMTRYRETURN(TPM_Bind(&vtpm_globals.storage_key,
keybuf,
sizeof(keybuf),
ptr));
ptr+= RSA_CIPHER_SIZE;
/* Write the header to disk */
lseek(blkfront_fd, 0, SEEK_SET);
TRY_WRITE(buf, ptr-buf, "vtpm header");
/* Save the location of the uuid table */
g_store.uuid_offset = get_offset();
/* Save the end offset */
g_store.end_offset = (g_store.uuid_offset + RSA_CIPHER_SIZE) & ~(RSA_CIPHER_SIZE -1);
vtpmloginfo(VTPM_LOG_VTPM, "Saved new manager disk header.\n");
goto egress;
abort_egress:
egress:
return status;
}
TPM_RESULT vtpm_storage_load_header(void)
{
TPM_RESULT status = TPM_SUCCESS;
uint32_t v32;
uint8_t buf[BUF_SIZE];
uint8_t* ptr = buf;
aes_context aes;
/* Clear everything first */
reset_store();
/* Read the header from disk */
lseek(blkfront_fd, 0, SEEK_SET);
TRY_READ(buf, IDSTRLEN + sizeof(UINT32) + sizeof(UINT32), "vtpm header");
vtpmloginfo(VTPM_LOG_VTPM, "Loading disk image header\n");
/* Verify the ID string */
if(memcmp(ptr, IDSTR, IDSTRLEN)) {
vtpmlogerror(VTPM_LOG_VTPM, "Invalid ID string in disk image!\n");
status = TPM_FAIL;
goto abort_egress;
}
ptr+=IDSTRLEN;
/* Unpack the version */
ptr = unpack_UINT32(ptr, &v32);
/* Verify the version */
if(v32 != DISKVERS) {
vtpmlogerror(VTPM_LOG_VTPM, "Unsupported disk image version number %" PRIu32 "\n", v32);
status = TPM_FAIL;
goto abort_egress;
}
/* Size of the storage key */
ptr = unpack_UINT32(ptr, &v32);
/* Sanity check */
if(v32 > BUF_SIZE) {
vtpmlogerror(VTPM_LOG_VTPM, "Size of storage key (%" PRIu32 ") is too large!\n", v32);
status = TPM_IOERROR;
goto abort_egress;
}
/* read the storage key */
TRY_READ(buf, v32, "storage pub key");
vtpmloginfo(VTPM_LOG_VTPM, "Unpacking storage key\n");
/* unpack the storage key */
ptr = unpack_TPM_KEY(buf, &vtpm_globals.storage_key, UNPACK_ALLOC);
/* Load Storage Key into the TPM */
TPMTRYRETURN( TPM_LoadKey(
TPM_SRK_KEYHANDLE,
&vtpm_globals.storage_key,
&vtpm_globals.storage_key_handle,
(const TPM_AUTHDATA*)&vtpm_globals.srk_auth,
&vtpm_globals.oiap));
/* Initialize the storage key auth */
memset(vtpm_globals.storage_key_usage_auth, 0, sizeof(TPM_AUTHDATA));
/* Store the offset of the aes key */
g_store.aes_offset = get_offset();
/* Read the rsa cipher text for the aes key */
TRY_READ(buf, RSA_CIPHER_SIZE, "aes key");
ptr = buf + RSA_CIPHER_SIZE;
vtpmloginfo(VTPM_LOG_VTPM, "Unbinding uuid table symmetric key\n");
/* Decrypt the aes key protecting the uuid table */
UINT32 datalen;
TPMTRYRETURN(TPM_UnBind(
vtpm_globals.storage_key_handle,
RSA_CIPHER_SIZE,
buf,
&datalen,
ptr,
(const TPM_AUTHDATA*)&vtpm_globals.storage_key_usage_auth,
&vtpm_globals.oiap));
/* Validate the length of the output buffer */
if(datalen < AES_KEY_SIZE + sizeof(UINT32)) {
vtpmlogerror(VTPM_LOG_VTPM, "Unbound AES key size (%d) was too small! expected (%ld)\n", datalen, AES_KEY_SIZE + sizeof(UINT32));
status = TPM_IOERROR;
goto abort_egress;
}
/* Extract the aes key */
aes_setkey_dec(&aes, ptr, AES_KEY_BITS);
ptr+= AES_KEY_SIZE;
/* Extract the ciphertext size */
ptr = unpack_UINT32(ptr, &v32);
int cipher_size = v32;
/* Sanity check */
if(cipher_size & (AES_BLOCK_SIZE-1)) {
vtpmlogerror(VTPM_LOG_VTPM, "Cipher text size (%" PRIu32 ") is not a multiple of the aes block size! (%d)\n", v32, AES_BLOCK_SIZE);
status = TPM_IOERROR;
goto abort_egress;
}
/* Save the location of the uuid table */
g_store.uuid_offset = get_offset();
/* Only decrypt the table if there are vtpms to decrypt */
if(cipher_size > 0) {
int rbytes;
int overlap = 0;
uint8_t plain[BUF_SIZE + AES_BLOCK_SIZE];
uint8_t iv[AES_BLOCK_SIZE];
vtpmloginfo(VTPM_LOG_VTPM, "Decrypting uuid table\n");
/* Pre allocate the vtpm array */
g_store.num_vtpms_alloced = cipher_size / UUID_TBL_ENT_SIZE;
g_store.vtpms = malloc(sizeof(struct Vtpm) * g_store.num_vtpms_alloced);
/* Read the iv and the first chunk of cipher text */
rbytes = MIN(cipher_size, BUF_SIZE);
TRY_READ(buf, rbytes, "vtpm uuid table\n");
cipher_size -= rbytes;
/* Copy the iv */
memcpy(iv, buf, AES_BLOCK_SIZE);
ptr = buf + AES_BLOCK_SIZE;
/* Remove the iv from the number of bytes to decrypt */
rbytes -= AES_BLOCK_SIZE;
/* Decrypt and extract vtpms */
vtpm_decrypt_block(&aes,
iv, ptr, plain,
rbytes, &overlap);
/* Read the rest of the table if there is more */
while(cipher_size > 0) {
/* Read next chunk of cipher text */
rbytes = MIN(cipher_size, BUF_SIZE);
TRY_READ(buf, rbytes, "vtpm uuid table");
cipher_size -= rbytes;
/* Decrypt a block of text */
vtpm_decrypt_block(&aes,
iv, buf, plain,
rbytes, &overlap);
}
vtpmloginfo(VTPM_LOG_VTPM, "Loaded %d vtpms!\n", g_store.num_vtpms);
}
/* The end of the key table, new vtpms go here */
int uuid_end = (get_offset() + RSA_CIPHER_SIZE) & ~(RSA_CIPHER_SIZE -1);
g_store.end_offset = uuid_end;
/* Compute the end offset while validating vtpms*/
for(int i = 0; i < g_store.num_vtpms; ++i) {
/* offset must not collide with previous data */
if(g_store.vtpms[i].offset < uuid_end) {
vtpmlogerror(VTPM_LOG_VTPM, "vtpm: " UUID_FMT
" offset (%d) is before end of uuid table (%d)!\n",
UUID_BYTES(g_store.vtpms[i].uuid),
g_store.vtpms[i].offset, uuid_end);
status = TPM_IOERROR;
goto abort_egress;
}
/* offset must be at a multiple of cipher size */
if(g_store.vtpms[i].offset & (RSA_CIPHER_SIZE-1)) {
vtpmlogerror(VTPM_LOG_VTPM, "vtpm: " UUID_FMT
" offset(%d) is not at a multiple of the rsa cipher text size (%d)!\n",
UUID_BYTES(g_store.vtpms[i].uuid),
g_store.vtpms[i].offset, RSA_CIPHER_SIZE);
status = TPM_IOERROR;
goto abort_egress;
}
/* Save the last offset */
if(g_store.vtpms[i].offset >= g_store.end_offset) {
g_store.end_offset = g_store.vtpms[i].offset + RSA_CIPHER_SIZE;
}
}
goto egress;
abort_egress:
//An error occured somewhere
vtpmlogerror(VTPM_LOG_VTPM, "Failed to load manager data!\n");
//Clear the data store
reset_store();
//Reset the storage key structure
free_TPM_KEY(&vtpm_globals.storage_key);
{
TPM_KEY key = TPM_KEY_INIT;
vtpm_globals.storage_key = key;
}
//Reset the storage key handle
TPM_EvictKey(vtpm_globals.storage_key_handle);
vtpm_globals.storage_key_handle = 0;
egress:
return status;
}
#if 0
/* For testing disk IO */
void add_fake_vtpms(int num) {
for(int i = 0; i < num; ++i) {
uint32_t ind = cpu_to_be32(i);
uuid_t uuid;
memset(uuid, 0, sizeof(uuid_t));
memcpy(uuid, &ind, sizeof(ind));
int index = vtpm_get_index(uuid);
index = -index-1;
vtpm_storage_new_vtpm(uuid, index);
}
}
#endif