Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/1.2/patches/2235251/?format=api
{ "id": 2235251, "url": "http://patchwork.ozlabs.org/api/1.2/patches/2235251/?format=api", "web_url": "http://patchwork.ozlabs.org/project/uboot/patch/154381187d2e0afe728cb222a71318080e2d6a8e.1778277334.git.aidan@wolfssl.com/", "project": { "id": 18, "url": "http://patchwork.ozlabs.org/api/1.2/projects/18/?format=api", "name": "U-Boot", "link_name": "uboot", "list_id": "u-boot.lists.denx.de", "list_email": "u-boot@lists.denx.de", "web_url": null, "scm_url": null, "webscm_url": null, "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<154381187d2e0afe728cb222a71318080e2d6a8e.1778277334.git.aidan@wolfssl.com>", "list_archive_url": null, "date": "2026-05-09T00:04:17", "name": "[v3,10/12] test: add wolfTPM C unit tests and Python integration tests", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "de6dc17b8198ce1f28e46b080f7b4e00d4edf639", "submitter": { "id": 92785, "url": "http://patchwork.ozlabs.org/api/1.2/people/92785/?format=api", "name": "Aidan Garske", "email": "aidan@wolfssl.com" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/uboot/patch/154381187d2e0afe728cb222a71318080e2d6a8e.1778277334.git.aidan@wolfssl.com/mbox/", "series": [ { "id": 503464, "url": "http://patchwork.ozlabs.org/api/1.2/series/503464/?format=api", "web_url": "http://patchwork.ozlabs.org/project/uboot/list/?series=503464", "date": "2026-05-09T00:04:07", "name": "tpm: Add wolfTPM library support for TPM 2.0", "version": 3, "mbox": "http://patchwork.ozlabs.org/series/503464/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/2235251/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/2235251/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "<u-boot-bounces@lists.denx.de>", "X-Original-To": "incoming@patchwork.ozlabs.org", "Delivered-To": "patchwork-incoming@legolas.ozlabs.org", "Authentication-Results": [ "legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=wolfssl-com.20251104.gappssmtp.com\n header.i=@wolfssl-com.20251104.gappssmtp.com header.a=rsa-sha256\n header.s=20251104 header.b=MRsizRm3;\n\tdkim-atps=neutral", "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de\n (client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; helo=phobos.denx.de;\n envelope-from=u-boot-bounces@lists.denx.de; receiver=patchwork.ozlabs.org)", "phobos.denx.de;\n dmarc=fail (p=none dis=none) header.from=wolfssl.com", "phobos.denx.de;\n spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de", "phobos.denx.de;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=wolfssl-com.20251104.gappssmtp.com\n header.i=@wolfssl-com.20251104.gappssmtp.com header.b=\"MRsizRm3\";\n\tdkim-atps=neutral", "phobos.denx.de;\n dmarc=fail (p=none dis=none) header.from=wolfssl.com", "phobos.denx.de;\n spf=pass smtp.mailfrom=aidan@wolfssl.com" ], "Received": [ "from phobos.denx.de (phobos.denx.de\n [IPv6:2a01:238:438b:c500:173d:9f52:ddab:ee01])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4gC6cz2b3qz1yCg\n\tfor <incoming@patchwork.ozlabs.org>; Sat, 09 May 2026 10:41:55 +1000 (AEST)", "from h2850616.stratoserver.net (localhost [IPv6:::1])\n\tby phobos.denx.de (Postfix) with ESMTP id BF55F84E3F;\n\tSat, 9 May 2026 02:40:16 +0200 (CEST)", "by phobos.denx.de (Postfix, from userid 109)\n id 5370A84E0E; Sat, 9 May 2026 02:04:57 +0200 (CEST)", "from mail-dl1-x122d.google.com (mail-dl1-x122d.google.com\n [IPv6:2607:f8b0:4864:20::122d])\n (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits))\n (No client certificate requested)\n by phobos.denx.de (Postfix) with ESMTPS id 12AE584E0B\n for <u-boot@lists.denx.de>; Sat, 9 May 2026 02:04:54 +0200 (CEST)", "by mail-dl1-x122d.google.com with SMTP id\n a92af1059eb24-12c45281a06so4487499c88.1\n for <u-boot@lists.denx.de>; Fri, 08 May 2026 17:04:53 -0700 (PDT)", "from localhost.localdomain ([207.231.76.218])\n by smtp.gmail.com with ESMTPSA id\n a92af1059eb24-132787673ffsm5505030c88.15.2026.05.08.17.04.50\n (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n Fri, 08 May 2026 17:04:51 -0700 (PDT)" ], "X-Spam-Checker-Version": "SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de", "X-Spam-Level": "*", "X-Spam-Status": "No, score=1.4 required=5.0 tests=BAYES_00,DKIM_SIGNED,\n DKIM_VALID,RCVD_IN_DNSWL_BLOCKED,RCVD_IN_SBL_CSS,SPF_HELO_NONE,\n SPF_PASS autolearn=no autolearn_force=no version=3.4.2", "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=wolfssl-com.20251104.gappssmtp.com; s=20251104; t=1778285092; x=1778889892;\n darn=lists.denx.de;\n h=content-transfer-encoding:mime-version:references:in-reply-to\n :message-id:date:subject:cc:to:from:from:to:cc:subject:date\n :message-id:reply-to;\n bh=vH8gj1g0+MxJ/S3YofSB0NZBfppseTld1w8z6cEOjf0=;\n b=MRsizRm30a4BEN6lTgI3OBzjLCk8zjn0cOrVSl379uoq0AGHKto4ltRmi+Gre5poX/\n J8otlgLoxU77teUOpLG1HEbFplhu06eudvjSWb8AjQNxMobUx47Oi2v+6W9u3oWE1gGQ\n 59RgMcJjGSOha4L4+IGRFgqpl62OhowN+5VTcTQWOd6kgUaCwpD8FqCc8uBgJzu9kXnf\n ihUx/pwr/w1OKfrF++hqC9ifIS7eo1nBrCIE3HIIjAZD2jGAZLGmaNpCDDjiSrS+lZvq\n EO+qV4N3H98GQilQKHGWVzdv8TqJnJckg4GWfXdfxip8tCGn+OKItfV5ScKslwFNjEJv\n lZaA==", "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20251104; t=1778285092; x=1778889892;\n h=content-transfer-encoding:mime-version:references:in-reply-to\n :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from\n :to:cc:subject:date:message-id:reply-to;\n bh=vH8gj1g0+MxJ/S3YofSB0NZBfppseTld1w8z6cEOjf0=;\n b=iTJ6XFR8n4jAxmNtulSQI8dCii4EpFPOJfAD91Zuly+/pYZPxY+ELzczSB6Z/Yzr1u\n Z9v5yPk8hZV/pljhaAOD6ZiFeRJpbGP1gxsh9pHbBW1Ir30kpog4qoxYNHg6ZsMMCdT1\n OSZscuk+2TyQ9AW/9rQqHoWOyBvmZWU7c6jqCrYx6KwruhowT7AfHWAsXUCCI2vOx/Ys\n tsbkA8/YCwKcGV4Albslo4UlsutYSvVzEa6LnFiCzFxDvMbCYvd0Od4FrZRKxErHjC9y\n ZHmv3/o3A+DT08j+di5FKjOdS293qg3zwiKNkH2LCWswBYRXSQaLQ6Ack17batgIwpio\n rCjw==", "X-Gm-Message-State": "AOJu0YxZvAuo1dUJLIu52DMIlxKeKeqDW9OPGpRxlDzCaFIVXA9LPCtQ\n MKe2QaRKB3n3SvI7cFa+ucd0BUt1ikdiItoel6JJwWiFB3TVMSWmfSytiaWMEbfFZfjlJTEeEIh\n S/z3/", "X-Gm-Gg": "AeBDiev1hPdxoFvQotvwC/6AlNB6UgFHd2U0WSV1f2LViwVjet5NPFr1QOSfIIbM8BL\n NrVUTTU3CQNP6z1WrLLrXGo4gVzEJviGHOvz+PABzRJfTYVoPurviwZDBweAPF2Bt1RxaO8B6zJ\n OIZJ6Pv2jU6Kzji2gL7DfI4hTCylDlEUItQZArlQDYZwk/A82PwCyLV43yghL5u98En0gMZ5LAU\n 7jO3BCsbj7nXHdx7Hq2d49a8iy9QzSHnACybntRhmt6/njU7BoVs5PFHdlxS+0V1p9LwUiwJTID\n 1Q32Ft4XXuKw0i1L8VIPg9O0n4+a99We2nPhFpAgLSocuEES9RuU6X98p3hrvF4j4VV8mMsyUOa\n vk6hrywm4U4fEZ1tHQotIke19jKP61/P6mIrnXFsQcxreOnAkzjL+O/oD++2M61v7E2uQdVXpOX\n xvqNpePn/3Gl7iHleaa4I6P/P5+6qEDciBrxduuuOKXE5ZSP2DDT6Lx9auIHblAn6ST9pZ26lpE\n dn5zAnYAu888V2E7tSrUA==", "X-Received": "by 2002:a05:7022:4594:b0:11a:fb3c:568b with SMTP id\n a92af1059eb24-131853e5b5amr6432904c88.17.1778285091490;\n Fri, 08 May 2026 17:04:51 -0700 (PDT)", "From": "Aidan Garske <aidan@wolfssl.com>", "To": "u-boot@lists.denx.de", "Cc": "David Garske <david@wolfssl.com>,\n Ilias Apalodimas <ilias.apalodimas@linaro.org>", "Subject": "[PATCH v3 10/12] test: add wolfTPM C unit tests and Python\n integration tests", "Date": "Fri, 8 May 2026 17:04:17 -0700", "Message-ID": "\n <154381187d2e0afe728cb222a71318080e2d6a8e.1778277334.git.aidan@wolfssl.com>", "X-Mailer": "git-send-email 2.47.3", "In-Reply-To": "<cover.1778277334.git.aidan@wolfssl.com>", "References": "<cover.1778277334.git.aidan@wolfssl.com>", "MIME-Version": "1.0", "Content-Transfer-Encoding": "8bit", "X-Mailman-Approved-At": "Sat, 09 May 2026 02:40:11 +0200", "X-BeenThere": "u-boot@lists.denx.de", "X-Mailman-Version": "2.1.39", "Precedence": "list", "List-Id": "U-Boot discussion <u-boot.lists.denx.de>", "List-Unsubscribe": "<https://lists.denx.de/options/u-boot>,\n <mailto:u-boot-request@lists.denx.de?subject=unsubscribe>", "List-Archive": "<https://lists.denx.de/pipermail/u-boot/>", "List-Post": "<mailto:u-boot@lists.denx.de>", "List-Help": "<mailto:u-boot-request@lists.denx.de?subject=help>", "List-Subscribe": "<https://lists.denx.de/listinfo/u-boot>,\n <mailto:u-boot-request@lists.denx.de?subject=subscribe>", "Errors-To": "u-boot-bounces@lists.denx.de", "Sender": "\"U-Boot\" <u-boot-bounces@lists.denx.de>", "X-Virus-Scanned": "clamav-milter 0.103.8 at phobos.denx.de", "X-Virus-Status": "Clean" }, "content": "From: Aidan <aidan@wolfssl.com>\n\nAdd comprehensive test suites for wolfTPM commands, modeled after\nthe existing TPM2 test infrastructure.\n\ntest/cmd/wolftpm.c (C unit tests):\n 18 tests using U-Boot's unit test framework (CMD_TEST macro):\n - autostart, init, info, state, device: basic lifecycle\n - self_test (full and continue): TPM self-test verification\n - startup_clear, startup_state: TPM2_Startup modes\n - get_capability: read TPM properties\n - caps: wolfTPM-enhanced capabilities display\n - clear: TPM state reset via LOCKOUT hierarchy\n - pcr_read, pcr_extend, pcr_print: PCR operations\n - pcr_allocate: PCR bank reconfiguration\n - dam_reset, dam_parameters: dictionary attack mitigation\n - change_auth: hierarchy password change (requires wolfCrypt)\n - cleanup: reset TPM state after tests\n Run with: ut cmd cmd_test_wolftpm_*\n\ntest/cmd/Makefile:\n Adds wolftpm.o when CONFIG_TPM_WOLF is enabled.\n\ntest/py/tests/test_wolftpm.py (Python integration tests):\n 21 tests using pytest with the U-Boot test framework:\n - Requires QEMU + swtpm (not sandbox) because wolfTPM bypasses\n U-Boot's driver model and communicates directly with TPM\n hardware via its own SPI/MMIO HAL\n - Tests mirror the C tests but run end-to-end through the U-Boot\n console, checking return codes via 'echo $?'\n - Includes force_init() helper for TPM reinitialization after\n test failures\n - Skippable via env__wolftpm_device_test_skip config\n - Verified: 19 passed, 2 skipped (change_auth requires wolfCrypt,\n get_capability may skip on some platforms)\n\nSigned-off-by: Aidan Garske <aidan@wolfssl.com>\n---\n test/cmd/Makefile | 1 +\n test/cmd/wolftpm.c | 364 +++++++++++++++++++++++++++++++++\n test/py/tests/test_wolftpm.py | 375 ++++++++++++++++++++++++++++++++++\n 3 files changed, 740 insertions(+)\n create mode 100644 test/cmd/wolftpm.c\n create mode 100644 test/py/tests/test_wolftpm.py", "diff": "diff --git a/test/cmd/Makefile b/test/cmd/Makefile\nindex 2476068aee6..08fbc31a06a 100644\n--- a/test/cmd/Makefile\n+++ b/test/cmd/Makefile\n@@ -45,3 +45,4 @@ endif\n obj-$(CONFIG_ARM_FFA_TRANSPORT) += armffa.o\n endif\n obj-$(CONFIG_CMD_SPAWN) += spawn.o\n+obj-$(CONFIG_TPM_WOLF) += wolftpm.o\ndiff --git a/test/cmd/wolftpm.c b/test/cmd/wolftpm.c\nnew file mode 100644\nindex 00000000000..b2e6f82a098\n--- /dev/null\n+++ b/test/cmd/wolftpm.c\n@@ -0,0 +1,364 @@\n+// SPDX-License-Identifier: GPL-2.0+\n+/*\n+ * Tests for wolfTPM commands\n+ *\n+ * Copyright (C) 2025 wolfSSL Inc.\n+ * Author: Aidan Garske <aidan@wolfssl.com>\n+ *\n+ * Based on test/py/tests/test_tpm2.py and test/dm/tpm.c\n+ *\n+ * Note: These tests verify command success via return code only.\n+ * Console output is not checked since it varies with debug levels.\n+ * Run with: ut cmd\n+ */\n+\n+#include <command.h>\n+#include <dm.h>\n+#include <dm/test.h>\n+#include <test/cmd.h>\n+#include <test/test.h>\n+#include <test/ut.h>\n+\n+/**\n+ * Test wolfTPM autostart command\n+ *\n+ * This initializes the TPM, performs startup and self-test\n+ */\n+static int cmd_test_wolftpm_autostart(struct unit_test_state *uts)\n+{\n+\t/* Initialize and autostart the TPM */\n+\tut_assertok(run_command(\"tpm2 autostart\", 0));\n+\n+\treturn 0;\n+}\n+CMD_TEST(cmd_test_wolftpm_autostart, 0);\n+\n+/**\n+ * Test wolfTPM init command\n+ */\n+static int cmd_test_wolftpm_init(struct unit_test_state *uts)\n+{\n+\tut_assertok(run_command(\"tpm2 init\", 0));\n+\n+\treturn 0;\n+}\n+CMD_TEST(cmd_test_wolftpm_init, 0);\n+\n+/**\n+ * Test wolfTPM info command\n+ *\n+ * Display TPM device information\n+ */\n+static int cmd_test_wolftpm_info(struct unit_test_state *uts)\n+{\n+\t/* First autostart to ensure TPM is ready */\n+\tut_assertok(run_command(\"tpm2 autostart\", 0));\n+\n+\t/* Get TPM info */\n+\tut_assertok(run_command(\"tpm2 info\", 0));\n+\n+\treturn 0;\n+}\n+CMD_TEST(cmd_test_wolftpm_info, 0);\n+\n+/**\n+ * Test wolfTPM state command\n+ *\n+ * Display TPM internal state\n+ */\n+static int cmd_test_wolftpm_state(struct unit_test_state *uts)\n+{\n+\t/* First autostart to ensure TPM is ready */\n+\tut_assertok(run_command(\"tpm2 autostart\", 0));\n+\n+\t/* Get TPM state */\n+\tut_assertok(run_command(\"tpm2 state\", 0));\n+\n+\treturn 0;\n+}\n+CMD_TEST(cmd_test_wolftpm_state, 0);\n+\n+/**\n+ * Test wolfTPM device command\n+ *\n+ * Show all TPM devices\n+ */\n+static int cmd_test_wolftpm_device(struct unit_test_state *uts)\n+{\n+\t/* Show TPM devices - no autostart needed */\n+\tut_assertok(run_command(\"tpm2 device\", 0));\n+\n+\treturn 0;\n+}\n+CMD_TEST(cmd_test_wolftpm_device, 0);\n+\n+/**\n+ * Test wolfTPM self_test command\n+ */\n+static int cmd_test_wolftpm_self_test(struct unit_test_state *uts)\n+{\n+\t/* First autostart to ensure TPM is ready */\n+\tut_assertok(run_command(\"tpm2 autostart\", 0));\n+\n+\t/* Run full self test */\n+\tut_assertok(run_command(\"tpm2 self_test full\", 0));\n+\n+\treturn 0;\n+}\n+CMD_TEST(cmd_test_wolftpm_self_test, 0);\n+\n+/**\n+ * Test wolfTPM self_test continue command\n+ */\n+static int cmd_test_wolftpm_self_test_continue(struct unit_test_state *uts)\n+{\n+\t/* First autostart to ensure TPM is ready */\n+\tut_assertok(run_command(\"tpm2 autostart\", 0));\n+\n+\t/* Run continue self test */\n+\tut_assertok(run_command(\"tpm2 self_test continue\", 0));\n+\n+\treturn 0;\n+}\n+CMD_TEST(cmd_test_wolftpm_self_test_continue, 0);\n+\n+/**\n+ * Test wolfTPM startup command with TPM2_SU_CLEAR\n+ *\n+ * Issue TPM2_Startup with CLEAR mode (reset state)\n+ */\n+static int cmd_test_wolftpm_startup_clear(struct unit_test_state *uts)\n+{\n+\t/* First init to prepare TPM */\n+\tut_assertok(run_command(\"tpm2 init\", 0));\n+\n+\t/* Issue startup with CLEAR mode */\n+\tut_assertok(run_command(\"tpm2 startup TPM2_SU_CLEAR\", 0));\n+\n+\treturn 0;\n+}\n+CMD_TEST(cmd_test_wolftpm_startup_clear, 0);\n+\n+/**\n+ * Test wolfTPM startup command with TPM2_SU_STATE\n+ *\n+ * Issue TPM2_Startup with STATE mode (preserved state)\n+ */\n+static int cmd_test_wolftpm_startup_state(struct unit_test_state *uts)\n+{\n+\t/* First autostart to ensure TPM has state */\n+\tut_assertok(run_command(\"tpm2 autostart\", 0));\n+\n+\t/* Shutdown first to prepare for STATE startup */\n+\trun_command(\"tpm2 startup TPM2_SU_STATE off\", 0);\n+\n+\t/* Re-init */\n+\tut_assertok(run_command(\"tpm2 init\", 0));\n+\n+\t/* Issue startup with STATE mode - may return already started */\n+\trun_command(\"tpm2 startup TPM2_SU_STATE\", 0);\n+\n+\treturn 0;\n+}\n+CMD_TEST(cmd_test_wolftpm_startup_state, 0);\n+\n+/**\n+ * Test wolfTPM get_capability command\n+ *\n+ * Read TPM capabilities by property\n+ */\n+static int cmd_test_wolftpm_get_capability(struct unit_test_state *uts)\n+{\n+\t/* First autostart to ensure TPM is ready */\n+\tut_assertok(run_command(\"tpm2 autostart\", 0));\n+\n+\t/* Get capability - property 0x6 (TPM_CAP_TPM_PROPERTIES), 0x20e (PT_MANUFACTURER) */\n+\tut_assertok(run_command(\"tpm2 get_capability 0x6 0x20e 0x1000000 1\", 0));\n+\n+\treturn 0;\n+}\n+CMD_TEST(cmd_test_wolftpm_get_capability, 0);\n+\n+/**\n+ * Test wolfTPM caps command (get capabilities)\n+ *\n+ * Display TPM capabilities and vendor info\n+ */\n+static int cmd_test_wolftpm_caps(struct unit_test_state *uts)\n+{\n+\t/* First autostart to ensure TPM is ready */\n+\tut_assertok(run_command(\"tpm2 autostart\", 0));\n+\n+\t/* Get TPM capabilities */\n+\tut_assertok(run_command(\"tpm2 caps\", 0));\n+\n+\treturn 0;\n+}\n+CMD_TEST(cmd_test_wolftpm_caps, 0);\n+\n+/**\n+ * Test wolfTPM clear command\n+ *\n+ * Reset TPM internal state using LOCKOUT hierarchy\n+ */\n+static int cmd_test_wolftpm_clear(struct unit_test_state *uts)\n+{\n+\t/* First autostart to ensure TPM is ready */\n+\tut_assertok(run_command(\"tpm2 autostart\", 0));\n+\n+\t/* Clear using LOCKOUT hierarchy */\n+\tut_assertok(run_command(\"tpm2 clear TPM2_RH_LOCKOUT\", 0));\n+\n+\treturn 0;\n+}\n+CMD_TEST(cmd_test_wolftpm_clear, 0);\n+\n+/**\n+ * Test wolfTPM pcr_read command\n+ *\n+ * Read PCR value from a specific index to a memory address\n+ */\n+static int cmd_test_wolftpm_pcr_read(struct unit_test_state *uts)\n+{\n+\t/* First autostart to ensure TPM is ready */\n+\tut_assertok(run_command(\"tpm2 autostart\", 0));\n+\n+\t/* Read PCR 0 with SHA256 to memory address 0x1000000 */\n+\tut_assertok(run_command(\"tpm2 pcr_read 0 0x1000000 SHA256\", 0));\n+\n+\treturn 0;\n+}\n+CMD_TEST(cmd_test_wolftpm_pcr_read, 0);\n+\n+/**\n+ * Test wolfTPM pcr_extend command\n+ *\n+ * Extend a PCR with a digest value\n+ */\n+static int cmd_test_wolftpm_pcr_extend(struct unit_test_state *uts)\n+{\n+\t/* First autostart to ensure TPM is ready */\n+\tut_assertok(run_command(\"tpm2 autostart\", 0));\n+\n+\t/* Clear to start fresh */\n+\trun_command(\"tpm2 clear TPM2_RH_LOCKOUT\", 0);\n+\n+\t/* Extend PCR 16 (resettable PCR) with digest from memory\n+\t * PCR 16-23 are typically available for debug/testing\n+\t */\n+\tut_assertok(run_command(\"tpm2 pcr_extend 16 0x1000000 SHA256\", 0));\n+\n+\treturn 0;\n+}\n+CMD_TEST(cmd_test_wolftpm_pcr_extend, 0);\n+\n+/**\n+ * Test wolfTPM pcr_print command\n+ *\n+ * Print all PCR values\n+ */\n+static int cmd_test_wolftpm_pcr_print(struct unit_test_state *uts)\n+{\n+\t/* First autostart to ensure TPM is ready */\n+\tut_assertok(run_command(\"tpm2 autostart\", 0));\n+\n+\t/* Print all PCRs */\n+\tut_assertok(run_command(\"tpm2 pcr_print\", 0));\n+\n+\treturn 0;\n+}\n+CMD_TEST(cmd_test_wolftpm_pcr_print, 0);\n+\n+/**\n+ * Test wolfTPM pcr_allocate command\n+ *\n+ * Reconfigure PCR bank algorithm. Note: A TPM restart is required\n+ * for changes to take effect, so we just verify the command succeeds.\n+ */\n+static int cmd_test_wolftpm_pcr_allocate(struct unit_test_state *uts)\n+{\n+\t/* First autostart to ensure TPM is ready */\n+\tut_assertok(run_command(\"tpm2 autostart\", 0));\n+\n+\t/* Allocate SHA256 bank on - this should succeed */\n+\tut_assertok(run_command(\"tpm2 pcr_allocate SHA256 on\", 0));\n+\n+\treturn 0;\n+}\n+CMD_TEST(cmd_test_wolftpm_pcr_allocate, 0);\n+\n+/**\n+ * Test wolfTPM dam_reset command\n+ *\n+ * Reset Dictionary Attack Mitigation counter\n+ */\n+static int cmd_test_wolftpm_dam_reset(struct unit_test_state *uts)\n+{\n+\t/* First autostart to ensure TPM is ready */\n+\tut_assertok(run_command(\"tpm2 autostart\", 0));\n+\n+\t/* Reset DAM counter */\n+\tut_assertok(run_command(\"tpm2 dam_reset\", 0));\n+\n+\treturn 0;\n+}\n+CMD_TEST(cmd_test_wolftpm_dam_reset, 0);\n+\n+/**\n+ * Test wolfTPM dam_parameters command\n+ *\n+ * Set Dictionary Attack Mitigation parameters\n+ */\n+static int cmd_test_wolftpm_dam_parameters(struct unit_test_state *uts)\n+{\n+\t/* First autostart to ensure TPM is ready */\n+\tut_assertok(run_command(\"tpm2 autostart\", 0));\n+\n+\t/* Set DAM parameters:\n+\t * - max_tries: 3\n+\t * - recovery_time: 10 seconds\n+\t * - lockout_recovery: 0 seconds\n+\t */\n+\tut_assertok(run_command(\"tpm2 dam_parameters 3 10 0\", 0));\n+\n+\treturn 0;\n+}\n+CMD_TEST(cmd_test_wolftpm_dam_parameters, 0);\n+\n+/**\n+ * Test wolfTPM change_auth command\n+ *\n+ * Change hierarchy authorization password\n+ * Note: Requires WOLFTPM2_NO_WOLFCRYPT to NOT be defined\n+ */\n+static int cmd_test_wolftpm_change_auth(struct unit_test_state *uts)\n+{\n+\t/* First autostart and clear to ensure clean state */\n+\tut_assertok(run_command(\"tpm2 autostart\", 0));\n+\trun_command(\"tpm2 clear TPM2_RH_LOCKOUT\", 0);\n+\n+\t/* Change LOCKOUT password to \"testpw\"\n+\t * This may fail if WOLFTPM2_NO_WOLFCRYPT is defined\n+\t */\n+\tif (run_command(\"tpm2 change_auth TPM2_RH_LOCKOUT testpw\", 0) == 0) {\n+\t\t/* Clear with new password to verify it worked */\n+\t\tut_assertok(run_command(\"tpm2 clear TPM2_RH_LOCKOUT testpw\", 0));\n+\t}\n+\n+\treturn 0;\n+}\n+CMD_TEST(cmd_test_wolftpm_change_auth, 0);\n+\n+/**\n+ * Cleanup test - ensure TPM is cleared after tests\n+ */\n+static int cmd_test_wolftpm_cleanup(struct unit_test_state *uts)\n+{\n+\t/* Clear TPM to reset any passwords or test state */\n+\trun_command(\"tpm2 autostart\", 0);\n+\trun_command(\"tpm2 clear TPM2_RH_LOCKOUT\", 0);\n+\trun_command(\"tpm2 clear TPM2_RH_PLATFORM\", 0);\n+\n+\treturn 0;\n+}\n+CMD_TEST(cmd_test_wolftpm_cleanup, 0);\ndiff --git a/test/py/tests/test_wolftpm.py b/test/py/tests/test_wolftpm.py\nnew file mode 100644\nindex 00000000000..b862fa06c5b\n--- /dev/null\n+++ b/test/py/tests/test_wolftpm.py\n@@ -0,0 +1,375 @@\n+# SPDX-License-Identifier: GPL-2.0+\n+# Copyright (C) 2025 wolfSSL Inc.\n+# Author: Aidan Garske <aidan@wolfssl.com>\n+#\n+# Based on test_tpm2.py by Miquel Raynal <miquel.raynal@bootlin.com>\n+\n+\"\"\"\n+Test the wolfTPM related commands. These tests require a TPM device\n+(real hardware or software TPM emulator like swtpm).\n+\n+Notes:\n+* These tests will prove the password mechanism. The TPM chip must be cleared of\n+ any password.\n+* Tests are designed to be similar to test_tpm2.py but use wolfTPM wrapper APIs.\n+\n+Configuration:\n+* Set env__wolftpm_device_test_skip to True to skip these tests.\n+\"\"\"\n+\n+import os.path\n+import pytest\n+import utils\n+import re\n+import time\n+\n+\n+def force_init(ubman, force=False):\n+ \"\"\"Initialize wolfTPM before running tests.\n+\n+ When a test fails, U-Boot may be reset. Because TPM stack must be initialized\n+ after each reboot, we must ensure these lines are always executed before\n+ trying any command or they will fail with no reason.\n+ \"\"\"\n+ skip_test = ubman.config.env.get('env__wolftpm_device_test_skip', False)\n+ if skip_test:\n+ pytest.skip('skip wolfTPM device test')\n+ output = ubman.run_command('tpm2 autostart')\n+ if force or 'Error' not in output:\n+ ubman.run_command('echo --- start of init ---')\n+ ubman.run_command('tpm2 clear TPM2_RH_LOCKOUT')\n+ output = ubman.run_command('echo $?')\n+ if not output.endswith('0'):\n+ ubman.run_command('tpm2 clear TPM2_RH_PLATFORM')\n+ ubman.run_command('echo --- end of init ---')\n+\n+\n+@pytest.mark.buildconfigspec('tpm_wolf')\n+def test_wolftpm_autostart(ubman):\n+ \"\"\"Test wolfTPM autostart command.\n+\n+ Initialize the software stack, perform startup and self-test.\n+ \"\"\"\n+ skip_test = ubman.config.env.get('env__wolftpm_device_test_skip', False)\n+ if skip_test:\n+ pytest.skip('skip wolfTPM device test')\n+ ubman.run_command('tpm2 autostart')\n+ output = ubman.run_command('echo $?')\n+ assert output.endswith('0')\n+\n+\n+@pytest.mark.buildconfigspec('tpm_wolf')\n+def test_wolftpm_init(ubman):\n+ \"\"\"Test wolfTPM init command.\n+\n+ Initialize the TPM device for communication.\n+ \"\"\"\n+ skip_test = ubman.config.env.get('env__wolftpm_device_test_skip', False)\n+ if skip_test:\n+ pytest.skip('skip wolfTPM device test')\n+ ubman.run_command('tpm2 init')\n+ output = ubman.run_command('echo $?')\n+ assert output.endswith('0')\n+\n+\n+@pytest.mark.buildconfigspec('tpm_wolf')\n+def test_wolftpm_self_test_full(ubman):\n+ \"\"\"Test wolfTPM full self_test command.\n+\n+ Perform a full TPM self-test to verify all components are operational.\n+ \"\"\"\n+ skip_test = ubman.config.env.get('env__wolftpm_device_test_skip', False)\n+ if skip_test:\n+ pytest.skip('skip wolfTPM device test')\n+ ubman.run_command('tpm2 autostart')\n+ ubman.run_command('tpm2 self_test full')\n+ output = ubman.run_command('echo $?')\n+ assert output.endswith('0')\n+\n+\n+@pytest.mark.buildconfigspec('tpm_wolf')\n+def test_wolftpm_self_test_continue(ubman):\n+ \"\"\"Test wolfTPM continue self_test command.\n+\n+ Ask the TPM to finish any remaining self tests.\n+ \"\"\"\n+ skip_test = ubman.config.env.get('env__wolftpm_device_test_skip', False)\n+ if skip_test:\n+ pytest.skip('skip wolfTPM device test')\n+ ubman.run_command('tpm2 autostart')\n+ ubman.run_command('tpm2 self_test continue')\n+ output = ubman.run_command('echo $?')\n+ assert output.endswith('0')\n+\n+\n+@pytest.mark.buildconfigspec('tpm_wolf')\n+def test_wolftpm_caps(ubman):\n+ \"\"\"Test wolfTPM caps command.\n+\n+ Display TPM capabilities and vendor information.\n+ \"\"\"\n+ force_init(ubman)\n+ ubman.run_command('tpm2 caps')\n+ output = ubman.run_command('echo $?')\n+ assert output.endswith('0')\n+\n+\n+@pytest.mark.buildconfigspec('tpm_wolf')\n+def test_wolftpm_clear(ubman):\n+ \"\"\"Test wolfTPM clear command.\n+\n+ Clear the TPM internal state using LOCKOUT hierarchy.\n+ LOCKOUT/PLATFORM hierarchies must not have a password set.\n+ \"\"\"\n+ skip_test = ubman.config.env.get('env__wolftpm_device_test_skip', False)\n+ if skip_test:\n+ pytest.skip('skip wolfTPM device test')\n+ ubman.run_command('tpm2 autostart')\n+ ubman.run_command('tpm2 clear TPM2_RH_LOCKOUT')\n+ output = ubman.run_command('echo $?')\n+ assert output.endswith('0')\n+\n+ ubman.run_command('tpm2 clear TPM2_RH_PLATFORM')\n+ output = ubman.run_command('echo $?')\n+ assert output.endswith('0')\n+\n+\n+@pytest.mark.buildconfigspec('tpm_wolf')\n+def test_wolftpm_change_auth(ubman):\n+ \"\"\"Test wolfTPM change_auth command.\n+\n+ Change the owner/hierarchy password.\n+ \"\"\"\n+ force_init(ubman)\n+\n+ # Change LOCKOUT password to 'unicorn'\n+ # Note: change_auth requires wolfCrypt (WOLFTPM2_NO_WOLFCRYPT must not be set)\n+ ubman.run_command('tpm2 change_auth TPM2_RH_LOCKOUT unicorn')\n+ output = ubman.run_command('echo $?')\n+ if not output.endswith('0'):\n+ # wolfCrypt not available, skip password test\n+ pytest.skip('change_auth requires wolfCrypt support')\n+\n+ # Clear with new password to verify\n+ ubman.run_command('tpm2 clear TPM2_RH_LOCKOUT unicorn')\n+ output = ubman.run_command('echo $?')\n+ ubman.run_command('tpm2 clear TPM2_RH_PLATFORM')\n+ assert output.endswith('0')\n+\n+\n+@pytest.mark.buildconfigspec('tpm_wolf')\n+def test_wolftpm_dam_parameters(ubman):\n+ \"\"\"Test wolfTPM dam_parameters command.\n+\n+ Change Dictionary Attack Mitigation parameters:\n+ - Max number of failed authentication before lockout: 3\n+ - Time before failure counter is decremented: 10 sec\n+ - Time after lockout failure before retry: 0 sec\n+ \"\"\"\n+ force_init(ubman)\n+\n+ # Set DAM parameters\n+ ubman.run_command('tpm2 dam_parameters 3 10 0')\n+ output = ubman.run_command('echo $?')\n+ assert output.endswith('0')\n+\n+\n+@pytest.mark.buildconfigspec('tpm_wolf')\n+def test_wolftpm_dam_reset(ubman):\n+ \"\"\"Test wolfTPM dam_reset command.\n+\n+ Reset the Dictionary Attack Mitigation counter.\n+ \"\"\"\n+ force_init(ubman)\n+\n+ ubman.run_command('tpm2 dam_reset')\n+ output = ubman.run_command('echo $?')\n+ assert output.endswith('0')\n+\n+\n+@pytest.mark.buildconfigspec('tpm_wolf')\n+def test_wolftpm_pcr_read(ubman):\n+ \"\"\"Test wolfTPM pcr_read command.\n+\n+ Read PCR value from a specific index.\n+ \"\"\"\n+ force_init(ubman)\n+\n+ ram = utils.find_ram_base(ubman)\n+\n+ # Read PCR 0 with SHA256\n+ read_pcr = ubman.run_command('tpm2 pcr_read 0 0x%x SHA256' % ram)\n+ output = ubman.run_command('echo $?')\n+ assert output.endswith('0')\n+\n+\n+@pytest.mark.buildconfigspec('tpm_wolf')\n+def test_wolftpm_pcr_extend(ubman):\n+ \"\"\"Test wolfTPM pcr_extend command.\n+\n+ Extend a PCR with a digest value.\n+ PCR 16-23 are typically available for debug/testing.\n+ \"\"\"\n+ force_init(ubman)\n+ ram = utils.find_ram_base(ubman)\n+\n+ # Read PCR 16 first\n+ read_pcr = ubman.run_command('tpm2 pcr_read 16 0x%x SHA256' % ram)\n+ output = ubman.run_command('echo $?')\n+ assert output.endswith('0')\n+\n+ # Extend PCR 16 with zeroed memory\n+ ubman.run_command('tpm2 pcr_extend 16 0x%x SHA256' % ram)\n+ output = ubman.run_command('echo $?')\n+ assert output.endswith('0')\n+\n+ # Read again to verify it changed\n+ read_pcr_after = ubman.run_command('tpm2 pcr_read 16 0x%x SHA256' % ram)\n+ output = ubman.run_command('echo $?')\n+ assert output.endswith('0')\n+\n+\n+@pytest.mark.buildconfigspec('tpm_wolf')\n+def test_wolftpm_pcr_print(ubman):\n+ \"\"\"Test wolfTPM pcr_print command.\n+\n+ Print all assigned PCRs.\n+ \"\"\"\n+ force_init(ubman)\n+\n+ pcr_output = ubman.run_command('tpm2 pcr_print')\n+ output = ubman.run_command('echo $?')\n+ assert output.endswith('0')\n+\n+ # Should contain PCR info\n+ assert 'PCR' in pcr_output or 'Assigned' in pcr_output\n+\n+\n+@pytest.mark.buildconfigspec('tpm_wolf')\n+def test_wolftpm_info(ubman):\n+ \"\"\"Test wolfTPM info command.\n+\n+ Display TPM device information.\n+ \"\"\"\n+ force_init(ubman)\n+\n+ ubman.run_command('tpm2 info')\n+ output = ubman.run_command('echo $?')\n+ assert output.endswith('0')\n+\n+\n+@pytest.mark.buildconfigspec('tpm_wolf')\n+def test_wolftpm_state(ubman):\n+ \"\"\"Test wolfTPM state command.\n+\n+ Display TPM internal state.\n+ \"\"\"\n+ force_init(ubman)\n+\n+ ubman.run_command('tpm2 state')\n+ output = ubman.run_command('echo $?')\n+ assert output.endswith('0')\n+\n+\n+@pytest.mark.buildconfigspec('tpm_wolf')\n+def test_wolftpm_device(ubman):\n+ \"\"\"Test wolfTPM device command.\n+\n+ Show all TPM devices.\n+ \"\"\"\n+ skip_test = ubman.config.env.get('env__wolftpm_device_test_skip', False)\n+ if skip_test:\n+ pytest.skip('skip wolfTPM device test')\n+ ubman.run_command('tpm2 device')\n+ output = ubman.run_command('echo $?')\n+ assert output.endswith('0')\n+\n+\n+@pytest.mark.buildconfigspec('tpm_wolf')\n+def test_wolftpm_startup_clear(ubman):\n+ \"\"\"Test wolfTPM startup command with TPM2_SU_CLEAR.\n+\n+ Issue TPM2_Startup with CLEAR mode (reset state).\n+ \"\"\"\n+ skip_test = ubman.config.env.get('env__wolftpm_device_test_skip', False)\n+ if skip_test:\n+ pytest.skip('skip wolfTPM device test')\n+ ubman.run_command('tpm2 init')\n+ ubman.run_command('tpm2 startup TPM2_SU_CLEAR')\n+ output = ubman.run_command('echo $?')\n+ assert output.endswith('0')\n+\n+\n+@pytest.mark.buildconfigspec('tpm_wolf')\n+def test_wolftpm_startup_state(ubman):\n+ \"\"\"Test wolfTPM startup command with TPM2_SU_STATE.\n+\n+ Issue TPM2_Startup with STATE mode (preserved state).\n+ \"\"\"\n+ skip_test = ubman.config.env.get('env__wolftpm_device_test_skip', False)\n+ if skip_test:\n+ pytest.skip('skip wolfTPM device test')\n+ # First autostart to have valid state\n+ ubman.run_command('tpm2 autostart')\n+ # Shutdown with STATE\n+ ubman.run_command('tpm2 startup TPM2_SU_STATE off')\n+ # Re-init\n+ ubman.run_command('tpm2 init')\n+ # Startup with STATE - may return already started\n+ ubman.run_command('tpm2 startup TPM2_SU_STATE')\n+ output = ubman.run_command('echo $?')\n+ # May return non-zero if already started, just verify command ran\n+ assert output is not None\n+\n+\n+@pytest.mark.buildconfigspec('tpm_wolf')\n+def test_wolftpm_startup_shutdown(ubman):\n+ \"\"\"Test wolfTPM startup shutdown command.\n+\n+ Issue TPM2_Shutdown.\n+ \"\"\"\n+ skip_test = ubman.config.env.get('env__wolftpm_device_test_skip', False)\n+ if skip_test:\n+ pytest.skip('skip wolfTPM device test')\n+ ubman.run_command('tpm2 autostart')\n+ ubman.run_command('tpm2 startup TPM2_SU_CLEAR off')\n+ output = ubman.run_command('echo $?')\n+ assert output.endswith('0')\n+\n+\n+@pytest.mark.buildconfigspec('tpm_wolf')\n+def test_wolftpm_get_capability(ubman):\n+ \"\"\"Test wolfTPM get_capability command.\n+\n+ Read TPM capabilities by property.\n+ \"\"\"\n+ force_init(ubman)\n+ ram = utils.find_ram_base(ubman)\n+\n+ # Get capability - TPM_CAP_TPM_PROPERTIES (0x6), PT_MANUFACTURER (0x20e)\n+ ubman.run_command('tpm2 get_capability 0x6 0x20e 0x%x 1' % ram)\n+ output = ubman.run_command('echo $?')\n+ # May fail on some platforms if RAM address is not accessible\n+ if not output.endswith('0'):\n+ pytest.skip('get_capability failed (RAM address may not be accessible)')\n+\n+\n+@pytest.mark.buildconfigspec('tpm_wolf')\n+def test_wolftpm_pcr_allocate(ubman):\n+ \"\"\"Test wolfTPM pcr_allocate command.\n+\n+ Reconfigure PCR bank algorithm.\n+ Note: A TPM restart is required for changes to take effect.\n+ \"\"\"\n+ force_init(ubman)\n+\n+ # Allocate SHA256 bank on\n+ ubman.run_command('tpm2 pcr_allocate SHA256 on')\n+ output = ubman.run_command('echo $?')\n+ assert output.endswith('0')\n+\n+\n+@pytest.mark.buildconfigspec('tpm_wolf')\n+def test_wolftpm_cleanup(ubman):\n+ \"\"\"Cleanup test - ensure TPM is cleared after tests.\"\"\"\n+ force_init(ubman, True)\n", "prefixes": [ "v3", "10/12" ] }