diff options
author | Justus Winter <justus@sequoia-pgp.org> | 2018-07-02 11:38:28 +0200 |
---|---|---|
committer | Justus Winter <justus@sequoia-pgp.org> | 2018-07-02 13:09:26 +0200 |
commit | 4f6f0e48ad0ccc5556945a0c7bde58441f98e161 (patch) | |
tree | 949628d27114fb03c7a233188675c8c9e47163f8 /openpgp/examples | |
parent | 9cf384a58077cfaa6ab9af48cc023b010e2d2f8d (diff) |
openpgp: Implement detached signature generation in the Signer.
- Also, simplify the example accordingly.
- Add an example for a normal signature.
Diffstat (limited to 'openpgp/examples')
-rw-r--r-- | openpgp/examples/sign-detached.rs | 99 | ||||
-rw-r--r-- | openpgp/examples/sign.rs | 55 |
2 files changed, 70 insertions, 84 deletions
diff --git a/openpgp/examples/sign-detached.rs b/openpgp/examples/sign-detached.rs index 4cc0b021..a4052907 100644 --- a/openpgp/examples/sign-detached.rs +++ b/openpgp/examples/sign-detached.rs @@ -2,19 +2,15 @@ use std::env; use std::io; -use std::iter; -extern crate time; extern crate openpgp; -use openpgp::{armor, Key, Signature}; -use openpgp::constants::{SignatureType, HashAlgorithm}; -use openpgp::SecretKey; -use openpgp::serialize::Serialize; +use openpgp::armor; +use openpgp::serialize::stream::{wrap, Signer}; fn main() { let args: Vec<String> = env::args().collect(); if args.len() < 2 { - panic!("A simple encryption filter.\n\n\ + panic!("A simple filter creating a detached signature.\n\n\ Usage: {} <secret-keyfile> [<secret-keyfile>...] \ <input >output\n", args[0]); } @@ -29,87 +25,22 @@ fn main() { .expect("Failed to read key") }).collect(); - // Hash the file. - let hash_algo = HashAlgorithm::SHA512; - let hashes = openpgp::hash_file(io::stdin(), &[hash_algo]) - .expect("Failed to hash file"); - - // Get the one hash we computed. - let hash = &hashes[0].1; - // Compose a writer stack corresponding to the output format and // packet structure we want. First, we want the output to be as // armored. - let mut sink = armor::Writer::new(io::stdout(), armor::Kind::Message); - - for tsk in tsks { - // We need to find all (sub)keys capable of signing. - let can_sign = |key: &Key, sig: &Signature| -> bool { - sig.key_flags().can_sign() - // Check expiry. - && ! sig.signature_expired() - && ! sig.key_expired(key) - }; - - // Gather all signing-capable subkeys. - let subkeys = tsk.subkeys().filter_map(|skb| { - let key = skb.subkey(); - // The first signature is the most recent binding - // signature. - if skb.selfsigs().next() - .map(|sig| can_sign(key, sig)) - .unwrap_or(false) { - Some(key) - } else { - None - } - }); + let sink = armor::Writer::new(io::stdout(), armor::Kind::Signature); - // Check if the primary key is signing-capable. - let primary_can_sign = - // The key capabilities are defined by the most recent - // binding signature of the primary user id (or the - // most recent user id binding if no user id is marked - // as primary). In any case, this is the first user id. - tsk.userids().next().map(|ub| { - ub.selfsigs().next() - .map(|sig| can_sign(tsk.primary(), sig)) - .unwrap_or(false) - }).unwrap_or(false); + // Now, create a signer that emits a detached signature. + let mut signer = Signer::detached( + wrap(sink), &tsks.iter().collect::<Vec<&openpgp::TPK>>()) + .expect("Failed to create signer"); - // If the primary key is signing-capable, prepend to - // subkeys via iterator magic. - let keys = - iter::once(tsk.primary()) - .filter(|_| primary_can_sign) - .chain(subkeys); + // Finally, just copy all the data. + io::copy(&mut io::stdin(), &mut signer) + .expect("Failed to sign data"); - // For every suitable key, compute and emit a signature. - for key in keys { - if let &SecretKey::Unencrypted { mpis: ref sec } = - key.secret.as_ref().expect("No secret key") - { - // Clone hash so that we can hash the signature - // packet, and compute the digest. - let mut hash = hash.clone(); - - // Make and hash a signature packet. - let mut sig = Signature::new(SignatureType::Binary); - sig.set_signature_creation_time(time::now()) - .expect("Failed to set creation time"); - sig.set_issuer_fingerprint(key.fingerprint()) - .expect("Failed to set issuer fingerprint"); - sig.set_issuer(key.keyid()) - .expect("Failed to set issuer"); - - // Make signature. - sig.sign_hash(&key, sec, hash_algo, hash) - .expect("Failed to compute signature"); - - // And emit the packet. - sig.serialize(&mut sink) - .expect("Failed to write packet"); - } - } - } + // Teardown the stack to ensure all the data is written. + let _ = signer.into_inner() + .expect("Failed to write data") + .unwrap(); } diff --git a/openpgp/examples/sign.rs b/openpgp/examples/sign.rs new file mode 100644 index 00000000..f1b8282d --- /dev/null +++ b/openpgp/examples/sign.rs @@ -0,0 +1,55 @@ +/// This program demonstrates how to sign data. + +use std::env; +use std::io; + +extern crate openpgp; +use openpgp::armor; +use openpgp::serialize::stream::{wrap, LiteralWriter, Signer}; + +fn main() { + let args: Vec<String> = env::args().collect(); + if args.len() < 2 { + panic!("A simple signing filter.\n\n\ + Usage: {} <secret-keyfile> [<secret-keyfile>...] \ + <input >output\n", args[0]); + } + + // Read the transferable secret keys from the given files. + let tsks: Vec<openpgp::TPK> = args[1..].iter().map(|f| { + openpgp::TPK::from_reader( + // Use an openpgp::Reader so that we accept both armored + // and plain PGP data. + openpgp::Reader::from_file(f) + .expect("Failed to open file")) + .expect("Failed to read key") + }).collect(); + + // Compose a writer stack corresponding to the output format and + // packet structure we want. First, we want the output to be as + // armored. + let sink = armor::Writer::new(io::stdout(), armor::Kind::Message); + + // Now, create a signer that emits a detached signature. + let signer = Signer::new( + wrap(sink), &tsks.iter().collect::<Vec<&openpgp::TPK>>()) + .expect("Failed to create signer"); + + // Then, create a literal writer to wrap the data in a literal + // message packet. + let mut literal = LiteralWriter::new(signer, 'b', None, 0) + .expect("Failed to create literal writer"); + + // Finally, just copy all the data. + io::copy(&mut io::stdin(), &mut literal) + .expect("Failed to sign data"); + + // Teardown the stack to ensure all the data is written. + let signer = literal.into_inner() + .expect("Failed to write data") + .unwrap(); + + let _ = signer.into_inner() + .expect("Failed to write data") + .unwrap(); +} |