From 0731b2a8aabfd9a3581aa020b4b6654071913e53 Mon Sep 17 00:00:00 2001 From: Dmitrii Kuvaiskii Date: Fri, 3 Mar 2023 06:12:01 -0800 Subject: [PATCH 1/2] Add swtpm example Signed-off-by: Dmitrii Kuvaiskii --- swtpm/Makefile | 62 ++++++++++++++++++ swtpm/README.md | 114 ++++++++++++++++++++++++++++++++++ swtpm/myvtpm2/.dummy | 0 swtpm/swtpm.manifest.template | 45 ++++++++++++++ 4 files changed, 221 insertions(+) create mode 100644 swtpm/Makefile create mode 100644 swtpm/README.md create mode 100644 swtpm/myvtpm2/.dummy create mode 100644 swtpm/swtpm.manifest.template diff --git a/swtpm/Makefile b/swtpm/Makefile new file mode 100644 index 0000000..73ea4ca --- /dev/null +++ b/swtpm/Makefile @@ -0,0 +1,62 @@ +ARCH_LIBDIR ?= /lib/$(shell $(CC) -dumpmachine) + +ifeq ($(DEBUG),1) +GRAMINE_LOG_LEVEL = all +else +GRAMINE_LOG_LEVEL = error +endif + +ifeq ($(SGX),1) +GRAMINE_ENCRYPTION_KEY = "_sgx_mrenclave" +else +GRAMINE_ENCRYPTION_KEY = "direct" +endif + +.PHONY: all +all: swtpm.manifest +ifeq ($(SGX),1) +all: swtpm.manifest.sgx swtpm.sig +endif + +swtpm.manifest: swtpm.manifest.template + gramine-manifest \ + -Dlog_level=$(GRAMINE_LOG_LEVEL) \ + -Dencryption_key=$(GRAMINE_ENCRYPTION_KEY) \ + -Darch_libdir=$(ARCH_LIBDIR) \ + -Dentrypoint=$(realpath $(shell sh -c "command -v swtpm")) \ + $< $@ + +# gramine-sgx-sign generates both a .sig file and a .manifest.sgx file. This is somewhat +# hard to express properly in Make. The simple solution would be to use +# "Rules with Grouped Targets" (`&:`), however make on Ubuntu <= 20.04 doesn't support it. +# +# Simply using a normal rule with "two targets" is equivalent to creating separate rules +# for each of the targets, and when using `make -j`, this might cause two instances +# of gramine-sgx-sign to get launched simultaneously, potentially breaking the build. +# +# As a workaround, we use a dummy intermediate target, and mark both files as depending on it, to +# get the dependency graph we want. We mark this dummy target as .INTERMEDIATE, which means +# that make will consider the source tree up-to-date even if the sgx_sign file doesn't exist, +# as long as the other dependencies check out. This is in contrast to .PHONY, which would +# be rebuilt on every invocation of make. +swtpm.sig swtpm.manifest.sgx: sgx_sign + @: + +.INTERMEDIATE: sgx_sign +sgx_sign: swtpm.manifest + gramine-sgx-sign \ + --manifest $< \ + --output $<.sgx + +ifeq ($(SGX),) +GRAMINE = gramine-direct +else +GRAMINE = gramine-sgx +endif + +.PHONY: clean +clean: + $(RM) *.token *.sig *.manifest.sgx *.manifest myvtpm2/.lock myvtpm2/*.permall + +.PHONY: distclean +distclean: clean diff --git a/swtpm/README.md b/swtpm/README.md new file mode 100644 index 0000000..4e7c301 --- /dev/null +++ b/swtpm/README.md @@ -0,0 +1,114 @@ +# swtpm + +This directory contains a Makefile and a manifest template for running swtpm. +See https://github.com/stefanberger/swtpm/. + +**NOTE**: Currently works only with PR https://github.com/gramineproject/gramine/pull/1210. +See also https://github.com/stefanberger/swtpm/issues/792. + +## Installing + +1. Install `libtpms` like this: + https://github.com/stefanberger/libtpms/wiki#build-a-package-on-ubuntu + - Version used: `git checkout v0.9.6` + +2. Install `swtpm` like this: https://github.com/stefanberger/swtpm/wiki#compile-on-ubuntu-2104 + - Don't install `libtpms-dev` since we've done it already in step 1 + - Version used: `git checkout v0.8.0` + +Now swtpm tools are installed. We run only `swtpm` executable with Gramine. + +## Configuration of `swtpm` + +`swtpm` executable can be run in several modes. We hard-code the following configuration +(command-line options) to run with Gramine: +```sh +$ swtpm socket --tpm2 --tpmstate dir=/myvtpm2 --seccomp action=none \ + --server type=tcp,port=2321,disconnect --ctrl type=tcp,port=2320 \ + --flags not-need-init,startup-clear +``` + +This configuration means: +- run `swtpm` in TPM2 mode, +- save all TPM state under `/myvtpm2/` dir (encrypted under Gramine with SGX), +- don't use seccomp (Gramine doesn't support it, and it's not needed in Gramine env anyway), +- listen for client connections on TCP/IP port 2321 (in contrast to CUSE or chardev), +- create a control channel on TCP/IP port 2320, +- additional flags for the initial state of TPM. + +For more information, see `man swtpm`. + +## Building + +- `make clean; make` for Gramine without SGX (`gramine-direct`). +- `make clean; make SGX=1` for Gramine with SGX (`gramine-sgx`). + +You can add `DEBUG=1` for verbose Gramine logs. + +Notice that `gramine-direct` uses a dummy encryption key for TPM files, hard-coded in the manifest. +Whereas `gramine-sgx` uses the MRENCLAVE-based sealing encryption key for TPM files (and is +therefore secure). To make sure the correct key is used, we require a `make clean` step. For details +on how the key is chosen, see Makefile and manifest template. + +## Quick tests of swtpm with Gramine + +### 1. Self-test + +The test idea is taken from https://github.com/stefanberger/swtpm/wiki/Useful-scripts-for-TPM, +Section "Trigger a self-test on a TPM 2 listening on command port 2321 with the disconnect flag". + +```sh +# swtpm server in one window +gramine-sgx swtpm + +# client script in another window +bash -c "exec 100<>/dev/tcp/localhost/2321; \ + echo -en '\x80\x01\x00\x00\x00\x0b\x00\x00\x01\x43\x01' >&100; \ + od -tx1 <&100" + +## output must be like this: +## 0000000 80 01 00 00 00 0a 00 00 00 00 +``` + +### 2. Hashing in PCR 17 + +The test idea is taken from the unit test: +https://github.com/stefanberger/swtpm/blob/346b3d62/tests/_test_tpm2_hashing. + +```sh +# swtpm server in one window +gramine-sgx swtpm + +# client scripts in another window + +## 1 step: init TPM to known state +swtpm_ioctl --tcp localhost:2320 -i + +## 2 step: startup TPM2 +bash -c "exec 100<>/dev/tcp/localhost/2321; \ + echo -en '\x80\x01\x00\x00\x00\x0c\x00\x00\x01\x44\x00\x00' >&100; \ + od -tx1 <&100" + +## output must be like this: +## 0000000 80 01 00 00 00 0a 00 00 00 00 + +## 3 step: ask TPM to hash string "1234" in PCR 17 +swtpm_ioctl --tcp localhost:2320 -h 1234 + +## 4 step: read PCR 17 +bash -c "exec 100<>/dev/tcp/localhost/2321; \ + echo -en '\x80\x01\x00\x00\x00\x14\x00\x00\x01\x7e\x00\x00\x00\x01\x00\x0b\x03\x00\x00\x02' >&100; \ + od -tx1 <&100" + +## output must be like this: +## 0000000 80 01 00 00 00 3e 00 00 00 00 00 00 00 2c 00 00 +## 0000020 00 01 00 0b 03 00 00 02 00 00 00 01 00 20 fc a5 +## 0000040 d6 49 bf b0 c9 22 fd 33 0f 79 b2 00 43 28 9d af +## 0000060 d6 0d 01 a4 c4 37 3c f2 8a db 56 c9 b4 54 + +## 5 step: check TPM Established flag (must be 1) +swtpm_ioctl --tcp localhost:2320 -e + +## 6 step: shutdown TPM +swtpm_ioctl --tcp localhost:2320 -s +``` diff --git a/swtpm/myvtpm2/.dummy b/swtpm/myvtpm2/.dummy new file mode 100644 index 0000000..e69de29 diff --git a/swtpm/swtpm.manifest.template b/swtpm/swtpm.manifest.template new file mode 100644 index 0000000..54367ee --- /dev/null +++ b/swtpm/swtpm.manifest.template @@ -0,0 +1,45 @@ +# swtpm (TPM emulator) manifest file example + +loader.entrypoint = "file:{{ gramine.libos }}" +libos.entrypoint = "{{ entrypoint }}" +loader.log_level = "{{ log_level }}" + +loader.env.LD_LIBRARY_PATH = "/lib:{{ arch_libdir }}:/usr/{{ arch_libdir }}" + +loader.argv = [ + "swtpm", "socket", "--tpm2", + "--tpmstate", "dir=/myvtpm2", + "--seccomp", "action=none", + "--server", "type=tcp,port=2321,disconnect", + "--ctrl", "type=tcp,port=2320", + "--flags", "not-need-init,startup-clear", +] + +sys.enable_sigterm_injection = true +sys.enable_extra_runtime_domain_names_conf = true + +fs.mounts = [ + { path = "/lib", uri = "file:{{ gramine.runtimedir() }}" }, + { path = "{{ arch_libdir }}", uri = "file:{{ arch_libdir }}" }, + { path = "/usr/{{ arch_libdir }}", uri = "file:/usr/{{ arch_libdir }}" }, + { path = "/usr/lib/swtpm/", uri = "file:/usr/lib/swtpm/" }, + + { path = "{{ entrypoint }}", uri = "file:{{ entrypoint }}" }, + { type = "encrypted", path = "/myvtpm2/", uri = "file:myvtpm2/", key_name = "{{ encryption_key }}" }, +] + +{% if encryption_key == "direct" %} +fs.insecure__keys.direct = "ffeeddccbbaa99887766554433221100" +{% endif %} + +sgx.edmm_enable = {{ 'true' if env.get('EDMM', '0') == '1' else 'false' }} +sgx.enclave_size = "1G" + +sgx.trusted_files = [ + "file:{{ gramine.libos }}", + "file:{{ entrypoint }}", + "file:{{ gramine.runtimedir() }}/", + "file:{{ arch_libdir }}/", + "file:/usr/{{ arch_libdir }}/", + "file:/usr/lib/swtpm/", +] From 5ee496565bff8667a34b851cfe409f2be4378f4e Mon Sep 17 00:00:00 2001 From: Dmitrii Kuvaiskii Date: Wed, 8 Mar 2023 02:19:00 -0800 Subject: [PATCH 2/2] fixup! Add swtpm example Signed-off-by: Dmitrii Kuvaiskii --- swtpm/.gitignore | 2 ++ swtpm/Makefile | 6 ------ swtpm/README.md | 13 ++++++++----- 3 files changed, 10 insertions(+), 11 deletions(-) create mode 100644 swtpm/.gitignore diff --git a/swtpm/.gitignore b/swtpm/.gitignore new file mode 100644 index 0000000..44a8bcc --- /dev/null +++ b/swtpm/.gitignore @@ -0,0 +1,2 @@ +/myvtpm2/.lock +/myvtpm2/*.permall diff --git a/swtpm/Makefile b/swtpm/Makefile index 73ea4ca..db19993 100644 --- a/swtpm/Makefile +++ b/swtpm/Makefile @@ -48,12 +48,6 @@ sgx_sign: swtpm.manifest --manifest $< \ --output $<.sgx -ifeq ($(SGX),) -GRAMINE = gramine-direct -else -GRAMINE = gramine-sgx -endif - .PHONY: clean clean: $(RM) *.token *.sig *.manifest.sgx *.manifest myvtpm2/.lock myvtpm2/*.permall diff --git a/swtpm/README.md b/swtpm/README.md index 4e7c301..6fae9e0 100644 --- a/swtpm/README.md +++ b/swtpm/README.md @@ -30,7 +30,7 @@ $ swtpm socket --tpm2 --tpmstate dir=/myvtpm2 --seccomp action=none \ This configuration means: - run `swtpm` in TPM2 mode, -- save all TPM state under `/myvtpm2/` dir (encrypted under Gramine with SGX), +- save all TPM state under `/myvtpm2/` dir (transparently encrypted by Gramine), - don't use seccomp (Gramine doesn't support it, and it's not needed in Gramine env anyway), - listen for client connections on TCP/IP port 2321 (in contrast to CUSE or chardev), - create a control channel on TCP/IP port 2320, @@ -92,10 +92,13 @@ bash -c "exec 100<>/dev/tcp/localhost/2321; \ ## output must be like this: ## 0000000 80 01 00 00 00 0a 00 00 00 00 -## 3 step: ask TPM to hash string "1234" in PCR 17 +## 3 step: check TPM Established flag (must be 0) +swtpm_ioctl --tcp localhost:2320 -e + +## 4 step: ask TPM to hash string "1234" in PCR 17 swtpm_ioctl --tcp localhost:2320 -h 1234 -## 4 step: read PCR 17 +## 5 step: read PCR 17 bash -c "exec 100<>/dev/tcp/localhost/2321; \ echo -en '\x80\x01\x00\x00\x00\x14\x00\x00\x01\x7e\x00\x00\x00\x01\x00\x0b\x03\x00\x00\x02' >&100; \ od -tx1 <&100" @@ -106,9 +109,9 @@ bash -c "exec 100<>/dev/tcp/localhost/2321; \ ## 0000040 d6 49 bf b0 c9 22 fd 33 0f 79 b2 00 43 28 9d af ## 0000060 d6 0d 01 a4 c4 37 3c f2 8a db 56 c9 b4 54 -## 5 step: check TPM Established flag (must be 1) +## 6 step: check TPM Established flag (must be 1) swtpm_ioctl --tcp localhost:2320 -e -## 6 step: shutdown TPM +## 7 step: shutdown TPM swtpm_ioctl --tcp localhost:2320 -s ```