1use std::collections::BTreeMap;
2use std::collections::btree_map::Entry;
3use std::fs::File;
4use std::io::Write;
5use std::path::Path;
6use std::sync::Arc;
7use std::sync::Weak;
8use std::time::SystemTime;
9
10use anyhow::Context;
11
12use futures::lock::Mutex;
13
14use sequoia_openpgp as openpgp;
15use openpgp::Cert;
16use openpgp::Fingerprint;
17use openpgp::Packet;
18use openpgp::Result;
19use openpgp::crypto::Password;
20use openpgp::crypto::SessionKey;
21use openpgp::crypto::mpi;
22use openpgp::fmt::hex;
23use openpgp::packet::key::Key4;
24use openpgp::packet::key::PublicParts;
25use openpgp::packet::key::UnspecifiedRole;
26use openpgp::packet;
27use openpgp::serialize::SerializeInto;
28use openpgp::serialize::stream::Armorer;
29use openpgp::serialize::stream::Message;
30use openpgp::types::HashAlgorithm;
31use openpgp::types::PublicKeyAlgorithm;
32
33use sequoia_ipc::Keygrip;
34
35use sequoia_tpm::Description;
36
37use sequoia_keystore_backend as backend;
38use backend::Error;
39use backend::ImportStatus;
40use backend::PasswordSource;
41use backend::Protection;
42use backend::utils::Directory;
43
44mod certd;
45
46#[derive(Clone)]
47pub struct Backend {
48 inner: Arc<Mutex<BackendInternal>>,
49}
50
51struct BackendInternal {
52 home: Directory,
53
54 certd: Arc<certd::CertD>,
60
61 devices: Vec<Device>,
63}
64
65#[derive(Clone)]
71pub struct Device {
72 id: String,
74 inner: Arc<Mutex<DeviceInternal>>
75}
76
77impl Device {
78 fn downgrade(&self) -> WeakDevice {
80 WeakDevice {
81 id: self.id.clone(),
82 inner: Arc::downgrade(&self.inner),
83 }
84 }
85}
86
87#[derive(Clone)]
91pub struct WeakDevice {
92 id: String,
94 inner: Weak<Mutex<DeviceInternal>>,
95}
96
97impl WeakDevice {
98 fn upgrade(&self) -> Option<Device> {
100 Some(Device {
101 id: self.id.clone(),
102 inner: self.inner.upgrade()?,
103 })
104 }
105}
106
107struct DeviceInternal {
108 id: String,
110
111 keys: BTreeMap<Fingerprint, Key>,
113}
114
115#[derive(Clone)]
116pub struct Key {
117 fpr: Fingerprint,
119 inner: Arc<Mutex<KeyInternal>>,
120}
121
122struct KeyInternal {
124 device: WeakDevice,
125
126 fingerprint: Fingerprint,
127 public_key: packet::Key<packet::key::PublicParts,
128 packet::key::UnspecifiedRole>,
129
130 desc: Description,
131}
132
133impl Backend {
134 pub async fn init<P: AsRef<Path>>(home: P, _default: bool)
139 -> Result<Self>
140 {
141 log::trace!("Backend::init");
142
143 let home = Directory::from(home.as_ref());
144
145 let certd = Arc::new(certd::CertD::new()?);
146
147 let mut inner = BackendInternal {
148 home,
149 certd,
150 devices: vec![],
151 };
152
153 let _ = inner.scan_internal(true).await;
154
155 Ok(Backend {
156 inner: Arc::new(Mutex::new(inner)),
157 })
158 }
159
160 pub async fn init_ephemeral() -> Result<Self> {
164 log::trace!("Backend::init_ephemeral");
165
166 let home = Directory::ephemeral()?;
167 Self::init(home, false).await
168 }
169}
170
171fn derive_key(pk: &sequoia_tpm::PublicKeyBytes)
172 -> Result<packet::Key<PublicParts, UnspecifiedRole>>
173{
174 match pk {
175 sequoia_tpm::PublicKeyBytes::RSA(pk) => {
176 let bytes = hex::decode(&pk.bytes);
177 match bytes {
178 Ok(bytes) => {
179 Key4::import_public_rsa(
180 &[1, 0, 1], &bytes, SystemTime::UNIX_EPOCH)
181 .map(|k| packet::Key::V4(k))
182 }
183 Err(err) => {
184 Err(err.into())
185 }
186 }
187 }
188 _ => {
189 return Err(anyhow::anyhow!("Unsupported algorithm"));
190 }
191 }
192}
193
194impl BackendInternal {
195 async fn scan_internal(&mut self, _force: bool) -> Result<()> {
196 log::trace!("Backend::scan");
197
198 let certd = Arc::clone(&self.certd);
199
200 let home = &self.home;
202
203 log::debug!("Scanning: {:?}", home.display());
204 for entry in home.read_dir()
205 .with_context(|| format!("{:?}", home.display()))?
206 {
207 let entry = match entry {
208 Ok(entry) => entry,
209 Err(err) => {
210 log::debug!("While listing {:?}: {}",
211 home.display(), err);
212 continue;
213 }
214 };
215
216 let filename = entry.path();
217
218 let read = if let Some(extension) = filename.extension() {
219 if extension == "yml" || extension == "yaml" {
220 true
221 } else {
222 false
223 }
224 } else {
225 false
226 };
227
228 if ! read {
229 log::debug!("Ignoring {:?}", filename);
230 continue;
231 }
232 log::debug!("Considering: {:?}", filename);
233
234 let file = match File::open(&filename) {
235 Ok(file) => file,
236 Err(err) => {
237 log::debug!("Failed to open {}: {}",
238 filename.display(), err);
239 continue;
240 }
241 };
242
243 let mut desc: Description = match serde_yaml::from_reader(file) {
244 Ok(desc) => desc,
245 Err(err) => {
246 log::debug!("Failed to parse {}: {}",
247 filename.display(), err);
248 continue;
249 }
250 };
251
252 log::trace!("{}:\n{}",
253 filename.display(),
254 serde_yaml::to_string(&desc)?);
255
256 match sequoia_tpm::read_key(&mut desc.spec) {
257 Ok(_key) => (),
258 Err(err) => {
259 log::debug!("Error configured key ({}) on TPM: {}\n{}",
260 filename.display(), err,
261 serde_yaml::to_string(&desc)?);
262 continue;
263 }
264 }
265
266 let pk = if let Some(pk) = desc.spec.provider.tpm.unique.as_ref() {
267 pk
268 } else {
269 log::debug!("{}: No public key, skipping.",
270 filename.display());
271 continue;
272 };
273
274 let key = match derive_key(pk) {
275 Ok(key) => key,
276 Err(err) => {
277 log::debug!("{}: Failed to derive a null OpenPGP key: {}",
278 filename.display(), err);
279 continue;
280 }
281 };
282
283 let keygrip = match Keygrip::of(key.mpis()) {
284 Ok(keygrip) => keygrip,
285 Err(err) => {
286 log::debug!("{}: computing keygrip: {}",
287 filename.display(), err);
288 continue;
289 }
290 };
291
292 let key = match certd.find(&keygrip).await {
293 Ok(key) => key,
294 Err(err) => {
295 log::debug!("{}: looking for OpenPGP key: {}",
296 filename.display(), err);
297
298 let packet = Packet::from(
299 key.role_into_primary());
300
301 let packet = packet.to_vec()
302 .expect("serializing to a vec is infallible");
303
304 let mut bytes = Vec::new();
305 let message = Message::new(&mut bytes);
306 let mut message = Armorer::new(message)
307 .kind(openpgp::armor::Kind::PublicKey)
308 .build()
309 .expect("can build armorer");
310 message.write_all(&packet)
311 .expect("can serialize to vec");
312 message.finalize()
313 .expect("can serialize to vec");
314
315 log::debug!("Null key:\n{}",
316 String::from_utf8_lossy(&bytes));
317 continue;
318 }
319 };
320
321 let fpr = key.fingerprint();
322
323 let provider = desc.spec.provider.tpm.tcti.clone();
325 let mut device = None;
326 for d in self.devices.iter_mut() {
327 if d.id == provider {
328 device = Some(d);
329 }
330 }
331
332 let device = if let Some(device) = device {
333 device
334 } else {
335 self.devices.push(Device {
336 id: provider.clone(),
337 inner: Arc::new(Mutex::new(DeviceInternal {
338 id: provider.clone(),
339 keys: Default::default(),
340 })),
341 });
342 self.devices.last_mut().unwrap()
343 };
344
345 let mut device_internal = device.inner.lock().await;
346 match device_internal.keys.entry(fpr.clone()) {
347 Entry::Occupied(_oe) => {
348 }
350 Entry::Vacant(ve) => {
351 log::debug!("Found key {}", fpr);
353
354 let key = Key {
355 fpr: fpr.clone(),
356 inner: Arc::new(Mutex::new(KeyInternal {
357 device: device.downgrade(),
358 fingerprint: fpr,
359 public_key: key,
361 desc,
362 })),
363 };
364
365 ve.insert(key);
366 }
367 }
368 }
369
370 Ok(())
371 }
372}
373
374#[async_trait::async_trait]
375impl backend::Backend for Backend {
376 fn id(&self) -> String {
377 "tpm".into()
378 }
379
380 async fn scan(&mut self) -> Result<()> {
381 let mut backend = self.inner.lock().await;
382 backend.scan_internal(false).await
383 }
384
385 async fn list<'a>(&'a self)
386 -> Box<dyn Iterator<Item=Box<dyn backend::DeviceHandle + Send + Sync + 'a>>
387 + Send + Sync + 'a>
388 {
389 log::trace!("Backend::list");
390
391 let mut backend = self.inner.lock().await;
392
393 if let Err(err) = backend.scan_internal(false).await {
394 log::debug!("Scanning TPMs: {}", err);
395 }
396
397 Box::new(
398 backend.devices.iter()
399 .map(|device| {
400 Box::new(device.clone())
401 as Box<dyn backend::DeviceHandle + Send + Sync>
402 })
403 .collect::<Vec<_>>()
404 .into_iter())
405 }
406
407 async fn find_device<'a>(&self, id: &str)
408 -> Result<Box<dyn backend::DeviceHandle + Send + Sync + 'a>>
409 {
410 log::trace!("Backend::find_device");
411
412 let mut backend = self.inner.lock().await;
413
414 for scan in [false, true] {
417 if scan {
418 log::trace!("Rescanning");
419 if let Err(err) = backend.scan_internal(true).await {
420 log::debug!("Scanning TPMs: {}", err);
421 }
422 }
423
424 for device in backend.devices.iter() {
425 if device.id == id {
426 return Ok(Box::new(device.clone())
427 as Box<dyn backend::DeviceHandle + Send + Sync>);
428 }
429 }
430 }
431
432 Err(Error::NotFound(id.into()).into())
433 }
434
435 async fn find_key<'a>(&self, id: &str)
436 -> Result<Box<dyn backend::KeyHandle + Send + Sync + 'a>>
437 {
438 log::trace!("Backend::find_key");
439
440 let mut backend = self.inner.lock().await;
441
442 for scan in [false, true] {
445 if scan {
446 log::trace!("Rescanning");
447 if let Err(err) = backend.scan_internal(true).await {
448 log::debug!("Scanning TPMs: {}", err);
449 }
450 }
451
452 for device in backend.devices.iter() {
453 let device = device.inner.lock().await;
454
455 for (key_id, key) in device.keys.iter() {
456 if &key_id.to_string() == id {
457 return Ok(Box::new(key.clone())
458 as Box<dyn backend::KeyHandle + Send + Sync>);
459 }
460 }
461 }
462 }
463
464 Err(Error::NotFound(id.into()).into())
465 }
466
467 async fn import<'a>(&self, _cert: Cert)
468 -> Result<Vec<(ImportStatus,
469 Box<dyn backend::KeyHandle + Send + Sync + 'a>)>>
470 {
471 log::trace!("Backend::import");
472
473 Err(Error::ExternalImportRequired(Some(
474 "Use an external tool to manage TPM keys.".into()).into()).into())
475 }
476}
477
478#[async_trait::async_trait]
479impl backend::DeviceHandle for Device {
480 fn id(&self) -> String {
481 log::trace!("Device::id");
482
483 self.id.clone()
484 }
485
486 async fn available(&self) -> bool {
487 log::trace!("Device::available");
488
489 true
492 }
493
494 async fn configured(&self) -> bool {
495 log::trace!("Device::configured");
496
497 true
500 }
501
502 async fn registered(&self) -> bool {
503 log::trace!("Device::registered");
504
505 true
508 }
509
510 async fn lock(&mut self) -> Result<()> {
511 log::trace!("Device::lock");
512
513 Ok(())
517 }
518
519 async fn list<'a>(&'a self)
520 -> Box<dyn Iterator<Item=Box<dyn backend::KeyHandle + Send + Sync + 'a>>
521 + Send + Sync + 'a>
522 {
523 log::trace!("Device::list");
524
525 let device = self.inner.lock().await;
526 let keys = device.keys.values()
527 .map(|key| {
528 Box::new(key.clone())
529 as Box<dyn backend::KeyHandle + Send + Sync>
530 })
531 .collect::<Vec<_>>();
532
533 Box::new(keys.into_iter())
534 }
535}
536
537#[async_trait::async_trait]
538impl backend::KeyHandle for Key {
539 fn id(&self) -> String {
540 log::trace!("Key::id");
541
542 self.fpr.to_string()
543 }
544
545 fn fingerprint(&self) -> Fingerprint {
546 log::trace!("Key::fingerprint");
547
548 self.fpr.clone()
549 }
550
551 async fn device<'a>(&self)
552 -> Box<dyn backend::DeviceHandle + Send + Sync + 'a>
553 {
554 log::trace!("Key::device");
555
556 let key_internal = self.inner.lock().await;
557
558 let device = match key_internal.device.upgrade() {
560 Some(device) => device,
561 None => panic!("Device disappeared"),
562 };
563
564 Box::new(device)
565 }
566
567 async fn available(&self) -> bool {
568 log::trace!("Key::available");
569
570 true
571 }
572
573 async fn locked(&self) -> Protection {
574 log::trace!("Key::locked");
575
576 Protection::Unlocked
579 }
580
581 async fn password_source(&self) -> PasswordSource {
582 log::trace!("Key::password_source");
583
584 PasswordSource::Inline
585 }
586
587 async fn decryption_capable(&self) -> bool {
588 log::trace!("Key::decryption_capable");
589
590 let key_internal = self.inner.lock().await;
591 key_internal.desc.spec.capabilities.contains(
592 &sequoia_tpm::Capability::Decrypt)
593 }
594
595 async fn signing_capable(&self) -> bool {
596 log::trace!("Key::signing_capable");
597
598 let key_internal = self.inner.lock().await;
599 key_internal.desc.spec.capabilities.contains(
600 &sequoia_tpm::Capability::Sign)
601 }
602
603 async fn unlock(&mut self, password: Option<&Password>) -> Result<()> {
604 log::trace!("Key::unlock");
605
606 let key_internal = self.inner.lock().await;
607
608 let _password = if let Some(password) = password {
611 password
612 } else {
613 return Err(Error::NoExternalPassword(None).into());
614 };
615
616 log::trace!("KeyHandle::unlock({}): Already unlocked", self.fpr);
617 Err(Error::AlreadyUnlocked(key_internal.fingerprint.to_string()).into())
618 }
619
620 async fn lock(&mut self) -> Result<()> {
621 log::trace!("Key::lock");
622
623 Ok(())
624 }
625
626 async fn public_key(&self)
627 -> packet::Key<packet::key::PublicParts,
628 packet::key::UnspecifiedRole>
629 {
630 log::trace!("Key::public_key");
631
632 let key = self.inner.lock().await;
633 key.public_key.clone()
634 }
635
636 async fn decrypt_ciphertext(&mut self,
637 ciphertext: &mpi::Ciphertext,
638 _plaintext_len: Option<usize>)
639 -> Result<SessionKey>
640 {
641 log::trace!("Key::decrypt_ciphertext");
642
643 let key_internal = self.inner.lock().await;
644
645 let pk_algo = key_internal.public_key.pk_algo();
646
647 #[allow(deprecated)]
648 let session_key = match (ciphertext, pk_algo) {
649 (mpi::Ciphertext::RSA { c },
650 PublicKeyAlgorithm::RSAEncryptSign
651 | PublicKeyAlgorithm::RSAEncrypt
652 | PublicKeyAlgorithm::RSASign) =>
653 {
654 let session_key = sequoia_tpm::decrypt(&key_internal.desc.spec,
655 c.value())?;
656 SessionKey::from(&session_key[..])
657 }
658 _ => {
659 return Err(Error::OperationNotSupported(
660 format!("Unsupported public key algorithm: {}", pk_algo)).into());
661 }
662 };
663
664 Ok(session_key)
665 }
666
667 async fn sign(&mut self, hash_algo: HashAlgorithm, digest: &[u8])
668 -> Result<(PublicKeyAlgorithm, mpi::Signature)>
669 {
670 log::trace!("Key::sign({})", hash_algo);
671
672 let key_internal = self.inner.lock().await;
673
674 let pk_algo = key_internal.public_key.pk_algo();
675
676 let hash_algo = match hash_algo {
677 HashAlgorithm::SHA1 => sequoia_tpm::HashingAlgorithm::Sha1,
678 HashAlgorithm::SHA256 => sequoia_tpm::HashingAlgorithm::Sha256,
679 HashAlgorithm::SHA384 => sequoia_tpm::HashingAlgorithm::Sha384,
680 HashAlgorithm::SHA512 => sequoia_tpm::HashingAlgorithm::Sha512,
681 _ => {
682 return Err(Error::OperationNotSupported(
683 format!("Unsupported hash algorithm: {}", hash_algo)).into());
684 }
685 };
686
687 let sig = sequoia_tpm::sign(&key_internal.desc.spec, hash_algo, digest)?;
688 #[allow(deprecated)]
689 let sig = match pk_algo {
690 PublicKeyAlgorithm::RSAEncryptSign
691 | PublicKeyAlgorithm::RSAEncrypt
692 | PublicKeyAlgorithm::RSASign =>
693 {
694 openpgp::crypto::mpi::Signature::RSA { s: sig.into() }
695 }
696 _ => {
697 return Err(Error::OperationNotSupported(
698 format!("Unsupported public key algorithm: {}", pk_algo)).into());
699 }
700 };
701
702 Ok((pk_algo, sig))
703 }
704
705 async fn export(&mut self)
706 -> Result<openpgp::packet::Key<
707 openpgp::packet::key::SecretParts,
708 openpgp::packet::key::UnspecifiedRole>>
709 {
710 Err(Error::OperationNotSupported(
711 "Use an external tool to manage TPM keys.".into()).into())
712 }
713
714 async fn change_password(&mut self, password: Option<&Password>)
715 -> Result<()>
716 {
717 log::trace!("KeyHandle::change_password({}, {})",
718 self.fingerprint(),
719 if let Some(password) = password {
720 if password.map(|p| p.is_empty()) {
721 "clear password"
722 } else {
723 "set password"
724 }
725 } else {
726 "ask for password"
727 });
728
729 Err(Error::OperationNotSupported(
730 "Use an external tool to manage TPM keys.".into()).into())
731 }
732
733 async fn delete_secret_key_material(&mut self)
734 -> Result<()>
735 {
736 log::trace!("KeyHandle::delete_secret_key_material");
737
738 Err(Error::OperationNotSupported(
739 "Use an external tool to manage TPM keys.".into()).into())
740 }
741}
742
743#[cfg(test)]
744mod tests {
745 use super::*;
746
747 use openpgp::KeyHandle;
748 use openpgp::parse::Parse;
749 use openpgp::policy::StandardPolicy;
750
751 use backend::test_framework;
752
753 use backend::Backend as _;
754
755 fn get_test_device() -> Option<()>
758 {
759 None
761 }
762
763 fn preinit() -> bool {
764 get_test_device().is_some()
766 }
767
768 async fn init_backend() -> Backend {
769 let backend = Backend::init_ephemeral().await.expect("can init backend");
770 backend
771 }
772
773 async fn import_cert(backend: &mut Backend, cert: &Cert) {
774 log::debug!("Importing {}", cert.fingerprint());
775
776 let mut backend_internal = backend.inner.lock().await;
778 let mut device = None;
779 for d in backend_internal.devices.iter_mut() {
780 if d.id == "internal" {
781 device = Some(d);
782 break;
783 }
784 }
785 let _device = if let Some(device) = device {
786 device
787 } else {
788 backend_internal.devices.push(Device {
789 id: "internal".to_string(),
790 inner: Arc::new(Mutex::new(DeviceInternal {
791 id: "internal".to_string(),
792 keys: Default::default(),
793 })),
794 });
795 backend_internal.devices.last_mut().unwrap()
796 };
797
798 todo!("import_cert")
801 }
802
803 sequoia_keystore_backend::generate_tests!(
804 preinit,
805 true, Backend, init_backend,
807 import_cert,
808 false, None, None, false, false, false );
815}