1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
//! Defines the traits that keystore backends need to implement.
//!
//! Sequoia's keystore is a service, which manages and multiplexes
//! access to secret key material.  Conceptually, keys live on
//! devices, and devices are managed by backends.  A device may be as
//! simple as an on-disk file, it may be a smartcard, or it could be
//! another keystore server that is accessed over the network.
//!
//! A backend implements the traits defined in this crate.  The traits
//! abstract away the details of the various devices.  They are mostly
//! concerned with enumerating keys, and executing the low-level
//! decrypt and sign operations.  The backend interfaces are different
//! from, and more low level than the general-purpose interface
//! exposed to applications.
//!
//! The following figure illustrates the architecture.  The squares
//! represent different address spaces.
//!
//! ```text
//!    +---------------+        +---------------+
//!    |  Application  |        |  Application  |
//!    +---------------+        +---------------+
//!                  \            /
//! +----------------------------------------------+
//! |                   Keystore                   |
//! |                /            \                |
//! |        soft key              openpgp card    |
//! |        backend                 backend       |
//! +----------------------------------------------+
//! ```
//!
//! The keystore does not have to run as a server; it is also possible
//! to co-locate the keystore in an application, as shown here:
//!
//! ```text
//! +----------------------------------------------+
//! |                 Application                  |
//! |                      |                       |
//! |                   Keystore                   |
//! |                /            \                |
//! |        soft key              openpgp card    |
//! +----------------------------------------------+
//! ```
//!
//! Using a daemon instead of a library or a sub-process, which is
//! spawned once per application and is terminated when the
//! application terminates, offers several advantages.
//!
//! The main user-visible advantage is that the daemon is able to hold
//! state.  In the case of soft keys, the daemon can cache an
//! unencrypted key in memory so that the user doesn't have to unlock
//! the key as frequently.  This is particularly helpful when a
//! command-line tool like `sq` is executed multiple times in a row
//! and each time accesses the same password-protected key.  Likewise,
//! a daemon can cache a PIN needed to access an HSM.  It can also
//! keep the HSM open thereby avoiding the initialization overhead.
//! This also applies to remote keys: an ssh tunnel, for instance, can
//! be held open, and reused as required.
//!
//! A separate daemon also simplifies an important non-functional security
//! property: process separation.  Since soft keys aren't managed by the
//! application, but by the daemon, an attacker is not able to use a
//! [heartbleed]-style attack to exfiltrate secret key material.
//!
//!   [heartbleed]: https://heartbleed.com/
//!
//! The traits model backends as collections of devices each of which
//! contains zero or more keys.  The following figure illustrates a
//! possible configuration.  The keystore uses two backends, the
//! softkey backend, and the openpgp card backend, and each backend
//! has two devices.  The softkey backend models certificates as
//! devices; the openpgp card backend has one device for each physical
//! device.  Each device contains between 1 and 3 keys.  The interface
//! does not impose a limit on the number of devices per backend, or
//! the number of keys per device.  As such, a TPM managing thousands
//! of keys is conceivable, and in scope.
//!
//! ```text
//! +----------------------------------------------------+
//! |                   Keystore                         |
//! |                /            \                      |
//! |        soft key              openpgp card          |
//! |       /        \            /            \         |
//! |   0x1234      0xABCE     Gnuk         Nitro Key    |
//! |   /    \        |      #123456         #234567     |
//! | 0x10  0x23     0x34   /   |   \       /   |   \    |
//! |                     0x31 0x49 0x5A  0x64 0x71 0x88 |
//! +----------------------------------------------------+
//! ```
//!
//! The different devices may or may not be connected at any given
//! time.  For instance, the user may remove a smartcard, but if the
//! backend has recorded the configuration, the keystore still knows
//! about the
//!
//! When the keystore starts, it eagerly initializes the various
//! backends that it knows about.  At this time, backends are
//! statically linked to the keystore, and have to be explicitly
//! listed in the keystore initialization function.
//!
//! When a backend is initialized, the initialization function is
//! passed a directory.  The backend should read any required state
//! from a subdirectory, which is named after the backend.  For
//! instance, the soft keys backend uses the "softkeys" subdirectory.
//!
//! A backend must be extremely careful when using state stored
//! somewhere else.  If a user selects a different home directory,
//! then they usually want a different configuration, which is
//! isolated from the main configuration.  This is not entirely
//! possible in the case where a backend uses a physical resource, for
//! example.
//!
//! # Keys and Devices
//!
//! At its simplest, a device contains zero or more OpenPGP keys.  A
//! device may also be locked or unlocked, registered or not
//! registered, and available or unavailable.
//!
//! If a device is locked, it first has to be unlocked before it can
//! be used.  Sometimes a device can be unlocked by supplying a
//! password via the [`DeviceHandle::unlock`] interface.  Other times,
//! the device has to be manually unlocked by the user.  If a device
//! is locked, it may or may not be possible to enumerate the keys
//! stored on the device.
//!
//! If a device is registered, then the device's configuration has
//! been cached locally.  In this case, the keys on the device can be
//! enumerated even if the device is not connected to the host.  For
//! instance, when an OpenPGP card is registered, the OpenPGP card
//! backend records the serial number of device, the list of keys that
//! are stored on the smartcard, and their attributes.  When the user
//! enumerates the keys managed by the key store, these keys are
//! returned, even if the smartcard is not attached.  The user cannot,
//! of course, use the keys.
//!
//! If a device is registered, but is not attached to the system, then
//! it is considered unavailable.  If the user attempts to use a key
//! on an unavailable device, then an error is returned.  In this
//! case, the application could normally prompt the user to make the
//! corresponding device available.
//!
//! These states are documented in more detail in the documentation
//! for [`DeviceHandle`].
//!
//! Whether a key is registered or available is purely a function of
//! the device.  If a device contains multiple keys, and they can be
//! registered, or available independent of the other keys, then the
//! backend must model the keys as separate devices.

