//! Sequoia's key store.
//!
//! Sequoia's key store 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 (a soft key), it may be a smartcard, or
//! it could be another key store server that is accessed over the
//! network.  The key store manages all of these devices, and provides
//! a common, higher-level interface.
//!
//! The key store is a server.  It normally lives in a separate
//! process, but it may be co-located with the application.  Using a
//! separate process improves security, because secret key material
//! isn't exposed to the application, which can help prevent
//! [Heartbleed-style bugs].  It also means that the state can be
//! shared, which improves usability.  For instance, the server can
//! cache passwords.  Sometimes, a separate process is not desirable,
//! or awkward, e.g., when using the key store from an initrd.  In
//! these cases, the co-located key store is better.
//!
//!   [Heartbleed-style bugs]: https://heartbleed.com/
use std::any::Any;
use std::sync::Arc;

use capnp::any_pointer;
use capnp::capability;
use capnp::capability_list;
use capnp::message;
use capnp::traits::HasTypeId;

use sequoia_openpgp as openpgp;
use openpgp::Cert;
use openpgp::Fingerprint;
use openpgp::KeyID;
use openpgp::KeyHandle;
use openpgp::crypto::mpi;
use openpgp::crypto::SessionKey;
use openpgp::crypto::Password;
use openpgp::packet;
use openpgp::packet::PKESK;
use openpgp::packet::key;
use openpgp::parse::Parse;
use openpgp::types::HashAlgorithm;
use openpgp::types::PublicKeyAlgorithm;
use openpgp::types::SymmetricAlgorithm;

pub use sequoia_ipc;
use sequoia_ipc as ipc;
pub use ipc::Context;

/// Re-export, since this is part of our API.
pub use sequoia_directories;

mod import_status;
pub use import_status::ImportStatus;
mod password_source;
pub use password_source::PasswordSource;
mod protection;
pub use protection::Protection;

#[allow(dead_code)] mod keystore_protocol_capnp;
use crate::keystore_protocol_capnp::keystore;

/// Macros managing requests and responses.
#[macro_use] mod macros;
mod error;
pub use error::Error;
mod server;
mod capnp_relay;
use capnp_relay::CapnProtoRelay;
use capnp_relay::Cap;
use capnp_relay::CapTable;

#[cfg(test)]
mod testdata;


/// Result type.
pub type Result<T, E=anyhow::Error> = ::std::result::Result<T, E>;


#[doc(hidden)]
pub fn descriptor(c: &Context) -> ipc::Descriptor {
    ipc::Descriptor::new(
        c,
        c.home().join("keystore.cookie"),
        c.lib().join("sequoia-keystore"),
        server::Keystore::new_descriptor,
    )
}

/// A handle to the key store.
pub struct Keystore {
    relay: Arc<CapnProtoRelay>,
    cap: Cap,
}

impl Keystore {
    /// Connects to the keystore.
    ///
    /// To set the context's home directory, you should usually
    /// instantiate a `sequoia_dirs::Home` object, and use the value
    /// returned by
    /// `home.data_dir(sequoia_dirs::Component::Keystore)`.
    pub fn connect(c: &Context) -> Result<Self> {
        let descriptor = descriptor(&c);

        let relay = CapnProtoRelay::new(descriptor)?;
        let root = relay.root();
        Ok(Self {
            relay: relay,
            cap: root,
        })
    }

    crpc!(
        /// Lists all backends.
        fn [keystore] backends/0(&mut self)
            -> Result<Vec<Cap>>
            -> Result<Vec<Backend>>
        // Marshal.
        |_root: keystore::backends_params::Builder| -> Result<()> {
            Ok(())
        };
        // Extract.
        |relay, captable, response: keystore::backends_results::Reader| {
            use keystore::result::Which;
            match response.get_result()?.which()? {
                // The RPC's result:
                Which::Ok(Ok(r)) => {
                    let r: capability_list::Reader<keystore::backend::Client> = r;
                    let backends = r.iter()
                        .map(|backend| {
                            let cap: keystore::backend::Client = backend?;
                            Ok(captable.insert(cap.client))
                        }).collect::<Result<Vec<Cap>>>()?;

                    Ok(backends)
                },
                Which::Err(Ok(e)) => Err(Error::from_capnp(relay, captable, e)),

                // Protocol violations:
                // Protocol error:
                Which::Err(Err(e)) => Err(anyhow::Error::from(e)),
                // Error reading the result from the response:
                Which::Ok(Err(e)) => Err(anyhow::Error::from(e)),
            }
        };
        |caps: Vec<Cap>| {
            let backends: Vec<Backend> = caps
                .into_iter()
                .map(|cap| {
                    Backend {
                        relay: Arc::clone(&self.relay),
                        cap: cap,
                    }
                })
                .collect();
            Ok(backends)
        });

    /// Finds the specified keys.
    ///
    /// As a key may reside on multiple devices, this may return
    /// multiple handles for a given key.
    ///
    /// The second return value is the list of keys that were not
    /// found on the keystore.
    #[async_generic::async_generic]
    pub fn find_keys(&mut self, ids: &[KeyHandle])
        -> Result<(Vec<Key>, Vec<KeyHandle>)>
    {
        let mut found: Vec<Key> = Vec::new();

        let backends = if _sync {
            self.backends()
        } else {
            self.backends_async().await
        };

        for mut b in backends.unwrap_or_else(|_| Vec::new()).into_iter() {
            let devices = if _sync {
                b.devices()
            } else {
                b.devices_async().await
            };

            for mut d in devices.unwrap_or_else(|_| Vec::new()).into_iter() {
                let keys = if _sync {
                    d.keys()
                } else {
                    d.keys_async().await
                };

                for mut k in keys.unwrap_or_else(|_| Vec::new()).into_iter() {
                    let id = if _sync {
                        k.id()
                    } else {
                        k.id_async().await
                    };

                    if let Ok(fpr) = id.and_then(|f| f.parse::<Fingerprint>()) {
                        if ids.iter().any(|id| id.aliases(KeyHandle::from(&fpr))) {
                            found.push(k);
                        }
                    }
                }
            }
        }

        let have: Vec<KeyHandle> = found.iter().map(|k| {
            KeyHandle::from(k.fingerprint())
        }).collect();

        let missing = ids
            .iter()
            .filter(|id| ! have.iter().any(|fpr| id.aliases(fpr)))
            .cloned()
            .collect();

        Ok((found, missing))
    }

    /// Finds the specified key.
    ///
    /// As a key may reside on multiple devices, this may return
    /// multiple keys for a given id.
    #[async_generic::async_generic]
    pub fn find_key(&mut self, id: KeyHandle) -> Result<Vec<Key>> {
        let result = if _sync {
            self.find_keys(&[id])
        } else {
            self.find_keys_async(&[id]).await
        };

        result.map(|r| r.0)
    }

    crpc!(
        /// Decrypts a PKESK.
        ///
        /// The keystore tries to decrypt the PKESKs in an arbitrary
        /// order.  When it succeeds in decrypting a PKESK, it stops
        /// and returns the decrypted session key.  By not enforcing
        /// an order, the keystore is able to first try keys that are
        /// immediately available, and only try keys that need to be
        /// unlocked or connected to if that fails.
        ///
        /// On success, this function returns the index of the PKESK
        /// that was decrypted, the fingerprint of the key that
        /// decrypted the PKESK, and the plaintext (the symmetric
        /// algorithm and the session key).
        fn [keystore]decrypt/1(&mut self, pkesks: &[PKESK])
            -> Result<(usize, Fingerprint, Option<SymmetricAlgorithm>, SessionKey)>
        // Marshal.
        |root: keystore::decrypt_params::Builder| -> Result<()> {
            // Convert the arguments into the form expected by the RPC.
            let mut pkesks_param = root.init_pkesks(pkesks.len() as u32);

            pkesks
                .iter()
                .enumerate()
                .for_each(|(i, pkesk)| {
                    use openpgp::serialize::MarshalInto;
                    let pkesk = pkesk.to_vec()
                        .expect("serializing to a vec is infallible");
                    pkesks_param.set(i as u32, &pkesk[..]);
                });

            Ok(())
        };
        // Extract.
        |relay, captable, response: keystore::decrypt_results::Reader| {
            use keystore::result::Which;
            match response.get_result()?.which()? {
                // The RPC's result:
                Which::Ok(Ok(r)) => {
                    let i = r.get_index() as usize;
                    let fp_version = r.get_fingerprint_version();
                    let fpr = Fingerprint::from_bytes(
                        fp_version, r.get_fingerprint()?)?;
                    let algo = match r.get_algo() as u8 {
                        0 => None,
                        n => Some(n.into()),
                    };
                    let session_key = SessionKey::from(r.get_session_key()?);

                    let r: (usize, Fingerprint, Option<SymmetricAlgorithm>, SessionKey)
                        = (i, fpr, algo, session_key);
                    Ok(r)
                },
                Which::Err(Ok(e)) => Err(Error::from_capnp(relay, captable, e)),

                // Protocol violations:
                // Protocol error:
                Which::Err(Err(e)) => Err(anyhow::Error::from(e)),
                // Error reading the result from the response:
                Which::Ok(Err(e)) => Err(anyhow::Error::from(e)),
            }
        });
}

