1
0
mirror of https://git.code.sf.net/p/linux-ima/ima-evm-utils synced 2025-04-27 22:32:31 +02:00

ima-evm-utils: Add support for Intel TSS2 for PCR reading

This patch makes it possible to use the Intel TSS2 for getting
PCR values from the SHA1/SHA256 banks on a TPM2.
It is somewhat naive as it doesn't use the multi-PCR selection
that TSS2 is capable of, that is for a future patch.

Signed-off-by: Patrick Uiterwijk <patrick@puiterwijk.org>
[zohar@linux.ibm.com: added missing "stdint.h" in pcr_tsspcrread.c]
Signed-off-by: Mimi Zohar <zohar@linux.ibm.com>
This commit is contained in:
Patrick Uiterwijk 2020-02-24 15:04:33 -08:00 committed by Mimi Zohar
parent e532fb65fd
commit 03f99ea6d0
9 changed files with 386 additions and 83 deletions

View File

@ -34,6 +34,11 @@ AC_CHECK_PROG(TSSPCRREAD, [tsspcrread], yes, no)
if test "x$TSSPCRREAD" = "xyes"; then
AC_DEFINE(HAVE_TSSPCRREAD, 1, [Define to 1 if you have tsspcrread binary installed])
fi
AM_CONDITIONAL([USE_PCRTSSPCRREAD], [test "x$TSSPCRREAD" = "xyes"])
AC_CHECK_LIB([tss2-esys], [Esys_PCR_Read])
AC_CHECK_LIB([tss2-rc], [Tss2_RC_Decode])
AM_CONDITIONAL([USE_PCRTSS], [test "x$ac_cv_lib_tss2_esys_Esys_PCR_Read" = "xyes"])
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.])])
@ -78,4 +83,6 @@ echo "Configuration:"
echo " debug: $pkg_cv_enable_debug"
echo " openssl-conf: $enable_openssl_conf"
echo " tsspcrread: $TSSPCRREAD"
echo " tss2-esys: $ac_cv_lib_tss2_esys_Esys_PCR_Read"
echo " tss2-rc-decode: $ac_cv_lib_tss2_rc_Tss2_RC_Decode"
echo

View File

@ -17,11 +17,21 @@ hash_info.h: Makefile
bin_PROGRAMS = evmctl
evmctl_SOURCES = evmctl.c
evmctl_SOURCES = evmctl.c utils.c
evmctl_CPPFLAGS = $(AM_CPPFLAGS) $(LIBCRYPTO_CFLAGS)
evmctl_LDFLAGS = $(LDFLAGS_READLINE)
evmctl_LDADD = $(LIBCRYPTO_LIBS) -lkeyutils libimaevm.la
if USE_PCRTSS
evmctl_SOURCES += pcr_tss.c
else
if USE_PCRTSSPCRREAD
evmctl_SOURCES += pcr_tsspcrread.c
else
evmctl_SOURCES += pcr_none.c
endif
endif
AM_CPPFLAGS = -I$(top_srcdir) -include config.h
CLEANFILES = hash_info.h

View File