use sequoia_openpgp as openpgp;
use openpgp::Fingerprint;
use openpgp::KeyID;
use openpgp::Result;
use openpgp::Cert;
use openpgp::crypto::Password;
use openpgp::crypto::SessionKey;
use openpgp::crypto::mpi;
use openpgp::packet::PKESK;
use openpgp::types::HashAlgorithm;
use openpgp::types::PublicKeyAlgorithm;
use openpgp::types::SymmetricAlgorithm;

/// A testing framework for backends that implement this interface.
///
/// Define a couple of functions and then use
/// [`sequoia_keystore_backend::generate_tests!`] to generate a number
/// of standard tests.
pub mod test_framework;

pub mod utils;

mod protection;
pub use protection::Protection;

mod password_source;
pub use password_source::PasswordSource;

/// Errors used in this crate.
///
/// Note: This enum cannot be exhaustively matched to allow for future
/// extensions.
#[non_exhaustive]
#[derive(thiserror::Error, Debug)]
pub enum Error {
    /// Invalid argument.
    #[error("Invalid argument: {0}")]
    InvalidArgument(String),

    /// Not found.
    #[error("Not found: {0}")]
    NotFound(String),

    /// Operation not supported.
    #[error("Operation not supported: {0}")]
    OperationNotSupported(String),

    /// The device or key is locked.
    ///
    /// A device is locked when a pin, password, or some other
    /// interaction is needed to unlock the device.
    ///
    /// When this error is received, the caller should prompt the user
    /// for the password, unlock the object, and then retry the
    /// operation.
    #[error("Object is locked: {0}")]
    Locked(String),

    /// The device or key is not available.
    ///
    /// When this error is received, the caller may prompt the user to
    /// insert the device, and then retry the operation.
    #[error("Object is not available: {0}")]
    Unavailable(String),

    /// The device is not registered.
    #[error("Device is not registered: {0}")]
    Unregistered(String),

    /// The device is not configured.
    ///
    /// The device may contain keys, but it first needs to be
    /// configured before it can be used.
    #[error("Device needs to be configured: {0}")]
    Unconfigured(String),

