From fbc596abbb9ccde7c67b84f01f7fc1912c2d8a4d Mon Sep 17 00:00:00 2001 From: Stefan Berger Date: Wed, 21 Dec 2016 17:01:06 -0500 Subject: [PATCH] swtpm: Provide support for TPM2 using --tpm2 Implement support for TPM2. Some of the capabilities are not supported yet in this patch. Extend the man pages with description for --tpm2. Missing: configure should probe for needed API calls in libtpms Signed-off-by: Stefan Berger --- .travis.yml | 4 +- configure.ac | 4 ++ dist/swtpm.spec | 4 +- dist/swtpm.spec.in | 4 +- include/swtpm.h.in | 2 + man/man8/swtpm.8 | 5 +- man/man8/swtpm.pod | 6 ++- man/man8/swtpm_cuse.8 | 26 ++++++++++ man/man8/swtpm_cuse.pod | 29 ++++++++++++ src/swtpm/Makefile.am | 1 + src/swtpm/ctrlchannel.c | 60 +++++++++++++++++------- src/swtpm/cuse_tpm.c | 95 ++++++++++++++++++++++++++++--------- src/swtpm/mainloop.c | 6 ++- src/swtpm/mainloop.h | 1 + src/swtpm/options.c | 2 +- src/swtpm/swtpm.c | 23 ++++++++- src/swtpm/swtpm_chardev.c | 26 +++++++++- src/swtpm/swtpm_nvfile.c | 23 ++++++++- src/swtpm/swtpm_nvfile.h | 4 ++ src/swtpm/tpmlib.c | 99 +++++++++++++++++++++++++++++---------- src/swtpm/tpmlib.h | 16 +++++-- src/swtpm/utils.c | 52 +++++++++++--------- src/swtpm/utils.h | 2 +- 23 files changed, 384 insertions(+), 110 deletions(-) diff --git a/.travis.yml b/.travis.yml index 79aa735..0d38df0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,8 +12,8 @@ before_install: - git clone https://github.com/stefanberger/libtpms - cd libtpms - git checkout origin/tpm2-preview.rev146.v2 -b tpm2-preview.rev146.v2 -- "./bootstrap.sh && ./configure --with-openssl --prefix=/usr && make -j4 && sudo - make install" +- "./bootstrap.sh && ./configure --with-openssl --prefix=/usr --with-tpm2 && make -j4 && + sudo make install" - cd .. - sudo apt-get -y install libfuse-dev libglib2.0-dev libgmp-dev expect libtasn1-dev socat findutils tpm-tools diff --git a/configure.ac b/configure.ac index 664a144..8253715 100644 --- a/configure.ac +++ b/configure.ac @@ -162,6 +162,10 @@ LIBTPMS_LIBS=$(pkg-config --libs libtpms) if test $? -ne 0; then AC_MSG_ERROR("Is libtpms-devel installed? -- could not get libs for libtpms") fi +AC_CHECK_LIB(tpms, + TPMLIB_ChooseTPMVersion,, + AC_MSG_ERROR("libtpms 0.6 or later is required") +) AC_SUBST([LIBTPMS_LIBS]) AC_PATH_PROG([TPM_NVDEFINE], tpm_nvdefine) diff --git a/dist/swtpm.spec b/dist/swtpm.spec index 2978cc7..1802b64 100644 --- a/dist/swtpm.spec +++ b/dist/swtpm.spec @@ -21,7 +21,7 @@ BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root %endif BuildRequires: automake autoconf bash coreutils libtool sed -BuildRequires: libtpms-devel fuse-devel glib2-devel gmp-devel +BuildRequires: libtpms-devel >= 0.6.0 fuse-devel glib2-devel gmp-devel BuildRequires: expect bash net-tools nss-devel socat python-twisted %if %{with_gnutls} BuildRequires: gnutls >= 3.1.0 gnutls-devel gnutls-utils @@ -34,7 +34,7 @@ BuildRequires: libtasn1-tools BuildRequires: kernel-modules-extra %endif -Requires: fuse +Requires: fuse libtpms >= 0.6.0 %if 0%{?fedora} > 16 Requires: kernel-modules-extra %endif diff --git a/dist/swtpm.spec.in b/dist/swtpm.spec.in index f8608fe..41ec4b7 100644 --- a/dist/swtpm.spec.in +++ b/dist/swtpm.spec.in @@ -21,7 +21,7 @@ BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root %endif BuildRequires: automake autoconf bash coreutils libtool sed -BuildRequires: libtpms-devel fuse-devel glib2-devel gmp-devel +BuildRequires: libtpms-devel >= 0.6.0 fuse-devel glib2-devel gmp-devel BuildRequires: expect bash net-tools nss-devel socat python-twisted %if %{with_gnutls} BuildRequires: gnutls >= 3.1.0 gnutls-devel gnutls-utils @@ -34,7 +34,7 @@ BuildRequires: libtasn1-tools BuildRequires: kernel-modules-extra %endif -Requires: fuse +Requires: fuse libtpms >= 0.6.0 %if 0%{?fedora} > 16 Requires: kernel-modules-extra %endif diff --git a/include/swtpm.h.in b/include/swtpm.h.in index 918480e..494563c 100644 --- a/include/swtpm.h.in +++ b/include/swtpm.h.in @@ -38,6 +38,8 @@ #ifndef SWTPM_TPM_H #define SWTPM_TPM_H +#include + #define SWTPM_VER_MAJOR @SWTPM_VER_MAJOR@ #define SWTPM_VER_MINOR @SWTPM_VER_MINOR@ #define SWTPM_VER_MICRO @SWTPM_VER_MICRO@ diff --git a/man/man8/swtpm.8 b/man/man8/swtpm.8 index 7f049b1..3567af5 100644 --- a/man/man8/swtpm.8 +++ b/man/man8/swtpm.8 @@ -259,7 +259,10 @@ Use the given path rather than using the environment variable \s-1TPM_PATH.\s0 The \s-1TPM\s0 state files will be written with the given file mode bits. This value must be given as an octal number starting with a '0'. The default value is 0640. -.IP "\fB\-\-log [fd=|file=][,level=][,prefix=][,truncate]\fR" 4 +.IP "\fB\-\-tpm2\fR" 4 +.IX Item "--tpm2" +Choose \s-1TPM 2\s0 functionality; by default a \s-1TPM 1.2\s0 is chosen. +.IP "\fB\-\-log [fd=|file=][,level=]\fR[,prefix=][,truncate]" 4 .IX Item "--log [fd=|file=][,level=][,prefix=][,truncate]" Enable logging to a file given its file descriptor or its path. Use '\-' for path to suppress the logging. diff --git a/man/man8/swtpm.pod b/man/man8/swtpm.pod index 1c37228..e77dda9 100644 --- a/man/man8/swtpm.pod +++ b/man/man8/swtpm.pod @@ -164,7 +164,11 @@ The TPM state files will be written with the given file mode bits. This value must be given as an octal number starting with a '0'. The default value is 0640. -=item B<--log [fd=EfdE|file=EpathE][,level=EnE][,prefix=EprefixE][,truncate]> +=item B<--tpm2> + +Choose TPM 2 functionality; by default a TPM 1.2 is chosen. + +=item B<--log [fd=EfdE|file=EpathE][,level=EnE]>[,prefix=EprefixE][,truncate] Enable logging to a file given its file descriptor or its path. Use '-' for path to suppress the logging. diff --git a/man/man8/swtpm_cuse.8 b/man/man8/swtpm_cuse.8 index fffd925..6445ee5 100644 --- a/man/man8/swtpm_cuse.8 +++ b/man/man8/swtpm_cuse.8 @@ -173,6 +173,9 @@ The device major number to use; can be omitted. .IP "\fB\-m | \-\-min=\fR" 4 .IX Item "-m | --min=" The device minor number to use; can be omitted. +.IP "\fB\-\-tpm2\fR" 4 +.IX Item "--tpm2" +Choose \s-1TPM 2\s0 functionality; by default a \s-1TPM 1.2\s0 is chosen. .IP "\fB\-r | \-\-runas=\fR" 4 .IX Item "-r | --runas=" The user to switch to and drop privileges. @@ -259,6 +262,29 @@ A maximum of 32 bytes are read from the file and a key is derived from it using This options allows to set the name of file where the process \s-1ID \s0(pid) of the \s-1CUSE TPM\s0 will be written into. The file will be written by the root user. It is also possible to pass a file descriptor to a file that has been opened for writing. +.SH "EXAMPLES" +.IX Header "EXAMPLES" +To start the \s-1CUSE TPM\s0 and have it create the character device /dev/foo, +use the following commands: +.Sp +.Vb 1 +\& # ensure that previous swtpm_cuse using /dev/foo is gone +\& +\& swtpm_ioctl \-s /dev/foo +\& +\& # Start the swtpm with TPM 2 functionality and make it accessible +\& # through /dev/foo. Have the swtpm_cuse write the TPM\*(Aqs persistent +\& # state into the given directory. +\& +\& export TPM_PATH=/tmp/foo +\& mkdir \-p $TPM_PATH +\& +\& swtpm_cuse \-n foo \-\-tpm2 +\& +\& # Send TPM_Init to the TPM; this is absolutely necessary +\& +\& swtpm_ioctl \-i /dev/foo +.Ve .SH "SEE ALSO" .IX Header "SEE ALSO" \&\fBswtpm_bios\fR, \fBswtpm_ioctl\fR diff --git a/man/man8/swtpm_cuse.pod b/man/man8/swtpm_cuse.pod index 3cc33b4..f3ff3a7 100644 --- a/man/man8/swtpm_cuse.pod +++ b/man/man8/swtpm_cuse.pod @@ -44,6 +44,10 @@ The device major number to use; can be omitted. The device minor number to use; can be omitted. +=item B<--tpm2> + +Choose TPM 2 functionality; by default a TPM 1.2 is chosen. + =item B<-r EuserE | --runas=EuserE> The user to switch to and drop privileges. @@ -140,6 +144,31 @@ pass a file descriptor to a file that has been opened for writing. =back +=head1 EXAMPLES + +To start the CUSE TPM and have it create the character device /dev/foo, +use the following commands: + +=over 4 + + # ensure that previous swtpm_cuse using /dev/foo is gone + + swtpm_ioctl -s /dev/foo + + # Start the swtpm with TPM 2 functionality and make it accessible + # through /dev/foo. Have the swtpm_cuse write the TPM's persistent + # state into the given directory. + + export TPM_PATH=/tmp/foo + mkdir -p $TPM_PATH + + swtpm_cuse -n foo --tpm2 + + # Send TPM_Init to the TPM; this is absolutely necessary + + swtpm_ioctl -i /dev/foo + +=back =head1 SEE ALSO diff --git a/src/swtpm/Makefile.am b/src/swtpm/Makefile.am index 9b363da..5022a21 100644 --- a/src/swtpm/Makefile.am +++ b/src/swtpm/Makefile.am @@ -48,6 +48,7 @@ libswtpm_libtpms_la_SOURCES = \ utils.c libswtpm_libtpms_la_CFLAGS = \ + -I$(top_srcdir)/include \ -I$(top_srcdir)/include/swtpm \ $(HARDENING_CFLAGS) \ $(GLIB_CFLAGS) diff --git a/src/swtpm/ctrlchannel.c b/src/swtpm/ctrlchannel.c index 62e6084..e4d152e 100644 --- a/src/swtpm/ctrlchannel.c +++ b/src/swtpm/ctrlchannel.c @@ -432,6 +432,7 @@ wait_chunk: * this function in case TPM is stopped or started * @mlp: mainloop parameters used; may be altered by this function incase of * CMD_SET_DATAFD + * @tpmversion: the emulated TPM's version * * This function returns the passed file descriptor or -1 in case the * file descriptor was closed. @@ -505,25 +506,49 @@ int ctrlchannel_process_fd(int fd, switch (be32toh(input.cmd)) { case CMD_GET_CAPABILITY: - *ptm_caps = htobe64( - PTM_CAP_INIT | - PTM_CAP_SHUTDOWN | - PTM_CAP_GET_TPMESTABLISHED | - PTM_CAP_SET_LOCALITY | - PTM_CAP_HASHING | - PTM_CAP_CANCEL_TPM_CMD | - PTM_CAP_STORE_VOLATILE | - PTM_CAP_RESET_TPMESTABLISHED | - PTM_CAP_GET_STATEBLOB | - PTM_CAP_SET_STATEBLOB | - PTM_CAP_STOP | - PTM_CAP_GET_CONFIG | + switch (mlp->tpmversion) { + case TPMLIB_TPM_VERSION_2: + *ptm_caps = htobe64( + PTM_CAP_INIT + | PTM_CAP_SHUTDOWN + | PTM_CAP_STOP + | PTM_CAP_GET_TPMESTABLISHED + | PTM_CAP_SET_LOCALITY + //| PTM_CAP_RESET_TPMESTABLISHED + | PTM_CAP_HASHING + //| PTM_CAP_GET_STATEBLOB + //| PTM_CAP_SET_STATEBLOB + //| PTM_CAP_CANCEL_TPM_CMD + //| PTM_CAP_STORE_VOLATILE + | PTM_GET_CONFIG #ifndef __CYGWIN__ - PTM_CAP_SET_DATAFD | + | PTM_CAP_SET_DATAFD #endif - PTM_CAP_SET_BUFFERSIZE | - PTM_CAP_GET_INFO + | PTM_CAP_SET_BUFFERSIZE + | PTM_CAP_GET_INFO ); + break; + case TPMLIB_TPM_VERSION_1_2: + *ptm_caps = htobe64( + PTM_CAP_INIT + | PTM_CAP_SHUTDOWN + | PTM_CAP_STOP + | PTM_CAP_GET_TPMESTABLISHED + | PTM_CAP_SET_LOCALITY + | PTM_CAP_RESET_TPMESTABLISHED + | PTM_CAP_HASHING + | PTM_CAP_GET_STATEBLOB + | PTM_CAP_SET_STATEBLOB + | PTM_CAP_CANCEL_TPM_CMD + | PTM_CAP_STORE_VOLATILE + | PTM_CAP_GET_CONFIG +#ifndef __CYGWIN__ + | PTM_CAP_SET_DATAFD +#endif + | PTM_CAP_SET_BUFFERSIZE + | PTM_CAP_GET_INFO + ); + } out_len = sizeof(*ptm_caps); break; @@ -537,7 +562,8 @@ int ctrlchannel_process_fd(int fd, TPMLIB_Terminate(); *tpm_running = false; - res = tpmlib_start(be32toh(init_p->u.req.init_flags)); + res = tpmlib_start(be32toh(init_p->u.req.init_flags), + mlp->tpmversion); if (res) { logprintf(STDERR_FILENO, "Error: Could not initialize the TPM\n"); diff --git a/src/swtpm/cuse_tpm.c b/src/swtpm/cuse_tpm.c index 27367ff..8c0a1fc 100644 --- a/src/swtpm/cuse_tpm.c +++ b/src/swtpm/cuse_tpm.c @@ -79,6 +79,9 @@ /* maximum size of request buffer */ #define TPM_REQ_MAX 4096 +/* version of the TPM (1.2 or 2) */ +static TPMLIB_TPMVersion tpmversion; + /* buffer containing the TPM request */ static unsigned char *ptm_request; @@ -210,7 +213,7 @@ static const char *usage = " files; the default mode is 0640;\n" "-r|--runas : after creating the CUSE device, change to the given\n" " user\n" -"" +"--tpm2 : choose TPM2 functionality\n" "-h|--help : display this help screen and terminate\n" "\n"; @@ -220,6 +223,12 @@ const static unsigned char TPM_ResetEstablishmentBit[] = { 0x40, 0x00, 0x00, 0x0B /* TPM_ORD_ResetEstablishmentBit */ }; +const static unsigned char TPM2_Resp_FatalError[] = { + 0x80, 0x01, /* TPM Response */ + 0x00, 0x00, 0x00, 0x0A, /* length (10) */ + 0x00, 0x00, 0x01, 0x01 /* TPM_FAIL */ +}; + static TPM_RESULT ptm_io_getlocality(TPM_MODIFIER_INDICATOR *loc, uint32_t tpmnum) { @@ -434,7 +443,7 @@ static TPM_RESULT _TPM_IO_TpmEstablished_Reset(fuse_req_t req, * * @flags: libtpms init flags */ -static int tpm_start(uint32_t flags) +static int tpm_start(uint32_t flags, TPMLIB_TPMVersion l_tpmversion) { DIR *dir; const char *tpmdir = tpmstate_get_dir(); @@ -470,7 +479,7 @@ static int tpm_start(uint32_t flags) goto error_del_pool; } - if (tpmlib_start(flags) != TPM_SUCCESS) + if (tpmlib_start(flags, l_tpmversion) != TPM_SUCCESS) goto error_del_pool; logprintf(STDOUT_FILENO, @@ -490,11 +499,12 @@ error_del_pool: * * Write a fatal error response into the global ptm_response buffer. */ -static void ptm_write_fatal_error_response(void) +static void ptm_write_fatal_error_response(TPMLIB_TPMVersion l_tpmversion) { tpmlib_write_fatal_error_response(&ptm_response, &ptm_res_len, - &ptm_res_tot); + &ptm_res_tot, + l_tpmversion); } /************************************ read() support ***************************/ @@ -815,8 +825,10 @@ static void ptm_write_stateblob(fuse_req_t req, const char *buf, size_t size) * req: fuse_req_t * buf: the buffer containing the TPM command * size: the size of the buffer + * tpmversion: the version of the TPM */ -static void ptm_write_cmd(fuse_req_t req, const char *buf, size_t size) +static void ptm_write_cmd(fuse_req_t req, const char *buf, size_t size, + TPMLIB_TPMVersion l_tpmversion) { ptm_req_len = size; ptm_res_len = 0; @@ -837,11 +849,12 @@ static void ptm_write_cmd(fuse_req_t req, const char *buf, size_t size) /* process SetLocality command, if */ tpmlib_process(&ptm_response, &ptm_res_len, &ptm_res_tot, (unsigned char *)buf, ptm_req_len, - locality_flags, &locality); + locality_flags, &locality, tpmversion); if (ptm_res_len) goto skip_process; - if (tpmlib_is_request_cancelable(ptm_request, ptm_req_len)) { + if (tpmlib_is_request_cancelable((const unsigned char*)buf, + ptm_req_len)) { /* have command processed by thread pool */ memcpy(ptm_request, buf, ptm_req_len); @@ -857,7 +870,7 @@ static void ptm_write_cmd(fuse_req_t req, const char *buf, size_t size) } } else { /* TPM not initialized; return error */ - ptm_write_fatal_error_response(); + ptm_write_fatal_error_response(l_tpmversion); } skip_process: @@ -878,7 +891,7 @@ static void ptm_write(fuse_req_t req, const char *buf, size_t size, { switch (tx_state.state) { case TX_STATE_RW_COMMAND: - ptm_write_cmd(req, buf, size); + ptm_write_cmd(req, buf, size, tpmversion); break; case TX_STATE_GET_STATE_BLOB: fuse_reply_err(req, EIO); @@ -956,18 +969,36 @@ static void ptm_ioctl(fuse_req_t req, int cmd, void *arg, fuse_reply_ioctl_retry(req, &iov, 1, NULL, 0); } else { ptm_cap ptm_caps; - ptm_caps = PTM_CAP_INIT | PTM_CAP_SHUTDOWN - | PTM_CAP_GET_TPMESTABLISHED - | PTM_CAP_SET_LOCALITY - | PTM_CAP_HASHING - | PTM_CAP_CANCEL_TPM_CMD - | PTM_CAP_STORE_VOLATILE - | PTM_CAP_RESET_TPMESTABLISHED - | PTM_CAP_GET_STATEBLOB - | PTM_CAP_SET_STATEBLOB - | PTM_CAP_STOP - | PTM_CAP_GET_CONFIG - | PTM_CAP_SET_BUFFERSIZE; + switch (tpmversion) { + case TPMLIB_TPM_VERSION_2: + ptm_caps = PTM_CAP_INIT | PTM_CAP_SHUTDOWN + | PTM_CAP_GET_TPMESTABLISHED + | PTM_CAP_SET_LOCALITY + | PTM_CAP_HASHING + //| PTM_CAP_CANCEL_TPM_CMD + //| PTM_CAP_STORE_VOLATILE + //| PTM_CAP_RESET_TPMESTABLISHED + //| PTM_CAP_GET_STATEBLOB + //| PTM_CAP_SET_STATEBLOB + | PTM_CAP_STOP + | PTM_CAP_GET_CONFIG + | PTM_CAP_SET_BUFFERSIZE; + break; + case TPMLIB_TPM_VERSION_1_2: + ptm_caps = PTM_CAP_INIT | PTM_CAP_SHUTDOWN + | PTM_CAP_GET_TPMESTABLISHED + | PTM_CAP_SET_LOCALITY + | PTM_CAP_HASHING + | PTM_CAP_CANCEL_TPM_CMD + | PTM_CAP_STORE_VOLATILE + | PTM_CAP_RESET_TPMESTABLISHED + | PTM_CAP_GET_STATEBLOB + | PTM_CAP_SET_STATEBLOB + | PTM_CAP_STOP + | PTM_CAP_GET_CONFIG + | PTM_CAP_SET_BUFFERSIZE; + break; + } fuse_reply_ioctl(req, 0, &ptm_caps, sizeof(ptm_caps)); } break; @@ -984,7 +1015,7 @@ static void ptm_ioctl(fuse_req_t req, int cmd, void *arg, TPMLIB_Terminate(); tpm_running = false; - if (tpm_start(init_p->u.req.init_flags) < 0) { + if (tpm_start(init_p->u.req.init_flags, tpmversion) < 0) { res = TPM_FAIL; logprintf(STDERR_FILENO, "Error: Could not initialize the TPM.\n"); @@ -1320,6 +1351,7 @@ int swtpm_cuse_main(int argc, char **argv, const char *prgname, const char *ifac {"migration-key" , required_argument, 0, 'K'}, {"pid" , required_argument, 0, 'p'}, {"tpmstate" , required_argument, 0, 's'}, + {"tpm2" , no_argument, 0, '2'}, {"help" , no_argument, 0, 'h'}, {"version" , no_argument, 0, 'v'}, {NULL , 0 , 0, 0 }, @@ -1339,6 +1371,8 @@ int swtpm_cuse_main(int argc, char **argv, const char *prgname, const char *ifac log_set_prefix("swtpm: "); + tpmversion = TPMLIB_TPM_VERSION_1_2; + while (true) { opt = getopt_long(argc, argv, "M:m:n:r:hv", longopts, &longindex); @@ -1407,6 +1441,9 @@ int swtpm_cuse_main(int argc, char **argv, const char *prgname, const char *ifac case 'L': param.localitydata = optarg; break; + case '2': + tpmversion = TPMLIB_TPM_VERSION_2; + break; case 'h': /* help */ fprintf(stdout, usage, prgname, iface); return 0; @@ -1426,6 +1463,18 @@ int swtpm_cuse_main(int argc, char **argv, const char *prgname, const char *ifac return EXIT_FAILURE; } + /* + * choose the TPM version early so that getting/setting + * buffer size works. + */ + if (TPMLIB_ChooseTPMVersion(tpmversion) != TPM_SUCCESS) { + logprintf(STDERR_FILENO, + "Error: Could not choose TPM version.\n"); + return EXIT_FAILURE; + } + + SWTPM_NVRAM_Set_TPMVersion(tpmversion); + if (!cinfo.dev_info_argv) { logprintf(STDERR_FILENO, "Error: device name missing\n"); return -2; diff --git a/src/swtpm/mainloop.c b/src/swtpm/mainloop.c index a94d807..70efa47 100644 --- a/src/swtpm/mainloop.c +++ b/src/swtpm/mainloop.c @@ -216,7 +216,8 @@ int mainLoop(struct mainLoopParams *mlp, if (rc == 0) { if (!tpm_running) { tpmlib_write_fatal_error_response(&rbuffer, &rlength, - &rTotal); + &rTotal, + mlp->tpmversion); goto skip_process; } } @@ -229,7 +230,8 @@ int mainLoop(struct mainLoopParams *mlp, command, /* complete command array */ command_length, /* actual bytes in command */ mlp->locality_flags, - &locality); + &locality, + mlp->tpmversion); if (rlength) goto skip_process; } diff --git a/src/swtpm/mainloop.h b/src/swtpm/mainloop.h index 9b57da4..d081789 100644 --- a/src/swtpm/mainloop.h +++ b/src/swtpm/mainloop.h @@ -59,6 +59,7 @@ struct mainLoopParams { int fd; struct ctrlchannel *cc; uint32_t locality_flags; + TPMLIB_TPMVersion tpmversion; }; int mainLoop(struct mainLoopParams *mlp, diff --git a/src/swtpm/options.c b/src/swtpm/options.c index dc2938a..9df3eab 100644 --- a/src/swtpm/options.c +++ b/src/swtpm/options.c @@ -1,7 +1,7 @@ /* * options.c -- Option parsing * - * (c) Copyright IBM Corporation 2014. + * (c) Copyright IBM Corporation 2014, 2015. * * Author: Stefan Berger * diff --git a/src/swtpm/swtpm.c b/src/swtpm/swtpm.c index eb99728..e78c4a3 100644 --- a/src/swtpm/swtpm.c +++ b/src/swtpm/swtpm.c @@ -166,6 +166,7 @@ static void usage(FILE *file, const char *prgname, const char *iface) " : not-need-init: commands can be sent without needing to\n" " send an INIT via control channel;\n" "-r|--runas : change to the given user\n" + "--tpm2 : choose TPM2 functionality\n" "-h|--help : display this help screen and terminate\n" "\n", prgname, iface); @@ -219,8 +220,10 @@ int swtpm_main(int argc, char **argv, const char *prgname, const char *iface) {"tpmstate" , required_argument, 0, 's'}, {"ctrl" , required_argument, 0, 'C'}, {"flags" , required_argument, 0, 'F'}, + {"tpm2" , no_argument, 0, '2'}, {NULL , 0 , 0, 0 }, }; + TPMLIB_TPMVersion tpmversion = TPMLIB_TPM_VERSION_1_2; log_set_prefix("swtpm: "); @@ -332,6 +335,10 @@ int swtpm_main(int argc, char **argv, const char *prgname, const char *iface) flagsdata = optarg; break; + case '2': + tpmversion = TPMLIB_TPM_VERSION_2; + break; + case 'h': usage(stdout, prgname, iface); exit(EXIT_SUCCESS); @@ -359,6 +366,16 @@ int swtpm_main(int argc, char **argv, const char *prgname, const char *iface) return EXIT_FAILURE; } + /* + * choose the TPM version early so that getting/setting + * buffer size works. + */ + if (TPMLIB_ChooseTPMVersion(mlp.tpmversion) != TPM_SUCCESS) { + logprintf(STDERR_FILENO, + "Error: Could not choose TPM version.\n"); + return EXIT_FAILURE; + } + if (handle_ctrlchannel_options(ctrlchdata, &mlp.cc) < 0 || handle_server_options(serverdata, &server) < 0) { goto exit_failure; @@ -370,6 +387,8 @@ int swtpm_main(int argc, char **argv, const char *prgname, const char *iface) goto exit_failure; } + SWTPM_NVRAM_Set_TPMVersion(tpmversion); + if (handle_log_options(logdata) < 0 || handle_key_options(keydata) < 0 || handle_migration_key_options(migkeydata) < 0 || @@ -419,13 +438,13 @@ int swtpm_main(int argc, char **argv, const char *prgname, const char *iface) TPM_DEBUG("main: Initializing TPM at %s", ctime(&start_time)); - tpmlib_debug_libtpms_parameters(); + tpmlib_debug_libtpms_parameters(mlp.tpmversion); if ((rc = tpmlib_register_callbacks(&callbacks))) goto error_no_tpm; if (!need_init_cmd) { - if ((rc = tpmlib_start(0))) + if ((rc = tpmlib_start(0, tpmversion))) goto error_no_tpm; tpm_running = true; } diff --git a/src/swtpm/swtpm_chardev.c b/src/swtpm/swtpm_chardev.c index 7c76508..79d55f4 100644 --- a/src/swtpm/swtpm_chardev.c +++ b/src/swtpm/swtpm_chardev.c @@ -188,6 +188,7 @@ static void usage(FILE *file, const char *prgname, const char *iface) " : not-need-init: commands can be sent without needing to\n" " send an INIT via control channel; not needed when using\n" " --vtpm-proxy\n" + "--tpm2 : choose TPM2 functionality\n" "-h|--help : display this help screen and terminate\n" "\n", prgname, iface); @@ -204,6 +205,7 @@ int swtpm_chardev_main(int argc, char **argv, const char *prgname, const char *i .fd = -1, .flags = 0, .locality_flags = 0, + .tpmversion = TPMLIB_TPM_VERSION_1_2, }; unsigned long val; char *end_ptr; @@ -240,6 +242,7 @@ int swtpm_chardev_main(int argc, char **argv, const char *prgname, const char *i #ifdef WITH_VTPM_PROXY {"vtpm-proxy", no_argument, 0, 'v'}, #endif + {"tpm2" , no_argument, 0, '2'}, {NULL , 0 , 0, 0 }, }; @@ -336,6 +339,10 @@ int swtpm_chardev_main(int argc, char **argv, const char *prgname, const char *i flagsdata = optarg; break; + case '2': + mlp.tpmversion = TPMLIB_TPM_VERSION_2; + break; + case 'h': usage(stdout, prgname, iface); exit(EXIT_SUCCESS); @@ -372,6 +379,9 @@ int swtpm_chardev_main(int argc, char **argv, const char *prgname, const char *i }; int _errno; + if (mlp.tpmversion == TPMLIB_TPM_VERSION_2) + vtpm_new_dev.flags = VTPM_PROXY_FLAG_TPM2; + if (mlp.fd >= 0) { logprintf(STDERR_FILENO, "Cannot use vTPM proxy with a provided device.\n"); @@ -405,6 +415,18 @@ int swtpm_chardev_main(int argc, char **argv, const char *prgname, const char *i return EXIT_FAILURE; } + /* + * choose the TPM version early so that getting/setting + * buffer size works. + */ + if (TPMLIB_ChooseTPMVersion(mlp.tpmversion) != TPM_SUCCESS) { + logprintf(STDERR_FILENO, + "Error: Could not choose TPM version.\n"); + return EXIT_FAILURE; + } + + SWTPM_NVRAM_Set_TPMVersion(mlp.tpmversion); + if (handle_ctrlchannel_options(ctrlchdata, &mlp.cc) < 0) { goto exit_failure; } @@ -444,7 +466,7 @@ int swtpm_chardev_main(int argc, char **argv, const char *prgname, const char *i TPM_DEBUG("main: Initializing TPM at %s", ctime(&start_time)); - tpmlib_debug_libtpms_parameters(); + tpmlib_debug_libtpms_parameters(mlp.tpmversion); #ifdef WITH_VTPM_PROXY if (use_vtpm_proxy) @@ -455,7 +477,7 @@ int swtpm_chardev_main(int argc, char **argv, const char *prgname, const char *i goto error_no_tpm; if (!need_init_cmd) { - if ((rc = tpmlib_start(0))) + if ((rc = tpmlib_start(0, mlp.tpmversion))) goto error_no_tpm; tpm_running = true; } diff --git a/src/swtpm/swtpm_nvfile.c b/src/swtpm/swtpm_nvfile.c index 82cdbd1..ad07563 100644 --- a/src/swtpm/swtpm_nvfile.c +++ b/src/swtpm/swtpm_nvfile.c @@ -79,6 +79,7 @@ #endif #endif +#include "swtpm.h" #include "swtpm_aes.h" #include "swtpm_debug.h" #include "swtpm_nvfile.h" @@ -176,6 +177,15 @@ static TPM_RESULT SWTPM_NVRAM_CheckHeader(unsigned char *data, uint32_t length, static int lockfile_fd = -1; char state_directory[FILENAME_MAX]; +static TPMLIB_TPMVersion tpmversion = TPMLIB_TPM_VERSION_1_2; + +/* + * SWTPM_NVRAM_Set_TPMVersion() - set the version of the TPM being used + */ +void SWTPM_NVRAM_Set_TPMVersion(TPMLIB_TPMVersion version) +{ + tpmversion = version; +} static TPM_RESULT SWTPM_NVRAM_Lock_Lockfile(const char *directory, int *fd) @@ -574,11 +584,20 @@ static TPM_RESULT SWTPM_NVRAM_GetFilenameForName(char *filename, /* outpu { TPM_RESULT res = TPM_SUCCESS; int n; + const char *suffix = ""; TPM_DEBUG(" SWTPM_NVRAM_GetFilenameForName: For name %s\n", name); - n = snprintf(filename, bufsize, "%s/tpm-%02lx.%s", - state_directory, (unsigned long)tpm_number, name); + switch (tpmversion) { + case TPMLIB_TPM_VERSION_1_2: + break; + case TPMLIB_TPM_VERSION_2: + suffix = "2"; + break; + } + + n = snprintf(filename, bufsize, "%s/tpm%s-%02lx.%s", + state_directory, suffix, (unsigned long)tpm_number, name); if ((size_t)n > bufsize) { res = TPM_FAIL; } diff --git a/src/swtpm/swtpm_nvfile.h b/src/swtpm/swtpm_nvfile.h index ea129c5..20954cc 100644 --- a/src/swtpm/swtpm_nvfile.h +++ b/src/swtpm/swtpm_nvfile.h @@ -51,8 +51,12 @@ #define TPM_FILENAME_MAX 20 +#include + TPM_RESULT SWTPM_NVRAM_Init(void); +void SWTPM_NVRAM_Set_TPMVersion(TPMLIB_TPMVersion version); + /* Basic abstraction for read and write */ diff --git a/src/swtpm/tpmlib.c b/src/swtpm/tpmlib.c index 403eac3..cc95a0c 100644 --- a/src/swtpm/tpmlib.c +++ b/src/swtpm/tpmlib.c @@ -85,10 +85,16 @@ TPM_RESULT tpmlib_register_callbacks(struct libtpms_callbacks *cbs) return res; } -TPM_RESULT tpmlib_start(uint32_t flags) +TPM_RESULT tpmlib_start(uint32_t flags, TPMLIB_TPMVersion tpmversion) { TPM_RESULT res; + if ((res = TPMLIB_ChooseTPMVersion(tpmversion)) != TPM_SUCCESS) { + logprintf(STDERR_FILENO, + "Error: Could not choose TPM 2 implementation.\n"); + return res; + } + if ((res = TPMLIB_MainInit()) != TPM_SUCCESS) { logprintf(STDERR_FILENO, "Error: Could not initialize libtpms.\n"); @@ -179,10 +185,13 @@ TPM_RESULT tpmlib_TpmEstablished_Reset(TPM_MODIFIER_INDICATOR *g_locality, static void tpmlib_write_error_response(unsigned char **rbuffer, uint32_t *rlength, uint32_t *rTotal, - TPM_RESULT errcode) + TPM_RESULT errcode, + TPMLIB_TPMVersion tpmversion) { struct tpm_resp_header errresp = { - .tag = htobe16(0xc4), + .tag = (tpmversion == TPMLIB_TPM_VERSION_2) + ? htobe16(0x8001) + : htobe16(0xc4), .size = htobe32(sizeof(errresp)), .errcode = htobe32(errcode), }; @@ -205,31 +214,51 @@ static void tpmlib_write_error_response(unsigned char **rbuffer, void tpmlib_write_fatal_error_response(unsigned char **rbuffer, uint32_t *rlength, - uint32_t *rTotal) + uint32_t *rTotal, + TPMLIB_TPMVersion tpmversion) { - tpmlib_write_error_response(rbuffer, rlength, rTotal, TPM_FAIL); + TPM_RESULT errcode = (tpmversion == TPMLIB_TPM_VERSION_2) + ? TPM_RC_FAILURE + : TPM_FAIL; + + tpmlib_write_error_response(rbuffer, rlength, rTotal, errcode, + tpmversion); } void tpmlib_write_locality_error_response(unsigned char **rbuffer, uint32_t *rlength, - uint32_t *rTotal) + uint32_t *rTotal, + TPMLIB_TPMVersion tpmversion) { - tpmlib_write_error_response(rbuffer, rlength, rTotal, TPM_BAD_LOCALITY); + TPM_RESULT errcode = (tpmversion == TPMLIB_TPM_VERSION_2) + ? TPM_RC_LOCALITY + : TPM_BAD_LOCALITY; + + tpmlib_write_error_response(rbuffer, rlength, rTotal, errcode, + tpmversion); } void tpmlib_write_success_response(unsigned char **rbuffer, uint32_t *rlength, - uint32_t *rTotal) + uint32_t *rTotal, + TPMLIB_TPMVersion tpmversion) { - tpmlib_write_error_response(rbuffer, rlength, rTotal, 0); + tpmlib_write_error_response(rbuffer, rlength, rTotal, 0, + tpmversion); } #ifdef WITH_VTPM_PROXY static void tpmlib_write_shortmsg_error_response(unsigned char **rbuffer, uint32_t *rlength, - uint32_t *rTotal) + uint32_t *rTotal, + TPMLIB_TPMVersion tpmversion) { - tpmlib_write_error_response(rbuffer, rlength, rTotal, TPM_BAD_PARAM_SIZE); + TPM_RESULT errcode = (tpmversion == TPMLIB_TPM_VERSION_2) + ? TPM_RC_INSUFFICIENT + : TPM_BAD_PARAM_SIZE; + + tpmlib_write_error_response(rbuffer, rlength, rTotal, errcode, + tpmversion); } static TPM_RESULT tpmlib_process_setlocality(unsigned char **rbuffer, @@ -237,6 +266,7 @@ static TPM_RESULT tpmlib_process_setlocality(unsigned char **rbuffer, uint32_t *rTotal, unsigned char *command, uint32_t command_length, + TPMLIB_TPMVersion tpmversion, uint32_t locality_flags, TPM_MODIFIER_INDICATOR *locality) { @@ -246,23 +276,27 @@ static TPM_RESULT tpmlib_process_setlocality(unsigned char **rbuffer, if (!(locality_flags & LOCALITY_FLAG_ALLOW_SETLOCALITY)) { /* SETLOCALITY command is not allowed */ tpmlib_write_fatal_error_response(rbuffer, - rlength, rTotal); + rlength, rTotal, + tpmversion); } else { new_locality = command[sizeof(struct tpm_req_header)]; if (new_locality >=5 || (new_locality == 4 && locality_flags & LOCALITY_FLAG_REJECT_LOCALITY_4)) { tpmlib_write_locality_error_response(rbuffer, - rlength, rTotal); + rlength, rTotal, + tpmversion); } else { tpmlib_write_success_response(rbuffer, - rlength, rTotal); + rlength, rTotal, + tpmversion); *locality = new_locality; } } } else { tpmlib_write_shortmsg_error_response(rbuffer, - rlength, rTotal); + rlength, rTotal, + tpmversion); } return TPM_SUCCESS; } @@ -273,7 +307,8 @@ TPM_RESULT tpmlib_process(unsigned char **rbuffer, unsigned char *command, uint32_t command_length, uint32_t locality_flags, - TPM_MODIFIER_INDICATOR *locality) + TPM_MODIFIER_INDICATOR *locality, + TPMLIB_TPMVersion tpmversion) { /* process those commands we need to handle, e.g. SetLocality */ struct tpm_req_header *req = (struct tpm_req_header *)command; @@ -281,18 +316,33 @@ TPM_RESULT tpmlib_process(unsigned char **rbuffer, if (command_length < sizeof(*req)) { tpmlib_write_shortmsg_error_response(rbuffer, - rlength, rTotal); + rlength, rTotal, + tpmversion); return TPM_SUCCESS; } ordinal = be32toh(req->ordinal); - switch (ordinal) { - case TPM_CC_SET_LOCALITY: - return tpmlib_process_setlocality(rbuffer, rlength, rTotal, - command, command_length, - locality_flags, - locality); + switch (tpmversion) { + case TPMLIB_TPM_VERSION_1_2: + switch (ordinal) { + case TPM_CC_SET_LOCALITY: + return tpmlib_process_setlocality(rbuffer, rlength, rTotal, + command, command_length, + tpmversion, locality_flags, + locality); + } + break; + + case TPMLIB_TPM_VERSION_2: + switch (ordinal) { + case TPM2_CC_SET_LOCALITY: + return tpmlib_process_setlocality(rbuffer, rlength, rTotal, + command, command_length, + tpmversion, locality_flags, + locality); + } + break; } return TPM_SUCCESS; } @@ -305,7 +355,8 @@ TPM_RESULT tpmlib_process(unsigned char **rbuffer, unsigned char *command, uint32_t command_length, uint32_t locality_flags, - TPM_MODIFIER_INDICATOR *locality) + TPM_MODIFIER_INDICATOR *locality, + TPMLIB_TPMVersion tpmversion) { return TPM_SUCCESS; } diff --git a/src/swtpm/tpmlib.h b/src/swtpm/tpmlib.h index 0650c81..9d40d13 100644 --- a/src/swtpm/tpmlib.h +++ b/src/swtpm/tpmlib.h @@ -46,26 +46,30 @@ const char *tpmlib_get_blobname(uint32_t blobtype); enum TPMLIB_StateType tpmlib_blobtype_to_statetype(uint32_t blobtype); TPM_RESULT tpmlib_register_callbacks(struct libtpms_callbacks *cbs); -TPM_RESULT tpmlib_start(uint32_t flags); +TPM_RESULT tpmlib_start(uint32_t flags, TPMLIB_TPMVersion tpmversion); int tpmlib_get_tpm_property(enum TPMLIB_TPMProperty prop); bool tpmlib_is_request_cancelable(const unsigned char *request, size_t req_len); TPM_RESULT tpmlib_TpmEstablished_Reset(TPM_MODIFIER_INDICATOR *g_locty, TPM_MODIFIER_INDICATOR locty); void tpmlib_write_fatal_error_response(unsigned char **rbuffer, uint32_t *rlength, - uint32_t *rTotal); + uint32_t *rTotal, + TPMLIB_TPMVersion tpmversion); void tpmlib_write_locality_error_response(unsigned char **rbuffer, uint32_t *rlength, - uint32_t *rTotal); + uint32_t *rTotal, + TPMLIB_TPMVersion tpmversion); void tpmlib_write_success_response(unsigned char **rbuffer, uint32_t *rlength, - uint32_t *rTotal); + uint32_t *rTotal, + TPMLIB_TPMVersion tpmversion); TPM_RESULT tpmlib_process(unsigned char **rbuffer, uint32_t *rlength, uint32_t *rTotal, unsigned char *command, uint32_t command_length, uint32_t locality_flags, - TPM_MODIFIER_INDICATOR *locality); + TPM_MODIFIER_INDICATOR *locality, + TPMLIB_TPMVersion tpmversion); struct tpm_req_header { @@ -85,6 +89,8 @@ struct tpm_resp_header { #define TPMLIB_TPM_ORD_CreateWrapKey 0x0000001f /* TPM 2 error codes */ +#define TPM_RC_INSUFFICIENT 0x09a +#define TPM_RC_FAILURE 0x101 #define TPM_RC_LOCALITY 0x107 #endif /* _SWTPM_TPMLIB_H_ */ diff --git a/src/swtpm/utils.c b/src/swtpm/utils.c index 2299797..fa89de9 100644 --- a/src/swtpm/utils.c +++ b/src/swtpm/utils.c @@ -132,32 +132,38 @@ change_process_owner(const char *user) return 0; } -void tpmlib_debug_libtpms_parameters(void) +void tpmlib_debug_libtpms_parameters(TPMLIB_TPMVersion tpmversion) { - TPM_DEBUG("TPM 1.2: Compiled for %u auth, %u transport, " - "and %u DAA session slots\n", - tpmlib_get_tpm_property(TPMPROP_TPM_MIN_AUTH_SESSIONS), - tpmlib_get_tpm_property(TPMPROP_TPM_MIN_TRANS_SESSIONS), - tpmlib_get_tpm_property(TPMPROP_TPM_MIN_DAA_SESSIONS)); - TPM_DEBUG("TPM 1.2: Compiled for %u key slots, %u owner evict slots\n", - tpmlib_get_tpm_property(TPMPROP_TPM_KEY_HANDLES), - tpmlib_get_tpm_property(TPMPROP_TPM_OWNER_EVICT_KEY_HANDLES)); - TPM_DEBUG("TPM 1.2: Compiled for %u counters, %u saved sessions\n", - tpmlib_get_tpm_property(TPMPROP_TPM_MIN_COUNTERS), - tpmlib_get_tpm_property(TPMPROP_TPM_MIN_SESSION_LIST)); - TPM_DEBUG("TPM 1.2: Compiled for %u family, " - "%u delegate table entries\n", - tpmlib_get_tpm_property(TPMPROP_TPM_NUM_FAMILY_TABLE_ENTRY_MIN), - tpmlib_get_tpm_property(TPMPROP_TPM_NUM_DELEGATE_TABLE_ENTRY_MIN)); - TPM_DEBUG("TPM 1.2: Compiled for %u total NV, %u savestate, " - "%u volatile space\n", - tpmlib_get_tpm_property(TPMPROP_TPM_MAX_NV_SPACE), - tpmlib_get_tpm_property(TPMPROP_TPM_MAX_SAVESTATE_SPACE), - tpmlib_get_tpm_property(TPMPROP_TPM_MAX_VOLATILESTATE_SPACE)); + switch (tpmversion) { + case TPMLIB_TPM_VERSION_1_2: + TPM_DEBUG("TPM 1.2: Compiled for %u auth, %u transport, " + "and %u DAA session slots\n", + tpmlib_get_tpm_property(TPMPROP_TPM_MIN_AUTH_SESSIONS), + tpmlib_get_tpm_property(TPMPROP_TPM_MIN_TRANS_SESSIONS), + tpmlib_get_tpm_property(TPMPROP_TPM_MIN_DAA_SESSIONS)); + TPM_DEBUG("TPM 1.2: Compiled for %u key slots, %u owner evict slots\n", + tpmlib_get_tpm_property(TPMPROP_TPM_KEY_HANDLES), + tpmlib_get_tpm_property(TPMPROP_TPM_OWNER_EVICT_KEY_HANDLES)); + TPM_DEBUG("TPM 1.2: Compiled for %u counters, %u saved sessions\n", + tpmlib_get_tpm_property(TPMPROP_TPM_MIN_COUNTERS), + tpmlib_get_tpm_property(TPMPROP_TPM_MIN_SESSION_LIST)); + TPM_DEBUG("TPM 1.2: Compiled for %u family, " + "%u delegate table entries\n", + tpmlib_get_tpm_property(TPMPROP_TPM_NUM_FAMILY_TABLE_ENTRY_MIN), + tpmlib_get_tpm_property(TPMPROP_TPM_NUM_DELEGATE_TABLE_ENTRY_MIN)); + TPM_DEBUG("TPM 1.2: Compiled for %u total NV, %u savestate, " + "%u volatile space\n", + tpmlib_get_tpm_property(TPMPROP_TPM_MAX_NV_SPACE), + tpmlib_get_tpm_property(TPMPROP_TPM_MAX_SAVESTATE_SPACE), + tpmlib_get_tpm_property(TPMPROP_TPM_MAX_VOLATILESTATE_SPACE)); #if 0 - TPM_DEBUG("TPM1.2: Compiled for %u NV defined space\n", - tpmlib_get_tpm_property(TPMPROP_TPM_MAX_NV_DEFINED_SIZE)); + TPM_DEBUG("TPM1.2: Compiled for %u NV defined space\n", + tpmlib_get_tpm_property(TPMPROP_TPM_MAX_NV_DEFINED_SIZE)); #endif + break; + case TPMLIB_TPM_VERSION_2: + break; + } } char *fd_to_filename(int fd) diff --git a/src/swtpm/utils.h b/src/swtpm/utils.h index ad93717..c5d718f 100644 --- a/src/swtpm/utils.h +++ b/src/swtpm/utils.h @@ -49,7 +49,7 @@ typedef void (*sighandler_t)(int); int install_sighandlers(int pipefd[2], sighandler_t handler); int change_process_owner(const char *owner); -void tpmlib_debug_libtpms_parameters(void); +void tpmlib_debug_libtpms_parameters(TPMLIB_TPMVersion); char *fd_to_filename(int fd);