From patchwork Tue Jan 21 20:01:40 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Berger X-Patchwork-Id: 1226740 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [203.11.71.2]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 482KFB2NS9z9sRG for ; Wed, 22 Jan 2020 07:02:06 +1100 (AEDT) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.ibm.com Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 482KF96vCfzDqRn for ; Wed, 22 Jan 2020 07:02:05 +1100 (AEDT) X-Original-To: slof@lists.ozlabs.org Delivered-To: slof@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=linux.ibm.com (client-ip=148.163.156.1; helo=mx0a-001b2d01.pphosted.com; envelope-from=stefanb@linux.ibm.com; receiver=) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.ibm.com Received: from mx0a-001b2d01.pphosted.com (mx0a-001b2d01.pphosted.com [148.163.156.1]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 482KF03BqZzDqFv for ; Wed, 22 Jan 2020 07:01:55 +1100 (AEDT) Received: from pps.filterd (m0098410.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.42/8.16.0.42) with SMTP id 00LJqn20146561; Tue, 21 Jan 2020 15:01:52 -0500 Received: from ppma04wdc.us.ibm.com (1a.90.2fa9.ip4.static.sl-reverse.com [169.47.144.26]) by mx0a-001b2d01.pphosted.com with ESMTP id 2xp1jg75ga-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 21 Jan 2020 15:01:52 -0500 Received: from pps.filterd (ppma04wdc.us.ibm.com [127.0.0.1]) by ppma04wdc.us.ibm.com (8.16.0.27/8.16.0.27) with SMTP id 00LK0LGC032226; Tue, 21 Jan 2020 20:01:50 GMT Received: from b03cxnp08028.gho.boulder.ibm.com (b03cxnp08028.gho.boulder.ibm.com [9.17.130.20]) by ppma04wdc.us.ibm.com with ESMTP id 2xksn6eh2p-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 21 Jan 2020 20:01:50 +0000 Received: from b03ledav003.gho.boulder.ibm.com (b03ledav003.gho.boulder.ibm.com [9.17.130.234]) by b03cxnp08028.gho.boulder.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 00LK1nOo53477648 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 21 Jan 2020 20:01:49 GMT Received: from b03ledav003.gho.boulder.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 5E9226A061; Tue, 21 Jan 2020 20:01:49 +0000 (GMT) Received: from b03ledav003.gho.boulder.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id CD66A6A058; Tue, 21 Jan 2020 20:01:48 +0000 (GMT) Received: from sbct-3.pok.ibm.com (unknown [9.47.158.153]) by b03ledav003.gho.boulder.ibm.com (Postfix) with ESMTP; Tue, 21 Jan 2020 20:01:48 +0000 (GMT) From: Stefan Berger To: slof@lists.ozlabs.org, aik@ozlabs.ru Date: Tue, 21 Jan 2020 15:01:40 -0500 Message-Id: <20200121200147.1002075-2-stefanb@linux.ibm.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200121200147.1002075-1-stefanb@linux.ibm.com> References: <20200121200147.1002075-1-stefanb@linux.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:6.0.138, 18.0.634 definitions=2020-01-21_06:2020-01-21, 2020-01-21 signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 clxscore=1015 bulkscore=0 suspectscore=8 lowpriorityscore=0 spamscore=0 malwarescore=0 mlxlogscore=999 mlxscore=0 impostorscore=0 phishscore=0 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-1910280000 definitions=main-2001210148 Subject: [SLOF] [PATCH v7 1/8] slof: Implement SLOF_get_keystroke() and SLOF_reset() X-BeenThere: slof@lists.ozlabs.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "Patches for https://github.com/aik/SLOF" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kevin@koconnor.net, Stefan Berger Errors-To: slof-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "SLOF" Implement SLOF_get_keystroke() and SLOF_reset() helper functions. Signed-off-by: Stefan Berger --- include/helpers.h | 2 ++ slof/helpers.c | 11 +++++++++++ 2 files changed, 13 insertions(+) diff --git a/include/helpers.h b/include/helpers.h index 5834bce..9a06a5c 100644 --- a/include/helpers.h +++ b/include/helpers.h @@ -42,6 +42,8 @@ extern void SLOF_encode_bootp_response(void *addr, size_t size); extern void SLOF_encode_dhcp_response(void *addr, size_t size); extern int SLOF_get_property(const char *node, const char *propname, char **addr, int *len); +extern int SLOF_get_keystroke(void); +extern void SLOF_reset(void); #define offset_of(type, member) ((long) &((type *)0)->member) #define container_of(ptr, type, member) ({ \ diff --git a/slof/helpers.c b/slof/helpers.c index dfb0c13..9d37bc3 100644 --- a/slof/helpers.c +++ b/slof/helpers.c @@ -224,3 +224,14 @@ int SLOF_get_property(const char *node, const char *propname, *addr = (char *)forth_pop(); return 0; } + +int SLOF_get_keystroke(void) +{ + forth_eval("key"); + return forth_pop(); +} + +void SLOF_reset(void) +{ + forth_eval("reset-all"); +} From patchwork Tue Jan 21 20:01:41 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Berger X-Patchwork-Id: 1226743 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [203.11.71.2]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 482KFW47Rzz9sRk for ; Wed, 22 Jan 2020 07:02:23 +1100 (AEDT) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.ibm.com Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 482KFW38pkzDqSh for ; Wed, 22 Jan 2020 07:02:23 +1100 (AEDT) X-Original-To: slof@lists.ozlabs.org Delivered-To: slof@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=linux.ibm.com (client-ip=148.163.156.1; helo=mx0a-001b2d01.pphosted.com; envelope-from=stefanb@linux.ibm.com; receiver=) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.ibm.com Received: from mx0a-001b2d01.pphosted.com (mx0a-001b2d01.pphosted.com [148.163.156.1]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 482KF175TqzDqFv for ; Wed, 22 Jan 2020 07:01:57 +1100 (AEDT) Received: from pps.filterd (m0187473.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.42/8.16.0.42) with SMTP id 00LJqeWv002694; Tue, 21 Jan 2020 15:01:54 -0500 Received: from ppma01wdc.us.ibm.com (fd.55.37a9.ip4.static.sl-reverse.com [169.55.85.253]) by mx0a-001b2d01.pphosted.com with ESMTP id 2xkxhyex96-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 21 Jan 2020 15:01:54 -0500 Received: from pps.filterd (ppma01wdc.us.ibm.com [127.0.0.1]) by ppma01wdc.us.ibm.com (8.16.0.27/8.16.0.27) with SMTP id 00LK17fT011333; Tue, 21 Jan 2020 20:01:51 GMT Received: from b03cxnp08025.gho.boulder.ibm.com (b03cxnp08025.gho.boulder.ibm.com [9.17.130.17]) by ppma01wdc.us.ibm.com with ESMTP id 2xp7x48056-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 21 Jan 2020 20:01:51 +0000 Received: from b03ledav003.gho.boulder.ibm.com (b03ledav003.gho.boulder.ibm.com [9.17.130.234]) by b03cxnp08025.gho.boulder.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 00LK1oVs53412270 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 21 Jan 2020 20:01:50 GMT Received: from b03ledav003.gho.boulder.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 0DF006A047; Tue, 21 Jan 2020 20:01:50 +0000 (GMT) Received: from b03ledav003.gho.boulder.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 7E5AD6A064; Tue, 21 Jan 2020 20:01:49 +0000 (GMT) Received: from sbct-3.pok.ibm.com (unknown [9.47.158.153]) by b03ledav003.gho.boulder.ibm.com (Postfix) with ESMTP; Tue, 21 Jan 2020 20:01:49 +0000 (GMT) From: Stefan Berger To: slof@lists.ozlabs.org, aik@ozlabs.ru Date: Tue, 21 Jan 2020 15:01:41 -0500 Message-Id: <20200121200147.1002075-3-stefanb@linux.ibm.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200121200147.1002075-1-stefanb@linux.ibm.com> References: <20200121200147.1002075-1-stefanb@linux.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:6.0.138, 18.0.634 definitions=2020-01-21_06:2020-01-21, 2020-01-21 signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 spamscore=0 clxscore=1015 phishscore=0 lowpriorityscore=0 malwarescore=0 suspectscore=9 priorityscore=1501 bulkscore=0 adultscore=1 mlxscore=0 mlxlogscore=953 impostorscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-1910280000 definitions=main-2001210148 Subject: [SLOF] [PATCH v7 2/8] slof: Make linker script variables accessible X-BeenThere: slof@lists.ozlabs.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "Patches for https://github.com/aik/SLOF" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kevin@koconnor.net, Stefan Berger Errors-To: slof-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "SLOF" Make linker script variables related to 'text' addresses available to the code so we can measure the static core root of trust contents. When hashing the 'data' part of SLOF we do not end up with the same measurements for the same firmware when booting with different configurations, so we don't make those available. Signed-off-by: Stefan Berger --- slof/OF.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 slof/OF.h diff --git a/slof/OF.h b/slof/OF.h new file mode 100644 index 0000000..981a80a --- /dev/null +++ b/slof/OF.h @@ -0,0 +1,20 @@ +/****************************************************************************** + * Copyright (c) 2020 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef _SLOF_OF_H +#define _SLOF_OF_H + +/* from OF.lds */ +extern long _slof_text; +extern long _slof_text_end; + +#endif From patchwork Tue Jan 21 20:01:42 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Berger X-Patchwork-Id: 1226742 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 482KFQ5wYzz9sRW for ; Wed, 22 Jan 2020 07:02:18 +1100 (AEDT) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.ibm.com Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 482KFQ58kWzDqSy for ; Wed, 22 Jan 2020 07:02:18 +1100 (AEDT) X-Original-To: slof@lists.ozlabs.org Delivered-To: slof@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=linux.ibm.com (client-ip=148.163.156.1; helo=mx0a-001b2d01.pphosted.com; envelope-from=stefanb@linux.ibm.com; receiver=) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.ibm.com Received: from mx0a-001b2d01.pphosted.com (mx0a-001b2d01.pphosted.com [148.163.156.1]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 482KF134CczDqFv for ; Wed, 22 Jan 2020 07:01:57 +1100 (AEDT) Received: from pps.filterd (m0098394.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.42/8.16.0.42) with SMTP id 00LJqp1E052382; Tue, 21 Jan 2020 15:01:53 -0500 Received: from ppma02dal.us.ibm.com (a.bd.3ea9.ip4.static.sl-reverse.com [169.62.189.10]) by mx0a-001b2d01.pphosted.com with ESMTP id 2xmg5ttyy2-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 21 Jan 2020 15:01:53 -0500 Received: from pps.filterd (ppma02dal.us.ibm.com [127.0.0.1]) by ppma02dal.us.ibm.com (8.16.0.27/8.16.0.27) with SMTP id 00LK1Drc026357; Tue, 21 Jan 2020 20:01:52 GMT Received: from b03cxnp08025.gho.boulder.ibm.com (b03cxnp08025.gho.boulder.ibm.com [9.17.130.17]) by ppma02dal.us.ibm.com with ESMTP id 2xksn6x5s7-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 21 Jan 2020 20:01:52 +0000 Received: from b03ledav003.gho.boulder.ibm.com (b03ledav003.gho.boulder.ibm.com [9.17.130.234]) by b03cxnp08025.gho.boulder.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 00LK1oXg26345788 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 21 Jan 2020 20:01:51 GMT Received: from b03ledav003.gho.boulder.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id CFF296A047; Tue, 21 Jan 2020 20:01:50 +0000 (GMT) Received: from b03ledav003.gho.boulder.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 4B8E26A04F; Tue, 21 Jan 2020 20:01:50 +0000 (GMT) Received: from sbct-3.pok.ibm.com (unknown [9.47.158.153]) by b03ledav003.gho.boulder.ibm.com (Postfix) with ESMTP; Tue, 21 Jan 2020 20:01:50 +0000 (GMT) From: Stefan Berger To: slof@lists.ozlabs.org, aik@ozlabs.ru Date: Tue, 21 Jan 2020 15:01:42 -0500 Message-Id: <20200121200147.1002075-4-stefanb@linux.ibm.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200121200147.1002075-1-stefanb@linux.ibm.com> References: <20200121200147.1002075-1-stefanb@linux.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:6.0.138, 18.0.634 definitions=2020-01-21_06:2020-01-21, 2020-01-21 signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 lowpriorityscore=0 spamscore=0 suspectscore=0 bulkscore=0 phishscore=0 impostorscore=0 priorityscore=1501 mlxscore=0 malwarescore=0 mlxlogscore=805 adultscore=0 clxscore=1015 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-1910280000 definitions=main-2001210148 Subject: [SLOF] [PATCH v7 3/8] qemu: Make print_version variable accessible X-BeenThere: slof@lists.ozlabs.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "Patches for https://github.com/aik/SLOF" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kevin@koconnor.net, Stefan Berger Errors-To: slof-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "SLOF" Make the print_version global variable accessible so that we can measure the firmware version. Signed-off-by: Stefan Berger --- board-qemu/include/version.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 board-qemu/include/version.h diff --git a/board-qemu/include/version.h b/board-qemu/include/version.h new file mode 100644 index 0000000..036d2b5 --- /dev/null +++ b/board-qemu/include/version.h @@ -0,0 +1,19 @@ +/****************************************************************************** + * Copyright (c) 2020 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef _SLOF_VERSION_H +#define _SLOF_VERSION_F + +/* slof/version.S */ +extern long print_version; + +#endif From patchwork Tue Jan 21 20:01:43 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Berger X-Patchwork-Id: 1226744 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [203.11.71.2]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 482KFc3YlPz9sRG for ; Wed, 22 Jan 2020 07:02:28 +1100 (AEDT) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.ibm.com Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 482KFc34KjzDqSR for ; Wed, 22 Jan 2020 07:02:28 +1100 (AEDT) X-Original-To: slof@lists.ozlabs.org Delivered-To: slof@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=linux.ibm.com (client-ip=148.163.156.1; helo=mx0a-001b2d01.pphosted.com; envelope-from=stefanb@linux.ibm.com; receiver=) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.ibm.com Received: from mx0a-001b2d01.pphosted.com (mx0a-001b2d01.pphosted.com [148.163.156.1]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 482KF203JNzDqPf for ; Wed, 22 Jan 2020 07:01:57 +1100 (AEDT) Received: from pps.filterd (m0098399.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.42/8.16.0.42) with SMTP id 00LJqm2j111267; Tue, 21 Jan 2020 15:01:54 -0500 Received: from ppma02dal.us.ibm.com (a.bd.3ea9.ip4.static.sl-reverse.com [169.62.189.10]) by mx0a-001b2d01.pphosted.com with ESMTP id 2xp3u69nf2-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 21 Jan 2020 15:01:53 -0500 Received: from pps.filterd (ppma02dal.us.ibm.com [127.0.0.1]) by ppma02dal.us.ibm.com (8.16.0.27/8.16.0.27) with SMTP id 00LJqtE7015469; Tue, 21 Jan 2020 20:01:53 GMT Received: from b03cxnp08026.gho.boulder.ibm.com (b03cxnp08026.gho.boulder.ibm.com [9.17.130.18]) by ppma02dal.us.ibm.com with ESMTP id 2xksn6x5sd-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 21 Jan 2020 20:01:52 +0000 Received: from b03ledav003.gho.boulder.ibm.com (b03ledav003.gho.boulder.ibm.com [9.17.130.234]) by b03cxnp08026.gho.boulder.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 00LK1pBK46072236 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 21 Jan 2020 20:01:51 GMT Received: from b03ledav003.gho.boulder.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 826AD6A051; Tue, 21 Jan 2020 20:01:51 +0000 (GMT) Received: from b03ledav003.gho.boulder.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 080AC6A047; Tue, 21 Jan 2020 20:01:50 +0000 (GMT) Received: from sbct-3.pok.ibm.com (unknown [9.47.158.153]) by b03ledav003.gho.boulder.ibm.com (Postfix) with ESMTP; Tue, 21 Jan 2020 20:01:50 +0000 (GMT) From: Stefan Berger To: slof@lists.ozlabs.org, aik@ozlabs.ru Date: Tue, 21 Jan 2020 15:01:43 -0500 Message-Id: <20200121200147.1002075-5-stefanb@linux.ibm.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200121200147.1002075-1-stefanb@linux.ibm.com> References: <20200121200147.1002075-1-stefanb@linux.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:6.0.138, 18.0.634 definitions=2020-01-21_06:2020-01-21, 2020-01-21 signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 phishscore=0 bulkscore=0 adultscore=0 mlxlogscore=999 lowpriorityscore=0 mlxscore=0 spamscore=0 malwarescore=0 priorityscore=1501 impostorscore=0 suspectscore=2 clxscore=1015 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-1910280000 definitions=main-2001210148 Subject: [SLOF] [PATCH v7 4/8] tpm: Add TPM CRQ driver implementation X-BeenThere: slof@lists.ozlabs.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "Patches for https://github.com/aik/SLOF" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kevin@koconnor.net, Stefan Berger Errors-To: slof-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "SLOF" This patch adds a TPM driver for the CRQ interface as used by the QEMU PAPR implementation. Also add a Readme that explains the benefits and installation procedure for the vTPM. Signed-off-by: Stefan Berger --- board-qemu/Makefile | 2 +- include/helpers.h | 1 + lib/Makefile | 2 +- lib/libtpm/Makefile | 50 +++++ lib/libtpm/Readme | 57 +++++ lib/libtpm/tcgbios_int.h | 30 +++ lib/libtpm/tpm_drivers.c | 437 +++++++++++++++++++++++++++++++++++++++ lib/libtpm/tpm_drivers.h | 82 ++++++++ slof/helpers.c | 6 + 9 files changed, 665 insertions(+), 2 deletions(-) create mode 100644 lib/libtpm/Makefile create mode 100644 lib/libtpm/Readme create mode 100644 lib/libtpm/tcgbios_int.h create mode 100644 lib/libtpm/tpm_drivers.c create mode 100644 lib/libtpm/tpm_drivers.h diff --git a/board-qemu/Makefile b/board-qemu/Makefile index 61a1367..f419202 100644 --- a/board-qemu/Makefile +++ b/board-qemu/Makefile @@ -15,7 +15,7 @@ BOARD_TARGETS = tools_build romfs_build stage1 subdirs SUBDIRS = slof COMMON_LIBS = libc libbootmsg libbases libnvram libelf libhvcall libvirtio \ - libusb libveth libe1k libnet libbootmenu + libusb libveth libe1k libnet libbootmenu libtpm all: $(BOARD_TARGETS) $(MAKE) boot_rom.bin diff --git a/include/helpers.h b/include/helpers.h index 9a06a5c..2f460d6 100644 --- a/include/helpers.h +++ b/include/helpers.h @@ -44,6 +44,7 @@ extern int SLOF_get_property(const char *node, const char *propname, char **addr, int *len); extern int SLOF_get_keystroke(void); extern void SLOF_reset(void); +extern unsigned long SLOF_get_vtpm_unit(void); #define offset_of(type, member) ((long) &((type *)0)->member) #define container_of(ptr, type, member) ({ \ diff --git a/lib/Makefile b/lib/Makefile index 1e8bb62..7369894 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -11,7 +11,7 @@ # ****************************************************************************/ SUBDIRS = libc libipmi libbootmsg libbases libnvram libelf libhvcall libvirtio \ - libusb libveth libe1k libbcm libnet libbootmenu + libusb libveth libe1k libbcm libnet libbootmenu libtpm all: subdirs diff --git a/lib/libtpm/Makefile b/lib/libtpm/Makefile new file mode 100644 index 0000000..47fc5d0 --- /dev/null +++ b/lib/libtpm/Makefile @@ -0,0 +1,50 @@ +# ***************************************************************************** +# * Copyright (c) 2015-2020 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ****************************************************************************/ + +TOPCMNDIR ?= ../.. + +CPPFLAGS = -I../libc/include $(CPUARCHDEF) -I$(INCLBRDDIR) \ + -I$(INCLCMNDIR) -I$(INCLCMNDIR)/$(CPUARCH) -I$(SLOFCMNDIR) +CPPFLAGS += -I../libhvcall + +LDFLAGS = -nostdlib + +TARGET = ../libtpm.a + + +all: $(TARGET) + +SRCS = tpm_drivers.c + +OBJS = $(SRCS:%.c=%.o) + +$(TARGET): $(OBJS) + $(AR) -rc $@ $(OBJS) + $(RANLIB) $@ + +clean: + $(RM) $(TARGET) $(OBJS) + +distclean: clean + $(RM) Makefile.dep + + +# Rules for creating the dependency file: +depend: + $(RM) Makefile.dep + $(MAKE) Makefile.dep + +Makefile.dep: Makefile + $(CC) -M $(CPPFLAGS) $(CFLAGS) $(SRCS) $(SRCSS) > Makefile.dep + +# Include dependency file if available: +-include Makefile.dep diff --git a/lib/libtpm/Readme b/lib/libtpm/Readme new file mode 100644 index 0000000..2c362ac --- /dev/null +++ b/lib/libtpm/Readme @@ -0,0 +1,57 @@ +This directory hosts (v)TPM related code. + +Background: +----------- + +A TPM is a crypto chip that is found in many systems. Besides it offering +a secure key store, among other functionality, it is also used to implement +'trusted boot'. This is realized by code in the firmware measuring parts of the +firmware's code and data as well as system data, such as the boot block, and +logging these measurements and storing (extending) them in the TPM's platform +configuration register (PCR). + +The benefits of having a TPM (or vTPM) in a system are: + +- enablement of trusted boot; this allow us to eventually extend the chain of + trust from the hypervisor to the guests +- enablement of attestation so that one can verify what software is running on + a machine (OpenPTS, OpenAttestation) +- provides TPM functionality to VMs, which includes a standardized mechanism + to store keys and other blobs (Linux trusted keys, GNU TLS's TPM extensions) + + +QEMU/KVM + SLOF support: +------------------------ + +vTPM for QEMU/KVM pSeries virtual machines is support in QEMU 5.0. + +To start a QEMU VM with an attached vTPM (swtpm), run the below shown commands. +The following will setup the vTPM so that its state will be stored in +/tmp/myvtpm1. A unique directory for each VM instance with attached vTPM +must be provided. Whenever QEMU is started, the swtpm has to be started +before it. The file 'boot_rom.bin' is SLOF with vTPM extensions built-in. + + #> mkdir -p /tmp/mytpm1 + #> swtpm socket --tpm2 --tpmstate dir=/tmp/mytpm1 \ + --ctrl type=unixio,path=/tmp/mytpm1/swtpm-sock + + In another terminal: + + #> sudo qemu-system-ppc64 -display sdl \ + -machine pseries,accel=kvm \ + -m 1024 -bios boot_rom.bin -boot menu=on \ + -nodefaults -device VGA -device pci-ohci -device usb-kbd \ + -chardev socket,id=chrtpm,path=/tmp/mytpm1/swtpm-sock \ + -tpmdev emulator,id=tpm0,chardev=chrtpm \ + -device tpm-spapr,tpmdev=tpm0 \ + -device spapr-vscsi,id=scsi0,reg=0x00002000 \ + -device virtio-blk-pci,scsi=off,bus=pci.0,addr=0x3,drive=drive-virtio-disk0,id=virtio-disk0 \ + -drive file=test.img,format=raw,if=none,id=drive-virtio-disk0 + +Notes: + - The Linux kernel in the VM must have the tpm_ibmvtpm module available + or built-in. A recent kernel is needed that enables TPM 2.0 support + in this module. + + - 'swtpm_ioctl --unix /tmp/mytpm1/swtpm-sock -s' can be used to gracefully + shut down the vTPM. diff --git a/lib/libtpm/tcgbios_int.h b/lib/libtpm/tcgbios_int.h new file mode 100644 index 0000000..835bd36 --- /dev/null +++ b/lib/libtpm/tcgbios_int.h @@ -0,0 +1,30 @@ +/***************************************************************************** + * Copyright (c) 2015-2020 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef TCGBIOS_INT_H +#define TCGBIOS_INT_H + +#include + +struct tpm_req_header { + uint16_t tag; + uint32_t totlen; + uint32_t ordinal; +} __attribute__((packed)); + +struct tpm_rsp_header { + uint16_t tag; + uint32_t totlen; + uint32_t errcode; +} __attribute__((packed)); + +#endif /* TCGBIOS_INT_H */ diff --git a/lib/libtpm/tpm_drivers.c b/lib/libtpm/tpm_drivers.c new file mode 100644 index 0000000..5005176 --- /dev/null +++ b/lib/libtpm/tpm_drivers.c @@ -0,0 +1,437 @@ +/***************************************************************************** + * Copyright (c) 2015-2020 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include +#include +#include + +#include "string.h" +#include "helpers.h" +#include "byteorder.h" +#include "tcgbios_int.h" +#include "tpm_drivers.h" +#include "libhvcall.h" +#include "paflof.h" + +#undef PAPR_VTPM_DEBUG +//#define PAPR_VTPM_DEBUG +#ifdef PAPR_VTPM_DEBUG +#define dprintf(_x ...) do { printf("VTPM CRQ: " _x); } while(0) +#else +#define dprintf(_x ...) +#endif + +#define MIN(a, b) ((a) > (b) ? (b) : (a)) + +/* layout of the command request queue for vTPM; all fields are big endian */ +struct crq { + uint8_t valid; + uint8_t msg; + uint16_t len; + uint32_t data; + uint64_t reserved; +} __attribute__((packed)); + +#define PAPR_VTPM_INIT_CRQ_COMMAND 0xC0 +#define PAPR_VTPM_VALID_COMMAND 0x80 +#define PAPR_VTPM_MSG_RESULT 0x80 + +/* crq.msg request types when crq.valid = PAPR_VTPM_INIT_CRQ_COMMAND */ +#define PAPR_VTPM_INIT_CRQ_RESULT 0x1 + +/* crq.msg request types when crq.valid = PAPR_VTPM_VALID_COMMAND */ +#define PAPR_VTPM_GET_VERSION 0x1 +#define PAPR_VTPM_TPM_COMMAND 0x2 +#define PAPR_VTPM_GET_RTCE_BUFFER_SIZE 0x3 + +#define TPM2_DEFAULT_DURATION_SHORT 750000 /* us */ +#define TPM2_DEFAULT_DURATION_MEDIUM 2000000 /* us */ +#define TPM2_DEFAULT_DURATION_LONG 2000000 /* us */ + +static const uint32_t tpm2_durations[3] = { + TPM2_DEFAULT_DURATION_SHORT, + TPM2_DEFAULT_DURATION_MEDIUM, + TPM2_DEFAULT_DURATION_LONG, +}; + +#define QUEUE_SIZE 4096 + +/* state of the PAPR CRQ VTPM driver */ +static struct { + /* whether it driver been initialized */ + bool initialized; + + /* unit number */ + unsigned long unit; + + /* CRQ queue address and size */ + unsigned char *qaddr; + unsigned long qsize; + + /* current q_entry */ + unsigned int curr_q_entry; + + /* current response CRQ */ + struct crq *response; + + /* power firmware defined state and error code */ + vtpm_drv_state driver_state; + vtpm_drv_error driver_error; + + /* size of buffer supported by hypervisor */ + unsigned int buffer_size; + + /* buffer for commands and responses */ + char *buffer; +} spapr_vtpm = { + .qsize = QUEUE_SIZE, + .driver_state = VTPM_DRV_STATE_INVALID, + .driver_error = VTPM_DRV_ERROR_NO_FAILURE, +}; + +static void vtpm_drv_state_set(vtpm_drv_state s, vtpm_drv_error e) +{ + spapr_vtpm.driver_state = s; + spapr_vtpm.driver_error = e; +} + +static vtpm_drv_error vtpm_drv_error_get(void) +{ + return spapr_vtpm.driver_error; +} + +static struct crq *spapr_get_crq(void *qaddr, unsigned long q_entry) +{ + return &((struct crq *)qaddr)[q_entry]; +} + +/* + * Get the crq where the response will be found. This + * function will clear the CRQ's valid field and advance + * the entry counter to the next entry. + */ +static struct crq *spapr_get_response_crq(void) +{ + struct crq *crq; + + dprintf("curr_q_entry = %d\n", spapr_vtpm.curr_q_entry); + + crq = spapr_get_crq(spapr_vtpm.qaddr, spapr_vtpm.curr_q_entry); + memset(crq, 0, sizeof(*crq)); + + spapr_vtpm.curr_q_entry += 1; + if (spapr_vtpm.curr_q_entry == (spapr_vtpm.qsize / sizeof(struct crq))) + spapr_vtpm.curr_q_entry = 0; + + return crq; +} + +/* + * Send a message via CRQ and wait for the response + */ +static bool spapr_send_crq_and_wait(unsigned long unit, + struct crq *crq, + struct crq **response, + unsigned timeout, + vtpm_drv_state state1, + vtpm_drv_state state2) +{ + long rc; + unsigned i; + + *response = spapr_get_response_crq(); + + vtpm_drv_state_set(state1, VTPM_DRV_ERROR_NO_FAILURE); + + rc = hv_send_crq(unit, (uint64_t *)crq); + if (rc != H_SUCCESS) { + vtpm_drv_state_set(VTPM_DRV_STATE_WAIT_INIT, + VTPM_DRV_ERROR_TPM_CRQ_ERROR); + return false; + } + + vtpm_drv_state_set(state2, VTPM_DRV_ERROR_NO_FAILURE); + + for (i = 0; i < timeout; i += 1000) { + if (((*response)->valid & PAPR_VTPM_MSG_RESULT)) + return true; + SLOF_usleep(1000); + } + + vtpm_drv_state_set(VTPM_DRV_STATE_FAILURE, + VTPM_DRV_ERROR_WAIT_TIMEOUT); + + dprintf("Received no response from CRQ\n"); + return false; +} + +/* + * Get parameters from the CRQ + */ +static bool spapr_vtpm_get_params(void) +{ + struct crq crq, *response; + static bool completed = false; /* only once */ + + if (completed) + return true; + + /* get the TPM's buffer size */ + crq.valid = PAPR_VTPM_VALID_COMMAND; + crq.msg = PAPR_VTPM_GET_RTCE_BUFFER_SIZE; + + if (!spapr_send_crq_and_wait(spapr_vtpm.unit, &crq, &response, 10, + VTPM_DRV_STATE_SEND_BUFSIZE_REQ, + VTPM_DRV_STATE_WAIT_BUFSIZE)) { + printf("%s: Failure getting RTCE buffer size from CRQ\n", + __func__); + return false; + } + + vtpm_drv_state_set(VTPM_DRV_STATE_ALLOC_RTCE_BUF, + VTPM_DRV_ERROR_NO_FAILURE); + + dprintf("RTCE buffer size: %u\n", be16_to_cpu(response->len)); + spapr_vtpm.buffer_size = be16_to_cpu(response->len); + if (spapr_vtpm.buffer_size < 1024) { + printf("%s: RTCE buffer size of %u bytes is too small. " + "Minimum is 1024 bytes.\n", __func__, + spapr_vtpm.buffer_size); + vtpm_drv_state_set(VTPM_DRV_STATE_FAILURE, + VTPM_DRV_ERROR_BAD_RTCE_SIZE); + return false; + } + spapr_vtpm.buffer = SLOF_alloc_mem(spapr_vtpm.buffer_size); + if (!spapr_vtpm.buffer) { + printf("%s: Could not allocate buffer of size %u.\n", + __func__, spapr_vtpm.buffer_size); + vtpm_drv_state_set(VTPM_DRV_STATE_FAILURE, + VTPM_DRV_ERROR_BAD_RTCE_SIZE); + return false; + } + + completed = true; + + return true; +} + +static bool spapr_vtpm_activate(void) +{ + long rc; + struct crq crq, *response; + + if (vtpm_drv_error_get() != VTPM_DRV_ERROR_NO_FAILURE) { + printf("%s: CRQ: In failure mode\n", __func__); + return false; + } + + vtpm_drv_state_set(VTPM_DRV_STATE_REG_CRQ, + VTPM_DRV_ERROR_NO_FAILURE); + + rc = hv_reg_crq(spapr_vtpm.unit, (unsigned long)spapr_vtpm.qaddr, + spapr_vtpm.qsize); + if (rc != H_SUCCESS) { + vtpm_drv_state_set(VTPM_DRV_STATE_WAIT_INIT, + VTPM_DRV_ERROR_UNEXPECTED_REG_ERROR); + printf("%s: CRQ registration failed\n", __func__); + return false; + } + + /* we always start with curr_q_entry 0 */ + spapr_vtpm.curr_q_entry = 0; + + if (!spapr_vtpm.initialized) { + + crq.valid = PAPR_VTPM_INIT_CRQ_COMMAND; + crq.msg = PAPR_VTPM_INIT_CRQ_RESULT; + + if (!spapr_send_crq_and_wait(spapr_vtpm.unit, + &crq, + &response, + 10, + VTPM_DRV_STATE_SEND_INIT, + VTPM_DRV_STATE_WAIT_INIT_COMP)) { + printf("%s: Initializing CRQ failed\n", __func__); + goto err_exit; + } + dprintf("Successfully initialized CRQ\n"); + + spapr_vtpm.initialized = true; + } + + if (spapr_vtpm_get_params()) + return true; + +err_exit: + hv_free_crq(spapr_vtpm.unit); + spapr_vtpm.unit = 0; + + return false; +} + +void spapr_vtpm_finalize(void) +{ + if (spapr_vtpm.unit) { + hv_free_crq(spapr_vtpm.unit); + spapr_vtpm.unit = 0; + } +} + +/* + * Check whether we have a CRQ underneath us; if we do, the CRQ will + * be left open. + */ +static bool spapr_vtpm_probe(void) +{ + if (!spapr_vtpm.qaddr) { + spapr_vtpm.qaddr = SLOF_alloc_mem(spapr_vtpm.qsize); + if (!spapr_vtpm.qaddr) { + printf("%s: Unable to allocate memory\n", __func__); + return false; + } + memset(spapr_vtpm.qaddr, 0, spapr_vtpm.qsize); + + dprintf("getting FORTH vtpm-unit\n"); + spapr_vtpm.unit = SLOF_get_vtpm_unit(); + if (!spapr_vtpm.unit) { + printf("%s: Could not get valid vtpm-unit\n", __func__); + return false; + } + } + + dprintf("vtpm_unit = %lx, buffer = %p\n", + spapr_vtpm.unit, spapr_vtpm.qaddr); + + if (!spapr_vtpm_activate()) + return false; + + return true; +} + +static bool spapr_vtpm_senddata(const uint8_t *const data, uint32_t len) +{ + struct crq crq; + long rc; + + if (vtpm_drv_error_get() != VTPM_DRV_ERROR_NO_FAILURE) { + printf("%s: VTPM CRQ: In failure mode\n", __func__); + return false; + } + + if (len > spapr_vtpm.buffer_size) { + printf("%s: VTPM CRQ: Send buffer too large: %u > %u\n", + __func__, len, spapr_vtpm.buffer_size); + return false; + } + + spapr_vtpm.response = spapr_get_response_crq(); + spapr_vtpm.response->data = (uint64_t)spapr_vtpm.buffer; + + crq.valid = PAPR_VTPM_VALID_COMMAND; + crq.msg = PAPR_VTPM_TPM_COMMAND; + crq.len = cpu_to_be16(len); + crq.data = (uint64_t)spapr_vtpm.buffer; + memcpy(spapr_vtpm.buffer, data, MIN(len, spapr_vtpm.buffer_size)); + + vtpm_drv_state_set(VTPM_DRV_STATE_SEND_TPM_CMD, + VTPM_DRV_ERROR_NO_FAILURE); + + rc = hv_send_crq(spapr_vtpm.unit, (uint64_t *)&crq); + + if (rc == H_SUCCESS) + vtpm_drv_state_set(VTPM_DRV_STATE_WAIT_TPM_RSP, + VTPM_DRV_ERROR_NO_FAILURE); + else + vtpm_drv_state_set(VTPM_DRV_STATE_WAIT_INIT, + VTPM_DRV_ERROR_UNEXPECTED_SEND_ERROR); + + return (rc == H_SUCCESS); +} + +static bool spapr_vtpm_waitresponseready(enum tpm_duration_type to_t) +{ + uint32_t timeout = tpm2_durations[to_t]; + int i; + + if (vtpm_drv_error_get() != VTPM_DRV_ERROR_NO_FAILURE) { + printf("%s: VTPM CRQ: In failure mode\n", __func__); + return false; + } + + for (i = 0; i < timeout; i += 1000) { + if (spapr_vtpm.response->valid & PAPR_VTPM_MSG_RESULT) { + /* TPM responded: move to Send tpm-cmd state */ + vtpm_drv_state_set(VTPM_DRV_STATE_SEND_TPM_CMD, + VTPM_DRV_ERROR_NO_FAILURE); + dprintf("Received response to TPM command\n"); + return true; + } + SLOF_usleep(1000); + } + + vtpm_drv_state_set(VTPM_DRV_STATE_FAILURE, + VTPM_DRV_ERROR_WAIT_TIMEOUT); + + dprintf("Received NO response to TPM command"); + + return false; +} + +static bool spapr_vtpm_readresponse(uint8_t *buffer, uint32_t *len) +{ + uint32_t length; + + if (vtpm_drv_error_get() != VTPM_DRV_ERROR_NO_FAILURE) { + printf("%s: VTPM CRQ: In failure mode\n", __func__); + return false; + } + + length = MIN(*len, be32_to_cpu(spapr_vtpm.response->len)); + + memcpy(buffer, (void *)(uint64_t)spapr_vtpm.response->data, length); + + dprintf("Length of copied response: %d\n", length); + + spapr_vtpm.response = NULL; + *len = length; + + return true; +} + +/**** higher layer interface ****/ + +vtpm_drv_error spapr_vtpm_get_error(void) +{ + return vtpm_drv_error_get(); +} + +void spapr_vtpm_set_error(vtpm_drv_error errcode) +{ + spapr_vtpm.driver_error = errcode; +} + +bool spapr_is_vtpm_present(void) +{ + return spapr_vtpm_probe(); +} + +int spapr_transmit(uint8_t locty, struct tpm_req_header *req, + void *respbuffer, uint32_t *respbufferlen, + enum tpm_duration_type to_t) +{ + if (!spapr_vtpm_senddata((uint8_t *)req, be32_to_cpu(req->totlen)) || + !spapr_vtpm_waitresponseready(to_t) || + !spapr_vtpm_readresponse(respbuffer, respbufferlen) || + *respbufferlen < sizeof(struct tpm_rsp_header)) + return -1; + return 0; +} diff --git a/lib/libtpm/tpm_drivers.h b/lib/libtpm/tpm_drivers.h new file mode 100644 index 0000000..b5d347f --- /dev/null +++ b/lib/libtpm/tpm_drivers.h @@ -0,0 +1,82 @@ +/***************************************************************************** + * Copyright (c) 2015-2020 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef TPM_DRIVERS_H +#define TPM_DRIVERS_H + +#include +#include +#include + +#include "tcgbios_int.h" + +enum tpm_duration_type { + TPM_DURATION_TYPE_SHORT = 0, + TPM_DURATION_TYPE_MEDIUM, + TPM_DURATION_TYPE_LONG, +}; + +/* firmware driver states */ +typedef enum { + VTPM_DRV_STATE_INVALID = 0, + VTPM_DRV_STATE_INIT_CALLED = 1, + VTPM_DRV_STATE_REG_CRQ = 2, + VTPM_DRV_STATE_WAIT_INIT = 3, + VTPM_DRV_STATE_SEND_INIT = 4, + VTPM_DRV_STATE_FAILURE = 5, + VTPM_DRV_STATE_WAIT_INIT_COMP = 6, + VTPM_DRV_STATE_SEND_INIT_COMP = 7, + VTPM_DRV_STATE_SEND_GET_VERSION = 8, + VTPM_DRV_STATE_WAIT_VERSION = 9, + VTPM_DRV_STATE_CHECK_VERSION = 10, + VTPM_DRV_STATE_SEND_BUFSIZE_REQ = 11, + VTPM_DRV_STATE_WAIT_BUFSIZE = 12, + VTPM_DRV_STATE_ALLOC_RTCE_BUF = 13, + VTPM_DRV_STATE_SEND_TPM_CMD = 14, + VTPM_DRV_STATE_WAIT_TPM_RSP = 15, +} vtpm_drv_state; + +/* firmware driver errors */ +typedef enum { + VTPM_DRV_ERROR_NO_FAILURE = -1, + VTPM_DRV_ERROR_NOT_FOUND_TIMEOUT = 0, + VTPM_DRV_ERROR_UNEXPECTED_REG_ERROR = 1, + VTPM_DRV_ERROR_PARTNER_FAILED = 2, + VTPM_DRV_ERROR_UNEXPECTED_TSP_ERROR = 3, + VTPM_DRV_ERROR_TPM_PROTOCOL_ERROR = 4, + VTPM_DRV_ERROR_WAIT_TIMEOUT = 5, + VTPM_DRV_ERROR_UNEXPECTED_SEND_ERROR = 6, + VTPM_DRV_ERROR_CRQ_OPEN_FAIL = 7, + VTPM_DRV_ERROR_BAD_STATE = 8, + VTPM_DRV_ERROR_TPM_FAIL = 9, + VTPM_DRV_ERROR_TPM_CRQ_ERROR = 10, + VTPM_DRV_ERROR_BAD_VERSION = 11, + VTPM_DRV_ERROR_BAD_RTCE_SIZE = 12, + VTPM_DRV_ERROR_SML_FAILURE = 13, + VTPM_DRV_ERROR_SML_HANDED_OVER = 14, +} vtpm_drv_error; + +/* the max. buffer size by the external TPM is 4k */ +#define PAPR_VTPM_MAX_BUFFER_SIZE 4096 + +/* exported functions */ +bool spapr_is_vtpm_present(void); +void spapr_vtpm_finalize(void); +vtpm_drv_error spapr_vtpm_get_error(void); +void spapr_vtpm_set_error(vtpm_drv_error errcode); + +struct tpm_req_header; +int spapr_transmit(uint8_t locty, struct tpm_req_header *req, + void *respbuffer, uint32_t *respbufferlen, + enum tpm_duration_type to_t); + +#endif /* TPM_DRIVERS_H */ diff --git a/slof/helpers.c b/slof/helpers.c index 9d37bc3..64023b2 100644 --- a/slof/helpers.c +++ b/slof/helpers.c @@ -235,3 +235,9 @@ void SLOF_reset(void) { forth_eval("reset-all"); } + +unsigned long SLOF_get_vtpm_unit(void) +{ + forth_eval("vtpm-unit"); + return forth_pop(); +} From patchwork Tue Jan 21 20:01:44 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Berger X-Patchwork-Id: 1226745 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [203.11.71.2]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 482KFg1gcyz9sRW for ; Wed, 22 Jan 2020 07:02:31 +1100 (AEDT) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.ibm.com Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 482KFg0vpRzDqRb for ; Wed, 22 Jan 2020 07:02:31 +1100 (AEDT) X-Original-To: slof@lists.ozlabs.org Delivered-To: slof@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=linux.ibm.com (client-ip=148.163.156.1; helo=mx0a-001b2d01.pphosted.com; envelope-from=stefanb@linux.ibm.com; receiver=) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.ibm.com Received: from mx0a-001b2d01.pphosted.com (mx0a-001b2d01.pphosted.com [148.163.156.1]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 482KF23DwZzDqPm for ; Wed, 22 Jan 2020 07:01:58 +1100 (AEDT) Received: from pps.filterd (m0098409.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.42/8.16.0.42) with SMTP id 00LJqmXj106463; Tue, 21 Jan 2020 15:01:54 -0500 Received: from ppma02dal.us.ibm.com (a.bd.3ea9.ip4.static.sl-reverse.com [169.62.189.10]) by mx0a-001b2d01.pphosted.com with ESMTP id 2xnx9apbg4-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 21 Jan 2020 15:01:54 -0500 Received: from pps.filterd (ppma02dal.us.ibm.com [127.0.0.1]) by ppma02dal.us.ibm.com (8.16.0.27/8.16.0.27) with SMTP id 00LK1X66026972; Tue, 21 Jan 2020 20:01:53 GMT Received: from b03cxnp07028.gho.boulder.ibm.com (b03cxnp07028.gho.boulder.ibm.com [9.17.130.15]) by ppma02dal.us.ibm.com with ESMTP id 2xksn6x5su-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 21 Jan 2020 20:01:53 +0000 Received: from b03ledav003.gho.boulder.ibm.com (b03ledav003.gho.boulder.ibm.com [9.17.130.234]) by b03cxnp07028.gho.boulder.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 00LK1qOA46399896 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 21 Jan 2020 20:01:52 GMT Received: from b03ledav003.gho.boulder.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 52B426A054; Tue, 21 Jan 2020 20:01:52 +0000 (GMT) Received: from b03ledav003.gho.boulder.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id CBF386A051; Tue, 21 Jan 2020 20:01:51 +0000 (GMT) Received: from sbct-3.pok.ibm.com (unknown [9.47.158.153]) by b03ledav003.gho.boulder.ibm.com (Postfix) with ESMTP; Tue, 21 Jan 2020 20:01:51 +0000 (GMT) From: Stefan Berger To: slof@lists.ozlabs.org, aik@ozlabs.ru Date: Tue, 21 Jan 2020 15:01:44 -0500 Message-Id: <20200121200147.1002075-6-stefanb@linux.ibm.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200121200147.1002075-1-stefanb@linux.ibm.com> References: <20200121200147.1002075-1-stefanb@linux.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:6.0.138, 18.0.634 definitions=2020-01-21_06:2020-01-21, 2020-01-21 signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 malwarescore=0 spamscore=0 priorityscore=1501 impostorscore=0 bulkscore=0 clxscore=1015 lowpriorityscore=0 mlxlogscore=999 phishscore=0 mlxscore=0 suspectscore=0 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-1910280000 definitions=main-2001210148 Subject: [SLOF] [PATCH v7 5/8] tpm: Add sha256 implementation X-BeenThere: slof@lists.ozlabs.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "Patches for https://github.com/aik/SLOF" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kevin@koconnor.net, Stefan Berger Errors-To: slof-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "SLOF" The following patch adds a SHA256 implementation based on the algorithm description in NIST FIPS PUB 180-4. The patch includes test cases that test the sha256 implementation and pass on big and little endian ppc64 hosts. Signed-off-by: Stefan Berger --- lib/libtpm/Makefile | 2 +- lib/libtpm/sha256.c | 214 ++++++++++++++++++++++++++++++++++++++++++++ lib/libtpm/sha256.h | 20 +++++ 3 files changed, 235 insertions(+), 1 deletion(-) create mode 100644 lib/libtpm/sha256.c create mode 100644 lib/libtpm/sha256.h diff --git a/lib/libtpm/Makefile b/lib/libtpm/Makefile index 47fc5d0..8fa781e 100644 --- a/lib/libtpm/Makefile +++ b/lib/libtpm/Makefile @@ -23,7 +23,7 @@ TARGET = ../libtpm.a all: $(TARGET) -SRCS = tpm_drivers.c +SRCS = tpm_drivers.c sha256.c OBJS = $(SRCS:%.c=%.o) diff --git a/lib/libtpm/sha256.c b/lib/libtpm/sha256.c new file mode 100644 index 0000000..fb67e19 --- /dev/null +++ b/lib/libtpm/sha256.c @@ -0,0 +1,214 @@ +/***************************************************************************** + * Copyright (c) 2015-2020 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +/* + * See: NIST standard for SHA-256 in FIPS PUB 180-4 + */ + +#include "byteorder.h" +#include "sha256.h" +#include "string.h" + +typedef struct _sha256_ctx { + uint32_t h[8]; +} sha256_ctx; + +static inline uint32_t rotr(uint32_t x, uint8_t n) +{ + return (x >> n) | (x << (32 - n)); +} + +static inline uint32_t Ch(uint32_t x, uint32_t y, uint32_t z) +{ + return (x & y) | ((x ^ 0xffffffff) & z); +} + +static inline uint32_t Maj(uint32_t x, uint32_t y, uint32_t z) +{ + return (x & y) | (x & z) | (y & z); +} + +static inline uint32_t sum0(uint32_t x) +{ + return rotr(x, 2) ^ rotr(x, 13) ^ rotr(x, 22); +} + +static inline uint32_t sum1(uint32_t x) +{ + return rotr(x, 6) ^ rotr(x, 11) ^ rotr(x, 25); +} + +static inline uint32_t sigma0(uint32_t x) +{ + return rotr(x, 7) ^ rotr(x, 18) ^ (x >> 3); +} + +static inline uint32_t sigma1(uint32_t x) +{ + return rotr(x, 17) ^ rotr(x, 19) ^ (x >> 10); +} + +static void sha256_block(uint32_t *w, sha256_ctx *ctx) +{ + uint32_t t; + uint32_t a, b, c, d, e, f, g, h; + uint32_t T1, T2; + + /* + * FIPS 180-4 4.2.2: SHA256 Constants + */ + static const uint32_t sha_ko[64] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, + 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, + 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 + }; + + /* + * FIPS 180-4 6.2.2: step 1 + * + * 0 <= i <= 15: + * W(t) = M(t) + * 16 <= i <= 79: + * W(t) = sigma1(W(t-2)) + W(t-7) + sigma0(W(t-15)) + W(t-16) + */ + + /* w(0)..w(15) are in big endian format */ + for (t = 0; t <= 15; t++) + w[t] = be32_to_cpu(w[t]); + + for (t = 16; t <= 63; t++) + w[t] = sigma1(w[t-2]) + w[t-7] + sigma0(w[t-15]) + w[t-16]; + + /* + * step 2: a = H0, b = H1, c = H2, d = H3, e = H4, f = H5, g = H6, h = H7 + */ + a = ctx->h[0]; + b = ctx->h[1]; + c = ctx->h[2]; + d = ctx->h[3]; + e = ctx->h[4]; + f = ctx->h[5]; + g = ctx->h[6]; + h = ctx->h[7]; + + /* + * step 3: For i = 0 to 63: + * T1 = h + sum1(e) + Ch(e,f,g) + K(t) + W(t); + * T2 = sum0(a) + Maj(a,b,c) + * h = g; g = f; f = e; e = d + T1; d = c; c = b; b = a; a + T1 + T2 + */ + for (t = 0; t <= 63; t++) { + T1 = h + sum1(e) + Ch(e, f, g) + sha_ko[t] + w[t]; + T2 = sum0(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + } + + /* + * step 4: + * H0 = a + H0, H1 = b + H1, H2 = c + H2, H3 = d + H3, H4 = e + H4 + */ + ctx->h[0] += a; + ctx->h[1] += b; + ctx->h[2] += c; + ctx->h[3] += d; + ctx->h[4] += e; + ctx->h[5] += f; + ctx->h[6] += g; + ctx->h[7] += h; +} + +static void sha256_do(sha256_ctx *ctx, const uint8_t *data32, uint32_t length) +{ + uint32_t offset; + uint16_t num; + uint32_t bits = 0; + uint32_t w[64]; + uint64_t tmp; + + /* treat data in 64-byte chunks */ + for (offset = 0; length - offset >= 64; offset += 64) { + memcpy(w, data32 + offset, 64); + sha256_block((uint32_t *)w, ctx); + bits += (64 * 8); + } + + /* last block with less than 64 bytes */ + num = length - offset; + bits += (num << 3); + + memcpy(w, data32 + offset, num); + /* + * FIPS 180-4 5.1: Padding the Message + */ + ((uint8_t *)w)[num] = 0x80; + if (64 - (num + 1) > 0) + memset( &((uint8_t *)w)[num + 1], 0, 64 - (num + 1)); + + if (num >= 56) { + /* cannot append number of bits here */ + sha256_block((uint32_t *)w, ctx); + memset(w, 0, 60); + } + + /* write number of bits to end of block */ + tmp = cpu_to_be64(bits); + memcpy(&w[14], &tmp, 8); + + sha256_block(w, ctx); + + /* need to switch result's endianness */ + for (num = 0; num < 8; num++) + ctx->h[num] = cpu_to_be32(ctx->h[num]); +} + +void sha256(const uint8_t *data, uint32_t length, uint8_t *hash) +{ + sha256_ctx ctx = { + .h = { + /* + * FIPS 180-4: 6.2.1 + * -> 5.3.3: initial hash value + */ + 0x6a09e667, + 0xbb67ae85, + 0x3c6ef372, + 0xa54ff53a, + 0x510e527f, + 0x9b05688c, + 0x1f83d9ab, + 0x5be0cd19 + } + }; + + sha256_do(&ctx, data, length); + memcpy(hash, ctx.h, sizeof(ctx.h)); +} diff --git a/lib/libtpm/sha256.h b/lib/libtpm/sha256.h new file mode 100644 index 0000000..04b774b --- /dev/null +++ b/lib/libtpm/sha256.h @@ -0,0 +1,20 @@ +/***************************************************************************** + * Copyright (c) 2015-2020 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef __SHA256_H +#define __SHA256_H + +#include "types.h" + +void sha256(const uint8_t *data, uint32_t length, uint8_t *hash); + +#endif /* __SHA256_H */ From patchwork Tue Jan 21 20:01:45 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Berger X-Patchwork-Id: 1226748 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 482KFy1xbQz9sRW for ; Wed, 22 Jan 2020 07:02:46 +1100 (AEDT) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.ibm.com Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 482KFy12XzzDqRn for ; Wed, 22 Jan 2020 07:02:46 +1100 (AEDT) X-Original-To: slof@lists.ozlabs.org Delivered-To: slof@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=linux.ibm.com (client-ip=148.163.158.5; helo=mx0a-001b2d01.pphosted.com; envelope-from=stefanb@linux.ibm.com; receiver=) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.ibm.com Received: from mx0a-001b2d01.pphosted.com (mx0b-001b2d01.pphosted.com [148.163.158.5]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 482KF445WHzDqFv for ; Wed, 22 Jan 2020 07:02:00 +1100 (AEDT) Received: from pps.filterd (m0098420.ppops.net [127.0.0.1]) by mx0b-001b2d01.pphosted.com (8.16.0.42/8.16.0.42) with SMTP id 00LJqoCq117442; Tue, 21 Jan 2020 15:01:55 -0500 Received: from ppma02wdc.us.ibm.com (aa.5b.37a9.ip4.static.sl-reverse.com [169.55.91.170]) by mx0b-001b2d01.pphosted.com with ESMTP id 2xp5ye4085-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 21 Jan 2020 15:01:54 -0500 Received: from pps.filterd (ppma02wdc.us.ibm.com [127.0.0.1]) by ppma02wdc.us.ibm.com (8.16.0.27/8.16.0.27) with SMTP id 00LJrAsY005928; Tue, 21 Jan 2020 20:01:54 GMT Received: from b03cxnp07029.gho.boulder.ibm.com (b03cxnp07029.gho.boulder.ibm.com [9.17.130.16]) by ppma02wdc.us.ibm.com with ESMTP id 2xksn6eha1-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 21 Jan 2020 20:01:54 +0000 Received: from b03ledav003.gho.boulder.ibm.com (b03ledav003.gho.boulder.ibm.com [9.17.130.234]) by b03cxnp07029.gho.boulder.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 00LK1r8O56623388 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 21 Jan 2020 20:01:53 GMT Received: from b03ledav003.gho.boulder.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 1201D6A05D; Tue, 21 Jan 2020 20:01:53 +0000 (GMT) Received: from b03ledav003.gho.boulder.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 754056A047; Tue, 21 Jan 2020 20:01:52 +0000 (GMT) Received: from sbct-3.pok.ibm.com (unknown [9.47.158.153]) by b03ledav003.gho.boulder.ibm.com (Postfix) with ESMTP; Tue, 21 Jan 2020 20:01:52 +0000 (GMT) From: Stefan Berger To: slof@lists.ozlabs.org, aik@ozlabs.ru Date: Tue, 21 Jan 2020 15:01:45 -0500 Message-Id: <20200121200147.1002075-7-stefanb@linux.ibm.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200121200147.1002075-1-stefanb@linux.ibm.com> References: <20200121200147.1002075-1-stefanb@linux.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:6.0.138, 18.0.634 definitions=2020-01-21_06:2020-01-21, 2020-01-21 signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 impostorscore=0 clxscore=1015 priorityscore=1501 lowpriorityscore=0 phishscore=0 malwarescore=0 mlxscore=0 suspectscore=0 spamscore=0 bulkscore=0 mlxlogscore=999 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-1910280000 definitions=main-2001210148 Subject: [SLOF] [PATCH v7 6/8] tcgbios: Add TPM 2.0 support and firmware API X-BeenThere: slof@lists.ozlabs.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "Patches for https://github.com/aik/SLOF" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kevin@koconnor.net, Stefan Berger Errors-To: slof-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "SLOF" This patch adds TPM 2.0 support along with the firmware API that Linux uses to transfer the firmware log. The firmware API follows the "PFW Virtual TPM Driver" specification. The API has callers in existing Linux code (prom_init.c) from TPM 1.2 times but the API also works for TPM 2.0 without modifications. The TPM 2.0 support logs PCR extensions of measurements of code and data. For this part we follow the TCG specification "TCG PC Client Platform Firmware Profile Specification" (section "Event Logging"). Other relevant specs for the construction of TPM commands are: - Trusted Platform Module Library; Part 2 Structures - Trusted Platform Module Library; Part 3 Commands Signed-off-by: Stefan Berger Signed-off-by: Kevin O'Connor --- board-qemu/slof/Makefile | 13 +- board-qemu/slof/tree.fs | 3 + board-qemu/slof/vio-vtpm-cdriver.fs | 105 ++++ board-qemu/slof/vtpm-sml.fs | 68 ++ include/helpers.h | 1 + lib/libtpm/Makefile | 2 +- lib/libtpm/tcgbios.c | 925 ++++++++++++++++++++++++++++ lib/libtpm/tcgbios.h | 32 + lib/libtpm/tcgbios_int.h | 241 ++++++++ lib/libtpm/tpm.code | 130 ++++ lib/libtpm/tpm.in | 26 + slof/fs/packages/disk-label.fs | 9 + slof/fs/start-up.fs | 5 + 13 files changed, 1556 insertions(+), 4 deletions(-) create mode 100644 board-qemu/slof/vio-vtpm-cdriver.fs create mode 100644 board-qemu/slof/vtpm-sml.fs create mode 100644 lib/libtpm/tcgbios.c create mode 100644 lib/libtpm/tcgbios.h create mode 100644 lib/libtpm/tpm.code create mode 100644 lib/libtpm/tpm.in diff --git a/board-qemu/slof/Makefile b/board-qemu/slof/Makefile index d7ed2d7..a8cff6d 100644 --- a/board-qemu/slof/Makefile +++ b/board-qemu/slof/Makefile @@ -22,7 +22,8 @@ CPPFLAGS = -I$(LIBCMNDIR)/libbootmsg -I$(LIBCMNDIR)/libhvcall \ -I$(LIBCMNDIR)/libvirtio -I$(LIBCMNDIR)/libnvram \ -I$(LIBCMNDIR)/libusb -I$(LIBCMNDIR)/libveth \ -I$(LIBCMNDIR)/libe1k -I$(LIBCMNDIR)/libnet \ - -I$(LIBCMNDIR)/libbootmenu + -I$(LIBCMNDIR)/libbootmenu -I$(LIBCMNDIR)/libtpm + SLOF_LIBS = \ $(LIBCMNDIR)/libbootmsg.a \ $(LIBCMNDIR)/libelf.a \ @@ -33,7 +34,9 @@ SLOF_LIBS = \ $(LIBCMNDIR)/libveth.a \ $(LIBCMNDIR)/libe1k.a \ $(LIBCMNDIR)/libnet.a \ - $(LIBCMNDIR)/libbootmenu.a + $(LIBCMNDIR)/libbootmenu.a \ + $(LIBCMNDIR)/libtpm.a + BOARD_SLOF_IN = \ $(LIBCMNDIR)/libhvcall/hvcall.in \ $(LIBCMNDIR)/libvirtio/virtio.in \ @@ -45,7 +48,9 @@ BOARD_SLOF_IN = \ $(LIBCMNDIR)/libveth/veth.in \ $(LIBCMNDIR)/libe1k/e1k.in \ $(LIBCMNDIR)/libnet/libnet.in \ - $(LIBCMNDIR)/libbootmenu/bootmenu.in + $(LIBCMNDIR)/libbootmenu/bootmenu.in \ + $(LIBCMNDIR)/libtpm/tpm.in + BOARD_SLOF_CODE = $(BOARD_SLOF_IN:%.in=%.code) include $(SLOFCMNDIR)/Makefile.inc @@ -83,6 +88,7 @@ VIO_FFS_FILES = \ $(SLOFBRDDIR)/pci-device_1af4_1050.fs \ $(SLOFBRDDIR)/vio-hvterm.fs \ $(SLOFBRDDIR)/vio-vscsi.fs \ + $(SLOFBRDDIR)/vio-vtpm-cdriver.fs \ $(SLOFBRDDIR)/vio-veth.fs \ $(SLOFBRDDIR)/rtas-nvram.fs \ $(SLOFBRDDIR)/virtio-net.fs \ @@ -114,6 +120,7 @@ OF_FFS_FILES = \ $(SLOFBRDDIR)/default-font.bin \ $(SLOFBRDDIR)/pci-phb.fs \ $(SLOFBRDDIR)/rtas.fs \ + $(SLOFBRDDIR)/vtpm-sml.fs \ $(SLOFBRDDIR)/pci-device_1234_1111.fs \ $(SLOFBRDDIR)/pci-device_1013_00b8.fs \ $(SLOFBRDDIR)/pci-device_8086_100e.fs \ diff --git a/board-qemu/slof/tree.fs b/board-qemu/slof/tree.fs index d95fde3..7b34125 100644 --- a/board-qemu/slof/tree.fs +++ b/board-qemu/slof/tree.fs @@ -87,6 +87,9 @@ include fbuffer.fs 2dup " qemu,spapr-nvram" strequal IF " rtas-nvram.fs" included THEN + 2dup " IBM,vtpm20" strequal IF + " vio-vtpm-cdriver.fs" included + THEN 2drop THEN peer diff --git a/board-qemu/slof/vio-vtpm-cdriver.fs b/board-qemu/slof/vio-vtpm-cdriver.fs new file mode 100644 index 0000000..7a2ffc3 --- /dev/null +++ b/board-qemu/slof/vio-vtpm-cdriver.fs @@ -0,0 +1,105 @@ +\ ***************************************************************************** +\ * Copyright (c) 2015-2020 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +." Populating " pwd cr + +false VALUE vtpm-debug? +0 VALUE vtpm-unit + +0 VALUE log-base +40000 CONSTANT LOG-SIZE \ 256k per VTPM FW spec. + +e CONSTANT VTPM_DRV_ERROR_SML_HANDED_OVER + +LOG-SIZE BUFFER: log-base + +\ firmware API call +: sml-get-allocated-size ( -- buffer-size) + LOG-SIZE +; + +\ firmware API call +: sml-get-handover-size ( -- size) + tpm-get-logsize +; + +\ firmware API call +: sml-handover ( dest size -- ) + log-base ( dest size src ) + -rot ( src dest size ) + move + + VTPM_DRV_ERROR_SML_HANDED_OVER tpm-driver-set-failure-reason +; + +\ firmware API call +: get-failure-reason ( -- reason ) + tpm-driver-get-failure-reason ( reason ) +; + +0 0 s" ibm,sml-efi-reformat-supported" property + +\ firmware API call +: reformat-sml-to-efi-alignment ( -- success ) + true +; + +: open true ; +: close ; + +: vtpm-cleanup ( -- ) + vtpm-debug? IF ." VTPM: Disabling RTAS bypass" cr THEN + tpm-finalize + \ Disable TCE bypass + vtpm-unit 0 rtas-set-tce-bypass +; + +: vtpm-init ( -- success ) + 0 0 get-node open-node ?dup 0= IF false EXIT THEN + my-self >r + dup to my-self + + vtpm-debug? IF ." VTPM: Initializing for c-driver" cr THEN + + my-unit to vtpm-unit + + \ Enable TCE bypass special qemu feature + vtpm-unit 1 rtas-set-tce-bypass + + \ Have TCE bypass cleaned up + ['] vtpm-cleanup add-quiesce-xt + + \ close temporary node + close-node + r> to my-self + + tpm-start ?dup 0= IF + vtpm-debug? IF ." VTPM: Success from tpm-start" cr THEN + true + ELSE + ." VTPM: Error code from tpm-start: " . cr + false + THEN +; + +\ inititialize unit and set RTAS bypass +vtpm-init IF + \ pass logbase and size to the C driver; we may only do this after + \ init of the lower levels since this calls needs to know the PCR banks + \ when setting up the log + log-base LOG-SIZE tpm-set-log-parameters + s" vtpm-sml.fs" included +ELSE + ." VTPM: vtpm-init failed" cr +THEN + + diff --git a/board-qemu/slof/vtpm-sml.fs b/board-qemu/slof/vtpm-sml.fs new file mode 100644 index 0000000..8e2ab6d --- /dev/null +++ b/board-qemu/slof/vtpm-sml.fs @@ -0,0 +1,68 @@ +\ ***************************************************************************** +\ * Copyright (c) 2015-2020 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +" /" find-device + +new-device + +false VALUE vtpm-debug? + +\ create /ibm,vtpm +s" ibm,vtpm" 2dup device-name device-type + +\ +\ only internal API calls +\ + +: separator-event ( start-pcr end-pcr -- ) + tpm-add-event-separators ( errcode ) + ?dup IF + ." VTPM: Error code from tpm-add-event-separators: " . cr + THEN +; + +80 CONSTANT BCV_DEVICE_HDD + +: measure-hdd-mbr ( addr length -- ) + 0 7 separator-event + BCV_DEVICE_HDD ( addr length bootdrv ) + -rot ( bootdrv addr length ) + tpm-measure-bcv-mbr ( errcode ) + ?dup IF + ." VTPM: Error code from tpm-measure-hdd: " . cr + THEN +; + +: leave-firmware ( -- ) + tpm-leave-firmware ( errcode ) + ?dup IF + ." VTPM: Error code from tpm-leave-firmware: " . cr + THEN +; + +: measure-scrtm ( -- ) + tpm-measure-scrtm ( errcode ) + ?dup IF + ." VTPM: Error code from tpm-measure-scrtm: " . cr + THEN +; + +: open true ; +: close ; + +finish-device +device-end + +s" /ibm,vtpm" find-node ?dup IF + s" measure-scrtm" rot $call-static +THEN + diff --git a/include/helpers.h b/include/helpers.h index 2f460d6..47b2674 100644 --- a/include/helpers.h +++ b/include/helpers.h @@ -50,5 +50,6 @@ extern unsigned long SLOF_get_vtpm_unit(void); #define container_of(ptr, type, member) ({ \ const typeof(((type *)0)->member)* struct_ptr = (ptr); \ (type *)((char *)struct_ptr - offset_of(type, member)); }) +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) #endif diff --git a/lib/libtpm/Makefile b/lib/libtpm/Makefile index 8fa781e..bcfe88d 100644 --- a/lib/libtpm/Makefile +++ b/lib/libtpm/Makefile @@ -23,7 +23,7 @@ TARGET = ../libtpm.a all: $(TARGET) -SRCS = tpm_drivers.c sha256.c +SRCS = tpm_drivers.c sha256.c tcgbios.c OBJS = $(SRCS:%.c=%.o) diff --git a/lib/libtpm/tcgbios.c b/lib/libtpm/tcgbios.c new file mode 100644 index 0000000..d81d392 --- /dev/null +++ b/lib/libtpm/tcgbios.c @@ -0,0 +1,925 @@ +/***************************************************************************** + * Copyright (c) 2015-2020 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + * Stefan Berger, stefanb@linux.ibm.com + * Kevin O'Connor, kevin@koconnor.net + *****************************************************************************/ + +/* + * Implementation of the TPM BIOS extension according to the specification + * described in the IBM VTPM Firmware document and the TCG Specification + * that can be found here under the following link: + * https://trustedcomputinggroup.org/resource/pc-client-work-group-specific-implementation-specification-for-conventional-bios/ + */ + +#include +#include + +#include "types.h" +#include "byteorder.h" +#include "tpm_drivers.h" +#include "string.h" +#include "tcgbios.h" +#include "tcgbios_int.h" +#include "stdio.h" +#include "sha256.h" +#include "helpers.h" +#include "version.h" +#include "OF.h" + +#undef TCGBIOS_DEBUG +//#define TCGBIOS_DEBUG +#ifdef TCGBIOS_DEBUG +#define dprintf(_x ...) do { printf("TCGBIOS: " _x); } while(0) +#else +#define dprintf(_x ...) +#endif + +#define MIN(a, b) ((a) < (b) ? (a) : (b)) + +static struct { + unsigned tpm_probed:1; + unsigned tpm_found:1; + unsigned tpm_working:1; + + /* base address of the log area */ + uint8_t *log_base; + + /* size of the logging area */ + size_t log_area_size; + + /* where to write the next log entry to */ + uint8_t *log_area_next_entry; + + /* PCR selection as received from TPM */ + uint32_t tpm20_pcr_selection_size; + struct tpml_pcr_selection *tpm20_pcr_selection; +} tpm_state; + +/* + * TPM 2 logs are written in little endian format. + */ +static inline uint32_t log32_to_cpu(uint32_t val) +{ + return le32_to_cpu(val); +} + +static inline uint32_t cpu_to_log32(uint32_t val) +{ + return cpu_to_le32(val); +} + +static inline uint16_t cpu_to_log16(uint16_t val) +{ + return cpu_to_le16(val); +} + +/******************************************************** + Extensions for TCG-enabled BIOS + *******************************************************/ + +static void probe_tpm(void) +{ + tpm_state.tpm_probed = true; + tpm_state.tpm_found = spapr_is_vtpm_present(); + tpm_state.tpm_working = tpm_state.tpm_found; +} + +/**************************************************************** + * Digest formatting + ****************************************************************/ + +/* A 'struct tpm_log_entry' is a local data structure containing a + * 'TCG_PCR_EVENT2_Header' followed by space for the maximum supported + * digest. The digest is a series of TPMT_HA structs on tpm2.0. + */ +struct tpm_log_entry { + TCG_PCR_EVENT2_Header hdr; + uint8_t pad[sizeof(struct TPML_DIGEST_VALUES) + + 5 * sizeof(struct TPMT_HA) + + SHA1_BUFSIZE + SHA256_BUFSIZE + SHA384_BUFSIZE + + SHA512_BUFSIZE + SM3_256_BUFSIZE]; +} __attribute__((packed)); + +static const struct hash_parameters { + uint16_t hashalg; + uint8_t hash_buffersize; +} hash_parameters[] = { + { + .hashalg = TPM2_ALG_SHA1, + .hash_buffersize = SHA1_BUFSIZE, + }, { + .hashalg = TPM2_ALG_SHA256, + .hash_buffersize = SHA256_BUFSIZE, + }, { + .hashalg = TPM2_ALG_SHA384, + .hash_buffersize = SHA384_BUFSIZE, + }, { + .hashalg = TPM2_ALG_SHA512, + .hash_buffersize = SHA512_BUFSIZE, + }, { + .hashalg = TPM2_ALG_SM3_256, + .hash_buffersize = SM3_256_BUFSIZE, + } +}; + +static const struct hash_parameters *tpm20_find_by_hashalg(uint16_t hashAlg) +{ + unsigned i; + + for (i = 0; i < ARRAY_SIZE(hash_parameters); i++) { + if (hash_parameters[i].hashalg == hashAlg) + return &hash_parameters[i]; + } + return NULL; +} + +static inline int tpm20_get_hash_buffersize(uint16_t hashAlg) +{ + const struct hash_parameters *hp = tpm20_find_by_hashalg(hashAlg); + + if (hp) + return hp->hash_buffersize; + return -1; +} + +/* + * Build the TPM2 TPML_DIGEST_VALUES data structure from the given hash. + * Follow the PCR bank configuration of the TPM and write the same hash + * in either truncated or zero-padded form in the areas of all the other + * hashes. For example, write the sha256 hash in the area of the sha384 + * hash and fill the remaining bytes with zeros. Or truncate the sha256 + * hash when writing it in the area of the sha1 hash. + * + * le: the log entry to build the digest in + * sha1: the sha1 hash value to use + * bigEndian: whether to build in big endian format for the TPM or log + * little endian for the log (TPM 2.0) + * + * Returns the digest size; -1 on fatal error + */ +static int tpm20_build_digest(struct tpm_log_entry *le, const uint8_t *sha256, + bool bigEndian) +{ + struct tpms_pcr_selection *sel; + void *nsel, *end; + void *dest = le->hdr.digests + sizeof(struct TPML_DIGEST_VALUES); + uint32_t count; + struct TPMT_HA *v; + struct TPML_DIGEST_VALUES *vs; + + sel = tpm_state.tpm20_pcr_selection->selections; + end = (void *)tpm_state.tpm20_pcr_selection + + tpm_state.tpm20_pcr_selection_size; + + for (count = 0; + count < be32_to_cpu(tpm_state.tpm20_pcr_selection->count); + count++) { + int hsize; + uint8_t sizeOfSelect = sel->sizeOfSelect; + + nsel = (void*)sel + sizeof(*sel) + sizeOfSelect; + if (nsel > end) + break; + + hsize = tpm20_get_hash_buffersize(be16_to_cpu(sel->hashAlg)); + if (hsize < 0) { + dprintf("TPM is using an unsupported hash: %d\n", + be16_to_cpu(sel->hashAlg)); + return -1; + } + + /* buffer size sanity check before writing */ + v = dest; + if (dest + sizeof(*v) + hsize > (void*)le + sizeof(*le)) { + dprintf("tpm_log_entry is too small\n"); + return -1; + } + + if (bigEndian) + v->hashAlg = sel->hashAlg; + else + v->hashAlg = cpu_to_le16(be16_to_cpu(sel->hashAlg)); + + memset(v->hash, 0, hsize); + memcpy(v->hash, sha256, + hsize < SHA256_BUFSIZE ? hsize : SHA256_BUFSIZE); + + dest += sizeof(*v) + hsize; + sel = nsel; + } + + if (sel != end) { + dprintf("Malformed pcr selection structure fron TPM\n"); + return -1; + } + + vs = (void*)le->hdr.digests; + if (bigEndian) + vs->count = cpu_to_be32(count); + else + vs->count = cpu_to_le32(count); + + return dest - (void*)le->hdr.digests; +} + +/**************************************************************** + * TPM hardware command wrappers + ****************************************************************/ + +/* Helper function for sending TPM commands that take a single + * optional parameter (0, 1, or 2 bytes) and have no special response. + */ +static int +tpm_simple_cmd(uint8_t locty, uint32_t ordinal, int param_size, uint16_t param, + enum tpm_duration_type to_t) +{ + struct { + struct tpm_req_header trqh; + uint16_t param; + } __attribute__((packed)) req = { + .trqh.totlen = cpu_to_be32(sizeof(req.trqh) + param_size), + .trqh.tag = cpu_to_be16(TPM2_ST_NO_SESSIONS), + .trqh.ordinal = cpu_to_be32(ordinal), + }; + uint8_t obuffer[64]; + struct tpm_rsp_header *trsh = (void *)obuffer; + uint32_t obuffer_len = sizeof(obuffer); + int ret; + + switch (param_size) { + case 2: + req.param = cpu_to_be16(param); + break; + case 1: + *(uint8_t *)&req.param = param; + break; + } + + memset(obuffer, 0, sizeof(obuffer)); + ret = spapr_transmit(locty, &req.trqh, obuffer, &obuffer_len, to_t); + ret = ret ? -1 : be32_to_cpu(trsh->errcode); + dprintf("Return from tpm_simple_cmd(%x, %x) = %x\n", + ordinal, param, ret); + + return ret; +} + +static int +tpm20_getcapability(uint32_t capability, uint32_t property, uint32_t count, + struct tpm_rsp_header *rsp, uint32_t rsize) +{ + struct tpm2_req_getcapability trg = { + .hdr.tag = cpu_to_be16(TPM2_ST_NO_SESSIONS), + .hdr.totlen = cpu_to_be32(sizeof(trg)), + .hdr.ordinal = cpu_to_be32(TPM2_CC_GetCapability), + .capability = cpu_to_be32(capability), + .property = cpu_to_be32(property), + .propertycount = cpu_to_be32(count), + }; + uint32_t resp_size = rsize; + int ret; + + ret = spapr_transmit(0, &trg.hdr, rsp, &resp_size, + TPM_DURATION_TYPE_SHORT); + ret = (ret || + rsize < be32_to_cpu(rsp->totlen)) ? -1 + : be32_to_cpu(rsp->errcode); + + dprintf("TCGBIOS: Return value from sending TPM2_CC_GetCapability = 0x%08x\n", + ret); + + return ret; +} + +static int +tpm20_get_pcrbanks(void) +{ + uint8_t buffer[128]; + uint32_t size; + struct tpm2_res_getcapability *trg = + (struct tpm2_res_getcapability *)&buffer; + uint32_t resplen; + int ret; + + ret = tpm20_getcapability(TPM2_CAP_PCRS, 0, 8, &trg->hdr, + sizeof(buffer)); + if (ret) + return ret; + + /* defend against (broken) TPM sending packets that are too short */ + resplen = be32_to_cpu(trg->hdr.totlen); + if (resplen <= offset_of(struct tpm2_res_getcapability, data)) + return -1; + + size = resplen - offset_of(struct tpm2_res_getcapability, data); + /* we need a valid tpml_pcr_selection up to and including sizeOfSelect*/ + if (size < offset_of(struct tpml_pcr_selection, selections) + + offset_of(struct tpms_pcr_selection, pcrSelect)) + return -1; + + tpm_state.tpm20_pcr_selection = SLOF_alloc_mem(size); + if (tpm_state.tpm20_pcr_selection) { + memcpy(tpm_state.tpm20_pcr_selection, &trg->data, size); + tpm_state.tpm20_pcr_selection_size = size; + } else { + printf("TCGBIOS: Failed to allocated %u bytes.\n", size); + return -1; + } + + return 0; +} + +static int tpm20_extend(struct tpm_log_entry *le, int digest_len) +{ + struct tpm2_req_extend tmp_tre = { + .hdr.tag = cpu_to_be16(TPM2_ST_SESSIONS), + .hdr.totlen = cpu_to_be32(0), + .hdr.ordinal = cpu_to_be32(TPM2_CC_PCR_Extend), + .pcrindex = cpu_to_be32(log32_to_cpu(le->hdr.pcrindex)), + .authblocksize = cpu_to_be32(sizeof(tmp_tre.authblock)), + .authblock = { + .handle = cpu_to_be32(TPM2_RS_PW), + .noncesize = cpu_to_be16(0), + .contsession = TPM2_YES, + .pwdsize = cpu_to_be16(0), + }, + }; + uint8_t buffer[sizeof(tmp_tre) + sizeof(le->pad)]; + struct tpm2_req_extend *tre = (struct tpm2_req_extend *)buffer; + struct tpm_rsp_header rsp; + uint32_t resp_length = sizeof(rsp); + int ret; + + memcpy(tre, &tmp_tre, sizeof(tmp_tre)); + memcpy(&tre->digest[0], le->hdr.digests, digest_len); + + tre->hdr.totlen = cpu_to_be32(sizeof(tmp_tre) + digest_len); + + ret = spapr_transmit(0, &tre->hdr, &rsp, &resp_length, + TPM_DURATION_TYPE_SHORT); + if (ret || resp_length != sizeof(rsp) || rsp.errcode) + return -1; + + return 0; +} + +static int tpm20_stirrandom(void) +{ + struct tpm2_req_stirrandom stir = { + .hdr.tag = cpu_to_be16(TPM2_ST_NO_SESSIONS), + .hdr.totlen = cpu_to_be32(sizeof(stir)), + .hdr.ordinal = cpu_to_be32(TPM2_CC_StirRandom), + .size = cpu_to_be16(sizeof(stir.stir)), + .stir = rand(), + }; + struct tpm_rsp_header rsp; + uint32_t resp_length = sizeof(rsp); + int ret = spapr_transmit(0, &stir.hdr, &rsp, &resp_length, + TPM_DURATION_TYPE_SHORT); + + if (ret || resp_length != sizeof(rsp) || rsp.errcode) + ret = -1; + + dprintf("TCGBIOS: Return value from sending TPM2_CC_StirRandom = 0x%08x\n", + ret); + + return ret; +} + +static int tpm20_getrandom(uint8_t *buf, uint16_t buf_len) +{ + struct tpm2_res_getrandom rsp; + struct tpm2_req_getrandom trgr = { + .hdr.tag = cpu_to_be16(TPM2_ST_NO_SESSIONS), + .hdr.totlen = cpu_to_be32(sizeof(trgr)), + .hdr.ordinal = cpu_to_be32(TPM2_CC_GetRandom), + .bytesRequested = cpu_to_be16(buf_len), + }; + uint32_t resp_length = sizeof(rsp); + int ret; + + if (buf_len > sizeof(rsp.rnd.buffer)) + return -1; + + ret = spapr_transmit(0, &trgr.hdr, &rsp, &resp_length, + TPM_DURATION_TYPE_MEDIUM); + if (ret || resp_length != sizeof(rsp) || rsp.hdr.errcode) + ret = -1; + else + memcpy(buf, rsp.rnd.buffer, buf_len); + + dprintf("TCGBIOS: Return value from sending TPM2_CC_GetRandom = 0x%08x\n", + ret); + + return ret; +} + +static int tpm20_hierarchychangeauth(uint8_t auth[20]) +{ + struct tpm2_req_hierarchychangeauth trhca = { + .hdr.tag = cpu_to_be16(TPM2_ST_SESSIONS), + .hdr.totlen = cpu_to_be32(sizeof(trhca)), + .hdr.ordinal = cpu_to_be32(TPM2_CC_HierarchyChangeAuth), + .authhandle = cpu_to_be32(TPM2_RH_PLATFORM), + .authblocksize = cpu_to_be32(sizeof(trhca.authblock)), + .authblock = { + .handle = cpu_to_be32(TPM2_RS_PW), + .noncesize = cpu_to_be16(0), + .contsession = TPM2_YES, + .pwdsize = cpu_to_be16(0), + }, + .newAuth = { + .size = cpu_to_be16(sizeof(trhca.newAuth.buffer)), + }, + }; + struct tpm_rsp_header rsp; + uint32_t resp_length = sizeof(rsp); + int ret; + + memcpy(trhca.newAuth.buffer, auth, sizeof(trhca.newAuth.buffer)); + + ret = spapr_transmit(0, &trhca.hdr, &rsp, &resp_length, + TPM_DURATION_TYPE_MEDIUM); + if (ret || resp_length != sizeof(rsp) || rsp.errcode) + ret = -1; + + dprintf("TCGBIOS: Return value from sending TPM2_CC_HierarchyChangeAuth = 0x%08x\n", + ret); + + return ret; +} + +static int tpm20_hierarchycontrol(uint32_t hierarchy, uint8_t state) +{ + struct tpm2_req_hierarchycontrol trh = { + .hdr.tag = cpu_to_be16(TPM2_ST_SESSIONS), + .hdr.totlen = cpu_to_be32(sizeof(trh)), + .hdr.ordinal = cpu_to_be32(TPM2_CC_HierarchyControl), + .authhandle = cpu_to_be32(TPM2_RH_PLATFORM), + .authblocksize = cpu_to_be32(sizeof(trh.authblock)), + .authblock = { + .handle = cpu_to_be32(TPM2_RS_PW), + .noncesize = cpu_to_be16(0), + .contsession = TPM2_YES, + .pwdsize = cpu_to_be16(0), + }, + .enable = cpu_to_be32(hierarchy), + .state = state, + }; + struct tpm_rsp_header rsp; + uint32_t resp_length = sizeof(rsp); + int ret; + + ret = spapr_transmit(0, &trh.hdr, &rsp, &resp_length, + TPM_DURATION_TYPE_MEDIUM); + if (ret || resp_length != sizeof(rsp) || rsp.errcode) + ret = -1; + + dprintf("TCGBIOS: Return value from sending TPM2_CC_HierarchyControl = 0x%08x\n", + ret); + + return ret; +} + +/**************************************************************** + * Setup and Measurements + ****************************************************************/ + +bool tpm_is_working(void) +{ + if (!tpm_state.tpm_probed) + probe_tpm(); + + return tpm_state.tpm_working; +} + +static void tpm_set_failure(void) +{ + tpm20_hierarchycontrol(TPM2_RH_ENDORSEMENT, TPM2_NO); + tpm20_hierarchycontrol(TPM2_RH_OWNER, TPM2_NO); + + tpm_state.tpm_working = false; +} + +/* + * Extend the OFDT log with the given entry by copying the + * entry data into the log. + * + * @pcpes: Pointer to the structure to be copied into the log + * @event: The event to be appended to 'pcpes' + * @event_length: The length of the event + * + * Returns 0 on success, an error code otherwise. + */ +static uint32_t tpm_log_event_long(TCG_PCR_EVENT2_Header *entry, + int digest_len, + const void *event, uint32_t event_length) +{ + size_t size, logsize; + void *dest; + TCG_PCR_EVENT2_Trailer *t; + + dprintf("log base address = %p, next entry = %p\n", + tpm_state.log_base, tpm_state.log_area_next_entry); + + if (tpm_state.log_area_next_entry == NULL) + return TCGBIOS_LOGOVERFLOW; + + size = sizeof(*entry) + digest_len + + sizeof(TCG_PCR_EVENT2_Trailer) + event_length; + logsize = (tpm_state.log_area_next_entry + size - + tpm_state.log_base); + if (logsize > tpm_state.log_area_size) { + dprintf("TCGBIOS: LOG OVERFLOW: size = %zu\n", size); + return TCGBIOS_LOGOVERFLOW; + } + + dest = tpm_state.log_area_next_entry; + memcpy(dest, entry, sizeof(*entry) + digest_len); + + t = dest + sizeof(*entry) + digest_len; + t->eventdatasize = cpu_to_log32(event_length); + if (event_length) + memcpy(t->event, event, event_length); + + tpm_state.log_area_next_entry += size; + + return 0; +} + +/* Add an entry at the start of the log describing digest formats + */ +static int tpm20_write_EfiSpecIdEventStruct(void) +{ + struct { + struct TCG_EfiSpecIdEventStruct hdr; + uint32_t pad[256]; + } event = { + .hdr.signature = "Spec ID Event03", + .hdr.platformClass = TPM_TCPA_ACPI_CLASS_CLIENT, + .hdr.specVersionMinor = 0, + .hdr.specVersionMajor = 2, + .hdr.specErrata = 0, + .hdr.uintnSize = 2, + }; + struct tpms_pcr_selection *sel; + void *nsel, *end; + int event_size; + uint32_t *vendorInfoSize; + struct tpm_log_entry le = { + .hdr.eventtype = cpu_to_log32(EV_NO_ACTION), + }; + uint32_t count; + + sel = tpm_state.tpm20_pcr_selection->selections; + end = (void*)tpm_state.tpm20_pcr_selection + + tpm_state.tpm20_pcr_selection_size; + + for (count = 0; + count < be32_to_cpu(tpm_state.tpm20_pcr_selection->count); + count++) { + int hsize; + uint8_t sizeOfSelect = sel->sizeOfSelect; + + nsel = (void*)sel + sizeof(*sel) + sizeOfSelect; + if (nsel > end) + break; + + hsize = tpm20_get_hash_buffersize(be16_to_cpu(sel->hashAlg)); + if (hsize < 0) { + dprintf("TPM is using an unsupported hash: %d\n", + be16_to_cpu(sel->hashAlg)); + return -1; + } + + event_size = offset_of(struct TCG_EfiSpecIdEventStruct, + digestSizes[count+1]); + if (event_size > sizeof(event) - sizeof(uint32_t)) { + dprintf("EfiSpecIdEventStruct pad too small\n"); + return -1; + } + + event.hdr.digestSizes[count].algorithmId = + cpu_to_log16(be16_to_cpu(sel->hashAlg)); + event.hdr.digestSizes[count].digestSize = cpu_to_log16(hsize); + + sel = nsel; + } + + if (sel != end) { + dprintf("Malformed pcr selection structure fron TPM\n"); + return -1; + } + + event.hdr.numberOfAlgorithms = cpu_to_log32(count); + event_size = offset_of(struct TCG_EfiSpecIdEventStruct, + digestSizes[count]); + vendorInfoSize = (void*)&event + event_size; + *vendorInfoSize = 0; + event_size += sizeof(*vendorInfoSize); + + return tpm_log_event_long(&le.hdr, SHA1_BUFSIZE, &event, event_size); +} + +static int tpm20_startup(void) +{ + int ret; + + ret = tpm_simple_cmd(0, TPM2_CC_Startup, + 2, TPM2_SU_CLEAR, TPM_DURATION_TYPE_SHORT); + dprintf("TCGBIOS: Return value from sending TPM2_CC_Startup(SU_CLEAR) = 0x%08x\n", + ret); + + if (ret) + goto err_exit; + + ret = tpm_simple_cmd(0, TPM2_CC_SelfTest, + 1, TPM2_YES, TPM_DURATION_TYPE_LONG); + + dprintf("TCGBIOS: Return value from sending TPM2_CC_SELF_TEST = 0x%08x\n", + ret); + + if (ret) + goto err_exit; + + ret = tpm20_get_pcrbanks(); + if (ret) + goto err_exit; + + /* the log parameters will be passed from Forth layer */ + + return 0; + +err_exit: + dprintf("TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__); + + tpm_set_failure(); + return -1; +} + +uint32_t tpm_start(void) +{ + probe_tpm(); + + if (!tpm_is_working()) { + dprintf("%s: Machine does not have a working TPM\n", + __func__); + return TCGBIOS_FATAL_COM_ERROR; + } + + return tpm20_startup(); +} + +void tpm_finalize(void) +{ + spapr_vtpm_finalize(); +} + +static void tpm20_prepboot(void) +{ + uint8_t auth[20]; + int ret; + + ret = tpm20_stirrandom(); + if (ret) + goto err_exit; + + ret = tpm20_getrandom(&auth[0], sizeof(auth)); + if (ret) + goto err_exit; + + ret = tpm20_hierarchychangeauth(auth); + if (ret) + goto err_exit; + + return; + +err_exit: + dprintf("TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__); + + tpm_set_failure(); +} + +/* + * Prepare TPM for boot; this function has to be called before + * the firmware transitions to the boot loader. + */ +uint32_t tpm_leave_firmware(void) +{ + tpm20_prepboot(); + + return 0; +} + +/**************************************************************** + * Forth interface + ****************************************************************/ + +void tpm_set_log_parameters(void *addr, size_t size) +{ + int ret; + + dprintf("Log is at 0x%llx; size is %zu bytes\n", + (uint64_t)addr, size); + tpm_state.log_base = addr; + tpm_state.log_area_next_entry = addr; + tpm_state.log_area_size = size; + + ret = tpm20_write_EfiSpecIdEventStruct(); + if (ret) + tpm_set_failure(); +} + +uint32_t tpm_get_logsize(void) +{ + uint32_t logsize = tpm_state.log_area_next_entry - tpm_state.log_base; + + dprintf("log size: %u\n", logsize); + + return logsize; +} + +/* + * Add a measurement to the log; + * + * Input parameters: + * @pcrindex : PCR to extend + * @event_type : type of event + * @info : pointer to info (i.e., string) to be added to the log as-is + * @info_length: length of the info + * @hashdata : pointer to data to be hashed + * @hashdata_length: length of the data + * + */ +static uint32_t tpm_add_measurement_to_log(uint32_t pcrindex, + uint32_t eventtype, + const char *info, + uint32_t infolen, + const uint8_t *hashdata, + uint32_t hashdatalen) +{ + uint8_t hash[SHA256_BUFSIZE]; + struct tpm_log_entry le = { + .hdr.pcrindex = cpu_to_log32(pcrindex), + .hdr.eventtype = cpu_to_log32(eventtype), + }; + int digest_len; + int ret; + + sha256(hashdata, hashdatalen, hash); + digest_len = tpm20_build_digest(&le, hash, true); + if (digest_len < 0) + return TCGBIOS_GENERAL_ERROR; + ret = tpm20_extend(&le, digest_len); + if (ret) { + tpm_set_failure(); + return TCGBIOS_COMMAND_ERROR; + } + tpm20_build_digest(&le, hash, false); + return tpm_log_event_long(&le.hdr, digest_len, info, infolen); +} + +/* + * Add an EV_ACTION measurement to the list of measurements + */ +static uint32_t tpm_add_action(uint32_t pcrIndex, const char *string) +{ + uint32_t len = strlen(string); + + return tpm_add_measurement_to_log(pcrIndex, EV_ACTION, + string, len, (uint8_t *)string, len); +} + +/* + * Add event separators for a range of PCRs + */ +uint32_t tpm_add_event_separators(uint32_t start_pcr, uint32_t end_pcr) +{ + static const uint8_t evt_separator[] = {0xff,0xff,0xff,0xff}; + uint32_t pcrIndex; + int rc; + + if (!tpm_is_working()) + return TCGBIOS_GENERAL_ERROR; + + if (start_pcr >= 24 || start_pcr > end_pcr) + return TCGBIOS_INVALID_INPUT_PARA; + + /* event separators need to be extended and logged for PCRs 0-7 */ + for (pcrIndex = start_pcr; pcrIndex <= end_pcr; pcrIndex++) { + rc = tpm_add_measurement_to_log(pcrIndex, EV_SEPARATOR, + NULL, 0, + evt_separator, + sizeof(evt_separator)); + if (rc) + return rc; + } + + return 0; +} + +uint32_t tpm_measure_bcv_mbr(uint32_t bootdrv, const uint8_t *addr, + uint32_t length) +{ + uint32_t rc; + const char *string; + + if (!tpm_is_working()) + return TCGBIOS_GENERAL_ERROR; + + if (length < 0x200) + return TCGBIOS_INVALID_INPUT_PARA; + + string = "Booting BCV device 00h (Floppy)"; + if (bootdrv == BCV_DEVICE_HDD) + string = "Booting BCV device 80h (HDD)"; + + rc = tpm_add_action(4, string); + if (rc) + return rc; + + /* + * equivalent to: dd if=/dev/hda ibs=1 count=440 | sha256sum + */ + string = "MBR"; + rc = tpm_add_measurement_to_log(4, EV_IPL, + string, strlen(string), + addr, 0x1b8); + if (rc) + return rc; + + /* + * equivalent to: dd if=/dev/hda ibs=1 count=72 skip=440 | sha256sum + */ + string = "MBR PARTITION TABLE"; + return tpm_add_measurement_to_log(5, EV_IPL_PARTITION_DATA, + string, strlen(string), + addr + 0x1b8, 0x48); +} + +uint32_t tpm_measure_scrtm(void) +{ + uint32_t rc; + char *version_start = strstr((char *)&print_version, "FW Version"); + char *version_end; + uint32_t version_length; + char *slof_text_start = (char *)&_slof_text; + uint32_t slof_text_length = (long)&_slof_text_end - (long)&_slof_text; + const char *scrtm = "S-CRTM Contents"; + + version_end = strchr(version_start, '\r'); + version_length = version_end - version_start; + + dprintf("Measure S-CRTM Version: addr = %p, length = %d\n", + version_start, version_length); + + rc = tpm_add_measurement_to_log(0, EV_S_CRTM_VERSION, + version_start, version_length, + (uint8_t *)version_start, + version_length); + if (rc) + return rc; + + dprintf("Measure S-CRTM Content (text): start = %p, length = %d\n", + slof_text_start, slof_text_length); + + rc = tpm_add_measurement_to_log(0, EV_S_CRTM_CONTENTS, + scrtm, strlen(scrtm), + (uint8_t *)slof_text_start, + slof_text_length); + + return rc; +} + +/* + * tpm_driver_get_failure_reason: Function for interfacing with the firmware + * API + */ +uint32_t tpm_driver_get_failure_reason(void) +{ + /* do not check for a working TPM here */ + if (!tpm_state.tpm_found) + return VTPM_DRV_STATE_INVALID; + + return spapr_vtpm_get_error(); +} + +/* + * tpm_driver_set_failure_reason: Function for interfacing with the firmware + * API + */ +void tpm_driver_set_failure_reason(uint32_t errcode) +{ + if (!tpm_state.tpm_found) + return; + + spapr_vtpm_set_error(errcode); +} diff --git a/lib/libtpm/tcgbios.h b/lib/libtpm/tcgbios.h new file mode 100644 index 0000000..e9f9c36 --- /dev/null +++ b/lib/libtpm/tcgbios.h @@ -0,0 +1,32 @@ +/***************************************************************************** + * Copyright (c) 2015-2020 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef TCGBIOS_H +#define TCGBIOS_H + +#include +#include + +uint32_t tpm_start(void); +void tpm_finalize(void); +uint32_t tpm_leave_firmware(void); +uint32_t tpm_measure_scrtm(void); +void tpm_set_log_parameters(void *address, size_t size); +uint32_t tpm_get_logsize(void); +uint32_t tpm_measure_bcv_mbr(uint32_t bootdrv, const uint8_t *addr, + uint32_t length); +uint32_t tpm_add_event_separators(uint32_t start_pcr, uint32_t end_pcr); +uint32_t tpm_driver_get_failure_reason(void); +void tpm_driver_set_failure_reason(uint32_t errcode); +bool tpm_is_working(void); + +#endif /* TCGBIOS_H */ diff --git a/lib/libtpm/tcgbios_int.h b/lib/libtpm/tcgbios_int.h index 835bd36..6892e6f 100644 --- a/lib/libtpm/tcgbios_int.h +++ b/lib/libtpm/tcgbios_int.h @@ -15,6 +15,83 @@ #include +/* internal error codes */ +#define TCGBIOS_OK 0x0 +#define TCGBIOS_LOGOVERFLOW 0x1 +#define TCGBIOS_GENERAL_ERROR 0x2 +#define TCGBIOS_FIRMWARE_ERROR 0x3 +#define TCGBIOS_FATAL_COM_ERROR 0x4 +#define TCGBIOS_INVALID_INPUT_PARA 0x5 +#define TCGBIOS_COMMAND_ERROR 0x6 +#define TCGBIOS_INTERFACE_SHUTDOWN 0x7 + +/* + * event types from spec: + * TCG PC Client Specific Implementation Specification + * for Conventional BIOS + */ +#define EV_POST_CODE 1 +#define EV_NO_ACTION 3 +#define EV_SEPARATOR 4 +#define EV_ACTION 5 +#define EV_EVENT_TAG 6 +#define EV_S_CRTM_CONTENTS 7 +#define EV_S_CRTM_VERSION 8 +#define EV_IPL 13 +#define EV_IPL_PARTITION_DATA 14 + +#define BCV_DEVICE_HDD 0x80 + +/* hash sizes */ +#define SHA1_BUFSIZE 20 +#define SHA256_BUFSIZE 32 +#define SHA384_BUFSIZE 48 +#define SHA512_BUFSIZE 64 +#define SM3_256_BUFSIZE 32 + +/* + * Logging for TPM 2 is specified in TCG spec "TCG PC Client Platform + * Firmware Profile Specification" in section "Event Logging" and sub- + * section "TCG_PCR_EVENT2 structure" + * + * Each entry in the TPM log contains: a TCG_PCR_EVENT2_Header, a variable + * length digest, a TCG_PCR_EVENT2_Trailer, and a variable length event. + * The 'digest' matches what is sent to the TPM hardware via the Extend + * command. On TPM2.0 the digest contains a TPML_DIGEST_VALUES struct + * followed by a variable number of TPMT_HA structs (as specified by the + * hardware via the TPM2_CAP_PCRS request). + */ +typedef struct tdTCG_PCR_EVENT2_Header { + uint32_t pcrindex; + uint32_t eventtype; + uint8_t digests[0]; +} __attribute__((packed)) TCG_PCR_EVENT2_Header; + +typedef struct tdTCG_PCR_EVENT2_Trailer { + uint32_t eventdatasize; + uint8_t event[0]; +} __attribute__((packed)) TCG_PCR_EVENT2_Trailer; + +struct TCG_EfiSpecIdEventStruct { + uint8_t signature[16]; + uint32_t platformClass; +#define TPM_TCPA_ACPI_CLASS_CLIENT 0 + uint8_t specVersionMinor; + uint8_t specVersionMajor; + uint8_t specErrata; + uint8_t uintnSize; + uint32_t numberOfAlgorithms; + struct TCG_EfiSpecIdEventAlgorithmSize { + uint16_t algorithmId; + uint16_t digestSize; + } digestSizes[0]; + /* + uint8_t vendorInfoSize; + uint8_t vendorInfo[0]; + */ +} __attribute__((packed)); + +/* Input and Output headers for all TPM commands */ struct tpm_req_header { uint16_t tag; uint32_t totlen; @@ -27,4 +104,168 @@ struct tpm_rsp_header { uint32_t errcode; } __attribute__((packed)); +/**************************************************************** + * TPM v2.0 hardware commands + * + * Relevant specs for #defines and commonly used structures: + * - Trusted Platform Module Library; Part 2: Structures + * Relevant specs for command structures: + * - Trusted Platform Module Library; Part 3: Commands + ****************************************************************/ + +#define TPM2_NO 0 +#define TPM2_YES 1 + +#define TPM2_SU_CLEAR 0x0000 +#define TPM2_SU_STATE 0x0001 + +#define TPM2_RH_OWNER 0x40000001 +#define TPM2_RS_PW 0x40000009 +#define TPM2_RH_ENDORSEMENT 0x4000000b +#define TPM2_RH_PLATFORM 0x4000000c + +#define TPM2_ALG_SHA1 0x0004 +#define TPM2_ALG_SHA256 0x000b +#define TPM2_ALG_SHA384 0x000c +#define TPM2_ALG_SHA512 0x000d +#define TPM2_ALG_SM3_256 0x0012 + +/* TPM 2 command tags */ +#define TPM2_ST_NO_SESSIONS 0x8001 +#define TPM2_ST_SESSIONS 0x8002 + +/* TPM 2 commands */ +#define TPM2_CC_HierarchyControl 0x121 +#define TPM2_CC_Clear 0x126 +#define TPM2_CC_ClearControl 0x127 +#define TPM2_CC_HierarchyChangeAuth 0x129 +#define TPM2_CC_PCR_Allocate 0x12b +#define TPM2_CC_SelfTest 0x143 +#define TPM2_CC_Startup 0x144 +#define TPM2_CC_Shutdown 0x145 +#define TPM2_CC_StirRandom 0x146 +#define TPM2_CC_GetCapability 0x17a +#define TPM2_CC_GetRandom 0x17b +#define TPM2_CC_PCR_Extend 0x182 + +/* TPM 2 Capabilities */ +#define TPM2_CAP_PCRS 0x00000005 + +/* TPM 2 data structures */ + +struct TPMT_HA { + uint16_t hashAlg; + uint8_t hash[0]; /* size depends on hashAlg */ +} __attribute__((packed)); + +struct TPML_DIGEST_VALUES { + uint32_t count; + struct TPMT_HA digest[0]; /* variable number of entries */ +} __attribute__((packed)); + +struct tpm2_req_stirrandom { + struct tpm_req_header hdr; + uint16_t size; + uint64_t stir; +} __attribute__((packed)); + +struct tpm2_req_getrandom { + struct tpm_req_header hdr; + uint16_t bytesRequested; +} __attribute__((packed)); + +struct tpm2b_20 { + uint16_t size; + uint8_t buffer[20]; +} __attribute__((packed)); + +struct tpm2_res_getrandom { + struct tpm_rsp_header hdr; + struct tpm2b_20 rnd; +} __attribute__((packed)); + +/* + * tpm2_authblock is used in TPM 2 commands using 'Auth. Handle' + */ +struct tpm2_authblock { + uint32_t handle; + uint16_t noncesize; /* always 0 */ + uint8_t contsession; /* always TPM2_YES */ + uint16_t pwdsize; /* always 0 */ +} __attribute__((packed)); + +struct tpm2_req_hierarchychangeauth { + struct tpm_req_header hdr; + uint32_t authhandle; + uint32_t authblocksize; + struct tpm2_authblock authblock; + struct tpm2b_20 newAuth; +} __attribute__((packed)); + +struct tpm2_req_extend { + struct tpm_req_header hdr; + uint32_t pcrindex; + uint32_t authblocksize; + struct tpm2_authblock authblock; + uint8_t digest[0]; +} __attribute__((packed)); + +struct tpm2_req_clearcontrol { + struct tpm_req_header hdr; + uint32_t authhandle; + uint32_t authblocksize; + struct tpm2_authblock authblock; + uint8_t disable; +} __attribute__((packed)); + +struct tpm2_req_clear { + struct tpm_req_header hdr; + uint32_t authhandle; + uint32_t authblocksize; + struct tpm2_authblock authblock; +} __attribute__((packed)); + +struct tpm2_req_hierarchycontrol { + struct tpm_req_header hdr; + uint32_t authhandle; + uint32_t authblocksize; + struct tpm2_authblock authblock; + uint32_t enable; + uint8_t state; +} __attribute__((packed)); + +struct tpm2_req_getcapability { + struct tpm_req_header hdr; + uint32_t capability; + uint32_t property; + uint32_t propertycount; +} __attribute__((packed)); + +struct tpm2_res_getcapability { + struct tpm_rsp_header hdr; + uint8_t moreData; + uint32_t capability; + uint8_t data[0]; /* capability dependent data */ +} __attribute__((packed)); + +struct tpm2_req_pcr_allocate { + struct tpm_req_header hdr; + uint32_t authhandle; + uint32_t authblocksize; + struct tpm2_authblock authblock; + uint32_t count; + uint8_t tpms_pcr_selections[4]; +} __attribute__((packed)); + +struct tpms_pcr_selection { + uint16_t hashAlg; + uint8_t sizeOfSelect; + uint8_t pcrSelect[0]; +} __attribute__((packed)); + +struct tpml_pcr_selection { + uint32_t count; + struct tpms_pcr_selection selections[0]; +} __attribute__((packed)); + #endif /* TCGBIOS_INT_H */ diff --git a/lib/libtpm/tpm.code b/lib/libtpm/tpm.code new file mode 100644 index 0000000..05f4547 --- /dev/null +++ b/lib/libtpm/tpm.code @@ -0,0 +1,130 @@ +/****************************************************************************** + * Copyright (c) 2015-2020 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ +/* + * libtpm bindings for SLOF - implementation + */ + +#include +#include + +/************************************************/ +/* Startup TPM code */ +/* SLOF: tpm-start ( -- errcode ) */ +/* LIBTPM: tpm_start(void) */ +/************************************************/ +PRIM(tpm_X2d_start) + PUSH; + TOS.n = tpm_start(); +MIRP + +/************************************************/ +/* Shutdown TPM layer before OS takes over */ +/* SLOF: tpm-finalize ( -- ) */ +/* LIBTPM: tpm_finalize(void) */ +/************************************************/ +PRIM(tpm_X2d_finalize) + tpm_finalize(); +MIRP + +/***************************************************************/ +/* Prepare TPM state for bootloader */ +/* SLOF: tpm-leave-firwmare ( -- errcode ) */ +/* LIBTPM: tpm_leave_firmware(void) */ +/***************************************************************/ +PRIM(tpm_X2d_leave_X2d_firmware) + PUSH; + TOS.n = tpm_leave_firmware(); +MIRP + +/*************************************************************/ +/* Convey log address and size */ +/* SLOF: tpm-set-log-parameters ( addr size -- ) */ +/* LIBTPM: tpm_set_log_parameters(void *addr, uint64_t size) */ +/*************************************************************/ +PRIM(tpm_X2d_set_X2d_log_X2d_parameters) + int size = TOS.u; POP; + void *addr = TOS.a; POP; + tpm_set_log_parameters(addr, size); +MIRP + +/*********************************************************/ +/* Firmware API */ +/* SLOF: tpm-driver-get_failure-reason ( -- errcode) */ +/* LIBTPM: errcode = tpm_driver_get_failure_reason(void) */ +/*********************************************************/ +PRIM(tpm_X2d_driver_X2d_get_X2d_failure_X2d_reason) + PUSH; + TOS.n = tpm_driver_get_failure_reason(); +MIRP + +/********************************************************/ +/* Firmware API */ +/* SLOF: tpm-driver-set-failure_reason ( errcode -- ) */ +/* LIBTPM: tpm_driver_set_failure_reason(errcode) */ +/********************************************************/ +PRIM(tpm_X2d_driver_X2d_set_X2d_failure_X2d_reason) + int errcode = TOS.u; POP; + tpm_driver_set_failure_reason(errcode); +MIRP + +/************************************************/ +/* Get the size of the log */ +/* SLOF: tpm-get-logsize ( -- size ) */ +/* LIBTPM: logsize = tpm_get_logsize(void) */ +/************************************************/ +PRIM(tpm_X2d_get_X2d_logsize) + PUSH; + TOS.n = tpm_get_logsize(); +MIRP + +/**********************************************************************/ +/* Measure and log event separators */ +/* SLOF: tpm-add-event-separators ( start-pcr end-pcr -- errcode) */ +/* LIBTPM: errcode = tpm_add_event_separators(start_pcr, end_pcr) */ +/**********************************************************************/ +PRIM(tpm_X2d_add_X2d_event_X2d_separators) + int end_pcr = TOS.u; POP; + int start_pcr = TOS.u; + TOS.n = tpm_add_event_separators(start_pcr, end_pcr); +MIRP + +/*************************************************************************/ +/* Measure and log boot connect vector (bcv) device's master boot record */ +/* SLOF: tpm-measure-bcv-mbr ( bootdrv addr length -- errcode ) */ +/* LIBTPM: errcode = tpm_measure_bcv_mbr(bbotdrv, addr, length) */ +/*************************************************************************/ +PRIM(tpm_X2d_measure_X2d_bcv_X2d_mbr) + int length = TOS.u; POP; + void *addr = TOS.a; POP; + int bootdrv = TOS.u; + TOS.n = tpm_measure_bcv_mbr(bootdrv, addr, length); +MIRP + +/************************************************/ +/* Check whether the TPM is working */ +/* SLOF: tpm-is-working ( -- true | false ) */ +/* LIBTPM: bool = tpm_is_working() */ +/************************************************/ +PRIM(tpm_X2d_is_X2d_working) + PUSH; + TOS.n = tpm_is_working(); +MIRP + +/************************************************/ +/* Have the S-CRTM measured */ +/* SLOF: tpm-measure-scrtm ( -- errcode ) */ +/* LIBTPM: errcode = tpm_measure_scrtm */ +/************************************************/ +PRIM(tpm_X2d_measure_X2d_scrtm) + PUSH; + TOS.n = tpm_measure_scrtm(); +MIRP diff --git a/lib/libtpm/tpm.in b/lib/libtpm/tpm.in new file mode 100644 index 0000000..22713e4 --- /dev/null +++ b/lib/libtpm/tpm.in @@ -0,0 +1,26 @@ +/****************************************************************************** + * Copyright (c) 2015-2020 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ +/* + * libtpm bindings for SLOF - definitions + */ + +cod(tpm-start) +cod(tpm-finalize) +cod(tpm-leave-firmware) +cod(tpm-set-log-parameters) +cod(tpm-get-logsize) +cod(tpm-add-event-separators) +cod(tpm-measure-bcv-mbr) +cod(tpm-is-working) +cod(tpm-measure-scrtm) +cod(tpm-driver-get-failure-reason) +cod(tpm-driver-set-failure-reason) diff --git a/slof/fs/packages/disk-label.fs b/slof/fs/packages/disk-label.fs index 8859fb0..252a44e 100644 --- a/slof/fs/packages/disk-label.fs +++ b/slof/fs/packages/disk-label.fs @@ -338,6 +338,14 @@ CONSTANT /gpt-part-entry dup c@ eb = swap 2+ c@ 90 = and ; +: measure-mbr ( addr length -- ) + s" /ibm,vtpm" find-node ?dup IF + s" measure-hdd-mbr" rot $call-static + ELSE + 2drop + THEN +; + \ NOTE: block-size is always 512 bytes for DOS partition tables. : load-from-dos-boot-partition ( addr -- size ) @@ -361,6 +369,7 @@ CONSTANT /gpt-part-entry block-size * to part-offset 0 0 seek drop ( addr offset ) block-size * read ( size ) + block block-size measure-mbr UNLOOP EXIT ELSE 2drop ( addr ) diff --git a/slof/fs/start-up.fs b/slof/fs/start-up.fs index 7020f5c..c1f931a 100644 --- a/slof/fs/start-up.fs +++ b/slof/fs/start-up.fs @@ -56,6 +56,11 @@ ; : (boot?) ( -- ) + \ last step before we boot we give up physical presence on the TPM + s" /ibm,vtpm" find-node ?dup IF + s" leave-firmware" rot $call-static + THEN + of-prompt? not auto-boot? and IF (boot) THEN From patchwork Tue Jan 21 20:01:46 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Berger X-Patchwork-Id: 1226746 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 482KFl4K8Nz9sRW for ; Wed, 22 Jan 2020 07:02:35 +1100 (AEDT) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.ibm.com Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 482KFl3WMnzDqSy for ; Wed, 22 Jan 2020 07:02:35 +1100 (AEDT) X-Original-To: slof@lists.ozlabs.org Delivered-To: slof@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=linux.ibm.com (client-ip=148.163.158.5; helo=mx0a-001b2d01.pphosted.com; envelope-from=stefanb@linux.ibm.com; receiver=) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.ibm.com Received: from mx0a-001b2d01.pphosted.com (mx0b-001b2d01.pphosted.com [148.163.158.5]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 482KF44K5RzDqPm for ; Wed, 22 Jan 2020 07:02:00 +1100 (AEDT) Received: from pps.filterd (m0098414.ppops.net [127.0.0.1]) by mx0b-001b2d01.pphosted.com (8.16.0.42/8.16.0.42) with SMTP id 00LJqos6094160; Tue, 21 Jan 2020 15:01:55 -0500 Received: from ppma03wdc.us.ibm.com (ba.79.3fa9.ip4.static.sl-reverse.com [169.63.121.186]) by mx0b-001b2d01.pphosted.com with ESMTP id 2xmfy24n1w-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 21 Jan 2020 15:01:55 -0500 Received: from pps.filterd (ppma03wdc.us.ibm.com [127.0.0.1]) by ppma03wdc.us.ibm.com (8.16.0.27/8.16.0.27) with SMTP id 00LK1ZCn021141; Tue, 21 Jan 2020 20:01:54 GMT Received: from b03cxnp07029.gho.boulder.ibm.com (b03cxnp07029.gho.boulder.ibm.com [9.17.130.16]) by ppma03wdc.us.ibm.com with ESMTP id 2xksn66h0w-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 21 Jan 2020 20:01:54 +0000 Received: from b03ledav003.gho.boulder.ibm.com (b03ledav003.gho.boulder.ibm.com [9.17.130.234]) by b03cxnp07029.gho.boulder.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 00LK1rjr11338090 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 21 Jan 2020 20:01:53 GMT Received: from b03ledav003.gho.boulder.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id AE8BA6A04D; Tue, 21 Jan 2020 20:01:53 +0000 (GMT) Received: from b03ledav003.gho.boulder.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 33AFE6A061; Tue, 21 Jan 2020 20:01:53 +0000 (GMT) Received: from sbct-3.pok.ibm.com (unknown [9.47.158.153]) by b03ledav003.gho.boulder.ibm.com (Postfix) with ESMTP; Tue, 21 Jan 2020 20:01:53 +0000 (GMT) From: Stefan Berger To: slof@lists.ozlabs.org, aik@ozlabs.ru Date: Tue, 21 Jan 2020 15:01:46 -0500 Message-Id: <20200121200147.1002075-8-stefanb@linux.ibm.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200121200147.1002075-1-stefanb@linux.ibm.com> References: <20200121200147.1002075-1-stefanb@linux.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:6.0.138, 18.0.634 definitions=2020-01-21_06:2020-01-21, 2020-01-21 signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 mlxscore=0 lowpriorityscore=0 phishscore=0 spamscore=0 adultscore=0 bulkscore=0 impostorscore=0 clxscore=1015 mlxlogscore=999 suspectscore=9 priorityscore=1501 malwarescore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-1910280000 definitions=main-2001210148 Subject: [SLOF] [PATCH v7 7/8] tcgbios: Implement menu to clear TPM 2 and activate its PCR banks X-BeenThere: slof@lists.ozlabs.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "Patches for https://github.com/aik/SLOF" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kevin@koconnor.net, Stefan Berger Errors-To: slof-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "SLOF" Implement a TPM 2 menu and enable the user to clear the TPM and its activate PCR banks. The main TPM menu is activated by pressing the 't' key during firmware startup. Signed-off-by: Stefan Berger Signed-off-by: Kevin O'Connor --- board-qemu/slof/OF.fs | 3 + board-qemu/slof/vtpm-sml.fs | 6 + lib/libtpm/tcgbios.c | 348 ++++++++++++++++++++++++++++++++++++ lib/libtpm/tcgbios.h | 1 + lib/libtpm/tpm.code | 9 + lib/libtpm/tpm.in | 1 + slof/fs/start-up.fs | 7 + 7 files changed, 375 insertions(+) diff --git a/board-qemu/slof/OF.fs b/board-qemu/slof/OF.fs index 3e117ad..f0fc9c6 100644 --- a/board-qemu/slof/OF.fs +++ b/board-qemu/slof/OF.fs @@ -175,6 +175,9 @@ CREATE version-str 10 ALLOT version-str 8 + @ \ end over - dump-display-write " Press 's' to enter Open Firmware." dump-display-write + s" /ibm,vtpm" find-node IF + " Press 't' to enter TPM menu." dump-display-write + THEN cr cr temp-ptr disp-size > IF temp-ptr disp-size MOD diff --git a/board-qemu/slof/vtpm-sml.fs b/board-qemu/slof/vtpm-sml.fs index 8e2ab6d..a51c907 100644 --- a/board-qemu/slof/vtpm-sml.fs +++ b/board-qemu/slof/vtpm-sml.fs @@ -56,6 +56,12 @@ s" ibm,vtpm" 2dup device-name device-type THEN ; +: vtpm-menu + tpm-is-working IF + tpm20-menu + THEN +; + : open true ; : close ; diff --git a/lib/libtpm/tcgbios.c b/lib/libtpm/tcgbios.c index d81d392..c5f8ccf 100644 --- a/lib/libtpm/tcgbios.c +++ b/lib/libtpm/tcgbios.c @@ -63,6 +63,12 @@ static struct { struct tpml_pcr_selection *tpm20_pcr_selection; } tpm_state; +#define TPM2_ALG_SHA1_FLAG (1 << 0) +#define TPM2_ALG_SHA256_FLAG (1 << 1) +#define TPM2_ALG_SHA384_FLAG (1 << 2) +#define TPM2_ALG_SHA512_FLAG (1 << 3) +#define TPM2_ALG_SM3_256_FLAG (1 << 4) + /* * TPM 2 logs are written in little endian format. */ @@ -110,23 +116,36 @@ struct tpm_log_entry { static const struct hash_parameters { uint16_t hashalg; + uint8_t hashalg_flag; uint8_t hash_buffersize; + const char *name; } hash_parameters[] = { { .hashalg = TPM2_ALG_SHA1, + .hashalg_flag = TPM2_ALG_SHA1_FLAG, .hash_buffersize = SHA1_BUFSIZE, + .name = "SHA1", }, { .hashalg = TPM2_ALG_SHA256, + .hashalg_flag = TPM2_ALG_SHA256_FLAG, .hash_buffersize = SHA256_BUFSIZE, + .name = "SHA256", }, { .hashalg = TPM2_ALG_SHA384, + .hashalg_flag = TPM2_ALG_SHA384_FLAG, .hash_buffersize = SHA384_BUFSIZE, + .name = "SHA384", + }, { .hashalg = TPM2_ALG_SHA512, + .hashalg_flag = TPM2_ALG_SHA512_FLAG, .hash_buffersize = SHA512_BUFSIZE, + .name = "SHA512", }, { .hashalg = TPM2_ALG_SM3_256, + .hashalg_flag = TPM2_ALG_SM3_256_FLAG, .hash_buffersize = SM3_256_BUFSIZE, + .name = "SM3-256", } }; @@ -141,6 +160,18 @@ static const struct hash_parameters *tpm20_find_by_hashalg(uint16_t hashAlg) return NULL; } +static const struct hash_parameters * +tpm20_find_by_hashalg_flag(uint16_t hashalg_flag) +{ + unsigned i; + + for (i = 0; i < ARRAY_SIZE(hash_parameters); i++) { + if (hash_parameters[i].hashalg_flag == hashalg_flag) + return &hash_parameters[i]; + } + return NULL; +} + static inline int tpm20_get_hash_buffersize(uint16_t hashAlg) { const struct hash_parameters *hp = tpm20_find_by_hashalg(hashAlg); @@ -150,6 +181,35 @@ static inline int tpm20_get_hash_buffersize(uint16_t hashAlg) return -1; } +static inline uint8_t tpm20_hashalg_to_flag(uint16_t hashAlg) +{ + const struct hash_parameters *hp = tpm20_find_by_hashalg(hashAlg); + + if (hp) + return hp->hashalg_flag; + return 0; +} + +static uint16_t tpm20_hashalg_flag_to_hashalg(uint8_t hashalg_flag) +{ + const struct hash_parameters *hp; + + hp = tpm20_find_by_hashalg_flag(hashalg_flag); + if (hp) + return hp->hashalg; + return 0; +} + +static const char * tpm20_hashalg_flag_to_name(uint8_t hashalg_flag) +{ + const struct hash_parameters *hp; + + hp = tpm20_find_by_hashalg_flag(hashalg_flag); + if (hp) + return hp->name; + return NULL; +} + /* * Build the TPM2 TPML_DIGEST_VALUES data structure from the given hash. * Follow the PCR bank configuration of the TPM and write the same hash @@ -923,3 +983,291 @@ void tpm_driver_set_failure_reason(uint32_t errcode) spapr_vtpm_set_error(errcode); } + +/**************************************************************** + * TPM Configuration Menu + ****************************************************************/ + +static int +tpm20_get_suppt_pcrbanks(uint8_t *suppt_pcrbanks, uint8_t *active_pcrbanks) +{ + struct tpms_pcr_selection *sel; + void *end; + + *suppt_pcrbanks = 0; + *active_pcrbanks = 0; + + sel = tpm_state.tpm20_pcr_selection->selections; + end = (void*)tpm_state.tpm20_pcr_selection + + tpm_state.tpm20_pcr_selection_size; + + while (1) { + uint16_t hashalg; + uint8_t hashalg_flag; + unsigned i; + uint8_t sizeOfSelect = sel->sizeOfSelect; + void *nsel = (void*)sel + sizeof(*sel) + sizeOfSelect; + + if (nsel > end) + return 0; + + hashalg = be16_to_cpu(sel->hashAlg); + hashalg_flag = tpm20_hashalg_to_flag(hashalg); + + *suppt_pcrbanks |= hashalg_flag; + + for (i = 0; i < sizeOfSelect; i++) { + if (sel->pcrSelect[i]) { + *active_pcrbanks |= hashalg_flag; + break; + } + } + + sel = nsel; + } +} + +static int +tpm20_set_pcrbanks(uint32_t active_banks) +{ + struct tpm2_req_pcr_allocate trpa = { + .hdr.tag = cpu_to_be16(TPM2_ST_SESSIONS), + .hdr.ordinal = cpu_to_be32(TPM2_CC_PCR_Allocate), + .authhandle = cpu_to_be32(TPM2_RH_PLATFORM), + .authblocksize = cpu_to_be32(sizeof(trpa.authblock)), + .authblock = { + .handle = cpu_to_be32(TPM2_RS_PW), + .noncesize = cpu_to_be16(0), + .contsession = TPM2_YES, + .pwdsize = cpu_to_be16(0), + }, + }; + struct tpms_pcr_selection3 { + uint16_t hashAlg; + uint8_t sizeOfSelect; + uint8_t pcrSelect[3]; + } tps[ARRAY_SIZE(trpa.tpms_pcr_selections)]; + int i = 0; + uint8_t hashalg_flag = TPM2_ALG_SHA1_FLAG; + uint8_t dontcare, suppt_banks; + struct tpm_rsp_header rsp; + uint32_t resp_length = sizeof(rsp); + uint16_t hashalg; + int ret; + + tpm20_get_suppt_pcrbanks(&suppt_banks, &dontcare); + + while (hashalg_flag) { + if ((hashalg_flag & suppt_banks)) { + hashalg = tpm20_hashalg_flag_to_hashalg(hashalg_flag); + + if (hashalg) { + uint8_t mask = 0; + + tps[i].hashAlg = cpu_to_be16(hashalg); + tps[i].sizeOfSelect = 3; + + if (active_banks & hashalg_flag) + mask = 0xff; + + tps[i].pcrSelect[0] = mask; + tps[i].pcrSelect[1] = mask; + tps[i].pcrSelect[2] = mask; + i++; + } + } + hashalg_flag <<= 1; + } + + trpa.count = cpu_to_be32(i); + memcpy(trpa.tpms_pcr_selections, tps, i * sizeof(tps[0])); + trpa.hdr.totlen = cpu_to_be32(offset_of(struct tpm2_req_pcr_allocate, + tpms_pcr_selections) + + i * sizeof(tps[0])); + + ret = spapr_transmit(0, &trpa.hdr, &rsp, &resp_length, + TPM_DURATION_TYPE_SHORT); + ret = ret ? -1 : be32_to_cpu(rsp.errcode); + + return ret; +} + +static int tpm20_activate_pcrbanks(uint32_t active_banks) +{ + int ret; + + ret = tpm20_set_pcrbanks(active_banks); + if (!ret) + ret = tpm_simple_cmd(0, TPM2_CC_Shutdown, + 2, TPM2_SU_CLEAR, TPM_DURATION_TYPE_SHORT); + if (!ret) + SLOF_reset(); + return ret; +} + +static int +tpm20_clearcontrol(uint8_t disable) +{ + struct tpm2_req_clearcontrol trc = { + .hdr.tag = cpu_to_be16(TPM2_ST_SESSIONS), + .hdr.totlen = cpu_to_be32(sizeof(trc)), + .hdr.ordinal = cpu_to_be32(TPM2_CC_ClearControl), + .authhandle = cpu_to_be32(TPM2_RH_PLATFORM), + .authblocksize = cpu_to_be32(sizeof(trc.authblock)), + .authblock = { + .handle = cpu_to_be32(TPM2_RS_PW), + .noncesize = cpu_to_be16(0), + .contsession = TPM2_YES, + .pwdsize = cpu_to_be16(0), + }, + .disable = disable, + }; + struct tpm_rsp_header rsp; + uint32_t resp_length = sizeof(rsp); + int ret; + + ret = spapr_transmit(0, &trc.hdr, &rsp, &resp_length, + TPM_DURATION_TYPE_SHORT); + if (ret || resp_length != sizeof(rsp) || rsp.errcode) + ret = -1; + + dprintf("TCGBIOS: Return value from sending TPM2_CC_ClearControl = 0x%08x\n", + ret); + + return ret; +} + +static int +tpm20_clear(void) +{ + struct tpm2_req_clear trq = { + .hdr.tag = cpu_to_be16(TPM2_ST_SESSIONS), + .hdr.totlen = cpu_to_be32(sizeof(trq)), + .hdr.ordinal = cpu_to_be32(TPM2_CC_Clear), + .authhandle = cpu_to_be32(TPM2_RH_PLATFORM), + .authblocksize = cpu_to_be32(sizeof(trq.authblock)), + .authblock = { + .handle = cpu_to_be32(TPM2_RS_PW), + .noncesize = cpu_to_be16(0), + .contsession = TPM2_YES, + .pwdsize = cpu_to_be16(0), + }, + }; + struct tpm_rsp_header rsp; + uint32_t resp_length = sizeof(rsp); + int ret; + + ret = spapr_transmit(0, &trq.hdr, &rsp, &resp_length, + TPM_DURATION_TYPE_MEDIUM); + if (ret || resp_length != sizeof(rsp) || rsp.errcode) + ret = -1; + + dprintf("TCGBIOS: Return value from sending TPM2_CC_Clear = 0x%08x\n", + ret); + + return ret; +} + +static int tpm20_menu_change_active_pcrbanks(void) +{ + uint8_t active_banks, suppt_banks, activate_banks; + + tpm20_get_suppt_pcrbanks(&suppt_banks, &active_banks); + + activate_banks = active_banks; + + while (1) { + uint8_t hashalg_flag = TPM2_ALG_SHA1_FLAG; + uint8_t i = 0; + uint8_t flagnum; + int show = 0; + + printf("\nToggle active PCR banks by pressing number key\n\n"); + + while (hashalg_flag) { + uint8_t flag = hashalg_flag & suppt_banks; + const char *hashname = tpm20_hashalg_flag_to_name(flag); + + i++; + if (hashname) { + printf(" %d: %s", i, hashname); + if (activate_banks & hashalg_flag) + printf(" (enabled)"); + printf("\n"); + } + + hashalg_flag <<= 1; + } + printf("\n" + "ESC: return to previous menu without changes\n"); + if (activate_banks) + printf("a : activate selection\n"); + + while (!show) { + int key_code = SLOF_get_keystroke(); + + switch (key_code) { + case ~0: + continue; + case 27: /* ESC */ + printf("\n"); + return -1; + case '1' ... '5': /* keys 1 .. 5 */ + flagnum = key_code - '0'; + if (flagnum > i) + continue; + if (suppt_banks & (1 << (flagnum - 1))) { + activate_banks ^= 1 << (flagnum - 1); + show = 1; + } + break; + case 'a': /* a */ + if (activate_banks) + tpm20_activate_pcrbanks(activate_banks); + } + } + } +} + +void tpm20_menu(void) +{ + int key_code; + int waitkey; + int ret; + + for (;;) { + printf("1. Clear TPM\n"); + printf("2. Change active PCR banks\n"); + + printf("\nIf not change is desired or if this menu was reached by " + "mistake, press ESC to\ncontinue the boot.\n"); + + waitkey = 1; + + while (waitkey) { + key_code = SLOF_get_keystroke(); + switch (key_code) { + case 27: + // ESC + return; + case '1': + ret = tpm20_clearcontrol(false); + if (!ret) + ret = tpm20_clear(); + if (ret) + printf("An error occurred clearing " + "the TPM: 0x%x\n", + ret); + break; + case '2': + tpm20_menu_change_active_pcrbanks(); + waitkey = 0; + continue; + default: + continue; + } + + waitkey = 0; + } + } +} diff --git a/lib/libtpm/tcgbios.h b/lib/libtpm/tcgbios.h index e9f9c36..c4a2e71 100644 --- a/lib/libtpm/tcgbios.h +++ b/lib/libtpm/tcgbios.h @@ -28,5 +28,6 @@ uint32_t tpm_add_event_separators(uint32_t start_pcr, uint32_t end_pcr); uint32_t tpm_driver_get_failure_reason(void); void tpm_driver_set_failure_reason(uint32_t errcode); bool tpm_is_working(void); +void tpm20_menu(void); #endif /* TCGBIOS_H */ diff --git a/lib/libtpm/tpm.code b/lib/libtpm/tpm.code index 05f4547..b8f5669 100644 --- a/lib/libtpm/tpm.code +++ b/lib/libtpm/tpm.code @@ -128,3 +128,12 @@ PRIM(tpm_X2d_measure_X2d_scrtm) PUSH; TOS.n = tpm_measure_scrtm(); MIRP + +/*******************************************************************/ +/* Firmware API */ +/* SLOF: tpm20-menu ( -- tpm-version ) */ +/* LIBTPM: tpm20_menu() */ +/*******************************************************************/ +PRIM(tpm20_X2d_menu) + tpm20_menu(); +MIRP diff --git a/lib/libtpm/tpm.in b/lib/libtpm/tpm.in index 22713e4..590fee1 100644 --- a/lib/libtpm/tpm.in +++ b/lib/libtpm/tpm.in @@ -24,3 +24,4 @@ cod(tpm-is-working) cod(tpm-measure-scrtm) cod(tpm-driver-get-failure-reason) cod(tpm-driver-set-failure-reason) +cod(tpm20-menu) diff --git a/slof/fs/start-up.fs b/slof/fs/start-up.fs index c1f931a..45e8926 100644 --- a/slof/fs/start-up.fs +++ b/slof/fs/start-up.fs @@ -55,6 +55,12 @@ nvramlog-write-string-cr ; +: (t-pressed) ( -- ) + s" /ibm,vtpm" find-node ?dup IF + s" vtpm-menu" rot $call-static + THEN +; + : (boot?) ( -- ) \ last step before we boot we give up physical presence on the TPM s" /ibm,vtpm" find-node ?dup IF @@ -105,6 +111,7 @@ TRUE VALUE use-load-watchdog? key? IF key CASE [char] s OF (s-pressed) ENDOF + [char] t OF (t-pressed) (boot?) ENDOF 1b OF (esc-sequence) CASE 1 OF From patchwork Tue Jan 21 20:01:47 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Berger X-Patchwork-Id: 1226747 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [203.11.71.2]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 482KFs0YGwz9sRW for ; Wed, 22 Jan 2020 07:02:41 +1100 (AEDT) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.ibm.com Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 482KFs03c0zDqSc for ; Wed, 22 Jan 2020 07:02:41 +1100 (AEDT) X-Original-To: slof@lists.ozlabs.org Delivered-To: slof@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=linux.ibm.com (client-ip=148.163.158.5; helo=mx0a-001b2d01.pphosted.com; envelope-from=stefanb@linux.ibm.com; receiver=) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.ibm.com Received: from mx0a-001b2d01.pphosted.com (mx0b-001b2d01.pphosted.com [148.163.158.5]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 482KF445kpzDqPf for ; Wed, 22 Jan 2020 07:02:00 +1100 (AEDT) Received: from pps.filterd (m0098419.ppops.net [127.0.0.1]) by mx0b-001b2d01.pphosted.com (8.16.0.42/8.16.0.42) with SMTP id 00LJqnS7130365; Tue, 21 Jan 2020 15:01:57 -0500 Received: from ppma01dal.us.ibm.com (83.d6.3fa9.ip4.static.sl-reverse.com [169.63.214.131]) by mx0b-001b2d01.pphosted.com with ESMTP id 2xp0s788fd-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 21 Jan 2020 15:01:56 -0500 Received: from pps.filterd (ppma01dal.us.ibm.com [127.0.0.1]) by ppma01dal.us.ibm.com (8.16.0.27/8.16.0.27) with SMTP id 00LK0nrs023411; Tue, 21 Jan 2020 20:01:55 GMT Received: from b03cxnp08027.gho.boulder.ibm.com (b03cxnp08027.gho.boulder.ibm.com [9.17.130.19]) by ppma01dal.us.ibm.com with ESMTP id 2xksn6p43b-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 21 Jan 2020 20:01:55 +0000 Received: from b03ledav003.gho.boulder.ibm.com (b03ledav003.gho.boulder.ibm.com [9.17.130.234]) by b03cxnp08027.gho.boulder.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 00LK1soU59048304 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 21 Jan 2020 20:01:54 GMT Received: from b03ledav003.gho.boulder.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 6683D6A051; Tue, 21 Jan 2020 20:01:54 +0000 (GMT) Received: from b03ledav003.gho.boulder.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id CFADF6A05A; Tue, 21 Jan 2020 20:01:53 +0000 (GMT) Received: from sbct-3.pok.ibm.com (unknown [9.47.158.153]) by b03ledav003.gho.boulder.ibm.com (Postfix) with ESMTP; Tue, 21 Jan 2020 20:01:53 +0000 (GMT) From: Stefan Berger To: slof@lists.ozlabs.org, aik@ozlabs.ru Date: Tue, 21 Jan 2020 15:01:47 -0500 Message-Id: <20200121200147.1002075-9-stefanb@linux.ibm.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200121200147.1002075-1-stefanb@linux.ibm.com> References: <20200121200147.1002075-1-stefanb@linux.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:6.0.138, 18.0.634 definitions=2020-01-21_06:2020-01-21, 2020-01-21 signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 spamscore=0 priorityscore=1501 suspectscore=29 mlxlogscore=999 phishscore=0 impostorscore=0 clxscore=1015 bulkscore=0 malwarescore=0 mlxscore=0 lowpriorityscore=0 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-1910280000 definitions=main-2001210148 Subject: [SLOF] [PATCH v7 8/8] tcgbios: Measure the GPT table X-BeenThere: slof@lists.ozlabs.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "Patches for https://github.com/aik/SLOF" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Stefan Berger , kevin@koconnor.net Errors-To: slof-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "SLOF" From: Stefan Berger Measure and log the GPT table including LBA1 and all GPT table entries with a non-zero Type GUID. We follow the specification "TCG PC Client Platform Firmware Profile Specification" for the format of what needs to be logged and measured. See section "Event Logging" subsection "Measuring UEFI Variables" for the UEFI_GPT_DATA structure. Signed-off-by: Stefan Berger --- board-qemu/slof/vtpm-sml.fs | 8 ++++ lib/libtpm/tcgbios.c | 88 ++++++++++++++++++++++++++++++++++ lib/libtpm/tcgbios.h | 3 ++ lib/libtpm/tcgbios_int.h | 40 ++++++++++++++++ lib/libtpm/tpm.code | 32 +++++++++++++ lib/libtpm/tpm.in | 3 ++ slof/fs/packages/disk-label.fs | 22 +++++++++ 7 files changed, 196 insertions(+) diff --git a/board-qemu/slof/vtpm-sml.fs b/board-qemu/slof/vtpm-sml.fs index a51c907..fd0e6ee 100644 --- a/board-qemu/slof/vtpm-sml.fs +++ b/board-qemu/slof/vtpm-sml.fs @@ -42,6 +42,14 @@ s" ibm,vtpm" 2dup device-name device-type THEN ; +: measure-gpt ( ) + 0 7 separator-event + tpm-measure-gpt + ?dup IF + ." VTPM: Error code from tpm-measure-gpt: " . cr + THEN +; + : leave-firmware ( -- ) tpm-leave-firmware ( errcode ) ?dup IF diff --git a/lib/libtpm/tcgbios.c b/lib/libtpm/tcgbios.c index c5f8ccf..be6c3d1 100644 --- a/lib/libtpm/tcgbios.c +++ b/lib/libtpm/tcgbios.c @@ -69,6 +69,11 @@ static struct { #define TPM2_ALG_SHA512_FLAG (1 << 3) #define TPM2_ALG_SM3_256_FLAG (1 << 4) +static const uint8_t ZeroGuid[16] = { 0 }; + +static UEFI_GPT_DATA *uefi_gpt_data; +static size_t uefi_gpt_data_size; + /* * TPM 2 logs are written in little endian format. */ @@ -925,6 +930,89 @@ uint32_t tpm_measure_bcv_mbr(uint32_t bootdrv, const uint8_t *addr, addr + 0x1b8, 0x48); } +/* + * This is the first function to call when measuring a GPT table. + * It allocates memory for the data to log which are 'measured' later on. + */ +void tpm_gpt_set_lba1(const uint8_t *addr, uint32_t length) +{ + if (!tpm_is_working()) + return; + + SLOF_free_mem(uefi_gpt_data, uefi_gpt_data_size); + + uefi_gpt_data_size = sizeof(UEFI_GPT_DATA); + uefi_gpt_data = SLOF_alloc_mem(uefi_gpt_data_size); + if (!uefi_gpt_data) + return; + + memcpy(&uefi_gpt_data->EfiPartitionHeader, + addr, sizeof(uefi_gpt_data->EfiPartitionHeader)); + uefi_gpt_data->NumberOfPartitions = 0; +} + +/* + * This function adds a GPT entry to the data to measure. It must + * be called after tpm_gpt_set_lba1. + */ +void tpm_gpt_add_entry(const uint8_t *addr, uint32_t length) +{ + size_t sz; + UEFI_PARTITION_ENTRY *upe = (void *)addr; + void *tmp; + + if (!tpm_is_working() || + !uefi_gpt_data || + length < sizeof(*upe) || + !memcmp(upe->partTypeGuid, ZeroGuid, sizeof(ZeroGuid))) + return; + + sz = offset_of(UEFI_GPT_DATA, Partitions) + + (uefi_gpt_data->NumberOfPartitions + 1) + * sizeof(UEFI_PARTITION_ENTRY); + if (sz > uefi_gpt_data_size) { + tmp = SLOF_alloc_mem(sz); + if (!tmp) + goto err_no_mem; + + memcpy(tmp, uefi_gpt_data, uefi_gpt_data_size); + SLOF_free_mem(uefi_gpt_data, uefi_gpt_data_size); + uefi_gpt_data = tmp; + uefi_gpt_data_size = sz; + } + + memcpy(&uefi_gpt_data->Partitions[uefi_gpt_data->NumberOfPartitions], + addr, + sizeof(UEFI_PARTITION_ENTRY)); + uefi_gpt_data->NumberOfPartitions++; + + return; + +err_no_mem: + SLOF_free_mem(uefi_gpt_data, uefi_gpt_data_size); + uefi_gpt_data_size = 0; + uefi_gpt_data = NULL; +} + +/* + * tpm_measure_gpt finally measures the GPT table and adds an entry + * to the log. + */ +uint32_t tpm_measure_gpt(void) +{ + size_t sz; + + if (!tpm_is_working()) + return TCGBIOS_GENERAL_ERROR; + + sz = offset_of(UEFI_GPT_DATA, Partitions) + + uefi_gpt_data->NumberOfPartitions * sizeof(UEFI_PARTITION_ENTRY); + + return tpm_add_measurement_to_log(5, EV_EFI_GPT_EVENT, + (const char *)uefi_gpt_data, sz, + (const uint8_t *)uefi_gpt_data, sz); +} + uint32_t tpm_measure_scrtm(void) { uint32_t rc; diff --git a/lib/libtpm/tcgbios.h b/lib/libtpm/tcgbios.h index c4a2e71..8174d86 100644 --- a/lib/libtpm/tcgbios.h +++ b/lib/libtpm/tcgbios.h @@ -29,5 +29,8 @@ uint32_t tpm_driver_get_failure_reason(void); void tpm_driver_set_failure_reason(uint32_t errcode); bool tpm_is_working(void); void tpm20_menu(void); +void tpm_gpt_set_lba1(const uint8_t *addr, uint32_t length); +void tpm_gpt_add_entry(const uint8_t *addr, uint32_t length); +uint32_t tpm_measure_gpt(void); #endif /* TCGBIOS_H */ diff --git a/lib/libtpm/tcgbios_int.h b/lib/libtpm/tcgbios_int.h index 6892e6f..1a88402 100644 --- a/lib/libtpm/tcgbios_int.h +++ b/lib/libtpm/tcgbios_int.h @@ -39,6 +39,8 @@ #define EV_S_CRTM_VERSION 8 #define EV_IPL 13 #define EV_IPL_PARTITION_DATA 14 +#define EV_EFI_EVENT_BASE 0x80000000 +#define EV_EFI_GPT_EVENT (EV_EFI_EVENT_BASE + 0x6) #define BCV_DEVICE_HDD 0x80 @@ -91,6 +93,44 @@ struct TCG_EfiSpecIdEventStruct { */ } __attribute__((packed)); +/* EFI related data structures for logging */ +typedef struct { + uint64_t signature; + uint32_t revision; + uint32_t size; + uint32_t crc32; + uint8_t reserved[4]; +} __attribute__((packed)) UEFI_TABLE_HEADER; + +typedef struct { + UEFI_TABLE_HEADER header; + uint64_t currentLba; + uint64_t backupLba; + uint64_t firstLba; + uint64_t lastLba; + uint8_t diskGuid[16]; + uint64_t partEntryLba; + uint32_t numPartEntry; + uint32_t partEntrySize; + uint32_t partArrayCrc32; + uint8_t reserved[420]; +} __attribute__((packed)) UEFI_PARTITION_TABLE_HEADER; + +typedef struct { + uint8_t partTypeGuid[16]; + uint8_t partGuid[16]; + uint64_t firstLba; + uint64_t lastLba; + uint64_t attribute; + uint8_t partName[72]; +} __attribute__((packed)) UEFI_PARTITION_ENTRY; + +typedef struct { + UEFI_PARTITION_TABLE_HEADER EfiPartitionHeader; + uint64_t NumberOfPartitions; + UEFI_PARTITION_ENTRY Partitions[0]; +} __attribute__((packed)) UEFI_GPT_DATA; + /* Input and Output headers for all TPM commands */ struct tpm_req_header { uint16_t tag; diff --git a/lib/libtpm/tpm.code b/lib/libtpm/tpm.code index b8f5669..205c608 100644 --- a/lib/libtpm/tpm.code +++ b/lib/libtpm/tpm.code @@ -137,3 +137,35 @@ MIRP PRIM(tpm20_X2d_menu) tpm20_menu(); MIRP + +/*************************************************************************/ +/* Set the LBA1 of the GPT */ +/* SLOF: tpm-gpt-set-lba1 ( addr length -- ) */ +/* LIBTPM: tpm_gpt_set_lba1(addr, length) */ +/*************************************************************************/ +PRIM(tpm_X2d_gpt_X2d_set_X2d_lba1) + int length = TOS.u; POP; + void *addr = TOS.a; POP; + tpm_gpt_set_lba1(addr, length); +MIRP + +/*************************************************************************/ +/* Add a GPT table entry */ +/* SLOF: tpm-gpt-add-entry ( addr length -- ) */ +/* LIBTPM: tpm_gpt_add_entry(addr, length) */ +/*************************************************************************/ +PRIM(tpm_X2d_gpt_X2d_add_X2d_entry) + int length = TOS.u; POP; + void *addr = TOS.a; POP; + tpm_gpt_add_entry(addr, length); +MIRP + +/*************************************************************************/ +/* Measure and log GPT EVENT */ +/* SLOF: tpm-measure-gpt ( -- errcode ) */ +/* LIBTPM: errcode = tpm_measure_gpt() */ +/*************************************************************************/ +PRIM(tpm_X2d_measure_X2d_gpt) + PUSH; + TOS.n = tpm_measure_gpt(); +MIRP diff --git a/lib/libtpm/tpm.in b/lib/libtpm/tpm.in index 590fee1..bdbc47d 100644 --- a/lib/libtpm/tpm.in +++ b/lib/libtpm/tpm.in @@ -25,3 +25,6 @@ cod(tpm-measure-scrtm) cod(tpm-driver-get-failure-reason) cod(tpm-driver-set-failure-reason) cod(tpm20-menu) +cod(tpm-gpt-set-lba1) +cod(tpm-gpt-add-entry) +cod(tpm-measure-gpt) diff --git a/slof/fs/packages/disk-label.fs b/slof/fs/packages/disk-label.fs index 252a44e..1ea3dfa 100644 --- a/slof/fs/packages/disk-label.fs +++ b/slof/fs/packages/disk-label.fs @@ -433,6 +433,27 @@ B9E5 CONSTANT GPT-BASIC-DATA-PARTITION-2 block gpt>signature x@ GPT-SIGNATURE = ; +\ Measure the GPT partition table by collecting its LBA1 +\ and GPT Entries and then measuring them. +\ This function modifies 'block' and 'seek-pos' + +: measure-gpt-partition ( -- ) + s" /ibm,vtpm" find-node ?dup IF + get-gpt-partition 0= if drop EXIT THEN + + block block-size tpm-gpt-set-lba1 + + block gpt>num-part-entry l@-le + 1+ 1 ?DO + seek-pos 0 seek drop + block gpt-part-size read drop + block gpt-part-size tpm-gpt-add-entry + seek-pos gpt-part-size + to seek-pos + LOOP + s" measure-gpt" rot $call-static + THEN +; + : load-from-gpt-prep-partition ( addr -- size ) get-gpt-partition 0= IF false EXIT THEN block gpt>num-part-entry l@-le dup 0= IF false exit THEN @@ -455,6 +476,7 @@ B9E5 CONSTANT GPT-BASIC-DATA-PARTITION-2 ; : try-gpt-dos-partition ( -- true|false ) + measure-gpt-partition get-gpt-partition 0= IF false EXIT THEN block gpt>num-part-entry l@-le dup 0= IF false EXIT THEN 1+ 1 ?DO