Skip to content

Commit

Permalink
First end-to-end working prototype of the TPS Client APIs
Browse files Browse the repository at this point in the history
An end-to-end working demo of the TPS Client APIs which should work on any desktop
class machine, and should be easily portable into constrained embedded devices as
the Rust components do not require the Rust standard library (c_example requires a
C library currently)

There is a very basic demo of how to write a connector and TPS Service in Rust - ROT13.

- tps_error: Common Rust error handling for TPS crates
- tps_connector: Common Connector API definitions
- tps_client_common: Common definitions for TPS crates (no dependencies)
- tps_client_c: C language API (and example program) for the TPS Client API
- tps_client_api: The TPS Client API Rust library

At this point the code is of "demo" quality and intended to show the basic operation of
the APIs. Code should be thread-safe, but has not been extensively tested.

Signed-off-by: Jeremy O'Donoghue <[email protected]>
  • Loading branch information
quic-jodonogh committed Oct 21, 2022
1 parent 2625c50 commit 0c27126
Show file tree
Hide file tree
Showing 39 changed files with 4,893 additions and 24 deletions.
30 changes: 30 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Copyright © 2022, Qualcomm Innovation Center, Inc. All rights reserved.
#
# 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.

cmake_minimum_required(VERSION 3.20)
project(tps_client_api C)

set(CMAKE_C_STANDARD 99)
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake_rust")
enable_language(Rust)
include(CMakeCargo)

include_directories(tps_client_c)

add_subdirectory(tps_client_c)
add_subdirectory(rot13_connector)
add_subdirectory(tps_client_c/c_example)

33 changes: 33 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Copyright (c) 2021, 2022, Qualcomm Innovation Center, Inc. All rights reserved. Jeremy O'Donoghue. All rights reserved.
#
# 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.
[workspace]

members = [
"rs_minicbor",
"rs_cddl",
"tps_client_common",
"tps_error",
"tps_client_api",
"tps_client_c",
"tps_connector",
"rot13_connector",
"rot13_service"
]

[profile.release]
opt-level = 'z'
lto = true
1 change: 1 addition & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
MIT License

Copyright © 2019-2021, Qualcomm Innovation Center, Inc. All rights reserved.
Copyright (c) 2021 GlobalPlatform ®

Permission is hereby granted, free of charge, to any person obtaining a copy
Expand Down
124 changes: 100 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,39 +1,115 @@
# TPS API Reference Implementations
## TPS Client API

