diff options
author | Justus Winter <justus@sequoia-pgp.org> | 2018-08-15 16:29:46 +0200 |
---|---|---|
committer | Justus Winter <justus@sequoia-pgp.org> | 2018-08-15 16:34:49 +0200 |
commit | 10276b9e442596849fb0e3742408c26f621b9162 (patch) | |
tree | 569e442fd54adc15f5743f038fb341ea60f6cefc /tool | |
parent | 8ad003bf46987a1adee5bbd3c1c8370544be2147 (diff) |
tool: Implement sq sign.
- Fixes #17.
Diffstat (limited to 'tool')
-rw-r--r-- | tool/src/commands.rs | 33 | ||||
-rw-r--r-- | tool/src/sq-usage.rs | 23 | ||||
-rw-r--r-- | tool/src/sq.rs | 16 | ||||
-rw-r--r-- | tool/src/sq_cli.rs | 24 |
4 files changed, 95 insertions, 1 deletions
diff --git a/tool/src/commands.rs b/tool/src/commands.rs index 7bbadfa4..419f1d2b 100644 --- a/tool/src/commands.rs +++ b/tool/src/commands.rs @@ -10,7 +10,7 @@ use openpgp::constants::DataFormat; use openpgp::{Packet, Key, TPK, KeyID, SecretKey}; use openpgp::parse::PacketParserResult; use openpgp::serialize::stream::{ - wrap, LiteralWriter, Encryptor, EncryptionMode, + wrap, Signer, LiteralWriter, Encryptor, EncryptionMode, }; extern crate sequoia_store as store; @@ -181,6 +181,37 @@ pub fn encrypt(store: &mut store::Store, Ok(()) } +pub fn sign(input: &mut io::Read, output: &mut io::Write, + secrets: Vec<openpgp::TPK>, detached: bool) + -> Result<(), failure::Error> { + let sink = wrap(output); + // Build a vector of references to hand to Signer. + let keys: Vec<&openpgp::TPK> = secrets.iter().collect(); + let signer = if detached { + Signer::detached(sink, &keys) + } else { + Signer::new(sink, &keys) + }.context("Failed to create signer")?; + + let mut writer = if detached { + // Detached signatures do not need a literal data packet, just + // hash the data as is. + signer + } else { + // We want to wrap the data in a literal data packet. + LiteralWriter::new(signer, DataFormat::Binary, None, None) + .context("Failed to create literal writer")? + }; + + // Finally, copy stdin to our writer stack to encrypt the data. + io::copy(input, &mut writer) + .context("Failed to sign")?; + + writer.finalize() + .context("Failed to sign")?; + Ok(()) +} + pub fn dump(input: &mut io::Read, output: &mut io::Write, map: bool) -> Result<(), failure::Error> { let mut ppr diff --git a/tool/src/sq-usage.rs b/tool/src/sq-usage.rs index 8db6f589..377f1a11 100644 --- a/tool/src/sq-usage.rs +++ b/tool/src/sq-usage.rs @@ -20,6 +20,7 @@ //! SUBCOMMANDS: //! decrypt Decrypts an OpenPGP message //! encrypt Encrypts a message +//! sign Signs a message //! store Interacts with key stores //! keyserver Interacts with keyservers //! autocrypt Autocrypt support @@ -76,6 +77,28 @@ //! <FILE> Sets the input file to use //! ``` //! +//! ## Subcommand sign +//! +//! ```text +//! Signs a message +//! +//! USAGE: +//! sq sign [FLAGS] [OPTIONS] [--] [FILE] +//! +//! FLAGS: +//! -B, --binary Emit unencoded OpenPGP data +//! --detached Create a detached signature +//! -h, --help Prints help information +//! -V, --version Prints version information +//! +//! OPTIONS: +//! -o, --output <FILE> Sets the output file to use +//! --secret-key-file <TSK-FILE>... Secret key to sign with, given as a file (can be given multiple times) +//! +//! ARGS: +//! <FILE> Sets the input file to use +//! ``` +//! //! ## Subcommand store //! //! ```text diff --git a/tool/src/sq.rs b/tool/src/sq.rs index 1936a2fd..98f3a447 100644 --- a/tool/src/sq.rs +++ b/tool/src/sq.rs @@ -111,6 +111,22 @@ fn real_main() -> Result<(), failure::Error> { m.occurrences_of("symmetric") as usize, recipients, additional_tpks)?; }, + ("sign", Some(m)) => { + let mut input = open_or_stdin(m.value_of("input"))?; + let mut output = create_or_stdout(m.value_of("output"))?; + let mut output = if ! m.is_present("binary") { + Box::new(armor::Writer::new(&mut output, + armor::Kind::Message, + &[][..])?) + } else { + output + }; + let detached = m.is_present("detached"); + let secrets = m.values_of("secret-key-file") + .map(load_tpks) + .unwrap_or(Ok(vec![]))?; + commands::sign(&mut input, &mut output, secrets, detached)?; + }, ("enarmor", Some(m)) => { let mut input = open_or_stdin(m.value_of("input"))?; diff --git a/tool/src/sq_cli.rs b/tool/src/sq_cli.rs index 53ff53e1..25ac508c 100644 --- a/tool/src/sq_cli.rs +++ b/tool/src/sq_cli.rs @@ -77,6 +77,30 @@ pub fn build() -> App<'static, 'static> { .multiple(true) .help("Encrypt with a password \ (can be given multiple times)"))) + .subcommand(SubCommand::with_name("sign") + .display_order(25) + .about("Signs a message") + .arg(Arg::with_name("input").value_name("FILE") + .help("Sets the input file to use")) + .arg(Arg::with_name("output").value_name("FILE") + .long("output") + .short("o") + .help("Sets the output file to use")) + .arg(Arg::with_name("binary") + .long("binary") + .short("B") + .help("Emit unencoded OpenPGP data")) + .arg(Arg::with_name("detached") + .long("detached") + .help("Create a detached signature")) + .arg(Arg::with_name("secret-key-file") + .long("secret-key-file") + .multiple(true) + .takes_value(true) + .value_name("TSK-FILE") + .number_of_values(1) + .help("Secret key to sign with, given as a file \ + (can be given multiple times)"))) .subcommand(SubCommand::with_name("enarmor") .about("Applies ASCII Armor to a file") .arg(Arg::with_name("input").value_name("FILE") |