    /// The device or key is already unlocked.
    ///
    /// Returned by [`DeviceHandle::unlock`] and [`KeyHandle::unlock`]
    /// if a device or key is already unlocked or doesn't need to be
    /// unlocked.
    #[error("Device is already unlocked: {0}")]
    AlreadyUnlocked(String),

    /// The backend doesn't support importing keys using this interface.
    ///
    /// This error is returned by [`Backend::import`] if the backend
    /// requires backend-specific information in order to import a
    /// key, which is not provided via this interface.  For instance,
    /// when importing a key to a smartcard, the user needs to specify
    /// the smartcard, and the slot to use on the smartcard.  Rather
    /// than try and model these parameters using this generic
    /// interface, backends should just have their own tools.  The
    /// text should be a hint that is displayed to the user describing
    /// how to find the tool.
    #[error("Can't import keys into the backend: {}",
            .0.as_deref().unwrap_or("use another tool to import keys \
                                     into this backend"))]
    ExternalImportRequired(Option<String>),

    /// The key doesn't support inline passwords.
    ///
    /// Password entry is taken care of by the device managing the
    /// key.  For instance, the password may be obtained using an
    /// external PIN pad.
    #[error("Can't unlock using an inline password{}{}",
            .0.as_ref().map(|_| ": ").unwrap_or(""),
            .0.as_deref().map(|msg| msg).unwrap_or(""))]
    NoInlinePassword(Option<String>),

    /// The key doesn't support getting passwords.
    ///
    /// The password must be provided inline.  The password cannot be
    /// obtained using something like an external PIN pad.
    #[error("External password entry is not supported{}{}",
            .0.as_ref().map(|_| ": ").unwrap_or(""),
            .0.as_deref().map(|msg| msg).unwrap_or(""))]
    NoExternalPassword(Option<String>),
}

/// The result of an import operation.
///
/// This is returned by [`Backend::import`].
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ImportStatus {
    /// The imported object is new.
    New,

    /// The imported object updated an existing object.
    Updated,

    /// The object already existed, and is unchanged.
    Unchanged,
}

/// The backend interface for the sequoia key store.
///
/// This is the the interface that each device driver needs to
/// implement.
#[async_trait::async_trait]
pub trait Backend: Send {
    /// Returns the backend's identifier.
    ///
    /// This should be an identifier that uniquely identifies the
    /// device driver, is human readable, and is stable across
    /// restarts.
    fn id(&self) -> String;

    /// Causes the backend to look for devices.
    ///
    /// This function should perform a lightweight scan.  In
    /// particular, it should:
    ///
    ///   - Read in the configuration of any devices that have been
    ///     registered.
    ///
    ///   - Look for locally connected devices with OpenPGP keys,
    ///     e.g., smartcards, TPMs, etc.
    ///
    /// This function should not search for devices that may take a
    /// long time to find.  For instance, it should not scan the
    /// network, or prompt the user for a password.  Instead, a
    /// separate utility should be used to discover and register those
    /// devices.
    ///
    /// The backend should cache information about any devices that it
    /// finds in memory, but it should not register them.
    ///
    /// This function should not initialize registered devices for
    /// use, e.g., the ssh tunnel needed to access a remote key should
    /// not be brought up.
    ///
    /// In the terminology of [`DeviceHandle`], this should look for
    /// devices that are available or registered.
    async fn scan(&mut self) -> Result<()> {
        Err(Error::OperationNotSupported("Backend::scan".into()).into())
    }

