use anyhow::Context as _;
use std::borrow::Borrow;
use std::cmp::Ordering;
use std::collections::{HashMap, HashSet};
use std::fs::File;
use std::io::{self, Write};
use std::time::SystemTime;
use sequoia_net::pks;
use sequoia_openpgp as openpgp;
use crate::openpgp::{
armor,
};
use crate::openpgp::types::{
CompressionAlgorithm,
};
use crate::openpgp::cert::prelude::*;
use crate::openpgp::crypto;
use crate::openpgp::{Cert, KeyID, Result};
use crate::openpgp::packet::prelude::*;
use crate::openpgp::parse::{
Parse,
PacketParserResult,
};
use crate::openpgp::parse::stream::*;
use crate::openpgp::serialize::stream::{
Message, Signer, LiteralWriter, Encryptor, Recipient,
Compressor,
padding::Padder,
};
use crate::openpgp::policy::Policy;
use crate::openpgp::types::KeyFlags;
use crate::openpgp::types::RevocationStatus;
use crate::{
Config,
parse_armor_kind,
};
#[cfg(feature = "autocrypt")]
pub mod autocrypt;
pub mod decrypt;
pub use self::decrypt::decrypt;
pub mod sign;
pub use self::sign::sign;
pub mod revoke;
pub mod dump;
pub use self::dump::dump;
mod inspect;
pub use self::inspect::inspect;
pub mod key;
pub mod merge_signatures;
pub use self::merge_signatures::merge_signatures;
pub mod keyring;
pub mod net;
pub mod certify;
/// Returns suitable signing keys from a given list of Certs.
fn get_keys<C>(certs: &[C], p: &dyn Policy,
private_key_store: Option<&str>,
timestamp: Option<SystemTime>,
flags: KeyFlags)
-> Result<Vec<Box<dyn crypto::Signer + Send + Sync>>>
where C: Borrow<Cert>
{
let mut bad = Vec::new();
let mut keys: Vec<Box<dyn crypto::Signer + Send + Sync>> = Vec::new();
'next_cert: for tsk in certs {
let tsk = tsk.borrow();
let vc = match tsk.with_policy(p, timestamp) {
Ok(vc) => vc,
Err(err) => {
return Err(
err.context(format!("Found no suitable key on {}", tsk)));
}
};
for ka in vc.keys().key_flags(flags.clone()) {
let bad_ = [
matches!(ka.alive(), Err(_)),
matches!(ka.revocation_status(), RevocationStatus::Revoked(_)),
! ka.pk_algo().is_supported(),
];
if bad_.iter().any(|x| *x) {
bad.push((ka.fingerprint(), bad_));
continue;
}
let key = ka.key();
if let Some(secret) = key.optional_secret() {
let unencrypted = match secret {
SecretKeyMaterial::Encrypted(ref e) => {
let password = rpassword::read_password_from_tty(Some(
&format!("Please enter password to decrypt {}/{}: ",
tsk, key)))
.context("Reading password from tty")?;
e.decrypt(key.pk_algo(), &password.into())
.expect("decryption failed")
},
SecretKeyMaterial::Unencrypted(ref u) => u.clone(),
};
keys.push(Box::new(crypto::KeyPair::new(key.clone(), unencrypted)
.unwrap()));
continue 'next_cert;
} else if let Some(private_key_store) = private_key_store {