Skip to content

Commit c7120ca

Browse files
committed
Add asymmetric sign and verify to TS provider
This commit adds functionality to the Trusted Service provider allowing it to sign and verify hashes. Signed-off-by: Ionut Mihalcea <[email protected]>
1 parent d4090be commit c7120ca

File tree

6 files changed

+223
-36
lines changed

6 files changed

+223
-36
lines changed

build.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@ use std::io::{Error, ErrorKind, Result};
55
use std::path::{Path, PathBuf};
66

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

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

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

3131
println!("cargo:rustc-link-search=native=/usr/local/lib");
32-
println!("cargo:rustc-link-lib=static=ts-lib");
32+
println!("cargo:rustc-link-lib=dylib=ts");
3333
// TODO: Remove once we can use the full TS stack and this isn't needed
3434
println!("cargo:rustc-link-lib=static=mbedcrypto");
3535
println!("cargo:rustc-link-lib=static=protobuf-nanopb");
+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
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+
use parsec_interface::operations::{psa_sign_hash, psa_verify_hash};
8+
use parsec_interface::requests::{ProviderID, Result};
9+
10+
impl Provider {
11+
pub(super) fn psa_sign_hash_internal(
12+
&self,
13+
app_name: ApplicationName,
14+
op: psa_sign_hash::Operation,
15+
) -> Result<psa_sign_hash::Result> {
16+
let key_triple = KeyTriple::new(app_name, ProviderID::TrustedService, op.key_name.clone());
17+
let store_handle = self.key_info_store.read().expect("Key store lock poisoned");
18+
let key_id = key_management::get_key_id(&key_triple, &*store_handle)?;
19+
20+
Ok(psa_sign_hash::Result {
21+
signature: self
22+
.context
23+
.asym_sign(key_id, op.hash.to_vec(), op.alg)?
24+
.into(),
25+
})
26+
}
27+
28+
pub(super) fn psa_verify_hash_internal(
29+
&self,
30+
app_name: ApplicationName,
31+
op: psa_verify_hash::Operation,
32+
) -> Result<psa_verify_hash::Result> {
33+
let key_triple = KeyTriple::new(app_name, ProviderID::TrustedService, op.key_name.clone());
34+
let store_handle = self.key_info_store.read().expect("Key store lock poisoned");
35+
let key_id = key_management::get_key_id(&key_triple, &*store_handle)?;
36+
37+
self.context
38+
.asym_verify(key_id, op.hash.to_vec(), op.signature.to_vec(), op.alg)?;
39+
40+
Ok(psa_verify_hash::Result {})
41+
}
42+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// Copyright 2020 Contributors to the Parsec project.
2+
// SPDX-License-Identifier: Apache-2.0
3+
use super::ts_protobuf::{SignHashIn, SignHashOut, VerifyHashIn};
4+
use super::Context;
5+
use log::info;
6+
use parsec_interface::operations::psa_algorithm::AsymmetricSignature;
7+
use parsec_interface::requests::ResponseStatus;
8+
use std::convert::TryInto;
9+
10+
impl Context {
11+
pub fn asym_sign(
12+
&self,
13+
key_id: u32,
14+
hash: Vec<u8>,
15+
algorithm: AsymmetricSignature,
16+
) -> Result<Vec<u8>, ResponseStatus> {
17+
info!("Handling GenerateKey request");
18+
let proto_req = SignHashIn {
19+
handle: 0,
20+
hash,
21+
alg: algorithm.try_into()?,
22+
};
23+
let SignHashOut { signature } = self.send_request_with_key(proto_req, key_id)?;
24+
25+
Ok(signature)
26+
}
27+
28+
pub fn asym_verify(
29+
&self,
30+
key_id: u32,
31+
hash: Vec<u8>,
32+
signature: Vec<u8>,
33+
algorithm: AsymmetricSignature,
34+
) -> Result<(), ResponseStatus> {
35+
info!("Handling GenerateKey request");
36+
let proto_req = VerifyHashIn {
37+
handle: 0,
38+
hash,
39+
signature,
40+
alg: algorithm.try_into()?,
41+
};
42+
self.send_request_with_key(proto_req, key_id)?;
43+
44+
Ok(())
45+
}
46+
}

src/providers/trusted_service/context/key_management.rs

+12-15
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// SPDX-License-Identifier: Apache-2.0
33
use super::ts_protobuf::{
44
CloseKeyIn, DestroyKeyIn, DestroyKeyOut, GenerateKeyIn, GenerateKeyOut, KeyAttributes,
5-
KeyLifetime, KeyPolicy, Opcode, OpenKeyIn, OpenKeyOut,
5+
KeyLifetime, KeyPolicy, OpenKeyIn, OpenKeyOut,
66
};
77
use super::Context;
88
use log::info;
@@ -26,37 +26,34 @@ impl Context {
2626
}),
2727
}),
2828
};
29-
let GenerateKeyOut { handle } =
30-
self.send_request(&proto_req, Opcode::GenerateKey, self.rpc_caller)?;
29+
let GenerateKeyOut { handle } = self.send_request(&proto_req)?;
3130

