From patchwork Sat Jan 11 01:21:49 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Berger X-Patchwork-Id: 1221514 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 47vhsZ0rnXz9sP6 for ; Sat, 11 Jan 2020 12:22:10 +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 47vhsZ0FH4zDqkL for ; Sat, 11 Jan 2020 12:22:10 +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 47vhsR4zTtzDqfB for ; Sat, 11 Jan 2020 12:22:02 +1100 (AEDT) Received: from pps.filterd (m0098393.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.42/8.16.0.42) with SMTP id 00B1Hw1M033510; Fri, 10 Jan 2020 20:21:59 -0500 Received: from ppma04dal.us.ibm.com (7a.29.35a9.ip4.static.sl-reverse.com [169.53.41.122]) by mx0a-001b2d01.pphosted.com with ESMTP id 2xeeyx50r2-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Fri, 10 Jan 2020 20:21:59 -0500 Received: from pps.filterd (ppma04dal.us.ibm.com [127.0.0.1]) by ppma04dal.us.ibm.com (8.16.0.27/8.16.0.27) with SMTP id 00B1LTgK006856; Sat, 11 Jan 2020 01:21:58 GMT Received: from b03cxnp07029.gho.boulder.ibm.com (b03cxnp07029.gho.boulder.ibm.com [9.17.130.16]) by ppma04dal.us.ibm.com with ESMTP id 2xajb7t4gf-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Sat, 11 Jan 2020 01:21:58 +0000 Received: from b03ledav001.gho.boulder.ibm.com (b03ledav001.gho.boulder.ibm.com [9.17.130.232]) by b03cxnp07029.gho.boulder.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 00B1LwUJ53805518 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Sat, 11 Jan 2020 01:21:58 GMT Received: from b03ledav001.gho.boulder.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id F34EE6E053; Sat, 11 Jan 2020 01:21:57 +0000 (GMT) Received: from b03ledav001.gho.boulder.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 86BDC6E052; Sat, 11 Jan 2020 01:21:57 +0000 (GMT) Received: from sbct-3.pok.ibm.com (unknown [9.47.158.153]) by b03ledav001.gho.boulder.ibm.com (Postfix) with ESMTP; Sat, 11 Jan 2020 01:21:57 +0000 (GMT) From: Stefan Berger To: slof@lists.ozlabs.org, aik@ozlabs.ru Date: Fri, 10 Jan 2020 20:21:49 -0500 Message-Id: <20200111012155.3350198-2-stefanb@linux.ibm.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200111012155.3350198-1-stefanb@linux.ibm.com> References: <20200111012155.3350198-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.572 definitions=2020-01-10_04:2020-01-10, 2020-01-10 signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 lowpriorityscore=0 suspectscore=8 malwarescore=0 bulkscore=0 priorityscore=1501 impostorscore=0 spamscore=0 mlxscore=0 clxscore=1015 adultscore=0 mlxlogscore=999 phishscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-1910280000 definitions=main-2001110008 Subject: [SLOF] [PATCH v5 1/7] 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 Sat Jan 11 01:21:50 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Berger X-Patchwork-Id: 1221517 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 47vhsr6xKsz9sPn for ; Sat, 11 Jan 2020 12:22:24 +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 47vhsr5RPbzDql6 for ; Sat, 11 Jan 2020 12:22:24 +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 47vhsT6pfRzDqf6 for ; Sat, 11 Jan 2020 12:22:05 +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 00B1HqGO172327; Fri, 10 Jan 2020 20:22:03 -0500 Received: from ppma05wdc.us.ibm.com (1b.90.2fa9.ip4.static.sl-reverse.com [169.47.144.27]) by mx0a-001b2d01.pphosted.com with ESMTP id 2xee3fbvqn-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Fri, 10 Jan 2020 20:22:03 -0500 Received: from pps.filterd (ppma05wdc.us.ibm.com [127.0.0.1]) by ppma05wdc.us.ibm.com (8.16.0.27/8.16.0.27) with SMTP id 00B1M2oj006168; Sat, 11 Jan 2020 01:22:02 GMT Received: from b03cxnp07029.gho.boulder.ibm.com (b03cxnp07029.gho.boulder.ibm.com [9.17.130.16]) by ppma05wdc.us.ibm.com with ESMTP id 2xajb73ct8-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Sat, 11 Jan 2020 01:22:02 +0000 Received: from b03ledav001.gho.boulder.ibm.com (b03ledav001.gho.boulder.ibm.com [9.17.130.232]) by b03cxnp07029.gho.boulder.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 00B1LwFD53870908 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Sat, 11 Jan 2020 01:21:58 GMT Received: from b03ledav001.gho.boulder.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 99AF46E04E; Sat, 11 Jan 2020 01:21:58 +0000 (GMT) Received: from b03ledav001.gho.boulder.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 2E2A86E04C; Sat, 11 Jan 2020 01:21:58 +0000 (GMT) Received: from sbct-3.pok.ibm.com (unknown [9.47.158.153]) by b03ledav001.gho.boulder.ibm.com (Postfix) with ESMTP; Sat, 11 Jan 2020 01:21:58 +0000 (GMT) From: Stefan Berger To: slof@lists.ozlabs.org, aik@ozlabs.ru Date: Fri, 10 Jan 2020 20:21:50 -0500 Message-Id: <20200111012155.3350198-3-stefanb@linux.ibm.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200111012155.3350198-1-stefanb@linux.ibm.com> References: <20200111012155.3350198-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.572 definitions=2020-01-10_04:2020-01-10, 2020-01-10 signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 bulkscore=0 adultscore=5 impostorscore=0 lowpriorityscore=0 suspectscore=9 clxscore=1015 phishscore=0 spamscore=0 malwarescore=0 mlxscore=0 mlxlogscore=870 priorityscore=1501 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-1910280000 definitions=main-2001110008 Subject: [SLOF] [PATCH v5 2/7] 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 and data addresses available to the code so we can measure the static core root of trust contents. Signed-off-by: Stefan Berger --- slof/OF.h | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 slof/OF.h diff --git a/slof/OF.h b/slof/OF.h new file mode 100644 index 0000000..83eb121 --- /dev/null +++ b/slof/OF.h @@ -0,0 +1,22 @@ +/****************************************************************************** + * 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_data; +extern long _slof_data_end; +extern long _slof_text; +extern long _slof_text_end; + +#endif From patchwork Sat Jan 11 01:21:51 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Berger X-Patchwork-Id: 1221515 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 47vhsf6Qxrz9sP6 for ; Sat, 11 Jan 2020 12:22:14 +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 47vhsf4G8lzDqfD for ; Sat, 11 Jan 2020 12:22:14 +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 47vhsR6xgfzDqfD for ; Sat, 11 Jan 2020 12:22:03 +1100 (AEDT) Received: from pps.filterd (m0098393.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.42/8.16.0.42) with SMTP id 00B1Hw4E033572; Fri, 10 Jan 2020 20:22:01 -0500 Received: from ppma02wdc.us.ibm.com (aa.5b.37a9.ip4.static.sl-reverse.com [169.55.91.170]) by mx0a-001b2d01.pphosted.com with ESMTP id 2xeeyx50rh-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Fri, 10 Jan 2020 20:22:01 -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 00B1LTi2005332; Sat, 11 Jan 2020 01:22:00 GMT Received: from b03cxnp08025.gho.boulder.ibm.com (b03cxnp08025.gho.boulder.ibm.com [9.17.130.17]) by ppma02wdc.us.ibm.com with ESMTP id 2xajb7u90a-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Sat, 11 Jan 2020 01:22:00 +0000 Received: from b03ledav001.gho.boulder.ibm.com (b03ledav001.gho.boulder.ibm.com [9.17.130.232]) by b03cxnp08025.gho.boulder.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 00B1LxT653018944 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Sat, 11 Jan 2020 01:21:59 GMT Received: from b03ledav001.gho.boulder.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 387556E050; Sat, 11 Jan 2020 01:21:59 +0000 (GMT) Received: from b03ledav001.gho.boulder.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id C11806E04C; Sat, 11 Jan 2020 01:21:58 +0000 (GMT) Received: from sbct-3.pok.ibm.com (unknown [9.47.158.153]) by b03ledav001.gho.boulder.ibm.com (Postfix) with ESMTP; Sat, 11 Jan 2020 01:21:58 +0000 (GMT) From: Stefan Berger To: slof@lists.ozlabs.org, aik@ozlabs.ru Date: Fri, 10 Jan 2020 20:21:51 -0500 Message-Id: <20200111012155.3350198-4-stefanb@linux.ibm.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200111012155.3350198-1-stefanb@linux.ibm.com> References: <20200111012155.3350198-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.572 definitions=2020-01-10_04:2020-01-10, 2020-01-10 signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 lowpriorityscore=0 suspectscore=0 malwarescore=0 bulkscore=0 priorityscore=1501 impostorscore=0 spamscore=0 mlxscore=0 clxscore=1015 adultscore=0 mlxlogscore=793 phishscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-1910280000 definitions=main-2001110008 Subject: [SLOF] [PATCH v5 3/7] 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 Sat Jan 11 01:21:52 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Berger X-Patchwork-Id: 1221522 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 47vht80b8Tz9sPn for ; Sat, 11 Jan 2020 12:22:40 +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 47vht74LjQzDqld for ; Sat, 11 Jan 2020 12:22:39 +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=mx0b-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 mx0b-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 47vhsX6dNyzDqf6 for ; Sat, 11 Jan 2020 12:22:08 +1100 (AEDT) Received: from pps.filterd (m0127361.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.42/8.16.0.42) with SMTP id 00B1HpuB176878; Fri, 10 Jan 2020 20:22:05 -0500 Received: from ppma01dal.us.ibm.com (83.d6.3fa9.ip4.static.sl-reverse.com [169.63.214.131]) by mx0a-001b2d01.pphosted.com with ESMTP id 2xea2m330a-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Fri, 10 Jan 2020 20:22:05 -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 00B1Li4E030871; Sat, 11 Jan 2020 01:22:01 GMT Received: from b03cxnp08026.gho.boulder.ibm.com (b03cxnp08026.gho.boulder.ibm.com [9.17.130.18]) by ppma01dal.us.ibm.com with ESMTP id 2xajb7t4v5-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Sat, 11 Jan 2020 01:22:00 +0000 Received: from b03ledav001.gho.boulder.ibm.com (b03ledav001.gho.boulder.ibm.com [9.17.130.232]) by b03cxnp08026.gho.boulder.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 00B1M0EL31457572 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Sat, 11 Jan 2020 01:22:00 GMT Received: from b03ledav001.gho.boulder.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 019EC6E04C; Sat, 11 Jan 2020 01:22:00 +0000 (GMT) Received: from b03ledav001.gho.boulder.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 6078F6E050; Sat, 11 Jan 2020 01:21:59 +0000 (GMT) Received: from sbct-3.pok.ibm.com (unknown [9.47.158.153]) by b03ledav001.gho.boulder.ibm.com (Postfix) with ESMTP; Sat, 11 Jan 2020 01:21:59 +0000 (GMT) From: Stefan Berger To: slof@lists.ozlabs.org, aik@ozlabs.ru Date: Fri, 10 Jan 2020 20:21:52 -0500 Message-Id: <20200111012155.3350198-5-stefanb@linux.ibm.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200111012155.3350198-1-stefanb@linux.ibm.com> References: <20200111012155.3350198-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.572 definitions=2020-01-10_04:2020-01-10, 2020-01-10 signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 adultscore=0 mlxscore=0 malwarescore=0 suspectscore=0 spamscore=0 clxscore=1015 priorityscore=1501 mlxlogscore=999 impostorscore=0 lowpriorityscore=0 phishscore=0 bulkscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-1910280000 definitions=main-2001110008 Subject: [SLOF] [PATCH v5 4/7] 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 | 95 ++++++++ lib/libtpm/tcgbios_int.h | 30 +++ lib/libtpm/tpm_drivers.c | 466 +++++++++++++++++++++++++++++++++++++++ lib/libtpm/tpm_drivers.h | 82 +++++++ slof/helpers.c | 6 + 9 files changed, 732 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..ff19e1c --- /dev/null +++ b/lib/libtpm/Makefile @@ -0,0 +1,50 @@ +# ***************************************************************************** +# * Copyright (c) 2015 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..50f5e95 --- /dev/null +++ b/lib/libtpm/Readme @@ -0,0 +1,95 @@ +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: +------------------------ + +To enable a vTPM with QEMU, the following steps need to be followed + +- build a recent version of libtpms + + #> git clone https://github.com/stefanberger/libtpms + #> cd libtpms + #> ./autogen.sh --prefix=/usr --with-tpm2 --with-openssl + + The following step may require to install dependencies + + #> make + #> make check + #> make install + +- build swtpm + + #> git clone https://github.com/stefanberger/swtpm + #> cd swtpm + #> ./autogen.sh --prefix=/usr --with-openssl + + The following step may require to install dependencies + + #> ./configure --prefix=/usr --with-openssl + #> make + #> make check + #> make install + +- build QEMU with vTPM support: + + #> git clone https://github.com/stefanberger/qemu-tpm + #> cd qemu-tpm + + The PPC64 patches are currently in the tpm-next+spapr.v8 branch + #> git checkout origin/tpm-next+spapr.v8 -b tpm-next+spapr.v8 + + The following step may require to install dependencies + + #> ./configure --prefix=/usr --enable-kvm --target-list="ppc64-softmmu" + #> make + #> make install + +To start a QEMU VM with an attached vTPM (swtpm), run the following commands +as 'root'. The following will setup the vTPM so that its state will be stored +in /tmp/mytpm1. A unique directory for each VM instance with attached vTPM +should be provided. Whenever QEMU is started, the swtpm has to be started +before it. The './boot_rom.bin' represents SLOF with vTPM extensions built-in. + + #> mkdir -p /tmp/mytpm1 + #> swtpm socket --tpm2 --tpmstate dir=/tmp \ + --ctrl type=unixio,path=/tmp/mytpm1/ctrl.sock + + In another terminal: + + #> qemu-system-ppc64 \ + -enable-kvm \ + -boot menu=on \ + --chardev socket,id=chrtpm,path=/tmp/mytpm1/ctrl.sock \ + -tpmdev emulator,id=tpm0,chardev=chrtpm \ + -device tpm-spapr,tpmdev=tpm0 \ + -vnc 0.0.0.0:2 \ + [...] + + Add hard disk and other parameters as needed. + +Notes: + - The Linux kernel in the VM must have the tpm_ibmvtpm module available + or built-in. + + - 'swtpm_ioctl --unix /tmp/ctrl.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..c1335d7 --- /dev/null +++ b/lib/libtpm/tpm_drivers.c @@ -0,0 +1,466 @@ +/***************************************************************************** + * 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 */ +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 spapr_vtpm_driver_state { + /* 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; + + /* version of the TPM we talk to -- from CRQ message */ + uint32_t tpm_version; +} 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* 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 *get_response_crq(void) +{ + struct crq *crq; + + dprintf("curr_q_entry = %d\n", spapr_vtpm.curr_q_entry); + + crq = 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 = 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 version */ + crq.valid = PAPR_VTPM_VALID_COMMAND; + crq.msg = PAPR_VTPM_GET_VERSION; + + if (!spapr_send_crq_and_wait(spapr_vtpm.unit, &crq, &response, 10, + VTPM_DRV_STATE_SEND_GET_VERSION, + VTPM_DRV_STATE_WAIT_VERSION)) { + printf("%s: Failure getting TPM version from CRQ\n", __func__); + return false; + } + + vtpm_drv_state_set(VTPM_DRV_STATE_CHECK_VERSION, + VTPM_DRV_ERROR_NO_FAILURE); + + spapr_vtpm.tpm_version = be32_to_cpu(response->data); + dprintf("TPM backend version: %d\n", spapr_vtpm.tpm_version); + + /* 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); +} + +/* + * 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 = get_response_crq(); + spapr_vtpm.response->data = (uint64_t)spapr_vtpm.buffer; + /* response CRQ has been set and valid field cleared */ + + 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; + } + + /* response CRQ has been set */ + + 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; + } + + /* response CRQ has been set */ + 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; +} + +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; +} + +/**** higher layer interface ****/ + +bool spapr_is_vtpm_present(void) +{ + bool rc = false; + + if (spapr_vtpm_probe()) { + rc = true; + } + + return rc; +} + +int tpmhw_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..1de1532 --- /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 tpmhw_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 Sat Jan 11 01:21:53 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Berger X-Patchwork-Id: 1221519 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 47vht05J3Mz9sPn for ; Sat, 11 Jan 2020 12:22:32 +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 47vht03MtTzDqfJ for ; Sat, 11 Jan 2020 12:22:32 +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 47vhsV4YMqzDqf6 for ; Sat, 11 Jan 2020 12:22:06 +1100 (AEDT) Received: from pps.filterd (m0098421.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.42/8.16.0.42) with SMTP id 00B1Hxr4058232; Fri, 10 Jan 2020 20:22:02 -0500 Received: from ppma03dal.us.ibm.com (b.bd.3ea9.ip4.static.sl-reverse.com [169.62.189.11]) by mx0a-001b2d01.pphosted.com with ESMTP id 2xerexnqu5-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Fri, 10 Jan 2020 20:22:02 -0500 Received: from pps.filterd (ppma03dal.us.ibm.com [127.0.0.1]) by ppma03dal.us.ibm.com (8.16.0.27/8.16.0.27) with SMTP id 00B1LTPu012648; Sat, 11 Jan 2020 01:22:01 GMT Received: from b03cxnp08026.gho.boulder.ibm.com (b03cxnp08026.gho.boulder.ibm.com [9.17.130.18]) by ppma03dal.us.ibm.com with ESMTP id 2xajb8j5gh-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Sat, 11 Jan 2020 01:22:01 +0000 Received: from b03ledav001.gho.boulder.ibm.com (b03ledav001.gho.boulder.ibm.com [9.17.130.232]) by b03cxnp08026.gho.boulder.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 00B1M0b131457578 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Sat, 11 Jan 2020 01:22:00 GMT Received: from b03ledav001.gho.boulder.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id B5B536E052; Sat, 11 Jan 2020 01:22:00 +0000 (GMT) Received: from b03ledav001.gho.boulder.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 4775C6E04C; Sat, 11 Jan 2020 01:22:00 +0000 (GMT) Received: from sbct-3.pok.ibm.com (unknown [9.47.158.153]) by b03ledav001.gho.boulder.ibm.com (Postfix) with ESMTP; Sat, 11 Jan 2020 01:22:00 +0000 (GMT) From: Stefan Berger To: slof@lists.ozlabs.org, aik@ozlabs.ru Date: Fri, 10 Jan 2020 20:21:53 -0500 Message-Id: <20200111012155.3350198-6-stefanb@linux.ibm.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200111012155.3350198-1-stefanb@linux.ibm.com> References: <20200111012155.3350198-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.572 definitions=2020-01-10_04:2020-01-10, 2020-01-10 signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 impostorscore=0 lowpriorityscore=0 malwarescore=0 suspectscore=0 clxscore=1015 bulkscore=0 mlxscore=0 adultscore=0 priorityscore=1501 phishscore=0 mlxlogscore=999 spamscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-1910280000 definitions=main-2001110008 Subject: [SLOF] [PATCH v5 5/7] tpm: Add sha1 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 SHA1 implementation based on the algorithm description in NIST FIPS PUB 180-4. Signed-off-by: Stefan Berger --- lib/libtpm/Makefile | 2 +- lib/libtpm/sha1.c | 204 ++++++++++++++++++++++++++++++++++++++++++++ lib/libtpm/sha1.h | 20 +++++ 3 files changed, 225 insertions(+), 1 deletion(-) create mode 100644 lib/libtpm/sha1.c create mode 100644 lib/libtpm/sha1.h diff --git a/lib/libtpm/Makefile b/lib/libtpm/Makefile index ff19e1c..52d22f2 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 sha1.c OBJS = $(SRCS:%.c=%.o) diff --git a/lib/libtpm/sha1.c b/lib/libtpm/sha1.c new file mode 100644 index 0000000..931e651 --- /dev/null +++ b/lib/libtpm/sha1.c @@ -0,0 +1,204 @@ +/***************************************************************************** + * 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-1 in FIPS PUB 180-4 + */ + +#include "byteorder.h" +#include "sha1.h" +#include "string.h" + +typedef struct _sha1_ctx { + uint32_t h[5]; +} sha1_ctx; + +static inline uint32_t rol(uint32_t data, uint8_t n) +{ + register uint32_t res; + + /* rotlw a,b,c : a = rol(b, c) */ + __asm__ __volatile__ ( + "rotlw %0,%1,%2" + : "=&r" (res) + : "r" (data), "r" (n) + : "cc" + ); + return res; +} + +static void sha1_block(uint32_t *w, sha1_ctx *ctx) +{ + uint32_t i; + uint32_t a,b,c,d,e,f; + uint32_t tmp; + uint32_t idx; + + /* + * FIPS 180-4 4.2.1: SHA1 Constants + */ + static const uint32_t sha_ko[4] = { + 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6 + }; + + /* + * FIPS 180-4 6.1.2: step 1 + * + * 0 <= i <= 15: + * W(t) = M(t) + * 16 <= i <= 79: + * W(t) = ROTL(W(t-3) XOR W(t-8) XOR W(t-14) XOR W(t-16), 1) + */ + + /* w(0)..(w15) already in big endian format */ + + for (i = 16; i <= 79; i++) { + tmp = w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16]; + w[i] = rol(tmp, 1); + } + + /* + * step 2: a = H0, b = H1, c = H2, d = H3, e = H4. + */ + a = ctx->h[0]; + b = ctx->h[1]; + c = ctx->h[2]; + d = ctx->h[3]; + e = ctx->h[4]; + + /* + * step 3: For i = 0 to 79: + * T = ROTL(a, 5) + f(i; b,c,d) + e + W(t) + K(t); + */ + for (i = 0; i <= 79; i++) { + /* + * FIPS 180-4: 4.1.1 : definition of f(i; b,c,d) + */ + if (i <= 19) { + /* + * 0 <= i <= 19: + * f(i; b,c,d) = (b AND c) OR ((NOT b) AND d) + */ + f = (b & c) | ((b ^ 0xffffffff) & d); + idx = 0; + } else if (i <= 39) { + /* + * 20 <= i <= 39: + * f(i; b,c,d) = b XOR c XOR d + */ + f = b ^ c ^ d; + idx = 1; + } else if (i <= 59) { + /* + * 40 <= i <= 59: + * f(i; b,c,d) = (b AND c) OR (b AND d) OR (c AND d) + */ + f = (b & c) | (b & d) | (c & d); + idx = 2; + } else { + /* + * 60 <= i <= 79: + * f(i; b,c,d) = b XOR c XOR d + */ + f = b ^ c ^ d; + idx = 3; + } + + /* + * step 3: + * t = ROTL(a, 5) + f(t;b,c,d) + e + K(t) + W(t); + * e = d; d = c; c = ROTL(b, 30); b = a; a = t; + */ + tmp = rol(a, 5) + + f + + e + + sha_ko[idx] + + w[i]; + e = d; + d = c; + c = rol(b, 30); + b = a; + a = tmp; + } + + /* + * 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; +} + +static void sha1_do(sha1_ctx *ctx, const uint8_t*data32, uint32_t length) +{ + uint32_t offset; + uint16_t num; + uint32_t bits = 0; + uint32_t w[80]; + uint64_t tmp; + + /* treat data in 64-byte chunks */ + for (offset = 0; length - offset >= 64; offset += 64) { + memcpy(w, data32 + offset, 64); + sha1_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 */ + sha1_block((uint32_t *)w, ctx); + memset(w, 0, 60); + } + + /* write number of bits to end of block */ + tmp = bits; + memcpy(&w[14], &tmp, 8); + + sha1_block(w, ctx); +} + +uint32_t sha1(const uint8_t *data, uint32_t length, uint8_t *hash) +{ + sha1_ctx ctx = { + .h = { + /* + * FIPS 180-4: 6.1.1 + * -> 5.3.1: initial hash value + */ + 0x67452301, + 0xefcdab89, + 0x98badcfe, + 0x10325476, + 0xc3d2e1f0, + } + }; + + sha1_do(&ctx, data, length); + memcpy(hash, &ctx.h[0], 20); + + return 0; +} diff --git a/lib/libtpm/sha1.h b/lib/libtpm/sha1.h new file mode 100644 index 0000000..7fa3e03 --- /dev/null +++ b/lib/libtpm/sha1.h @@ -0,0 +1,20 @@ +/***************************************************************************** + * Copyright (c) 2015 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 __SHA1_H +#define __SHA1_H + +#include "types.h" + +uint32_t sha1(const uint8_t *data, uint32_t length, uint8_t *hash); + +#endif /* __SHA1_H */ From patchwork Sat Jan 11 01:21:54 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Berger X-Patchwork-Id: 1221520 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 47vht3632Dz9sP6 for ; Sat, 11 Jan 2020 12:22: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 47vht35GByzDqkZ for ; Sat, 11 Jan 2020 12:22: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 47vhsW0874zDqfB for ; Sat, 11 Jan 2020 12:22:06 +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 00B1Hxaw045500; Fri, 10 Jan 2020 20:22:03 -0500 Received: from ppma01wdc.us.ibm.com (fd.55.37a9.ip4.static.sl-reverse.com [169.55.85.253]) by mx0b-001b2d01.pphosted.com with ESMTP id 2xee145vrh-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Fri, 10 Jan 2020 20:22:03 -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 00B1LZKq009930; Sat, 11 Jan 2020 01:22:09 GMT Received: from b03cxnp08027.gho.boulder.ibm.com (b03cxnp08027.gho.boulder.ibm.com [9.17.130.19]) by ppma01wdc.us.ibm.com with ESMTP id 2xajb7ba3f-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Sat, 11 Jan 2020 01:22:08 +0000 Received: from b03ledav001.gho.boulder.ibm.com (b03ledav001.gho.boulder.ibm.com [9.17.130.232]) by b03cxnp08027.gho.boulder.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 00B1M1lW60883278 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Sat, 11 Jan 2020 01:22:01 GMT Received: from b03ledav001.gho.boulder.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 85DD46E04E; Sat, 11 Jan 2020 01:22:01 +0000 (GMT) Received: from b03ledav001.gho.boulder.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id DE8656E053; Sat, 11 Jan 2020 01:22:00 +0000 (GMT) Received: from sbct-3.pok.ibm.com (unknown [9.47.158.153]) by b03ledav001.gho.boulder.ibm.com (Postfix) with ESMTP; Sat, 11 Jan 2020 01:22:00 +0000 (GMT) From: Stefan Berger To: slof@lists.ozlabs.org, aik@ozlabs.ru Date: Fri, 10 Jan 2020 20:21:54 -0500 Message-Id: <20200111012155.3350198-7-stefanb@linux.ibm.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200111012155.3350198-1-stefanb@linux.ibm.com> References: <20200111012155.3350198-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.572 definitions=2020-01-10_04:2020-01-10, 2020-01-10 signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 clxscore=1015 suspectscore=9 malwarescore=0 mlxlogscore=999 impostorscore=0 adultscore=0 phishscore=0 lowpriorityscore=0 mlxscore=0 spamscore=0 bulkscore=0 priorityscore=1501 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-1910280000 definitions=main-2001110008 Subject: [SLOF] [PATCH v5 6/7] 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. Signed-off-by: Stefan Berger --- board-qemu/slof/Makefile | 13 +- board-qemu/slof/tree.fs | 3 + board-qemu/slof/vio-vtpm-cdriver.fs | 137 +++++ board-qemu/slof/vtpm-sml.fs | 123 ++++ include/helpers.h | 1 + lib/libtpm/Makefile | 2 +- lib/libtpm/tcgbios.c | 916 ++++++++++++++++++++++++++++ lib/libtpm/tcgbios.h | 32 + lib/libtpm/tcgbios_int.h | 240 ++++++++ lib/libtpm/tpm.code | 130 ++++ lib/libtpm/tpm.in | 26 + slof/fs/packages/disk-label.fs | 10 +- slof/fs/start-up.fs | 7 + 13 files changed, 1635 insertions(+), 5 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..24b5290 --- /dev/null +++ b/board-qemu/slof/vio-vtpm-cdriver.fs @@ -0,0 +1,137 @@ +\ ***************************************************************************** +\ * 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 + +false VALUE vtpm-debug? +0 VALUE vtpm-unit +0 VALUE vtpm-ihandle + +: setup-alias + " ibm,vtpm" find-alias 0= IF + " ibm,vtpm" get-node node>path set-alias + ELSE + drop + THEN +; + +: vtpm-cleanup ( ) + vtpm-debug? IF ." VTPM: Disabling RTAS bypass" cr THEN + tpm-finalize + vtpm-unit 0 rtas-set-tce-bypass +; + +: vtpm-init ( -- true | false ) + 0 0 get-node open-node ?dup 0= IF 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 + + tpm-start dup 0= IF + vtpm-debug? IF ." VTPM: Success from tpm-start" cr THEN + drop + setup-alias + ELSE + ." VTPM: Error code from tpm-start: " . cr + THEN + + close-node + r> to my-self +; + +\ forward a call to /ibm,vtpm, which implements the function with the +\ given name +: vtpm-call-forward ( arg ... arg name namelen -- ret ... ret failure? ) + \ assign /ibm,vtpm node to vtpm-ihandle, if not assigned + vtpm-ihandle 0= IF + s" /ibm,vtpm" open-dev to vtpm-ihandle + THEN + + vtpm-ihandle 0<> IF + vtpm-ihandle ( arg ... arg name namelen ihandle ) + $call-method ( ret ... ret ) + false ( ret ... ret false ) + ELSE + true ( true ) + THEN +; + +\ firmware API call +: sml-get-allocated-size ( -- buffer-size) + " sml-get-allocated-size" vtpm-call-forward IF + \ vtpm-call-forward failed + 0 + THEN +; + +\ firmware API call +: sml-get-handover-size ( -- size) + " sml-get-handover-size" vtpm-call-forward IF + \ vtpm-call-forward failed + 0 + THEN +; + +\ firmware API call +: sml-handover ( dest size -- ) + " sml-handover" vtpm-call-forward IF + \ vtpm-call-forward failed; clean up stack + 2drop + THEN +; + +\ firmware API call +: get-failure-reason ( -- reason ) + " get-failure-reason" vtpm-call-forward IF + \ vtpm-call-forward failed; return a value + 0 \ invalid + THEN +; + +0 0 s" ibm,sml-efi-reformat-supported" property + +\ firmware API call +: reformat-sml-to-efi-alignment ( -- success ) + " reformat-sml-to-efi-alignment" vtpm-call-forward IF + false + THEN +; + +: open ( ) + vtpm-debug? IF ." VTPM: vTPM open()" cr THEN + true +; + +: close ( ) + vtpm-debug? IF ." VTPM: vTPM close()" cr THEN +; + +\ setup alias and the RTAS bypass +vtpm-init + +\ setup the log +include vtpm-sml.fs + +s" /ibm,vtpm" find-node dup IF + s" measure-scrtm" rot $call-static +ELSE + drop +THEN diff --git a/board-qemu/slof/vtpm-sml.fs b/board-qemu/slof/vtpm-sml.fs new file mode 100644 index 0000000..a140276 --- /dev/null +++ b/board-qemu/slof/vtpm-sml.fs @@ -0,0 +1,123 @@ +\ ***************************************************************************** +\ * 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 +\ ****************************************************************************/ + +\ KVM/qemu TPM Stored Measurement Log (SML) entries in /ibm,vtpm + +" /" find-device + +new-device + +false VALUE vtpm-debug? +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 + +\ create /ibm,vtpm +s" ibm,vtpm" 2dup device-name device-type + +\ convey logbase and size to the C driver +log-base LOG-SIZE tpm-set-log-parameters + +: sml-get-allocated-size ( -- buffer-size) + vtpm-debug? IF + ." Call to sml-get-allocated-size; size = 0x" LOG-SIZE . cr + THEN + LOG-SIZE +; + +: sml-get-handover-size ( -- size ) + tpm-get-logsize + vtpm-debug? IF + ." Call to sml-get-handover-size; size = 0x" dup . cr + THEN +; + +: sml-handover ( dest size -- ) + vtpm-debug? IF + 2dup + ." Call to sml-handover; size = 0x" . ." dest = " . cr + THEN + log-base ( dest size src ) + -rot ( src dest size ) + move + + VTPM_DRV_ERROR_SML_HANDED_OVER tpm-driver-set-failure-reason +; + +: get-failure-reason ( -- reason ) + tpm-driver-get-failure-reason ( reason ) + vtpm-debug? IF + ." VTPM: Return value from tpm-driver-get-failure-reason: " dup . cr + THEN +; + +: reformat-sml-to-efi-alignment ( -- success? ) + vtpm-debug? IF + ." Call to reformat-sml-to-efi-alignment" cr + THEN + \ a no-op since already byte aligned + true +; + +\ +\ internal API calls +\ + +: separator-event ( start-pcr end-pcr -- ) + tpm-add-event-separators ( errcode ) + dup 0<> IF + ." VTPM: Error code from tpm-add-event-separators: " . cr + ELSE + drop + THEN +; + +80 CONSTANT BCV_DEVICE_HDD + +: measure-hdd-mbr ( addr -- ) + 0 7 separator-event + 200 BCV_DEVICE_HDD ( addr length bootdrv ) + -rot ( bootdrv addr length ) + tpm-measure-bcv-mbr ( errcode ) + dup 0<> IF + ." VTPM: Error code from tpm-measure-hdd: " . cr + ELSE + drop + THEN +; + +: leave-firmware ( -- ) + tpm-leave-firmware ( errcode ) + dup 0<> IF + ." VTPM: Error code from tpm-leave-firmware: " . cr + ELSE + drop + THEN +; + +: measure-scrtm ( -- ) + tpm-measure-scrtm ( errcode ) + dup 0<> IF + ." VTPM: Error code from tpm-measure-scrtm: " . cr + ELSE + drop + THEN +; + +: open true ; +: close ; + +finish-device +device-end 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 52d22f2..2e3d644 100644 --- a/lib/libtpm/Makefile +++ b/lib/libtpm/Makefile @@ -23,7 +23,7 @@ TARGET = ../libtpm.a all: $(TARGET) -SRCS = tpm_drivers.c sha1.c +SRCS = tpm_drivers.c sha1.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..ba5cc46 --- /dev/null +++ b/lib/libtpm/tcgbios.c @@ -0,0 +1,916 @@ +/***************************************************************************** + * 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 + * Kevin O'Connor (SeaBIOS) + *****************************************************************************/ + +/* + * 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: + * http://www.trustedcomputinggroup.org/resources/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 "sha1.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)) + +struct tpm_state { + 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; +}; + +static struct tpm_state 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 + ****************************************************************/ + +static uint32_t tpm20_pcr_selection_size; +static struct tpml_pcr_selection *tpm20_pcr_selection; + +/* A 'struct tpm_log_entry' is a local data structure containing a + * 'tpm_log_header' followed by space for the maximum supported + * digest. (The digest is a sha1 hash on tpm1.2 or a series of + * tpm2_digest_value structs on tpm2.0) + */ +struct tpm_log_entry { + struct tpm_log_header hdr; + uint8_t pad[sizeof(struct tpm2_digest_values) + + 5 * sizeof(struct tpm2_digest_value) + + SHA1_BUFSIZE + SHA256_BUFSIZE + SHA384_BUFSIZE + + SHA512_BUFSIZE + SM3_256_BUFSIZE]; +} __attribute__((packed)); + +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, + .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 int +tpm20_get_hash_buffersize(uint16_t hashAlg) +{ + unsigned i; + + for (i = 0; i < ARRAY_SIZE(hash_parameters); i++) { + if (hash_parameters[i].hashalg == hashAlg) + return hash_parameters[i].hash_buffersize; + } + return -1; +} + +/* + * Build the TPM2 tpm2_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 sha1 hash in the area of the sha256 + * 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 *sha1, + bool bigEndian) +{ + struct tpms_pcr_selection *sel; + void *nsel, *end; + void *dest = le->hdr.digest + sizeof(struct tpm2_digest_values); + uint32_t count; + struct tpm2_digest_value *v; + struct tpm2_digest_values *vs; + + if (!tpm20_pcr_selection) + return -1; + + sel = tpm20_pcr_selection->selections; + end = (void *)tpm20_pcr_selection + tpm20_pcr_selection_size; + + for (count = 0; count < be32_to_cpu(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, sha1, hsize > SHA1_BUFSIZE ? SHA1_BUFSIZE : hsize); + + dest += sizeof(*v) + hsize; + sel = nsel; + } + + if (sel != end) { + dprintf("Malformed pcr selection structure fron TPM\n"); + return -1; + } + + vs = (void*)le->hdr.digest; + if (bigEndian) + vs->count = cpu_to_be32(count); + else + vs->count = cpu_to_le32(count); + + return dest - (void*)le->hdr.digest; +} + +/**************************************************************** + * 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 = tpmhw_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 = tpmhw_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; + + int 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 */ + uint32_t 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; + + tpm20_pcr_selection = SLOF_alloc_mem(size); + if (tpm20_pcr_selection) { + memcpy(tpm20_pcr_selection, &trg->data, size); + tpm20_pcr_selection_size = size; + } else { + printf("TCGBIOS: Failed to allocated %u bytes.\n", size); + ret = -1; + } + + return ret; +} + +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; + + memcpy(tre, &tmp_tre, sizeof(tmp_tre)); + memcpy(&tre->digest[0], le->hdr.digest, digest_len); + + tre->hdr.totlen = cpu_to_be32(sizeof(tmp_tre) + digest_len); + + struct tpm_rsp_header rsp; + uint32_t resp_length = sizeof(rsp); + int ret = tpmhw_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 = tpmhw_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); + + if (buf_len > sizeof(rsp.rnd.buffer)) + return -1; + + int ret = tpmhw_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)), + }, + }; + memcpy(trhca.newAuth.buffer, auth, sizeof(trhca.newAuth.buffer)); + + struct tpm_rsp_header rsp; + uint32_t resp_length = sizeof(rsp); + int ret = tpmhw_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) +{ + /* we will try to deactivate the TPM now - ignoring all errors */ + 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 = tpmhw_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(struct tpm_log_header *entry, + int digest_len, + const void *event, uint32_t event_length) +{ + size_t size, logsize; + void *dest; + + 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(struct tpm_log_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 = %u\n", size); + return TCGBIOS_LOGOVERFLOW; + } + + dest = tpm_state.log_area_next_entry; + memcpy(dest, entry, sizeof(*entry) + digest_len); + struct tpm_log_trailer *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) +{ + if (!tpm20_pcr_selection) + return -1; + + 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 = tpm20_pcr_selection->selections; + void *nsel, *end = (void*)tpm20_pcr_selection + tpm20_pcr_selection_size; + int event_size; + uint32_t *vendorInfoSize; + struct tpm_log_entry le = { + .hdr.eventtype = cpu_to_log32(EV_NO_ACTION), + }; + uint32_t count; + + for (count = 0; + count < be32_to_cpu(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 = 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 %u 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[SHA1_BUFSIZE]; + struct tpm_log_entry le = { + .hdr.pcrindex = cpu_to_log32(pcrindex), + .hdr.eventtype = cpu_to_log32(eventtype), + }; + int digest_len; + + sha1(hashdata, hashdatalen, hash); + digest_len = tpm20_build_digest(&le, hash, true); + if (digest_len < 0) + return TCGBIOS_GENERAL_ERROR; + int 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 rc = 0; + uint32_t pcrIndex; + + 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) + break; + } + + return rc; +} + +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 | sha1sum + */ + 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 | sha1sum + */ + 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_data_start = (char *)&_slof_data; + char *slof_text_start = (char *)&_slof_text; + uint32_t slof_data_length = (long)&_slof_data_end - (long)&_slof_data; + 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 (data): start = %p, length = %d\n", + slof_data_start, slof_data_length); + + rc = tpm_add_measurement_to_log(0, EV_S_CRTM_CONTENTS, + scrtm, strlen(scrtm), + (uint8_t *)slof_data_start, + slof_data_length); + + 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..a9fbbb8 --- /dev/null +++ b/lib/libtpm/tcgbios.h @@ -0,0 +1,32 @@ +/***************************************************************************** + * Copyright (c) 2015 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..3cc4f46 100644 --- a/lib/libtpm/tcgbios_int.h +++ b/lib/libtpm/tcgbios_int.h @@ -15,6 +15,94 @@ #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 */ +#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 SHA1_BUFSIZE 20 +#define SHA256_BUFSIZE 32 +#define SHA384_BUFSIZE 48 +#define SHA512_BUFSIZE 64 +#define SM3_256_BUFSIZE 32 + +#define BCV_DEVICE_HDD 0x80 + +struct tpm2_digest_value { + uint16_t hashAlg; + uint8_t hash[0]; /* size depends on hashAlg */ +} __attribute__((packed)); + +struct tpm2_digest_values { + uint32_t count; + struct tpm2_digest_value digest[0]; +} __attribute__((packed)); + +/* Each entry in the TPM log contains: a tpm_log_header, a variable + * length digest, a tpm_log_trailer, and a variable length event. The + * 'digest' matches what is sent to the TPM hardware via the Extend + * command. On TPM1.2 the digest is a SHA1 hash; on TPM2.0 the digest + * contains a tpm2_digest_values struct followed by a variable number + * of tpm2_digest_value structs (as specified by the hardware via the + * TPM2_CAP_PCRS request). + */ +struct tpm_log_header { + uint32_t pcrindex; + uint32_t eventtype; + uint8_t digest[0]; +} __attribute__((packed)); + +struct tpm_log_trailer { + uint32_t eventdatasize; + uint8_t event[0]; +} __attribute__((packed)); + +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 blocks for the TCG BIOS commands */ + +/* PCClient_PCREventStruct -- format of log entries; compatible with x86 */ +struct pcpes { + uint32_t pcrindex; + uint32_t eventtype; + uint8_t digest[SHA1_BUFSIZE]; + uint32_t eventdatasize; + uint32_t event; +} __attribute__((packed)); + struct tpm_req_header { uint16_t tag; uint32_t totlen; @@ -27,4 +115,156 @@ struct tpm_rsp_header { uint32_t errcode; } __attribute__((packed)); +/**************************************************************** + * TPM v2.0 hardware 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 + +#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 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 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)); + +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..b130743 100644 --- a/slof/fs/packages/disk-label.fs +++ b/slof/fs/packages/disk-label.fs @@ -550,7 +550,15 @@ B9E5 CONSTANT GPT-BASIC-DATA-PARTITION-2 \ load from a bootable partition : load-from-boot-partition ( addr -- size ) debug-disk-label? IF ." Trying DOS boot " .s cr THEN - dup load-from-dos-boot-partition ?dup 0 <> IF nip EXIT THEN + dup load-from-dos-boot-partition ?dup 0 <> IF + nip + block s" /ibm,vtpm" find-node dup IF + s" measure-hdd-mbr" rot $call-static + ELSE + 2drop + THEN + EXIT + THEN debug-disk-label? IF ." Trying CHRP boot " .s cr THEN 1 disk-chrp-boot ! diff --git a/slof/fs/start-up.fs b/slof/fs/start-up.fs index 7020f5c..8254eba 100644 --- a/slof/fs/start-up.fs +++ b/slof/fs/start-up.fs @@ -56,6 +56,13 @@ ; : (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 + ELSE + drop + THEN + of-prompt? not auto-boot? and IF (boot) THEN From patchwork Sat Jan 11 01:21:55 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Berger X-Patchwork-Id: 1221518 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 47vhsw5pt8z9sP6 for ; Sat, 11 Jan 2020 12:22: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 47vhsw4qVyzDqk7 for ; Sat, 11 Jan 2020 12:22: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 47vhsV23kczDqfB for ; Sat, 11 Jan 2020 12:22:06 +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 00B1HxuI007332; Fri, 10 Jan 2020 20:22:04 -0500 Received: from ppma04dal.us.ibm.com (7a.29.35a9.ip4.static.sl-reverse.com [169.53.41.122]) by mx0a-001b2d01.pphosted.com with ESMTP id 2xedsu68rs-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Fri, 10 Jan 2020 20:22:03 -0500 Received: from pps.filterd (ppma04dal.us.ibm.com [127.0.0.1]) by ppma04dal.us.ibm.com (8.16.0.27/8.16.0.27) with SMTP id 00B1LTgP006856; Sat, 11 Jan 2020 01:22:03 GMT Received: from b03cxnp08028.gho.boulder.ibm.com (b03cxnp08028.gho.boulder.ibm.com [9.17.130.20]) by ppma04dal.us.ibm.com with ESMTP id 2xajb7t4h0-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Sat, 11 Jan 2020 01:22:03 +0000 Received: from b03ledav001.gho.boulder.ibm.com (b03ledav001.gho.boulder.ibm.com [9.17.130.232]) by b03cxnp08028.gho.boulder.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 00B1M2BT61276586 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Sat, 11 Jan 2020 01:22:02 GMT Received: from b03ledav001.gho.boulder.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 3313A6E054; Sat, 11 Jan 2020 01:22:02 +0000 (GMT) Received: from b03ledav001.gho.boulder.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id ADA1D6E04C; Sat, 11 Jan 2020 01:22:01 +0000 (GMT) Received: from sbct-3.pok.ibm.com (unknown [9.47.158.153]) by b03ledav001.gho.boulder.ibm.com (Postfix) with ESMTP; Sat, 11 Jan 2020 01:22:01 +0000 (GMT) From: Stefan Berger To: slof@lists.ozlabs.org, aik@ozlabs.ru Date: Fri, 10 Jan 2020 20:21:55 -0500 Message-Id: <20200111012155.3350198-8-stefanb@linux.ibm.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200111012155.3350198-1-stefanb@linux.ibm.com> References: <20200111012155.3350198-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.572 definitions=2020-01-10_04:2020-01-10, 2020-01-10 signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 suspectscore=9 priorityscore=1501 lowpriorityscore=0 malwarescore=0 impostorscore=0 phishscore=0 bulkscore=0 adultscore=0 mlxscore=0 mlxlogscore=999 spamscore=0 clxscore=1015 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-1910280000 definitions=main-2001110008 Subject: [SLOF] [PATCH v5 7/7] 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 --- board-qemu/slof/OF.fs | 3 + board-qemu/slof/vtpm-sml.fs | 6 + lib/libtpm/tcgbios.c | 324 ++++++++++++++++++++++++++++++++++++ lib/libtpm/tcgbios.h | 1 + lib/libtpm/tpm.code | 9 + lib/libtpm/tpm.in | 1 + slof/fs/start-up.fs | 9 + 7 files changed, 353 insertions(+) diff --git a/board-qemu/slof/OF.fs b/board-qemu/slof/OF.fs index 3e117ad..7bdd6ea 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." terminal-write drop + 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 a140276..53d9eae 100644 --- a/board-qemu/slof/vtpm-sml.fs +++ b/board-qemu/slof/vtpm-sml.fs @@ -116,6 +116,12 @@ log-base LOG-SIZE tpm-set-log-parameters 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 ba5cc46..c493bb7 100644 --- a/lib/libtpm/tcgbios.c +++ b/lib/libtpm/tcgbios.c @@ -117,19 +117,30 @@ static const struct hash_parameters { } 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", } }; @@ -145,6 +156,42 @@ tpm20_get_hash_buffersize(uint16_t hashAlg) return -1; } +static uint8_t +tpm20_hashalg_to_flag(uint16_t hashAlg) +{ + unsigned i; + + for (i = 0; i < ARRAY_SIZE(hash_parameters); i++) { + if (hash_parameters[i].hashalg == hashAlg) + return hash_parameters[i].hashalg_flag; + } + return 0; +} + +static uint16_t +tpm20_hashalg_flag_to_hashalg(uint8_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].hashalg; + } + return 0; +} + +static const char * +tpm20_hashalg_flag_to_name(uint8_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].name; + } + return NULL; +} + /* * Build the TPM2 tpm2_digest_values data structure from the given hash. * Follow the PCR bank configuration of the TPM and write the same hash @@ -914,3 +961,280 @@ 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) +{ + *suppt_pcrbanks = 0; + *active_pcrbanks = 0; + + if (!tpm20_pcr_selection) + return -1; + + struct tpms_pcr_selection *sel = tpm20_pcr_selection->selections; + void *end = (void*)tpm20_pcr_selection + tpm20_pcr_selection_size; + + while (1) { + uint8_t sizeOfSelect = sel->sizeOfSelect; + void *nsel = (void*)sel + sizeof(*sel) + sizeOfSelect; + if (nsel > end) + return 0; + + uint16_t hashalg = be16_to_cpu(sel->hashAlg); + uint8_t hashalg_flag = tpm20_hashalg_to_flag(hashalg); + + *suppt_pcrbanks |= hashalg_flag; + + unsigned i; + 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; + + tpm20_get_suppt_pcrbanks(&suppt_banks, &dontcare); + + while (hashalg_flag) { + if ((hashalg_flag & suppt_banks)) { + uint16_t 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])); + + struct tpm_rsp_header rsp; + uint32_t resp_length = sizeof(rsp); + + int ret = tpmhw_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 = 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 = tpmhw_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 = tpmhw_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; + + tpm20_get_suppt_pcrbanks(&suppt_banks, &active_banks); + + uint8_t activate_banks = active_banks; + + while (1) { + uint8_t hashalg_flag = TPM2_ALG_SHA1_FLAG; + uint8_t i = 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"); + + uint8_t flagnum; + int show = 0; + 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 a9fbbb8..ef792c5 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 8254eba..1ec91ca 100644 --- a/slof/fs/start-up.fs +++ b/slof/fs/start-up.fs @@ -55,6 +55,14 @@ nvramlog-write-string-cr ; +: (t-pressed) ( -- ) + s" /ibm,vtpm" find-node dup IF + s" vtpm-menu" rot $call-static + ELSE + drop + THEN +; + : (boot?) ( -- ) \ last step before we boot we give up physical presence on the TPM s" /ibm,vtpm" find-node dup IF @@ -107,6 +115,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