diff options
author | Justus Winter <justus@sequoia-pgp.org> | 2018-06-22 15:23:27 +0200 |
---|---|---|
committer | Justus Winter <justus@sequoia-pgp.org> | 2018-06-29 15:18:11 +0200 |
commit | 1a1a6feb9f2ed2e0c1986a415a5761b6dc6025c6 (patch) | |
tree | 63c038a418dcbce2f1ced9e64b5808a7951b08a4 /openpgp/examples | |
parent | fd900de3dc87d1c3ac93ec9e2992befd8d71c90a (diff) |
openpgp: Implement signing.
- This implements the low-level functionality necessary to create
signatures using RSA, DSA, ECDSA, and EdDSA.
Diffstat (limited to 'openpgp/examples')
-rw-r--r-- | openpgp/examples/sign-detached.rs | 115 |
1 files changed, 115 insertions, 0 deletions
diff --git a/openpgp/examples/sign-detached.rs b/openpgp/examples/sign-detached.rs new file mode 100644 index 00000000..4cc0b021 --- /dev/null +++ b/openpgp/examples/sign-detached.rs @@ -0,0 +1,115 @@ +/// This program demonstrates how to make a detached signature. + +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; + +fn main() { + let args: Vec<String> = env::args().collect(); + if args.len() < 2 { + panic!("A simple encryption 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(); + + // 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 + } + }); + + // 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); + + // 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); + + // 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"); + } + } + } +} |