1use anyhow::anyhow;
3
4use crate::{
5 common::{
6 crypto::{hash::Hash, signature::PublicKey},
7 key_format::{KeyFormat, KeyFormatAtom},
8 namespace::Namespace,
9 },
10 consensus::{
11 beacon::EpochTime,
12 keymanager::{
13 SignedEncryptedEphemeralSecret, SignedEncryptedMasterSecret, SignedPolicySGX,
14 },
15 state::StateError,
16 },
17 key_format,
18 storage::mkvs::ImmutableMKVS,
19};
20
21pub mod churp;
22
23pub struct ImmutableState<'a, T: ImmutableMKVS> {
25 mkvs: &'a T,
26}
27
28impl<T: ImmutableMKVS> ImmutableState<'_, T> {
29 pub fn new(mkvs: &T) -> ImmutableState<'_, T> {
31 ImmutableState { mkvs }
32 }
33}
34
35key_format!(StatusKeyFmt, 0x70, Hash);
36key_format!(MasterSecretKeyFmt, 0x72, Hash);
37key_format!(EphemeralSecretKeyFmt, 0x73, Hash);
38
39#[derive(Clone, Debug, Default, PartialEq, Eq, cbor::Decode, cbor::Encode)]
41pub struct Status {
42 pub id: Namespace,
44 pub is_initialized: bool,
46 pub is_secure: bool,
48 pub generation: u64,
50 pub rotation_epoch: EpochTime,
52 pub checksum: Vec<u8>,
54 pub nodes: Vec<PublicKey>,
56 pub policy: Option<SignedPolicySGX>,
58 pub next_policy: Option<SignedPolicySGX>,
60 pub rsk: Option<PublicKey>,
62}
63
64impl<T: ImmutableMKVS> ImmutableState<'_, T> {
65 pub fn status(&self, id: Namespace) -> Result<Option<Status>, StateError> {
67 let h = Hash::digest_bytes(id.as_ref());
68 match self.mkvs.get(&StatusKeyFmt(h).encode()) {
69 Ok(Some(b)) => Ok(Some(self.decode_status(&b)?)),
70 Ok(None) => Ok(None),
71 Err(err) => Err(StateError::Unavailable(anyhow!(err))),
72 }
73 }
74
75 pub fn statuses(&self) -> Result<Vec<Status>, StateError> {
77 let mut it = self.mkvs.iter();
78 it.seek(&StatusKeyFmt::default().encode_partial(0));
79
80 let mut result: Vec<Status> = Vec::new();
81
82 while let Some(value) = it
83 .next()
84 .and_then(|(key, value)| StatusKeyFmt::decode(&key).map(|_| value))
85 {
86 result.push(self.decode_status(&value)?)
87 }
88
89 Ok(result)
90 }
91
92 pub fn master_secret(
94 &self,
95 id: Namespace,
96 ) -> Result<Option<SignedEncryptedMasterSecret>, StateError> {
97 let h = Hash::digest_bytes(id.as_ref());
98 match self.mkvs.get(&MasterSecretKeyFmt(h).encode()) {
99 Ok(Some(b)) => Ok(Some(self.decode_master_secret(&b)?)),
100 Ok(None) => Ok(None),
101 Err(err) => Err(StateError::Unavailable(anyhow!(err))),
102 }
103 }
104
105 pub fn ephemeral_secret(
107 &self,
108 id: Namespace,
109 ) -> Result<Option<SignedEncryptedEphemeralSecret>, StateError> {
110 let h = Hash::digest_bytes(id.as_ref());
111 match self.mkvs.get(&EphemeralSecretKeyFmt(h).encode()) {
112 Ok(Some(b)) => Ok(Some(self.decode_ephemeral_secret(&b)?)),
113 Ok(None) => Ok(None),
114 Err(err) => Err(StateError::Unavailable(anyhow!(err))),
115 }
116 }
117
118 fn decode_status(&self, data: &[u8]) -> Result<Status, StateError> {
119 cbor::from_slice(data).map_err(|err| StateError::Unavailable(anyhow!(err)))
120 }
121
122 fn decode_master_secret(&self, data: &[u8]) -> Result<SignedEncryptedMasterSecret, StateError> {
123 cbor::from_slice(data).map_err(|err| StateError::Unavailable(anyhow!(err)))
124 }
125
126 fn decode_ephemeral_secret(
127 &self,
128 data: &[u8],
129 ) -> Result<SignedEncryptedEphemeralSecret, StateError> {
130 cbor::from_slice(data).map_err(|err| StateError::Unavailable(anyhow!(err)))
131 }
132}
133
134#[cfg(test)]
135mod test {
136 use std::collections::HashMap;
137
138 use rustc_hex::FromHex;
139
140 use super::*;
141 use crate::{
142 common::{
143 crypto::{
144 signature::{Signature, SignatureBundle},
145 x25519,
146 },
147 sgx::{EnclaveIdentity, MrEnclave, MrSigner},
148 },
149 consensus::keymanager::{
150 EnclavePolicySGX, EncryptedEphemeralSecret, EncryptedSecret, PolicySGX,
151 },
152 storage::mkvs::{
153 interop::{Fixture, ProtocolServer},
154 Root, RootType, Tree,
155 },
156 };
157
158 #[test]
159 fn test_keymanager_secrets_state_interop() {
160 let server = ProtocolServer::new(Fixture::ConsensusMock.into());
168 let mock_consensus_root = Root {
169 version: 1,
170 root_type: RootType::State,
171 hash: Hash::from("8e39bf193f8a954ab8f8d7cb6388c591fd0785ea060bbd8e3752e266b54499d3"),
172 ..Default::default()
173 };
174 let mkvs = Tree::builder()
175 .with_capacity(100_000, 10_000_000)
176 .with_root(mock_consensus_root)
177 .build(server.read_sync());
178 let keymanager_state = ImmutableState::new(&mkvs);
179
180 let runtime =
182 Namespace::from("8000000000000000000000000000000000000000000000000000000000000000");
183 let keymanager1 =
184 Namespace::from("c000000000000000fffffffffffffffffffffffffffffffffffffffffffffffe");
185 let keymanager2 =
186 Namespace::from("c000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff");
187 let runtime_enclave = EnclaveIdentity {
188 mr_enclave: MrEnclave::from(
189 "18256f783c071521be2da041cd9347b5bdb5a8ef58fb34658571a6e14cf1fcb0",
190 ),
191 mr_signer: MrSigner::from(
192 "e48049d1de0eb333523991671a6c93b97dd65bcf09273d5b6bfe8262dc968ec7",
193 ),
194 };
195 let keymanager_enclave1 = EnclaveIdentity {
196 mr_enclave: MrEnclave::from(
197 "c9a589851b1f35627177fd70378ed778170f737611e4dfbf0b6d25bdff55b474",
198 ),
199 mr_signer: MrSigner::from(
200 "7d310664780931ae103ab30a90171c201af385a72757bb4683578fdebde9adf5",
201 ),
202 };
203 let keymanager_enclave2 = EnclaveIdentity {
204 mr_enclave: MrEnclave::from(
205 "756eaf76f5482c5345808b1eaccdd5c60f864bb2aa2d2b870df00ce435af4e23",
206 ),
207 mr_signer: MrSigner::from(
208 "3597a2ff0743016f28e5d7e129304ee1c43dbdae3dba94e19cee3549038a5a32",
209 ),
210 };
211 let signer1 =
212 PublicKey::from("96533c123a6f4d33c68357109c2eb7c6e6a0f947be3ae1e320d153f561523ff2");
213 let signer2 =
214 PublicKey::from("4b97bfd95e829d5838131492b5c133e66ac6ef0db414c0be6207ec78c12d2b17");
215 let sig1 = Signature::from("eda666cff6e4030200737e0c7707ad4a378aab4cc0455306992c13da2155b97c91b0fde0325a7a6818f2cbf92813cc587723c8c205a7cb5389ca7b21a038b60a");
216 let sig2 = Signature::from("db90d354272e025aa9a5856f32ea4f5d6becb0ff6340f3cb7f9104ac04ef29ed4f9b5c21b7ea82924800b30f94724b40c376414f80780ff8b7b60a34edea9f02");
217 let checksum = "1bff211fae98c88ba82388ae954b88a71d3bbe327e162e9fa711fe7a1b759c3e"
218 .from_hex()
219 .unwrap();
220
221 let expected_statuses = vec![
222 Status {
223 id: keymanager1,
224 is_initialized: false,
225 is_secure: false,
226 generation: 0,
227 rotation_epoch: 0,
228 checksum: vec![],
229 nodes: vec![],
230 policy: None,
231 next_policy: None,
232 rsk: None,
233 },
234 Status {
235 id: keymanager2,
236 is_initialized: true,
237 is_secure: true,
238 generation: 0,
239 rotation_epoch: 0,
240 checksum: checksum,
241 nodes: vec![signer1, signer2],
242 policy: Some(SignedPolicySGX {
243 policy: PolicySGX {
244 serial: 1,
245 id: keymanager2,
246 enclaves: HashMap::from([(
247 keymanager_enclave1,
248 EnclavePolicySGX {
249 may_query: HashMap::from([(runtime, vec![runtime_enclave])]),
250 may_replicate: vec![keymanager_enclave2],
251 },
252 )]),
253 master_secret_rotation_interval: 0,
254 max_ephemeral_secret_age: 10,
255 },
256 signatures: vec![
257 SignatureBundle {
258 public_key: signer1,
259 signature: sig1,
260 },
261 SignatureBundle {
262 public_key: signer2,
263 signature: sig2,
264 },
265 ],
266 }),
267 next_policy: None,
268 rsk: None,
269 },
270 ];
271
272 let rek1 = x25519::PrivateKey::from_test_seed("first rek".to_string());
273 let rek2 = x25519::PrivateKey::from_test_seed("second rek".to_string());
274
275 let expected_secret = SignedEncryptedEphemeralSecret {
276 secret: EncryptedEphemeralSecret {
277 runtime_id: keymanager1,
278 epoch: 1,
279 secret: EncryptedSecret{
280 checksum: vec![1,2,3,4,5],
281 pub_key: rek1.public_key(),
282 ciphertexts: HashMap::from([
283 (rek1.public_key(), vec![1, 2, 3]),
284 (rek2.public_key(), vec![4, 5, 6]),
285 ]),
286 },
287 },
288 signature: Signature::from("4a2d098e02411fdc14d6a36f91bb362fd4f4dbaadb4cbf70e20e038fe1740bc7dde0b20afd25657d6abc916be2b9ed0054d586aedb2b7951c99aab3206b24b02"),
289 };
290
291 let mut statuses = keymanager_state
293 .statuses()
294 .expect("statuses query should work");
295 statuses.sort_by(|a, b| a.id.partial_cmp(&b.id).unwrap());
296 assert_eq!(statuses, expected_statuses, "invalid statuses");
297
298 let status = keymanager_state
300 .status(expected_statuses[1].id)
301 .expect("status query should work")
302 .expect("status query should return a result");
303 assert_eq!(status, expected_statuses[1], "invalid status");
304
305 let id =
306 Namespace::from("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
307 let status = keymanager_state
308 .status(id)
309 .expect("status query should work");
310 assert_eq!(status, None, "invalid status");
311
312 let secret = keymanager_state
314 .ephemeral_secret(keymanager1)
315 .expect("ephemeral secret query should work")
316 .expect("ephemeral secret query should return a result");
317 assert_eq!(secret, expected_secret, "invalid ephemeral secret");
318 }
319}