/// A handle to a backend.
///
/// The key store may have multiple backends.  These include a backend
/// for soft keys (keys stored on disk), and a `gpg-agent` backend.
///
/// Use [`Keystore::backends`] to get a list of the backends that are
/// enabled.
pub struct Backend {
    relay: Arc<CapnProtoRelay>,
    cap: Cap,
}

impl Backend {
    crpc!(
        /// Returns the backend's ID.
        fn [keystore::backend]id/0(&mut self) -> Result<String>
        // Marshal.
        |_root: keystore::backend::id_params::Builder| -> Result<()> {
            Ok(())
        };
        // Extract.
        |relay, captable, response: keystore::backend::id_results::Reader| {
            use keystore::result::Which;
            match response.get_result()?.which()? {
                // The RPC's result:
                Which::Ok(Ok(r)) => {
                    Ok(r.to_string()?)
                },
                Which::Err(Ok(e)) => Err(Error::from_capnp(relay, captable, e)),

                // Protocol violations:
                // Protocol error:
                Which::Err(Err(e)) => Err(anyhow::Error::from(e)),
                // Error reading the result from the response:
                Which::Ok(Err(e)) => Err(anyhow::Error::from(e)),
            }
        });

    crpc!(
        /// Lists all devices.
        ///
        /// Lists the devices managed by a backend.
        fn [keystore::backend] devices/1(&mut self)
            -> Result<Vec<Cap>>
            -> Result<Vec<Device>>
        // Marshal.
        |_root: keystore::backend::devices_params::Builder| -> Result<()> {
            Ok(())
        };
        // Extract.
        |relay, captable, response: keystore::backend::devices_results::Reader| {
            use keystore::result::Which;
            match response.get_result()?.which()? {
                // The RPC's result:
                Which::Ok(Ok(r)) => {
                    let r: capability_list::Reader<keystore::device::Client> = r;
                    let devices = r.iter()
                        .map(|device| {
                            let cap: keystore::device::Client = device?;
                            Ok(captable.insert(cap.client))
                        }).collect::<Result<Vec<Cap>>>()?;

                    Ok(devices)
                },
                Which::Err(Ok(e)) => Err(Error::from_capnp(
                    Arc::clone(&relay), captable, e)),

                // Protocol violations:
                // Protocol error:
                Which::Err(Err(e)) => Err(anyhow::Error::from(e)),
                // Error reading the result from the response:
                Which::Ok(Err(e)) => Err(anyhow::Error::from(e)),
            }
        };
        |caps: Vec<Cap>| {
            let devices: Vec<Device> = caps
                .into_iter()
                .map(|cap| {
                    Device {
                        relay: Arc::clone(&self.relay),
                        cap: cap,
                    }
                })
                .collect();
            Ok(devices)
        });

    crpc!(
        /// Imports secret key material.
        ///
        /// cert is a TSK.  Any keys without secret key material are
        /// silent ignored.
        ///
        /// If a key already exists, it is overwritten.
        ///
        /// An [`ImportStatus`] is returned for each secret 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.
        fn [keystore::backend] import/2(&mut self, cert: &Cert)
            -> Result<Vec<(ImportStatus,
                           Cap,
                           packet::Key::<key::PublicParts,
                                         key::UnspecifiedRole>)>>
            -> Result<Vec<(ImportStatus, Key)>>
        // Marshal.
        |root: keystore::backend::import_params::Builder| -> Result<()> {
            use openpgp::serialize::MarshalInto;

            let bytes = cert.as_tsk().to_vec()?;
            let cert_param = root.init_cert(bytes.len() as u32);
            cert_param.copy_from_slice(&bytes);

            Ok(())
        };
        // Extract.
        |relay, captable, response: keystore::backend::import_results::Reader| {
            use keystore::result::Which;
            match response.get_result()?.which()? {
                // The RPC's result:
                Which::Ok(Ok(r)) => {
                    let r: capnp::struct_list::Reader<keystore::import_result::Owned> = r;
                    let r = r.iter()
                        .map(|x| {
                            use openpgp::parse::Parse;

                            let status =
                                ImportStatus::try_from(x.get_status()?)?;

                            let key = x.get_key()?;

                            let cap = key.get_handle()?;
                            let pk = key.get_public_key()?;
                            let pk = packet::Key::<key::UnspecifiedParts,
                                                   key::UnspecifiedRole>
                                ::from_bytes(pk)?;
                            let pk = pk.parts_into_public();
                            Ok((status, captable.insert(cap.client), pk))
                        }).collect::<Result<Vec<(ImportStatus, Cap, packet::Key<_, _>)>>>();

                    Ok(r?)
                },
                Which::Err(Ok(e)) => Err(Error::from_capnp(
                    Arc::clone(&relay), captable, e)),

                // Protocol violations:
                // Protocol error:
                Which::Err(Err(e)) => Err(anyhow::Error::from(e)),
                // Error reading the result from the response:
                Which::Ok(Err(e)) => Err(anyhow::Error::from(e)),
            }
        };
        |caps: Vec<(ImportStatus, Cap, packet::Key<_, _>)>| {
            let keys: Vec<(ImportStatus, Key)> = caps
                .into_iter()
                .map(|(import_status, cap, key)| {
                    (
                        import_status,
                        Key {
                            relay: Arc::clone(&self.relay),
                            cap: cap,
                            key: key,
                        }
                    )
                })
                .collect();
            Ok(keys)
        });

//    crpc!(fn [keystore::backend]scan/2(&mut self) -> Result<()>
//          });

//    crpc!(fn register(&mut self, description: &str) -> Result<Device>
//          |slf: &mut Self, device| {
//              Ok(Device {
//                  relay: Arc::clone(&slf.relay),
//                  cap: Arc::new(Mutex::new(device)),
//              })
//          });
}

/// A handle to a Device.
///
/// A device contains zero or more keys.
///
/// Some backends manage multiple physical devices.  For instance, the
/// smartcard backend exposes each smartcard as a separate device.
/// Other backends use the device abstraction to logically group
/// related keys together.  For instance, the soft keys backend
/// exposes each certificate as a separate device.
pub struct Device {
    relay: Arc<CapnProtoRelay>,
    cap: Cap,
}

impl Device {
    crpc!(
        /// Returns the device's ID.
        fn [keystore::device]id/0(&mut self) -> Result<String>
        // Marshal.
        |_root: keystore::device::id_params::Builder| -> Result<()> {
            Ok(())
        };
        // Extract.
        |relay, captable, response: keystore::device::id_results::Reader| {
            use keystore::result::Which;
            match response.get_result()?.which()? {
                // The RPC's result:
                Which::Ok(Ok(r)) => {
                    Ok(r.to_string()?)
                },
                Which::Err(Ok(e)) => Err(Error::from_capnp(relay, captable, e)),

                // Protocol violations:
                // Protocol error:
                Which::Err(Err(e)) => Err(anyhow::Error::from(e)),
                // Error reading the result from the response:
                Which::Ok(Err(e)) => Err(anyhow::Error::from(e)),
            }
        });

