Virtual Machine with vTPM in Ubuntu

Preparation

SeaBIOS

SeaBIOS 包含 vTPM 支持的分支 seabios-tpm 最开始由 Stefan 维护,现在已经成功将其合并到主分支 SeaBIOS。因此,下面的实验中我们使用其主分支。

  1. 下载
1
2
3
4
$ mkdir workspace
$ cd workspace
$ git clone https://git.seabios.org/seabios.git
$ cd seabios
  1. 编译
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
$ sudo apt install python2
$ make
Building ld scripts
Version: rel-1.13.0-5-g7655185
Fixed space: 0xe05b-0x10000  total: 8101  slack: 11  Percent slack: 0.1%
16bit size:           37920
32bit segmented size: 2194
32bit flat size:      39854
32bit flat init size: 83168
Lowmem size:          2240
f-segment var size:   1248
  Linking out/rom16.o
  Stripping out/rom16.strip.o
  Linking out/rom32seg.o
  Stripping out/rom32seg.strip.o
  Linking out/rom.o
  Prepping out/bios.bin.prep
Total size: 172352  Fixed: 81216  Free: 89792 (used 65.7% of 256KiB rom)
  Creating out/bios.bin

libtpms

libtpms 是对 TCG(Trusted Computing Group) 发布的可信平台模块(TPM,Trusted Platform Module)标准 TPM1.2 Main SpecificationTPM 2.0 Library SpecificationTPM2.0 Specifications in Public Review 的软件模拟库,在 Linux 上以 「shared object (dynamic) library」 的形式存在,即:

1
2
3
4
kip@ubu:/usr/lib/x86_64-linux-gnu $ ls -hl | grep libtpms
lrwxrwxrwx  1 root root    16 Jul 20  2019 libtpms.so - libtpms.so.0.8.0
lrwxrwxrwx  1 root root    16 Jul 20  2019 libtpms.so.0 - libtpms.so.0.8.0
-rw-r--r--  1 root root  883K Jul 20  2019 libtpms.so.0.8.0
  1. 安装依赖
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
$ git clone https://github.com/stefanberger/libtpms.git
$ cd libtpms
$ sudo apt-get -y install automake autoconf libtool gcc build-essential \
libssl-dev dh-exec pkg-config gawk
$ ./autogen.sh --with-openssl --with-tpm2
<snip>
CFLAGS=-g -O2 -DUSE_OPENSSL_FUNCTIONS_SYMMETRIC=1 -DUSE_OPENSSL_FUNCTIONS_EC=1 -DUSE_OPENSSL_FUNCTIONS_ECDSA=1 -DUSE_OPENSSL_FUNCTIONS_RSA=1  -Wall -Werror -Wreturn-type -Wsign-compare -Wno-self-assign
HARDENING_CFLAGS=-fstack-protector-strong 
HARDENING_LDFLAGS= -Wl,-z,relro  -Wl,-z,now 
LDFLAGS= 

Version to build        : 0.8.0
Crypto library          : openssl
Debug build             : no
With TPM2 support       : yes
HAVE_VERSION_SCRIPT     : yes
Use openssl crypto for  : symmetric (AES, TDES) general elliptic curve (EC) elliptic curve (ECDSA) RSA
  1. 生成安装包
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
$ make dist
$ dpkg-buildpackage -us -uc -j$(nproc)
<snip
make[3]: Leaving directory '/home/kip/workspace/libtpms/tests'
make  check-TESTS
make[3]: Entering directory '/home/kip/workspace/libtpms/tests'
make[4]: Entering directory '/home/kip/workspace/libtpms/tests'
PASS: nvram_offsets
PASS: tpm2_createprimary.sh
PASS: tpm2_pcr_read.sh
PASS: tpm2_selftest.sh
PASS: base64decode.sh
PASS: fuzz.sh
============================================================================
Testsuite summary for libtpms 0.8.0
============================================================================
# TOTAL: 6
# PASS:  6
# SKIP:  0
# XFAIL: 0
# FAIL:  0
# XPASS: 0
# ERROR: 0
============================================================================
<snip>

执行完上述命令,可以看到生成了 .deb 安装包:

1
2
$ cd .. && ls
libtpms0_0.8.0~dev1_amd64.deb  libtpms-dev_0.8.0~dev1_amd64.deb  libtpms_0.8.0~dev1.tar.xz  ...
  1. 安装 libtpms
1
$ sudo dpkg -i libtpms0_0.8.0~dev1_amd64.deb   libtpms-dev_0.8.0~dev1_amd64.deb

swtpm

