Skip to content

Commit

Permalink
First draft of rust-psa-crypto, Rust wrapper for (some of) mbed-crypto.
Browse files Browse the repository at this point in the history
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]>
  • Loading branch information
egrimley-arm committed Apr 28, 2020
1 parent dd6c1cd commit 5f48609
Show file tree
Hide file tree
Showing 8 changed files with 1,028 additions and 1 deletion.
13 changes: 12 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
[package]
name = "psa-crypto"
version = "0.1.0"
authors = ["Paul Howard <[email protected]>",
authors = ["Edmund Grimley Evans <[email protected]>",
"Paul Howard <[email protected]>",
"Ionut Mihalcea <[email protected]>",
"Hugues de Valon <[email protected]>"]
edition = "2018"
Expand All @@ -13,3 +14,13 @@ license = "Apache-2.0"
repository = "https://github.com/parallaxsecond/rust-psa-crypto"

[dependencies]
lazy_static = "1.4.0"

[build-dependencies]
bindgen = "0.50.0"
cargo_toml = "0.7.0"
serde = { version = "1.0", features = ["derive"] }
toml = "0.4.2"

[package.metadata.config]
mbed-crypto-version = "mbedcrypto-2.0.0"
19 changes: 19 additions & 0 deletions build-conf.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Configuration values for setting up and building the Mbed Crypto library that
# psa-crypto currently depends on
[mbed_config]
# Path (either relative or absolute) where the Mbed Crypto source code will be
# persisted.
# This value default to the OUT_DIR environment variable.
mbed_path = "/tmp/"

# When compiling natively
[mbed_config.native]
# The compiler to use when building the Mbed Crypto library
# mbed_compiler = "clang"
# The archiver to use when building the Mbed Crypto library
# mbed_archiver = "ar"

# When cross-compiling for aarch64-unknown-linux-gnu target
[mbed_config.aarch64_unknown_linux_gnu]
# mbed_compiler = "aarch64-linux-gnu-gcc"
# mbed_archiver = "aarch64-linux-gnu-ar"
279 changes: 279 additions & 0 deletions build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,279 @@
// Copyright 2020 Contributors to the Parsec project.
// SPDX-License-Identifier: Apache-2.0

#![deny(
nonstandard_style,
const_err,
dead_code,
improper_ctypes,
non_shorthand_field_patterns,
no_mangle_generic_items,
overflowing_literals,
path_statements,
patterns_in_fns_without_body,
private_in_public,
unconditional_recursion,
unused,
unused_allocation,
unused_comparisons,
unused_parens,
while_true,
missing_debug_implementations,
trivial_casts,
trivial_numeric_casts,
unused_extern_crates,
unused_import_braces,
unused_qualifications,
unused_results,
missing_copy_implementations
)]
// This one is hard to avoid.
#![allow(clippy::multiple_crate_versions)]

use cargo_toml::{Manifest, Value};
use serde::Deserialize;
use std::env;
use std::io::{Error, ErrorKind, Result};
use std::path::{Path, PathBuf};

const CONFIG_TABLE_NAME: &str = "config";
const MBED_CRYPTO_VERSION_KEY: &str = "mbed-crypto-version";

const SETUP_MBED_SCRIPT_PATH: &str = "./setup_mbed_crypto.sh";
const BUILD_CONFIG_FILE_PATH: &str = "./build-conf.toml";

const DEFAULT_NATIVE_MBED_COMPILER: &str = "clang";
const DEFAULT_NATIVE_MBED_ARCHIVER: &str = "ar";
const DEFAULT_ARM64_MBED_COMPILER: &str = "aarch64-linux-gnu-gcc";
const DEFAULT_ARM64_MBED_ARCHIVER: &str = "aarch64-linux-gnu-ar";

#[derive(Debug, Deserialize)]
struct Configuration {
mbed_config: Option<MbedConfig>,
}

#[derive(Debug, Deserialize)]
struct MbedConfig {
mbed_path: Option<String>,
native: Option<Toolchain>,
aarch64_unknown_linux_gnu: Option<Toolchain>,
}

#[derive(Debug, Deserialize)]
struct Toolchain {
mbed_compiler: Option<String>,
mbed_archiver: Option<String>,
}

fn get_configuration_string(parsec_config: &Value, key: &str) -> Result<String> {
let config_value = get_value_from_table(parsec_config, key)?;
match config_value {
Value::String(string) => Ok(string.clone()),
_ => Err(Error::new(
ErrorKind::InvalidInput,
"Configuration key missing",
)),
}
}

