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}