Skip to content

Commit

Permalink
Add generate and destroy key to TS provider
Browse files Browse the repository at this point in the history
This commit adds functionality for generating and destroying
keys in the Trusted Service provider.

Signed-off-by: Ionut Mihalcea <ionut.mihalcea@arm.com>
  • Loading branch information
ionut-arm committed Nov 17, 2020
1 parent 8f489e0 commit f28f23f
Show file tree
Hide file tree
Showing 8 changed files with 321 additions and 13 deletions.
18 changes: 18 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,8 +1,26 @@
# Cargo build directory
/target

# Mbed Crypto key files
*.psa_its

# Editor swap files
*.swp


tags

# MacOS folder attributes file
*DS_Store

# VS Code config folder
*vscode

# Git patch files
*.patch

# Parsec key info mappings directory
mappings/

# TPM simulator state file
NVChip
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,4 @@ mbed-crypto-provider = ["psa-crypto"]
pkcs11-provider = ["pkcs11", "picky-asn1-der", "picky-asn1", "picky-asn1-x509", "psa-crypto", "rand"]
tpm-provider = ["tss-esapi", "picky-asn1-der", "picky-asn1", "picky-asn1-x509", "hex"]
all-providers = ["tpm-provider", "pkcs11-provider", "mbed-crypto-provider"]
trusted-service-provider = ["psa-crypto", "prost"]
trusted-service-provider = ["mbed-crypto-provider", "prost"]
6 changes: 4 additions & 2 deletions src/providers/mbed_crypto/key_management.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ pub fn get_key_id(
}

/// Creates a new PSA Key ID and stores it in the Key Info Manager.
fn create_key_id(
pub fn create_key_id(
key_triple: KeyTriple,
key_attributes: Attributes,
store_handle: &mut dyn ManageKeyInfo,
Expand Down Expand Up @@ -76,14 +76,16 @@ fn create_key_id(
}
}

fn remove_key_id(key_triple: &KeyTriple, store_handle: &mut dyn ManageKeyInfo) -> Result<()> {
/// Remove the info for a key triple from the Key Info Manager
pub fn remove_key_id(key_triple: &KeyTriple, store_handle: &mut dyn ManageKeyInfo) -> Result<()> {
// ID Counter not affected as overhead and extra complication deemed unnecessary
match store_handle.remove(key_triple) {
Ok(_) => Ok(()),
Err(string) => Err(key_info_managers::to_response_status(string)),
}
}

/// Check whether any key info exists for a given key triple in the Key Info Manager
pub fn key_info_exists(key_triple: &KeyTriple, store_handle: &dyn ManageKeyInfo) -> Result<bool> {
store_handle
.exists(key_triple)
Expand Down
2 changes: 1 addition & 1 deletion src/providers/mbed_crypto/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ mod asym_sign;
mod generate_random;
mod hash;
mod key_agreement;
mod key_management;
pub(super) mod key_management;

const SUPPORTED_OPCODES: [Opcode; 15] = [
Opcode::PsaGenerateKey,
Expand Down
71 changes: 71 additions & 0 deletions src/providers/trusted_service/context/key_management.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// Copyright 2020 Contributors to the Parsec project.
// SPDX-License-Identifier: Apache-2.0
use super::ts_protobuf::{
CloseKeyIn, DestroyKeyIn, DestroyKeyOut, GenerateKeyIn, GenerateKeyOut, KeyAttributes,
KeyLifetime, KeyPolicy, Opcode, OpenKeyIn, OpenKeyOut,
};
use super::Context;
use log::info;
use parsec_interface::operations::psa_key_attributes::Attributes;
use parsec_interface::requests::ResponseStatus;
use psa_crypto::types::status::Error;
use std::convert::{TryFrom, TryInto};

impl Context {
pub fn generate_key(&self, key_attrs: Attributes, id: u32) -> Result<u32, ResponseStatus> {
info!("Handling GenerateKey request");
let proto_req = GenerateKeyIn {
attributes: Some(KeyAttributes {
r#type: u16::try_from(key_attrs.key_type)? as u32,
key_bits: key_attrs.bits.try_into()?,
lifetime: KeyLifetime::Persistent as u32,
id,
policy: Some(KeyPolicy {
usage: key_attrs.policy.usage_flags.try_into()?,
alg: key_attrs.policy.permitted_algorithms.try_into()?,
}),
}),
};
let GenerateKeyOut { handle } =
self.send_request(&proto_req, Opcode::GenerateKey, self.rpc_caller)?;

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

Ok(0)
}

pub fn destroy_key(&self, id: u32) -> Result<(), ResponseStatus> {
info!("Handling DestroyKey request");
if !self.check_key_exists(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 = DestroyKeyIn { handle };
let _proto_resp: DestroyKeyOut =
self.send_request(&proto_req, Opcode::DestroyKey, self.rpc_caller)?;
Ok(())
}

pub fn check_key_exists(&self, 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) {
Ok(OpenKeyOut { handle }) => {
let proto_req = CloseKeyIn { handle };
self.send_request(&proto_req, Opcode::CloseKey, self.rpc_caller)?;
Ok(true)
}
Err(e) => {
if e == Error::DoesNotExist {
Ok(false)
} else {
Err(e)
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
// Copyright 2020 Contributors to the Parsec project.
// SPDX-License-Identifier: Apache-2.0
use log::info;
use log::{error, info, trace};
use prost::Message;
use psa_crypto::types::status::{Error as PsaError, Status};
use std::convert::TryInto;
use std::ffi::{c_void, CString};
use std::io::{Error, ErrorKind};
use std::ptr::null_mut;
use std::slice;
use std::sync::Mutex;
use ts_binding::*;
use ts_protobuf::Opcode;

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

mod key_management;

#[allow(
non_snake_case,
non_camel_case_types,
Expand All @@ -42,11 +50,17 @@ mod ts_protobuf {
include!(concat!(env!("OUT_DIR"), "/ts_crypto.rs"));
}

// TODO:
// * RPC caller error handling
// * proper logging
// * docs

#[derive(Debug)]
pub struct Context {
rpc_caller: *mut rpc_caller,
service_context: *mut service_context,
rpc_session_handle: *mut c_void,
call_mutex: Mutex<()>,
}

impl Context {
Expand Down Expand Up @@ -82,10 +96,70 @@ impl Context {
rpc_caller,
service_context,
rpc_session_handle,
call_mutex: Mutex::new(()),
};

Ok(ctx)
}

fn send_request<T: Message + Default>(
&self,
req: &impl Message,
opcode: Opcode,
rpc_cl: *mut rpc_caller,
) -> 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()) };
if call_handle == null_mut() {
error!("Call handle was null");
return Err(PsaError::CommunicationFailure);
} else if buf_out == null_mut() {
error!("Call buffer was null");
return Err(PsaError::CommunicationFailure);
}
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) };
format_error!("Failed to serialize Protobuf request", e);
PsaError::CommunicationFailure
})?;

trace!("Invoking RPC call");
let mut opstatus = 0;
let mut resp = T::default();
let mut resp_buf = null_mut();
let mut resp_buf_size = 0;
let status = unsafe {
rpc_caller_invoke(
rpc_cl,
call_handle,
i32::from(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) };
error!(
"Error on call invocation: status = {}, opstatus = {}",
status, opstatus as i32
);
Status::from(opstatus as i32).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) };
format_error!("Failed to serialize Protobuf request", e);
PsaError::CommunicationFailure
})?;
unsafe { rpc_caller_end(rpc_cl, call_handle) };

