summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJustus Winter <justus@sequoia-pgp.org>2021-02-10 16:12:39 +0100
committerJustus Winter <justus@sequoia-pgp.org>2021-02-24 11:08:00 +0100
commit23bda8c0c64b5cf63aafdb39cd85dab4ebca5698 (patch)
tree3a8dd3727129122664f35063fce7a82569e764fd
parent1a9a05b875abd94a1d5886592b86876d2ff39aec (diff)
sq: Implement creation of cleartext signatures.
- See #151.
-rw-r--r--sq/src/commands/mod.rs2
-rw-r--r--sq/src/commands/sign.rs46
-rw-r--r--sq/src/sq-usage.rs3
-rw-r--r--sq/src/sq.rs50
-rw-r--r--sq/src/sq_cli.rs10
5 files changed, 87 insertions, 24 deletions
diff --git a/sq/src/commands/mod.rs b/sq/src/commands/mod.rs
index 6eb0fb74..8ae65b07 100644
--- a/sq/src/commands/mod.rs
+++ b/sq/src/commands/mod.rs
@@ -39,7 +39,7 @@ use crate::{
pub mod autocrypt;
pub mod decrypt;
pub use self::decrypt::decrypt;
-mod sign;
+pub mod sign;
pub use self::sign::sign;
pub mod dump;
pub use self::dump::dump;
diff --git a/sq/src/commands/sign.rs b/sq/src/commands/sign.rs
index 1b337486..90ec39f0 100644
--- a/sq/src/commands/sign.rs
+++ b/sq/src/commands/sign.rs
@@ -21,6 +21,7 @@ use crate::openpgp::serialize::stream::{
use crate::openpgp::policy::Policy;
use crate::openpgp::types::SignatureType;
use crate::{
+ Config,
create_or_stdout,
create_or_stdout_pgp,
};
@@ -376,3 +377,48 @@ fn sign_message_(policy: &dyn Policy,
Ok(())
}
+
+pub fn clearsign(config: Config,
+ mut input: impl io::Read + Sync + Send,
+ mut output: impl io::Write + Sync + Send,
+ secrets: Vec<openpgp::Cert>,
+ time: Option<SystemTime>,
+ notations: &[(bool, NotationData)])
+ -> Result<()>
+{
+ let mut keypairs = super::get_signing_keys(&secrets, &config.policy, time)?;
+ if keypairs.is_empty() {
+ return Err(anyhow::anyhow!("No signing keys found"));
+ }
+
+ // Prepare a signature template.
+ let mut builder = SignatureBuilder::new(SignatureType::Text);
+ for (critical, n) in notations.iter() {
+ builder = builder.add_notation(
+ n.name(),
+ n.value(),
+ Some(n.flags().clone()),
+ *critical)?;
+ }
+
+ let message = Message::new(&mut output);
+ let mut signer = Signer::with_template(
+ message, keypairs.pop().unwrap(), builder)
+ .cleartext();
+ if let Some(time) = time {
+ signer = signer.creation_time(time);
+ }
+ for s in keypairs {
+ signer = signer.add_signer(s);
+ }
+ let mut message = signer.build().context("Failed to create signer")?;
+
+ // Finally, copy stdin to our writer stack to sign the data.
+ io::copy(&mut input, &mut message)
+ .context("Failed to sign")?;
+
+ message.finalize()
+ .context("Failed to sign")?;
+
+ Ok(())
+}
diff --git a/sq/src/sq-usage.rs b/sq/src/sq-usage.rs
index 04aea10c..6eef5394 100644
--- a/sq/src/sq-usage.rs
+++ b/sq/src/sq-usage.rs
@@ -201,6 +201,9 @@
//! -B, --binary
//! Emits binary data
//!
+//! --cleartext-signature
+//! Creates a cleartext signature
+//!
//! --detached
//! Creates a detached signature
//!
diff --git a/sq/src/sq.rs b/sq/src/sq.rs
index 6ba4c675..bb22c2d7 100644
--- a/sq/src/sq.rs
+++ b/sq/src/sq.rs
@@ -451,35 +451,39 @@ fn main() -> Result<()> {
} else {
None
};
+ // Each --notation takes two values. The iterator
+ // returns them one at a time, however.
+ let mut notations: Vec<(bool, NotationData)> = Vec::new();
+ if let Some(mut n) = m.values_of("notation") {
+ while let Some(name) = n.next() {
+ let value = n.next().unwrap();
+
+ let (critical, name) = if name.len() > 0
+ && Some('!') == name.chars().next()
+ {
+ (true, &name[1..])
+ } else {
+ (false, name)
+ };
+
+ notations.push(
+ (critical,
+ NotationData::new(
+ name, value,
+ NotationDataFlags::empty().set_human_readable())));
+ }
+ }
+
if let Some(merge) = m.value_of("merge") {
let output = create_or_stdout_pgp(output, force, binary,
armor::Kind::Message)?;
let mut input2 = open_or_stdin(Some(merge))?;
commands::merge_signatures(&mut input, &mut input2, output)?;
+ } else if m.is_present("clearsign") {
+ let output = create_or_stdout(output, force)?;
+ commands::sign::clearsign(config, input, output, secrets,
+ time, &notations)?;
} else {
- // Each --notation takes two values. The iterator
- // returns them one at a time, however.
- let mut notations: Vec<(bool, NotationData)> = Vec::new();
- if let Some(mut n) = m.values_of("notation") {
- while let Some(name) = n.next() {
- let value = n.next().unwrap();
-
- let (critical, name) = if name.len() > 0
- && Some('!') == name.chars().next()
- {
- (true, &name[1..])
- } else {
- (false, name)
- };
-
- notations.push(
- (critical,
- NotationData::new(
- name, value,
- NotationDataFlags::empty().set_human_readable())));
- }
- }
-
commands::sign(policy, &mut input, output, secrets, detached,
binary, append, notarize, time, &notations, force)?;
}
diff --git a/sq/src/sq_cli.rs b/sq/src/sq_cli.rs
index 642418c1..6a0d9b86 100644
--- a/sq/src/sq_cli.rs
+++ b/sq/src/sq_cli.rs
@@ -233,6 +233,15 @@ $ sq sign --detached --signer-key juliet.pgp message.txt
.arg(Arg::with_name("detached")
.long("detached")
.help("Creates a detached signature"))
+ .arg(Arg::with_name("clearsign")
+ .long("cleartext-signature")
+ .conflicts_with_all(&[
+ "detached",
+ "append",
+ "notarize",
+ "binary",
+ ])
+ .help("Creates a cleartext signature"))
.arg(Arg::with_name("append")
.short("a").long("append")
.conflicts_with("notarize")
@@ -246,6 +255,7 @@ $ sq sign --detached --signer-key juliet.pgp message.txt
.conflicts_with_all(&[
"append",
"detached",
+ "clearsign",
"notarize",
"secret-key-file",
"time",