Skip to content

Commit

Permalink
Merge pull request #286 from ionut-arm/ts-sign-verify
Browse files Browse the repository at this point in the history
Add asymmetric sign and verify to TS provider
  • Loading branch information
ionut-arm authored Nov 19, 2020
2 parents eadc312 + 7cf3f1b commit c17f874
Show file tree
Hide file tree
Showing 6 changed files with 223 additions and 36 deletions.
6 changes: 3 additions & 3 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ use std::io::{Error, ErrorKind, Result};
use std::path::{Path, PathBuf};

fn generate_ts_bindings(ts_include_dir: String) -> Result<()> {
let header = ts_include_dir.clone() + "/service/locator/service_locator.h";
let header = ts_include_dir.clone() + "/service/locator/interface/service_locator.h";

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

let bindings = bindgen::Builder::default()
.clang_arg(format!("-I{}", ts_include_dir))
.clang_arg(format!("-I{}", ts_include_dir + "/rpc/common/interface"))
.rustfmt_bindings(true)
.header(header)
.generate_comments(false)
Expand All @@ -29,7 +29,7 @@ fn generate_ts_bindings(ts_include_dir: String) -> Result<()> {
println!("cargo:rustc-link-lib=dylib=c++");

println!("cargo:rustc-link-search=native=/usr/local/lib");
println!("cargo:rustc-link-lib=static=ts-lib");
println!("cargo:rustc-link-lib=dylib=ts");
// TODO: Remove once we can use the full TS stack and this isn't needed
println!("cargo:rustc-link-lib=static=mbedcrypto");
println!("cargo:rustc-link-lib=static=protobuf-nanopb");
Expand Down
42 changes: 42 additions & 0 deletions src/providers/trusted_service/asym_sign.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright 2020 Contributors to the Parsec project.
// SPDX-License-Identifier: Apache-2.0
use super::Provider;
use crate::authenticators::ApplicationName;
use crate::key_info_managers::KeyTriple;
use crate::providers::mbed_crypto::key_management;
use parsec_interface::operations::{psa_sign_hash, psa_verify_hash};
use parsec_interface::requests::{ProviderID, Result};

impl Provider {
pub(super) fn psa_sign_hash_internal(
&self,
app_name: ApplicationName,
op: psa_sign_hash::Operation,
) -> Result<psa_sign_hash::Result> {
let key_triple = KeyTriple::new(app_name, ProviderID::TrustedService, op.key_name.clone());
let store_handle = self.key_info_store.read().expect("Key store lock poisoned");
let key_id = key_management::get_key_id(&key_triple, &*store_handle)?;

Ok(psa_sign_hash::Result {
signature: self
.context
.asym_sign(key_id, op.hash.to_vec(), op.alg)?
.into(),
})
}

pub(super) fn psa_verify_hash_internal(
&self,
app_name: ApplicationName,
op: psa_verify_hash::Operation,
) -> Result<psa_verify_hash::Result> {
let key_triple = KeyTriple::new(app_name, ProviderID::TrustedService, op.key_name.clone());
let store_handle = self.key_info_store.read().expect("Key store lock poisoned");
let key_id = key_management::get_key_id(&key_triple, &*store_handle)?;

self.context
.asym_verify(key_id, op.hash.to_vec(), op.signature.to_vec(), op.alg)?;

Ok(psa_verify_hash::Result {})
}
}
46 changes: 46 additions & 0 deletions src/providers/trusted_service/context/asym_sign.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright 2020 Contributors to the Parsec project.
// SPDX-License-Identifier: Apache-2.0
use super::ts_protobuf::{SignHashIn, SignHashOut, VerifyHashIn};
use super::Context;
use log::info;
use parsec_interface::operations::psa_algorithm::AsymmetricSignature;
use parsec_interface::requests::ResponseStatus;
use std::convert::TryInto;

impl Context {
pub fn asym_sign(
&self,
key_id: u32,
hash: Vec<u8>,
algorithm: AsymmetricSignature,
) -> Result<Vec<u8>, ResponseStatus> {
info!("Handling GenerateKey request");
let proto_req = SignHashIn {
handle: 0,
hash,
alg: algorithm.try_into()?,
};
let SignHashOut { signature } = self.send_request_with_key(proto_req, key_id)?;

Ok(signature)
}

pub fn asym_verify(
&self,
key_id: u32,
hash: Vec<u8>,
signature: Vec<u8>,
algorithm: AsymmetricSignature,
) -> Result<(), ResponseStatus> {
info!("Handling GenerateKey request");
let proto_req = VerifyHashIn {
handle: 0,
hash,
signature,
alg: algorithm.try_into()?,
};
self.send_request_with_key(proto_req, key_id)?;

Ok(())
}
}
27 changes: 12 additions & 15 deletions src/providers/trusted_service/context/key_management.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0
use super::ts_protobuf::{
CloseKeyIn, DestroyKeyIn, DestroyKeyOut, GenerateKeyIn, GenerateKeyOut, KeyAttributes,
KeyLifetime, KeyPolicy, Opcode, OpenKeyIn, OpenKeyOut,
KeyLifetime, KeyPolicy, OpenKeyIn, OpenKeyOut,
};
use super::Context;
use log::info;
Expand All @@ -26,37 +26,34 @@ impl Context {
}),
}),
};
let GenerateKeyOut { handle } =
self.send_request(&proto_req, Opcode::GenerateKey, self.rpc_caller)?;
let GenerateKeyOut { handle } = self.send_request(&proto_req)?;

