From patchwork Sun Oct 19 07:23:01 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 625 Return-Path: X-Original-To: u-boot-concept@u-boot.org Delivered-To: u-boot-concept@u-boot.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1760858622; bh=dE/WtxhirVUr7Kyel6xOz9FG7ZlFV7mtz4p+ZgvdCY0=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=gtTEiDJANHvXb7n/xBfCBzFT6u2b69H9LXEXigL2xKoA9p0IaWunyno/RReot49Ok xn4t+GxVTSL4q8q3Z1XLfqSJ6fardXerOSZPSXEMrumERchA1vasMNpIkY7pOQx9z5 4Co9H5cWDPTn2gRC+02INt9EB5kkJIfJNM+AizTqakB0Lr0n0nucz9U2WqKhGoP6Sm edIiKRFEz8EzJN3onvsjX5cD6qnKenn+2H6Tkxf3sr/e4FuwT0z+2DB7SFhgd+Ro4I Y4mY96gEH+KijXLT6x6ebpwhPgvakHF5jpp+tHF8Y0URQDBxrvUlewcM4eyB4ROXsU Yo6Gq/kbV3iEA== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id EEDAA681AD for ; Sun, 19 Oct 2025 01:23:42 -0600 (MDT) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10024) with ESMTP id r-Iw9jRB81Od for ; Sun, 19 Oct 2025 01:23:42 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1760858622; bh=dE/WtxhirVUr7Kyel6xOz9FG7ZlFV7mtz4p+ZgvdCY0=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=gtTEiDJANHvXb7n/xBfCBzFT6u2b69H9LXEXigL2xKoA9p0IaWunyno/RReot49Ok xn4t+GxVTSL4q8q3Z1XLfqSJ6fardXerOSZPSXEMrumERchA1vasMNpIkY7pOQx9z5 4Co9H5cWDPTn2gRC+02INt9EB5kkJIfJNM+AizTqakB0Lr0n0nucz9U2WqKhGoP6Sm edIiKRFEz8EzJN3onvsjX5cD6qnKenn+2H6Tkxf3sr/e4FuwT0z+2DB7SFhgd+Ro4I Y4mY96gEH+KijXLT6x6ebpwhPgvakHF5jpp+tHF8Y0URQDBxrvUlewcM4eyB4ROXsU Yo6Gq/kbV3iEA== Received: from mail.u-boot.org (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id DD92068105 for ; Sun, 19 Oct 2025 01:23:42 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1760858620; bh=kbTIM8HH+1rrReKPEEpgUIQoT+0aRq75yfLCK1JD8VI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=tsXTOEIGtVPutBOWd9PSQqcFwxc08Y2PlM9GgPoRwcWON8sLPokV1a90dUW5/EULj 7T0JVlkb0gRP6zDsTP/NYI7O0r4zO23b9SYQxSUeRj9L3NCeHrW4REZbPxAUMIkMVn /rgj0YhYl0KWUhY4nuiuyk6iLSNL2sb1W4u2FO5Bb2GuDyUbQVSdKHcHUixf6GN8y6 +R91V2g8CIP+LgFg32w2TB/bBxW0LQi6QRAqEAFx3VRJhYcqbQA4qn0P/alem+Cp4O HFs7YN219j9WsOQGe3ycOye2d0O4O7HvN5ozPhBq4kJKj21P9t9nGTnz7e0nvWL/MX mHNLMKhIiCgLA== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 91ADE5E435; Sun, 19 Oct 2025 01:23:40 -0600 (MDT) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10026) with ESMTP id MVyeeNLxbdxJ; Sun, 19 Oct 2025 01:23:40 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1760858616; bh=LH9nXvkMXlFYLEueUce752hM6Oq29yquDV8dq1Ia5IQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=wg/k/mw92Q5m+BYkf5LmwlFDX/QVqNOraM++5juAzLT6F/u5u78g+JvGRc1vZPlH0 VIFI9HplXwqnfddkp0YLRwO43rw1ODYI2glv1PEflrxwH61caXSsN+32MkGGTt9y6d LSX59w7eIfil+t/DKZk/3ryEExbw/zgfmYzZOEE96Fs3PTcPsEeMuI8/J8pm7w8tKg 5gWUBq64lAfwgh6CkFyv9l6El6uzPPLTYI4BhH7eMz7wN4Cq+tNKtJvSNk+vLbte27 pGf2fSR55OfsLtiM1+bKAyKNxDbH0h01KyTK8drwE3gvvVO7I3BXnjZyOMx8k5aAOK Qzz+eG/VFNiTA== Received: from u-boot.org (unknown [73.34.74.121]) by mail.u-boot.org (Postfix) with ESMTPSA id 42CED68170; Sun, 19 Oct 2025 01:23:36 -0600 (MDT) From: Simon Glass To: U-Boot Concept Date: Sun, 19 Oct 2025 01:23:01 -0600 Message-ID: <20251019072313.3235339-2-sjg@u-boot.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251019072313.3235339-1-sjg@u-boot.org> References: <20251019072313.3235339-1-sjg@u-boot.org> MIME-Version: 1.0 Message-ID-Hash: PAZQNSGUSUQ4XQCL72KBVOIE36GCCPZV X-Message-ID-Hash: PAZQNSGUSUQ4XQCL72KBVOIE36GCCPZV X-MailFrom: sjg@u-boot.org X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: Simon Glass , Claude X-Mailman-Version: 3.3.10 Precedence: list Subject: [Concept] [PATCH 1/8] serial: ns16550: Add skip-init devicetree property List-Id: Discussion and patches related to U-Boot Concept Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: From: Simon Glass Add support for a 'skip-init' property in the device tree that preserves UART settings from a previous boot phase. This is useful when the UART is already configured by firmware (e.g., EFI firmware on x86 platforms) and changing the settings would disrupt console output or cause communication issues. Co-developed-by: Claude Signed-off-by: Simon Glass --- drivers/serial/ns16550.c | 12 +++++++++++- include/ns16550.h | 2 ++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c index 5126cf8bc1a..1f0d1c894cb 100644 --- a/drivers/serial/ns16550.c +++ b/drivers/serial/ns16550.c @@ -426,6 +426,9 @@ static int ns16550_serial_setbrg(struct udevice *dev, int baudrate) struct ns16550_plat *plat = com_port->plat; int clock_divisor; + if (plat->skip_init) + return 0; + clock_divisor = ns16550_calc_divisor(com_port, plat->clock, baudrate); ns16550_setbrg(com_port, clock_divisor); @@ -436,11 +439,15 @@ static int ns16550_serial_setbrg(struct udevice *dev, int baudrate) static int ns16550_serial_setconfig(struct udevice *dev, uint serial_config) { struct ns16550 *const com_port = dev_get_priv(dev); + struct ns16550_plat *plat = com_port->plat; int lcr_val = UART_LCR_WLS_8; uint parity = SERIAL_GET_PARITY(serial_config); uint bits = SERIAL_GET_BITS(serial_config); uint stop = SERIAL_GET_STOP(serial_config); + if (plat->skip_init) + return 0; + /* * only parity config is implemented, check if other serial settings * are the default one. @@ -533,7 +540,8 @@ int ns16550_serial_probe(struct udevice *dev) reset_deassert_bulk(&reset_bulk); com_port->plat = dev_get_plat(dev); - ns16550_init(com_port, -1); + if (!plat->skip_init) + ns16550_init(com_port, -1); return 0; } @@ -589,6 +597,8 @@ int ns16550_serial_of_to_plat(struct udevice *dev) if (port_type == PORT_JZ4780) plat->fcr |= UART_FCR_UME; + plat->skip_init = dev_read_bool(dev, "skip-init"); + return 0; } #endif diff --git a/include/ns16550.h b/include/ns16550.h index 7f481300083..787680853c7 100644 --- a/include/ns16550.h +++ b/include/ns16550.h @@ -66,6 +66,7 @@ enum ns16550_flags { * @fcr: Offset of FCR register (normally UART_FCR_DEFVAL) * @flags: A few flags (enum ns16550_flags) * @bdf: PCI slot/function (pci_dev_t) + * @skip_init: Skip UART initialization (preserve existing settings) */ struct ns16550_plat { ulong base; @@ -79,6 +80,7 @@ struct ns16550_plat { #if defined(CONFIG_PCI) && defined(CONFIG_SPL) int bdf; #endif + bool skip_init; }; struct udevice; From patchwork Sun Oct 19 07:23:02 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 626 Return-Path: X-Original-To: u-boot-concept@u-boot.org Delivered-To: u-boot-concept@u-boot.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1760858627; bh=ZldZuoQS/DHhLI4pXVSKClkt6/BoltzSq06gcFTCYNw=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=nvgUeoAWdXpHtZuTe0zoVJaP4Ph9/vVk73eM13syO09gLFprdsomM+CrxhpTWpNbj /e9MQQbakVMJYMfJUsfGD5yOqNcmAOFVy4s7G6y5n9IX4mVUKNi2qATATm8ASYxrJo QJKjofYkISu5ralSUsqszl+ScNQQ18y1dmVDZrYyHfV4G2me7DmWx4p30qin19Px7o ES1/8Fou4SGuuO9HOWVV8FsVDiE7XLQcKhi2oKdtpOJ17/hvmHn00cIAnFd7CL8Mt4 kK0XmWdAwxy4ML7AdVHap8+bKJFhcfG+Tqy3m/y4PWl1QfXI3s0Lgo62vLb2jXkcb0 hvOlNb/kG+T0A== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 5F86F681B1 for ; Sun, 19 Oct 2025 01:23:47 -0600 (MDT) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10024) with ESMTP id mHkCTpDZp9Pw for ; Sun, 19 Oct 2025 01:23:47 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1760858627; bh=ZldZuoQS/DHhLI4pXVSKClkt6/BoltzSq06gcFTCYNw=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=nvgUeoAWdXpHtZuTe0zoVJaP4Ph9/vVk73eM13syO09gLFprdsomM+CrxhpTWpNbj /e9MQQbakVMJYMfJUsfGD5yOqNcmAOFVy4s7G6y5n9IX4mVUKNi2qATATm8ASYxrJo QJKjofYkISu5ralSUsqszl+ScNQQ18y1dmVDZrYyHfV4G2me7DmWx4p30qin19Px7o ES1/8Fou4SGuuO9HOWVV8FsVDiE7XLQcKhi2oKdtpOJ17/hvmHn00cIAnFd7CL8Mt4 kK0XmWdAwxy4ML7AdVHap8+bKJFhcfG+Tqy3m/y4PWl1QfXI3s0Lgo62vLb2jXkcb0 hvOlNb/kG+T0A== Received: from mail.u-boot.org (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 4C1B268198 for ; Sun, 19 Oct 2025 01:23:47 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1760858625; bh=Zk80KOaxlHse9B+IZX67nVGoV3JKY3WZuXxu8Pg23Pc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=r7z9Odg7fBr+dqcX5Ml8/fodtRfibQxIxcolIpiSx+04GrgGP6+i4oVowooTwamnQ Z3ZJnf+EQAM8aHUxh+tysWpW4Mus5ZEOT0ZsNEwStC6Zl4If5ZAyYwlwR/Gu+4aA6G O9dR8/AMPAmYC8o+Cn5JtKeC8ZD1Sus7taL8c86aQ/Dm+vgJFSkvrnc+IixNDlXjL/ XqZQjcO6SFJYl3nEj2XGyOtrp+vTxYQ1pLMAM+UfHNK+RGI3yEdayjtOF9lEA2ef4b +IahFx5hWIzq0yGWtFwV7gWzR4X8MEc1si14kXMACbEf+tKVwYuuClttFIQH9Vy39Y ZTz0vQ5ChdudQ== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 572C46807A; Sun, 19 Oct 2025 01:23:45 -0600 (MDT) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10026) with ESMTP id hsbrf5-ggldC; Sun, 19 Oct 2025 01:23:45 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1760858621; bh=jsFasjvyW+z8ANAiBPpnFUgpe76u12sMSPTeJ7ga/kg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ZtoA/gXkNdA8FyqZ15P54u5xQoTJXn4YX/svnRoxbxZPp+m391DA3CMNxbW3oTh7N sdk/goE6Zuh65Dqv78cKhQGtjuQ5uLMlWNAyXml9aZNK8CYgrGGkKmCo+zKRJylDGx xYUnNZxh8zlHKl7vH1XrF8NLofHi5avFUPqllT76DgpT0rI7J0U0y3EEJfBuxoR5Ic P7y2tlE5jpcGCKYs6gnUY5byq8XQrSntLV3C4L/9MhqR1fmyj32y+GmGL6FbLYLjiZ 3GiU2kH7EEwXl8tet+WMP0RriPNLHIVISDaillUHIBVTbQqRxpk06q0YC3kpYA8nnk UTZI5j+XHxVvw== Received: from u-boot.org (unknown [73.34.74.121]) by mail.u-boot.org (Postfix) with ESMTPSA id D3B9F6810E; Sun, 19 Oct 2025 01:23:40 -0600 (MDT) From: Simon Glass To: U-Boot Concept Date: Sun, 19 Oct 2025 01:23:02 -0600 Message-ID: <20251019072313.3235339-3-sjg@u-boot.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251019072313.3235339-1-sjg@u-boot.org> References: <20251019072313.3235339-1-sjg@u-boot.org> MIME-Version: 1.0 Message-ID-Hash: UWE3J2TW2KH3M7BBDIYXD4TKU5UFD2DZ X-Message-ID-Hash: UWE3J2TW2KH3M7BBDIYXD4TKU5UFD2DZ X-MailFrom: sjg@u-boot.org X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: Simon Glass , Claude X-Mailman-Version: 3.3.10 Precedence: list Subject: [Concept] [PATCH 2/8] lib: Add blake2s support for TKey USS derivation List-Id: Discussion and patches related to U-Boot Concept Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: From: Simon Glass The TKey User-Supplied Secret (USS) feature requires blake2s hashing to derive app-specific secrets. Add blake2s implementation alongside the existing blake2b support. The blake2s implementation is ported from the reference BLAKE2 implementation at https://github.com/BLAKE2/BLAKE2 Co-developed-by: Claude Signed-off-by: Simon Glass --- include/u-boot/blake2.h | 51 +++++++- lib/Makefile | 2 +- lib/blake2/blake2s.c | 282 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 331 insertions(+), 4 deletions(-) create mode 100644 lib/blake2/blake2s.c diff --git a/include/u-boot/blake2.h b/include/u-boot/blake2.h index 4984023a1a2..d4d88744eaf 100644 --- a/include/u-boot/blake2.h +++ b/include/u-boot/blake2.h @@ -19,9 +19,7 @@ * Modifications includes: * * - Remove unsupported compilers like MSC/CPP - * - Remove blake2s/blake2sp/blake2bp - * This blake2 implementation is mostly for btrfs, which only utilizes - * blake2b. + * - Added blake2s for TKey USS support */ #ifndef BLAKE2_H #define BLAKE2_H @@ -91,4 +89,51 @@ /* This is simply an alias for blake2b */ int blake2( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ); + enum blake2s_constant + { + BLAKE2S_BLOCKBYTES = 64, + BLAKE2S_OUTBYTES = 32, + BLAKE2S_KEYBYTES = 32, + BLAKE2S_SALTBYTES = 8, + BLAKE2S_PERSONALBYTES = 8 + }; + + typedef struct blake2s_state__ + { + uint32_t h[8]; + uint32_t t[2]; + uint32_t f[2]; + uint8_t buf[BLAKE2S_BLOCKBYTES]; + size_t buflen; + size_t outlen; + uint8_t last_node; + } blake2s_state; + + BLAKE2_PACKED(struct blake2s_param__ + { + uint8_t digest_length; /* 1 */ + uint8_t key_length; /* 2 */ + uint8_t fanout; /* 3 */ + uint8_t depth; /* 4 */ + uint32_t leaf_length; /* 8 */ + uint32_t node_offset; /* 12 */ + uint16_t xof_length; /* 14 */ + uint8_t node_depth; /* 15 */ + uint8_t inner_length; /* 16 */ + uint8_t salt[BLAKE2S_SALTBYTES]; /* 24 */ + uint8_t personal[BLAKE2S_PERSONALBYTES]; /* 32 */ + }); + + typedef struct blake2s_param__ blake2s_param; + + /* Streaming API */ + int blake2s_init( blake2s_state *S, size_t outlen ); + int blake2s_init_key( blake2s_state *S, size_t outlen, const void *key, size_t keylen ); + int blake2s_init_param( blake2s_state *S, const blake2s_param *P ); + int blake2s_update( blake2s_state *S, const void *in, size_t inlen ); + int blake2s_final( blake2s_state *S, void *out, size_t outlen ); + + /* Simple API */ + int blake2s( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ); + #endif diff --git a/lib/Makefile b/lib/Makefile index fd18002181d..43df5733ffd 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -79,7 +79,7 @@ obj-$(CONFIG_$(PHASE_)ACPI) += acpi/ obj-$(CONFIG_ECDSA) += ecdsa/ obj-$(CONFIG_$(PHASE_)RSA) += rsa/ obj-$(CONFIG_HASH) += hash-checksum.o -obj-$(CONFIG_BLAKE2) += blake2/blake2b.o +obj-$(CONFIG_BLAKE2) += blake2/blake2b.o blake2/blake2s.o obj-$(CONFIG_$(PHASE_)MD5_LEGACY) += md5.o obj-$(CONFIG_$(PHASE_)SHA1_LEGACY) += sha1.o diff --git a/lib/blake2/blake2s.c b/lib/blake2/blake2s.c new file mode 100644 index 00000000000..eebc369fae8 --- /dev/null +++ b/lib/blake2/blake2s.c @@ -0,0 +1,282 @@ +/* SPDX-License-Identifier: CC0-1.0 */ +/* + BLAKE2 reference source code package - reference C implementations + + Copyright 2012, Samuel Neves . You may use this under the + terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at + your option. The terms of these licenses can be found at: + + - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0 + - OpenSSL license : https://www.openssl.org/source/license.html + - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0 + + More information about the BLAKE2 hash function can be found at + https://blake2.net. +*/ + +/* + * Cross-ported from BLAKE2 (https://github.com/BLAKE2/BLAKE2). + * Modifications includes: + * + * - Remove unused features like selftest + * - Use u-boot library functions/macros + */ +#include +#include +#include +#include +#include "blake2-impl.h" + +static const uint32_t blake2s_IV[8] = +{ + 0x6A09E667UL, 0xBB67AE85UL, 0x3C6EF372UL, 0xA54FF53AUL, + 0x510E527FUL, 0x9B05688CUL, 0x1F83D9ABUL, 0x5BE0CD19UL +}; + +static const uint8_t blake2s_sigma[10][16] = +{ + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } , + { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } , + { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 } , + { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 } , + { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 } , + { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } , + { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 } , + { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 } , + { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 } , + { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 } , +}; + +static void blake2s_set_lastnode( blake2s_state *S ) +{ + S->f[1] = (uint32_t)-1; +} + +static int blake2s_is_lastblock( const blake2s_state *S ) +{ + return S->f[0] != 0; +} + +static void blake2s_set_lastblock( blake2s_state *S ) +{ + if( S->last_node ) blake2s_set_lastnode( S ); + + S->f[0] = (uint32_t)-1; +} + +static void blake2s_increment_counter( blake2s_state *S, const uint32_t inc ) +{ + S->t[0] += inc; + S->t[1] += ( S->t[0] < inc ); +} + +static void blake2s_init0( blake2s_state *S ) +{ + size_t i; + memset( S, 0, sizeof( blake2s_state ) ); + + for( i = 0; i < 8; ++i ) S->h[i] = blake2s_IV[i]; +} + +int blake2s_init_param( blake2s_state *S, const blake2s_param *P ) +{ + const unsigned char *p = ( const unsigned char * )( P ); + size_t i; + + blake2s_init0( S ); + + for( i = 0; i < 8; ++i ) + S->h[i] ^= load32( &p[i * 4] ); + + S->outlen = P->digest_length; + return 0; +} + +int blake2s_init( blake2s_state *S, size_t outlen ) +{ + blake2s_param P[1]; + + if ( ( !outlen ) || ( outlen > BLAKE2S_OUTBYTES ) ) return -1; + + P->digest_length = (uint8_t)outlen; + P->key_length = 0; + P->fanout = 1; + P->depth = 1; + store32( &P->leaf_length, 0 ); + store32( &P->node_offset, 0 ); + store16( &P->xof_length, 0 ); + P->node_depth = 0; + P->inner_length = 0; + memset( P->salt, 0, sizeof( P->salt ) ); + memset( P->personal, 0, sizeof( P->personal ) ); + return blake2s_init_param( S, P ); +} + +int blake2s_init_key( blake2s_state *S, size_t outlen, const void *key, size_t keylen ) +{ + blake2s_param P[1]; + + if ( ( !outlen ) || ( outlen > BLAKE2S_OUTBYTES ) ) return -1; + + if ( !key || !keylen || keylen > BLAKE2S_KEYBYTES ) return -1; + + P->digest_length = (uint8_t)outlen; + P->key_length = (uint8_t)keylen; + P->fanout = 1; + P->depth = 1; + store32( &P->leaf_length, 0 ); + store32( &P->node_offset, 0 ); + store16( &P->xof_length, 0 ); + P->node_depth = 0; + P->inner_length = 0; + memset( P->salt, 0, sizeof( P->salt ) ); + memset( P->personal, 0, sizeof( P->personal ) ); + + if( blake2s_init_param( S, P ) < 0 ) return -1; + + { + uint8_t block[BLAKE2S_BLOCKBYTES]; + memset( block, 0, BLAKE2S_BLOCKBYTES ); + memcpy( block, key, keylen ); + blake2s_update( S, block, BLAKE2S_BLOCKBYTES ); + memset( block, 0, BLAKE2S_BLOCKBYTES ); + } + return 0; +} + +#define G(r,i,a,b,c,d) \ + do { \ + a = a + b + m[blake2s_sigma[r][2*i+0]]; \ + d = rotr32(d ^ a, 16); \ + c = c + d; \ + b = rotr32(b ^ c, 12); \ + a = a + b + m[blake2s_sigma[r][2*i+1]]; \ + d = rotr32(d ^ a, 8); \ + c = c + d; \ + b = rotr32(b ^ c, 7); \ + } while(0) + +#define ROUND(r) \ + do { \ + G(r,0,v[ 0],v[ 4],v[ 8],v[12]); \ + G(r,1,v[ 1],v[ 5],v[ 9],v[13]); \ + G(r,2,v[ 2],v[ 6],v[10],v[14]); \ + G(r,3,v[ 3],v[ 7],v[11],v[15]); \ + G(r,4,v[ 0],v[ 5],v[10],v[15]); \ + G(r,5,v[ 1],v[ 6],v[11],v[12]); \ + G(r,6,v[ 2],v[ 7],v[ 8],v[13]); \ + G(r,7,v[ 3],v[ 4],v[ 9],v[14]); \ + } while(0) + +static void blake2s_compress( blake2s_state *S, const uint8_t in[BLAKE2S_BLOCKBYTES] ) +{ + uint32_t m[16]; + uint32_t v[16]; + size_t i; + + for( i = 0; i < 16; ++i ) { + m[i] = load32( in + i * sizeof( m[i] ) ); + } + + for( i = 0; i < 8; ++i ) { + v[i] = S->h[i]; + } + + v[ 8] = blake2s_IV[0]; + v[ 9] = blake2s_IV[1]; + v[10] = blake2s_IV[2]; + v[11] = blake2s_IV[3]; + v[12] = S->t[0] ^ blake2s_IV[4]; + v[13] = S->t[1] ^ blake2s_IV[5]; + v[14] = S->f[0] ^ blake2s_IV[6]; + v[15] = S->f[1] ^ blake2s_IV[7]; + + ROUND( 0 ); + ROUND( 1 ); + ROUND( 2 ); + ROUND( 3 ); + ROUND( 4 ); + ROUND( 5 ); + ROUND( 6 ); + ROUND( 7 ); + ROUND( 8 ); + ROUND( 9 ); + + for( i = 0; i < 8; ++i ) { + S->h[i] = S->h[i] ^ v[i] ^ v[i + 8]; + } +} + +#undef G +#undef ROUND + +int blake2s_update( blake2s_state *S, const void *pin, size_t inlen ) +{ + const unsigned char * in = (const unsigned char *)pin; + if( inlen > 0 ) + { + size_t left = S->buflen; + size_t fill = BLAKE2S_BLOCKBYTES - left; + if( inlen > fill ) + { + S->buflen = 0; + memcpy( S->buf + left, in, fill ); + blake2s_increment_counter( S, BLAKE2S_BLOCKBYTES ); + blake2s_compress( S, S->buf ); + in += fill; inlen -= fill; + while(inlen > BLAKE2S_BLOCKBYTES) { + blake2s_increment_counter(S, BLAKE2S_BLOCKBYTES); + blake2s_compress( S, in ); + in += BLAKE2S_BLOCKBYTES; + inlen -= BLAKE2S_BLOCKBYTES; + } + } + memcpy( S->buf + S->buflen, in, inlen ); + S->buflen += inlen; + } + return 0; +} + +int blake2s_final( blake2s_state *S, void *out, size_t outlen ) +{ + uint8_t buffer[BLAKE2S_OUTBYTES] = {0}; + size_t i; + + if( out == NULL || outlen < S->outlen ) + return -1; + + if( blake2s_is_lastblock( S ) ) + return -1; + + blake2s_increment_counter( S, ( uint32_t )S->buflen ); + blake2s_set_lastblock( S ); + memset( S->buf + S->buflen, 0, BLAKE2S_BLOCKBYTES - S->buflen ); + blake2s_compress( S, S->buf ); + + for( i = 0; i < 8; ++i ) + store32( buffer + sizeof( S->h[i] ) * i, S->h[i] ); + + memcpy( out, buffer, S->outlen ); + memset( buffer, 0, sizeof( buffer ) ); + return 0; +} + +int blake2s( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ) +{ + blake2s_state S[1]; + + if ( ( ( !key ) || ( !keylen ) ) && ( keylen > 0 ) ) return -1; + + if( keylen > 0 ) + { + if( blake2s_init_key( S, outlen, key, keylen ) < 0 ) return -1; + } + else + { + if( blake2s_init( S, outlen ) < 0 ) return -1; + } + + blake2s_update( S, ( const uint8_t * )in, inlen ); + blake2s_final( S, out, outlen ); + return 0; +} From patchwork Sun Oct 19 07:23:03 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 627 Return-Path: X-Original-To: u-boot-concept@u-boot.org Delivered-To: u-boot-concept@u-boot.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1760858629; bh=6Aw8gl03h+ZkrcoyNt14Dx4x0FMnFw5/8+cwH7bOETM=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=SLNjKcixmE+v5MMI3VjFaogW08q/D5TNvUdUov1KfB5+M18kshbSMrmnT30oYiDDu 9KZ1/9WuxJRzTnSjpN5Z5dB3kCgWRTpy03DgCNxzVWR3VhVibOF1UvFHpWiyeEUbuQ jj3u/522ZQOjudovHfpDElYMB5++S5K8605ZYktrED1QRrOBNV/CZBOH/swZc5oaaN CDMmYAqwJZRFxk7zWj+W8PG+T8z7PmbZZ4y/9DOWR86PvnakZ6RdpoeXqV5m70w6XE XjegwxFp7BdTQ4jPRkBtaNp5oIhyG1BAJK/ibcZplvwYAYkLeOwdIA/5LEAdIS2Zgl inGwYcBRjla+Q== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id BB62E681BB for ; Sun, 19 Oct 2025 01:23:49 -0600 (MDT) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10024) with ESMTP id 9GgFrrnTxKcT for ; Sun, 19 Oct 2025 01:23:49 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1760858628; bh=6Aw8gl03h+ZkrcoyNt14Dx4x0FMnFw5/8+cwH7bOETM=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=QhMMX6gtc58vbJ8DWjaVZ0BCqIG9kk5/OgPNPvPo70hbjdAx9Q152bTc64FrPC57c 8YPT3PeSHutrKv6Jp0WAC1/Vq4s4YxxurcTltSBHI8PguMmpgmPwUXSuBDbTqrTNFG dmZ+kjVAkm06w/ta8icfKAvB37HWQsvyt9id7tnbKL5ghM0MHro12aoJnPPVQ95G6y QQWEqoHKx7DNToV/9Lh87us/64m9tR8L4X/Rhxp+Bl9tIApy3/D8YcXRnY/WnL3F4N sgkqo6MDc+ylFDil+NifW8nzduGGnRZpsaMYzuEz2k4q95LF9zs5nSmj5hHgfe5gVN qc6NLWlM4Zw4w== Received: from mail.u-boot.org (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id AF88B68168 for ; Sun, 19 Oct 2025 01:23:48 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1760858627; bh=F00ZRlb77qpx8v9IFomSbxCXzaf09022FziAi4whKHg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=odv2hZB3ltsml3/3kGC7fvjAxMo7zte5+Z2QHzmzHN7nl0BQZ6W2nlOwQV5j5CMtY 0C2r6dC+nCVAdrhuXYETTitU1XQ5OICu2NhdyWl42YvgVfR7cNXuFgolCWQxWOSZ8N RXl+Rx16HMbQlxI47r88I3SyfACkIENnIVOKsBw+P6SUxZOdL1v5ugT+kG4TBjwfME kGDUdluBr57oqNc0rN57qDTyXtsOKcwgpDpLkNen2SE/T7ERHUCOQUtGigIS1DL5/N u16rhReH/FgX812SFoqTGh0HNPoKg7fJC5HuQ5lKIrV/GrJ3fGTgCZCmHojmqB03l4 sSA9ja1bYOjQA== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 798F56807A; Sun, 19 Oct 2025 01:23:47 -0600 (MDT) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10026) with ESMTP id 8EEbz1T7qLIb; Sun, 19 Oct 2025 01:23:47 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1760858625; bh=XWB1YN/Jl5WNidZgNL5nZmTaAdiHqsmv9V+o17F6NjM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=I4TozPJ7RxMgpKnRUDcWMdI+emxxGcdi3oUOGbAKO8GbDMWmTvakKh1LccYnTeNDy ++WCngo7+i20v+DUXglUhuDcZLiNS4WRrmZj+p+PTXBGi/SIiLbfR+k7WI64fZfMq2 vjd/ZqYnxTKp6uu3XYhDf+k/r8WozbzvhdcDzEKuL5ak12YGrRHMi0PbaMOu32YctM wb0yfIgAg41ziMOG4s8qZZcxmjy2gV5bbVLoiiHwnpXgwoaZcdDuBANGz4x0VlW3Iv VE67m9jjzmAwvbly7r2DcOwP2Z+8c3xocXmUj77jePlx7yzJBIF5MIMBwctka3RmQJ 46u8sUuhCS5mw== Received: from u-boot.org (unknown [73.34.74.121]) by mail.u-boot.org (Postfix) with ESMTPSA id 9ABE26810E; Sun, 19 Oct 2025 01:23:45 -0600 (MDT) From: Simon Glass To: U-Boot Concept Date: Sun, 19 Oct 2025 01:23:03 -0600 Message-ID: <20251019072313.3235339-4-sjg@u-boot.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251019072313.3235339-1-sjg@u-boot.org> References: <20251019072313.3235339-1-sjg@u-boot.org> MIME-Version: 1.0 Message-ID-Hash: PH3A2LUSZX2ALSRMQ26OYH4VQ4CBKZHD X-Message-ID-Hash: PH3A2LUSZX2ALSRMQ26OYH4VQ4CBKZHD X-MailFrom: sjg@u-boot.org X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: Simon Glass , Claude X-Mailman-Version: 3.3.10 Precedence: list Subject: [Concept] [PATCH 3/8] tkey: Provide a uclass for the Tillitis TKey List-Id: Discussion and patches related to U-Boot Concept Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: From: Simon Glass The TKey is a USB device which can run ephemeral firmware and perform cyrptographic operations. Add a uclass for the communication layer. Co-developed-by: Claude Signed-off-by: Simon Glass --- drivers/misc/Kconfig | 11 + drivers/misc/Makefile | 1 + drivers/misc/tkey-uclass.c | 741 +++++++++++++++++++++++++++++++++++++ include/dm/uclass-id.h | 1 + include/tkey.h | 227 ++++++++++++ 5 files changed, 981 insertions(+) create mode 100644 drivers/misc/tkey-uclass.c create mode 100644 include/tkey.h diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 9559b2c56d5..a352fa5fee0 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -33,6 +33,17 @@ config TPL_MISC set of generic read, write and ioctl methods may be used to access the device. +config TKEY + bool "TKey security token support" + depends on DM + default y if SANDBOX + select BLAKE2 + help + Enable driver model support for Tillitis TKey security tokens. + This provides a common interface for TKey operations including + reading device information, getting the unique device identifier + (UDI), and communicating with the device. + config VPL_MISC bool "Enable Driver Model for Misc drivers in VPL" depends on VPL_DM diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index fd45491551a..23fd8f8ef3b 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_$(PHASE_)MISC) += misc-uclass.o obj-$(CONFIG_$(PHASE_)NVMEM) += nvmem.o +obj-$(CONFIG_TKEY) += tkey-uclass.o obj-$(CONFIG_$(PHASE_)CROS_EC) += cros_ec.o obj-$(CONFIG_$(PHASE_)CROS_EC_SANDBOX) += cros_ec_sandbox.o diff --git a/drivers/misc/tkey-uclass.c b/drivers/misc/tkey-uclass.c new file mode 100644 index 00000000000..4696f9c8d83 --- /dev/null +++ b/drivers/misc/tkey-uclass.c @@ -0,0 +1,741 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2025 Canonical Ltd + * + * Tillitis TKey security token uclass + */ + +#define LOG_CATEGORY UCLASS_TKEY + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* TKey Protocol Constants */ +#define TKEY_FRAME_HEADER_SIZE 1 +#define TKEY_MAX_DATA_SIZE 128 +#define TKEY_MAX_FRAME_SIZE (TKEY_FRAME_HEADER_SIZE + \ + TKEY_MAX_DATA_SIZE) + +/* Frame Header Bits */ +#define TKEY_FRAME_ID_MASK 0x60 +#define TKEY_FRAME_ENDPOINT_MASK 0x18 +#define TKEY_FRAME_STATUS_MASK 0x04 +#define TKEY_FRAME_LEN_MASK 0x03 + +/* Frame ID Values */ +#define TKEY_FRAME_ID_CMD 0 +#define TKEY_FRAME_ID_RSP 1 + +/* Endpoint Values */ +#define TKEY_ENDPOINT_FIRMWARE 2 +#define TKEY_ENDPOINT_APP 3 + +/* Data Length Values */ +#define TKEY_LEN_1_BYTE 0 +#define TKEY_LEN_4_BYTES 1 +#define TKEY_LEN_32_BYTES 2 +#define TKEY_LEN_128_BYTES 3 + +/* Status Values */ +#define TKEY_STATUS_OK 0 +#define TKEY_STATUS_ERROR 0x04 + +/* Firmware Commands */ +#define TKEY_FW_CMD_NAME_VERSION 0x01 +#define TKEY_FW_CMD_LOAD_APP 0x03 +#define TKEY_FW_CMD_LOAD_APP_DATA 0x05 +#define TKEY_FW_CMD_GET_UDI 0x08 + +/* Signer App Commands */ +#define TKEY_APP_CMD_GET_PUBKEY 0x01 +#define TKEY_APP_RSP_GET_PUBKEY 0x02 + +/* Constants */ +#define TKEY_USS_SIZE 32 +#define TKEY_PUBKEY_SIZE 32 + +/* Timeouts (ms) */ +#define TKEY_TIMEOUT_MS 1000 +#define TKEY_LOAD_TIMEOUT_MS 2000 + +/* TKey frame structure */ +struct tkey_frame { + u8 header; + u8 data[TKEY_MAX_DATA_SIZE]; +}; + +/** + * make_hdr() - Build a TKey frame header byte + * + * Constructs a TKey protocol frame header by encoding the frame ID, endpoint, + * status, and length code into a single byte according to the TKey protocol + * specification. + * + * Frame header format (8 bits): + * Bit 7: Reserved (always 0) + * Bits 6-5: Frame ID (0=CMD, 1=RSP, 2-3=reserved) + * Bits 4-3: Endpoint (0-1=reserved, 2=Firmware, 3=App) + * Bit 2: Status (0=OK, 1=Error) + * Bits 1-0: Length code (0=1 byte, 1=4 bytes, 2=32 bytes, 3=128 bytes) + * + * @id: Frame ID (TKEY_FRAME_ID_CMD=0 or TKEY_FRAME_ID_RSP=1) + * @endpoint: Target endpoint (TKEY_ENDPOINT_FIRMWARE=2 or TKEY_ENDPOINT_APP=3) + * @status: Status flag (TKEY_STATUS_OK=0 or TKEY_STATUS_ERROR=1) + * @len: Length code (TKEY_LEN_1_BYTE=0, TKEY_LEN_4_BYTES=1, + * TKEY_LEN_32_BYTES=2, TKEY_LEN_128_BYTES=3) + * Return: 8-bit frame header value + */ +static uint make_hdr(uint id, uint endpoint, uint status, uint len) +{ + return ((id & 0x3) << 5) | ((endpoint & 0x3) << 3) | + ((status & 0x1) << 2) | (len & 0x3); +} + +static int tkey_send_frame(struct udevice *dev, + const struct tkey_frame *frame, int len) +{ + u8 buffer[TKEY_MAX_FRAME_SIZE]; + int total_len = TKEY_FRAME_HEADER_SIZE + len; + int ret; + + log_debug("Sending frame - header=%02x, len=%x\n", frame->header, len); + + /* Build frame */ + buffer[0] = frame->header; + if (len > 0) + memcpy(&buffer[1], frame->data, len); + + /* Send via generic write */ + ret = tkey_write(dev, buffer, total_len); + if (ret < 0) { + log_debug("Frame send failed\n"); + return ret; + } + log_debug("Frame sent successfully\n"); + + return total_len; +} + +static int tkey_recv_frame(struct udevice *dev, struct tkey_frame *frame, + int timeout_ms) +{ + const struct tkey_ops *ops; + int len, ret; + u8 buf[256]; + + log_debug("Receiving frame...\n"); + ops = tkey_get_ops(dev); + + /* Try read_all first for USB devices that send raw responses */ + if (ops->read_all) { + log_debug("Using read_all for USB raw response reception\n"); + ret = tkey_read_all(dev, buf, sizeof(buf), timeout_ms); + if (ret < 0) { + log_debug("Read_all failed: %d\n", ret); + return ret; + } + if (ret < 1) { + log_debug("Read_all got no data\n"); + return -EIO; + } + log_debug("USB raw response: %x bytes received\n", ret); + + /* + * USB TKey sends raw responses, not framed responses. Create a + * synthetic frame with a success header + */ + frame->header = make_hdr(TKEY_FRAME_ID_RSP, + TKEY_ENDPOINT_FIRMWARE, + TKEY_STATUS_OK, TKEY_LEN_128_BYTES); + + /* Copy the raw response data */ + len = 0; + if (ret > 0) { + len = min(ret, (int)TKEY_MAX_DATA_SIZE); + memcpy(frame->data, buf, len); + } + + log_debug("USB raw response converted to frame: header=%02x, " + "data_len=%x\n", frame->header, len); + return TKEY_FRAME_HEADER_SIZE + len; + } + + /* Fallback to byte-by-byte reading for serial devices */ + log_debug("Using byte-by-byte frame reception\n"); + + /* Read header first */ + ret = tkey_read(dev, &frame->header, 1, timeout_ms); + if (ret != 1) { + log_debug("Header read failed: got %x bytes\n", ret); + return (ret < 0) ? ret : -EIO; + } + + log_debug("Received header: %02x\n", frame->header); + + /* Decode data length from header */ + switch (frame->header & TKEY_FRAME_LEN_MASK) { + case TKEY_LEN_1_BYTE: + len = 1; + break; + case TKEY_LEN_4_BYTES: + len = 4; + break; + case TKEY_LEN_32_BYTES: + len = 32; + break; + case TKEY_LEN_128_BYTES: + len = 128; + break; + default: + log_debug("Invalid length code: %02x\n", + frame->header & TKEY_FRAME_LEN_MASK); + return -EINVAL; + } + + log_debug("Expected data length: %x bytes\n", len); + + /* Read data bytes if any */ + if (len > 0) { + ret = tkey_read(dev, frame->data, len, timeout_ms); + if (ret != len) { + log_debug("Data read failed: expected %x, got %x " + "bytes\n", len, ret); + return (ret < 0) ? ret : -EIO; + } + } + + log_debug("got frame: %x total bytes\n", TKEY_FRAME_HEADER_SIZE + len); + + return TKEY_FRAME_HEADER_SIZE + len; +} + +int tkey_read(struct udevice *dev, void *buf, int len, int timeout_ms) +{ + const struct tkey_ops *ops = tkey_get_ops(dev); + + return ops->read(dev, buf, len, timeout_ms); +} + +int tkey_write(struct udevice *dev, const void *buf, int len) +{ + const struct tkey_ops *ops = tkey_get_ops(dev); + + return ops->write(dev, buf, len); +} + +int tkey_read_all(struct udevice *dev, void *buf, int maxlen, int timeout_ms) +{ + const struct tkey_ops *ops = tkey_get_ops(dev); + + /* Use read_all if available, otherwise fall back to regular read */ + if (ops->read_all) + return ops->read_all(dev, buf, maxlen, timeout_ms); + + return ops->read(dev, buf, maxlen, timeout_ms); +} + +int tkey_get_udi(struct udevice *dev, void *udi) +{ + struct tkey_frame cmd_frame, rsp_frame; + int ret; + + /* Build command frame */ + cmd_frame.header = make_hdr(TKEY_FRAME_ID_CMD, TKEY_ENDPOINT_FIRMWARE, + 0, TKEY_LEN_1_BYTE); + cmd_frame.data[0] = TKEY_FW_CMD_GET_UDI; + + /* Send command */ + ret = tkey_send_frame(dev, &cmd_frame, 1); + if (ret < 0) + return ret; + + /* Receive response */ + ret = tkey_recv_frame(dev, &rsp_frame, TKEY_TIMEOUT_MS); + if (ret < 0) + return ret; + + /* Check response status */ + if (rsp_frame.header & TKEY_FRAME_STATUS_MASK) { + /* GetUDI is a firmware command - check if we're in app mode */ + char name0[TKEY_NAME_SIZE], name1[TKEY_NAME_SIZE]; + u32 version; + + if (!tkey_get_name_version(dev, name0, name1, &version)) { + if (!strcmp(name0, "tk1 ") && !strcmp(name1, "sign")) { + log_debug("GetUDI failed - device is in app mode, UDI only available in firmware mode\n"); + return -ENOTSUPP; + } + } + + log_debug("GetUDI failed with error status, error code=%02x\n", + ret > 1 ? rsp_frame.data[0] : 0); + return -EIO; + } + + /* Extract UDI */ + if (ret >= (TKEY_FRAME_HEADER_SIZE + TKEY_UDI_SIZE)) { + /* + * For USB responses, check if we have the expected response + * pattern. USB TKey UDI responses have format: [padding...] + * [0x52] [0x09] [status] [UDI...] + */ + int ofs = -1; + + /* Look for the USB response pattern 0x52 0x09 */ + for (int i = 0; i < ret - TKEY_UDI_SIZE - 3; i++) { + if (rsp_frame.data[i] == 0x52 && + rsp_frame.data[i + 1] == 0x09) { + ofs = i; + break; + } + } + + if (ofs >= 0) { + /* USB format: UDI starts after 0x52 0x09 status */ + memcpy(udi, &rsp_frame.data[ofs + 3], TKEY_UDI_SIZE); + } else { + /* Standard format: UDI starts at offset 0 */ + memcpy(udi, rsp_frame.data, TKEY_UDI_SIZE); + } + return 0; + } + + return -EINVAL; +} + +int tkey_get_name_version(struct udevice *dev, char name0[TKEY_NAME_SIZE], + char name1[TKEY_NAME_SIZE], u32 *version) +{ + struct tkey_frame cmd_frame, rsp_frame; + int ret; + + /* Build command frame */ + cmd_frame.header = make_hdr(TKEY_FRAME_ID_CMD, TKEY_ENDPOINT_FIRMWARE, + 0, TKEY_LEN_1_BYTE); + cmd_frame.data[0] = TKEY_FW_CMD_NAME_VERSION; + + /* Send command */ + ret = tkey_send_frame(dev, &cmd_frame, 1); + if (ret < 0) + return ret; + + /* Receive response */ + ret = tkey_recv_frame(dev, &rsp_frame, TKEY_TIMEOUT_MS); + if (ret < 0) + return ret; + + /* Check response status and handle different modes */ + if (rsp_frame.header & TKEY_FRAME_STATUS_MASK) { + /* + * Error status set - could be app mode responding to + * firmware command + */ + log_debug("GetNameVersion status bit set, header=%02x, " + "error code=%02x\n", rsp_frame.header, + ret > 1 ? rsp_frame.data[0] : 0); + + /* + * In app mode, TKey responds with error status to firmware + * commands. Try to decode as app mode response + */ + if (ret >= 1 && rsp_frame.data[0] == 0x00) { + /* App mode: return standard app identifiers */ + strcpy(name0, "tk1 "); + strcpy(name1, "sign"); + *version = 1; /* Default app version */ + log_debug("Detected app mode response, using default " + "app identifiers\n"); + return 0; + } + return -EIO; + } + + /* Parse response data */ + if (ret >= 13) { /* Header + 4 + 4 + 4 bytes */ + /* + * For USB responses, check if we have the expected response + * pattern. USB TKey responses have format: [padding...] [0x52] + * [0x02] [tk1 ] [mkdf] [version] + */ + int ofs = -1; + + /* Look for the USB response pattern 0x52 0x02 */ + for (int i = 0; i < ret - 13; i++) { + if (rsp_frame.data[i] == 0x52 && + rsp_frame.data[i + 1] == 0x02) { + ofs = i; + break; + } + } + + if (ofs >= 0) { + /* USB format: found pattern at offset */ + memcpy(name0, &rsp_frame.data[ofs + 2], 4); + name0[4] = '\0'; + memcpy(name1, &rsp_frame.data[ofs + 6], 4); + name1[4] = '\0'; + *version = + get_unaligned_le32(&rsp_frame.data[ofs + 10]); + } else { + /* + * Standard format: skip the first byte (command + * response code) + */ + memcpy(name0, &rsp_frame.data[1], 4); + name0[4] = '\0'; + memcpy(name1, &rsp_frame.data[5], 4); + name1[4] = '\0'; + *version = get_unaligned_le32(&rsp_frame.data[9]); + } + } + + return 0; +} + +int tkey_in_app_mode(struct udevice *dev) +{ + char name0[TKEY_NAME_SIZE], name1[TKEY_NAME_SIZE]; + u32 version; + int ret; + + ret = tkey_get_name_version(dev, name0, name1, &version); + if (ret) + return ret; + + /* Check if in firmware mode */ + if (!strcmp(name0, "tk1 ") && !strcmp(name1, "mkdf")) + return 0; /* Firmware mode */ + + /* Check if in app mode */ + if (!strcmp(name0, "tk1 ") && !strcmp(name1, "sign")) + return 1; /* App mode */ + + /* Unknown mode */ + return -EINVAL; +} + +static int tkey_load_app_header(struct udevice *dev, int app_size, + const void *uss, int uss_size) +{ + struct tkey_frame cmd_frame, rsp_frame; + int ret; + + log_debug("Loading app header, size=%u\n", app_size); + + /* + * Build LOAD_APP command frame with app size (128-byte frame like + * Go app) + */ + cmd_frame.header = make_hdr(TKEY_FRAME_ID_CMD, TKEY_ENDPOINT_FIRMWARE, + TKEY_STATUS_OK, TKEY_LEN_128_BYTES); + cmd_frame.data[0] = TKEY_FW_CMD_LOAD_APP; + /* Pack app size as little-endian 32-bit */ + cmd_frame.data[1] = app_size & 0xff; + cmd_frame.data[2] = (app_size >> 8) & 0xff; + cmd_frame.data[3] = (app_size >> 16) & 0xff; + cmd_frame.data[4] = (app_size >> 24) & 0xff; + + /* Include USS if provided */ + if (uss && uss_size > 0) { + blake2s_state state; + u8 uss_hash[32]; + + /* Hash the USS using BLAKE2s to get 32 bytes */ + ret = blake2s_init(&state, 32); + if (ret) { + log_debug("Failed to init BLAKE2s\n"); + return ret; + } + + ret = blake2s_update(&state, uss, uss_size); + if (ret) { + log_debug("Failed to update BLAKE2s\n"); + return ret; + } + + ret = blake2s_final(&state, uss_hash, 32); + if (ret) { + log_debug("Failed to finalize BLAKE2s\n"); + return ret; + } + + /* USS present flag */ + cmd_frame.data[5] = 1; + /* Copy USS hash (32 bytes) */ + memcpy(&cmd_frame.data[6], uss_hash, 32); + /* Pad remaining bytes with zeros */ + memset(&cmd_frame.data[38], '\0', 128 - 38); + + log_debug("USS hash included in app header\n"); + } else { + /* No USS - set flag to 0 and pad with zeros */ + memset(&cmd_frame.data[5], '\0', 128 - 5); + } + + /* Send command */ + ret = tkey_send_frame(dev, &cmd_frame, 128); + if (ret < 0) + return ret; + + /* Receive response */ + ret = tkey_recv_frame(dev, &rsp_frame, TKEY_LOAD_TIMEOUT_MS); + if (ret < 0) + return ret; + + /* Check response status */ + if (rsp_frame.header & TKEY_STATUS_ERROR) { + log_debug("Load app header failed with error status\n"); + return -EIO; + } + + log_debug("App header loaded successfully\n"); + + return 0; +} + +static int tkey_load_app_data(struct udevice *dev, const void *data, int size) +{ + struct tkey_frame cmd_frame, rsp_frame; + int offset = 0; + int ret; + + log_debug("Loading app data, %u bytes\n", size); + + while (offset < size) { + int todo = min(size - offset, TKEY_MAX_DATA_SIZE - 1); + u8 len_code; + + /* Determine length code for chunk */ + if (todo <= 1) + len_code = TKEY_LEN_1_BYTE; + else if (todo <= 4) + len_code = TKEY_LEN_4_BYTES; + else if (todo <= 32) + len_code = TKEY_LEN_32_BYTES; + else + len_code = TKEY_LEN_128_BYTES; + + /* + * Build LOAD_APP_DATA command (always use 128-byte frames + * like Go app) + */ + cmd_frame.header = make_hdr(TKEY_FRAME_ID_CMD, + TKEY_ENDPOINT_FIRMWARE, + TKEY_STATUS_OK, + TKEY_LEN_128_BYTES); + cmd_frame.data[0] = TKEY_FW_CMD_LOAD_APP_DATA; + memcpy(&cmd_frame.data[1], data + offset, todo); + + /* Pad remaining bytes with zeros */ + if (todo + 1 < 128) + memset(&cmd_frame.data[todo + 1], '\0', + 128 - (todo + 1)); + + /* Send chunk (always 128 bytes like Go app) */ + ret = tkey_send_frame(dev, &cmd_frame, 128); + if (ret < 0) + return ret; + + /* Receive response */ + ret = tkey_recv_frame(dev, &rsp_frame, TKEY_LOAD_TIMEOUT_MS); + if (ret < 0) + return ret; + + /* Check response status */ + if (rsp_frame.header & TKEY_STATUS_ERROR) { + log_debug("Load app data failed at offset %u\n", + offset); + return -EIO; + } + + offset += todo; + log_debug("Loaded chunk: %u/%u bytes\n", offset, size); + schedule(); + } + + log_debug("App data loaded successfully\n"); + + return 0; +} + +int tkey_load_app_with_uss(struct udevice *dev, const void *app_data, + int app_size, const void *uss, int uss_size) +{ + int ret; + + /* Check if we're in firmware mode first */ + ret = tkey_in_app_mode(dev); + if (ret < 0) { + log_debug("Failed to check device mode (error %d)\n", ret); + return ret; + } + + if (ret) { + log_debug("Device must be in firmware mode to load app\n"); + return -ENOTSUPP; + } + + log_debug("Loading app (%u bytes)...\n", app_size); + + /* Send app header with size and USS (if provided) */ + ret = tkey_load_app_header(dev, app_size, uss, uss_size); + if (ret) { + log_debug("Failed to send app header (error %d)\n", ret); + return ret; + } + + /* Send app data */ + ret = tkey_load_app_data(dev, app_data, app_size); + if (ret) { + log_debug("Failed to send app data (error %d)\n", ret); + return ret; + } + + log_debug("App loaded successfully\n"); + + return 0; +} + +int tkey_load_app(struct udevice *dev, const void *app_data, int app_size) +{ + return tkey_load_app_with_uss(dev, app_data, app_size, NULL, 0); +} + +int tkey_get_pubkey(struct udevice *dev, void *pubkey) +{ + struct tkey_frame cmd_frame, rsp_frame; + int ret; + + /* Build GET_PUBKEY command frame */ + cmd_frame.header = make_hdr(TKEY_FRAME_ID_CMD, TKEY_ENDPOINT_APP, + TKEY_STATUS_OK, TKEY_LEN_1_BYTE); + cmd_frame.data[0] = TKEY_APP_CMD_GET_PUBKEY; + + log_debug("Getting public key from signer app\n"); + + /* Send command */ + ret = tkey_send_frame(dev, &cmd_frame, 1); + if (ret < 0) + return ret; + + /* Receive response */ + ret = tkey_recv_frame(dev, &rsp_frame, TKEY_TIMEOUT_MS); + if (ret < 0) + return ret; + + /* Check response status */ + if (rsp_frame.header & TKEY_FRAME_STATUS_MASK) { + log_debug("GetPubkey failed with error status\n"); + return -EIO; + } + + /* Extract public key (32 bytes) from response */ + if (ret >= TKEY_FRAME_HEADER_SIZE + TKEY_PUBKEY_SIZE) { + memcpy(pubkey, rsp_frame.data, TKEY_PUBKEY_SIZE); + log_debug("Public key retrieved successfully\n"); + return 0; + } + log_debug("GetPubkey response too short: %d bytes\n", ret); + + return -EINVAL; +} + +int tkey_derive_disk_key(struct udevice *dev, const void *app_data, + int app_size, const void *uss, int uss_size, + void *disk_key, void *pubkey, void *key_hash) +{ + int ret; + + /* Load the signer app with USS */ + log_debug("Loading signer app with USS for disk key derivation\n"); + ret = tkey_load_app_with_uss(dev, app_data, app_size, uss, + uss_size); + if (ret == -ENOTSUPP) { + /* Already in app mode - continue */ + log_debug("App already loaded, retrieving key\n"); + } else if (ret) { + log_debug("Failed to load app (error %d)\n", ret); + return ret; + } + + /* Get public key from signer */ + ret = tkey_get_pubkey(dev, pubkey); + if (ret) { + log_debug("Failed to get public key (error %d)\n", ret); + return ret; + } + + log_debug("Public key retrieved\n"); + + /* Derive disk encryption key from public key using BLAKE2b */ + ret = blake2b(disk_key, 32, pubkey, 32, NULL, 0); + if (ret) { + log_debug("Failed to derive disk key (error %d)\n", ret); + return ret; + } + + log_debug("Disk encryption key derived\n"); + + /* Generate verification hash if requested */ + if (key_hash) { + ret = blake2b(key_hash, 32, disk_key, 32, NULL, 0); + if (ret) { + log_debug("Failed to generate verification hash " + "(error %d)\n", ret); + return ret; + } + log_debug("Verification hash generated\n"); + } + + return 0; +} + +int tkey_derive_wrapping_key(struct udevice *dev, const char *password, + void *wrapping_key) +{ + u8 udi[TKEY_UDI_SIZE]; + blake2b_state state; + int ret; + + /* Get UDI from device (only available in firmware mode) */ + ret = tkey_get_udi(dev, udi); + if (ret) { + log_debug("Failed to get UDI (error %d)\n", ret); + return ret; + } + + /* Derive wrapping key using BLAKE2b(UDI || password) */ + ret = blake2b_init(&state, TKEY_WRAPPING_KEY_SIZE); + if (ret) + return ret; + + ret = blake2b_update(&state, udi, TKEY_UDI_SIZE); + if (ret) + return ret; + + ret = blake2b_update(&state, password, strlen(password)); + if (ret) + return ret; + + ret = blake2b_final(&state, wrapping_key, TKEY_WRAPPING_KEY_SIZE); + if (ret) + return ret; + + log_debug("Wrapping key derived from password and UDI\n"); + + return 0; +} + +UCLASS_DRIVER(tkey) = { + .id = UCLASS_TKEY, + .name = "tkey", +}; diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index 6bc2d440f96..7c553c0bd3b 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -149,6 +149,7 @@ enum uclass_id { UCLASS_SYSINFO, /* Device information from hardware */ UCLASS_SYSRESET, /* System reset device */ UCLASS_TCPM, /* TypeC port manager */ + UCLASS_TKEY, /* Tillitis TKey security token */ UCLASS_TEE, /* Trusted Execution Environment device */ UCLASS_THERMAL, /* Thermal sensor */ UCLASS_TIMER, /* Timer device */ diff --git a/include/tkey.h b/include/tkey.h new file mode 100644 index 00000000000..8f4f4c7e512 --- /dev/null +++ b/include/tkey.h @@ -0,0 +1,227 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2025 Canonical Ltd + * + * Tillitis TKey security-token uclass interface + */ + +#ifndef _TKEY_UCLASS_H +#define _TKEY_UCLASS_H + +#include + +struct tkey_frame; +struct udevice; + +/* TKey constants */ +#define TKEY_NAME_SIZE 5 +#define TKEY_CDI_SIZE 32 +#define TKEY_UDI_SIZE 8 +#define TKEY_WRAPPING_KEY_SIZE 32 +#define TKEY_USS_MAX_SIZE 32 +#define TKEY_PUBKEY_SIZE 32 +#define TKEY_DISK_KEY_SIZE 32 +#define TKEY_HASH_SIZE 32 + +/** + * struct tkey_ops - The functions that a TKey driver must implement. + * + * @read: Read data from TKey device + * @write: Write data to TKey device + * @read_all: Read all available data from TKey device (optional) + */ +struct tkey_ops { + /** + * read() - Read data from TKey device + * + * @dev: TKey device + * @buf: Buffer to store read data + * @len: Maximum number of bytes to read + * @timeout_ms: Timeout in milliseconds + * + * Returns: Number of bytes read on success, -ve error on failure + */ + int (*read)(struct udevice *dev, void *buf, int len, int timeout_ms); + + /** + * write() - Write data to TKey device + * + * @dev: TKey device + * @buf: Buffer containing data to write + * @len: Number of bytes to write + * + * Returns: Number of bytes written on success, -ve error on failure + */ + int (*write)(struct udevice *dev, const void *buf, int len); + + /** + * read_all() - Read all available data from TKey device (optional) + * + * @dev: TKey device + * @buf: Buffer to store read data + * @maxlen: Maximum number of bytes to read + * @timeout_ms: Timeout in milliseconds + * + * This method reads all available data in one operation, which is + * more suitable for USB devices that send complete frames. + * + * Returns: Number of bytes read on success, -ve error on failure + */ + int (*read_all)(struct udevice *dev, void *buf, int maxlen, + int timeout_ms); +}; + +#define tkey_get_ops(dev) ((struct tkey_ops *)(dev)->driver->ops) + +/** + * tkey_read() - Read data from TKey device + * + * @dev: TKey device + * @buf: Buffer to store read data + * @len: Maximum number of bytes to read + * @timeout_ms: Timeout in milliseconds + * Return: Number of bytes read on success, -ve error on failure + */ +int tkey_read(struct udevice *dev, void *buf, int len, int timeout_ms); + +/** + * tkey_write() - Write data to TKey device + * + * @dev: TKey device + * @buf: Buffer containing data to write + * @len: Number of bytes to write + * Return: Number of bytes written on success, -ve error on failure + */ +int tkey_write(struct udevice *dev, const void *buf, int len); + +/** + * tkey_read_all() - Read all available data from TKey device + * + * @dev: TKey device + * @buf: Buffer to store read data + * @maxlen: Maximum number of bytes to read + * @timeout_ms: Timeout in milliseconds + * + * Reads all available data in one operation, suitable for USB devices. + * Falls back to regular read if read_all is not implemented. + * + * Return: Number of bytes read on success, -ve error on failure + */ +int tkey_read_all(struct udevice *dev, void *buf, int maxlen, + int timeout_ms); + +/** + * tkey_get_udi() - Get Unique Device Identifier + * + * @dev: TKey device + * @udi: Buffer to store UDI (must be at least 8 bytes) + * Return: 0 on success, -ve error on failure + */ +int tkey_get_udi(struct udevice *dev, void *udi); + +/** + * tkey_get_name_version() - Get device name and version + * + * @dev: TKey device + * @name0: Buffer for first name field (TKEY_NAME_SIZE bytes) + * @name1: Buffer for second name field (TKEY_NAME_SIZE bytes) + * @version: Pointer to store version number + * Return: 0 on success, -ve error on failure + */ +int tkey_get_name_version(struct udevice *dev, char name0[TKEY_NAME_SIZE], + char name1[TKEY_NAME_SIZE], u32 *version); + +/** + * tkey_in_app_mode() - Check if device is in firmware or app mode + * + * @dev: TKey device + * Return: 0 if in firmware mode, 1 if in app mode, -ve error on failure + */ +int tkey_in_app_mode(struct udevice *dev); + +/** + * tkey_load_app() - Load complete app to TKey device + * + * @dev: TKey device + * @app_data: Complete app binary data + * @app_size: Size of app data + * + * This function performs all steps needed to load an app: + * - Verifies device is in firmware mode + * - Sends app header with size + * - Sends app data in chunks + * + * Return: 0 on success, -ve error on failure (-ENOTSUPP if not in + * firmware mode) + */ +int tkey_load_app(struct udevice *dev, const void *app_data, int app_size); + +/** + * tkey_load_app_with_uss() - Load app with User-Supplied Secret + * + * @dev: TKey device + * @app_data: Complete app binary data + * @app_size: Size of app data + * @uss: User-Supplied Secret (password/passphrase) - can be NULL + * @uss_size: Size of USS data (max 32 bytes) + * + * This function performs all steps needed to load an app with USS: + * - Verifies device is in firmware mode + * - Sends app header with size + * - Sends app data in chunks + * - Sends USS if provided + * + * Return: 0 on success, -ve error on failure (-ENOTSUPP if not in + * firmware mode) + */ +int tkey_load_app_with_uss(struct udevice *dev, const void *app_data, + int app_size, const void *uss, int uss_size); + +/** + * tkey_get_pubkey() - Get public key from signer app + * + * @dev: TKey device (must be in app mode with signer loaded) + * @pubkey: Buffer to store public key (must be at least 32 bytes) + * Return: 0 on success, -ve error on failure + */ +int tkey_get_pubkey(struct udevice *dev, void *pubkey); + +/** + * tkey_derive_disk_key() - Derive disk encryption key from USS + * + * @dev: TKey device + * @app_data: Signer app binary data + * @app_size: Size of app data + * @uss: User-Supplied Secret for key derivation + * @uss_size: Size of USS + * @disk_key: Buffer to store derived disk key (32 bytes) + * @pubkey: Buffer to store public key (32 bytes) + * @key_hash: Buffer to store verification hash (32 bytes), or NULL if + * not needed + * + * This function loads the signer app with USS, retrieves the public key, + * and derives a disk encryption key. Optionally generates a verification + * hash. + * + * Return: 0 on success, -ve error on failure + */ +int tkey_derive_disk_key(struct udevice *dev, const void *app_data, + int app_size, const void *uss, int uss_size, + void *disk_key, void *pubkey, void *key_hash); + +/** + * tkey_derive_wrapping_key() - Derive wrapping key from password and UDI + * + * @dev: TKey device (must be in firmware mode to access UDI) + * @password: User-provided password + * @wrapping_key: Buffer to store wrapping key (32 bytes) + * + * This function gets the device UDI and derives a wrapping key using + * BLAKE2b(UDI || password). + * + * Return: 0 on success, -ve error on failure + */ +int tkey_derive_wrapping_key(struct udevice *dev, const char *password, + void *wrapping_key); + +#endif /* _TKEY_UCLASS_H */ From patchwork Sun Oct 19 07:23:04 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 628 Return-Path: X-Original-To: u-boot-concept@u-boot.org Delivered-To: u-boot-concept@u-boot.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1760858634; bh=aX9nx5cer4wpfCPuw7D/Txzb9lO+Ior2gdMpTTereVk=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=o5AsHTdQeyPoSVQ1s2kyoBKeBH0A2G6+4bbd1CmRWd8A0t6gXK3WrUINNai203PfD LQwMKe3M4ERkeOV9wjbVrqkNNbc3Vy8qJhv3eLiQI0vG2AAR3W4iSnYiTVNwG7m0gC 3gJL24kLDd711b5rNg5cxAvfnoCtCp1+SbIWgPSqs4ey3vZOdPGfzk4zmHY0ZRpx0G ersbsCrH5hxFvkinFMKdbHfXGbfErNfUBhLlQLK0RzXS5OKcUGJYwa9P7OBP5O5FJP Ik9fKhz81r6U85jcLiirfAgcx44YCMCmKzIBIBe8/JmpFNmc/3B0eiMbUGFaVQPVra SP26CSvGgqjFg== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 24165681AD for ; Sun, 19 Oct 2025 01:23:54 -0600 (MDT) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10024) with ESMTP id LaIzAMV4ts2M for ; Sun, 19 Oct 2025 01:23:54 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1760858634; bh=aX9nx5cer4wpfCPuw7D/Txzb9lO+Ior2gdMpTTereVk=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=o5AsHTdQeyPoSVQ1s2kyoBKeBH0A2G6+4bbd1CmRWd8A0t6gXK3WrUINNai203PfD LQwMKe3M4ERkeOV9wjbVrqkNNbc3Vy8qJhv3eLiQI0vG2AAR3W4iSnYiTVNwG7m0gC 3gJL24kLDd711b5rNg5cxAvfnoCtCp1+SbIWgPSqs4ey3vZOdPGfzk4zmHY0ZRpx0G ersbsCrH5hxFvkinFMKdbHfXGbfErNfUBhLlQLK0RzXS5OKcUGJYwa9P7OBP5O5FJP Ik9fKhz81r6U85jcLiirfAgcx44YCMCmKzIBIBe8/JmpFNmc/3B0eiMbUGFaVQPVra SP26CSvGgqjFg== Received: from mail.u-boot.org (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 12D41680DD for ; Sun, 19 Oct 2025 01:23:54 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1760858632; bh=9722D1sfBdzJTHwnE7ICzlpRFY/H6zO3dwvt/32ifbA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=GENfgLNjf7kyBIyTjmI5zzXPUkRZ9ZfiuCpM1pHmgQQAfKXuqVb2QxY2TNjd7rC5a WeeQdy3b883lLhOSm8p4FkotKVab9IxhvW6Y8PilOMpqIUrhuiNuJapLAvy+U44Cbs O86pUO05RrvuuXfLLYA8whuToJSl9XXQx/phP/uwIkJfJEmA7VN0zr7nE2ED61Dty/ 1ljIfpoeUnVDIITjLzSMfJ02H0oAV0co/jmrU4s2n2jOpUUHrx+jhNk8xqogKyqGda seRUu0r/pVIHwTMbWh41g32BRZFlF1Y+Avr3Y1TGKJUqrmB/K1ZlP1xwQZgLIFVOuF 8naHqySwH8ZLg== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 6BFDA6807A; Sun, 19 Oct 2025 01:23:52 -0600 (MDT) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10026) with ESMTP id 768UMcSFGMw7; Sun, 19 Oct 2025 01:23:52 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1760858627; bh=6tsowrxGzVFuw++WeyKrnKlyqNxuHMaEd3kgNvQ9KH0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=g24is7kYss+6rAC50VMoUAhe2Bt04XvaJ7YtMphos43F5ski+YNqRjYNNMLMaNYSC w6q2Ditk09o30vK9/rEu45TunYDQy+XyDUyPIhmoGT/CLJlM2t5f4FuE4RqN+9aTZ5 UyZ5rGpU0on4SbXAEKrq0bAcFSNGtaoQemPZZagGTic19C/qg6+E/ZyI3UvvRnfHTP Ol+T5ZIgyBRg0rtQi4LhmHvy6qV5bqhwOr6Ry/Sy484Bvh4uTodPZgWOeUgZkqlaKv yb+O+EDfauY0dQfXFMGQbmEEPayEeLhMGOQTM/OqjjMESsFl9E1n1Ya4rq4Yz+cKGo Mo/KW7ASNInag== Received: from u-boot.org (unknown [73.34.74.121]) by mail.u-boot.org (Postfix) with ESMTPSA id B55116810E; Sun, 19 Oct 2025 01:23:47 -0600 (MDT) From: Simon Glass To: U-Boot Concept Date: Sun, 19 Oct 2025 01:23:04 -0600 Message-ID: <20251019072313.3235339-5-sjg@u-boot.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251019072313.3235339-1-sjg@u-boot.org> References: <20251019072313.3235339-1-sjg@u-boot.org> MIME-Version: 1.0 Message-ID-Hash: MP4D4X76B3ABLGC5XBXBJTBQ4BMO7FZF X-Message-ID-Hash: MP4D4X76B3ABLGC5XBXBJTBQ4BMO7FZF X-MailFrom: sjg@u-boot.org X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: Simon Glass X-Mailman-Version: 3.3.10 Precedence: list Subject: [Concept] [PATCH 4/8] tkey: Add the signer firmware List-Id: Discussion and patches related to U-Boot Concept Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: From: Simon Glass Add a binary for the TKey signer, so that it can be downloaded to the key when needed. Signed-off-by: Simon Glass --- drivers/misc/Makefile | 1 + drivers/misc/signer.bin-v1.0.0 | Bin 0 -> 28024 bytes include/tkey.h | 5 +++++ scripts/Makefile.lib | 20 ++++++++++++++++++++ 4 files changed, 26 insertions(+) create mode 100644 drivers/misc/signer.bin-v1.0.0 index 8f4f4c7e512..a16447795b1 100644 diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 23fd8f8ef3b..8db02bb9614 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_$(PHASE_)MISC) += misc-uclass.o obj-$(CONFIG_$(PHASE_)NVMEM) += nvmem.o obj-$(CONFIG_TKEY) += tkey-uclass.o +obj-$(CONFIG_TKEY) += signer-1.0.0.o obj-$(CONFIG_$(PHASE_)CROS_EC) += cros_ec.o obj-$(CONFIG_$(PHASE_)CROS_EC_SANDBOX) += cros_ec_sandbox.o diff --git a/drivers/misc/signer.bin-v1.0.0 b/drivers/misc/signer.bin-v1.0.0 new file mode 100644 index 0000000000000000000000000000000000000000..c80dfe12d9989436e4e54beaaaea6ec3df64a128 GIT binary patch literal 28024 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 $@ + +$(obj)/signer-%.S: $(src)/signer.bin-v% + $(call cmd,S_signer) + # Splash logos # --------------------------------------------------------------------------- From patchwork Sun Oct 19 07:23:05 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 629 Return-Path: X-Original-To: u-boot-concept@u-boot.org Delivered-To: u-boot-concept@u-boot.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1760858636; bh=q+XJLbl9u1u/mWo4WBR75OfHAa36qdCH8CAS8rgYcBE=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=fhSkv/B0htoWvB3/nkTbRZ+xa4odg42/AfDlnaQHubnM4wLn4Jy49yZ0PT7iKAwwU Vtmq54XmPzTeBgrs1itwRWH/QeCT0XUaPf1eNg7tS1T26qLeJwE6VeQ2F/4TqAzmhZ GDgWWBdlc3MomWVww6ymAY7JtOcKrNEUlDNq3oPopTqWrgnZSJvyv2EDulkkm0Gpor KF7YYS7W32iNz0Z1CZ//eKXYLdLOEZYklWKMQwESVkVL9YGtmJJOHCx9YitfydtH0p 1pFoKahwOqZVEwiW0L2YC9EpjkTYARiUUZYle3/qHsFir+V0+CKo+diEZzYYmr6BAH OYiXVRC3/WPEA== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 9388668198 for ; Sun, 19 Oct 2025 01:23:56 -0600 (MDT) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10024) with ESMTP id ZUennoUsIB3v for ; Sun, 19 Oct 2025 01:23:56 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1760858636; bh=q+XJLbl9u1u/mWo4WBR75OfHAa36qdCH8CAS8rgYcBE=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=fhSkv/B0htoWvB3/nkTbRZ+xa4odg42/AfDlnaQHubnM4wLn4Jy49yZ0PT7iKAwwU Vtmq54XmPzTeBgrs1itwRWH/QeCT0XUaPf1eNg7tS1T26qLeJwE6VeQ2F/4TqAzmhZ GDgWWBdlc3MomWVww6ymAY7JtOcKrNEUlDNq3oPopTqWrgnZSJvyv2EDulkkm0Gpor KF7YYS7W32iNz0Z1CZ//eKXYLdLOEZYklWKMQwESVkVL9YGtmJJOHCx9YitfydtH0p 1pFoKahwOqZVEwiW0L2YC9EpjkTYARiUUZYle3/qHsFir+V0+CKo+diEZzYYmr6BAH OYiXVRC3/WPEA== Received: from mail.u-boot.org (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 840D6680DD for ; Sun, 19 Oct 2025 01:23:56 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1760858634; bh=kjS1rNhG1GPmlHgYKnCICu0j0ik9Fw7uPLLlZFnNBgg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=YR+DSNi6vY8THFmWfqnaaGF1z1LUfnG4+Cx77a0zrUlU3rIheA9nlDDkGRFg21UwL XRQijxosLCkP0jOy59TwQmQ4pybi4LVZd3rMcZI5mH7r6cTBVAFNcAxaacbSP678ff E+UGM/PsjI2FfluWyhsdM3JBiVZLZMs/zyLlkoke50WTJBXUBQi+84Hth0gFzUg6tP Cdng8qtIhp0u/7aTAe5Hgj38okPw4y8B7nIFCkvvto4FVmgZgfskctcAg0HW1MpYSQ YAjoc/07sycahh7O8suAqOmDkWjM0fYVaAIVrBcventk27V1j1kh31AHYP0wciblp3 xA7Wq7HK1iKLQ== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 39811681B3; Sun, 19 Oct 2025 01:23:54 -0600 (MDT) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10026) with ESMTP id sWKUCGnbr6FB; Sun, 19 Oct 2025 01:23:54 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1760858632; bh=xiK2k5gwbwN0y5zu+W3yaW/+epXHr225voLYGzt7S/s=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ljRnfeyfa3MG2cUMUq5uCS6LezUe5d7LENDPy4efBI4VlUIDXsjA9MxWITzcYihMX Cyr7Nlf26zAA/TwI7+uWFOwbZDtTV1tG6r0poWfmtKNmkcl/V2GIYHgfkH7MrQs+Nu u5itdKXY1xC5bFUHyK43r+Cpxr6JbyFRw4s3O8UH48QJdCk7oeKebr0+xX00MlfUfi lViuGt9rMFzgRrwucP4o/D3YrwHltxfSgn5QPT3WpHKLv8vs2mZXnLM8UU/frjLXWm GDKuseXFcce3/cNY6fEXMta15callvkc29sZqGu5d/HIUxEdPEEzIaWmStJS4dr/ct q1vNWUf7acFQw== Received: from u-boot.org (unknown [73.34.74.121]) by mail.u-boot.org (Postfix) with ESMTPSA id AD69D6810E; Sun, 19 Oct 2025 01:23:52 -0600 (MDT) From: Simon Glass To: U-Boot Concept Date: Sun, 19 Oct 2025 01:23:05 -0600 Message-ID: <20251019072313.3235339-6-sjg@u-boot.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251019072313.3235339-1-sjg@u-boot.org> References: <20251019072313.3235339-1-sjg@u-boot.org> MIME-Version: 1.0 Message-ID-Hash: VE44KFCEPW4ZEO2TQCPCD7JJ7LHFMJMG X-Message-ID-Hash: VE44KFCEPW4ZEO2TQCPCD7JJ7LHFMJMG X-MailFrom: sjg@u-boot.org X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: Simon Glass , Claude X-Mailman-Version: 3.3.10 Precedence: list Subject: [Concept] [PATCH 5/8] tkey: Add emulator and test List-Id: Discussion and patches related to U-Boot Concept Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: From: Simon Glass Provide a simple emulator which can handle the TKey operations. Add a test which uses it. Co-developed-by: Claude Signed-off-by: Simon Glass --- arch/sandbox/dts/test.dts | 4 + drivers/misc/Makefile | 3 + drivers/misc/tkey_emul.c | 284 +++++++++++++++++++++++++++++++++++++ test/dm/Makefile | 1 + test/dm/tkey.c | 290 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 582 insertions(+) create mode 100644 drivers/misc/tkey_emul.c create mode 100644 test/dm/tkey.c diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index 86c01545462..9b0a5736cf8 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -1123,6 +1123,10 @@ }; }; + tkey-emul { + compatible = "tkey,emul"; + }; + mmc2 { compatible = "sandbox,mmc"; non-removable; diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 8db02bb9614..298bc1c0a69 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -18,6 +18,9 @@ obj-$(CONFIG_CROS_EC_I2C) += cros_ec_i2c.o obj-$(CONFIG_CROS_EC_SPI) += cros_ec_spi.o obj-$(CONFIG_SANDBOX) += p2sb_sandbox.o p2sb_emul.o obj-$(CONFIG_SANDBOX) += swap_case.o +ifdef CONFIG_SANDBOX +obj-$(CONFIG_TKEY) += tkey_emul.o +endif endif ifdef CONFIG_$(PHASE_)DM_I2C diff --git a/drivers/misc/tkey_emul.c b/drivers/misc/tkey_emul.c new file mode 100644 index 00000000000..d8d81280486 --- /dev/null +++ b/drivers/misc/tkey_emul.c @@ -0,0 +1,284 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2025 Canonical Ltd + * + * TKey emulator for testing TKey functionality in sandbox + */ + +#define LOG_CATEGORY UCLASS_TKEY + +#include +#include +#include +#include +#include +#include +#include +#include + +/* TKey protocol frame structure */ +#define FRAME_SIZE 128 +#define FRAME_HEADER_SIZE 1 +#define FRAME_DATA_SIZE (FRAME_SIZE - FRAME_HEADER_SIZE) + +/* Frame header bit masks and values */ +#define FRAME_ENDPOINT_MASK 0x18 +#define FRAME_ENDPOINT_SHIFT 3 +#define ENDPOINT_FIRMWARE 2 +#define ENDPOINT_APP 3 + +/* Firmware Commands */ +#define FW_CMD_GET_NAME_VERSION 0x01 +#define FW_CMD_GET_UDI 0x08 +#define FW_CMD_LOAD_APP 0x03 +#define FW_CMD_LOAD_APP_DATA 0x05 + +/* App Commands */ +#define APP_CMD_GET_PUBKEY 0x01 + +/* USB Response format markers */ +#define USB_FRAME_MARKER 0x52 +#define USB_RSP_NAME_VERSION 0x02 +#define USB_RSP_GET_UDI 0x09 + +/* Status codes */ +#define STATUS_OK 0x00 +#define STATUS_ERROR 0x01 + +/* + * struct tkey_emul_priv - TKey emulator state + * + * @app_loaded: Whether an app is loaded (app mode vs firmware mode) + * @udi: Unique Device Identifier (8 bytes) + * @app_size: Size of loaded app + * @pubkey: Simulated public key (32 bytes) + * @resp: Buffer for storing response to be read + * @resp_len: Length of data in response buffer + * @total_loaded: Track total app data loaded + */ +struct tkey_emul_priv { + bool app_loaded; + u8 udi[8]; + u32 app_size; + u8 pubkey[32]; + u8 resp[FRAME_SIZE]; + int resp_len; + u32 total_loaded; +}; + +static int tkey_emul_read(struct udevice *dev, void *buf, int len, + int timeout_ms) +{ + /* + * Read operations are immediate with no actual I/O. The data is + * prepared by write operations in the emulated response buffer + */ + log_debug("read: %d bytes requested\n", len); + + return -ENOSYS; +} + +static int handle_fw_get_name_version(struct tkey_emul_priv *priv) +{ + /* USB format: 0x52 0x02 [tk1 ] [name1] [version] */ + priv->resp[0] = USB_FRAME_MARKER; + priv->resp[1] = USB_RSP_NAME_VERSION; + memcpy(priv->resp + 2, "tk1 ", 4); + + /* name1 changes based on firmware vs app mode */ + if (priv->app_loaded) + memcpy(priv->resp + 6, "sign", 4); + else + memcpy(priv->resp + 6, "mkdf", 4); + put_unaligned_le32(4, priv->resp + 10); + priv->resp_len = 14; + log_debug("GET_NAME_VERSION (mode=%s)\n", + priv->app_loaded ? "app" : "firmware"); + + return 0; +} + +static int handle_fw_get_udi(struct tkey_emul_priv *priv) +{ + /* UDI is only available in firmware mode */ + if (priv->app_loaded) { + priv->resp_len = 0; + log_debug("GET_UDI rejected (app mode)\n"); + } else { + priv->resp[0] = USB_FRAME_MARKER; + priv->resp[1] = USB_RSP_GET_UDI; + priv->resp[2] = STATUS_OK; + memcpy(priv->resp + 3, priv->udi, 8); + priv->resp_len = 11; + log_debug("GET_UDI OK\n"); + } + + return 0; +} + +static int handle_fw_load_app(struct tkey_emul_priv *priv, const u8 *data) +{ + /* App size is in bytes 2-5 (big endian) */ + priv->app_size = get_unaligned_be32(data + 2); + + /* Simple ACK - just return status */ + priv->resp[0] = STATUS_OK; + priv->resp_len = 1; + log_debug("LOAD_APP (size=%u)\n", priv->app_size); + + return 0; +} + +static int handle_fw_load_app_data(struct tkey_emul_priv *priv, const u8 *data) +{ + int chunk_size = get_unaligned_be32(data + 2); + + priv->total_loaded += chunk_size; + + /* Simple ACK */ + priv->resp[0] = STATUS_OK; + priv->resp_len = 1; + + if (priv->total_loaded >= priv->app_size) { + /* App fully loaded - enter app mode */ + priv->app_loaded = true; + priv->total_loaded = 0; + log_debug("App loaded, entering app mode\n"); + } else { + log_debug("LOAD_APP_DATA (%u/%u)\n", + priv->total_loaded, priv->app_size); + } + + return 0; +} + +static int handle_firmware_cmd(struct udevice *dev, u8 cmd, const u8 *data) +{ + struct tkey_emul_priv *priv = dev_get_priv(dev); + + switch (cmd) { + case FW_CMD_GET_NAME_VERSION: + return handle_fw_get_name_version(priv); + case FW_CMD_GET_UDI: + return handle_fw_get_udi(priv); + case FW_CMD_LOAD_APP: + return handle_fw_load_app(priv, data); + case FW_CMD_LOAD_APP_DATA: + return handle_fw_load_app_data(priv, data); + default: + log_err("Unknown firmware command %02x\n", cmd); + return -EINVAL; + } +} + +static int handle_app_get_pubkey(struct tkey_emul_priv *priv) +{ + memcpy(priv->resp, priv->pubkey, 32); + priv->resp_len = 32; + log_debug("GET_PUBKEY\n"); + + return 0; +} + +static int handle_app_cmd(struct udevice *dev, u8 cmd) +{ + struct tkey_emul_priv *priv = dev_get_priv(dev); + + if (!priv->app_loaded) { + log_err("App command sent but not in app mode\n"); + return -EINVAL; + } + + switch (cmd) { + case APP_CMD_GET_PUBKEY: + return handle_app_get_pubkey(priv); + default: + log_err("Unknown app command %02x\n", cmd); + return -EINVAL; + } +} + +static int tkey_emul_write(struct udevice *dev, const void *buf, int len) +{ + const u8 *data = buf; + u8 header, endpoint, cmd; + int ret; + + if (len < 2) + return -EINVAL; + + header = data[0]; + endpoint = (header & FRAME_ENDPOINT_MASK) >> FRAME_ENDPOINT_SHIFT; + cmd = data[1]; + + log_debug("header %02x endpoint %u cmd %02x\n", header, endpoint, cmd); + + /* Route to appropriate endpoint handler */ + if (endpoint == ENDPOINT_FIRMWARE) { + ret = handle_firmware_cmd(dev, cmd, data); + } else if (endpoint == ENDPOINT_APP) { + ret = handle_app_cmd(dev, cmd); + } else { + log_err("Unknown endpoint %u\n", endpoint); + return -EINVAL; + } + + return ret ? ret : len; +} + +static int tkey_emul_read_all(struct udevice *dev, void *buf, int maxlen, + int timeout_ms) +{ + struct tkey_emul_priv *priv = dev_get_priv(dev); + int len = min(priv->resp_len, maxlen); + + log_debug("read_all: %d bytes max, returning %d bytes\n", maxlen, len); + + /* Copy the raw USB response data including the 0x52 marker */ + if (len > 0) + memcpy(buf, priv->resp, len); + + return len; +} + +static int tkey_emul_probe(struct udevice *dev) +{ + struct tkey_emul_priv *priv = dev_get_priv(dev); + int i; + + /* Generate a deterministic UDI based on device name */ + for (i = 0; i < 8; i++) + priv->udi[i] = 0xa0 + i; + + /* Generate a deterministic public key */ + for (i = 0; i < 32; i++) + priv->pubkey[i] = 0x50 + (i & 0xf); + + log_debug("init with UDI: "); + for (i = 0; i < 8; i++) + log_debug("%02x", priv->udi[i]); + log_debug("\n"); + + return 0; +} + +/* TKey uclass operations */ +static const struct tkey_ops tkey_emul_ops = { + .read = tkey_emul_read, + .write = tkey_emul_write, + .read_all = tkey_emul_read_all, +}; + +static const struct udevice_id tkey_emul_ids[] = { + { .compatible = "tkey,emul" }, + { } +}; + +U_BOOT_DRIVER(tkey_emul) = { + .name = "tkey_emul", + .id = UCLASS_TKEY, + .of_match = tkey_emul_ids, + .probe = tkey_emul_probe, + .ops = &tkey_emul_ops, + .priv_auto = sizeof(struct tkey_emul_priv), +}; diff --git a/test/dm/Makefile b/test/dm/Makefile index b38de3e12d0..45aee79c8f2 100644 --- a/test/dm/Makefile +++ b/test/dm/Makefile @@ -121,6 +121,7 @@ obj-$(CONFIG_SYSINFO) += sysinfo.o obj-$(CONFIG_SYSINFO_GPIO) += sysinfo-gpio.o obj-$(CONFIG_UT_DM) += tag.o obj-$(CONFIG_TEE) += tee.o +obj-$(CONFIG_TKEY) += tkey.o obj-$(CONFIG_TIMER) += timer.o obj-$(CONFIG_TPM_V2) += tpm.o obj-$(CONFIG_DM_USB) += usb.o diff --git a/test/dm/tkey.c b/test/dm/tkey.c new file mode 100644 index 00000000000..9dffae66a5e --- /dev/null +++ b/test/dm/tkey.c @@ -0,0 +1,290 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2025 Canonical Ltd + * + * Test for TKey uclass and emulator + */ + +#include +#include +#include +#include +#include + +/* Test that we can find a TKey device */ +static int dm_test_tkey_find(struct unit_test_state *uts) +{ + struct udevice *dev; + + ut_assertok(uclass_first_device_err(UCLASS_TKEY, &dev)); + ut_assertnonnull(dev); + + return 0; +} +DM_TEST(dm_test_tkey_find, UTF_SCAN_FDT); + +/* Test getting UDI from TKey */ +static int dm_test_tkey_get_udi(struct unit_test_state *uts) +{ + u8 udi[TKEY_UDI_SIZE]; + struct udevice *dev; + + ut_assertok(uclass_first_device_err(UCLASS_TKEY, &dev)); + + ut_assertok(tkey_get_udi(dev, udi)); + + /* Verify emulator returns expected UDI */ + ut_asserteq(0xa0, udi[0]); + ut_asserteq(0xa1, udi[1]); + ut_asserteq(0xa2, udi[2]); + ut_asserteq(0xa3, udi[3]); + ut_asserteq(0xa4, udi[4]); + ut_asserteq(0xa5, udi[5]); + ut_asserteq(0xa6, udi[6]); + ut_asserteq(0xa7, udi[7]); + + return 0; +} +DM_TEST(dm_test_tkey_get_udi, UTF_SCAN_FDT); + +/* Test getting name and version from TKey */ +static int dm_test_tkey_get_name_version(struct unit_test_state *uts) +{ + char name0[TKEY_NAME_SIZE], name1[TKEY_NAME_SIZE]; + struct udevice *dev; + u32 version; + + ut_assertok(uclass_first_device_err(UCLASS_TKEY, &dev)); + + /* Get name and version */ + ut_assertok(tkey_get_name_version(dev, name0, name1, &version)); + + /* Verify emulator returns expected values */ + ut_asserteq_str("tk1 ", name0); + ut_asserteq_str("mkdf", name1); + ut_asserteq(4, version); + + return 0; +} +DM_TEST(dm_test_tkey_get_name_version, UTF_SCAN_FDT); + +/* Test checking firmware mode */ +static int dm_test_tkey_in_app_mode(struct unit_test_state *uts) +{ + struct udevice *dev; + int ret; + + ut_assertok(uclass_first_device_err(UCLASS_TKEY, &dev)); + + /* Check mode - should be in firmware mode initially */ + ret = tkey_in_app_mode(dev); + ut_assert(ret >= 0); + ut_asserteq(0, ret); /* 0 = firmware mode */ + + return 0; +} +DM_TEST(dm_test_tkey_in_app_mode, UTF_SCAN_FDT); + +/* Test loading an app */ +static int dm_test_tkey_load_app(struct unit_test_state *uts) +{ + struct udevice *dev; + u8 dummy_app[128]; + int ret; + + ut_assertok(uclass_first_device_err(UCLASS_TKEY, &dev)); + + /* Create a dummy app */ + memset(dummy_app, 0x42, sizeof(dummy_app)); + + /* Load the app */ + ret = tkey_load_app(dev, dummy_app, sizeof(dummy_app)); + ut_assertok(ret); + + /* After loading, should be in app mode */ + ret = tkey_in_app_mode(dev); + ut_assert(ret >= 0); + ut_asserteq(1, ret); /* 1 = app mode */ + + return 0; +} +DM_TEST(dm_test_tkey_load_app, UTF_SCAN_FDT); + +/* Test getting public key from signer app */ +static int dm_test_tkey_get_pubkey(struct unit_test_state *uts) +{ + u8 pubkey[TKEY_PUBKEY_SIZE]; + struct udevice *dev; + u8 dummy_app[128]; + int i; + + ut_assertok(uclass_first_device_err(UCLASS_TKEY, &dev)); + + /* Load a dummy app first */ + memset(dummy_app, 0x42, sizeof(dummy_app)); + ut_assertok(tkey_load_app(dev, dummy_app, sizeof(dummy_app))); + + /* Get public key */ + ut_assertok(tkey_get_pubkey(dev, pubkey)); + + /* Verify emulator returns expected pattern */ + for (i = 0; i < TKEY_PUBKEY_SIZE; i++) + ut_asserteq(0x50 + (i & 0xf), pubkey[i]); + + return 0; +} +DM_TEST(dm_test_tkey_get_pubkey, UTF_SCAN_FDT); + +/* Test deriving wrapping key from password */ +static int dm_test_tkey_derive_wrapping_key(struct unit_test_state *uts) +{ + u8 wrapping_key[TKEY_WRAPPING_KEY_SIZE]; + const char *password = "test_password"; + /* Expected BLAKE2b(UDI || password) where UDI = a0a1a2a3a4a5a6a7 */ + const u8 expected[TKEY_WRAPPING_KEY_SIZE] = { + 0x95, 0x22, 0x9c, 0xd3, 0x76, 0x89, 0x8f, 0x3f, + 0xb0, 0x22, 0xa6, 0x27, 0x34, 0x9d, 0xc9, 0x85, + 0xbc, 0x46, 0x75, 0xda, 0x58, 0x0d, 0x26, 0x96, + 0xbd, 0xd6, 0xf7, 0x1f, 0x48, 0x8e, 0x30, 0x6c, + }; + struct udevice *dev; + + ut_assertok(uclass_first_device_err(UCLASS_TKEY, &dev)); + + /* Derive wrapping key from password */ + ut_assertok(tkey_derive_wrapping_key(dev, password, wrapping_key)); + + /* Verify the exact wrapping key value */ + ut_asserteq_mem(expected, wrapping_key, TKEY_WRAPPING_KEY_SIZE); + + return 0; +} +DM_TEST(dm_test_tkey_derive_wrapping_key, UTF_SCAN_FDT); + +/* Test deriving disk key with USS */ +static int dm_test_tkey_derive_disk_key(struct unit_test_state *uts) +{ + const char *uss = "user_secret"; + u8 disk_key[TKEY_DISK_KEY_SIZE]; + u8 pubkey[TKEY_PUBKEY_SIZE]; + u8 key_hash[TKEY_HASH_SIZE]; + /* Expected pubkey from emulator (deterministic pattern) */ + const u8 expected_pubkey[TKEY_PUBKEY_SIZE] = { + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + }; + /* Expected disk key: BLAKE2b(pubkey) */ + const u8 expected_disk_key[TKEY_DISK_KEY_SIZE] = { + 0x22, 0x8b, 0x2f, 0x6a, 0xbf, 0x8b, 0xe0, 0x56, + 0x49, 0xb2, 0x41, 0x75, 0x86, 0x15, 0x0b, 0xbf, + 0x3e, 0x1b, 0x3f, 0x66, 0x9a, 0xfa, 0x1c, 0x61, + 0x51, 0xdd, 0xc7, 0x29, 0x57, 0x93, 0x3c, 0x21, + }; + /* Expected key hash: BLAKE2b(disk_key) */ + const u8 expected_key_hash[TKEY_HASH_SIZE] = { + 0xa7, 0x2a, 0x46, 0xb8, 0xf8, 0xc7, 0xff, 0x08, + 0x24, 0x41, 0x6a, 0xda, 0x88, 0x6f, 0x62, 0xb6, + 0xc2, 0x80, 0x88, 0x96, 0xd7, 0x12, 0x01, 0xa3, + 0x28, 0x14, 0xab, 0x43, 0x2c, 0x7a, 0x81, 0xcf, + }; + struct udevice *dev; + u8 dummy_app[128]; + + ut_assertok(uclass_first_device_err(UCLASS_TKEY, &dev)); + + /* Create a dummy signer app */ + memset(dummy_app, 0x42, sizeof(dummy_app)); + + /* Derive disk key */ + ut_assertok(tkey_derive_disk_key(dev, dummy_app, sizeof(dummy_app), + uss, strlen(uss), disk_key, pubkey, + key_hash)); + + ut_asserteq_mem(expected_pubkey, pubkey, TKEY_PUBKEY_SIZE); + ut_asserteq_mem(expected_disk_key, disk_key, TKEY_DISK_KEY_SIZE); + ut_asserteq_mem(expected_key_hash, key_hash, TKEY_HASH_SIZE); + + return 0; +} +DM_TEST(dm_test_tkey_derive_disk_key, UTF_SCAN_FDT); + +/* Test UDI not available in app mode */ +static int dm_test_tkey_udi_app_mode(struct unit_test_state *uts) +{ + u8 udi[TKEY_UDI_SIZE]; + struct udevice *dev; + u8 dummy_app[128]; + + ut_assertok(uclass_first_device_err(UCLASS_TKEY, &dev)); + + /* Load an app to enter app mode */ + memset(dummy_app, 0x42, sizeof(dummy_app)); + ut_assertok(tkey_load_app(dev, dummy_app, sizeof(dummy_app))); + + /* Verify we're in app mode */ + ut_asserteq(1, tkey_in_app_mode(dev)); + + /* Try to get UDI - emulator returns -EIO for empty response */ + ut_asserteq(-EIO, tkey_get_udi(dev, udi)); + + return 0; +} +DM_TEST(dm_test_tkey_udi_app_mode, UTF_SCAN_FDT); + +/* Test loading app with USS */ +static int dm_test_tkey_load_app_with_uss(struct unit_test_state *uts) +{ + struct udevice *dev; + u8 dummy_app[128]; + const char *uss = "my_secret"; + + ut_assertok(uclass_first_device_err(UCLASS_TKEY, &dev)); + + /* Create a dummy app */ + memset(dummy_app, 0x55, sizeof(dummy_app)); + + /* Load app with USS */ + ut_assertok(tkey_load_app_with_uss(dev, dummy_app, sizeof(dummy_app), + uss, strlen(uss))); + + /* Should be in app mode */ + ut_asserteq(1, tkey_in_app_mode(dev)); + + return 0; +} +DM_TEST(dm_test_tkey_load_app_with_uss, UTF_SCAN_FDT); + +/* Test basic read/write operations */ +static int dm_test_tkey_read_write(struct unit_test_state *uts) +{ + /* Expected USB response: 0x52 0x02 [tk1 ] [mkdf] [version=4] */ + static const u8 expected[14] = { + 0x52, 0x02, /* USB marker and response type */ + 't', 'k', '1', ' ', /* name0 */ + 'm', 'k', 'd', 'f', /* name1 */ + 0x04, 0x00, 0x00, 0x00, /* version = 4 (little-endian) */ + }; + struct udevice *dev; + u8 write_buf[129]; /* Header + command */ + u8 read_buf[256]; + + ut_assertok(uclass_first_device_err(UCLASS_TKEY, &dev)); + + /* Prepare a GET_NAME_VERSION command */ + write_buf[0] = 0x10; /* Header: CMD, FIRMWARE endpoint */ + write_buf[1] = 0x01; /* CMD_GET_NAME_VERSION */ + + /* Write the command - should return 2 bytes written */ + ut_asserteq(2, tkey_write(dev, write_buf, 2)); + + /* Read the response - should get exactly 14 bytes */ + ut_asserteq(14, tkey_read_all(dev, read_buf, sizeof(read_buf), 1000)); + + /* Verify full response matches expected */ + ut_asserteq_mem(expected, read_buf, 14); + + return 0; +} +DM_TEST(dm_test_tkey_read_write, UTF_SCAN_FDT); From patchwork Sun Oct 19 07:23:06 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 630 Return-Path: X-Original-To: u-boot-concept@u-boot.org Delivered-To: u-boot-concept@u-boot.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1760858641; bh=K5EN1gI1axSUK79wg7C43+oAAv3THns8mI+2UmMHC9s=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=XkSZl1mNshCfMcFHcRBMKs0bSsZIMeNa3AqF64mFn6DyW1cEJrIl47caYSSHc0McK Zzk8NpDVWUq/cKwf4O/3BH3N03aJJtJaf7Hi15Uz/tkVn1SUqt5Rgl5Hx+aWl/qcm4 eR7dXYezAb4VdumNX/qi7ztc0ufo+XjYq8+uFoPvR75CgqvI2uZRTMtzMMP/l0W5Vg /IqyDIwa54841YjeeIE79T+p2UgWvWUI3SYsOzf7My9DbkRoBiC7DZ2+Dyghw1VhHM grMuPdA6JGe+Gu/nYZvREiTZ84tr/qhh9s7pzBkIzsx0sDfAmSc+4RflUYRhu04oi1 LpvT7Q0KFwzzw== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 317495E435 for ; Sun, 19 Oct 2025 01:24:01 -0600 (MDT) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10024) with ESMTP id 9RLChl66CmNg for ; Sun, 19 Oct 2025 01:24:01 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1760858641; bh=K5EN1gI1axSUK79wg7C43+oAAv3THns8mI+2UmMHC9s=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=XkSZl1mNshCfMcFHcRBMKs0bSsZIMeNa3AqF64mFn6DyW1cEJrIl47caYSSHc0McK Zzk8NpDVWUq/cKwf4O/3BH3N03aJJtJaf7Hi15Uz/tkVn1SUqt5Rgl5Hx+aWl/qcm4 eR7dXYezAb4VdumNX/qi7ztc0ufo+XjYq8+uFoPvR75CgqvI2uZRTMtzMMP/l0W5Vg /IqyDIwa54841YjeeIE79T+p2UgWvWUI3SYsOzf7My9DbkRoBiC7DZ2+Dyghw1VhHM grMuPdA6JGe+Gu/nYZvREiTZ84tr/qhh9s7pzBkIzsx0sDfAmSc+4RflUYRhu04oi1 LpvT7Q0KFwzzw== Received: from mail.u-boot.org (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 1EF696807A for ; Sun, 19 Oct 2025 01:24:01 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1760858639; bh=R+2vOAgW5IlFOVutrfRJ5Pj8H4sjkpADye/xiS7Bwb8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=hINW4NCzJbJVW/iXCxJSGZ1qAiYXJbEAxxN5OBeyOSUTPFHgrcZFM0y64zFqJ+gpx 2wdwbHfM4pDMt8b7JpeYTh8oVP9pUMy1Yg1glty6AaOSAUqTsWrrf4O6y8peha3ZQA jjWNh8nHBgLQ/pvKNKUkR31QUwbieOJIdFOL1uA7SPBCzLiuUsaTPGRqO6YkRgOVWZ jnZa1yvW+GNXYvmSESLhWEt3sPWvKZ70tFaKIHO6FCxVOYrjsFN9190ksGm62bVXCv ow3r3IKaV/gx7MT3MqVhexrHHE85wpxMZR8m06mkYQfaCn1rI5KaI3R757Qo95kGPB jPRojjS98UtDg== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 000F36807A; Sun, 19 Oct 2025 01:23:59 -0600 (MDT) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10026) with ESMTP id PuxKrvnU4ZdO; Sun, 19 Oct 2025 01:23:58 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1760858634; bh=KeiKtPwKRSYPjRHkpK8P613AkQetriLzV4MfYWdwkME=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=dzo88/du+LK+KnoiKnqCO2pXwi/6DXD+YrbaizYoGKZHeO+UKjIYQzTPzk0kb53DU DdgQ53yqTi19asf4aIIkjj4ho1Gds6yc0geT9VhtopCcT6XsiMpNPMb2MjFMQ9Yc8n OMu0b2Hf38/YpSFywaPtPm+zNtOoeXnCRB3eTH6ulqfX+dKazJimRcImupNVPkAF8x YsJbA7Xcyssb8MGgkLxRhqQt40AGTZXlQTo9c/LNy5npTHS5VVGfIkGXJbeqBesOl+ CoieEPD4W/JKPDDuPlyLI4LFBMPTcR9gpMGcDVwV1Sy0l9iqY3r4mTJgg5fSHK9B0I j/lGTDWugokfw== Received: from u-boot.org (unknown [73.34.74.121]) by mail.u-boot.org (Postfix) with ESMTPSA id 683CD681B8; Sun, 19 Oct 2025 01:23:54 -0600 (MDT) From: Simon Glass To: U-Boot Concept Date: Sun, 19 Oct 2025 01:23:06 -0600 Message-ID: <20251019072313.3235339-7-sjg@u-boot.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251019072313.3235339-1-sjg@u-boot.org> References: <20251019072313.3235339-1-sjg@u-boot.org> MIME-Version: 1.0 Message-ID-Hash: WJQI2NKGGXXAATEHBZUHFLQBT325YXHA X-Message-ID-Hash: WJQI2NKGGXXAATEHBZUHFLQBT325YXHA X-MailFrom: sjg@u-boot.org X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: Simon Glass , Claude X-Mailman-Version: 3.3.10 Precedence: list Subject: [Concept] [PATCH 6/8] tkey: Add a command List-Id: Discussion and patches related to U-Boot Concept Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: From: Simon Glass Add a new 'tkey' command that provides an interface to interact with Tillitis TKey security tokens. Subcommands include: - info: Display device information (UDI, name, version, mode) - load: Load and run applications on the TKey - pubkey: Get the public key from a signer app - getkey: Derive disk encryption keys with password and USS This command enables U-Boot to use TKey devices for secure key derivation for full-disk encryption. Co-developed-by: Claude Signed-off-by: Simon Glass --- cmd/Kconfig | 10 ++ cmd/Makefile | 1 + cmd/tkey.c | 298 +++++++++++++++++++++++++++++++++++++++++ doc/usage/cmd/tkey.rst | 247 ++++++++++++++++++++++++++++++++++ doc/usage/index.rst | 1 + test/cmd/Makefile | 1 + test/cmd/tkey.c | 67 +++++++++ 7 files changed, 625 insertions(+) create mode 100644 cmd/tkey.c create mode 100644 doc/usage/cmd/tkey.rst create mode 100644 test/cmd/tkey.c diff --git a/cmd/Kconfig b/cmd/Kconfig index 224d5a83987..f4d6e544cc0 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -2390,6 +2390,16 @@ config CMD_MP This enables commands to bringup different processors in multiprocessor cases. +config CMD_TKEY + bool "tkey - Tillitis TKey operations" + depends on TKEY + default y + help + The allows interacting with a Tillitis TKey security token, + including connecting to the device, getting device information and + creating cryptographic wrapping keys from passwords combined with + device secrets. + config CMD_TIMER bool "timer" help diff --git a/cmd/Makefile b/cmd/Makefile index b73725cfe41..28e9c261683 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -189,6 +189,7 @@ obj-$(CONFIG_CMD_TEMPERATURE) += temperature.o obj-$(CONFIG_CMD_TERMINAL) += terminal.o obj-$(CONFIG_CMD_TIME) += time.o obj-$(CONFIG_CMD_TIMER) += timer.o +obj-$(CONFIG_CMD_TKEY) += tkey.o obj-$(CONFIG_CMD_TRACE) += trace.o obj-$(CONFIG_HUSH_PARSER) += test.o obj-$(CONFIG_CMD_TPM) += tpm-common.o diff --git a/cmd/tkey.c b/cmd/tkey.c new file mode 100644 index 00000000000..a269ca86085 --- /dev/null +++ b/cmd/tkey.c @@ -0,0 +1,298 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2025 Canonical Ltd + * + * Command for communicating with Tillitis TKey to create wrapping keys + * from user-provided passwords. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static struct udevice *tkey_get_device(void) +{ + struct udevice *dev; + int ret; + + ret = uclass_first_device_err(UCLASS_TKEY, &dev); + if (ret) { + printf("No device found (err %dE)\n", ret); + return NULL; + } + + return dev; +} + +static void print_hex(const char *label, const u8 *data, size_t len) +{ + size_t i; + + printf("%s: ", label); + for (i = 0; i < len; i++) + printf("%02x", data[i]); + printf("\n"); +} + +static int do_tkey_connect(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + struct udevice *dev; + + dev = tkey_get_device(); + if (!dev) + return CMD_RET_FAILURE; + + printf("Connected to TKey device\n"); + + return CMD_RET_SUCCESS; +} + +static int do_tkey_info(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + char name0[TKEY_NAME_SIZE], name1[TKEY_NAME_SIZE]; + u8 udi[TKEY_UDI_SIZE]; + struct udevice *dev; + u32 version; + int ret; + + dev = tkey_get_device(); + if (!dev) + return CMD_RET_FAILURE; + + ret = tkey_get_name_version(dev, name0, name1, &version); + if (ret) { + printf("Failed to get device info (err %dE)\n", ret); + return CMD_RET_FAILURE; + } + + printf("Name0: %.4s Name1: %.4s Version: %u\n", name0, name1, version); + + ret = tkey_get_udi(dev, udi); + if (ret) { + if (ret == -ENOTSUPP) + printf("UDI not available - replug device\n"); + else + printf("Failed to get UDI (err %dE)\n", ret); + return CMD_RET_FAILURE; + } + print_hex("UDI", udi, TKEY_UDI_SIZE); + + return CMD_RET_SUCCESS; +} + +static int do_tkey_wrapkey(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + u8 wrapping_key[TKEY_WRAPPING_KEY_SIZE]; + const char *password; + struct udevice *dev; + int ret; + + if (argc != 2) + return CMD_RET_USAGE; + + dev = tkey_get_device(); + if (!dev) + return CMD_RET_FAILURE; + + password = argv[1]; + + ret = tkey_derive_wrapping_key(dev, password, wrapping_key); + if (ret) { + if (ret == -ENOTSUPP) + printf("UDI not available - replug device\n"); + else + printf("Cannot derive wrapping key (err %dE)\n", ret); + return CMD_RET_FAILURE; + } + + print_hex("Wrapping Key", wrapping_key, TKEY_WRAPPING_KEY_SIZE); + + return CMD_RET_SUCCESS; +} + +static int do_tkey_fwmode(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + struct udevice *dev; + int ret; + + dev = tkey_get_device(); + if (!dev) + return CMD_RET_FAILURE; + + ret = tkey_in_app_mode(dev); + if (ret < 0) { + printf("Failed to check device mode (err %dE)\n", ret); + return CMD_RET_FAILURE; + } + + if (!ret) + printf("firmware mode\n"); + else + printf("app mode\n"); + + return CMD_RET_SUCCESS; +} + +static int do_tkey_signer(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + printf("signer binary: %lx bytes at %p-%p\n", TKEY_SIGNER_SIZE, + __signer_1_0_0_begin, __signer_1_0_0_end); + + return CMD_RET_SUCCESS; +} + +static int do_tkey_getkey(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + const char *hash = NULL; + u8 expect[TKEY_HASH_SIZE]; + u8 disk_key[TKEY_DISK_KEY_SIZE]; + u8 key_hash[TKEY_HASH_SIZE]; + u8 pubkey[TKEY_PUBKEY_SIZE]; + bool verify = false; + struct udevice *dev; + u32 uss_len, ret; + const char *uss; + + if (argc != 2 && argc != 3) + return CMD_RET_USAGE; + + dev = tkey_get_device(); + if (!dev) + return CMD_RET_FAILURE; + + uss = argv[1]; + uss_len = strlen(uss); + if (uss_len > TKEY_USS_MAX_SIZE) { + printf("USS too long (max %x bytes, got %x)\n", + TKEY_USS_MAX_SIZE, uss_len); + return CMD_RET_FAILURE; + } + + /* Check if verification hash is provided */ + if (argc == 3) { + int i; + + hash = argv[2]; + verify = true; + + /* Convert hex string to bytes */ + if (strlen(hash) != TKEY_HASH_SIZE * 2) { + printf("Verification hash must be %x hex chars\n", + TKEY_HASH_SIZE * 2); + return CMD_RET_USAGE; + } + + for (i = 0; i < TKEY_HASH_SIZE; i++) + expect[i] = (hex_to_bin(hash[i * 2]) << 4) | + hex_to_bin(hash[i * 2 + 1]); + } + + /* Derive disk key using uclass function */ + ret = tkey_derive_disk_key(dev, (const u8 *)__signer_1_0_0_begin, + TKEY_SIGNER_SIZE, (const u8 *)uss, + uss_len, disk_key, pubkey, key_hash); + if (ret) { + printf("Failed to derive disk key (err %dE)\n", ret); + return CMD_RET_FAILURE; + } + + /* Display results */ + print_hex("Public Key", pubkey, TKEY_PUBKEY_SIZE); + print_hex("Disk Key", disk_key, TKEY_DISK_KEY_SIZE); + + /* Verify or display verification hash */ + if (verify) { + /* Verify USS by comparing hashes */ + if (memcmp(key_hash, expect, TKEY_HASH_SIZE) == 0) { + printf("\npassword correct\n"); + } else { + printf("\nwrong password\n"); + print_hex("Expected", expect, TKEY_HASH_SIZE); + print_hex("Got", key_hash, TKEY_HASH_SIZE); + return CMD_RET_FAILURE; + } + } else { + print_hex("Verification Hash", key_hash, TKEY_HASH_SIZE); + /* to verify USS later: tkey getkey */ + } + + return CMD_RET_SUCCESS; +} + +static int do_tkey_loadapp(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + struct udevice *dev; + const char *uss = NULL; + u32 ret, ulen = 0; + + if (argc != 1 && argc != 2) + return CMD_RET_USAGE; + + dev = tkey_get_device(); + if (!dev) + return CMD_RET_FAILURE; + + /* Optional USS parameter */ + if (argc == 2) { + uss = argv[1]; + ulen = strlen(uss); + if (ulen > TKEY_USS_MAX_SIZE) { + printf("USS too long (max %x bytes, got %x)\n", + TKEY_USS_MAX_SIZE, ulen); + return CMD_RET_FAILURE; + } + } + + printf("Loading signer app (%lx bytes)%s...", TKEY_SIGNER_SIZE, + uss ? " with USS" : ""); + ret = tkey_load_app_with_uss(dev, (const u8 *)__signer_1_0_0_begin, + TKEY_SIGNER_SIZE, (const u8 *)uss, ulen); + if (ret) { + if (ret == -ENOTSUPP) + printf("Invalid mode - replug device?\n"); + else + printf("Failed to load app (err %dE)\n", ret); + return CMD_RET_FAILURE; + } + printf("done\n"); + + return CMD_RET_SUCCESS; +} + +U_BOOT_LONGHELP(tkey, + "connect - Connect to TKey device\n" + "tkey fwmode - Check if device is in firmware or app mode\n" + "tkey getkey [verify-hash] - Get disk encryption key\n" + " Loads app with USS, derives key. Same USS always produces same key.\n" + " Optional verify-hash checks if USS is correct\n" + "tkey info - Show TKey device information\n" + "tkey loadapp [uss] - Load embedded signer app to TKey\n" + " Firmware mode only. Optional USS for key derivation\n" + "tkey signer - Show embedded signer binary information\n" + "tkey wrapkey - Create wrapping key from password and UDI"); + +U_BOOT_CMD_WITH_SUBCMDS(tkey, "Tillitis TKey security token operations", + tkey_help_text, + U_BOOT_SUBCMD_MKENT(connect, 1, 1, do_tkey_connect), + U_BOOT_SUBCMD_MKENT(fwmode, 1, 1, do_tkey_fwmode), + U_BOOT_SUBCMD_MKENT(getkey, 3, 1, do_tkey_getkey), + U_BOOT_SUBCMD_MKENT(info, 1, 1, do_tkey_info), + U_BOOT_SUBCMD_MKENT(loadapp, 2, 1, do_tkey_loadapp), + U_BOOT_SUBCMD_MKENT(signer, 1, 1, do_tkey_signer), + U_BOOT_SUBCMD_MKENT(wrapkey, 2, 1, do_tkey_wrapkey)); diff --git a/doc/usage/cmd/tkey.rst b/doc/usage/cmd/tkey.rst new file mode 100644 index 00000000000..6a9f37354eb --- /dev/null +++ b/doc/usage/cmd/tkey.rst @@ -0,0 +1,247 @@ +.. SPDX-License-Identifier: GPL-2.0+: + +.. index:: + single: tkey (command) + +tkey command +============ + +Synopsis +-------- + +:: + + tkey connect + tkey fwmode + tkey getkey [verify-hash] + tkey info + tkey loadapp [uss] + tkey signer + tkey wrapkey + +Description +----------- + +The *tkey* command provides an interface to interact with Tillitis TKey +security tokens. The TKey is a USB security device that can be used for +cryptographic operations, particularly for deriving encryption keys in a +secure and reproducible manner. + +The TKey operates in two modes: + +Firmware mode + The device starts in this mode after being plugged in. In firmware mode, + the device provides access to its Unique Device Identifier (UDI) and allows + loading applications. + +App mode + After an application is loaded, the device enters app mode. The UDI is no + longer accessible, but the loaded app can perform cryptographic operations. + +The primary use case is full disk encryption (FDE) key derivation, where the +TKey combines a User-Supplied Secret (USS, typically a password) with its +internal UDI to generate deterministic encryption keys. + + +tkey connect +~~~~~~~~~~~~ + +Test connectivity to a TKey device. This command attempts to find and connect +to the first available TKey device in the system. + + +tkey fwmode +~~~~~~~~~~~ + +Check whether the TKey device is currently in firmware mode or app mode. + +Firmware mode + The device has just been plugged in or reset. The UDI is accessible and + apps can be loaded. + +App mode + An application has been loaded and is running. The UDI is not accessible. + + +tkey getkey +~~~~~~~~~~~ + +Derive a disk encryption key by loading the embedded signer app with a +User-Supplied Secret (USS). This is the main command for full-disk-encryption +workflows. + +The command performs these steps: + +#. Loads the embedded signer app with the provided USS +#. Retrieves the public key from the signer app +#. Derives the disk encryption key (BLAKE2b hash of the public key) +#. Computes a verification hash (BLAKE2b hash of the disk key) + +The USS is typically a user password or passphrase. The same USS always produces +the same disk encryption key, making this suitable for unlocking encrypted +disks. + +If a verification hash is provided as the second argument, the command verifies +that the USS is correct by comparing the computed hash with the expected hash. +This is useful for validating user passwords before attempting to decrypt a +disk. + +uss + User-Supplied Secret (password/passphrase) for key derivation + +verify-hash + Optional 64-character hex string to verify the USS is correct + +The command outputs: + +Public Key + 32-byte Ed25519 public key derived from USS + +Disk Key + 32-byte encryption key (BLAKE2b-256 of public key) + +Verification Hash + 32-byte hash of disk key (save this for later verification) + + +tkey info +~~~~~~~~~ + +Display information about the TKey device, including its name, version, and +Unique Device Identifier (UDI). + +The UDI is only available in firmware mode. If the device is in app mode, the +command will report that the UDI is not available and suggest replugging the +device. + + +tkey loadapp +~~~~~~~~~~~~ + +Load the embedded signer application to the TKey device. This can only be done +when the device is in firmware mode. + +An optional USS (User-Supplied Secret) can be provided, which will be used by +the signer app for key derivation. If no USS is provided, the app loads without +a secret. + +After loading, the device transitions to app mode and the UDI becomes +inaccessible. + +uss + Optional User-Supplied Secret for the signer app + + +tkey signer +~~~~~~~~~~~ + +Display information about the embedded signer application binary that is +compiled into U-Boot. + + +tkey wrapkey +~~~~~~~~~~~~ + +Derive a wrapping key from a password and the device's UDI. This uses the +BLAKE2b-256 hash function to combine the UDI with the password. + +The wrapping key can be used to encrypt/decrypt other secrets. Unlike getkey, +this command does not load an app - it only requires the UDI, so it must be +run in firmware mode. + +The same password always produces the same wrapping key for a given device, +but different TKey devices (with different UDIs) will produce different +wrapping keys even with the same password. + +password + Password to combine with UDI for key derivation + + +Example +------- + +Connect to device:: + + => tkey connect + Connected to TKey device + +Check device mode:: + + => tkey fwmode + firmware mode + + => tkey loadapp + Loading signer app (a9c bytes)... + + => tkey fwmode + app mode + +Get device information (firmware mode):: + + => tkey info + Name0: tk1 Name1: mkdf Version: 4 + UDI: a0a1a2a3a4a5a6a7 + +Get device information (app mode):: + + => tkey info + Name0: tk1 Name1: sign Version: 4 + UDI not available - replug device + +Derive disk encryption key without verification:: + + => tkey getkey mypassword + Public Key: 1a2b3c4d... + Disk Key: 9f8e7d6c... + Verification Hash: 5a4b3c2d... + +Derive disk encryption key with verification (correct password):: + + => tkey getkey mypassword 5a4b3c2d1e0f... + Public Key: 1a2b3c4d... + Disk Key: 9f8e7d6c... + + password correct + +Derive disk encryption key with verification (wrong password):: + + => tkey getkey wrongpassword 5a4b3c2d1e0f... + Public Key: aaaa1111... + Disk Key: bbbb2222... + + wrong password + Expected: 5a4b3c2d1e0f... + Got: cccc3333... + +Load app without USS:: + + => tkey loadapp + Loading signer app (a9c bytes)... + +Load app with USS:: + + => tkey loadapp mypassword + Loading signer app (a9c bytes) with USS... + +Show signer binary information:: + + => tkey signer + signer binary: a9c bytes at 0x1234-0x5678 + +Derive wrapping key from password:: + + => tkey wrapkey mypassword + Wrapping Key: 95229cd376898f3fb022a627349dc985bc4675da580d2696bdd6f71f488e306c + + +Configuration +------------- + +The tkey command is available if CONFIG_CMD_TKEY is enabled. The command +requires a TKey driver to be configured (USB or serial). + + +See also +-------- + +* `Tillitis TKey documentation `_ diff --git a/doc/usage/index.rst b/doc/usage/index.rst index d1887f7d26a..701f03ca373 100644 --- a/doc/usage/index.rst +++ b/doc/usage/index.rst @@ -130,6 +130,7 @@ Shell commands cmd/source cmd/tcpm cmd/temperature + cmd/tkey cmd/tftpput cmd/trace cmd/true diff --git a/test/cmd/Makefile b/test/cmd/Makefile index ffb78f69041..3fc07f0cacf 100644 --- a/test/cmd/Makefile +++ b/test/cmd/Makefile @@ -43,6 +43,7 @@ obj-$(CONFIG_CMD_READ) += rw.o obj-$(CONFIG_CMD_SETEXPR) += setexpr.o obj-$(CONFIG_CMD_SMBIOS) += smbios.o obj-$(CONFIG_CMD_TEMPERATURE) += temperature.o +obj-$(CONFIG_CMD_TKEY) += tkey.o ifdef CONFIG_NET obj-$(CONFIG_CMD_WGET) += wget.o endif diff --git a/test/cmd/tkey.c b/test/cmd/tkey.c new file mode 100644 index 00000000000..605ce070f0e --- /dev/null +++ b/test/cmd/tkey.c @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Tests for tkey command + * + * Copyright (C) 2025 Canonical Ltd + */ + +#include +#include +#include +#include +#include + +/* Test 'tkey' command help output */ +static int cmd_test_tkey_help(struct unit_test_state *uts) +{ + ut_asserteq(1, run_command("tkey", 0)); + ut_assert_nextlinen("tkey - Tillitis TKey security token operations"); + ut_assert_nextline_empty(); + ut_assert_nextlinen("Usage:"); + ut_assert_nextlinen("tkey connect"); + ut_assert_skip_to_linen("tkey wrapkey"); + + return 0; +} +CMD_TEST(cmd_test_tkey_help, UTF_DM | UTF_SCAN_FDT | UTF_CONSOLE); + +/* Test 'tkey' subcommands with emulator */ +static int cmd_test_tkey_sandbox(struct unit_test_state *uts) +{ + struct udevice *dev; + + /* TKey device should be available in sandbox */ + ut_assertok(uclass_first_device_err(UCLASS_TKEY, &dev)); + + /* Test info command */ + ut_assertok(run_command("tkey info", 0)); + ut_assert_nextline("Name0: tk1 Name1: mkdf Version: 4"); + ut_assert_nextline("UDI: a0a1a2a3a4a5a6a7"); + + /* Test fwmode command - should be in firmware mode initially */ + ut_assertok(run_command("tkey fwmode", 0)); + ut_assert_nextline("firmware mode"); + + /* Test signer command */ + ut_assertok(run_command("tkey signer", 0)); + ut_assert_nextlinen("signer binary: "); + + /* Test wrapkey command */ + ut_assertok(run_command("tkey wrapkey testpass", 0)); + ut_assert_nextline("Wrapping Key: f91450f0396768885aeaee7f0cc3305de25f6e50db79e7978a83c08896fcbf0d"); + + /* Test getkey command */ + ut_assertok(run_command("tkey getkey testuss", 0)); + ut_assert_nextline("Public Key: 505152535455565758595a5b5c5d5e5f505152535455565758595a5b5c5d5e5f"); + ut_assert_nextline("Disk Key: 228b2f6abf8be05649b2417586150bbf3e1b3f669afa1c6151ddc72957933c21"); + ut_assert_nextline("Verification Hash: a72a46b8f8c7ff0824416ada886f62b6c2808896d71201a32814ab432c7a81cf"); + + /* After getkey, device should be in app mode */ + ut_assertok(run_command("tkey fwmode", 0)); + ut_assert_nextline("app mode"); + + ut_assert_console_end(); + + return 0; +} +CMD_TEST(cmd_test_tkey_sandbox, UTF_DM | UTF_SCAN_FDT | UTF_CONSOLE); From patchwork Sun Oct 19 07:23:07 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 631 Return-Path: X-Original-To: u-boot-concept@u-boot.org Delivered-To: u-boot-concept@u-boot.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1760858644; bh=NsFG9Ch1ztC23cBsVmVbA5MKvhGrDlv+T7vWyTblzDI=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=kmdhGXSJXlqDDNMrvGW9sJwj/RC0in9OiDCFLrRYRaungktB9Re9NTZNSEcCcYncc sCUxf0E2MQQc+pss0k+oElpXMmknT9oOzNeHEP+3Ea82kZ/+ep4JNXlFdJRM5S49yL Nlp+GKc8iMipYR7rzaNJag+t3vfou/5Xk1HuF5XuWCMCOTmdmZaMfT/Q86lS9wOmIJ zMku/fcxOB2pemNgn1Dw9p84F5gSElPmrChvdP2B+DzE4fzHsFwRvCB5NTjn2hJX7V PaBlTCWhONmloZdypAsUoQxaN78nCL6O6cza477uanW/woGPhfd+19XPSY/b5kJtOd XMSyeguw2CV3A== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 98333680DD for ; Sun, 19 Oct 2025 01:24:04 -0600 (MDT) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10024) with ESMTP id 5dbyzzfkkvy2 for ; Sun, 19 Oct 2025 01:24:04 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1760858644; bh=NsFG9Ch1ztC23cBsVmVbA5MKvhGrDlv+T7vWyTblzDI=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=kmdhGXSJXlqDDNMrvGW9sJwj/RC0in9OiDCFLrRYRaungktB9Re9NTZNSEcCcYncc sCUxf0E2MQQc+pss0k+oElpXMmknT9oOzNeHEP+3Ea82kZ/+ep4JNXlFdJRM5S49yL Nlp+GKc8iMipYR7rzaNJag+t3vfou/5Xk1HuF5XuWCMCOTmdmZaMfT/Q86lS9wOmIJ zMku/fcxOB2pemNgn1Dw9p84F5gSElPmrChvdP2B+DzE4fzHsFwRvCB5NTjn2hJX7V PaBlTCWhONmloZdypAsUoQxaN78nCL6O6cza477uanW/woGPhfd+19XPSY/b5kJtOd XMSyeguw2CV3A== Received: from mail.u-boot.org (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 85F355E435 for ; Sun, 19 Oct 2025 01:24:04 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1760858643; bh=NcRsEMzKULOEF3upyeDsbaGQn3SK1WuT8FPSuJo3glw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=JCXN3GbHUQk4X4n4rEY6eUKw5aYaDeryEUDce814wSwiCAv/BN79MkwMLI2Tbx6B1 DR5rlnnaJw1mmHTH7q1R+ao376HDbdrp4z5uajh18G2WOVE0dpBVNDUDo4n+ys62tp SA8dDuMFjtvjvaoGgqAcOrwEzVFHbxIPYU7d240JaNZJvFZpSkFwV9+sZCbnTXvvb8 8JErizsBrYx2jMo733vGN+gd2uj9cvfWEdhF0vxFYSvrLfZaKfW+fzkaYAkRQ90KF1 NolNV7K7rLh3qGLBB52afWIetLd3uC5FubBFlfDbCdrT51Gu+zhGql9wiTdOzd527f JxQw73wrGGOLA== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 8BE7D68198; Sun, 19 Oct 2025 01:24:03 -0600 (MDT) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10026) with ESMTP id Ix3X4Ke8t9bp; Sun, 19 Oct 2025 01:24:03 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1760858639; bh=qA5TfuN2G7i3uZXxYSKmY0muey7aby42ZuLzOBWwbGc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=gr7Rk88ECJkNN7b9IEJ3Jv9BeEGXvcJVNRKb1OjvqPto/ODq+XSvfbno4JnB2Oeg4 yjOsmSB/rH6W7JE1VoXcSO54ANkXsNgjKKarFtkA1dqRTC4Ophkyn52HYHq5FB85JX GqT10/FDT+lZeKELgOT/1+vSkVFMR5s4rnIFBNVLtaQ3QIHfHV47M2YGzx9te3nKtV TMrRt+qZcUovDGIaHPN8WAS4ostvaEO6ic06ZeFK6JXlGJVcZyqYx4GcyihVD1mMZR 4CX7/4MOet7YpUga0vYcDtalJ9iC88VlBFjnjV8zrMFB7JEnyuDTB3DyLiNJXdsdyy Jfqi4mdbd1mwA== Received: from u-boot.org (unknown [73.34.74.121]) by mail.u-boot.org (Postfix) with ESMTPSA id 3D6CC680DD; Sun, 19 Oct 2025 01:23:59 -0600 (MDT) From: Simon Glass To: U-Boot Concept Date: Sun, 19 Oct 2025 01:23:07 -0600 Message-ID: <20251019072313.3235339-8-sjg@u-boot.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251019072313.3235339-1-sjg@u-boot.org> References: <20251019072313.3235339-1-sjg@u-boot.org> MIME-Version: 1.0 Message-ID-Hash: BZZFYRY6SJB4ZWJPMOBDM5L65BIP4LVY X-Message-ID-Hash: BZZFYRY6SJB4ZWJPMOBDM5L65BIP4LVY X-MailFrom: sjg@u-boot.org X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: Simon Glass , Claude X-Mailman-Version: 3.3.10 Precedence: list Subject: [Concept] [PATCH 7/8] sandbox: Add TTY configuration for TKey serial communication List-Id: Discussion and patches related to U-Boot Concept Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: From: Simon Glass Add os_tty_set_params() function to configure terminal devices for serial communication with TKey devices: - Custom baud rate of 62500 using termios2 - 8n1 configuration (8 data bits, no parity, 1 stop bit) - Raw mode for binary communication - Appropriate timeouts for frame-based protocols This is needed for serial-based TKey communication on sandbox, allowing U-Boot to communicate with TKey security tokens via a serial port. Co-developed-by: Claude Signed-off-by: Simon Glass --- arch/sandbox/cpu/Makefile | 4 +-- arch/sandbox/cpu/tty.c | 56 +++++++++++++++++++++++++++++++++++++++ include/os.h | 12 +++++++++ 3 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 arch/sandbox/cpu/tty.c diff --git a/arch/sandbox/cpu/Makefile b/arch/sandbox/cpu/Makefile index 35f853776f7..ef9a01c5d7c 100644 --- a/arch/sandbox/cpu/Makefile +++ b/arch/sandbox/cpu/Makefile @@ -5,7 +5,7 @@ # (C) Copyright 2000-2003 # Wolfgang Denk, DENX Software Engineering, wd@denx.de. -obj-y := cache.o cpu.o mem.o state.o os.o +obj-y := cache.o cpu.o mem.o state.o os.o tty.o ifdef CONFIG_FUZZ obj-y += fuzz.o else @@ -17,7 +17,7 @@ obj-$(CONFIG_XPL_BUILD) += spl.o obj-$(CONFIG_ETH_SANDBOX_RAW) += eth-raw-os.o # Compile these files with system headers -CFLAGS_USE_SYSHDRS := eth-raw-os.o fuzz.o main.o os.o sdl.o +CFLAGS_USE_SYSHDRS := eth-raw-os.o fuzz.o main.o os.o sdl.o tty.o # sdl.c fails to build with -fshort-wchar using musl cmd_cc_sdl.o = $(CC) $(filter-out -nostdinc -fshort-wchar, \ diff --git a/arch/sandbox/cpu/tty.c b/arch/sandbox/cpu/tty.c new file mode 100644 index 00000000000..04c6fff9bbe --- /dev/null +++ b/arch/sandbox/cpu/tty.c @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2024 U-Boot TKey Support + * + * TTY configuration for TKey serial communication + */ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include + +int os_tty_set_params(int fd) +{ + struct termios2 tty2; + + /* Get current termios2 attributes */ + if (ioctl(fd, TCGETS2, &tty2) != 0) + return -errno; + + /* Configure for raw mode */ + tty2.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON); + tty2.c_oflag &= ~OPOST; + tty2.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); + tty2.c_cflag &= ~(CSIZE | PARENB); + + /* 8N1 configuration */ + tty2.c_cflag |= CS8; /* 8 data bits */ + tty2.c_cflag &= ~PARENB; /* No parity */ + tty2.c_cflag &= ~CSTOPB; /* 1 stop bit */ + tty2.c_cflag |= (CLOCAL | CREAD); /* Enable receiver, ignore modem lines */ + + /* Set custom baud rate using termios2 */ + tty2.c_cflag &= ~CBAUD; + tty2.c_cflag |= BOTHER; /* Use custom baud rate */ + tty2.c_ispeed = 62500; /* Input speed */ + tty2.c_ospeed = 62500; /* Output speed */ + + /* Blocking with timeout for complete frames */ + tty2.c_cc[VMIN] = 1; /* Wait for at least 1 character */ + tty2.c_cc[VTIME] = 50; /* 5 second timeout */ + + /* Apply termios2 settings */ + if (ioctl(fd, TCSETS2, &tty2) != 0) + return -errno; + + /* Flush buffers */ + if (ioctl(fd, TCFLSH, TCIOFLUSH) != 0) + return -errno; + + return 0; +} diff --git a/include/os.h b/include/os.h index bc4c9073cff..1b2243d46d4 100644 --- a/include/os.h +++ b/include/os.h @@ -185,6 +185,18 @@ void os_raise_sigalrm(void); */ void os_tty_raw(int fd, bool allow_sigs); +/** + * os_tty_set_params() - configure terminal parameters + * + * Configure the terminal device for serial communication with specific + * baud rate, data bits, parity, and flow control suitable for embedded + * device protocols like TKey. + * + * @fd: file descriptor of terminal device + * Return: 0 on success, -errno on error + */ +int os_tty_set_params(int fd); + /** * os_fd_restore() - restore the tty to its original mode * From patchwork Sun Oct 19 07:23:08 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 632 Return-Path: X-Original-To: u-boot-concept@u-boot.org Delivered-To: u-boot-concept@u-boot.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1760858647; bh=O85K0sGUhuZPseHfHA6LpUsGUjIwVs2nT0gYf1NZaHI=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=Cw0MJ0nQKHFhkxiufj7RvNuSkLJkHM2SsNeduOhu7moePC0NsI0cTLe8QgYAobB6Z dT0rjqWnK3GRrUfxtCCQGkhRMhkdL0qn/7FnrNAYWbwe+xu84SpIt0l0oFi0qcFORk Z0oABm07cRbMS053G9US5Hkx+I2WczmxLs0iqMa/84yS9sMWrvJ3LiPwMGi6Wo36kM rbASaRjxoJxPsiCQ66ZVhH1RFWjJzOVV5JjRFGpVOnR7gVlhpNG8ee0ZdyzdVVfsVq 5uzntq98ar+PdnIc55umqNr4tMhzssN8CVzuT/MMa2735aS9NW5aFJ2RQ8jY2Yw3+/ HmaAPg+8sFaHQ== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 07B16681C2 for ; Sun, 19 Oct 2025 01:24:07 -0600 (MDT) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10024) with ESMTP id WwSFL8H7EBba for ; Sun, 19 Oct 2025 01:24:06 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1760858646; bh=O85K0sGUhuZPseHfHA6LpUsGUjIwVs2nT0gYf1NZaHI=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=OZpNDUMC3+nHhICSamDmWv+ZqqsmalmMXToTQrCloT+6G5ji++QrUDe8IyQQzY1jC fXgu3QjsJZ7lCInEbjm5uJL+3ZJbyYCRPHhg8W0x5A7ACk0hYFOvI2oZlI37IuTHM8 fioQ1/HSB53jMXFxpMhovmf9PK2lAtJW+Q9OrEVe4lQVwd4+4iqJVbvWwDka6FJvcG 23JnaiOUknjX1FdmSpJotEtMMRO0y8QjdjhFTGS5f69dk01Q3Wow5MNrvt5Kgaud6p vv77dlDQYI28WODNQtVnwVasQx0goOQx09Zhue7pXmwN4iyTigSQ889e+xsgzzmeqO LoXobs+bEWF7Q== Received: from mail.u-boot.org (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 04387680DD for ; Sun, 19 Oct 2025 01:24:06 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1760858644; bh=59E71ur1Kb1slqiVVPJh5tN3Un1EJ1cSL1TnCy7pMw4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Hx5I62MTjS6hIxvaySxm1C+OTKWzPk4VkwDbr6V6jtz/ci4SRYwCGvptB3vxqvd3Z pL5T3d9G/UDNKnj4nXPZYsekkCk/wDHyd/G6c0FsRdMHKNGZk694M0OW5MmrZ83t7Z hMWCle3fHdN6TGfvnMcbjosCWncS4sIlE2S9dg9hlqe5ankVJvSdK65DWPAmsq1gT4 IGe4sm6Sl2PeEPo0gqsAMsy5NhN69U+PnYaeqGZsu804heKb4YwKbnAT4wqVk1wZkF 25nr8GkjQvyXaD25RxV3q5OUHMVs3Fw0kGxSPYXl/uKXRH7SQ9PlUDS+gD1ek86p9x ahp5EfT4BWhsQ== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 79B8D68198; Sun, 19 Oct 2025 01:24:04 -0600 (MDT) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10026) with ESMTP id orjfYghyAhoI; Sun, 19 Oct 2025 01:24:04 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1760858644; bh=UuCokSPEBeQQaBSHhGbyMjuDvuHuLlohj1to1WkBHak=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=knacEnGPeDw9VqZTxdY88/Kl9LwWRZrOQZKQUh3KTS85NW0uifB7mXevMJ6BFHxyR lLT4kZQs4uk/RHVBQfF5rWdOYVZqGL0bTVlIWQSi93d18DLAGMjH0HfHVbRWfDtUNn 1cFvmoHa7f8kVNjJHFJPO6Y/ojxDkRIAqYir5h8boNJlZK2Y8tHp+NxbVw2qrcdIG/ yXAT5/sPU3URbtqx2vZFQiyHFS7t311R/2N48pRTnUG0JQUiZIgzOMfcK38SF8ps6N vMFzmBIib5t9KlH1ybLU2tN8BQXUypY7q0SjFfnMFNBzo+57yjNjYcg+IfwqgTm+R5 ZvZuiWPVZWDbQ== Received: from u-boot.org (unknown [73.34.74.121]) by mail.u-boot.org (Postfix) with ESMTPSA id CC8055E435; Sun, 19 Oct 2025 01:24:03 -0600 (MDT) From: Simon Glass To: U-Boot Concept Date: Sun, 19 Oct 2025 01:23:08 -0600 Message-ID: <20251019072313.3235339-9-sjg@u-boot.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251019072313.3235339-1-sjg@u-boot.org> References: <20251019072313.3235339-1-sjg@u-boot.org> MIME-Version: 1.0 Message-ID-Hash: DKKKN7UA5BDI4GBEI4HA7GYSJBHKDAX6 X-Message-ID-Hash: DKKKN7UA5BDI4GBEI4HA7GYSJBHKDAX6 X-MailFrom: sjg@u-boot.org X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: Simon Glass , Claude X-Mailman-Version: 3.3.10 Precedence: list Subject: [Concept] [PATCH 8/8] tkey: Add a sandbox driver for real TKey hardware List-Id: Discussion and patches related to U-Boot Concept Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: From: Simon Glass Add a sandbox TKey driver that enables communication with physical TKey devices via serial port (/dev/ttyACM0). This allows testing TKey functionality in sandbox with real hardware. The driver: - Opens the configured device path from device tree - Configures TTY parameters using os_tty_set_params() - Implements read/write operations for TKey protocol - Supports both read() and read_all() operations Device tree configuration: tkey-test { compatible = "sandbox,tkey"; sandbox,device-path = "/dev/ttyACM0"; }; Co-developed-by: Claude Signed-off-by: Simon Glass --- arch/sandbox/dts/sandbox.dtsi | 5 + drivers/misc/Makefile | 1 + drivers/misc/tkey_sandbox.c | 170 ++++++++++++++++++++++++++++++++++ 3 files changed, 176 insertions(+) create mode 100644 drivers/misc/tkey_sandbox.c diff --git a/arch/sandbox/dts/sandbox.dtsi b/arch/sandbox/dts/sandbox.dtsi index 48e34a7aee5..e5d6be633fb 100644 --- a/arch/sandbox/dts/sandbox.dtsi +++ b/arch/sandbox/dts/sandbox.dtsi @@ -356,6 +356,11 @@ clock-frequency = <1000000>; }; + tkey-test { + compatible = "sandbox,tkey"; + sandbox,device-path = "/dev/ttyACM0"; + }; + tpm { compatible = "google,sandbox-tpm"; }; diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 298bc1c0a69..cd7170986ac 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_SANDBOX) += p2sb_sandbox.o p2sb_emul.o obj-$(CONFIG_SANDBOX) += swap_case.o ifdef CONFIG_SANDBOX obj-$(CONFIG_TKEY) += tkey_emul.o +obj-$(CONFIG_TKEY) += tkey_sandbox.o endif endif diff --git a/drivers/misc/tkey_sandbox.c b/drivers/misc/tkey_sandbox.c new file mode 100644 index 00000000000..9b26bd36f1b --- /dev/null +++ b/drivers/misc/tkey_sandbox.c @@ -0,0 +1,170 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2025 Canonical Ltd + * + * Sandbox TKey driver for testing TKey functionality in sandbox + * Communicates with TKey devices via /dev/ttyACM0 + */ + +#define LOG_CATEGORY UCLASS_TKEY + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * struct tkey_sandbox_priv - private information about sandbox + * + * @path: Path to the tkey device, e.g. "/dev/ttyACM0" + * @fd: File descriptor + */ +struct tkey_sandbox_priv { + char *path; + int fd; +}; + +static int tkey_sandbox_read(struct udevice *dev, void *buffer, int len, + int timeout_ms) +{ + struct tkey_sandbox_priv *priv = dev_get_priv(dev); + u8 *buf = buffer; + int total, ret; + + if (priv->fd < 0) + return -ENODEV; + + log_debug("Reading %d bytes...\n", len); + + /* Read data in chunks until we get the full amount */ + for (total = 0; total < len; total += ret) { + ret = os_read(priv->fd, buf + total, len - total); + log_debug("Read attempt returned: %d (total: %d/%d)\n", ret, + total, len); + + if (ret < 0) { + log_debug("Read failed with error %d\n", ret); + return -EIO; + } + + if (!ret) { + if (!total) { + log_debug("Read timeout - no data received\n"); + return -EIO; + } + /* Partial read - break and return what we got */ + log_debug("Partial read, got %x/%x bytes\n", total, + len); + break; + } + } + + log_debug("Read %d bytes:", total); + for (int i = 0; i < total; i++) + log_debug(" %02x", buf[i]); + log_debug("\n"); + + return total; +} + +static int tkey_sandbox_write(struct udevice *dev, const void *buffer, int len) +{ + struct tkey_sandbox_priv *priv = dev_get_priv(dev); + int ret; + + if (priv->fd < 0) + return -ENODEV; + + log_debug("Writing %d bytes:", len); + for (int i = 0; i < len; i++) + log_debug(" %02x", ((u8*)buffer)[i]); + log_debug("\n"); + + ret = os_write(priv->fd, buffer, len); + if (ret < 0) { + log_debug("Write failed with error %d\n", ret); + return -EIO; + } + log_debug("Wrote %d bytes\n", ret); + + return ret; +} + +static int tkey_sandbox_probe(struct udevice *dev) +{ + struct tkey_sandbox_priv *priv = dev_get_priv(dev); + const char *device_path; + + /* Get device path from device tree or use default */ + device_path = dev_read_string(dev, "sandbox,device-path"); + if (!device_path) + device_path = "/dev/ttyACM0"; + + priv->path = strdup(device_path); + if (!priv->path) + return -ENOMEM; + + /* Open the serial device */ + priv->fd = os_open(priv->path, OS_O_RDWR); + if (priv->fd < 0) { + log_err("Failed to open %s (error %d)\n", priv->path, priv->fd); + free(priv->path); + return -ENODEV; + } + + /* Configure serial port for raw mode */ + if (os_tty_set_params(priv->fd) < 0) { + log_err("Failed to configure serial port %s\n", priv->path); + os_close(priv->fd); + free(priv->path); + return -ENODEV; + } + log_debug("Connected to %s with serial parameters configured\n", + priv->path); + + return 0; +} + +static int tkey_sandbox_remove(struct udevice *dev) +{ + struct tkey_sandbox_priv *priv = dev_get_priv(dev); + + if (priv->fd >= 0) { + os_close(priv->fd); + priv->fd = -1; + } + + if (priv->path) { + free(priv->path); + priv->path = NULL; + } + log_debug("Disconnected\n"); + + return 0; +} + +/* TKey uclass operations */ +static const struct tkey_ops tkey_sandbox_ops = { + .read = tkey_sandbox_read, + .write = tkey_sandbox_write, +}; + +static const struct udevice_id tkey_sandbox_ids[] = { + { .compatible = "sandbox,tkey" }, + { } +}; + +U_BOOT_DRIVER(tkey_sandbox) = { + .name = "tkey_sandbox", + .id = UCLASS_TKEY, + .of_match = tkey_sandbox_ids, + .probe = tkey_sandbox_probe, + .remove = tkey_sandbox_remove, + .ops = &tkey_sandbox_ops, + .priv_auto = sizeof(struct tkey_sandbox_priv), +};