ockam_entity/
authentication.rs1use crate::{EntityError, ProfileVault};
2use ockam_core::compat::vec::Vec;
3use ockam_core::vault::Signature;
4use ockam_core::{Decodable, Encodable, Result};
5use ockam_vault::{PublicKey, Secret};
6use serde::{Deserialize, Serialize};
7
8#[derive(Debug, Serialize, Deserialize)]
9pub(crate) struct AuthenticationProof {
10 signature: Signature,
11}
12
13impl AuthenticationProof {
14 pub(crate) fn signature(&self) -> &Signature {
15 &self.signature
16 }
17}
18
19impl AuthenticationProof {
20 pub(crate) fn new(signature: Signature) -> Self {
21 AuthenticationProof { signature }
22 }
23}
24
25pub(crate) struct Authentication {}
26
27impl Authentication {
28 pub(crate) async fn generate_proof<V: ProfileVault>(
29 channel_state: &[u8],
30 secret: &Secret,
31 vault: &mut V,
32 ) -> Result<Vec<u8>> {
33 let signature = vault.sign(secret, channel_state).await?;
34
35 let proof = AuthenticationProof::new(signature);
36
37 proof.encode().map_err(|_| EntityError::BareError.into())
38 }
39
40 pub(crate) async fn verify_proof<V: ProfileVault>(
41 channel_state: &[u8],
42 responder_public_key: &PublicKey,
43 proof: &[u8],
44 vault: &mut V,
45 ) -> Result<bool> {
46 let proof = AuthenticationProof::decode(proof).map_err(|_| EntityError::BareError)?;
47
48 vault
49 .verify(proof.signature(), responder_public_key, channel_state)
50 .await
51 }
52}
53
54#[cfg(test)]
55mod test {
56
57 use crate::{Entity, Identity};
58 use ockam_core::{Error, Result};
59 use ockam_node::Context;
60 use ockam_vault_sync_core::Vault;
61 use rand::{thread_rng, RngCore};
62
63 fn test_error<S: Into<String>>(error: S) -> Result<()> {
64 Err(Error::new(0, error))
65 }
66
67 async fn test_auth_use_case(ctx: &Context) -> Result<()> {
68 let alice_vault = Vault::create(ctx).await.expect("failed to create vault");
69 let bob_vault = Vault::create(ctx).await.expect("failed to create vault");
70
71 let mut alice = Entity::create(ctx, &alice_vault).await?;
73 let mut bob = Entity::create(ctx, &bob_vault).await?;
74
75 let mut alice_chat = alice.create_profile(&alice_vault).await?;
77 let mut bob_chat = bob.create_profile(&bob_vault).await?;
78
79 let alice_contact = alice_chat.as_contact().await?;
81 let bob_contact = bob_chat.as_contact().await?;
82
83 if !alice_chat
85 .verify_and_add_contact(bob_contact.clone())
86 .await?
87 {
88 return test_error("alice failed to add bob");
89 }
90
91 if !bob_chat
92 .verify_and_add_contact(alice_contact.clone())
93 .await?
94 {
95 return test_error("bob failed to add alice");
96 }
97
98 let state = {
100 let mut state = [0u8; 32];
101 let mut rng = thread_rng();
102 rng.fill_bytes(&mut state);
103 state
104 };
105
106 let alice_proof = alice_chat.create_auth_proof(&state).await?;
107 let bob_proof = bob_chat.create_auth_proof(&state).await?;
108
109 if !alice_chat
110 .verify_auth_proof(&state, bob_contact.identifier(), &bob_proof)
111 .await?
112 {
113 return test_error("bob's proof was invalid");
114 }
115
116 if !bob_chat
117 .verify_auth_proof(&state, alice_contact.identifier(), &alice_proof)
118 .await?
119 {
120 return test_error("alice's proof was invalid");
121 }
122 Ok(())
123 }
124
125 async fn test_key_rotation(ctx: &Context) -> Result<()> {
126 let alice_vault = Vault::create(ctx).await.expect("failed to create vault");
127 let bob_vault = Vault::create(ctx).await.expect("failed to create vault");
128
129 let mut alice = Entity::create(ctx, &alice_vault).await?;
131 let mut bob = Entity::create(ctx, &bob_vault).await?;
132
133 let mut alice_chat = alice.create_profile(&alice_vault).await?;
135 let mut bob_chat = bob.create_profile(&bob_vault).await?;
136
137 alice_chat.rotate_root_secret_key().await?;
139 bob_chat.rotate_root_secret_key().await?;
140
141 let alice_contact = alice_chat.as_contact().await?;
143 let bob_contact = bob_chat.as_contact().await?;
144
145 if !alice_chat
147 .verify_and_add_contact(bob_contact.clone())
148 .await?
149 {
150 return test_error("alice failed to add bob");
151 }
152
153 if !bob_chat
154 .verify_and_add_contact(alice_contact.clone())
155 .await?
156 {
157 return test_error("bob failed to add alice");
158 }
159
160 Ok(())
161 }
162
163 async fn test_update_contact_and_reprove(ctx: &Context) -> Result<()> {
164 let alice_vault = Vault::create(ctx).await.expect("failed to create vault");
165 let bob_vault = Vault::create(ctx).await.expect("failed to create vault");
166
167 let mut alice = Entity::create(ctx, &alice_vault).await?;
168 let mut bob = Entity::create(ctx, &bob_vault).await?;
169
170 let mut alice_chat = alice.create_profile(&alice_vault).await?;
172 let mut bob_chat = bob.create_profile(&bob_vault).await?;
173
174 let alice_contact = alice_chat.as_contact().await?;
176 let bob_contact = bob_chat.as_contact().await?;
177
178 if !alice_chat
180 .verify_and_add_contact(bob_contact.clone())
181 .await?
182 {
183 return test_error("alice failed to add bob");
184 }
185
186 if !bob_chat
187 .verify_and_add_contact(alice_contact.clone())
188 .await?
189 {
190 return test_error("bob failed to add alice");
191 }
192
193 let state = {
195 let mut state = [0u8; 32];
196 let mut rng = thread_rng();
197 rng.fill_bytes(&mut state);
198 state
199 };
200
201 let alice_proof = alice_chat.create_auth_proof(&state).await?;
202 let bob_proof = bob_chat.create_auth_proof(&state).await?;
203
204 if !alice_chat
205 .verify_auth_proof(&state, bob_contact.identifier(), &bob_proof)
206 .await?
207 {
208 return test_error("bob's proof was invalid");
209 }
210
211 if !bob_chat
212 .verify_auth_proof(&state, alice_contact.identifier(), &alice_proof)
213 .await?
214 {
215 return test_error("alice's proof was invalid");
216 }
217
218 alice_chat.rotate_root_secret_key().await?;
219 bob_chat.rotate_root_secret_key().await?;
220
221 let alice_contact = alice_chat.as_contact().await?;
222 let bob_contact = bob_chat.as_contact().await?;
223
224 let bob_last_event = bob_contact.change_events().last().unwrap().clone();
226 if !alice_chat
227 .verify_and_update_contact(bob_contact.identifier(), &[bob_last_event])
228 .await?
229 {
230 return test_error("alice failed to add bob");
231 }
232
233 let alice_last_event = alice_contact.change_events().last().unwrap().clone();
235 if !bob_chat
236 .verify_and_update_contact(alice_contact.identifier(), &[alice_last_event])
237 .await?
238 {
239 return test_error("bob failed to add alice");
240 }
241
242 let state = {
244 let mut state = [0u8; 32];
245 let mut rng = thread_rng();
246 rng.fill_bytes(&mut state);
247 state
248 };
249
250 let alice_proof = alice_chat.create_auth_proof(&state).await?;
251 let bob_proof = bob_chat.create_auth_proof(&state).await?;
252
253 if !alice_chat
254 .verify_auth_proof(&state, bob_contact.identifier(), &bob_proof)
255 .await?
256 {
257 return test_error("bob's proof was invalid");
258 }
259
260 if !bob_chat
261 .verify_auth_proof(&state, alice_contact.identifier(), &alice_proof)
262 .await?
263 {
264 return test_error("alice's proof was invalid");
265 }
266
267 Ok(())
268 }
269
270 #[test]
271 fn authentication_tests() {
272 let (mut ctx, mut exe) = ockam_node::start_node();
273 exe.execute(async move {
274 let mut results = Vec::new();
275
276 results.push(test_auth_use_case(&ctx).await);
278 results.push(test_key_rotation(&ctx).await);
279 results.push(test_update_contact_and_reprove(&ctx).await);
280
281 ctx.stop().await.unwrap();
283
284 for r in results {
285 match r {
286 Err(e) => panic!("test failure: {}", e),
287 _ => (),
288 }
289 }
290 })
291 .unwrap();
292 }
293}