swtpm 基于 libtpms 以不同的方式实现对 TPM 的模拟,包括:「passthrough」、「character device」、「socket」和「CUSE」。

因此,安装 swtpm 之前,必须先安装 libtpms。

  1. 安装依赖
1
2
3
4
5
6
7
$ git clone https://github.com/stefanberger/swtpm.git
$ cd swtpm
$ sudo su
# ln -s /dev/null /etc/systemd/system/trousers.service
# exit
$ sudo apt-get -y install  libfuse-dev libglib2.0-dev libgmp-dev expect libtasn1-dev socat \
tpm-tools python3-twisted gnutls-dev gnutls-bin softhsm2 libseccomp-dev

Note: trousers 是 TPM1.2 的依赖软件,tpm-tools 是 TPM2.0 的依赖软件,Ubuntu 默认安装 tpm-tools 必须先安装 trousers。如果你不需要模拟 TPM1.2,这便不是必须的。Stefan 提了 report,不过社区并没有回应。

  1. 生成安装包
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
$ dpkg-buildpackage -us -uc -j$(nproc)
<snip>
make  check-TESTS
make[4]: Entering directory '/home/kip/workspace/swtpm/tests'
make[5]: Entering directory '/home/kip/workspace/swtpm/tests'
SKIP: test_tpm2_vtpm_proxy
SKIP: test_vtpm_proxy
PASS: test_ctrlchannel4
PASS: test_ctrlchannel3
PASS: test_tpm2_ctrlchannel2
PASS: test_ctrlchannel2
PASS: test_ctrlchannel
PASS: test_getcap
PASS: test_hashing
PASS: test_locality
PASS: test_encrypted_state
PASS: test_hashing2
PASS: test_resume_volatile
PASS: test_migration_key
PASS: test_setbuffersize
PASS: test_save_load_state
PASS: test_save_load_encrypted_state
PASS: test_init
SKIP: test_tpm12
PASS: test_volatilestate
PASS: test_print_capabilities
PASS: test_tpm_probe
PASS: test_wrongorder
PASS: test_tpm2_derived_keys
PASS: test_tpm2_encrypted_state
PASS: test_tpm2_getcap
PASS: test_tpm2_locality
PASS: test_swtpm_bios
PASS: test_tpm2_hashing
PASS: test_tpm2_hashing3
PASS: test_tpm2_resume_volatile
PASS: test_tpm2_migration_key
PASS: test_tpm2_hashing2
SKIP: test_tpm2_save_load_state_3
PASS: test_tpm2_savestate
PASS: test_tpm2_init
PASS: test_tpm2_setbuffersize
PASS: test_tpm2_wrongorder
PASS: test_tpm2_volatilestate
PASS: test_tpm2_probe
SKIP: test_tpm2_ibmtss2
PASS: test_commandline
SKIP: test_parameters
PASS: test_swtpm_cert
SKIP: test_tpm2_parameters
PASS: test_tpm2_samples_swtpm_localca
SKIP: test_tpm2_samples_swtpm_localca_pkcs11
PASS: test_tpm2_swtpm_cert
PASS: test_tpm2_swtpm_cert_ecc
PASS: test_tpm2_swtpm_setup_create_cert
SKIP: test_swtpm_setup_create_cert
SKIP: test_samples_create_tpmca
PASS: test_tpm2_save_load_encrypted_state
PASS: test_tpm2_swtpm_bios
PASS: test_tpm2_save_load_state_da_timeout
============================================================================
Testsuite summary for swtpm 0.3.0
============================================================================
# TOTAL: 55
# PASS:  45
# SKIP:  10
# XFAIL: 0
# FAIL:  0
# XPASS: 0
# ERROR: 0
============================================================================
<snip>

同样,可以看到生成了几个 .deb 安装包

1
2
$ cd .. && ls
swtpm_0.3.0-1_amd64.deb  swtpm-dev_0.3.0-1_amd64.deb  swtpm-libs_0.3.0-1_amd64.deb  swtpm-tools_0.3.0-1_amd64.deb  ...
  1. 安装
1
2
$ sudo dpkg -i swtpm_0.3.0-1_amd64.deb swtpm-dev_0.3.0-1_amd64.deb swtpm-libs_0.3.0-1_amd64.deb \
swtpm-tools_0.3.0-1_amd64.deb

qemu-tpm

  1. 下载并配置
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
$ git clone https://github.com/stefanberger/qemu-tpm.git
$ cd qemu-tpm
$ mkdir build
$ cd build
$ ../configure --enable-debug --enable-tpm --enable-kvm --enable-vnc --target-list=x86_64-softmmu
<snip>
TCG support       yes
TCG debug enabled yes
TCG interpreter   no
<snip
  1. 编译