    /// Lists all devices that are available or registered.
    ///
    /// This does not actively perform a scan.  It simply returns the
    /// devices that were available or registered as of the last scan.
    ///
    /// In the terminology of [`DeviceHandle`], it returns devices
    /// that are available or are registered.
    async fn list<'a>(&'a self)
        -> Box<dyn Iterator<Item=Box<dyn DeviceHandle + Send + Sync + 'a>>
               + Send + Sync + 'a>;

    /// Returns a handle for the specified device.
    ///
    /// id is a string as returned by [`DeviceHandle::id`].
    ///
    /// If the device is not available or not registered, then this
    /// should return [`Error::NotFound`].
    async fn find_device<'a>(&self, id: &str)
        -> Result<Box<dyn DeviceHandle + Send + Sync + 'a>>;

    /// Returns a handle for the specified key.
    ///
    /// `id` is a string as returned by [`KeyHandle::id`].
    ///
    /// If the key is not available or not registered, then this
    /// should return [`Error::NotFound`].
    async fn find_key<'a>(&self, id: &str)
        -> Result<Box<dyn KeyHandle + Send + Sync + 'a>>;

    /// Imports the keys in the cert.
    ///
    /// `cert` is a TSK.  Any keys without secret key material are
    /// silently ignored.
    ///
    /// Returns each key's import status, and a capability to the key.
    ///
    /// If the TSK doesn't include any secret keys, then an empty list
    /// is returned.
    ///
    /// Some backends require additional information to import a key.
    /// These backends should [`Error::ExternalImportRequired`], and
    /// indicate how a user might import a key to this backend.
    async fn import<'a>(&self, cert: Cert)
        -> Result<Vec<(ImportStatus, Box<dyn KeyHandle + Send + Sync + 'a>)>>;
}

/// A device that contains zero or more keys.
///
/// # Device Properties
///
/// A device has three properties: it can be available or not,
/// configured or not, and registered or not.
///
/// ## Available
///
/// A device is available if the secret key material can be used.
/// (This is independent of whether the secret key material is
/// locked.)  A smart card, for instance, is available when it is
/// inserted, and it is not available when it is not inserted.
/// Devices that are available are always returned by
/// [`Backend::list`].
///
/// ## Configured
///
/// A device is configured if it can be used without further
/// configuration.  (This is independent of whether the secret key
/// material is locked.)  To use the secret key material on a
/// smartcard or a TPM, the user may first need to load the OpenPGP
/// certificate corresponding to the secret keys.  Most devices,
/// however, are already configured, or are able to configure
/// themselves without the user's intervention.  For instance, OpenPGP
/// smartcards don't normally contain the OpenPGP certificate
/// corresponding to the secret keys, but they do contain the keys'
/// OpenPGP fingerprints, and an OpenPGP card backend could fetch
/// the certificate's without user intervention.
///
/// Devices that are available, but not configured should still be
/// returned by [`Backend::list`].  However, because the keys may not
/// be known, the keys may not be enumerable or not usable.  In this
/// case, [`DeviceHandle::list`] should return
/// [`Error::Unconfigured`].
///
/// If a device contains multiple keys, and some can be configured
/// while others aren't, then each key should be exposed as a separate
/// device; this API assumes that either no key or all keys on a given
/// device are configured.
///
/// ## Registered
///
/// A device that is registered is a device whose meta-data has been
/// saved locally.  Devices that are registered are returned by
/// [`Backend::list`] even if they are not available.  Likewise, the
/// keys on a registered device are returned by [`DeviceHandle::list`]
/// even when the device is not available.  When the key store
/// attempts to decrypt a message, it may prompt the user to insert an
/// unavailable, registered device.
///
/// When a backend scans for devices, it should not automatically
/// register devices.  Once a device has been successfully used,
/// however, a backend may register the device.  For instance, a smart
/// card that is discovered by a scan should not automatically be
/// registered.  However, when the smart card is successfully used to
/// create a signature or decrypt a message, then it may be registered
/// without further intervention from the user.
///
/// ## Alternate View
///
/// Another, less precise view, is that a device may be in one of the
/// following states:
///
///   - Ready: The device is available and configured.
///
///     The device can be used immediately.  For instance, a soft key,
///     or a smartcard that is inserted.
///
///     A device that is ready may still need to be unlocked.
///
///   - Disconnected: A device that was registered, but is not
///     available.
///
///     The device is not available, but the user may be prompted to
///     make it available.  For instance, if a key needed to decrypt a
///     message is on a smartcard that is unavailable, the user may be
///     prompted to insert the smartcard.  Similarly, if a key is
///     accessible via an ssh tunnel, but the ssh tunnel cannot be
///     established, the user may be prompted to connect to the
///     network.
///
///     The backend should still expose all of an unavailable device's
///     keys (insofar as they are known), however, the decrypt and
///     sign operations should fail with [`Error::Unavailable`].
///
///   - Unusable: A device that was discovered, but that cannot be
///     used without some additional configuration.  For instance, a
///     smartcard or a TPM key may need the corresponding certificate
///     before it can be used.
///
///   - Unknown: A device that is not available, and not registered.
///
/// The aforementioned three properties map onto these states as
/// follows:
///
/// ```text
///     Available,     Configured,     Registered: Ready
///     Available,     Configured, Not Registered: Ready
///     Available, Not Configured,     Registered: Unusable
///     Available, Not Configured, Not Registered: Unusable
/// Not Available,     Configured,     Registered: Disconnected
/// Not Available,     Configured, Not Registered: Unknown
/// Not Available, Not Configured,     Registered: Disconnected
/// Not Available, Not Configured, Not Registered: Unknown
/// ```
///
/// A device is only ever instantiated if it is available or registered.
#[async_trait::async_trait]
pub trait DeviceHandle {
    /// Returns the device's id.
    ///
    /// The id is a globally unique, stable, and mostly human readable
    /// identifier.
    fn id(&self) -> String;

