//! An implementation of the Stateless OpenPGP Command Line Interface
//! using Sequoia.
//!
//! This implements a subset of the [Stateless OpenPGP Command Line
//! Interface] using the Sequoia OpenPGP implementation.
//!
//! [Stateless OpenPGP Command Line Interface]: https://datatracker.ietf.org/doc/draft-dkg-openpgp-stateless-cli/
use std::collections::HashMap;
use std::convert::TryFrom;
use std::io::{self, Read, Write};
use anyhow::Context;
use structopt::StructOpt;
use sequoia_openpgp as openpgp;
use openpgp::{
armor,
Cert,
Fingerprint,
KeyID,
KeyHandle,
Packet,
};
use openpgp::crypto::{self, Password, SessionKey};
use openpgp::fmt::hex;
use openpgp::types::*;
use openpgp::packet::{key, signature, Key, PKESK, SKESK};
use openpgp::parse::{Parse, PacketParser, PacketParserResult, stream::*};
use openpgp::policy::Policy;
use openpgp::cert::prelude::*;
use openpgp::serialize::{
Serialize,
stream::*,
stream::padding::Padder,
};
use openpgp::policy::StandardPolicy;
mod errors;
use errors::{Error, print_error_chain};
type Result<T> = anyhow::Result<T>;
mod cli;
use cli::{
SOP, SignAs, EncryptAs, ArmorKind,
load_file, create_file, load_certs, frob_passwords,
};
mod dates;
fn main() {
use std::process::exit;
match real_main() {
Ok(()) => (),
Err(e) => {
print_error_chain(&e);
if let Ok(e) = e.downcast::<Error>() {
exit(e.into())
}
exit(1);
},
}
}
fn real_main() -> Result<()> {
let p = &StandardPolicy::default();
match SOP::from_args() {
SOP::Version {} => {
println!("Sequoia-SOP {}", openpgp::VERSION);
},
SOP::GenerateKey { no_armor, mut userids, } => {
userids.reverse();
let mut builder = CertBuilder::general_purpose(None, userids.pop());
for u in userids {
builder = builder.add_userid(u);
}
let (cert, _) = builder.generate()?;
let mut sink = stdout(no_armor, armor::Kind::SecretKey)?;
cert.as_tsk().serialize(&mut sink)?;
sink.finalize()?;
},
SOP::ExtractCert { no_armor, } => {
let cert = Cert::from_reader(&mut io::stdin())?;
let mut sink = stdout(no_armor, armor::Kind::PublicKey)?;
cert.serialize(&mut sink)?;
sink.finalize()?;
},
SOP::Sign { no_armor, as_, keys, } => {
let mut data = Vec::new();
io::stdin().read_to_end(&mut data)?;
if let SignAs::Text = as_ {
if let Err(e) = std::str::from_utf8(&data) {
return Err(anyhow::Error::from(Error::