    crpc!(
        /// List keys on a device.
        ///
        /// Lists the keys on the device.
        ///
        /// Some of the returned keys may be known, but not currently
        /// available.  For instance, if a smartcard is not plugged
        /// in, or an ssh connection is not established.
        fn [keystore::device] keys/1(&mut self)
            -> Result<Vec<(Cap,
                           packet::Key::<key::PublicParts,
                                         key::UnspecifiedRole>)>>
            -> Result<Vec<Key>>
        // Marshal.
        |_root: keystore::device::keys_params::Builder| -> Result<()> {
            Ok(())
        };
        // Extract.
        |relay, captable, response: keystore::device::keys_results::Reader| {
            use keystore::result::Which;
            match response.get_result()?.which()? {
                // The RPC's result:
                Which::Ok(Ok(r)) => {
                    let r: capnp::struct_list::Reader<keystore::key_descriptor::Owned> = r;
                    let r = r.iter()
                        .map(|x| {
                            use openpgp::parse::Parse;

                            let cap = x.get_handle()?;
                            let pk = x.get_public_key()?;
                            let pk = packet::Key::<key::UnspecifiedParts,
                                                   key::UnspecifiedRole>
                                ::from_bytes(pk)?;
                            let pk = pk.parts_into_public();
                            Ok((captable.insert(cap.client), pk))
                        }).collect::<Result<Vec<(Cap, packet::Key<_, _>)>>>();

                    Ok(r?)
                },
                Which::Err(Ok(e)) => Err(Error::from_capnp(
                    Arc::clone(&relay), captable, e)),

                // Protocol violations:
                // Protocol error:
                Which::Err(Err(e)) => Err(anyhow::Error::from(e)),
                // Error reading the result from the response:
                Which::Ok(Err(e)) => Err(anyhow::Error::from(e)),
            }
        };
        |caps: Vec<(Cap, packet::Key<_, _>)>| {
            let keys: Vec<Key> = caps
                .into_iter()
                .map(|(cap, key)| {
                    Key {
                        relay: Arc::clone(&self.relay),
                        cap: cap,
                        key: key,
                    }
                })
                .collect();
            Ok(keys)
        });

    // /// Forget a device.
    // ///
    // /// Unregister the device from the backend.  This should not
    // /// destroy any secret key material stored on the device.
    // pub fn unregister(&mut self) -> Result<()> {
    //     todo!()
    // }

    // /// Unlock a device.
    // ///
    // /// Connects to and unlocks a 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.  In this case, the parameter might be
    // /// "password='1234'".
    // pub fn unlock(&mut self, _password: &[u8]) -> Result<()> {
    //     todo!();
    // }

    // /// Lock a device.
    // ///
    // /// Locks the device if it has been previously unlock.  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 be closed later.  A
    // /// smartcard, however, should be released immediately.
    // pub fn lock(&mut self) -> Result<()> {
    //     todo!()
    // }
}

/// A handle to a key.
///
/// A key encapsulates secret key material, and exposes some secret
/// key operations like decrypting a message, signing a message,
/// changing the key's password, and deleting the secret key material.
/// Not all keys implement all operations.  In particular, a key will
/// typically either implement [`Key::decrypt_ciphertext`] or
/// [`Key::sign_message`].
#[derive(Clone)]
pub struct Key {
    relay: Arc<CapnProtoRelay>,
    cap: Cap,
    key: packet::Key<key::PublicParts, key::UnspecifiedRole>,
}

impl Key {
    /// Returns the key's key handle.
    pub fn key_handle(&self) -> KeyHandle {
        self.key.fingerprint().into()
    }

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

    /// Returns the key's Key ID.
    pub fn keyid(&self) -> KeyID {
        self.key.keyid()
    }

    /// Returns the key's public key.
    pub fn public_key(&self)
        -> &packet::Key<key::PublicParts, key::UnspecifiedRole>
    {
        &self.key
    }

    crpc!(
        /// Returns a unique key identifier.
        ///
        /// It should be a well-formed UTF-8 string, which should give a
        /// curious user a pretty good idea of what key this is.
        fn [keystore::key]id/0(&mut self) -> Result<String>
        // Marshal.
        |_root: keystore::key::id_params::Builder| -> Result<()> {
            Ok(())
        };
        // Extract.
        |relay, captable, response: keystore::key::id_results::Reader| {
            use keystore::result::Which;
            match response.get_result()?.which()? {
                // The RPC's result:
                Which::Ok(Ok(r)) => {
                    Ok(r.to_string()?)
                },
                Which::Err(Ok(e)) => Err(Error::from_capnp(relay, captable, e)),

                // Protocol violations:
                // Protocol error:
                Which::Err(Err(e)) => Err(anyhow::Error::from(e)),
                // Error reading the result from the response:
                Which::Ok(Err(e)) => Err(anyhow::Error::from(e)),
            }
        });

    crpc!(
        /// 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.
        fn [keystore::key]unlock/3(&mut self, password: Password) -> Result<()>
            // Marshal.
            |mut root: keystore::key::unlock_params::Builder| -> Result<()> {
                password.map(|password| {
                    root.set_password(&password[..]);
                });
                Ok(())
            };
            // Extract.
            |relay, captable, response: keystore::key::unlock_results::Reader| {
                use keystore::void_result::Which;
                match response.get_result()?.which()? {
                    // The RPC's result:
                    Which::Ok(()) => Ok(()),
                    Which::Err(Ok(e)) => Err(Error::from_capnp(relay, captable, e)),

                    // Protocol violations:
                    // Protocol error:
                    Which::Err(Err(e)) => Err(anyhow::Error::from(e)),
                }
            });

    // /// Lock a key (optional)
    // ///
    // /// Relocks the key.  This usually causes the backend to forget the
    // /// key's password.  If the key can't be locked or is already locked,
    // /// this is a noop.
    // pub fn lock(&mut self) -> Result<()> {
    //     todo!()
    // }

    crpc!(
        /// Decrypts a ciphertext.
        ///
        /// This function corresponds to [`Decryptor::decrypt`].
        ///
        /// When decrypting a message you normally don't want to manually
        /// try to decrypt each PKESK using this function, but use
        /// [`Keystore::decrypt`], which first tries to use keys that
        /// don't require user interaction.
        ///
        /// [`Decryptor::decrypt`]: https://docs.sequoia-pgp.org/sequoia_openpgp/crypto/trait.Decryptor.html#tymethod.decrypt
        ///
        /// If you want to decrypt a `PKESK`, then you should pass the
        /// `Key` to `PKESK::decrypt`.
        fn [keystore::key]decrypt_ciphertext/1(&mut self,
                                               ciphertext: &Ciphertext,
                                               plaintext_len: Option<usize>)
            -> Result<SessionKey>
        // Marshal.
        |mut root: keystore::key::decrypt_ciphertext_params::Builder| -> Result<()> {
            // Convert the arguments into the form expected by the RPC.
            let algo = ciphertext.pk_algo().map(u8::from).unwrap_or(0);
            let ciphertext = {
                use sequoia_openpgp::serialize::MarshalInto;
                ciphertext.to_vec().expect("serializing to a vec is infallible")
            };

            root.set_algo(algo);
            root.set_ciphertext(&ciphertext);
            root.set_plaintext_len(plaintext_len.unwrap_or(0) as u32);

            Ok(())
        };
        // Extract.
        |relay, captable, response: keystore::key::decrypt_ciphertext_results::Reader| {
            use keystore::result::Which;
            match response.get_result()?.which()? {
                // The RPC's result:
                Which::Ok(Ok(r)) => {
                    let r: capnp::data::Reader = r;
                    Ok(SessionKey::from(r))
                },
                Which::Err(Ok(e)) => Err(Error::from_capnp(relay, captable, e)),

                // Protocol violations:
                // Protocol error:
                Which::Err(Err(e)) => Err(anyhow::Error::from(e)),
                // Error reading the result from the response:
                Which::Ok(Err(e)) => Err(anyhow::Error::from(e)),
            }
        });