    /// Returns the device's description.
    ///
    /// The description is a human readable string, e.g., "GnuK with
    /// certificate FINGERPRINT".
    async fn description(&self) -> String {
        self.id()
    }

    /// Sets the device's human readable description.
    ///
    /// This should fail if the device is not registered.
    async fn set_description(&self, _description: String) -> Result<()> {
        Err(Error::Unregistered(self.id()).into())
    }

    /// Returns whether the device is available.
    ///
    /// A device is available if it is plugged-in.
    async fn available(&self) -> bool;

    /// Returns whether the device is configured.
    ///
    /// A device is configured if the keys can be used without further
    /// configuration.
    async fn configured(&self) -> bool;

    /// Returns whether the device is registered.
    ///
    /// A device is registered if the device is locally memorized.  In
    /// this case, the user may be prompted to insert the device.
    async fn registered(&self) -> bool;

    /// Registers the device.
    ///
    /// This explicitly registers the device.  The backend should
    /// memorize the device and should return it during a scan even if
    /// it is not available.  If the device is already registered,
    /// this should silently succeed.
    async fn register(&mut self) -> Result<()> {
        Err(Error::OperationNotSupported("DeviceHandle::register".into()).into())
    }

    /// Unregisters the device from the backend.
    ///
    /// This should not destroy any secret key material stored on the
    /// device.  It should just remove any cached state about the
    /// device.  For instance, if the device is an ssh tunnel, then
    /// the ssh tunnel's configuration should be forgotten.  If the
    /// device is a smart card, then the smart card should be
    /// forgotten.  Note: if the smart card is inserted, it is still
    /// available and thus still usable.
    ///
    /// Note: devices that are not available can only be registered
    /// using a backend-specific tool.  For instance, a device
    /// accessible via an ssh tunnel is never available.
    async fn unregister(&mut self) -> Result<()> {
        Err(Error::OperationNotSupported("DeviceHandle::unregister".into()).into())
    }

    /// Connects to and unlocks the device.
    ///
    /// Some devices need to be initialized.  For instance, to access
    /// a remote key, it may be necessary to create an ssh tunnel.
    /// Some devices need to be unlocked before the keys can be
    /// enumerated.  For instance, if soft keys are stored in a
    /// database and the database is encrypted, it may be necessary to
    /// supply a password to decrypt the database.
    async fn unlock(&mut self, _password: &Password) -> Result<()> {
        Err(Error::AlreadyUnlocked("DeviceHandle::unlock".into()).into())
    }

