From 776a970d4e82905dec46f9c868553783490db49a Mon Sep 17 00:00:00 2001 From: Manuel Domke Date: Wed, 25 Mar 2026 23:20:40 +0100 Subject: [PATCH 01/18] deps: upgrade trussed ecosystem to latest versions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - interchange 0.2.2 → 0.3 - apdu-dispatch 0.1.1 → 0.3 - ctaphid-dispatch 0.1.1 → 0.3 - ctap-types 0.1 → 0.4 - fido-authenticator 0.1.1 → 0.2 - usbd-ccid 0.1.0 → 0.3 - usbd-ctaphid 0.1.0 → 0.3 - littlefs2 0.3.2 → 0.6 (git tag v0.6.1-nitrokey.1) - trussed: pin to git rev e107ed3 - admin-app: pin to git tag v0.1.0-nitrokey.20 - trussed-staging v0.3.3 with hkdf/fs-info/manage features (required by fido-authenticator 0.2) - Add trussed-core, trussed-fs-info, trussed-hkdf, trussed-manage, ref-swap deps - [patch.crates-io] for littlefs2, littlefs2-sys, littlefs2-core (resolves DynFilesystem trait version mismatch) - Remove oath-authenticator from default features - Remove trussed/clients-N feature flags (no longer needed with new trussed API) - Update runners/pc and component Cargo.toml files to match --- components/ndef-app/Cargo.toml | 4 +- components/nfc-device/Cargo.toml | 4 +- runners/lpc55/Cargo.lock | 917 ++++++++++++++++++++----------- runners/lpc55/Cargo.toml | 43 +- runners/pc/Cargo.toml | 25 +- 5 files changed, 655 insertions(+), 338 deletions(-) diff --git a/components/ndef-app/Cargo.toml b/components/ndef-app/Cargo.toml index d4a6dad5..f2225dfc 100644 --- a/components/ndef-app/Cargo.toml +++ b/components/ndef-app/Cargo.toml @@ -7,7 +7,7 @@ edition = "2024" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -heapless = "0.7" +heapless = "0.8" -apdu-dispatch = "0.1" +apdu-dispatch = "0.3" iso7816 = "0.1" diff --git a/components/nfc-device/Cargo.toml b/components/nfc-device/Cargo.toml index e7e5b39f..d9c3b6c0 100644 --- a/components/nfc-device/Cargo.toml +++ b/components/nfc-device/Cargo.toml @@ -10,6 +10,6 @@ embedded-time = "0.12" heapless = "0.7" nb = "1" -apdu-dispatch = "0.1" +apdu-dispatch = "0.3" iso7816 = "0.1" -interchange = "0.2.1" +interchange = "0.3" diff --git a/runners/lpc55/Cargo.lock b/runners/lpc55/Cargo.lock index 1dbdc1f0..1db77f83 100644 --- a/runners/lpc55/Cargo.lock +++ b/runners/lpc55/Cargo.lock @@ -5,36 +5,44 @@ version = 3 [[package]] name = "admin-app" version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67d9f4831720ac3f95d708922b71cbec0d085548affb935f4af35395af28366c" +source = "git+https://github.com/Nitrokey/admin-app.git?tag=v0.1.0-nitrokey.20#ff574d810f718c7ce0912512f6c551ca2ea7c88a" dependencies = [ - "apdu-dispatch", - "ctaphid-dispatch", + "apdu-app", + "cbor-smol", + "ctaphid-app", "delog", + "heapless 0.7.17", + "heapless-bytes", + "hex-literal 0.4.1", "iso7816", + "littlefs2-core", + "serde", + "strum_macros", "trussed", + "trussed-core", + "trussed-manage", ] [[package]] name = "aead" -version = "0.4.3" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b613b8e1e3cf911a086f53f03bf286f52fd7a7258e4fa606f0ef220d39d8877" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" dependencies = [ - "generic-array 0.14.9", + "crypto-common", + "generic-array 0.14.7", "heapless 0.7.17", ] [[package]] name = "aes" -version = "0.7.5" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" dependencies = [ "cfg-if", - "cipher", + "cipher 0.4.4", "cpufeatures", - "opaque-debug", ] [[package]] @@ -63,7 +71,20 @@ checksum = "898c4ae30eeab17a209d5576cf7b312fdbee4d1cb739333c1308908fc841a5fb" dependencies = [ "delog", "heapless 0.7.17", - "interchange", + "interchange 0.2.2", + "iso7816", +] + +[[package]] +name = "apdu-dispatch" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d6e6883b2c23b9fe1a488913705c7b68f751bdb73da036ff8191da729337a5d" +dependencies = [ + "apdu-app", + "delog", + "heapless 0.7.17", + "interchange 0.3.2", "iso7816", ] @@ -75,7 +96,7 @@ checksum = "45403b49e3954a4b8428a0ac21a4b7afadccf92bfd96273f1a58cd4812496ae0" dependencies = [ "generic-array 0.12.4", "generic-array 0.13.3", - "generic-array 0.14.9", + "generic-array 0.14.7", "stable_deref_trait", ] @@ -111,21 +132,20 @@ checksum = "f8fe8f5a8a398345e52358e18ff07cc17a568fbca5c6f73873d3a62056309603" [[package]] name = "bindgen" -version = "0.56.0" +version = "0.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2da379dbebc0b76ef63ca68d8fc6e71c0f13e59432e0987e508c1820e6ab5239" +checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.10.0", "cexpr", "clang-sys", - "lazy_static", - "lazycell", - "peeking_take_while", + "itertools", "proc-macro2", "quote", "regex", "rustc-hash", - "shlex 0.1.1", + "shlex", + "syn 2.0.114", ] [[package]] @@ -152,24 +172,26 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" dependencies = [ - "generic-array 0.14.9", + "generic-array 0.14.7", ] [[package]] -name = "block-modes" -version = "0.8.1" +name = "block-buffer" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cb03d1bed155d89dce0f845b7899b18a9a163e148fd004e1c28421a783e2d8e" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ - "block-padding", - "cipher", + "generic-array 0.14.7", ] [[package]] name = "block-padding" -version = "0.2.1" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" +checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93" +dependencies = [ + "generic-array 0.14.7", +] [[package]] name = "board" @@ -192,15 +214,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] -name = "cbor-smol" -version = "0.4.1" +name = "cbc" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f2529cc8240fcc91e8642754ce85e5360c2ee7f4435a76aa150e4ed746a5da4" +checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6" dependencies = [ - "delog", - "heapless 0.7.17", - "heapless-bytes 0.3.0", - "serde", + "cipher 0.4.4", ] [[package]] @@ -211,7 +230,7 @@ checksum = "0b6dd31f7069836e87169bc5910212571b873cebe389c7c7f2d8b1fb3e55c80d" dependencies = [ "delog", "heapless 0.7.17", - "heapless-bytes 0.3.0", + "heapless-bytes", "serde_core", ] @@ -222,14 +241,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47b26a0954ae34af09b50f0de26458fa95369a0d478d8236d3f93082b219bd29" dependencies = [ "find-msvc-tools", - "shlex 1.3.0", + "shlex", ] [[package]] name = "cexpr" -version = "0.4.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4aedb84272dbe89af497cf81375129abda4fc0a9e7c5d317498c15cc30c0d27" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" dependencies = [ "nom", ] @@ -242,26 +261,24 @@ checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "chacha20" -version = "0.7.3" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f08493fa7707effc63254c66c6ea908675912493cd67952eda23c09fae2610b1" +checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" dependencies = [ "cfg-if", - "cipher", + "cipher 0.4.4", "cpufeatures", - "rand_core", - "zeroize", ] [[package]] name = "chacha20poly1305" -version = "0.8.2" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6547abe025f4027edacd9edaa357aded014eecec42a5070d9b885c3c334aba2" +checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35" dependencies = [ "aead", "chacha20", - "cipher", + "cipher 0.4.4", "poly1305", "zeroize", ] @@ -272,7 +289,18 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" dependencies = [ - "generic-array 0.14.9", + "generic-array 0.14.7", +] + +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", + "zeroize", ] [[package]] @@ -320,24 +348,13 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "cosey" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dae70ebe61c8f9b022729efe68ed35d9330631edd39d873de975083deb4c74f8" -dependencies = [ - "heapless-bytes 0.2.0", - "serde", - "serde_repr", -] - [[package]] name = "cosey" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75494895fa1a9713ca725ddf2db084ee84fb0c20938fdd7c89293febe732d30a" dependencies = [ - "heapless-bytes 0.3.0", + "heapless-bytes", "serde", "serde_repr", ] @@ -359,65 +376,77 @@ checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" [[package]] name = "crypto-bigint" -version = "0.2.11" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f83bd3bb4314701c568e340cd8cf78c975aa0ca79e03d3f6d1677d5b0c9c0c03" +checksum = "8658c15c5d921ddf980f7fe25b1e82f4b7a4083b2c4985fea4922edb8e43e07d" dependencies = [ - "generic-array 0.14.9", + "generic-array 0.14.7", "rand_core", "subtle", "zeroize", ] [[package]] -name = "crypto-mac" -version = "0.11.1" +name = "crypto-common" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" dependencies = [ - "generic-array 0.14.9", - "subtle", + "generic-array 0.14.7", + "typenum", ] [[package]] -name = "cstr_core" -version = "0.2.6" +name = "crypto-mac" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd98742e4fdca832d40cab219dc2e3048de17d873248f83f17df47c1bea70956" +checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" dependencies = [ - "cty", - "memchr", + "generic-array 0.14.7", + "subtle", ] [[package]] name = "ctap-types" -version = "0.1.2" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e4fa005ff525537460e1fd70a1ff4f417ae4a6ed14887f3e4720221e20f7562" +checksum = "bb8b105c5e728afd373e99874f0c1911c170b3a56848456cc16feb4506321606" dependencies = [ "bitflags 1.3.2", - "cbor-smol 0.4.1", - "cosey 0.3.2", + "cbor-smol", + "cosey", "delog", "heapless 0.7.17", - "heapless-bytes 0.3.0", - "interchange", + "heapless-bytes", "iso7816", "serde", "serde-indexed", + "serde_bytes", "serde_repr", ] +[[package]] +name = "ctaphid-app" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fe93489fe96c998488d0843dffea35c02ed9add2585e55228e1d45988727ecc" +dependencies = [ + "heapless-bytes", + "trussed-core", +] + [[package]] name = "ctaphid-dispatch" -version = "0.1.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9e775f67c3a82a134a9e23e0771d3fb3808612ab03843cd31a9b0312004bdde" +checksum = "38fd4316573df369820c5a9f8285fe522d8871c0b20bcf7d390f73b8e6caee28" dependencies = [ + "ctaphid-app", "delog", - "heapless 0.7.17", - "heapless-bytes 0.3.0", - "interchange", + "heapless-bytes", + "interchange 0.3.2", + "ref-swap", + "trussed-core", ] [[package]] @@ -477,16 +506,6 @@ dependencies = [ "log", ] -[[package]] -name = "der" -version = "0.2.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce93ba4502a73722aa4b955d97f4b1bd26f4f8da74315399ca58fb88fe2bdaae" -dependencies = [ - "der_derive 0.2.2", - "typenum", -] - [[package]] name = "der" version = "0.4.5" @@ -494,19 +513,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79b71cca7d95d7681a4b3b9cdf63c8dbc3730d0584c2c74e31416d64a90493f4" dependencies = [ "crypto-bigint", - "der_derive 0.4.1", -] - -[[package]] -name = "der_derive" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4fbbc8e9e0db3a9068cffa43dcf0e314eb9feff083b7afa6eaa9e698412bb23" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", - "synstructure 0.12.6", + "der_derive", ] [[package]] @@ -523,13 +530,11 @@ dependencies = [ [[package]] name = "des" -version = "0.7.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac41dd49fb554432020d52c875fc290e110113f864c6b1b525cd62c7e7747a5d" +checksum = "ffdd80ce8ce993de27e9f063a444a4d53ce8e8db4c1f00cc03af5ad5a9867a1e" dependencies = [ - "byteorder", - "cipher", - "opaque-debug", + "cipher 0.4.4", ] [[package]] @@ -538,7 +543,18 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" dependencies = [ - "generic-array 0.14.9", + "generic-array 0.14.7", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer 0.10.4", + "crypto-common", + "subtle", ] [[package]] @@ -547,30 +563,36 @@ version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43ee23aa5b4f68c7a092b5c3beb25f50c406adc75e2363634f242f28ab255372" dependencies = [ - "der 0.4.5", + "der", "elliptic-curve", - "hmac", - "signature", + "hmac 0.11.0", + "signature 1.3.2", ] [[package]] name = "ed25519" -version = "1.5.3" +version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" dependencies = [ - "signature", + "signature 2.2.0", ] +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + [[package]] name = "elliptic-curve" -version = "0.10.6" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "beca177dcb8eb540133e7680baff45e7cc4d93bf22002676cec549f82343721b" +checksum = "83e5c176479da93a0983f0a6fdc3c1b8e7d5be0d7fe3fe05a99f15b96582b9a8" dependencies = [ "crypto-bigint", "ff", - "generic-array 0.14.9", + "generic-array 0.14.7", "group", "rand_core", "subtle", @@ -622,6 +644,19 @@ dependencies = [ "num", ] +[[package]] +name = "encrypted_container" +version = "0.1.0" +source = "git+https://github.com/Nitrokey/trussed-secrets-app?tag=v0.14.0#e72e80491b79962ac0f8030581eca8ba0004a732" +dependencies = [ + "cbor-smol", + "delog", + "heapless 0.7.17", + "heapless-bytes", + "serde", + "trussed-core", +] + [[package]] name = "equivalent" version = "1.0.2" @@ -640,22 +675,27 @@ dependencies = [ [[package]] name = "fido-authenticator" -version = "0.1.1" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda469ecf5b58ba898e1a6e68f99529b568e24490f45ced8222240d10d7c6508" +checksum = "0f7367d82579f74638875b1a277d55a4c23a3b4865b53d26cd315e99aa528b42" dependencies = [ - "apdu-dispatch", + "apdu-app", + "cbor-smol", + "cosey", "ctap-types", - "ctaphid-dispatch", + "ctaphid-app", "delog", "heapless 0.7.17", - "interchange", + "heapless-bytes", "iso7816", - "littlefs2 0.3.2", + "littlefs2-core", "serde", "serde-indexed", - "serde_cbor", - "trussed", + "serde_bytes", + "sha2 0.10.9", + "trussed-core", + "trussed-fs-info", + "trussed-hkdf", ] [[package]] @@ -737,6 +777,19 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d758ba1b47b00caf47f24925c0074ecb20d6dfcffe7f6d53395c0465674841a" +[[package]] +name = "generator" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cc16584ff22b460a382b7feec54b23d2908d858152e5739a120b949293bd74e" +dependencies = [ + "cc", + "libc", + "log", + "rustversion", + "windows", +] + [[package]] name = "generator" version = "0.8.8" @@ -772,9 +825,9 @@ dependencies = [ [[package]] name = "generic-array" -version = "0.14.9" +version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", @@ -797,12 +850,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "half" -version = "1.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b43ede17f21864e81be2fa654110bf1e793774238d86ef8555c37e6519c0403" - [[package]] name = "hash32" version = "0.1.1" @@ -849,7 +896,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "634bd4d29cbf24424d0a4bfcbf80c6960129dc24424752a7d1d1390607023422" dependencies = [ "as-slice", - "generic-array 0.14.9", + "generic-array 0.14.7", "hash32 0.1.1", "stable_deref_trait", ] @@ -888,17 +935,6 @@ dependencies = [ "stable_deref_trait", ] -[[package]] -name = "heapless-bytes" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1729797499905912c3e4d6d20d5981720da157a27b834531d721905fb8a9b48a" -dependencies = [ - "heapless 0.6.1", - "serde", - "typenum", -] - [[package]] name = "heapless-bytes" version = "0.3.0" @@ -907,16 +943,36 @@ checksum = "7285eba272c6af3e9f15fb9e1c1b6e7d35aa70580ffe0d47af017e97dfb6f48b" dependencies = [ "heapless 0.7.17", "serde", - "serde_cbor", "typenum", ] +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + [[package]] name = "hex-literal" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ebdb29d2ea9ed0083cd8cece49bbd968021bd99b0849edb4a9a7ee0fdf6a4e0" +[[package]] +name = "hex-literal" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" + +[[package]] +name = "hkdf" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +dependencies = [ + "hmac 0.12.1", +] + [[package]] name = "hmac" version = "0.11.0" @@ -924,7 +980,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" dependencies = [ "crypto-mac", - "digest", + "digest 0.9.0", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.7", ] [[package]] @@ -947,12 +1012,31 @@ dependencies = [ "hashbrown 0.16.1", ] +[[package]] +name = "inout" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" +dependencies = [ + "block-padding", + "generic-array 0.14.7", +] + [[package]] name = "interchange" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "310d743c23f798f10d5ba2f77fdd3eff06aaf2d8f8b9d78beba7fb1167f4ccbf" +[[package]] +name = "interchange" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cc2a6b02f14a47afb0dbccdf96ae4f527ab32b05f78918d9da92e336bcbc222" +dependencies = [ + "loom 0.5.6", +] + [[package]] name = "iso7816" version = "0.1.4" @@ -963,16 +1047,19 @@ dependencies = [ ] [[package]] -name = "lazy_static" -version = "1.5.0" +name = "itertools" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] [[package]] -name = "lazycell" -version = "1.3.0" +name = "lazy_static" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" @@ -992,53 +1079,34 @@ dependencies = [ [[package]] name = "littlefs2" -version = "0.3.2" -dependencies = [ - "bitflags 1.3.2", - "cstr_core", - "cty", - "delog", - "generic-array 0.14.9", - "heapless 0.7.17", - "littlefs2-sys", - "serde", -] - -[[package]] -name = "littlefs2" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95c72bdf63e7ad35f391e60c48e4c32560038f1d3a0dd97f90a2891ce09160bf" +version = "0.6.1" +source = "git+https://github.com/trussed-dev/littlefs2.git?tag=v0.6.1-nitrokey.1#b3a7371d849695fa05ab75910c4b14057db7ceb2" dependencies = [ - "bitflags 1.3.2", - "cstr_core", - "cty", + "bitflags 2.10.0", "delog", - "generic-array 0.14.9", + "generic-array 0.14.7", "heapless 0.7.17", + "littlefs2-core", "littlefs2-sys", - "serde", ] [[package]] name = "littlefs2-core" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd2d1cad5532f5e11b0fd871b8a981885efd3fdaec0427c0d637322ae09efbf" +version = "0.1.1" +source = "git+https://github.com/trussed-dev/littlefs2.git?tag=v0.6.1-nitrokey.1#b3a7371d849695fa05ab75910c4b14057db7ceb2" dependencies = [ "bitflags 2.10.0", + "heapless-bytes", "serde", ] [[package]] name = "littlefs2-sys" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c25e4f545f6ca5415c6325066260e764674d7893dcf0017a52a2ef456ba915f5" +version = "0.3.1" +source = "git+https://github.com/trussed-dev/littlefs2-sys.git?tag=v0.3.1-nitrokey.1#1cfd35c9974b877761e8bb45417f7ad2a61bedad" dependencies = [ "bindgen", "cc", - "cty", ] [[package]] @@ -1056,6 +1124,19 @@ version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" +[[package]] +name = "loom" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff50ecb28bb86013e935fb6683ab1f6d3a20016f123c76fd4c27470076ac30f5" +dependencies = [ + "cfg-if", + "generator 0.7.5", + "scoped-tls", + "tracing", + "tracing-subscriber", +] + [[package]] name = "loom" version = "0.7.2" @@ -1063,7 +1144,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "419e0dc8046cb947daa77eb95ae174acfbddb7673b4151f56d1eed8e93fbfaca" dependencies = [ "cfg-if", - "generator", + "generator 0.8.8", "pin-utils", "scoped-tls", "tracing", @@ -1076,14 +1157,13 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67e9bba980b3a2de5813c8db696806c59bdb5f57956c8137ebe1e10b2e988a53" dependencies = [ - "block-buffer", - "cipher", + "block-buffer 0.9.0", + "cipher 0.3.0", "cortex-m", - "digest", + "digest 0.9.0", "embedded-hal 0.2.7", "embedded-time", - "generic-array 0.14.9", - "littlefs2 0.4.0", + "generic-array 0.14.7", "lpc55-pac", "lpc55-rtic", "nb 1.1.0", @@ -1099,13 +1179,13 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ca5d2ad4d3068ed67b8d5b2f59eb64d4194e5d59c096657901c7b09e30069f" dependencies = [ - "block-buffer", - "cipher", + "block-buffer 0.9.0", + "cipher 0.3.0", "cortex-m", - "digest", + "digest 0.9.0", "embedded-hal 0.2.7", "embedded-time", - "generic-array 0.14.9", + "generic-array 0.14.7", "lpc55-pac", "nb 1.1.0", "rand_core", @@ -1166,23 +1246,18 @@ version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" -[[package]] -name = "micro-ecc-sys" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b861c7e7eba25ec3fe0fde221a46bf38bd1ad200a5404b6f7e45c99b74a00fa" -dependencies = [ - "bindgen", - "cc", - "cty", -] - [[package]] name = "micromath" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3c8dda44ff03a2f238717214da50f65d5a53b45cd213a7370424ffdb6fae815" +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "nb" version = "0.1.3" @@ -1202,8 +1277,8 @@ checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" name = "ndef-app" version = "0.1.0" dependencies = [ - "apdu-dispatch", - "heapless 0.7.17", + "apdu-dispatch 0.3.1", + "heapless 0.8.0", "iso7816", ] @@ -1211,36 +1286,23 @@ dependencies = [ name = "nfc-device" version = "0.0.1" dependencies = [ - "apdu-dispatch", + "apdu-dispatch 0.3.1", "defmt", "embedded-time", "heapless 0.7.17", - "interchange", + "interchange 0.3.2", "iso7816", "nb 1.1.0", ] -[[package]] -name = "nisty" -version = "0.1.0-alpha.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a50765b4bf261cc343bc5eede18fcd48d1fbe0e5e9352f43a9d0423ddae3ef30" -dependencies = [ - "cosey 0.2.0", - "der 0.2.10", - "heapless-bytes 0.2.0", - "micro-ecc-sys", - "sha2", -] - [[package]] name = "nom" -version = "5.1.3" +version = "7.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08959a387a676302eebf4ddbcbc611da04285579f76f88ee0506c63b1a61dd4b" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" dependencies = [ "memchr", - "version_check", + "minimal-lexical", ] [[package]] @@ -1320,13 +1382,13 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11470bb97635a0d1943211c7b9cd473ecee002342480e8fc7347beba27f38243" dependencies = [ - "apdu-dispatch", + "apdu-dispatch 0.1.2", "delog", "flexiber", "heapless 0.7.17", - "heapless-bytes 0.3.0", - "hex-literal", - "interchange", + "heapless-bytes", + "hex-literal 0.3.4", + "interchange 0.2.2", "iso7816", "serde", "trussed", @@ -1352,7 +1414,7 @@ checksum = "d053368e1bae4c8a672953397bd1bd7183dde1c72b0b7612a15719173148d186" dependencies = [ "ecdsa", "elliptic-curve", - "sha2", + "sha2 0.9.9", ] [[package]] @@ -1361,13 +1423,13 @@ version = "0.1.0-alpha.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "647353e42d97cbbc7018cb27c0258a7f5ec1db69a0ac336bd954f468a66af38a" dependencies = [ - "der 0.4.5", + "der", "ecdsa", "elliptic-curve", "p256", "p256-cortex-m4-sys", "rand_core", - "sha2", + "sha2 0.9.9", "zeroize", ] @@ -1387,12 +1449,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a513e167849a384b7f9b746e517604398518590a9142f4846a32e3c2a4de7b11" -[[package]] -name = "peeking_take_while" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" - [[package]] name = "pin-project-lite" version = "0.2.16" @@ -1408,15 +1464,15 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "piv-authenticator" version = "0.5.3" -source = "git+https://github.com/solokeys/piv-authenticator#a4a4204e7089a6a5a99907877576cc40c75825ab" +source = "git+https://github.com/trussed-dev/piv-authenticator?tag=v0.5.3#5c858c2dd60fe2c3f628f50e308e2a2c39e34bd3" dependencies = [ "apdu-app", - "cbor-smol 0.5.1", + "cbor-smol", "cfg-if", "flexiber", "heapless 0.7.17", - "heapless-bytes 0.3.0", - "hex-literal", + "heapless-bytes", + "hex-literal 0.3.4", "iso7816", "littlefs2-core", "log", @@ -1432,9 +1488,9 @@ dependencies = [ [[package]] name = "poly1305" -version = "0.7.2" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "048aeb476be11a4b6ca432ca569e375810de9294ae78f4774e78ea98a9246ede" +checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" dependencies = [ "cpufeatures", "opaque-debug", @@ -1464,6 +1520,15 @@ version = "0.1.5-pre" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c68cb38ed13fd7bc9dd5db8f165b7c8d9c1a315104083a2b10f11354c2af97f" +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + [[package]] name = "proc-macro-error-attr2" version = "2.0.0" @@ -1499,13 +1564,12 @@ dependencies = [ name = "provisioner-app" version = "0.1.0" dependencies = [ - "apdu-dispatch", + "apdu-dispatch 0.3.1", "defmt", - "heapless 0.7.17", - "heapless-bytes 0.3.0", - "littlefs2 0.3.2", + "heapless 0.8.0", + "littlefs2", "lpc55-hal 0.3.1", - "nisty", + "p256", "salty", "trussed", ] @@ -1525,12 +1589,28 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2a38df5b15c8d5c7e8654189744d8e396bddc18ad48041a500ce52d6948941f" +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + [[package]] name = "rand_core" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +[[package]] +name = "ref-swap" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09c30c54dffee5b40af088d5d50aa3455c91a0127164b51f0215efc4cb28fb3c" + [[package]] name = "regex" version = "1.12.2" @@ -1639,7 +1719,7 @@ dependencies = [ "embedded-hal-async", "embedded-hal-bus", "heapless 0.8.0", - "loom", + "loom 0.7.2", "portable-atomic", "rtic-common", ] @@ -1674,7 +1754,7 @@ name = "runner" version = "2.964.0" dependencies = [ "admin-app", - "apdu-dispatch", + "apdu-dispatch 0.3.1", "board", "cortex-m", "ctap-types", @@ -1685,8 +1765,8 @@ dependencies = [ "fido-authenticator", "fm11nc08", "heapless 0.9.2", - "interchange", - "littlefs2 0.3.2", + "interchange 0.3.2", + "littlefs2", "nb 1.1.0", "ndef-app", "nfc-device", @@ -1694,12 +1774,21 @@ dependencies = [ "panic-halt", "piv-authenticator", "provisioner-app", + "ref-swap", "rtic", "rtic-monotonics", "rtic-sync", + "secrets-app", "static_cell", "systick-monotonic", "trussed", + "trussed-auth", + "trussed-auth-backend", + "trussed-core", + "trussed-fs-info", + "trussed-hkdf", + "trussed-manage", + "trussed-staging", "usb-device", "usbd-ccid", "usbd-ctaphid", @@ -1738,11 +1827,11 @@ checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "salty" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77cdd38ed8bfe51e53ee991aae0791b94349d0a05cfdecd283835a8a965d4c37" +checksum = "b947325a585e90733e0e9ec097228f40b637cc346f9bd68f84d5c6297d0fcfef" dependencies = [ - "cosey 0.3.2", + "cosey", "ed25519", "subtle", "zeroize", @@ -1760,6 +1849,28 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "secrets-app" +version = "0.14.0" +source = "git+https://github.com/Nitrokey/trussed-secrets-app?tag=v0.14.0#e72e80491b79962ac0f8030581eca8ba0004a732" +dependencies = [ + "apdu-app", + "bitflags 2.10.0", + "block-padding", + "cbor-smol", + "delog", + "encrypted_container", + "flexiber", + "heapless 0.7.17", + "heapless-bytes", + "hex-literal 0.3.4", + "iso7816", + "littlefs2-core", + "serde", + "trussed-auth", + "trussed-core", +] + [[package]] name = "semver" version = "0.9.0" @@ -1812,13 +1923,13 @@ dependencies = [ ] [[package]] -name = "serde_cbor" -version = "0.11.2" +name = "serde_bytes" +version = "0.11.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" +checksum = "a5d440709e79d88e51ac01c4b72fc6cb7314017bb7da9eeff678aa94c10e3ea8" dependencies = [ - "half", "serde", + "serde_core", ] [[package]] @@ -1854,15 +1965,13 @@ dependencies = [ [[package]] name = "sha-1" -version = "0.9.8" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6" +checksum = "f5058ada175748e33390e40e872bd0fe59a19f265d0158daa551c5a88a76009c" dependencies = [ - "block-buffer", "cfg-if", "cpufeatures", - "digest", - "opaque-debug", + "digest 0.10.7", ] [[package]] @@ -1871,13 +1980,24 @@ version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" dependencies = [ - "block-buffer", + "block-buffer 0.9.0", "cfg-if", "cpufeatures", - "digest", + "digest 0.9.0", "opaque-debug", ] +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + [[package]] name = "sharded-slab" version = "0.1.7" @@ -1887,12 +2007,6 @@ dependencies = [ "lazy_static", ] -[[package]] -name = "shlex" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2" - [[package]] name = "shlex" version = "1.3.0" @@ -1905,10 +2019,16 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2807892cfa58e081aa1f1111391c7a0649d4fa127a4ffbe34bcbfb35a1171a4" dependencies = [ - "digest", + "digest 0.9.0", "rand_core", ] +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" + [[package]] name = "smallvec" version = "1.15.1" @@ -1939,6 +2059,19 @@ dependencies = [ "portable-atomic", ] +[[package]] +name = "strum_macros" +version = "0.25.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.114", +] + [[package]] name = "subtle" version = "2.4.1" @@ -2037,9 +2170,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" dependencies = [ "pin-project-lite", + "tracing-attributes", "tracing-core", ] +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + [[package]] name = "tracing-core" version = "0.1.36" @@ -2082,37 +2227,36 @@ dependencies = [ [[package]] name = "trussed" version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7173399ed80afefa978da6c601d9712d1de03f7c6e2b9d4630addfcc0598f5e" +source = "git+https://github.com/trussed-dev/trussed.git?rev=e107ed315a07dc6c992fac39d542e847cc3a1b6c#e107ed315a07dc6c992fac39d542e847cc3a1b6c" dependencies = [ "aes", - "bitflags 1.3.2", - "block-modes", - "cbor-smol 0.4.1", + "bitflags 2.10.0", + "cbc", + "cbor-smol", "cfg-if", "chacha20", "chacha20poly1305", - "cosey 0.3.2", + "cosey", "delog", "des", - "embedded-hal 0.2.7", "flexiber", - "generic-array 0.14.9", + "generic-array 0.14.7", "heapless 0.7.17", - "heapless-bytes 0.3.0", - "hex-literal", - "hmac", - "interchange", - "littlefs2 0.3.2", + "heapless-bytes", + "hex-literal 0.4.1", + "hmac 0.12.1", + "interchange 0.3.2", + "littlefs2-core", "nb 1.1.0", "p256-cortex-m4", "postcard", + "rand_chacha", "rand_core", "salty", "serde", - "serde-indexed", "sha-1", - "sha2", + "sha2 0.10.9", + "trussed-core", "zeroize", ] @@ -2126,6 +2270,25 @@ dependencies = [ "trussed-core", ] +[[package]] +name = "trussed-auth-backend" +version = "0.1.0" +source = "git+https://github.com/trussed-dev/trussed-auth?tag=v0.4.0#ab6ad8422531fb4801fee795cb44baa375320f15" +dependencies = [ + "chacha20poly1305", + "hkdf", + "hmac 0.12.1", + "littlefs2-core", + "rand_core", + "serde", + "serde-byte-array", + "sha2 0.10.9", + "subtle", + "trussed", + "trussed-auth", + "trussed-core", +] + [[package]] name = "trussed-chunked" version = "0.2.0" @@ -2143,7 +2306,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "afddad280ae8a5235e1b06408cca909ce9454cdd89f941b94b024c580732b3ce" dependencies = [ - "heapless-bytes 0.3.0", + "heapless-bytes", "littlefs2-core", "postcard", "rand_core", @@ -2151,6 +2314,27 @@ dependencies = [ "serde-indexed", ] +[[package]] +name = "trussed-fs-info" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44822e0abc5a32b3f370f82644ee9cb08aa693847aac0d48f6dc115389157aea" +dependencies = [ + "serde", + "serde-byte-array", + "trussed-core", +] + +[[package]] +name = "trussed-hkdf" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17884daee9214e24c7bb9cf2429d0f53c569cfa4a8d728106e459e60aed5be69" +dependencies = [ + "serde", + "trussed-core", +] + [[package]] name = "trussed-hpke" version = "0.2.0" @@ -2162,6 +2346,37 @@ dependencies = [ "trussed-core", ] +[[package]] +name = "trussed-manage" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd9663f2c1b5bddbb02f9edbbe9085313ae8cd03e53a2eb266f43b1dba365287" +dependencies = [ + "littlefs2-core", + "serde", + "trussed-core", +] + +[[package]] +name = "trussed-staging" +version = "0.3.3" +source = "git+https://github.com/trussed-dev/trussed-staging.git?tag=v0.3.3#2e44cf8ca3e6597880a1e59757228da2d6cce3f1" +dependencies = [ + "delog", + "digest 0.10.7", + "hkdf", + "littlefs2-core", + "rand_core", + "salty", + "serde", + "serde-byte-array", + "sha2 0.10.9", + "trussed", + "trussed-fs-info", + "trussed-hkdf", + "trussed-manage", +] + [[package]] name = "trussed-wrap-key-to-file" version = "0.2.0" @@ -2192,11 +2407,11 @@ checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "universal-hash" -version = "0.4.1" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f214e8f697e925001e66ec2c6e37a4ef93f0f78c2eed7814394e10c62025b05" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" dependencies = [ - "generic-array 0.14.9", + "crypto-common", "subtle", ] @@ -2214,32 +2429,32 @@ checksum = "1f6cc3adc849b5292b4075fc0d5fdcf2f24866e88e336dd27a8943090a520508" [[package]] name = "usbd-ccid" -version = "0.1.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2bbc1b6619517411ddd8f94a84c093f710d740895644bdafd70c0fe90b31839" +checksum = "403fefa622483869d1b36f2accd7458291202c18aa2f2e5147caf638825dde0c" dependencies = [ "delog", "embedded-time", "heapless 0.7.17", - "interchange", + "interchange 0.3.2", "iso7816", "usb-device", ] [[package]] name = "usbd-ctaphid" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddb69f660f962236eb21565780c433412ad0ba35e5106f53191cdf443c1d03d2" +version = "0.3.0" +source = "git+https://github.com/leetronics/usbd-ctaphid.git?branch=v0.3-wouldblock-fix#3823eb7fc3cec223749e7e83e32a56f178d4ce64" dependencies = [ - "ctap-types", "ctaphid-dispatch", + "defmt", "delog", "embedded-time", - "heapless 0.7.17", - "heapless-bytes 0.3.0", - "interchange", + "heapless-bytes", + "interchange 0.3.2", + "ref-swap", "serde", + "trussed-core", "usb-device", ] @@ -2287,6 +2502,15 @@ dependencies = [ "vcell", ] +[[package]] +name = "windows" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" +dependencies = [ + "windows-targets", +] + [[package]] name = "windows-link" version = "0.2.1" @@ -2311,11 +2535,88 @@ dependencies = [ "windows-link", ] +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "zerocopy" +version = "0.8.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2578b716f8a7a858b7f02d5bd870c14bf4ddbbcf3a4c05414ba6503640505e3" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e6cc098ea4d3bd6246687de65af3f920c430e236bee1e3bf2e441463f08a02f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + [[package]] name = "zeroize" -version = "1.3.0" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4756f7db3f7b5574938c3eb1c117038b8e07f95ee6718c0efad4ac21508f1efd" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" dependencies = [ "zeroize_derive", ] diff --git a/runners/lpc55/Cargo.toml b/runners/lpc55/Cargo.toml index ea8c6bde..f43d058f 100644 --- a/runners/lpc55/Cargo.toml +++ b/runners/lpc55/Cargo.toml @@ -23,21 +23,27 @@ defmt = "1.0.1" defmt-rtt = "1.1.0" delog = "0.1.1" heapless = "0.9" -interchange = "0.2.2" +interchange = "0.3" nb = "1" static_cell = "2.1.1" +ref-swap = "0.1" usb-device = "0.2.3" # usbd-hid = { version = "0.4.5", optional = true } usbd-serial = "0.1.0" admin-app = { version = "0.1", optional = true } -apdu-dispatch = "0.1.1" -ctaphid-dispatch = "0.1.1" -ctap-types = "0.1" -fido-authenticator = { version = "0.1.1", features = ["dispatch"], optional = true } +trussed-staging = { git = "https://github.com/trussed-dev/trussed-staging.git", tag = "v0.3.3", features = ["hkdf", "fs-info", "manage"] } +trussed-fs-info = "0.2" +trussed-hkdf = "0.3" +trussed-manage = "0.2" +apdu-dispatch = "0.3" +ctaphid-dispatch = "0.3" +ctap-types = "0.4" +fido-authenticator = { version = "0.2", features = ["dispatch"], optional = true } oath-authenticator = { version = "0.1", features = ["apdu-dispatch"], optional = true } -piv-authenticator = { git = "https://github.com/solokeys/piv-authenticator", features = ["apdu-dispatch"], optional = true, commit = "1922d6d97ba9ea4800572eea4b8a243ada2bf668" } +piv-authenticator = { git = "https://github.com/trussed-dev/piv-authenticator", features = ["apdu-dispatch"], optional = true, tag = "v0.5.3" } trussed = "0.1" +trussed-core = "0.1" # board board = { path = "board" } @@ -48,8 +54,8 @@ ndef-app = { path = "../../components/ndef-app", optional = true } provisioner-app = { path = "../../components/provisioner-app", optional = true } fm11nc08 = {path = "../../components/fm11nc08"} nfc-device = {path = "../../components/nfc-device"} -usbd-ccid = "0.1.0" -usbd-ctaphid = "0.1.0" +usbd-ccid = "0.3" +usbd-ctaphid = "0.3" # panic @@ -57,19 +63,19 @@ panic-halt = "1.0.0" # panic-semihosting = "0.5.6" # storage -littlefs2 = { version = "0.3.2", features = ["c-stubs"] } +littlefs2 = { version = "0.6", features = ["c-stubs"] } [features] # ndef-app is an annoyance on some mobile platforms -default = ["admin-app", "fido-authenticator", "ndef-app", "oath-authenticator", "trussed/clients-4"] +default = ["admin-app", "fido-authenticator", "ndef-app"] # develop = ["no-encrypted-storage", "no-buttons", "no-reset-time-window"] # develop = ["no-encrypted-storage", "no-reset-time-window"] # develop = ["no-encrypted-storage", "no-buttons"] -develop = ["no-encrypted-storage", "trussed/clients-4"] +develop = ["no-encrypted-storage"] -develop-piv = ["develop", "piv-authenticator", "trussed/clients-5"] -develop-provisioner = ["develop", "provisioner-app", "trussed/clients-5"] +develop-piv = ["develop", "piv-authenticator"] +develop-provisioner = ["develop", "provisioner-app"] # Do not use encryption for the filesystem no-encrypted-storage = [] @@ -119,7 +125,12 @@ opt-level = 2 # [profile.release.package.nisty] # opt-level = 2 -# Littlefs2 needs to be patched to deal with a bug in the lookahead buffer. -# This can be undone once we can move away from littlefs2 0.3.2 [patch.crates-io] -littlefs2 = {path = "vendor/littlefs2"} +trussed = { git = "https://github.com/trussed-dev/trussed.git", rev = "e107ed315a07dc6c992fac39d542e847cc3a1b6c" } +admin-app = { git = "https://github.com/Nitrokey/admin-app.git", tag = "v0.1.0-nitrokey.20" } +littlefs2 = { git = "https://github.com/trussed-dev/littlefs2.git", tag = "v0.6.1-nitrokey.1" } +littlefs2-sys = { git = "https://github.com/trussed-dev/littlefs2-sys.git", tag = "v0.3.1-nitrokey.1" } +# Force both trussed and littlefs2 to use the same littlefs2-core (resolves DynFilesystem version mismatch) +littlefs2-core = { git = "https://github.com/trussed-dev/littlefs2.git", tag = "v0.6.1-nitrokey.1" } +# Extension backends needed by fido-authenticator 0.2 (FsInfoClient, HkdfClient) +trussed-staging = { git = "https://github.com/trussed-dev/trussed-staging.git", tag = "v0.3.3" } diff --git a/runners/pc/Cargo.toml b/runners/pc/Cargo.toml index 06d248d4..a5470fb1 100644 --- a/runners/pc/Cargo.toml +++ b/runners/pc/Cargo.toml @@ -9,25 +9,26 @@ chacha20 = { version = "0.7", features = ["rng"] } delog = "0.1.0" embedded-hal = { version = "0.2", features = ["unproven"] } generic-array = "0.14.3" -interchange = "0.2.2" +interchange = "0.3" nb = "1" admin-app = "0.1" -apdu-dispatch = "0.1.1" +apdu-dispatch = "0.3" ctap-types = "0.1" -ctaphid-dispatch = "0.1.1" -fido-authenticator = { version = "0.1.1", features = ["dispatch"], optional = true } -piv-authenticator = { git = "https://github.com/solokeys/piv-authenticator" } -trussed = { version = "0.1", features = ["clients-3"] } +ctaphid-dispatch = "0.2" +fido-authenticator = { version = "0.2", features = ["dispatch"], optional = true } +piv-authenticator = { git = "https://github.com/trussed-dev/piv-authenticator", tag = "v0.5.3" } +trussed = "0.1" +trussed-core = "0.1" # components -usbd-ccid = "0.1.0" -usbd-ctaphid = "0.1.0" +usbd-ccid = "0.2" +usbd-ctaphid = "0.3" nfc-device = {path = "./../../components/nfc-device"} ndef-app = {path = "./../../components/ndef-app"} # storage -littlefs2 = "0.3.1" +littlefs2 = "0.6" [features] default = [] @@ -45,7 +46,11 @@ log-debug = [] log-warn = [] log-error = [] -# patch dependencies like so to test local changes +[patch.crates-io] +trussed = { git = "https://github.com/trussed-dev/trussed.git", rev = "e107ed315a07dc6c992fac39d542e847cc3a1b6c" } +admin-app = { git = "https://github.com/Nitrokey/admin-app.git", tag = "v0.1.0-nitrokey.20" } +littlefs2 = { git = "https://github.com/trussed-dev/littlefs2.git", tag = "v0.6.1-nitrokey.1" } +littlefs2-sys = { git = "https://github.com/trussed-dev/littlefs2-sys.git", tag = "v0.3.1-nitrokey.1" } [profile.release] codegen-units = 1 From 73bffb95027aadd903ef0db35e7ace7e7203ddf7 Mon Sep 17 00:00:00 2001 From: Manuel Domke Date: Wed, 25 Mar 2026 23:30:50 +0100 Subject: [PATCH 02/18] runners/lpc55: migrate to trussed 0.2 API with extension dispatch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit API migration for trussed 0.2 / interchange 0.3 / usbd-ccid 0.3: Source changes: - types/usb.rs: CcidClass gains 'static,'static lifetime params; CtapHidClass gains 3 lifetime params + const N; use usbd_ccid::Status (types module is private in 0.3) - initializer.rs + stages.rs: replace interchange::Interchange static claims with Channel::new().split(); wire CTAPHID interrupt flag (OptionRefSwap); use CtapHid::with_interrupt for interrupt-based dispatch coordination - lib.rs: remove unused Board import - board/trussed.rs: add wildcard arm to exhaustive match - ndef-app/ndef.rs, nfc-device/iso14443.rs: update apdu-dispatch 0.3 API (App, CommandView, Data, Interface types) - main.rs: usbd_ccid::types::Status -> usbd_ccid::Status Extension dispatch (required by fido-authenticator 0.2): - types.rs: add Dispatch struct wrapping StagingBackend (provides FsInfoClient, HkdfClient for fido-authenticator; ManageClient for admin-app) - BackendIds enum, ExtensionIds enum (Hkdf=1, Manage=2, FsInfo=4) - STAGING_BACKENDS: [StagingBackend, Core] — Core is critical; omitting it causes all standard crypto calls to fail with RequestNotAvailable - Trussed wrapper struct holding Service + service endpoints; replaces bare trussed::Service type alias - Static TrussedChannel per app; make_client() splits channel and registers endpoint - Apps struct rebuilt with new client provisioning pattern - AdminApp gains StatusBytes type param (AdminStatus); uses with_default_config() - fido_authenticator::Config gains nfc_transport field --- components/ndef-app/src/ndef.rs | 9 +- components/nfc-device/src/iso14443.rs | 15 +- runners/lpc55/board/src/trussed.rs | 1 + runners/lpc55/src/initializer.rs | 184 +++++---- runners/lpc55/src/initializer/stages.rs | 10 +- runners/lpc55/src/lib.rs | 2 - runners/lpc55/src/main.rs | 6 +- runners/lpc55/src/types.rs | 512 ++++++++++++++++++------ runners/lpc55/src/types/usb.rs | 11 +- 9 files changed, 527 insertions(+), 223 deletions(-) diff --git a/components/ndef-app/src/ndef.rs b/components/ndef-app/src/ndef.rs index 56814482..2e8c7543 100644 --- a/components/ndef-app/src/ndef.rs +++ b/components/ndef-app/src/ndef.rs @@ -1,5 +1,6 @@ use iso7816::{Instruction, Status}; -use apdu_dispatch::{Command, response, app, command::SIZE as CommandSize, response::SIZE as ResponseSize}; +use apdu_dispatch::{app, response::SIZE as ResponseSize}; +use apdu_dispatch::app::{CommandView, Data, Interface}; pub struct App<'a>{ reader: &'a [u8] @@ -37,15 +38,15 @@ impl<'a> iso7816::App for App<'a> { } } -impl<'a> app::App for App<'a> { +impl<'a> app::App for App<'a> { - fn select(&mut self, _apdu: &Command, _reply: &mut response::Data) -> app::Result { + fn select(&mut self, _interface: Interface, _apdu: CommandView<'_>, _reply: &mut Data) -> app::Result { Ok(()) } fn deselect(&mut self) {} - fn call(&mut self, _type: app::Interface, apdu: &Command, reply: &mut response::Data) -> app::Result { + fn call(&mut self, _interface: Interface, apdu: CommandView<'_>, reply: &mut Data) -> app::Result { let instruction = apdu.instruction(); let p1 = apdu.p1; let p2 = apdu.p2; diff --git a/components/nfc-device/src/iso14443.rs b/components/nfc-device/src/iso14443.rs index d5e94fcb..c56553e1 100644 --- a/components/nfc-device/src/iso14443.rs +++ b/components/nfc-device/src/iso14443.rs @@ -4,7 +4,7 @@ use apdu_dispatch::interchanges; use defmt::{info, debug}; use embedded_time::duration::Milliseconds; use heapless::Vec; -use interchange::Requester; +use interchange; use crate::traits::nfc; @@ -87,7 +87,7 @@ impl Block { /// Iso14443 device follows related rules for PICC in iso14443-4. /// Rules C - E and rules 9 - 13. -pub struct Iso14443 { +pub struct Iso14443<'pipe, DEV: nfc::Device> { device: DEV, state: Iso14443State, @@ -101,14 +101,14 @@ pub struct Iso14443 { buffer: interchanges::Data, - interchange: Requester, + interchange: interchanges::Requester<'pipe>, } -impl Iso14443 +impl<'pipe, DEV> Iso14443<'pipe, DEV> where DEV: nfc::Device { - pub fn new(device: DEV, interchange: Requester) -> Self { + pub fn new(device: DEV, interchange: interchanges::Requester<'pipe>) -> Self { Self { device: device, state: Iso14443State::Receiving, @@ -117,7 +117,7 @@ where wtx_requested: false, block_num: true, - buffer: Vec::new(), + buffer: interchanges::Data::new(), interchange: interchange, } @@ -357,7 +357,7 @@ where self.buffer.clear(); if command.is_ok() { if self.interchange.request( - command.as_ref().unwrap() + command.unwrap() ).is_ok() { Ok(()) } else { @@ -403,7 +403,6 @@ where if let Some(msg) = self.interchange.take_response() { - let msg = msg.clone(); // if let Some(last_iblock_recv) = self.last_iblock_recv { info!("send!"); let (frame, data_used) = self.construct_iblock(&msg); diff --git a/runners/lpc55/board/src/trussed.rs b/runners/lpc55/board/src/trussed.rs index d47cabc2..72260ac8 100644 --- a/runners/lpc55/board/src/trussed.rs +++ b/runners/lpc55/board/src/trussed.rs @@ -124,6 +124,7 @@ RGB: RgbLed, // ui::Status::WaitingForUserPresence => ORANGE, ui::Status::WaitingForUserPresence => BLUE, ui::Status::Error => RED, + _ => BLACK, }); } } diff --git a/runners/lpc55/src/initializer.rs b/runners/lpc55/src/initializer.rs index 415c9a01..6dc00c40 100644 --- a/runners/lpc55/src/initializer.rs +++ b/runners/lpc55/src/initializer.rs @@ -13,7 +13,6 @@ use hal::typestates::pin::state::Gpio; use static_cell::StaticCell; use usb_device::device::{UsbDeviceBuilder, UsbVidPid}; -use interchange::Interchange; use trussed::platform::UserInterface; use board::traits::buttons; @@ -21,9 +20,22 @@ use board::traits::buttons::Press; use board::traits::rgb_led::RgbLed; use crate::{build_constants, clock_controller, types}; +use ref_swap::OptionRefSwap; +use trussed::interrupt::InterruptFlag; pub mod stages; +/// Static APDU interchange channels (contactless = NFC, contact = USB/CCID). +static NFC_APDU_CHANNEL: apdu_dispatch::interchanges::Channel = + apdu_dispatch::interchanges::Channel::new(); +static USB_APDU_CHANNEL: apdu_dispatch::interchanges::Channel = + apdu_dispatch::interchanges::Channel::new(); +/// Static CTAPHID channel. +static CTAPHID_CHANNEL: ctaphid_dispatch::Channel<{ ctaphid_dispatch::DEFAULT_MESSAGE_SIZE }> = + ctaphid_dispatch::Channel::new(); +/// Static CTAPHID interrupt flag for coordinating between CTAPHID layer and apps. +static CTAPHID_INTERRUPT: OptionRefSwap<'static, InterruptFlag> = OptionRefSwap::new(None); + pub trait State {} pub struct Booted; pub struct EnabledIo; @@ -455,11 +467,11 @@ impl Initializer { None }; - let mut iso14443: Option> = None; + let mut iso14443: Option = None; - let (contactless_requester, contactless_responder) = - apdu_dispatch::interchanges::Contactless::claim() - .expect("could not setup iso14443 ApduInterchange"); + let (contactless_requester, contactless_responder) = NFC_APDU_CHANNEL + .split() + .expect("could not setup iso14443 ApduInterchange"); if nfc_chip.is_some() { iso14443 = Some(nfc_device::Iso14443::new( @@ -499,12 +511,13 @@ impl Initializer { let pmc = &mut self.pmc; let anactrl = &mut self.anactrl; - let (contact_requester, contact_responder) = apdu_dispatch::interchanges::Contact::claim() + let (contact_requester, contact_responder) = USB_APDU_CHANNEL + .split() .expect("could not setup ccid ApduInterchange"); - let (ctaphid_requester, ctaphid_responder) = - ctaphid_dispatch::types::HidInterchange::claim() - .expect("could not setup HidInterchange"); + let (ctaphid_requester, ctaphid_responder) = CTAPHID_CHANNEL + .split() + .expect("could not setup HidInterchange"); info!( "usb class start {} ms", @@ -550,10 +563,15 @@ impl Initializer { // So for instance "Hacker Solo 2" would work, but "Solo 2 (custom)" would not. let ccid = usbd_ccid::Ccid::new(usb_bus, contact_requester, Some(b"Solo 2")); let current_time = basic_stage.perf_timer.elapsed().0 / 1000; - let mut ctaphid = usbd_ctaphid::CtapHid::new(usb_bus, ctaphid_requester, current_time) - .implements_ctap1() - .implements_ctap2() - .implements_wink(); + let mut ctaphid = usbd_ctaphid::CtapHid::with_interrupt( + usb_bus, + ctaphid_requester, + Some(&CTAPHID_INTERRUPT), + current_time, + ) + .implements_ctap1() + .implements_ctap2() + .implements_wink(); ctaphid.set_version(usbd_ctaphid::Version { major: crate::build_constants::CARGO_PKG_VERSION_MAJOR, @@ -606,8 +624,10 @@ impl Initializer { usb_stage.contact_responder.take().unwrap(), nfc_stage.contactless_responder.take().unwrap(), ); - let ctaphid_dispatch = - types::CtaphidDispatch::new(usb_stage.ctaphid_responder.take().unwrap()); + let ctaphid_dispatch = types::CtaphidDispatch::with_interrupt( + usb_stage.ctaphid_responder.take().unwrap(), + Some(&CTAPHID_INTERRUPT), + ); stages::Interfaces { apdu_dispatch, @@ -682,75 +702,101 @@ impl Initializer { "mount start {} ms", basic_stage.perf_timer.elapsed().0 / 1000 ); + + // Convert all refs to raw pointers to allow retry after formatting. + // Only one derived &mut ref is live at a time (safe by construction). static INTERNAL_STORAGE: StaticCell = StaticCell::new(); - let internal_storage = INTERNAL_STORAGE.init(filesystem); + let internal_storage = INTERNAL_STORAGE.init(filesystem) as *mut types::FlashStorage; static INTERNAL_FS_ALLOC: StaticCell> = StaticCell::new(); - let internal_fs_alloc = INTERNAL_FS_ALLOC.init(Filesystem::allocate()); + let internal_fs_alloc = + INTERNAL_FS_ALLOC.init(Filesystem::allocate()) as *mut Allocation; static EXTERNAL_STORAGE: StaticCell = StaticCell::new(); - let external_storage = EXTERNAL_STORAGE.init(ExternalStorage::new()); + let external_storage = + EXTERNAL_STORAGE.init(ExternalStorage::new()) as *mut ExternalStorage; static EXTERNAL_FS_ALLOC: StaticCell> = StaticCell::new(); - let external_fs_alloc = EXTERNAL_FS_ALLOC.init(Filesystem::allocate()); + let external_fs_alloc = + EXTERNAL_FS_ALLOC.init(Filesystem::allocate()) as *mut Allocation; static VOLATILE_STORAGE: StaticCell = StaticCell::new(); - let volatile_storage: &mut VolatileStorage = VOLATILE_STORAGE.init(VolatileStorage::new()); + let volatile_storage = + VOLATILE_STORAGE.init(VolatileStorage::new()) as *mut VolatileStorage; static VOLATILE_FS_ALLOC: StaticCell> = StaticCell::new(); - let volatile_fs_alloc = VOLATILE_FS_ALLOC.init(Filesystem::allocate()); - - let store = types::Store::claim().unwrap(); + let volatile_fs_alloc = + VOLATILE_FS_ALLOC.init(Filesystem::allocate()) as *mut Allocation; if let Some(iso14443) = &mut nfc_stage.iso14443 { iso14443.poll(); } - // We need to be able to recreate mutable references when retrying the mount with a format - // For this, we first convert all existing references to pointers, and then derive new mutable - // references from these pointers. As the references of a failed store.mount are not used - // after return of that function, this is still sound to do. - - let internal_fs_alloc = internal_fs_alloc as *mut _; - let internal_storage = internal_storage as *mut _; - let external_fs_alloc = external_fs_alloc as *mut _; - let external_storage = external_storage as *mut _; - let volatile_fs_alloc = volatile_fs_alloc as *mut _; - let volatile_storage = volatile_storage as *mut _; - - let result = store.mount( - unsafe { &mut *internal_fs_alloc }, - // unsafe { &mut INTERNAL_STORAGE }, - unsafe { &mut *internal_storage }, - unsafe { &mut *external_fs_alloc }, - unsafe { &mut *external_storage }, - unsafe { &mut *volatile_fs_alloc }, - unsafe { &mut *volatile_storage }, - // to trash existing data, set to true - false, - ); - - if result.is_err() || cfg!(feature = "format-filesystem") { - let rgb = basic_stage.rgb.as_mut().unwrap(); - rgb.blue(200); - rgb.red(200); - + // Try to mount internal FS without formatting. If it fails (or format-filesystem + // feature is set), format all three filesystems then re-mount. + let needs_format = Filesystem::mount(unsafe { &mut *internal_fs_alloc }, unsafe { + &mut *internal_storage + }) + .is_err(); + + if needs_format || cfg!(feature = "format-filesystem") { + if let Some(rgb) = basic_stage.rgb.as_mut() { + rgb.blue(200); + rgb.red(200); + } basic_stage.delay_timer.start(300_000.microseconds()); nb::block!(basic_stage.delay_timer.wait()).ok(); info!("Not yet formatted! Formatting.."); - store - .mount( - unsafe { &mut *internal_fs_alloc }, - // unsafe { &mut INTERNAL_STORAGE }, - unsafe { &mut *internal_storage }, - unsafe { &mut *external_fs_alloc }, - unsafe { &mut *external_storage }, - unsafe { &mut *volatile_fs_alloc }, - unsafe { &mut *volatile_storage }, - // to trash existing data, set to true - true, - ) - .unwrap(); - rgb.turn_off(); + Filesystem::format(unsafe { &mut *internal_storage }).unwrap(); + Filesystem::format(unsafe { &mut *external_storage }).unwrap(); + Filesystem::format(unsafe { &mut *volatile_storage }).unwrap(); + + if let Some(rgb) = basic_stage.rgb.as_mut() { + rgb.turn_off(); + } } + + // Final mounts. Internal was either already formatted or just formatted above. + // External and volatile are RAM-based; format on first use if needed. + static INTERNAL_FS: StaticCell> = + StaticCell::new(); + let internal_fs: &'static mut Filesystem<'static, types::FlashStorage> = INTERNAL_FS.init( + Filesystem::mount(unsafe { &mut *internal_fs_alloc }, unsafe { + &mut *internal_storage + }) + .unwrap(), + ); + + static EXTERNAL_FS: StaticCell> = StaticCell::new(); + let external_fs: &'static mut Filesystem<'static, ExternalStorage> = EXTERNAL_FS.init({ + match Filesystem::mount(unsafe { &mut *external_fs_alloc }, unsafe { + &mut *external_storage + }) { + Ok(fs) => fs, + Err(_) => { + Filesystem::format(unsafe { &mut *external_storage }).unwrap(); + Filesystem::mount(unsafe { &mut *external_fs_alloc }, unsafe { + &mut *external_storage + }) + .unwrap() + } + } + }); + + static VOLATILE_FS: StaticCell> = StaticCell::new(); + let volatile_fs: &'static mut Filesystem<'static, VolatileStorage> = VOLATILE_FS.init({ + match Filesystem::mount(unsafe { &mut *volatile_fs_alloc }, unsafe { + &mut *volatile_storage + }) { + Ok(fs) => fs, + Err(_) => { + Filesystem::format(unsafe { &mut *volatile_storage }).unwrap(); + Filesystem::mount(unsafe { &mut *volatile_fs_alloc }, unsafe { + &mut *volatile_storage + }) + .unwrap() + } + } + }); + info!("mount end {} ms", basic_stage.perf_timer.elapsed().0 / 1000); // return to slow freq @@ -769,6 +815,8 @@ impl Initializer { // Cancel any possible outstanding use in delay timer basic_stage.delay_timer.cancel().ok(); + let store = types::RunnerStore::new(internal_fs, external_fs, volatile_fs); + stages::Filesystem { store, internal_storage_fs: internal_storage, @@ -804,9 +852,9 @@ impl Initializer { let rng = flash_stage.rng.take().unwrap(); let store = filesystem_stage.store; let board = types::Board::new(rng, store, solobee_interface); - let trussed = trussed::service::Service::new(board); + let service = trussed::service::Service::with_dispatch(board, types::Dispatch::default()); - trussed + types::Trussed::new(service) } #[inline(never)] diff --git a/runners/lpc55/src/initializer/stages.rs b/runners/lpc55/src/initializer/stages.rs index 13a58baf..6cc343dc 100644 --- a/runners/lpc55/src/initializer/stages.rs +++ b/runners/lpc55/src/initializer/stages.rs @@ -39,18 +39,18 @@ pub struct Basic { /// Initialized NFC Iso14443 transport pub struct Nfc { - pub iso14443: Option>, + pub iso14443: Option>, - pub contactless_responder: - Option>, + pub contactless_responder: Option>, } /// Initialized USB device + USB classes, Dynamic Clock controller. pub struct Usb { pub usb_classes: Option, - pub contact_responder: Option>, - pub ctaphid_responder: Option>, + pub contact_responder: Option>, + pub ctaphid_responder: + Option>, } /// Initialized apdu + ctaphid dispatches diff --git a/runners/lpc55/src/lib.rs b/runners/lpc55/src/lib.rs index fc72caa2..d7d04c3b 100644 --- a/runners/lpc55/src/lib.rs +++ b/runners/lpc55/src/lib.rs @@ -15,8 +15,6 @@ use usb_device::device::UsbVidPid; // re-export for convenience #[allow(unused_imports)] use hal::drivers::timer::Elapsed; -use types::Board; - pub mod initializer; pub mod types; diff --git a/runners/lpc55/src/main.rs b/runners/lpc55/src/main.rs index cd05c430..dfdfd1ca 100644 --- a/runners/lpc55/src/main.rs +++ b/runners/lpc55/src/main.rs @@ -216,7 +216,7 @@ mod app { usb_classes.poll(); match usb_classes.ccid.did_start_processing() { - usbd_ccid::types::Status::ReceivedData(milliseconds) => { + usbd_ccid::Status::ReceivedData(milliseconds) => { c.shared .ccid_wait_extension_sender .lock(|ccid_wait_extension_sender| { @@ -268,7 +268,7 @@ mod app { usb_classes.poll(); match usb_classes.ccid.did_start_processing() { - usbd_ccid::types::Status::ReceivedData(milliseconds) => { + usbd_ccid::Status::ReceivedData(milliseconds) => { // if remaining < 60_000 { // debug_now!("scheduling CCID wait extension"); // } @@ -348,7 +348,7 @@ mod app { .lock(|ccid_wait_extension_sender| { c.local.ccid_wait_extension_receiver.try_recv().ok(); match status { - usbd_ccid::types::Status::ReceivedData(milliseconds) => { + usbd_ccid::Status::ReceivedData(milliseconds) => { ccid_wait_extension_sender.try_send(milliseconds).ok(); } _ => {} diff --git a/runners/lpc55/src/types.rs b/runners/lpc55/src/types.rs index 3cfc8668..27fd2614 100644 --- a/runners/lpc55/src/types.rs +++ b/runners/lpc55/src/types.rs @@ -4,8 +4,17 @@ use crate::hal; use hal::drivers::timer; use hal::peripherals::ctimer; use littlefs2::{const_ram_storage, consts}; -use trussed::types::{LfsResult, LfsStorage}; -use trussed::{platform, store}; +use trussed::backend::BackendId; +use trussed::interrupt::InterruptFlag; +use trussed::pipe::{ServiceEndpoint, TrussedChannel}; +use trussed::platform; +use trussed::serde_extensions::{ExtensionDispatch, ExtensionId, ExtensionImpl}; +use trussed::store::DynFilesystem; +use trussed::types::CoreContext; +use trussed_fs_info::FsInfoExtension; +use trussed_hkdf::HkdfExtension; +use trussed_manage::ManageExtension; +use trussed_staging::{StagingBackend, StagingContext}; // Compile time assertion that build_constants::CONFIG_FILESYSTEM_BOUNDARY is 512 byte aligned. const _FILESYSTEM_ALIGNED_CHECK: usize = ((core::mem::size_of::< @@ -30,7 +39,7 @@ pub mod littlefs_params { #[allow(non_camel_case_types, reason = "These are type-level constants")] pub type CACHE_SIZE = hal::drivers::flash::U512; #[allow(non_camel_case_types, reason = "These are type-level constants")] - pub type LOOKAHEADWORDS_SIZE = hal::drivers::flash::U16; + pub type LOOKAHEAD_SIZE = hal::drivers::flash::U16; } #[cfg(feature = "no-encrypted-storage")] @@ -59,25 +68,25 @@ mod littlefs2_filesystem { const BLOCK_CYCLES: isize = super::littlefs_params::BLOCK_CYCLES; type CACHE_SIZE = super::littlefs_params::CACHE_SIZE; - type LOOKAHEADWORDS_SIZE = super::littlefs_params::LOOKAHEADWORDS_SIZE; + type LOOKAHEAD_SIZE = super::littlefs_params::LOOKAHEAD_SIZE; - fn read(&self, off: usize, buf: &mut [u8]) -> LfsResult { + fn read(&mut self, off: usize, buf: &mut [u8]) -> littlefs2::io::Result { >::read(&self.flash_gordon, Self::BASE_OFFSET + off, buf); Ok(buf.len()) } - fn write(&mut self, off: usize, data: &[u8]) -> LfsResult { + fn write(&mut self, off: usize, data: &[u8]) -> littlefs2::io::Result { let ret = >::write(&mut self.flash_gordon, Self::BASE_OFFSET + off, data); ret.map(|_| data.len()) - .map_err(|_| littlefs2::io::Error::Io) + .map_err(|_| littlefs2::io::Error::IO) } - fn erase(&mut self, off: usize, len: usize) -> LfsResult { + fn erase(&mut self, off: usize, len: usize) -> littlefs2::io::Result { let first_page = (Self::BASE_OFFSET + off) / 512; let pages = len / 512; for i in 0..pages { @@ -85,7 +94,7 @@ mod littlefs2_filesystem { hal::drivers::flash::U512, hal::drivers::flash::U512, >>::erase_page(&mut self.flash_gordon, first_page + i) - .map_err(|_| littlefs2::io::Error::Io)?; + .map_err(|_| littlefs2::io::Error::IO)?; } Ok(512 * len) } @@ -125,9 +134,9 @@ mod littlefs2_prince_filesystem { const BLOCK_CYCLES: isize = super::littlefs_params::BLOCK_CYCLES; type CACHE_SIZE = super::littlefs_params::CACHE_SIZE; - type LOOKAHEADWORDS_SIZE = super::littlefs_params::LOOKAHEADWORDS_SIZE; + type LOOKAHEAD_SIZE = super::littlefs_params::LOOKAHEAD_SIZE; - fn read(&self, off: usize, buf: &mut [u8]) -> LfsResult { + fn read(&mut self, off: usize, buf: &mut [u8]) -> littlefs2::io::Result { self.prince.enable_region_2_for(|| { let flash: *const u8 = (Self::BASE_OFFSET + off) as *const u8; for i in 0..buf.len() { @@ -137,7 +146,7 @@ mod littlefs2_prince_filesystem { Ok(buf.len()) } - fn write(&mut self, off: usize, data: &[u8]) -> LfsResult { + fn write(&mut self, off: usize, data: &[u8]) -> littlefs2::io::Result { let prince = &mut self.prince; let flash_gordon = &mut self.flash_gordon; let ret = prince.write_encrypted(|prince| { @@ -149,10 +158,10 @@ mod littlefs2_prince_filesystem { }) }); ret.map(|_| data.len()) - .map_err(|_| littlefs2::io::Error::Io) + .map_err(|_| littlefs2::io::Error::IO) } - fn erase(&mut self, off: usize, len: usize) -> LfsResult { + fn erase(&mut self, off: usize, len: usize) -> littlefs2::io::Result { let first_page = (Self::BASE_OFFSET + off) / 512; let pages = len / 512; for i in 0..pages { @@ -160,7 +169,7 @@ mod littlefs2_prince_filesystem { hal::drivers::flash::U512, hal::drivers::flash::U512, >>::erase_page(&mut self.flash_gordon, first_page + i) - .map_err(|_| littlefs2::io::Error::Io)?; + .map_err(|_| littlefs2::io::Error::IO)?; } Ok(512 * len) } @@ -181,32 +190,56 @@ pub use usb::{CcidClass, CtapHidClass, EnabledUsbPeripheral, SerialClass, UsbCla // 8KB of RAM const_ram_storage!( - name=VolatileStorage, - trait=LfsStorage, - erase_value=0xff, - read_size=1, - write_size=1, - cache_size_ty=consts::U128, + name = VolatileStorage, + erase_value = 0xff, + read_size = 1, + write_size = 1, + cache_size_ty = consts::U128, // this is a limitation of littlefs // https://git.io/JeHp9 - block_size=128, + block_size = 128, // block_size=128, - block_count=8192/104, - lookaheadwords_size_ty=consts::U8, - filename_max_plus_one_ty=consts::U256, - path_max_plus_one_ty=consts::U256, - result=LfsResult, + block_count = 8192 / 104, + lookahead_size_ty = consts::U8, + filename_max_plus_one_ty = consts::U256, + path_max_plus_one_ty = consts::U256, ); // minimum: 2 blocks // TODO: make this optional const_ram_storage!(ExternalStorage, 1024); -store!(Store, - Internal: FlashStorage, - External: ExternalStorage, - Volatile: VolatileStorage -); +/// Store implementation using three mounted littlefs2 filesystems. +#[derive(Clone, Copy)] +pub struct RunnerStore { + ifs: &'static dyn DynFilesystem, + efs: &'static dyn DynFilesystem, + vfs: &'static dyn DynFilesystem, +} + +impl RunnerStore { + pub fn new( + ifs: &'static dyn DynFilesystem, + efs: &'static dyn DynFilesystem, + vfs: &'static dyn DynFilesystem, + ) -> Self { + Self { ifs, efs, vfs } + } +} + +impl trussed::store::Store for RunnerStore { + fn ifs(&self) -> &dyn DynFilesystem { + self.ifs + } + fn efs(&self) -> &dyn DynFilesystem { + self.efs + } + fn vfs(&self) -> &dyn DynFilesystem { + self.vfs + } +} + +pub type Store = RunnerStore; pub type ThreeButtons = board::ThreeButtons; pub type RgbLed = board::RgbLed; @@ -217,7 +250,123 @@ platform!(Board, UI: board::trussed::UserInterface, ); -#[derive(Default)] +/// Extension dispatch type providing FsInfo, Hkdf, and Manage extensions via trussed-staging. +/// Required because fido-authenticator 0.2 unconditionally needs FsInfoClient + HkdfClient, +/// and admin-app requires ManageClient. +pub struct Dispatch { + staging_backend: StagingBackend, +} + +impl Default for Dispatch { + fn default() -> Self { + Self { + staging_backend: StagingBackend::new(), + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum BackendIds { + StagingBackend, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum ExtensionIds { + Hkdf = 1, + Manage = 2, + FsInfo = 4, +} + +impl From for u8 { + fn from(id: ExtensionIds) -> u8 { + id as u8 + } +} + +impl TryFrom for ExtensionIds { + type Error = trussed::Error; + fn try_from(id: u8) -> Result { + match id { + 1 => Ok(Self::Hkdf), + 2 => Ok(Self::Manage), + 4 => Ok(Self::FsInfo), + _ => Err(trussed::Error::FunctionNotSupported), + } + } +} + +impl ExtensionId for Dispatch { + type Id = ExtensionIds; + const ID: ExtensionIds = ExtensionIds::FsInfo; +} + +impl ExtensionId for Dispatch { + type Id = ExtensionIds; + const ID: ExtensionIds = ExtensionIds::Hkdf; +} + +impl ExtensionId for Dispatch { + type Id = ExtensionIds; + const ID: ExtensionIds = ExtensionIds::Manage; +} + +impl ExtensionDispatch for Dispatch { + type BackendId = BackendIds; + type Context = StagingContext; + type ExtensionId = ExtensionIds; + + fn core_request( + &mut self, + backend: &Self::BackendId, + ctx: &mut trussed::types::Context, + request: &trussed::api::Request, + resources: &mut trussed::service::ServiceResources

, + ) -> Result { + use trussed::backend::Backend; + match backend { + BackendIds::StagingBackend => self.staging_backend.request( + &mut ctx.core, + &mut ctx.backends, + request, + resources, + ), + } + } + + fn extension_request( + &mut self, + _backend: &Self::BackendId, + extension: &Self::ExtensionId, + ctx: &mut trussed::types::Context, + request: &trussed::api::request::SerdeExtension, + resources: &mut trussed::service::ServiceResources

, + ) -> Result { + match extension { + ExtensionIds::FsInfo => ExtensionImpl::::extension_request_serialized( + &mut self.staging_backend, + &mut ctx.core, + &mut ctx.backends, + request, + resources, + ), + ExtensionIds::Hkdf => ExtensionImpl::::extension_request_serialized( + &mut self.staging_backend, + &mut ctx.core, + &mut ctx.backends, + request, + resources, + ), + ExtensionIds::Manage => ExtensionImpl::::extension_request_serialized( + &mut self.staging_backend, + &mut ctx.core, + &mut ctx.backends, + request, + resources, + ), + } + } +} + pub struct Syscall {} impl trussed::client::Syscall for Syscall { @@ -227,18 +376,96 @@ impl trussed::client::Syscall for Syscall { } } -pub type Trussed = trussed::Service; -pub type TrussedClient = trussed::ClientImplementation; +impl Default for Syscall { + fn default() -> Self { + Self {} + } +} + +/// Service endpoint type for our Dispatch. +pub type TrussedEndpoint = ServiceEndpoint<'static, BackendIds, StagingContext>; +/// Client type for apps — parameterized with Dispatch to get extension support. +pub type TrussedClient = trussed::ClientImplementation<'static, Syscall, Dispatch>; + +/// Backends for all apps: StagingBackend (FsInfo, Hkdf, Manage) + Core. +/// BackendId::Core must be present or all standard crypto/filesystem calls return +/// RequestNotAvailable, causing syscall!() to panic and the device to freeze. +static STAGING_BACKENDS: [BackendId; 2] = [ + BackendId::Custom(BackendIds::StagingBackend), + BackendId::Core, +]; + +/// Wrapper around the trussed Service that also holds the service endpoints. +/// `process()` and `update_ui()` are called from the RTIC OS_EVENT handler and +/// the periodic UI task respectively. +pub struct Trussed { + service: trussed::Service, + endpoints: heapless::Vec, +} + +impl Trussed { + pub fn new(service: trussed::Service) -> Self { + Self { + service, + endpoints: heapless::Vec::new(), + } + } + + pub fn add_endpoint(&mut self, ep: TrussedEndpoint) { + self.endpoints.push(ep).ok(); + } + + pub fn process(&mut self) { + self.service.process(&mut self.endpoints); + } + + pub fn update_ui(&mut self) { + self.service.update_ui(); + } +} -pub type Iso14443 = nfc_device::Iso14443; +pub type Iso14443 = nfc_device::Iso14443<'static, board::nfc::NfcChip>; pub type ExternalInterrupt = hal::Pint; -pub type ApduDispatch = apdu_dispatch::dispatch::ApduDispatch; -pub type CtaphidDispatch = ctaphid_dispatch::dispatch::Dispatch; +pub type ApduDispatch = apdu_dispatch::dispatch::ApduDispatch<'static>; +pub type CtaphidDispatch = + ctaphid_dispatch::Dispatch<'static, 'static, { ctaphid_dispatch::DEFAULT_MESSAGE_SIZE }>; + +/// Minimal status implementation for admin-app. +#[cfg(feature = "admin-app")] +pub struct AdminStatus { + random_error: bool, +} #[cfg(feature = "admin-app")] -pub type AdminApp = admin_app::App; +impl Default for AdminStatus { + fn default() -> Self { + Self { + random_error: false, + } + } +} + +#[cfg(feature = "admin-app")] +impl admin_app::StatusBytes for AdminStatus { + type Serialized = [u8; 1]; + + fn set_random_error(&mut self, value: bool) { + self.random_error = value; + } + + fn get_random_error(&self) -> bool { + self.random_error + } + + fn serialize(&self) -> Self::Serialized { + [self.random_error as u8] + } +} + +#[cfg(feature = "admin-app")] +pub type AdminApp = admin_app::App; #[cfg(feature = "piv-authenticator")] pub type PivApp = piv_authenticator::Authenticator; #[cfg(feature = "oath-authenticator")] @@ -252,82 +479,53 @@ pub type NdefApp = ndef_app::App<'static>; #[cfg(feature = "provisioner-app")] pub type ProvisionerApp = provisioner_app::Provisioner; -use apdu_dispatch::{command::SIZE as CommandSize, response::SIZE as ResponseSize, App as ApduApp}; +use apdu_dispatch::response::SIZE as ResponseSize; +use apdu_dispatch::App as ApduApp; use ctaphid_dispatch::app::App as CtaphidApp; pub type DynamicClockController = board::clock_controller::DynamicClockController; pub type NfcWaitExtender = timer::Timer>; pub type PerformanceTimer = timer::Timer>; -pub trait TrussedApp: Sized { - /// non-portable resources needed by this Trussed app - type NonPortable; - - /// the desired client ID - const CLIENT_ID: &'static [u8]; - - fn with_client(trussed: TrussedClient, non_portable: Self::NonPortable) -> Self; +// Static trussed channels — one per app. Channels are split during Apps::new(). +#[cfg(feature = "admin-app")] +static ADMIN_TRUSSED_CHANNEL: TrussedChannel = TrussedChannel::new(); +#[cfg(feature = "admin-app")] +static ADMIN_INTERRUPT: InterruptFlag = InterruptFlag::new(); - fn with(trussed: &mut trussed::Service, non_portable: Self::NonPortable) -> Self { - let client_id = core::str::from_utf8(Self::CLIENT_ID).unwrap(); - let client = trussed - .try_new_client(client_id, Syscall::default()) - .unwrap(); - Self::with_client(client, non_portable) - } -} +#[cfg(feature = "fido-authenticator")] +static FIDO_TRUSSED_CHANNEL: TrussedChannel = TrussedChannel::new(); +#[cfg(feature = "fido-authenticator")] +static FIDO_INTERRUPT: InterruptFlag = InterruptFlag::new(); #[cfg(feature = "oath-authenticator")] -impl TrussedApp for OathApp { - const CLIENT_ID: &'static [u8] = b"oath\0"; - - type NonPortable = (); - fn with_client(trussed: TrussedClient, _: ()) -> Self { - Self::new(trussed) - } -} +static OATH_TRUSSED_CHANNEL: TrussedChannel = TrussedChannel::new(); +#[cfg(feature = "oath-authenticator")] +static OATH_INTERRUPT: InterruptFlag = InterruptFlag::new(); #[cfg(feature = "piv-authenticator")] -impl TrussedApp for PivApp { - const CLIENT_ID: &'static [u8] = b"piv\0"; - - type NonPortable = (); - fn with_client(trussed: TrussedClient, _: ()) -> Self { - Self::new(trussed) - } -} - -#[cfg(feature = "admin-app")] -impl TrussedApp for AdminApp { - const CLIENT_ID: &'static [u8] = b"admin\0"; - - // TODO: declare uuid + version - type NonPortable = (); - fn with_client(trussed: TrussedClient, _: ()) -> Self { - Self::new(trussed, hal::uuid(), build_constants::CARGO_PKG_VERSION) - } -} +static PIV_TRUSSED_CHANNEL: TrussedChannel = TrussedChannel::new(); +#[cfg(feature = "piv-authenticator")] +static PIV_INTERRUPT: InterruptFlag = InterruptFlag::new(); -#[cfg(feature = "fido-authenticator")] -impl TrussedApp for FidoApp { - const CLIENT_ID: &'static [u8] = b"fido\0"; - - type NonPortable = (); - fn with_client(trussed: TrussedClient, _: ()) -> Self { - let authnr = fido_authenticator::Authenticator::new( - trussed, - fido_authenticator::Conforming {}, - FidoConfig { - max_msg_size: usbd_ctaphid::constants::MESSAGE_SIZE, - // max_creds_in_list: ctap_types::sizes::MAX_CREDENTIAL_COUNT_IN_LIST, - // max_cred_id_length: ctap_types::sizes::MAX_CREDENTIAL_ID_LENGTH, - skip_up_timeout: None, - }, - ); - - // Self::new(authnr) - authnr - } +#[cfg(feature = "provisioner-app")] +static PROVISIONER_TRUSSED_CHANNEL: TrussedChannel = TrussedChannel::new(); +#[cfg(feature = "provisioner-app")] +static PROVISIONER_INTERRUPT: InterruptFlag = InterruptFlag::new(); + +/// Helper: split a static channel, register the service endpoint with `trussed`, +/// and return the client end. +fn make_client( + channel: &'static TrussedChannel, + client_id: &'static littlefs2::path::Path, + trussed: &mut Trussed, + interrupt: Option<&'static InterruptFlag>, +) -> TrussedClient { + let (req, resp) = channel.split().expect("channel already split"); + let context = CoreContext::with_interrupt(littlefs2::path::PathBuf::from(client_id), interrupt); + let ep = ServiceEndpoint::new(resp, context, &STAGING_BACKENDS); + trussed.add_endpoint(ep); + TrussedClient::new(req, Syscall::default(), interrupt) } pub struct ProvisionerNonPortable { @@ -336,23 +534,6 @@ pub struct ProvisionerNonPortable { pub nfc_powered: bool, } -#[cfg(feature = "provisioner-app")] -impl TrussedApp for ProvisionerApp { - const CLIENT_ID: &'static [u8] = b"attn\0"; - - type NonPortable = ProvisionerNonPortable; - fn with_client( - trussed: TrussedClient, - ProvisionerNonPortable { - store, - stolen_filesystem, - nfc_powered, - }: Self::NonPortable, - ) -> Self { - Self::new(trussed, store, stolen_filesystem, nfc_powered) - } -} - pub struct Apps { #[cfg(feature = "admin-app")] pub admin: AdminApp, @@ -370,21 +551,88 @@ pub struct Apps { impl Apps { pub fn new( - trussed: &mut trussed::Service, - #[cfg(feature = "provisioner-app")] provisioner: ProvisionerNonPortable, + trussed: &mut Trussed, + #[cfg(feature = "provisioner-app")] provisioner_np: ProvisionerNonPortable, ) -> Self { #[cfg(feature = "admin-app")] - let admin = AdminApp::with(trussed, ()); + let admin = { + let client = make_client( + &ADMIN_TRUSSED_CHANNEL, + littlefs2::path!("admin"), + trussed, + Some(&ADMIN_INTERRUPT), + ); + AdminApp::with_default_config( + client, + hal::uuid(), + build_constants::CARGO_PKG_VERSION, + env!("CARGO_PKG_VERSION"), + AdminStatus::default(), + &[], + ) + }; + #[cfg(feature = "fido-authenticator")] - let fido = FidoApp::with(trussed, ()); + let fido = { + let client = make_client( + &FIDO_TRUSSED_CHANNEL, + littlefs2::path!("fido"), + trussed, + Some(&FIDO_INTERRUPT), + ); + fido_authenticator::Authenticator::new( + client, + fido_authenticator::Conforming {}, + FidoConfig { + max_msg_size: ctaphid_dispatch::DEFAULT_MESSAGE_SIZE, + skip_up_timeout: None, + max_resident_credential_count: Some(50), + large_blobs: None, + nfc_transport: false, + }, + ) + }; + #[cfg(feature = "oath-authenticator")] - let oath = OathApp::with(trussed, ()); + let oath = { + let client = make_client( + &OATH_TRUSSED_CHANNEL, + littlefs2::path!("oath"), + trussed, + Some(&OATH_INTERRUPT), + ); + OathApp::new(client) + }; + #[cfg(feature = "piv-authenticator")] - let piv = PivApp::with(trussed, ()); + let piv = { + let client = make_client( + &PIV_TRUSSED_CHANNEL, + littlefs2::path!("piv"), + trussed, + Some(&PIV_INTERRUPT), + ); + PivApp::new(client) + }; + #[cfg(feature = "ndef-app")] let ndef = NdefApp::new(); + #[cfg(feature = "provisioner-app")] - let provisioner = ProvisionerApp::with(trussed, provisioner); + let provisioner = { + let client = make_client( + &PROVISIONER_TRUSSED_CHANNEL, + littlefs2::path!("attn"), + trussed, + Some(&PROVISIONER_INTERRUPT), + ); + let ProvisionerNonPortable { + store, + stolen_filesystem, + nfc_powered, + } = provisioner_np; + ProvisionerApp::new(client, store, stolen_filesystem, nfc_powered) + }; Self { #[cfg(feature = "admin-app")] @@ -405,7 +653,7 @@ impl Apps { #[inline(never)] pub fn apdu_dispatch(&mut self, f: F) -> T where - F: FnOnce(&mut [&mut dyn ApduApp]) -> T, + F: FnOnce(&mut [&mut dyn ApduApp]) -> T, { f(&mut [ #[cfg(feature = "ndef-app")] @@ -426,13 +674,15 @@ impl Apps { #[inline(never)] pub fn ctaphid_dispatch(&mut self, f: F) -> T where - F: FnOnce(&mut [&mut dyn CtaphidApp]) -> T, + F: FnOnce( + &mut [&mut dyn CtaphidApp<'static, { ctaphid_dispatch::DEFAULT_MESSAGE_SIZE }>], + ) -> T, { f(&mut [ - #[cfg(feature = "fido-authenticator")] - &mut self.fido, #[cfg(feature = "admin-app")] &mut self.admin, + #[cfg(feature = "fido-authenticator")] + &mut self.fido, ]) } } diff --git a/runners/lpc55/src/types/usb.rs b/runners/lpc55/src/types/usb.rs index e16841cc..7203386e 100644 --- a/runners/lpc55/src/types/usb.rs +++ b/runners/lpc55/src/types/usb.rs @@ -7,11 +7,18 @@ pub type EnabledUsbPeripheral = hal::peripherals::usbhs::EnabledUsbhsDevice; pub type EnabledUsbPeripheral = hal::peripherals::usbfs::EnabledUsbfsDevice; pub type CcidClass = usbd_ccid::Ccid< + 'static, + 'static, UsbBus, - apdu_dispatch::interchanges::Contact, { apdu_dispatch::interchanges::SIZE }, >; -pub type CtapHidClass = usbd_ctaphid::CtapHid<'static, UsbBus>; +pub type CtapHidClass = usbd_ctaphid::CtapHid< + 'static, + 'static, + 'static, + UsbBus, + { ctaphid_dispatch::DEFAULT_MESSAGE_SIZE }, +>; // pub type KeyboardClass = usbd_hid::hid_class::HIDClass<'static, UsbBus>; pub type SerialClass = usbd_serial::SerialPort<'static, UsbBus>; From f6e0890bb1fde2cba6c7b163691a816065be1728 Mon Sep 17 00:00:00 2001 From: Manuel Domke Date: Wed, 25 Mar 2026 23:31:56 +0100 Subject: [PATCH 03/18] =?UTF-8?q?runners/lpc55:=20fix=20CTAP2=20reliabilit?= =?UTF-8?q?y=20=E2=80=94=20deadlock,=20poll=20order,=20interrupt=20coordin?= =?UTF-8?q?ation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix a deadlock that caused all CTAP2 commands to hang indefinitely: ctaphid_dispatch.poll() was called inside usb_classes.lock(), which creates an RTIC critical section that masks interrupts. When a FIDO/admin app calls syscall!() to access trussed, it pends OS_EVENT and waits for the response. OS_EVENT cannot run while interrupts are masked, so the device hangs. Fix: move ctaphid_dispatch.poll() outside usb_classes.lock() so OS_EVENT can preempt and process trussed requests during CTAP2 command handling. Also fix USB poll ordering: usb_classes.poll() must run before ctaphid_dispatch.poll() to ensure received USB packets are available for processing by the dispatcher. Fix vendor command dispatch order: admin-app must be checked before fido-authenticator so admin vendor commands (VERSION, UUID, etc.) are not absorbed by the FIDO handler. Add minimal defmt logging for USB interrupts and CTAP2 flow. --- runners/lpc55/src/main.rs | 44 +++++++++++++++++---------------------- 1 file changed, 19 insertions(+), 25 deletions(-) diff --git a/runners/lpc55/src/main.rs b/runners/lpc55/src/main.rs index dfdfd1ca..9d8b6518 100644 --- a/runners/lpc55/src/main.rs +++ b/runners/lpc55/src/main.rs @@ -201,20 +201,15 @@ mod app { _ => {} } - if c.shared - .apps - .ctaphid_dispatch(|apps| c.shared.ctaphid_dispatch.poll(apps)) - { - rtic::pend(USB_INTERRUPT); - } - c.shared.usb_classes.lock(|usb_classes_maybe| { if usb_classes_maybe.is_some() { let usb_classes = usb_classes_maybe.as_mut().unwrap(); - usb_classes.ctaphid.check_timeout(time / 1000); + // Poll USB first so data is available before dispatching usb_classes.poll(); + usb_classes.ctaphid.check_timeout(time / 1000); + match usb_classes.ccid.did_start_processing() { usbd_ccid::Status::ReceivedData(milliseconds) => { c.shared @@ -226,7 +221,6 @@ mod app { } _ => {} } - match usb_classes.ctaphid.did_start_processing() { usbd_ctaphid::types::Status::ReceivedData(milliseconds) => { c.shared @@ -240,6 +234,17 @@ mod app { } } }); + + // Poll CTAP HID dispatch OUTSIDE the usb_classes lock. + // ctaphid_dispatch.poll() may trigger a trussed syscall which pends OS_EVENT. + // If called inside usb_classes.lock(), the resulting critical section would + // prevent OS_EVENT from running, causing a deadlock. + if c.shared + .apps + .ctaphid_dispatch(|apps| c.shared.ctaphid_dispatch.poll(apps)) + { + rtic::pend(USB_INTERRUPT); + } } } @@ -252,26 +257,19 @@ mod app { /// Manages all traffic on the USB bus. #[task(binds = USB1, shared = [usb_classes, ccid_wait_extension_sender, ctaphid_keep_alive_sender], priority=6)] fn usb(mut c: usb::Context) { - // let remaining = msp() - 0x2000_0000; - // if remaining < 100_000 { - // debug_now!("USB interrupt: remaining stack size: {} bytes", remaining); - // } let usb = unsafe { hal::raw::Peripherals::steal().USB1 }; - // let before = Instant::now(); + let intstat = usb.intstat.read().bits(); + // Log non-SOF USB interrupts (SOF = bit 30, dev_status = bit 31) + if intstat & 0x0FFF_FFFF != 0 { + defmt::debug!("USB interrupt: intstat={:08x}", intstat); + } c.shared.usb_classes.lock(|usb_classes_maybe| { let usb_classes = usb_classes_maybe.as_mut().unwrap(); - ////////////// - // if remaining < 60_000 { - // debug_now!("polling usb classes"); - // } usb_classes.poll(); match usb_classes.ccid.did_start_processing() { usbd_ccid::Status::ReceivedData(milliseconds) => { - // if remaining < 60_000 { - // debug_now!("scheduling CCID wait extension"); - // } c.shared .ccid_wait_extension_sender .lock(|ccid_wait_extension_sender| { @@ -283,9 +281,6 @@ mod app { } match usb_classes.ctaphid.did_start_processing() { usbd_ctaphid::types::Status::ReceivedData(milliseconds) => { - // if remaining < 60_000 { - // debug_now!("scheduling CTAPHID wait extension"); - // } c.shared .ctaphid_keep_alive_sender .lock(|ctaphid_keep_alive_sender| { @@ -296,7 +291,6 @@ mod app { _ => {} } }); - ////////////// // let after = Instant::now(); // let length = (after - before).as_cycles(); From f7fb2b6c5d5ab3befd3fa847be12bcaecf7b3f35 Mon Sep 17 00:00:00 2001 From: Manuel Domke Date: Wed, 25 Mar 2026 23:32:51 +0100 Subject: [PATCH 04/18] runners/lpc55: patch usbd-ctaphid for WouldBlock fix and enable defmt logging Patch usbd-ctaphid to use a fork that fixes a WouldBlock race condition: when a PING or other single-packet response is sent, the upstream crate returns WouldBlock on retry instead of completing the transfer, causing CTAP HID to stall indefinitely. Also enable defmt logging on usbd-ctaphid (log-info + defmt-logging features) and add log-defmt to the develop feature set for debug builds. --- runners/lpc55/Cargo.toml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/runners/lpc55/Cargo.toml b/runners/lpc55/Cargo.toml index f43d058f..7c39df0d 100644 --- a/runners/lpc55/Cargo.toml +++ b/runners/lpc55/Cargo.toml @@ -55,7 +55,7 @@ provisioner-app = { path = "../../components/provisioner-app", optional = true } fm11nc08 = {path = "../../components/fm11nc08"} nfc-device = {path = "../../components/nfc-device"} usbd-ccid = "0.3" -usbd-ctaphid = "0.3" +usbd-ctaphid = { version = "0.3", features = ["log-info", "defmt-logging"] } # panic @@ -72,7 +72,7 @@ default = ["admin-app", "fido-authenticator", "ndef-app"] # develop = ["no-encrypted-storage", "no-buttons", "no-reset-time-window"] # develop = ["no-encrypted-storage", "no-reset-time-window"] # develop = ["no-encrypted-storage", "no-buttons"] -develop = ["no-encrypted-storage"] +develop = ["no-encrypted-storage", "log-defmt"] develop-piv = ["develop", "piv-authenticator"] develop-provisioner = ["develop", "provisioner-app"] @@ -134,3 +134,5 @@ littlefs2-sys = { git = "https://github.com/trussed-dev/littlefs2-sys.git", tag littlefs2-core = { git = "https://github.com/trussed-dev/littlefs2.git", tag = "v0.6.1-nitrokey.1" } # Extension backends needed by fido-authenticator 0.2 (FsInfoClient, HkdfClient) trussed-staging = { git = "https://github.com/trussed-dev/trussed-staging.git", tag = "v0.3.3" } +# Fix WouldBlock retry for single-packet responses (PING race condition) +usbd-ctaphid = { git = "https://github.com/leetronics/usbd-ctaphid.git", branch = "v0.3-wouldblock-fix" } From 900c8b5a8d868d0092c966b1bc65da4849bfcf11 Mon Sep 17 00:00:00 2001 From: Manuel Domke Date: Wed, 25 Mar 2026 23:33:19 +0100 Subject: [PATCH 05/18] components/provisioner-app: replace nisty with p256 nisty is unmaintained and uses an internal ECC implementation. Replace it with the actively maintained p256 crate for P-256 key generation and attestation certificate operations. Migrate the provisioner to the new apdu-dispatch 0.3 API (CommandView, Interface, Data types) and update heapless to 0.8. Also clean up the key serialization documentation (the binary format for trussed key objects). --- components/provisioner-app/Cargo.toml | 18 +- components/provisioner-app/src/lib.rs | 603 ++++++++++---------------- 2 files changed, 233 insertions(+), 388 deletions(-) diff --git a/components/provisioner-app/Cargo.toml b/components/provisioner-app/Cargo.toml index e0089651..221da3ce 100644 --- a/components/provisioner-app/Cargo.toml +++ b/components/provisioner-app/Cargo.toml @@ -4,21 +4,15 @@ version = "0.1.0" authors = ["Conor Patrick "] edition = "2024" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - [dependencies] -apdu-dispatch = "0.1" +apdu-dispatch = "0.3" defmt = "1.0.1" -heapless = "0.7" -heapless-bytes = "0.3" -lpc55-hal = { version = "0.3", features = ["littlefs", "rtic-peripherals"] } -littlefs2 = "0.3.1" -salty = { version = "0.2", features = ["cose"] } +heapless = "0.8" +lpc55-hal = { version = "0.3", features = ["rtic-peripherals"] } +littlefs2 = "0.6" trussed = "0.1" - -[dependencies.nisty] -version = "0.1.0-alpha.5" -features = ["asn1-der", "cose"] +p256 = { version = "0.9", default-features = false, features = ["arithmetic"] } +salty = "0.3" [features] test-attestation = [] diff --git a/components/provisioner-app/src/lib.rs b/components/provisioner-app/src/lib.rs index fcb0c907..2296a467 100644 --- a/components/provisioner-app/src/lib.rs +++ b/components/provisioner-app/src/lib.rs @@ -1,60 +1,66 @@ //! # Solo 2 provisioner app //! -//! This is a highly *non-portable* Trussed app. +//! Allows injecting arbitrary binary files at arbitrary paths via CCID APDU interface. //! -//! It allows injecting arbitrary binary files at arbitrary paths, e.g., to inject FIDO batch -//! attestation keys. -//! It allows generating Trussed device attestation keys and obtaining their public keys, -//! to then generate and inject attn certs from a given root or intermedidate CA. -//! -//! See `solo2-cli` for usage. +//! Used to provision FIDO batch attestation keys and certificates, and to generate +//! Trussed device attestation keys for factory provisioning. +//! See `solo2-cli app provision` for usage. #![no_std] use core::convert::TryFrom; -use trussed::types::LfsStorage; +use littlefs2::driver::Storage as LfsStorage; +use littlefs2::path::PathBuf; use defmt::info; -use littlefs2::path::{PathBuf}; -use trussed::store::{self, Store}; use trussed::{ + store::{self, Store}, syscall, - client, + types::Location, Client as TrussedClient, - key::{Kind as KeyKind, Key, Flags}, }; use heapless::Vec; use apdu_dispatch::iso7816::{Status, Instruction}; use apdu_dispatch::app::Result as ResponseResult; -use apdu_dispatch::{Command, response, command::SIZE as CommandSize, response::SIZE as ResponseSize}; +use apdu_dispatch::app::{CommandView, Interface}; use lpc55_hal as hal; -// -const SOLO_PROVISIONER_AID: [u8; 9] = [ 0xA0, 0x00, 0x00, 0x08, 0x47, 0x01, 0x00, 0x00, 0x01]; +// Trussed key serialization: flags(2 BE) + kind(2 BE) + material(32) +// Flags: LOCAL=0x0001, SENSITIVE=0x0002 +// Kind codes (from trussed src/key.rs Kind::code()): +const KEY_FLAGS_LOCAL_SENSITIVE: u16 = 0x0003; // LOCAL | SENSITIVE +const KEY_KIND_ED255: u16 = 4; +const KEY_KIND_P256: u16 = 5; +const KEY_KIND_X255: u16 = 6; + +const SOLO_PROVISIONER_AID: [u8; 9] = [0xA0, 0x00, 0x00, 0x08, 0x47, 0x01, 0x00, 0x00, 0x01]; -const TESTER_FILENAME_ID: [u8; 2] = [0xe1,0x01]; -const TESTER_FILE_ID: [u8; 2] = [0xe1,0x02]; +const TESTER_FILENAME_ID: [u8; 2] = [0xe1, 0x01]; +const TESTER_FILE_ID: [u8; 2] = [0xe1, 0x02]; + +const FILENAME_T1_PUBLIC: &[u8] = b"/attn/pub/00"; +const FILENAME_P256_SECRET: &[u8] = b"/attn/sec/01"; +const FILENAME_ED255_SECRET: &[u8] = b"/attn/sec/02"; +const FILENAME_X255_SECRET: &[u8] = b"/attn/sec/03"; +const FILENAME_P256_CERT: &[u8] = b"/attn/x5c/01"; +const FILENAME_ED255_CERT: &[u8] = b"/attn/x5c/02"; +const FILENAME_X255_CERT: &[u8] = b"/attn/x5c/03"; #[repr(u8)] #[derive(Copy, Clone, Debug, PartialEq)] pub enum Instructions { WriteFile = 0xbf, - BootToBootrom = 0x51, ReformatFilesystem = 0xbd, GetUuid = 0x62, - GenerateP256Key = 0xbc, GenerateEd255Key = 0xbb, GenerateX255Key = 0xb7, - SaveP256AttestationCertificate = 0xba, SaveEd255AttestationCertificate = 0xb9, SaveX255AttestationCertificate = 0xb6, - SaveT1IntermediatePublicKey = 0xb5, - #[cfg(feature = "test-attestation")] TestAttestation = 0xb8, } @@ -65,21 +71,16 @@ impl TryFrom for Instructions { use Instructions::*; Ok(match ins { 0xbf => WriteFile, - 0x51 => BootToBootrom, 0xbd => ReformatFilesystem, 0x62 => GetUuid, - 0xbc => GenerateP256Key, 0xbb => GenerateEd255Key, 0xb7 => GenerateX255Key, - 0xba => SaveP256AttestationCertificate, 0xb9 => SaveEd255AttestationCertificate, 0xb6 => SaveX255AttestationCertificate, - 0xb5 => SaveT1IntermediatePublicKey, - #[cfg(feature = "test-attestation")] 0xb8 => TestAttestation, _ => return Err(()), @@ -87,39 +88,16 @@ impl TryFrom for Instructions { } } -#[cfg(feature = "test-attestation")] -#[derive(Copy,Clone)] -enum TestAttestationP1 { - P256Sign = 0, - P256Cert = 1, - Ed255Sign= 2, - Ed255Cert= 3, - X255Agree = 4, - X255Cert = 5, -} - - -const FILENAME_T1_PUBLIC: &'static [u8] = b"/attn/pub/00"; - -const FILENAME_P256_SECRET: &'static [u8] = b"/attn/sec/01"; -const FILENAME_ED255_SECRET: &'static [u8] = b"/attn/sec/02"; -const FILENAME_X255_SECRET: &'static [u8] = b"/attn/sec/03"; - -const FILENAME_P256_CERT: &'static [u8] = b"/attn/x5c/01"; -const FILENAME_ED255_CERT: &'static [u8] = b"/attn/x5c/02"; -const FILENAME_X255_CERT: &'static [u8] = b"/attn/x5c/03"; - - - enum SelectedBuffer { Filename, File, } pub struct Provisioner -where S: Store, - FS: 'static + LfsStorage, - T: TrussedClient + client::X255 + client::HmacSha256, +where + S: Store, + FS: 'static + LfsStorage, + T: TrussedClient, { trussed: T, @@ -134,9 +112,10 @@ where S: Store, } impl Provisioner -where S: Store, - FS: 'static + LfsStorage, - T: TrussedClient + client::X255 + client::HmacSha256, +where + S: Store, + FS: 'static + LfsStorage, + T: TrussedClient, { pub fn new( trussed: T, @@ -144,11 +123,8 @@ where S: Store, stolen_filesystem: &'static mut FS, is_passive: bool, ) -> Provisioner { - - - return Self { + Self { trussed, - selected_buffer: SelectedBuffer::Filename, buffer_filename: Vec::new(), buffer_file_contents: Vec::new(), @@ -158,15 +134,30 @@ where S: Store, } } - fn handle(&mut self, command: &Command, reply: &mut response::Data) -> ResponseResult { + /// Build a serialized trussed secret key: flags(2 BE) + kind(2 BE) + material(32) + fn serialize_secret_key(kind_code: u16, material: &[u8; 32]) -> heapless::Vec { + let mut bytes: heapless::Vec = heapless::Vec::new(); + bytes.extend_from_slice(&KEY_FLAGS_LOCAL_SENSITIVE.to_be_bytes()).unwrap(); + bytes.extend_from_slice(&kind_code.to_be_bytes()).unwrap(); + bytes.extend_from_slice(material).unwrap(); + bytes + } + fn handle( + &mut self, + command: CommandView<'_>, + reply: &mut apdu_dispatch::response::Data, + ) -> ResponseResult { match command.instruction() { - Instruction::Select => self.select(command, reply), + Instruction::Select => self.do_select(command, reply), Instruction::WriteBinary => { - let _offset: u16 = ((command.p1 as u16) << 8) | command.p2 as u16; match self.selected_buffer { - SelectedBuffer::Filename => self.buffer_filename.extend_from_slice(command.data()).unwrap(), - SelectedBuffer::File => self.buffer_file_contents.extend_from_slice(command.data()).unwrap(), + SelectedBuffer::Filename => { + self.buffer_filename.extend_from_slice(command.data()).unwrap() + } + SelectedBuffer::File => { + self.buffer_file_contents.extend_from_slice(command.data()).unwrap() + } }; Ok(()) } @@ -175,346 +166,196 @@ where S: Store, use Instructions::*; match instruction { ReformatFilesystem => { - // Provide a method to reset the FS. - info!("Reformatting the FS.."); + info!("Reformatting FS"); littlefs2::fs::Filesystem::format(self.stolen_filesystem) .map_err(|_| Status::NotEnoughMemory)?; Ok(()) } WriteFile => { - if self.buffer_file_contents.len() == 0 || self.buffer_filename.len() == 0 { - Err(Status::IncorrectDataParameter) - } else { - // self.buffer_filename.push(0); - let _filename = unsafe{ core::str::from_utf8_unchecked(self.buffer_filename.as_slice()) }; - info!("writing file {} {} bytes", _filename, self.buffer_file_contents.len()); - // logging::dump_hex(&self.buffer_file_contents, self.buffer_file_contents.len()); - - let res = store::store( - self.store, - trussed::types::Location::Internal, - &PathBuf::from(self.buffer_filename.as_slice()), - &self.buffer_file_contents - ); - self.buffer_file_contents.clear(); - self.buffer_filename.clear(); - if !res.is_ok() { - info!("failed writing file!"); - Err(Status::NotEnoughMemory) - } else { - info!("wrote file"); - Ok(()) - } + if self.buffer_file_contents.is_empty() + || self.buffer_filename.is_empty() + { + return Err(Status::IncorrectDataParameter); } + let _name = unsafe { + core::str::from_utf8_unchecked(self.buffer_filename.as_slice()) + }; + info!( + "write-file {} ({} bytes)", + _name, + self.buffer_file_contents.len() + ); + let path = PathBuf::try_from(self.buffer_filename.as_slice()) + .map_err(|_| Status::IncorrectDataParameter)?; + let result = store::store( + &self.store, + Location::Internal, + &path, + &self.buffer_file_contents, + ); + self.buffer_file_contents.clear(); + self.buffer_filename.clear(); + result.map_err(|_| Status::NotEnoughMemory) } GenerateP256Key => { info!("GenerateP256Key"); let mut seed = [0u8; 32]; seed.copy_from_slice( - &syscall!(self.trussed.random_bytes(32)).bytes.as_slice() + syscall!(self.trussed.random_bytes(32)).bytes.as_slice(), ); - let serialized_key = Key { - flags: Flags::LOCAL | Flags::SENSITIVE, - kind: KeyKind::P256, - material: Vec::from_slice(&seed).unwrap(), - }; - - let serialized_bytes = serialized_key.serialize(); - - store::store( - self.store, - trussed::types::Location::Internal, - &PathBuf::from(FILENAME_P256_SECRET), - &serialized_bytes - ).map_err(|_| Status::NotEnoughMemory)?; - info!("stored to {}", core::str::from_utf8(FILENAME_P256_SECRET).unwrap()); - - let keypair = nisty::Keypair::generate_patiently(&seed); + let key_bytes = Self::serialize_secret_key(KEY_KIND_P256, &seed); + let path = PathBuf::try_from(FILENAME_P256_SECRET) + .map_err(|_| Status::UnspecifiedNonpersistentExecutionError)?; + store::store(&self.store, Location::Internal, &path, &key_bytes) + .map_err(|_| Status::NotEnoughMemory)?; - reply.extend_from_slice(keypair.public.as_bytes()).unwrap(); + // Derive public key — pure-Rust p256 (no C bindings) + let scalar = p256::Scalar::from_bytes_reduced( + p256::FieldBytes::from_slice(&seed), + ); + let affine = p256::AffinePoint::from( + p256::ProjectivePoint::generator() * scalar, + ); + let encoded: p256::EncodedPoint = affine.into(); + // encoded = 0x04 || x(32) || y(32); skip prefix → 64 bytes + reply.extend_from_slice(&encoded.as_bytes()[1..]).unwrap(); Ok(()) } GenerateEd255Key => { - info!("GenerateEd255Key"); let mut seed = [0u8; 32]; seed.copy_from_slice( - &syscall!(self.trussed.random_bytes(32)).bytes.as_slice() + syscall!(self.trussed.random_bytes(32)).bytes.as_slice(), ); - let serialized_key = Key { - flags: Flags::LOCAL | Flags::SENSITIVE, - kind: KeyKind::Ed255, - material: Vec::from_slice(&seed).unwrap(), - }; - - // let serialized_key = Key::try_deserialize(&seed[..]) - // .map_err(|_| Status::WrongLength)?; - - let serialized_bytes = serialized_key.serialize(); - - store::store( - self.store, - trussed::types::Location::Internal, - &PathBuf::from(FILENAME_ED255_SECRET), - &serialized_bytes - ).map_err(|_| Status::NotEnoughMemory)?; + let key_bytes = Self::serialize_secret_key(KEY_KIND_ED255, &seed); + let path = PathBuf::try_from(FILENAME_ED255_SECRET) + .map_err(|_| Status::UnspecifiedNonpersistentExecutionError)?; + store::store(&self.store, Location::Internal, &path, &key_bytes) + .map_err(|_| Status::NotEnoughMemory)?; let keypair = salty::Keypair::from(&seed); - reply.extend_from_slice(keypair.public.as_bytes()).unwrap(); Ok(()) - }, - + } GenerateX255Key => { - info!("GenerateX255Key"); let mut seed = [0u8; 32]; seed.copy_from_slice( - &syscall!(self.trussed.random_bytes(32)).bytes.as_slice() + syscall!(self.trussed.random_bytes(32)).bytes.as_slice(), ); - let serialized_key = Key { - flags: Flags::LOCAL | Flags::SENSITIVE, - kind: KeyKind::X255, - material: Vec::from_slice(&seed).unwrap(), - }; - - // let serialized_key = Key::try_deserialize(&seed[..]) - // .map_err(|_| Status::WrongLength)?; - - let serialized_bytes = serialized_key.serialize(); - - store::store( - self.store, - trussed::types::Location::Internal, - &PathBuf::from(FILENAME_X255_SECRET), - &serialized_bytes - ).map_err(|_| Status::NotEnoughMemory)?; - - let secret_key = salty::agreement::SecretKey::from_seed(&seed); - let public_key = salty::agreement::PublicKey::from(&secret_key); + let key_bytes = Self::serialize_secret_key(KEY_KIND_X255, &seed); + let path = PathBuf::try_from(FILENAME_X255_SECRET) + .map_err(|_| Status::UnspecifiedNonpersistentExecutionError)?; + store::store(&self.store, Location::Internal, &path, &key_bytes) + .map_err(|_| Status::NotEnoughMemory)?; - reply.extend_from_slice(&public_key.to_bytes()).unwrap(); + let sk = salty::agreement::SecretKey::from_seed(&seed); + let pk = salty::agreement::PublicKey::from(&sk); + reply.extend_from_slice(&pk.to_bytes()).unwrap(); Ok(()) - }, - + } SaveP256AttestationCertificate => { - let secret_path = PathBuf::from(FILENAME_P256_SECRET); - if !secret_path.exists(&self.store.ifs()) { - Err(Status::IncorrectDataParameter) - } else if command.data().len() < 100 { - // Assuming certs will always be >100 bytes - Err(Status::IncorrectDataParameter) - } else { - info!("saving P256 CERT, {} bytes", command.data().len()); - store::store( - self.store, - trussed::types::Location::Internal, - &PathBuf::from(FILENAME_P256_CERT), - command.data() - ).map_err(|_| Status::NotEnoughMemory)?; - Ok(()) + let secret_path = PathBuf::try_from(FILENAME_P256_SECRET) + .map_err(|_| Status::UnspecifiedNonpersistentExecutionError)?; + if !store::exists(&self.store, Location::Internal, &secret_path) { + return Err(Status::IncorrectDataParameter); } - }, - + if command.data().len() < 100 { + return Err(Status::IncorrectDataParameter); + } + info!("saving P256 CERT, {} bytes", command.data().len()); + let cert_path = PathBuf::try_from(FILENAME_P256_CERT) + .map_err(|_| Status::UnspecifiedNonpersistentExecutionError)?; + store::store( + &self.store, + Location::Internal, + &cert_path, + command.data(), + ) + .map_err(|_| Status::NotEnoughMemory) + } SaveEd255AttestationCertificate => { - let secret_path = PathBuf::from(FILENAME_ED255_SECRET); - if !secret_path.exists(&self.store.ifs()) { - Err(Status::IncorrectDataParameter) - } else if command.data().len() < 100 { - // Assuming certs will always be >100 bytes - Err(Status::IncorrectDataParameter) - } else { - info!("saving ED25519 CERT, {} bytes", command.data().len()); - store::store( - self.store, - trussed::types::Location::Internal, - &PathBuf::from(FILENAME_ED255_CERT), - command.data() - ).map_err(|_| Status::NotEnoughMemory)?; - Ok(()) + let secret_path = PathBuf::try_from(FILENAME_ED255_SECRET) + .map_err(|_| Status::UnspecifiedNonpersistentExecutionError)?; + if !store::exists(&self.store, Location::Internal, &secret_path) { + return Err(Status::IncorrectDataParameter); } - }, - + if command.data().len() < 100 { + return Err(Status::IncorrectDataParameter); + } + info!("saving ED255 CERT, {} bytes", command.data().len()); + let cert_path = PathBuf::try_from(FILENAME_ED255_CERT) + .map_err(|_| Status::UnspecifiedNonpersistentExecutionError)?; + store::store( + &self.store, + Location::Internal, + &cert_path, + command.data(), + ) + .map_err(|_| Status::NotEnoughMemory) + } SaveX255AttestationCertificate => { - let secret_path = PathBuf::from(FILENAME_X255_SECRET); - if !secret_path.exists(&self.store.ifs()) { - Err(Status::IncorrectDataParameter) - } else if command.data().len() < 100 { - // Assuming certs will always be >100 bytes - Err(Status::IncorrectDataParameter) - } else { - info!("saving X25519 CERT, {} bytes", command.data().len()); - store::store( - self.store, - trussed::types::Location::Internal, - &PathBuf::from(FILENAME_X255_CERT), - command.data() - ).map_err(|_| Status::NotEnoughMemory)?; - Ok(()) + let secret_path = PathBuf::try_from(FILENAME_X255_SECRET) + .map_err(|_| Status::UnspecifiedNonpersistentExecutionError)?; + if !store::exists(&self.store, Location::Internal, &secret_path) { + return Err(Status::IncorrectDataParameter); } - }, - - SaveT1IntermediatePublicKey => { - info!("saving T1 INTERMEDIATE PUBLIC KEY, {} bytes", command.data().len()); - let public_key = &command.data(); - if public_key.len() != 32 { - Err(Status::IncorrectDataParameter) - } else { - let serialized_key = Key { - flags: Default::default(), - kind: KeyKind::Ed255, - material: Vec::from_slice(&public_key).unwrap(), - }; - - let serialized_key = serialized_key.serialize(); - - store::store( - self.store, - trussed::types::Location::Internal, - &PathBuf::from(FILENAME_T1_PUBLIC), - &serialized_key, - ).map_err(|_| Status::NotEnoughMemory) + if command.data().len() < 100 { + return Err(Status::IncorrectDataParameter); } - }, - - #[cfg(feature = "test-attestation")] - TestAttestation => { - // This is only exposed for development and testing. - - use trussed::{ - types::Mechanism, - types::SignatureSerialization, - types::KeyId, - types::Message, - types::StorageAttributes, - types::Location, - types::KeySerialization, - - }; - use trussed::config::MAX_SIGNATURE_LENGTH; - - - let p1 = command.p1; - let mut challenge = [0u8; 32]; - challenge.copy_from_slice( - &syscall!(self.trussed.random_bytes(32)).bytes.as_slice() + info!("saving X255 CERT, {} bytes", command.data().len()); + let cert_path = PathBuf::try_from(FILENAME_X255_CERT) + .map_err(|_| Status::UnspecifiedNonpersistentExecutionError)?; + store::store( + &self.store, + Location::Internal, + &cert_path, + command.data(), + ) + .map_err(|_| Status::NotEnoughMemory) + } + SaveT1IntermediatePublicKey => { + info!( + "saving T1 INTERMEDIATE PUBLIC KEY, {} bytes", + command.data().len() ); - - match p1 { - _x if p1 == TestAttestationP1::P256Sign as u8 => { - let sig: trussed::Bytes = syscall!(self.trussed.sign( - Mechanism::P256, - KeyId::from_special(1), - &challenge, - SignatureSerialization::Asn1Der - )).signature; - - // let sig = Bytes::try_from_slice(&sig); - - reply.extend_from_slice(&challenge).unwrap(); - reply.extend_from_slice(&sig).unwrap(); - Ok(()) - } - _x if p1 == TestAttestationP1::P256Cert as u8 => { - let cert: Message = store::read(self.store, - trussed::types::Location::Internal, - &PathBuf::from(FILENAME_P256_CERT), - ).map_err(|_| Status::NotFound)?; - reply.extend_from_slice(&cert).unwrap(); - Ok(()) - } - _x if p1 == TestAttestationP1::Ed255Sign as u8 => { - - let sig: trussed::Bytes = syscall!(self.trussed.sign( - Mechanism::Ed255, - KeyId::from_special(2), - &challenge, - SignatureSerialization::Asn1Der - )).signature; - - // let sig = Bytes::try_from_slice(&sig); - - reply.extend_from_slice(&challenge).unwrap(); - reply.extend_from_slice(&sig).unwrap(); - Ok(()) - } - _x if p1 == TestAttestationP1::Ed255Cert as u8 => { - let cert:Message = store::read(self.store, - trussed::types::Location::Internal, - &PathBuf::from(FILENAME_ED255_CERT), - ).map_err(|_| Status::NotFound)?; - reply.extend_from_slice(&cert).unwrap(); - Ok(()) - } - _x if p1 == TestAttestationP1::X255Agree as u8 => { - - syscall!(self.trussed.debug_dump_store()); - - let mut platform_pk_bytes = [0u8; 32]; - for i in 0 .. 32 { - platform_pk_bytes[i] = command.data()[i] - } - - info!("1"); - - let platform_kak = syscall!(self.trussed.deserialize_key( - Mechanism::X255, - // platform sends it's pk as 32 bytes - &platform_pk_bytes, - KeySerialization::Raw, - StorageAttributes::new().set_persistence(Location::Volatile) - )).key; - info!("3"); - - let shared_secret = syscall!(self.trussed.agree_x255( - KeyId::from_special(3), - platform_kak, - Location::Volatile - )).shared_secret; - info!("4"); - - let sig = syscall!(self.trussed.sign_hmacsha256( - shared_secret, - &challenge, - )).signature; - - info!("5"); - reply.extend_from_slice(&challenge).unwrap(); - reply.extend_from_slice(&sig).unwrap(); - Ok(()) - } - _x if p1 == TestAttestationP1::X255Cert as u8 => { - let cert: Message = store::read(self.store, - trussed::types::Location::Internal, - &PathBuf::from(FILENAME_X255_CERT), - ).map_err(|_| Status::NotFound)?; - reply.extend_from_slice(&cert).unwrap(); - Ok(()) - } - _ => Err(Status::FunctionNotSupported) - + let public_key = command.data(); + if public_key.len() != 32 { + return Err(Status::IncorrectDataParameter); } - + // Ed255 public key: no SENSITIVE flag + let mut key_bytes: heapless::Vec = heapless::Vec::new(); + key_bytes.extend_from_slice(&0x0000u16.to_be_bytes()).unwrap(); + key_bytes + .extend_from_slice(&KEY_KIND_ED255.to_be_bytes()) + .unwrap(); + key_bytes.extend_from_slice(public_key).unwrap(); + let path = PathBuf::try_from(FILENAME_T1_PUBLIC) + .map_err(|_| Status::UnspecifiedNonpersistentExecutionError)?; + store::store(&self.store, Location::Internal, &path, &key_bytes) + .map_err(|_| Status::NotEnoughMemory) } - GetUuid => { - // Get UUID reply.extend_from_slice(&hal::uuid()).unwrap(); Ok(()) - }, + } BootToBootrom => { - // Boot to bootrom via flash 0 page erase use hal::traits::flash::WriteErase; - let flash = unsafe { hal::peripherals::flash::Flash::steal() }.enabled( - &mut unsafe { hal::peripherals::syscon::Syscon::steal()} - ); + let flash = unsafe { hal::peripherals::flash::Flash::steal() } + .enabled(&mut unsafe { + hal::peripherals::syscon::Syscon::steal() + }); hal::drivers::flash::FlashGordon::new(flash).erase_page(0).ok(); hal::raw::SCB::sys_reset() - }, - + } + #[cfg(feature = "test-attestation")] + TestAttestation => { + // Not implemented in this port + Err(Status::FunctionNotSupported) + } } } else { Err(Status::FunctionNotSupported) @@ -524,53 +365,63 @@ where S: Store, } } - fn select(&mut self, command: &Command, _reply: &mut response::Data) -> ResponseResult { - + fn do_select( + &mut self, + command: CommandView<'_>, + _reply: &mut apdu_dispatch::response::Data, + ) -> ResponseResult { if command.data().starts_with(&TESTER_FILENAME_ID) { - info!("select filename"); + info!("select: filename buffer"); self.selected_buffer = SelectedBuffer::Filename; Ok(()) } else if command.data().starts_with(&TESTER_FILE_ID) { - info!("select file"); + info!("select: file buffer"); self.selected_buffer = SelectedBuffer::File; Ok(()) } else { - info!("unknown ID: {:?}", &command.data()); + info!("select: unknown ID"); Err(Status::NotFound) } - } - } impl apdu_dispatch::iso7816::App for Provisioner -where S: Store, - FS: 'static + LfsStorage, - T: TrussedClient + client::X255 + client::HmacSha256, +where + S: Store, + FS: 'static + LfsStorage, + T: TrussedClient, { fn aid(&self) -> apdu_dispatch::iso7816::Aid { apdu_dispatch::iso7816::Aid::new(&SOLO_PROVISIONER_AID) } } - -impl apdu_dispatch::app::App for Provisioner -where S: Store, - FS: 'static + LfsStorage, - T: TrussedClient + client::X255 + client::HmacSha256, +impl apdu_dispatch::App<{ apdu_dispatch::response::SIZE }> for Provisioner +where + S: Store, + FS: 'static + LfsStorage, + T: TrussedClient, { - fn select(&mut self, _apdu: &Command, reply: &mut response::Data) -> apdu_dispatch::app::Result { + fn select( + &mut self, + _interface: Interface, + _apdu: CommandView<'_>, + reply: &mut apdu_dispatch::response::Data, + ) -> ResponseResult { self.buffer_file_contents.clear(); self.buffer_filename.clear(); - // For manufacture speed, return uuid on select reply.extend_from_slice(&hal::uuid()).unwrap(); Ok(()) } - fn deselect(&mut self) -> () { - } + fn deselect(&mut self) {} - fn call(&mut self, _interface_type: apdu_dispatch::app::Interface, apdu: &Command, reply: &mut response::Data) -> apdu_dispatch::app::Result { - self.handle(&apdu, reply) + fn call( + &mut self, + _interface: Interface, + apdu: CommandView<'_>, + reply: &mut apdu_dispatch::response::Data, + ) -> ResponseResult { + self.handle(apdu, reply) } } From 1312680a6d251653286096974e876348a4761b01 Mon Sep 17 00:00:00 2001 From: Manuel Domke Date: Wed, 25 Mar 2026 23:36:59 +0100 Subject: [PATCH 06/18] runners/lpc55: add OATH/TOTP/HOTP support via secrets-app Integrate trussed-secrets-app v0.14.0 to support Yubico OATH AID (TOTP/HOTP). The secrets-app requires an Auth extension backend for PIN-protected credentials. Extend the dispatch system with AuthBackend (trussed-auth-backend v0.4.0) alongside the existing StagingBackend: - Add BackendIds::Auth and ExtensionIds::Auth = 0 to the dispatch - RunnerContext replaces StagingContext as the dispatch context type, combining AuthContext and StagingContext - AUTH_BACKENDS: [Auth, Core] for secrets-app (auth extension must be first) - make_client() now accepts a backends slice parameter to support both STAGING_BACKENDS (fido/admin/piv) and AUTH_BACKENDS (secrets-app) Available features: - oath = dep:secrets-app (APDU only; ctaphid-dispatch not used due to ctaphid-app 0.1.0-rc.1 vs 0.1.0 version conflict) - develop-secrets = develop + oath (for debug builds with OATH support) --- runners/lpc55/Cargo.toml | 8 +++ runners/lpc55/src/types.rs | 102 +++++++++++++++++++++++++++++++++---- 2 files changed, 100 insertions(+), 10 deletions(-) diff --git a/runners/lpc55/Cargo.toml b/runners/lpc55/Cargo.toml index 7c39df0d..95ba2067 100644 --- a/runners/lpc55/Cargo.toml +++ b/runners/lpc55/Cargo.toml @@ -36,11 +36,16 @@ trussed-staging = { git = "https://github.com/trussed-dev/trussed-staging.git", trussed-fs-info = "0.2" trussed-hkdf = "0.3" trussed-manage = "0.2" +trussed-auth = "0.4" +trussed-auth-backend = { git = "https://github.com/trussed-dev/trussed-auth", tag = "v0.4.0" } apdu-dispatch = "0.3" ctaphid-dispatch = "0.3" ctap-types = "0.4" fido-authenticator = { version = "0.2", features = ["dispatch"], optional = true } oath-authenticator = { version = "0.1", features = ["apdu-dispatch"], optional = true } +# OATH/TOTP/HOTP support via trussed-secrets-app (Nitrokey's implementation, Yubico OATH AID) +# OATH via APDU only (not ctaphid-dispatch: ctaphid-app 0.1.0-rc.1 conflicts with 0.1.0) +secrets-app = { git = "https://github.com/Nitrokey/trussed-secrets-app", tag = "v0.14.0", features = ["apdu-dispatch"], optional = true } piv-authenticator = { git = "https://github.com/trussed-dev/piv-authenticator", features = ["apdu-dispatch"], optional = true, tag = "v0.5.3" } trussed = "0.1" trussed-core = "0.1" @@ -68,6 +73,8 @@ littlefs2 = { version = "0.6", features = ["c-stubs"] } [features] # ndef-app is an annoyance on some mobile platforms default = ["admin-app", "fido-authenticator", "ndef-app"] +# OATH/TOTP/HOTP via secrets-app (replaces incompatible oath-authenticator 0.1) +oath = ["dep:secrets-app"] # develop = ["no-encrypted-storage", "no-buttons", "no-reset-time-window"] # develop = ["no-encrypted-storage", "no-reset-time-window"] @@ -76,6 +83,7 @@ develop = ["no-encrypted-storage", "log-defmt"] develop-piv = ["develop", "piv-authenticator"] develop-provisioner = ["develop", "provisioner-app"] +develop-secrets = ["develop", "oath"] # Do not use encryption for the filesystem no-encrypted-storage = [] diff --git a/runners/lpc55/src/types.rs b/runners/lpc55/src/types.rs index 27fd2614..0d1339e4 100644 --- a/runners/lpc55/src/types.rs +++ b/runners/lpc55/src/types.rs @@ -11,6 +11,8 @@ use trussed::platform; use trussed::serde_extensions::{ExtensionDispatch, ExtensionId, ExtensionImpl}; use trussed::store::DynFilesystem; use trussed::types::CoreContext; +use trussed_auth::AuthExtension; +use trussed_auth_backend::{AuthBackend, AuthContext, FilesystemLayout}; use trussed_fs_info::FsInfoExtension; use trussed_hkdf::HkdfExtension; use trussed_manage::ManageExtension; @@ -250,17 +252,21 @@ platform!(Board, UI: board::trussed::UserInterface, ); -/// Extension dispatch type providing FsInfo, Hkdf, and Manage extensions via trussed-staging. +/// Extension dispatch type providing FsInfo, Hkdf, Manage (via trussed-staging) and +/// Auth (via trussed-auth-backend) extensions. /// Required because fido-authenticator 0.2 unconditionally needs FsInfoClient + HkdfClient, -/// and admin-app requires ManageClient. +/// admin-app requires ManageClient, and secrets-app requires AuthClient. pub struct Dispatch { staging_backend: StagingBackend, + auth_backend: AuthBackend, } impl Default for Dispatch { fn default() -> Self { Self { staging_backend: StagingBackend::new(), + // V0 layout: new device, no existing auth data to migrate + auth_backend: AuthBackend::new(trussed::types::Location::Internal, FilesystemLayout::V0), } } } @@ -268,10 +274,12 @@ impl Default for Dispatch { #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum BackendIds { StagingBackend, + Auth, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum ExtensionIds { + Auth = 0, Hkdf = 1, Manage = 2, FsInfo = 4, @@ -287,6 +295,7 @@ impl TryFrom for ExtensionIds { type Error = trussed::Error; fn try_from(id: u8) -> Result { match id { + 0 => Ok(Self::Auth), 1 => Ok(Self::Hkdf), 2 => Ok(Self::Manage), 4 => Ok(Self::FsInfo), @@ -295,6 +304,11 @@ impl TryFrom for ExtensionIds { } } +impl ExtensionId for Dispatch { + type Id = ExtensionIds; + const ID: ExtensionIds = ExtensionIds::Auth; +} + impl ExtensionId for Dispatch { type Id = ExtensionIds; const ID: ExtensionIds = ExtensionIds::FsInfo; @@ -310,9 +324,16 @@ impl ExtensionId for Dispatch { const ID: ExtensionIds = ExtensionIds::Manage; } +/// Combined context for all backends in the dispatch. +#[derive(Default)] +pub struct RunnerContext { + pub auth: AuthContext, + pub staging: StagingContext, +} + impl ExtensionDispatch for Dispatch { type BackendId = BackendIds; - type Context = StagingContext; + type Context = RunnerContext; type ExtensionId = ExtensionIds; fn core_request( @@ -326,7 +347,13 @@ impl ExtensionDispatch for Dispatch { match backend { BackendIds::StagingBackend => self.staging_backend.request( &mut ctx.core, - &mut ctx.backends, + &mut ctx.backends.staging, + request, + resources, + ), + BackendIds::Auth => self.auth_backend.request( + &mut ctx.core, + &mut ctx.backends.auth, request, resources, ), @@ -342,24 +369,30 @@ impl ExtensionDispatch for Dispatch { resources: &mut trussed::service::ServiceResources

, ) -> Result { match extension { + ExtensionIds::Auth => self.auth_backend.extension_request_serialized( + &mut ctx.core, + &mut ctx.backends.auth, + request, + resources, + ), ExtensionIds::FsInfo => ExtensionImpl::::extension_request_serialized( &mut self.staging_backend, &mut ctx.core, - &mut ctx.backends, + &mut ctx.backends.staging, request, resources, ), ExtensionIds::Hkdf => ExtensionImpl::::extension_request_serialized( &mut self.staging_backend, &mut ctx.core, - &mut ctx.backends, + &mut ctx.backends.staging, request, resources, ), ExtensionIds::Manage => ExtensionImpl::::extension_request_serialized( &mut self.staging_backend, &mut ctx.core, - &mut ctx.backends, + &mut ctx.backends.staging, request, resources, ), @@ -383,11 +416,11 @@ impl Default for Syscall { } /// Service endpoint type for our Dispatch. -pub type TrussedEndpoint = ServiceEndpoint<'static, BackendIds, StagingContext>; +pub type TrussedEndpoint = ServiceEndpoint<'static, BackendIds, RunnerContext>; /// Client type for apps — parameterized with Dispatch to get extension support. pub type TrussedClient = trussed::ClientImplementation<'static, Syscall, Dispatch>; -/// Backends for all apps: StagingBackend (FsInfo, Hkdf, Manage) + Core. +/// Backends for most apps: StagingBackend (FsInfo, Hkdf, Manage) + Core. /// BackendId::Core must be present or all standard crypto/filesystem calls return /// RequestNotAvailable, causing syscall!() to panic and the device to freeze. static STAGING_BACKENDS: [BackendId; 2] = [ @@ -395,6 +428,14 @@ static STAGING_BACKENDS: [BackendId; 2] = [ BackendId::Core, ]; +/// Backends for apps requiring Auth extension (secrets-app). +/// Auth must come first so AuthClient calls reach AuthBackend. +#[cfg(feature = "oath")] +static AUTH_BACKENDS: [BackendId; 2] = [ + BackendId::Custom(BackendIds::Auth), + BackendId::Core, +]; + /// Wrapper around the trussed Service that also holds the service endpoints. /// `process()` and `update_ui()` are called from the RTIC OS_EVENT handler and /// the periodic UI task respectively. @@ -470,6 +511,8 @@ pub type AdminApp = admin_app::App; pub type PivApp = piv_authenticator::Authenticator; #[cfg(feature = "oath-authenticator")] pub type OathApp = oath_authenticator::Authenticator; +#[cfg(feature = "oath")] +pub type SecretsApp = secrets_app::Authenticator; #[cfg(feature = "fido-authenticator")] pub type FidoApp = fido_authenticator::Authenticator; #[cfg(feature = "fido-authenticator")] @@ -513,6 +556,11 @@ static PROVISIONER_TRUSSED_CHANNEL: TrussedChannel = TrussedChannel::new(); #[cfg(feature = "provisioner-app")] static PROVISIONER_INTERRUPT: InterruptFlag = InterruptFlag::new(); +#[cfg(feature = "oath")] +static SECRETS_TRUSSED_CHANNEL: TrussedChannel = TrussedChannel::new(); +#[cfg(feature = "oath")] +static SECRETS_INTERRUPT: InterruptFlag = InterruptFlag::new(); + /// Helper: split a static channel, register the service endpoint with `trussed`, /// and return the client end. fn make_client( @@ -520,10 +568,11 @@ fn make_client( client_id: &'static littlefs2::path::Path, trussed: &mut Trussed, interrupt: Option<&'static InterruptFlag>, + backends: &'static [BackendId], ) -> TrussedClient { let (req, resp) = channel.split().expect("channel already split"); let context = CoreContext::with_interrupt(littlefs2::path::PathBuf::from(client_id), interrupt); - let ep = ServiceEndpoint::new(resp, context, &STAGING_BACKENDS); + let ep = ServiceEndpoint::new(resp, context, backends); trussed.add_endpoint(ep); TrussedClient::new(req, Syscall::default(), interrupt) } @@ -541,6 +590,8 @@ pub struct Apps { pub fido: FidoApp, #[cfg(feature = "oath-authenticator")] pub oath: OathApp, + #[cfg(feature = "oath")] + pub secrets: SecretsApp, #[cfg(feature = "ndef-app")] pub ndef: NdefApp, #[cfg(feature = "piv-authenticator")] @@ -561,6 +612,7 @@ impl Apps { littlefs2::path!("admin"), trussed, Some(&ADMIN_INTERRUPT), + &STAGING_BACKENDS, ); AdminApp::with_default_config( client, @@ -579,6 +631,7 @@ impl Apps { littlefs2::path!("fido"), trussed, Some(&FIDO_INTERRUPT), + &STAGING_BACKENDS, ); fido_authenticator::Authenticator::new( client, @@ -600,6 +653,7 @@ impl Apps { littlefs2::path!("oath"), trussed, Some(&OATH_INTERRUPT), + &STAGING_BACKENDS, ); OathApp::new(client) }; @@ -611,10 +665,33 @@ impl Apps { littlefs2::path!("piv"), trussed, Some(&PIV_INTERRUPT), + &STAGING_BACKENDS, ); PivApp::new(client) }; + #[cfg(feature = "oath")] + let secrets = { + let client = make_client( + &SECRETS_TRUSSED_CHANNEL, + littlefs2::path!("secrets"), + trussed, + Some(&SECRETS_INTERRUPT), + &AUTH_BACKENDS, + ); + let uuid = hal::uuid(); + SecretsApp::new( + client, + secrets_app::Options::new( + trussed::types::Location::Internal, + 0, // custom_status_reverse_hotp_success + 1, // custom_status_reverse_hotp_error + [uuid[0], uuid[1], uuid[2], uuid[3]], + 50, // max_resident_credentials_allowed + ), + ) + }; + #[cfg(feature = "ndef-app")] let ndef = NdefApp::new(); @@ -625,6 +702,7 @@ impl Apps { littlefs2::path!("attn"), trussed, Some(&PROVISIONER_INTERRUPT), + &STAGING_BACKENDS, ); let ProvisionerNonPortable { store, @@ -641,6 +719,8 @@ impl Apps { fido, #[cfg(feature = "oath-authenticator")] oath, + #[cfg(feature = "oath")] + secrets, #[cfg(feature = "ndef-app")] ndef, #[cfg(feature = "piv-authenticator")] @@ -662,6 +742,8 @@ impl Apps { &mut self.piv, #[cfg(feature = "oath-authenticator")] &mut self.oath, + #[cfg(feature = "oath")] + &mut self.secrets, #[cfg(feature = "fido-authenticator")] &mut self.fido, #[cfg(feature = "admin-app")] From 03aa757086f5c8cf5117779ae0fce4f4a3c02a5c Mon Sep 17 00:00:00 2001 From: Manuel Domke Date: Thu, 26 Mar 2026 15:05:35 +0100 Subject: [PATCH 07/18] Enable oath feature in default features --- runners/lpc55/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runners/lpc55/Cargo.toml b/runners/lpc55/Cargo.toml index 95ba2067..75af43b2 100644 --- a/runners/lpc55/Cargo.toml +++ b/runners/lpc55/Cargo.toml @@ -72,7 +72,7 @@ littlefs2 = { version = "0.6", features = ["c-stubs"] } [features] # ndef-app is an annoyance on some mobile platforms -default = ["admin-app", "fido-authenticator", "ndef-app"] +default = ["admin-app", "fido-authenticator", "ndef-app", "oath"] # OATH/TOTP/HOTP via secrets-app (replaces incompatible oath-authenticator 0.1) oath = ["dep:secrets-app"] From 8972bac8886a22fb177eff75dec80dfbe910ddfb Mon Sep 17 00:00:00 2001 From: Manuel Domke Date: Thu, 26 Mar 2026 18:24:04 +0100 Subject: [PATCH 08/18] runners/lpc55: add PIV authenticator support with extension backends --- runners/lpc55/src/types.rs | 93 +++++++++++++++++++++++++++++++++----- 1 file changed, 82 insertions(+), 11 deletions(-) diff --git a/runners/lpc55/src/types.rs b/runners/lpc55/src/types.rs index 0d1339e4..0dfae654 100644 --- a/runners/lpc55/src/types.rs +++ b/runners/lpc55/src/types.rs @@ -13,10 +13,13 @@ use trussed::store::DynFilesystem; use trussed::types::CoreContext; use trussed_auth::AuthExtension; use trussed_auth_backend::{AuthBackend, AuthContext, FilesystemLayout}; +use trussed_chunked::ChunkedExtension; use trussed_fs_info::FsInfoExtension; use trussed_hkdf::HkdfExtension; +use trussed_hpke::HpkeExtension; use trussed_manage::ManageExtension; use trussed_staging::{StagingBackend, StagingContext}; +use trussed_wrap_key_to_file::WrapKeyToFileExtension; // Compile time assertion that build_constants::CONFIG_FILESYSTEM_BOUNDARY is 512 byte aligned. const _FILESYSTEM_ALIGNED_CHECK: usize = ((core::mem::size_of::< @@ -209,7 +212,13 @@ const_ram_storage!( // minimum: 2 blocks // TODO: make this optional +// piv-authenticator hardcodes Location::External for PUK_USER_KEY_BACKUP in init_pins, +// requiring at least 3 blocks (2 metadata + 1 data). Without PIV, 2 blocks suffices +// as nothing writes to External storage. +#[cfg(not(feature = "piv-authenticator"))] const_ram_storage!(ExternalStorage, 1024); +#[cfg(feature = "piv-authenticator")] +const_ram_storage!(ExternalStorage, 8192); /// Store implementation using three mounted littlefs2 filesystems. #[derive(Clone, Copy)] @@ -266,7 +275,10 @@ impl Default for Dispatch { Self { staging_backend: StagingBackend::new(), // V0 layout: new device, no existing auth data to migrate - auth_backend: AuthBackend::new(trussed::types::Location::Internal, FilesystemLayout::V0), + auth_backend: AuthBackend::new( + trussed::types::Location::Internal, + FilesystemLayout::V0, + ), } } } @@ -282,7 +294,10 @@ pub enum ExtensionIds { Auth = 0, Hkdf = 1, Manage = 2, + WrapKeyToFile = 3, FsInfo = 4, + Hpke = 5, + Chunked = 6, } impl From for u8 { @@ -298,7 +313,10 @@ impl TryFrom for ExtensionIds { 0 => Ok(Self::Auth), 1 => Ok(Self::Hkdf), 2 => Ok(Self::Manage), + 3 => Ok(Self::WrapKeyToFile), 4 => Ok(Self::FsInfo), + 5 => Ok(Self::Hpke), + 6 => Ok(Self::Chunked), _ => Err(trussed::Error::FunctionNotSupported), } } @@ -309,6 +327,11 @@ impl ExtensionId for Dispatch { const ID: ExtensionIds = ExtensionIds::Auth; } +impl ExtensionId for Dispatch { + type Id = ExtensionIds; + const ID: ExtensionIds = ExtensionIds::Chunked; +} + impl ExtensionId for Dispatch { type Id = ExtensionIds; const ID: ExtensionIds = ExtensionIds::FsInfo; @@ -319,11 +342,21 @@ impl ExtensionId for Dispatch { const ID: ExtensionIds = ExtensionIds::Hkdf; } +impl ExtensionId for Dispatch { + type Id = ExtensionIds; + const ID: ExtensionIds = ExtensionIds::Hpke; +} + impl ExtensionId for Dispatch { type Id = ExtensionIds; const ID: ExtensionIds = ExtensionIds::Manage; } +impl ExtensionId for Dispatch { + type Id = ExtensionIds; + const ID: ExtensionIds = ExtensionIds::WrapKeyToFile; +} + /// Combined context for all backends in the dispatch. #[derive(Default)] pub struct RunnerContext { @@ -351,12 +384,10 @@ impl ExtensionDispatch for Dispatch { request, resources, ), - BackendIds::Auth => self.auth_backend.request( - &mut ctx.core, - &mut ctx.backends.auth, - request, - resources, - ), + BackendIds::Auth => { + self.auth_backend + .request(&mut ctx.core, &mut ctx.backends.auth, request, resources) + } } } @@ -396,6 +427,31 @@ impl ExtensionDispatch for Dispatch { request, resources, ), + ExtensionIds::Chunked => { + ExtensionImpl::::extension_request_serialized( + &mut self.staging_backend, + &mut ctx.core, + &mut ctx.backends.staging, + request, + resources, + ) + } + ExtensionIds::Hpke => ExtensionImpl::::extension_request_serialized( + &mut self.staging_backend, + &mut ctx.core, + &mut ctx.backends.staging, + request, + resources, + ), + ExtensionIds::WrapKeyToFile => { + ExtensionImpl::::extension_request_serialized( + &mut self.staging_backend, + &mut ctx.core, + &mut ctx.backends.staging, + request, + resources, + ) + } } } } @@ -431,8 +487,15 @@ static STAGING_BACKENDS: [BackendId; 2] = [ /// Backends for apps requiring Auth extension (secrets-app). /// Auth must come first so AuthClient calls reach AuthBackend. #[cfg(feature = "oath")] -static AUTH_BACKENDS: [BackendId; 2] = [ +static AUTH_BACKENDS: [BackendId; 2] = + [BackendId::Custom(BackendIds::Auth), BackendId::Core]; + +/// Backends for piv-authenticator: needs Auth (PIN management), Staging (Chunked/Hpke/WrapKeyToFile), +/// and Core (standard crypto/filesystem). +#[cfg(feature = "piv-authenticator")] +static PIV_BACKENDS: [BackendId; 3] = [ BackendId::Custom(BackendIds::Auth), + BackendId::Custom(BackendIds::StagingBackend), BackendId::Core, ]; @@ -508,7 +571,7 @@ impl admin_app::StatusBytes for AdminStatus { #[cfg(feature = "admin-app")] pub type AdminApp = admin_app::App; #[cfg(feature = "piv-authenticator")] -pub type PivApp = piv_authenticator::Authenticator; +pub type PivApp = piv_authenticator::Authenticator; #[cfg(feature = "oath-authenticator")] pub type OathApp = oath_authenticator::Authenticator; #[cfg(feature = "oath")] @@ -665,9 +728,15 @@ impl Apps { littlefs2::path!("piv"), trussed, Some(&PIV_INTERRUPT), - &STAGING_BACKENDS, + &PIV_BACKENDS, ); - PivApp::new(client) + // Use Internal storage: External is only 1024 bytes (too small for PIV key material). + // PIV needs Auth backend for PIN management (has_pin/set_pin/get_pin_key) and + // StagingBackend for Chunked/Hpke/WrapKeyToFile extensions. + PivApp::new( + client, + piv_authenticator::Options::default().storage(trussed::types::Location::Internal), + ) }; #[cfg(feature = "oath")] @@ -765,6 +834,8 @@ impl Apps { &mut self.admin, #[cfg(feature = "fido-authenticator")] &mut self.fido, + #[cfg(feature = "oath")] + &mut self.secrets, ]) } } From dd9545065b693a1b527629c2febb8a7cbb012966 Mon Sep 17 00:00:00 2001 From: Manuel Domke Date: Thu, 26 Mar 2026 18:30:44 +0100 Subject: [PATCH 09/18] runners/lpc55: enable PIV authenticator in default features, remove develop-piv --- runners/lpc55/Cargo.toml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/runners/lpc55/Cargo.toml b/runners/lpc55/Cargo.toml index 75af43b2..85d1a37a 100644 --- a/runners/lpc55/Cargo.toml +++ b/runners/lpc55/Cargo.toml @@ -72,7 +72,7 @@ littlefs2 = { version = "0.6", features = ["c-stubs"] } [features] # ndef-app is an annoyance on some mobile platforms -default = ["admin-app", "fido-authenticator", "ndef-app", "oath"] +default = ["admin-app", "fido-authenticator", "ndef-app", "oath", "piv-authenticator"] # OATH/TOTP/HOTP via secrets-app (replaces incompatible oath-authenticator 0.1) oath = ["dep:secrets-app"] @@ -81,7 +81,6 @@ oath = ["dep:secrets-app"] # develop = ["no-encrypted-storage", "no-buttons"] develop = ["no-encrypted-storage", "log-defmt"] -develop-piv = ["develop", "piv-authenticator"] develop-provisioner = ["develop", "provisioner-app"] develop-secrets = ["develop", "oath"] From 6ae4e5bb3e3738cc41a25e2a56178943f8bbe08a Mon Sep 17 00:00:00 2001 From: Manuel Domke Date: Fri, 27 Mar 2026 00:14:03 +0100 Subject: [PATCH 10/18] runners/lpc55: use PIN protection fix fork (v0.14.1) Switch secrets-app from upstream v0.14.0 to the fork at leetronics/solokeys-secrets-app-fork branch fix-pin-protection-isolation-v0.14 which backports the PIN protection key isolation security fix. Also: - Add trussed-chunked/hpke/wrap-key-to-file as direct deps (required by unconditional imports in types.rs for PIV extension dispatch) - Enable chunked/hpke/wrap-key-to-file features in trussed-staging so StagingBackend implements ExtensionImpl for those PIV extensions - Enable ctaphid feature in secrets-app (allows OATH access via CTAPHID vendor command H70, ctaphid-app 0.1.0-rc.1 compatible with 0.1.0) --- runners/lpc55/Cargo.lock | 16 +++++++++++++--- runners/lpc55/Cargo.toml | 9 ++++++--- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/runners/lpc55/Cargo.lock b/runners/lpc55/Cargo.lock index 1db77f83..f0e088f3 100644 --- a/runners/lpc55/Cargo.lock +++ b/runners/lpc55/Cargo.lock @@ -647,7 +647,7 @@ dependencies = [ [[package]] name = "encrypted_container" version = "0.1.0" -source = "git+https://github.com/Nitrokey/trussed-secrets-app?tag=v0.14.0#e72e80491b79962ac0f8030581eca8ba0004a732" +source = "git+https://github.com/leetronics/solokeys-secrets-app-fork?branch=fix-pin-protection-isolation-v0.14#2887af9b8d2c28891110dd05d8a379303d770611" dependencies = [ "cbor-smol", "delog", @@ -1784,11 +1784,14 @@ dependencies = [ "trussed", "trussed-auth", "trussed-auth-backend", + "trussed-chunked", "trussed-core", "trussed-fs-info", "trussed-hkdf", + "trussed-hpke", "trussed-manage", "trussed-staging", + "trussed-wrap-key-to-file", "usb-device", "usbd-ccid", "usbd-ctaphid", @@ -1851,13 +1854,14 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "secrets-app" -version = "0.14.0" -source = "git+https://github.com/Nitrokey/trussed-secrets-app?tag=v0.14.0#e72e80491b79962ac0f8030581eca8ba0004a732" +version = "0.14.1" +source = "git+https://github.com/leetronics/solokeys-secrets-app-fork?branch=fix-pin-protection-isolation-v0.14#2887af9b8d2c28891110dd05d8a379303d770611" dependencies = [ "apdu-app", "bitflags 2.10.0", "block-padding", "cbor-smol", + "ctaphid-app", "delog", "encrypted_container", "flexiber", @@ -2362,8 +2366,11 @@ name = "trussed-staging" version = "0.3.3" source = "git+https://github.com/trussed-dev/trussed-staging.git?tag=v0.3.3#2e44cf8ca3e6597880a1e59757228da2d6cce3f1" dependencies = [ + "aead", + "chacha20poly1305", "delog", "digest 0.10.7", + "hex-literal 0.4.1", "hkdf", "littlefs2-core", "rand_core", @@ -2372,9 +2379,12 @@ dependencies = [ "serde-byte-array", "sha2 0.10.9", "trussed", + "trussed-chunked", "trussed-fs-info", "trussed-hkdf", + "trussed-hpke", "trussed-manage", + "trussed-wrap-key-to-file", ] [[package]] diff --git a/runners/lpc55/Cargo.toml b/runners/lpc55/Cargo.toml index 85d1a37a..82e3a0d4 100644 --- a/runners/lpc55/Cargo.toml +++ b/runners/lpc55/Cargo.toml @@ -32,10 +32,13 @@ usb-device = "0.2.3" usbd-serial = "0.1.0" admin-app = { version = "0.1", optional = true } -trussed-staging = { git = "https://github.com/trussed-dev/trussed-staging.git", tag = "v0.3.3", features = ["hkdf", "fs-info", "manage"] } +trussed-staging = { git = "https://github.com/trussed-dev/trussed-staging.git", tag = "v0.3.3", features = ["hkdf", "fs-info", "manage", "chunked", "hpke", "wrap-key-to-file"] } trussed-fs-info = "0.2" trussed-hkdf = "0.3" trussed-manage = "0.2" +trussed-chunked = "0.2" +trussed-hpke = "0.2" +trussed-wrap-key-to-file = "0.2" trussed-auth = "0.4" trussed-auth-backend = { git = "https://github.com/trussed-dev/trussed-auth", tag = "v0.4.0" } apdu-dispatch = "0.3" @@ -44,8 +47,8 @@ ctap-types = "0.4" fido-authenticator = { version = "0.2", features = ["dispatch"], optional = true } oath-authenticator = { version = "0.1", features = ["apdu-dispatch"], optional = true } # OATH/TOTP/HOTP support via trussed-secrets-app (Nitrokey's implementation, Yubico OATH AID) -# OATH via APDU only (not ctaphid-dispatch: ctaphid-app 0.1.0-rc.1 conflicts with 0.1.0) -secrets-app = { git = "https://github.com/Nitrokey/trussed-secrets-app", tag = "v0.14.0", features = ["apdu-dispatch"], optional = true } +# Using fork with PIN protection key isolation fix backported to v0.14 +secrets-app = { git = "https://github.com/leetronics/solokeys-secrets-app-fork", branch = "fix-pin-protection-isolation-v0.14", features = ["apdu-dispatch", "ctaphid"], optional = true } piv-authenticator = { git = "https://github.com/trussed-dev/piv-authenticator", features = ["apdu-dispatch"], optional = true, tag = "v0.5.3" } trussed = "0.1" trussed-core = "0.1" From c9e5f7d67111587f91be00c6628e3bd1895755ce Mon Sep 17 00:00:00 2001 From: Manuel Domke Date: Fri, 27 Mar 2026 01:34:44 +0100 Subject: [PATCH 11/18] runners/lpc55: upgrade to secrets-app v0.15 / trussed-core v0.2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bump the full trussed ecosystem to support the v0.15 secrets-app branch (fix-pin-protection-isolation) which is based on trussed-core v0.2. Dependency changes: - trussed: rev e107ed3 → 0f8df68 (trussed-core v0.2 basis) - trussed-core: 0.1 → 0.2 - trussed-auth: 0.4 → 0.5 - trussed-auth-backend: tag v0.4.0 → backend-v0.1.0 - trussed-staging: v0.3.3 → v0.4.0 (adds chunked, hpke, wrap-key-to-file) - apdu-dispatch: 0.3 → 0.4 - ctaphid-dispatch: 0.3 → 0.4 - fido-authenticator: 0.2 → 0.3 (requires dispatch feature) - piv-authenticator: v0.5.3 → v0.6.0 - admin-app patch: v0.1.0-nitrokey.20 → v0.1.0-nitrokey.21 - usbd-ccid: 0.3 → 0.4 - usbd-ctaphid: 0.3 → 0.4 (crates.io; wouldblock fork no longer needed) - littlefs2: git v0.6.1-nitrokey.1 → crates.io 0.7 - littlefs2-core patch: v0.6.1-nitrokey.1 → core-0.1.2 (has heapless-bytes05) - ctap-types: 0.4 → 0.5 - components/ndef-app, nfc-device: heapless→0.9, apdu-dispatch→0.4, iso7816→0.2 API fixes: - apdu_dispatch::App no longer has a ResponseSize generic param - apdu_dispatch::iso7816::Interface replaces dispatch::Interface - ctaphid_dispatch::App no longer has a message size generic param - ndef-app: use VecView instead of Data (apdu-app 0.2) Tested on hardware: CTAPHID PING, FIDO2 GET_INFO all pass. WouldBlock fix confirmed unnecessary with usbd-ctaphid 0.4. --- components/ndef-app/Cargo.toml | 6 +- components/ndef-app/src/ndef.rs | 10 +- components/nfc-device/Cargo.toml | 6 +- runners/lpc55/Cargo.lock | 387 ++++++++++++++++++------------- runners/lpc55/Cargo.toml | 54 ++--- runners/lpc55/src/main.rs | 4 +- runners/lpc55/src/types.rs | 7 +- 7 files changed, 268 insertions(+), 206 deletions(-) diff --git a/components/ndef-app/Cargo.toml b/components/ndef-app/Cargo.toml index f2225dfc..b43f0235 100644 --- a/components/ndef-app/Cargo.toml +++ b/components/ndef-app/Cargo.toml @@ -7,7 +7,7 @@ edition = "2024" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -heapless = "0.8" +heapless = "0.9" -apdu-dispatch = "0.3" -iso7816 = "0.1" +apdu-dispatch = "0.4" +iso7816 = "0.2" diff --git a/components/ndef-app/src/ndef.rs b/components/ndef-app/src/ndef.rs index 2e8c7543..97b6b733 100644 --- a/components/ndef-app/src/ndef.rs +++ b/components/ndef-app/src/ndef.rs @@ -1,6 +1,6 @@ use iso7816::{Instruction, Status}; -use apdu_dispatch::{app, response::SIZE as ResponseSize}; -use apdu_dispatch::app::{CommandView, Data, Interface}; +use apdu_dispatch::app; +use apdu_dispatch::app::{CommandView, Interface, VecView}; pub struct App<'a>{ reader: &'a [u8] @@ -38,15 +38,15 @@ impl<'a> iso7816::App for App<'a> { } } -impl<'a> app::App for App<'a> { +impl<'a> app::App for App<'a> { - fn select(&mut self, _interface: Interface, _apdu: CommandView<'_>, _reply: &mut Data) -> app::Result { + fn select(&mut self, _interface: Interface, _apdu: CommandView<'_>, _reply: &mut VecView) -> app::Result { Ok(()) } fn deselect(&mut self) {} - fn call(&mut self, _interface: Interface, apdu: CommandView<'_>, reply: &mut Data) -> app::Result { + fn call(&mut self, _interface: Interface, apdu: CommandView<'_>, reply: &mut VecView) -> app::Result { let instruction = apdu.instruction(); let p1 = apdu.p1; let p2 = apdu.p2; diff --git a/components/nfc-device/Cargo.toml b/components/nfc-device/Cargo.toml index d9c3b6c0..9247f17b 100644 --- a/components/nfc-device/Cargo.toml +++ b/components/nfc-device/Cargo.toml @@ -7,9 +7,9 @@ edition = "2024" [dependencies] defmt = "1.0.1" embedded-time = "0.12" -heapless = "0.7" +heapless = "0.9" nb = "1" -apdu-dispatch = "0.3" -iso7816 = "0.1" +apdu-dispatch = "0.4" +iso7816 = "0.2" interchange = "0.3" diff --git a/runners/lpc55/Cargo.lock b/runners/lpc55/Cargo.lock index f0e088f3..05f6c55d 100644 --- a/runners/lpc55/Cargo.lock +++ b/runners/lpc55/Cargo.lock @@ -5,16 +5,16 @@ version = 3 [[package]] name = "admin-app" version = "0.1.0" -source = "git+https://github.com/Nitrokey/admin-app.git?tag=v0.1.0-nitrokey.20#ff574d810f718c7ce0912512f6c551ca2ea7c88a" +source = "git+https://github.com/Nitrokey/admin-app.git?tag=v0.1.0-nitrokey.21#261c47d791f7862a8fd1b52d485860ff82216478" dependencies = [ - "apdu-app", + "apdu-app 0.2.0", "cbor-smol", "ctaphid-app", "delog", - "heapless 0.7.17", - "heapless-bytes", + "heapless 0.9.2", + "heapless-bytes 0.5.0", "hex-literal 0.4.1", - "iso7816", + "iso7816 0.2.0", "littlefs2-core", "serde", "strum_macros", @@ -60,7 +60,17 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce391931a2cc4597eaf0d464db9d4d5e1939ccc8dd6eda0f86cda117e914c02d" dependencies = [ - "iso7816", + "iso7816 0.1.4", +] + +[[package]] +name = "apdu-app" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfe0bbbf8e3c1034ec9b1d1f9f50ab634e65a8249972f2a34ada1cf115efb0a9" +dependencies = [ + "heapless 0.9.2", + "iso7816 0.2.0", ] [[package]] @@ -72,7 +82,7 @@ dependencies = [ "delog", "heapless 0.7.17", "interchange 0.2.2", - "iso7816", + "iso7816 0.1.4", ] [[package]] @@ -81,11 +91,24 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d6e6883b2c23b9fe1a488913705c7b68f751bdb73da036ff8191da729337a5d" dependencies = [ - "apdu-app", + "apdu-app 0.1.0", "delog", "heapless 0.7.17", "interchange 0.3.2", - "iso7816", + "iso7816 0.1.4", +] + +[[package]] +name = "apdu-dispatch" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3c9f7729cfb0991e556f650a1478e1e8bd8db7fc57ff2dec4a3a67669d406ff" +dependencies = [ + "apdu-app 0.2.0", + "delog", + "heapless 0.9.2", + "interchange 0.3.2", + "iso7816 0.2.0", ] [[package]] @@ -136,7 +159,7 @@ version = "0.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "cexpr", "clang-sys", "itertools", @@ -145,7 +168,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -162,9 +185,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.10.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" [[package]] name = "block-buffer" @@ -229,16 +252,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b6dd31f7069836e87169bc5910212571b873cebe389c7c7f2d8b1fb3e55c80d" dependencies = [ "delog", - "heapless 0.7.17", - "heapless-bytes", + "heapless 0.9.2", + "heapless-bytes 0.5.0", "serde_core", ] [[package]] name = "cc" -version = "1.2.55" +version = "1.2.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47b26a0954ae34af09b50f0de26458fa95369a0d478d8236d3f93082b219bd29" +checksum = "7a0dd1ca384932ff3641c8718a02769f1698e7563dc6974ffd03346116310423" dependencies = [ "find-msvc-tools", "shlex", @@ -350,11 +373,11 @@ dependencies = [ [[package]] name = "cosey" -version = "0.3.2" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75494895fa1a9713ca725ddf2db084ee84fb0c20938fdd7c89293febe732d30a" +checksum = "540d9a2a9f2d35a876fedb35f4c0b51c7a69f71f042252cf34fc159708f962d4" dependencies = [ - "heapless-bytes", + "heapless-bytes 0.5.0", "serde", "serde_repr", ] @@ -398,9 +421,9 @@ dependencies = [ [[package]] name = "crypto-mac" -version = "0.11.1" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" +checksum = "25fab6889090c8133f3deb8f73ba3c65a7f456f66436fc012a1b1e272b1e103e" dependencies = [ "generic-array 0.14.7", "subtle", @@ -408,17 +431,17 @@ dependencies = [ [[package]] name = "ctap-types" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb8b105c5e728afd373e99874f0c1911c170b3a56848456cc16feb4506321606" +checksum = "ab74c7ac39f3bde2a13960ab8257975a35cfcc3d45420ca59b21b55dcbadc6f9" dependencies = [ "bitflags 1.3.2", "cbor-smol", "cosey", "delog", - "heapless 0.7.17", - "heapless-bytes", - "iso7816", + "heapless 0.9.2", + "heapless-bytes 0.5.0", + "iso7816 0.2.0", "serde", "serde-indexed", "serde_bytes", @@ -427,23 +450,23 @@ dependencies = [ [[package]] name = "ctaphid-app" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fe93489fe96c998488d0843dffea35c02ed9add2585e55228e1d45988727ecc" +checksum = "2dc7bdd7194322583c6f3ec411713cb555da3ab9b97414a322639ca4adc728c7" dependencies = [ - "heapless-bytes", + "heapless-bytes 0.5.0", "trussed-core", ] [[package]] name = "ctaphid-dispatch" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38fd4316573df369820c5a9f8285fe522d8871c0b20bcf7d390f73b8e6caee28" +checksum = "147f7046a868d513bfa57c04417a585cc9d5de126556cf6814318d5393901b87" dependencies = [ "ctaphid-app", "delog", - "heapless-bytes", + "heapless-bytes 0.5.0", "interchange 0.3.2", "ref-swap", "trussed-core", @@ -475,7 +498,7 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -647,12 +670,12 @@ dependencies = [ [[package]] name = "encrypted_container" version = "0.1.0" -source = "git+https://github.com/leetronics/solokeys-secrets-app-fork?branch=fix-pin-protection-isolation-v0.14#2887af9b8d2c28891110dd05d8a379303d770611" +source = "git+https://github.com/leetronics/solokeys-secrets-app-fork?branch=fix-pin-protection-isolation#d49ed35a0d1378bc66284c788ce059d4e7bd70d6" dependencies = [ "cbor-smol", "delog", - "heapless 0.7.17", - "heapless-bytes", + "heapless 0.9.2", + "heapless-bytes 0.5.0", "serde", "trussed-core", ] @@ -675,19 +698,19 @@ dependencies = [ [[package]] name = "fido-authenticator" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f7367d82579f74638875b1a277d55a4c23a3b4865b53d26cd315e99aa528b42" +checksum = "5a71f10c27a05873e7020d4c54eb8318236f35c60821b6d65b0a59b9ee8d821c" dependencies = [ - "apdu-app", + "apdu-app 0.2.0", "cbor-smol", "cosey", "ctap-types", "ctaphid-app", "delog", - "heapless 0.7.17", - "heapless-bytes", - "iso7816", + "heapless 0.9.2", + "heapless-bytes 0.5.0", + "iso7816 0.2.0", "littlefs2-core", "serde", "serde-indexed", @@ -715,6 +738,17 @@ dependencies = [ "heapless 0.7.17", ] +[[package]] +name = "flexiber" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0dde85f89d92790f7052d357fa120881128e61431a70558bbc0355cc0a5dca4" +dependencies = [ + "delog", + "flexiber_derive", + "heapless 0.9.2", +] + [[package]] name = "flexiber_derive" version = "0.1.3" @@ -723,7 +757,7 @@ checksum = "e9985657bc39bae5cb7f4e686b46c67b1ea37390d82fe4bab56d7cd1933429d7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", "synstructure 0.13.2", ] @@ -749,26 +783,25 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" [[package]] name = "futures-task" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" [[package]] name = "futures-util" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" dependencies = [ "futures-core", "futures-task", "pin-project-lite", - "pin-utils", ] [[package]] @@ -932,6 +965,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2af2455f757db2b292a9b1768c4b70186d443bcb3b316252d6b540aec1cd89ed" dependencies = [ "hash32 0.3.1", + "serde_core", "stable_deref_trait", ] @@ -946,6 +980,16 @@ dependencies = [ "typenum", ] +[[package]] +name = "heapless-bytes" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "774f9dbf3f3a66edc65579e68b9f564ad5ec52e770a755af46b87d40909b8024" +dependencies = [ + "heapless 0.9.2", + "serde_core", +] + [[package]] name = "heck" version = "0.4.1" @@ -1046,6 +1090,15 @@ dependencies = [ "heapless 0.7.17", ] +[[package]] +name = "iso7816" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b574e1a9ae668e3167a82fe2c62fe629ca60383da01c6f70acb0fb642d9c55f" +dependencies = [ + "heapless 0.9.2", +] + [[package]] name = "itertools" version = "0.13.0" @@ -1063,9 +1116,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.180" +version = "0.2.183" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" +checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" [[package]] name = "libloading" @@ -1080,9 +1133,9 @@ dependencies = [ [[package]] name = "littlefs2" version = "0.6.1" -source = "git+https://github.com/trussed-dev/littlefs2.git?tag=v0.6.1-nitrokey.1#b3a7371d849695fa05ab75910c4b14057db7ceb2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a43f3c0c6a7d127e3e1241665dd896d8bf1ca31cf9d826a1dc65239bd59868" dependencies = [ - "bitflags 2.10.0", "delog", "generic-array 0.14.7", "heapless 0.7.17", @@ -1090,20 +1143,35 @@ dependencies = [ "littlefs2-sys", ] +[[package]] +name = "littlefs2" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8022e5141ceff5b7b12897113f54fc9dac5ad36402c787941c97272b9241eb" +dependencies = [ + "bitflags 2.11.0", + "delog", + "generic-array 0.14.7", + "heapless 0.9.2", + "littlefs2-core", + "littlefs2-sys", +] + [[package]] name = "littlefs2-core" -version = "0.1.1" -source = "git+https://github.com/trussed-dev/littlefs2.git?tag=v0.6.1-nitrokey.1#b3a7371d849695fa05ab75910c4b14057db7ceb2" +version = "0.1.2" +source = "git+https://github.com/trussed-dev/littlefs2.git?tag=core-0.1.2#4eec5f2fcd4d9f7d49532b822de012995d695327" dependencies = [ - "bitflags 2.10.0", - "heapless-bytes", + "bitflags 2.11.0", + "heapless-bytes 0.5.0", "serde", ] [[package]] name = "littlefs2-sys" -version = "0.3.1" -source = "git+https://github.com/trussed-dev/littlefs2-sys.git?tag=v0.3.1-nitrokey.1#1cfd35c9974b877761e8bb45417f7ad2a61bedad" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae112b732df34c1420471e1ff21c562dfdf81219efb5960dd15b3947097e784a" dependencies = [ "bindgen", "cc", @@ -1242,9 +1310,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.6" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" [[package]] name = "micromath" @@ -1277,21 +1345,21 @@ checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" name = "ndef-app" version = "0.1.0" dependencies = [ - "apdu-dispatch 0.3.1", - "heapless 0.8.0", - "iso7816", + "apdu-dispatch 0.4.0", + "heapless 0.9.2", + "iso7816 0.2.0", ] [[package]] name = "nfc-device" version = "0.0.1" dependencies = [ - "apdu-dispatch 0.3.1", + "apdu-dispatch 0.4.0", "defmt", "embedded-time", - "heapless 0.7.17", + "heapless 0.9.2", "interchange 0.3.2", - "iso7816", + "iso7816 0.2.0", "nb 1.1.0", ] @@ -1384,21 +1452,21 @@ checksum = "11470bb97635a0d1943211c7b9cd473ecee002342480e8fc7347beba27f38243" dependencies = [ "apdu-dispatch 0.1.2", "delog", - "flexiber", + "flexiber 0.1.3", "heapless 0.7.17", - "heapless-bytes", + "heapless-bytes 0.3.0", "hex-literal 0.3.4", "interchange 0.2.2", - "iso7816", + "iso7816 0.1.4", "serde", "trussed", ] [[package]] name = "once_cell" -version = "1.21.3" +version = "1.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" [[package]] name = "opaque-debug" @@ -1451,9 +1519,9 @@ checksum = "a513e167849a384b7f9b746e517604398518590a9142f4846a32e3c2a4de7b11" [[package]] name = "pin-project-lite" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" [[package]] name = "pin-utils" @@ -1463,17 +1531,17 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "piv-authenticator" -version = "0.5.3" -source = "git+https://github.com/trussed-dev/piv-authenticator?tag=v0.5.3#5c858c2dd60fe2c3f628f50e308e2a2c39e34bd3" +version = "0.6.0" +source = "git+https://github.com/trussed-dev/piv-authenticator?tag=v0.6.0#be6918199642d53ae1af75f181e0b5577449d7a2" dependencies = [ - "apdu-app", + "apdu-app 0.2.0", "cbor-smol", "cfg-if", - "flexiber", - "heapless 0.7.17", - "heapless-bytes", + "flexiber 0.2.0", + "heapless 0.9.2", + "heapless-bytes 0.5.0", "hex-literal 0.3.4", - "iso7816", + "iso7816 0.2.0", "littlefs2-core", "log", "serde", @@ -1548,7 +1616,7 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -1567,7 +1635,7 @@ dependencies = [ "apdu-dispatch 0.3.1", "defmt", "heapless 0.8.0", - "littlefs2", + "littlefs2 0.6.1", "lpc55-hal 0.3.1", "p256", "salty", @@ -1576,9 +1644,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.44" +version = "1.0.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" dependencies = [ "proc-macro2", ] @@ -1613,9 +1681,9 @@ checksum = "09c30c54dffee5b40af088d5d50aa3455c91a0127164b51f0215efc4cb28fb3c" [[package]] name = "regex" -version = "1.12.2" +version = "1.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" dependencies = [ "aho-corasick", "memchr", @@ -1625,9 +1693,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" dependencies = [ "aho-corasick", "memchr", @@ -1636,9 +1704,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.8" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" [[package]] name = "rtic" @@ -1686,7 +1754,7 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -1754,7 +1822,7 @@ name = "runner" version = "2.964.0" dependencies = [ "admin-app", - "apdu-dispatch 0.3.1", + "apdu-dispatch 0.4.0", "board", "cortex-m", "ctap-types", @@ -1766,7 +1834,7 @@ dependencies = [ "fm11nc08", "heapless 0.9.2", "interchange 0.3.2", - "littlefs2", + "littlefs2 0.7.1", "nb 1.1.0", "ndef-app", "nfc-device", @@ -1834,7 +1902,6 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b947325a585e90733e0e9ec097228f40b637cc346f9bd68f84d5c6297d0fcfef" dependencies = [ - "cosey", "ed25519", "subtle", "zeroize", @@ -1854,21 +1921,21 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "secrets-app" -version = "0.14.1" -source = "git+https://github.com/leetronics/solokeys-secrets-app-fork?branch=fix-pin-protection-isolation-v0.14#2887af9b8d2c28891110dd05d8a379303d770611" +version = "0.15.1" +source = "git+https://github.com/leetronics/solokeys-secrets-app-fork?branch=fix-pin-protection-isolation#d49ed35a0d1378bc66284c788ce059d4e7bd70d6" dependencies = [ - "apdu-app", - "bitflags 2.10.0", + "apdu-app 0.2.0", + "bitflags 2.11.0", "block-padding", "cbor-smol", "ctaphid-app", "delog", "encrypted_container", - "flexiber", - "heapless 0.7.17", - "heapless-bytes", + "flexiber 0.2.0", + "heapless 0.9.2", + "heapless-bytes 0.5.0", "hex-literal 0.3.4", - "iso7816", + "iso7816 0.2.0", "littlefs2-core", "serde", "trussed-auth", @@ -1923,7 +1990,7 @@ checksum = "fca2da10b1f1623f47130256065e05e94fd7a98dbd26a780a4c5de831b21e5c2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -1953,7 +2020,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -1964,7 +2031,7 @@ checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -2073,14 +2140,14 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] name = "subtle" -version = "2.4.1" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" @@ -2095,9 +2162,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.114" +version = "2.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" dependencies = [ "proc-macro2", "quote", @@ -2124,7 +2191,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -2155,7 +2222,7 @@ checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -2186,7 +2253,7 @@ checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -2212,9 +2279,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.22" +version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e" +checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319" dependencies = [ "matchers", "nu-ansi-term", @@ -2231,10 +2298,10 @@ dependencies = [ [[package]] name = "trussed" version = "0.1.0" -source = "git+https://github.com/trussed-dev/trussed.git?rev=e107ed315a07dc6c992fac39d542e847cc3a1b6c#e107ed315a07dc6c992fac39d542e847cc3a1b6c" +source = "git+https://github.com/trussed-dev/trussed.git?rev=0f8df68be879acdde1f8cf428c11e5d29692a47b#0f8df68be879acdde1f8cf428c11e5d29692a47b" dependencies = [ "aes", - "bitflags 2.10.0", + "bitflags 2.11.0", "cbc", "cbor-smol", "cfg-if", @@ -2243,13 +2310,14 @@ dependencies = [ "cosey", "delog", "des", - "flexiber", + "flexiber 0.2.0", "generic-array 0.14.7", - "heapless 0.7.17", - "heapless-bytes", + "heapless 0.9.2", + "heapless-bytes 0.5.0", "hex-literal 0.4.1", "hmac 0.12.1", "interchange 0.3.2", + "littlefs2 0.7.1", "littlefs2-core", "nb 1.1.0", "p256-cortex-m4", @@ -2266,9 +2334,9 @@ dependencies = [ [[package]] name = "trussed-auth" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3110004319491b9210f50c3653a574d354e27a3de73ae5a3dfc2e686027702e7" +checksum = "36b4123667b5c36495d1f650732338c64fd645d9a9f27cada941d5f00ce2b631" dependencies = [ "serde", "trussed-core", @@ -2277,7 +2345,7 @@ dependencies = [ [[package]] name = "trussed-auth-backend" version = "0.1.0" -source = "git+https://github.com/trussed-dev/trussed-auth?tag=v0.4.0#ab6ad8422531fb4801fee795cb44baa375320f15" +source = "git+https://github.com/trussed-dev/trussed-auth?tag=backend-v0.1.0#faeb596778be5739afc86c34e45634f57f0f28ff" dependencies = [ "chacha20poly1305", "hkdf", @@ -2295,9 +2363,9 @@ dependencies = [ [[package]] name = "trussed-chunked" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9268d9d812440965ce31684e0115ceafa2636b7a8cc04dc117594567c53ff75e" +checksum = "5773ec78597cb55f609c45ce1cf9566cd20d4749aba53a9a9408a47707289ff3" dependencies = [ "serde", "serde-byte-array", @@ -2306,11 +2374,11 @@ dependencies = [ [[package]] name = "trussed-core" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afddad280ae8a5235e1b06408cca909ce9454cdd89f941b94b024c580732b3ce" +checksum = "3ac4d4507be66aa1a5ba6921bed58d37af1e0118772e0a4955df58aa3cb4f5e8" dependencies = [ - "heapless-bytes", + "heapless-bytes 0.5.0", "littlefs2-core", "postcard", "rand_core", @@ -2320,9 +2388,9 @@ dependencies = [ [[package]] name = "trussed-fs-info" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44822e0abc5a32b3f370f82644ee9cb08aa693847aac0d48f6dc115389157aea" +checksum = "4f29e12a051798fc37e531379862a23ac62a1ca38e2357684cd04fc69dc4f1d9" dependencies = [ "serde", "serde-byte-array", @@ -2331,9 +2399,9 @@ dependencies = [ [[package]] name = "trussed-hkdf" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17884daee9214e24c7bb9cf2429d0f53c569cfa4a8d728106e459e60aed5be69" +checksum = "31644e234cbfa703017f13d98b643851d814c45f90d969ce0bbbb3cb28879edc" dependencies = [ "serde", "trussed-core", @@ -2341,9 +2409,9 @@ dependencies = [ [[package]] name = "trussed-hpke" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d382b3bb98a71862e7db71437204d3e9f1542e42d30c1f18515ba07db4d970a" +checksum = "eb285be4d1ddc4a69c81481fb2148e9f68c4153c6c2e9a3bfd234ab37c225601" dependencies = [ "serde", "serde-byte-array", @@ -2352,9 +2420,9 @@ dependencies = [ [[package]] name = "trussed-manage" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd9663f2c1b5bddbb02f9edbbe9085313ae8cd03e53a2eb266f43b1dba365287" +checksum = "dfab5a172be33bcbbdb7362842a887f84bb594af6f3ccd248739673f1e890c42" dependencies = [ "littlefs2-core", "serde", @@ -2363,13 +2431,15 @@ dependencies = [ [[package]] name = "trussed-staging" -version = "0.3.3" -source = "git+https://github.com/trussed-dev/trussed-staging.git?tag=v0.3.3#2e44cf8ca3e6597880a1e59757228da2d6cce3f1" +version = "0.4.0" +source = "git+https://github.com/trussed-dev/trussed-staging.git?tag=v0.4.0#bda6a9afec4f3ceeaf096002f95126653066615e" dependencies = [ "aead", "chacha20poly1305", "delog", "digest 0.10.7", + "heapless 0.9.2", + "heapless-bytes 0.5.0", "hex-literal 0.4.1", "hkdf", "littlefs2-core", @@ -2389,9 +2459,9 @@ dependencies = [ [[package]] name = "trussed-wrap-key-to-file" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b923d89f632ac2b62af4193844f1afb6d0fe4e31af8a1a85053a328da1f512d7" +checksum = "ee53579ffe7d100a84a53ae29240552fa83a5686969db73c4f74cf13a23b00de" dependencies = [ "serde", "trussed-core", @@ -2405,9 +2475,9 @@ checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" [[package]] name = "unicode-ident" -version = "1.0.22" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" [[package]] name = "unicode-xid" @@ -2439,28 +2509,27 @@ checksum = "1f6cc3adc849b5292b4075fc0d5fdcf2f24866e88e336dd27a8943090a520508" [[package]] name = "usbd-ccid" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "403fefa622483869d1b36f2accd7458291202c18aa2f2e5147caf638825dde0c" +checksum = "8acbc8d41fe1b6dc92347f5988a44252fc9e2511f7cb312fa23e9eee186bfdd3" dependencies = [ "delog", "embedded-time", - "heapless 0.7.17", + "heapless 0.9.2", "interchange 0.3.2", - "iso7816", "usb-device", ] [[package]] name = "usbd-ctaphid" -version = "0.3.0" -source = "git+https://github.com/leetronics/usbd-ctaphid.git?branch=v0.3-wouldblock-fix#3823eb7fc3cec223749e7e83e32a56f178d4ce64" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c527a4840bcb38299924c7a6b0c31f95a89172bdfb4577c515315ce9b097f15a" dependencies = [ "ctaphid-dispatch", - "defmt", "delog", "embedded-time", - "heapless-bytes", + "heapless-bytes 0.5.0", "interchange 0.3.2", "ref-swap", "serde", @@ -2604,22 +2673,22 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "zerocopy" -version = "0.8.42" +version = "0.8.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2578b716f8a7a858b7f02d5bd870c14bf4ddbbcf3a4c05414ba6503640505e3" +checksum = "efbb2a062be311f2ba113ce66f697a4dc589f85e78a4aea276200804cea0ed87" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.42" +version = "0.8.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e6cc098ea4d3bd6246687de65af3f920c430e236bee1e3bf2e441463f08a02f" +checksum = "0e8bc7269b54418e7aeeef514aa68f8690b8c0489a06b0136e5f57c4c5ccab89" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -2639,5 +2708,5 @@ checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] diff --git a/runners/lpc55/Cargo.toml b/runners/lpc55/Cargo.toml index 82e3a0d4..379188a2 100644 --- a/runners/lpc55/Cargo.toml +++ b/runners/lpc55/Cargo.toml @@ -32,26 +32,26 @@ usb-device = "0.2.3" usbd-serial = "0.1.0" admin-app = { version = "0.1", optional = true } -trussed-staging = { git = "https://github.com/trussed-dev/trussed-staging.git", tag = "v0.3.3", features = ["hkdf", "fs-info", "manage", "chunked", "hpke", "wrap-key-to-file"] } -trussed-fs-info = "0.2" -trussed-hkdf = "0.3" -trussed-manage = "0.2" -trussed-chunked = "0.2" -trussed-hpke = "0.2" -trussed-wrap-key-to-file = "0.2" -trussed-auth = "0.4" -trussed-auth-backend = { git = "https://github.com/trussed-dev/trussed-auth", tag = "v0.4.0" } -apdu-dispatch = "0.3" -ctaphid-dispatch = "0.3" -ctap-types = "0.4" -fido-authenticator = { version = "0.2", features = ["dispatch"], optional = true } +trussed-staging = { git = "https://github.com/trussed-dev/trussed-staging.git", tag = "v0.4.0", features = ["hkdf", "fs-info", "manage", "chunked", "hpke", "wrap-key-to-file"] } +trussed-fs-info = "0.3" +trussed-hkdf = "0.4" +trussed-manage = "0.3" +trussed-chunked = "0.3" +trussed-hpke = "0.3" +trussed-wrap-key-to-file = "0.3" +trussed-auth = "0.5" +trussed-auth-backend = { git = "https://github.com/trussed-dev/trussed-auth", tag = "backend-v0.1.0" } +apdu-dispatch = "0.4" +ctaphid-dispatch = "0.4" +ctap-types = "0.5" +fido-authenticator = { version = "0.3", features = ["dispatch"], optional = true } oath-authenticator = { version = "0.1", features = ["apdu-dispatch"], optional = true } # OATH/TOTP/HOTP support via trussed-secrets-app (Nitrokey's implementation, Yubico OATH AID) # Using fork with PIN protection key isolation fix backported to v0.14 -secrets-app = { git = "https://github.com/leetronics/solokeys-secrets-app-fork", branch = "fix-pin-protection-isolation-v0.14", features = ["apdu-dispatch", "ctaphid"], optional = true } -piv-authenticator = { git = "https://github.com/trussed-dev/piv-authenticator", features = ["apdu-dispatch"], optional = true, tag = "v0.5.3" } +secrets-app = { git = "https://github.com/leetronics/solokeys-secrets-app-fork", branch = "fix-pin-protection-isolation", features = ["apdu-dispatch", "ctaphid"], optional = true } +piv-authenticator = { git = "https://github.com/trussed-dev/piv-authenticator", features = ["apdu-dispatch"], optional = true, tag = "v0.6.0" } trussed = "0.1" -trussed-core = "0.1" +trussed-core = "0.2" # board board = { path = "board" } @@ -62,8 +62,8 @@ ndef-app = { path = "../../components/ndef-app", optional = true } provisioner-app = { path = "../../components/provisioner-app", optional = true } fm11nc08 = {path = "../../components/fm11nc08"} nfc-device = {path = "../../components/nfc-device"} -usbd-ccid = "0.3" -usbd-ctaphid = { version = "0.3", features = ["log-info", "defmt-logging"] } +usbd-ccid = "0.4" +usbd-ctaphid = { version = "0.4", features = ["log-info"] } # panic @@ -71,7 +71,7 @@ panic-halt = "1.0.0" # panic-semihosting = "0.5.6" # storage -littlefs2 = { version = "0.6", features = ["c-stubs"] } +littlefs2 = { version = "0.7", features = ["c-stubs"] } [features] # ndef-app is an annoyance on some mobile platforms @@ -136,13 +136,9 @@ opt-level = 2 # opt-level = 2 [patch.crates-io] -trussed = { git = "https://github.com/trussed-dev/trussed.git", rev = "e107ed315a07dc6c992fac39d542e847cc3a1b6c" } -admin-app = { git = "https://github.com/Nitrokey/admin-app.git", tag = "v0.1.0-nitrokey.20" } -littlefs2 = { git = "https://github.com/trussed-dev/littlefs2.git", tag = "v0.6.1-nitrokey.1" } -littlefs2-sys = { git = "https://github.com/trussed-dev/littlefs2-sys.git", tag = "v0.3.1-nitrokey.1" } -# Force both trussed and littlefs2 to use the same littlefs2-core (resolves DynFilesystem version mismatch) -littlefs2-core = { git = "https://github.com/trussed-dev/littlefs2.git", tag = "v0.6.1-nitrokey.1" } -# Extension backends needed by fido-authenticator 0.2 (FsInfoClient, HkdfClient) -trussed-staging = { git = "https://github.com/trussed-dev/trussed-staging.git", tag = "v0.3.3" } -# Fix WouldBlock retry for single-packet responses (PING race condition) -usbd-ctaphid = { git = "https://github.com/leetronics/usbd-ctaphid.git", branch = "v0.3-wouldblock-fix" } +trussed = { git = "https://github.com/trussed-dev/trussed.git", rev = "0f8df68be879acdde1f8cf428c11e5d29692a47b" } +admin-app = { git = "https://github.com/Nitrokey/admin-app.git", tag = "v0.1.0-nitrokey.21" } +# Force all crates to use littlefs2-core 0.1.2 which has heapless-bytes05 support +littlefs2-core = { git = "https://github.com/trussed-dev/littlefs2.git", tag = "core-0.1.2" } +# Extension backends needed by fido-authenticator (FsInfo, Hkdf, etc.) +trussed-staging = { git = "https://github.com/trussed-dev/trussed-staging.git", tag = "v0.4.0" } diff --git a/runners/lpc55/src/main.rs b/runners/lpc55/src/main.rs index 9d8b6518..d988e744 100644 --- a/runners/lpc55/src/main.rs +++ b/runners/lpc55/src/main.rs @@ -192,10 +192,10 @@ mod app { .apps .apdu_dispatch(|apps| c.shared.apdu_dispatch.poll(apps)) { - Some(apdu_dispatch::dispatch::Interface::Contact) => { + Some(apdu_dispatch::iso7816::Interface::Contact) => { rtic::pend(USB_INTERRUPT); } - Some(apdu_dispatch::dispatch::Interface::Contactless) => { + Some(apdu_dispatch::iso7816::Interface::Contactless) => { rtic::pend(NFC_INTERRUPT); } _ => {} diff --git a/runners/lpc55/src/types.rs b/runners/lpc55/src/types.rs index 0dfae654..4a81d7d0 100644 --- a/runners/lpc55/src/types.rs +++ b/runners/lpc55/src/types.rs @@ -585,7 +585,6 @@ pub type NdefApp = ndef_app::App<'static>; #[cfg(feature = "provisioner-app")] pub type ProvisionerApp = provisioner_app::Provisioner; -use apdu_dispatch::response::SIZE as ResponseSize; use apdu_dispatch::App as ApduApp; use ctaphid_dispatch::app::App as CtaphidApp; @@ -802,7 +801,7 @@ impl Apps { #[inline(never)] pub fn apdu_dispatch(&mut self, f: F) -> T where - F: FnOnce(&mut [&mut dyn ApduApp]) -> T, + F: FnOnce(&mut [&mut dyn ApduApp]) -> T, { f(&mut [ #[cfg(feature = "ndef-app")] @@ -825,9 +824,7 @@ impl Apps { #[inline(never)] pub fn ctaphid_dispatch(&mut self, f: F) -> T where - F: FnOnce( - &mut [&mut dyn CtaphidApp<'static, { ctaphid_dispatch::DEFAULT_MESSAGE_SIZE }>], - ) -> T, + F: FnOnce(&mut [&mut dyn CtaphidApp<'static>]) -> T, { f(&mut [ #[cfg(feature = "admin-app")] From 6f8ff988d82c500e0072cd80b19edc40900867fe Mon Sep 17 00:00:00 2001 From: Manuel Domke Date: Sat, 28 Mar 2026 20:39:54 +0100 Subject: [PATCH 12/18] runners/lpc55: add opcard (OpenPGP) applet MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Integrates opcard-rs v1.7.0 as the OpenPGP smartcard applet. The applet is included in the default feature set alongside PIV and TOTP. Key implementation details: - OPCARD_BACKENDS: [Auth, StagingBackend, Core] — same as PIV, needed for PIN operations (has_pin/set_pin/get_pin_key) and key wrapping - opts.storage = Location::Internal so card state (PINs, keys, ADMIN_USER_KEY_BACKUP) persists across reboots; the default Location::External causes init_pins() to write to ExternalStorage, which on a 2-block filesystem has zero data blocks and panics via syscall!() → panic_halt - ExternalStorage bumped to 8192 bytes whenever piv-authenticator or opcard is active (both write to External during init_pins) --- runners/lpc55/Cargo.lock | 30 +++++++++++++++++++-- runners/lpc55/Cargo.toml | 7 +++-- runners/lpc55/src/lib.rs | 2 +- runners/lpc55/src/main.rs | 6 ++--- runners/lpc55/src/types.rs | 53 +++++++++++++++++++++++++++++++++++--- 5 files changed, 86 insertions(+), 12 deletions(-) diff --git a/runners/lpc55/Cargo.lock b/runners/lpc55/Cargo.lock index 05f6c55d..ac3c2e26 100644 --- a/runners/lpc55/Cargo.lock +++ b/runners/lpc55/Cargo.lock @@ -670,7 +670,7 @@ dependencies = [ [[package]] name = "encrypted_container" version = "0.1.0" -source = "git+https://github.com/leetronics/solokeys-secrets-app-fork?branch=fix-pin-protection-isolation#d49ed35a0d1378bc66284c788ce059d4e7bd70d6" +source = "git+https://github.com/leetronics/solokeys-secrets-app-fork?branch=fix-pin-protection-isolation#aa4ff03f0b1b8e62964b96d78aa6dc4842a694c4" dependencies = [ "cbor-smol", "delog", @@ -1474,6 +1474,31 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" +[[package]] +name = "opcard" +version = "1.7.0" +source = "git+https://github.com/Nitrokey/opcard-rs?tag=v1.7.0#2b94d6aa0d1d533e01997b61332b229247e41c49" +dependencies = [ + "apdu-app 0.2.0", + "bitflags 2.11.0", + "cbor-smol", + "cfg-if", + "delog", + "heapless 0.9.2", + "heapless-bytes 0.5.0", + "hex-literal 0.4.1", + "iso7816 0.2.0", + "littlefs2-core", + "log", + "serde", + "serde_repr", + "subtle", + "trussed-auth", + "trussed-chunked", + "trussed-core", + "trussed-wrap-key-to-file", +] + [[package]] name = "p256" version = "0.9.0" @@ -1839,6 +1864,7 @@ dependencies = [ "ndef-app", "nfc-device", "oath-authenticator", + "opcard", "panic-halt", "piv-authenticator", "provisioner-app", @@ -1922,7 +1948,7 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "secrets-app" version = "0.15.1" -source = "git+https://github.com/leetronics/solokeys-secrets-app-fork?branch=fix-pin-protection-isolation#d49ed35a0d1378bc66284c788ce059d4e7bd70d6" +source = "git+https://github.com/leetronics/solokeys-secrets-app-fork?branch=fix-pin-protection-isolation#aa4ff03f0b1b8e62964b96d78aa6dc4842a694c4" dependencies = [ "apdu-app 0.2.0", "bitflags 2.11.0", diff --git a/runners/lpc55/Cargo.toml b/runners/lpc55/Cargo.toml index 379188a2..2296aa6c 100644 --- a/runners/lpc55/Cargo.toml +++ b/runners/lpc55/Cargo.toml @@ -48,8 +48,9 @@ fido-authenticator = { version = "0.3", features = ["dispatch"], optional = true oath-authenticator = { version = "0.1", features = ["apdu-dispatch"], optional = true } # OATH/TOTP/HOTP support via trussed-secrets-app (Nitrokey's implementation, Yubico OATH AID) # Using fork with PIN protection key isolation fix backported to v0.14 -secrets-app = { git = "https://github.com/leetronics/solokeys-secrets-app-fork", branch = "fix-pin-protection-isolation", features = ["apdu-dispatch", "ctaphid"], optional = true } +secrets-app = { git = "https://github.com/leetronics/solokeys-secrets-app-fork", branch = "fix-pin-protection-isolation", features = ["apdu-dispatch", "ctaphid", "log-all"], optional = true } piv-authenticator = { git = "https://github.com/trussed-dev/piv-authenticator", features = ["apdu-dispatch"], optional = true, tag = "v0.6.0" } +opcard = { git = "https://github.com/Nitrokey/opcard-rs", tag = "v1.7.0", features = ["apdu-dispatch", "delog"], optional = true } trussed = "0.1" trussed-core = "0.2" @@ -75,7 +76,7 @@ littlefs2 = { version = "0.7", features = ["c-stubs"] } [features] # ndef-app is an annoyance on some mobile platforms -default = ["admin-app", "fido-authenticator", "ndef-app", "oath", "piv-authenticator"] +default = ["admin-app", "fido-authenticator", "ndef-app", "oath", "piv-authenticator", "opcard"] # OATH/TOTP/HOTP via secrets-app (replaces incompatible oath-authenticator 0.1) oath = ["dep:secrets-app"] @@ -86,6 +87,8 @@ develop = ["no-encrypted-storage", "log-defmt"] develop-provisioner = ["develop", "provisioner-app"] develop-secrets = ["develop", "oath"] +opcard = ["dep:opcard"] +develop-opcard = ["develop", "opcard"] # Do not use encryption for the filesystem no-encrypted-storage = [] diff --git a/runners/lpc55/src/lib.rs b/runners/lpc55/src/lib.rs index d7d04c3b..94f120c8 100644 --- a/runners/lpc55/src/lib.rs +++ b/runners/lpc55/src/lib.rs @@ -30,7 +30,7 @@ impl delog::Flusher for Flusher { } // delog!(Delogger, 16*1024, 3*1024, Flusher); -delog!(Delogger, 1, 2048, Flusher); +delog!(Delogger, 3, 2048, Flusher); #[cfg(any(feature = "log-defmt"))] static FLUSHER: Flusher = Flusher {}; diff --git a/runners/lpc55/src/main.rs b/runners/lpc55/src/main.rs index d988e744..cbd33e6b 100644 --- a/runners/lpc55/src/main.rs +++ b/runners/lpc55/src/main.rs @@ -187,11 +187,11 @@ mod app { runner::Delogger::flush(); } - match c + let apdu_result = c .shared .apps - .apdu_dispatch(|apps| c.shared.apdu_dispatch.poll(apps)) - { + .apdu_dispatch(|apps| c.shared.apdu_dispatch.poll(apps)); + match apdu_result { Some(apdu_dispatch::iso7816::Interface::Contact) => { rtic::pend(USB_INTERRUPT); } diff --git a/runners/lpc55/src/types.rs b/runners/lpc55/src/types.rs index 4a81d7d0..adf5bd47 100644 --- a/runners/lpc55/src/types.rs +++ b/runners/lpc55/src/types.rs @@ -213,11 +213,14 @@ const_ram_storage!( // minimum: 2 blocks // TODO: make this optional // piv-authenticator hardcodes Location::External for PUK_USER_KEY_BACKUP in init_pins, -// requiring at least 3 blocks (2 metadata + 1 data). Without PIV, 2 blocks suffices -// as nothing writes to External storage. -#[cfg(not(feature = "piv-authenticator"))] +// and opcard defaults to Location::External for its persistent state + ADMIN_USER_KEY_BACKUP. +// Both write to ExternalStorage during init_pins; the write fails on a 2-block filesystem +// (zero data blocks) → syscall!() panic → panic_halt → firmware freeze. +// Anything writing to External needs at least 3 blocks (2 metadata + 1 data). +// We keep 8192 bytes (16 blocks) whenever either app is enabled. +#[cfg(not(any(feature = "piv-authenticator", feature = "opcard")))] const_ram_storage!(ExternalStorage, 1024); -#[cfg(feature = "piv-authenticator")] +#[cfg(any(feature = "piv-authenticator", feature = "opcard"))] const_ram_storage!(ExternalStorage, 8192); /// Store implementation using three mounted littlefs2 filesystems. @@ -499,6 +502,15 @@ static PIV_BACKENDS: [BackendId; 3] = [ BackendId::Core, ]; +/// Backends for opcard: same requirements as PIV (Auth for PIN, Staging for Chunked/WrapKeyToFile, +/// Core for standard crypto/filesystem). +#[cfg(feature = "opcard")] +static OPCARD_BACKENDS: [BackendId; 3] = [ + BackendId::Custom(BackendIds::Auth), + BackendId::Custom(BackendIds::StagingBackend), + BackendId::Core, +]; + /// Wrapper around the trussed Service that also holds the service endpoints. /// `process()` and `update_ui()` are called from the RTIC OS_EVENT handler and /// the periodic UI task respectively. @@ -572,6 +584,8 @@ impl admin_app::StatusBytes for AdminStatus { pub type AdminApp = admin_app::App; #[cfg(feature = "piv-authenticator")] pub type PivApp = piv_authenticator::Authenticator; +#[cfg(feature = "opcard")] +pub type OpcardApp = opcard::Card; #[cfg(feature = "oath-authenticator")] pub type OathApp = oath_authenticator::Authenticator; #[cfg(feature = "oath")] @@ -613,6 +627,11 @@ static PIV_TRUSSED_CHANNEL: TrussedChannel = TrussedChannel::new(); #[cfg(feature = "piv-authenticator")] static PIV_INTERRUPT: InterruptFlag = InterruptFlag::new(); +#[cfg(feature = "opcard")] +static OPCARD_TRUSSED_CHANNEL: TrussedChannel = TrussedChannel::new(); +#[cfg(feature = "opcard")] +static OPCARD_INTERRUPT: InterruptFlag = InterruptFlag::new(); + #[cfg(feature = "provisioner-app")] static PROVISIONER_TRUSSED_CHANNEL: TrussedChannel = TrussedChannel::new(); #[cfg(feature = "provisioner-app")] @@ -658,6 +677,8 @@ pub struct Apps { pub ndef: NdefApp, #[cfg(feature = "piv-authenticator")] pub piv: PivApp, + #[cfg(feature = "opcard")] + pub opcard: OpcardApp, #[cfg(feature = "provisioner-app")] pub provisioner: ProvisionerApp, } @@ -738,6 +759,26 @@ impl Apps { ) }; + #[cfg(feature = "opcard")] + let opcard = { + let client = make_client( + &OPCARD_TRUSSED_CHANNEL, + littlefs2::path!("opcard"), + trussed, + Some(&OPCARD_INTERRUPT), + &OPCARD_BACKENDS, + ); + // Use Internal storage so card state (PINs, keys) persists across reboots. + // opcard::Options::default() uses Location::External (volatile RAM) which would + // lose all card state on every reboot and cause init_pins to write + // ADMIN_USER_KEY_BACKUP to ExternalStorage — same failure mode as PIV. + { + let mut opts = opcard::Options::default(); + opts.storage = trussed::types::Location::Internal; + OpcardApp::new(client, opts) + } + }; + #[cfg(feature = "oath")] let secrets = { let client = make_client( @@ -793,6 +834,8 @@ impl Apps { ndef, #[cfg(feature = "piv-authenticator")] piv, + #[cfg(feature = "opcard")] + opcard, #[cfg(feature = "provisioner-app")] provisioner, } @@ -808,6 +851,8 @@ impl Apps { &mut self.ndef, #[cfg(feature = "piv-authenticator")] &mut self.piv, + #[cfg(feature = "opcard")] + &mut self.opcard, #[cfg(feature = "oath-authenticator")] &mut self.oath, #[cfg(feature = "oath")] From f0b80d3cb677a166dbfc64bd2f7160237d7f910c Mon Sep 17 00:00:00 2001 From: Manuel Domke Date: Sat, 4 Apr 2026 02:03:33 +0200 Subject: [PATCH 13/18] add root Cargo workspace with centralized dependencies --- .cargo/config.toml | 11 + runners/lpc55/Cargo.lock => Cargo.lock | 250 +-- Cargo.toml | 110 ++ components/fm11nc08/Cargo.toml | 14 +- components/ndef-app/Cargo.toml | 11 +- components/nfc-device/Cargo.toml | 17 +- components/provisioner-app/Cargo.toml | 17 +- components/provisioner-app/src/lib.rs | 29 +- runners/lpc55/Cargo.toml | 138 +- runners/lpc55/board/Cargo.toml | 27 +- .../vendor/littlefs2/.cargo-checksum.json | 1 - .../vendor/littlefs2/.cargo_vcs_info.json | 5 - .../vendor/littlefs2/.github/FUNDING.yml | 1 - .../vendor/littlefs2/.github/workflows/ci.yml | 48 - runners/lpc55/vendor/littlefs2/CHANGELOG.md | 34 - runners/lpc55/vendor/littlefs2/Cargo.toml | 71 - .../lpc55/vendor/littlefs2/Cargo.toml.orig | 59 - runners/lpc55/vendor/littlefs2/LICENSE-APACHE | 201 --- runners/lpc55/vendor/littlefs2/LICENSE-MIT | 25 - runners/lpc55/vendor/littlefs2/README.md | 63 - runners/lpc55/vendor/littlefs2/netlify.toml | 8 - runners/lpc55/vendor/littlefs2/src/c_stubs.rs | 29 - runners/lpc55/vendor/littlefs2/src/consts.rs | 15 - runners/lpc55/vendor/littlefs2/src/driver.rs | 144 -- runners/lpc55/vendor/littlefs2/src/fs.rs | 1569 ----------------- runners/lpc55/vendor/littlefs2/src/io.rs | 172 -- .../lpc55/vendor/littlefs2/src/io/prelude.rs | 8 - runners/lpc55/vendor/littlefs2/src/lib.rs | 168 -- runners/lpc55/vendor/littlefs2/src/macros.rs | 230 --- runners/lpc55/vendor/littlefs2/src/path.rs | 456 ----- runners/lpc55/vendor/littlefs2/src/tests.rs | 452 ----- .../vendor/littlefs2/tests/test_serde.rs | 53 - .../littlefs2/tests/ui/constructors-fail.rs | 65 - .../tests/ui/constructors-fail.stderr | 8 - .../vendor/littlefs2/tests/ui/sync-fail.rs | 72 - .../littlefs2/tests/ui/sync-fail.stderr | 17 - 36 files changed, 269 insertions(+), 4329 deletions(-) create mode 100644 .cargo/config.toml rename runners/lpc55/Cargo.lock => Cargo.lock (92%) create mode 100644 Cargo.toml delete mode 100644 runners/lpc55/vendor/littlefs2/.cargo-checksum.json delete mode 100644 runners/lpc55/vendor/littlefs2/.cargo_vcs_info.json delete mode 100644 runners/lpc55/vendor/littlefs2/.github/FUNDING.yml delete mode 100644 runners/lpc55/vendor/littlefs2/.github/workflows/ci.yml delete mode 100644 runners/lpc55/vendor/littlefs2/CHANGELOG.md delete mode 100644 runners/lpc55/vendor/littlefs2/Cargo.toml delete mode 100644 runners/lpc55/vendor/littlefs2/Cargo.toml.orig delete mode 100644 runners/lpc55/vendor/littlefs2/LICENSE-APACHE delete mode 100644 runners/lpc55/vendor/littlefs2/LICENSE-MIT delete mode 100644 runners/lpc55/vendor/littlefs2/README.md delete mode 100644 runners/lpc55/vendor/littlefs2/netlify.toml delete mode 100644 runners/lpc55/vendor/littlefs2/src/c_stubs.rs delete mode 100644 runners/lpc55/vendor/littlefs2/src/consts.rs delete mode 100644 runners/lpc55/vendor/littlefs2/src/driver.rs delete mode 100644 runners/lpc55/vendor/littlefs2/src/fs.rs delete mode 100644 runners/lpc55/vendor/littlefs2/src/io.rs delete mode 100644 runners/lpc55/vendor/littlefs2/src/io/prelude.rs delete mode 100644 runners/lpc55/vendor/littlefs2/src/lib.rs delete mode 100644 runners/lpc55/vendor/littlefs2/src/macros.rs delete mode 100644 runners/lpc55/vendor/littlefs2/src/path.rs delete mode 100644 runners/lpc55/vendor/littlefs2/src/tests.rs delete mode 100644 runners/lpc55/vendor/littlefs2/tests/test_serde.rs delete mode 100644 runners/lpc55/vendor/littlefs2/tests/ui/constructors-fail.rs delete mode 100644 runners/lpc55/vendor/littlefs2/tests/ui/constructors-fail.stderr delete mode 100644 runners/lpc55/vendor/littlefs2/tests/ui/sync-fail.rs delete mode 100644 runners/lpc55/vendor/littlefs2/tests/ui/sync-fail.stderr diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 00000000..99cba13b --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,11 @@ +[target.'cfg(all(target_arch = "arm", target_os = "none"))'] +runner = "probe-rs run --chip LPC55S69JBD100" +rustflags = [ + "-C", "linker=flip-link", + "-C", "link-arg=-Tlink.x", + "-C", "link-arg=-Tdefmt.x", + "-Dwarnings", +] + +[build] +target = "thumbv8m.main-none-eabi" diff --git a/runners/lpc55/Cargo.lock b/Cargo.lock similarity index 92% rename from runners/lpc55/Cargo.lock rename to Cargo.lock index ac3c2e26..3a220ec4 100644 --- a/runners/lpc55/Cargo.lock +++ b/Cargo.lock @@ -7,7 +7,7 @@ name = "admin-app" version = "0.1.0" source = "git+https://github.com/Nitrokey/admin-app.git?tag=v0.1.0-nitrokey.21#261c47d791f7862a8fd1b52d485860ff82216478" dependencies = [ - "apdu-app 0.2.0", + "apdu-app", "cbor-smol", "ctaphid-app", "delog", @@ -30,7 +30,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" dependencies = [ "crypto-common", - "generic-array 0.14.7", + "generic-array", "heapless 0.7.17", ] @@ -54,15 +54,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "apdu-app" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce391931a2cc4597eaf0d464db9d4d5e1939ccc8dd6eda0f86cda117e914c02d" -dependencies = [ - "iso7816 0.1.4", -] - [[package]] name = "apdu-app" version = "0.2.0" @@ -85,44 +76,19 @@ dependencies = [ "iso7816 0.1.4", ] -[[package]] -name = "apdu-dispatch" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d6e6883b2c23b9fe1a488913705c7b68f751bdb73da036ff8191da729337a5d" -dependencies = [ - "apdu-app 0.1.0", - "delog", - "heapless 0.7.17", - "interchange 0.3.2", - "iso7816 0.1.4", -] - [[package]] name = "apdu-dispatch" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3c9f7729cfb0991e556f650a1478e1e8bd8db7fc57ff2dec4a3a67669d406ff" dependencies = [ - "apdu-app 0.2.0", + "apdu-app", "delog", "heapless 0.9.2", "interchange 0.3.2", "iso7816 0.2.0", ] -[[package]] -name = "as-slice" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45403b49e3954a4b8428a0ac21a4b7afadccf92bfd96273f1a58cd4812496ae0" -dependencies = [ - "generic-array 0.12.4", - "generic-array 0.13.3", - "generic-array 0.14.7", - "stable_deref_trait", -] - [[package]] name = "atomic-polyfill" version = "1.0.3" @@ -195,7 +161,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" dependencies = [ - "generic-array 0.14.7", + "generic-array", ] [[package]] @@ -204,7 +170,7 @@ version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ - "generic-array 0.14.7", + "generic-array", ] [[package]] @@ -213,7 +179,7 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93" dependencies = [ - "generic-array 0.14.7", + "generic-array", ] [[package]] @@ -223,7 +189,7 @@ dependencies = [ "admin-app", "defmt", "fm11nc08", - "lpc55-hal 0.4.1", + "lpc55-hal", "micromath", "nb 1.1.0", "rtic", @@ -259,9 +225,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.57" +version = "1.2.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a0dd1ca384932ff3641c8718a02769f1698e7563dc6974ffd03346116310423" +checksum = "b7a4d3ec6524d28a329fc53654bbadc9bdd7b0431f5d65f1a56ffb28a1ee5283" dependencies = [ "find-msvc-tools", "shlex", @@ -312,7 +278,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" dependencies = [ - "generic-array 0.14.7", + "generic-array", ] [[package]] @@ -403,7 +369,7 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8658c15c5d921ddf980f7fe25b1e82f4b7a4083b2c4985fea4922edb8e43e07d" dependencies = [ - "generic-array 0.14.7", + "generic-array", "rand_core", "subtle", "zeroize", @@ -415,7 +381,7 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" dependencies = [ - "generic-array 0.14.7", + "generic-array", "typenum", ] @@ -425,7 +391,7 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25fab6889090c8133f3deb8f73ba3c65a7f456f66436fc012a1b1e272b1e103e" dependencies = [ - "generic-array 0.14.7", + "generic-array", "subtle", ] @@ -566,7 +532,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" dependencies = [ - "generic-array 0.14.7", + "generic-array", ] [[package]] @@ -615,7 +581,7 @@ checksum = "83e5c176479da93a0983f0a6fdc3c1b8e7d5be0d7fe3fe05a99f15b96582b9a8" dependencies = [ "crypto-bigint", "ff", - "generic-array 0.14.7", + "generic-array", "group", "rand_core", "subtle", @@ -702,7 +668,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a71f10c27a05873e7020d4c54eb8318236f35c60821b6d65b0a59b9ee8d821c" dependencies = [ - "apdu-app 0.2.0", + "apdu-app", "cbor-smol", "cosey", "ctap-types", @@ -838,24 +804,6 @@ dependencies = [ "windows-result", ] -[[package]] -name = "generic-array" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd" -dependencies = [ - "typenum", -] - -[[package]] -name = "generic-array" -version = "0.13.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f797e67af32588215eaaab8327027ee8e71b9dd0b2b26996aedf20c030fce309" -dependencies = [ - "typenum", -] - [[package]] name = "generic-array" version = "0.14.7" @@ -883,15 +831,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "hash32" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4041af86e63ac4298ce40e5cca669066e75b6f1aa3390fe2561ffa5e1d9f4cc" -dependencies = [ - "byteorder", -] - [[package]] name = "hash32" version = "0.2.1" @@ -910,30 +849,12 @@ dependencies = [ "byteorder", ] -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - [[package]] name = "hashbrown" version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" -[[package]] -name = "heapless" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634bd4d29cbf24424d0a4bfcbf80c6960129dc24424752a7d1d1390607023422" -dependencies = [ - "as-slice", - "generic-array 0.14.7", - "hash32 0.1.1", - "stable_deref_trait", -] - [[package]] name = "heapless" version = "0.7.17" @@ -1038,22 +959,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg", - "hashbrown 0.12.3", -] - -[[package]] -name = "indexmap" -version = "2.13.0" +version = "2.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +checksum = "45a8a2b9cb3e0b0c1803dbb0758ffac5de2f425b23c28f518faabd9d805342ff" dependencies = [ "equivalent", - "hashbrown 0.16.1", + "hashbrown", ] [[package]] @@ -1063,7 +974,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" dependencies = [ "block-padding", - "generic-array 0.14.7", + "generic-array", ] [[package]] @@ -1116,9 +1027,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.183" +version = "0.2.184" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" +checksum = "48f5d2a454e16a5ea0f4ced81bd44e4cfc7bd3a507b61887c99fd3538b28e4af" [[package]] name = "libloading" @@ -1130,19 +1041,6 @@ dependencies = [ "windows-link", ] -[[package]] -name = "littlefs2" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a43f3c0c6a7d127e3e1241665dd896d8bf1ca31cf9d826a1dc65239bd59868" -dependencies = [ - "delog", - "generic-array 0.14.7", - "heapless 0.7.17", - "littlefs2-core", - "littlefs2-sys", -] - [[package]] name = "littlefs2" version = "0.7.1" @@ -1151,7 +1049,7 @@ checksum = "6c8022e5141ceff5b7b12897113f54fc9dac5ad36402c787941c97272b9241eb" dependencies = [ "bitflags 2.11.0", "delog", - "generic-array 0.14.7", + "generic-array", "heapless 0.9.2", "littlefs2-core", "littlefs2-sys", @@ -1219,28 +1117,6 @@ dependencies = [ "tracing-subscriber", ] -[[package]] -name = "lpc55-hal" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67e9bba980b3a2de5813c8db696806c59bdb5f57956c8137ebe1e10b2e988a53" -dependencies = [ - "block-buffer 0.9.0", - "cipher 0.3.0", - "cortex-m", - "digest 0.9.0", - "embedded-hal 0.2.7", - "embedded-time", - "generic-array 0.14.7", - "lpc55-pac", - "lpc55-rtic", - "nb 1.1.0", - "rand_core", - "usb-device", - "vcell", - "void", -] - [[package]] name = "lpc55-hal" version = "0.4.1" @@ -1253,7 +1129,7 @@ dependencies = [ "digest 0.9.0", "embedded-hal 0.2.7", "embedded-time", - "generic-array 0.14.7", + "generic-array", "lpc55-pac", "nb 1.1.0", "rand_core", @@ -1273,32 +1149,6 @@ dependencies = [ "vcell", ] -[[package]] -name = "lpc55-rtic" -version = "0.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4472b3ed70fa24afef24fa55fd0ebd77fbc781a4c649bb48ca6b1b9fa6b90073" -dependencies = [ - "cortex-m", - "cortex-m-rt", - "heapless 0.6.1", - "lpc55-rtic-macros", - "rtic-core 0.3.1", - "version_check", -] - -[[package]] -name = "lpc55-rtic-macros" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c4958d6458bf70ef0789830bb2ed28e9a8d95d500e7cad2b1e9bd3a3169c680" -dependencies = [ - "proc-macro2", - "quote", - "rtic-syntax", - "syn 1.0.109", -] - [[package]] name = "matchers" version = "0.2.0" @@ -1479,7 +1329,7 @@ name = "opcard" version = "1.7.0" source = "git+https://github.com/Nitrokey/opcard-rs?tag=v1.7.0#2b94d6aa0d1d533e01997b61332b229247e41c49" dependencies = [ - "apdu-app 0.2.0", + "apdu-app", "bitflags 2.11.0", "cbor-smol", "cfg-if", @@ -1559,7 +1409,7 @@ name = "piv-authenticator" version = "0.6.0" source = "git+https://github.com/trussed-dev/piv-authenticator?tag=v0.6.0#be6918199642d53ae1af75f181e0b5577449d7a2" dependencies = [ - "apdu-app 0.2.0", + "apdu-app", "cbor-smol", "cfg-if", "flexiber 0.2.0", @@ -1657,11 +1507,12 @@ dependencies = [ name = "provisioner-app" version = "0.1.0" dependencies = [ - "apdu-dispatch 0.3.1", + "apdu-dispatch 0.4.0", "defmt", - "heapless 0.8.0", - "littlefs2 0.6.1", - "lpc55-hal 0.3.1", + "heapless 0.9.2", + "iso7816 0.2.0", + "littlefs2", + "lpc55-hal", "p256", "salty", "trussed", @@ -1743,7 +1594,7 @@ dependencies = [ "cortex-m", "critical-section", "portable-atomic", - "rtic-core 1.0.0", + "rtic-core", "rtic-macros", ] @@ -1757,12 +1608,6 @@ dependencies = [ "portable-atomic", ] -[[package]] -name = "rtic-core" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bd58a6949de8ff797a346a28d9f13f7b8f54fa61bb5e3cb0985a4efb497a5ef" - [[package]] name = "rtic-core" version = "1.0.0" @@ -1775,7 +1620,7 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f387b12bd6c01d2c9d4776dddeefaf0ae51b9497c83c0186b1693f6821ff3c4a" dependencies = [ - "indexmap 2.13.0", + "indexmap", "proc-macro-error2", "proc-macro2", "quote", @@ -1817,17 +1662,6 @@ dependencies = [ "rtic-common", ] -[[package]] -name = "rtic-syntax" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8152fcaa845720d61e6cc570548b89144c2c307f18a480bbd97e55e9f6eeff04" -dependencies = [ - "indexmap 1.9.3", - "proc-macro2", - "syn 1.0.109", -] - [[package]] name = "rtic-time" version = "2.0.1" @@ -1844,7 +1678,7 @@ dependencies = [ [[package]] name = "runner" -version = "2.964.0" +version = "2.2281.0" dependencies = [ "admin-app", "apdu-dispatch 0.4.0", @@ -1859,7 +1693,7 @@ dependencies = [ "fm11nc08", "heapless 0.9.2", "interchange 0.3.2", - "littlefs2 0.7.1", + "littlefs2", "nb 1.1.0", "ndef-app", "nfc-device", @@ -1950,7 +1784,7 @@ name = "secrets-app" version = "0.15.1" source = "git+https://github.com/leetronics/solokeys-secrets-app-fork?branch=fix-pin-protection-isolation#aa4ff03f0b1b8e62964b96d78aa6dc4842a694c4" dependencies = [ - "apdu-app 0.2.0", + "apdu-app", "bitflags 2.11.0", "block-padding", "cbor-smol", @@ -2337,13 +2171,13 @@ dependencies = [ "delog", "des", "flexiber 0.2.0", - "generic-array 0.14.7", + "generic-array", "heapless 0.9.2", "heapless-bytes 0.5.0", "hex-literal 0.4.1", "hmac 0.12.1", "interchange 0.3.2", - "littlefs2 0.7.1", + "littlefs2", "littlefs2-core", "nb 1.1.0", "p256-cortex-m4", @@ -2699,18 +2533,18 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "zerocopy" -version = "0.8.47" +version = "0.8.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efbb2a062be311f2ba113ce66f697a4dc589f85e78a4aea276200804cea0ed87" +checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.47" +version = "0.8.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e8bc7269b54418e7aeeef514aa68f8690b8c0489a06b0136e5f57c4c5ccab89" +checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 00000000..b6865f8c --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,110 @@ +[workspace] +members = [ + "runners/lpc55", + "runners/lpc55/board", + "components/ndef-app", + "components/nfc-device", + "components/fm11nc08", + "components/provisioner-app", +] +resolver = "2" + +[workspace.package] +version = "2.2281.0" +edition = "2021" +authors = [ + "Nicolas Stalder ", + "Conor Patrick ", +] + +[workspace.dependencies] +# ── Internal workspace members ──────────────────────────────────────────────── +board = { path = "runners/lpc55/board" } +ndef-app = { path = "components/ndef-app" } +fm11nc08 = { path = "components/fm11nc08" } +nfc-device = { path = "components/nfc-device" } +provisioner-app = { path = "components/provisioner-app" } + +# ── RTIC framework ──────────────────────────────────────────────────────────── +rtic = "2.0.0" +rtic-monotonics = { version = "2.0.0", features = ["cortex-m-systick"] } +rtic-sync = "1.4.0" +systick-monotonic = "1.0.1" + +# ── Cortex-M / embedded ─────────────────────────────────────────────────────── +cortex-m = { version = "0.7.0", features = ["critical-section-single-core"] } +lpc55-hal = "0.4.1" +micromath = "2" +embedded-time = "0.12" +embedded-hal = { version = "0.2.5", features = ["unproven"] } + +# ── Logging / debug ─────────────────────────────────────────────────────────── +defmt = "1.0.1" +defmt-rtt = "1.1.0" +delog = "0.1.1" +panic-halt = "1.0.0" + +# ── Core utilities ──────────────────────────────────────────────────────────── +heapless = "0.9" +nb = "1" +interchange = "0.3" +static_cell = "2.1.1" +ref-swap = "0.1" + +# ── USB ─────────────────────────────────────────────────────────────────────── +usb-device = "0.2.3" +usbd-serial = "0.1.0" +usbd-ccid = "0.4" +usbd-ctaphid = { version = "0.4", features = ["log-info"] } + +# ── APDU / ISO 7816 stack ───────────────────────────────────────────────────── +apdu-dispatch = "0.4" +ctaphid-dispatch = "0.4" +ctap-types = "0.5" +iso7816 = "0.2" + +# ── Storage ─────────────────────────────────────────────────────────────────── +littlefs2 = { version = "0.7", features = ["c-stubs"] } + +# ── Trussed core ───────────────────────────────────────────────────────────── +trussed = "0.1" +trussed-core = "0.2" + +# ── Trussed extensions ──────────────────────────────────────────────────────── +trussed-staging = { git = "https://github.com/trussed-dev/trussed-staging.git", tag = "v0.4.0", features = ["hkdf", "fs-info", "manage", "chunked", "hpke", "wrap-key-to-file"] } +trussed-fs-info = "0.3" +trussed-hkdf = "0.4" +trussed-manage = "0.3" +trussed-chunked = "0.3" +trussed-hpke = "0.3" +trussed-wrap-key-to-file = "0.3" +trussed-auth = "0.5" +trussed-auth-backend = { git = "https://github.com/trussed-dev/trussed-auth", tag = "backend-v0.1.0" } + +# ── Applications ───────────────────────────────────────────────────────────── +admin-app = "0.1" +fido-authenticator = { version = "0.3", features = ["dispatch"] } +oath-authenticator = { version = "0.1", features = ["apdu-dispatch"] } +secrets-app = { git = "https://github.com/leetronics/solokeys-secrets-app-fork", branch = "fix-pin-protection-isolation", features = ["apdu-dispatch", "ctaphid", "log-all"] } +piv-authenticator = { git = "https://github.com/trussed-dev/piv-authenticator", tag = "v0.6.0", features = ["apdu-dispatch"] } +opcard = { git = "https://github.com/Nitrokey/opcard-rs", tag = "v1.7.0", features = ["apdu-dispatch", "delog"] } + +# ── Release profile ─────────────────────────────────────────────────────────── +[profile.release] +codegen-units = 1 +lto = true +opt-level = "z" +incremental = false +debug = true + +[profile.release.package.salty] +opt-level = 2 + +# ── Patches ─────────────────────────────────────────────────────────────────── +[patch.crates-io] +trussed = { git = "https://github.com/trussed-dev/trussed.git", rev = "0f8df68be879acdde1f8cf428c11e5d29692a47b" } +admin-app = { git = "https://github.com/Nitrokey/admin-app.git", tag = "v0.1.0-nitrokey.21" } +# Force all crates to use littlefs2-core 0.1.2 which has heapless-bytes05 support +littlefs2-core = { git = "https://github.com/trussed-dev/littlefs2.git", tag = "core-0.1.2" } +# Extension backends needed by fido-authenticator (FsInfo, Hkdf, etc.) +trussed-staging = { git = "https://github.com/trussed-dev/trussed-staging.git", tag = "v0.4.0" } diff --git a/components/fm11nc08/Cargo.toml b/components/fm11nc08/Cargo.toml index d907071a..5fbd14e1 100644 --- a/components/fm11nc08/Cargo.toml +++ b/components/fm11nc08/Cargo.toml @@ -1,14 +1,12 @@ [package] name = "fm11nc08" version = "0.1.0" -authors = ["Conor Patrick ", "Nicolas Stalder "] +authors.workspace = true edition = "2024" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - [dependencies] -defmt = "1.0.1" -embedded-time = "0.12" -embedded-hal = { version = "0.2.5", features = ["unproven"] } -nb = "1" -nfc-device = {path = "../nfc-device"} +defmt .workspace = true +embedded-time .workspace = true +embedded-hal .workspace = true +nb .workspace = true +nfc-device .workspace = true diff --git a/components/ndef-app/Cargo.toml b/components/ndef-app/Cargo.toml index b43f0235..33f79775 100644 --- a/components/ndef-app/Cargo.toml +++ b/components/ndef-app/Cargo.toml @@ -1,13 +1,10 @@ [package] name = "ndef-app" version = "0.1.0" -authors = ["Conor Patrick "] +authors.workspace = true edition = "2024" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - [dependencies] -heapless = "0.9" - -apdu-dispatch = "0.4" -iso7816 = "0.2" +heapless .workspace = true +apdu-dispatch .workspace = true +iso7816 .workspace = true diff --git a/components/nfc-device/Cargo.toml b/components/nfc-device/Cargo.toml index 9247f17b..4fb65a29 100644 --- a/components/nfc-device/Cargo.toml +++ b/components/nfc-device/Cargo.toml @@ -1,15 +1,14 @@ [package] name = "nfc-device" version = "0.0.1" -authors = ["Conor Patrick "] +authors.workspace = true edition = "2024" [dependencies] -defmt = "1.0.1" -embedded-time = "0.12" -heapless = "0.9" -nb = "1" - -apdu-dispatch = "0.4" -iso7816 = "0.2" -interchange = "0.3" +defmt .workspace = true +embedded-time .workspace = true +heapless .workspace = true +nb .workspace = true +apdu-dispatch .workspace = true +iso7816 .workspace = true +interchange .workspace = true diff --git a/components/provisioner-app/Cargo.toml b/components/provisioner-app/Cargo.toml index 221da3ce..2fb3b7ce 100644 --- a/components/provisioner-app/Cargo.toml +++ b/components/provisioner-app/Cargo.toml @@ -1,17 +1,18 @@ [package] name = "provisioner-app" version = "0.1.0" -authors = ["Conor Patrick "] +authors.workspace = true edition = "2024" [dependencies] -apdu-dispatch = "0.3" -defmt = "1.0.1" -heapless = "0.8" -lpc55-hal = { version = "0.3", features = ["rtic-peripherals"] } -littlefs2 = "0.6" -trussed = "0.1" -p256 = { version = "0.9", default-features = false, features = ["arithmetic"] } +apdu-dispatch .workspace = true +defmt .workspace = true +heapless .workspace = true +iso7816 .workspace = true +lpc55-hal .workspace = true +littlefs2 .workspace = true +trussed .workspace = true +p256 = { version = "0.9", default-features = false, features = ["arithmetic"] } salty = "0.3" [features] diff --git a/components/provisioner-app/src/lib.rs b/components/provisioner-app/src/lib.rs index 2296a467..d3d760e2 100644 --- a/components/provisioner-app/src/lib.rs +++ b/components/provisioner-app/src/lib.rs @@ -20,9 +20,8 @@ use trussed::{ Client as TrussedClient, }; use heapless::Vec; -use apdu_dispatch::iso7816::{Status, Instruction}; -use apdu_dispatch::app::Result as ResponseResult; -use apdu_dispatch::app::{CommandView, Interface}; +use iso7816::{Status, Instruction}; +use apdu_dispatch::app::{self, CommandView, Interface, VecView}; use lpc55_hal as hal; @@ -146,8 +145,8 @@ where fn handle( &mut self, command: CommandView<'_>, - reply: &mut apdu_dispatch::response::Data, - ) -> ResponseResult { + reply: &mut VecView, + ) -> app::Result { match command.instruction() { Instruction::Select => self.do_select(command, reply), Instruction::WriteBinary => { @@ -368,8 +367,8 @@ where fn do_select( &mut self, command: CommandView<'_>, - _reply: &mut apdu_dispatch::response::Data, - ) -> ResponseResult { + _reply: &mut VecView, + ) -> app::Result { if command.data().starts_with(&TESTER_FILENAME_ID) { info!("select: filename buffer"); self.selected_buffer = SelectedBuffer::Filename; @@ -385,18 +384,18 @@ where } } -impl apdu_dispatch::iso7816::App for Provisioner +impl iso7816::App for Provisioner where S: Store, FS: 'static + LfsStorage, T: TrussedClient, { - fn aid(&self) -> apdu_dispatch::iso7816::Aid { - apdu_dispatch::iso7816::Aid::new(&SOLO_PROVISIONER_AID) + fn aid(&self) -> iso7816::Aid { + iso7816::Aid::new(&SOLO_PROVISIONER_AID) } } -impl apdu_dispatch::App<{ apdu_dispatch::response::SIZE }> for Provisioner +impl app::App for Provisioner where S: Store, FS: 'static + LfsStorage, @@ -406,8 +405,8 @@ where &mut self, _interface: Interface, _apdu: CommandView<'_>, - reply: &mut apdu_dispatch::response::Data, - ) -> ResponseResult { + reply: &mut VecView, + ) -> app::Result { self.buffer_file_contents.clear(); self.buffer_filename.clear(); reply.extend_from_slice(&hal::uuid()).unwrap(); @@ -420,8 +419,8 @@ where &mut self, _interface: Interface, apdu: CommandView<'_>, - reply: &mut apdu_dispatch::response::Data, - ) -> ResponseResult { + reply: &mut VecView, + ) -> app::Result { self.handle(apdu, reply) } } diff --git a/runners/lpc55/Cargo.toml b/runners/lpc55/Cargo.toml index 2296aa6c..f8e1d488 100644 --- a/runners/lpc55/Cargo.toml +++ b/runners/lpc55/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "runner" -version = "2.964.0" -authors = ["Nicolas Stalder ", "Conor Patrick "] -edition = "2021" +version.workspace = true +authors.workspace = true +edition.workspace = true rust-version = "1.62.0" [lib] @@ -13,66 +13,63 @@ name = "runner" path = "src/main.rs" [dependencies] -rtic = "2.0.0" -rtic-monotonics = { version = "2.0.0", features = ["cortex-m-systick"] } -rtic-sync = "1.4.0" -# FIXME: get rid of critical-section-single-core feature once old versions of critical-section are no longer needed. -cortex-m = { version = "0.7.0", features = ["critical-section-single-core"] } -systick-monotonic = "1.0.1" -defmt = "1.0.1" -defmt-rtt = "1.1.0" -delog = "0.1.1" -heapless = "0.9" -interchange = "0.3" -nb = "1" -static_cell = "2.1.1" -ref-swap = "0.1" -usb-device = "0.2.3" +rtic .workspace = true +rtic-monotonics .workspace = true +rtic-sync .workspace = true +cortex-m .workspace = true +systick-monotonic .workspace = true +defmt .workspace = true +defmt-rtt .workspace = true +delog .workspace = true +heapless .workspace = true +interchange .workspace = true +nb .workspace = true +static_cell .workspace = true +ref-swap .workspace = true +usb-device .workspace = true # usbd-hid = { version = "0.4.5", optional = true } -usbd-serial = "0.1.0" - -admin-app = { version = "0.1", optional = true } -trussed-staging = { git = "https://github.com/trussed-dev/trussed-staging.git", tag = "v0.4.0", features = ["hkdf", "fs-info", "manage", "chunked", "hpke", "wrap-key-to-file"] } -trussed-fs-info = "0.3" -trussed-hkdf = "0.4" -trussed-manage = "0.3" -trussed-chunked = "0.3" -trussed-hpke = "0.3" -trussed-wrap-key-to-file = "0.3" -trussed-auth = "0.5" -trussed-auth-backend = { git = "https://github.com/trussed-dev/trussed-auth", tag = "backend-v0.1.0" } -apdu-dispatch = "0.4" -ctaphid-dispatch = "0.4" -ctap-types = "0.5" -fido-authenticator = { version = "0.3", features = ["dispatch"], optional = true } -oath-authenticator = { version = "0.1", features = ["apdu-dispatch"], optional = true } +usbd-serial .workspace = true + +admin-app = { workspace = true, optional = true } +trussed-staging .workspace = true +trussed-fs-info .workspace = true +trussed-hkdf .workspace = true +trussed-manage .workspace = true +trussed-chunked .workspace = true +trussed-hpke .workspace = true +trussed-wrap-key-to-file.workspace = true +trussed-auth .workspace = true +trussed-auth-backend.workspace = true +apdu-dispatch .workspace = true +ctaphid-dispatch .workspace = true +ctap-types .workspace = true +fido-authenticator = { workspace = true, optional = true } +oath-authenticator = { workspace = true, optional = true } # OATH/TOTP/HOTP support via trussed-secrets-app (Nitrokey's implementation, Yubico OATH AID) # Using fork with PIN protection key isolation fix backported to v0.14 -secrets-app = { git = "https://github.com/leetronics/solokeys-secrets-app-fork", branch = "fix-pin-protection-isolation", features = ["apdu-dispatch", "ctaphid", "log-all"], optional = true } -piv-authenticator = { git = "https://github.com/trussed-dev/piv-authenticator", features = ["apdu-dispatch"], optional = true, tag = "v0.6.0" } -opcard = { git = "https://github.com/Nitrokey/opcard-rs", tag = "v1.7.0", features = ["apdu-dispatch", "delog"], optional = true } -trussed = "0.1" -trussed-core = "0.2" +secrets-app = { workspace = true, optional = true } +piv-authenticator = { workspace = true, optional = true } +opcard = { workspace = true, optional = true } +trussed .workspace = true +trussed-core .workspace = true # board -board = { path = "board" } +board.workspace = true # components -ndef-app = { path = "../../components/ndef-app", optional = true } +ndef-app = { workspace = true, optional = true } # NB: when using this app, need to raise trussed/clients-5 -provisioner-app = { path = "../../components/provisioner-app", optional = true } -fm11nc08 = {path = "../../components/fm11nc08"} -nfc-device = {path = "../../components/nfc-device"} -usbd-ccid = "0.4" -usbd-ctaphid = { version = "0.4", features = ["log-info"] } - +provisioner-app = { workspace = true, optional = true } +fm11nc08 .workspace = true +nfc-device .workspace = true +usbd-ccid .workspace = true +usbd-ctaphid .workspace = true # panic -panic-halt = "1.0.0" -# panic-semihosting = "0.5.6" +panic-halt.workspace = true # storage -littlefs2 = { version = "0.7", features = ["c-stubs"] } +littlefs2.workspace = true [features] # ndef-app is an annoyance on some mobile platforms @@ -86,9 +83,9 @@ oath = ["dep:secrets-app"] develop = ["no-encrypted-storage", "log-defmt"] develop-provisioner = ["develop", "provisioner-app"] -develop-secrets = ["develop", "oath"] -opcard = ["dep:opcard"] -develop-opcard = ["develop", "opcard"] +develop-secrets = ["develop", "oath"] +opcard = ["dep:opcard"] +develop-opcard = ["develop", "opcard"] # Do not use encryption for the filesystem no-encrypted-storage = [] @@ -107,41 +104,16 @@ format-filesystem = [] # TODO: get rid of these (depends on moving "initialize_basic" &friends into `board` board-lpcxpresso55 = ["board/lpcxpresso55"] -board-okdoe1 = ["board/okdoe1", "usbfs-peripheral"] -board-solo2 = ["board/solo2"] +board-okdoe1 = ["board/okdoe1", "usbfs-peripheral"] +board-solo2 = ["board/solo2"] log-defmt = [] -highspeed = [] +highspeed = [] usbfs-peripheral = [] -serial = [] +serial = [] # Reconfigure the NFC chip in any case reconfigure-nfc = [] no-clock-controller = ["board/no-clock-controller"] enable-clock-controller-signal-pin = ["board/enable-clock-controller-signal-pin"] # very-twitchy-mouse = ["usbd-hid"] - -# patch dependencies like so to test local changes - -[profile.release] -codegen-units = 1 -lto = true -opt-level = "z" -incremental = false -debug = true - -# Speed up crypto packages -[profile.release.package.salty] -opt-level = 2 - -# TODO: see which if any settings are best for p256-cortex-m4 -# [profile.release.package.nisty] -# opt-level = 2 - -[patch.crates-io] -trussed = { git = "https://github.com/trussed-dev/trussed.git", rev = "0f8df68be879acdde1f8cf428c11e5d29692a47b" } -admin-app = { git = "https://github.com/Nitrokey/admin-app.git", tag = "v0.1.0-nitrokey.21" } -# Force all crates to use littlefs2-core 0.1.2 which has heapless-bytes05 support -littlefs2-core = { git = "https://github.com/trussed-dev/littlefs2.git", tag = "core-0.1.2" } -# Extension backends needed by fido-authenticator (FsInfo, Hkdf, etc.) -trussed-staging = { git = "https://github.com/trussed-dev/trussed-staging.git", tag = "v0.4.0" } diff --git a/runners/lpc55/board/Cargo.toml b/runners/lpc55/board/Cargo.toml index c1887254..1218bb53 100644 --- a/runners/lpc55/board/Cargo.toml +++ b/runners/lpc55/board/Cargo.toml @@ -1,18 +1,18 @@ [package] name = "board" version = "0.1.0-unreleased" -authors = ["Conor Patrick "] -edition = "2024" +authors.workspace = true +edition.workspace = true [dependencies] -admin-app = "0.1" -defmt = "1.0.1" -fm11nc08 = {path = "../../../components/fm11nc08"} -lpc55-hal = "0.4.1" -rtic = { version = "2.0.0", features = ["thumbv8main-backend"] } -micromath = "2" -nb = "1" -trussed = "0.1" +admin-app .workspace = true +defmt .workspace = true +fm11nc08 .workspace = true +lpc55-hal .workspace = true +rtic = { workspace = true, features = ["thumbv8main-backend"] } +micromath .workspace = true +nb .workspace = true +trussed .workspace = true [features] lpcxpresso55 = [] @@ -22,10 +22,3 @@ solo2 = [] no-buttons = [] no-clock-controller = [] enable-clock-controller-signal-pin = [] - -[profile.release] -codegen-units = 1 -# lto = true -# opt-level = "s" -incremental = false -debug = true diff --git a/runners/lpc55/vendor/littlefs2/.cargo-checksum.json b/runners/lpc55/vendor/littlefs2/.cargo-checksum.json deleted file mode 100644 index da5e1141..00000000 --- a/runners/lpc55/vendor/littlefs2/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{".cargo_vcs_info.json":"45b1dfbf8e0433f4ade2e4c1163024c3ead667e379a897f5600eb2a6d2f1318e",".github/FUNDING.yml":"033732b47d38088261d40805c7d52660d3545d15c5cd9cb7a7bca30a37c447ae",".github/workflows/ci.yml":"0613e7a1bdfe5d7f255c35c10ad30e9e4340b3cc5574aeb75cd09d990e61cee6","CHANGELOG.md":"fc9c5317f22257dad8676876b0fc022115111005ad88ecec84e2dce3e9f01bb0","Cargo.toml":"19cc73fd2a4e47b6eab124a1518fe073358327001b561079750c476299102a03","Cargo.toml.orig":"72296eb23b52940f2829081746b4fb29f93fbb3e50faa035647560df28d3a74e","LICENSE-APACHE":"fdc8e36ed6672ad9bd8c2b9dbfc6d98abbbda52622e1518890be4941e7e4f479","LICENSE-MIT":"996f796de7302410a4cc1b7b5712b8977e79999937bd9213ad0162205070ab75","README.md":"dabb2a4942967fd3694b0921496aff3f959c9e4b8951c8c4c689cfd0133957c0","netlify.toml":"7d21f6b0cff102986d1e21a951536ab8b94994eb87d408967ef1105be88c2eac","src/c_stubs.rs":"1875cee1b0defee8aae5864d1fbe432e2d8bb27df3495e397b30584b204cfe7f","src/consts.rs":"f3ea8af06facb5bc9e73cb8bcb7292aab8f40b033d201ad76bb1f934ae848a99","src/driver.rs":"88fd3552de5724bedaf8756be7cffcfd4674895f45531c9664ebbabaced9ed74","src/fs.rs":"c04396e8110ba9d228b418053b1b71691ed318ff58099ec28386716686e58bff","src/io.rs":"83f102b80fbc0360089fd35e4aae4df906bdd0300fa64be335af591524d28995","src/io/prelude.rs":"17e97e0ef401e704d0ced606c9bac1aabb7b624c8bb45e68ef54e98980774097","src/lib.rs":"4b8fc7f4f3e07e4a1b40da959ea9180b0b37a41faf93520201deaeadd21c1e41","src/macros.rs":"71e947c4162d071dd8867a9b6466267f5d321650075eae8fb1dda07fe37f63b7","src/path.rs":"ba3ecbb50fb0007b0e9402b8b8895eb3d1ce8c62746f3ee07853994be7c3c52d","src/tests.rs":"c016cb25d9e45bd2eafcfc3c3069ccc4ed73d06e0d70472ce76319bf473f0d2e","tests/test_serde.rs":"13600e96ff78bb765373d0854b2989e939c830e744ae251d121bec6288c3d953","tests/ui/constructors-fail.rs":"7b817d4c1dc5403344e80d88baafe4172901f08e885e49fa8906116b6ea1897f","tests/ui/constructors-fail.stderr":"97ae61c2083d8be4a5d018e6d18dd79bda3cbd23f646e3058b4826b97b0d92fc","tests/ui/sync-fail.rs":"bb1d81382072bdd8f372cd18d98730e00e9c0da6eb69ac1ca15b635fc713dd24","tests/ui/sync-fail.stderr":"84f43d369d9dc79a3134536d80e670315eb5a6d5f89cf98f86e05097c7c74f13"},"package":"0dc089501e32d62b3e4d809a29b9e00d6211a197440602d69f304f1e4e82136b"} \ No newline at end of file diff --git a/runners/lpc55/vendor/littlefs2/.cargo_vcs_info.json b/runners/lpc55/vendor/littlefs2/.cargo_vcs_info.json deleted file mode 100644 index b60cfeb6..00000000 --- a/runners/lpc55/vendor/littlefs2/.cargo_vcs_info.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "git": { - "sha1": "31109121e915959ecba48e8f8ac1482885280153" - } -} diff --git a/runners/lpc55/vendor/littlefs2/.github/FUNDING.yml b/runners/lpc55/vendor/littlefs2/.github/FUNDING.yml deleted file mode 100644 index c2ad9b9a..00000000 --- a/runners/lpc55/vendor/littlefs2/.github/FUNDING.yml +++ /dev/null @@ -1 +0,0 @@ -github: nickray diff --git a/runners/lpc55/vendor/littlefs2/.github/workflows/ci.yml b/runners/lpc55/vendor/littlefs2/.github/workflows/ci.yml deleted file mode 100644 index 6e9f646b..00000000 --- a/runners/lpc55/vendor/littlefs2/.github/workflows/ci.yml +++ /dev/null @@ -1,48 +0,0 @@ -name: CI - -on: [push, pull_request] - -jobs: - build: - runs-on: ubuntu-latest - - strategy: - matrix: - target: - - thumbv7em-none-eabi - - x86_64-unknown-linux-gnu - - steps: - - name: Install build dependencies - shell: bash - run: | - env && pwd && sudo apt-get update -y -qq && sudo apt-get install -y -qq llvm libc6-dev-i386 libclang-dev - - uses: fiam/arm-none-eabi-gcc@v1 - with: - release: "9-2020-q2" - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: stable - target: ${{ matrix.target }} - override: true - components: llvm-tools-preview - - - uses: actions/checkout@v2 - - name: Build - run: cargo build --release --verbose - - - name: Run tests - if: matrix.target == 'x86_64-unknown-linux-gnu' - run: > - cargo test && - cargo test --release - - - name: Build Documentation - run: cargo doc --no-deps - - name: Deploy Docs - uses: peaceiris/actions-gh-pages@v3 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - publish_dir: ./target/doc - diff --git a/runners/lpc55/vendor/littlefs2/CHANGELOG.md b/runners/lpc55/vendor/littlefs2/CHANGELOG.md deleted file mode 100644 index 5001608e..00000000 --- a/runners/lpc55/vendor/littlefs2/CHANGELOG.md +++ /dev/null @@ -1,34 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. - -The format is based on [Keep a Changelog](http://keepachangelog.com/) -and this project adheres to [Semantic Versioning](http://semver.org/). - -## [Unreleased] - -## [v0.2.2] - 2021-03-20 - -### Changed -- Added `remove_dir_all_when`, allowing to filter "rm -rf " - -## [v0.2.1] - 2021-02-26 - -### Changed -- PathBuf::from errors on embedded nuls, and prevents ending - with nuls -- get rid of ufmt (oversight in 0.2 release) -- get rid of dead code (oversight in 0.2 release) - -## [v0.2.0] - 2021-02-02 - -### Changed - -- [breaking-change] The version of the `generic-array` dependency has been - bumped to v0.14.2 (now that `heapless` v0.6.0` is out). - -## [v0.1.1] - 2021-02-11 - -### Fixed - -- `std`-triggering regression diff --git a/runners/lpc55/vendor/littlefs2/Cargo.toml b/runners/lpc55/vendor/littlefs2/Cargo.toml deleted file mode 100644 index 63d341f3..00000000 --- a/runners/lpc55/vendor/littlefs2/Cargo.toml +++ /dev/null @@ -1,71 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies -# -# If you believe there's an error in this file please file an -# issue against the rust-lang/cargo repository. If you're -# editing this file be aware that the upstream Cargo.toml -# will likely look very different (and much more reasonable) - -[package] -edition = "2018" -name = "littlefs2" -version = "0.3.2" -authors = ["Nicolas Stalder ", "Brandon Edens "] -description = "Idiomatic Rust API for littlefs" -readme = "README.md" -categories = ["embedded", "filesystem", "no-std"] -license = "Apache-2.0 OR MIT" -repository = "https://github.com/nickray/littlefs2" -resolver = "2" -[dependencies.bitflags] -version = "1" - -[dependencies.cstr_core] -version = "0.2" -default-features = false - -[dependencies.cty] -version = "0.2.1" - -[dependencies.delog] -version = "0.1.0" - -[dependencies.generic-array] -version = "0.14" - -[dependencies.heapless] -version = "0.7" - -[dependencies.littlefs2-sys] -version = "0.1.6" - -[dependencies.serde] -version = "1" -features = ["derive"] -optional = true -default-features = false -[dev-dependencies.serde] -version = "1.0" -features = ["derive"] -default-features = false - -[dev-dependencies.ssmarshal] -version = "1" - -[features] -c-stubs = [] -default = ["dir-entry-path", "serde"] -dir-entry-path = [] -ll-assertions = ["littlefs2-sys/assertions"] -ll-trace = ["littlefs2-sys/trace"] -log-all = [] -log-debug = [] -log-error = [] -log-info = [] -log-none = [] -log-warn = [] -log-trace = [] diff --git a/runners/lpc55/vendor/littlefs2/Cargo.toml.orig b/runners/lpc55/vendor/littlefs2/Cargo.toml.orig deleted file mode 100644 index 83697854..00000000 --- a/runners/lpc55/vendor/littlefs2/Cargo.toml.orig +++ /dev/null @@ -1,59 +0,0 @@ -[package] -name = "littlefs2" -description = "Idiomatic Rust API for littlefs" -version = "0.3.2" -authors = ["Nicolas Stalder ", "Brandon Edens "] -edition = "2018" -license = "Apache-2.0 OR MIT" -readme = "README.md" -categories = ["embedded", "filesystem", "no-std"] -repository = "https://github.com/nickray/littlefs2" -resolver = "2" - -[dependencies] -bitflags = "1" -cty = "0.2.1" -delog = "0.1.0" -generic-array = "0.14" -heapless = "0.7" - -[dependencies.cstr_core] -default-features = false -version = "0.2" - -[dependencies.littlefs2-sys] -version = "0.1.6" - -[dependencies.serde] -version = "1" -default-features = false -features = ["derive"] -optional = true - -[dev-dependencies] -ssmarshal = "1" -serde = { version = "1.0", default-features = false, features = ["derive"] } -# trybuild = "1" - -[features] -default = ["dir-entry-path", "serde"] -# use experimental closure-based API -dir-entry-path = [] -# enable assertions in backend C code -ll-assertions = ["littlefs2-sys/assertions"] -# enable trace in backend C code -ll-trace = ["littlefs2-sys/trace"] -c-stubs = [] - -log-all = [] -log-none = [] -log-info = [] -log-debug = [] -log-warn = [] -log-error = [] - -# TODO: LFS_NAME_MAX (and maybe other sizes) are baked into the -# compiled C library. For instance, the `lfs_info` struct has a -# member `char name[LFS_NAME_MAX+1]`. -# This means that if we change `traits::Storage::FILENAME_MAX_PLUS_ONE`, -# we need to pass this on! diff --git a/runners/lpc55/vendor/littlefs2/LICENSE-APACHE b/runners/lpc55/vendor/littlefs2/LICENSE-APACHE deleted file mode 100644 index 2c10c51b..00000000 --- a/runners/lpc55/vendor/littlefs2/LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ -Apache License -Version 2.0, January 2004 -http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - -"License" shall mean the terms and conditions for use, reproduction, -and distribution as defined by Sections 1 through 9 of this document. - -"Licensor" shall mean the copyright owner or entity authorized by -the copyright owner that is granting the License. - -"Legal Entity" shall mean the union of the acting entity and all -other entities that control, are controlled by, or are under common -control with that entity. For the purposes of this definition, -"control" means (i) the power, direct or indirect, to cause the -direction or management of such entity, whether by contract or -otherwise, or (ii) ownership of fifty percent (50%) or more of the -outstanding shares, or (iii) beneficial ownership of such entity. - -"You" (or "Your") shall mean an individual or Legal Entity -exercising permissions granted by this License. - -"Source" form shall mean the preferred form for making modifications, -including but not limited to software source code, documentation -source, and configuration files. - -"Object" form shall mean any form resulting from mechanical -transformation or translation of a Source form, including but -not limited to compiled object code, generated documentation, -and conversions to other media types. - -"Work" shall mean the work of authorship, whether in Source or -Object form, made available under the License, as indicated by a -copyright notice that is included in or attached to the work -(an example is provided in the Appendix below). - -"Derivative Works" shall mean any work, whether in Source or Object -form, that is based on (or derived from) the Work and for which the -editorial revisions, annotations, elaborations, or other modifications -represent, as a whole, an original work of authorship. For the purposes -of this License, Derivative Works shall not include works that remain -separable from, or merely link (or bind by name) to the interfaces of, -the Work and Derivative Works thereof. - -"Contribution" shall mean any work of authorship, including -the original version of the Work and any modifications or additions -to that Work or Derivative Works thereof, that is intentionally -submitted to Licensor for inclusion in the Work by the copyright owner -or by an individual or Legal Entity authorized to submit on behalf of -the copyright owner. For the purposes of this definition, "submitted" -means any form of electronic, verbal, or written communication sent -to the Licensor or its representatives, including but not limited to -communication on electronic mailing lists, source code control systems, -and issue tracking systems that are managed by, or on behalf of, the -Licensor for the purpose of discussing and improving the Work, but -excluding communication that is conspicuously marked or otherwise -designated in writing by the copyright owner as "Not a Contribution." - -"Contributor" shall mean Licensor and any individual or Legal Entity -on behalf of whom a Contribution has been received by Licensor and -subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of -this License, each Contributor hereby grants to You a perpetual, -worldwide, non-exclusive, no-charge, royalty-free, irrevocable -copyright license to reproduce, prepare Derivative Works of, -publicly display, publicly perform, sublicense, and distribute the -Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of -this License, each Contributor hereby grants to You a perpetual, -worldwide, non-exclusive, no-charge, royalty-free, irrevocable -(except as stated in this section) patent license to make, have made, -use, offer to sell, sell, import, and otherwise transfer the Work, -where such license applies only to those patent claims licensable -by such Contributor that are necessarily infringed by their -Contribution(s) alone or by combination of their Contribution(s) -with the Work to which such Contribution(s) was submitted. If You -institute patent litigation against any entity (including a -cross-claim or counterclaim in a lawsuit) alleging that the Work -or a Contribution incorporated within the Work constitutes direct -or contributory patent infringement, then any patent licenses -granted to You under this License for that Work shall terminate -as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the -Work or Derivative Works thereof in any medium, with or without -modifications, and in Source or Object form, provided that You -meet the following conditions: - -(a) You must give any other recipients of the Work or -Derivative Works a copy of this License; and - -(b) You must cause any modified files to carry prominent notices -stating that You changed the files; and - -(c) You must retain, in the Source form of any Derivative Works -that You distribute, all copyright, patent, trademark, and -attribution notices from the Source form of the Work, -excluding those notices that do not pertain to any part of -the Derivative Works; and - -(d) If the Work includes a "NOTICE" text file as part of its -distribution, then any Derivative Works that You distribute must -include a readable copy of the attribution notices contained -within such NOTICE file, excluding those notices that do not -pertain to any part of the Derivative Works, in at least one -of the following places: within a NOTICE text file distributed -as part of the Derivative Works; within the Source form or -documentation, if provided along with the Derivative Works; or, -within a display generated by the Derivative Works, if and -wherever such third-party notices normally appear. The contents -of the NOTICE file are for informational purposes only and -do not modify the License. You may add Your own attribution -notices within Derivative Works that You distribute, alongside -or as an addendum to the NOTICE text from the Work, provided -that such additional attribution notices cannot be construed -as modifying the License. - -You may add Your own copyright statement to Your modifications and -may provide additional or different license terms and conditions -for use, reproduction, or distribution of Your modifications, or -for any such Derivative Works as a whole, provided Your use, -reproduction, and distribution of the Work otherwise complies with -the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, -any Contribution intentionally submitted for inclusion in the Work -by You to the Licensor shall be under the terms and conditions of -this License, without any additional terms or conditions. -Notwithstanding the above, nothing herein shall supersede or modify -the terms of any separate license agreement you may have executed -with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade -names, trademarks, service marks, or product names of the Licensor, -except as required for reasonable and customary use in describing the -origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or -agreed to in writing, Licensor provides the Work (and each -Contributor provides its Contributions) on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied, including, without limitation, any warranties or conditions -of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A -PARTICULAR PURPOSE. You are solely responsible for determining the -appropriateness of using or redistributing the Work and assume any -risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, -whether in tort (including negligence), contract, or otherwise, -unless required by applicable law (such as deliberate and grossly -negligent acts) or agreed to in writing, shall any Contributor be -liable to You for damages, including any direct, indirect, special, -incidental, or consequential damages of any character arising as a -result of this License or out of the use or inability to use the -Work (including but not limited to damages for loss of goodwill, -work stoppage, computer failure or malfunction, or any and all -other commercial damages or losses), even if such Contributor -has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing -the Work or Derivative Works thereof, You may choose to offer, -and charge a fee for, acceptance of support, warranty, indemnity, -or other liability obligations and/or rights consistent with this -License. However, in accepting such obligations, You may act only -on Your own behalf and on Your sole responsibility, not on behalf -of any other Contributor, and only if You agree to indemnify, -defend, and hold each Contributor harmless for any liability -incurred by, or claims asserted against, such Contributor by reason -of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - -To apply the Apache License to your work, attach the following -boilerplate notice, with the fields enclosed by brackets "[]" -replaced with your own identifying information. (Don't include -the brackets!) The text should be enclosed in the appropriate -comment syntax for the file format. We also recommend that a -file or class name and description of purpose be included on the -same "printed page" as the copyright notice for easier -identification within third-party archives. - -Copyright 2019 Nicolas Stalder - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/runners/lpc55/vendor/littlefs2/LICENSE-MIT b/runners/lpc55/vendor/littlefs2/LICENSE-MIT deleted file mode 100644 index 1a8a613f..00000000 --- a/runners/lpc55/vendor/littlefs2/LICENSE-MIT +++ /dev/null @@ -1,25 +0,0 @@ -Copyright (c) 2019 Nicolas Stalder - -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/runners/lpc55/vendor/littlefs2/README.md b/runners/lpc55/vendor/littlefs2/README.md deleted file mode 100644 index 34078fbf..00000000 --- a/runners/lpc55/vendor/littlefs2/README.md +++ /dev/null @@ -1,63 +0,0 @@ -

littlefs2

-
- - Idiomatic Rust API for littlefs - -
- -
- -
- - - Crates.io version - - - - API docs - - - - CI - -
- -## What is this? - -Idiomatic Rust API for the [littlefs][littlefs] microcontroller filesystem by [Chris Haster][geky]. - -Number `2` refers to the on-disk format version, [supporting inline files, custom attributes and dynamic wear-leveling][release-notes-2]. - -We follow [`std::fs`][std-fs] as much as reasonable. - -The low-level bindings are provided by the [littlefs2-sys][littlefs2-sys] library. - -Upstream release: [v2.1.4][upstream-release] - -[geky]: https://github.com/geky -[littlefs]: https://github.com/ARMmbed/littlefs -[release-notes-2]: https://github.com/ARMmbed/littlefs/releases/tag/v2.0.0 -[std-fs]: https://doc.rust-lang.org/std/fs/index.html -[littlefs2-sys]: https://lib.rs/littlefs2-sys -[upstream-release]: https://github.com/ARMmbed/littlefs/releases/tag/v2.1.4 - -## `no_std` - -This library is `no_std` compatible, but there are two gotchas. - -- The dev-dependency `memchr` of `littlefs2-sys` has its `std` features activated. To prevent this, upgrade to at least Rust 1.51 - and add `resolver = "2"` in the consuming code's `[package]` section. This will be the default in Rust 2021 edition. - -- At link time, `lfs.c` has a dependency on `strcpy`. When not linking to a `libc` with this symbol, activate the `c-stubs` feature - to provide an implementation. - -#### License - -littlefs is licensed under [BSD-3-Clause](https://github.com/ARMmbed/littlefs/blob/master/LICENSE.md). -This API for littlefs is licensed under either of [Apache License, Version 2.0](LICENSE-APACHE) or [MIT License](LICENSE-MIT) at your option. -Previous bindings exist in the [rust-littlefs](https://github.com/brandonedens/rust-littlefs) repository, also dual-licensed under Apache-2.0 and MIT. -
-Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. diff --git a/runners/lpc55/vendor/littlefs2/netlify.toml b/runners/lpc55/vendor/littlefs2/netlify.toml deleted file mode 100644 index 8721cd8a..00000000 --- a/runners/lpc55/vendor/littlefs2/netlify.toml +++ /dev/null @@ -1,8 +0,0 @@ -[build] - # command = "curl https://sh.rustup.rs -sSf | sh -s -- -y && source $HOME/.cargo/env && sudo apt-get install llvm && cargo doc" - command = "curl https://sh.rustup.rs -sSf | sh -s -- -y && source $HOME/.cargo/env && env && cargo doc" - publish = "target/doc" - -[[redirects]] - from = "/" - to = "/littlefs2" diff --git a/runners/lpc55/vendor/littlefs2/src/c_stubs.rs b/runners/lpc55/vendor/littlefs2/src/c_stubs.rs deleted file mode 100644 index 92d1dc6d..00000000 --- a/runners/lpc55/vendor/littlefs2/src/c_stubs.rs +++ /dev/null @@ -1,29 +0,0 @@ -//! C functions not provided by compiler-builtins -//! -//! Use this instead of linking to libc if you only need a handful of free functions - -use cty::{c_char, c_void, size_t}; - -extern "C" { - // provided by `compiler-builtins` - fn memcpy(dst: *mut c_void, src: *const c_void, n: size_t) -> *mut c_void; -} - -/// # Safety -/// - `src` must be a valid C string (null terminated) -/// - `dst` must be large enough to hold `src` -#[no_mangle] -unsafe fn strcpy(dst: *mut c_char, src: *const c_char) -> *mut c_char { - memcpy(dst as *mut c_void, src as *const c_void, strlen(src)) as *mut c_char -} - -/// # Safety -/// `s` must point to valid memory; `s` will be treated as a null terminated string -pub unsafe fn strlen(mut s: *const c_char) -> size_t { - let mut n = 0; - while *s != 0 { - s = s.add(1); - n += 1; - } - n -} diff --git a/runners/lpc55/vendor/littlefs2/src/consts.rs b/runners/lpc55/vendor/littlefs2/src/consts.rs deleted file mode 100644 index c5e00416..00000000 --- a/runners/lpc55/vendor/littlefs2/src/consts.rs +++ /dev/null @@ -1,15 +0,0 @@ -#![allow(non_camel_case_types)] - -/// Re-export of `typenum::consts`. -pub use generic_array::typenum::consts::*; - -pub const FILENAME_MAX_PLUS_ONE: u32 = 255 + 1; -// pub type PATH_DEFAULT_MAX = generic_array::typenum::consts::U255; -// pub const PATH_MAX: u32 = 255; -pub const PATH_MAX: usize = 255; -pub const PATH_MAX_PLUS_ONE: usize = PATH_MAX + 1; -pub const FILEBYTES_MAX: u32 = crate::ll::LFS_FILE_MAX as _; -pub const ATTRBYTES_MAX: u32 = 1_022; -pub type ATTRBYTES_MAX_TYPE = U1022; -pub const LOOKAHEADWORDS_SIZE: u32 = 16; - diff --git a/runners/lpc55/vendor/littlefs2/src/driver.rs b/runners/lpc55/vendor/littlefs2/src/driver.rs deleted file mode 100644 index acd19704..00000000 --- a/runners/lpc55/vendor/littlefs2/src/driver.rs +++ /dev/null @@ -1,144 +0,0 @@ -//! The `Storage`, `Read`, `Write` and `Seek` driver. -#![allow(non_camel_case_types)] - -use generic_array::ArrayLength; -use littlefs2_sys as ll; - -use crate::{ - io::Result, -}; - -/// Users of this library provide a "storage driver" by implementing this trait. -/// -/// The `write` method is assumed to be synchronized to storage immediately. -/// littlefs provides more flexibility - if required, this could also be exposed. -/// Do note that due to caches, files still must be synched. And unfortunately, -/// this can't be automatically done in `drop`, since it needs mut refs to both -/// filesystem and storage. -/// -/// The `*_SIZE` types must be `generic_array::typenume::consts` such as `U256`. -/// -/// Why? Currently, associated constants can not be used (as constants...) to define -/// arrays. This "will be fixed" as part of const generics. -/// Once that's done, we can get rid of `generic-array`s, and replace the -/// `*_SIZE` types with `usize`s. -pub trait Storage { - - // /// Error type for user-provided read/write/erase methods - // type Error = usize; - - /// Minimum size of block read in bytes. Not in superblock - const READ_SIZE: usize; - - /// Minimum size of block write in bytes. Not in superblock - const WRITE_SIZE: usize; - - /// Size of an erasable block in bytes, as unsigned typenum. - /// Must be a multiple of both `READ_SIZE` and `WRITE_SIZE`. - /// At least 128 (https://git.io/JeHp9). Stored in superblock. - const BLOCK_SIZE: usize; - - /// Number of erasable blocks. - /// Hence storage capacity is `BLOCK_COUNT * BLOCK_SIZE` - const BLOCK_COUNT: usize; - - /// Suggested values are 100-1000, higher is more performant but - /// less wear-leveled. Default of -1 disables wear-leveling. - /// Value zero is invalid, must be positive or -1. - const BLOCK_CYCLES: isize = -1; - - /// littlefs uses a read cache, a write cache, and one cache per per file. - /// Must be a multiple of `READ_SIZE` and `WRITE_SIZE`. - /// Must be a factor of `BLOCK_SIZE`. - type CACHE_SIZE: ArrayLength; - - /// littlefs itself has a `LOOKAHEAD_SIZE`, which must be a multiple of 8, - /// as it stores data in a bitmap. It also asks for 4-byte aligned buffers. - /// Hence, we further restrict `LOOKAHEAD_SIZE` to be a multiple of 32. - /// Our LOOKAHEADWORDS_SIZE is this multiple. - type LOOKAHEADWORDS_SIZE: ArrayLength; - // type LOOKAHEAD_SIZE: ArrayLength; - - ///// Maximum length of a filename plus one. Stored in superblock. - ///// Should default to 255+1, but associated type defaults don't exist currently. - ///// At most 1_022+1. - ///// - ///// TODO: We can't actually change this - need to pass on as compile flag - ///// to the C backend. - //type FILENAME_MAX_PLUS_ONE: ArrayLength; - - // /// Maximum length of a path plus one. Necessary to convert Rust string slices - // /// to C strings, which requires an allocation for the terminating - // /// zero-byte. If in doubt, set to `FILENAME_MAX_PLUS_ONE`. - // /// Must be larger than `FILENAME_MAX_PLUS_ONE`. - // type PATH_MAX_PLUS_ONE: ArrayLength; - - ///// Maximum size of file. Stored in superblock. - ///// Defaults to 2_147_483_647 (or u31, to avoid sign issues in the C code). - ///// At most 2_147_483_647. - ///// - ///// TODO: We can't actually change this - need to pass on as compile flag - ///// to the C backend. - //const FILEBYTES_MAX: usize = ll::LFS_FILE_MAX as _; - - ///// Maximum size of custom attributes. - ///// Should default to 1_022, but associated type defaults don't exists currently. - ///// At most 1_022. - ///// - ///// TODO: We can't actually change this - need to pass on as compile flag - ///// to the C backend. - //type ATTRBYTES_MAX: ArrayLength; - - /// Read data from the storage device. - /// Guaranteed to be called only with bufs of length a multiple of READ_SIZE. - fn read(&self, off: usize, buf: &mut [u8]) -> Result; - /// Write data to the storage device. - /// Guaranteed to be called only with bufs of length a multiple of WRITE_SIZE. - fn write(&mut self, off: usize, data: &[u8]) -> Result; - /// Erase data from the storage device. - /// Guaranteed to be called only with bufs of length a multiple of BLOCK_SIZE. - fn erase(&mut self, off: usize, len: usize) -> Result; - // /// Synchronize writes to the storage device. - // fn sync(&mut self) -> Result; -} - -// in the future, try to split the megatrait `Storage` into pieces -// like this? -mod future { - // content of "superblock" - pub trait DiskFormat { - // version, upper/lower half-word contain major/minor - // const DISK_FORMAT_VERSION: u32, - - // block_size, block_count - const BLOCK_SIZE: usize; - const BLOCK_COUNT: usize; - - // name_max, file_max, attr_max - type FILENAME_MAX_PLUS_ONE; - const FILEBYTES_MAX: usize = super::ll::LFS_FILE_MAX as _; - type ATTRBYTES_MAX; - } - - pub trait Driver { - const READ_SIZE: usize; - const WRITE_SIZE: usize; - - const BLOCK_SIZE: usize; - const BLOCK_COUNT: usize; - - // fn read(&self, offset: usize, buf: &mut [u8]) -> Result; - // fn write(&mut self, offset: usize, data: &[u8]) -> Result; - // fn erase(&mut self, offset: usize, len: usize) -> Result; - } - - pub trait MemoryUsage { - // TODO: this supposedly influences whether files are inlined or not. Clarify - type CACHE_SIZE; - type LOOKAHEADWORDS_SIZE; - } - - pub trait RuntimeParameters { - const BLOCK_CYCLES: isize = -1; - } -} diff --git a/runners/lpc55/vendor/littlefs2/src/fs.rs b/runners/lpc55/vendor/littlefs2/src/fs.rs deleted file mode 100644 index 1d26c96e..00000000 --- a/runners/lpc55/vendor/littlefs2/src/fs.rs +++ /dev/null @@ -1,1569 +0,0 @@ -//! Experimental Filesystem version using closures. - -use core::{cell::RefCell, cmp, mem, slice}; - -use bitflags::bitflags; -use generic_array::typenum::marker_traits::Unsigned; -use littlefs2_sys as ll; -use serde::{Deserialize, Serialize}; - -// so far, don't need `heapless-bytes`. -pub type Bytes = generic_array::GenericArray; - -use crate::{ - io::{self, Result}, - path::{Path, PathBuf}, - driver, -}; - -struct Cache { - read: Bytes, - write: Bytes, - // lookahead: aligned::Aligned>, - lookahead: generic_array::GenericArray, -} - -impl Cache { - pub fn new() -> Self { - Self { - read: Default::default(), - write: Default::default(), - // lookahead: aligned::Aligned(Default::default()), - lookahead: Default::default(), - } - } -} - -impl Default for Cache { - fn default() -> Self { - Self::new() - } -} - -pub struct Allocation { - cache: Cache, - config: ll::lfs_config, - state: ll::lfs_t, -} - -// pub fn check_storage_requirements( - -impl Default for Allocation { - fn default() -> Self { - Self::new() - } -} -impl Allocation { - - pub fn new() -> Allocation { - let read_size: u32 = Storage::READ_SIZE as _; - let write_size: u32 = Storage::WRITE_SIZE as _; - let block_size: u32 = Storage::BLOCK_SIZE as _; - let cache_size: u32 = ::CACHE_SIZE::U32; - let lookahead_size: u32 = - 4 * ::LOOKAHEADWORDS_SIZE::U32; - let block_cycles: i32 = Storage::BLOCK_CYCLES as _; - let block_count: u32 = Storage::BLOCK_COUNT as _; - - debug_assert!(block_cycles >= -1); - debug_assert!(block_cycles != 0); - debug_assert!(block_count > 0); - - debug_assert!(read_size > 0); - debug_assert!(write_size > 0); - // https://github.com/ARMmbed/littlefs/issues/264 - // Technically, 104 is enough. - debug_assert!(block_size >= 128); - debug_assert!(cache_size > 0); - debug_assert!(lookahead_size > 0); - - // cache must be multiple of read - debug_assert!(read_size <= cache_size); - debug_assert!(cache_size % read_size == 0); - - // cache must be multiple of write - debug_assert!(write_size <= cache_size); - debug_assert!(cache_size % write_size == 0); - - // block must be multiple of cache - debug_assert!(cache_size <= block_size); - debug_assert!(block_size % cache_size == 0); - - let cache = Cache::new(); - - let filename_max_plus_one: u32 = crate::consts::FILENAME_MAX_PLUS_ONE; - debug_assert!(filename_max_plus_one > 1); - debug_assert!(filename_max_plus_one <= 1_022+1); - // limitation of ll-bindings - debug_assert!(filename_max_plus_one == 255+1); - let path_max_plus_one: u32 = crate::consts::PATH_MAX_PLUS_ONE as _; - // TODO: any upper limit? - debug_assert!(path_max_plus_one >= filename_max_plus_one); - let file_max = crate::consts::FILEBYTES_MAX; - assert!(file_max > 0); - assert!(file_max <= 2_147_483_647); - // limitation of ll-bindings - assert!(file_max == 2_147_483_647); - let attr_max: u32 = crate::consts::ATTRBYTES_MAX; - assert!(attr_max > 0); - assert!(attr_max <= 1_022); - // limitation of ll-bindings - assert!(attr_max == 1_022); - - let config = ll::lfs_config { - context: core::ptr::null_mut(), - read: Some(>::lfs_config_read), - prog: Some(>::lfs_config_prog), - erase: Some(>::lfs_config_erase), - sync: Some(>::lfs_config_sync), - // read: None, - // prog: None, - // erase: None, - // sync: None, - read_size, - prog_size: write_size, - block_size, - block_count, - block_cycles, - cache_size, - lookahead_size, - - read_buffer: core::ptr::null_mut(), - prog_buffer: core::ptr::null_mut(), - lookahead_buffer: core::ptr::null_mut(), - - name_max: filename_max_plus_one.wrapping_sub(1), - file_max, - attr_max, - }; - - Self { - cache, - state: unsafe { mem::MaybeUninit::zeroed().assume_init() }, - config, - } - } - -} - -// pub struct Filesystem<'alloc, 'storage, Storage: driver::Storage> { -// pub(crate) alloc: &'alloc mut Allocation, -// pub(crate) storage: &'storage mut Storage, -// } - -// one lifetime is simpler than two... hopefully should be enough -// also consider "erasing" the lifetime completely -pub struct Filesystem<'a, Storage: driver::Storage> { - alloc: RefCell<&'a mut Allocation>, - storage: &'a mut Storage, -} - -/// Regular file vs directory -#[derive(Clone,Copy,Debug,Eq,Hash,PartialEq,Serialize,Deserialize)] -pub enum FileType { - File, - Dir, -} - -impl FileType { - #[allow(clippy::all)] // following `std::fs` - pub fn is_dir(&self) -> bool { - *self == FileType::Dir - } - - #[allow(clippy::all)] // following `std::fs` - pub fn is_file(&self) -> bool { - *self == FileType::File - } -} - -/// File type (regular vs directory) and size of a file. -#[derive(Clone,Debug,Eq,PartialEq,Serialize,Deserialize)] -pub struct Metadata { - file_type: FileType, - size: usize, -} - -impl Metadata -{ - pub fn file_type(&self) -> FileType { - self.file_type - } - - pub fn is_dir(&self) -> bool { - self.file_type().is_dir() - } - - pub fn is_file(&self) -> bool { - self.file_type().is_file() - } - - pub fn len(&self) -> usize { - self.size - } - - pub fn is_empty(&self) -> bool { - self.size == 0 - } -} - -impl From for Metadata -{ - fn from(info: ll::lfs_info) -> Self { - let file_type = match info.type_ as u32 { - ll::lfs_type_LFS_TYPE_DIR => FileType::Dir, - ll::lfs_type_LFS_TYPE_REG => FileType::File, - _ => { unreachable!(); } - }; - - Metadata { - file_type, - size: info.size as usize, - } - } -} - -impl Filesystem<'_, Storage> { - - pub fn allocate() -> Allocation { - Allocation::new() - } - - pub fn format(storage: &mut Storage) -> Result<()> { - - let alloc = &mut Allocation::new(); - let fs = Filesystem::new(alloc, storage); - let mut alloc = fs.alloc.borrow_mut(); - let return_code = unsafe { ll::lfs_format(&mut alloc.state, &alloc.config) }; - io::result_from((), return_code) - } - - // TODO: check if this is equivalent to `is_formatted`. - pub fn is_mountable(storage: &mut Storage) -> bool { - let alloc = &mut Allocation::new(); - matches!(Filesystem::mount(alloc, storage), Ok(_)) - } - - // Can BorrowMut be implemented "unsafely" instead? - // This is intended to be a second option, besides `into_inner`, to - // get access to the Flash peripheral in Storage. - pub unsafe fn borrow_storage_mut(&mut self) -> &mut Storage { - self.storage - } - - /// This API avoids the need for using `Allocation`. - pub fn mount_and_then( - storage: &mut Storage, - f: impl FnOnce(&Filesystem<'_, Storage>) -> Result, - ) -> Result { - - let mut alloc = Allocation::new(); - let fs = Filesystem::mount(&mut alloc, storage)?; - f(&fs) - } - - /// Total number of blocks in the filesystem - pub fn total_blocks(&self) -> usize { - Storage::BLOCK_COUNT - } - - /// Total number of bytes in the filesystem - pub fn total_space(&self) -> usize { - Storage::BLOCK_COUNT * Storage::BLOCK_SIZE - } - - /// Available number of unused blocks in the filesystem - /// - /// Upstream littlefs documentation notes (on its "current size" function): - /// "Result is best effort. If files share COW structures, the returned size may be larger - /// than the filesystem actually is." - /// - /// So it would seem that there are *at least* the number of blocks returned - /// by this method available, at any given time. - pub fn available_blocks(&self) -> Result { - let return_code = unsafe { ll::lfs_fs_size( &mut self.alloc.borrow_mut().state) }; - io::result_from(return_code, return_code).map(|blocks| self.total_blocks() - blocks as usize) - } - - /// Available number of unused bytes in the filesystem - /// - /// This is a lower bound, more may be available. First, more blocks may be available as - /// explained in [`available_blocks`](struct.Filesystem.html#method.available_blocks). - /// Second, files may be inlined. - pub fn available_space(&self) -> Result { - self.available_blocks().map(|blocks| blocks * Storage::BLOCK_SIZE) - } - - /// Remove a file or directory. - pub fn remove(&self, path: &Path) -> Result<()> { - let return_code = unsafe { ll::lfs_remove( - &mut self.alloc.borrow_mut().state, - path.as_ptr(), - ) }; - io::result_from((), return_code) - } - - /// Remove a file or directory. - pub fn remove_dir(&self, path: &Path) -> Result<()> { - self.remove(path) - } - - /// TODO: This method fails if some `println!` calls are removed. - /// Whyy? - #[cfg(feature = "dir-entry-path")] - pub fn remove_dir_all(&self, path: &Path) -> Result<()> { - self.remove_dir_all_where(path, &|_| true).map(|_| ()) - } - - #[cfg(feature = "dir-entry-path")] - pub fn remove_dir_all_where

(&self, path: &Path, predicate: &P) -> Result - where - P: Fn(&DirEntry) -> bool, - { - if !path.exists(self) { - debug_now!("no such directory {}, early return", path); - return Ok(0); - } - let mut skipped_any = false; - let mut files_removed = 0; - debug_now!("starting to remove_dir_all_where in {}", path); - self.read_dir_and_then(path, |read_dir| { - // skip "." and ".." - for entry in read_dir.skip(2) { - let entry = entry?; - - if entry.file_type().is_file() { - if predicate(&entry) { - debug_now!("removing file {}", &entry.path()); - self.remove(entry.path())?; - debug_now!("...done"); - files_removed += 1; - } else { - debug_now!("skipping file {}", &entry.path()); - skipped_any = true; - } - } - if entry.file_type().is_dir() { - debug_now!("recursing into directory {}", &entry.path()); - files_removed += self.remove_dir_all_where(entry.path(), predicate)?; - debug_now!("...back"); - } - } - Ok(()) - })?; - if !skipped_any { - debug_now!("removing directory {} too", &path); - self.remove_dir(path)?; - debug_now!("..worked"); - } - Ok(files_removed) - } - - /// Rename or move a file or directory. - pub fn rename(&self, from: &Path, to: &Path) -> Result<()> { - let return_code = unsafe { ll::lfs_rename( - &mut self.alloc.borrow_mut().state, - from.as_ptr(), - to.as_ptr(), - ) }; - io::result_from((),return_code) - } - - /// Given a path, query the filesystem to get information about a file or directory. - /// - /// To read user attributes, use - /// [`Filesystem::attribute`](struct.Filesystem.html#method.attribute) - pub fn metadata(&self, path: &Path) -> Result { - - // do *not* not call assume_init here and pass into the unsafe block. - // strange things happen ;) - - // TODO: Check we don't have UB here *too*. - // I think it's fine, as we immediately copy out the data - // to our own structure. - let mut info: ll::lfs_info = unsafe { mem::MaybeUninit::zeroed().assume_init() }; - let return_code = unsafe { - ll::lfs_stat( - &mut self.alloc.borrow_mut().state, - path.as_ptr(), - &mut info, - ) - }; - - io::result_from((), return_code).map(|_| info.into()) - } - - pub fn create_file_and_then( - &self, - path: &Path, - f: impl FnOnce(&File<'_, '_, Storage>) -> Result, - ) -> - Result - { - File::create_and_then(self, path, f) - } - - pub fn open_file_and_then( - &self, - path: &Path, - f: impl FnOnce(&File<'_, '_, Storage>) -> Result, - ) -> - Result - { - File::open_and_then(self, path, f) - } - - pub fn with_options() -> OpenOptions { - OpenOptions::new() - } - - pub fn open_file_with_options_and_then( - &self, - o: impl FnOnce(&mut OpenOptions) -> &OpenOptions, - path: &Path, - f: impl FnOnce(&File<'_, '_, Storage>) -> Result, - ) -> Result - { - let mut options = OpenOptions::new(); - o(&mut options).open_and_then(self, path, f) - } - - - /// Read attribute. - pub fn attribute( - &self, - path: &Path, - id: u8, - ) -> - Result> - { - let mut attribute = Attribute::new(id); - let attr_max = crate::consts::ATTRBYTES_MAX; - - let return_code = unsafe { ll::lfs_getattr( - &mut self.alloc.borrow_mut().state, - path.as_ptr(), - id, - &mut attribute.data as *mut _ as *mut cty::c_void, - attr_max, - ) }; - - if return_code >= 0 { - attribute.size = cmp::min(attr_max, return_code as u32) as usize; - return Ok(Some(attribute)); - } - if return_code == ll::lfs_error_LFS_ERR_NOATTR { - return Ok(None) - } - - io::result_from((), return_code)?; - // TODO: get rid of this - unreachable!(); - } - - /// Remove attribute. - pub fn remove_attribute( - &self, - path: &Path, - id: u8, - ) -> Result<()> { - let return_code = unsafe { ll::lfs_removeattr( - &mut self.alloc.borrow_mut().state, - path.as_ptr(), - id, - ) }; - io::result_from((), return_code) - } - - /// Set attribute. - pub fn set_attribute( - &self, - path: &Path, - attribute: &Attribute, - ) -> - Result<()> - { - let return_code = unsafe { ll::lfs_setattr( - &mut self.alloc.borrow_mut().state, - path.as_ptr(), - attribute.id, - &attribute.data as *const _ as *const cty::c_void, - attribute.size as u32, - ) }; - - io::result_from((), return_code) - } - - - /// C callback interface used by LittleFS to read data with the lower level system below the - /// filesystem. - extern "C" fn lfs_config_read( - c: *const ll::lfs_config, - block: ll::lfs_block_t, - off: ll::lfs_off_t, - buffer: *mut cty::c_void, - size: ll::lfs_size_t, - ) -> cty::c_int { - // println!("in lfs_config_read for {} bytes", size); - let storage = unsafe { &*((*c).context as *const Storage) }; - debug_assert!(!c.is_null()); - let block_size = unsafe { c.read().block_size }; - let off = (block * block_size + off) as usize; - let buf: &mut [u8] = unsafe { slice::from_raw_parts_mut(buffer as *mut u8, size as usize) }; - - // TODO - storage.read(off, buf).unwrap(); - 0 - } - - /// C callback interface used by LittleFS to program data with the lower level system below the - /// filesystem. - extern "C" fn lfs_config_prog( - c: *const ll::lfs_config, - block: ll::lfs_block_t, - off: ll::lfs_off_t, - buffer: *const cty::c_void, - size: ll::lfs_size_t, - ) -> cty::c_int { - // println!("in lfs_config_prog"); - let storage = unsafe { &mut *((*c).context as *mut Storage) }; - debug_assert!(!c.is_null()); - // let block_size = unsafe { c.read().block_size }; - let block_size = Storage::BLOCK_SIZE as u32; - let off = (block * block_size + off) as usize; - let buf: &[u8] = unsafe { slice::from_raw_parts(buffer as *const u8, size as usize) }; - - // TODO - storage.write(off, buf).unwrap(); - 0 - } - - /// C callback interface used by LittleFS to erase data with the lower level system below the - /// filesystem. - extern "C" fn lfs_config_erase( - c: *const ll::lfs_config, - block: ll::lfs_block_t, - ) -> cty::c_int { - // println!("in lfs_config_erase"); - let storage = unsafe { &mut *((*c).context as *mut Storage) }; - let off = block as usize * Storage::BLOCK_SIZE as usize; - - // TODO - storage.erase(off, Storage::BLOCK_SIZE as usize).unwrap(); - 0 - } - - /// C callback interface used by LittleFS to sync data with the lower level interface below the - /// filesystem. Note that this function currently does nothing. - extern "C" fn lfs_config_sync(_c: *const ll::lfs_config) -> i32 { - // println!("in lfs_config_sync"); - // Do nothing; we presume that data is synchronized. - 0 - } - -} - -#[derive(Clone,Debug,Eq,PartialEq)] -/// Custom user attribute that can be set on files and directories. -/// -/// Consists of an numerical identifier between 0 and 255, and arbitrary -/// binary data up to size `ATTRBYTES_MAX`. -/// -/// Use [`Filesystem::attribute`](struct.Filesystem.html#method.attribute), -/// [`Filesystem::set_attribute`](struct.Filesystem.html#method.set_attribute), and -/// [`Filesystem::clear_attribute`](struct.Filesystem.html#method.clear_attribute). -pub struct Attribute { - id: u8, - data: Bytes, - size: usize, -} - -impl Attribute { - pub fn new(id: u8) -> Self { - Attribute { - id, - data: Default::default(), - size: 0, - } - } - - pub fn id(&self) -> u8 { - self.id - } - - pub fn data(&self) -> &[u8] { - let attr_max = crate::consts::ATTRBYTES_MAX as _; - let len = cmp::min(attr_max, self.size); - &self.data[..len] - } - - pub fn set_data(&mut self, data: &[u8]) -> &mut Self { - let attr_max = crate::consts::ATTRBYTES_MAX as _; - let len = cmp::min(attr_max, data.len()); - self.data[..len].copy_from_slice(&data[..len]); - self.size = len; - for entry in self.data[len..].iter_mut() { - *entry = 0; - } - self - } -} - -bitflags! { - /// Definition of file open flags which can be mixed and matched as appropriate. These definitions - /// are reminiscent of the ones defined by POSIX. - struct FileOpenFlags: u32 { - /// Open file in read only mode. - const READ = 0x1; - /// Open file in write only mode. - const WRITE = 0x2; - /// Open file for reading and writing. - const READWRITE = Self::READ.bits | Self::WRITE.bits; - /// Create the file if it does not exist. - const CREATE = 0x0100; - /// Fail if creating a file that already exists. - /// TODO: Good name for this - const EXCL = 0x0200; - /// Truncate the file if it already exists. - const TRUNCATE = 0x0400; - /// Open the file in append only mode. - const APPEND = 0x0800; - } -} - -/// The state of a `File`. Pre-allocate with `File::allocate`. -pub struct FileAllocation -{ - cache: Bytes, - state: ll::lfs_file_t, - config: ll::lfs_file_config, -} - -impl Default for FileAllocation { - fn default() -> Self { - Self::new() - } -} - -impl FileAllocation { - pub fn new() -> Self { - let cache_size: u32 = ::CACHE_SIZE::to_u32(); - debug_assert!(cache_size > 0); - unsafe { mem::MaybeUninit::zeroed().assume_init() } - } -} - -pub struct File<'a, 'b, S: driver::Storage> -{ - alloc: RefCell<&'b mut FileAllocation>, - fs: &'b Filesystem<'a, S>, -} - -impl<'a, 'b, Storage: driver::Storage> File<'a, 'b, Storage> -{ - pub fn allocate() -> FileAllocation { - FileAllocation::new() - } - - /// Returns a new OpenOptions object. - /// - /// This function returns a new OpenOptions object that you can use to open or create a file - /// with specific options if open() or create() are not appropriate. - /// - /// It is equivalent to OpenOptions::new() but allows you to write more readable code. - /// This also avoids the need to import OpenOptions`. - - pub fn with_options() -> OpenOptions { - OpenOptions::new() - } - - pub unsafe fn open( - fs: &'b Filesystem<'a, Storage>, - alloc: &'b mut FileAllocation, - path: &Path, - ) -> - Result - { - OpenOptions::new() - .read(true) - .open(fs, alloc, path) - } - - pub fn open_and_then( - fs: &Filesystem<'a, Storage>, - path: &Path, - f: impl FnOnce(&File<'_, '_, Storage>) -> Result, - ) -> - Result - { - OpenOptions::new() - .read(true) - .open_and_then(fs, path, f) - } - - pub unsafe fn create( - fs: &'b Filesystem<'a, Storage>, - alloc: &'b mut FileAllocation, - path: &Path, - ) -> - Result - { - OpenOptions::new() - .write(true) - .create(true) - .truncate(true) - .open(fs, alloc, path) - } - - pub fn create_and_then( - fs: &Filesystem<'a, Storage>, - path: &Path, - f: impl FnOnce(&File<'_, '_, Storage>) -> Result, - ) -> - Result - { - OpenOptions::new() - .write(true) - .create(true) - .truncate(true) - .open_and_then(fs, path, f) - } - - // Safety-hatch to experiment with missing parts of API - pub unsafe fn borrow_filesystem<'c>(&'c mut self) -> &'c Filesystem<'a, Storage> { - &self.fs - } - - /// Sync the file and drop it from the internal linked list. - /// Not doing this is UB, which is why we have all the closure-based APIs. - /// - /// TODO: check if this can be closed >1 times, if so make it safe - /// - /// Update: It seems like there's an assertion on a flag called `LFS_F_OPENED`: - /// https://github.com/ARMmbed/littlefs/blob/4c9146ea539f72749d6cc3ea076372a81b12cb11/lfs.c#L2549 - /// https://github.com/ARMmbed/littlefs/blob/4c9146ea539f72749d6cc3ea076372a81b12cb11/lfs.c#L2566 - /// - /// - On second call, shouldn't find ourselves in the "mlist of mdirs" - /// - Since we don't have dynamically allocated buffers, at least we don't hit the double-free. - /// - Not sure what happens in `lfs_file_sync`, but it should be easy to just error on - /// not LFS_F_OPENED... - pub unsafe fn close(self) -> Result<()> - { - let return_code = ll::lfs_file_close( - &mut self.fs.alloc.borrow_mut().state, - &mut self.alloc.borrow_mut().state, - ); - io::result_from((), return_code) - } - - /// Synchronize file contents to storage. - pub fn sync(&self) -> Result<()> { - let return_code = unsafe { ll::lfs_file_sync( - &mut self.fs.alloc.borrow_mut().state, - &mut self.alloc.borrow_mut().state, - ) }; - io::result_from((), return_code) - } - - /// Size of the file in bytes. - pub fn len(&self) -> Result { - let return_code = unsafe { ll::lfs_file_size( - &mut self.fs.alloc.borrow_mut().state, - &mut self.alloc.borrow_mut().state - ) }; - io::result_from(return_code as usize, return_code) - } - - /// Truncates or extends the underlying file, updating the size of this file to become size. - /// - /// If the size is less than the current file's size, then the file will be shrunk. If it is - /// greater than the current file's size, then the file will be extended to size and have all - /// of the intermediate data filled in with 0s. - pub fn set_len(&self, size: usize) -> Result<()> { - let return_code = unsafe { ll::lfs_file_truncate( - &mut self.fs.alloc.borrow_mut().state, - &mut self.alloc.borrow_mut().state, - size as u32, - ) }; - io::result_from((), return_code) - } - - // This belongs in `io::Read` but really don't want that to have a generic parameter - pub fn read_to_end(&self, buf: &mut heapless::Vec) -> Result { - // My understanding of - // https://github.com/ARMmbed/littlefs/blob/4c9146ea539f72749d6cc3ea076372a81b12cb11/lfs.c#L2816 - // is that littlefs keeps reading until either the buffer is full, or the file is exhausted - - let had = buf.len(); - // no panic by construction - buf.resize_default(buf.capacity()).unwrap(); - // use io::Read; - let read = self.read(&mut buf[had..])?; - // no panic by construction - buf.resize_default(had + read).unwrap(); - Ok(read) - } - - pub fn read(&self, buf: &mut [u8]) -> Result { - ::read(self, buf) - } - - pub fn seek(&self, pos: io::SeekFrom) -> Result { - ::seek(self, pos) - } - - pub fn write(&self, buf: &[u8]) -> Result { - ::write(self, buf) - } -} - - -/// Options and flags which can be used to configure how a file is opened. -/// -/// This builder exposes the ability to configure how a File is opened and what operations -/// are permitted on the open file. The File::open and File::create methods are aliases -/// for commonly used options using this builder. -/// -/// Consider `File::with_options()` to avoid having to `use` OpenOptions. -#[derive(Clone,Debug,Eq,PartialEq)] -pub struct OpenOptions (FileOpenFlags); - -impl Default for OpenOptions { - fn default() -> Self { - Self::new() - } -} - -impl OpenOptions { - - /// Open the file with the options previously specified, keeping references. - /// - /// unsafe since UB can arise if files are not closed (see below). - /// - /// The alternative method `open_and_then` is suggested. - /// - /// Note that: - /// - files *must* be closed before going out of scope (they are stored in a linked list), - /// closing removes them from there - /// - since littlefs is supposed to be *fail-safe*, we can't just close files in - /// Drop and panic if something went wrong. - pub unsafe fn open<'a, 'b, S: driver::Storage>( - &self, - fs: &'b Filesystem<'a, S>, - alloc: &'b mut FileAllocation, - path: &Path, - ) -> - Result> - { - alloc.config.buffer = &mut alloc.cache as *mut _ as *mut cty::c_void; - - let return_code = ll::lfs_file_opencfg( - &mut fs.alloc.borrow_mut().state, - &mut alloc.state, - path.as_ptr(), - self.0.bits() as i32, - &alloc.config, - ); - - let file = File { - alloc: RefCell::new(alloc), - fs, - }; - - io::result_from(file, return_code) - } - - /// (Hopefully) safe abstraction around `open`. - pub fn open_and_then<'a, R, S: driver::Storage>( - &self, - fs: &Filesystem<'a, S>, - path: &Path, - f: impl FnOnce(&File<'a, '_, S>) -> Result, - ) - -> Result - { - let mut alloc = FileAllocation::new(); // lifetime 'c - let mut file = unsafe { self.open(fs, &mut alloc, path)? }; - // Q: what is the actually correct behaviour? - // E.g. if res is Ok but closing gives an error. - // Or if closing fails because something is broken and - // we'd already know that from an Err res. - let res = f(&mut file); - unsafe { file.close()? }; - res - } - - pub fn new() -> Self { - OpenOptions(FileOpenFlags::empty()) - } - - pub fn read(&mut self, read: bool) -> &mut Self { - if read { - self.0.insert(FileOpenFlags::READ) - } else { - self.0.remove(FileOpenFlags::READ) - }; self - } - - pub fn write(&mut self, write: bool) -> &mut Self { - if write { - self.0.insert(FileOpenFlags::WRITE) - } else { - self.0.remove(FileOpenFlags::WRITE) - }; self - } - - pub fn append(&mut self, append: bool) -> &mut Self { - if append { - self.0.insert(FileOpenFlags::APPEND) - } else { - self.0.remove(FileOpenFlags::APPEND) - }; self - } - - pub fn create(&mut self, create: bool) -> &mut Self { - if create { - self.0.insert(FileOpenFlags::CREATE) - } else { - self.0.remove(FileOpenFlags::CREATE) - }; self - } - - pub fn create_new(&mut self, create_new: bool) -> &mut Self { - if create_new { - self.0.insert(FileOpenFlags::EXCL); - self.0.insert(FileOpenFlags::CREATE); - } else { - self.0.remove(FileOpenFlags::EXCL); - self.0.remove(FileOpenFlags::CREATE); - }; self - } - - pub fn truncate(&mut self, truncate: bool) -> &mut Self { - if truncate { - self.0.insert(FileOpenFlags::TRUNCATE) - } else { - self.0.remove(FileOpenFlags::TRUNCATE) - }; self - } - -} - -impl io::Read for File<'_, '_, S> -{ - fn read(&self, buf: &mut [u8]) -> Result { - let return_code = unsafe { ll::lfs_file_read( - &mut self.fs.alloc.borrow_mut().state, - &mut self.alloc.borrow_mut().state, - buf.as_mut_ptr() as *mut cty::c_void, - buf.len() as u32, - ) }; - io::result_from(return_code as usize, return_code) - } -} - -impl io::Seek for File<'_, '_, S> -{ - fn seek(&self, pos: io::SeekFrom) -> Result { - let return_code = unsafe { ll::lfs_file_seek( - &mut self.fs.alloc.borrow_mut().state, - &mut self.alloc.borrow_mut().state, - pos.off(), - pos.whence(), - ) }; - io::result_from(return_code as usize, return_code) - } -} - -impl io::Write for File<'_, '_, S> -{ - fn write(&self, buf: &[u8]) -> Result { - let return_code = unsafe { ll::lfs_file_write( - &mut self.fs.alloc.borrow_mut().state, - &mut self.alloc.borrow_mut().state, - buf.as_ptr() as *const cty::c_void, - buf.len() as u32, - ) }; - io::result_from(return_code as usize, return_code) - } - - fn flush(&self) -> Result<()> { Ok(()) } -} - -#[derive(Clone,Debug,PartialEq,Eq,Serialize,Deserialize)] -pub struct DirEntry { - file_name: PathBuf, - metadata: Metadata, - #[cfg(feature = "dir-entry-path")] - path: PathBuf, -} - -impl DirEntry { - // // Returns the full path to the file that this entry represents. - // pub fn path(&self) -> Path {} - - // Returns the metadata for the file that this entry points at. - pub fn metadata(&self) -> Metadata { - self.metadata.clone() - } - - // Returns the file type for the file that this entry points at. - pub fn file_type(&self) -> FileType { - self.metadata.file_type - } - - // Returns the bare file name of this directory entry without any other leading path component. - pub fn file_name(&self) -> &Path { - &self.file_name - } - - /// Returns the full path to the file that this entry represents. - /// - /// The full path is created by joining the original path to read_dir with the filename of this entry. - #[cfg(feature = "dir-entry-path")] - pub fn path(&self) -> &Path { - &self.path - } - - #[cfg(feature = "dir-entry-path")] - #[doc(hidden)] - // This is used in `crypto-service` to "namespace" paths - // by mutating a DirEntry in-place. - pub unsafe fn path_buf_mut(&mut self) -> &mut PathBuf { - &mut self.path - } - -} - -pub struct ReadDirAllocation { - state: ll::lfs_dir_t, -} - -impl Default for ReadDirAllocation { - fn default() -> Self { - Self::new() - } -} - -impl ReadDirAllocation { - pub fn new() -> Self { - unsafe { mem::MaybeUninit::zeroed().assume_init() } - } -} - -pub struct ReadDir<'a, 'b, S: driver::Storage> -{ - alloc: RefCell<&'b mut ReadDirAllocation>, - fs: &'b Filesystem<'a, S>, - #[cfg(feature = "dir-entry-path")] - path: PathBuf, -} - -impl<'a, 'b, S: driver::Storage> Iterator for ReadDir<'a, 'b, S> -{ - type Item = Result; - - // remove this allowance again, once path overflow is properly handled - #[allow(unreachable_code)] - fn next(&mut self) -> Option { - let mut info: ll::lfs_info = unsafe { - mem::MaybeUninit::zeroed().assume_init() - }; - - let return_code = unsafe { - ll::lfs_dir_read( - &mut self.fs.alloc.borrow_mut().state, - &mut self.alloc.borrow_mut().state, - &mut info, - ) - }; - - if return_code > 0 { - let file_name = unsafe { PathBuf::from_buffer(info.name) }; - let metadata = info.into(); - - #[cfg(feature = "dir-entry-path")] - // TODO: error handling... - let path = self.path.join(&file_name); - - let dir_entry = DirEntry { - file_name, - metadata, - #[cfg(feature = "dir-entry-path")] - path, - }; - return Some(Ok(dir_entry)); - } - - if return_code == 0 { - return None - } - - Some(Err(io::result_from((), return_code).unwrap_err())) - } -} - -impl<'a, 'b, S: driver::Storage> ReadDir<'a, 'b, S> { - - // Safety-hatch to experiment with missing parts of API - pub unsafe fn borrow_filesystem<'c>(&'c mut self) -> &'c Filesystem<'a, S> { - &self.fs - } -} - -impl ReadDir<'_, '_, S> { - // Again, not sure if this can be called twice - // Update: This one seems to be safe to call multiple times, - // it just goes through the "mlist" and removes itself. - // - // Although I guess if the compiler reuses the ReadDirAllocation, and we still - // have an (unsafely genereated) ReadDir with that handle; on the other hand - // as long as ReadDir is not Copy. - pub /* unsafe */ fn close(self) -> Result<()> - { - let return_code = unsafe { ll::lfs_dir_close( - &mut self.fs.alloc.borrow_mut().state, - &mut self.alloc.borrow_mut().state, - ) }; - io::result_from((), return_code) - } -} - - -impl<'a, Storage: driver::Storage> Filesystem<'a, Storage> { - - pub fn read_dir_and_then( - &self, - path: &Path, - // *not* &ReadDir, as Iterator takes &mut - f: impl FnOnce(&mut ReadDir<'_, '_, Storage>) -> Result, - ) -> Result - { - let mut alloc = ReadDirAllocation::new(); - let mut read_dir = unsafe { self.read_dir(&mut alloc, path)? }; - let res = f(&mut read_dir); - // unsafe { read_dir.close()? }; - read_dir.close()?; - res - } - - /// Returns a pseudo-iterator over the entries within a directory. - /// - /// This is unsafe since it can induce UB just like File::open. - pub unsafe fn read_dir<'b>( - &'b self, - alloc: &'b mut ReadDirAllocation, - path: &Path, - ) -> - Result> - { - let return_code = ll::lfs_dir_open( - &mut self.alloc.borrow_mut().state, - &mut alloc.state, - path.as_ptr(), - ); - - let read_dir = ReadDir { - alloc: RefCell::new(alloc), - fs: self, - #[cfg(feature = "dir-entry-path")] - path: PathBuf::from(path), - }; - - io::result_from(read_dir, return_code) - } - -} - - -impl<'a, Storage: driver::Storage> Filesystem<'a, Storage> { - - pub fn mount( - alloc: &'a mut Allocation, - storage: &'a mut Storage, - ) -> Result { - let fs = Self::new(alloc, storage); - let mut alloc = fs.alloc.borrow_mut(); - let return_code = unsafe { ll::lfs_mount(&mut alloc.state, &alloc.config) }; - drop(alloc); - io::result_from(fs, return_code) - } - - // Not public, user should use `mount`, possibly after `format` - fn new(alloc: &'a mut Allocation, storage: &'a mut Storage) -> Self { - - alloc.config.context = storage as *mut _ as *mut cty::c_void; - - alloc.config.read_buffer = &mut alloc.cache.read as *mut _ as *mut cty::c_void; - alloc.config.prog_buffer = &mut alloc.cache.write as *mut _ as *mut cty::c_void; - alloc.config.lookahead_buffer = &mut alloc.cache.lookahead as *mut _ as *mut cty::c_void; - - Filesystem { alloc: RefCell::new(alloc), storage } - } - - /// Deconstruct `Filesystem`, intention is to allow access to - /// the underlying Flash peripheral in driver::Storage etc. - /// - /// See also `borrow_storage_mut`. - pub fn into_inner(self) -> (&'a mut Allocation, &'a mut Storage) { - (self.alloc.into_inner(), self.storage) - } - - /// Creates a new, empty directory at the provided path. - pub fn create_dir(&self, path: &Path) -> Result<()> { - - #[cfg(test)] - println!("creating {:?}", path); - let return_code = unsafe { ll::lfs_mkdir( - &mut self.alloc.borrow_mut().state, - path.as_ptr(), - ) }; - io::result_from((), return_code) - } - - /// Recursively create a directory and all of its parent components if they are missing. - pub fn create_dir_all(&self, path: &Path) -> Result<()> { - // Placeholder implementation! - // - Path should gain a few methods - // - Maybe should pull in `heapless-bytes` (and merge upstream into `heapless`) - // - All kinds of sanity checks and possible logic errors possible... - - let path_slice = path.as_ref().as_bytes(); - for i in 0..path_slice.len() { - if path_slice[i] == b'/' { - let dir = PathBuf::from(&path_slice[..i]); - #[cfg(test)] - println!("generated PathBuf dir {:?} using i = {}", &dir, i); - match self.create_dir(&dir) { - Ok(_) => {} - Err(io::Error::EntryAlreadyExisted) => {} - error => { panic!("{:?}", &error); } - } - } - } - match self.create_dir(path) { - Ok(_) => {} - Err(io::Error::EntryAlreadyExisted) => {} - error => { panic!("{:?}", &error); } - } - Ok(()) - - // if path.as_ref() == "" { - // return Ok(()); - // } - - // match self.create_dir(path) { - // Ok(()) => return Ok(()), - // Err(_) if path.is_dir() => return Ok(()), - // Err(e) => return Err(e), - // } - - // match path.parent() { - // Some(p) => self.create_dir(p)?, - // None => panic!("unexpected"), - // } - - // match self.create_dir(path) { - // Ok(()) => return Ok(()), - // Err(e) => return Err(e), - // } - - } - - /// Read the entire contents of a file into a bytes vector. - pub fn read( - &self, - path: &Path, - ) - -> Result> - { - let mut contents: heapless::Vec:: = Default::default(); - File::open_and_then(self, path, |file| { - // use io::Read; - let len = file.read_to_end(&mut contents)?; - Ok(len) - })?; - Ok(contents) - } - - /// Write a slice as the entire contents of a file. - /// - /// This function will create a file if it does not exist, - /// and will entirely replace its contents if it does. - pub fn write( - &self, - path: &Path, - contents: &[u8], - ) -> Result<()> - { - #[cfg(test)] - println!("writing {:?}", path); - File::create_and_then(self, path, |file| { - use io::Write; - file.write_all(contents) - })?; - Ok(()) - } - -} - -#[cfg(test)] -mod tests { - use super::*; - use core::convert::TryInto; - use generic_array::typenum::consts; - use driver::Storage as LfsStorage; - use io::Result as LfsResult; - const_ram_storage!(TestStorage, 4096); - - #[test] - fn todo() { - let mut test_storage = TestStorage::new(); - // let jackson5 = [b"A", b"B", b"C", 1, 2, 3]; - let jackson5 = b"ABC 123"; - let jackson5 = &jackson5[..]; - - Filesystem::format(&mut test_storage).unwrap(); - Filesystem::mount_and_then(&mut test_storage, |fs| { - - println!("blocks going in: {}", fs.available_blocks()?); - fs.create_dir_all(b"/tmp/test\0".try_into().unwrap())?; - println!("dir done"); - // let weird_filename = b"/tmp/test/a.t\x7fxt"; - // fs.write(&weird_filename[..], jackson5)?; - fs.write(b"/tmp/test/a.txt\0".try_into().unwrap(), jackson5)?; - println!("a.txt"); - fs.write(b"/tmp/test/b.txt\0".try_into().unwrap(), jackson5)?; - fs.write(b"/tmp/test/c.txt\0".try_into().unwrap(), jackson5)?; - println!("blocks after 3 files of size 3: {}", fs.available_blocks()?); - - // Not only does this need "unsafe", but also the compiler catches - // the double-call of `file.close` (here, and in the closure teardown). - // - // File::create_and_then(&mut fs, "/tmp/zzz", |file| { - // unsafe { file.close() } - // }).unwrap(); - - #[cfg(feature = "dir-entry-path")] - fs.read_dir_and_then(b"/\0".try_into().unwrap(), |read_dir| { - for entry in read_dir { - let entry = entry?; - println!("{:?} --> path = {:?}", entry.file_name(), entry.path()); - } - Ok(()) - })?; - - fs.read_dir_and_then(b"/tmp\0".try_into().unwrap(), |read_dir| { - for entry in read_dir { - println!("entry: {:?}", entry?.file_name()); - } - Ok(()) - })?; - - fs.read_dir_and_then(b"/tmp/test\0".try_into().unwrap(), |read_dir| { - for entry in read_dir { - let entry = entry?; - println!("entry: {:?}", entry.file_name()); - #[cfg(feature = "dir-entry-path")] { - println!("path: {:?}", entry.path()); - - let mut attribute = Attribute::new(37); - if entry.file_type().is_dir() { - attribute.set_data(b"directory alarm"); - } else { - attribute.set_data(b"ceci n'est pas une pipe"); - // not 100% sure this is allowed, but if seems to work :) - fs.write(entry.path(), b"Alles neu macht n\xc3\xa4chstens der Mai")?; - } - fs.set_attribute(entry.path(), &attribute)?; - } - } - Ok(()) - })?; - - #[cfg(feature = "dir-entry-path")] - fs.read_dir_and_then(b"/tmp/test\0".try_into().unwrap(), |read_dir| { - for (i, entry) in read_dir.enumerate() { - let entry = entry?; - println!("\nfile {}: {:?}", i, entry.file_name()); - - if entry.file_type().is_file() { - let content: heapless::Vec:: = fs.read(entry.path())?; - println!("content:\n{:?}", core::str::from_utf8(&content).unwrap()); - // println!("and now the removal"); - // fs.remove(entry.path())?; - } - - if let Some(attribute) = fs.attribute(entry.path(), 37)? { - println!("attribute 37: {:?}", core::str::from_utf8(attribute.data()).unwrap()); - } - - // deleting (self) file while iterating! - if entry.file_type().is_file() { - println!("removing {:?}", entry.path()); - fs.remove(entry.path())?; - } - - // // WE CANNOT REMOVE THE NEXT FILE - // // can we `remove` the "next" file? - // if entry.file_name() == "b.txt"{ - // println!("deleting c.txt"); - // fs.remove(&PathBuf::from(b"/tmp/test/c.txt\0"))?; - // } - - // adding file while iterating! - if i == 1 { - println!("writing new file"); - fs.write(b"/tmp/test/out-of-nowhere.txt\0".try_into().unwrap(), &[])?; - } - - } - Ok(()) - })?; - - #[cfg(feature = "dir-entry-path")] { - println!("\nDELETION SPREE\n"); - // behaves veeryweirldy - // (...) - // entry = DirEntry { file_name: "test", metadata: Metadata { file_type: Dir, size: 0 }, path: "/tmp\u{0}/test" } - // (...) - // fs.remove_dir_all(&PathBuf::from(b"/tmp\0"))?; - // fs.remove_dir_all(&PathBuf::from(b"/tmp"))?; - fs.remove_dir_all(&PathBuf::from("/tmp"))?; - } - - Ok(()) - }).unwrap(); - - let mut alloc = Allocation::new(); - let fs = Filesystem::mount(&mut alloc, &mut test_storage).unwrap(); - // fs.write(b"/z.txt\0".try_into().unwrap(), &jackson5).unwrap(); - fs.write(&PathBuf::from("z.txt"), &jackson5).unwrap(); - } - - #[cfg(feature = "dir-entry-path")] - #[test] - fn remove_dir_all() { - let mut test_storage = TestStorage::new(); - let jackson5 = b"ABC 123"; - let jackson5 = &jackson5[..]; - - Filesystem::format(&mut test_storage).unwrap(); - Filesystem::mount_and_then(&mut test_storage, |fs| { - - fs.create_dir_all(b"/tmp/test\0".try_into().unwrap())?; - fs.write(b"/tmp/test/a.txt\0".try_into().unwrap(), jackson5)?; - fs.write(b"/tmp/test/b.txt\0".try_into().unwrap(), jackson5)?; - fs.write(b"/tmp/test/c.txt\0".try_into().unwrap(), jackson5)?; - - println!("\nDELETION SPREE\n"); - fs.remove_dir_all(b"/tmp\0".try_into().unwrap())?; - - Ok(()) - }).unwrap(); - } - - #[test] - fn path() { - let _path: &Path = b"a.txt\0".try_into().unwrap(); - } - - #[test] - fn open_file_with_options_and_then() { - let mut test_storage = TestStorage::new(); - Filesystem::format(&mut test_storage).unwrap(); - Filesystem::mount_and_then(&mut test_storage, |fs| { - let filename = b"append.to.me\0".try_into().unwrap(); - fs.write(filename, b"first part")?; - - fs.open_file_with_options_and_then( - |options| options.write(true).create(false).truncate(false), - filename, - |file| { - // this is a bit of a pitfall :) - file.seek(io::SeekFrom::End(0))?; - file.write(b" - ")?; - file.write(b"second part")?; - - Ok(()) - } - )?; - - let content: heapless::Vec<_, 256> = fs.read(filename)?; - assert_eq!(content, b"first part - second part"); - // println!("content: {:?}", core::str::from_utf8(&content).unwrap()); - Ok(()) - }).unwrap(); - } - - #[test] - fn nested() { - let mut test_storage = TestStorage::new(); - - Filesystem::format(&mut test_storage).unwrap(); - Filesystem::mount_and_then(&mut test_storage, |fs| { - - fs.write(b"a.txt\0".try_into().unwrap(), &[])?; - fs.write(b"b.txt\0".try_into().unwrap(), &[])?; - fs.write(b"c.txt\0".try_into().unwrap(), &[])?; - - fs.read_dir_and_then(b".\0".try_into().unwrap(), |read_dir| { - for entry in read_dir { - let entry = entry?; - println!("{:?}", entry.file_name()); - - // The `&mut ReadDir` is not actually available here - // Do we want a way to borrow_filesystem for DirEntry? - // One usecase is to read data from the files iterated over. - // - if entry.metadata.is_file() { - fs.write( - &entry.file_name(), - b"wowee zowie" - )?; - } - } - Ok(()) - })?; - - Ok(()) - }).unwrap(); - } - - - #[test] - fn issue_3_original_report() { - let mut test_storage = TestStorage::new(); - - Filesystem::format(&mut test_storage).unwrap(); - Filesystem::mount_and_then(&mut test_storage, |fs| { - - fs.write(b"a.txt\0".try_into().unwrap(), &[])?; - fs.write(b"b.txt\0".try_into().unwrap(), &[])?; - fs.write(b"c.txt\0".try_into().unwrap(), &[])?; - - // works fine - fs.read_dir_and_then(b".\0".try_into().unwrap(), |read_dir| { - for entry in read_dir { - let entry = entry?; - println!("{:?}", entry.file_type()); - } - Ok(()) - })?; - - - let mut a1 = File::allocate(); - let f1 = unsafe { File::open(&fs, &mut a1, b"a.txt\0".try_into().unwrap())? }; - f1.write(b"some text")?; - - let mut a2 = File::allocate(); - let f2 = unsafe { File::open(&fs, &mut a2, b"b.txt\0".try_into().unwrap())? }; - f2.write(b"more text")?; - - unsafe { f1.close()? }; // program hangs here - unsafe { f2.close()? }; // this statement is never reached - - Ok(()) - }).unwrap(); - } -} diff --git a/runners/lpc55/vendor/littlefs2/src/io.rs b/runners/lpc55/vendor/littlefs2/src/io.rs deleted file mode 100644 index a41333e2..00000000 --- a/runners/lpc55/vendor/littlefs2/src/io.rs +++ /dev/null @@ -1,172 +0,0 @@ -//! Traits and types for core I/O functionality. - -pub mod prelude; - -use littlefs2_sys as ll; - -/// The `Read` trait allows for reading bytes from a file. -pub trait Read { - /// Read at most buf.len() bytes. - /// Upon success, return how many bytes were read. - fn read(&self, buf: &mut [u8]) -> Result; - - fn read_exact(&self, buf: &mut [u8]) -> Result<()> { - // Same assumption as for `read_to_end`. - let len = self.read(buf)?; - if len == buf.len() { - Ok(()) - } else { - // TODO: Decide whether to add an equivalent of `ErrorKind::UnexpectedEof` - Err(Error::Io) - } - } - -} - -/** The `Write` trait allows for writing bytes to a file. - -By analogy with `std::io::Write`, we also define a `flush()` -method. In the current implementation, writes are final and -flush has no effect. -*/ -pub trait Write { - /// Write at most data.len() bytes. - /// The file will not necessarily be updated unless - /// flush is called as there is a cache. - /// Upon success, return how many bytes were written. - fn write(&self, data: &[u8]) -> Result; - - /// Write out all pending writes to storage. - fn flush(&self) -> Result<()>; - - fn write_all(&self, mut buf: &[u8]) -> Result<()> { - while !buf.is_empty() { - match self.write(buf) { - Ok(0) => { - // failed to write whole buffer - return Err(Error::Io) - } - Ok(n) => buf = &buf[n..], - Err(e) => return Err(e), - } - } - Ok(()) - } -} - -/** Enumeration of possible methods to seek within an I/O object. - -Use the [`Seek`](../io/trait.Seek.html) trait. -*/ -#[derive(Clone,Copy,Debug,Eq,PartialEq)] -pub enum SeekFrom { - Start(u32), - End(i32), - Current(i32), -} - -impl SeekFrom { - pub(crate) fn off(self) -> i32 { - match self { - SeekFrom::Start(u) => u as i32, - SeekFrom::End(i) => i, - SeekFrom::Current(i) => i, - } - } - - pub(crate) fn whence(self) -> i32 { - match self { - SeekFrom::Start(_) => 0, - SeekFrom::End(_) => 2, - SeekFrom::Current(_) => 1, - } - } -} - -/** The `Seek` trait provides a cursor which can be moved within a file. - -It is possible to seek relative to either end or the current offset. -*/ -pub trait Seek { - /// Seek to an offset in bytes. - /// If successful, returns the new position from start of file. - fn seek(&self, pos: SeekFrom) -> Result; -} - -pub type Result = core::result::Result; - -/// Definition of errors that might be returned by filesystem functionality. -#[derive(Clone,Copy,Debug,PartialEq)] -pub enum Error { - /// Error code was >=0, operation was successful. - Success, - /// Input / output error occurred. - Io, - /// File or filesystem was corrupt. - Corruption, - /// No entry found with that name. - NoSuchEntry, - /// File or directory already exists. - EntryAlreadyExisted, - /// Path name is not a directory. - PathNotDir, - /// Path specification is to a directory. - PathIsDir, - /// Directory was not empty. - DirNotEmpty, - /// Bad file descriptor. - BadFileDescriptor, - /// File is too big. - FileTooBig, - /// Incorrect value specified to function. - Invalid, - /// No space left available for operation. - NoSpace, - /// No memory available for completing request. - NoMemory, - /// No attribute or data available - NoAttribute, - /// Filename too long - FilenameTooLong, - /// Unknown error occurred, integer code specified. - Unknown(i32), -} - -impl From for Error { - fn from(_error: crate::path::Error) -> Self { - Error::Io - } -} - -impl From for Error { - fn from(error_code: i32) -> Error { - match error_code { - n if n >= 0 => Error::Success, - // negative codes - ll::lfs_error_LFS_ERR_IO => Error::Io, - ll::lfs_error_LFS_ERR_CORRUPT => Error::Corruption, - ll::lfs_error_LFS_ERR_NOENT => Error::NoSuchEntry, - ll::lfs_error_LFS_ERR_EXIST => Error::EntryAlreadyExisted, - ll::lfs_error_LFS_ERR_NOTDIR => Error::PathNotDir, - ll::lfs_error_LFS_ERR_ISDIR => Error::PathIsDir, - ll::lfs_error_LFS_ERR_NOTEMPTY => Error::DirNotEmpty, - ll::lfs_error_LFS_ERR_BADF => Error::BadFileDescriptor, - ll::lfs_error_LFS_ERR_FBIG => Error::FileTooBig, - ll::lfs_error_LFS_ERR_INVAL => Error::Invalid, - ll::lfs_error_LFS_ERR_NOSPC => Error::NoSpace, - ll::lfs_error_LFS_ERR_NOMEM => Error::NoMemory, - ll::lfs_error_LFS_ERR_NOATTR => Error::NoAttribute, - ll::lfs_error_LFS_ERR_NAMETOOLONG => Error::FilenameTooLong, - // positive codes should always indicate success - _ => Error::Unknown(error_code), - } - } -} - -pub fn result_from(return_value: T, error_code: ll::lfs_error) -> Result { - let error: Error = error_code.into(); - match error { - Error::Success => Ok(return_value), - _ => Err(error) - } -} diff --git a/runners/lpc55/vendor/littlefs2/src/io/prelude.rs b/runners/lpc55/vendor/littlefs2/src/io/prelude.rs deleted file mode 100644 index cdd4d0b5..00000000 --- a/runners/lpc55/vendor/littlefs2/src/io/prelude.rs +++ /dev/null @@ -1,8 +0,0 @@ -//! Export of the Read, Write and Seek traits for ease of use. - -pub use super::{ - Read, - Write, - Seek, - SeekFrom, -}; diff --git a/runners/lpc55/vendor/littlefs2/src/lib.rs b/runners/lpc55/vendor/littlefs2/src/lib.rs deleted file mode 100644 index 2c95ed87..00000000 --- a/runners/lpc55/vendor/littlefs2/src/lib.rs +++ /dev/null @@ -1,168 +0,0 @@ -#![cfg_attr(not(test), no_std)] -// Allow unused since we don't use the entirety of the functionality from this crate. -#![allow(unused)] -// Allow deprecated since this crate uses an old version of GenericArray. -#![allow(deprecated)] -/*! - -[littlefs](https://github.com/ARMmbed/littlefs) is a filesystem for microcontrollers -written in C, that claims to be *fail-safe*: -- power-loss resilience, by virtue of copy-on-write guarantees -- bounded RAM/ROM, with stack-allocated buffers - -Since [version 2](https://github.com/ARMmbed/littlefs/releases/tag/v2.0.0), it has -some nifty features such as: -- dynamic wear-leveling, including detection of bad Flash blocks -- custom user attributes -- inline files, avoiding block waste - -For more background, see its [design notes](https://github.com/ARMmbed/littlefs/blob/master/DESIGN.md) -and the [specification](https://github.com/ARMmbed/littlefs/blob/master/SPEC.md) of its format. - -### What is this? - -This library, [`littlefs2`](https://lib.rs/littlefs2), offers an idiomatic Rust API for littlefs. - -It follows the design of [`std::fs`](https://doc.rust-lang.org/std/fs/index.html) as much as reasonable, -and builds on the bindings [`littlefs2-sys`](https://lib.rs/littlefs2-sys). - -Some complications arise due to the lack of const generics in Rust, we work around these -with the [`generic-array`](https://lib.rs/generic-array) library, and long for the day when -constants associated to traits will be treated as constants by the compiler. - -Another complication is the fact that files (and directories) need to be closed before they go out of scope, -since the main littlefs state structure contains a linked list which would exhibit UB (undefined behaviour) -otherwise, see [issue #3](https://github.com/nickray/littlefs2/issues/3) and -[issue #5](https://github.com/nickray/littlefs2/issues/5). We choose *not* to call `close` in `drop` (as -`std::fs` does), since these operations could panic if for instance `littlefs` detects Flash corruption -(from which the application might otherwise recover). - -For this reason, the various `File`-related `open` methods are marked as `unsafe`. -Instead, a closure-based API is offered (`open_and_then` and friends), -the same is done for `Filesystem::read_dir`. Under the hood, this API first calls the unsafe constructor, -then calls the user-supplied closure, and finally closes the object. - -**FOLLOWING SECTION OUT-OF-DATE** - -⯈ [**The best place to start reading the API docs is here**](fs/index.html). ⯇ - -### Usage - -To use this library, implement `littlefs2::driver::Storage`. -The macro `ram_storage!` generates examples of this. - -Roughly speaking, the [`Storage`](driver/trait.Storage.html) trait defines a block device in -terms of actual and `typenum` constants, and an implementation supplies methods to read, erase and write. - -The filesystem and each open file need memory for state and caching, this has to be allocated -beforehand and passed to constructors. - -### `no_std` - -This library is `no_std` compatible, but there are two gotchas. - -- The dev-dependency `memchr` of `littlefs2-sys` has its `std` features activated. To prevent this, upgrade to at least Rust 1.51 - and add `resolver = "2"` in the consuming code's `[package]` section. This will be the default in Rust 2021 edition. - -- At link time, `lfs.c` has a dependency on `strcpy`. When not linking to a `libc` with this symbol, activate the `c-stubs` feature - to provide an implementation. - -### Design notes - -All operations on the filesystem require passing a `&mut Storage`, which guarantees by Rust's -borrow checker that only one thread can manipulate the filesystem. -This design choice (as opposed to consuming the Storage, which would be less verbose) was made to -enable use of the underlying flash peripheral outside of the filesystem (the `Storage` can be -dropped and reconstructed). For instance, one could setup an additional filesystem, -or handle some flash data manually. - -As an experiment, we implemented [`ReadDirWith`](fs/struct.ReadDirWith.html). It converts a -[`ReadDir`](fs/struct.ReadDir.html) (which needs mutable references, and so is "not quite an iterator" -over the files of a directory), into a true iterator, by temporarily binding the mutable references. - -Currying with lifetime gymnastics! - -In the future, we may extend this approach to other operations, thus adding a secondary API layer. - - - -Separately, keeping track of the allocations is a chore, we hope that -[`Pin`](https://doc.rust-lang.org/core/pin/index.html) magic will help fix this. - -### Example - -``` -# use littlefs2::fs::{Filesystem, File, OpenOptions}; -# use littlefs2::io::prelude::*; -# use littlefs2::path::PathBuf; -# -# use littlefs2::{consts, ram_storage, driver, io::Result}; -# -# -// example storage backend -ram_storage!(tiny); -let mut ram = Ram::default(); -let mut storage = RamStorage::new(&mut ram); - -// must format before first mount -Filesystem::format(&mut storage).unwrap(); -// must allocate state statically before use -let mut alloc = Filesystem::allocate(); -let mut fs = Filesystem::mount(&mut alloc, &mut storage).unwrap(); - -// may use common `OpenOptions` -let mut buf = [0u8; 11]; -fs.open_file_with_options_and_then( - |options| options.read(true).write(true).create(true), - &PathBuf::from(b"example.txt"), - |file| { - file.write(b"Why is black smoke coming out?!")?; - file.seek(SeekFrom::End(-24)).unwrap(); - assert_eq!(file.read(&mut buf)?, 11); - Ok(()) - } -).unwrap(); -assert_eq!(&buf, b"black smoke"); -``` -*/ - -/// Low-level bindings -pub use littlefs2_sys as ll; - -#[macro_use] -extern crate delog; -generate_macros!(); - -/// cf. Macros documentation -#[macro_use] -pub mod macros; - -#[cfg(feature = "c-stubs")] -mod c_stubs; - -pub mod consts; -pub mod driver; - -pub mod fs; -pub mod io; -pub mod path; - -/// get information about the C backend -pub fn version() -> Version { - Version { - format: (ll::LFS_DISK_VERSION_MAJOR, ll::LFS_DISK_VERSION_MINOR), - backend: (ll::LFS_VERSION_MAJOR, ll::LFS_VERSION_MINOR), - } -} - -/// Information about the C backend -#[derive(Clone,Copy,Debug)] -pub struct Version { - /// On-disk format (currently: 2.0) - pub format: (u32, u32), - /// Backend release (currently: 2.1) - pub backend: (u32, u32), -} - -#[cfg(test)] -mod tests; diff --git a/runners/lpc55/vendor/littlefs2/src/macros.rs b/runners/lpc55/vendor/littlefs2/src/macros.rs deleted file mode 100644 index 6d4fd6a5..00000000 --- a/runners/lpc55/vendor/littlefs2/src/macros.rs +++ /dev/null @@ -1,230 +0,0 @@ -// TODO: should add another backend that randomly returns less -// data than requested, to emphasize the difference between -// `io::Read::read` and `::read_exact`. -/// A configurable implementation of the Storage trait in memory. -#[macro_export] -macro_rules! ram_storage { ( - - name=$Name:ident, - backend=$Backend:ident, - trait=$StorageTrait:path, - erase_value=$erase_value:expr, - read_size=$read_size:expr, - write_size=$write_size:expr, - cache_size_ty=$cache_size:path, - block_size=$block_size:expr, - block_count=$block_count:expr, - lookaheadwords_size_ty=$lookaheadwords_size:path, - filename_max_plus_one_ty=$filename_max_plus_one:path, - path_max_plus_one_ty=$path_max_plus_one:path, - result=$Result:ident, - -) => { - pub struct $Backend { - buf: [u8; $block_size * $block_count], - } - - impl Default for $Backend { - fn default() -> Self { - $Backend { - buf: [$erase_value; $block_size * $block_count], - } - } - } - - pub struct $Name<'backend> { - backend: &'backend mut $Backend, - } - - impl<'backend> $Name<'backend> { - const ERASE_VALUE: u8 = $erase_value; - pub fn new(backend: &'backend mut $Backend) -> Self { - $Name { backend } - } - } - - impl<'backend> $StorageTrait for $Name<'backend> { - const READ_SIZE: usize = $read_size; - const WRITE_SIZE: usize = $write_size; - type CACHE_SIZE = $cache_size; - const BLOCK_SIZE: usize = $block_size; - const BLOCK_COUNT: usize = $block_count; - type LOOKAHEADWORDS_SIZE = $lookaheadwords_size; - - fn read(&self, offset: usize, buf: &mut [u8]) -> $Result { - let read_size: usize = Self::READ_SIZE; - debug_assert!(offset % read_size == 0); - debug_assert!(buf.len() % read_size == 0); - for (from, to) in self.backend.buf[offset..].iter().zip(buf.iter_mut()) { - *to = *from; - } - Ok(buf.len()) - } - - fn write(&mut self, offset: usize, data: &[u8]) -> $Result { - let write_size: usize = Self::WRITE_SIZE; - debug_assert!(offset % write_size == 0); - debug_assert!(data.len() % write_size == 0); - for (from, to) in data.iter().zip(self.backend.buf[offset..].iter_mut()) { - *to = *from; - } - Ok(data.len()) - } - - fn erase(&mut self, offset: usize, len: usize) -> $Result { - let block_size: usize = Self::BLOCK_SIZE; - debug_assert!(offset % block_size == 0); - debug_assert!(len % block_size == 0); - for byte in self.backend.buf[offset..offset + len].iter_mut() { - *byte = Self::ERASE_VALUE; - } - Ok(len) - } - } - }; - ($Name:ident, $Backend:ident, $bytes:expr) => { - ram_storage!( - name=$Name, - backend=$Backend, - trait=LfsStorage, - erase_value=0xff, - read_size=1, - write_size=1, - cache_size_ty=$crate::consts::U32, - block_size=128, - block_count=$bytes/128, - lookaheadwords_size_ty=$crate::consts::U1, - filename_max_plus_one_ty=$crate::consts::U256, - path_max_plus_one_ty=$crate::consts::U256, - result=LfsResult, - ); - }; - (tiny) => { - ram_storage!( - name=RamStorage, - backend=Ram, - trait=driver::Storage, - erase_value=0xff, - read_size=32, - write_size=32, - cache_size_ty=$crate::consts::U32, - block_size=128, - block_count=8, - lookaheadwords_size_ty=$crate::consts::U1, - filename_max_plus_one_ty=$crate::consts::U256, - path_max_plus_one_ty=$crate::consts::U256, - result=Result, - ); - }; - (large) => { - ram_storage!( - name=RamStorage, - backend=Ram, - trait=driver::Storage, - erase_value=0xff, - read_size=32, - write_size=32, - cache_size_ty=$crate::consts::U32, - block_size=256, - block_count=512, - lookaheadwords_size_ty=$crate::consts::U4, - filename_max_plus_one_ty=$crate::consts::U256, - path_max_plus_one_ty=$crate::consts::U256, - result=Result, - ); - }; -} - -#[macro_export] -macro_rules! const_ram_storage { ( - - name=$Name:ident, - trait=$StorageTrait:path, - erase_value=$erase_value:expr, - read_size=$read_size:expr, - write_size=$write_size:expr, - cache_size_ty=$cache_size:path, - block_size=$block_size:expr, - block_count=$block_count:expr, - lookaheadwords_size_ty=$lookaheadwords_size:path, - filename_max_plus_one_ty=$filename_max_plus_one:path, - path_max_plus_one_ty=$path_max_plus_one:path, - result=$Result:ident, - -) => { - pub struct $Name { - buf: [u8; $block_size * $block_count], - } - - impl $Name { - const ERASE_VALUE: u8 = $erase_value; - pub const fn new() -> Self { - // Self::default() - Self { buf: [$erase_value; $block_size * $block_count] } - } - } - - impl Default for $Name { - fn default() -> Self { - Self { - buf: [$erase_value; $block_size * $block_count], - } - } - } - - impl $StorageTrait for $Name { - const READ_SIZE: usize = $read_size; - const WRITE_SIZE: usize = $write_size; - type CACHE_SIZE = $cache_size; - const BLOCK_SIZE: usize = $block_size; - const BLOCK_COUNT: usize = $block_count; - type LOOKAHEADWORDS_SIZE = $lookaheadwords_size; - - fn read(&self, offset: usize, buf: &mut [u8]) -> $Result { - let read_size: usize = Self::READ_SIZE; - debug_assert!(offset % read_size == 0); - debug_assert!(buf.len() % read_size == 0); - for (from, to) in self.buf[offset..].iter().zip(buf.iter_mut()) { - *to = *from; - } - Ok(buf.len()) - } - - fn write(&mut self, offset: usize, data: &[u8]) -> $Result { - let write_size: usize = Self::WRITE_SIZE; - debug_assert!(offset % write_size == 0); - debug_assert!(data.len() % write_size == 0); - for (from, to) in data.iter().zip(self.buf[offset..].iter_mut()) { - *to = *from; - } - Ok(data.len()) - } - - fn erase(&mut self, offset: usize, len: usize) -> $Result { - let block_size: usize = Self::BLOCK_SIZE; - debug_assert!(offset % block_size == 0); - debug_assert!(len % block_size == 0); - for byte in self.buf[offset..offset + len].iter_mut() { - *byte = Self::ERASE_VALUE; - } - Ok(len) - } - } - }; - ($Name:ident, $bytes:expr) => { - const_ram_storage!( - name=$Name, - trait=LfsStorage, - erase_value=0xff, - read_size=16, - write_size=512, - cache_size_ty=$crate::consts::U512, - block_size=512, - block_count=$bytes/512, - lookaheadwords_size_ty=$crate::consts::U1, - filename_max_plus_one_ty=$crate::consts::U256, - path_max_plus_one_ty=$crate::consts::U256, - result=LfsResult, - ); - }; -} diff --git a/runners/lpc55/vendor/littlefs2/src/path.rs b/runners/lpc55/vendor/littlefs2/src/path.rs deleted file mode 100644 index 9f8a73a3..00000000 --- a/runners/lpc55/vendor/littlefs2/src/path.rs +++ /dev/null @@ -1,456 +0,0 @@ -//! Paths - -use core::{convert::TryFrom, fmt, marker::PhantomData, ops, ptr, slice, str}; - -use cstr_core::CStr; -use cty::{c_char, size_t}; - -use crate::consts; - -/// A path -/// -/// Paths must be null terminated ASCII strings -/// -/// This assumption is not needed for littlefs itself (it works like Linux and -/// accepts arbitrary C strings), but the assumption makes `AsRef` trivial -/// to implement. -pub struct Path { - inner: CStr, -} - -impl Path { - /// Creates a path from a byte buffer - /// - /// The buffer will be first interpreted as a `CStr` and then checked to be comprised only of - /// ASCII characters. - pub fn from_bytes_with_nul(bytes: &[u8]) -> Result<&Self> { - let cstr = CStr::from_bytes_with_nul(bytes).map_err(|_| Error::NotCStr)?; - Self::from_cstr(cstr) - } - - /// Unchecked version of `from_bytes_with_nul` - /// - /// # Safety - /// `bytes` must be null terminated string comprised of only ASCII characters - pub unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &Self { - &*(bytes as *const [u8] as *const Path) - } - - /// Creates a path from a C string - /// - /// The string will be checked to be comprised only of ASCII characters - // XXX should we reject empty paths (`""`) here? - pub fn from_cstr(cstr: &CStr) -> Result<&Self> { - let bytes = cstr.to_bytes(); - let n = cstr.to_bytes().len(); - if n > consts::PATH_MAX { - Err(Error::TooLarge) - } else if bytes.is_ascii() { - Ok(unsafe { Self::from_cstr_unchecked(cstr) }) - } else { - Err(Error::NotAscii) - } - } - - /// Unchecked version of `from_cstr` - /// - /// # Safety - /// `cstr` must be comprised only of ASCII characters - pub unsafe fn from_cstr_unchecked(cstr: &CStr) -> &Self { - &*(cstr as *const CStr as *const Path) - } - - /// Returns the inner pointer to this C string. - pub(crate) fn as_ptr(&self) -> *const c_char { - self.inner.as_ptr() - } - - /// Creates an owned `PathBuf` with `path` adjoined to `self`. - pub fn join(&self, path: &Path) -> PathBuf { - let mut p = PathBuf::from(self); - p.push(path); - p - } - - pub fn exists(&self, fs: &crate::fs::Filesystem) -> bool { - fs.metadata(self).is_ok() - } - - // helpful for debugging wither the trailing nul is indeed a trailing nul. - pub fn as_str_ref_with_trailing_nul(&self) -> &str { - unsafe { str::from_utf8_unchecked(self.inner.to_bytes_with_nul()) } - } - - pub fn parent(&self) -> Option { - let rk_path_bytes = self.as_ref()[..].as_bytes(); - match rk_path_bytes.iter().rposition(|x| *x == b'/') { - Some(slash_index) => { - // if we have a directory that ends with `/`, - // still need to "go up" one parent - if slash_index + 1 == rk_path_bytes.len() { - PathBuf::from(&rk_path_bytes[..slash_index]).parent() - } else { - Some(PathBuf::from(&rk_path_bytes[..slash_index])) - } - } - None => None, - } - } -} - -impl AsRef for Path { - fn as_ref(&self) -> &str { - // NOTE(unsafe) ASCII is valid UTF-8 - unsafe { str::from_utf8_unchecked(self.inner.to_bytes()) } - } -} - -impl fmt::Debug for Path { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - // helpful for debugging wither the trailing nul is indeed a trailing nul. - write!(f, "p{:?}", self.as_str_ref_with_trailing_nul()) - } -} - -impl fmt::Display for Path { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(self.as_ref()) - } -} - -impl<'b> TryFrom<&'b [u8]> for &'b Path { - type Error = Error; - - fn try_from(bytes: &[u8]) -> Result<&Path> { - Path::from_bytes_with_nul(bytes) - } -} - -impl PartialEq for Path { - fn eq(&self, rhs: &str) -> bool { - self.as_ref() == rhs - } -} - -// without this you need to slice byte string literals (`b"foo\0"[..].try_into()`) -macro_rules! array_impls { - ($($N:expr),+) => { - $( - impl<'b> TryFrom<&'b [u8; $N]> for &'b Path { - type Error = Error; - - fn try_from(bytes: &[u8; $N]) -> Result<&Path> { - Path::from_bytes_with_nul(&bytes[..]) - } - } - - impl From<&[u8; $N]> for PathBuf { - fn from(bytes: &[u8; $N]) -> Self { - Self::from(&bytes[..]) - } - } - - impl PartialEq<[u8; $N]> for Path { - fn eq(&self, rhs: &[u8; $N]) -> bool { - self.as_ref().as_bytes() == &rhs[..] - } - } - - )+ - } -} - -array_impls!( - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, - 28, 29, 30, 31, 32 -); - -/// An owned, mutable path -#[derive(Clone)] -pub struct PathBuf { - buf: [c_char; consts::PATH_MAX_PLUS_ONE], - // NOTE `len` DOES include the final null byte - len: usize, -} - -/// # Safety -/// `s` must point to valid memory; `s` will be treated as a null terminated string -unsafe fn strlen(mut s: *const c_char) -> size_t { - let mut n = 0; - while *s != 0 { - s = s.add(1); - n += 1; - } - n -} - -impl PathBuf { - pub fn new() -> Self { - Self { buf: [0; consts::PATH_MAX_PLUS_ONE], len: 1 } - } - - pub fn clear(&mut self) { - self.buf = [0; consts::PATH_MAX_PLUS_ONE]; - self.len = 1; - } - - pub(crate) unsafe fn from_buffer(buf: [c_char; consts::PATH_MAX_PLUS_ONE]) -> Self { - let len = strlen(buf.as_ptr()) + 1 /* null byte */; - PathBuf { buf, len } - } - - /// Extends `self` with `path` - pub fn push(&mut self, path: &Path) { - match path.as_ref() { - // no-operation - "" => return, - - // `self` becomes `/` (root), to match `std::Path` implementation - // NOTE(allow) cast is necessary on some architectures (e.g. x86) - #[allow(clippy::unnecessary_cast)] - "/" => { - self.buf[0] = b'/' as c_char; - self.buf[1] = 0; - self.len = 2; - return; - } - _ => {} - } - - let src = path.as_ref().as_bytes(); - let needs_separator = self - .as_ref() - .as_bytes() - .last() - .map(|byte| *byte != b'/') - .unwrap_or(false); - let slen = src.len(); - #[cfg(test)] - println!("{}, {}, {}", self.len, slen, consts::PATH_MAX_PLUS_ONE); - // hprintln!("{}, {}, {}", self.len, slen, consts::PATH_MAX_PLUS_ONE); - assert!( - self.len - + slen - + if needs_separator { - // b'/' - 1 - } else { - 0 - } - <= consts::PATH_MAX_PLUS_ONE - ); - - let len = self.len; - unsafe { - let mut p = self.buf.as_mut_ptr().cast::().add(len - 1); - if needs_separator { - p.write(b'/'); - p = p.add(1); - self.len += 1; - } - ptr::copy_nonoverlapping(src.as_ptr(), p, slen); - p.add(slen).write(0); // null byte - self.len += slen; - } - } -} - -impl From<&Path> for PathBuf { - fn from(path: &Path) -> Self { - let bytes = path.as_ref().as_bytes(); - - let mut buf = [0; consts::PATH_MAX_PLUS_ONE]; - let len = bytes.len(); - assert!(len <= consts::PATH_MAX); - unsafe { ptr::copy_nonoverlapping(bytes.as_ptr(), buf.as_mut_ptr().cast(), len + 1) } - Self { - buf, - len: len + 1, - } - } -} - -impl From<&[u8]> for PathBuf { - /// Accepts byte string, with or without trailing nul. - /// - /// PANICS: when there are embedded nuls - fn from(bytes: &[u8]) -> Self { - // NB: This needs to set the final NUL byte, unless it already has one - // It also checks that there are no inner NUL bytes - let bytes = if !bytes.is_empty() && bytes[bytes.len() - 1] == b'\0' { - &bytes[..bytes.len() - 1] - } else { - bytes - }; - let has_no_embedded_nul = bytes.iter().find(|&&byte| byte == b'\0').is_none(); - assert!(has_no_embedded_nul); - - let mut buf = [0; consts::PATH_MAX_PLUS_ONE]; - let len = bytes.len(); - assert!(len <= consts::PATH_MAX); - assert!(bytes.is_ascii()); - unsafe { ptr::copy_nonoverlapping(bytes.as_ptr(), buf.as_mut_ptr().cast(), len) } - Self { - buf, - len: len + 1, - } - } -} - -impl From<&str> for PathBuf { - fn from(s: &str) -> Self { - PathBuf::from(s.as_bytes()) - } -} - -impl ops::Deref for PathBuf { - type Target = Path; - - fn deref(&self) -> &Path { - unsafe { - Path::from_bytes_with_nul_unchecked(slice::from_raw_parts( - self.buf.as_ptr().cast(), - self.len, - )) - } - } -} - - -impl serde::Serialize for PathBuf { - fn serialize(&self, serializer: S) -> core::result::Result - where - S: serde::Serializer, - { - serializer.serialize_bytes(self.as_ref().as_bytes()) - } -} - -impl<'de> serde::Deserialize<'de> for PathBuf -{ - fn deserialize(deserializer: D) -> core::result::Result - where - D: serde::Deserializer<'de>, - { - struct ValueVisitor<'de>(PhantomData<&'de ()>); - - impl<'de> serde::de::Visitor<'de> for ValueVisitor<'de> - { - type Value = PathBuf; - - fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - formatter.write_str("a path buffer") - } - - fn visit_bytes(self, v: &[u8]) -> core::result::Result - where - E: serde::de::Error, - { - if v.len() > consts::PATH_MAX { - return Err(E::invalid_length(v.len(), &self)); - } - Ok(PathBuf::from(v)) - } - } - - deserializer.deserialize_bytes(ValueVisitor(PhantomData)) - } -} - -impl fmt::Debug for PathBuf { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - ::fmt(self, f) - } -} - -impl fmt::Display for PathBuf { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - ::fmt(self, f) - } -} - -impl core::cmp::PartialEq for PathBuf { - fn eq(&self, other: &Self) -> bool { - // from cstr_core - self.as_ref() == other.as_ref() - - // // use cortex_m_semihosting::hprintln; - // // hprintln!("inside PathBuf PartialEq"); - // // hprintln!("self.len {}, other.len {}", self.len, other.len).ok(); - // // hprintln!("self..len {:?}, other..len {:?}", &self.buf[..self.len], &other.buf[..other.len]).ok(); - // self.len == other.len && self.buf[..self.len - 1] == other.buf[..other.len - 1] - } -} - -impl core::cmp::Eq for PathBuf {} - -// use core::cmp::Ordering; - -// impl Ord for PathBuf { -// fn cmp(&self, other: &Self) -> Ordering { -// self.len.cmp(&other.len) -// } -// } - -// impl PartialOrd for PathBuf { -// fn partial_cmp(&self, other: &Self) -> Option { -// Some(self.cmp(other)) -// } -// } - -/// Errors that arise from converting byte buffers into paths -#[derive(Clone, Copy, Debug)] -pub enum Error { - /// Byte buffer contains non-ASCII characters - NotAscii, - /// Byte buffer is not a C string - NotCStr, - /// Byte buffer is too long (longer than `consts::PATH_MAX_PLUS_ONE`) - TooLarge, -} - -/// Result type that has its Error variant set to `path::Error` -pub type Result = core::result::Result; - -#[cfg(test)] -mod tests { - use super::{Path, PathBuf}; - - #[test] - fn join() { - let empty = Path::from_bytes_with_nul(b"\0").unwrap(); - let slash = Path::from_bytes_with_nul(b"/\0").unwrap(); - let a = Path::from_bytes_with_nul(b"a\0").unwrap(); - let b = Path::from_bytes_with_nul(b"b\0").unwrap(); - - assert_eq!(empty.join(empty).as_ref(), ""); - assert_eq!(empty.join(slash).as_ref(), "/"); - assert_eq!(empty.join(a).as_ref(), "a"); - assert_eq!(empty.join(b).as_ref(), "b"); - - assert_eq!(slash.join(empty).as_ref(), "/"); - assert_eq!(slash.join(slash).as_ref(), "/"); - assert_eq!(slash.join(a).as_ref(), "/a"); - assert_eq!(slash.join(b).as_ref(), "/b"); - - assert_eq!(a.join(empty).as_ref(), "a"); - assert_eq!(a.join(slash).as_ref(), "/"); - assert_eq!(a.join(a).as_ref(), "a/a"); - assert_eq!(a.join(b).as_ref(), "a/b"); - - assert_eq!(b.join(empty).as_ref(), "b"); - assert_eq!(b.join(slash).as_ref(), "/"); - assert_eq!(b.join(a).as_ref(), "b/a"); - assert_eq!(b.join(b).as_ref(), "b/b"); - } - - #[test] - fn nulls() { - assert!(Path::from_bytes_with_nul(b"abc\0def").is_err()); - } - - #[test] - fn trailing_nuls() { - assert_eq!(PathBuf::from("abc"), PathBuf::from("abc\0")); - } -} diff --git a/runners/lpc55/vendor/littlefs2/src/tests.rs b/runners/lpc55/vendor/littlefs2/src/tests.rs deleted file mode 100644 index 8dae2864..00000000 --- a/runners/lpc55/vendor/littlefs2/src/tests.rs +++ /dev/null @@ -1,452 +0,0 @@ -use core::convert::TryInto; -use generic_array::typenum::consts; - -use crate::{ - fs::{ - Attribute, - File, - Filesystem, - }, - io::{ - Error, - Result, - Read, - SeekFrom, - }, - driver, -}; - -ram_storage!( - name=OtherRamStorage, - backend=OtherRam, - trait=driver::Storage, - erase_value=0xff, - read_size=1, - write_size=32, - cache_size_ty=consts::U32, - block_size=256, - block_count=512, - lookaheadwords_size_ty=consts::U1, - filename_max_plus_one_ty=consts::U256, - path_max_plus_one_ty=consts::U256, - result=Result, -); - -ram_storage!( - name=RamStorage, - backend=Ram, - trait=driver::Storage, - erase_value=0xff, - read_size=20*5, - write_size=20*7, - cache_size_ty=consts::U700, - block_size=20*35, - block_count=32, - lookaheadwords_size_ty=consts::U16, - filename_max_plus_one_ty=consts::U256, - path_max_plus_one_ty=consts::U256, - result=Result, -); - -#[test] -fn version() { - assert_eq!(crate::version().format, (2, 0)); - assert_eq!(crate::version().backend, (2, 2)); -} - -#[test] -fn format() { - let mut backend = OtherRam::default(); - let mut storage = OtherRamStorage::new(&mut backend); - let mut alloc = Filesystem::allocate(); - - // should fail: FS is not formatted - assert_eq!( - Filesystem::mount(&mut alloc, &mut storage) - .map(drop).unwrap_err(), - Error::Corruption - ); - // should succeed - assert!(Filesystem::format(&mut storage).is_ok()); - // should succeed now that storage is formatted - let fs = Filesystem::mount(&mut alloc, &mut storage).unwrap(); - // check there are no segfaults - drop(fs); - drop(storage); -} - -// #[macro_use] -// macro_rules! setup_fs { -// () => { -// let mut backend = OtherRam::default(); -// let mut storage = OtherRamStorage::new(&mut backend); -// let mut alloc_fs = Filesystem::allocate(); -// Filesystem::format(&mut alloc_fs, &mut storage).unwrap(); -// let mut fs = Filesystem::mount(&mut alloc_fs, &mut storage).unwrap(); -// } -// } - -#[test] -fn borrow_fs_allocation() { - let mut backend = OtherRam::default(); - - let mut storage = OtherRamStorage::new(&mut backend); - let mut alloc_fs = Filesystem::allocate(); - Filesystem::format(&mut storage).unwrap(); - let _fs = Filesystem::mount(&mut alloc_fs, &mut storage).unwrap(); - // previous `_fs` is fine as it's masked, due to NLL - let fs = Filesystem::mount(&mut alloc_fs, &mut storage).unwrap(); - - fs.create_file_and_then(b"data.bin\0".try_into().unwrap(), |_| { Ok(()) }).unwrap(); - fs.create_file_and_then(b"data.bin\0".try_into().unwrap(), |_| { Ok(()) }).unwrap(); -} - -#[test] -fn borrow_fs_allocation2() { - let mut backend = OtherRam::default(); - - let mut storage = OtherRamStorage::new(&mut backend); - let mut alloc_fs = Filesystem::allocate(); - Filesystem::format(&mut storage).unwrap(); - let _fs = Filesystem::mount(&mut alloc_fs, &mut storage).unwrap(); - // previous `_fs` is fine as it's masked, due to NLL - - Filesystem::mount_and_then(&mut storage, |fs| { - fs.create_file_and_then(b"data.bin\0".try_into().unwrap(), |_| { Ok(()) }).unwrap(); - fs.create_file_and_then(b"data.bin\0".try_into().unwrap(), |_| { Ok(()) }).unwrap(); - // where is boats when you need him lol - Ok(()) - }).unwrap(); -} - -#[test] -fn borrow_fs_allocation3() { - let mut backend = OtherRam::default(); - let mut storage = OtherRamStorage::new(&mut backend); - - Filesystem::format(&mut storage).unwrap(); - Filesystem::mount_and_then(&mut storage, |_| { - Ok(()) - }).unwrap(); - - Filesystem::mount_and_then(&mut storage, |fs| { - fs.create_file_and_then(b"data.bin\0".try_into().unwrap(), |_| { Ok(()) }).unwrap(); - fs.create_file_and_then(b"data.bin\0".try_into().unwrap(), |_| { Ok(()) }).unwrap(); - // where is boats when you need him lol - Ok(()) - }).unwrap(); -} - -#[test] -fn test_fs_with() -> Result<()> { - let mut backend = OtherRam::default(); - let mut storage = OtherRamStorage::new(&mut backend); - - Filesystem::format(&mut storage).unwrap(); - Filesystem::mount_and_then(&mut storage, |fs| { - - assert_eq!(fs.total_blocks(), 512); - assert_eq!(fs.total_space(), 256*512); - // superblock - assert_eq!(fs.available_blocks()?, 512 - 2); - assert_eq!(fs.available_space()?, 130_560); - - fs.create_dir(b"/tmp\0".try_into().unwrap())?; assert_eq!(fs.available_blocks()?, 512 - 4); - fs.create_dir(b"/mnt\0".try_into().unwrap())?; assert_eq!(fs.available_blocks()?, 512 - 6); - fs.rename( - b"tmp\0".try_into().unwrap(), - b"mnt/tmp\0".try_into().unwrap())?; assert_eq!(fs.available_blocks()?, 512 - 6); - fs.remove(b"/mnt/tmp\0".try_into().unwrap())?; assert_eq!(fs.available_blocks()?, 512 - 4); - fs.remove(b"/mnt\0".try_into().unwrap())?; assert_eq!(fs.available_blocks()?, 512 - 2); - - fs.create_file_and_then(b"/test_with.txt\0".try_into().unwrap(), |file| { - assert!(file.write(&[0u8, 1, 2])? == 3); - Ok(()) - }).unwrap(); - - let mut buf = [0u8; 3]; - fs.open_file_and_then(b"/test_with.txt\0".try_into().unwrap(), |file| { - assert_eq!(fs.available_blocks()?, 510); - assert!(file.read_exact(&mut buf).is_ok()); - assert_eq!(&buf, &[0, 1, 2]); - Ok(()) - }).unwrap(); - - // surprise surprise, inline files! - assert_eq!(fs.available_blocks()?, 512 - 2); - - Ok(()) - }) -} - -#[test] -fn test_create() { - let mut backend = OtherRam::default(); - let mut storage = OtherRamStorage::new(&mut backend); - - Filesystem::format(&mut storage).unwrap(); - Filesystem::mount_and_then(&mut storage, |fs| { - assert_eq!(fs.total_blocks(), 512); - assert_eq!(fs.total_space(), 256*512); - // superblock - assert_eq!(fs.available_blocks().unwrap(), 512 - 2); - assert_eq!(fs.available_space().unwrap(), 130_560); - - assert!(!crate::path::PathBuf::from(b"/test_open.txt").exists(&fs)); - assert_eq!( - File::open_and_then(fs, b"/test_open.txt\0".try_into().unwrap(), |_| { Ok(()) }) - .map(drop) - .unwrap_err(), // "real" contains_err is experimental - Error::NoSuchEntry - ); - assert!(!crate::path::PathBuf::from(b"/test_open.txt").exists(&fs)); - - fs.create_dir(b"/tmp\0".try_into().unwrap()).unwrap(); - assert_eq!(fs.available_blocks().unwrap(), 512 - 2 - 2); - - // can create new files - assert!(!crate::path::PathBuf::from(b"/tmp/test_open.txt").exists(&fs)); - fs.create_file_and_then(b"/tmp/test_open.txt\0".try_into().unwrap(), |file| { - - // can write to files - assert!(file.write(&[0u8, 1, 2]).unwrap() == 3); - file.sync()?; - // surprise surprise, inline files! - assert_eq!(fs.available_blocks()?, 512 - 2 - 2); - // no longer exists! - // file.close()?; - Ok(()) - })?; - assert!(crate::path::PathBuf::from(b"/tmp/test_open.txt").exists(&fs)); - - // // cannot remove non-empty directories - assert_eq!(fs.remove(b"/tmp\0".try_into().unwrap()).unwrap_err(), Error::DirNotEmpty); - - let metadata = fs.metadata(b"/tmp\0".try_into().unwrap())?; - assert!(metadata.is_dir()); - assert_eq!(metadata.len(), 0); - - // can move files - fs.rename(b"/tmp/test_open.txt\0".try_into().unwrap(), b"moved.txt\0".try_into().unwrap())?; - assert_eq!(fs.available_blocks().unwrap(), 512 - 2 - 2); - - let metadata = fs.metadata(b"/moved.txt\0".try_into().unwrap())?; - assert!(metadata.is_file()); - assert_eq!(metadata.len(), 3); - - fs.remove(b"/tmp/../tmp/.\0".try_into().unwrap()).unwrap(); - assert_eq!(fs.available_blocks().unwrap(), 512 - 2); - - fs.open_file_and_then(b"/moved.txt\0".try_into().unwrap(), |file| { - assert!(file.len().unwrap() == 3); - let mut contents: [u8; 3] = Default::default(); - assert!(file.read(&mut contents).unwrap() == 3); - assert_eq!(contents, [0u8, 1, 2]); - - // alternative approach - file.seek(SeekFrom::Start(0))?; - let mut contents_vec = heapless::Vec::::new(); - assert!(file.read_to_end(&mut contents_vec).unwrap() == 3); - Ok(()) - })?; - - Ok(()) - - }).unwrap(); -} - -#[test] -fn test_unbind() { - let mut backend = Ram::default(); - - { - let mut storage = RamStorage::new(&mut backend); - Filesystem::format(&mut storage).unwrap(); - Filesystem::mount_and_then(&mut storage, |fs| { - fs.create_file_and_then(b"test_unbind.txt\0".try_into().unwrap(), |file| { - file.write(b"hello world")?; - assert_eq!(file.len()?, 11); - Ok(()) - }) - }).unwrap(); - } - - let mut storage = RamStorage::new(&mut backend); - Filesystem::mount_and_then(&mut storage, |fs| { - let contents: heapless::Vec<_, 37> = fs.read(b"test_unbind.txt\0".try_into().unwrap())?; - assert_eq!(contents, b"hello world"); - Ok(()) - }).unwrap(); -} - -#[test] -fn test_seek() { - let mut backend = OtherRam::default(); - let mut storage = OtherRamStorage::new(&mut backend); - - Filesystem::format(&mut storage).unwrap(); - Filesystem::mount_and_then(&mut storage, |fs| { - fs.write(b"test_seek.txt\0".try_into().unwrap(), b"hello world")?; - fs.open_file_and_then(b"test_seek.txt\0".try_into().unwrap(), |file| { - file.seek(SeekFrom::End(-5))?; - let mut buf = [0u8; 5]; - assert_eq!(file.len()?, 11); - file.read(&mut buf)?; - assert_eq!(&buf, b"world"); - Ok(()) - }) - }).unwrap(); -} - -#[test] -fn test_file_set_len() { - let mut backend = OtherRam::default(); - let mut storage = OtherRamStorage::new(&mut backend); - - Filesystem::format(&mut storage).unwrap(); - Filesystem::mount_and_then(&mut storage, |fs| { - fs.create_file_and_then(b"test_set_len.txt\0".try_into().unwrap(), |file| { - file.write(b"hello littlefs")?; - assert_eq!(file.len()?, 14); - - file.set_len(10).unwrap(); - assert_eq!(file.len()?, 10); - - // note that: - // a) "tell" can be implemented as follows, - // b) truncating a file does not change the cursor position - assert_eq!(file.seek(SeekFrom::Current(0))?, 14); - Ok(()) - }) - }).unwrap(); -} - -#[test] -fn test_fancy_open() { - let mut backend = Ram::default(); - let mut storage = RamStorage::new(&mut backend); - - Filesystem::format(&mut storage).unwrap(); - - let mut buf = [0u8; 5]; - - Filesystem::mount_and_then(&mut storage, |fs| { - fs.open_file_with_options_and_then( - |options| options.read(true).write(true).create_new(true), - b"test_fancy_open.txt\0".try_into().unwrap(), - |file| { - file.write(b"hello world")?; - assert_eq!(file.len()?, 11); - file.seek(SeekFrom::Start(6))?; - - file.read(&mut buf) - } - ) - }).unwrap(); - - assert_eq!(&buf, b"world"); -} - -#[test] -fn attributes() { - let mut backend = Ram::default(); - let mut storage = RamStorage::new(&mut backend); - Filesystem::format(&mut storage).unwrap(); - Filesystem::mount_and_then(&mut storage, |fs| { - - let filename = b"some.file\0".try_into().unwrap(); - fs.write(filename, &[])?; - assert!(fs.attribute(filename, 37)?.is_none()); - - let mut attribute = Attribute::new(37); - attribute.set_data(b"top secret"); - - fs.set_attribute(filename, &attribute).unwrap(); - assert_eq!( - b"top secret", - fs.attribute(filename, 37)?.unwrap().data() - ); - - // // not sure if we should have this method (may be quite expensive) - // let attributes = unsafe { fs.attributes("some.file", &mut storage).unwrap() }; - // assert!(attributes[37]); - // assert_eq!(attributes.iter().fold(0, |sum, i| sum + (*i as u8)), 1); - - fs.remove_attribute(filename, 37)?; - assert!(fs.attribute(filename, 37)?.is_none()); - - // // Directories can have attributes too - let tmp_dir = b"/tmp\0".try_into().unwrap(); - fs.create_dir(tmp_dir)?; - - attribute.set_data(b"temporary directory"); - fs.set_attribute(tmp_dir, &attribute)?; - - assert_eq!( - b"temporary directory", - fs.attribute(tmp_dir, 37)?.unwrap().data() - ); - - fs.remove_attribute(tmp_dir, 37)?; - assert!(fs.attribute(tmp_dir, 37)?.is_none()); - - Ok(()) - - }).unwrap(); -} - -#[test] -fn test_iter_dirs() { - let mut backend = Ram::default(); - let mut storage = RamStorage::new(&mut backend); - Filesystem::format(&mut storage).unwrap(); - Filesystem::mount_and_then(&mut storage, |fs| { - - fs.create_dir(b"/tmp\0".try_into()?)?; - - // TODO: we might want "multi-open" - fs.create_file_and_then(b"/tmp/file.a\0".try_into()?, |file| { - file.set_len(37)?; - fs.create_file_and_then(b"/tmp/file.b\0".try_into()?, |file| { - file.set_len(42) - }) - })?; - - fs.read_dir_and_then(b"/tmp\0".try_into()?, |dir| { - let mut found_files: usize = 0; - let mut sizes = [0usize; 4]; - - for (i, entry) in dir.enumerate() { - let entry = entry?; - - // assert_eq!(entry.file_name(), match i { - // 0 => b".\0", - // 1 => b"..\0", - // 2 => b"file.a\0", - // 3 => b"file.b\0", - // _ => panic!("oh noes"), - // }); - - sizes[i] = entry.metadata().len(); - found_files += 1; - } - - assert_eq!(sizes, [0, 0, 37, 42]); - assert_eq!(found_files, 4); - - Ok(()) - }) - }).unwrap(); -} - -// // These are some tests that ensure our type constructions -// // actually do what we intend them to do. -// // Since dev-features cannot be optional, trybuild is not `no_std`, -// // and we want to actually test `no_std`... -// #[test] -// #[cfg(feature = "ui-tests")] -// fn test_api_safety() { -// let t = trybuild::TestCases::new(); -// t.compile_fail("tests/ui/*-fail.rs"); -// t.pass("tests/ui/*-pass.rs"); -// } diff --git a/runners/lpc55/vendor/littlefs2/tests/test_serde.rs b/runners/lpc55/vendor/littlefs2/tests/test_serde.rs deleted file mode 100644 index da72d228..00000000 --- a/runners/lpc55/vendor/littlefs2/tests/test_serde.rs +++ /dev/null @@ -1,53 +0,0 @@ -use littlefs2::{ - consts, - driver, - fs::Filesystem, - io::Result, - path::Path, - ram_storage, -}; - -use serde::{Deserialize,Serialize}; -use ssmarshal::{deserialize, serialize}; - -#[derive(Serialize, Deserialize, PartialEq, Debug, Default/*, Desse, DesseSized*/)] -struct Entity { - z: [u8; 16], - // x: u32, - x: f32, - y: u64, -} - -ram_storage!(tiny); - -#[test] -fn main() { - let mut ram = Ram::default(); - let mut storage = RamStorage::new(&mut ram); - Filesystem::format(&mut storage).unwrap(); - - let mut alloc = Filesystem::allocate(); - let fs = Filesystem::mount(&mut alloc, &mut storage).unwrap(); - - let entity = Entity::default(); - - let mut buf = [0u8; core::mem::size_of::()]; - assert_eq!(buf.len(), 32); - let size = serialize(&mut buf, &entity).unwrap(); - assert_eq!(size, 28); - - fs.write(Path::from_bytes_with_nul(b"entity.bin\0").unwrap(), &buf[..size]).unwrap(); - fs.open_file_and_then(Path::from_bytes_with_nul(b"entity.bin\0").unwrap(), |file| { - file.read(&mut buf) - }).unwrap(); - // let mut alloc = File::allocate(); - // let mut file = File::create("entity.bin", &mut alloc, &mut fs, &mut storage).unwrap(); - // file.write(&mut fs, &mut storage, &buf[..size]).unwrap(); - // file.sync(&mut fs, &mut storage).unwrap(); - - // let mut file = File::open("entity.bin", &mut alloc, &mut fs, &mut storage).unwrap(); - // file.read(&mut fs, &mut storage, &mut buf).unwrap(); - let read_entity: Entity = deserialize(&buf).unwrap().0; - - assert_eq!(read_entity, entity); -} diff --git a/runners/lpc55/vendor/littlefs2/tests/ui/constructors-fail.rs b/runners/lpc55/vendor/littlefs2/tests/ui/constructors-fail.rs deleted file mode 100644 index b44b5ff3..00000000 --- a/runners/lpc55/vendor/littlefs2/tests/ui/constructors-fail.rs +++ /dev/null @@ -1,65 +0,0 @@ -use littlefs2::{ - consts, - fs::{File, Filesystem}, - io::{Error, Result}, - ram_storage, driver, -}; - -ram_storage!( - name=OtherRamStorage, - backend=OtherRam, - trait=driver::Storage, - erase_value=0xff, - read_size=1, - write_size=32, - cache_size_ty=consts::U32, - block_size=256, - block_count=512, - lookaheadwords_size_ty=consts::U1, - filename_max_plus_one_ty=consts::U256, - path_max_plus_one_ty=consts::U256, - result=Result, -); - -ram_storage!( - name=RamStorage, - backend=Ram, - trait=driver::Storage, - erase_value=0xff, - read_size=20*5, - write_size=20*7, - cache_size_ty=consts::U700, - block_size=20*35, - block_count=32, - lookaheadwords_size_ty=consts::U1, - filename_max_plus_one_ty=consts::U256, - path_max_plus_one_ty=consts::U256, - result=Result, -); - -fn main() { - let mut other_ram = OtherRam::default(); - let mut other_storage = OtherRamStorage::new(&mut other_ram); - let mut alloc = Filesystem::allocate(); - assert!(Filesystem::format(&mut other_storage).is_ok()); - let other_fs = Filesystem::mount(&mut alloc, &mut other_storage).unwrap(); - - let mut ram = Ram::default(); - let mut storage = RamStorage::new(&mut ram); - let mut alloc = Filesystem::allocate(); - Filesystem::format(&mut storage).unwrap(); - let mut fs = Filesystem::mount(&mut alloc, &mut storage).unwrap(); - - let mut alloc = File::allocate(); - // file does not exist yet, can't open for reading - assert_eq!( - File::open("/test_open.txt", &mut alloc, &mut fs, &mut storage) - .map(drop) - .unwrap_err(), // "real" contains_err is experimental - Error::NoSuchEntry - ); - - // won't work: "expected struct `tests::RamStorage`, found struct - // `tests::RamStorageNormal`. - fs.create_dir("/tmp", &mut other_storage).unwrap(); -} diff --git a/runners/lpc55/vendor/littlefs2/tests/ui/constructors-fail.stderr b/runners/lpc55/vendor/littlefs2/tests/ui/constructors-fail.stderr deleted file mode 100644 index ddbddb1e..00000000 --- a/runners/lpc55/vendor/littlefs2/tests/ui/constructors-fail.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error[E0308]: mismatched types - --> $DIR/constructors-fail.rs:64:27 - | -64 | fs.create_dir("/tmp", &mut other_storage).unwrap(); - | ^^^^^^^^^^^^^^^^^^ expected struct `RamStorage`, found struct `OtherRamStorage` - | - = note: expected type `&mut RamStorage<'_>` - found type `&mut OtherRamStorage<'_>` diff --git a/runners/lpc55/vendor/littlefs2/tests/ui/sync-fail.rs b/runners/lpc55/vendor/littlefs2/tests/ui/sync-fail.rs deleted file mode 100644 index cc1a0131..00000000 --- a/runners/lpc55/vendor/littlefs2/tests/ui/sync-fail.rs +++ /dev/null @@ -1,72 +0,0 @@ -use littlefs2::{ - consts, - fs::{File, Filesystem}, - io::{Error, Result, Write}, - ram_storage, driver, -}; - -ram_storage!( - name=OtherRamStorage, - backend=OtherRam, - trait=driver::Storage, - erase_value=0xff, - read_size=1, - write_size=32, - cache_size_ty=consts::U32, - block_size=256, - block_count=512, - lookaheadwords_size_ty=consts::U1, - filename_max_plus_one_ty=consts::U256, - path_max_plus_one_ty=consts::U256, - result=Result, -); - -ram_storage!( - name=RamStorage, - backend=Ram, - trait=driver::Storage, - erase_value=0xff, - read_size=20*5, - write_size=20*7, - cache_size_ty=consts::U700, - block_size=20*35, - block_count=32, - lookaheadwords_size_ty=consts::U1, - filename_max_plus_one_ty=consts::U256, - path_max_plus_one_ty=consts::U256, - result=Result, -); - -fn main() { - let mut ram = Ram::default(); - let mut storage = RamStorage::new(&mut ram); - let mut alloc = Filesystem::allocate(); - Filesystem::format(&mut storage).unwrap(); - let mut fs = Filesystem::mount(&mut alloc, &mut storage).unwrap(); - - let mut other_ram = OtherRam::default(); - let mut other_storage = OtherRamStorage::new(&mut other_ram); - let mut alloc = Filesystem::allocate(); - assert!(Filesystem::format(&mut other_storage).is_ok()); - let other_fs = Filesystem::mount(&mut alloc, &mut other_storage).unwrap(); - - let mut alloc = File::allocate(); - // file does not exist yet, can't open for reading - assert_eq!( - File::open("/test_open.txt", &mut alloc, &mut fs, &mut storage) - .map(drop) - .unwrap_err(), // "real" contains_err is experimental - Error::NoSuchEntry - ); - - fs.create_dir("/tmp", &mut storage).unwrap(); - - // TODO: make previous allocation reusable - let mut alloc = File::allocate(); - // can create new files - let mut file = File::create("/tmp/test_open.txt", &mut alloc, &mut fs, &mut storage).unwrap(); - // can write to files - assert!(file.write(&mut fs, &mut storage, &[0u8, 1, 2]).unwrap() == 3); - // won't work: "expected `RamStorage`, found `RamStorageNormal`. - file.sync(&mut other_fs, &mut other_storage).unwrap(); -} diff --git a/runners/lpc55/vendor/littlefs2/tests/ui/sync-fail.stderr b/runners/lpc55/vendor/littlefs2/tests/ui/sync-fail.stderr deleted file mode 100644 index 690fa65e..00000000 --- a/runners/lpc55/vendor/littlefs2/tests/ui/sync-fail.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error[E0308]: mismatched types - --> $DIR/sync-fail.rs:71:15 - | -71 | file.sync(&mut other_fs, &mut other_storage).unwrap(); - | ^^^^^^^^^^^^^ expected struct `RamStorage`, found struct `OtherRamStorage` - | - = note: expected type `&mut littlefs2::fs::Filesystem<'_, RamStorage<'_>>` - found type `&mut littlefs2::fs::Filesystem<'_, OtherRamStorage<'_>>` - -error[E0308]: mismatched types - --> $DIR/sync-fail.rs:71:30 - | -71 | file.sync(&mut other_fs, &mut other_storage).unwrap(); - | ^^^^^^^^^^^^^^^^^^ expected struct `RamStorage`, found struct `OtherRamStorage` - | - = note: expected type `&mut RamStorage<'_>` - found type `&mut OtherRamStorage<'_>` From 542fd2dbb47fa8dd6a4cafd4730c2a7f08c820a2 Mon Sep 17 00:00:00 2001 From: Manuel Domke Date: Sat, 4 Apr 2026 20:43:23 +0200 Subject: [PATCH 14/18] Fix LPC55 workspace build and hacker targets --- runners/lpc55/.cargo/config.toml | 11 ----------- runners/lpc55/Makefile | 13 ++++++++++++- runners/lpc55/README.md | 13 +++++++++++++ runners/lpc55/build.rs | 4 ++-- 4 files changed, 27 insertions(+), 14 deletions(-) delete mode 100644 runners/lpc55/.cargo/config.toml diff --git a/runners/lpc55/.cargo/config.toml b/runners/lpc55/.cargo/config.toml deleted file mode 100644 index 99cba13b..00000000 --- a/runners/lpc55/.cargo/config.toml +++ /dev/null @@ -1,11 +0,0 @@ -[target.'cfg(all(target_arch = "arm", target_os = "none"))'] -runner = "probe-rs run --chip LPC55S69JBD100" -rustflags = [ - "-C", "linker=flip-link", - "-C", "link-arg=-Tlink.x", - "-C", "link-arg=-Tdefmt.x", - "-Dwarnings", -] - -[build] -target = "thumbv8m.main-none-eabi" diff --git a/runners/lpc55/Makefile b/runners/lpc55/Makefile index a4bd58c2..edc55f2d 100644 --- a/runners/lpc55/Makefile +++ b/runners/lpc55/Makefile @@ -13,10 +13,22 @@ build-pro: cargo build --release $(PROVISIONER) cargo objcopy --release $(PROVISIONER) -- -O binary provisioner.bin +# Solo 2 Hacker: production-style build with encrypted storage. +# This requires the device to be provisioned for PRINCE/PUF. build-release: cargo build --release --features board-solo2 cargo objcopy --release --features board-solo2 -- -O binary app-solo2.bin +# Solo 2 Hacker: development build without encrypted storage. +build-hacker: + cargo build --release --features board-solo2,develop + cargo objcopy --release --features board-solo2,develop -- -O binary app-solo2.bin + +# Solo 2 Hacker recovery build: plain storage plus forced filesystem format. +build-hacker-recovery: + cargo build --release --features board-solo2,develop,format-filesystem + cargo objcopy --release --features board-solo2,develop,format-filesystem -- -O binary app-solo2.bin + .PHONY: today-as-minor-version today-in-days: python -c "from datetime import date as d; print((d.today() - d(2020, 1, 1)).days)" @@ -39,4 +51,3 @@ PACK_VERSION := $(shell wget -O - -qq https://mcuxpresso.nxp.com/cmsis_pack/repo PACK := NXP.LPC55S69_DFP.$(PACK_VERSION).pack get-cmsis-pack: wget -qq https://mcuxpresso.nxp.com/cmsis_pack/repo/$(PACK) -O ./lpc55s69.pack - diff --git a/runners/lpc55/README.md b/runners/lpc55/README.md index f302db36..128b24d2 100644 --- a/runners/lpc55/README.md +++ b/runners/lpc55/README.md @@ -2,6 +2,19 @@ The entire firmware that runs all the things. +## Solo 2 Hacker builds + +For a standalone Solo 2 Hacker, the safest custom-firmware path is the `develop` +variant because it disables encrypted storage (`no-encrypted-storage`). + +- `make build-hacker` + Builds `board-solo2,develop` and writes `app-solo2.bin`. +- `make build-hacker-recovery` + Builds `board-solo2,develop,format-filesystem` and forces a filesystem format on first boot. +- `make build-release` + Builds the PRINCE/PUF-backed production-style image. Use this only if the device is + provisioned for encrypted storage. + ### Logging diff --git a/runners/lpc55/build.rs b/runners/lpc55/build.rs index 3bf903cd..557d42d6 100644 --- a/runners/lpc55/build.rs +++ b/runners/lpc55/build.rs @@ -93,6 +93,7 @@ fn main() -> Result<(), Box> { println!("cargo:rerun-if-changed=cfg.toml"); let out_dir = env::var("OUT_DIR").expect("No out dir"); + println!("cargo:rustc-link-search={out_dir}"); // We would like to put configuration variables in cfg.toml, but due to a Cargo bug, // the serde feature flags will get merged with solo-bee's serde, causing build issues. @@ -108,8 +109,7 @@ fn main() -> Result<(), Box> { }, }; - let linker_script_file = env::var("CARGO_MANIFEST_DIR").expect("No out dir"); - let linker_script_file = Path::new(&linker_script_file).join("memory.x"); + let linker_script_file = Path::new(&out_dir).join("memory.x"); let mut linker_script_file = File::create(&linker_script_file).expect("Could not create file"); let dest_path = Path::new(&out_dir).join("build_constants.rs"); From 2fe26f39f7e725553627c652dbf3d004b44fae05 Mon Sep 17 00:00:00 2001 From: Manuel Domke Date: Sun, 5 Apr 2026 16:30:11 +0200 Subject: [PATCH 15/18] runners/lpc55: move secrets-app to trussed-secrets-app repo --- Cargo.lock | 6 +++--- Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3a220ec4..bc4aa059 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -636,7 +636,7 @@ dependencies = [ [[package]] name = "encrypted_container" version = "0.1.0" -source = "git+https://github.com/leetronics/solokeys-secrets-app-fork?branch=fix-pin-protection-isolation#aa4ff03f0b1b8e62964b96d78aa6dc4842a694c4" +source = "git+https://github.com/leetronics/trussed-secrets-app?branch=fix-pin-protection-isolation#30106e147559a72e849aa9ec17690e5167d04f8a" dependencies = [ "cbor-smol", "delog", @@ -1781,8 +1781,8 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "secrets-app" -version = "0.15.1" -source = "git+https://github.com/leetronics/solokeys-secrets-app-fork?branch=fix-pin-protection-isolation#aa4ff03f0b1b8e62964b96d78aa6dc4842a694c4" +version = "0.15.0" +source = "git+https://github.com/leetronics/trussed-secrets-app?branch=fix-pin-protection-isolation#30106e147559a72e849aa9ec17690e5167d04f8a" dependencies = [ "apdu-app", "bitflags 2.11.0", diff --git a/Cargo.toml b/Cargo.toml index b6865f8c..a7f9580b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -85,7 +85,7 @@ trussed-auth-backend = { git = "https://github.com/trussed-dev/trussed-auth" admin-app = "0.1" fido-authenticator = { version = "0.3", features = ["dispatch"] } oath-authenticator = { version = "0.1", features = ["apdu-dispatch"] } -secrets-app = { git = "https://github.com/leetronics/solokeys-secrets-app-fork", branch = "fix-pin-protection-isolation", features = ["apdu-dispatch", "ctaphid", "log-all"] } +secrets-app = { git = "https://github.com/leetronics/trussed-secrets-app", branch = "fix-pin-protection-isolation", features = ["apdu-dispatch", "ctaphid", "log-all"] } piv-authenticator = { git = "https://github.com/trussed-dev/piv-authenticator", tag = "v0.6.0", features = ["apdu-dispatch"] } opcard = { git = "https://github.com/Nitrokey/opcard-rs", tag = "v1.7.0", features = ["apdu-dispatch", "delog"] } From 01abd77bdc8b35db850d9ceaa4fee75ea239a41d Mon Sep 17 00:00:00 2001 From: Manuel Domke Date: Sun, 5 Apr 2026 20:24:54 +0200 Subject: [PATCH 16/18] add Manuel Domke as author --- Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.toml b/Cargo.toml index a7f9580b..3b76dbbc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,7 @@ edition = "2021" authors = [ "Nicolas Stalder ", "Conor Patrick ", + "Manuel Domke ", ] [workspace.dependencies] From e4f77262d9b48b28ca9d5f4f981ea3a0de983e2a Mon Sep 17 00:00:00 2001 From: Emanuele Cesena Date: Sat, 18 Apr 2026 20:55:45 -0700 Subject: [PATCH 17/18] ci: modernize and fix pc --- .cargo/config.toml | 3 - .github/workflows/ci.yml | 6 +- Cargo.lock | 110 ++++++++++++------ Cargo.toml | 11 +- runners/lpc55/.cargo/config.toml | 2 + runners/pc/.cargo/{config => config.toml} | 0 runners/pc/Cargo.toml | 52 ++++----- runners/pc/src/bin/main.rs | 129 ++++++++++------------ rust-toolchain.toml | 4 + 9 files changed, 170 insertions(+), 147 deletions(-) create mode 100644 runners/lpc55/.cargo/config.toml rename runners/pc/.cargo/{config => config.toml} (100%) create mode 100644 rust-toolchain.toml diff --git a/.cargo/config.toml b/.cargo/config.toml index 99cba13b..e7336ef0 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -6,6 +6,3 @@ rustflags = [ "-C", "link-arg=-Tdefmt.x", "-Dwarnings", ] - -[build] -target = "thumbv8m.main-none-eabi" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a442de3d..24734a23 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,7 +21,7 @@ jobs: - board-solo2 # - board-okdoe1 rust: - - stable + - "1.94" defaults: run: working-directory: runners/lpc55 @@ -73,7 +73,7 @@ jobs: path: runners/lpc55/target/thumbv8m.main-none-eabi/release/runner - name: Build Provisioner run: | - cargo build --release --features ${{ matrix.board }},provisioner-app,admin-app,trussed/clients-2,provisioner-app/test-attestation + cargo build --release --features ${{ matrix.board }},provisioner-app,admin-app,provisioner-app/test-attestation - name: Upload Provisioner uses: actions/upload-artifact@v4 continue-on-error: true @@ -91,7 +91,7 @@ jobs: # TODO: some build issue currently # - macos-latest rust: - - stable + - "1.94" defaults: run: working-directory: runners/pc diff --git a/Cargo.lock b/Cargo.lock index bc4aa059..a43210b0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -30,7 +30,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" dependencies = [ "crypto-common", - "generic-array", + "generic-array 0.14.7", "heapless 0.7.17", ] @@ -161,7 +161,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" dependencies = [ - "generic-array", + "generic-array 0.14.7", ] [[package]] @@ -170,7 +170,7 @@ version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ - "generic-array", + "generic-array 0.14.7", ] [[package]] @@ -179,7 +179,7 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93" dependencies = [ - "generic-array", + "generic-array 0.14.7", ] [[package]] @@ -248,6 +248,18 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +[[package]] +name = "chacha20" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f08493fa7707effc63254c66c6ea908675912493cd67952eda23c09fae2610b1" +dependencies = [ + "cfg-if", + "cipher 0.3.0", + "cpufeatures", + "rand_core", +] + [[package]] name = "chacha20" version = "0.9.1" @@ -266,7 +278,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35" dependencies = [ "aead", - "chacha20", + "chacha20 0.9.1", "cipher 0.4.4", "poly1305", "zeroize", @@ -278,7 +290,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" dependencies = [ - "generic-array", + "generic-array 0.14.7", ] [[package]] @@ -318,23 +330,22 @@ dependencies = [ [[package]] name = "cortex-m-rt" -version = "0.6.15" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "454f278bf469e2de0a4d22ea019d169d8944f86957c8207a39e3f66c32be2fc6" +checksum = "801d4dec46b34c299ccf6b036717ae0fce602faa4f4fe816d9013b9a7c9f5ba6" dependencies = [ "cortex-m-rt-macros", - "r0", ] [[package]] name = "cortex-m-rt-macros" -version = "0.6.15" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8e3aa52243e26f5922fa522b0814019e0c98fc567e2756d715dce7ad7a81f49" +checksum = "e37549a379a9e0e6e576fd208ee60394ccb8be963889eebba3ffe0980364f472" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.117", ] [[package]] @@ -369,7 +380,7 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8658c15c5d921ddf980f7fe25b1e82f4b7a4083b2c4985fea4922edb8e43e07d" dependencies = [ - "generic-array", + "generic-array 0.14.7", "rand_core", "subtle", "zeroize", @@ -381,7 +392,7 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" dependencies = [ - "generic-array", + "generic-array 0.14.7", "typenum", ] @@ -391,7 +402,7 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25fab6889090c8133f3deb8f73ba3c65a7f456f66436fc012a1b1e272b1e103e" dependencies = [ - "generic-array", + "generic-array 0.14.7", "subtle", ] @@ -532,7 +543,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" dependencies = [ - "generic-array", + "generic-array 0.14.7", ] [[package]] @@ -581,7 +592,7 @@ checksum = "83e5c176479da93a0983f0a6fdc3c1b8e7d5be0d7fe3fe05a99f15b96582b9a8" dependencies = [ "crypto-bigint", "ff", - "generic-array", + "generic-array 0.14.7", "group", "rand_core", "subtle", @@ -814,6 +825,16 @@ dependencies = [ "version_check", ] +[[package]] +name = "generic-array" +version = "1.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaf57c49a95fd1fe24b90b3033bee6dc7e8f1288d51494cb44e627c295e38542" +dependencies = [ + "rustversion", + "typenum", +] + [[package]] name = "glob" version = "0.3.3" @@ -974,7 +995,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" dependencies = [ "block-padding", - "generic-array", + "generic-array 0.14.7", ] [[package]] @@ -1049,7 +1070,7 @@ checksum = "6c8022e5141ceff5b7b12897113f54fc9dac5ad36402c787941c97272b9241eb" dependencies = [ "bitflags 2.11.0", "delog", - "generic-array", + "generic-array 0.14.7", "heapless 0.9.2", "littlefs2-core", "littlefs2-sys", @@ -1119,17 +1140,17 @@ dependencies = [ [[package]] name = "lpc55-hal" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ca5d2ad4d3068ed67b8d5b2f59eb64d4194e5d59c096657901c7b09e30069f" +checksum = "41e86e4e491dd3f8e07e7ba6de4aace716459ddefebd05743b2cb67b6a566d3c" dependencies = [ - "block-buffer 0.9.0", - "cipher 0.3.0", + "block-buffer 0.10.4", + "cipher 0.4.4", "cortex-m", - "digest 0.9.0", + "digest 0.10.7", "embedded-hal 0.2.7", "embedded-time", - "generic-array", + "generic-array 1.3.5", "lpc55-pac", "nb 1.1.0", "rand_core", @@ -1140,9 +1161,9 @@ dependencies = [ [[package]] name = "lpc55-pac" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf1b5b32d313af526145882f5115a55177f479e9328ca667a84aaaa1ae6d65d3" +checksum = "3a4952baed9d9e7e82a6bbc87333f939b90eb41df3e6c0be5e35d0ec61005f91" dependencies = [ "cortex-m", "cortex-m-rt", @@ -1527,12 +1548,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "r0" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2a38df5b15c8d5c7e8654189744d8e396bddc18ad48041a500ce52d6948941f" - [[package]] name = "rand_chacha" version = "0.3.1" @@ -1966,6 +1981,31 @@ version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +[[package]] +name = "solo-pc" +version = "2.2281.0" +dependencies = [ + "admin-app", + "apdu-dispatch 0.4.0", + "chacha20 0.7.3", + "ctap-types", + "ctaphid-dispatch", + "delog", + "embedded-hal 0.2.7", + "fido-authenticator", + "generic-array 0.14.7", + "interchange 0.3.2", + "littlefs2", + "nb 1.1.0", + "ndef-app", + "nfc-device", + "piv-authenticator", + "trussed", + "trussed-core", + "usbd-ccid", + "usbd-ctaphid", +] + [[package]] name = "spin" version = "0.9.8" @@ -2165,13 +2205,13 @@ dependencies = [ "cbc", "cbor-smol", "cfg-if", - "chacha20", + "chacha20 0.9.1", "chacha20poly1305", "cosey", "delog", "des", "flexiber 0.2.0", - "generic-array", + "generic-array 0.14.7", "heapless 0.9.2", "heapless-bytes 0.5.0", "hex-literal 0.4.1", diff --git a/Cargo.toml b/Cargo.toml index 3b76dbbc..66a97d70 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,11 +2,20 @@ members = [ "runners/lpc55", "runners/lpc55/board", + "runners/pc", "components/ndef-app", "components/nfc-device", "components/fm11nc08", "components/provisioner-app", ] +# Host-buildable members only. The lpc55 runner/board, fm11nc08, and +# provisioner-app (via lpc55-hal) / nfc-device (via embedded deps) all require an +# ARM target and can't link on the host, so they're excluded from default +# commands like `cargo test`. +default-members = [ + "runners/pc", + "components/ndef-app", +] resolver = "2" [workspace.package] @@ -34,7 +43,7 @@ systick-monotonic = "1.0.1" # ── Cortex-M / embedded ─────────────────────────────────────────────────────── cortex-m = { version = "0.7.0", features = ["critical-section-single-core"] } -lpc55-hal = "0.4.1" +lpc55-hal = "0.5.0" micromath = "2" embedded-time = "0.12" embedded-hal = { version = "0.2.5", features = ["unproven"] } diff --git a/runners/lpc55/.cargo/config.toml b/runners/lpc55/.cargo/config.toml new file mode 100644 index 00000000..c87b5c61 --- /dev/null +++ b/runners/lpc55/.cargo/config.toml @@ -0,0 +1,2 @@ +[build] +target = "thumbv8m.main-none-eabi" diff --git a/runners/pc/.cargo/config b/runners/pc/.cargo/config.toml similarity index 100% rename from runners/pc/.cargo/config rename to runners/pc/.cargo/config.toml diff --git a/runners/pc/Cargo.toml b/runners/pc/Cargo.toml index a5470fb1..b916e93f 100644 --- a/runners/pc/Cargo.toml +++ b/runners/pc/Cargo.toml @@ -1,40 +1,40 @@ [package] name = "solo-pc" -version = "0.1.0" -authors = ["Nicolas Stalder ", "Conor Patrick "] -edition = "2018" +version.workspace = true +authors.workspace = true +edition.workspace = true [dependencies] chacha20 = { version = "0.7", features = ["rng"] } delog = "0.1.0" embedded-hal = { version = "0.2", features = ["unproven"] } generic-array = "0.14.3" -interchange = "0.3" -nb = "1" - -admin-app = "0.1" -apdu-dispatch = "0.3" -ctap-types = "0.1" -ctaphid-dispatch = "0.2" -fido-authenticator = { version = "0.2", features = ["dispatch"], optional = true } -piv-authenticator = { git = "https://github.com/trussed-dev/piv-authenticator", tag = "v0.5.3" } -trussed = "0.1" -trussed-core = "0.1" +interchange.workspace = true +nb.workspace = true + +admin-app.workspace = true +apdu-dispatch.workspace = true +ctap-types.workspace = true +ctaphid-dispatch.workspace = true +fido-authenticator = { workspace = true, optional = true } +piv-authenticator.workspace = true +trussed.workspace = true +trussed-core.workspace = true # components -usbd-ccid = "0.2" -usbd-ctaphid = "0.3" -nfc-device = {path = "./../../components/nfc-device"} -ndef-app = {path = "./../../components/ndef-app"} +usbd-ccid.workspace = true +usbd-ctaphid.workspace = true +nfc-device.workspace = true +ndef-app.workspace = true # storage -littlefs2 = "0.6" +littlefs2.workspace = true [features] default = [] # Use to auto-succeed every user presence check -no-buttons= [] +no-buttons = [] # Reconfigure the NFC chip in any case reconfigure-nfc = [] @@ -45,15 +45,3 @@ log-info = [] log-debug = [] log-warn = [] log-error = [] - -[patch.crates-io] -trussed = { git = "https://github.com/trussed-dev/trussed.git", rev = "e107ed315a07dc6c992fac39d542e847cc3a1b6c" } -admin-app = { git = "https://github.com/Nitrokey/admin-app.git", tag = "v0.1.0-nitrokey.20" } -littlefs2 = { git = "https://github.com/trussed-dev/littlefs2.git", tag = "v0.6.1-nitrokey.1" } -littlefs2-sys = { git = "https://github.com/trussed-dev/littlefs2-sys.git", tag = "v0.3.1-nitrokey.1" } - -[profile.release] -codegen-units = 1 -opt-level = "z" -incremental = false -debug = true diff --git a/runners/pc/src/bin/main.rs b/runners/pc/src/bin/main.rs index 49f1a111..d7760955 100644 --- a/runners/pc/src/bin/main.rs +++ b/runners/pc/src/bin/main.rs @@ -2,14 +2,14 @@ use std::{fs::File, io::Write}; pub use embedded_hal::blocking::rng; use littlefs2::{const_ram_storage, consts}; use littlefs2::fs::{Allocation, Filesystem}; -use trussed::types::{LfsResult, LfsStorage}; +use trussed::store::DynFilesystem; use trussed::platform::{ ui, reboot, consent, }; -use trussed::{platform, store}; +use trussed::platform; pub use generic_array::{ GenericArray, @@ -33,7 +33,7 @@ pub mod littlefs_params { pub const BLOCK_CYCLES: isize = -1; pub type CACHE_SIZE = U512; - pub type LOOKAHEADWORDS_SIZE = U16; + pub type LOOKAHEAD_SIZE = U16; /// TODO: We can't actually be changed currently pub type FILENAME_MAX_PLUS_ONE = U256; pub type PATH_MAX_PLUS_ONE = U256; @@ -69,17 +69,17 @@ impl littlefs2::driver::Storage for FileFlash { const BLOCK_CYCLES: isize = littlefs_params::BLOCK_CYCLES; type CACHE_SIZE = littlefs_params::CACHE_SIZE; - type LOOKAHEADWORDS_SIZE = littlefs_params::LOOKAHEADWORDS_SIZE; + type LOOKAHEAD_SIZE = littlefs_params::LOOKAHEAD_SIZE; - fn read(&self, off: usize, buf: &mut [u8]) -> LfsResult { + fn read(&mut self, off: usize, buf: &mut [u8]) -> littlefs2::io::Result { for i in 0 .. buf.len() { buf[i] = self.state[i + off]; } Ok(buf.len()) } - fn write(&mut self, off: usize, data: &[u8]) -> LfsResult { + fn write(&mut self, off: usize, data: &[u8]) -> littlefs2::io::Result { for i in 0 .. data.len() { self.state[i + off] = data[i]; } @@ -89,7 +89,7 @@ impl littlefs2::driver::Storage for FileFlash { Ok(data.len()) } - fn erase(&mut self, off: usize, len: usize) -> LfsResult { + fn erase(&mut self, off: usize, len: usize) -> littlefs2::io::Result { for i in 0 .. len { self.state[i + off] = 0; } @@ -103,7 +103,6 @@ impl littlefs2::driver::Storage for FileFlash { // 8KB of RAM const_ram_storage!( name=VolatileStorage, - trait=LfsStorage, erase_value=0x00, read_size=1, write_size=1, @@ -111,42 +110,30 @@ const_ram_storage!( // this is a limitation of littlefs // https://git.io/JeHp9 block_size=128, - // block_size=128, block_count=8192/128, - lookaheadwords_size_ty=consts::U8, + lookahead_size_ty=consts::U8, filename_max_plus_one_ty=consts::U256, path_max_plus_one_ty=consts::U256, - result=LfsResult, ); // minimum: 2 blocks // TODO: make this optional const_ram_storage!(ExternalStorage, 1024); -store!(Store, - Internal: FileFlash, - External: ExternalStorage, - Volatile: VolatileStorage -); - - +#[derive(Clone, Copy)] +pub struct RunnerStore { + ifs: &'static dyn DynFilesystem, + efs: &'static dyn DynFilesystem, + vfs: &'static dyn DynFilesystem, +} -// #[derive(Default)] -// pub struct Rng { -// count: u64, -// } +impl trussed::store::Store for RunnerStore { + fn ifs(&self) -> &dyn DynFilesystem { self.ifs } + fn efs(&self) -> &dyn DynFilesystem { self.efs } + fn vfs(&self) -> &dyn DynFilesystem { self.vfs } +} -// impl rng::Read for Rng { -// type Error = core::convert::Infallible; -// fn read(&mut self, buffer: &mut [u8]) -> core::result::Result<(), Self::Error> { -// // bad -// for i in 0 .. buffer.len() { -// self.count += 1; -// buffer[i] = (self.count & 0xff) as u8; -// } -// Ok(()) -// } -// } +pub type Store = RunnerStore; #[derive(Default)] @@ -188,51 +175,47 @@ platform!(Board, fn main () { - let filesystem = FileFlash::new(); + // Allocate and mount three filesystems, leaking them to obtain 'static refs. + let internal_storage: &'static mut FileFlash = Box::leak(Box::new(FileFlash::new())); + let internal_alloc: &'static mut Allocation = + Box::leak(Box::new(Filesystem::allocate())); - static mut INTERNAL_STORAGE: Option = None; - unsafe { INTERNAL_STORAGE = Some(filesystem); } - static mut INTERNAL_FS_ALLOC: Option> = None; - unsafe { INTERNAL_FS_ALLOC = Some(Filesystem::allocate()); } + let external_storage: &'static mut ExternalStorage = + Box::leak(Box::new(ExternalStorage::new())); + let external_alloc: &'static mut Allocation = + Box::leak(Box::new(Filesystem::allocate())); - static mut EXTERNAL_STORAGE: ExternalStorage = ExternalStorage::new(); - static mut EXTERNAL_FS_ALLOC: Option> = None; - unsafe { EXTERNAL_FS_ALLOC = Some(Filesystem::allocate()); } + let volatile_storage: &'static mut VolatileStorage = + Box::leak(Box::new(VolatileStorage::new())); + let volatile_alloc: &'static mut Allocation = + Box::leak(Box::new(Filesystem::allocate())); - static mut VOLATILE_STORAGE: VolatileStorage = VolatileStorage::new(); - static mut VOLATILE_FS_ALLOC: Option> = None; - unsafe { VOLATILE_FS_ALLOC = Some(Filesystem::allocate()); } - - - let store = Store::claim().unwrap(); - - let result = store.mount( - unsafe { INTERNAL_FS_ALLOC.as_mut().unwrap() }, - // unsafe { &mut INTERNAL_STORAGE }, - unsafe { INTERNAL_STORAGE.as_mut().unwrap() }, - unsafe { EXTERNAL_FS_ALLOC.as_mut().unwrap() }, - unsafe { &mut EXTERNAL_STORAGE }, - unsafe { VOLATILE_FS_ALLOC.as_mut().unwrap() }, - unsafe { &mut VOLATILE_STORAGE }, - // to trash existing data, set to true - false, - ); - - if result.is_err() { + // Internal FS: try mount, format on failure. + if Filesystem::mount(internal_alloc, internal_storage).is_err() { println!("Not yet formatted! Formatting.."); - store.mount( - unsafe { INTERNAL_FS_ALLOC.as_mut().unwrap() }, - // unsafe { &mut INTERNAL_STORAGE }, - unsafe { INTERNAL_STORAGE.as_mut().unwrap() }, - unsafe { EXTERNAL_FS_ALLOC.as_mut().unwrap() }, - unsafe { &mut EXTERNAL_STORAGE }, - unsafe { VOLATILE_FS_ALLOC.as_mut().unwrap() }, - unsafe { &mut VOLATILE_STORAGE }, - // to trash existing data, set to true - true, - ).unwrap(); + Filesystem::format(internal_storage).unwrap(); } - + let internal_fs: &'static mut Filesystem<'static, FileFlash> = Box::leak(Box::new( + Filesystem::mount(internal_alloc, internal_storage).unwrap(), + )); + + // External FS (RAM): always needs format on first use. + Filesystem::format(external_storage).unwrap(); + let external_fs: &'static mut Filesystem<'static, ExternalStorage> = Box::leak(Box::new( + Filesystem::mount(external_alloc, external_storage).unwrap(), + )); + + // Volatile FS (RAM): always needs format on first use. + Filesystem::format(volatile_storage).unwrap(); + let volatile_fs: &'static mut Filesystem<'static, VolatileStorage> = Box::leak(Box::new( + Filesystem::mount(volatile_alloc, volatile_storage).unwrap(), + )); + + let store = RunnerStore { + ifs: internal_fs, + efs: external_fs, + vfs: volatile_fs, + }; use trussed::service::SeedableRng; let rng = chacha20::ChaCha8Rng::from_seed([0u8; 32]); diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 00000000..5929cac8 --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,4 @@ +[toolchain] +channel = "1.94" +components = ["llvm-tools-preview"] +targets = ["thumbv8m.main-none-eabi"] From c15277c3923469c1c70eebecf3a05db5398706eb Mon Sep 17 00:00:00 2001 From: Emanuele Cesena Date: Sat, 18 Apr 2026 21:48:42 -0700 Subject: [PATCH 18/18] cargo: fix fmt and clippy --- .github/workflows/ci.yml | 33 ++ components/fm11nc08/src/device.rs | 338 ++++++++---------- components/fm11nc08/src/lib.rs | 6 +- components/ndef-app/src/lib.rs | 2 +- components/ndef-app/src/ndef.rs | 70 ++-- components/nfc-device/src/iso14443.rs | 176 ++++----- components/nfc-device/src/lib.rs | 2 +- components/nfc-device/src/traits.rs | 5 +- components/provisioner-app/src/lib.rs | 50 ++- runners/lpc55/board/src/clock_controller.rs | 168 +++++---- runners/lpc55/board/src/lib.rs | 12 +- .../lpc55/board/src/lpcxpresso55/button.rs | 106 +++--- runners/lpc55/board/src/lpcxpresso55/led.rs | 39 +- runners/lpc55/board/src/nfc.rs | 121 ++++--- runners/lpc55/board/src/shared.rs | 13 +- runners/lpc55/board/src/solo2/button.rs | 115 +++--- runners/lpc55/board/src/solo2/led.rs | 33 +- runners/lpc55/board/src/traits/buttons.rs | 1 - runners/lpc55/board/src/traits/rgb_led.rs | 7 +- runners/lpc55/board/src/trussed.rs | 132 ++++--- runners/lpc55/build.rs | 6 +- runners/lpc55/rust-toolchain.toml | 4 - runners/lpc55/src/initializer.rs | 26 +- runners/lpc55/src/initializer/stages.rs | 4 +- runners/lpc55/src/lib.rs | 9 +- runners/lpc55/src/main.rs | 92 +++-- runners/lpc55/src/types.rs | 21 +- runners/pc/src/bin/main.rs | 97 +++-- rust-toolchain.toml | 2 +- 29 files changed, 836 insertions(+), 854 deletions(-) delete mode 100644 runners/lpc55/rust-toolchain.toml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 24734a23..d966c6ea 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -117,3 +117,36 @@ jobs: override: true - name: Build run: cargo build --release + + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - name: Install Linux build dependencies + shell: bash + run: | + apt-get update && apt-get install sudo + sudo apt update -y -qq && sudo apt install -y -qq llvm libc6-dev-i386 libclang-dev build-essential clang + - uses: fiam/arm-none-eabi-gcc@v1.0.4 + with: + release: "9-2020-q2" + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: "1.94" + target: thumbv8m.main-none-eabi + override: true + components: rustfmt, clippy + - name: cargo fmt --check + run: cargo fmt --all --check + - name: cargo clippy (host) + run: cargo clippy --all-targets -- -D warnings + - name: cargo clippy (lpc55, board-lpcxpresso55) + working-directory: runners/lpc55 + run: cargo clippy --release --features board-lpcxpresso55 + - name: cargo clippy (lpc55, board-solo2) + working-directory: runners/lpc55 + run: cargo clippy --release --features board-solo2 + - name: cargo clippy (lpc55, provisioner) + working-directory: runners/lpc55 + run: cargo clippy --release --features board-lpcxpresso55,provisioner-app,admin-app,provisioner-app/test-attestation diff --git a/components/fm11nc08/src/device.rs b/components/fm11nc08/src/device.rs index 73aba778..b08e13bc 100644 --- a/components/fm11nc08/src/device.rs +++ b/components/fm11nc08/src/device.rs @@ -1,13 +1,13 @@ use nb::block; -use embedded_time::duration::{Extensions, Microseconds}; use embedded_hal as hal; +use embedded_time::duration::{Extensions, Microseconds}; use defmt::info; use hal::{ - spi::FullDuplex, digital::v2::{InputPin, OutputPin}, + spi::FullDuplex, timer::CountDown, }; @@ -61,19 +61,15 @@ pub enum FifoInterrupt { WaterLevel = 1 << 3, } - - macro_rules! FM11_CMD { ($mode:expr, $addr:expr) => { match $mode { - Mode::WriteEeprom | Mode::ReadEeprom=> { - (( ($mode as u8) & 0x07) << 5) | (((($addr as u16) & 0x300) >> 8) as u8) - } - _ => { - (( ($mode as u8) & 0x07) << 5) | (($addr as u8) & 0x0f) + Mode::WriteEeprom | Mode::ReadEeprom => { + ((($mode as u8) & 0x07) << 5) | (((($addr as u16) & 0x300) >> 8) as u8) } + _ => ((($mode as u8) & 0x07) << 5) | (($addr as u8) & 0x0f), } - } + }; } pub struct Configuration { @@ -89,7 +85,7 @@ pub struct Configuration { pub nfc: u8, } -pub struct FM11NC08 +pub struct FM11NC08 where SPI: FullDuplex, CS: OutputPin, @@ -117,8 +113,7 @@ fn fsdi_to_frame_size(fsdi: u8) -> usize { } } - -impl FM11NC08 +impl FM11NC08 where SPI: FullDuplex, CS: OutputPin, @@ -126,9 +121,9 @@ where { pub fn new(spi: SPI, cs: CS, int: INT) -> Self { Self { - spi: spi, - cs: cs, - int: int, + spi, + cs, + int, packet: [0u8; 256], offset: 0usize, current_frame_size: 128, @@ -138,11 +133,11 @@ where pub fn write_reg(&mut self, addr: Register, data: u8) { self.cs.set_low().ok(); - block!( self.spi.send(FM11_CMD!(Mode::Write, addr)) ).ok(); - block!( self.spi.send(data) ).ok(); + block!(self.spi.send(FM11_CMD!(Mode::Write, addr))).ok(); + block!(self.spi.send(data)).ok(); - block!( self.spi.read() ).ok(); - block!( self.spi.read() ).ok(); + block!(self.spi.read()).ok(); + block!(self.spi.read()).ok(); self.cs.set_high().ok(); } @@ -150,11 +145,11 @@ where pub fn read_reg(&mut self, addr: Register) -> u8 { self.cs.set_low().ok(); - block!( self.spi.send(FM11_CMD!(Mode::Read, addr)) ).ok(); - block!( self.spi.send(0) ).ok(); + block!(self.spi.send(FM11_CMD!(Mode::Read, addr))).ok(); + block!(self.spi.send(0)).ok(); - block!( self.spi.read() ).ok(); - let data = block!( self.spi.read() ).ok().unwrap(); + block!(self.spi.read()).ok(); + let data = block!(self.spi.read()).ok().unwrap(); self.cs.set_high().ok(); @@ -164,45 +159,47 @@ where pub fn read_reg_raw(&mut self, addr: u8) -> u8 { self.cs.set_low().ok(); - block!( self.spi.send(FM11_CMD!(Mode::Read, addr)) ).ok(); - block!( self.spi.send(0) ).ok(); + block!(self.spi.send(FM11_CMD!(Mode::Read, addr))).ok(); + block!(self.spi.send(0)).ok(); - block!( self.spi.read() ).ok(); - let data = block!( self.spi.read() ).ok().unwrap(); + block!(self.spi.read()).ok(); + let data = block!(self.spi.read()).ok().unwrap(); self.cs.set_high().ok(); data } - - - fn start_write(&mut self, addr: u16){ - - let cmd : u8 = FM11_CMD!(Mode::WriteEeprom, addr); + fn start_write(&mut self, addr: u16) { + let cmd: u8 = FM11_CMD!(Mode::WriteEeprom, addr); self.cs.set_low().ok(); // Write EEPROM magic enable sequence - block!( self.spi.send( 0b11001110u8 )).ok(); - block!( self.spi.send( 0b01010101u8 )).ok(); + block!(self.spi.send(0b11001110u8)).ok(); + block!(self.spi.send(0b01010101u8)).ok(); - for _ in 0 .. 2 { block!( self.spi.read( )).ok().unwrap(); } + for _ in 0..2 { + block!(self.spi.read()).ok().unwrap(); + } self.cs.set_high().ok(); self.cs.set_low().ok(); - block!( self.spi.send( cmd )).ok(); - block!( self.spi.send( addr as u8)).ok(); + block!(self.spi.send(cmd)).ok(); + block!(self.spi.send(addr as u8)).ok(); - for _ in 0 .. 2 { block!( self.spi.read( )).ok().unwrap(); } + for _ in 0..2 { + block!(self.spi.read()).ok().unwrap(); + } } - fn end_write(&mut self, timer: &mut impl CountDown) -> Result<(),()> { + fn end_write(&mut self, timer: &mut impl CountDown