1pub use crate::wire::enrollment::{Authentication, RegistrationStatus};
3
4use super::*;
5const DOMAIN_VERSION: u32 = 1;
6use ed25519_dalek::{Signature, VerifyingKey};
7use hpke::PskBundle;
8use sha2::Sha256;
9
10pub const REQUEST_BYTES: usize = 314;
11pub const PEER_STORAGE_BYTES: usize = 538;
12pub const CONTROL_LIMIT: usize = 16384;
13
14fn check(ok: bool) -> Result<()> {
15 ensure!(ok, "error enrollment-invalid");
16 Ok(())
17}
18
19pub(super) fn verify(pk: &[u8; 32], label: &str, fields: &[&[u8]], signature: &[u8]) -> Result<()> {
20 VerifyingKey::from_bytes(pk)
21 .and_then(|key| key.verify_strict(&cce(label, fields), &Signature::from_slice(signature)?))
22 .map_err(|_| anyhow::anyhow!("error enrollment-signature"))
23}
24
25pub struct Invitation {
27 pub(super) vault: [u8; 32],
28 pub(super) inviter: [u8; 32],
29 pub(super) psk: Secret,
30}
31
32impl fmt::Debug for Invitation {
33 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
34 f.write_str("Invitation([REDACTED])")
35 }
36}
37
38impl Invitation {
39 pub fn vault(&self) -> [u8; 32] {
40 self.vault
41 }
42 pub fn handle(&self) -> [u8; 32] {
43 let kdf = hkdf::Hkdf::<Sha256>::new(Some(b"aven-e2ee/v1/invitation"), self.psk.expose());
44 let mut out = [0; 32];
45 kdf.expand(
46 &cce("aven-e2ee/v1/invitation/handle", &[&self.vault]),
47 &mut out,
48 )
49 .expect("fixed HKDF length");
50 out
51 }
52 pub fn protected_storage_bytes(&self) -> Zeroizing<Vec<u8>> {
53 let mut out = Zeroizing::new(Vec::with_capacity(96));
54 out.extend(self.vault);
55 out.extend(self.inviter);
56 out.extend(self.psk.expose());
57 out
58 }
59 pub fn from_protected_storage(bytes: &[u8]) -> Result<Self> {
60 check(bytes.len() == 96)?;
61 let mut r = Reader(bytes);
62 Ok(Self {
63 vault: r.array()?,
64 inviter: r.array()?,
65 psk: Secret::new(r.array()?),
66 })
67 }
68}
69
70#[derive(Clone, PartialEq, Eq)]
71pub(super) struct Recipient {
72 pub(super) device: [u8; 32],
73 pub(super) sign: [u8; 32],
74 pub(super) hpke: [u8; 32],
75 pub(super) verifier: [u8; 32],
76 pub(super) pop: [u8; 64],
77}
78impl Recipient {
79 pub(super) fn pop_message(
80 &self,
81 vault: &[u8; 32],
82 handle: &[u8; 32],
83 inviter: &[u8; 32],
84 ) -> Vec<u8> {
85 cce(
86 "aven-e2ee/v1/pairing/request-pop",
87 &[
88 vault,
89 handle,
90 inviter,
91 &self.device,
92 &self.sign,
93 &self.hpke,
94 &self.verifier,
95 &1_u32.to_be_bytes(),
96 &DOMAIN_VERSION.to_be_bytes(),
97 ],
98 )
99 }
100 pub(super) fn verify(
101 &self,
102 vault: &[u8; 32],
103 handle: &[u8; 32],
104 inviter: &[u8; 32],
105 ) -> Result<()> {
106 VerifyingKey::from_bytes(&self.sign)
107 .and_then(|key| {
108 key.verify_strict(
109 &self.pop_message(vault, handle, inviter),
110 &Signature::from_bytes(&self.pop),
111 )
112 })
113 .map_err(|_| anyhow::anyhow!("error enrollment-pop"))
114 }
115 pub(super) fn plaintext(&self) -> Vec<u8> {
116 let mut out = vec![1];
117 for v in [self.device, self.sign, self.hpke, self.verifier] {
118 bytes(&mut out, &v);
119 }
120 out.extend(1_u32.to_be_bytes());
121 out.extend(DOMAIN_VERSION.to_be_bytes());
122 bytes(&mut out, &self.pop);
123 out
124 }
125 pub(super) fn parse(raw: &[u8]) -> Result<Self> {
126 check(raw.len() == 221)?;
127 let mut r = Reader(raw);
128 check(r.take(1)? == [1])?;
129 let device = r.blob(32)?.try_into()?;
130 let sign = r.blob(32)?.try_into()?;
131 let hpke = r.blob(32)?.try_into()?;
132 let verifier = r.blob(32)?.try_into()?;
133 check(
134 u32::from_be_bytes(r.array()?) == 1 && u32::from_be_bytes(r.array()?) == DOMAIN_VERSION,
135 )?;
136 let pop = r.blob(64)?.try_into()?;
137 r.end()?;
138 Ok(Self {
139 device,
140 sign,
141 hpke,
142 verifier,
143 pop,
144 })
145 }
146}
147
148pub(super) fn seal(
149 inv: &Invitation,
150 public: &[u8; 32],
151 info: &[u8],
152 aad: &[u8],
153 plaintext: &[u8],
154) -> Result<(Vec<u8>, Vec<u8>)> {
155 let entropy = Secret::generate()?;
156 let mut rng = ChaCha20Rng::from_seed(*entropy.expose());
157 let pk = <Kem as hpke::Kem>::PublicKey::from_bytes(public)
158 .map_err(|_| anyhow::anyhow!("error enrollment-recipient"))?;
159 let handle = inv.handle();
160 let mode = OpModeS::Psk(
161 PskBundle::new(inv.psk.expose(), &handle)
162 .map_err(|_| anyhow::anyhow!("error enrollment-psk"))?,
163 );
164 let (enc, cipher) = hpke::single_shot_seal_with_rng::<Aead, Kdf, Kem>(
165 &mode, &pk, info, plaintext, aad, &mut rng,
166 )
167 .map_err(|_| anyhow::anyhow!("error enrollment-seal"))?;
168 Ok((enc.to_bytes().to_vec(), cipher))
169}
170pub(super) fn open(
171 inv: &Invitation,
172 private: &Secret,
173 info: &[u8],
174 aad: &[u8],
175 enc: &[u8],
176 cipher: &[u8],
177) -> Result<Zeroizing<Vec<u8>>> {
178 let private = HpkePrivate::from_bytes(private.expose())
179 .map_err(|_| anyhow::anyhow!("error enrollment-recipient"))?;
180 let enc =
181 Enc::from_bytes(enc).map_err(|_| anyhow::anyhow!("error enrollment-encapsulation"))?;
182 let handle = inv.handle();
183 let mode = OpModeR::Psk(
184 PskBundle::new(inv.psk.expose(), &handle)
185 .map_err(|_| anyhow::anyhow!("error enrollment-psk"))?,
186 );
187 hpke::single_shot_open::<Aead, Kdf, Kem>(&mode, &private, &enc, info, cipher, aad)
188 .map(Zeroizing::new)
189 .map_err(|_| anyhow::anyhow!("error enrollment-open"))
190}
191pub fn request_parts<'a>(raw: &'a [u8], handle: &[u8; 32]) -> Result<(&'a [u8], &'a [u8])> {
192 check(raw.len() == REQUEST_BYTES)?;
193 let mut r = Reader(raw);
194 check(r.take(1)? == [1])?;
195 check(r.blob(32)? == handle)?;
196 let enc = r.blob(32)?;
197 let cipher = r.blob(237)?;
198 r.end()?;
199 Ok((enc, cipher))
200}
201
202pub struct PeerAuthority {
204 pub(super) device: [u8; 32],
205 pub(super) signing: Secret,
206 pub(super) recipient: Secret,
207 pub(super) bearer: Secret,
208 pub(super) invitation: Invitation,
209 pub(super) request: Vec<u8>,
210}
211impl fmt::Debug for PeerAuthority {
212 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
213 f.write_str("PeerAuthority([REDACTED])")
214 }
215}
216impl PeerAuthority {
217 pub fn generate(invitation: Invitation) -> Result<Self> {
218 let ikm = Secret::generate()?;
219 let (recipient, _) = <Kem as hpke::Kem>::derive_keypair(ikm.expose());
220 Self {
221 device: *Secret::generate()?.expose(),
222 signing: Secret::generate()?,
223 recipient: Secret::new(recipient.to_bytes().into()),
224 bearer: Secret::generate()?,
225 invitation,
226 request: Vec::new(),
227 }
228 .sealed()
229 }
230 pub fn retry(&self, invitation: Invitation) -> Result<Self> {
232 Self {
233 device: self.device,
234 signing: Secret::new(*self.signing.expose()),
235 recipient: Secret::new(*self.recipient.expose()),
236 bearer: Secret::new(*self.bearer.expose()),
237 invitation,
238 request: Vec::new(),
239 }
240 .sealed()
241 }
242 fn sealed(mut self) -> Result<Self> {
243 let row = self.recipient()?;
244 let handle = self.invitation.handle();
245 let info = cce(
246 "aven-e2ee/v1/pairing/request",
247 &[&self.invitation.vault, &handle],
248 );
249 let aad = cce(
250 "aven-e2ee/v1/pairing/request-aad",
251 &[&self.invitation.vault, &handle, &self.invitation.inviter],
252 );
253 let (enc, cipher) = seal(
254 &self.invitation,
255 &self.invitation.inviter,
256 &info,
257 &aad,
258 &row.plaintext(),
259 )?;
260 let mut request = vec![1];
261 bytes(&mut request, &handle);
262 bytes(&mut request, &enc);
263 bytes(&mut request, &cipher);
264 self.request = request;
265 Ok(self)
266 }
267 pub(super) fn recipient(&self) -> Result<Recipient> {
268 let private = HpkePrivate::from_bytes(self.recipient.expose())
269 .map_err(|_| anyhow::anyhow!("error enrollment-recipient"))?;
270 let signer = SigningKey::from_bytes(self.signing.expose());
271 let mut row = Recipient {
272 device: self.device,
273 sign: signer.verifying_key().to_bytes(),
274 hpke: <Kem as hpke::Kem>::sk_to_pk(&private).to_bytes().into(),
275 verifier: credential_verifier(self.invitation.vault, self.device, &self.bearer),
276 pop: [0; 64],
277 };
278 row.pop = signer
279 .sign(&row.pop_message(
280 &self.invitation.vault,
281 &self.invitation.handle(),
282 &self.invitation.inviter,
283 ))
284 .to_bytes();
285 Ok(row)
286 }
287 pub fn matches_invitation(&self, invitation: &Invitation) -> bool {
288 bool::from(
289 self.invitation
290 .protected_storage_bytes()
291 .as_slice()
292 .ct_eq(invitation.protected_storage_bytes().as_slice()),
293 )
294 }
295 pub fn device(&self) -> [u8; 32] {
296 self.device
297 }
298 pub fn vault(&self) -> [u8; 32] {
299 self.invitation.vault
300 }
301 pub fn handle(&self) -> [u8; 32] {
302 self.invitation.handle()
303 }
304 pub fn bearer(&self) -> &Secret {
305 &self.bearer
306 }
307 pub fn request(&self) -> &[u8] {
308 &self.request
309 }
310 pub fn protected_storage_bytes(&self) -> Zeroizing<Vec<u8>> {
311 let mut out = Zeroizing::new(Vec::new());
312 out.extend(self.device);
313 for secret in [&self.signing, &self.recipient, &self.bearer] {
314 out.extend(secret.expose());
315 }
316 out.extend(self.invitation.protected_storage_bytes().iter());
317 out.extend(&self.request);
318 out
319 }
320 pub fn from_protected_storage(raw: &[u8]) -> Result<Self> {
321 check(raw.len() == PEER_STORAGE_BYTES)?;
322 let mut r = Reader(raw);
323 let peer = Self {
324 device: r.array()?,
325 signing: Secret::new(r.array()?),
326 recipient: Secret::new(r.array()?),
327 bearer: Secret::new(r.array()?),
328 invitation: Invitation::from_protected_storage(r.take(96)?)?,
329 request: r.take(REQUEST_BYTES)?.to_vec(),
330 };
331 request_parts(&peer.request, &peer.handle())?;
332 peer.recipient()?;
333 Ok(peer)
334 }
335}