Use the IBM TSS to implement the functions as an alternative to the command line tools. The algorithm_string_to_algid() function supports only the digest algorithms in use. The table has place holders for other algorithms as they are needed and the C strings are defined. The table can also be used for an algorithm ID to string function if it's ever needed. When using the IBM TSS, link in its library. Signed-off-by: Ken Goldman <kgoldman@xxxxxxxxxx> Please review the configure.ac change. --- configure.ac | 8 ++ src/Makefile.am | 15 +++- src/pcr_ibmtss.c | 192 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 213 insertions(+), 2 deletions(-) create mode 100644 src/pcr_ibmtss.c diff --git a/configure.ac b/configure.ac index e1ed100..4f6fe7c 100644 --- a/configure.ac +++ b/configure.ac @@ -30,10 +30,17 @@ AC_SUBST(KERNEL_HEADERS) AC_CHECK_HEADER(unistd.h) AC_CHECK_HEADERS(openssl/conf.h) +# Intel TSS AC_CHECK_LIB([tss2-esys], [Esys_Free]) AC_CHECK_LIB([tss2-rc], [Tss2_RC_Decode]) AM_CONDITIONAL([USE_PCRTSS], [test "x$ac_cv_lib_tss2_esys_Esys_Free" = "xyes"]) +# IBM TSS include files +AC_CHECK_HEADER(ibmtss/tss.h, [have_ibmtss=true], + [have_ibmtss=false], + [[#define TPM_POSIX]]) +AM_CONDITIONAL([USE_IBMTSS], $have_ibmtss) + AC_CHECK_HEADERS(sys/xattr.h, , [AC_MSG_ERROR([sys/xattr.h header not found. You need the c-library development package.])]) AC_CHECK_HEADERS(keyutils.h, , [AC_MSG_ERROR([keyutils.h header not found. You need the libkeyutils development package.])]) @@ -79,5 +86,6 @@ echo " debug: $pkg_cv_enable_debug" echo " openssl-conf: $enable_openssl_conf" echo " tss2-esys: $ac_cv_lib_tss2_esys_Esys_Free" echo " tss2-rc-decode: $ac_cv_lib_tss2_rc_Tss2_RC_Decode" +echo " ibmtss: $have_ibmtss" echo " doc: $have_doc" echo diff --git a/src/Makefile.am b/src/Makefile.am index d6c779f..f89d971 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -22,10 +22,21 @@ evmctl_CPPFLAGS = $(AM_CPPFLAGS) $(LIBCRYPTO_CFLAGS) evmctl_LDFLAGS = $(LDFLAGS_READLINE) evmctl_LDADD = $(LIBCRYPTO_LIBS) -lkeyutils libimaevm.la +# USE_PCRTSS uses the Intel TSS if USE_PCRTSS -evmctl_SOURCES += pcr_tss.c + evmctl_SOURCES += pcr_tss.c + +# USE_IBMTSS uses the IBM TSS +else +if USE_IBMTSS + evmctl_SOURCES += pcr_ibmtss.c + evmctl_LDADD += -libmtss + +# uses the IBM TSS command line utilities else -evmctl_SOURCES += pcr_tsspcrread.c + evmctl_SOURCES += pcr_tsspcrread.c + +endif endif AM_CPPFLAGS = -I$(top_srcdir) -include config.h diff --git a/src/pcr_ibmtss.c b/src/pcr_ibmtss.c new file mode 100644 index 0000000..551f9c4 --- /dev/null +++ b/src/pcr_ibmtss.c @@ -0,0 +1,192 @@ +/* + * ima-evm-utils - IMA/EVM support utilities + * + * Copyright (C) 2021 IBM + * + * Authors: + * Ken Goldman <kgoldman@xxxxxxxxxx> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the GNU General Public License in all respects + * for all of the code used other than as permitted herein. If you modify + * file(s) with this exception, you may extend this exception to your + * version of the file(s), but you are not obligated to do so. If you do not + * wish to do so, delete this exception statement from your version. If you + * delete this exception statement from all source files in the program, + * then also delete it in the license file. + * + * File: pcr_tsspcrread.c + * PCR reading implementation based on IBM TSS2 + */ + +#include <errno.h> +#include <limits.h> +#include <stdio.h> +#include <string.h> +#include <stdint.h> + +#include <openssl/sha.h> + +#define USE_FPRINTF +#include "utils.h" +#include "imaevm.h" + +#define TPM_POSIX /* use Posix, not Windows constructs in TSS */ +#undef MAX_DIGEST_SIZE /* imaevm uses a different value than the TSS */ +#include <ibmtss/tss.h> + +#define CMD "tsspcrread" + +static char path[PATH_MAX]; + +int tpm2_pcr_supported(void) +{ + if (imaevm_params.verbose > LOG_INFO) + log_info("Using %s to read PCRs.\n", CMD); + + if (get_cmd_path(CMD, path, sizeof(path))) { + log_debug("Couldn't find '%s' in $PATH\n", CMD); + return 0; + } + + log_debug("Found '%s' in $PATH\n", CMD); + return 1; +} + +/* Table mapping C strings to TCG algorithm identifiers */ +typedef struct tdAlgorithm_Map { + const char *algorithm_string; + TPMI_ALG_HASH algid; +} Algorithm_Map; + +Algorithm_Map algorithm_map[] = { + { "sha1", TPM_ALG_SHA1}, + { "sha256", TPM_ALG_SHA256}, +#if 0 /* uncomment as these digest algorithms are supported */ + { "", TPM_ALG_SHA384}, + { "", TPM_ALG_SHA512}, + { "", TPM_ALG_SM3_256}, + { "", TPM_ALG_SHA3_256}, + { "", TPM_ALG_SHA3_384}, + { "", TPM_ALG_SHA3_512}, +#endif +}; + +/* + * algorithm_string_to_algid() converts a digest algorithm from a C string to a + * TCG algorithm identifier as defined in the TCG Algorithm Regisrty.. + * + * Returns TPM_ALG_ERROR if the string has an unsupported value. + */ +static TPMI_ALG_HASH algorithm_string_to_algid(const char *algorithm_string) +{ + size_t i; + + for (i=0 ; i < sizeof(algorithm_map)/sizeof(Algorithm_Map) ; i++) { + if (strcmp(algorithm_string, algorithm_map[i].algorithm_string) + == 0) { + return algorithm_map[i].algid; /* if match */ + } + } + return TPM_ALG_ERROR; +} + +/* tpm2_pcr_read() reads the PCR + * + * algo_name: PCR digest algorithm (the PCR bank) as a C string + * pcr_handle: PCR number to read + * hwpcr: buffer for the PCR output in binary + * len: allocated size of hwpcr and should match the digest algorithm + */ +int tpm2_pcr_read(const char *algo_name, uint32_t pcr_handle, uint8_t *hwpcr, + int len, char **errmsg) +{ + int ret = 0; /* function return code */ + TPM_RC rc = 0; /* TCG return code */ + TPM_RC rc1 = 0; /* secondary return code */ + PCR_Read_In pcr_read_in; /* command input */ + PCR_Read_Out pcr_read_out; /* response output */ + TSS_CONTEXT *tss_context = NULL; + TPMI_ALG_HASH alg_id; /* PCR algorithm */ + + alg_id = algorithm_string_to_algid(algo_name); + if (alg_id == TPM_ALG_ERROR) { + ret = asprintf(errmsg, "tpm2_pcr_read: unknown algorithm %s", + algo_name); + if (ret == -1) /* the contents of errmsg is undefined */ + *errmsg = NULL; + rc = 1; + goto end; + } + rc = TSS_Create(&tss_context); + if (rc != 0) + goto end; + /* call TSS to execute the command */ + pcr_read_in.pcrSelectionIn.count = 1; + pcr_read_in.pcrSelectionIn.pcrSelections[0].hash = alg_id; + pcr_read_in.pcrSelectionIn.pcrSelections[0].sizeofSelect = 3; + pcr_read_in.pcrSelectionIn.pcrSelections[0].pcrSelect[0] = 0; + pcr_read_in.pcrSelectionIn.pcrSelections[0].pcrSelect[1] = 0; + pcr_read_in.pcrSelectionIn.pcrSelections[0].pcrSelect[2] = 0; + pcr_read_in.pcrSelectionIn.pcrSelections[0].pcrSelect[pcr_handle / 8] = + 1 << (pcr_handle % 8); + rc = TSS_Execute(tss_context, + (RESPONSE_PARAMETERS *)&pcr_read_out, + (COMMAND_PARAMETERS *)&pcr_read_in, + NULL, + TPM_CC_PCR_Read, + TPM_RH_NULL, NULL, 0); + if (rc != 0) + goto end; + /* nothing read, bank missing */ + if (pcr_read_out.pcrValues.count == 0) { + ret = asprintf(errmsg, "tpm2_pcr_read: returned count 0 for %s", + algo_name); + if (ret == -1) /* the contents of errmsg is undefined */ + *errmsg = NULL; + rc = 1; + goto end; + } + /* len parameter did not match the digest algorithm */ + else if (pcr_read_out.pcrValues.digests[0].t.size != len) { + ret = asprintf(errmsg, + "tpm2_pcr_read: " + "expected length %d actual %u for %s", + len, pcr_read_out.pcrValues.digests[0].t.size, + algo_name); + if (ret == -1) /* the contents of errmsg is undefined */ + *errmsg = NULL; + rc = 1; + goto end; + } + else { + memcpy(hwpcr, + pcr_read_out.pcrValues.digests[0].t.buffer, + pcr_read_out.pcrValues.digests[0].t.size); + } + end: + rc1 = TSS_Delete(tss_context); + if (rc == 0) + rc = rc1; + /* map TCG return code to function return code */ + if (rc == 0) + return 0; + else + return -1; +} + -- 2.25.1