diff options
author | Justus Winter <justus@sequoia-pgp.org> | 2021-02-10 16:12:39 +0100 |
---|---|---|
committer | Justus Winter <justus@sequoia-pgp.org> | 2021-02-24 11:08:00 +0100 |
commit | 23bda8c0c64b5cf63aafdb39cd85dab4ebca5698 (patch) | |
tree | 3a8dd3727129122664f35063fce7a82569e764fd /sq | |
parent | 1a9a05b875abd94a1d5886592b86876d2ff39aec (diff) |
sq: Implement creation of cleartext signatures.
- See #151.
Diffstat (limited to 'sq')
-rw-r--r-- | sq/src/commands/mod.rs | 2 | ||||
-rw-r--r-- | sq/src/commands/sign.rs | 46 | ||||
-rw-r--r-- | sq/src/sq-usage.rs | 3 | ||||
-rw-r--r-- | sq/src/sq.rs | 50 | ||||
-rw-r--r-- | sq/src/sq_cli.rs | 10 |
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, ¬ations)?; } 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, ¬ations, 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", |