├── .envrc ├── .gitignore ├── .gitlab-ci.yml ├── 70-nitrokey-3.rules ├── CHANGELOG.md ├── Cargo.lock ├── Cargo.toml ├── Dockerfile ├── Info.plist ├── LICENSE-APACHE ├── LICENSE-MIT ├── Makefile ├── README.md ├── components ├── apps │ ├── Cargo.toml │ └── src │ │ ├── dispatch.rs │ │ ├── lib.rs │ │ └── migrations.rs ├── boards │ ├── Cargo.toml │ └── src │ │ ├── flash.rs │ │ ├── init.rs │ │ ├── lib.rs │ │ ├── nk3am.rs │ │ ├── nk3am │ │ ├── migrations │ │ │ ├── ftl_journal │ │ │ │ ├── backends.rs │ │ │ │ ├── ifs_flash_old.rs │ │ │ │ └── mod.rs │ │ │ └── mod.rs │ │ └── ui.rs │ │ ├── nk3xn.rs │ │ ├── nk3xn │ │ ├── button.rs │ │ ├── led.rs │ │ ├── nfc.rs │ │ ├── prince.rs │ │ └── spi.rs │ │ ├── nkpk.rs │ │ ├── runtime.rs │ │ ├── soc.rs │ │ ├── soc │ │ ├── lpc55.rs │ │ ├── lpc55 │ │ │ ├── clock_controller.rs │ │ │ └── monotonic.rs │ │ ├── nrf52.rs │ │ └── nrf52 │ │ │ ├── flash.rs │ │ │ └── rtic_monotonic.rs │ │ ├── store.rs │ │ ├── ui.rs │ │ └── ui │ │ ├── buttons.rs │ │ └── rgb_led.rs ├── fm11nc08 │ ├── Cargo.toml │ └── src │ │ ├── device.rs │ │ └── lib.rs ├── lfs-backup │ ├── Cargo.toml │ └── src │ │ ├── lfs_backup.rs │ │ ├── lib.rs │ │ └── tests.rs ├── memory-regions │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── ndef-app │ ├── Cargo.toml │ └── src │ │ ├── lib.rs │ │ └── ndef.rs ├── nfc-device │ ├── Cargo.toml │ └── src │ │ ├── iso14443.rs │ │ ├── lib.rs │ │ ├── traits.rs │ │ └── types.rs ├── provisioner-app │ ├── Cargo.toml │ └── src │ │ ├── apdu.rs │ │ ├── ctaphid.rs │ │ └── lib.rs └── utils │ ├── Cargo.toml │ └── src │ ├── build.rs │ ├── lib.rs │ ├── storage.rs │ └── version.rs ├── docker-Makefile ├── docs ├── contributing.md ├── ctaphid-commands.md ├── hardware.md ├── identifiers.md ├── index.md ├── lpc55-quickstart.md ├── maintenance.md ├── storage.md ├── testing.md ├── troubleshooting.md └── usbip.md ├── repometrics.toml ├── runners ├── .gitignore ├── arm-none-eabi-arch-symbols.txt ├── embedded │ ├── .cargo │ │ └── config.toml │ ├── .gitignore │ ├── Cargo.toml │ ├── Makefile │ ├── build.rs │ ├── data │ │ └── fido-cert.der │ ├── deny.toml │ ├── profiles │ │ ├── lpc55.toml │ │ └── nrf52-bootloader.toml │ └── src │ │ ├── bin │ │ ├── app-lpc.rs │ │ └── app-nrf.rs │ │ ├── lib.rs │ │ ├── nk3xn.rs │ │ └── nk3xn │ │ └── init.rs ├── ld │ ├── cortex-m-rt_0.6.15_link.x │ ├── lpc55-memory-template.x │ └── nrf52-memory-template.x ├── nkpk │ ├── .cargo │ │ └── config │ ├── .gitignore │ ├── Cargo.toml │ ├── Makefile │ ├── build.rs │ └── src │ │ └── main.rs └── usbip │ ├── .gitignore │ ├── Cargo.toml │ ├── Makefile │ ├── build.rs │ ├── src │ ├── main.rs │ ├── store.rs │ └── ui.rs │ └── walk.sh ├── rust-toolchain.toml ├── rustfmt.toml ├── scripts ├── bump-jlink ├── defuse-bee └── fuse-bee ├── ssh └── troubles │ ├── .gitignore │ ├── Dockerfile │ ├── Makefile │ ├── README.md │ ├── entrypoint │ └── works ├── tests ├── basic.py ├── beep.py ├── ccid.py ├── test_ccid.py └── totp.py └── utils ├── collect-license-info ├── Cargo.toml ├── src │ └── main.rs └── templates │ └── license.txt ├── compare-bloat.py ├── fido2-mds ├── .gitignore ├── Makefile ├── attestation │ ├── nk3am.der │ ├── nk3xn.der │ └── test.der ├── generate-mds.py ├── metadata │ ├── v1 │ │ ├── metadata-nk3am-v1.json │ │ ├── metadata-nk3am-v1.test.json │ │ ├── metadata-nk3xn-v1.json │ │ └── metadata-nk3xn-v1.test.json │ ├── v2 │ │ ├── metadata-nk3am-v2.json │ │ ├── metadata-nk3am-v2.test.json │ │ ├── metadata-nk3xn-v2.json │ │ └── metadata-nk3xn-v2.test.json │ ├── v3 │ │ ├── metadata-nk3am-v3.json │ │ ├── metadata-nk3am-v3.test.json │ │ ├── metadata-nk3xn-v3.json │ │ └── metadata-nk3xn-v3.test.json │ ├── v4 │ │ ├── metadata-nk3am-v4.json │ │ ├── metadata-nk3am-v4.test.json │ │ ├── metadata-nk3xn-v4.json │ │ └── metadata-nk3xn-v4.test.json │ └── v5 │ │ ├── metadata-nk3am-v5.json │ │ ├── metadata-nk3am-v5.test.json │ │ ├── metadata-nk3xn-v5.json │ │ └── metadata-nk3xn-v5.test.json ├── nitrokey.svg ├── requirements.in └── requirements.txt ├── gen-commands-bd ├── Cargo.toml └── src │ └── main.rs ├── lpc55-builder ├── .gitignore ├── 70-lpc55.rules ├── Makefile ├── README.md ├── config │ ├── cfpa.toml │ ├── cmpa-develop.toml │ ├── cmpa-empty.toml │ ├── cmpa-release.toml │ ├── flash-erase-all.toml │ ├── flash-erase-firmware.toml │ └── keystore.toml ├── jlink.gdb ├── jlink.sh ├── jlink │ ├── connect.txt │ └── erase.txt └── scripts │ ├── boot-to-bootrom.sh │ └── usbwait.sh ├── manifest.template.json ├── nix ├── .gitignore ├── Makefile ├── nrf-command-line-tools │ └── default.nix └── shell.nix ├── nrf-bootloader ├── .gitignore ├── Dockerfile ├── Makefile ├── Makefile.bootloader ├── Makefile.docker ├── config │ ├── default_sdk_config.h │ ├── nk3am_sdk_config.h │ ├── nkpk_sdk_config.h │ └── sdk_config.h ├── generate_key.sh ├── secure_bootloader_gcc_nrf52.ld ├── sha256sums.txt ├── sign-bootloader.sh ├── sign.sh ├── src │ ├── main.c │ └── nrf_crypto_allocator.h └── upload.sh ├── nrf-builder ├── .gitignore ├── Makefile ├── Makefile.nkpk ├── Makefile.test-ftl-migration ├── README.md └── wait_for_usb.sh ├── nrf-debugging ├── Makefile ├── README.md ├── binary ├── binary.elf ├── gdb-stack.cmds ├── gdb.cmds ├── gdb_bt.cmds ├── gdb_regs.cmds ├── graph_stack.py ├── ocd.conf.example ├── ocdtool.py ├── parse-memrd.py ├── symbols.txt └── walk.py └── test-certificates ├── fido ├── nk-fido-ca-cert.der ├── nk-fido-ca-cert.pem ├── nk-fido-ca-key.pem ├── nk-fido-ca-key.trussed ├── nk-fido-ee-cert.der ├── nk-fido-ee-cert.pem ├── nk-fido-ee-key.pem └── nk-fido-ee-key.trussed ├── firmware-lpc55 ├── nk-firmware-ee1-cert.der ├── nk-firmware-ee1-cert.pem ├── nk-firmware-ee1-cert.viewable.pem ├── nk-firmware-ee1-key.der ├── nk-firmware-ee1-key.pem ├── nk-firmware-ee2-cert.der ├── nk-firmware-ee2-cert.pem ├── nk-firmware-ee2-cert.viewable.pem ├── nk-firmware-ee2-key.der ├── nk-firmware-ee2-key.pem ├── nk-firmware-ee3-cert.der ├── nk-firmware-ee3-cert.pem ├── nk-firmware-ee3-cert.viewable.pem ├── nk-firmware-ee3-key.der ├── nk-firmware-ee3-key.pem ├── nk-firmware-ee4-cert.der ├── nk-firmware-ee4-cert.pem ├── nk-firmware-ee4-cert.viewable.pem ├── nk-firmware-ee4-key.der ├── nk-firmware-ee4-key.pem ├── nk-firmware-root-cert.der ├── nk-firmware-root-cert.pem ├── nk-firmware-root-cert.viewable.pem └── nk-firmware-root-key.pem ├── firmware-nk3am ├── dfu_private.key ├── dfu_public.pem └── dfu_public_key.c ├── firmware-nkpk ├── dfu_private.key ├── dfu_public_key.c └── dfu_public_key.pem ├── index.md └── root ├── nk-root-cert.pem ├── nk-root-cert.viewable.pem └── nk-root-key.pem /.envrc: -------------------------------------------------------------------------------- 1 | export RUNNER=$(pwd)/platforms/lpc55/runner 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | binaries 2 | target 3 | **/.gdb_history 4 | ctap-2-1-pre.pdf 5 | solo-bee.code-workspace 6 | ref/ 7 | memory.x 8 | solo-state.bin 9 | bee.littlefs2 10 | Cargo.lock 11 | !runners/lpc55/Cargo.lock 12 | !Cargo.lock 13 | /license.txt 14 | /commands.bd 15 | /manifest.json 16 | metrics.toml 17 | utils/nrf-debugging/binary 18 | utils/nrf-debugging/symbols.txt 19 | utils/nrf-debugging/ocd.conf 20 | utils/nrf-bootloader/build 21 | utils/nrf-bootloader/bootloader.hex 22 | utils/nrf-bootloader/mbr.hex 23 | utils/nrf-bootloader/signing-key 24 | utils/nrf-builder/bootloader-nk3am-nrf52-.zip 25 | utils/nrf-builder/bootloader-nk3am-nrf52-1.2.2.zip 26 | utils/nrf-builder/bootloader.hex 27 | utils/nrf-builder/csr.pem 28 | utils/nrf-builder/develop-nk3am-nrf52-.bin 29 | utils/nrf-builder/develop-nk3am-nrf52-.hex 30 | utils/nrf-builder/develop-nk3am-nrf52-.zip 31 | utils/nrf-builder/develop-nk3am-nrf52-1.2.2.bin 32 | utils/nrf-builder/develop-nk3am-nrf52-1.2.2.hex 33 | utils/nrf-builder/develop-nk3am-nrf52-1.2.2.zip 34 | utils/nrf-builder/firmware-nk3am-nrf52-.bin 35 | utils/nrf-builder/firmware-nk3am-nrf52-.hex 36 | utils/nrf-builder/firmware-nk3am-nrf52-.zip 37 | utils/nrf-builder/firmware-nk3am-nrf52-1.2.2.bin 38 | utils/nrf-builder/firmware-nk3am-nrf52-1.2.2.hex 39 | utils/nrf-builder/firmware-nk3am-nrf52-1.2.2.zip 40 | utils/nrf-builder/log.log 41 | utils/nrf-builder/mbr.hex 42 | utils/nrf-builder/provisioner-nk3am-nrf52-.bin 43 | utils/nrf-builder/provisioner-nk3am-nrf52-.hex 44 | utils/nrf-builder/provisioner-nk3am-nrf52-.zip 45 | utils/nrf-builder/provisioner-nk3am-nrf52-1.2.2.bin 46 | utils/nrf-builder/provisioner-nk3am-nrf52-1.2.2.hex 47 | utils/nrf-builder/provisioner-nk3am-nrf52-1.2.2.zip 48 | utils/nrf-builder/test-certs/ 49 | -------------------------------------------------------------------------------- /70-nitrokey-3.rules: -------------------------------------------------------------------------------- 1 | # Nitrokey 3 firmware 2 | SUBSYSTEM=="hidraw", ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="42b2", TAG+="uaccess" 3 | SUBSYSTEM=="tty", ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="42b2", TAG+="uaccess" 4 | SUBSYSTEM=="usb", ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="42b2", TAG+="uaccess" 5 | 6 | # Nitrokey 3 bootloader 7 | SUBSYSTEM=="hidraw", ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="42dd", TAG+="uaccess" 8 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "components/*", 4 | "runners/embedded", 5 | "runners/nkpk", 6 | "runners/usbip", 7 | "utils/collect-license-info", 8 | "utils/gen-commands-bd", 9 | ] 10 | resolver = "2" 11 | 12 | [workspace.package] 13 | version = "1.8.2" 14 | 15 | [workspace.dependencies] 16 | littlefs2 = "0.6" 17 | 18 | [patch.crates-io] 19 | # components 20 | memory-regions = { path = "components/memory-regions" } 21 | 22 | # unreleased libraries 23 | p256-cortex-m4 = { git = "https://github.com/ycrypto/p256-cortex-m4.git", rev = "cdb31e12594b4dc1f045b860a885fdc94d96aee2" } 24 | trussed = { git = "https://github.com/trussed-dev/trussed.git", rev = "e107ed315a07dc6c992fac39d542e847cc3a1b6c" } 25 | trussed-usbip = { git = "https://github.com/trussed-dev/pc-usbip-runner.git", rev = "504674453c9573a30aa2f155101df49eb2af1ba7" } 26 | 27 | # applications 28 | admin-app = { git = "https://github.com/Nitrokey/admin-app.git", tag = "v0.1.0-nitrokey.20" } 29 | fido-authenticator = { git = "https://github.com/Nitrokey/fido-authenticator.git",tag = "v0.1.1-nitrokey.27" } 30 | opcard = { git = "https://github.com/Nitrokey/opcard-rs", rev = "39ec4c37f808c0cfeb84e0a8493bbee06f02c8e2" } 31 | piv-authenticator = { git = "https://github.com/trussed-dev/piv-authenticator.git", tag = "v0.5.1" } 32 | secrets-app = { git = "https://github.com/Nitrokey/trussed-secrets-app", rev = "700863bdfa90a3616cbb695d6638c7aea7730c03" } 33 | 34 | # backends 35 | trussed-auth-backend = { git = "https://github.com/trussed-dev/trussed-auth", tag = "v0.4.0" } 36 | trussed-rsa-alloc = { git = "https://github.com/trussed-dev/trussed-rsa-backend.git", rev = "743d9aaa3d8a17d7dbf492bd54dc18ab8fca3dc0" } 37 | trussed-se050-backend = { git = "https://github.com/Nitrokey/trussed-se050-backend.git", rev = "be89dc04fc6b06505d2eed484802107b4aa3fe71" } 38 | trussed-staging = { git = "https://github.com/trussed-dev/trussed-staging.git", tag = "v0.3.3" } 39 | cargo-license = { git = "https://github.com/Nitrokey/cargo-license.git", rev = "d38912dc4b7a10d3cf48f8cf86f49640ff3173ab" } 40 | littlefs2-sys = { git = "https://github.com/trussed-dev/littlefs2-sys.git", rev = "v0.3.1-nitrokey.1" } 41 | littlefs2 = { git = "https://github.com/trussed-dev/littlefs2.git", rev = "v0.6.1-nitrokey.1" } 42 | littlefs2-core = { git = "https://github.com/trussed-dev/littlefs2.git", rev = "v0.6.1-nitrokey.1" } 43 | 44 | [profile.release] 45 | codegen-units = 1 46 | lto = "fat" 47 | opt-level = "z" 48 | incremental = false 49 | debug = true 50 | 51 | [profile.release-thin-lto] 52 | lto = "thin" 53 | inherits = "release" 54 | 55 | [profile.release.package.salty] 56 | opt-level = 2 57 | 58 | [profile.release-thin-lto.package.salty] 59 | opt-level = 2 60 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM rust:1.82.0 2 | RUN apt-get update && \ 3 | apt-get install -y python3 python3-toml git curl llvm clang libclang-dev gcc-arm-none-eabi libc6-dev-i386 make wget zip 4 | RUN cargo install flip-link cargo-binutils 5 | RUN rustup target add thumbv7em-none-eabihf thumbv8m.main-none-eabi 6 | RUN rustup component add llvm-tools-preview clippy rustfmt 7 | RUN cargo install --git https://github.com/Nitrokey/nitrokey-ci --rev ef155b0c34317fab71405fe5e914d4732f8c9396 --locked 8 | RUN cargo install --git https://github.com/Nitrokey/repometrics --rev 98ffa20ddded8f09c0ef252b4e93ec6a9792f9dc --locked 9 | RUN rustup install nightly-2024-08-30 10 | RUN rustup component add rust-src --toolchain nightly-2024-08-30 11 | WORKDIR /app 12 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2020 SoloKeys 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: check 2 | check: 3 | $(MAKE) -C runners/embedded check-all 4 | $(MAKE) -C runners/nkpk check 5 | $(MAKE) -C runners/usbip check 6 | 7 | .PHONY: check-components 8 | check-components: 9 | cargo check --manifest-path components/fm11nc08/Cargo.toml 10 | cargo check --manifest-path components/lfs-backup/Cargo.toml 11 | cargo check --manifest-path components/memory-regions/Cargo.toml 12 | cargo check --manifest-path components/ndef-app/Cargo.toml 13 | cargo check --manifest-path components/nfc-device/Cargo.toml 14 | cargo check --manifest-path components/provisioner-app/Cargo.toml 15 | 16 | cargo check --manifest-path components/apps/Cargo.toml 17 | for feature in nk3 nk3-test nk3-provisioner nkpk nkpk-provisioner ; do \ 18 | echo "apps: $$feature" ; \ 19 | cargo check --manifest-path components/apps/Cargo.toml --features $$feature ; \ 20 | done 21 | cargo check --manifest-path components/apps/Cargo.toml --all-features 22 | 23 | cargo check --manifest-path components/boards/Cargo.toml 24 | for feature in board-nk3am board-nk3xn board-nkpk ; do \ 25 | echo "boards: $$feature" ; \ 26 | cargo check --manifest-path components/boards/Cargo.toml --features $$feature ; \ 27 | done 28 | 29 | cargo check --manifest-path components/utils/Cargo.toml 30 | cargo check --manifest-path components/utils/Cargo.toml --all-features 31 | 32 | .PHONY: doc 33 | doc: 34 | $(MAKE) -C runners/embedded doc-nk3am 35 | 36 | .PHONY: lint 37 | lint: 38 | cargo fmt -- --check 39 | $(MAKE) -C runners/embedded lint-all 40 | $(MAKE) -C runners/nkpk lint 41 | $(MAKE) -C runners/usbip lint 42 | 43 | .PHONY: binaries 44 | binaries: 45 | mkdir -p binaries 46 | $(MAKE) -C runners/embedded build-all FEATURES= 47 | cp runners/embedded/artifacts/runner-lpc55-nk3xn.bin binaries/firmware-nk3xn.bin 48 | cp runners/embedded/artifacts/runner-lpc55-nk3xn.elf binaries/firmware-nk3xn.elf 49 | cp runners/embedded/artifacts/runner-nrf52-bootloader-nk3am.bin.ihex binaries/firmware-nk3am.ihex 50 | $(MAKE) -C runners/embedded build-all FEATURES=provisioner 51 | cp runners/embedded/artifacts/runner-lpc55-nk3xn.bin binaries/provisioner-nk3xn.bin 52 | cp runners/embedded/artifacts/runner-lpc55-nk3xn.elf binaries/provisioner-nk3xn.elf 53 | cp runners/embedded/artifacts/runner-nrf52-bootloader-nk3am.bin.ihex binaries/provisioner-nk3am.ihex 54 | $(MAKE) -C runners/embedded build-all FEATURES=test 55 | cp runners/embedded/artifacts/runner-lpc55-nk3xn.bin binaries/firmware-nk3xn-test.bin 56 | cp runners/embedded/artifacts/runner-lpc55-nk3xn.elf binaries/firmware-nk3xn-test.elf 57 | cp runners/embedded/artifacts/runner-nrf52-bootloader-nk3am.bin.ihex binaries/firmware-nk3am-test.ihex 58 | $(MAKE) -C runners/nkpk build 59 | cp runners/nkpk/artifacts/runner-nkpk.elf binaries/firmware-nkpk.elf 60 | cp runners/nkpk/artifacts/runner-nkpk.bin.ihex binaries/firmware-nkpk.ihex 61 | $(MAKE) -C runners/nkpk build FEATURES=provisioner 62 | cp runners/nkpk/artifacts/runner-nkpk.elf binaries/provisioner-nkpk.elf 63 | cp runners/nkpk/artifacts/runner-nkpk.bin.ihex binaries/provisioner-nkpk.ihex 64 | 65 | .PHONY: metrics 66 | metrics: binaries 67 | repometrics generate > metrics.toml 68 | 69 | license.txt: 70 | cargo run --release --manifest-path utils/collect-license-info/Cargo.toml -- runners/embedded/Cargo.toml "Nitrokey 3" > license.txt 71 | 72 | commands.bd: 73 | cargo run --release --manifest-path utils/gen-commands-bd/Cargo.toml -- runners/embedded/Cargo.toml > $@ 74 | 75 | manifest.json: 76 | sed "s/@VERSION@/`git describe --always`/g" utils/manifest.template.json > manifest.json 77 | 78 | .PHONY: software-tests 79 | software-tests: 80 | cd components/apps && cargo test 81 | cd components/boards && cargo test 82 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Nitrokey 3 Firmware 2 | 3 | This repository contains the firmware of Nitrokey 3 USB keys. 4 | 5 | ## About 6 | 7 | The Nitrokey 3 firmware is written in [Rust][]. It uses the [Trussed][] firmware framework and is developed in collaboration with [SoloKeys][] (see the [solo2][] repository). 8 | 9 | [Rust]: https://rust-lang.org 10 | [Trussed]: https://trussed.dev/ 11 | [SoloKeys]: https://solokeys.com/ 12 | [solo2]: https://github.com/solokeys/solo2 13 | 14 | ## Documentation 15 | 16 | Documentation for users is available in the [Nitrokey 3 section on docs.nitrokey.com][docs.nitrokey.com]. For developer documentation, see the [`docs`](./docs/index.md) directory. 17 | 18 | [docs.nitrokey.com]: https://docs.nitrokey.com/nitrokey3/index.html 19 | 20 | ## Dependencies 21 | 22 | To build the firmware from source, you need these dependencies: 23 | 24 | - Rust (current stable release for the `thumbv8m.main-none-eabi` target with the `llvm-tools-preview` component) 25 | - clang with development headers 26 | - [`flip-link`][] 27 | - [`cargo-binutils`][] 28 | 29 | [`flip-link`]: https://github.com/knurling-rs/flip-link 30 | [`cargo-binutils`]: https://github.com/rust-embedded/cargo-binutils 31 | 32 | To flash the firmware to the device, you need [`mboot`][] or [`lpc55`][]. 33 | 34 | [`mboot`]: https://github.com/molejar/pyMBoot 35 | [`lpc55`]: https://github.com/lpc55/lpc55-host 36 | 37 | ## License 38 | 39 | This software is fully open source. 40 | 41 | All software, unless otherwise noted, is dual licensed under [Apache 2.0](LICENSE-APACHE) and [MIT](LICENSE-MIT). 42 | You may use the software under the terms of either the Apache 2.0 license or MIT license. 43 | 44 | 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. 45 | 46 | ## Funding 47 | 48 | [Logo NLnet: abstract logo of four people seen from above](https://nlnet.nl/) 49 | [Logo NGI Zero: letterlogo shaped like a tag](https://nlnet.nl/NGI0/) 50 | 51 | This project was funded through the [NGI0 PET](https://nlnet.nl/PET) Fund, a fund established by [NLnet](https://nlnet.nl/) with financial support from the European Commission's [Next Generation Internet programme](https://ngi.eu/), under the aegis of DG Communications Networks, Content and Technology under grant agreement No 825310. 52 | -------------------------------------------------------------------------------- /components/apps/src/migrations.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused)] 2 | 3 | use admin_app::migrations::Migrator; 4 | use littlefs2_core::path; 5 | 6 | pub(crate) const MIGRATION_VERSION_SPACE_EFFICIENCY: u32 = 1; 7 | const MIGRATION_VERSION_FIDO_RK_DIR: u32 = 2; 8 | 9 | #[cfg(feature = "backend-auth")] 10 | pub(crate) const TRUSSED_AUTH_FS_LAYOUT: trussed_auth_backend::FilesystemLayout = 11 | trussed_auth_backend::FilesystemLayout::V1; 12 | #[cfg(feature = "se050")] 13 | pub(crate) const SE050_BACKEND_FS_LAYOUT: trussed_se050_backend::FilesystemLayout = 14 | trussed_se050_backend::FilesystemLayout::V1; 15 | 16 | pub(crate) const MIGRATORS: &[Migrator] = &[ 17 | // We first migrate the SE050 since this migration deletes data to make sure that the other 18 | // migrations succeed even on low block availability 19 | #[cfg(feature = "se050")] 20 | Migrator { 21 | migrate: |ifs, _efs| { 22 | trussed_se050_backend::migrate::migrate_remove_all_dat(ifs, &[path!("/opcard")]) 23 | }, 24 | version: MIGRATION_VERSION_SPACE_EFFICIENCY, 25 | }, 26 | #[cfg(feature = "backend-auth")] 27 | Migrator { 28 | migrate: |ifs, _efs| { 29 | trussed_auth_backend::migrate::migrate_remove_dat( 30 | ifs, 31 | &[ 32 | path!("opcard"), 33 | path!("webcrypt"), 34 | path!("secrets"), 35 | path!("piv"), 36 | ], 37 | ) 38 | }, 39 | version: MIGRATION_VERSION_SPACE_EFFICIENCY, 40 | }, 41 | #[cfg(feature = "fido-authenticator")] 42 | Migrator { 43 | migrate: |ifs, _efs| fido_authenticator::migrate::migrate_no_rp_dir(ifs, path!("fido/dat")), 44 | version: MIGRATION_VERSION_FIDO_RK_DIR, 45 | }, 46 | ]; 47 | -------------------------------------------------------------------------------- /components/boards/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "boards" 3 | edition = "2021" 4 | version.workspace = true 5 | 6 | [dependencies] 7 | apdu-dispatch = "0.3" 8 | apps = { path = "../apps", features = ["fido-authenticator"] } 9 | cortex-m = "0.7" 10 | cortex-m-rtic = "1.0" 11 | cortex-m-rt = "0.6.15" 12 | ctaphid-dispatch = "0.3" 13 | delog = "0.1" 14 | embedded-hal = "0.2.3" 15 | embedded-time = "0.12" 16 | generic-array = "0.14" 17 | interchange = "0.3" 18 | littlefs2 = { workspace = true, features = ["c-stubs"] } 19 | memory-regions = { path = "../memory-regions" } 20 | nb = "1" 21 | nfc-device = { path = "../nfc-device" } 22 | rand = { version = "0.8.5", default-features = false } 23 | rand_chacha = { version = "0.3.1", default-features = false } 24 | ref-swap = "0.1.0" 25 | spi-memory = "0.2.0" 26 | trussed = { version = "0.1", default-features = false } 27 | usb-device = "0.2" 28 | usbd-ccid = "0.3" 29 | usbd-ctaphid = "0.3" 30 | utils = { path = "../utils" } 31 | 32 | # soc-lpc55 33 | lpc55-hal = { version = "0.4", optional = true } 34 | lpc55-pac = { version = "0.4", optional = true } 35 | systick-monotonic = { version = "1.0.0", optional = true } 36 | 37 | # soc-nrf52 38 | embedded-storage = { version = "0.3", optional = true } 39 | nrf52840-hal = { version = "0.15.1", optional = true } 40 | nrf52840-pac = { version = "0.11", optional = true } 41 | 42 | # board-nk3am 43 | lfs-backup = { path = "../lfs-backup", optional = true } 44 | 45 | # board-nk3xn 46 | fm11nc08 = { path = "../fm11nc08", optional = true } 47 | 48 | # logging 49 | cortex-m-semihosting = { version = "0.3.5", optional = true } 50 | rtt-target = { version = "0.3", features = ["cortex-m"], optional = true } 51 | 52 | # se050 53 | se05x = { version = "0.2.0", optional = true } 54 | 55 | trussed-manage = "0.2.0" 56 | 57 | [dev-dependencies] 58 | littlefs2-core = { version = "0.1", features = ["debug-error"] } 59 | 60 | [features] 61 | board-nk3am = ["soc-nrf52", "lfs-backup", "se05x/embedded-hal-v0.2.7"] 62 | board-nk3xn = ["soc-lpc55", "fm11nc08", "utils/storage", "se05x/embedded-hal-v0.2.7"] 63 | board-nkpk = ["board-nk3am", "utils/storage"] 64 | 65 | soc-lpc55 = ["lpc55-hal", "lpc55-pac", "se05x?/lpc55-v0.4", "systick-monotonic"] 66 | soc-nrf52 = ["embedded-storage", "nrf52840-hal", "nrf52840-pac", "se05x?/nrf"] 67 | 68 | log-all = [] 69 | log-trace = [] 70 | log-debug = [] 71 | log-info = [] 72 | log-warn = [] 73 | log-error = [] 74 | log-none = [] 75 | 76 | log-rtt = ["rtt-target"] 77 | log-semihosting = ["cortex-m-semihosting"] 78 | 79 | no-buttons = [] 80 | no-delog = [] 81 | no-encrypted-storage = [] 82 | format-filesystem = [] 83 | provisioner = ["apps/provisioner-app"] 84 | se050 = ["se05x", "apps/se050"] 85 | trussed-auth = ["apps/backend-auth"] 86 | -------------------------------------------------------------------------------- /components/boards/src/nk3am/migrations/ftl_journal/backends.rs: -------------------------------------------------------------------------------- 1 | use littlefs2::driver::Storage; 2 | use trussed::types::Bytes; 3 | 4 | use lfs_backup::{BackupBackend, FSBackupError, Result, MAX_DUMP_BLOB_LENGTH}; 5 | 6 | use crate::nk3am::ExternalFlashStorage; 7 | 8 | pub struct EFSBackupBackend<'a> { 9 | extflash: &'a mut ExternalFlashStorage, 10 | initial_offset: usize, 11 | offset: usize, 12 | len: usize, 13 | } 14 | 15 | impl<'a> EFSBackupBackend<'a> { 16 | pub fn new(extflash: &'a mut ExternalFlashStorage, offset: usize, len: usize) -> Self { 17 | Self { 18 | extflash, 19 | initial_offset: offset, 20 | offset, 21 | len, 22 | } 23 | } 24 | } 25 | 26 | impl BackupBackend for EFSBackupBackend<'_> { 27 | // would be good to get this from ext-flash directly 28 | const RW_SIZE: usize = 256; 29 | 30 | fn write(&mut self, content: &[u8]) -> Result { 31 | let len = 32 | content.len() + ((Self::RW_SIZE - (content.len() % Self::RW_SIZE)) % Self::RW_SIZE); 33 | let mut data: Bytes = Bytes::from_slice(content).unwrap(); 34 | 35 | data.resize(len, 0x00) 36 | .map_err(|_| FSBackupError::BackendWriteErr)?; 37 | 38 | let count = self 39 | .extflash 40 | .write(self.offset, &data) 41 | .map_err(|_| FSBackupError::BackendWriteErr)?; 42 | self.offset += data.len(); 43 | 44 | //trace_now!("W-addr: {} len: {} datalen: {}", self.offset, content.len(), data.len()); 45 | //trace_now!("W-data: {} = {:?}", data); 46 | 47 | Ok(count) 48 | } 49 | 50 | fn read(&mut self, len: usize) -> Result> { 51 | let mut output = Bytes::::default(); 52 | output.resize_default(len).expect("assuming: N > len"); 53 | 54 | self.extflash 55 | .read(self.offset, &mut output) 56 | .map_err(|_| FSBackupError::BackendReadErr)?; 57 | 58 | self.offset += 59 | output.len() + ((Self::RW_SIZE - (output.len() % Self::RW_SIZE)) % Self::RW_SIZE); 60 | 61 | //trace_now!("R-addr: {} len {:}", self.offset, output.len()); 62 | //trace_now!("R-data {:?}", output); 63 | 64 | Ok(output) 65 | } 66 | 67 | fn erase(&mut self) -> Result { 68 | self.extflash 69 | .erase(self.initial_offset, self.len) 70 | .map_err(|_| FSBackupError::BackendEraseErr)?; 71 | self.offset = self.initial_offset; 72 | Ok(self.len) 73 | } 74 | 75 | fn reset(&mut self) { 76 | self.offset = self.initial_offset; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /components/boards/src/nk3am/migrations/ftl_journal/ifs_flash_old.rs: -------------------------------------------------------------------------------- 1 | use embedded_storage::nor_flash::{NorFlash, ReadNorFlash}; 2 | 3 | use crate::nk3am::MEMORY_REGIONS; 4 | 5 | const FS_BASE: usize = MEMORY_REGIONS.filesystem.start; 6 | const FS_CEIL: usize = MEMORY_REGIONS.filesystem.end; 7 | 8 | pub const FLASH_BASE: *mut u8 = FS_BASE as *mut u8; 9 | pub const FLASH_SIZE: usize = FS_CEIL - FS_BASE; 10 | 11 | pub struct FlashStorage { 12 | nvmc: nrf52840_hal::nvmc::Nvmc, 13 | } 14 | 15 | impl littlefs2::driver::Storage for FlashStorage { 16 | const BLOCK_SIZE: usize = 256; 17 | const READ_SIZE: usize = 4; 18 | const WRITE_SIZE: usize = 4; 19 | const BLOCK_COUNT: usize = FLASH_SIZE / Self::BLOCK_SIZE; 20 | 21 | type CACHE_SIZE = generic_array::typenum::U256; 22 | type LOOKAHEAD_SIZE = generic_array::typenum::U1; 23 | 24 | fn read(&mut self, off: usize, buf: &mut [u8]) -> Result { 25 | // w/o this too much spam is generated, thus writes/deletes traces get lost 26 | if buf.len() > 4 { 27 | trace!("IFr {:x} {:x}", off, buf.len()); 28 | } 29 | let res = self.nvmc.read(off as u32, buf); 30 | nvmc_to_lfs_return(res, buf.len()) 31 | } 32 | 33 | fn write(&mut self, off: usize, buf: &[u8]) -> Result { 34 | trace!("IFw {:x} {:x}", off, buf.len()); 35 | let res = self.nvmc.write(off as u32, buf); 36 | nvmc_to_lfs_return(res, buf.len()) 37 | } 38 | 39 | fn erase(&mut self, off: usize, len: usize) -> Result { 40 | trace!("EE {:x} {:x}", off, len); 41 | 42 | const REAL_BLOCK_SIZE: usize = 4 * 1024; 43 | 44 | let block_off: usize = off - (off % REAL_BLOCK_SIZE); 45 | 46 | let mut buf: [u8; REAL_BLOCK_SIZE] = [0x00; REAL_BLOCK_SIZE]; 47 | self.nvmc 48 | .read(block_off as u32, &mut buf) 49 | .expect("EE - failed read"); 50 | let erase_res = self 51 | .nvmc 52 | .erase(block_off as u32, (block_off + REAL_BLOCK_SIZE) as u32); 53 | 54 | let left_end: usize = off - block_off; 55 | if left_end > 0 { 56 | self.nvmc 57 | .write(block_off as u32, &buf[..left_end]) 58 | .expect("EE - failed write 1"); 59 | } 60 | 61 | let right_off: usize = left_end + len; 62 | if REAL_BLOCK_SIZE - right_off > 0 { 63 | self.nvmc 64 | .write((off + len) as u32, &buf[right_off..]) 65 | .expect("EE - failed write 2"); 66 | } 67 | 68 | nvmc_to_lfs_return(erase_res, len) 69 | } 70 | } 71 | 72 | /** 73 | * Source Result type does not provide a useful Ok value, and Destination Result type 74 | * does not contain a meaningful low-level error code we could return; so here goes 75 | * the most stupid result conversion routine ever 76 | */ 77 | fn nvmc_to_lfs_return( 78 | r: Result<(), nrf52840_hal::nvmc::NvmcError>, 79 | len: usize, 80 | ) -> Result { 81 | r.map(|_| len).map_err(|_| littlefs2::io::Error::IO) // 'NVMC' 82 | } 83 | 84 | impl FlashStorage { 85 | pub fn new(nvmc_pac: nrf52840_hal::pac::NVMC) -> Self { 86 | let buf = unsafe { core::slice::from_raw_parts_mut(FLASH_BASE, FLASH_SIZE) }; 87 | let nvmc = nrf52840_hal::nvmc::Nvmc::new(nvmc_pac, buf); 88 | Self { nvmc } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /components/boards/src/nk3am/migrations/ftl_journal/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod backends; 2 | pub mod ifs_flash_old; 3 | 4 | use littlefs2::fs::{Allocation, Filesystem}; 5 | 6 | use backends::EFSBackupBackend; 7 | use ifs_flash_old::FlashStorage as OldFlashStorage; 8 | use lfs_backup::{BackupBackend, FSBackupError, Result}; 9 | 10 | use crate::nk3am::{ExternalFlashStorage, InternalFlashStorage}; 11 | 12 | pub fn migrate( 13 | old_ifs_storage: &mut OldFlashStorage, 14 | old_ifs_alloc: &mut Allocation, 15 | ifs_alloc: &mut Allocation, 16 | ifs_storage: &mut InternalFlashStorage, 17 | efs_storage: &mut ExternalFlashStorage, 18 | ) -> Result<()> { 19 | let old_mounted = Filesystem::mount(old_ifs_alloc, old_ifs_storage) 20 | .map_err(|_| FSBackupError::LittleFs2Err)?; 21 | 22 | trace!("old IFS mount success - migrating"); 23 | 24 | // ext.flash = 2MB, spare for e.g., backup operations = 128kb (at end) 25 | let spare_len = 4096 * 32; 26 | let spare_offset = (2 * 1024 * 1024) - spare_len; 27 | let mut backend = EFSBackupBackend::new(efs_storage, spare_offset, spare_len); 28 | 29 | backend.erase()?; 30 | 31 | trace!("backing: old IFS -> backend"); 32 | backend.backup(&old_mounted)?; 33 | 34 | // only format IFS on failed backup... 35 | trace!("backup done, format new IFS"); 36 | let _fmt_ifs = Filesystem::format(ifs_storage); 37 | ifs_storage.format_journal_blocks(); 38 | 39 | let new_mounted = 40 | Filesystem::mount(ifs_alloc, ifs_storage).map_err(|_| FSBackupError::LittleFs2Err)?; 41 | 42 | trace!("restore: backend -> new IFS"); 43 | backend.reset(); 44 | let _res = backend.restore(&new_mounted)?; 45 | 46 | // any outcome should erase the external flash contents 47 | backend.erase()?; 48 | Ok(()) 49 | } 50 | -------------------------------------------------------------------------------- /components/boards/src/nk3am/migrations/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod ftl_journal; 2 | -------------------------------------------------------------------------------- /components/boards/src/nk3xn.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "se050")] 2 | use embedded_hal::{blocking::delay::DelayUs, timer::CountDown}; 3 | #[cfg(feature = "se050")] 4 | use embedded_time::duration::Microseconds; 5 | #[cfg(feature = "se050")] 6 | use lpc55_hal::drivers::Timer; 7 | use lpc55_hal::{ 8 | drivers::pins::{Pio0_9, Pio1_14}, 9 | peripherals::{ctimer, flexcomm::I2c5}, 10 | typestates::{ 11 | init_state::Unknown, 12 | pin::{ 13 | function::{FC5_CTS_SDA_SSEL0, FC5_TXD_SCL_MISO_WS}, 14 | state::Special, 15 | }, 16 | }, 17 | I2cMaster, Pin, 18 | }; 19 | #[cfg(feature = "se050")] 20 | use se05x::embedded_hal::Hal027; 21 | 22 | use memory_regions::MemoryRegions; 23 | use utils::OptionalStorage; 24 | 25 | use crate::{flash::ExtFlashStorage, soc::lpc55::Lpc55, Board}; 26 | 27 | pub mod button; 28 | pub mod led; 29 | pub mod nfc; 30 | pub mod prince; 31 | pub mod spi; 32 | 33 | #[cfg(feature = "no-encrypted-storage")] 34 | use trussed::types::LfsResult; 35 | 36 | #[cfg(feature = "no-encrypted-storage")] 37 | lpc55_hal::littlefs2_filesystem!(InternalFilesystem: (prince::FS_START, prince::BLOCK_COUNT)); 38 | #[cfg(not(feature = "no-encrypted-storage"))] 39 | use prince::InternalFilesystem; 40 | 41 | use nfc::NfcChip; 42 | use spi::{FlashCs, Spi}; 43 | 44 | pub const MEMORY_REGIONS: &MemoryRegions = &MemoryRegions::NK3XN; 45 | 46 | pub type PwmTimer = ctimer::Ctimer3; 47 | pub type ButtonsTimer = ctimer::Ctimer1; 48 | 49 | pub type I2C = I2cMaster< 50 | Pio0_9, 51 | Pio1_14, 52 | I2c5, 53 | ( 54 | Pin>, 55 | Pin>, 56 | ), 57 | >; 58 | 59 | pub struct NK3xN; 60 | 61 | impl Board for NK3xN { 62 | type Soc = Lpc55; 63 | 64 | type Resources = (); 65 | 66 | type NfcDevice = NfcChip; 67 | type Buttons = button::ThreeButtons; 68 | type Led = led::RgbLed; 69 | 70 | type InternalStorage = InternalFlashStorage; 71 | type ExternalStorage = ExternalFlashStorage; 72 | 73 | #[cfg(feature = "se050")] 74 | type Se050Timer = Hal027>>>; 75 | #[cfg(feature = "se050")] 76 | type Twi = Hal027; 77 | #[cfg(not(feature = "se050"))] 78 | type Twi = (); 79 | #[cfg(not(feature = "se050"))] 80 | type Se050Timer = (); 81 | 82 | const BOARD_NAME: &'static str = "nk3xn"; 83 | const HAS_NFC: bool = true; 84 | } 85 | 86 | pub type InternalFlashStorage = InternalFilesystem; 87 | pub type ExternalFlashStorage = OptionalStorage>; 88 | 89 | #[cfg(feature = "se050")] 90 | pub struct TimerDelay(pub T); 91 | 92 | #[cfg(feature = "se050")] 93 | impl DelayUs for TimerDelay 94 | where 95 | T: CountDown