Files
xen/stubdom/vtpm/vtpmblk.c
T
Olaf Hering 55ab292c42 stubdom/vtpm: include stdio.h for declaration of printf
The function read_vtpmblk uses printf(3), but stdio.h is not included
in this file. This results in a warning from gcc-7:

vtpmblk.c: In function 'read_vtpmblk':
vtpmblk.c:322:7: warning: implicit declaration of function 'printf' [-Wimplicit-function-declaration]
       printf("Expected: ");
vtpmblk.c:322:7: warning: incompatible implicit declaration of built-in function 'printf'
vtpmblk.c:322:7: note: include '<stdio.h>' or provide a declaration of 'printf'

Signed-off-by: Olaf Hering <olaf@aepfle.de>
Acked-by: Daniel De Graaf <dgdegra@tycho.nsa.gov>
Reviewed-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
Release-acked-by: Juergen Gross <jgross@suse.com>
2019-10-14 14:42:37 +01:00

355 lines
9.1 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.
*/
#include <mini-os/byteorder.h>
#include "vtpmblk.h"
#include "tpm/tpm_marshalling.h"
#include "vtpm_cmd.h"
#include "polarssl/aes.h"
#include "polarssl/sha1.h"
#include <blkfront.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
/*Encryption key and block sizes */
#define BLKSZ 16
static struct blkfront_dev* blkdev = NULL;
static int blkfront_fd = -1;
static uint64_t slot_size = 0;
int init_vtpmblk(struct tpmfront_dev* tpmfront_dev)
{
struct blkfront_info blkinfo;
info("Initializing persistent NVM storage\n");
if((blkdev = init_blkfront(NULL, &blkinfo)) == NULL) {
error("BLKIO: ERROR Unable to initialize blkfront");
return -1;
}
if (blkinfo.info & VDISK_READONLY || blkinfo.mode != O_RDWR) {
error("BLKIO: ERROR block device is read only!");
goto error;
}
if((blkfront_fd = blkfront_open(blkdev)) == -1) {
error("Unable to open blkfront file descriptor!");
goto error;
}
slot_size = blkinfo.sectors * blkinfo.sector_size / 2;
return 0;
error:
shutdown_blkfront(blkdev);
blkdev = NULL;
return -1;
}
void shutdown_vtpmblk(void)
{
close(blkfront_fd);
blkfront_fd = -1;
blkdev = NULL;
}
static int write_vtpmblk_raw(uint8_t *data, size_t data_length, int slot)
{
int rc;
uint32_t lenbuf;
debug("Begin Write data=%p len=%u slot=%u ssize=%u", data, data_length, slot, slot_size);
if (data_length > slot_size - 4) {
error("vtpm data cannot fit in data slot (%d/%d).", data_length, slot_size - 4);
return -1;
}
lenbuf = cpu_to_be32((uint32_t)data_length);
lseek(blkfront_fd, slot * slot_size, SEEK_SET);
if((rc = write(blkfront_fd, (uint8_t*)&lenbuf, 4)) != 4) {
error("write(length) failed! error was %s", strerror(errno));
return -1;
}
if((rc = write(blkfront_fd, data, data_length)) != data_length) {
error("write(data) failed! error was %s", strerror(errno));
return -1;
}
info("Wrote %u bytes to NVM persistent storage", data_length);
return 0;
}
static int read_vtpmblk_raw(uint8_t **data, size_t *data_length, int slot)
{
int rc;
uint32_t lenbuf;
lseek(blkfront_fd, slot * slot_size, SEEK_SET);
if(( rc = read(blkfront_fd, (uint8_t*)&lenbuf, 4)) != 4) {
error("read(length) failed! error was %s", strerror(errno));
return -1;
}
*data_length = (size_t) cpu_to_be32(lenbuf);
if(*data_length == 0) {
error("read 0 data_length for NVM");
return -1;
}
if(*data_length > slot_size - 4) {
error("read invalid data_length for NVM");
return -1;
}
*data = tpm_malloc(*data_length);
if((rc = read(blkfront_fd, *data, *data_length)) != *data_length) {
error("read(data) failed! error was %s", strerror(errno));
return -1;
}
info("Read %u bytes from NVM persistent storage (slot %d)", *data_length, slot);
return 0;
}
int encrypt_vtpmblk(uint8_t* clear, size_t clear_len, uint8_t** cipher, size_t* cipher_len, uint8_t* symkey)
{
int rc = 0;
uint8_t iv[BLKSZ];
aes_context aes_ctx;
UINT32 temp;
int mod;
uint8_t* clbuf = NULL;
uint8_t* ivptr;
int ivlen;
uint8_t* cptr; //Cipher block pointer
int clen; //Cipher block length
/*Create a new 256 bit encryption key */
if(symkey == NULL) {
rc = -1;
goto abort_egress;
}
tpm_get_extern_random_bytes(symkey, NVMKEYSZ);
/*Setup initialization vector - random bits and then 4 bytes clear text size at the end*/
temp = sizeof(UINT32);
ivlen = BLKSZ - temp;
tpm_get_extern_random_bytes(iv, ivlen);
ivptr = iv + ivlen;
tpm_marshal_UINT32(&ivptr, &temp, (UINT32) clear_len);
/*The clear text needs to be padded out to a multiple of BLKSZ */
mod = clear_len % BLKSZ;
clen = mod ? clear_len + BLKSZ - mod : clear_len;
clbuf = malloc(clen);
if (clbuf == NULL) {
rc = -1;
goto abort_egress;
}
memcpy(clbuf, clear, clear_len);
/* zero out the padding bits - FIXME: better / more secure way to handle these? */
if(clen - clear_len) {
memset(clbuf + clear_len, 0, clen - clear_len);
}
/* Setup the ciphertext buffer */
*cipher_len = BLKSZ + clen; /*iv + ciphertext */
cptr = *cipher = malloc(*cipher_len);
if (*cipher == NULL) {
rc = -1;
goto abort_egress;
}
/* Copy the IV to cipher text blob*/
memcpy(cptr, iv, BLKSZ);
cptr += BLKSZ;
/* Setup encryption */
aes_setkey_enc(&aes_ctx, symkey, 256);
/* Do encryption now */
aes_crypt_cbc(&aes_ctx, AES_ENCRYPT, clen, iv, clbuf, cptr);
goto egress;
abort_egress:
egress:
free(clbuf);
return rc;
}
int decrypt_vtpmblk(uint8_t* cipher, size_t cipher_len, uint8_t** clear, size_t* clear_len, uint8_t* symkey)
{
int rc = 0;
uint8_t iv[BLKSZ];
uint8_t* ivptr;
UINT32 u32, temp;
aes_context aes_ctx;
uint8_t* cptr = cipher; //cipher block pointer
int clen = cipher_len; //cipher block length
/* Pull out the initialization vector */
memcpy(iv, cipher, BLKSZ);
cptr += BLKSZ;
clen -= BLKSZ;
/* Setup the clear text buffer */
if((*clear = malloc(clen)) == NULL) {
rc = -1;
goto abort_egress;
}
/* Get the length of clear text from last 4 bytes of iv */
temp = sizeof(UINT32);
ivptr = iv + BLKSZ - temp;
tpm_unmarshal_UINT32(&ivptr, &temp, &u32);
*clear_len = u32;
/* Setup decryption */
aes_setkey_dec(&aes_ctx, symkey, 256);
/* Do decryption now */
if ((clen % BLKSZ) != 0) {
error("Decryption Error: Cipher block size was not a multiple of %u", BLKSZ);
rc = -1;
goto abort_egress;
}
aes_crypt_cbc(&aes_ctx, AES_DECRYPT, clen, iv, cptr, *clear);
goto egress;
abort_egress:
egress:
return rc;
}
/* Current active state slot, or -1 if no valid saved state exists */
static int active_slot = -1;
int write_vtpmblk(struct tpmfront_dev* tpmfront_dev, uint8_t* data, size_t data_length) {
int rc;
uint8_t* cipher = NULL;
size_t cipher_len = 0;
uint8_t hashkey[HASHKEYSZ];
uint8_t* symkey = hashkey + HASHSZ;
/* Switch to the other slot. Note that in a new vTPM, the read will not
* succeed, so active_slot will be -1 and we will write to slot 0.
*/
active_slot = !active_slot;
/* Encrypt the data */
if((rc = encrypt_vtpmblk(data, data_length, &cipher, &cipher_len, symkey))) {
goto abort_egress;
}
/* Write to disk */
if((rc = write_vtpmblk_raw(cipher, cipher_len, active_slot))) {
goto abort_egress;
}
/* Get sha1 hash of data */
sha1(cipher, cipher_len, hashkey);
/* Send hash and key to manager */
if((rc = VTPM_SaveHashKey(tpmfront_dev, hashkey, HASHKEYSZ)) != TPM_SUCCESS) {
goto abort_egress;
}
goto egress;
abort_egress:
egress:
free(cipher);
return rc;
}
int read_vtpmblk(struct tpmfront_dev* tpmfront_dev, uint8_t** data, size_t *data_length) {
int rc;
uint8_t* cipher = NULL;
size_t cipher_len = 0;
size_t keysize;
uint8_t* hashkey = NULL;
uint8_t hash0[HASHSZ];
uint8_t hash1[HASHSZ];
uint8_t* symkey;
/* Retreive the hash and the key from the manager */
if((rc = VTPM_LoadHashKey(tpmfront_dev, &hashkey, &keysize)) != TPM_SUCCESS) {
goto abort_egress;
}
if(keysize != HASHKEYSZ) {
error("Manager returned a hashkey of invalid size! expected %d, actual %d", NVMKEYSZ, keysize);
rc = -1;
goto abort_egress;
}
symkey = hashkey + HASHSZ;
active_slot = 0;
debug("Reading slot 0 from disk\n");
if((rc = read_vtpmblk_raw(&cipher, &cipher_len, 0))) {
goto abort_egress;
}
/* Compute the hash of the cipher text and compare */
sha1(cipher, cipher_len, hash0);
if(!memcmp(hash0, hashkey, HASHSZ))
goto valid;
free(cipher);
cipher = NULL;
active_slot = 1;
debug("Reading slot 1 from disk (offset=%u)\n", slot_size);
if((rc = read_vtpmblk_raw(&cipher, &cipher_len, 1))) {
goto abort_egress;
}
/* Compute the hash of the cipher text and compare */
sha1(cipher, cipher_len, hash1);
if(!memcmp(hash1, hashkey, HASHSZ))
goto valid;
{
int i;
error("NVM Storage Checksum failed!");
printf("Expected: ");
for(i = 0; i < HASHSZ; ++i) {
printf("%02hhX ", hashkey[i]);
}
printf("\n");
printf("Slot 0: ");
for(i = 0; i < HASHSZ; ++i) {
printf("%02hhX ", hash0[i]);
}
printf("\n");
printf("Slot 1: ");
for(i = 0; i < HASHSZ; ++i) {
printf("%02hhX ", hash1[i]);
}
printf("\n");
rc = -1;
goto abort_egress;
}
valid:
/* Decrypt the blob */
if((rc = decrypt_vtpmblk(cipher, cipher_len, data, data_length, symkey))) {
goto abort_egress;
}
goto egress;
abort_egress:
active_slot = -1;
egress:
free(cipher);
free(hashkey);
return rc;
}