    crpc!(
        /// Signs a message.
        ///
        /// `digest` is the message to sign.
        fn [keystore::key]sign_message/2(&mut self, hash_algo: HashAlgorithm,
                                         digest: &[u8])
            -> Result<mpi::Signature>
        // Marshal.
        |mut root: keystore::key::sign_message_params::Builder| -> Result<()> {
            // Convert the arguments into the form expected by the RPC.
            root.set_hash_algo(u8::from(hash_algo));
            root.set_digest(digest);

            Ok(())
        };
        // Extract.
        |relay, captable, response: keystore::key::sign_message_results::Reader| {
            use keystore::result::Which;
            match response.get_result()?.which()? {
                // The RPC's result:
                Which::Ok(Ok(r)) => {
                    let pk_algo = PublicKeyAlgorithm::from(r.get_pk_algo());
                    let mpis = r.get_mpis()?;

                    let sig = mpi::Signature::parse(pk_algo, mpis)?;
                    Ok(sig)
                },
                Which::Err(Ok(e)) => Err(Error::from_capnp(relay, captable, e)),

                // Protocol violations:
                // Protocol error:
                Which::Err(Err(e)) => Err(anyhow::Error::from(e)),
                // Error reading the result from the response:
                Which::Ok(Err(e)) => Err(anyhow::Error::from(e)),
            }
        });

    crpc!(
        /// Whether the key is available.
        ///
        /// If false, this usually means the device needs to be
        /// connected, e.g., a smartcard needs to be plugged in.
        fn [keystore::key]available/4(&mut self) -> Result<bool>
        // Marshal.
        |_root: keystore::key::available_params::Builder| -> Result<()> {
            Ok(())
        };
        // Extract.
        |relay, captable, response: keystore::key::available_results::Reader| {
            use keystore::bool_result::Which;
            match response.get_result()?.which()? {
                // The RPC's result:
                Which::Ok(b) => {
                    Ok(b)
                },
                Which::Err(Ok(e)) => Err(Error::from_capnp(relay, captable, e)),

                // Protocol violations:
                // Protocol error:
                Which::Err(Err(e)) => Err(anyhow::Error::from(e)),
            }
        });

    crpc!(
        /// Whether the key is locked, and the type of protection.
        fn [keystore::key]locked/5(&mut self) -> Result<Protection>
        // Marshal.
        |_root: keystore::key::locked_params::Builder| -> Result<()> {
            Ok(())
        };
        // Extract.
        |relay, captable, response: keystore::key::locked_results::Reader| {
            use keystore::result::Which;
            match response.get_result()?.which()? {
                // The RPC's result:
                Which::Ok(protection) => {
                    Protection::try_from(protection?)
                },
                Which::Err(Ok(e)) => Err(Error::from_capnp(relay, captable, e)),

                // Protocol violations:
                // Protocol error:
                Which::Err(Err(e)) => Err(anyhow::Error::from(e)),
            }
        });

    crpc!(
        /// How the password is obtained to unlock the key.
        ///
        /// This is independent of whether the key is currently
        /// protected.
        fn [keystore::key]password_source/9(&mut self) -> Result<PasswordSource>
        // Marshal.
        |_root: keystore::key::password_source_params::Builder| -> Result<()> {
            Ok(())
        };
        // Extract.
        |relay, captable, response: keystore::key::password_source_results::Reader| {
            use keystore::result::Which;
            match response.get_result()?.which()? {
                // The RPC's result:
                Which::Ok(password_source) => {
                    PasswordSource::try_from(password_source?)
                },
                Which::Err(Ok(e)) => Err(Error::from_capnp(relay, captable, e)),

                // Protocol violations:
                // Protocol error:
                Which::Err(Err(e)) => Err(anyhow::Error::from(e)),
            }
        });

    crpc!(
        /// Whether the key can be used for decryption.
        fn [keystore::key]decryption_capable/6(&mut self) -> Result<bool>
        // Marshal.
        |_root: keystore::key::decryption_capable_params::Builder| -> Result<()> {
            Ok(())
        };
        // Extract.
        |relay, captable, response: keystore::key::decryption_capable_results::Reader| {
            use keystore::bool_result::Which;
            match response.get_result()?.which()? {
                // The RPC's result:
                Which::Ok(b) => {
                    Ok(b)
                },
                Which::Err(Ok(e)) => Err(Error::from_capnp(relay, captable, e)),

                // Protocol violations:
                // Protocol error:
                Which::Err(Err(e)) => Err(anyhow::Error::from(e)),
            }
        });

    crpc!(
        /// Whether the key can be used for signing.
        fn [keystore::key]signing_capable/7(&mut self) -> Result<bool>
        // Marshal.
        |_root: keystore::key::signing_capable_params::Builder| -> Result<()> {
            Ok(())
        };
        // Extract.
        |relay, captable, response: keystore::key::signing_capable_results::Reader| {
            use keystore::bool_result::Which;
            match response.get_result()?.which()? {
                // The RPC's result:
                Which::Ok(b) => {
                    Ok(b)
                },
                Which::Err(Ok(e)) => Err(Error::from_capnp(relay, captable, e)),

                // Protocol violations:
                // Protocol error:
                Which::Err(Err(e)) => Err(anyhow::Error::from(e)),
            }
        });

    crpc!(
        /// Exports the secret key material.
        fn [keystore::key]export/8(&mut self)
            -> Result<openpgp::packet::Key<
                   openpgp::packet::key::SecretParts,
                   openpgp::packet::key::UnspecifiedRole>>
        // Marshal.
        |mut _root: keystore::key::export_params::Builder| -> Result<()> {
            // Convert the arguments into the form expected by the RPC.
            Ok(())
        };
        // Extract.
        |relay, captable, response: keystore::key::export_results::Reader| {
            use keystore::result::Which;
            match response.get_result()?.which()? {
                // The RPC's result:
                Which::Ok(Ok(bytes)) => {
                    let key = openpgp::packet::Key::from_bytes(bytes)?;
                    let secret_key = key.parts_into_secret()?;
                    Ok(secret_key)
                },
                Which::Err(Ok(e)) => Err(Error::from_capnp(relay, captable, e)),

                // Protocol violations:
                // Protocol error:
                Which::Err(Err(e)) => Err(anyhow::Error::from(e)),
                // Error reading the result from the response:
                Which::Ok(Err(e)) => Err(anyhow::Error::from(e)),
            }
        });

    crpc!(
        /// Changes the key's password.
        fn [keystore::key]change_password/10(&mut self, password: Option<&Password>)
            -> Result<()>
        // Marshal.
        |root: keystore::key::change_password_params::Builder| -> Result<()> {
            // Convert the arguments into the form expected by the RPC.
            let mut change_password_action = root.init_password();
            if let Some(password) = password {
                password.map(|password| {
                    change_password_action.set_password(&password[..]);
                });
            } else {
                change_password_action.set_ask(());
            }

            Ok(())
        };
        // Extract.
        |relay, captable, response: keystore::key::change_password_results::Reader| {
            use keystore::void_result::Which;
            match response.get_result()?.which()? {
                // The RPC's result:
                Which::Ok(()) => Ok(()),
                Which::Err(Ok(e)) => Err(Error::from_capnp(relay, captable, e)),

                // Protocol violations:
                // Protocol error:
                Which::Err(Err(e)) => Err(anyhow::Error::from(e)),
            }
        });

    crpc!(
        /// Deletes the specified key's secret key material.
        ///
        /// On success, the key is no registered with the device, and
        /// future operations on the current key handle will fail.
        fn [keystore::key]delete_secret_key_material/11(&mut self)
            -> Result<()>
        // Marshal.
        |_root: keystore::key::delete_secret_key_material_params::Builder| -> Result<()> {
            // Convert the arguments into the form expected by the RPC.

            Ok(())
        };
        // Extract.
        |relay, captable, response: keystore::key::delete_secret_key_material_results::Reader| {
            use keystore::void_result::Which;
            match response.get_result()?.which()? {
                // The RPC's result:
                Which::Ok(()) => Ok(()),
                Which::Err(Ok(e)) => Err(Error::from_capnp(relay, captable, e)),

                // Protocol violations:
                // Protocol error:
                Which::Err(Err(e)) => Err(anyhow::Error::from(e)),
            }
        });
}

/// Information about key that could not be used for decryption.
///
/// This is returned by [`Keystore::decrypt`] when a key appears to be
/// able to decrypt a message, but the key isn't accessible, e.g.,
/// because it is locked.
#[derive(Clone)]
pub struct InaccessibleDecryptionKey {
    key: Key,
    pkesk: PKESK,
}