    /// Locks the device and any keys in contains.
    ///
    /// Locks the device if it has been previously unlocked as well as
    /// any keys managed by the device.  If the device is locked or
    /// can't be locked, this is a noop.  If the device needs to be
    /// deinitialized, it MAY be deinitialized lazily if doing so
    /// cannot result in a user-visible error.  For instance, if the
    /// device uses an ssh tunnel, the ssh tunnel may be closed later.
    async fn lock(&mut self) -> Result<()> {
        Ok(())
    }

    /// Lists keys on the device.
    ///
    /// Returns the keys on the device.  If the device is not usable,
    /// then this should return [`Error::Unconfigured`].
    async fn list<'a>(&'a self)
        -> Box<dyn Iterator<Item=Box<dyn KeyHandle + Send + Sync + 'a>>
               + Send + Sync + 'a>;
}

/// A Key on a Device.
///
/// A key may or may not be available.  This is a function of the
/// device.
#[async_trait::async_trait]
pub trait KeyHandle {
    /// Returns the key's id.
    ///
    /// The id is a globally unique, stable, and mostly human readable
    /// identifier.  An example of a good id is the concatenation of
    /// the the key's fingerprint, and the device's serial number,
    /// e.g., "Key 8F17777118A33DDA9BA48E62AACB3243630052D9 on Yubikey
    /// 5 #217813388320."
    fn id(&self) -> String;

    /// Returns the key's fingerprint.
    fn fingerprint(&self) -> Fingerprint;

    /// Returns the key's key ID.
    fn keyid(&self) -> KeyID {
        KeyID::from(self.fingerprint())
    }

    /// Returns the key's device.
    async fn device<'a>(&self) -> Box<dyn DeviceHandle + Send + Sync + 'a>;

    /// Returns whether the key is available.
    async fn available(&self) -> bool;

    /// Returns whether the key is locked.
    async fn locked(&self) -> Protection;

    /// Returns how the password is obtained.
    ///
    /// This is similar to, but not identical to
    /// [`KeyHandle::locked`].  This function indicates how the
    /// password must be provided independency of the current
    /// protection.
    async fn password_source(&self) -> PasswordSource;

    /// Returns whether the key is decryption capable.
    async fn decryption_capable(&self) -> bool;

    /// Returns whether the key is signing capable.
    async fn signing_capable(&self) -> bool;

    /// Unlocks a key.
    ///
    /// A key is typically unlocked by providing a password or pin.
    /// Not all keys are locked.  If the key is not available, this
    /// should attempt to connect to the device.  If the device is not
    /// available or cannot be initialized, then this should fail.
    ///
    /// If `password` is `Some` and [`KeyHandle::password_source`]
    /// indicates that the password cannot be provided inline, then
    /// the backend must return [`Error::NoInlinePassword`].  Likewise,
    /// if `password` is `None`, and [`KeyHandle::password_source`]
    /// does not indicate that the user can be prompted for the
    /// password ([`PasswordSource::ExternalOnDemand`]), then the
    /// backend must return [`Error::NoExternalPassword`].
    ///
    /// If the key is already unlocked, this returns
    /// [`Error::AlreadyUnlocked`].
    async fn unlock(&mut self, _password: Option<&Password>) -> Result<()> {
        Err(Error::AlreadyUnlocked("KeyHandle::unlock".into()).into())
    }

    /// Lock a key.
    ///
    /// Relocks the key.  This usually causes the backend to forget the
    /// key's password.
    async fn lock(&mut self) -> Result<()> {
        Ok(())
    }

    /// Returns the corresponding public key.
    ///
    /// The backend SHOULD ensure that the secret key material is
    /// removed.
    async fn public_key(&self)
        -> openpgp::packet::Key<openpgp::packet::key::PublicParts,
                                openpgp::packet::key::UnspecifiedRole>;

