kassandra_shared/
ratls.rs1use alloc::vec::Vec;
8
9use chacha20poly1305::aead::Aead;
10use chacha20poly1305::{AeadCore, ChaCha20Poly1305, Key, KeyInit, Nonce};
11use fmd::DetectionKey;
12use rand_core::{CryptoRng, RngCore};
13use serde::de::DeserializeOwned;
14use serde::{Deserialize, Deserializer, Serialize, Serializer};
15use thiserror::Error;
16
17use crate::db::EncKey;
18use crate::{ClientMsg, MsgToHost};
19
20#[derive(Error, Debug)]
21pub enum RatlsError {
22 #[error("Cannot perform Diffie-Hellman on a connection that is already initialized")]
23 AlreadyInitialized,
24 #[error("Shared Secret was non-contributory. This suggests a man-in-the-middle attack.")]
25 NonContributory,
26 #[error("Cannot encrypt to a non-initialized channel")]
27 NotInitialized,
28 #[error("Could not decrypt message")]
29 Decryption,
30 #[error("Failed to deserialize message with: {0}")]
31 Deserialize(serde_cbor::Error),
32}
33
34#[derive(Debug, Clone)]
36pub struct TlsCiphertext {
37 payload: Vec<u8>,
38 nonce: Nonce,
39}
40
41#[derive(Deserialize, Serialize)]
44pub struct FmdKeyRegistration {
45 pub fmd_key: DetectionKey,
47 pub enc_key: EncKey,
50 pub birthday: Option<u64>,
52}
53
54impl Serialize for TlsCiphertext {
55 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
56 where
57 S: Serializer,
58 {
59 #[derive(Serialize)]
60 struct SimplifiedCiphertext {
61 payload: Vec<u8>,
62 nonce: Vec<u8>,
63 }
64 let simplified = SimplifiedCiphertext {
65 payload: self.payload.clone(),
66 nonce: self.nonce.as_slice().to_vec(),
67 };
68 simplified.serialize(serializer)
69 }
70}
71
72impl<'de> Deserialize<'de> for TlsCiphertext {
73 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
74 where
75 D: Deserializer<'de>,
76 {
77 #[derive(Deserialize)]
78 struct SimplifiedCiphertext {
79 payload: Vec<u8>,
80 nonce: Vec<u8>,
81 }
82 let simplified = SimplifiedCiphertext::deserialize(deserializer)?;
83 Ok(Self {
84 payload: simplified.payload,
85 nonce: *Nonce::from_slice(&simplified.nonce),
86 })
87 }
88}
89
90pub enum Connection {
96 Handshake {
97 ephemeral_key: x25519_dalek::EphemeralSecret,
98 },
99 Initialized {
100 shared_key: ChaCha20Poly1305,
101 },
102}
103
104impl Connection {
105 pub fn new(rng: impl CryptoRng + RngCore) -> Self {
108 Self::Handshake {
109 ephemeral_key: x25519_dalek::EphemeralSecret::random_from_rng(rng),
110 }
111 }
112
113 pub fn client_send(&self, nonce: u64) -> Result<ClientMsg, RatlsError> {
115 match &self {
116 Self::Handshake { ephemeral_key } => Ok(ClientMsg::RegisterKey {
117 nonce,
118 pk: x25519_dalek::PublicKey::from(ephemeral_key)
119 .to_bytes()
120 .into(),
121 }),
122 Self::Initialized { .. } => Err(RatlsError::AlreadyInitialized),
123 }
124 }
125
126 pub fn enclave_reply(&self, report: Vec<u8>) -> Result<MsgToHost, RatlsError> {
129 match &self {
130 Self::Handshake { .. } => Ok(MsgToHost::RATLS { report }),
131 Self::Initialized { .. } => Err(RatlsError::AlreadyInitialized),
132 }
133 }
134
135 pub fn initialize(self, pk: x25519_dalek::PublicKey) -> Result<Self, RatlsError> {
137 let Self::Handshake { ephemeral_key } = self else {
138 return Err(RatlsError::AlreadyInitialized);
139 };
140 let shared_secret = ephemeral_key.diffie_hellman(&pk);
141 let shared_key = if shared_secret.was_contributory() {
142 ChaCha20Poly1305::new(Key::from_slice(shared_secret.as_bytes()))
143 } else {
144 return Err(RatlsError::NonContributory);
145 };
146 Ok(Self::Initialized { shared_key })
147 }
148
149 pub fn encrypt_msg<T: CryptoRng + RngCore>(
151 &self,
152 payload: &[u8],
153 rng: &mut T,
154 ) -> Result<TlsCiphertext, RatlsError> {
155 if let Self::Initialized { shared_key } = &self {
156 let nonce = ChaCha20Poly1305::generate_nonce(rng);
157 Ok(TlsCiphertext {
158 payload: shared_key.encrypt(&nonce, payload).unwrap(),
159 nonce,
160 })
161 } else {
162 Err(RatlsError::NotInitialized)
163 }
164 }
165
166 pub fn decrypt_msg<T: DeserializeOwned>(&self, msg: &TlsCiphertext) -> Result<T, RatlsError> {
168 if let Self::Initialized { shared_key } = &self {
169 shared_key
170 .decrypt(&msg.nonce, &*msg.payload)
171 .or(Err(RatlsError::Decryption))
172 .and_then(|p| serde_cbor::from_slice(p.as_slice()).map_err(RatlsError::Deserialize))
173 } else {
174 Err(RatlsError::NotInitialized)
175 }
176 }
177}