This project provides a set of reference implementations for specifications created
by the [GlobalPlatform](https://globalplatform.org) Trusted Platform Services
Committee and its Working Groups.
## Overview

The Trusted Platform Services Committee aims to create APIs which allow application
developers to use standardized security services hosted on Secure Components such as
a Trusted Execution Environment, a Secure Element or a Trusted Platform Module (TPM).
This crate contains a reference implementation of the GlobalPlatform TPS Client API.
This implementation is intended to be suitable for relatively constrained embedded targets.

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 implementations are intended to support `no_std` environments and thus have no
dependency on the Rust standard library.

The Trusted Platform Services APIs make heavy use of
[CBOR](https://www.rfc-editor.org/info/rfc8949) and related technologies such as
[COSE](https://www.rfc-editor.org/info/rfc8152) and
[CDDL](https://www.rfc-editor.org/info/rfc8610), which are standardized by the IETF.

The reference implementations on this site are, where appropriate, intended to be
usable on relatively constrained embedded microcontroller platforms (circa 200-500kB RAM/ROM).
This project is composed of multiple sub-crates:

As this is a new project, we have preference for contributions in the
[Rust](https://rust-lang.org) programming language.
- `tps_client_api` implements most of the Client API functionality in a Rust crate.
- `tps_client_api_c` creates a statically linkable C library with a C language API
which allows the TPS Client API to be used anywhere that supports a C language FFI.
This library includes `tps_client_api`, and is able to connect to libraries that
export the `tps_connector` API.
- `tps_client_common` provides definitions that are used across multiple crates in
a system. It has no dependencies.
- `tps_error` contains error definitions for any crate using the TPS API ecosystem.
- `tps_connector` defines an API which enables security component back-ends to be
called from `tps_client_api`. Both Rust and C language APIs are provided,
allowing Connector instances to be written in either language.
- `rot13_connector` provides a minimal implementation of the TPS Connector API
- `rot13_service` provides a minimal implementation of a TPS Service (in this case, ROT13
"encryption).
- `rs_minicbor` is an implementation of [IETF CBOR (RFC8949)](https://www.rfc-editor.org/rfc/rfc8949.html)
encoding and decoding, with no requirement for an allocator or the standard
library.

## License

Contributions *and their dependencies* must be MIT licensed or provided under a
compatible license. Dual-licensed (Apache 2 OR MIT) dependencies, which are
common in the Rust language ecosystem, are fine.
All parts of the TPS Client API are MIT licensed, See LICENSE.

## Building

> The current version of the project is built using CMake. This is likely to change
> in a future version to a build system based entirely on Cargo.
The build system is in a state of flux, and doesn't manage generated header files as
it should. The following instructions should enable you to build and run the example
and tests.

### Build dependencies

You will need to have the following installed:

- Rust toolchain (tested for Rust v1.64.0)
- [cbindgen](https://github.com/eqrion/cbindgen)
- `cargo install --force cbindgen` is easiest way to install.
- CMake (tested for version 3.20 - this is set as a lower bound in the scripts, so
older versions will not work)
- Install from [CMake downloads](https://cmake.org/download/) or your package manager.
- [CMakeRust](https://github.com/Devolutions/CMakeRust)
- Instructions to use CMakeRust can be found on
[Devolutions blog](https://blog.devolutions.net/2018/06/insider-series-using-rust-code-in-a-cc-project-with-cmake/)

#### Using CMakeRust in the build system

Create a directory in the top of the repo for CMakeRust:

`cd <path_to_tps_repository>`
`mkdir cmake_rust`

Copy the contents of the cmake directory in the CMakeRust repository into the `cmake_rust` directory. I have
the following files:

- `CargoLink.cmake`
- `CMakeCargo.cmake`
- `CMakeDetermineRustCOmpiler.cmake`
- `CMakeRustCompiler.cmake.in`
- `CMakeRustInformation.cmake`
- `CMakeTestRustCompiler.cmake`
- `FindRust.cmake`
- Various license files.

Credit to the team at [Devolutions](https://devolutions.net) for CMakeRust, which is dual MIT/Apache2 licensed.

### Building the example

This assumes that you are in the top directory of the repository.

`cd <path_to_tps_repository`

Next, create a directory for CMake artifacts

`mkdir cmake-build-debug`

Now you need to build everything with Cartgo, as this generates headers.

`cargo build`

This takes 30 seconds or so on my moderately powerful laptop with a decent internet connection.

The easiest way to verify license conditions is to install `cargo license` and
run it inside each crate.
```
cd cmake-build-debug
cmake ..
cd ..
cmake --build cmake-build-debug
```

## Components
### Running the Example

- [**`rs_minicbor`**](rs_minicbor/README.md): An implementation of
[RFC 8949 Concise Binary Object Representation (CBOR)](https://www.rfc-editor.org/rfc/rfc8949)
intended for use on embedded platforms, or other places where the developer requires more
control over serialization and deserialization than something like SERDE CBOR.
- [**`rs_cddl`**](rs_cddl/README.md): Tooling for working with
[RFC8610 Concise Data Definition Language](https://www.rfc-editor.org/rfc/rfc8610.txt). This
tooling is at an early development phase, but does include a complete CDDL parser and AST.
16 changes: 16 additions & 0 deletions rot13_connector/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Copyright © 2022 Qualcomm Innovation Center, Inc. All rights reserved.
#
# 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.
cargo_build(NAME rot13_connector)
43 changes: 43 additions & 0 deletions rot13_connector/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Copyright © 2022 Qualcomm Innovation Center, Inc. All rights reserved.
#
# 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.
[package]
name = "rot13_connector"
version = "0.1.0"
edition = "2021"
license = "MIT"
authors = ["Jeremy O'Donoghue<[email protected]"]
description = "Minmal reference implementation of a Connector for the GlobalPlatform Trusted Platform Services API"
homepage = "https://globalplatform.org"
repository = "https://github.com/GlobalPlatform/TPS-API-Reference-Implementations"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
getrandom = { version = "0.2.7" }
tps_client_common = { path = "../tps_client_common" }
tps_connector = { path = "../tps_connector"}
tps_error = { path = "../tps_error" }
rot13_service = { path = "../rot13_service" }

[lib]
crate-type = ["lib", "staticlib"]

# [features] # Features not yet used
# std = []

[profile.release]
opt-level = 'z'
lto = true
125 changes: 125 additions & 0 deletions rot13_connector/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
# ROT13 Connector

A minimal example of TPS Client connector implementation in Rust.

The ROT13 Connector builds as a static (C-linkable) library exporting the
connector API

## License

`rot13_connector` is MIT licensed.

## Usage

The `rot13_connector` crate provides a minimal example of how to implement a
TPS connector. The implementation should work for connectors implemented both
as statically loadable libraries and as dynamically loaded libraries.

The connector API requires exports a single function:

```rust
pub unsafe extern "C" fn TPSC_GetConnectorAPI() -> *const Connector {}
```

Where the `Connector` definition is provided by the `tps_connector` crate.

### lib.rs

The underlying implementation of the top-level module is fairly simple: there
is a static structure, `CONNECTOR` which holds the required C callable APIs
for the connector. There are sample implementations of each of these
functions in the `c_api` module.

### c_api.rs

Each of the callable functions in the `c_api` module does some sanitization
of any pointers provided - this is necessarily limited mainly to checking
for NULL pointers - and calls the relevant function in the `service` module,
which is pure safe Rust.

It is quite likely that the functions in the `c_api` module can be re-used
without change in many implementations.

### service.rs

The majority of the sample implementation is in the `service` module.

To adapt this code to some other component, you will need to do at least the
following:

#### Secure Component Instance

Set the Secure Component Instance on which your service is running.

In this sample code I have used a randomly generated UUID. If you are
implementing on a real Secure Component, you should use an appropriate
mechanism to generate a repeatable, but statistically unique UUID for the
Secure Component Instance. Some Secure Component APIs may already provide
a suitable mechanism for this.

The TPS Client API Specification suggests some recommended ways to do this,
but the thing that matters is that the value is stable over time and
statistically unique.

#### Determine the Service Instance ID

As with the Secure Component Instance, this is a UUID and is required to
be statistically unique.

#### SERVICES array

During Service Discovery, a connector reports the services available from
the attached Secure Component.

The implementation in this sample is simplified too much to be used in most
real-world deployment scenarios, and is intended purely to show how the API
is expected to work.

The `SERVICES` array is a reference to an array of `ServiceIdentifier`
instances. Each `ServiceIdentifier` needs to define the following fields:

- `service_instance` a UUID which provides a unique and stable identifier
for the instance of a service on a Secure Component. This value *must* be
different for each service on a given secure component. Where there is
more than one Secure Component on a device, it *must* be unique across
devices. This means that you should generate this identity when a service
is installed or first created on a device.
- `service_id` a UUID which defines what the service does. This value *must*
be the same for all instances of the same type of service. GlobalPlatform
specifies UUIDs for every service that it defines, and here we use the
standard UUID for the ROT13 service.
- `secure_component_type` a UUID defining the type of Secure Component, for
example TEE, Secure Element, TPM etc., that the service runs on. Bodies
defining standardized Secure Components such as GlobalPlatform and the
Trusted Computing Group define these for the components they standardize.
In this case we use a "test" value, `GPP_TEST_SC_TYPE` which indicates
that we are using a test component for which no security guarantees are made.
- `service_version`: this is a structure indicating the version of the
service API that is supported. For specifications defined by GlobalPlatform,
this will align with the version of the GlobalPlatform document that defines
the specification.

## Platform requirements

The implementation does not require the standard library, except when compiled
for test.

This implementation is intended to run on constrained devices (bare-metal or
RTOS-based) which may not have rich synchronization and threading APIs. The
code is thread-safe if the underlying platform provides atomic operations, as
there is a dependency on `AtomicBool` and `AtomicU32`.

The provided implementation generates somewhat unpredictable values for
`session_id` using a random number generator. In general, the use of
unpredictable values of `session_id` has some security benefit, but it may
be acceptable to replace this with something simpler on some platforms. There
is in any case no expectation of cryptographic quality randomness here.

## Known Limitations

This implementation is unlikely to be well-suited to interactions with
complex Secure Components supporting dynamic installation and update of
services.

Currently the implementation of `execute_transaction` does not support
session handling, which prevents use with multi-service cases.
Loading

0 comments on commit 0c27126

Please sign in to comment.