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 <stefanb@linux.vnet.ibm.com>
This commit is contained in:
Stefan Berger 2016-12-21 17:01:06 -05:00
parent 66b42f52ef
commit fbc596abbb
23 changed files with 384 additions and 110 deletions

View File

@ -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

View File

@ -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)

4
dist/swtpm.spec vendored
View File

@ -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

4
dist/swtpm.spec.in vendored
View File

@ -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

View File

@ -38,6 +38,8 @@
#ifndef SWTPM_TPM_H
#define SWTPM_TPM_H
#include <libtpms/tpm_library.h>
#define SWTPM_VER_MAJOR @SWTPM_VER_MAJOR@
#define SWTPM_VER_MINOR @SWTPM_VER_MINOR@
#define SWTPM_VER_MICRO @SWTPM_VER_MICRO@

View File

@ -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=<fd>|file=<path>][,level=<n>][,prefix=<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=<fd>|file=<path>][,level=<n>]\fR[,prefix=<prefix>][,truncate]" 4
.IX Item "--log [fd=<fd>|file=<path>][,level=<n>][,prefix=<prefix>][,truncate]"
Enable logging to a file given its file descriptor or its path. Use '\-' for path to
suppress the logging.

View File

@ -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=E<lt>fdE<gt>|file=E<lt>pathE<gt>][,level=E<lt>nE<gt>][,prefix=E<lt>prefixE<gt>][,truncate]>
=item B<--tpm2>
Choose TPM 2 functionality; by default a TPM 1.2 is chosen.
=item B<--log [fd=E<lt>fdE<gt>|file=E<lt>pathE<gt>][,level=E<lt>nE<gt>]>[,prefix=E<lt>prefixE<gt>][,truncate]
Enable logging to a file given its file descriptor or its path. Use '-' for path to
suppress the logging.

View File

@ -173,6 +173,9 @@ The device major number to use; can be omitted.
.IP "\fB\-m <minor> | \-\-min=<minor>\fR" 4
.IX Item "-m <minor> | --min=<minor>"
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 <user> | \-\-runas=<user>\fR" 4
.IX Item "-r <user> | --runas=<user>"
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

View File

@ -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 E<lt>userE<gt> | --runas=E<lt>userE<gt>>
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

View File

@ -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)

View File

@ -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");

View File

@ -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 <user> : 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;

View File

@ -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;
}

View File

@ -59,6 +59,7 @@ struct mainLoopParams {
int fd;
struct ctrlchannel *cc;
uint32_t locality_flags;
TPMLIB_TPMVersion tpmversion;
};
int mainLoop(struct mainLoopParams *mlp,

View File

@ -1,7 +1,7 @@
/*
* options.c -- Option parsing
*
* (c) Copyright IBM Corporation 2014.
* (c) Copyright IBM Corporation 2014, 2015.
*
* Author: Stefan Berger <stefanb@us.ibm.com>
*

View File

@ -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 <user>: 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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -51,8 +51,12 @@
#define TPM_FILENAME_MAX 20
#include <libtpms/tpm_library.h>
TPM_RESULT SWTPM_NVRAM_Init(void);
void SWTPM_NVRAM_Set_TPMVersion(TPMLIB_TPMVersion version);
/*
Basic abstraction for read and write
*/

View File

@ -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;
}

View File

@ -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_ */

View File

@ -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)

View File

@ -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);