Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ members = ["crates/tropic01-driver"]

[workspace.package]
edition = "2024"
version = "0.1.0"
version = "0.0.1"
rust-version = "1.88"
authors = ["PatinaKey <contact@patinakey.fr>"]
repository = "https://github.com/PatinaKey/firmware"
license = "GPL-3.0-or-later"
Expand All @@ -28,7 +29,7 @@ hmac = { version = "0.13", default-features = false }
# release candidates. the last STABLE curve releases (p384 0.13, ecdsa 0.16) speak the older
# digest 0.10 generation and would pull a SECOND copy of sha2/digest into the
# binary. Pinning the rc keeps a single crypto generation, which is the smaller
# audit and flash surface.
# audit and flash surface.
# TODO: drop the -rc pins once p384/p521 0.14 and ecdsa 0.17 ship stable.
ecdsa = { version = "0.17.0-rc.19", default-features = false }
p384 = { version = "0.14.0-rc.11", default-features = false, features = ["ecdsa"] }
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

[![CI](https://github.com/PatinaKey/firmware/actions/workflows/ci.yml/badge.svg)](https://github.com/PatinaKey/firmware/actions/workflows/ci.yml)
[![License: GPL-3.0-or-later](https://img.shields.io/badge/License-GPL--3.0--or--later-blue.svg)](LICENSE)
[![Rust 1.95+](https://img.shields.io/badge/Rust-1.95%2B%20edition%202024-orange.svg)](https://doc.rust-lang.org/edition-guide/)
[![Rust 1.88+](https://img.shields.io/badge/Rust-1.88%2B%20edition%202024-orange.svg)](https://doc.rust-lang.org/edition-guide/)
[![no_std](https://img.shields.io/badge/no__std-bare--metal-green.svg)](https://docs.rust-embedded.org/book/intro/no-std.html)

Open-source Rust firmware for **PatinaKey**, a USB hardware security key implementing FIDO2, OpenPGP card, and PKCS#11.
Expand Down Expand Up @@ -51,7 +51,7 @@ The project is under active development. Only the secure-element driver (`crates

## Building

Developed using rustc 1.95. No guarantee is provided that the code will work with an earlier version.
Minimum supported Rust version (MSRV): 1.88 (edition 2024), verified to build. Developed on a newer stable. No guarantee is provided below 1.88.

```sh
# Host check and tests
Expand Down
24 changes: 18 additions & 6 deletions crates/tropic01-driver/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,27 @@
name = "tropic01-driver"
edition.workspace = true
version.workspace = true
rust-version.workspace = true
authors.workspace = true
repository.workspace = true
license.workspace = true
description = "Unofficial no_std, panic-free Rust driver for the TROPIC01 secure element."
readme = "README.md"
documentation = "Not published to docs.rs yet."
keywords = ["tropic01", "secure-element", "no-std", "no_std", "embedded", "crypto"]
keywords = ["tropic01", "secure-element", "no-std", "embedded", "crypto"]
categories = ["embedded", "no-std", "cryptography", "hardware-support"]
# Dev/validation tooling kept out of the published package. The crate is the
# library. The fuzz harness has its own detached workspace and the scripts need
# external services.
exclude = ["/fuzz", "/scripts"]

[features]
# X.509 attestation chain verification (verify_cert_chain, parse_verified_stpub,
# RootAnchor, read_verified_chip_stpub). ON by default. It pulls the ECDSA curve
# crates (ecdsa / p384 / p521). Disable via default-features = false to drop
# those deps when only STPUB extraction (parse_stpub / read_chip_stpub) is
# needed. The handshake still binds STPUB, so a session stays authenticated.
default = ["attestation"]
attestation = ["dep:ecdsa", "dep:p384", "dep:p521"]
# Exposes the `fuzz` module (attacker-facing parsers) to libFuzzer harnesses.
# Not for production. Enabled only by the fuzz crate.
_fuzz = []
Expand All @@ -33,9 +40,14 @@ x25519-dalek = { workspace = true }
aes-gcm = { workspace = true }
sha2 = { workspace = true }
hmac = { workspace = true }
ecdsa = { workspace = true }
p384 = { workspace = true }
p521 = { workspace = true }
ecdsa = { workspace = true, optional = true }
p384 = { workspace = true, optional = true }
p521 = { workspace = true, optional = true }

# Render the attestation API on docs.rs. Explicit (not all-features) so the
# dev-only _fuzz / model-itest modules stay hidden from the published docs.
[package.metadata.docs.rs]
features = ["attestation"]

[lints]
workspace = true
workspace = true
72 changes: 66 additions & 6 deletions crates/tropic01-driver/README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,69 @@
# tropic01-driver - TROPIC01 secure-element driver (no_std)

[![crates.io](https://img.shields.io/crates/v/tropic01-driver.svg)](https://crates.io/crates/tropic01-driver)
[![docs.rs](https://docs.rs/tropic01-driver/badge.svg)](https://docs.rs/tropic01-driver)
[![MSRV 1.88+](https://img.shields.io/badge/MSRV-1.88-blue.svg)](https://www.rust-lang.org)
[![License: GPL-3.0-or-later](https://img.shields.io/badge/license-GPL--3.0--or--later-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)


> **BETA - unofficial, NOT silicon-validated.** This is an early `0.0.x`
> release. The driver has been validated host-side against the official
> `tropic01_model` emulator, but it has NOT run on real TROPIC01 silicon. Do not
> use it for production trust decisions yet.

A `no_std`, heap-free, `unsafe-free` Rust driver for the **TROPIC01** secure
element (Tropic Square, part `TR01-C2P-T301`), spoken over SPI through an
authenticated, encrypted **Noise KK1** session.

⚠️ Disclaimer: This is an unofficial, community-driven project. It is not affiliated with, endorsed by, or officially supported by Tropic Square. For the official SDK, please refer to Tropic Square's libtropic.
## Quick start

The integrator supplies the SPI bus (`embedded_hal::spi::SpiDevice`) and a
ready/timeout provider (the crate's `SeWait` trait). All key material is
caller-provided via `SessionConfig`. Open a channel, run a command, close it:

```rust,no_run
use tropic01_driver::{SeCommands, SessionConfig, StartupId, Tropic01};
use zeroize::Zeroizing;

fn run(spi: impl embedded_hal::spi::SpiDevice, wait: impl tropic01_driver::SeWait)
-> Result<(), tropic01_driver::SeError>
{
let mut dev = Tropic01::new(spi, wait);
dev.reboot(StartupId::Reboot)?; // load the Application firmware

// Placeholder keys: real ephemerals come from a TRNG, the pairing keys from
// provisioning, and `stpub` from the chip certificate. For a genuine-chip
// trust decision, get `stpub` via `read_verified_chip_stpub` (not the
// unverified `read_chip_stpub`) against an out-of-band-pinned `RootAnchor`.
let ehpriv = Zeroizing::new([0u8; 32]);
let shipriv = Zeroizing::new([0u8; 32]);
let shipub = [0u8; 32];
let stpub = [0u8; 32];
let cfg = SessionConfig
{
ehpriv: &ehpriv,
shipriv: &shipriv,
shipub: &shipub,
stpub: &stpub,
pkey_index: 0,
};
// open_session reports its error as a tuple (handle, error).
let mut session = dev.open_session(cfg).map_err(|(_dev, e)| e)?;

let mut random = [0u8; 32];
session.random_into(&mut random)?;
let _dev = session.close_session();
Ok(())
}
```

The `attestation` feature (ON by default) enables X.509 chain verification
(`verify_cert_chain` / `read_verified_chip_stpub`) and pulls the ECDSA curve
crates (`ecdsa` / `p384` / `p521`), which are PRE-RELEASE (`-rc`) today (pinned to
keep one `digest` generation in the tree). Build with `default-features = false`
to drop those dependencies when only STPUB extraction is needed.

**Disclaimer:** This is an unofficial, community-driven project. It is not affiliated with, endorsed by, or officially supported by Tropic Square. For the official SDK, please refer to Tropic Square's libtropic.

Written as a clean-room rewrite with the official C SDK
[`libtropic`](https://github.com/tropicsquare/libtropic) used as a differential
Expand Down Expand Up @@ -106,11 +165,12 @@ This runs in the normal hermetic test suite.
The TROPIC01 command surface is fully wired: every L2 request and L3 command,
attestation, and the firmware-update bootloader are implemented.

Non-command work toward a publishable crate: validate against silicon (the
`tropic01_model` emulator is already wired, see
[Validation](#validation-against-real-libtropic)), examples on docs.rs,
and an optional `embedded-hal`-based port so external users can plug
their own HAL (currently the ports are the crate's own `SpiDevice` / `SeWait` traits).
Work toward a production `1.0`: validate against real silicon (the
`tropic01_model` emulator is wired, see
[Validation](#validation-against-real-libtropic), but no silicon run yet). Move the
`ecdsa` / `p384` / `p521` curve crates off their release candidates once stable
versions on the same `digest` generation ship. A type-state `open_session` that
consumes a chain-verified STPUB and an `embedded-hal-async` path.

## Design principles

Expand Down
2 changes: 1 addition & 1 deletion crates/tropic01-driver/fuzz/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion crates/tropic01-driver/fuzz/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ libfuzzer-sys = "0.4"

[dependencies.tropic01-driver]
path = ".."
features = ["_fuzz"]
# attestation is needed so the verify_cert_chain fuzz target still builds.
features = ["_fuzz", "attestation"]

[[bin]]
name = "parse_l2_response"
Expand Down
Loading
Loading