impl std::fmt::Debug for InaccessibleDecryptionKey {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "InaccessibleDecryptionKey {{ {} }}",
               self.key.fingerprint())
    }
}

impl InaccessibleDecryptionKey {
    /// Returns the key handle.
    pub fn key(&self) -> &Key {
        &self.key
    }

    /// Returns the key handle.
    pub fn key_mut(&mut self) -> &mut Key {
        &mut self.key
    }

    /// Returns the key handle.
    pub fn into_key(self) -> Key {
        self.key
    }

    /// Returns the PKESK that could not be decrypted.
    ///
    /// Normally, you'd follow up the failed generic decryption by
    /// retrying with the unlocked key, and the relevant PKESK.
    pub fn pkesk(&self) -> &PKESK {
        &self.pkesk
    }
}


use openpgp::crypto::Decryptor;
use openpgp::crypto::Signer;
use openpgp::crypto::mpi::Ciphertext;
use openpgp::crypto::mpi::Signature;

impl Decryptor for &mut Key {
    fn public(&self) -> &packet::Key<key::PublicParts, key::UnspecifiedRole> {
        self.public_key()
    }

    fn decrypt(
        &mut self,
        ciphertext: &Ciphertext,
        plaintext_len: Option<usize>
    ) -> Result<SessionKey> {
        <Key as Decryptor>::decrypt(self, ciphertext, plaintext_len)
    }
}

impl Decryptor for Key {
    fn public(&self) -> &packet::Key<key::PublicParts, key::UnspecifiedRole> {
        self.public_key()
    }

    fn decrypt(
        &mut self,
        ciphertext: &Ciphertext,
        plaintext_len: Option<usize>
    ) -> Result<SessionKey> {
        self.decrypt_ciphertext(ciphertext, plaintext_len)
    }
}

impl Signer for &mut Key {
    fn public(&self) -> &packet::Key<key::PublicParts, key::UnspecifiedRole> {
        self.public_key()
    }

    fn sign(
        &mut self,
        hash_algo: HashAlgorithm,
        digest: &[u8]
    ) -> Result<Signature> {
        <Key as Signer>::sign(self, hash_algo, digest)
    }
}

impl Signer for Key {
    fn public(&self) -> &packet::Key<key::PublicParts, key::UnspecifiedRole> {
        self.public_key()
    }

    fn sign(
        &mut self,
        hash_algo: HashAlgorithm,
        digest: &[u8]
    ) -> Result<Signature> {
        self.sign_message(hash_algo, digest)
    }
}

#[cfg(test)]
mod tests {
    use test_log::test;

    use super::*;

    use anyhow::Context as _;

    use openpgp::Cert;
    use openpgp::cert::CertBuilder;
    use openpgp::PacketPile;
    use openpgp::packet::PKESK;
    use openpgp::packet::Packet;
    use openpgp::packet::SEIP;
    use openpgp::packet::signature::SignatureBuilder;
    use openpgp::parse::PacketParserBuilder;
    use openpgp::parse::PacketParserResult;
    use openpgp::parse::Parse;
    use openpgp::types::SignatureType;

    use sequoia_directories::Home;
    use sequoia_directories::Component;

    use testdata::password;
    use testdata::simple;

    /// Tries to decrypt the message using the key store.
    ///
    /// Iterates over each of the PKESKs and tries to decrypt them
    /// using a key on the keystore.  If the key is in recipients and
    /// has a password, the key is also unlocked, if needed.
    ///
    /// If assert_exact is true, asserts that exactly the recipients
    /// in `recipients` decrypt the message.  That is, if there are
    /// two recipients, then both must decrypt the message, and no
    /// others.
    ///
    /// Returns the keys that decrypted the message and whether they
    /// were in `recipients`.
    fn try_decrypt(ks: &mut Keystore, msg: &[u8],
                   recipients: &[(Fingerprint, Option<&str>)],
                   assert_exact: bool)
        -> Result<Vec<(Fingerprint, bool)>>
    {
        let mut results: Vec<(Fingerprint, bool)> = Vec::new();

        let mut saw_pkesk = false;
        let mut ppr = PacketParserBuilder::from_bytes(msg)
            .expect("PacketParserBuilder")
            .buffer_unread_content()
            .build()
            .context("Parsing message")?;

        while let PacketParserResult::Some(pp) = ppr {
            // Get the packet out of the parser and start parsing
            // the next packet, recursing.
            let (packet, next_ppr) = pp.recurse()?;
            ppr = next_ppr;

            if let Packet::PKESK(pkesk) = packet {
                saw_pkesk = true;

                let recipient = pkesk.recipient();

                let should_decrypt = recipients.iter()
                    .find(|(rcpv, _password)| {
                        recipient.as_ref()
                            .map(|r| r.aliases(KeyHandle::from(rcpv)))
                            .unwrap_or(false)
                    });

                let recipient = if let Some(r) = recipient {
                    r
                } else {
                    continue;
                };

                let kh = match ks.find_key(recipient.clone()) {
                    Ok(kh) => kh,
                    Err(err) => {
                        if should_decrypt.is_some() {
                            eprintln!("{} should decrypt message, \
                                       but isn't on the key store: {}",
                                      recipient, err);
                        }
                        continue;
                    }
                };
                let mut kh = if let Some(kh) = kh.into_iter().next() {
                    kh
                } else {
                    continue;
                };
                let fpr = kh.fingerprint();
                assert!(recipient.aliases(KeyHandle::from(&fpr)));
                let recipient: Fingerprint = fpr;

                let decrypted = pkesk.decrypt(&mut kh, None);

                match (decrypted, should_decrypt) {
                    (Some(_), Some((_, _))) => {
                        eprintln!("PKESK ({}) decrypted as expected.",
                                  recipient);
                        results.push((recipient.clone(), true));
                    }
                    (Some(_), None) => {
                        eprintln!("PKESK ({}) unexpectedly decrypted!",
                                  recipient);
                        results.push((recipient.clone(), false));
                    }
                    (None, Some((_, password))) => {
                        if let Some(password) = password {
                            if let Err(err) = kh.unlock(Password::from(*password)) {
                                eprintln!("Failed to unlock {}: {}",
                                          recipient, err);
                            } else {
                                if pkesk.decrypt(&mut kh, None).is_some() {
                                    results.push((recipient.clone(), true));
                                } else {
                                    eprintln!("Failed to decrypt PKESK for {} \
                                               after unlocking it",
                                              recipient);
                                }
                            }
                        } else {
                            eprintln!("Failed to unlock PKESK for {}",
                                      recipient);
                        }
                    }
                    (None, None) => {
                        eprintln!("Failed to decrypt PKESK ({}), \
                                   and shouldn't have.",
                                  recipient);
                    }
                }
            }
        }

        // All messages have at least one PKESK.
        assert!(saw_pkesk);

        if assert_exact {
            let mut decryptors = results.iter()
                .map(|(decryptor, expected)| {
                    assert!(expected, "Unexpected decrypted PKESK for {}",
                            decryptor);
                    decryptor
                })
                .collect::<Vec<&Fingerprint>>();
            decryptors.sort();

            let mut recipients: Vec<&Fingerprint>
                = recipients.iter().map(|(r, _)| r).collect();
            recipients.sort();

            assert_eq!(decryptors, recipients);
        }

        Ok(results)
    }

    // A simple test that lists all the keys.
    #[test]
    #[cfg(feature = "softkeys")]
    fn simple_ping() -> Result<()> {
        let home = Home::ephemeral().unwrap();
        eprintln!("Using {}", home);
        let keystore_home = home.data_dir(Component::Keystore);

        let source = simple::dir().join("keystore");
        dircpy::copy_dir(&source, &keystore_home)
            .with_context(|| format!("Copying {:?} to {:?}",
                                     source, keystore_home))?;

        // Start and connect to the keystore.
        let c = Context::configure()
            .ephemeral()
            .home(keystore_home)
            .build()?;
        let mut ks = Keystore::connect(&c)?;

        let mut backends = ks.backends()?;
        eprintln!("Got {} backends", backends.len());
        for backend in &mut backends {
            eprintln!(" - {}", backend.id()?);
        }

        eprintln!("Listing devices");
        let mut saw_softkeys = false;
        for backend in &mut backends {
            let is_softkeys = backend.id().map(|id| id == "softkeys")
                .unwrap_or(false);
            if is_softkeys {
                saw_softkeys = true;
            }

            eprintln!(" - {}", backend.id()?);
            let devices = backend.devices()?;
            if is_softkeys {
                assert_eq!(devices.len(), 3);
            }
            for mut device in devices {
                eprintln!("   - {}", device.id()?);
                let keys = device.keys()?;
                if is_softkeys {
                    assert_eq!(keys.len(), 4);
                }
                for mut key in keys.into_iter() {
                    eprintln!("     - {}", key.id()?);
                }
            }
        }
        assert!(saw_softkeys);

        Ok(())
    }

