summaryrefslogtreecommitdiffstats
path: root/tool
diff options
context:
space:
mode:
authorJustus Winter <justus@sequoia-pgp.org>2018-08-15 16:29:46 +0200
committerJustus Winter <justus@sequoia-pgp.org>2018-08-15 16:34:49 +0200
commit10276b9e442596849fb0e3742408c26f621b9162 (patch)
tree569e442fd54adc15f5743f038fb341ea60f6cefc /tool
parent8ad003bf46987a1adee5bbd3c1c8370544be2147 (diff)
tool: Implement sq sign.
- Fixes #17.
Diffstat (limited to 'tool')
-rw-r--r--tool/src/commands.rs33
-rw-r--r--tool/src/sq-usage.rs23
-rw-r--r--tool/src/sq.rs16
-rw-r--r--tool/src/sq_cli.rs24
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")