1use std::sync::Arc;
3
4use tiny_keccak::{Hasher, TupleHash};
5
6use oasis_core_keymanager::client::{KeyManagerClient as CoreKeyManagerClient, RemoteClient};
7pub use oasis_core_keymanager::{
8 api::KeyManagerError,
9 crypto::{KeyPair, KeyPairId, SignedPublicKey, StateKey},
10 policy::TrustedSigners,
11};
12use oasis_core_runtime::{
13 common::{crypto::signature::PublicKey, namespace::Namespace},
14 consensus::{beacon::EpochTime, verifier::Verifier},
15 future::block_on,
16 identity::Identity,
17 protocol::Protocol,
18 RpcDispatcher,
19};
20
21pub(crate) struct KeyManagerClient {
24 inner: Arc<dyn CoreKeyManagerClient>,
25}
26
27impl KeyManagerClient {
28 pub(crate) fn new(
30 runtime_id: Namespace,
31 protocol: Arc<Protocol>,
32 consensus_verifier: Arc<dyn Verifier>,
33 identity: Arc<Identity>,
34 rpc: &mut RpcDispatcher,
35 key_cache_sizes: usize,
36 signers: TrustedSigners,
37 ) -> Self {
38 let remote_client = Arc::new(RemoteClient::new_runtime(
39 runtime_id,
40 protocol,
41 consensus_verifier,
42 identity,
43 key_cache_sizes,
44 signers,
45 ));
46
47 let handler_remote_client = remote_client.clone();
49 rpc.set_keymanager_quote_policy_update_handler(Some(Box::new(move |policy| {
50 block_on(handler_remote_client.set_quote_policy(policy));
51 })));
52
53 let handler_remote_client = remote_client.clone();
55 rpc.set_keymanager_status_update_handler(Some(Box::new(move |status| {
56 block_on(handler_remote_client.set_status(status))
57 .expect("failed to update km client status");
58 })));
59
60 KeyManagerClient {
61 inner: remote_client,
62 }
63 }
64
65 pub(crate) fn with_context(self: &Arc<Self>) -> Box<dyn KeyManager> {
68 Box::new(KeyManagerClientWithContext::new(self.clone(), false)) as Box<dyn KeyManager>
69 }
70
71 pub(crate) fn with_private_context(self: &Arc<Self>) -> Box<dyn KeyManager> {
74 Box::new(KeyManagerClientWithContext::new(self.clone(), true)) as Box<dyn KeyManager>
75 }
76
77 pub(crate) fn runtime_id(&self) -> Option<Namespace> {
82 self.inner.runtime_id()
83 }
84
85 pub(crate) fn runtime_signing_key(&self) -> Option<PublicKey> {
89 self.inner.runtime_signing_key()
90 }
91
92 pub(crate) fn clear_cache(&self) {
96 self.inner.clear_cache()
97 }
98
99 pub(crate) async fn get_or_create_keys(
103 &self,
104 key_pair_id: KeyPairId,
105 ) -> Result<KeyPair, KeyManagerError> {
106 retryable(|| self.inner.get_or_create_keys(key_pair_id, 0)).await
107 }
108
109 pub(crate) async fn get_public_key(
113 &self,
114 key_pair_id: KeyPairId,
115 ) -> Result<SignedPublicKey, KeyManagerError> {
116 retryable(|| self.inner.get_public_key(key_pair_id, 0)).await
117 }
118
119 pub(crate) async fn get_or_create_ephemeral_keys(
123 &self,
124 key_pair_id: KeyPairId,
125 epoch: EpochTime,
126 ) -> Result<KeyPair, KeyManagerError> {
127 retryable(|| self.inner.get_or_create_ephemeral_keys(key_pair_id, epoch)).await
128 }
129
130 pub(crate) async fn get_public_ephemeral_key(
134 &self,
135 key_pair_id: KeyPairId,
136 epoch: EpochTime,
137 ) -> Result<SignedPublicKey, KeyManagerError> {
138 retryable(|| self.inner.get_public_ephemeral_key(key_pair_id, epoch)).await
139 }
140}
141
142async fn retryable<A>(action: A) -> Result<A::Item, A::Error>
144where
145 A: tokio_retry::Action,
146{
147 let retry_strategy = tokio_retry::strategy::ExponentialBackoff::from_millis(4)
148 .max_delay(std::time::Duration::from_millis(250))
149 .map(tokio_retry::strategy::jitter)
150 .take(5);
151
152 tokio_retry::Retry::spawn(retry_strategy, action).await
153}
154
155pub trait KeyManager {
157 fn runtime_id(&self) -> Option<Namespace>;
162
163 fn runtime_signing_key(&self) -> Option<PublicKey>;
167
168 fn clear_cache(&self);
172
173 fn get_or_create_keys(&self, key_pair_id: KeyPairId) -> Result<KeyPair, KeyManagerError>;
178
179 fn get_public_key(&self, key_pair_id: KeyPairId) -> Result<SignedPublicKey, KeyManagerError>;
184
185 fn get_or_create_ephemeral_keys(
190 &self,
191 key_pair_id: KeyPairId,
192 epoch: EpochTime,
193 ) -> Result<KeyPair, KeyManagerError>;
194
195 fn get_public_ephemeral_key(
200 &self,
201 key_pair_id: KeyPairId,
202 epoch: EpochTime,
203 ) -> Result<SignedPublicKey, KeyManagerError>;
204
205 fn box_clone(&self) -> Box<dyn KeyManager>;
206}
207
208impl Clone for Box<dyn KeyManager> {
209 fn clone(&self) -> Box<dyn KeyManager> {
210 self.box_clone()
211 }
212}
213
214#[derive(Clone)]
217pub struct KeyManagerClientWithContext {
218 parent: Arc<KeyManagerClient>,
219 allow_private: bool,
220}
221
222impl KeyManagerClientWithContext {
223 fn new(parent: Arc<KeyManagerClient>, allow_private: bool) -> KeyManagerClientWithContext {
224 KeyManagerClientWithContext {
225 parent,
226 allow_private,
227 }
228 }
229
230 async fn get_or_create_keys_async(
234 &self,
235 key_pair_id: KeyPairId,
236 ) -> Result<KeyPair, KeyManagerError> {
237 if !self.allow_private {
238 return Err(KeyManagerError::Other(anyhow::anyhow!(
239 "not allowed by local runtime policy"
240 )));
241 }
242
243 self.parent.get_or_create_keys(key_pair_id).await
244 }
245
246 async fn get_public_key_async(
250 &self,
251 key_pair_id: KeyPairId,
252 ) -> Result<SignedPublicKey, KeyManagerError> {
253 self.parent.get_public_key(key_pair_id).await
254 }
255
256 async fn get_or_create_ephemeral_keys_async(
260 &self,
261 key_pair_id: KeyPairId,
262 epoch: EpochTime,
263 ) -> Result<KeyPair, KeyManagerError> {
264 if !self.allow_private {
265 return Err(KeyManagerError::Other(anyhow::anyhow!(
266 "not allowed by local runtime policy"
267 )));
268 }
269
270 self.parent
271 .get_or_create_ephemeral_keys(key_pair_id, epoch)
272 .await
273 }
274
275 async fn get_public_ephemeral_key_async(
279 &self,
280 key_pair_id: KeyPairId,
281 epoch: EpochTime,
282 ) -> Result<SignedPublicKey, KeyManagerError> {
283 self.parent
284 .get_public_ephemeral_key(key_pair_id, epoch)
285 .await
286 }
287}
288
289impl KeyManager for KeyManagerClientWithContext {
290 fn runtime_id(&self) -> Option<Namespace> {
291 self.parent.runtime_id()
292 }
293
294 fn runtime_signing_key(&self) -> Option<PublicKey> {
295 self.parent.runtime_signing_key()
296 }
297
298 fn clear_cache(&self) {
299 self.parent.clear_cache();
300 }
301
302 fn get_or_create_keys(&self, key_pair_id: KeyPairId) -> Result<KeyPair, KeyManagerError> {
303 block_on(self.get_or_create_keys_async(key_pair_id))
304 }
305
306 fn get_public_key(&self, key_pair_id: KeyPairId) -> Result<SignedPublicKey, KeyManagerError> {
307 block_on(self.get_public_key_async(key_pair_id))
308 }
309
310 fn get_or_create_ephemeral_keys(
311 &self,
312 key_pair_id: KeyPairId,
313 epoch: EpochTime,
314 ) -> Result<KeyPair, KeyManagerError> {
315 block_on(self.get_or_create_ephemeral_keys_async(key_pair_id, epoch))
316 }
317
318 fn get_public_ephemeral_key(
319 &self,
320 key_pair_id: KeyPairId,
321 epoch: EpochTime,
322 ) -> Result<SignedPublicKey, KeyManagerError> {
323 block_on(self.get_public_ephemeral_key_async(key_pair_id, epoch))
324 }
325
326 fn box_clone(&self) -> Box<dyn KeyManager> {
327 Box::new(self.clone())
328 }
329}
330
331pub const KEY_PAIR_ID_CONTEXT: &[u8] = b"oasis-runtime-sdk/keymanager: key pair id";
333
334pub fn get_key_pair_id<'a, C>(context: C) -> KeyPairId
336where
337 C: IntoIterator<Item = &'a [u8]> + 'a,
338{
339 let mut h = TupleHash::v256(KEY_PAIR_ID_CONTEXT);
340 for item in context.into_iter() {
341 h.update(item);
342 }
343 let mut key_pair_id = [0u8; 32];
344 h.finalize(&mut key_pair_id);
345
346 KeyPairId(key_pair_id)
347}