diff options
author | Justus Winter <justus@sequoia-pgp.org> | 2018-11-02 12:52:45 +0100 |
---|---|---|
committer | Justus Winter <justus@sequoia-pgp.org> | 2018-11-02 12:52:45 +0100 |
commit | d4eb1d81803976a8a87f5c198a4493c1fc629a47 (patch) | |
tree | cec9c8f613b960d9ace6a12c6cedca521c3a3228 | |
parent | 188bc17560f8e0015cf4a4d14891340eea37fc66 (diff) |
openpgp: Create revocation certificates for TPKs.
- Fixes #95.
-rw-r--r-- | ffi/include/sequoia/openpgp.h | 6 | ||||
-rw-r--r-- | ffi/src/openpgp.rs | 42 | ||||
-rw-r--r-- | openpgp/src/parse/stream.rs | 2 | ||||
-rw-r--r-- | openpgp/src/tpk/builder.rs | 45 | ||||
-rw-r--r-- | openpgp/src/tpk/mod.rs | 10 | ||||
-rw-r--r-- | openpgp/src/tsk.rs | 7 |
6 files changed, 84 insertions, 28 deletions
diff --git a/ffi/include/sequoia/openpgp.h b/ffi/include/sequoia/openpgp.h index 0043b0bd..f09ff1ea 100644 --- a/ffi/include/sequoia/openpgp.h +++ b/ffi/include/sequoia/openpgp.h @@ -622,7 +622,8 @@ void sq_tpk_builder_add_certification_subkey(sq_tpk_builder_t *tpkb); /// /// Consumes `tpkb`. /*/ -sq_tpk_t sq_tpk_builder_generate(sq_context_t ctx, sq_tpk_builder_t tpkb); +sq_tpk_t sq_tpk_builder_generate(sq_context_t ctx, sq_tpk_builder_t tpkb, + sq_tpk_t *tpk, sq_signature_t *revocation); /* TSK */ @@ -630,7 +631,8 @@ sq_tpk_t sq_tpk_builder_generate(sq_context_t ctx, sq_tpk_builder_t tpkb); /*/ /// Generates a new RSA 3072 bit key with UID `primary_uid`. /*/ -sq_tsk_t sq_tsk_new (sq_context_t ctx, char *primary_uid); +sq_tsk_t sq_tsk_new (sq_context_t ctx, char *primary_uid, + sq_tsk_t *tpk, sq_signature_t *revocation); /*/ /// Frees the TSK. diff --git a/ffi/src/openpgp.rs b/ffi/src/openpgp.rs index 8b34e32c..07bf359d 100644 --- a/ffi/src/openpgp.rs +++ b/ffi/src/openpgp.rs @@ -13,6 +13,9 @@ extern crate openpgp; use self::openpgp::{ armor, Fingerprint, KeyID, PacketPile, TPK, TSK, Packet, crypto::Password, + packet::{ + Signature, + }, }; use self::openpgp::tpk::{CipherSuite, TPKBuilder}; use self::openpgp::parse::{PacketParserResult, PacketParser, PacketParserEOF}; @@ -822,6 +825,7 @@ pub extern "system" fn sq_tpk_into_tsk(tpk: *mut TPK) /// sq_context_t ctx; /// sq_tpk_builder_t builder; /// sq_tpk_t tpk; +/// sq_signature_t revocation; /// /// ctx = sq_context_new ("org.sequoia-pgp.tests", NULL); /// @@ -830,8 +834,9 @@ pub extern "system" fn sq_tpk_into_tsk(tpk: *mut TPK) /// sq_tpk_builder_add_userid (&builder, "some@example.org"); /// sq_tpk_builder_add_signing_subkey (&builder); /// sq_tpk_builder_add_encryption_subkey (&builder); -/// tpk = sq_tpk_builder_generate (ctx, builder); +/// sq_tpk_builder_generate (ctx, builder, &tpk, &revocation); /// assert (tpk); +/// assert (revocation); /// ``` #[no_mangle] pub extern "system" fn sq_tpk_builder_default() -> *mut TPKBuilder { @@ -933,13 +938,24 @@ pub extern "system" fn sq_tpk_builder_add_certification_subkey /// Consumes `tpkb`. #[no_mangle] pub extern "system" fn sq_tpk_builder_generate - (ctx: Option<&mut Context>, tpkb: *mut TPKBuilder) - -> *mut TPK + (ctx: Option<&mut Context>, tpkb: *mut TPKBuilder, + tpk_out: Option<&mut *mut TPK>, + revocation_out: Option<&mut *mut Signature>) + -> Status { let ctx = ctx.expect("CTX is NULL"); assert!(!tpkb.is_null()); + let tpk_out = tpk_out.expect("TPK is NULL"); + let revocation_out = revocation_out.expect("REVOCATION is NULL"); let tpkb = unsafe { Box::from_raw(tpkb) }; - fry_box!(ctx, tpkb.generate()) + match tpkb.generate() { + Ok((tpk, revocation)) => { + *tpk_out = box_raw!(tpk); + *revocation_out = box_raw!(revocation); + Status::Success + }, + Err(e) => fry_status!(ctx, Err::<(), failure::Error>(e)), + } } @@ -948,14 +964,26 @@ pub extern "system" fn sq_tpk_builder_generate /// Generates a new RSA 3072 bit key with UID `primary_uid`. #[no_mangle] pub extern "system" fn sq_tsk_new(ctx: Option<&mut Context>, - primary_uid: *const c_char) - -> *mut TSK { + primary_uid: *const c_char, + tpk_out: Option<&mut *mut TSK>, + revocation_out: Option<&mut *mut Signature>) + -> Status +{ let ctx = ctx.expect("CONTEXT is NULL"); assert!(!primary_uid.is_null()); + let tpk_out = tpk_out.expect("TPK is NULL"); + let revocation_out = revocation_out.expect("REVOCATION is NULL"); let primary_uid = unsafe { CStr::from_ptr(primary_uid) }; - fry_box!(ctx, TSK::new(primary_uid.to_string_lossy())) + match TSK::new(primary_uid.to_string_lossy()) { + Ok((tpk, revocation)) => { + *tpk_out = box_raw!(tpk); + *revocation_out = box_raw!(revocation); + Status::Success + }, + Err(e) => fry_status!(ctx, Err::<(), failure::Error>(e)), + } } /// Frees the TSK. diff --git a/openpgp/src/parse/stream.rs b/openpgp/src/parse/stream.rs index aa6f3b35..88fb473a 100644 --- a/openpgp/src/parse/stream.rs +++ b/openpgp/src/parse/stream.rs @@ -1076,7 +1076,7 @@ mod test { use serialize::stream::{LiteralWriter, Signer, Message}; use std::io::Write; - let tpk = TPKBuilder::default() + let (tpk, _) = TPKBuilder::default() .set_cipher_suite(CipherSuite::Cv25519) .add_signing_subkey() .generate().unwrap(); diff --git a/openpgp/src/tpk/builder.rs b/openpgp/src/tpk/builder.rs index 3449dd0e..4e0b68ba 100644 --- a/openpgp/src/tpk/builder.rs +++ b/openpgp/src/tpk/builder.rs @@ -14,7 +14,10 @@ use TPK; use PublicKeyAlgorithm; use Error; use conversions::Time; -use constants::SignatureType; +use constants::{ + ReasonForRevocation, + SignatureType, +}; use autocrypt::Autocrypt; /// Groups symmetric and asymmetric algorithms @@ -125,7 +128,7 @@ impl TPKBuilder { } /// Generates the actual TPK. - pub fn generate(mut self) -> Result<TPK> { + pub fn generate(mut self) -> Result<(TPK, Signature)> { use packet::Common; // make sure the primary key can sign subkeys @@ -182,7 +185,7 @@ impl TPKBuilder { subkeys.push(Self::subkey(subkey, &primary, self.ciphersuite)?); } - Ok(TPK{ + let tpk = TPK { primary: primary, primary_selfsigs: selfsigs, primary_certifications: vec![], @@ -193,7 +196,12 @@ impl TPKBuilder { subkeys: subkeys, unknowns: vec![], bad: vec![], - }) + }; + + let revocation = tpk.revoke(ReasonForRevocation::Unspecified, + b"Unspecified")?; + + Ok((tpk, revocation)) } fn primary_key(blueprint: KeyBlueprint, uid: Option<UserID>, cs: CipherSuite) @@ -352,7 +360,8 @@ mod tests { #[test] fn all_opts() { - let tpk = TPKBuilder::default() + let (tpk, _) = TPKBuilder::default() + .set_cipher_suite(CipherSuite::Cv25519) .add_userid("test1@example.com") .add_userid("test2@example.com") .add_signing_subkey() @@ -374,7 +383,8 @@ mod tests { #[test] fn direct_key_sig() { - let tpk = TPKBuilder::default() + let (tpk, _) = TPKBuilder::default() + .set_cipher_suite(CipherSuite::Cv25519) .add_signing_subkey() .add_encryption_subkey() .add_certification_subkey() @@ -393,14 +403,14 @@ mod tests { #[test] fn setter() { - let tpk1 = TPKBuilder::default() + let (tpk1, _) = TPKBuilder::default() .set_cipher_suite(CipherSuite::Cv25519) .set_cipher_suite(CipherSuite::RSA3k) .set_cipher_suite(CipherSuite::Cv25519) .generate().unwrap(); assert_eq!(tpk1.primary().pk_algo, PublicKeyAlgorithm::EdDSA); - let tpk2 = TPKBuilder::default() + let (tpk2, _) = TPKBuilder::default() .add_userid("test2@example.com") .add_encryption_subkey() .generate().unwrap(); @@ -410,7 +420,7 @@ mod tests { #[test] fn defaults() { - let tpk1 = TPKBuilder::default() + let (tpk1, _) = TPKBuilder::default() .add_userid("test2@example.com") .generate().unwrap(); assert_eq!(tpk1.primary().pk_algo, PublicKeyAlgorithm::RSAEncryptSign); @@ -425,7 +435,7 @@ mod tests { #[test] fn autocrypt() { - let tpk1 = TPKBuilder::autocrypt(None) + let (tpk1, _) = TPKBuilder::autocrypt(None) .generate().unwrap(); assert_eq!(tpk1.primary().pk_algo, PublicKeyAlgorithm::RSAEncryptSign); assert_eq!(tpk1.subkeys().next().unwrap().subkey().pk_algo, PublicKeyAlgorithm::RSAEncryptSign); @@ -433,7 +443,8 @@ mod tests { #[test] fn always_certify() { - let tpk1 = TPKBuilder::default() + let (tpk1, _) = TPKBuilder::default() + .set_cipher_suite(CipherSuite::Cv25519) .primary_keyflags(KeyFlags::default()) .add_encryption_subkey() .generate().unwrap(); @@ -451,7 +462,8 @@ mod tests { #[test] fn gen_wired_subkeys() { - let tpk1 = TPKBuilder::default() + let (tpk1, _) = TPKBuilder::default() + .set_cipher_suite(CipherSuite::Cv25519) .primary_keyflags(KeyFlags::default()) .add_subkey(KeyFlags::default().set_encrypt_for_transport(true).set_certify(true)) .generate().unwrap(); @@ -467,4 +479,13 @@ mod tests { assert_eq!(tpk1.subkeys().count(), 1); } + + #[test] + fn generate_revocation_certificate() { + use RevocationStatus; + let (tpk, revocation) = TPKBuilder::default() + .set_cipher_suite(CipherSuite::Cv25519) + .generate().unwrap(); + assert_eq!(tpk.revoked(), RevocationStatus::NotAsFarAsWeKnow); + } } diff --git a/openpgp/src/tpk/mod.rs b/openpgp/src/tpk/mod.rs index a9a7eb26..3ccb0c0d 100644 --- a/openpgp/src/tpk/mod.rs +++ b/openpgp/src/tpk/mod.rs @@ -2983,7 +2983,8 @@ mod test { fn set_expiry() { let now = time::now_utc(); - let tpk = TSK::new(Some("Test".into())).unwrap().into_tpk(); + let (tsk, _) = TSK::new(Some("Test".into())).unwrap(); + let tpk = tsk.into_tpk(); let expiry_orig = tpk.primary_key_signature().unwrap() .key_expiration_time() .expect("Keys expire by default."); @@ -3020,7 +3021,7 @@ mod test { // XXX: testing sequoia against itself isn't optimal, but I couldn't // find a tool to generate direct key signatures :-( - let tpk1 = TPKBuilder::default().generate().unwrap(); + let (tpk1, _) = TPKBuilder::default().generate().unwrap(); let mut buf = Vec::default(); tpk1.serialize(&mut buf).unwrap(); @@ -3124,7 +3125,8 @@ mod test { #[test] fn revoke() { - let tpk = TSK::new(Some("Test".into())).unwrap().into_tpk(); + let (tsk, _) = TSK::new(Some("Test".into())).unwrap(); + let tpk = tsk.into_tpk(); assert_eq!(RevocationStatus::NotAsFarAsWeKnow, tpk.revoked()); let sig = tpk.revoke(ReasonForRevocation::KeyCompromised, @@ -3137,7 +3139,7 @@ mod test { #[test] fn tsk_filter() { - let tpk = TPKBuilder::default() + let (tpk, _) = TPKBuilder::default() .add_signing_subkey() .add_encryption_subkey() .generate().unwrap(); diff --git a/openpgp/src/tsk.rs b/openpgp/src/tsk.rs index 53b0ff0c..500125ff 100644 --- a/openpgp/src/tsk.rs +++ b/openpgp/src/tsk.rs @@ -6,6 +6,7 @@ use std::path::Path; use { Result, TPK, + packet::Signature, packet::Tag, }; use serialize::{ @@ -67,7 +68,8 @@ impl TSK { /// Generates a new key OpenPGP key. The key will be capable of encryption /// and signing. If no user id is given the primary self signature will be /// a direct key signature. - pub fn new<'a, O: Into<Option<Cow<'a,str>>>>(primary_uid: O) -> Result<TSK> { + pub fn new<'a, O: Into<Option<Cow<'a,str>>>>(primary_uid: O) + -> Result<(TSK, Signature)> { use tpk::TPKBuilder; let mut key = TPKBuilder::autocrypt(None); @@ -77,7 +79,8 @@ impl TSK { None => {} } - Ok(TSK::from_tpk(key.generate()?)) + let (tpk, revocation) = key.generate()?; + Ok((TSK::from_tpk(tpk), revocation)) } /// Returns a reference to the corresponding TPK. |