use std::{
fmt,
io,
time::SystemTime,
};
use super::{
Error,
ParseError,
Load,
Password,
Result,
SOP,
Save,
SessionKey,
};
pub trait Version<'s> {
fn frontend(&self) -> Result<VersionInfo>;
fn backend(&self) -> Result<VersionInfo>;
fn extended(&self) -> Result<String>;
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct VersionInfo {
pub name: String,
pub version: String,
}
impl fmt::Display for VersionInfo {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} {}", self.name, self.version)
}
}
pub trait GenerateKey<'s, S: SOP<'s>, Keys: Load<'s, S> + Save> {
fn list_profiles(&self) -> Vec<(String, String)> {
vec![]
}
fn profile(self: Box<Self>, _profile: &str)
-> Result<Box<dyn GenerateKey<'s, S, Keys> + 's>> {
Err(Error::UnsupportedProfile)
}
fn signing_only(self: Box<Self>) -> Box<dyn GenerateKey<'s, S, Keys> + 's>;
fn with_key_password(self: Box<Self>, password: Password)
-> Result<Box<dyn GenerateKey<'s, S, Keys> + 's>>;
fn userid(self: Box<Self>, userid: &str) -> Box<dyn GenerateKey<'s, S, Keys> + 's>;
fn generate(self: Box<Self>) -> Result<Keys>;
}
pub trait ChangeKeyPassword<'s, S: SOP<'s>, Keys: Load<'s, S>> {
fn new_key_password(self: Box<Self>, password: Password)
-> Result<Box<dyn ChangeKeyPassword<'s, S, Keys> + 's>>;
fn old_key_password(self: Box<Self>, password: Password)
-> Result<Box<dyn ChangeKeyPassword<'s, S, Keys> + 's>>;
fn keys(self: Box<Self>, keys: &Keys) -> Result<Keys>;
}
pub trait RevokeKey<'s, S: SOP<'s>, Certs: Save, Keys: Load<'s, S>> {
fn with_key_password(self: Box<Self>, password: Password)
-> Result<Box<dyn RevokeKey<'s, S, Certs, Keys> + 's>>;
fn keys(self: Box<Self>, keys: &Keys) -> Result<Certs>;
}
pub trait ExtractCert<'s, S: SOP<'s>, Certs: Save, Keys: Load<'s, S>> {
fn keys(self: Box<Self>, keys: &Keys) -> Result<Certs>;
}
pub trait Sign<'s, S: SOP<'s>, Keys: Load<'s, S>, Sigs: Save> {
fn mode(self: Box<Self>, mode: SignAs)
-> Box<dyn Sign<'s, S, Keys, Sigs> + 's>;
fn keys(self: Box<Self>, keys: &Keys)
-> Result<Box<dyn Sign<'s, S, Keys, Sigs> + 's>>;
fn with_key_password(self: Box<Self>, password: Password)
-> Result<Box<dyn Sign<'s, S, Keys, Sigs> + 's>>;
fn data(self: Box<Self>, data: &mut (dyn io::Read + Send + Sync))
-> Result<(Micalg, Sigs)>;
}
pub trait Verify<'s, S: SOP<'s>, Certs: Load<'s, S>, Sigs: Load<'s, S>> {
fn not_before(self: Box<Self>, t: SystemTime)
-> Box<dyn Verify<'s, S, Certs, Sigs> + 's>;
fn not_after(self: Box<Self>, t: SystemTime)
-> Box<dyn Verify<'s, S, Certs, Sigs> + 's>;
fn certs(self: Box<Self>, certs: &Certs)
-> Result<Box<dyn Verify<'s, S, Certs, Sigs> + 's>>;
fn signatures<'sigs>(self: Box<Self>, signatures: &'sigs Sigs)
-> Result<Box<dyn VerifySignatures + 'sigs>>
where
's: 'sigs;
}
pub trait VerifySignatures<'sigs> {
fn data(self: Box<Self>,
data: &mut (dyn io::Read + Send + Sync))
-> Result<Vec<Verification>>;
}
pub trait Encrypt<'s, S: SOP<'s>, Certs: Load<'s, S>, Keys: Load<'s, S>> {
fn no_armor(self: Box<Self>) -> Box<dyn Encrypt<'s, S, Certs, Keys> + 's>;
fn list_profiles(&self) -> Vec<(String, String)> {
vec![]
}
fn profile(self: Box<Self>, _profile: &str)
-> Result<Box<dyn Encrypt<'s, S, Certs, Keys> + 's>> {
Err(Error::UnsupportedProfile)
}
fn mode(self: Box<Self>, mode: EncryptAs) -> Box<dyn Encrypt<'s, S, Certs, Keys> + 's>;
fn sign_with_keys(self: Box<Self>, keys: &Keys)
-> Result<Box<dyn Encrypt<'s, S, Certs, Keys> + 's>>;
fn with_key_password(self: Box<Self>, password: Password)
-> Result<Box<dyn Encrypt<'s, S, Certs, Keys> + 's>>;
fn with_password(self: Box<Self>, password: Password)
-> Result<Box<dyn Encrypt<'s, S, Certs, Keys> + 's>>;
fn with_certs(self: Box<Self>, certs: &Certs)
-> Result<Box<dyn Encrypt<'s, S, Certs, Keys> + 's>>;
fn plaintext<'d>(self: Box<Self>,
plaintext: &'d mut (dyn io::Read + Send + Sync))
-> Result<Box<dyn Ready<Option<SessionKey>> + 'd>>
where
's: 'd;
}
pub trait Decrypt<'s, S: SOP<'s>, Certs: Load<'s, S>, Keys: Load<'s, S>> {
fn verify_not_before(self: Box<Self>,
t: SystemTime)
-> Box<dyn Decrypt<'s, S, Certs, Keys> + 's>;
fn verify_not_after(self: Box<Self>,
t: SystemTime)
-> Box<dyn Decrypt<'s, S, Certs, Keys> + 's>;
fn verify_with_certs(self: Box<Self>,
certs: &Certs)
-> Result<Box<dyn Decrypt<'s, S, Certs, Keys> + 's>>;
fn with_session_key(self: Box<Self>, sk: SessionKey)
-> Result<Box<dyn Decrypt<'s, S, Certs, Keys> + 's>>;
fn with_password(self: Box<Self>, password: Password)
-> Result<Box<dyn Decrypt<'s, S, Certs, Keys> + 's>>;
fn with_keys(self: Box<Self>, key: &Keys)
-> Result<Box<dyn Decrypt<'s, S, Certs, Keys> + 's>>;
fn with_key_password(self: Box<Self>, password: Password)
-> Result<Box<dyn Decrypt<'s, S, Certs, Keys> + 's>>;
fn ciphertext<'d>(self: Box<Self>,
ciphertext: &'d mut (dyn io::Read + Send + Sync))
-> Result<Box<dyn Ready<(Option<SessionKey>,
Vec<Verification>)> + 'd>>
where
's: 'd;
}
pub trait Armor<'s> {
#[deprecated]
fn label(self: Box<Self>, label: ArmorLabel) -> Box<dyn Armor<'s> + 's>;
fn data<'d>(self: Box<Self>, data: &'d mut (dyn io::Read + Send + Sync))
-> Result<Box<dyn Ready + 'd>>
where
's: 'd;
}
pub trait Dearmor<'s> {
fn data<'d>(self: Box<Self>, data: &'d mut (dyn io::Read + Send + Sync))
-> Result<Box<dyn Ready + 'd>>
where
's: 'd;
}
pub trait InlineDetach<'s, Sigs: Save> {
fn message<'d>(self: Box<Self>,
data: &'d mut (dyn io::Read + Send + Sync))
-> Result<Box<dyn Ready<Sigs> + 'd>>
where
's: 'd;
}
pub trait InlineVerify<'s, S: SOP<'s>, Certs: Load<'s, S>> {
fn not_before(self: Box<Self>, t: SystemTime) -> Box<dyn InlineVerify<'s, S, Certs> + 's>;
fn not_after(self: Box<Self>, t: SystemTime) -> Box<dyn InlineVerify<'s, S, Certs> + 's>;
fn certs(self: Box<Self>, certs: &Certs)
-> Result<Box<dyn InlineVerify<'s, S, Certs> + 's>>;
fn message<'d>(self: Box<Self>,
data: &'d mut (dyn io::Read + Send + Sync))
-> Result<Box<dyn Ready<Vec<Verification>> + 'd>>
where
's: 'd;
}
pub trait InlineSign<'s, S: SOP<'s>, Keys: Load<'s, S>> {
fn no_armor(self: Box<Self>) -> Box<dyn InlineSign<'s, S, Keys> + 's>;
fn mode(self: Box<Self>, mode: InlineSignAs) -> Box<dyn InlineSign<'s, S, Keys> + 's>;
fn keys(self: Box<Self>, keys: &Keys)
-> Result<Box<dyn InlineSign<'s, S, Keys> + 's>>;
fn with_key_password(self: Box<Self>, password: Password)
-> Result<Box<dyn InlineSign<'s, S, Keys> + 's>>;
fn data<'d>(self: Box<Self>, data: &'d mut (dyn io::Read + Send + Sync))
-> Result<Box<dyn Ready + 'd>>
where
's: 'd;
}
pub trait Ready<T = ()> {
fn to_writer(self: Box<Self>, sink: &mut (dyn io::Write + Send + Sync))
-> Result<T>;
fn to_vec(self: Box<Self>) -> Result<(T, Vec<u8>)> {
let mut v = Vec::new();
let r = self.to_writer(&mut v)?;
Ok((r, v))
}
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Verification {
creation_time: SystemTime,
signing_key_fingerprint: String,
signing_cert_fingerprint: String,
signature_mode: SignatureMode,
message: Option<String>,
}
#[cfg(feature = "cli")]
impl fmt::Display for Verification {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f,
"{} {} {} {}{}",
chrono::DateTime::<chrono::Utc>::from(self.creation_time())
.format("%Y-%m-%dT%H:%M:%SZ"),
self.signing_key_fingerprint(),
self.signing_cert_fingerprint(),
self.signature_mode(),
if let Some(m) = self.message() {
format!(" {}", m)
} else {
"".into()
})
}
}
impl Verification {
pub fn new<'m, T, K, C, M>(creation_time: T,
signing_key_fingerprint: K,
signing_cert_fingerprint: C,
signature_mode: SignatureMode,
message: M)
-> Result<Verification>
where T: Into<SystemTime>,
K: ToString,
C: ToString,
M: Into<Option<&'m str>>,
{
fn normalize(s: String) -> Result<String> {
Ok(s)
}
let signing_key_fingerprint =
normalize(signing_key_fingerprint.to_string())?;
let signing_cert_fingerprint =
normalize(signing_cert_fingerprint.to_string())?;
Ok(Verification {
creation_time: creation_time.into(),
signing_key_fingerprint,
signing_cert_fingerprint,
signature_mode,
message: message.into().map(Into::into),
})
}
pub fn creation_time(&self) -> SystemTime {
self.creation_time
}
pub fn signing_key_fingerprint(&self) -> &str {
&self.signing_key_fingerprint
}
pub fn signing_cert_fingerprint(&self) -> &str {
&self.signing_cert_fingerprint
}
pub fn signature_mode(&self) -> SignatureMode {
self.signature_mode
}
pub fn message(&self) -> Option<&str> {
self.message.as_ref().map(AsRef::as_ref)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum SignatureMode {
Text,
Binary,
}
#[cfg(feature = "cli")]
impl fmt::Display for SignatureMode {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
SignatureMode::Text => f.write_str("mode:text"),
SignatureMode::Binary => f.write_str("mode:binary"),
}
}
}
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
pub enum SignAs {
Binary,
Text,
}
impl Default for SignAs {
fn default() -> Self {
SignAs::Binary
}
}
impl From<EncryptAs> for SignAs {
fn from(a: EncryptAs) -> Self {
match a {
EncryptAs::Binary => SignAs::Binary,
EncryptAs::Text => SignAs::Text,
}
}
}
impl std::str::FromStr for SignAs {
type Err = ParseError;
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
match s {
"binary" => Ok(SignAs::Binary),
"text" => Ok(SignAs::Text),
_ => Err(ParseError(format!(
"{:?}, expected one of {{binary|text}}", s))),
}
}
}
impl fmt::Display for SignAs {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
SignAs::Binary => f.write_str("binary"),
SignAs::Text => f.write_str("text"),
}
}
}
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
pub enum InlineSignAs {
Binary,
Text,
ClearSigned,
}
impl Default for InlineSignAs {
fn default() -> Self {
InlineSignAs::Binary
}
}
impl std::str::FromStr for InlineSignAs {
type Err = ParseError;
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
match s {
"binary" => Ok(InlineSignAs::Binary),
"text" => Ok(InlineSignAs::Text),
"clearsigned" => Ok(InlineSignAs::ClearSigned),
_ => Err(ParseError(format!(
"{:?}, expected one of {{binary|text|clearsigned}}", s))),
}
}
}
impl fmt::Display for InlineSignAs {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
InlineSignAs::Binary => f.write_str("binary"),
InlineSignAs::Text => f.write_str("text"),
InlineSignAs::ClearSigned => f.write_str("clearsigned"),
}
}
}
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
pub enum EncryptAs {
Binary,
Text,
}
impl Default for EncryptAs {
fn default() -> Self {
EncryptAs::Binary
}
}
impl std::str::FromStr for EncryptAs {
type Err = ParseError;
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
match s {
"binary" => Ok(EncryptAs::Binary),
"text" => Ok(EncryptAs::Text),
_ => Err(ParseError(format!(
"{}, expected one of {{binary|text}}", s))),
}
}
}
impl fmt::Display for EncryptAs {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
EncryptAs::Binary => f.write_str("binary"),
EncryptAs::Text => f.write_str("text"),
}
}
}
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
pub enum ArmorLabel {
Auto,
Sig,
Key,
Cert,
Message,
}
impl Default for ArmorLabel {
fn default() -> Self {
ArmorLabel::Auto
}
}
impl std::str::FromStr for ArmorLabel {
type Err = ParseError;
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
match s {
"auto" => Ok(ArmorLabel::Auto),
"sig" => Ok(ArmorLabel::Sig),
"key" => Ok(ArmorLabel::Key),
"cert" => Ok(ArmorLabel::Cert),
"message" => Ok(ArmorLabel::Message),
_ => Err(ParseError(format!(
"{:?}, expected one of \
{{auto|sig|key|cert|message}}", s))),
}
}
}
impl fmt::Display for ArmorLabel {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
ArmorLabel::Auto => f.write_str("auto"),
ArmorLabel::Sig => f.write_str("sig"),
ArmorLabel::Key => f.write_str("key"),
ArmorLabel::Cert => f.write_str("cert"),
ArmorLabel::Message => f.write_str("message"),
}
}
}
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub enum Micalg {
MD5,
SHA1,
RipeMD,
SHA256,
SHA384,
SHA512,
SHA224,
Unknown(String),
}
impl From<u8> for Micalg {
fn from(o: u8) -> Self {
match o {
1 => Micalg::MD5,
2 => Micalg::SHA1,
3 => Micalg::RipeMD,
8 => Micalg::SHA256,
9 => Micalg::SHA384,
10 => Micalg::SHA512,
11 => Micalg::SHA224,
u => Micalg::Unknown(format!("unknown-algo-{}", u)),
}
}
}
impl fmt::Display for Micalg {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("pgp-")?;
match self {
Micalg::MD5 => f.write_str("md5"),
Micalg::SHA1 => f.write_str("sha1"),
Micalg::RipeMD => f.write_str("ripemd160"),
Micalg::SHA256 => f.write_str("sha256"),
Micalg::SHA384 => f.write_str("sha384"),
Micalg::SHA512 => f.write_str("sha512"),
Micalg::SHA224 => f.write_str("sha224"),
Micalg::Unknown(a) => f.write_str(&a.to_lowercase()),
}
}
}