1
2
3
4
5
6
7
8
$ make -j$(nproc)
<snip
  GEN     trace/generated-helpers.c
  CC      x86_64-softmmu/trace/control-target.o
  CC      x86_64-softmmu/gdbstub-xml.o
  CC      x86_64-softmmu/trace/generated-helpers.o
  LINK    x86_64-softmmu/qemu-system-x86_64
rm tests/qemu-iotests/socket_scm_helper.o
  1. 安装
1
2
$ sudo su
# make install

Create VM with vTPM

上面我们完成了试验环境的安装,下面我们开始创建可信虚拟机,即具备 vTPM 设备的虚拟机。

Note: 为了避免破坏 Host 主机上的实验环境,我这里没有执行 qemu-tpm 的安装操作,而是直接使用源路径下的可执行文件。

下面我们以 socket 的模拟方式举例说明。

vTPM Emulator

  1. 安装 VNC-Viewer
1
$ sudo apt install tigervnc-viewer
  1. 生成磁盘镜像
1
2
3
4
$ mkdir ~/workspace/test
$ cd ~/workspace/test
$ ../qemu-tpm/build/qemu-img create -f qcow2 ubuntu14.04.qcow2 20G
Formatting 'ubuntu14.04.qcow2', fmt=qcow2 size=21474836480 cluster_size=65536 lazy_refcounts=off refcount_bits=16
  1. 在 Host 创建 vTPM 模拟设备

新开一个终端:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
$ sudo mkdir /tmp/mytpm2
$ sudo chown tss:root /tmp/mytpm2
$ sudo swtpm_setup --tpmstate /tmp/mytpm2 \
--create-ek-cert \
--create-platform-cert \
--allow-signing --tpm2
$ sudo swtpm socket --tpmstate dir=/tmp/mytpm2 \
--ctrl type=unixio,path=/tmp/mytpm2/swtpm-sock \
--tpm2 \
--log level=20

Guest OS

  1. 安装操作系统

事先已将 Ubuntu 14.04 的镜像下载到了路径 ~/Downloads 下。

安装:

1
2
3
4
5
6
7
8
9
~/workspace/test $ sudo ../qemu-tpm/build/x86_64-softmmu/qemu-system-x86_64 \
-accel kvm -m 2048 -smp 4 -hda ubuntu14.04.qcow2 \
-boot menu=on -bios ../seabios/out/bios.bin \
-device tpm-tis,tpmdev=tpm0 \
-tpmdev emulator,id=tpm0,chardev=chrtpm \
-chardev socket,id=chrtpm,path=/tmp/mytpm2/swtpm-sock \
-d unimp \
-cdrom ~/Downloads/ubuntu-14.04.6-desktop-amd64.iso
VNC server running on 127.0.0.1:5900

再新开一个终端:

1
$ vncviewer :5900

然后会跳出操作系统的安装界面,将 Ubuntu 14.04 按照正常步骤安装即可。

当安装完成,提示重启时,直接关闭 VNCViewer 窗口即可。

  1. 测试

重新启动模拟设备:

1
2
3
4
$ sudo swtpm socket --tpmstate dir=/tmp/mytpm2 \
--ctrl type=unixio,path=/tmp/mytpm2/swtpm-sock \
--tpm2 \
--log level=20

重新运行虚拟机:

1
2
3
4
5
6
7
8
~/workspace/test $ sudo ../qemu-tpm/build/x86_64-softmmu/qemu-system-x86_64 \
-accel kvm -m 2048 -smp 4 -hda ubuntu14.04.qcow2 \
-boot menu=on -bios ../seabios/out/bios.bin \
-device tpm-tis,tpmdev=tpm0 \
-tpmdev emulator,id=tpm0,chardev=chrtpm \
-chardev socket,id=chrtpm,path=/tmp/mytpm2/swtpm-sock \
-d unimp
VNC server running on 127.0.0.1:5900

再次打开 VNC-Viewer:

1
$ vncviewer :5900

测试:

ubuntu14.04

Summary

综上,我们成功创建了一个具备 vTPM 模拟设备的可信虚拟机。

和 TPM 设备交互,需要安装可信软件栈(TSS, TPM Software Stack)。

可以通过下载 tpm2-software/tpm2-tss 编译安装,或者直接安装 IBM 维护的命令行工具 tss2:

1
$ sudo apt install tss2

不过 Ubuntu 14.04 并不支持 tss2, 可以在 Ubuntu 16.04 上尝试。

© 2019 - 2021 · Kip Jiang · Theme Simpleness Powered by Hugo ·