diff options
author | Justus Winter <justus@sequoia-pgp.org> | 2019-01-17 11:11:27 +0100 |
---|---|---|
committer | Justus Winter <justus@sequoia-pgp.org> | 2019-01-17 16:48:28 +0100 |
commit | 3f58832474a4b270e136544016a401ef773ac065 (patch) | |
tree | c617160250c3040ca964c1b72ab5957cd872b82f /openpgp-ffi/src/common.rs | |
parent | 38b4108cc1eac851ac17932c5c33623dd535bebb (diff) |
openpgp-ffi: New crate.
- This creates a new crate, 'sequoia-openpgp-ffi', and moves a
handful of functions from 'sequoia-ffi' to it.
- The 'sequoia-ffi' crate is a superset of the 'sequoia-openpgp-ffi'
crate. This is accomplished by some include! magic.
- My first attempt involved having 'sequoia-ffi' depend on
'sequoia-openpgp-ffi', so that the former just re-exports the
symbols. However, that turned out to be unreliable, and might be
not what we want, because it could also duplicate parts of Rust's
standard library.
- Fixes #144.
Diffstat (limited to 'openpgp-ffi/src/common.rs')
-rw-r--r-- | openpgp-ffi/src/common.rs | 1873 |
1 files changed, 1873 insertions, 0 deletions
diff --git a/openpgp-ffi/src/common.rs b/openpgp-ffi/src/common.rs new file mode 100644 index 00000000..8adacb81 --- /dev/null +++ b/openpgp-ffi/src/common.rs @@ -0,0 +1,1873 @@ +// Common code for sequoia-openpgp-ffi and sequoia-ffi. + +use std::collections::hash_map::{DefaultHasher, RandomState}; +use std::hash::BuildHasher; + +/* Canonical free(). */ + +/// Transfers ownership from C to Rust, then frees the object. +/// +/// NOP if called with NULL. +macro_rules! ffi_free { + ($name:ident) => {{ + if let Some(ptr) = $name { + unsafe { + drop(Box::from_raw(ptr)) + } + } + }}; +} + +/* Parameter handling. */ + +/// Transfers ownership from C to Rust. +/// +/// # Panics +/// +/// Panics if called with NULL. +macro_rules! ffi_param_move { + ($name:expr) => {{ + if $name.is_null() { + panic!("Parameter {} is NULL", stringify!($name)); + } + unsafe { + Box::from_raw($name) + } + }}; +} + +/// Transfers a reference from C to Rust. +/// +/// # Panics +/// +/// Panics if called with NULL. +macro_rules! ffi_param_ref { + ($name:ident) => {{ + if $name.is_null() { + panic!("Parameter {} is NULL", stringify!($name)); + } + unsafe { + &*$name + } + }}; +} + +/// Transfers a mutable reference from C to Rust. +/// +/// # Panics +/// +/// Panics if called with NULL. +macro_rules! ffi_param_ref_mut { + ($name:ident) => {{ + if $name.is_null() { + panic!("Parameter {} is NULL", stringify!($name)); + } + unsafe { + &mut *$name + } + }}; +} + +/// Transfers a reference to a string from C to Rust. +/// +/// # Panics +/// +/// Panics if called with NULL. +macro_rules! ffi_param_cstr { + ($name:expr) => {{ + if $name.is_null() { + panic!("Parameter {} is NULL", stringify!($name)); + } + unsafe { + ::std::ffi::CStr::from_ptr($name) + } + }}; +} + +/* Return value handling. */ + +/// Duplicates a string similar to strndup(3). +#[allow(dead_code)] +pub(crate) fn strndup(src: &[u8]) -> Option<*mut libc::c_char> { + if src.contains(&0) { + return None; + } + + let l = src.len() + 1; + let s = unsafe { + ::std::slice::from_raw_parts_mut(libc::malloc(l) as *mut u8, l) + }; + &mut s[..l - 1].copy_from_slice(src); + s[l - 1] = 0; + + Some(s.as_mut_ptr() as *mut libc::c_char) +} + +/// Transfers a string from Rust to C, allocating it using malloc. +/// +/// # Panics +/// +/// Panics if the given string contains a 0. +macro_rules! ffi_return_string { + ($name:expr) => {{ + let string = $name; + let bytes: &[u8] = string.as_ref(); + ::strndup(bytes).expect( + &format!("Returned string {} contains a 0 byte.", stringify!($name)) + ) + }}; +} + +/// Transfers a string from Rust to C, allocating it using malloc. +/// +/// # Panics +/// +/// Does *NOT* panic if the given string contains a 0, but returns +/// `NULL`. +macro_rules! ffi_return_maybe_string { + ($name:expr) => {{ + let string = $name; + let bytes: &[u8] = string.as_ref(); + ::strndup(bytes).unwrap_or(::std::ptr::null_mut()) + }}; +} + +/* Error handling with implicit error return argument. */ + +/// Emits local macros for error handling that use the given context +/// to store complex errors. +macro_rules! ffi_make_fry_from_errp { + ($errp:expr) => { + /// Like try! for ffi glue. + /// + /// Evaluates the given expression. On success, evaluate to + /// `Status.Success`. On failure, stashes the error in the + /// context and evaluates to the appropriate Status code. + #[allow(unused_macros)] + macro_rules! ffi_try_status { + ($expr:expr) => { + match $expr { + Ok(_) => Status::Success, + Err(e) => { + let status = Status::from(&e); + if let Some(errp) = $errp { + *errp = box_raw!(e); + } + status + }, + } + }; + } + + /// Like try! for ffi glue. + /// + /// Unwraps the given expression. On failure, stashes the + /// error in the context and returns $or. + #[allow(unused_macros)] + macro_rules! ffi_try_or { + ($expr:expr, $or:expr) => { + match $expr { + Ok(v) => v, + Err(e) => { + if let Some(errp) = $errp { + *errp = box_raw!(e); + } + return $or; + }, + } + }; + } + + /// Like try! for ffi glue. + /// + /// Unwraps the given expression. On failure, stashes the + /// error in the context and returns NULL. + #[allow(unused_macros)] + macro_rules! ffi_try { + ($expr:expr) => { + ffi_try_or!($expr, ::std::ptr::null_mut()) + }; + } + + /// Like try! for ffi glue, then box into raw pointer. + /// + /// This is used to transfer ownership from Rust to C. + /// + /// Unwraps the given expression. On success, it boxes the + /// value and turns it into a raw pointer. On failure, + /// stashes the error in the context and returns NULL. + #[allow(unused_macros)] + macro_rules! ffi_try_box { + ($expr:expr) => { + Box::into_raw(Box::new(ffi_try!($expr))) + } + } + } +} + +/// Box, then turn into raw pointer. +/// +/// This is used to transfer ownership from Rust to C. +macro_rules! box_raw { + ($expr:expr) => { + Box::into_raw(Box::new($expr)) + } +} + +/// Box an Option<T>, then turn into raw pointer. +/// +/// This is used to transfer ownership from Rust to C. +macro_rules! maybe_box_raw { + ($expr:expr) => { + $expr.map(|x| box_raw!(x)).unwrap_or(ptr::null_mut()) + } +} + +/// Builds hashers for computing hashes. +/// +/// This is used to derive Hasher instances for computing hashes of +/// objects so that they can be used in hash tables by foreign code. +pub(crate) fn build_hasher() -> DefaultHasher { + lazy_static! { + static ref RANDOM_STATE: RandomState = RandomState::new(); + } + RANDOM_STATE.build_hasher() +} + +pub mod armor; +pub mod crypto; +pub mod error; +pub mod fingerprint; +pub mod io; +pub mod keyid; +pub mod packet_pile; +pub mod tpk; +pub mod tsk; + +use std::mem::forget; +use std::ptr; +use std::slice; +use std::io as std_io; +use std::io::{Read, Write}; +use libc::{uint8_t, c_char, c_int, size_t, ssize_t, c_void, time_t}; +use failure::ResultExt; + +extern crate sequoia_openpgp as openpgp; +extern crate time; + +use self::openpgp::{ + Fingerprint, + KeyID, + RevocationStatus, + TPK, + Packet, + packet::{ + Signature, + Tag, + PKESK, + SKESK, + key::SecretKey, + }, + crypto::Password, +}; +use self::openpgp::packet; +use self::openpgp::parse::{ + Parse, + PacketParserResult, + PacketParser, + PacketParserEOF, +}; +use self::openpgp::parse::stream::{ + DecryptionHelper, + Decryptor, + Secret, + VerificationHelper, + VerificationResult, + Verifier, + DetachedVerifier, +}; +use self::openpgp::constants::{ + DataFormat, +}; + +use error::Status; + + +/* openpgp::packet::Tag. */ + +/// Returns a human-readable tag name. +/// +/// ```c +/// #include <assert.h> +/// #include <string.h> +/// #include <sequoia/openpgp.h> +/// +/// assert (strcmp (sq_tag_to_string (2), "SIGNATURE") == 0); +/// ``` +#[::ffi_catch_abort] #[no_mangle] +pub extern "system" fn sq_tag_to_string(tag: u8) -> *const c_char { + match Tag::from(tag) { + Tag::PKESK => "PKESK\x00", + Tag::Signature => "SIGNATURE\x00", + Tag::SKESK => "SKESK\x00", + Tag::OnePassSig => "ONE PASS SIG\x00", + Tag::SecretKey => "SECRET KEY\x00", + Tag::PublicKey => "PUBLIC KEY\x00", + Tag::SecretSubkey => "SECRET SUBKEY\x00", + Tag::CompressedData => "COMPRESSED DATA\x00", + Tag::SED => "SED\x00", + Tag::Marker => "MARKER\x00", + Tag::Literal => "LITERAL\x00", + Tag::Trust => "TRUST\x00", + Tag::UserID => "USER ID\x00", + Tag::PublicSubkey => "PUBLIC SUBKEY\x00", + Tag::UserAttribute => "USER ATTRIBUTE\x00", + Tag::SEIP => "SEIP\x00", + Tag::MDC => "MDC\x00", + _ => "OTHER\x00", + }.as_bytes().as_ptr() as *const c_char +} + +fn revocation_status_to_int(rs: &RevocationStatus) -> c_int { + match rs { + RevocationStatus::Revoked(_) => 0, + RevocationStatus::CouldBe(_) => 1, + RevocationStatus::NotAsFarAsWeKnow => 2, + } +} + +/// Returns the TPK's revocation status variant. +#[::ffi_catch_abort] #[no_mangle] +pub extern "system" fn sq_revocation_status_variant( + rs: *mut RevocationStatus) + -> c_int +{ + let rs = ffi_param_move!(rs); + let variant = revocation_status_to_int(rs.as_ref()); + Box::into_raw(rs); + variant +} + +/// Frees a sq_revocation_status_t. +#[::ffi_catch_abort] #[no_mangle] +pub extern "system" fn sq_revocation_status_free( + rs: Option<&mut RevocationStatus>) +{ + ffi_free!(rs) +} + +/* openpgp::Packet. */ + +/// Frees the Packet. +#[::ffi_catch_abort] #[no_mangle] +pub extern "system" fn sq_packet_free(p: Option<&mut Packet>) { + ffi_free!(p) +} + +/// Returns the `Packet's` corresponding OpenPGP tag. +/// +/// Tags are explained in [Section 4.3 of RFC 4880]. +/// +/// [Section 4.3 of RFC 4880]: https://tools.ietf.org/html/rfc4880#section-4.3 +#[::ffi_catch_abort] #[no_mangle] +pub extern "system" fn sq_packet_tag(p: *const Packet) + -> uint8_t { + let p = ffi_param_ref!(p); + let tag: u8 = p.tag().into(); + tag as uint8_t +} + +/// Returns the parsed `Packet's` corresponding OpenPGP tag. +/// +/// Returns the packets tag, but only if it was successfully +/// parsed into the corresponding packet type. If e.g. a +/// Signature Packet uses some unsupported methods, it is parsed +/// into an `Packet::Unknown`. `tag()` returns `SQ_TAG_SIGNATURE`, +/// whereas `kind()` returns `0`. +#[::ffi_catch_abort] #[no_mangle] +pub extern "system" fn sq_packet_kind(p: *const Packet) + -> uint8_t { + let p = ffi_param_ref!(p); + if let Some(kind) = p.kind() { + kind.into() + } else { + 0 + } +} + +/// Frees the Signature. +#[::ffi_catch_abort] #[no_mangle] +pub extern "system" fn sq_signature_free(s: Option<&mut Signature>) { + ffi_free!(s) +} + +/// Converts the signature to a packet. +#[::ffi_catch_abort] #[no_mangle] +pub extern "system" fn sq_signature_to_packet(s: *mut Signature) + -> *mut Packet +{ + let s = ffi_param_move!(s); + box_raw!(s.to_packet()) +} + +/// Returns the value of the `Signature` packet's Issuer subpacket. +/// +/// If there is no Issuer subpacket, this returns NULL. Note: if +/// there is no Issuer subpacket, but there is an IssuerFingerprint +/// subpacket, this still returns NULL. +#[::ffi_catch_abort] #[no_mangle] +pub extern "system" fn sq_signature_issuer(sig: *const packet::Signature) + -> *mut KeyID { + let sig = ffi_param_ref!(sig); + maybe_box_raw!(sig.issuer()) +} + +/// Returns the value of the `Signature` packet's IssuerFingerprint subpacket. +/// +/// If there is no IssuerFingerprint subpacket, this returns NULL. +/// Note: if there is no IssuerFingerprint subpacket, but there is an +/// Issuer subpacket, this still returns NULL. +#[::ffi_catch_abort] #[no_mangle] +pub extern "system" fn sq_signature_issuer_fingerprint( + sig: *const packet::Signature) + -> *mut Fingerprint +{ + let sig = ffi_param_ref!(sig); + maybe_box_raw!(sig.issuer_fingerprint()) +} + + +/// Returns whether the KeyFlags indicates that the key can be used to +/// make certifications. +#[::ffi_catch_abort] #[no_mangle] +pub extern "system" fn sq_signature_can_certify(sig: *const packet::Signature) + -> bool +{ + let sig = ffi_param_ref!(sig); + sig.key_flags().can_certify() +} + +/// Returns whether the KeyFlags indicates that the key can be used to +/// make signatures. +#[::ffi_catch_abort] #[no_mangle] +pub extern "system" fn sq_signature_can_sign(sig: *const packet::Signature) + -> bool +{ + let sig = ffi_param_ref!(sig); + sig.key_flags().can_sign() +} + +/// Returns whether the KeyFlags indicates that the key can be used to +/// encrypt data for transport. +#[::ffi_catch_abort] #[no_mangle] +pub extern "system" fn sq_signature_can_encrypt_for_transport(sig: *const packet::Signature) + -> bool +{ + let sig = ffi_param_ref!(sig); + sig.key_flags().can_encrypt_for_transport() +} + +/// Returns whether the KeyFlags indicates that the key can be used to +/// encrypt data at rest. +#[::ffi_catch_abort] #[no_mangle] +pub extern "system" fn sq_signature_can_encrypt_at_rest(sig: *const packet::Signature) + -> bool +{ + let sig = ffi_param_ref!(sig); + sig.key_flags().can_encrypt_at_rest() +} + +/// Returns whether the KeyFlags indicates that the key can be used +/// for authentication. +#[::ffi_catch_abort] #[no_mangle] +pub extern "system" fn sq_signature_can_authenticate(sig: *const packet::Signature) + -> bool +{ + let sig = ffi_param_ref!(sig); + sig.key_flags().can_authenticate() +} + +/// Returns whether the KeyFlags indicates that the key is a split +/// key. +#[::ffi_catch_abort] #[no_mangle] +pub extern "system" fn sq_signature_is_split_key(sig: *const packet::Signature) + -> bool +{ + let sig = ffi_param_ref!(sig); + sig.key_flags().is_split_key() +} + +/// Returns whether the KeyFlags indicates that the key is a group +/// key. +#[::ffi_catch_abort] #[no_mangle] +pub extern "system" fn sq_signature_is_group_key(sig: *const packet::Signature) + -> bool +{ + let sig = ffi_param_ref!(sig); + sig.key_flags().is_group_key() +} + + +/// Returns whether the signature is alive. +/// +/// A signature is alive if the creation date is in the past, and the +/// signature has not expired. +#[::ffi_catch_abort] #[no_mangle] +pub extern "system" fn sq_signature_alive(sig: *const packet::Signature) + -> bool +{ + let sig = ffi_param_ref!(sig); + sig.signature_alive() +} + +/// Returns whether the signature is alive at the specified time. +/// +/// A signature is alive if the creation date is in the past, and the +/// signature has not expired at the specified time. +#[::ffi_catch_abort] #[no_mangle] +pub extern "system" fn sq_signature_alive_at(sig: *const packet::Signature, + when: time_t) + -> bool +{ + let sig = ffi_param_ref!(sig); + sig.signature_alive_at(time::at(time::Timespec::new(when as i64, 0))) +} + +/// Returns whether the signature is expired. +#[::ffi_catch_abort] #[no_mangle] +pub extern "system" fn sq_signature_expired(sig: *const packet::Signature) + -> bool +{ + let sig = ffi_param_ref!(sig); + sig.signature_expired() +} + +/// Returns whether the signature is expired at the specified time. +#[::ffi_catch_abort] #[no_mangle] +pub extern "system" fn sq_signature_expired_at(sig: *const packet::Signature, + when: time_t) + -> bool +{ + let sig = ffi_param_ref!(sig); + sig.signature_expired_at(time::at(time::Timespec::new(when as i64, 0))) +} + + +/// Clones the key. +#[::ffi_catch_abort] #[no_mangle] +pub extern "system" fn sq_p_key_clone(key: *const packet::Key) + -> *mut packet::Key { + let key = ffi_param_ref!(key); + box_raw!(key.clone()) +} + +/// Computes and returns the key's fingerprint as per Section 12.2 +/// of RFC 4880. +#[::ffi_catch_abort] #[no_mangle] +pub extern "system" fn sq_p_key_fingerprint(key: *const packet::Key) + -> *mut Fingerprint { + let key = ffi_param_ref!(key); + box_raw!(key.fingerprint()) +} + +/// Computes and returns the key's key ID as per Section 12.2 of RFC +/// 4880. +#[::ffi_catch_abort] #[no_mangle] +pub extern "system" fn sq_p_key_keyid(key: *const packet::Key) + -> *mut KeyID { + let key = ffi_param_ref!(key); + box_raw!(key.keyid()) +} + +/// Returns whether the key is expired according to the provided +/// self-signature. +/// +/// Note: this is with respect to the provided signature, which is not +/// checked for validity. That is, we do not check whether the +/// signature is a valid self-signature for the given key. +#[::ffi_catch_abort] #[no_mangle] +pub extern "system" fn sq_p_key_expired(key: *const packet::Key, + sig: *const packet::Signature) + -> bool +{ + let key = ffi_param_ref!(key); + let sig = ffi_param_ref!(sig); + + sig.key_expired(key) +} + +/// Like sq_p_key_expired, but at a specific time. +#[::ffi_catch_abort] #[no_mangle] +pub extern "system" fn sq_p_key_expired_at(key: *const packet::Key, + sig: *const packet::Signature, + when: time_t) + -> bool +{ + let key = ffi_param_ref!(key); + let sig = ffi_param_ref!(sig); + + sig.key_expired_at(key, time::at(time::Timespec::new(when as i64, 0))) +} + +/// Returns whether the key is alive according to the provided +/// self-signature. +/// +/// A key is alive if the creation date is in the past, and the key +/// has not expired. +/// +/// Note: this is with respect to the provided signature, which is not +/// checked for validity. That is, we do not check whether the +/// signature is a valid self-signature for the given key. +#[::ffi_catch_abort] #[no_mangle] +pub extern "system" fn sq_p_key_alive(key: *const packet::Key, + sig: *const packet::Signature) + -> bool +{ + let key = ffi_param_ref!(key); + let sig = ffi_param_ref!(sig); + + sig.key_alive(key) +} + +/// Like sq_p_key_alive, but at a specific time. +#[::ffi_catch_abort] #[no_mangle] +pub extern "system" fn sq_p_key_alive_at(key: *const packet::Key, + sig: *const packet::Signature, + when: time_t) + -> bool +{ + let key = ffi_param_ref!(key); + let sig = ffi_param_ref!(sig); + + sig.key_alive_at(key, time::at(time::Timespec::new(when as i64, 0))) +} + +/// Returns the key's creation time. +#[::ffi_catch_abort] #[no_mangle] +pub extern "system" fn sq_p_key_creation_time(key: *const packet::Key) + -> u32 +{ + let key = ffi_param_ref!(key); + let ct = key.creation_time(); + + ct.to_timespec().sec as u32 +} + +/// Returns the key's public key algorithm. +#[::ffi_catch_abort] #[no_mangle] +pub extern "system" fn sq_p_key_public_key_algo(key: *const packet::Key) + -> c_int +{ + let key = ffi_param_ref!(key); + let pk_algo : u8 = key.pk_algo().into(); + pk_algo as c_int +} + +/// Returns the public key's size in bits. +#[::ffi_catch_abort] #[no_mangle] +pub extern "system" fn sq_p_key_public_key_bits(key: *const packet::Key) + -> c_int +{ + use self::openpgp::crypto::mpis::PublicKey::*; + + let key = ffi_param_ref!(key); + match key.mpis() { + RSA { e: _, n } => n.bits as c_int, + DSA { p: _, q: _, g: _, y } => y.bits as c_int, + Elgamal { p: _, g: _, y } => y.bits as c_int, + EdDSA { curve: _, q } => q.bits as c_int, + ECDSA { curve: _, q } => q.bits as c_int, + ECDH { curve: _, q, hash: _, sym: _ } => q.bits as c_int, + Unknown { mpis: _, rest: _ } => 0, + } +} + +/// Creates a new key pair from a Key packet with an unencrypted +/// secret key. +/// +/// # Errors +/// +/// Fails if the secret key is missing, or encrypted. +#[::ffi_catch_abort] #[no_mangle] +pub extern "system" fn sq_p_key_into_key_pair(errp: Option<&mut *mut failure::Error>, + key: *mut packet::Key) + -> *mut self::openpgp::crypto::KeyPair +{ + ffi_make_fry_from_errp!(errp); + let key = ffi_param_move!(key); + ffi_try_box!(key.into_keypair()) +} + +/// Returns the value of the User ID Packet. +/// +/// The returned pointer is valid until `uid` is deallocated. If +/// `value_len` is not `NULL`, the size of value is stored there. +#[::ffi_catch_abort] #[no_mangle] +pub extern "system" fn sq_user_id_value(uid: *const Packet, + value_len: Option<&mut size_t>) + -> *const uint8_t { + let uid = ffi_param_ref!(uid); + if let &Packet::UserID(ref uid) = uid { + if let Some(p) = value_len { + *p = uid.userid().len(); + } + uid.userid().as_ptr() + } else { + panic!("Not a UserID packet"); + } +} + +/// Returns the value of the User Attribute Packet. +/// +/// The returned pointer is valid until `ua` is deallocated. If +/// `value_len` is not `NULL`, the size of value is stored there. +#[::ffi_catch_abort] #[no_mangle] +pub extern "system" fn sq_user_attribute_value(ua: *const Packet, + value_len: Option<&mut size_t>) + -> *const uint8_t { + let ua = ffi_param_ref!(ua); + if let &Packet::UserAttribute(ref ua) = ua { + if let Some(p) = value_len { + *p = ua.user_attribute().len(); + } + ua.user_attribute().as_ptr() + } else { + panic!("Not a UserAttribute packet"); + } +} + +/// Returns the session key. +/// +/// `key` of size `key_len` must be a buffer large enough to hold the +/// session key. If `key` is NULL, or not large enough, then the key +/// is not written to it. Either way, `key_len` is set to the size of +/// the session key. +#[::ffi_catch_abort] #[no_mangle] +pub extern "system" fn sq_skesk_decrypt(errp: Option<&mut *mut failure::Error>, + skesk: *const Packet, + password: *const uint8_t, + password_len: size_t, + algo: *mut uint8_t, // XXX + key: *mut uint8_t, + key_len: *mut size_t) + -> Status { + ffi_make_fry_from_errp!(errp); + let skesk = ffi_param_ref!(skesk); + assert!(!password.is_null()); + let password = unsafe { + slice::from_raw_parts(password, password_len as usize) + }; + let algo = ffi_param_ref_mut!(algo); + let key_len = ffi_param_ref_mut!(key_len); + + if let &Packet::SKESK(ref skesk) = skesk { + match skesk.decrypt(&password.to_owned().into()) { + Ok((a, k)) => { + *algo = a.into(); + if !key.is_null() && *key_len >= k.len() { + unsafe { + ::std::ptr::copy(k.as_ptr(), + key, + k.len()); + } + } + *key_len = k.len(); + Status::Success + }, + Err(e) => ffi_try_status!(Err::<(), failure::Error>(e)), + } + } else { + panic!("Not a SKESK packet"); + } +} + +/// Returns the PKESK's recipient. +/// +/// The return value is a reference ot a `KeyID`. The caller must not +/// modify or free it. +#[::ffi_catch_abort] #[no_mangle] +pub extern "system" fn sq_pkesk_recipient(pkesk: *const PKESK) + -> *const KeyID { + let pkesk = ffi_param_ref!(pkesk); + pkesk.recipient() +} + +/// Returns the session key. +/// +/// `key` of size `key_len` must be a buffer large enough to hold the +/// session key. If `key` is NULL, or not large enough, then the key +/// is not written to it. Either way, `key_len` is set to the size of +/// the session key. +#[::ffi_catch_abort] #[no_mangle] +pub extern "system" fn sq_pkesk_decrypt(errp: Option<&mut *mut failure::Error>, + pkesk: *const PKESK, + secret_key: *const packet::Key, + algo: *mut uint8_t, // XXX + key: *mut uint8_t, + key_len: *mut size_t) + -> Status { + ffi_make_fry_from_errp!(errp); + let pkesk = ffi_param_ref!(pkesk); + let secret_key = ffi_param_ref!(secret_key); + let algo = ffi_param_ref_mut!(algo); + let key_len = ffi_param_ref_mut!(key_len); + + if let Some(SecretKey::Unencrypted{ mpis: ref secret_part }) = secret_key.secret() { + match pkesk.decrypt(secret_key, secret_part) { + Ok((a, k)) => { + *algo = a.into(); + if !key.is_null() && *key_len >= k.len() { + unsafe { + ::std::ptr::copy(k.as_ptr(), + key, + k.len()); + } + } + *key_len = k.len(); + Status::Success + }, + Err(e) => ffi_try_status!(Err::<(), failure::Error>(e)), + } + } else { + // XXX: Better message. + panic!("No secret parts"); + } +} + +/* openpgp::parse. */ + +/// Starts parsing OpenPGP packets stored in a `sq_reader_t` +/// object. +/// +/// This function returns a `PacketParser` for the first packet in +/// the stream. +#[::ffi_catch_abort] #[no_mangle] +pub extern "system" fn sq_packet_parser_from_reader<'a> + (errp: Option<&mut *mut failure::Error>, read |