Skip to content

Commit d4090be

Browse files
committed
Add generate and destroy key to TS provider
This commit adds functionality for generating and destroying keys in the Trusted Service provider. Signed-off-by: Ionut Mihalcea <[email protected]>
1 parent 6fe57f3 commit d4090be

File tree

8 files changed

+331
-12
lines changed

8 files changed

+331
-12
lines changed

.gitignore

+18
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,26 @@
1+
# Cargo build directory
12
/target
3+
4+
# Mbed Crypto key files
25
*.psa_its
6+
7+
# Editor swap files
38
*.swp
9+
10+
411
tags
12+
13+
# MacOS folder attributes file
514
*DS_Store
15+
16+
# VS Code config folder
17+
*vscode
18+
19+
# Git patch files
620
*.patch
21+
22+
# Parsec key info mappings directory
723
mappings/
24+
25+
# TPM simulator state file
826
NVChip

src/providers/mbed_crypto/key_management.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -81,14 +81,22 @@ fn create_key_id(max_current_id: &AtomicU32) -> Result<key::psa_key_id_t> {
8181
Ok(new_key_id)
8282
}
8383

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

93+
/// Check whether any key info exists for a given key triple in the Key Info Manager
94+
pub fn key_info_exists(key_triple: &KeyTriple, store_handle: &dyn ManageKeyInfo) -> Result<bool> {
95+
store_handle
96+
.exists(key_triple)
97+
.map_err(key_info_managers::to_response_status)
98+
}
99+
92100
impl Provider {
93101
pub(super) fn psa_generate_key_internal(
94102
&self,

src/providers/mbed_crypto/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ mod asym_sign;
3131
mod generate_random;
3232
mod hash;
3333
mod key_agreement;
34-
mod key_management;
34+
pub(super) mod key_management;
3535

3636
const SUPPORTED_OPCODES: [Opcode; 15] = [
3737
Opcode::PsaGenerateKey,

src/providers/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ impl ProviderConfig {
110110
ProviderConfig::CryptoAuthLib {
111111
ref key_info_manager,
112112
..
113-
} =
113+
} => key_info_manager,
114114
ProviderConfig::TrustedService {
115115
ref key_info_manager,
116116
..
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// Copyright 2020 Contributors to the Parsec project.
2+
// SPDX-License-Identifier: Apache-2.0
3+
use super::ts_protobuf::{
4+
CloseKeyIn, DestroyKeyIn, DestroyKeyOut, GenerateKeyIn, GenerateKeyOut, KeyAttributes,
5+
KeyLifetime, KeyPolicy, Opcode, OpenKeyIn, OpenKeyOut,
6+
};
7+
use super::Context;
8+
use log::info;
9+
use parsec_interface::operations::psa_key_attributes::Attributes;
10+
use parsec_interface::requests::ResponseStatus;
11+
use psa_crypto::types::status::Error;
12+
use std::convert::{TryFrom, TryInto};
13+
14+
impl Context {
15+
pub fn generate_key(&self, key_attrs: Attributes, id: u32) -> Result<(), ResponseStatus> {
16+
info!("Handling GenerateKey request");
17+
let proto_req = GenerateKeyIn {
18+
attributes: Some(KeyAttributes {
19+
r#type: u16::try_from(key_attrs.key_type)? as u32,
20+
key_bits: key_attrs.bits.try_into()?,
21+
lifetime: KeyLifetime::Persistent as u32,
22+
id,
23+
policy: Some(KeyPolicy {
24+
usage: key_attrs.policy.usage_flags.try_into()?,
25+
alg: key_attrs.policy.permitted_algorithms.try_into()?,
26+
}),
27+
}),
28+
};
29+
let GenerateKeyOut { handle } =
30+
self.send_request(&proto_req, Opcode::GenerateKey, self.rpc_caller)?;
31+
32+
let proto_req = CloseKeyIn { handle };
33+
self.send_request(&proto_req, Opcode::CloseKey, self.rpc_caller)?;
34+
35+
Ok(())
36+
}
37+
38+
pub fn destroy_key(&self, id: u32) -> Result<(), ResponseStatus> {
39+
info!("Handling DestroyKey request");
40+
if !self.check_key_exists(id)? {
41+
return Err(ResponseStatus::PsaErrorDoesNotExist);
42+
}
43+
let proto_req = OpenKeyIn { id };
44+
let OpenKeyOut { handle } =
45+
self.send_request(&proto_req, Opcode::OpenKey, self.rpc_caller)?;
46+
47+
let proto_req = DestroyKeyIn { handle };
48+
let _proto_resp: DestroyKeyOut =
49+
self.send_request(&proto_req, Opcode::DestroyKey, self.rpc_caller)?;
50+
Ok(())
51+
}
52+
53+
pub fn check_key_exists(&self, id: u32) -> Result<bool, Error> {
54+
info!("Handling CheckKey request");
55+
let proto_req = OpenKeyIn { id };
56+
match self.send_request(&proto_req, Opcode::OpenKey, self.rpc_caller) {
57+
Ok(OpenKeyOut { handle }) => {
58+
let proto_req = CloseKeyIn { handle };
59+
self.send_request(&proto_req, Opcode::CloseKey, self.rpc_caller)?;
60+
Ok(true)
61+
}
62+
Err(e) => {
63+
if e == Error::DoesNotExist {
64+
Ok(false)
65+
} else {
66+
Err(e)
67+
}
68+
}
69+
}
70+
}
71+
}

src/providers/trusted_service/context.rs renamed to src/providers/trusted_service/context/mod.rs

+75-1
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
11
// Copyright 2020 Contributors to the Parsec project.
22
// SPDX-License-Identifier: Apache-2.0
3-
use log::info;
3+
use log::{error, info, trace};
4+
use prost::Message;
5+
use psa_crypto::types::status::{Error as PsaError, Status};
6+
use std::convert::TryInto;
47
use std::ffi::{c_void, CString};
58
use std::io::{Error, ErrorKind};
69
use std::ptr::null_mut;
10+
use std::slice;
11+
use std::sync::Mutex;
712
use ts_binding::*;
13+
use ts_protobuf::Opcode;
814

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

33+
mod key_management;
34+
2735
#[allow(
2836
non_snake_case,
2937
non_camel_case_types,
@@ -42,11 +50,17 @@ mod ts_protobuf {
4250
include!(concat!(env!("OUT_DIR"), "/ts_crypto.rs"));
4351
}
4452

53+
// TODO:
54+
// * RPC caller error handling
55+
// * proper logging
56+
// * docs
57+
4558
#[derive(Debug)]
4659
pub struct Context {
4760
rpc_caller: *mut rpc_caller,
4861
service_context: *mut service_context,
4962
rpc_session_handle: *mut c_void,
63+
call_mutex: Mutex<()>,
5064
}
5165

5266
impl Context {
@@ -82,10 +96,70 @@ impl Context {
8296
rpc_caller,
8397
service_context,
8498
rpc_session_handle,
99+
call_mutex: Mutex::new(()),
85100
};
86101

87102
Ok(ctx)
88103
}
104+
105+
fn send_request<T: Message + Default>(
106+
&self,
107+
req: &impl Message,
108+
opcode: Opcode,
109+
rpc_cl: *mut rpc_caller,
110+
) -> Result<T, PsaError> {
111+
let _mutex_guard = self.call_mutex.try_lock().expect("Call mutex poisoned");
112+
info!("Beginning call to Trusted Service");
113+
114+
let mut buf_out = null_mut();
115+
let call_handle = unsafe { rpc_caller_begin(rpc_cl, &mut buf_out, req.encoded_len()) };
116+
if call_handle == null_mut() {
117+
error!("Call handle was null");
118+
return Err(PsaError::CommunicationFailure);
119+
} else if buf_out == null_mut() {
120+
error!("Call buffer was null");
121+
return Err(PsaError::CommunicationFailure);
122+
}
123+
let mut buf_out = unsafe { slice::from_raw_parts_mut(buf_out, req.encoded_len()) };
124+
req.encode(&mut buf_out).map_err(|e| {
125+
unsafe { rpc_caller_end(rpc_cl, call_handle) };
126+
format_error!("Failed to serialize Protobuf request", e);
127+
PsaError::CommunicationFailure
128+
})?;
129+
130+
trace!("Invoking RPC call");
131+
let mut opstatus = 0;
132+
let mut resp = T::default();
133+
let mut resp_buf = null_mut();
134+
let mut resp_buf_size = 0;
135+
let status = unsafe {
136+
rpc_caller_invoke(
137+
rpc_cl,
138+
call_handle,
139+
i32::from(opcode).try_into().unwrap(),
140+
&mut opstatus,
141+
&mut resp_buf,
142+
&mut resp_buf_size,
143+
)
144+
};
145+
if status != 0 || opstatus != 0 {
146+
unsafe { rpc_caller_end(rpc_cl, call_handle) };
147+
error!(
148+
"Error on call invocation: status = {}, opstatus = {}",
149+
status, opstatus as i32
150+
);
151+
Status::from(opstatus as i32).to_result()?;
152+
}
153+
let resp_buf = unsafe { slice::from_raw_parts_mut(resp_buf, resp_buf_size) };
154+
resp.merge(&*resp_buf).map_err(|e| {
155+
unsafe { rpc_caller_end(rpc_cl, call_handle) };
156+
format_error!("Failed to serialize Protobuf request", e);
157+
PsaError::CommunicationFailure
158+
})?;
159+
unsafe { rpc_caller_end(rpc_cl, call_handle) };
160+
161+
Ok(resp)
162+
}
89163
}
90164

91165
impl Drop for Context {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
// Copyright 2020 Contributors to the Parsec project.
2+
// SPDX-License-Identifier: Apache-2.0
3+
use super::Provider;
4+
use crate::authenticators::ApplicationName;
5+
use crate::key_info_managers::KeyTriple;
6+
use crate::providers::mbed_crypto::key_management::{
7+
create_key_id, get_key_id, insert_key_id, key_info_exists, remove_key_id,
8+
};
9+
use parsec_interface::operations::{psa_destroy_key, psa_generate_key};
10+
use parsec_interface::requests::{ProviderID, ResponseStatus, Result};
11+
12+
impl Provider {
13+
pub(super) fn psa_generate_key_internal(
14+
&self,
15+
app_name: ApplicationName,
16+
op: psa_generate_key::Operation,
17+
) -> Result<psa_generate_key::Result> {
18+
let key_name = op.key_name;
19+
let key_attributes = op.attributes;
20+
let key_triple = KeyTriple::new(app_name, ProviderID::TrustedService, key_name);
21+
let mut store_handle = self
22+
.key_info_store
23+
.write()
24+
.expect("Key store lock poisoned");
25+
if key_info_exists(&key_triple, &*store_handle)? {
26+
return Err(ResponseStatus::PsaErrorAlreadyExists);
27+
}
28+
let key_id = create_key_id(&self.id_counter)?;
29+
30+
match self.context.generate_key(key_attributes, key_id) {
31+
Ok(_) => {
32+
if let Err(e) =
33+
insert_key_id(key_triple, key_attributes, &mut *store_handle, key_id)
34+
{
35+
if self.context.destroy_key(key_id).is_err() {
36+
error!("Failed to destroy the previously generated key.");
37+
}
38+
Err(e)
39+
} else {
40+
Ok(psa_generate_key::Result {})
41+
}
42+
}
43+
Err(error) => {
44+
let error = ResponseStatus::from(error);
45+
format_error!("Generate key error", error);
46+
Err(error)
47+
}
48+
}
49+
}
50+
51+
pub(super) fn psa_destroy_key_internal(
52+
&self,
53+
app_name: ApplicationName,
54+
op: psa_destroy_key::Operation,
55+
) -> Result<psa_destroy_key::Result> {
56+
let key_name = op.key_name;
57+
let key_triple = KeyTriple::new(app_name, ProviderID::TrustedService, key_name);
58+
let mut store_handle = self
59+
.key_info_store
60+
.write()
61+
.expect("Key store lock poisoned");
62+
let key_id = get_key_id(&key_triple, &*store_handle)?;
63+
64+
match self.context.destroy_key(key_id) {
65+
Ok(()) => {
66+
remove_key_id(&key_triple, &mut *store_handle)?;
67+
Ok(psa_destroy_key::Result {})
68+
}
69+
Err(error) => {
70+
let error = ResponseStatus::from(error);
71+
format_error!("Destroy key status: ", error);
72+
Err(error)
73+
}
74+
}
75+
}
76+
}

0 commit comments

Comments
 (0)