summaryrefslogtreecommitdiffstats
path: root/openpgp-ffi/src/common.rs
diff options
context:
space:
mode:
authorJustus Winter <justus@sequoia-pgp.org>2019-01-17 11:11:27 +0100
committerJustus Winter <justus@sequoia-pgp.org>2019-01-17 16:48:28 +0100
commit3f58832474a4b270e136544016a401ef773ac065 (patch)
treec617160250c3040ca964c1b72ab5957cd872b82f /openpgp-ffi/src/common.rs
parent38b4108cc1eac851ac17932c5c33623dd535bebb (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.rs1873
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