    // Bash on the relay from multiple threads.
    #[test]
    #[cfg(feature = "softkeys")]
    fn simple_bash() -> Result<()> {
        use std::thread;
        use std::sync::Mutex;

        let home = Home::ephemeral().unwrap();
        eprintln!("Using {}", home);
        let keystore_home = home.data_dir(Component::Keystore);

        let source = simple::dir().join("keystore");
        dircpy::copy_dir(&source, &keystore_home)
            .with_context(|| format!("Copying {:?} to {:?}",
                                     source, keystore_home))?;

        // Start and connect to the keystore.
        let c = Context::configure()
            .ephemeral()
            .home(keystore_home)
            .build()?;
        let ks = Arc::new(Mutex::new(Box::new(Keystore::connect(&c)?)));

        let handles: Vec<_> = (0..10u32).map(|t| {
            let ks = Arc::clone(&ks);
            thread::spawn(move || -> Result<()> {
                for _ in 0..10 {
                    thread::yield_now();

                    let mut ks = ks.lock().unwrap();
                    let backends: Vec<Backend> = ks.backends()?;
                    // Drop ks to increase concurrency.
                    drop(ks);

                    let mut saw_softkeys = false;
                    for (b, mut backend) in &mut backends.into_iter().enumerate() {
                        let is_softkeys = backend.id().map(|id| id == "softkeys")
                            .unwrap_or(false);
                        if is_softkeys {
                            saw_softkeys = true;
                        }

                        // Don't just use a capability once and then throw it
                        // away.
                        for _ in 1..3 {
                            eprintln!(" {}.{}. {}", t, b, backend.id()?);
                            let devices = backend.devices()?;
                            if is_softkeys {
                                assert_eq!(devices.len(), 3);
                            }
                            for (d, mut device) in devices.into_iter().enumerate() {
                                for _ in 1..3 {
                                    eprintln!("   {}.{}.{}. {}",
                                              t, b, d, device.id()?);
                                    let keys = device.keys()?;
                                    if is_softkeys {
                                        assert_eq!(keys.len(), 4);
                                    }
                                    for (k, mut key) in keys.into_iter().enumerate() {
                                        eprintln!("     {}.{}.{}.{}. {}",
                                                  t, b, d, k, key.id()?);
                                    }
                                }
                            }
                        }
                    }
                    assert!(saw_softkeys);
                }

                Ok(())
            })
        }).collect();

        for h in handles.into_iter() {
            h.join().unwrap().expect("worked");
        }

        Ok(())
    }

    // Test Keystore::decrypt using the simple keystore.
    #[test]
    #[cfg(feature = "softkeys")]
    fn simple_keystore_decrypt() -> Result<()> {
        let home = Home::ephemeral().unwrap();
        eprintln!("Using {}", home);
        let keystore_home = home.data_dir(Component::Keystore);

        let source = simple::dir().join("keystore");
        dircpy::copy_dir(&source, &keystore_home)
            .with_context(|| format!("Copying {:?} to {:?}",
                                     source, keystore_home))?;

        // Start and connect to the keystore.
        let c = Context::configure()
            .ephemeral()
            .home(keystore_home)
            .build()?;
        let mut ks = Keystore::connect(&c)?;

        // Run the tests.
        let mut bad = 0;
        for msg in simple::msgs() {
            eprintln!("Decrypting {}", msg.filename);

            let mut pkesks = Vec::new();

            let mut decrypted = false;
            let mut ppr = PacketParserBuilder::from_bytes(
                    testdata::file(msg.filename))?
                .buffer_unread_content()
                .build()?;
            while let PacketParserResult::Some(mut pp) = ppr {
                if let Packet::SEIP(_) = pp.packet {
                    match ks.decrypt(&pkesks[..]) {
                        // Decrypted, but shouldn't have.
                        Ok(_) if msg.recipients.is_empty() => {
                            eprintln!("Decrypted, but should have failed");
                            bad += 1;
                        }
                        // Decrypted, and should have.
                        Ok((i, fpr, algo, sk)) => {
                            let fpr = KeyHandle::from(fpr);

                            // Make sure we used an expected PKESK.
                            if ! msg.recipients.iter().any(|&r| {
                                KeyHandle::from(r).aliases(&fpr)
                            })
                            {
                                eprintln!("fpr ({:?}) is not an expected \
                                           recipient ({})",
                                          fpr,
                                          msg.recipients
                                              .iter()
                                              .map(|r| format!("{:?}", r))
                                              .collect::<Vec<String>>()
                                              .join(", "));
                                bad += 1;
                                break;
                            }

                            // Make sure the fpr and the pkesk match.
                            if ! pkesks[i].recipient()
                                .map(|r| fpr.aliases(r))
                                .unwrap_or(true)
                            {
                                eprintln!("fpr ({}) and pkesk ({}) \
                                           don't match",
                                          fpr, pkesks[i].recipient().unwrap());
                                bad += 1;
                                break;
                            }

                            // Decrypt the SEIP.
                            match pp.decrypt(algo, &sk) {
                                Ok(()) => {
                                    decrypted = true;
                                }
                                Err(err) => {
                                    eprintln!("Failed to decrypt SEIP: {}",
                                              err);
                                    bad += 1;
                                    break;
                                }
                            }
                        }

                        // Can't decrypt, as expected.
                        Err(_) if msg.recipients.is_empty() => break,
                        // Can't decrypt, and that's a problem.
                        Err(err) => {
                            eprintln!("Failed to decrypt: {}", err);
                            bad += 1;
                            break;
                        }
                    }
                }

                // Get the packet out of the parser and start parsing
                // the next packet, recursing.
                let (packet, next_ppr) = pp.recurse()?;
                ppr = next_ppr;

                #[allow(deprecated)]
                match packet {
                    Packet::PKESK(pkesk) if ! decrypted => pkesks.push(pkesk),
                    Packet::SEIP(_) if decrypted => (),
                    Packet::MDC(_) if decrypted => (),
                    Packet::CompressedData(_) if decrypted => (),
                    Packet::Literal(lit) if decrypted => {
                        if msg.content.as_bytes() != lit.body() {
                            eprintln!("Decrypted plaintext does not match \
                                       expected plaintext:\n    got: {:?}\n\
                                       expected: {:?}",
                                      String::from_utf8_lossy(lit.body()),
                                      msg.content);
                            bad += 1;
                            break;
                        }
                    }
                    p => unreachable!("Unexpected packet: {}.", p.tag()),
                }
            }
        }

        if bad > 0 {
            panic!("{} tests failed", bad);
        }

        Ok(())
    }

