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