@ -64,6 +64,8 @@
#include <openssl/rsa.h>
#include <openssl/engine.h>
#include "hash_info.h"
#include "pcr.h"
#include "utils.h"
#ifndef XATTR_APPAARMOR_SUFFIX
#define XATTR_APPARMOR_SUFFIX "apparmor"
@ -230,35 +232,6 @@ static int find_xattr(const char *list, int list_size, const char *xattr)
return 0;
}
static int hex_to_bin(char ch)
{
if ((ch >= '0') && (ch <= '9'))
return ch - '0';
ch = tolower(ch);
if ((ch >= 'a') && (ch <= 'f'))
return ch - 'a' + 10;
return -1;
}
static int hex2bin(void *dst, const char *src, size_t count)
{
int hi, lo;
while (count--) {
if (*src == ' ')
src++;
hi = hex_to_bin(*src++);
lo = hex_to_bin(*src++);
if ((hi < 0) || (lo < 0))
return -1;
*(uint8_t *)dst++ = (hi << 4) | lo;
}
return 0;
}
#define hex_asc_lo(x) hex_asc[((x) & 0x0f)]
#define hex_asc_hi(x) hex_asc[((x) & 0xf0) >> 4]
@ -1422,58 +1395,6 @@ static int tpm_pcr_read(int idx, uint8_t *pcr, int len)
return result;
}
#ifdef HAVE_TSSPCRREAD
static int tpm2_pcrread = 1;
static int tpm2_pcr_read(const char *algo_name, int idx, uint8_t *hwpcr,
int len, char **errmsg)
{
FILE *fp;
char pcr[100]; /* may contain an error */
char cmd[50];
int ret;
sprintf(cmd, "tsspcrread -halg %s -ha %d -ns 2> /dev/null",
algo_name, idx);
fp = popen(cmd, "r");
if (!fp) {
ret = asprintf(errmsg, "popen failed: %s", strerror(errno));
if (ret == -1) /* the contents of errmsg is undefined */
*errmsg = NULL;
return -1;
}
if (fgets(pcr, sizeof(pcr), fp) == NULL) {
ret = asprintf(errmsg, "tsspcrread failed: %s",
strerror(errno));
if (ret == -1) /* the contents of errmsg is undefined */
*errmsg = NULL;
ret = pclose(fp);
return -1;
}
/* get the popen "cmd" return code */
ret = pclose(fp);
/* Treat an unallocated bank as an error */
if (!ret && (strlen(pcr) < SHA_DIGEST_LENGTH))
ret = -1;
if (!ret)
hex2bin(hwpcr, pcr, len);
else
*errmsg = strndup(pcr, strlen(pcr) - 1); /* remove newline */
return ret;
}
#else
static int tpm2_pcrread = 0;
static int tpm2_pcr_read(const char *algo_name, int idx, uint8_t *hwpcr,
int len, char **errmsg)
{
return -1;
}
#endif
#define TCG_EVENT_NAME_LEN_MAX 255
struct template_entry {
@ -1866,7 +1787,7 @@ static int read_tpm_banks(int num_banks, struct tpm_bank_info *bank)
return 0;
/* Any userspace applications available for reading TPM 2.0 PCRs? */
if (!tpm2_pcrread) {
if (!tpm2_pcr_supported()) {
log_debug("Failed to read TPM 2.0 PCRs\n");
return 1;
}

3
src/pcr.h Normal file
View File

@ -0,0 +1,3 @@
int tpm2_pcr_supported(void);
int tpm2_pcr_read(const char *algo_name, int idx, uint8_t *hwpcr,
int len, char **errmsg);

52
src/pcr_none.c Normal file
View File

@ -0,0 +1,52 @@
/*
* ima-evm-utils - IMA/EVM support utilities
*
* Copyright (C) 2011 Nokia Corporation
* Copyright (C) 2011,2012,2013 Intel Corporation
* Copyright (C) 2013,2014 Samsung Electronics
*
* Authors:
* Dmitry Kasatkin <dmitry.kasatkin@nokia.com>
* <dmitry.kasatkin@intel.com>
* <d.kasatkin@samsung.com>
*
* 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_none.c
* PCR reading implementation that always fails
*/
#include <stdint.h>
int tpm2_pcr_supported(void)
{
return 0;
}
int tpm2_pcr_read(const char *algo_name, int idx, uint8_t *hwpcr,
int len, char **errmsg)
{
return -1;
}

178
src/pcr_tss.c Normal file
View File

@ -0,0 +1,178 @@
/*
* ima-evm-utils - IMA/EVM support utilities
*
* Copyright (C) 2011 Nokia Corporation
* Copyright (C) 2011,2012,2013 Intel Corporation
* Copyright (C) 2013,2014 Samsung Electronics
*
* Authors:
* Dmitry Kasatkin <dmitry.kasatkin@nokia.com>
* <dmitry.kasatkin@intel.com>
* <d.kasatkin@samsung.com>
*
* 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_tss.c
* PCR reading implementation based on Intel TSS2
*/
#include <stdio.h>
#include <string.h>
#include <openssl/sha.h>
#ifdef HAVE_LIBTSS2_ESYS
#include <tss2/tss2_esys.h>
#ifdef HAVE_LIBTSS2_RC
#include <tss2/tss2_rc.h>
#endif
#endif
int tpm2_pcr_supported(void)
{
return 1;
}
static int pcr_selections_match(TPML_PCR_SELECTION *a, TPML_PCR_SELECTION *b)
{
if (a->count != b->count)
return 0;
for (int i = 0; i < a->count; i++) {
if (a->pcrSelections[i].hash != b->pcrSelections[i].hash)
return 0;
if (a->pcrSelections[i].sizeofSelect != b->pcrSelections[i].sizeofSelect)
return 0;
for (int j = 0; j < a->pcrSelections[i].sizeofSelect; j++) {
if (a->pcrSelections[i].pcrSelect[j] != b->pcrSelections[i].pcrSelect[j])
return 0;
}
}
return 1;
}
static inline int tpm2_set_errmsg(char **errmsg, const char *message, TSS2_RC ret)
{
#ifdef HAVE_LIBTSS2_RC
return asprintf(errmsg, "%s: %s", message, Tss2_RC_Decode(ret));
#else
return asprintf(errmsg, "%s: #%d", message, ret);
#endif
}
static TPM2_ALG_ID algo_to_tss2(const char *algo_name)
{
if (!strcmp(algo_name, "sha1"))
return TPM2_ALG_SHA1;
else if (!strcmp(algo_name, "sha256"))
return TPM2_ALG_SHA256;
return TPM2_ALG_ERROR;
}
int tpm2_pcr_read(const char *algo_name, int idx, uint8_t *hwpcr,
int len, char **errmsg)
{
TSS2_ABI_VERSION abi_version = {
.tssCreator = 1,
.tssFamily = 2,
.tssLevel = 1,
.tssVersion = 108,
};
ESYS_CONTEXT *ctx = NULL;
TSS2_RC ret = 0;
TPML_PCR_SELECTION *pcr_select_out;
TPML_DIGEST *pcr_digests;
UINT32 pcr_update_counter;
TPM2_ALG_ID algid = algo_to_tss2(algo_name);
if (algid == TPM2_ALG_ERROR) {
ret = asprintf(errmsg, "unsupported tss2 algorithm");
if (ret == -1) /* the contents of errmsg are undefined */
*errmsg = NULL;
return -1;
}
TPML_PCR_SELECTION pcr_select_in = {
.count = 1,
.pcrSelections = {
{
.hash = algid,
.sizeofSelect = 3,
.pcrSelect = { 0x00, 0x00, 0x00 },
}
}
};
pcr_select_in.pcrSelections[0].pcrSelect[idx / 8] = (1 << (idx % 8));
ret = Esys_Initialize(&ctx, NULL, &abi_version);
if (ret != TPM2_RC_SUCCESS) {
ret = tpm2_set_errmsg(errmsg, "esys initialize failed", ret);
if (ret == -1) /* the contents of errmsg are undefined */
*errmsg = NULL;
return -1;
}
ret = Esys_PCR_Read(ctx,
ESYS_TR_NONE,
ESYS_TR_NONE,
ESYS_TR_NONE,
&pcr_select_in,
&pcr_update_counter,
&pcr_select_out,
&pcr_digests);
Esys_Finalize(&ctx);
if (ret != TPM2_RC_SUCCESS) {
ret = tpm2_set_errmsg(errmsg, "esys PCR reading failed", ret);
if (ret == -1) /* the contents of errmsg is undefined */
*errmsg = NULL;
return -1;
}
if (!pcr_selections_match(&pcr_select_in, pcr_select_out)) {
Esys_Free(pcr_select_out);
Esys_Free(pcr_digests);
ret = asprintf(errmsg, "TPM returned incorrect PCRs");
if (ret == -1) /* the contents of errmsg are undefined */
*errmsg = NULL;
return -1;
}
Esys_Free(pcr_select_out);
if (pcr_digests->count != 1 || pcr_digests->digests[0].size != len) {
Esys_Free(pcr_digests);
ret = asprintf(errmsg, "TPM returned incorrect digests");
if (ret == -1) /* the contents of errmsg is undefined */
*errmsg = NULL;
return -1;
}
memcpy(hwpcr, pcr_digests->digests[0].buffer, len);
Esys_Free(pcr_digests);
return 0;
}

95
src/pcr_tsspcrread.c Normal file
View File

@ -0,0 +1,95 @@
/*
* ima-evm-utils - IMA/EVM support utilities
*
* Copyright (C) 2011 Nokia Corporation
* Copyright (C) 2011,2012,2013 Intel Corporation
* Copyright (C) 2013,2014 Samsung Electronics
*
* Authors:
* Dmitry Kasatkin <dmitry.kasatkin@nokia.com>
* <dmitry.kasatkin@intel.com>
* <d.kasatkin@samsung.com>
*
* 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 <stdio.h>
#include <string.h>
#include <stdint.h>
#include <openssl/sha.h>
#include "utils.h"
int tpm2_pcr_supported(void)
{
return 1;
}
int tpm2_pcr_read(const char *algo_name, int idx, uint8_t *hwpcr,
int len, char **errmsg)
{
FILE *fp;
char pcr[100]; /* may contain an error */
char cmd[50];
int ret;
sprintf(cmd, "tsspcrread -halg %s -ha %d -ns 2> /dev/null",
algo_name, idx);
fp = popen(cmd, "r");
if (!fp) {
ret = asprintf(errmsg, "popen failed: %s", strerror(errno));
if (ret == -1) /* the contents of errmsg is undefined */
*errmsg = NULL;
return -1;
}
if (fgets(pcr, sizeof(pcr), fp) == NULL) {
ret = asprintf(errmsg, "tsspcrread failed: %s",
strerror(errno));
if (ret == -1) /* the contents of errmsg is undefined */
*errmsg = NULL;
ret = pclose(fp);
return -1;
}
/* get the popen "cmd" return code */
ret = pclose(fp);
/* Treat an unallocated bank as an error */
if (!ret && (strlen(pcr) < SHA_DIGEST_LENGTH))
ret = -1;
if (!ret)
hex2bin(hwpcr, pcr, len);
else
*errmsg = strndup(pcr, strlen(pcr) - 1); /* remove newline */
return ret;
}

32
src/utils.c Normal file
View File

@ -0,0 +1,32 @@
#include <stdint.h>
#include "utils.h"
int hex_to_bin(char ch)
{
if ((ch >= '0') && (ch <= '9'))
return ch - '0';
ch = tolower(ch);
if ((ch >= 'a') && (ch <= 'f'))
return ch - 'a' + 10;
return -1;
}
int hex2bin(void *dst, const char *src, size_t count)
{
int hi, lo;
while (count--) {
if (*src == ' ')
src++;
hi = hex_to_bin(*src++);
lo = hex_to_bin(*src++);
if ((hi < 0) || (lo < 0))
return -1;
*(uint8_t *)dst++ = (hi << 4) | lo;
}
return 0;
}

5
src/utils.h Normal file
View File

@ -0,0 +1,5 @@
#include <ctype.h>
#include <sys/types.h>
int hex_to_bin(char ch);
int hex2bin(void *dst, const char *src, size_t count);