aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/misc/vtpm.txt41
-rw-r--r--stubdom/Makefile2
-rw-r--r--stubdom/grub/Makefile1
-rw-r--r--stubdom/grub/kexec.c54
-rw-r--r--stubdom/grub/minios.cfg1
5 files changed, 89 insertions, 10 deletions
diff --git a/docs/misc/vtpm.txt b/docs/misc/vtpm.txt
index c0a60542f9..b8979a3b93 100644
--- a/docs/misc/vtpm.txt
+++ b/docs/misc/vtpm.txt
@@ -1,7 +1,7 @@
Copyright (c) 2010-2012 United States Government, as represented by
the Secretary of Defense. All rights reserved.
November 12 2012
-Authors: Matthew Fioravante (JHUAPL),
+Authors: Matthew Fioravante (JHUAPL), Daniel De Graaf (NSA)
This document describes the virtual Trusted Platform Module (vTPM) subsystem
for Xen. The reader is assumed to have familiarity with building and installing
@@ -15,7 +15,8 @@ operating system (a DomU). This allows programs to interact with a TPM in a
virtual system the same way they interact with a TPM on the physical system.
Each guest gets its own unique, emulated, software TPM. However, each of the
vTPM's secrets (Keys, NVRAM, etc) are managed by a vTPM Manager domain, which
-seals the secrets to the Physical TPM. Thus, the vTPM subsystem extends the
+seals the secrets to the Physical TPM. If the process of creating each of these
+domains (manager, vTPM, and guest) is trusted, the vTPM subsystem extends the
chain of trust rooted in the hardware TPM to virtual machines in Xen. Each
major component of vTPM is implemented as a separate domain, providing secure
separation guaranteed by the hypervisor. The vTPM domains are implemented in
@@ -119,14 +120,17 @@ the stubdom tree.
Compiling the LINUX dom0 kernel:
--------------------------------
-The Linux dom0 kernel has no special prerequisites.
+The Linux dom0 kernel should not try accessing the TPM while the vTPM
+Manager domain is accessing it; the simplest way to accomplish this is
+to ensure the kernel is compiled without a driver for the TPM, or avoid
+loading the driver by blacklisting the module.
Compiling the LINUX domU kernel:
--------------------------------
-The domU kernel used by domains with vtpms must
-include the xen-tpmfront.ko driver. It can be built
-directly into the kernel or as a module.
+The domU kernel used by domains with vtpms must include the xen-tpmfront.ko
+driver. It can be built directly into the kernel or as a module; however, some
+features such as IMA require the TPM to be built in to the kernel.
CONFIG_TCG_TPM=y
CONFIG_TCG_XEN=y
@@ -160,9 +164,10 @@ disk=["file:/var/vtpmmgr-stubdom.img,hda,w"]
name="vtpmmgr"
iomem=["fed40,5"]
-The iomem line tells xl to allow access to the TPM
-IO memory pages, which are 5 pages that start at
-0xfed40000.
+The iomem line tells xl to allow access to all of the TPM IO memory
+pages, which are 5 pages (one per locality) that start at 0xfed40000. By
+default, the TPM manager uses locality 0 (so only the page at 0xfed40 is
+needed); this can be changed on the domain's command line.
Starting and stopping the manager:
----------------------------------
@@ -285,6 +290,24 @@ On guest:
You may wish to write a script to start your vtpm and guest together.
------------------------------
+INTEGRATION WITH PV-GRUB
+------------------------------
+
+The vTPM currently starts up with all PCRs set to their default values (all
+zeros for the lower 16). This means that any decisions about the
+trustworthiness of the created domain must be made based on the environment that
+created the vTPM and the domU; for example, a system that only constructs images
+using a trusted configuration and guest kernel be able to provide guarantees
+about the guests and any measurements done that kernel (such as the IMA TCB
+log). Guests wishing to use a custom kernel in such a secure environment are
+often started using the pv-grub bootloader as the kernel, which then can load
+the untrusted kernel without needing to parse an untrusted filesystem and kernel
+in dom0. If the pv-grub stub domain succeeds in connecting to a vTPM, it will
+extend the hash of the kernel that it boots into PCR #4, and will extend the
+command line and initrd into PCR #5 before booting so that a domU booted in this
+way can attest to its early boot state.
+
+------------------------------
MORE INFORMATION
------------------------------
diff --git a/stubdom/Makefile b/stubdom/Makefile
index b7143431d9..427e4d66e8 100644
--- a/stubdom/Makefile
+++ b/stubdom/Makefile
@@ -400,7 +400,7 @@ grub-upstream: grub-$(GRUB_VERSION).tar.gz
done
.PHONY: grub
-grub: grub-upstream $(CROSS_ROOT)
+grub: cross-polarssl grub-upstream $(CROSS_ROOT)
mkdir -p grub-$(XEN_TARGET_ARCH)
CPPFLAGS="$(TARGET_CPPFLAGS)" CFLAGS="$(TARGET_CFLAGS)" $(MAKE) DESTDIR= -C $@ OBJ_DIR=$(CURDIR)/grub-$(XEN_TARGET_ARCH)
diff --git a/stubdom/grub/Makefile b/stubdom/grub/Makefile
index d6e3a1e5b6..6bd2c4c9f1 100644
--- a/stubdom/grub/Makefile
+++ b/stubdom/grub/Makefile
@@ -60,6 +60,7 @@ NETBOOT_SOURCES:=$(addprefix netboot/,$(NETBOOT_SOURCES))
$(BOOT): DEF_CPPFLAGS+=-D__ASSEMBLY__
PV_GRUB_SOURCES = kexec.c mini-os.c
+PV_GRUB_SOURCES += ../polarssl-$(XEN_TARGET_ARCH)/library/sha1.o
SOURCES = $(NETBOOT_SOURCES) $(STAGE2_SOURCES) $(PV_GRUB_SOURCES)
diff --git a/stubdom/grub/kexec.c b/stubdom/grub/kexec.c
index b21c91ae99..cef357eff9 100644
--- a/stubdom/grub/kexec.c
+++ b/stubdom/grub/kexec.c
@@ -28,7 +28,9 @@
#include <blkfront.h>
#include <netfront.h>
#include <fbfront.h>
+#include <tpmfront.h>
#include <shared.h>
+#include <byteswap.h>
#include "mini-os.h"
@@ -54,6 +56,22 @@ static unsigned long allocated;
int pin_table(xc_interface *xc_handle, unsigned int type, unsigned long mfn,
domid_t dom);
+#define TPM_TAG_RQU_COMMAND 0xC1
+#define TPM_ORD_Extend 20
+
+struct pcr_extend_cmd {
+ uint16_t tag;
+ uint32_t size;
+ uint32_t ord;
+
+ uint32_t pcr;
+ unsigned char hash[20];
+} __attribute__((packed));
+
+/* Not imported from polarssl's header since the prototype unhelpfully defines
+ * the input as unsigned char, which causes pointer type mismatches */
+void sha1(const void *input, size_t ilen, unsigned char output[20]);
+
/* We need mfn to appear as target_pfn, so exchange with the MFN there */
static void do_exchange(struct xc_dom_image *dom, xen_pfn_t target_pfn, xen_pfn_t source_mfn)
{
@@ -117,6 +135,40 @@ int kexec_allocate(struct xc_dom_image *dom, xen_vaddr_t up_to)
return 0;
}
+static void tpm_hash2pcr(struct xc_dom_image *dom, char *cmdline)
+{
+ struct tpmfront_dev* tpm = init_tpmfront(NULL);
+ uint8_t *resp;
+ size_t resplen = 0;
+ struct pcr_extend_cmd cmd;
+
+ /* If all guests have access to a vTPM, it may be useful to replace this
+ * with ASSERT(tpm) to prevent configuration errors from allowing a guest
+ * to boot without a TPM (or with a TPM that has not been sent any
+ * measurements, which could allow forging the measurements).
+ */
+ if (!tpm)
+ return;
+
+ cmd.tag = bswap_16(TPM_TAG_RQU_COMMAND);
+ cmd.size = bswap_32(sizeof(cmd));
+ cmd.ord = bswap_32(TPM_ORD_Extend);
+ cmd.pcr = bswap_32(4); // PCR #4 for kernel
+ sha1(dom->kernel_blob, dom->kernel_size, cmd.hash);
+
+ tpmfront_cmd(tpm, (void*)&cmd, sizeof(cmd), &resp, &resplen);
+
+ cmd.pcr = bswap_32(5); // PCR #5 for cmdline
+ sha1(cmdline, strlen(cmdline), cmd.hash);
+ tpmfront_cmd(tpm, (void*)&cmd, sizeof(cmd), &resp, &resplen);
+
+ cmd.pcr = bswap_32(5); // PCR #5 for initrd
+ sha1(dom->ramdisk_blob, dom->ramdisk_size, cmd.hash);
+ tpmfront_cmd(tpm, (void*)&cmd, sizeof(cmd), &resp, &resplen);
+
+ shutdown_tpmfront(tpm);
+}
+
void kexec(void *kernel, long kernel_size, void *module, long module_size, char *cmdline, unsigned long flags)
{
struct xc_dom_image *dom;
@@ -151,6 +203,8 @@ void kexec(void *kernel, long kernel_size, void *module, long module_size, char
dom->console_evtchn = start_info.console.domU.evtchn;
dom->xenstore_evtchn = start_info.store_evtchn;
+ tpm_hash2pcr(dom, cmdline);
+
if ( (rc = xc_dom_boot_xen_init(dom, xc_handle, domid)) != 0 ) {
grub_printf("xc_dom_boot_xen_init returned %d\n", rc);
errnum = ERR_BOOT_FAILURE;
diff --git a/stubdom/grub/minios.cfg b/stubdom/grub/minios.cfg
index 40cfa68e87..8df49092cd 100644
--- a/stubdom/grub/minios.cfg
+++ b/stubdom/grub/minios.cfg
@@ -1,2 +1,3 @@
CONFIG_START_NETWORK=n
CONFIG_SPARSE_BSS=n
+CONFIG_TPMFRONT=y