fn get_value_from_table<'a>(table: &'a Value, key: &str) -> Result<&'a Value> {
match table {
Value::Table(table) => table.get(key).ok_or_else(|| {
println!("Config table does not contain configuration key: {}", key);
Error::new(ErrorKind::InvalidInput, "Configuration key missing.")
}),
_ => Err(Error::new(
ErrorKind::InvalidInput,
"Value provided is not a TOML table",
)),
}
}

// Get the Mbed Crypto version to branch on from Cargo.toml file. Use that and MbedConfig to pass
// parameters to the setup_mbed_crypto.sh script which clones and builds Mbed Crypto and create
// a static library.
fn setup_mbed_crypto(mbed_config: &MbedConfig, mbed_version: &str) -> Result<()> {
let (mbed_compiler, mbed_archiver) =
if std::env::var("TARGET").unwrap() == "aarch64-unknown-linux-gnu" {
let toolchain;
toolchain = mbed_config
.aarch64_unknown_linux_gnu
.as_ref()
.ok_or_else(|| {
Error::new(
ErrorKind::InvalidInput,
"The aarch64_unknown_linux_gnu subtable of mbed_config should exist",
)
})?;
(
toolchain
.mbed_compiler
.clone()
.unwrap_or_else(|| DEFAULT_ARM64_MBED_COMPILER.to_string()),
toolchain
.mbed_archiver
.clone()
.unwrap_or_else(|| DEFAULT_ARM64_MBED_ARCHIVER.to_string()),
)
} else {
let toolchain;
toolchain = mbed_config.native.as_ref().ok_or_else(|| {
Error::new(
ErrorKind::InvalidInput,
"The native subtable of mbed_config should exist",
)
})?;
(
toolchain
.mbed_compiler
.clone()
.unwrap_or_else(|| DEFAULT_NATIVE_MBED_COMPILER.to_string()),
toolchain
.mbed_archiver
.clone()
.unwrap_or_else(|| DEFAULT_NATIVE_MBED_ARCHIVER.to_string()),
)
};

let script_fail = |_| {
Err(Error::new(
ErrorKind::Other,
"setup_mbed_crypto.sh script failed",
))
};

println!("cargo:rerun-if-changed={}", SETUP_MBED_SCRIPT_PATH);
println!("cargo:rerun-if-changed={}", "src/c/Makefile");
println!("cargo:rerun-if-changed={}", "src/c/shim.c");
println!("cargo:rerun-if-changed={}", "src/c/shim.h");

if !::std::process::Command::new(SETUP_MBED_SCRIPT_PATH)
.arg(mbed_version)
.arg(
mbed_config
.mbed_path
.clone()
.unwrap_or_else(|| env::var("OUT_DIR").unwrap()),
)
.arg(format!("CC={}", mbed_compiler))
.arg(format!("AR={}", mbed_archiver))
.status()
.or_else(script_fail)?
.success()
{
Err(Error::new(
ErrorKind::Other,
"setup_mbed_crypto.sh returned an error status.",
))
} else {
Ok(())
}
}

fn generate_mbed_bindings(mbed_config: &MbedConfig, mbed_version: &str) -> Result<()> {
let mbed_include_dir = mbed_config
.mbed_path
.clone()
.unwrap_or_else(|| env::var("OUT_DIR").unwrap())
+ "/mbed-crypto-"
+ mbed_version
+ "/include";
let header = mbed_include_dir.clone() + "/psa/crypto.h";

println!("cargo:rerun-if-changed={}", header);

let shim_bindings = bindgen::Builder::default()
.clang_arg(format!("-I{}", mbed_include_dir))
.rustfmt_bindings(true)
.header("src/c/shim.h")
.generate_comments(false)
.generate()
.or_else(|_| {
Err(Error::new(
ErrorKind::Other,
"Unable to generate bindings to mbed crypto",
))
})?;
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
shim_bindings.write_to_file(out_path.join("shim_bindings.rs"))
}

// Get the compiler, the archiver and the location where to clone the Mbed Crypto repository.
fn parse_config_file() -> Result<Configuration> {
let config_str = ::std::fs::read_to_string(Path::new(BUILD_CONFIG_FILE_PATH))?;
Ok(toml::from_str(&config_str).or_else(|e| {
println!("Error parsing build configuration file ({}).", e);
Err(Error::new(
ErrorKind::InvalidInput,
"Could not parse build configuration file.",
))
})?)
}