    // Test Key::decrypt_pkesk using the simple keystore.
    #[test]
    #[cfg(feature = "softkeys")]
    fn simple_key_decrypt_pkesk() -> Result<()> {
        let home = Home::ephemeral().unwrap();
        eprintln!("Using {}", home);
        let keystore_home = home.data_dir(Component::Keystore);

        let source = simple::dir().join("keystore");
        dircpy::copy_dir(&source, &keystore_home)
            .with_context(|| format!("Copying {:?} to {:?}",
                                     source, keystore_home))?;

        // Start and connect to the keystore.
        let c = Context::configure()
            .ephemeral()
            .home(keystore_home)
            .build()?;
        let mut ks = Keystore::connect(&c)?;

        // We also try to decrypt with Alice's and Carol's primary
        // keys to make sure that that fails.
        let alice_pri = ks.find_key(KeyHandle::from(&simple::fp().alice_pri))
            .expect("keystore is up");
        // In the simple keystore, keys are not repeated.
        assert!(alice_pri.len() <= 1);
        let mut alice_pri = if let Some(kh) = alice_pri.into_iter().next() {
            kh
        } else {
            panic!("Alice's primary key is not present on the key store.");
        };

        let carol_pri = ks.find_key(KeyHandle::from(&simple::fp().carol_pri))
            .expect("keystore is up");
        // In the simple keystore, keys are not repeated.
        assert!(carol_pri.len() <= 1);
        let mut carol_pri = if let Some(kh) = carol_pri.into_iter().next() {
            kh
        } else {
            panic!("Carol's primary key is not present on the key store.");
        };


        // Run the tests.
        let mut bad = 0;
        for msg in simple::msgs() {
            eprintln!("Decrypting {}", msg.filename);

            let mut saw_pkesk = false;
            let mut ppr = PacketParserBuilder::from_bytes(
                    testdata::file(msg.filename))?
                .buffer_unread_content()
                .build()?;
            while let PacketParserResult::Some(pp) = ppr {
                // Get the packet out of the parser and start parsing
                // the next packet, recursing.
                let (packet, next_ppr) = pp.recurse()?;
                ppr = next_ppr;

                if let Packet::PKESK(pkesk) = packet {
                    saw_pkesk = true;

                    let recip = pkesk.recipient();

                    let should_decrypt = msg.recipients
                        .iter()
                        .any(|&r| {
                            recip.as_ref()
                                .map(|recip| recip.aliases(&KeyHandle::from(r)))
                                .unwrap_or(false)
                        });

                    let recip = if let Some(r) = recip {
                        r
                    } else {
                        continue;
                    };

                    let kh = ks.find_key(recip.clone())?;
                    // In the simple keystore, keys are not repeated.
                    assert!(kh.len() <= 1);
                    let mut kh = if let Some(kh) = kh.into_iter().next() {
                        kh
                    } else {
                        // No key corresponding to recip in the key
                        // store.
                        if should_decrypt {
                            eprintln!("Should decrypt PKESK ({}), \
                                       but there is no key for it on the \
                                       key store.",
                                      recip);
                            bad += 1;
                        }
                        continue;
                    };

                    let decrypted = pkesk.decrypt(&mut kh, None);

                    match (decrypted, should_decrypt) {
                        (Some(_), true) => {
                            eprintln!("PKESK ({}) decrypted as expected.",
                                      recip);
                        }
                        (Some(_), false) => {
                            eprintln!("PKESK ({}) unexpectedly decrypted!",
                                      recip);
                            bad += 1;
                        }
                        (None, true) => {
                            eprintln!("Failed to decrypt PKESK ({}), \
                                       but should have!",
                                      recip);
                            bad += 1;
                        }
                        (None, false) => {
                            eprintln!("Failed to decrypt PKESK ({}), \
                                       and shouldn't have.",
                                      recip);
                        }
                    }

                    // Make sure we can't decrypt using alice's or
                    // carol's primary keys.
                    if pkesk.decrypt(&mut alice_pri, None).is_some() {
                        eprintln!("Unexpected decrypted message using \
                                   alice's primary key");
                        bad += 1;
                    }
                    if pkesk.decrypt(&mut carol_pri, None).is_some() {
                        eprintln!("Unexpected decrypted message using \
                                   carol's primary key");
                        bad += 1;
                    }
                }
            }

            // All messages have at least one PKESK.
            assert!(saw_pkesk);
        }

        if bad > 0 {
            panic!("{} tests failed", bad);
        }

        Ok(())
    }

    #[test]
    #[cfg(feature = "softkeys")]
    fn simple_key_sign() -> Result<()> {
        let home = Home::ephemeral().unwrap();
        eprintln!("Using {}", home);
        let keystore_home = home.data_dir(Component::Keystore);

        let source = simple::dir().join("keystore");
        dircpy::copy_dir(&source, &keystore_home)
            .with_context(|| format!("Copying {:?} to {:?}",
                                     source, keystore_home))?;

        let certs = [
            testdata::file("simple/keystore/softkeys/alice.pgp"),
            testdata::file("simple/keystore/softkeys/bob.pgp"),
            testdata::file("simple/keystore/softkeys/carol.pgp")
        ];
        let certs: Vec<Cert> = certs.iter()
            .map(|cert| {
                Cert::from_bytes(cert)
            })
            .collect::<Result<Vec<Cert>>>()?;
        let lookup = |fpr: Fingerprint| {
            certs
                .iter()
                .flat_map(|cert| cert.keys())
                .find(|k| {
                    k.key().fingerprint() == fpr
                })
        };

        // Start and connect to the keystore.
        let c = Context::configure()
            .ephemeral()
            .home(keystore_home)
            .build()?;
        let mut ks = Keystore::connect(&c)?;

        let msg = b"hi?!";

        let mut bad = 0;

        let mut backends = ks.backends()?;

        let mut saw_softkeys = false;
        for backend in &mut backends {
            let is_softkeys = backend.id().map(|id| id == "softkeys")
                .unwrap_or(false);
            if is_softkeys {
                saw_softkeys = true;
            } else {
                continue;
            }

            let devices = backend.devices()?;
            assert_eq!(devices.len(), 3);

            for mut device in devices {
                let keys = device.keys()?;
                assert_eq!(keys.len(), 4);

                for mut key in keys.into_iter() {
                    let ka = lookup(key.fingerprint())
                        .expect("have corresponding certificate");

                    eprintln!("  - {} ({}, {})",
                              ka.key().fingerprint(),
                              ka
                                  .cert()
                                  .userids()
                                  .next()
                                  .map(|ua| {
                                      String::from_utf8_lossy(ua.userid().value())
                                          .into_owned()
                                  })
                                  .unwrap_or_else(|| {
                                      String::from("<no user ids>")
                                  }),
                              ka.key().pk_algo());

                    // Note: we don't consider keyflags, because the
                    // key store can't either (even if a backend has
                    // the whole cert, it may not be up to date).
                    let bad_key = ! ka.key().pk_algo().for_signing();

                    let sig = SignatureBuilder::new(SignatureType::Binary);

                    match sig.sign_message(&mut key, msg) {
                        Ok(sig) => {
                            if bad_key {
                                eprintln!("Key created signature, \
                                           but shouldn't have.");
                                bad += 1;
                                continue;
                            }

                            // Make sure the signature checks out.
                            if let Err(err) = sig.clone()
                                .verify_message(ka.key(), msg)
                            {
                                eprintln!("Failed to verify signature, \
                                           but should have: {}", err);
                                bad += 1;
                                continue;
                            }
                        }
                        Err(err) => {
                            if ! bad_key {
                                eprintln!("Key failed to create signature, \
                                           but should have: {}",
                                          err);
                                bad += 1;
                                continue;
                            }
                        }
                    }
                }
            }
        }
        assert!(saw_softkeys);

        if bad > 0 {
            panic!("{} tests failed", bad);
        }

        Ok(())
    }

    // Test Key::decrypt_pkesk using the password keystore.
    #[test]
    #[cfg(feature = "softkeys")]
    fn password_key_decrypt_pkesk() -> Result<()> {
        let _ = env_logger::Builder::from_default_env().try_init();

        let home = Home::ephemeral().unwrap();
        eprintln!("Using {}", home);
        let keystore_home = home.data_dir(Component::Keystore);

        let source = password::dir().join("keystore");
        dircpy::copy_dir(&source, &keystore_home)
            .with_context(|| format!("Copying {:?} to {:?}",
                                     source, keystore_home))?;

        // Start and connect to the keystore.
        let c = Context::configure()
            .ephemeral()
            .home(keystore_home)
            .build()?;
        let mut ks = Keystore::connect(&c)?;

        // Run the tests.
        for (msg, pw) in password::msgs() {
            eprintln!("Decrypting {}", msg.filename);

            let content = testdata::file(msg.filename);

            let recipients = msg.recipients.iter().map(|&r| (r.clone(), pw))
                .collect::<Vec<(Fingerprint, Option<&str>)>>();
            try_decrypt(
                &mut ks, content, &recipients[..], true)
                .unwrap();
        }

        Ok(())
    }

