Skip to content
Draft
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
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ simulator with a uniform interface.
* [Thread safety](#thread-safety)
* [UTA Key Hierarchy](#uta-key-hierarchy)
* [TPM TCG and TPM IBM](#tpm-tcg-and-tpm-ibm)
* [Rust Bindings](#rust-bindings)
* [Coding Standard](#coding-standard)
* [Versioning](#versioning)

Expand Down Expand Up @@ -502,6 +503,13 @@ primary HMAC key in the endorsement hierarchy using the 8 Byte string
+----------------------+ +-------------------------------+
```

## Rust Bindings

This library includes an interface for the [Rust programming
language](https://rust-lang.org/), located in the rust-bindings subdirectory.
For detailed instructions and usage information, please refer to the dedicated
[README file](rust-bindings/README.md).

## Coding Standard
The UTA library code is oriented to the Barr Group's Embedded C Coding Standard.

Expand Down
32 changes: 32 additions & 0 deletions rust-bindings/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Rust Wrapper for the Unified Trust Anchor API

This project is part of the libuta library and provides a Rust wrapper
implemented in the crate `libuta_rust`, along with example usage in the
`examples` crate.

For detailed information, please refer to the crate’s documentation in the
corresponding [README.md](libuta_rust/README.md)

The examples crate is organized as follows and serves as a starting point for
integrating `libuta_rust` into your own projects:

```
├── Cargo.toml
└── src
└── main.rs
```

Build and run the examples as follows:

```
cargo build
cargo run
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a minor thing, you have 2 separate rust projects (two Cargo.toml files) rather than a single project with examples. If you have a single rust project, there is a standard approach to run examples #cargo run --example <example_name>. But a separate example project is easier to take and integrate by the user.

```

## Licensing

This work is licensed under the term of the Apache License, Version 2.0.
Copyright (c) 2025 Siemens Mobility GmbH.

* SPDX-FileCopyrightText: Copyright 2025 Siemens
* SPDX-License-Identifier: Apache-2.0
17 changes: 17 additions & 0 deletions rust-bindings/examples/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Unified Trust Anchor API Rust Wrapper
#
# Copyright (c) Siemens Mobility GmbH, 2025
#
# Authors:
# Christian P. Feist <christian.feist@siemens.com>
# Hermann Seuschek <hermann.seuschek@siemens.com>
#
# This work is licensed under the terms of the Apache Software License
# 2.0. See the COPYING file in the top-level directory.
#
# SPDX-FileCopyrightText: Copyright 2025 Siemens
# SPDX-License-Identifier: Apache-2.0
#
/target
**/*.rs.bk
Cargo.lock
33 changes: 33 additions & 0 deletions rust-bindings/examples/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Unified Trust Anchor API Rust Wrapper
#
# Copyright (c) Siemens Mobility GmbH, 2025
#
# Authors:
# Christian P. Feist <christian.feist@siemens.com>
# Hermann Seuschek <hermann.seuschek@siemens.com>
#
# This work is licensed under the terms of the Apache Software License
# 2.0. See the COPYING file in the top-level directory.
#
# SPDX-FileCopyrightText: Copyright 2025 Siemens
# SPDX-License-Identifier: Apache-2.0
#
[package]
name = "examples"
version = "1.2.0"
authors = ["Christian P. Feist <christian.feist@siemens.com>", "Hermann Seuschek <hermann.seuschek@siemens.com>"]
edition = "2018"

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

[dependencies]
libuta_rust = {path = "../libuta_rust"}

[[bin]]
name = "uta_examples"
path = "src/main.rs"

[profile.release]
opt-level = "z"
lto = true
strip = true
58 changes: 58 additions & 0 deletions rust-bindings/examples/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/* Unified Trust Anchor API Rust Wrapper
*
* Example code that demonstrates the use of the libuta Rust wrapper.
*
* Copyright (c) Siemens Mobility GmbH, 2025
*
* Authors:
* Christian P. Feist <christian.feist@siemens.com>
* Hermann Seuschek <hermann.seuschek@siemens.com>
*
* This work is licensed under the terms of the Apache Software License
* 2.0. See the COPYING file in the top-level directory.
*
* SPDX-FileCopyrightText: Copyright 2025 Siemens
* SPDX-License-Identifier: Apache-2.0
*/
extern crate libuta_rust;
use libuta_rust::UtaApiV1;

fn main() {

match UtaApiV1::new() {
Ok(ref mut uta) => {

println!("Execute uta.get_version() ...");
match uta.get_version() {
Ok(uuid) => println!("Library version: {:?}\n", uuid),
Err(e) => println!("Error calling uta.get_version(), got error code {:?}\n", e.get_rc())
}

println!("Execute uta.self_test() ...");
match uta.self_test() {
Ok(()) => println!("Success!\n"),
Err(e) => println!("Error calling uta.self_test(), got error code {:?}\n", e.get_rc())
}

println!("Execute uta.get_device_uuid() ...");
match uta.get_device_uuid() {
Ok(uuid) => println!("Device UUID bytes: {:?}\n", uuid),
Err(e) => println!("Error calling uta.get_device_uuid(), got error code {:?}\n", e.get_rc())
}

println!("Execute uta.derive_key(32, &dv, 0) ...");
let dv = vec![1u8; 8];
match uta.derive_key(32, &dv, 0) {
Ok(key) => println!("Derived key: {:?}\n", key),
Err(e) => println!("Error calling uta.derive_key(), got error code {:?}\n", e.get_rc())
}

println!("Execute uta.get_random(32) ...");
match uta.get_random(32) {
Ok(random) => println!("Random bytes: {:?}\n", random),
Err(e) => println!("Error calling uta.get_random(), got error code {:?}\n", e.get_rc())
}
},
Err(e) => println!("Error on uta.init(), got error code {:?}", e.get_rc())
}
}
17 changes: 17 additions & 0 deletions rust-bindings/libuta_rust/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Unified Trust Anchor API Rust Wrapper
#
# Copyright (c) Siemens Mobility GmbH, 2025
#
# Authors:
# Christian P. Feist <christian.feist@siemens.com>
# Hermann Seuschek <hermann.seuschek@siemens.com>
#
# This work is licensed under the terms of the Apache Software License
# 2.0. See the COPYING file in the top-level directory.
#
# SPDX-FileCopyrightText: Copyright 2025 Siemens
# SPDX-License-Identifier: Apache-2.0
#
/target
**/*.rs.bk
Cargo.lock
36 changes: 36 additions & 0 deletions rust-bindings/libuta_rust/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Unified Trust Anchor API Rust Wrapper
#
# Copyright (c) Siemens Mobility GmbH, 2025
#
# Authors:
# Christian P. Feist <christian.feist@siemens.com>
# Hermann Seuschek <hermann.seuschek@siemens.com>
#
# This work is licensed under the terms of the Apache Software License
# 2.0. See the COPYING file in the top-level directory.
#
# SPDX-FileCopyrightText: Copyright 2025 Siemens
# SPDX-License-Identifier: Apache-2.0
#
[package]
name = "libuta_rust"
license = "Apache-2.0"
description = "Rust wrapper for the Unified Trust Anchor API (libuta)"
repository = "https://github.com/siemens/libuta"
readme = "README.md"
version = "1.2.0"
authors = ["Christian P. Feist <christian.feist@siemens.com>", "Hermann Seuschek <hermann.seuschek@siemens.com>"]
edition = "2018"
build = "build.rs"

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

[build-dependencies]
bindgen = "0.71.1"

[lib]
path = "src/lib.rs"

[profile.release]
opt-level = 0
lto = true
128 changes: 128 additions & 0 deletions rust-bindings/libuta_rust/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
# Rust Wrapper for the Unified Trust Anchor API

This crate provides a lightweight Rust wrapper around the C implementation of
the Unified Trust Anchor API (libuta). The underlying C bindings are generated
using [bindgen](https://rust-lang.github.io/rust-bindgen/introduction.html),
while additional Rust code exposes these low-level interfaces through a more
idiomatic Rust API.

## Licensing

This work is licensed under the terms of the Apache License, Version 2.0.
Copyright (c) 2025 Siemens Mobility GmbH.

* SPDX-FileCopyrightText: Copyright 2025 Siemens
* SPDX-License-Identifier: Apache-2.0

## Prerequisites

* Proper installation of libuta
* The header file `uta.h` must be available in the compiler’s include
path (e.g., `/usr/local/include/uta.h`)
* The shared library must be accessible in the system library path (e.g.,
`/usr/lib` or `/lib`). **Note:** `/usr/local/lib` is not included in
the default search path on Debian-based systems. To add it manually,
use: `export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH`
* Installation of Rust envionment (On Debian-based systems: `apt install rustc`)
* Tested with the following Rust toolchain: `rustc 1.85.0 (4d91de4e4 2025-02-17)`
* LLVM installed (required by bindgen). For details, see [bindgen requirements](https://rust-lang.github.io/rust-bindgen/requirements.html)

## Architecture of the Rust bindings

The Rust bindings for libuta are structured in two layers. The lower layer
(mod bindings) provides a direct mapping of the C API to Rust and is primarily
generated using bindgen, exposing all available symbols. The upper layer (mod api)
builds on top of bindings, importing only the necessary components and
presenting them through an idiomatic Rust interface. This high-level wrapper
enhances usability by incorporating Rust-style error handling and memory
management. The following diagram illustrates the architecture from the native
libuta library up to its integration in a Rust application:

```
+--------------------+
| application |
| e.g., examples |
| (Rust) |
+--------------------+
| crate: libuta_rust |
| mod api |
| mod bindings |
| (Rust) |
+--------------------+
| libuta |
| (C) |
+--------------------+
```

## Wrapper library (`libuta_rust`)

The directory `libuta_rust` contains the primary wrapper crate designed for use in
Rust applications through an idiomatic Rust interface. Its purpose is to
encapsulate the data structures, types, and functions defined in the low-level
C implementation exposed by the generated bindings. This includes replacing
patterns such as "output parameters" with Rust-native constructs like
`Result<T>` for error handling, and managing context within an instance of the
`UtaApiV1` structure. These design choices significantly reduce the risk of
misuse and provide a safer, more ergonomic API for developers.

Basic unit tests have been implemented to verify the core functionality of the
library. Please note that the expected outputs for certain functions rely on
default keys provided by the software simulation embedded in libuta. When
executed against a real hardware secure element, these keys differ, resulting
in mismatches between actual and expected values. Consequently, some unit tests
may fail under hardware conditions even though the underlying functionality is
correct. Since the keys used by hardware implementations are unknown in
advance, the test code cannot be adapted to produce matching results.

**Note:** An `UtaApiV1` instance must always be declared as mutable because
most methods require `&mut self`. While this may initially seem
counterintuitive, it reflects the fact that the object’s internal state changes
frequently, particularly when managing context, such as acquiring or releasing
locks. This behavior is mandated by the underlying C library interface, and
therefore cannot be avoided.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a remark: in your use-case the mutable reference to self makes more sense, but there is also a way how to avoid a mutable reference in every method: RWLock.


The file structure of crate `libuta_rust` is as follows:

```
├── Cargo.toml
├── build.rs
├── README.md
└── src
├── lib.rs
├── bindings.h
└── bindings.rc
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bindings.rs maybe?

```

Building and testing the library:

```
cargo build
cargo test
```

### Low-level bindings (mod bindings)

The file bindings.rc includes the low-level Rust bindings for the libuta
library. These bindings are generated using bindgen and supplemented
with additional code to suppress warnings caused by Rust naming conventions.
The bindgen tool is invoked automatically by Cargo during the build process, so
manual execution is not required. The build steps are implemented in build.rs,
which translates the input header file bindings.h (including the main libuta
header) into Rust bindings accessible through src/bindings.rs. Because this
layer is a direct one-to-one mapping of the C API, it is not intended for
direct use in Rust applications. Instead, it serves as the foundation for the
higher-level wrapper located in the lib.rs file.

**Note:** The Rust compiler emits warnings regarding the use of 128-bit integers
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's great that you explain why you suppress some warnings 👍

because **bindings for this data type are not yet fully stable and may break
compatibility in future releases.** These warnings are explicitly suppressed in
the code. Additional warnings related to naming conventions are also
suppressed, as the original libuta naming is preserved to maintain consistency
with the underlying C API. Since this low-level binding layer is not intended
for direct use in Rust applications, but rather serves as the foundation for
the higher-level wrapper, these warnings do not pose a practical issue.

**Note:** Rust introduces several C-based dependencies through libuta.
Vulnerabilities in any of these linked C libraries could potentially be
exploited, even when accessed via a Rust abstraction layer. At present, these
dependencies cannot be removed because they are integral to libuta.
42 changes: 42 additions & 0 deletions rust-bindings/libuta_rust/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/** @file build.rs
*
* @brief This code orchestrates the bindgen tool to create Rust-bindings.
*
* @copyright Copyright (c) Siemens Mobility GmbH, 2025
*
* @author Christian P. Feist <christian.feist@siemens.com>
* @author Hermann Seuschek <hermann.seuschek@siemens.com>
*
* @license This work is licensed under the terms of the Apache Software License
* 2.0. See the COPYING file in the top-level directory.
*
* SPDX-FileCopyrightText: Copyright 2025 Siemens
* SPDX-License-Identifier: Apache-2.0
*/
extern crate bindgen;
use std::env;
use std::path::PathBuf;

fn main() {
println!("cargo:rerun-if-changed=src/bindings.h");

// The bindgen::Builder is the main entry point to bindgen
let bindings = bindgen::Builder::default()
// The input header we would like to generate bindings for.
.header("src/bindings.h")
// Invalidate the built crate whenever included header files change.
.parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
// Finish the builder and generate the bindings.
.generate()
// Unwrap the Result and panic on failure.
.expect("Unable to generate bindings");

// Write the bindings to file $OUT_DIR/bindings.rs
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
bindings
.write_to_file(out_path.join("bindgen_bindings.rs"))
.expect("Couldn't write bindings!");

// Ensure the crate links against the libuta C library
println!("cargo:rustc-link-lib=uta");
}
Loading