This repository is a Cargo workspace containing reference implementations of GlobalPlatform Trusted Platform Services (TPS) specifications, together with a set of libraries and command-line tools for working with the IETF CBOR ecosystem that those specifications are built on.
Two things live here:
- The TPS Client API — a reference implementation of the GlobalPlatform TPS Client API
(
specifications/GPP_TPS_Client_API_Spec_v1.0_PublicRelease_signed.pdf), with a sample Connector and a sample Service, suitable for constrained embedded targets. - A CBOR/COSE/CDDL toolchain — encoders, decoders, validators, tree-sitter grammars and CLI/TUI/GUI tools used to author and inspect the artifacts the TPS services exchange.
The Client API is implemented as a library which can be linked with anything that exposes a C language FFI (which means virtually anything). It also provides a Rust API to simplify integration with applications written in Rust.
Communication with Secure Components is provided by Connectors, which provide an abstract service-oriented interface to TPS Services implemented on Secure Components.
The TPS APIs make heavy use of CBOR and related technologies such as COSE and CDDL, which are standardized by the IETF.
The crates that make up a shipped TPS Client API implementation are no_std by default, with
an opt-in std feature used for host-side testing and tooling. Platform-specific code is
featurized rather than assumed, so the same sources build for a host and for bare metal.
The developer tools in this workspace (cose-tool, edn-tool, cbor-tui, ts-highlight,
cddl, the GUI and the tree-sitter grammars) are std-only by design — they are not intended
to be deployed to a constrained target.
tock/ contains a bare-metal validation of the Client API on TockOS,
running the client and the ROT13 service as two separate Tock processes over Tock IPC, against
unmodified tps_client_api, tps_connector and rot13_service crates. It targets the
Raspberry Pi Pico (Arm Cortex-M0+) and the OpenTitan/Ibex earlgrey-cw310 board (RISC-V, run
under QEMU). It is a separate, isolated Cargo workspace and is deliberately not built by
the root cargo build --workspace. See tock/README.md.
Current version: 0.10.0. All crates are Rust edition 2024.
The TPS Client API implementation is complete through Phase 6 of
specifications/TPS_CLIENT_API_PLAN.md, which is the living plan and decision record for this
work — including spec errata found during implementation and the rationale for each design
ruling. The automated bare-metal round-trip test passes on Ibex/QEMU; Pico build, package and
flash tooling is complete, with on-hardware observation documented as a manual step.
CODE_REVIEW_CAMPAIGN.md tracks the multi-stage spec-compliance and code review of the core
crates.
tps_client_apiimplements most of the Client API functionality in a Rust crate.tps_client_cwrapstps_client_apiin a C language API and builds a statically linkable library (libtps_client_api_c.a), allowing the TPS Client API to be used anywhere that supports a C language FFI. It links against any library exporting thetps_connectorAPI. The C header (tps_client_c/tpsc_client_api.h) is generated bycbindgenfrom the crate'sbuild.rs.tps_client_commonprovides definitions used across multiple crates in a system. It has no dependencies.tps_errorcontains error definitions for any crate using the TPS API ecosystem.tps_connectordefines an API which enables security component back-ends to be called fromtps_client_api. Both Rust and C language APIs are provided, allowing Connector instances to be written in either language.rot13_connectorprovides a minimal implementation of the TPS Connector API.rot13_serviceprovides a minimal implementation of a TPS Service (in this case, ROT13 "encryption").
tps_minicboris an implementation of CBOR (RFC 8949) encoding and decoding with preferred serialization, requiring neither an allocator nor the standard library.tps_coseis an implementation of COSE (RFC 9052) encoding and decoding, supporting a selection of crypto algorithms.tps_cddlis a CDDL (RFC 8610) parser, validator and code generator, with support for RFC 9165 and RFC 9682.
tps_cose_toolprovides thecose-toolCLI for COSE_Sign1/COSE_Encrypt0 operations and COSE key management (plus agen-testdatahelper).tps_edn_toolprovides theedn-toolCLI for converting between CBOR extended diagnostic notation (EDN) and binary CBOR.tps_cddladditionally provides thecddlCLI for validating CDDL, checking CBOR/JSON against a schema, and generatingtps_minicborencoders/decoders from a schema.tps_cbor_tuiprovidescbor-tui, a terminal workbench for CDDL editing, CBOR/EDN viewing and COSE sign/encrypt.tps_cbor_guiis a cross-platform Tauri GUI IDE for the CBOR/COSE/CDDL ecosystem. The Rust crate lives intps_cbor_gui/src-tauri.tps_ts_highlight_toolprovidests-highlight, a terminal syntax-highlighting preview for the tree-sitter grammars below.tree-sitter-cddlis a tree-sitter grammar for CDDL.tree-sitter-ednis a tree-sitter grammar for CBOR EDN.
USAGE.md— walkthrough of thetps_minicborandtps_coseAPIs.CONTRIBUTING.md— contribution process, DCO sign-off, GPG signing and dependency licensing rules.specifications/TPS_CLIENT_API_PLAN.md— Client API implementation plan, spec errata and design rulings.CODE_REVIEW_CAMPAIGN.md— code review campaign scope and progress.specifications/— the TPS Client API specification and the relevant IETF RFCs.- Individual crates carry their own
README.mdand, where useful,DESIGN.md.
All parts of this project are MIT licensed. See LICENSE for the full text. Every crate
declares license = "MIT", and every source file authored for this project carries the header:
Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries
SPDX-License-Identifier: MIT
(EDN files use "and its subsidiaries" without the slash, because RFC 8610 Appendix G.6 delimits
an EDN comment with a pair of / and a slash inside one would terminate it early.)
Third-party content is covered by its own upstream licenses and retains its own copyright
notices: code vendored under tock/third_party/ (the Tock kernel, libtock-rs and elf2tab,
included as git submodules), the tree-sitter runtime headers under
tree-sitter-{cddl,edn}/src/tree_sitter/, the IETF RFC and draft texts under specifications/,
tps_cose/, tps_cddl/ and tps_minicbor/, the COSE test vectors in
tps_cose/tests/Examples/, and GlobalPlatform normative material.
The workspace is built with Cargo. The CMakeLists.txt files are a legacy path retained only
for building the C example (see below); they are not required to build the Rust crates.
- Rust toolchain 1.85 or later. All crates are edition 2024, which 1.85 is the first release
to support. There is no root
rust-toolchain.toml, so your default toolchain is used. - cbindgen on
PATH.tps_client_c/build.rsinvokes thecbindgenbinary to regeneratetpsc_client_api.hand fails the build if it is absent. Install withcargo install --force cbindgen. - A C compiler, needed to build the
tree-sitter-cddlandtree-sitter-edngrammars.
Only if you want to build tps_cbor_gui:
- Tauri system dependencies — on Linux this includes
webkit2gtkand its development headers; see the Tauri prerequisites. - Node.js and npm, for the GUI frontend.
To build everything except the GUI:
cargo build --workspace --exclude tps_cbor_gui --features stdTo run the test suite:
cargo test --workspace --exclude tps_cbor_gui --features stdThe std feature is what makes the crates testable on a host; it pulls in, among other things,
the critical-section implementation that tps_client_api's global service store needs at link
time. A real no_std consumer registers its own via critical_section::set_impl! — see the
comments in tps_client_api/Cargo.toml and tock/tock_rot13_client for a worked example.
To check that the Client API crates still build in their normal no_std configuration:
cargo check -p tps_client_common -p tps_error -p tps_connector -p tps_client_apiThe TPS Client API crates pass raw pointers across extern "C" boundaries, where neither the
compiler nor cargo test can detect aliasing or pointer-provenance violations — such code can
compile without warnings, pass its tests and still be undefined behaviour.
Miri interprets MIR instead of running native code and does
detect them, along with out-of-bounds accesses, reads of uninitialized memory, misaligned
accesses and data races.
run_miri.sh runs the test suites of the six crates that contain unsafe code under Miri:
./run_miri.sh # all six crates, Stacked Borrows (Miri's default model)
./run_miri.sh -t # the stricter, experimental Tree Borrows model
./run_miri.sh -p tps_client_c # a single crate
./run_miri.sh -- some_filter # pass a test-name filter to the harnessIt needs a nightly toolchain with the miri component — Miri is not available on stable:
rustup toolchain install nightly
rustup component add --toolchain nightly miri rust-srcBoth aliasing models currently report no undefined behaviour. Notes on the setup:
- The script sets
-Zmiri-disable-isolation, needed because severaltps_client_ctests read the cbindgen-generatedtpsc_client_api.hfrom disk and Miri denies filesystem access by default. It grants host access only and does not relax any UB check. - Tests that cannot run under Miri are marked
#[cfg_attr(miri, ignore = "...")]at the test rather than filtered inside the script, so the reason stays with the test. Only two are excluded, both because they spawn a subprocess (cc,false), which Miri cannot do. tree-sitter-cddlandtree-sitter-ednlink a C parser, so Miri cannot execute them; the remaining crates (tps_minicbor,tps_cose,tps_cddland the CLI/TUI tools) are safe Rust and are not covered by the script.- Miri is slow — roughly a few seconds per crate under Stacked Borrows and several times that
under Tree Borrows, against hundredths of a second natively. It is a pre-merge check on the
unsafecrates, not part of the normal edit-compile-test loop.
tps_client_c/c_example/c_example.c is about the simplest possible example of performing a
service discovery and then performing an "encryption" using the ROT13 service. The object file
produced by compiling it is linked against the static libraries generated for the TPS Client API
(libtps_client_api_c.a) and for the ROT13 Connector (librot13_connector.a). It depends on
the C standard library, even though the Rust components do not.
Build the static libraries and link the example (from the top of the repository):
cargo build -p tps_client_c -p rot13_connector --features std
cc -std=c99 -I tps_client_c -o c_example tps_client_c/c_example/c_example.c \
target/debug/libtps_client_api_c.a target/debug/librot13_connector.a \
-lpthread -ldl -lm
./c_exampleEach crate's std feature forwards to the std features of its dependencies, so enabling it on
the two crates that produce static libraries is enough: tps_client_c/std pulls in
tps_client_api/std, which in turn enables critical-section/std and so registers the
critical_section::Impl the link needs.
The expected output is:
Input Message
ca,
a1, 1, 70, 54, 68, 69, 73, 67,
6f, 65, 73, 74, 6f, 65, 6c, 65,
76, 65, 6e,
Received Message
ca,
a1, 1, 70, 47, 75, 76, 66, 74,
62, 72, 66, 67, 62, 72, 79, 72,
69, 72, 61,
An older CMake-driven build of the C example is still present
(CMakeLists.txt, tps_client_c/CMakeLists.txt, rot13_connector/CMakeLists.txt,
rot13_service/CMakeLists.txt, tps_client_c/c_example/CMakeLists.txt). It needs CMake 3.20 or
later plus CMakeRust, whose cmake directory must be
copied into a cmake_rust/ directory at the top of this repository — that directory is not
checked in, and this path is not covered by CI. Prefer the Cargo instructions above.
Credit to the team at Devolutions for CMakeRust, which is dual MIT/Apache-2.0 licensed.
tock/ is a separate Cargo workspace with its own toolchain pinning, git submodules and build
scripts. See tock/README.md for setup and for the build_opentitan.sh /
run_opentitan_test.sh / build_pico.sh / flash_pico.sh workflows.