    // Test Key::decrypt_pkesk using the password keystore.
    #[test]
    #[cfg(feature = "softkeys")]
    fn password_key_decrypt_pkesk2() -> Result<()> {
        let home = Home::ephemeral().unwrap();
        eprintln!("Using {}", home);
        let keystore_home = home.data_dir(Component::Keystore);

        let source = password::dir().join("keystore");
        dircpy::copy_dir(&source, &keystore_home)
            .with_context(|| format!("Copying {:?} to {:?}",
                                     source, keystore_home))?;

        // Start and connect to the keystore.
        let c = Context::configure()
            .ephemeral()
            .home(keystore_home)
            .build()?;
        let mut ks = Keystore::connect(&c)?;

        for (msg, password) in testdata::password::msgs() {
            eprintln!("{}", msg.filename);

            let pp = PacketPile::from_bytes(testdata::file(msg.filename))
                .expect("valid OpenPGP message");

            pp.children().enumerate().for_each(|(i, p)| {
                eprintln!("  {}: {}", i, p.tag());
            });

            let pkesks: Vec<PKESK> = pp.children()
                .filter_map(|p| {
                    match p {
                        Packet::PKESK(p) => Some(p.clone()),
                        _ => None,
                    }
                })
                .collect();
            assert!(pkesks.len() > 0);

            let seip: Vec<&SEIP> = pp.children()
                .filter_map(|p| {
                    match p {
                        Packet::SEIP(p) => Some(p),
                        _ => None,
                    }
                })
                .collect();
            assert!(seip.len() == 1);

            match (ks.decrypt(&pkesks), password) {
                (Ok(_), None) => {
                    // Decrypted and no password is required.  Success.
                }
                (Ok(_), Some(_password)) => {
                    panic!("Decrypted, but a password should be required.");
                }
                (Err(err), None) => {
                    panic!("Failed to decrypt, but a password isn't required: {}.",
                           err);
                }
                (Err(mut err), Some(password)) => {
                    let keys = if let Some(Error::InaccessibleDecryptionKey(keys))
                        = err.downcast_mut()
                    {
                        keys
                    } else {
                        panic!("Unexpected error decrypting message: {}",
                               err);
                    };

                    // There's only one.
                    assert_eq!(keys.len(), 1);
                    let key = &mut keys[0];
                    let pkesk = key.pkesk().clone();

                    // Try to decryt it; it should still be locked.
                    let r = pkesk.decrypt(key.key_mut(), None);
                    assert!(r.is_none());

                    // Unlock it and try again.
                    key.key_mut().unlock(Password::from(password))
                        .expect("correct password");

                    let r = pkesk.decrypt(key.key_mut(), None);
                    assert!(r.is_some());
                }
            }
        }

        Ok(())
    }

    // Test Key::import and Key::export.
    #[test]
    #[cfg(feature = "softkeys")]
    fn import_export() -> Result<()> {
        let home = Home::ephemeral().unwrap();
        eprintln!("Using {}", home);
        let keystore_home = home.data_dir(Component::Keystore);

        // Start and connect to the keystore.
        let c = Context::configure()
            .ephemeral()
            .home(keystore_home)
            .build()?;
        let mut ks = Keystore::connect(&c)?;

        let mut softkeys = None;
        for mut backend in ks.backends()?.into_iter() {
            if backend.id().expect("ok") == "softkeys" {
                softkeys = Some(backend);
                break;
            }
        }
        let mut softkeys = softkeys.expect("have softkeys backend");

        use openpgp::cert::CipherSuite::*;
        for cs in [ Cv25519, RSA3k, P256, P384, P521, RSA2k, RSA4k ] {
            if cs.is_supported().is_err() {
                continue;
            }

            eprintln!("Testing a {:?} cert", cs);

            let (cert, _rev) = CertBuilder::general_purpose(
                Some("alice"))
                .set_cipher_suite(cs)
                .generate()?;

            softkeys.import(&cert).expect("can import");

            for key in cert.keys() {
                eprintln!("Exporting {}", key.key().fingerprint());

                let key = key.parts_into_secret().expect("has secret");

                let remote = ks.find_key(key.key().key_handle()).expect("have key");
                assert_eq!(remote.len(), 1, "only one key under this name");
                let mut remote = remote.into_iter().next().unwrap();
                assert_eq!(remote.fingerprint(), key.key().fingerprint());

                let export = remote.export().expect("can export");
                assert_eq!(&export, key.key());
            }
        }

        Ok(())
    }


    // Test Key::password_source.
    #[test]
    #[cfg(feature = "softkeys")]
    fn password_source() -> Result<()> {
        let home = Home::ephemeral().unwrap();
        eprintln!("Using {}", home);
        let keystore_home = home.data_dir(Component::Keystore);

        // Start and connect to the keystore.
        let c = Context::configure()
            .ephemeral()
            .home(keystore_home)
            .build()?;
        let mut ks = Keystore::connect(&c)?;

        let mut softkeys = None;
        for mut backend in ks.backends()?.into_iter() {
            if backend.id().expect("ok") == "softkeys" {
                softkeys = Some(backend);
                break;
            }
        }
        let mut softkeys = softkeys.expect("have softkeys backend");

        // This is a pretty naive test: we just make sure the backend
        // returns success.
        for password in [false, true] {
            let mut builder = CertBuilder::general_purpose(Some("alice"));
            if password {
                builder = builder.set_password(Some("foo".into()));
            }
            let (cert, _rev) = builder.generate()?;

            let result = softkeys.import(&cert).expect("can import");
            assert_eq!(result.len(), cert.keys().count());
            for (_import_status, mut key) in result.into_iter() {
                match key.locked() {
                    Ok(Protection::Unlocked) => {
                        if password {
                            panic!("Key is password protected and should be locked, \
                                    but is unlocked?");
                        }
                    }
                    Ok(other) => {
                        if ! password {
                            panic!("Key is not password protected and shouldn't \
                                    be locked, but got: {:?}",
                                   other);
                        }
                    }
                    Err(err) => {
                        panic!("Getting locked status: {}", err);
                    }
                }
                assert!(key.password_source().is_ok());
            }
        }

        Ok(())
    }

    // Test Key::change_password
    #[test]
    #[cfg(feature = "softkeys")]
    fn change_password() -> Result<()> {
        let _ = env_logger::Builder::from_default_env().try_init();

        let home = Home::ephemeral().unwrap();
        eprintln!("Using {}", home);
        let keystore_home = home.data_dir(Component::Keystore);

        let source = password::dir().join("keystore");
        dircpy::copy_dir(&source, &keystore_home)
            .with_context(|| format!("Copying {:?} to {:?}",
                                     source, keystore_home))?;

        // Start and connect to the keystore.
        let c = Context::configure()
            .ephemeral()
            .home(keystore_home)
            .build()?;
        let mut ks = Keystore::connect(&c)?;

        // Run the tests.
        for (msg, pw) in password::msgs() {
            eprintln!("Decrypting {}", msg.filename);

            let content = testdata::file(msg.filename);

            let new_password = "a NEW pa$$word";

            let recipients = msg.recipients.iter().map(|&r| (r.clone(), pw))
                .collect::<Vec<(Fingerprint, Option<&str>)>>();

            try_decrypt(
                &mut ks, content, &recipients[..], true)
                .unwrap();

            // Change the passwords.
            let recipients = msg.recipients.iter()
                .map(|&r| {
                    let kh = ks.find_key(KeyHandle::from(r))
                        .expect(&format!("Have key {}", r));
                    let mut kh = if let Some(kh) = kh.into_iter().next() {
                        kh
                    } else {
                        panic!("Should have a key for {}", r);
                    };

                    if let Some(pw) = pw {
                        if let Protection::Password(_hint)
                            = kh.locked().expect("locked")
                        {
                            kh.unlock(Password::from(pw))
                                .expect("Can unlock locked key");
                        }
                    }
                    kh.change_password(Some(&Password::from(new_password)))
                        .expect("can change password");

                    (r.clone(), Some(new_password))
                })
                .collect::<Vec<(Fingerprint, Option<&str>)>>();

            try_decrypt(
                &mut ks, content, &recipients[..], true)
                .unwrap();
        }


        Ok(())
    }
}
