summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJustus Winter <justus@sequoia-pgp.org>2018-11-02 12:52:45 +0100
committerJustus Winter <justus@sequoia-pgp.org>2018-11-02 12:52:45 +0100
commitd4eb1d81803976a8a87f5c198a4493c1fc629a47 (patch)
treecec9c8f613b960d9ace6a12c6cedca521c3a3228
parent188bc17560f8e0015cf4a4d14891340eea37fc66 (diff)
openpgp: Create revocation certificates for TPKs.
- Fixes #95.
-rw-r--r--ffi/include/sequoia/openpgp.h6
-rw-r--r--ffi/src/openpgp.rs42
-rw-r--r--openpgp/src/parse/stream.rs2
-rw-r--r--openpgp/src/tpk/builder.rs45
-rw-r--r--openpgp/src/tpk/mod.rs10
-rw-r--r--openpgp/src/tsk.rs7
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.