Skip to content

Commit

Permalink
Add asymmetric sign and verify to TS provider
Browse files Browse the repository at this point in the history
This commit adds functionality to the Trusted Service provider
allowing it to sign and verify hashes.

Signed-off-by: Ionut Mihalcea <ionut.mihalcea@arm.com>
  • Loading branch information
ionut-arm committed Nov 18, 2020
1 parent eadc312 commit c44e6fa
Show file tree
Hide file tree
Showing 6 changed files with 228 additions and 27 deletions.
12 changes: 12 additions & 0 deletions src/providers/mbed_crypto/key_management.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,18 @@ pub fn get_key_id(
}
}

/// Get key Attributes from the Key Info Manager.
pub fn get_key_attributes(
key_triple: &KeyTriple,
store_handle: &dyn ManageKeyInfo,
) -> Result<Attributes> {
match store_handle.get(key_triple) {
Ok(Some(key_info)) => Ok(key_info.attributes),
Ok(None) => Err(ResponseStatus::PsaErrorDoesNotExist),
Err(string) => Err(key_info_managers::to_response_status(string)),
}
}

/// Creates a new PSA Key ID and stores it in the Key Info Manager.
pub fn create_key_id(
key_triple: KeyTriple,
Expand Down
52 changes: 52 additions & 0 deletions src/providers/trusted_service/asym_sign.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// 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)?;

op.validate(key_management::get_key_attributes(
&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)?;

op.validate(key_management::get_key_attributes(
&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 mut proto_req = SignHashIn {
handle: 0,
hash,
alg: algorithm.try_into()?,
};
let SignHashOut { signature } = self.send_request_with_key(&mut 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 mut proto_req = VerifyHashIn {
handle: 0,
hash,
signature,
alg: algorithm.try_into()?,
};
self.send_request_with_key(&mut 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
95 changes: 84 additions & 11 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, OpcodeT, 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 OpcodeT {
fn opcode(&self) -> Opcode;
}

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

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

impl OpcodeT 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 Down Expand Up @@ -104,15 +158,14 @@ impl Context {

fn send_request<T: Message + Default>(
&self,
req: &impl Message,
opcode: Opcode,
rpc_cl: *mut rpc_caller,
req: &(impl Message + OpcodeT),
) -> 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 +175,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,16 +187,16 @@ 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
Expand All @@ -152,14 +205,34 @@ impl Context {
}
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,
req: &mut (impl Message + OpcodeT + 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);
if res.is_err() {
res
} else if res_close.is_err() {
res_close
} else {
res
}
}
}

impl Drop for Context {
Expand Down
23 changes: 22 additions & 1 deletion src/providers/trusted_service/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ use context::Context;
use derivative::Derivative;
use log::{error, trace};
use parsec_interface::operations::list_providers::ProviderInfo;
use parsec_interface::operations::{psa_destroy_key, psa_generate_key};
use parsec_interface::operations::{
psa_destroy_key, psa_generate_key, psa_sign_hash, psa_verify_hash,
};
use parsec_interface::requests::{Opcode, ProviderID, Result};
use psa_crypto::types::key;
use std::collections::HashSet;
Expand All @@ -22,6 +24,7 @@ use std::sync::{
};
use uuid::Uuid;

mod asym_sign;
mod context;
mod key_management;

Expand Down Expand Up @@ -142,6 +145,24 @@ impl Provide for Provider {
trace!("psa_destroy_key ingress");
self.psa_destroy_key_internal(app_name, op)
}

fn psa_sign_hash(
&self,
app_name: ApplicationName,
op: psa_sign_hash::Operation,
) -> Result<psa_sign_hash::Result> {
trace!("psa_sign_hash ingress");
self.psa_sign_hash_internal(app_name, op)
}

fn psa_verify_hash(
&self,
app_name: ApplicationName,
op: psa_verify_hash::Operation,
) -> Result<psa_verify_hash::Result> {
trace!("psa_verify_hash ingress");
self.psa_verify_hash_internal(app_name, op)
}
}

/// Trusted Service provider builder
Expand Down

0 comments on commit c44e6fa

Please sign in to comment.