let proto_req = CloseKeyIn { handle };
self.send_request(&proto_req, Opcode::CloseKey, self.rpc_caller)?;
self.send_request(&proto_req)?;

Ok(())
}

pub fn destroy_key(&self, id: u32) -> Result<(), ResponseStatus> {
pub fn destroy_key(&self, key_id: u32) -> Result<(), ResponseStatus> {
info!("Handling DestroyKey request");
if !self.check_key_exists(id)? {
if !self.check_key_exists(key_id)? {
return Err(ResponseStatus::PsaErrorDoesNotExist);
}
let proto_req = OpenKeyIn { id };
let OpenKeyOut { handle } =
self.send_request(&proto_req, Opcode::OpenKey, self.rpc_caller)?;
let proto_req = OpenKeyIn { id: key_id };
let OpenKeyOut { handle } = self.send_request(&proto_req)?;

let proto_req = DestroyKeyIn { handle };
let _proto_resp: DestroyKeyOut =
self.send_request(&proto_req, Opcode::DestroyKey, self.rpc_caller)?;
let _proto_resp: DestroyKeyOut = self.send_request(&proto_req)?;
Ok(())
}

pub fn check_key_exists(&self, id: u32) -> Result<bool, Error> {
pub fn check_key_exists(&self, key_id: u32) -> Result<bool, Error> {
info!("Handling CheckKey request");
let proto_req = OpenKeyIn { id };
match self.send_request(&proto_req, Opcode::OpenKey, self.rpc_caller) {
let proto_req = OpenKeyIn { id: key_id };
match self.send_request(&proto_req) {
Ok(OpenKeyOut { handle }) => {
let proto_req = CloseKeyIn { handle };
self.send_request(&proto_req, Opcode::CloseKey, self.rpc_caller)?;
self.send_request(&proto_req)?;
Ok(true)
}
Err(e) => {
Expand Down
115 changes: 98 additions & 17 deletions src/providers/trusted_service/context/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use std::ptr::null_mut;
use std::slice;
use std::sync::Mutex;
use ts_binding::*;
use ts_protobuf::Opcode;
use ts_protobuf::{CloseKeyIn, GetOpcode, OpenKeyIn, OpenKeyOut, SetHandle};

#[allow(
non_snake_case,
Expand All @@ -30,6 +30,7 @@ pub mod ts_binding {
include!(concat!(env!("OUT_DIR"), "/ts_bindings.rs"));
}

mod asym_sign;
mod key_management;

#[allow(
Expand All @@ -48,6 +49,59 @@ mod key_management;
)]
mod ts_protobuf {
include!(concat!(env!("OUT_DIR"), "/ts_crypto.rs"));

pub trait GetOpcode {
fn opcode(&self) -> Opcode;
}

macro_rules! opcode_impl {
($type:ty, $opcode:ident) => {
impl GetOpcode for $type {
fn opcode(&self) -> Opcode {
Opcode::$opcode
}
}
};

($type_in:ty, $type_out:ty, $opcode:ident) => {
impl GetOpcode for $type_in {
fn opcode(&self) -> Opcode {
Opcode::$opcode
}
}

impl GetOpcode for $type_out {
fn opcode(&self) -> Opcode {
Opcode::$opcode
}
}
};
}

opcode_impl!(OpenKeyIn, OpenKeyOut, OpenKey);
opcode_impl!(CloseKeyIn, CloseKey);
opcode_impl!(GenerateKeyIn, GenerateKeyOut, GenerateKey);
opcode_impl!(DestroyKeyIn, DestroyKeyOut, DestroyKey);
opcode_impl!(SignHashIn, SignHashOut, SignHash);
opcode_impl!(VerifyHashIn, VerifyHashOut, VerifyHash);

pub trait SetHandle {
fn set_handle(&mut self, handle: u32);
}

macro_rules! set_handle_impl {
($type:ty) => {
impl SetHandle for $type {
fn set_handle(&mut self, handle: u32) {
self.handle = handle;
}
}
};
}

set_handle_impl!(DestroyKeyIn);
set_handle_impl!(SignHashIn);
set_handle_impl!(VerifyHashIn);
}

// TODO:
Expand All @@ -65,15 +119,27 @@ pub struct Context {

impl Context {
pub fn connect() -> anyhow::Result<Self> {
info!("Querying for crypto Trusted Services");
// Initialise service locator. Can be called multiple times,
// but *must* be called at least once.
unsafe { service_locator_init() };

info!("Obtaining a crypto Trusted Service context.");
let mut status = 0;
let service_context = unsafe {
service_locator_query(
CString::new("sn:tf.org:crypto:0").unwrap().into_raw(),
CString::new("sn:trustedfirmware.org:crypto:0")
.unwrap()
.into_raw(),
&mut status,
)
};
if service_context == null_mut() || status != 0 {
if service_context == null_mut() {
return Err(Error::new(
ErrorKind::Other,
"Failed to obtain a Trusted Service context",
)
.into());
} else if status != 0 {
return Err(Error::new(
ErrorKind::Other,
format!(
Expand Down Expand Up @@ -104,15 +170,14 @@ impl Context {

fn send_request<T: Message + Default>(
&self,
req: &impl Message,
opcode: Opcode,
rpc_cl: *mut rpc_caller,
req: &(impl Message + GetOpcode),
) -> Result<T, PsaError> {
let _mutex_guard = self.call_mutex.try_lock().expect("Call mutex poisoned");
info!("Beginning call to Trusted Service");

let mut buf_out = null_mut();
let call_handle = unsafe { rpc_caller_begin(rpc_cl, &mut buf_out, req.encoded_len()) };
let call_handle =
unsafe { rpc_caller_begin(self.rpc_caller, &mut buf_out, req.encoded_len()) };
if call_handle == null_mut() {
error!("Call handle was null");
return Err(PsaError::CommunicationFailure);
Expand All @@ -122,7 +187,7 @@ impl Context {
}
let mut buf_out = unsafe { slice::from_raw_parts_mut(buf_out, req.encoded_len()) };
req.encode(&mut buf_out).map_err(|e| {
unsafe { rpc_caller_end(rpc_cl, call_handle) };
unsafe { rpc_caller_end(self.rpc_caller, call_handle) };
format_error!("Failed to serialize Protobuf request", e);
PsaError::CommunicationFailure
})?;
Expand All @@ -134,39 +199,55 @@ impl Context {
let mut resp_buf_size = 0;
let status = unsafe {
rpc_caller_invoke(
rpc_cl,
self.rpc_caller,
call_handle,
i32::from(opcode).try_into().unwrap(),
i32::from(req.opcode()).try_into().unwrap(),
&mut opstatus,
&mut resp_buf,
&mut resp_buf_size,
)
};
if status != 0 || opstatus != 0 {
unsafe { rpc_caller_end(rpc_cl, call_handle) };
unsafe { rpc_caller_end(self.rpc_caller, call_handle) };
error!(
"Error on call invocation: status = {}, opstatus = {}",
status, opstatus as i32
status, opstatus
);
Status::from(opstatus as i32).to_result()?;
Status::from(opstatus).to_result()?;
}
let resp_buf = unsafe { slice::from_raw_parts_mut(resp_buf, resp_buf_size) };
resp.merge(&*resp_buf).map_err(|e| {
unsafe { rpc_caller_end(rpc_cl, call_handle) };
unsafe { rpc_caller_end(self.rpc_caller, call_handle) };
format_error!("Failed to serialize Protobuf request", e);
PsaError::CommunicationFailure
})?;
unsafe { rpc_caller_end(rpc_cl, call_handle) };
unsafe { rpc_caller_end(self.rpc_caller, call_handle) };

Ok(resp)
}

fn send_request_with_key<T: Message + Default>(
&self,
mut req: impl Message + GetOpcode + SetHandle,
key_id: u32,
) -> Result<T, PsaError> {
let proto_req = OpenKeyIn { id: key_id };
let OpenKeyOut { handle } = self.send_request(&proto_req)?;
req.set_handle(handle);
let res = self.send_request(&req);
let proto_req = CloseKeyIn { handle };
let res_close = self.send_request(&proto_req);
let res = res?;
res_close?;
Ok(res)
}
}

impl Drop for Context {
fn drop(&mut self) {
unsafe { service_context_close(self.service_context, self.rpc_session_handle) };

unsafe { service_locator_relinquish(self.service_context) };
unsafe { service_context_relinquish(self.service_context) };
}
}

Expand Down
Loading

0 comments on commit c17f874

Please sign in to comment.