fn main() -> Result<()> {
// Parsing build-conf.toml
let config = parse_config_file()?;

// Parsing Cargo.toml
let toml_path = std::path::Path::new("./Cargo.toml");
if !toml_path.exists() {
return Err(Error::new(
ErrorKind::InvalidInput,
"Could not find Cargo.toml.",
));
}
let manifest = Manifest::from_path(&toml_path).or_else(|e| {
println!("Error parsing Cargo.toml ({}).", e);
Err(Error::new(
ErrorKind::InvalidInput,
"Could not parse Cargo.toml.",
))
})?;

let package = manifest.package.ok_or_else(|| {
Error::new(
ErrorKind::InvalidInput,
"Cargo.toml does not contain package information.",
)
})?;
let metadata = package.metadata.ok_or_else(|| {
Error::new(
ErrorKind::InvalidInput,
"Cargo.toml does not contain package metadata.",
)
})?;
let parsec_config = get_value_from_table(&metadata, CONFIG_TABLE_NAME)?;

if true {
let mbed_config = config.mbed_config.ok_or_else(|| {
Error::new(
ErrorKind::InvalidInput,
"Could not find mbed_config table in the config file.",
)
})?;

let mbed_version = get_configuration_string(&parsec_config, MBED_CRYPTO_VERSION_KEY)?;

setup_mbed_crypto(&mbed_config, &mbed_version)?;
generate_mbed_bindings(&mbed_config, &mbed_version)?;

// Request rustc to link the Mbed Crypto static library
println!(
"cargo:rustc-link-search=native={}/mbed-crypto-{}/library/",
mbed_config
.mbed_path
.unwrap_or_else(|| env::var("OUT_DIR").unwrap()),
mbed_version,
);
println!("cargo:rustc-link-lib=static=mbedcrypto");

// Also link shim library
println!(
"cargo:rustc-link-search=native={}",
env::var("OUT_DIR").unwrap()
);
println!("cargo:rustc-link-lib=static=shim");
}

Ok(())
}
69 changes: 69 additions & 0 deletions setup_mbed_crypto.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#!/usr/bin/env bash

# ------------------------------------------------------------------------------
# Copyright 2020 Contributors to the Parsec project.
# SPDX-License-Identifier: Apache-2.0
# ------------------------------------------------------------------------------

MBED_VERSION=$1
if [[ -z "$MBED_VERSION" ]]; then
>&2 echo "No mbed version provided."
exit 1
fi

MBED_GITHUB_URL="https://github.com/ARMmbed/mbed-crypto"
MBED_ROOT_FOLDER_NAME="mbed-crypto-$MBED_VERSION"
MBED_LIB_FILENAME="libmbedcrypto.a"
MBED_SHIMLIB_DIR="src/c"

# Where to clone the Mbed Crypto library
TEMP_FOLDER=$2
if [[ -z "$TEMP_FOLDER" ]]; then
>&2 echo "No temporary folder for mbed provided."
exit 1
fi

# These options refer to CC and AR
OPTIONS="$3 $4"

if [[ -z "$(type git 2> /dev/null)" ]]; then
>&2 echo "Git not installed."
exit 1
fi

get_mbed_repo() {
echo "No mbed-crypto present locally. Cloning."
wget $MBED_GITHUB_URL/archive/$MBED_VERSION.tar.gz
tar xf $MBED_VERSION.tar.gz
pushd $MBED_ROOT_FOLDER_NAME
}

setup_mbed_library() {
echo "Building libmbedcrypto."
#TODO: explain the bug with SHARED, it is needed for correct linking on some Linux machine
make SHARED=0 $OPTIONS > /dev/null
}

# Fetch mbed-crypto source code
mkdir -p $TEMP_FOLDER
pushd $TEMP_FOLDER
if [[ -d "$MBED_ROOT_FOLDER_NAME" ]]; then
pushd $MBED_ROOT_FOLDER_NAME
else
get_mbed_repo
fi

# Set up lib
if [[ -e "library/$MBED_LIB_FILENAME" ]]; then
echo "Library is set up."
else
setup_mbed_library
fi

# Build shimlib
INCLUDE="`pwd`/include"
SRCDIR="$CARGO_MANIFEST_DIR/$MBED_SHIMLIB_DIR"
pushd "$OUT_DIR" || exit 1
#xx Some config may be needed here, and what about cross-compilation?
cc -I"$INCLUDE" -Wall -Werror -O2 -c "$SRCDIR"/shim.c -o shim.o
ar rv libshim.a shim.o
Loading

0 comments on commit 5f48609

Please sign in to comment.