3231
let proto_req = CloseKeyIn { handle };
33-
self.send_request(&proto_req, Opcode::CloseKey, self.rpc_caller)?;
32+
self.send_request(&proto_req)?;
3433

3534
Ok(())
3635
}
3736

38-
pub fn destroy_key(&self, id: u32) -> Result<(), ResponseStatus> {
37+
pub fn destroy_key(&self, key_id: u32) -> Result<(), ResponseStatus> {
3938
info!("Handling DestroyKey request");
40-
if !self.check_key_exists(id)? {
39+
if !self.check_key_exists(key_id)? {
4140
return Err(ResponseStatus::PsaErrorDoesNotExist);
4241
}
43-
let proto_req = OpenKeyIn { id };
44-
let OpenKeyOut { handle } =
45-
self.send_request(&proto_req, Opcode::OpenKey, self.rpc_caller)?;
42+
let proto_req = OpenKeyIn { id: key_id };
43+
let OpenKeyOut { handle } = self.send_request(&proto_req)?;
4644

4745
let proto_req = DestroyKeyIn { handle };
48-
let _proto_resp: DestroyKeyOut =
49-
self.send_request(&proto_req, Opcode::DestroyKey, self.rpc_caller)?;
46+
let _proto_resp: DestroyKeyOut = self.send_request(&proto_req)?;
5047
Ok(())
5148
}
5249

53-
pub fn check_key_exists(&self, id: u32) -> Result<bool, Error> {
50+
pub fn check_key_exists(&self, key_id: u32) -> Result<bool, Error> {
5451
info!("Handling CheckKey request");
55-
let proto_req = OpenKeyIn { id };
56-
match self.send_request(&proto_req, Opcode::OpenKey, self.rpc_caller) {
52+
let proto_req = OpenKeyIn { id: key_id };
53+
match self.send_request(&proto_req) {
5754
Ok(OpenKeyOut { handle }) => {
5855
let proto_req = CloseKeyIn { handle };
59-
self.send_request(&proto_req, Opcode::CloseKey, self.rpc_caller)?;
56+
self.send_request(&proto_req)?;
6057
Ok(true)
6158
}
6259
Err(e) => {

src/providers/trusted_service/context/mod.rs

+98-17
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use std::ptr::null_mut;
1010
use std::slice;
1111
use std::sync::Mutex;
1212
use ts_binding::*;
13-
use ts_protobuf::Opcode;
13+
use ts_protobuf::{CloseKeyIn, GetOpcode, OpenKeyIn, OpenKeyOut, SetHandle};
1414

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

33+
mod asym_sign;
3334
mod key_management;
3435

3536
#[allow(
@@ -48,6 +49,59 @@ mod key_management;
4849
)]
4950
mod ts_protobuf {
5051
include!(concat!(env!("OUT_DIR"), "/ts_crypto.rs"));
52+
53+
pub trait GetOpcode {
54+
fn opcode(&self) -> Opcode;
55+
}
56+
57+
macro_rules! opcode_impl {
58+
($type:ty, $opcode:ident) => {
59+
impl GetOpcode for $type {
60+
fn opcode(&self) -> Opcode {
61+
Opcode::$opcode
62+
}
63+
}
64+
};
65+
66+
($type_in:ty, $type_out:ty, $opcode:ident) => {
67+
impl GetOpcode for $type_in {
68+
fn opcode(&self) -> Opcode {
69+
Opcode::$opcode
70+
}
71+
}
72+
73+
impl GetOpcode for $type_out {
74+
fn opcode(&self) -> Opcode {
75+
Opcode::$opcode
76+
}
77+
}
78+
};
79+
}
80+
81+
opcode_impl!(OpenKeyIn, OpenKeyOut, OpenKey);
82+
opcode_impl!(CloseKeyIn, CloseKey);
83+
opcode_impl!(GenerateKeyIn, GenerateKeyOut, GenerateKey);
84+
opcode_impl!(DestroyKeyIn, DestroyKeyOut, DestroyKey);
85+
opcode_impl!(SignHashIn, SignHashOut, SignHash);
86+
opcode_impl!(VerifyHashIn, VerifyHashOut, VerifyHash);
87+
88+
pub trait SetHandle {
89+
fn set_handle(&mut self, handle: u32);
90+
}
91+
92+
macro_rules! set_handle_impl {
93+
($type:ty) => {
94+
impl SetHandle for $type {
95+
fn set_handle(&mut self, handle: u32) {
96+
self.handle = handle;
97+
}
98+
}
99+
};
100+
}
101+
102+
set_handle_impl!(DestroyKeyIn);
103+
set_handle_impl!(SignHashIn);
104+
set_handle_impl!(VerifyHashIn);
51105
}
52106

53107
// TODO:
@@ -65,15 +119,27 @@ pub struct Context {
65119

66120
impl Context {
67121
pub fn connect() -> anyhow::Result<Self> {
68-
info!("Querying for crypto Trusted Services");
122+
// Initialise service locator. Can be called multiple times,
123+
// but *must* be called at least once.
124+
unsafe { service_locator_init() };
125+
126+
info!("Obtaining a crypto Trusted Service context.");
69127
let mut status = 0;
70128
let service_context = unsafe {
71129
service_locator_query(
72-
CString::new("sn:tf.org:crypto:0").unwrap().into_raw(),
130+
CString::new("sn:trustedfirmware.org:crypto:0")
131+
.unwrap()
132+
.into_raw(),
73133
&mut status,
74134
)
75135
};
76-
if service_context == null_mut() || status != 0 {
136+
if service_context == null_mut() {
137+
return Err(Error::new(
138+
ErrorKind::Other,
139+
"Failed to obtain a Trusted Service context",
140+
)
141+
.into());
142+
} else if status != 0 {
77143
return Err(Error::new(
78144
ErrorKind::Other,
79145
format!(
@@ -104,15 +170,14 @@ impl Context {
104170

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

114178
let mut buf_out = null_mut();
115-
let call_handle = unsafe { rpc_caller_begin(rpc_cl, &mut buf_out, req.encoded_len()) };
179+
let call_handle =
180+
unsafe { rpc_caller_begin(self.rpc_caller, &mut buf_out, req.encoded_len()) };
116181
if call_handle == null_mut() {
117182
error!("Call handle was null");
118183
return Err(PsaError::CommunicationFailure);
@@ -122,7 +187,7 @@ impl Context {
122187
}
123188
let mut buf_out = unsafe { slice::from_raw_parts_mut(buf_out, req.encoded_len()) };
124189
req.encode(&mut buf_out).map_err(|e| {
125-
unsafe { rpc_caller_end(rpc_cl, call_handle) };
190+
unsafe { rpc_caller_end(self.rpc_caller, call_handle) };
126191
format_error!("Failed to serialize Protobuf request", e);
127192
PsaError::CommunicationFailure
128193
})?;
@@ -134,39 +199,55 @@ impl Context {
134199
let mut resp_buf_size = 0;
135200
let status = unsafe {
136201
rpc_caller_invoke(
137-
rpc_cl,
202+
self.rpc_caller,
138203
call_handle,
139-
i32::from(opcode).try_into().unwrap(),
204+
i32::from(req.opcode()).try_into().unwrap(),
140205
&mut opstatus,
141206
&mut resp_buf,
142207
&mut resp_buf_size,
143208
)
144209
};
145210
if status != 0 || opstatus != 0 {
146-
unsafe { rpc_caller_end(rpc_cl, call_handle) };
211+
unsafe { rpc_caller_end(self.rpc_caller, call_handle) };
147212
error!(
148213
"Error on call invocation: status = {}, opstatus = {}",
149-
status, opstatus as i32
214+
status, opstatus
150215
);
151-
Status::from(opstatus as i32).to_result()?;
216+
Status::from(opstatus).to_result()?;
152217
}
153218
let resp_buf = unsafe { slice::from_raw_parts_mut(resp_buf, resp_buf_size) };
154219
resp.merge(&*resp_buf).map_err(|e| {
155-
unsafe { rpc_caller_end(rpc_cl, call_handle) };
220+
unsafe { rpc_caller_end(self.rpc_caller, call_handle) };
156221
format_error!("Failed to serialize Protobuf request", e);
157222
PsaError::CommunicationFailure
158223
})?;
159-
unsafe { rpc_caller_end(rpc_cl, call_handle) };
224+
unsafe { rpc_caller_end(self.rpc_caller, call_handle) };
160225

161226
Ok(resp)
162227
}
228+
229+
fn send_request_with_key<T: Message + Default>(
230+
&self,
231+
mut req: impl Message + GetOpcode + SetHandle,
232+
key_id: u32,
233+
) -> Result<T, PsaError> {
234+
let proto_req = OpenKeyIn { id: key_id };
235+
let OpenKeyOut { handle } = self.send_request(&proto_req)?;
236+
req.set_handle(handle);
237+
let res = self.send_request(&req);
238+
let proto_req = CloseKeyIn { handle };
239+
let res_close = self.send_request(&proto_req);
240+
let res = res?;
241+
res_close?;
242+
Ok(res)
243+
}
163244
}
164245

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

169-
unsafe { service_locator_relinquish(self.service_context) };
250+
unsafe { service_context_relinquish(self.service_context) };
170251
}
171252
}
172253

0 commit comments

Comments
 (0)