    /// Decrypts a PKESK.
    ///
    async fn decrypt_pkesk(&mut self, pkesk: &PKESK)
        -> Option<(SymmetricAlgorithm, SessionKey)>
    {
        // We want to use `PKESK::decrypt`.  For that, we need
        // something that implements the `Decryptor` interface.  We
        // could implement `Decryptor` for `KeyHandle`, but then that
        // is part of our public API.  Instead, we do a bit of
        // acrobatics here.
        struct Decryptor<'a, T>
            where T: KeyHandle + ?Sized
        {
            slf: &'a mut T,
            pk: openpgp::packet::Key<
                    openpgp::packet::key::PublicParts,
                    openpgp::packet::key::UnspecifiedRole>,
        }

        impl<'a, T> openpgp::crypto::Decryptor for Decryptor<'a, T>
            where T: KeyHandle + ?Sized + Send
        {
            fn public(&self)
                -> &openpgp::packet::Key<
                    openpgp::packet::key::PublicParts,
                    openpgp::packet::key::UnspecifiedRole>
            {
                &self.pk
            }

            fn decrypt(&mut self, ciphertext: &mpi::Ciphertext,
                       plaintext_len: Option<usize>)
                -> Result<SessionKey>
            {
                // We know that pkesk.decrypt is running on a separate
                // thread.  So it is safe to create a new runtime on
                // this thread.
                let rt = tokio::runtime::Runtime::new()?;

                rt.block_on(async {
                    self.slf.decrypt_ciphertext(ciphertext, plaintext_len).await
                })
            }
        }

        let pk = self.public_key();
        let pk = pk.await;

        let mut decryptor = Decryptor {
            slf: self,
            pk: pk,
        };

        // To avoid blocking the current thread, we run the sync
        // function `pkesk.decrypt` on a separate thread.  When it is
        // done, it results the result via a one shot channel, which
        // we can asynchronously wait on.
        let (sender, receiver) = futures::channel::oneshot::channel::<_>();

        std::thread::scope(|s| {
            s.spawn(move || {
                sender.send(pkesk.decrypt(&mut decryptor, None))
            });
        });

        match receiver.await {
            Ok(Some(result)) => Some(result),
            Ok(None) => None,
            Err(_) => None,
        }
    }

    /// Decrypts a ciphertext.
    ///
    /// This method has the same semantics as
    /// [`sequoia_openpgp::crypto::Decryptor::decrypt`].
    ///
    /// Returns the session key.
    async fn decrypt_ciphertext(&mut self,
                                ciphertext: &mpi::Ciphertext,
                                plaintext_len: Option<usize>)
        -> Result<SessionKey>;

    /// Signs a message.
    ///
    /// `text` is the message to sign.
    async fn sign(&mut self, hash_algo: HashAlgorithm, text: &[u8])
        -> Result<(PublicKeyAlgorithm, mpi::Signature)>;

    /// Exports the secret key material.
    async fn export(&mut self)
        -> Result<openpgp::packet::Key<
            openpgp::packet::key::SecretParts,
            openpgp::packet::key::UnspecifiedRole>>;

    /// Changes the key's password.
    ///
    /// Changes the password.  Before calling this function, you
    /// should call [`KeyHandle::password_source`] to determine if you
    /// need to unlock the key, and whether you need to provide the
    /// new password directly, or if that is obtained externally.
    ///
    /// If `new_password` is `Some` and [`KeyHandle::password_source`]
    /// indicates that the password cannot be provided inline, then
    /// the backend must return [`Error::NoInlinePassword`].  Likewise,
    /// if `new_password` is `None`, and
    /// [`KeyHandle::password_source`] does not indicate that the user
    /// can be prompted for the password, then the backend must return
    /// [`Error::NoExternalPassword`].
    async fn change_password(&mut self, new_password: Option<&Password>)
         -> Result<()>;

    /// Deletes the key.
    ///
    /// This destroys the key's secret key material.
    ///
    /// If the key has to be unlocked, and the key is locked, the
    /// backend should return an error.
    ///
    /// If the device managing the key does not support deleting keys,
    /// then it should return [`Error::OperationNotSupported`].
    async fn delete_secret_key_material(&mut self) -> Result<()>;
}