summaryrefslogtreecommitdiffstats
path: root/ffi/src/openpgp
diff options
context:
space:
mode:
authorJustus Winter <justus@sequoia-pgp.org>2019-01-08 15:09:57 +0100
committerJustus Winter <justus@sequoia-pgp.org>2019-01-08 15:27:34 +0100
commit4d0a4f527e361ad29c082331e73dd8ed6750ffbd (patch)
treee3be6aca0353ebcba322daa512493f15b3aa7e45 /ffi/src/openpgp
parentb7eff1fc2a5559af75010955181152347ed64134 (diff)
ffi: Move TPK glue and friends to a new module.
Diffstat (limited to 'ffi/src/openpgp')
-rw-r--r--ffi/src/openpgp/mod.rs707
-rw-r--r--ffi/src/openpgp/tpk.rs729
2 files changed, 731 insertions, 705 deletions
diff --git a/ffi/src/openpgp/mod.rs b/ffi/src/openpgp/mod.rs
index 6f52484e..05afe9c0 100644
--- a/ffi/src/openpgp/mod.rs
+++ b/ffi/src/openpgp/mod.rs
@@ -1,7 +1,7 @@
//! XXX
use failure;
-use std::ffi::{CString, CStr};
+use std::ffi::CStr;
use std::mem::forget;
use std::ptr;
use std::slice;
@@ -17,7 +17,6 @@ use self::openpgp::{
Fingerprint,
KeyID,
RevocationStatus,
- PacketPile,
TPK,
TSK,
Packet,
@@ -30,13 +29,6 @@ use self::openpgp::{
},
crypto::Password,
};
-use self::openpgp::tpk::{
- CipherSuite,
- TPKBuilder,
- UserIDBinding,
- UserIDBindingIter,
- KeyIter
-};
use self::openpgp::packet;
use self::openpgp::parse::{
Parse,
@@ -56,7 +48,6 @@ use self::openpgp::parse::stream::{
use self::openpgp::serialize::Serialize;
use self::openpgp::constants::{
DataFormat,
- ReasonForRevocation,
};
use super::error::Status;
@@ -66,6 +57,7 @@ pub mod armor;
pub mod fingerprint;
pub mod keyid;
pub mod packet_pile;
+pub mod tpk;
/* openpgp::packet::Tag. */
@@ -102,420 +94,6 @@ pub extern "system" fn sq_tag_to_string(tag: u8) -> *const c_char {
}.as_bytes().as_ptr() as *const c_char
}
-/* sequoia::keys. */
-
-/// Returns the first TPK encountered in the reader.
-#[no_mangle]
-pub extern "system" fn sq_tpk_from_reader(ctx: Option<&mut Context>,
- reader: Option<&mut Box<Read>>)
- -> *mut TPK {
- let ctx = ctx.expect("Context is NULL");
- let reader = reader.expect("Reader is NULL");
- fry_box!(ctx, TPK::from_reader(reader))
-}
-
-/// Returns the first TPK encountered in the file.
-#[no_mangle]
-pub extern "system" fn sq_tpk_from_file(ctx: Option<&mut Context>,
- filename: *const c_char)
- -> *mut TPK {
- let ctx = ctx.expect("Context is NULL");
- assert!(! filename.is_null());
- let filename = unsafe {
- CStr::from_ptr(filename).to_string_lossy().into_owned()
- };
- fry_box!(ctx, TPK::from_file(&filename))
-}
-
-/// Returns the first TPK found in `m`.
-///
-/// Consumes `m`.
-#[no_mangle]
-pub extern "system" fn sq_tpk_from_packet_pile(ctx: Option<&mut Context>,
- m: *mut PacketPile)
- -> *mut TPK {
- let ctx = ctx.expect("Context is NULL");
- assert!(! m.is_null());
- let m = unsafe { Box::from_raw(m) };
- fry_box!(ctx, TPK::from_packet_pile(*m))
-}
-
-/// Returns the first TPK found in `buf`.
-///
-/// `buf` must be an OpenPGP-encoded TPK.
-#[no_mangle]
-pub extern "system" fn sq_tpk_from_bytes(ctx: Option<&mut Context>,
- b: *const uint8_t, len: size_t)
- -> *mut TPK {
- let ctx = ctx.expect("Context is NULL");
- assert!(!b.is_null());
- let buf = unsafe {
- slice::from_raw_parts(b, len as usize)
- };
-
- fry_box!(ctx, TPK::from_bytes(buf))
-}
-
-/// Returns the first TPK found in the packet parser.
-///
-/// Consumes the packet parser result.
-#[no_mangle]
-pub extern "system" fn sq_tpk_from_packet_parser(ctx: Option<&mut Context>,
- ppr: *mut PacketParserResult)
- -> *mut TPK
-{
- let ctx = ctx.expect("Context is NULL");
- assert!(! ppr.is_null());
- let ppr = unsafe { Box::from_raw(ppr) };
-
- fry_box!(ctx, TPK::from_packet_parser(*ppr))
-}
-
-/// Frees the TPK.
-#[no_mangle]
-pub extern "system" fn sq_tpk_free(tpk: *mut TPK) {
- if tpk.is_null() {
- return
- }
- unsafe {
- drop(Box::from_raw(tpk));
- }
-}
-
-/// Clones the TPK.
-#[no_mangle]
-pub extern "system" fn sq_tpk_clone(tpk: Option<&TPK>)
- -> *mut TPK {
- let tpk = tpk.expect("TPK is NULL");
- box_raw!(tpk.clone())
-}
-
-/// Compares TPKs.
-#[no_mangle]
-pub extern "system" fn sq_tpk_equal(a: Option<&TPK>,
- b: Option<&TPK>)
- -> bool {
- let a = a.expect("TPK 'a' is NULL");
- let b = b.expect("TPK 'b' is NULL");
- a == b
-}
-
-/// Serializes the TPK.
-#[no_mangle]
-pub extern "system" fn sq_tpk_serialize(ctx: Option<&mut Context>,
- tpk: Option<&TPK>,
- writer: Option<&mut Box<Write>>)
- -> Status {
- let ctx = ctx.expect("Context is NULL");
- let tpk = tpk.expect("TPK is NULL");
- let writer = writer.expect("Writer is NULL");
- fry_status!(ctx, tpk.serialize(writer))
-}
-
-/// Merges `other` into `tpk`.
-///
-/// If `other` is a different key, then nothing is merged into
-/// `tpk`, but `tpk` is still canonicalized.
-///
-/// Consumes `tpk` and `other`.
-#[no_mangle]
-pub extern "system" fn sq_tpk_merge(ctx: Option<&mut Context>,
- tpk: *mut TPK,
- other: *mut TPK)
- -> *mut TPK {
- let ctx = ctx.expect("Context is NULL");
- assert!(! tpk.is_null());
- let tpk = unsafe { Box::from_raw(tpk) };
- assert!(! other.is_null());
- let other = unsafe { Box::from_raw(other) };
- fry_box!(ctx, tpk.merge(*other))
-}
-
-/// Adds packets to the TPK.
-///
-/// This recanonicalizes the TPK. If the packets are invalid, they
-/// are dropped.
-///
-/// Consumes `tpk` and the packets in `packets`. The buffer, however,
-/// must be managed by the caller.
-#[no_mangle]
-pub extern "system" fn sq_tpk_merge_packets(ctx: Option<&mut Context>,
- tpk: *mut TPK,
- packets: *mut *mut Packet,
- packets_len: size_t)
- -> *mut TPK {
- let ctx = ctx.expect("Context is NULL");
- assert!(! tpk.is_null());
- let tpk = unsafe { Box::from_raw(tpk) };
- let packets = unsafe {
- slice::from_raw_parts_mut(packets, packets_len)
- };
- let packets =
- packets.iter_mut().map(|p| *unsafe { Box::from_raw(*p) } ).collect();
- fry_box!(ctx, tpk.merge_packets(packets))
-}
-
-/// Dumps the TPK.
-///
-/// XXX Remove this.
-#[no_mangle]
-pub extern "system" fn sq_tpk_dump(tpk: Option<&TPK>) {
- let tpk = tpk.expect("TPK is NULL");
- println!("{:?}", *tpk);
-}
-
-/// Returns the fingerprint.
-#[no_mangle]
-pub extern "system" fn sq_tpk_fingerprint(tpk: Option<&TPK>)
- -> *mut Fingerprint {
- let tpk = tpk.expect("TPK is NULL");
- box_raw!(tpk.fingerprint())
-}
-
-/// Cast the public key into a secret key that allows using the secret
-/// parts of the containing keys.
-#[no_mangle]
-pub extern "system" fn sq_tpk_into_tsk(tpk: *mut TPK)
- -> *mut TSK {
- assert!(!tpk.is_null());
- let tpk = unsafe {
- Box::from_raw(tpk)
- };
- box_raw!(tpk.into_tsk())
-}
-
-/// Returns a reference to the TPK's primary key.
-///
-/// The tpk still owns the key. The caller should neither modify nor
-/// free the key.
-#[no_mangle]
-pub extern "system" fn sq_tpk_primary(tpk: Option<&TPK>)
- -> Option<&packet::Key> {
- let tpk = tpk.expect("TPK is NULL");
- Some(tpk.primary())
-}
-
-/// Returns the TPK's revocation status.
-///
-/// Note: this only returns whether the TPK has been revoked, and does
-/// not reflect whether an individual user id, user attribute or
-/// subkey has been revoked.
-#[no_mangle]
-pub extern "system" fn sq_tpk_revocation_status(tpk: Option<&TPK>)
- -> *mut RevocationStatus {
- let tpk = tpk.expect("TPK is NULL");
- box_raw!(tpk.revoked())
-}
-
-fn int_to_reason_for_revocation(code: c_int) -> ReasonForRevocation {
- match code {
- 0 => ReasonForRevocation::KeyCompromised,
- 1 => ReasonForRevocation::Unspecified,
- 2 => ReasonForRevocation::KeySuperseded,
- 3 => ReasonForRevocation::KeyCompromised,
- 4 => ReasonForRevocation::KeyRetired,
- 5 => ReasonForRevocation::UIDRetired,
- _ => panic!("Bad reason for revocation: {}", code),
- }
-}
-
-
-/// Returns a new revocation certificate for the TPK.
-///
-/// This function does *not* consume `tpk`.
-///
-/// # Example
-///
-/// ```c
-/// #include <assert.h>
-/// #include <sequoia.h>
-///
-/// 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);
-///
-/// builder = sq_tpk_builder_default ();
-/// sq_tpk_builder_set_cipher_suite (&builder, SQ_TPK_CIPHER_SUITE_CV25519);
-/// sq_tpk_builder_generate (ctx, builder, &tpk, &revocation);
-/// assert (tpk);
-/// assert (revocation);
-/// sq_signature_free (revocation); /* Free the generated one. */
-///
-/// revocation = sq_tpk_revoke (ctx, tpk,
-/// SQ_REASON_FOR_REVOCATION_KEY_COMPROMISED,
-/// "It was the maid :/");
-/// assert (revocation);
-///
-/// sq_packet_t packet = sq_signature_to_packet (revocation);
-/// tpk = sq_tpk_merge_packets (ctx, tpk, &packet, 1);
-/// assert (tpk);
-///
-/// sq_revocation_status_t rs = sq_tpk_revocation_status (tpk);
-/// assert (sq_revocation_status_variant (rs) == SQ_REVOCATION_STATUS_REVOKED);
-/// sq_revocation_status_free (rs);
-///
-/// sq_tpk_free (tpk);
-/// sq_context_free (ctx);
-/// ```
-#[no_mangle]
-pub extern "system" fn sq_tpk_revoke(ctx: Option<&mut Context>,
- tpk: Option<&mut TPK>,
- code: c_int,
- reason: Option<*const c_char>)
- -> *mut packet::Signature
-{
- let ctx = ctx.expect("Context is NULL");
- let tpk = tpk.expect("TPK is NULL");
- let code = int_to_reason_for_revocation(code);
- let reason = if let Some(reason) = reason {
- unsafe {
- CStr::from_ptr(reason).to_bytes()
- }
- } else {
- b""
- };
-
- fry_box!(ctx, tpk.revoke(code, reason))
-}
-
-/// Adds a revocation certificate to the tpk.
-///
-/// This function consumes the tpk.
-///
-/// # Example
-///
-/// ```c
-/// #include <assert.h>
-/// #include <sequoia.h>
-///
-/// 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);
-///
-/// builder = sq_tpk_builder_default ();
-/// sq_tpk_builder_set_cipher_suite (&builder, SQ_TPK_CIPHER_SUITE_CV25519);
-/// sq_tpk_builder_generate (ctx, builder, &tpk, &revocation);
-/// assert (tpk);
-/// assert (revocation);
-/// sq_signature_free (revocation); /* Free the generated one. */
-///
-/// tpk = sq_tpk_revoke_in_place (ctx, tpk,
-/// SQ_REASON_FOR_REVOCATION_KEY_COMPROMISED,
-/// "It was the maid :/");
-///
-/// sq_revocation_status_t rs = sq_tpk_revocation_status (tpk);
-/// assert (sq_revocation_status_variant (rs) == SQ_REVOCATION_STATUS_REVOKED);
-/// sq_revocation_status_free (rs);
-///
-/// sq_tpk_free (tpk);
-/// sq_context_free (ctx);
-/// ```
-#[no_mangle]
-pub extern "system" fn sq_tpk_revoke_in_place(ctx: Option<&mut Context>,
- tpk: *mut TPK,
- code: c_int,
- reason: Option<*const c_char>)
- -> *mut TPK
-{
- let ctx = ctx.expect("Context is NULL");
- assert!(!tpk.is_null());
- let tpk = unsafe {
- Box::from_raw(tpk)
- };
- let code = int_to_reason_for_revocation(code);
- let reason = if let Some(reason) = reason {
- unsafe {
- CStr::from_ptr(reason).to_bytes()
- }
- } else {
- b""
- };
-
- fry_box!(ctx, tpk.revoke_in_place(code, reason))
-}
-
-/// Returns whether the TPK has expired.
-#[no_mangle]
-pub extern "system" fn sq_tpk_expired(tpk: Option<&TPK>)
- -> c_int {
- let tpk = tpk.expect("TPK is NULL");
-
- tpk.expired() as c_int
-}
-
-/// Returns whether the TPK has expired.
-#[no_mangle]
-pub extern "system" fn sq_tpk_expired_at(tpk: Option<&TPK>, when: time_t)
- -> c_int {
- let tpk = tpk.expect("TPK is NULL");
- tpk.expired_at(time::at(time::Timespec::new(when as i64, 0))) as c_int
-}
-
-/// Returns whether the TPK is alive.
-#[no_mangle]
-pub extern "system" fn sq_tpk_alive(tpk: Option<&TPK>)
- -> c_int {
- let tpk = tpk.expect("TPK is NULL");
-
- tpk.alive() as c_int
-}
-
-/// Returns whether the TPK is alive at the specified time.
-#[no_mangle]
-pub extern "system" fn sq_tpk_alive_at(tpk: Option<&TPK>, when: time_t)
- -> c_int {
- let tpk = tpk.expect("TPK is NULL");
- tpk.alive_at(time::at(time::Timespec::new(when as i64, 0))) as c_int
-}
-
-/// Changes the TPK's expiration.
-///
-/// Expiry is when the key should expire in seconds relative to the
-/// key's creation (not the current time).
-///
-/// This function consumes `tpk` and returns a new `TPK`.
-#[no_mangle]
-pub extern "system" fn sq_tpk_set_expiry(ctx: Option<&mut Context>,
- tpk: *mut TPK, expiry: u32)
- -> *mut TPK {
- let ctx = ctx.expect("CTX is NULL");
- assert!(!tpk.is_null());
- let tpk = unsafe {
- Box::from_raw(tpk)
- };
-
- fry_box!(ctx, tpk.set_expiry_in_seconds(expiry))
-}
-
-/// Returns whether the TPK includes any secret key material.
-#[no_mangle]
-pub extern "system" fn sq_tpk_is_tsk(tpk: Option<&TPK>)
- -> c_int {
- let tpk = tpk.expect("TPK is NULL");
- tpk.is_tsk() as c_int
-}
-
-/// Returns an iterator over the TPK's user id bindings.
-#[no_mangle]
-pub extern "system" fn sq_tpk_primary_user_id(tpk: Option<&TPK>)
- -> *mut c_char
-{
- let tpk = tpk.expect("TPK is NULL");
- if let Some(binding) = tpk.userids().nth(0) {
- CString::new(binding.userid().userid())
- .unwrap() // Errors only on internal nul bytes.
- .into_raw()
- } else {
- ptr::null_mut()
- }
-}
-
fn revocation_status_to_int(rs: &RevocationStatus) -> c_int {
match rs {
RevocationStatus::Revoked(_) => 0,
@@ -550,287 +128,6 @@ pub extern "system" fn sq_revocation_status_free(
};
}
-/* UserIDBinding */
-
-/// Returns the user id.
-///
-/// This function may fail and return NULL if the user id contains an
-/// interior NUL byte. We do this rather than complicate the API, as
-/// there is no valid use for such user ids; they must be malicious.
-///
-/// The caller must free the returned value.
-#[no_mangle]
-pub extern "system" fn sq_user_id_binding_user_id(
- binding: Option<&UserIDBinding>)
- -> *mut c_char
-{
- let binding = binding.expect("Binding is NULL");
-
- if let Ok(c_str) = CString::new(binding.userid().userid()) {
- c_str.into_raw()
- } else {
- ptr::null_mut()
- }
-}
-
-/// Returns a reference to the self-signature, if any.
-#[no_mangle]
-pub extern "system" fn sq_user_id_binding_selfsig(
- binding: Option<&UserIDBinding>)
- -> Option<&Signature>
-{
- let binding = binding.expect("Binding is NULL");
- binding.binding_signature()
-}
-
-
-/* UserIDBindingIter */
-
-/// Returns an iterator over the TPK's user id bindings.
-#[no_mangle]
-pub extern "system" fn sq_tpk_user_id_binding_iter(tpk: Option<&TPK>)
- -> *mut UserIDBindingIter
-{
- let tpk = tpk.expect("TPK is NULL");
- box_raw!(tpk.userids())
-}
-
-/// Frees a sq_user_id_binding_iter_t.
-#[no_mangle]
-pub extern "system" fn sq_user_id_binding_iter_free(
- iter: *mut UserIDBindingIter)
-{
- if iter.is_null() { return };
- unsafe {
- drop(Box::from_raw(iter))
- };
-}
-
-/// Returns the next `UserIDBinding`.
-#[no_mangle]
-pub extern "system" fn sq_user_id_binding_iter_next<'a>(
- iter: Option<&mut UserIDBindingIter<'a>>)
- -> Option<&'a UserIDBinding>
-{
- let iter = iter.expect("Iterator is NULL");
- iter.next()
-}
-
-/* tpk::KeyIter. */
-
-/// Wrapers a KeyIter for export via the FFI.
-pub struct KeyIterWrapper<'a> {
- iter: KeyIter<'a>,
- rso: Option<RevocationStatus<'a>>,
-}
-
-/// Returns an iterator over the TPK's keys.
-///
-/// This iterates over both the primary key and any subkeys.
-#[no_mangle]
-pub extern "system" fn sq_tpk_key_iter(tpk: Option<&TPK>)
- -> *mut KeyIterWrapper
-{
- let tpk = tpk.expect("TPK is NULL");
- box_raw!(KeyIterWrapper {
- iter: tpk.keys(),
- rso: None,
- })
-}
-
-/// Frees a sq_tpk_key_iter_t.
-#[no_mangle]
-pub extern "system" fn sq_tpk_key_iter_free(
- iter: *mut KeyIterWrapper)
-{
- if iter.is_null() { return };
- unsafe {
- drop(Box::from_raw(iter))
- };
-}
-
-/// Returns the next key. Returns NULL if there are no more elements.
-///
-/// If sigo is not NULL, stores the current self-signature (if any) in
-/// *sigo. (Note: subkeys always have signatures, but a primary key
-/// may not have a direct signature, and there might not be any user
-/// ids.)
-///
-/// If rso is not NULL, this stores the key's revocation status in
-/// *rso.
-#[no_mangle]
-pub extern "system" fn sq_tpk_key_iter_next<'a>(
- iter_wrapper: Option<&'a mut KeyIterWrapper<'a>>,
- sigo: Option<&mut Option<&'a packet::Signature>>,
- rso: Option<&mut &'a RevocationStatus<'a>>)
- -> Option<&'a packet::Key>
-{
- let iter_wrapper = iter_wrapper.expect("Iterator is NULL");
- iter_wrapper.rso = None;
-
- if let Some((sig, rs, key)) = iter_wrapper.iter.next() {
- if let Some(ptr) = sigo {
- *ptr = sig;
- }
-
- if let Some(ptr) = rso {
- iter_wrapper.rso = Some(rs);
- *ptr = iter_wrapper.rso.as_ref().unwrap();
- }
-
- Some(key)
- } else {
- None
- }
-}
-
-/* TPKBuilder */
-
-/// Creates a default `sq_tpk_builder_t`.
-///
-/// # Example
-///
-/// ```c
-/// #include <assert.h>
-/// #include <sequoia.h>
-///
-/// 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);
-///
-/// builder = sq_tpk_builder_default ();
-/// sq_tpk_builder_set_cipher_suite (&builder, SQ_TPK_CIPHER_SUITE_CV25519);
-/// sq_tpk_builder_add_userid (&builder, "some@example.org");
-/// sq_tpk_builder_add_signing_subkey (&builder);
-/// sq_tpk_builder_add_encryption_subkey (&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 {
- box_raw!(TPKBuilder::default())
-}
-
-/// Generates a key compliant to [Autocrypt Level 1].
-///
-/// [Autocrypt Level 1]: https://autocrypt.org/level1.html
-#[no_mangle]
-pub extern "system" fn sq_tpk_builder_autocrypt() -> *mut TPKBuilder {
- use self::openpgp::autocrypt::Autocrypt;
- box_raw!(TPKBuilder::autocrypt(Autocrypt::V1))
-}
-
-/// Frees an `sq_tpk_builder_t`.
-#[no_mangle]
-pub extern "system" fn sq_tpk_builder_free(tpkb: *mut TPKBuilder)
-{
- if tpkb.is_null() {
- return
- }
- unsafe {
- drop(Box::from_raw(tpkb));
- }
-}
-
-/// Sets the encryption and signature algorithms for primary and all
-/// subkeys.
-#[no_mangle]
-pub extern "system" fn sq_tpk_builder_set_cipher_suite
- (tpkb: Option<&mut *mut TPKBuilder>, cs: c_int)
-{
- use self::CipherSuite::*;
- let tpkb = tpkb.expect("TPKB is NULL");
- assert!(! tpkb.is_null());
- let tpkb_ = unsafe { Box::from_raw(*tpkb) };
- let cs = match cs {
- 0 => Cv25519,
- 1 => RSA3k,
- n => panic!("Bad ciphersuite: {}", n),
- };
- let tpkb_ = tpkb_.set_cipher_suite(cs);
- *tpkb = box_raw!(tpkb_);
-}
-
-/// Adds a new user ID. The first user ID added replaces the default
-/// ID that is just the empty string.
-#[no_mangle]
-pub extern "system" fn sq_tpk_builder_add_userid
- (tpkb: Option<&mut *mut TPKBuilder>, uid: *const c_char)
-{
- let tpkb = tpkb.expect("TPKB is NULL");
- assert!(!tpkb.is_null());
- let tpkb_ = unsafe { Box::from_raw(*tpkb) };
- let uid = unsafe { CStr::from_ptr(uid).to_string_lossy().to_string() };
- let tpkb_ = tpkb_.add_userid(uid.as_ref());
- *tpkb = box_raw!(tpkb_);
-}
-
-/// Adds a signing capable subkey.
-#[no_mangle]
-pub extern "system" fn sq_tpk_builder_add_signing_subkey
- (tpkb: Option<&mut *mut TPKBuilder>)
-{
- let tpkb = tpkb.expect("TPKB is NULL");
- assert!(!tpkb.is_null());
- let tpkb_ = unsafe { Box::from_raw(*tpkb) };
- let tpkb_ = tpkb_.add_signing_subkey();
- *tpkb = box_raw!(tpkb_);
-}
-
-/// Adds an encryption capable subkey.
-#[no_mangle]
-pub extern "system" fn sq_tpk_builder_add_encryption_subkey
- (tpkb: Option<&mut *mut TPKBuilder>)
-{
- let tpkb = tpkb.expect("TPKB is NULL");
- assert!(!tpkb.is_null());
- let tpkb_ = unsafe { Box::from_raw(*tpkb) };
- let tpkb_ = tpkb_.add_encryption_subkey();
- *tpkb = box_raw!(tpkb_);
-}
-
-/// Adds an certification capable subkey.
-#[no_mangle]
-pub extern "system" fn sq_tpk_builder_add_certification_subkey
- (tpkb: Option<&mut *mut TPKBuilder>)
-{
- let tpkb = tpkb.expect("TPKB is NULL");
- assert!(!tpkb.is_null());
- let tpkb_ = unsafe { Box::from_raw(*tpkb) };
- let tpkb_ = tpkb_.add_certification_subkey();
- *tpkb = box_raw!(tpkb_);
-}
-
-/// Generates the actual TPK.
-///
-/// Consumes `tpkb`.
-#[no_mangle]
-pub extern "system" fn sq_tpk_builder_generate
- (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) };
- 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)),
- }
-}
-
-
/* TSK */
/// Generates a new RSA 3072 bit key with UID `primary_uid`.
diff --git a/ffi/src/openpgp/tpk.rs b/ffi/src/openpgp/tpk.rs
new file mode 100644
index 00000000..eaa8ef40
--- /dev/null
+++ b/ffi/src/openpgp/tpk.rs
@@ -0,0 +1,729 @@
+//! Handles TPKs.
+//!
+//! Wraps [`sequoia-openpgp::TPK`] and [related functionality].
+//!
+//! [`sequoia-openpgp::TPK`]: ../../../sequoia_openpgp/struct.TPK.html
+//! [related functionality]: ../../../sequoia_openpgp/tpk/index.html
+
+use std::ffi::{CString, CStr};
+use std::ptr;
+use std::slice;
+use std::io::{Read, Write};
+use libc::{uint8_t, c_char, c_int, size_t, time_t};
+
+extern crate sequoia_openpgp;
+use self::sequoia_openpgp::{
+ Fingerprint,
+ Packet,
+ PacketPile,
+ RevocationStatus,
+ TPK,
+ TSK,
+ autocrypt::Autocrypt,
+ constants::ReasonForRevocation,
+ packet::{self, Signature},
+ parse::PacketParserResult,
+ parse::Parse,
+ serialize::Serialize,
+ tpk::{
+ CipherSuite,
+ KeyIter,
+ TPKBuilder,
+ UserIDBinding,
+ UserIDBindingIter,
+ },
+};
+
+use ::core::Context;
+use ::error::Status;
+
+/// Returns the first TPK encountered in the reader.
+#[no_mangle]
+pub extern "system" fn sq_tpk_from_reader(ctx: Option<&mut Context>,
+ reader: Option<&mut Box<Read>>)
+ -> *mut TPK {
+ let ctx = ctx.expect("Context is NULL");
+ let reader = reader.expect("Reader is NULL");
+ fry_box!(ctx, TPK::from_reader(reader))
+}
+
+/// Returns the first TPK encountered in the file.
+#[no_mangle]
+pub extern "system" fn sq_tpk_from_file(ctx: Option<&mut Context>,
+ filename: *const c_char)
+ -> *mut TPK {
+ let ctx = ctx.expect("Context is NULL");
+ assert!(! filename.is_null());
+ let filename = unsafe {
+ CStr::from_ptr(filename).to_string_lossy().into_owned()
+ };
+ fry_box!(ctx, TPK::from_file(&filename))
+}
+
+/// Returns the first TPK found in `m`.
+///
+/// Consumes `m`.
+#[no_mangle]
+pub extern "system" fn sq_tpk_from_packet_pile(ctx: Option<&mut Context>,
+ m: *mut PacketPile)
+ -> *mut TPK {
+ let ctx = ctx.expect("Context is NULL");
+ assert!(! m.is_null());
+ let m = unsafe { Box::from_raw(m) };
+ fry_box!(ctx, TPK::from_packet_pile(*m))
+}
+
+/// Returns the first TPK found in `buf`.
+///
+/// `buf` must be an OpenPGP-encoded TPK.
+#[no_mangle]
+pub extern "system" fn sq_tpk_from_bytes(ctx: Option<&mut Context>,
+ b: *const uint8_t, len: size_t)
+ -> *mut TPK {
+ let ctx = ctx.expect("Context is NULL");
+ assert!(!b.is_null());
+ let buf = unsafe {
+ slice::from_raw_parts(b, len as usize)
+ };
+
+ fry_box!(ctx, TPK::from_bytes(buf))
+}
+
+/// Returns the first TPK found in the packet parser.
+///
+/// Consumes the packet parser result.
+#[no_mangle]
+pub extern "system" fn sq_tpk_from_packet_parser(ctx: Option<&mut Context>,
+ ppr: *mut PacketParserResult)