Skip to content

Commit 218063b

Browse files
committed
First draft of rust-psa-crypto, Rust wrapper for (some of) mbed-crypto.
Currently this depends on an old version of mbed-crypto. These files are adapted from Parsec: build-conf.toml, build.rs, setup_mbed_crypto.sh Signed-off-by: Edmund Grimley Evans <[email protected]>
1 parent dd6c1cd commit 218063b

File tree

8 files changed

+992
-1
lines changed

8 files changed

+992
-1
lines changed

Cargo.toml

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
[package]
22
name = "psa-crypto"
33
version = "0.1.0"
4-
authors = ["Paul Howard <[email protected]>",
4+
authors = ["Edmund Grimley Evans <[email protected]>",
5+
"Paul Howard <[email protected]>",
56
"Ionut Mihalcea <[email protected]>",
67
"Hugues de Valon <[email protected]>"]
78
edition = "2018"
@@ -13,3 +14,13 @@ license = "Apache-2.0"
1314
repository = "https://github.com/parallaxsecond/rust-psa-crypto"
1415

1516
[dependencies]
17+
lazy_static = "1.4.0"
18+
19+
[build-dependencies]
20+
bindgen = "0.50.0"
21+
cargo_toml = "0.7.0"
22+
serde = { version = "1.0", features = ["derive"] }
23+
toml = "0.4.2"
24+
25+
[package.metadata.config]
26+
mbed-crypto-version = "mbedcrypto-2.0.0"

build-conf.toml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Configuration values for setting up and building the Mbed Crypto library that
2+
# psa-crypto currently depends on
3+
[mbed_config]
4+
# Path (either relative or absolute) where the Mbed Crypto source code will be
5+
# persisted.
6+
# This value default to the OUT_DIR environment variable.
7+
mbed_path = "/tmp/"
8+
9+
# When compiling natively
10+
[mbed_config.native]
11+
# The compiler to use when building the Mbed Crypto library
12+
# mbed_compiler = "clang"
13+
# The archiver to use when building the Mbed Crypto library
14+
# mbed_archiver = "ar"
15+
16+
# When cross-compiling for aarch64-unknown-linux-gnu target
17+
[mbed_config.aarch64_unknown_linux_gnu]
18+
# mbed_compiler = "aarch64-linux-gnu-gcc"
19+
# mbed_archiver = "aarch64-linux-gnu-ar"

build.rs

Lines changed: 277 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,277 @@
1+
// Copyright 2020 Contributors to the Parsec project.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
#![deny(
5+
nonstandard_style,
6+
const_err,
7+
dead_code,
8+
improper_ctypes,
9+
non_shorthand_field_patterns,
10+
no_mangle_generic_items,
11+
overflowing_literals,
12+
path_statements,
13+
patterns_in_fns_without_body,
14+
private_in_public,
15+
unconditional_recursion,
16+
unused,
17+
unused_allocation,
18+
unused_comparisons,
19+
unused_parens,
20+
while_true,
21+
missing_debug_implementations,
22+
trivial_casts,
23+
trivial_numeric_casts,
24+
unused_extern_crates,
25+
unused_import_braces,
26+
unused_qualifications,
27+
unused_results,
28+
missing_copy_implementations
29+
)]
30+
// This one is hard to avoid.
31+
#![allow(clippy::multiple_crate_versions)]
32+
33+
use cargo_toml::{Manifest, Value};
34+
use serde::Deserialize;
35+
use std::env;
36+
use std::io::{Error, ErrorKind, Result};
37+
use std::path::{Path, PathBuf};
38+
39+
const CONFIG_TABLE_NAME: &str = "config";
40+
const MBED_CRYPTO_VERSION_KEY: &str = "mbed-crypto-version";
41+
42+
const SETUP_MBED_SCRIPT_PATH: &str = "./setup_mbed_crypto.sh";
43+
const BUILD_CONFIG_FILE_PATH: &str = "./build-conf.toml";
44+
45+
const DEFAULT_NATIVE_MBED_COMPILER: &str = "clang";
46+
const DEFAULT_NATIVE_MBED_ARCHIVER: &str = "ar";
47+
const DEFAULT_ARM64_MBED_COMPILER: &str = "aarch64-linux-gnu-gcc";
48+
const DEFAULT_ARM64_MBED_ARCHIVER: &str = "aarch64-linux-gnu-ar";
49+
50+
#[derive(Debug, Deserialize)]
51+
struct Configuration {
52+
mbed_config: Option<MbedConfig>,
53+
}
54+
55+
#[derive(Debug, Deserialize)]
56+
struct MbedConfig {
57+
mbed_path: Option<String>,
58+
native: Option<Toolchain>,
59+
aarch64_unknown_linux_gnu: Option<Toolchain>,
60+
}
61+
62+
#[derive(Debug, Deserialize)]
63+
struct Toolchain {
64+
mbed_compiler: Option<String>,
65+
mbed_archiver: Option<String>,
66+
}
67+
68+
fn get_configuration_string(parsec_config: &Value, key: &str) -> Result<String> {
69+
let config_value = get_value_from_table(parsec_config, key)?;
70+
match config_value {
71+
Value::String(string) => Ok(string.clone()),
72+
_ => Err(Error::new(
73+
ErrorKind::InvalidInput,
74+
"Configuration key missing",
75+
)),
76+
}
77+
}
78+
79+
fn get_value_from_table<'a>(table: &'a Value, key: &str) -> Result<&'a Value> {
80+
match table {
81+
Value::Table(table) => table.get(key).ok_or_else(|| {
82+
println!("Config table does not contain configuration key: {}", key);
83+
Error::new(ErrorKind::InvalidInput, "Configuration key missing.")
84+
}),
85+
_ => Err(Error::new(
86+
ErrorKind::InvalidInput,
87+
"Value provided is not a TOML table",
88+
)),
89+
}
90+
}
91+
92+
// Get the Mbed Crypto version to branch on from Cargo.toml file. Use that and MbedConfig to pass
93+
// parameters to the setup_mbed_crypto.sh script which clones and builds Mbed Crypto and create
94+
// a static library.
95+
fn setup_mbed_crypto(mbed_config: &MbedConfig, mbed_version: &str) -> Result<()> {
96+
let (mbed_compiler, mbed_archiver) =
97+
if std::env::var("TARGET").unwrap() == "aarch64-unknown-linux-gnu" {
98+
let toolchain;
99+
toolchain = mbed_config
100+
.aarch64_unknown_linux_gnu
101+
.as_ref()
102+
.ok_or_else(|| {
103+
Error::new(
104+
ErrorKind::InvalidInput,
105+
"The aarch64_unknown_linux_gnu subtable of mbed_config should exist",
106+
)
107+
})?;
108+
(
109+
toolchain
110+
.mbed_compiler
111+
.clone()
112+
.unwrap_or_else(|| DEFAULT_ARM64_MBED_COMPILER.to_string()),
113+
toolchain
114+
.mbed_archiver
115+
.clone()
116+
.unwrap_or_else(|| DEFAULT_ARM64_MBED_ARCHIVER.to_string()),
117+
)
118+
} else {
119+
let toolchain;
120+
toolchain = mbed_config.native.as_ref().ok_or_else(|| {
121+
Error::new(
122+
ErrorKind::InvalidInput,
123+
"The native subtable of mbed_config should exist",
124+
)
125+
})?;
126+
(
127+
toolchain
128+
.mbed_compiler
129+
.clone()
130+
.unwrap_or_else(|| DEFAULT_NATIVE_MBED_COMPILER.to_string()),
131+
toolchain
132+
.mbed_archiver
133+
.clone()
134+
.unwrap_or_else(|| DEFAULT_NATIVE_MBED_ARCHIVER.to_string()),
135+
)
136+
};
137+
138+
let script_fail = |_| {
139+
Err(Error::new(
140+
ErrorKind::Other,
141+
"setup_mbed_crypto.sh script failed",
142+
))
143+
};
144+
145+
println!("cargo:rerun-if-changed={}", SETUP_MBED_SCRIPT_PATH);
146+
println!("cargo:rerun-if-changed={}", "src/c/Makefile");
147+
println!("cargo:rerun-if-changed={}", "src/c/shim.c");
148+
println!("cargo:rerun-if-changed={}", "src/c/shim.h");
149+
150+
if !::std::process::Command::new(SETUP_MBED_SCRIPT_PATH)
151+
.arg(mbed_version)
152+
.arg(
153+
mbed_config
154+
.mbed_path
155+
.clone()
156+
.unwrap_or_else(|| env::var("OUT_DIR").unwrap()),
157+
)
158+
.arg(format!("CC={}", mbed_compiler))
159+
.arg(format!("AR={}", mbed_archiver))
160+
.status()
161+
.or_else(script_fail)?
162+
.success()
163+
{
164+
Err(Error::new(
165+
ErrorKind::Other,
166+
"setup_mbed_crypto.sh returned an error status.",
167+
))
168+
} else {
169+
Ok(())
170+
}
171+
}
172+
173+
fn generate_mbed_bindings(mbed_config: &MbedConfig, mbed_version: &str) -> Result<()> {
174+
let mbed_include_dir = mbed_config
175+
.mbed_path
176+
.clone()
177+
.unwrap_or_else(|| env::var("OUT_DIR").unwrap())
178+
+ "/mbed-crypto-"
179+
+ mbed_version
180+
+ "/include";
181+
let header = mbed_include_dir.clone() + "/psa/crypto.h";
182+
183+
println!("cargo:rerun-if-changed={}", header);
184+
185+
let shim_bindings = bindgen::Builder::default()
186+
.clang_arg(format!("-I{}", mbed_include_dir))
187+
.rustfmt_bindings(true)
188+
.header("src/c/shim.h")
189+
.generate_comments(false)
190+
.generate()
191+
.or_else(|_| {
192+
Err(Error::new(
193+
ErrorKind::Other,
194+
"Unable to generate bindings to mbed crypto",
195+
))
196+
})?;
197+
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
198+
shim_bindings.write_to_file(out_path.join("shim_bindings.rs"))
199+
}
200+
201+
// Get the compiler, the archiver and the location where to clone the Mbed Crypto repository.
202+
fn parse_config_file() -> Result<Configuration> {
203+
let config_str = ::std::fs::read_to_string(Path::new(BUILD_CONFIG_FILE_PATH))?;
204+
Ok(toml::from_str(&config_str).or_else(|e| {
205+
println!("Error parsing build configuration file ({}).", e);
206+
Err(Error::new(
207+
ErrorKind::InvalidInput,
208+
"Could not parse build configuration file.",
209+
))
210+
})?)
211+
}
212+
213+
fn main() -> Result<()> {
214+
// Parsing build-conf.toml
215+
let config = parse_config_file()?;
216+
217+
// Parsing Cargo.toml
218+
let toml_path = std::path::Path::new("./Cargo.toml");
219+
if !toml_path.exists() {
220+
return Err(Error::new(
221+
ErrorKind::InvalidInput,
222+
"Could not find Cargo.toml.",
223+
));
224+
}
225+
let manifest = Manifest::from_path(&toml_path).or_else(|e| {
226+
println!("Error parsing Cargo.toml ({}).", e);
227+
Err(Error::new(
228+
ErrorKind::InvalidInput,
229+
"Could not parse Cargo.toml.",
230+
))
231+
})?;
232+
233+
let package = manifest.package.ok_or_else(|| {
234+
Error::new(
235+
ErrorKind::InvalidInput,
236+
"Cargo.toml does not contain package information.",
237+
)
238+
})?;
239+
let metadata = package.metadata.ok_or_else(|| {
240+
Error::new(
241+
ErrorKind::InvalidInput,
242+
"Cargo.toml does not contain package metadata.",
243+
)
244+
})?;
245+
let parsec_config = get_value_from_table(&metadata, CONFIG_TABLE_NAME)?;
246+
247+
if true {
248+
let mbed_config = config.mbed_config.ok_or_else(|| {
249+
Error::new(
250+
ErrorKind::InvalidInput,
251+
"Could not find mbed_config table in the config file.",
252+
)
253+
})?;
254+
255+
let mbed_version = get_configuration_string(&parsec_config, MBED_CRYPTO_VERSION_KEY)?;
256+
257+
setup_mbed_crypto(&mbed_config, &mbed_version)?;
258+
generate_mbed_bindings(&mbed_config, &mbed_version)?;
259+
260+
// Request rustc to link the Mbed Crypto static library
261+
println!(
262+
"cargo:rustc-link-search=native={}/mbed-crypto-{}/library/",
263+
mbed_config
264+
.mbed_path
265+
.unwrap_or_else(|| env::var("OUT_DIR").unwrap()),
266+
mbed_version,
267+
);
268+
println!("cargo:rustc-link-lib=static=mbedcrypto");
269+
270+
// Also link shim library
271+
println!("cargo:rustc-link-search=native={}",
272+
env::var("OUT_DIR").unwrap());
273+
println!("cargo:rustc-link-lib=static=shim");
274+
}
275+
276+
Ok(())
277+
}