Ok(resp)
}
}

impl Drop for Context {
Expand Down
71 changes: 71 additions & 0 deletions src/providers/trusted_service/key_management.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// 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::{
create_key_id, get_key_id, key_info_exists, remove_key_id,
};
use parsec_interface::operations::{psa_destroy_key, psa_generate_key};
use parsec_interface::requests::{ProviderID, ResponseStatus, Result};

impl Provider {
pub(super) fn psa_generate_key_internal(
&self,
app_name: ApplicationName,
op: psa_generate_key::Operation,
) -> Result<psa_generate_key::Result> {
let key_name = op.key_name;
let key_attributes = op.attributes;
let key_triple = KeyTriple::new(app_name, ProviderID::TrustedService, key_name);
let mut store_handle = self
.key_info_store
.write()
.expect("Key store lock poisoned");
if key_info_exists(&key_triple, &*store_handle)? {
return Err(ResponseStatus::PsaErrorAlreadyExists);
}
let key_id = create_key_id(
key_triple.clone(),
key_attributes,
&mut *store_handle,
&self.id_counter,
)?;

match self.context.generate_key(key_attributes, key_id) {
Ok(_) => Ok(psa_generate_key::Result {}),
Err(error) => {
remove_key_id(&key_triple, &mut *store_handle)?;
let error = ResponseStatus::from(error);
format_error!("Generate key error", error);
Err(error)
}
}
}

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

match self.context.destroy_key(key_id) {
Ok(()) => {
remove_key_id(&key_triple, &mut *store_handle)?;
Ok(psa_destroy_key::Result {})
}
Err(error) => {
let error = ResponseStatus::from(error);
format_error!("Destroy key status: ", error);
Err(error)
}
}
}
}
Loading

0 comments on commit f28f23f

Please sign in to comment.