1use std::collections::HashSet;
2
3use bc_components::{
4 EncapsulationPublicKey, KeyDerivationMethod, PrivateKeys,
5 PrivateKeysProvider, PublicKeys, PublicKeysProvider, Reference,
6 ReferenceProvider, Salt, SigningPublicKey, URI, Verifier,
7};
8use bc_envelope::{PrivateKeyBase, prelude::*};
9use known_values::{ENDPOINT, NICKNAME, PRIVATE_KEY};
10
11use super::Permissions;
12use crate::{Error, HasNickname, HasPermissions, Privilege, Result};
13
14#[derive(Debug, Clone)]
16pub enum PrivateKeyData {
17 Decrypted(PrivateKeys),
19
20 Encrypted(Envelope),
27}
28impl PartialEq for PrivateKeyData {
29 fn eq(&self, other: &Self) -> bool {
30 match (self, other) {
31 (Self::Decrypted(a), Self::Decrypted(b)) => a == b,
32 (Self::Encrypted(a), Self::Encrypted(b)) => {
33 a.ur_string() == b.ur_string()
35 }
36 _ => false,
37 }
38 }
39}
40
41impl Eq for PrivateKeyData {}
42
43#[derive(Debug, Clone, PartialEq, Eq)]
44pub struct Key {
45 public_keys: PublicKeys,
46 private_keys: Option<(PrivateKeyData, Salt)>,
47 nickname: String,
48 endpoints: HashSet<URI>,
49 permissions: Permissions,
50}
51impl Verifier for Key {
52 fn verify(
53 &self,
54 signature: &bc_components::Signature,
55 message: &dyn AsRef<[u8]>,
56 ) -> bool {
57 self.public_keys.verify(signature, message)
58 }
59}
60
61impl PublicKeysProvider for Key {
62 fn public_keys(&self) -> PublicKeys { self.public_keys.clone() }
63}
64
65impl std::hash::Hash for Key {
66 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
67 self.public_keys.hash(state);
68 }
69}
70
71impl Key {
72 pub fn new(public_keys: impl AsRef<PublicKeys>) -> Self {
73 Self {
74 public_keys: public_keys.as_ref().clone(),
75 private_keys: None,
76 nickname: String::new(),
77 endpoints: HashSet::new(),
78 permissions: Permissions::new(),
79 }
80 }
81
82 pub fn new_allow_all(public_keys: impl AsRef<PublicKeys>) -> Self {
83 Self {
84 public_keys: public_keys.as_ref().clone(),
85 private_keys: None,
86 nickname: String::new(),
87 endpoints: HashSet::new(),
88 permissions: Permissions::new_allow_all(),
89 }
90 }
91
92 pub fn new_with_private_keys(
93 private_keys: PrivateKeys,
94 public_keys: PublicKeys,
95 ) -> Self {
96 let salt = Salt::new_with_len(32).unwrap();
97 Self {
98 public_keys,
99 private_keys: Some((PrivateKeyData::Decrypted(private_keys), salt)),
100 nickname: String::new(),
101 endpoints: HashSet::new(),
102 permissions: Permissions::new_allow_all(),
103 }
104 }
105
106 pub fn new_with_private_key_base(private_key_base: PrivateKeyBase) -> Self {
107 let private_keys = private_key_base.private_keys();
108 let public_keys = private_key_base.public_keys();
109 Self::new_with_private_keys(private_keys, public_keys)
110 }
111
112 pub fn public_keys(&self) -> &PublicKeys { &self.public_keys }
113
114 pub fn private_keys(&self) -> Option<&PrivateKeys> {
115 self.private_keys.as_ref().and_then(|(data, _)| match data {
116 PrivateKeyData::Decrypted(keys) => Some(keys),
117 PrivateKeyData::Encrypted(_) => None,
118 })
119 }
120
121 pub fn has_private_keys(&self) -> bool {
122 matches!(
123 self.private_keys.as_ref(),
124 Some((PrivateKeyData::Decrypted(_), _))
125 )
126 }
127
128 pub fn has_encrypted_private_keys(&self) -> bool {
129 matches!(
130 self.private_keys.as_ref(),
131 Some((PrivateKeyData::Encrypted(_), _))
132 )
133 }
134
135 pub fn private_key_salt(&self) -> Option<&Salt> {
136 self.private_keys.as_ref().map(|(_, salt)| salt)
137 }
138
139 pub fn private_key_envelope(
170 &self,
171 password: Option<&str>,
172 ) -> Result<Option<Envelope>> {
173 match &self.private_keys {
174 None => Ok(None),
175 Some((PrivateKeyData::Decrypted(private_keys), _)) => {
176 Ok(Some(Envelope::new(private_keys.clone())))
178 }
179 Some((PrivateKeyData::Encrypted(encrypted_envelope), _)) => {
180 if let Some(pwd) = password {
181 match encrypted_envelope.clone().unlock_subject(pwd) {
183 Ok(decrypted) => {
184 Ok(Some(decrypted))
186 }
187 Err(_) => {
188 Err(Error::InvalidPassword)
190 }
191 }
192 } else {
193 Ok(Some(encrypted_envelope.clone()))
195 }
196 }
197 }
198 }
199
200 pub fn signing_public_key(&self) -> &SigningPublicKey {
201 self.public_keys.signing_public_key()
202 }
203
204 pub fn encapsulation_public_key(&self) -> &EncapsulationPublicKey {
205 self.public_keys.enapsulation_public_key()
206 }
207
208 pub fn endpoints(&self) -> &HashSet<URI> { &self.endpoints }
209
210 pub fn endpoints_mut(&mut self) -> &mut HashSet<URI> { &mut self.endpoints }
211
212 pub fn add_endpoint(&mut self, endpoint: URI) {
213 self.endpoints.insert(endpoint);
214 }
215
216 pub fn permissions(&self) -> &Permissions { &self.permissions }
217
218 pub fn permissions_mut(&mut self) -> &mut Permissions {
219 &mut self.permissions
220 }
221
222 pub fn add_permission(&mut self, privilege: Privilege) {
223 self.permissions.add_allow(privilege);
224 }
225}
226
227impl HasNickname for Key {
228 fn nickname(&self) -> &str { &self.nickname }
229
230 fn set_nickname(&mut self, nickname: impl Into<String>) {
231 self.nickname = nickname.into();
232 }
233}
234
235impl HasPermissions for Key {
236 fn permissions(&self) -> &Permissions { &self.permissions }
237
238 fn permissions_mut(&mut self) -> &mut Permissions { &mut self.permissions }
239}
240
241#[derive(Clone, Debug, PartialEq, Eq, Default)]
243pub enum XIDPrivateKeyOptions {
244 #[default]
246 Omit,
247
248 Include,
250
251 Elide,
253
254 Encrypt {
257 method: KeyDerivationMethod,
258 password: Vec<u8>,
259 },
260}
261
262impl Key {
263 fn private_key_assertion_envelope(&self) -> Envelope {
264 let (private_key_data, salt) = self.private_keys.clone().unwrap();
265 match private_key_data {
266 PrivateKeyData::Decrypted(private_keys) => {
267 Envelope::new_assertion(PRIVATE_KEY, private_keys)
268 .add_salt_instance(salt)
269 }
270 PrivateKeyData::Encrypted(encrypted_envelope) => {
271 Envelope::new_assertion(PRIVATE_KEY, encrypted_envelope)
274 .add_salt_instance(salt)
275 }
276 }
277 }
278
279 fn extract_optional_private_key_with_password(
280 envelope: &Envelope,
281 password: Option<&[u8]>,
282 ) -> Result<Option<(PrivateKeyData, Salt)>> {
283 if let Some(private_key_assertion) =
284 envelope.optional_assertion_with_predicate(PRIVATE_KEY)?
285 {
286 let private_key_object =
287 private_key_assertion.subject().try_object()?;
288
289 let salt = private_key_assertion
291 .extract_object_for_predicate::<Salt>(known_values::SALT)?;
292
293 if private_key_object.is_locked_with_password() {
295 if let Some(pwd) = password {
297 match private_key_object.unlock_subject(pwd) {
299 Ok(decrypted) => {
300 let private_keys_cbor =
302 decrypted.subject().try_leaf()?;
303 let private_keys =
304 PrivateKeys::try_from(private_keys_cbor)?;
305 return Ok(Some((
306 PrivateKeyData::Decrypted(private_keys),
307 salt,
308 )));
309 }
310 Err(_) => {
311 return Ok(Some((
314 PrivateKeyData::Encrypted(
315 private_key_object.clone(),
316 ),
317 salt,
318 )));
319 }
320 }
321 } else {
322 return Ok(Some((
324 PrivateKeyData::Encrypted(private_key_object.clone()),
325 salt,
326 )));
327 }
328 }
329
330 let private_keys_cbor = private_key_object.try_leaf()?;
332 let private_keys = PrivateKeys::try_from(private_keys_cbor)?;
333 return Ok(Some((PrivateKeyData::Decrypted(private_keys), salt)));
334 }
335 Ok(None)
336 }
337
338 pub fn into_envelope_opt(
339 self,
340 private_key_options: XIDPrivateKeyOptions,
341 ) -> Envelope {
342 let mut envelope = Envelope::new(self.public_keys().clone());
343 if let Some((private_key_data, _)) = &self.private_keys {
344 match private_key_data {
345 PrivateKeyData::Encrypted(_) => {
346 let assertion_envelope =
348 self.private_key_assertion_envelope();
349 envelope = envelope
350 .add_assertion_envelope(assertion_envelope)
351 .unwrap();
352 }
353 PrivateKeyData::Decrypted(_) => {
354 match private_key_options {
356 XIDPrivateKeyOptions::Include => {
357 let assertion_envelope =
358 self.private_key_assertion_envelope();
359 envelope = envelope
360 .add_assertion_envelope(assertion_envelope)
361 .unwrap();
362 }
363 XIDPrivateKeyOptions::Elide => {
364 let assertion_envelope =
365 self.private_key_assertion_envelope().elide();
366 envelope = envelope
367 .add_assertion_envelope(assertion_envelope)
368 .unwrap();
369 }
370 XIDPrivateKeyOptions::Encrypt { method, password } => {
371 let (private_keys, salt) =
372 self.private_keys.clone().unwrap();
373
374 match private_keys {
375 PrivateKeyData::Decrypted(keys) => {
376 let private_keys_envelope =
379 Envelope::new(keys);
380
381 let encrypted = private_keys_envelope
383 .lock_subject(method, password)
384 .expect(
385 "Failed to encrypt private key",
386 );
387
388 let assertion_envelope =
391 Envelope::new_assertion(
392 PRIVATE_KEY,
393 encrypted,
394 )
395 .add_salt_instance(salt);
396
397 envelope = envelope
398 .add_assertion_envelope(
399 assertion_envelope,
400 )
401 .unwrap();
402 }
403 PrivateKeyData::Encrypted(
404 encrypted_envelope,
405 ) => {
406 let assertion_envelope =
412 Envelope::new_assertion(
413 PRIVATE_KEY,
414 encrypted_envelope,
415 )
416 .add_salt_instance(salt);
417
418 envelope = envelope
419 .add_assertion_envelope(
420 assertion_envelope,
421 )
422 .unwrap();
423 }
424 }
425 }
426 XIDPrivateKeyOptions::Omit => {
427 }
429 }
430 }
431 }
432 }
433
434 envelope = envelope.add_nonempty_string_assertion(
435 known_values::NICKNAME,
436 self.nickname,
437 );
438
439 envelope = self
440 .endpoints
441 .into_iter()
442 .fold(envelope, |envelope, endpoint| {
443 envelope.add_assertion(ENDPOINT, endpoint)
444 });
445
446 self.permissions.add_to_envelope(envelope)
447 }
448}
449
450impl EnvelopeEncodable for Key {
451 fn into_envelope(self) -> Envelope {
452 self.into_envelope_opt(XIDPrivateKeyOptions::Omit)
453 }
454}
455
456impl TryFrom<&Envelope> for Key {
457 type Error = Error;
458
459 fn try_from(envelope: &Envelope) -> Result<Self> {
460 Self::try_from_envelope(envelope, None)
461 }
462}
463
464impl TryFrom<Envelope> for Key {
465 type Error = Error;
466
467 fn try_from(envelope: Envelope) -> Result<Self> { Key::try_from(&envelope) }
468}
469
470impl Key {
471 pub fn try_from_envelope(
477 envelope: &Envelope,
478 password: Option<&[u8]>,
479 ) -> Result<Self> {
480 let public_keys = PublicKeys::try_from(envelope.subject().try_leaf()?)?;
481 let private_keys = Key::extract_optional_private_key_with_password(
482 envelope, password,
483 )?;
484
485 let nickname = envelope.extract_object_for_predicate_with_default(
486 NICKNAME,
487 String::new(),
488 )?;
489
490 let mut endpoints = HashSet::new();
491 for assertion in envelope.assertions_with_predicate(ENDPOINT) {
492 let endpoint =
493 URI::try_from(assertion.try_object()?.subject().try_leaf()?)?;
494 endpoints.insert(endpoint);
495 }
496 let permissions = Permissions::try_from_envelope(envelope)?;
497 Ok(Self {
498 public_keys,
499 private_keys,
500 nickname,
501 endpoints,
502 permissions,
503 })
504 }
505}
506
507impl ReferenceProvider for &Key {
508 fn reference(&self) -> Reference { self.public_keys.reference() }
509}