setup_mbed_crypto.sh

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
#!/usr/bin/env bash
2+
3+
# ------------------------------------------------------------------------------
4+
# Copyright 2020 Contributors to the Parsec project.
5+
# SPDX-License-Identifier: Apache-2.0
6+
# ------------------------------------------------------------------------------
7+
8+
MBED_VERSION=$1
9+
if [[ -z "$MBED_VERSION" ]]; then
10+
>&2 echo "No mbed version provided."
11+
exit 1
12+
fi
13+
14+
MBED_GITHUB_URL="https://github.com/ARMmbed/mbed-crypto"
15+
MBED_ROOT_FOLDER_NAME="mbed-crypto-$MBED_VERSION"
16+
MBED_LIB_FILENAME="libmbedcrypto.a"
17+
MBED_SHIMLIB_DIR="src/c"
18+
19+
# Where to clone the Mbed Crypto library
20+
TEMP_FOLDER=$2
21+
if [[ -z "$TEMP_FOLDER" ]]; then
22+
>&2 echo "No temporary folder for mbed provided."
23+
exit 1
24+
fi
25+
26+
# These options refer to CC and AR
27+
OPTIONS="$3 $4"
28+
29+
if [[ -z "$(type git 2> /dev/null)" ]]; then
30+
>&2 echo "Git not installed."
31+
exit 1
32+
fi
33+
34+
get_mbed_repo() {
35+
echo "No mbed-crypto present locally. Cloning."
36+
wget $MBED_GITHUB_URL/archive/$MBED_VERSION.tar.gz
37+
tar xf $MBED_VERSION.tar.gz
38+
pushd $MBED_ROOT_FOLDER_NAME
39+
}
40+
41+
setup_mbed_library() {
42+
echo "Building libmbedcrypto."
43+
#TODO: explain the bug with SHARED, it is needed for correct linking on some Linux machine
44+
make SHARED=0 $OPTIONS > /dev/null
45+
}
46+
47+
# Fetch mbed-crypto source code
48+
mkdir -p $TEMP_FOLDER
49+
pushd $TEMP_FOLDER
50+
if [[ -d "$MBED_ROOT_FOLDER_NAME" ]]; then
51+
pushd $MBED_ROOT_FOLDER_NAME
52+
else
53+
get_mbed_repo
54+
fi
55+
56+
# Set up lib
57+
if [[ -e "library/$MBED_LIB_FILENAME" ]]; then
58+
echo "Library is set up."
59+
else
60+
setup_mbed_library
61+
fi
62+
63+
# Build shimlib
64+
INCLUDE="`pwd`/include"
65+
SRCDIR="$CARGO_MANIFEST_DIR/$MBED_SHIMLIB_DIR"
66+
pushd "$OUT_DIR" || exit 1
67+
#xx Some config may be needed here, and what about cross-compilation?
68+
cc -I"$INCLUDE" -Wall -Werror -O2 -c "$SRCDIR"/shim.c -o shim.o
69+
ar rv libshim.a shim.o

0 commit comments

Comments
 (0)