sequoia_keystore_backend/lib.rs
1//! Defines the traits that keystore backends need to implement.
2//!
3//! Sequoia's keystore is a service, which manages and multiplexes
4//! access to secret key material. Conceptually, keys live on
5//! devices, and devices are managed by backends. A device may be as
6//! simple as an on-disk file, it may be a smartcard, or it could be
7//! another keystore server that is accessed over the network.
8//!
9//! A backend implements the traits defined in this crate. The traits
10//! abstract away the details of the various devices. They are mostly
11//! concerned with enumerating keys, and executing the low-level
12//! decrypt and sign operations. The backend interfaces are different
13//! from, and more low level than the general-purpose interface
14//! exposed to applications.
15//!
16//! The following figure illustrates the architecture. The squares
17//! represent different address spaces.
18//!
19//! ```text
20//! +---------------+ +---------------+
21//! | Application | | Application |
22//! +---------------+ +---------------+
23//! \ /
24//! +----------------------------------------------+
25//! | Keystore |
26//! | / \ |
27//! | soft key openpgp card |
28//! | backend backend |
29//! +----------------------------------------------+
30//! ```
31//!
32//! The keystore does not have to run as a server; it is also possible
33//! to co-locate the keystore in an application, as shown here:
34//!
35//! ```text
36//! +----------------------------------------------+
37//! | Application |
38//! | | |
39//! | Keystore |
40//! | / \ |
41//! | soft key openpgp card |
42//! +----------------------------------------------+
43//! ```
44//!
45//! Using a daemon instead of a library or a sub-process, which is
46//! spawned once per application and is terminated when the
47//! application terminates, offers several advantages.
48//!
49//! The main user-visible advantage is that the daemon is able to hold
50//! state. In the case of soft keys, the daemon can cache an
51//! unencrypted key in memory so that the user doesn't have to unlock
52//! the key as frequently. This is particularly helpful when a
53//! command-line tool like `sq` is executed multiple times in a row
54//! and each time accesses the same password-protected key. Likewise,
55//! a daemon can cache a PIN needed to access an HSM. It can also
56//! keep the HSM open thereby avoiding the initialization overhead.
57//! This also applies to remote keys: an ssh tunnel, for instance, can
58//! be held open, and reused as required.
59//!
60//! A separate daemon also simplifies an important non-functional security
61//! property: process separation. Since soft keys aren't managed by the
62//! application, but by the daemon, an attacker is not able to use a
63//! [heartbleed]-style attack to exfiltrate secret key material.
64//!
65//! [heartbleed]: https://heartbleed.com/
66//!
67//! The traits model backends as collections of devices each of which
68//! contains zero or more keys. The following figure illustrates a
69//! possible configuration. The keystore uses two backends, the
70//! softkey backend, and the openpgp card backend, and each backend
71//! has two devices. The softkey backend models certificates as
72//! devices; the openpgp card backend has one device for each physical
73//! device. Each device contains between 1 and 3 keys. The interface
74//! does not impose a limit on the number of devices per backend, or
75//! the number of keys per device. As such, a TPM managing thousands
76//! of keys is conceivable, and in scope.
77//!
78//! ```text
79//! +----------------------------------------------------+
80//! | Keystore |
81//! | / \ |
82//! | soft key openpgp card |
83//! | / \ / \ |
84//! | 0x1234 0xABCE Gnuk Nitro Key |
85//! | / \ | #123456 #234567 |
86//! | 0x10 0x23 0x34 / | \ / | \ |
87//! | 0x31 0x49 0x5A 0x64 0x71 0x88 |
88//! +----------------------------------------------------+
89//! ```
90//!
91//! The different devices may or may not be connected at any given
92//! time. For instance, the user may remove a smartcard, but if the
93//! backend has recorded the configuration, the keystore still knows
94//! about the
95//!
96//! When the keystore starts, it eagerly initializes the various
97//! backends that it knows about. At this time, backends are
98//! statically linked to the keystore, and have to be explicitly
99//! listed in the keystore initialization function.
100//!
101//! When a backend is initialized, the initialization function is
102//! passed a directory. The backend should read any required state
103//! from a subdirectory, which is named after the backend. For
104//! instance, the soft keys backend uses the "softkeys" subdirectory.
105//!
106//! A backend must be extremely careful when using state stored
107//! somewhere else. If a user selects a different home directory,
108//! then they usually want a different configuration, which is
109//! isolated from the main configuration. This is not entirely
110//! possible in the case where a backend uses a physical resource, for
111//! example.
112//!
113//! # Keys and Devices
114//!
115//! At its simplest, a device contains zero or more OpenPGP keys. A
116//! device may also be locked or unlocked, registered or not
117//! registered, and available or unavailable.
118//!
119//! If a device is locked, it first has to be unlocked before it can
120//! be used. Sometimes a device can be unlocked by supplying a
121//! password via the [`DeviceHandle::unlock`] interface. Other times,
122//! the device has to be manually unlocked by the user. If a device
123//! is locked, it may or may not be possible to enumerate the keys
124//! stored on the device.
125//!
126//! If a device is registered, then the device's configuration has
127//! been cached locally. In this case, the keys on the device can be
128//! enumerated even if the device is not connected to the host. For
129//! instance, when an OpenPGP card is registered, the OpenPGP card
130//! backend records the serial number of device, the list of keys that
131//! are stored on the smartcard, and their attributes. When the user
132//! enumerates the keys managed by the key store, these keys are
133//! returned, even if the smartcard is not attached. The user cannot,
134//! of course, use the keys.
135//!
136//! If a device is registered, but is not attached to the system, then
137//! it is considered unavailable. If the user attempts to use a key
138//! on an unavailable device, then an error is returned. In this
139//! case, the application could normally prompt the user to make the
140//! corresponding device available.
141//!
142//! These states are documented in more detail in the documentation
143//! for [`DeviceHandle`].
144//!
145//! Whether a key is registered or available is purely a function of
146//! the device. If a device contains multiple keys, and they can be
147//! registered, or available independent of the other keys, then the
148//! backend must model the keys as separate devices.
149
150use sequoia_openpgp as openpgp;
151use openpgp::Fingerprint;
152use openpgp::KeyID;
153use openpgp::Result;
154use openpgp::Cert;
155use openpgp::crypto::Password;
156use openpgp::crypto::SessionKey;
157use openpgp::crypto::mpi;
158use openpgp::packet::PKESK;
159use openpgp::types::HashAlgorithm;
160use openpgp::types::PublicKeyAlgorithm;
161use openpgp::types::SymmetricAlgorithm;
162
163/// A testing framework for backends that implement this interface.
164///
165/// Define a couple of functions and then use
166/// [`sequoia_keystore_backend::generate_tests!`] to generate a number
167/// of standard tests.
168pub mod test_framework;
169
170pub mod utils;
171
172mod protection;
173pub use protection::Protection;
174
175mod password_source;
176pub use password_source::PasswordSource;
177
178/// Errors used in this crate.
179///
180/// Note: This enum cannot be exhaustively matched to allow for future
181/// extensions.
182#[non_exhaustive]
183#[derive(thiserror::Error, Debug)]
184pub enum Error {
185 /// Invalid argument.
186 #[error("Invalid argument: {0}")]
187 InvalidArgument(String),
188
189 /// Not found.
190 #[error("Not found: {0}")]
191 NotFound(String),
192
193 /// Operation not supported.
194 #[error("Operation not supported: {0}")]
195 OperationNotSupported(String),
196
197 /// The device or key is locked.
198 ///
199 /// A device is locked when a pin, password, or some other
200 /// interaction is needed to unlock the device.
201 ///
202 /// When this error is received, the caller should prompt the user
203 /// for the password, unlock the object, and then retry the
204 /// operation.
205 #[error("Object is locked: {0}")]
206 Locked(String),
207
208 /// The device or key is not available.
209 ///
210 /// When this error is received, the caller may prompt the user to
211 /// insert the device, and then retry the operation.
212 #[error("Object is not available: {0}")]
213 Unavailable(String),
214
215 /// The device is not registered.
216 #[error("Device is not registered: {0}")]
217 Unregistered(String),
218
219 /// The device is not configured.
220 ///
221 /// The device may contain keys, but it first needs to be
222 /// configured before it can be used.
223 #[error("Device needs to be configured: {0}")]
224 Unconfigured(String),
225
226 /// The device or key is already unlocked.
227 ///
228 /// Returned by [`DeviceHandle::unlock`] and [`KeyHandle::unlock`]
229 /// if a device or key is already unlocked or doesn't need to be
230 /// unlocked.
231 #[error("Device is already unlocked: {0}")]
232 AlreadyUnlocked(String),
233
234 /// The backend doesn't support importing keys using this interface.
235 ///
236 /// This error is returned by [`Backend::import`] if the backend
237 /// requires backend-specific information in order to import a
238 /// key, which is not provided via this interface. For instance,
239 /// when importing a key to a smartcard, the user needs to specify
240 /// the smartcard, and the slot to use on the smartcard. Rather
241 /// than try and model these parameters using this generic
242 /// interface, backends should just have their own tools. The
243 /// text should be a hint that is displayed to the user describing
244 /// how to find the tool.
245 #[error("Can't import keys into the backend: {}",
246 .0.as_deref().unwrap_or("use another tool to import keys \
247 into this backend"))]
248 ExternalImportRequired(Option<String>),
249
250 /// The key doesn't support inline passwords.
251 ///
252 /// Password entry is taken care of by the device managing the
253 /// key. For instance, the password may be obtained using an
254 /// external PIN pad.
255 #[error("Can't unlock using an inline password{}{}",
256 .0.as_ref().map(|_| ": ").unwrap_or(""),
257 .0.as_deref().map(|msg| msg).unwrap_or(""))]
258 NoInlinePassword(Option<String>),
259
260 /// The key doesn't support getting passwords.
261 ///
262 /// The password must be provided inline. The password cannot be
263 /// obtained using something like an external PIN pad.
264 #[error("External password entry is not supported{}{}",
265 .0.as_ref().map(|_| ": ").unwrap_or(""),
266 .0.as_deref().map(|msg| msg).unwrap_or(""))]
267 NoExternalPassword(Option<String>),
268}
269
270/// The result of an import operation.
271///
272/// This is returned by [`Backend::import`].
273#[derive(Debug, Clone, PartialEq, Eq)]
274pub enum ImportStatus {
275 /// The imported object is new.
276 New,
277
278 /// The imported object updated an existing object.
279 Updated,
280
281 /// The object already existed, and is unchanged.
282 Unchanged,
283}
284
285/// The backend interface for the sequoia key store.
286///
287/// This is the the interface that each device driver needs to
288/// implement.
289#[async_trait::async_trait]
290pub trait Backend: Send {
291 /// Returns the backend's identifier.
292 ///
293 /// This should be an identifier that uniquely identifies the
294 /// device driver, is human readable, and is stable across
295 /// restarts.
296 fn id(&self) -> String;
297
298 /// Causes the backend to look for devices.
299 ///
300 /// This function should perform a lightweight scan. In
301 /// particular, it should:
302 ///
303 /// - Read in the configuration of any devices that have been
304 /// registered.
305 ///
306 /// - Look for locally connected devices with OpenPGP keys,
307 /// e.g., smartcards, TPMs, etc.
308 ///
309 /// This function should not search for devices that may take a
310 /// long time to find. For instance, it should not scan the
311 /// network, or prompt the user for a password. Instead, a
312 /// separate utility should be used to discover and register those
313 /// devices.
314 ///
315 /// The backend should cache information about any devices that it
316 /// finds in memory, but it should not register them.
317 ///
318 /// This function should not initialize registered devices for
319 /// use, e.g., the ssh tunnel needed to access a remote key should
320 /// not be brought up.
321 ///
322 /// In the terminology of [`DeviceHandle`], this should look for
323 /// devices that are available or registered.
324 async fn scan(&mut self) -> Result<()> {
325 Err(Error::OperationNotSupported("Backend::scan".into()).into())
326 }
327
328 /// Lists all devices that are available or registered.
329 ///
330 /// This does not actively perform a scan. It simply returns the
331 /// devices that were available or registered as of the last scan.
332 ///
333 /// In the terminology of [`DeviceHandle`], it returns devices
334 /// that are available or are registered.
335 async fn list<'a>(&'a self)
336 -> Box<dyn Iterator<Item=Box<dyn DeviceHandle + Send + Sync + 'a>>
337 + Send + Sync + 'a>;
338
339 /// Returns a handle for the specified device.
340 ///
341 /// id is a string as returned by [`DeviceHandle::id`].
342 ///
343 /// If the device is not available or not registered, then this
344 /// should return [`Error::NotFound`].
345 async fn find_device<'a>(&self, id: &str)
346 -> Result<Box<dyn DeviceHandle + Send + Sync + 'a>>;
347
348 /// Returns a handle for the specified key.
349 ///
350 /// `id` is a string as returned by [`KeyHandle::id`].
351 ///
352 /// If the key is not available or not registered, then this
353 /// should return [`Error::NotFound`].
354 async fn find_key<'a>(&self, id: &str)
355 -> Result<Box<dyn KeyHandle + Send + Sync + 'a>>;
356
357 /// Imports the keys in the cert.
358 ///
359 /// `cert` is a TSK. Any keys without secret key material are
360 /// silently ignored.
361 ///
362 /// Returns each key's import status, and a capability to the key.
363 ///
364 /// If the TSK doesn't include any secret keys, then an empty list
365 /// is returned.
366 ///
367 /// Some backends require additional information to import a key.
368 /// These backends should [`Error::ExternalImportRequired`], and
369 /// indicate how a user might import a key to this backend.
370 async fn import<'a>(&self, cert: Cert)
371 -> Result<Vec<(ImportStatus, Box<dyn KeyHandle + Send + Sync + 'a>)>>;
372}
373
374/// A device that contains zero or more keys.
375///
376/// # Device Properties
377///
378/// A device has three properties: it can be available or not,
379/// configured or not, and registered or not.
380///
381/// ## Available
382///
383/// A device is available if the secret key material can be used.
384/// (This is independent of whether the secret key material is
385/// locked.) A smart card, for instance, is available when it is
386/// inserted, and it is not available when it is not inserted.
387/// Devices that are available are always returned by
388/// [`Backend::list`].
389///
390/// ## Configured
391///
392/// A device is configured if it can be used without further
393/// configuration. (This is independent of whether the secret key
394/// material is locked.) To use the secret key material on a
395/// smartcard or a TPM, the user may first need to load the OpenPGP
396/// certificate corresponding to the secret keys. Most devices,
397/// however, are already configured, or are able to configure
398/// themselves without the user's intervention. For instance, OpenPGP
399/// smartcards don't normally contain the OpenPGP certificate
400/// corresponding to the secret keys, but they do contain the keys'
401/// OpenPGP fingerprints, and an OpenPGP card backend could fetch
402/// the certificate's without user intervention.
403///
404/// Devices that are available, but not configured should still be
405/// returned by [`Backend::list`]. However, because the keys may not
406/// be known, the keys may not be enumerable or not usable. In this
407/// case, [`DeviceHandle::list`] should return
408/// [`Error::Unconfigured`].
409///
410/// If a device contains multiple keys, and some can be configured
411/// while others aren't, then each key should be exposed as a separate
412/// device; this API assumes that either no key or all keys on a given
413/// device are configured.
414///
415/// ## Registered
416///
417/// A device that is registered is a device whose meta-data has been
418/// saved locally. Devices that are registered are returned by
419/// [`Backend::list`] even if they are not available. Likewise, the
420/// keys on a registered device are returned by [`DeviceHandle::list`]
421/// even when the device is not available. When the key store
422/// attempts to decrypt a message, it may prompt the user to insert an
423/// unavailable, registered device.
424///
425/// When a backend scans for devices, it should not automatically
426/// register devices. Once a device has been successfully used,
427/// however, a backend may register the device. For instance, a smart
428/// card that is discovered by a scan should not automatically be
429/// registered. However, when the smart card is successfully used to
430/// create a signature or decrypt a message, then it may be registered
431/// without further intervention from the user.
432///
433/// ## Alternate View
434///
435/// Another, less precise view, is that a device may be in one of the
436/// following states:
437///
438/// - Ready: The device is available and configured.
439///
440/// The device can be used immediately. For instance, a soft key,
441/// or a smartcard that is inserted.
442///
443/// A device that is ready may still need to be unlocked.
444///
445/// - Disconnected: A device that was registered, but is not
446/// available.
447///
448/// The device is not available, but the user may be prompted to
449/// make it available. For instance, if a key needed to decrypt a
450/// message is on a smartcard that is unavailable, the user may be
451/// prompted to insert the smartcard. Similarly, if a key is
452/// accessible via an ssh tunnel, but the ssh tunnel cannot be
453/// established, the user may be prompted to connect to the
454/// network.
455///
456/// The backend should still expose all of an unavailable device's
457/// keys (insofar as they are known), however, the decrypt and
458/// sign operations should fail with [`Error::Unavailable`].
459///
460/// - Unusable: A device that was discovered, but that cannot be
461/// used without some additional configuration. For instance, a
462/// smartcard or a TPM key may need the corresponding certificate
463/// before it can be used.
464///
465/// - Unknown: A device that is not available, and not registered.
466///
467/// The aforementioned three properties map onto these states as
468/// follows:
469///
470/// ```text
471/// Available, Configured, Registered: Ready
472/// Available, Configured, Not Registered: Ready
473/// Available, Not Configured, Registered: Unusable
474/// Available, Not Configured, Not Registered: Unusable
475/// Not Available, Configured, Registered: Disconnected
476/// Not Available, Configured, Not Registered: Unknown
477/// Not Available, Not Configured, Registered: Disconnected
478/// Not Available, Not Configured, Not Registered: Unknown
479/// ```
480///
481/// A device is only ever instantiated if it is available or registered.
482#[async_trait::async_trait]
483pub trait DeviceHandle {
484 /// Returns the device's id.
485 ///
486 /// The id is a globally unique, stable, and mostly human readable
487 /// identifier.
488 fn id(&self) -> String;
489
490 /// Returns the device's description.
491 ///
492 /// The description is a human readable string, e.g., "GnuK with
493 /// certificate FINGERPRINT".
494 async fn description(&self) -> String {
495 self.id()
496 }
497
498 /// Sets the device's human readable description.
499 ///
500 /// This should fail if the device is not registered.
501 async fn set_description(&self, _description: String) -> Result<()> {
502 Err(Error::Unregistered(self.id()).into())
503 }
504
505 /// Returns whether the device is available.
506 ///
507 /// A device is available if it is plugged-in.
508 async fn available(&self) -> bool;
509
510 /// Returns whether the device is configured.
511 ///
512 /// A device is configured if the keys can be used without further
513 /// configuration.
514 async fn configured(&self) -> bool;
515
516 /// Returns whether the device is registered.
517 ///
518 /// A device is registered if the device is locally memorized. In
519 /// this case, the user may be prompted to insert the device.
520 async fn registered(&self) -> bool;
521
522 /// Registers the device.
523 ///
524 /// This explicitly registers the device. The backend should
525 /// memorize the device and should return it during a scan even if
526 /// it is not available. If the device is already registered,
527 /// this should silently succeed.
528 async fn register(&mut self) -> Result<()> {
529 Err(Error::OperationNotSupported("DeviceHandle::register".into()).into())
530 }
531
532 /// Unregisters the device from the backend.
533 ///
534 /// This should not destroy any secret key material stored on the
535 /// device. It should just remove any cached state about the
536 /// device. For instance, if the device is an ssh tunnel, then
537 /// the ssh tunnel's configuration should be forgotten. If the
538 /// device is a smart card, then the smart card should be
539 /// forgotten. Note: if the smart card is inserted, it is still
540 /// available and thus still usable.
541 ///
542 /// Note: devices that are not available can only be registered
543 /// using a backend-specific tool. For instance, a device
544 /// accessible via an ssh tunnel is never available.
545 async fn unregister(&mut self) -> Result<()> {
546 Err(Error::OperationNotSupported("DeviceHandle::unregister".into()).into())
547 }
548
549 /// Connects to and unlocks the device.
550 ///
551 /// Some devices need to be initialized. For instance, to access
552 /// a remote key, it may be necessary to create an ssh tunnel.
553 /// Some devices need to be unlocked before the keys can be
554 /// enumerated. For instance, if soft keys are stored in a
555 /// database and the database is encrypted, it may be necessary to
556 /// supply a password to decrypt the database.
557 async fn unlock(&mut self, _password: &Password) -> Result<()> {
558 Err(Error::AlreadyUnlocked("DeviceHandle::unlock".into()).into())
559 }
560
561 /// Locks the device and any keys in contains.
562 ///
563 /// Locks the device if it has been previously unlocked as well as
564 /// any keys managed by the device. If the device is locked or
565 /// can't be locked, this is a noop. If the device needs to be
566 /// deinitialized, it MAY be deinitialized lazily if doing so
567 /// cannot result in a user-visible error. For instance, if the
568 /// device uses an ssh tunnel, the ssh tunnel may be closed later.
569 async fn lock(&mut self) -> Result<()> {
570 Ok(())
571 }
572
573 /// Lists keys on the device.
574 ///
575 /// Returns the keys on the device. If the device is not usable,
576 /// then this should return [`Error::Unconfigured`].
577 async fn list<'a>(&'a self)
578 -> Box<dyn Iterator<Item=Box<dyn KeyHandle + Send + Sync + 'a>>
579 + Send + Sync + 'a>;
580}
581
582/// A Key on a Device.
583///
584/// A key may or may not be available. This is a function of the
585/// device.
586#[async_trait::async_trait]
587pub trait KeyHandle {
588 /// Returns the key's id.
589 ///
590 /// The id is a globally unique, stable, and mostly human readable
591 /// identifier. An example of a good id is the concatenation of
592 /// the the key's fingerprint, and the device's serial number,
593 /// e.g., "Key 8F17777118A33DDA9BA48E62AACB3243630052D9 on Yubikey
594 /// 5 #217813388320."
595 fn id(&self) -> String;
596
597 /// Returns the key's handle.
598 fn key_handle(&self) -> openpgp::KeyHandle {
599 self.fingerprint().into()
600 }
601
602 /// Returns the key's fingerprint.
603 fn fingerprint(&self) -> Fingerprint;
604
605 /// Returns the key's key ID.
606 fn keyid(&self) -> KeyID {
607 KeyID::from(self.fingerprint())
608 }
609
610 /// Returns the key's device.
611 async fn device<'a>(&self) -> Box<dyn DeviceHandle + Send + Sync + 'a>;
612
613 /// Returns whether the key is available.
614 async fn available(&self) -> bool;
615
616 /// Returns whether the key is locked.
617 async fn locked(&self) -> Protection;
618
619 /// Returns how the password is obtained.
620 ///
621 /// This is similar to, but not identical to
622 /// [`KeyHandle::locked`]. This function indicates how the
623 /// password must be provided independency of the current
624 /// protection.
625 async fn password_source(&self) -> PasswordSource;
626
627 /// Returns whether the key is decryption capable.
628 async fn decryption_capable(&self) -> bool;
629
630 /// Returns whether the key is signing capable.
631 async fn signing_capable(&self) -> bool;
632
633 /// Unlocks a key.
634 ///
635 /// A key is typically unlocked by providing a password or pin.
636 /// Not all keys are locked. If the key is not available, this
637 /// should attempt to connect to the device. If the device is not
638 /// available or cannot be initialized, then this should fail.
639 ///
640 /// If `password` is `Some` and [`KeyHandle::password_source`]
641 /// indicates that the password cannot be provided inline, then
642 /// the backend must return [`Error::NoInlinePassword`]. Likewise,
643 /// if `password` is `None`, and [`KeyHandle::password_source`]
644 /// does not indicate that the user can be prompted for the
645 /// password ([`PasswordSource::ExternalOnDemand`]), then the
646 /// backend must return [`Error::NoExternalPassword`].
647 ///
648 /// If the key is already unlocked, this returns
649 /// [`Error::AlreadyUnlocked`].
650 async fn unlock(&mut self, _password: Option<&Password>) -> Result<()> {
651 Err(Error::AlreadyUnlocked("KeyHandle::unlock".into()).into())
652 }
653
654 /// Lock a key.
655 ///
656 /// Relocks the key. This usually causes the backend to forget the
657 /// key's password.
658 async fn lock(&mut self) -> Result<()> {
659 Ok(())
660 }
661
662 /// Returns the corresponding public key.
663 ///
664 /// The backend SHOULD ensure that the secret key material is
665 /// removed.
666 async fn public_key(&self)
667 -> openpgp::packet::Key<openpgp::packet::key::PublicParts,
668 openpgp::packet::key::UnspecifiedRole>;
669
670 /// Decrypts a PKESK.
671 ///
672 async fn decrypt_pkesk(&mut self, pkesk: &PKESK)
673 -> Option<(Option<SymmetricAlgorithm>, SessionKey)>
674 {
675 // We want to use `PKESK::decrypt`. For that, we need
676 // something that implements the `Decryptor` interface. We
677 // could implement `Decryptor` for `KeyHandle`, but then that
678 // is part of our public API. Instead, we do a bit of
679 // acrobatics here.
680 struct Decryptor<'a, T>
681 where T: KeyHandle + ?Sized
682 {
683 slf: &'a mut T,
684 pk: openpgp::packet::Key<
685 openpgp::packet::key::PublicParts,
686 openpgp::packet::key::UnspecifiedRole>,
687 }
688
689 impl<'a, T> openpgp::crypto::Decryptor for Decryptor<'a, T>
690 where T: KeyHandle + ?Sized + Send
691 {
692 fn public(&self)
693 -> &openpgp::packet::Key<
694 openpgp::packet::key::PublicParts,
695 openpgp::packet::key::UnspecifiedRole>
696 {
697 &self.pk
698 }
699
700 fn decrypt(&mut self, ciphertext: &mpi::Ciphertext,
701 plaintext_len: Option<usize>)
702 -> Result<SessionKey>
703 {
704 // We know that pkesk.decrypt is running on a separate
705 // thread. So it is safe to create a new runtime on
706 // this thread.
707 let rt = tokio::runtime::Runtime::new()?;
708
709 rt.block_on(async {
710 self.slf.decrypt_ciphertext(ciphertext, plaintext_len).await
711 })
712 }
713 }
714
715 let pk = self.public_key();
716 let pk = pk.await;
717
718 let mut decryptor = Decryptor {
719 slf: self,
720 pk: pk,
721 };
722
723 // To avoid blocking the current thread, we run the sync
724 // function `pkesk.decrypt` on a separate thread. When it is
725 // done, it results the result via a one shot channel, which
726 // we can asynchronously wait on.
727 let (sender, receiver) = futures::channel::oneshot::channel::<_>();
728
729 std::thread::scope(|s| {
730 s.spawn(move || {
731 sender.send(pkesk.decrypt(&mut decryptor, None))
732 });
733 });
734
735 match receiver.await {
736 Ok(Some(result)) => Some(result),
737 Ok(None) => None,
738 Err(_) => None,
739 }
740 }
741
742 /// Decrypts a ciphertext.
743 ///
744 /// This method has the same semantics as
745 /// [`sequoia_openpgp::crypto::Decryptor::decrypt`].
746 ///
747 /// Returns the session key.
748 async fn decrypt_ciphertext(&mut self,
749 ciphertext: &mpi::Ciphertext,
750 plaintext_len: Option<usize>)
751 -> Result<SessionKey>;
752
753 /// Signs a message.
754 ///
755 /// `text` is the message to sign.
756 async fn sign(&mut self, hash_algo: HashAlgorithm, text: &[u8])
757 -> Result<(PublicKeyAlgorithm, mpi::Signature)>;
758
759 /// Exports the secret key material.
760 async fn export(&mut self)
761 -> Result<openpgp::packet::Key<
762 openpgp::packet::key::SecretParts,
763 openpgp::packet::key::UnspecifiedRole>>;
764
765 /// Changes the key's password.
766 ///
767 /// Changes the password. Before calling this function, you
768 /// should call [`KeyHandle::password_source`] to determine if you
769 /// need to unlock the key, and whether you need to provide the
770 /// new password directly, or if that is obtained externally.
771 ///
772 /// If `new_password` is `Some` and [`KeyHandle::password_source`]
773 /// indicates that the password cannot be provided inline, then
774 /// the backend must return [`Error::NoInlinePassword`]. Likewise,
775 /// if `new_password` is `None`, and
776 /// [`KeyHandle::password_source`] does not indicate that the user
777 /// can be prompted for the password, then the backend must return
778 /// [`Error::NoExternalPassword`].
779 async fn change_password(&mut self, new_password: Option<&Password>)
780 -> Result<()>;
781
782 /// Deletes the key.
783 ///
784 /// This destroys the key's secret key material.
785 ///
786 /// If the key has to be unlocked, and the key is locked, the
787 /// backend should return an error.
788 ///
789 /// If the device managing the key does not support deleting keys,
790 /// then it should return [`Error::OperationNotSupported`].
791 async fn delete_secret_key_material(&mut self) -> Result<()>;
792}