From 65141b09cbc3d9fdbb5e7d83c2393f089a8f3d7b Mon Sep 17 00:00:00 2001 From: Justus Winter Date: Tue, 8 Jan 2019 12:20:40 +0100 Subject: ffi: Prepare to split the openpgp module. --- ffi/src/openpgp.rs | 3080 ------------------------------------------------ ffi/src/openpgp/mod.rs | 3080 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 3080 insertions(+), 3080 deletions(-) delete mode 100644 ffi/src/openpgp.rs create mode 100644 ffi/src/openpgp/mod.rs (limited to 'ffi') diff --git a/ffi/src/openpgp.rs b/ffi/src/openpgp.rs deleted file mode 100644 index bfd59733..00000000 --- a/ffi/src/openpgp.rs +++ /dev/null @@ -1,3080 +0,0 @@ -//! XXX - -use failure; -use std::ffi::{CString, CStr}; -use std::hash::{Hash, Hasher}; -use std::mem::{size_of, forget}; -use std::ptr; -use std::slice; -use std::io; -use std::io::{Read, Write}; -use libc::{self, uint8_t, uint64_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::{ - armor, - Fingerprint, - KeyID, - RevocationStatus, - PacketPile, - TPK, - TSK, - Packet, - packet::{ - Signature, - Tag, - PKESK, - SKESK, - key::SecretKey, - }, - crypto::Password, -}; -use self::openpgp::tpk::{ - CipherSuite, - TPKBuilder, - UserIDBinding, - UserIDBindingIter, - KeyIter -}; -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::serialize::Serialize; -use self::openpgp::constants::{ - DataFormat, - ReasonForRevocation, -}; - -use super::build_hasher; -use super::error::Status; -use super::core::Context; - -/* openpgp::packet::Tag. */ - -/// Returns a human-readable tag name. -/// -/// ```c -/// #include -/// #include -/// #include -/// -/// assert (strcmp (sq_tag_to_string (2), "SIGNATURE") == 0); -/// ``` -#[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 -} - -/* sequoia::openpgp::KeyID. */ - -/// Reads a binary key ID. -#[no_mangle] -pub extern "system" fn sq_keyid_from_bytes(id: *const uint8_t) -> *mut KeyID { - assert!(!id.is_null()); - let id = unsafe { slice::from_raw_parts(id, 8) }; - Box::into_raw(Box::new(KeyID::from_bytes(id))) -} - -/// Reads a hex-encoded Key ID. -#[no_mangle] -pub extern "system" fn sq_keyid_from_hex(id: *const c_char) -> *mut KeyID { - assert!(!id.is_null()); - let id = unsafe { CStr::from_ptr(id).to_string_lossy() }; - KeyID::from_hex(&id) - .map(|id| Box::into_raw(Box::new(id))) - .unwrap_or(ptr::null_mut()) -} - -/// Frees an `KeyID` object. -#[no_mangle] -pub extern "system" fn sq_keyid_free(keyid: *mut KeyID) { - if keyid.is_null() { return } - unsafe { - drop(Box::from_raw(keyid)); - } -} - -/// Clones the KeyID. -#[no_mangle] -pub extern "system" fn sq_keyid_clone(id: Option<&KeyID>) - -> *mut KeyID { - let id = id.expect("KeyID is NULL"); - box_raw!(id.clone()) -} - -/// Hashes the KeyID. -#[no_mangle] -pub extern "system" fn sq_keyid_hash(id: Option<&KeyID>) - -> uint64_t { - let id = id.expect("KeyID is NULL"); - let mut hasher = build_hasher(); - id.hash(&mut hasher); - hasher.finish() -} - -/// Converts the KeyID to its standard representation. -#[no_mangle] -pub extern "system" fn sq_keyid_to_string(id: Option<&KeyID>) - -> *mut c_char { - let id = id.expect("KeyID is NULL"); - CString::new(id.to_string()) - .unwrap() // Errors only on internal nul bytes. - .into_raw() -} - -/// Converts the KeyID to a hexadecimal number. -#[no_mangle] -pub extern "system" fn sq_keyid_to_hex(id: Option<&KeyID>) - -> *mut c_char { - let id = id.expect("KeyID is NULL"); - CString::new(id.to_hex()) - .unwrap() // Errors only on internal nul bytes. - .into_raw() -} - -/// Compares KeyIDs. -#[no_mangle] -pub extern "system" fn sq_keyid_equal(a: Option<&KeyID>, - b: Option<&KeyID>) - -> bool { - let a = a.expect("KeyID 'a' is NULL"); - let b = b.expect("KeyID 'b' is NULL"); - a == b -} - - -/* sequoia::openpgp::Fingerprint. */ - -/// Reads a binary fingerprint. -#[no_mangle] -pub extern "system" fn sq_fingerprint_from_bytes(buf: *const uint8_t, - len: size_t) - -> *mut Fingerprint { - assert!(!buf.is_null()); - let buf = unsafe { - slice::from_raw_parts(buf, len as usize) - }; - Box::into_raw(Box::new(Fingerprint::from_bytes(buf))) -} - -/// Reads a hexadecimal fingerprint. -#[no_mangle] -pub extern "system" fn sq_fingerprint_from_hex(hex: *const c_char) - -> *mut Fingerprint { - assert!(!hex.is_null()); - let hex = unsafe { CStr::from_ptr(hex).to_string_lossy() }; - Fingerprint::from_hex(&hex) - .map(|fp| Box::into_raw(Box::new(fp))) - .unwrap_or(ptr::null_mut()) -} - -/// Frees a sq_fingerprint_t. -#[no_mangle] -pub extern "system" fn sq_fingerprint_free(fp: *mut Fingerprint) { - if fp.is_null() { return } - unsafe { - drop(Box::from_raw(fp)); - } -} - -/// Clones the Fingerprint. -#[no_mangle] -pub extern "system" fn sq_fingerprint_clone(fp: Option<&Fingerprint>) - -> *mut Fingerprint { - let fp = fp.expect("Fingerprint is NULL"); - box_raw!(fp.clone()) -} - -/// Hashes the Fingerprint. -#[no_mangle] -pub extern "system" fn sq_fingerprint_hash(fp: Option<&Fingerprint>) - -> uint64_t { - let fp = fp.expect("Fingerprint is NULL"); - let mut hasher = build_hasher(); - fp.hash(&mut hasher); - hasher.finish() -} - -/// Returns a reference to the raw Fingerprint. -/// -/// This returns a reference to the internal buffer that is valid as -/// long as the fingerprint is. -#[no_mangle] -pub extern "system" fn sq_fingerprint_as_bytes(fp: Option<&Fingerprint>, fp_len: Option<&mut size_t>) - -> *const uint8_t { - let fp = fp.expect("Fingerprint is NULL"); - if let Some(p) = fp_len { - *p = fp.as_slice().len(); - } - fp.as_slice().as_ptr() -} - -/// Converts the fingerprint to its standard representation. -#[no_mangle] -pub extern "system" fn sq_fingerprint_to_string(fp: Option<&Fingerprint>) - -> *mut c_char { - let fp = fp.expect("Fingerprint is NULL"); - CString::new(fp.to_string()) - .unwrap() // Errors only on internal nul bytes. - .into_raw() -} - -/// Converts the fingerprint to a hexadecimal number. -#[no_mangle] -pub extern "system" fn sq_fingerprint_to_hex(fp: Option<&Fingerprint>) - -> *mut c_char { - let fp = fp.expect("Fingerprint is NULL"); - CString::new(fp.to_hex()) - .unwrap() // Errors only on internal nul bytes. - .into_raw() -} - -/// Converts the fingerprint to a key ID. -#[no_mangle] -pub extern "system" fn sq_fingerprint_to_keyid(fp: Option<&Fingerprint>) - -> *mut KeyID { - let fp = fp.expect("Fingerprint is NULL"); - Box::into_raw(Box::new(fp.to_keyid())) -} - -/// Compares Fingerprints. -#[no_mangle] -pub extern "system" fn sq_fingerprint_equal(a: Option<&Fingerprint>, - b: Option<&Fingerprint>) - -> bool { - let a = a.expect("Fingerprint 'a' is NULL"); - let b = b.expect("Fingerprint 'b' is NULL"); - a == b -} - - -/* openpgp::armor. */ - -/// Represents a (key, value) pair in an armor header. -#[repr(C)] -pub struct ArmorHeader { - key: *const c_char, - value: *const c_char, -} - -fn int_to_kind(kind: c_int) -> Option { - match kind { - 0 => None, - 1 => Some(armor::Kind::Message), - 2 => Some(armor::Kind::PublicKey), - 3 => Some(armor::Kind::SecretKey), - 4 => Some(armor::Kind::Signature), - 5 => Some(armor::Kind::File), - _ => panic!("Bad kind: {}", kind), - } -} - -fn kind_to_int(kind: Option) -> c_int { - match kind { - None => 0, - Some(armor::Kind::Message) => 1, - Some(armor::Kind::PublicKey) => 2, - Some(armor::Kind::SecretKey) => 3, - Some(armor::Kind::Signature) => 4, - Some(armor::Kind::File) => 5, - } -} - -/// Constructs a new filter for the given type of data. -/// -/// A filter that strips ASCII Armor from a stream of data. -/// -/// # Example -/// -/// ```c -/// #define _GNU_SOURCE -/// #include -/// #include -/// #include -/// #include -/// #include -/// -/// #include -/// -/// const char *armored = -/// "-----BEGIN PGP ARMORED FILE-----\n" -/// "Key0: Value0\n" -/// "Key1: Value1\n" -/// "\n" -/// "SGVsbG8gd29ybGQh\n" -/// "=s4Gu\n" -/// "-----END PGP ARMORED FILE-----\n"; -/// -/// int -/// main (int argc, char **argv) -/// { -/// sq_error_t err; -/// sq_context_t ctx; -/// sq_reader_t bytes; -/// sq_reader_t armor; -/// sq_armor_kind_t kind; -/// char message[12]; -/// sq_armor_header_t *header; -/// size_t header_len; -/// -/// ctx = sq_context_new ("org.sequoia-pgp.example", &err); -/// if (ctx == NULL) -/// error (1, 0, "Initializing sequoia failed: %s", -/// sq_error_string (err)); -/// -/// bytes = sq_reader_from_bytes ((uint8_t *) armored, strlen (armored)); -/// armor = sq_armor_reader_new (bytes, SQ_ARMOR_KIND_ANY); -/// -/// header = sq_armor_reader_headers (ctx, armor, &header_len); -/// if (header == NULL) -/// { -/// err = sq_context_last_error (ctx); -/// error (1, 0, "Getting headers failed: %s", -/// sq_error_string (err)); -/// } -/// -/// assert (header_len == 2); -/// assert (strcmp (header[0].key, "Key0") == 0 -/// && strcmp (header[0].value, "Value0") == 0); -/// assert (strcmp (header[1].key, "Key1") == 0 -/// && strcmp (header[1].value, "Value1") == 0); -/// for (size_t i = 0; i < header_len; i++) -/// { -/// free (header[i].key); -/// free (header[i].value); -/// } -/// free (header); -/// -/// kind = sq_armor_reader_kind (armor); -/// assert (kind == SQ_ARMOR_KIND_FILE); -/// -/// if (sq_reader_read (ctx, armor, (uint8_t *) message, 12) < 0) -/// { -/// err = sq_context_last_error (ctx); -/// error (1, 0, "Reading failed: %s", -/// sq_error_string (err)); -/// } -/// -/// assert (memcmp (message, "Hello world!", 12) == 0); -/// -/// sq_reader_free (armor); -/// sq_reader_free (bytes); -/// sq_context_free (ctx); -/// return 0; -/// } -/// ``` -#[no_mangle] -pub extern "system" fn sq_armor_reader_new(inner: Option<&'static mut Box>, - kind: c_int) - -> *mut Box { - let inner = inner.expect("Inner is NULL"); - let kind = int_to_kind(kind); - - box_raw!(Box::new(armor::Reader::new(inner, kind))) -} - -/// Creates a `Reader` from a file. -#[no_mangle] -pub extern "system" fn sq_armor_reader_from_file(ctx: Option<&mut Context>, - filename: *const c_char, - kind: c_int) - -> *mut Box { - let ctx = ctx.expect("Context is NULL"); - assert!(! filename.is_null()); - let filename = unsafe { - CStr::from_ptr(filename).to_string_lossy().into_owned() - }; - let kind = int_to_kind(kind); - - fry_box!(ctx, armor::Reader::from_file(&filename, kind) - .map(|r| Box::new(r)) - .map_err(|e| e.into())) -} - -/// Creates a `Reader` from a buffer. -#[no_mangle] -pub extern "system" fn sq_armor_reader_from_bytes(b: *const uint8_t, len: size_t, - kind: c_int) - -> *mut Box { - assert!(!b.is_null()); - let buf = unsafe { - slice::from_raw_parts(b, len as usize) - }; - let kind = int_to_kind(kind); - - box_raw!(Box::new(armor::Reader::from_bytes(buf, kind))) -} - -/// Returns the kind of data this reader is for. -/// -/// Useful if the kind of data is not known in advance. If the header -/// has not been encountered yet (try reading some data first!), this -/// function returns SQ_ARMOR_KIND_ANY. -/// -/// # Example -/// -/// See [this] example. -/// -/// [this]: fn.sq_armor_reader_new.html -#[no_mangle] -pub extern "system" fn sq_armor_reader_kind(reader: *mut Box) - -> c_int { - // We need to downcast `reader`. To do that, we need to do a - // little dance. We will momentarily take ownership of `reader`, - // wrapping it in a Box again. Then, at the end of the function, - // we will leak it again. - assert!(! reader.is_null()); - let reader = unsafe { - Box::from_raw(reader as *mut Box) - }; - let kind = kind_to_int(reader.kind()); - Box::into_raw(reader); - kind -} - -/// Returns the armored headers. -/// -/// The tuples contain a key and a value. -/// -/// Note: if a key occurs multiple times, then there are multiple -/// entries in the vector with the same key; values with the same -/// key are *not* combined. -/// -/// The returned array and the strings in the headers have been -/// allocated with `malloc`, and the caller is responsible for freeing -/// both the array and the strings. -/// -/// # Example -/// -/// See [this] example. -/// -/// [this]: fn.sq_armor_reader_new.html -#[no_mangle] -pub extern "system" fn sq_armor_reader_headers(ctx: Option<&mut Context>, - reader: *mut Box, - len: Option<&mut size_t>) - -> *mut ArmorHeader { - let ctx = ctx.expect("Context is NULL"); - assert!(! reader.is_null()); - let len = len.expect("LEN is NULL"); - - // We need to downcast `reader`. To do that, we need to do a - // little dance. We will momentarily take ownership of `reader`, - // wrapping it in a Box again. Then, at the end of the function, - // we will leak it again. - let mut reader = unsafe { - Box::from_raw(reader as *mut Box) - }; - - // We need to be extra careful here in order not to keep ownership - // of `reader` in case of errors. - let result = match reader.headers().map_err(|e| e.into()) { - Ok(headers) => { - // Allocate space for the result. - let buf = unsafe { - libc::calloc(headers.len(), size_of::()) - as *mut ArmorHeader - }; - let sl = unsafe { - slice::from_raw_parts_mut(buf, headers.len()) - }; - for (i, (key, value)) in headers.iter().enumerate() { - sl[i].key = strdup(key); - sl[i].value = strdup(value); - } - - *len = headers.len(); - buf - }, - Err(e) => { - ctx.e = Some(e); - ptr::null_mut() - }, - }; - - // Release temporary ownership. - Box::into_raw(reader); - result -} - -/// Creates a zero-terminated C string from a &str allocated using -/// malloc. -fn strdup(s: &str) -> *mut c_char { - let b = s.as_bytes(); - let len = b.len() + 1; - let dup = unsafe { - libc::malloc(len) as *mut c_char - }; - let sl = unsafe { - slice::from_raw_parts_mut(dup as *mut uint8_t, len) - }; - sl[..len-1].copy_from_slice(b); - sl[len-1] = 0; - dup -} - -/// Constructs a new filter for the given type of data. -/// -/// A filter that applies ASCII Armor to the data written to it. -/// -/// # Example -/// -/// ```c -/// #define _GNU_SOURCE -/// #include -/// #include -/// #include -/// #include -/// #include -/// -/// #include -/// -/// int -/// main (int argc, char **argv) -/// { -/// void *buf = NULL; -/// size_t len = 0; -/// sq_writer_t alloc; -/// sq_writer_t armor; -/// sq_error_t err; -/// sq_context_t ctx; -/// char *message = "Hello world!"; -/// sq_armor_header_t header[2] = { -/// { "Key0", "Value0" }, -/// { "Key1", "Value1" }, -/// }; -/// -/// ctx = sq_context_new ("org.sequoia-pgp.example", &err); -/// if (ctx == NULL) -/// error (1, 0, "Initializing sequoia failed: %s", -/// sq_error_string (err)); -/// -/// alloc = sq_writer_alloc (&buf, &len); -/// armor = sq_armor_writer_new (ctx, alloc, SQ_ARMOR_KIND_FILE, header, 2); -/// if (armor == NULL) -/// { -/// err = sq_context_last_error (ctx); -/// error (1, 0, "Creating armor writer failed: %s", -/// sq_error_string (err)); -/// } -/// -/// if (sq_writer_write (ctx, armor, (uint8_t *) message, strlen (message)) < 0) -/// { -/// err = sq_context_last_error (ctx); -/// error (1, 0, "Writing failed: %s", -/// sq_error_string (err)); -/// } -/// sq_writer_free (armor); -/// sq_writer_free (alloc); -/// -/// assert (len == 114); -/// assert (memcmp (buf, -/// "-----BEGIN PGP ARMORED FILE-----\n" -/// "Key0: Value0\n" -/// "Key1: Value1\n" -/// "\n" -/// "SGVsbG8gd29ybGQh\n" -/// "=s4Gu\n" -/// "-----END PGP ARMORED FILE-----\n", -/// len) == 0); -/// -/// free (buf); -/// sq_context_free (ctx); -/// return 0; -/// } -/// ``` -#[no_mangle] -pub extern "system" fn sq_armor_writer_new - (ctx: Option<&mut Context>, - inner: Option<&'static mut Box>, - kind: c_int, - header: Option<&ArmorHeader>, - header_len: size_t) - -> *mut Box -{ - let ctx = ctx.expect("Context is NULL"); - let inner = inner.expect("Inner is NULL"); - let kind = int_to_kind(kind).expect("KIND must not be SQ_ARMOR_KIND_ANY"); - - let mut header_ = Vec::new(); - if header_len > 0 { - let header = header.expect("HEADER is NULL"); - let header = unsafe { - slice::from_raw_parts(header, header_len) - }; - for h in header { - assert!(! h.key.is_null()); - assert!(! h.value.is_null()); - header_.push(unsafe { - (CStr::from_ptr(h.key).to_string_lossy(), - CStr::from_ptr(h.value).to_string_lossy()) - }); - } - } - - let header: Vec<(&str, &str)> = - header_.iter().map(|h| (h.0.as_ref(), h.1.as_ref())).collect(); - - fry_box!(ctx, armor::Writer::new(inner, kind, &header) - .map(|r| Box::new(r)) - .map_err(|e| e.into())) -} - - -/* openpgp::PacketPile. */ - -/// Deserializes the OpenPGP message stored in a `std::io::Read` -/// object. -/// -/// Although this method is easier to use to parse an OpenPGP -/// message than a `PacketParser` or a `PacketPileParser`, this -/// interface buffers the whole message in memory. Thus, the -/// caller must be certain that the *deserialized* message is not -/// too large. -/// -/// Note: this interface *does* buffer the contents of packets. -#[no_mangle] -pub extern "system" fn sq_packet_pile_from_reader(ctx: Option<&mut Context>, - reader: Option<&mut Box>) - -> *mut PacketPile { - let ctx = ctx.expect("Context is NULL"); - let reader = reader.expect("Reader is NULL"); - fry_box!(ctx, PacketPile::from_reader(reader)) -} - -/// Deserializes the OpenPGP message stored in the file named by -/// `filename`. -/// -/// See `sq_packet_pile_from_reader` for more details and caveats. -#[no_mangle] -pub extern "system" fn sq_packet_pile_from_file(ctx: Option<&mut Context>, - filename: *const c_char) - -> *mut PacketPile { - 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, PacketPile::from_file(&filename)) -} - -/// Deserializes the OpenPGP message stored in the provided buffer. -/// -/// See `sq_packet_pile_from_reader` for more details and caveats. -#[no_mangle] -pub extern "system" fn sq_packet_pile_from_bytes(ctx: Option<&mut Context>, - b: *const uint8_t, len: size_t) - -> *mut PacketPile { - 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, PacketPile::from_bytes(buf)) -} - -/// Frees the packet_pile. -#[no_mangle] -pub extern "system" fn sq_packet_pile_free(packet_pile: *mut PacketPile) { - if packet_pile.is_null() { - return - } - unsafe { - drop(Box::from_raw(packet_pile)); - } -} - -/// Clones the PacketPile. -#[no_mangle] -pub extern "system" fn sq_packet_pile_clone(packet_pile: Option<&PacketPile>) - -> *mut PacketPile { - let packet_pile = packet_pile.expect("PacketPile is NULL"); - box_raw!(packet_pile.clone()) -} - -/// Serializes the packet pile. -#[no_mangle] -pub extern "system" fn sq_packet_pile_serialize(ctx: Option<&mut Context>, - packet_pile: Option<&PacketPile>, - writer: Option<&mut Box>) - -> Status { - let ctx = ctx.expect("Context is NULL"); - let packet_pile = packet_pile.expect("PacketPile is NULL"); - let writer = writer.expect("Writer is NULL"); - fry_status!(ctx, packet_pile.serialize(writer)) -} - - -/* 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>) - -> *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>) - -> 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 -/// #include -/// -/// 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 -/// #include -/// -/// 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, - RevocationStatus::CouldBe(_) => 1, - RevocationStatus::NotAsFarAsWeKnow => 2, - } -} - -/// Returns the TPK's revocation status variant. -#[no_mangle] -pub extern "system" fn sq_revocation_status_variant( - rs: *mut RevocationStatus) - -> c_int -{ - assert!(! rs.is_null()); - let rs = unsafe { - Box::from_raw(rs as *mut RevocationStatus) - }; - let variant = revocation_status_to_int(rs.as_ref()); - Box::into_raw(rs); - variant -} - -/// Frees a sq_revocation_status_t. -#[no_mangle] -pub extern "system" fn sq_revocation_status_free( - rs: *mut RevocationStatus) -{ - if rs.is_null() { return }; - unsafe { - drop(Box::from_raw(rs)) - }; -} - -/* 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>, -} - -/// 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 -/// #include -/// -/// 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`. -#[no_mangle] -pub extern "system" fn sq_tsk_new(ctx: Option<&mut Context>, - primary_uid: *const c_char, - tsk_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 tsk_out = tsk_out.expect("TSK is NULL"); - let revocation_out = revocation_out.expect("REVOCATION is NULL"); - let primary_uid = unsafe { - CStr::from_ptr(primary_uid) - }; - match TSK::new(primary_uid.to_string_lossy()) { - Ok((tsk, revocation)) => { - *tsk_out = box_raw!(tsk); - *revocation_out = box_raw!(revocation); - Status::Success - }, - Err(e) => fry_status!(ctx, Err::<(), failure::Error>(e)), - } -} - -/// Frees the TSK. -#[no_mangle] -pub extern "system" fn sq_tsk_free(tsk: *mut TSK) { - if tsk.is_null() { - return - } - unsafe { - drop(Box::from_raw(tsk)); - } -} - -/// Returns a reference to the corresponding TPK. -#[no_mangle] -pub extern "system" fn sq_tsk_tpk(tsk: Option<&TSK>) - -> &TPK { - let tsk = tsk.expect("TSK is NULL"); - tsk.tpk() -} - -/// Converts the TSK into a TPK. -#[no_mangle] -pub extern "system" fn sq_tsk_into_tpk(tsk: *mut TSK) - -> *mut TPK { - let tsk = unsafe { - Box::from_raw(tsk) - }; - box_raw!(tsk.into_tpk()) -} - - -/// Serializes the TSK. -#[no_mangle] -pub extern "system" fn sq_tsk_serialize(ctx: Option<&mut Context>, - tsk: Option<&TSK>, - writer: Option<&mut Box>) - -> Status { - let ctx = ctx.expect("Context is NULL"); - let tsk = tsk.expect("TSK is NULL"); - let writer = writer.expect("Writer is NULL"); - fry_status!(ctx, tsk.serialize(writer)) -} - -/* openpgp::Packet. */ - -/// Frees the Packet. -#[no_mangle] -pub extern "system" fn sq_packet_free(p: *mut Packet) { - if p.is_null() { return } - unsafe { - drop(Box::from_raw(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 -#[no_mangle] -pub extern "system" fn sq_packet_tag(p: Option<&Packet>) - -> uint8_t { - let p = p.expect("Packet is NULL"); - 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`. -#[no_mangle] -pub extern "system" fn sq_packet_kind(p: Option<&Packet>) - -> uint8_t { - let p = p.expect("Packet is NULL"); - if let Some(kind) = p.kind() { - kind.into() - } else { - 0 - } -} - -/// Frees the Signature. -#[no_mangle] -pub extern "system" fn sq_signature_free(s: *mut Signature) { - if s.is_null() { return } - unsafe { - drop(Box::from_raw(s)); - } -} - -/// Converts the signature to a packet. -#[no_mangle] -pub extern "system" fn sq_signature_to_packet(s: *mut Signature) - -> *mut Packet -{ - assert!(! s.is_null()); - unsafe { - box_raw!(Box::from_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. -#[no_mangle] -pub extern "system" fn sq_signature_issuer(sig: Option<&packet::Signature>) - -> *mut KeyID { - let sig = sig.expect("Signature is NULL"); - 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. -#[no_mangle] -pub extern "system" fn sq_signature_issuer_fingerprint( - sig: Option<&packet::Signature>) - -> *mut Fingerprint -{ - let sig = sig.expect("Signature is NULL"); - maybe_box_raw!(sig.issuer_fingerprint()) -} - - -/// Returns whether the KeyFlags indicates that the key can be used to -/// make certifications. -#[no_mangle] -pub extern "system" fn sq_signature_can_certify(sig: Option<&packet::Signature>) - -> bool -{ - let sig = sig.expect("Sig is NULL"); - sig.key_flags().can_certify() -} - -/// Returns whether the KeyFlags indicates that the key can be used to -/// make signatures. -#[no_mangle] -pub extern "system" fn sq_signature_can_sign(sig: Option<&packet::Signature>) - -> bool -{ - let sig = sig.expect("Sig is NULL"); - sig.key_flags().can_sign() -} - -/// Returns whether the KeyFlags indicates that the key can be used to -/// encrypt data for transport. -#[no_mangle] -pub extern "system" fn sq_signature_can_encrypt_for_transport(sig: Option<&packet::Signature>) - -> bool -{ - let sig = sig.expect("Sig is NULL"); - sig.key_flags().can_encrypt_for_transport() -} - -/// Returns whether the KeyFlags indicates that the key can be used to -/// encrypt data at rest. -#[no_mangle] -pub extern "system" fn sq_signature_can_encrypt_at_rest(sig: Option<&packet::Signature>) - -> bool -{ - let sig = sig.expect("Sig is NULL"); - sig.key_flags().can_encrypt_at_rest() -} - -/// Returns whether the KeyFlags indicates that the key can be used -/// for authentication. -#[no_mangle] -pub extern "system" fn sq_signature_can_authenticate(sig: Option<&packet::Signature>) - -> bool -{ - let sig = sig.expect("Sig is NULL"); - sig.key_flags().can_authenticate() -} - -/// Returns whether the KeyFlags indicates that the key is a split -/// key. -#[no_mangle] -pub extern "system" fn sq_signature_is_split_key(sig: Option<&packet::Signature>) - -> bool -{ - let sig = sig.expect("Sig is NULL"); - sig.key_flags().is_split_key() -} - -/// Returns whether the KeyFlags indicates that the key is a group -/// key. -#[no_mangle] -pub extern "system" fn sq_signature_is_group_key(sig: Option<&packet::Signature>) - -> bool -{ - let sig = sig.expect("Sig is NULL"); - 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. -#[no_mangle] -pub extern "system" fn sq_signature_alive(sig: Option<&packet::Signature>) - -> bool -{ - let sig = sig.expect("Sig is NULL"); - 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. -#[no_mangle] -pub extern "system" fn sq_signature_alive_at(sig: Option<&packet::Signature>, - when: time_t) - -> bool -{ - let sig = sig.expect("Sig is NULL"); - sig.signature_alive_at(time::at(time::Timespec::new(when as i64, 0))) -} - -/// Returns whether the signature is expired. -#[no_mangle] -pub extern "system" fn sq_signature_expired(sig: Option<&packet::Signature>) - -> bool -{ - let sig = sig.expect("Sig is NULL"); - sig.signature_expired() -} - -/// Returns whether the signature is expired at the specified time. -#[no_mangle] -pub extern "system" fn sq_signature_expired_at(sig: Option<&packet::Signature>, - when: time_t) - -> bool -{ - let sig = sig.expect("Sig is NULL"); - sig.signature_expired_at(time::at(time::Timespec::new(when as i64, 0))) -} - - -/// Clones the key. -#[no_mangle] -pub extern "system" fn sq_p_key_clone(key: Option<&packet::Key>) - -> *mut packet::Key { - let key = key.expect("Key is NULL"); - box_raw!(key.clone()) -} - -/// Computes and returns the key's fingerprint as per Section 12.2 -/// of RFC 4880. -#[no_mangle] -pub extern "system" fn sq_p_key_fingerprint(key: Option<&packet::Key>) - -> *mut Fingerprint { - let key = key.expect("Key is NULL"); - box_raw!(key.fingerprint()) -} - -/// Computes and returns the key's key ID as per Section 12.2 of RFC -/// 4880. -#[no_mangle] -pub extern "system" fn sq_p_key_keyid(key: Option<&packet::Key>) - -> *mut KeyID { - let key = key.expect("Key is NULL"); - 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. -#[no_mangle] -pub extern "system" fn sq_p_key_expired(key: Option<&packet::Key>, - sig: Option<&packet::Signature>) - -> bool -{ - let key = key.expect("Key is NULL"); - let sig = sig.expect("SIG is NULL"); - - sig.key_expired(key) -} - -/// Like sq_p_key_expired, but at a specific time. -#[no_mangle] -pub extern "system" fn sq_p_key_expired_at(key: Option<&packet::Key>, - sig: Option<&packet::Signature>, - when: time_t) - -> bool -{ - let key = key.expect("Key is NULL"); - let sig = sig.expect("SIG is NULL"); - - 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. -#[no_mangle] -pub extern "system" fn sq_p_key_alive(key: Option<&packet::Key>, - sig: Option<&packet::Signature>) - -> bool -{ - let key = key.expect("Key is NULL"); - let sig = sig.expect("SIG is NULL"); - - sig.key_alive(key) -} - -/// Like sq_p_key_alive, but at a specific time. -#[no_mangle] -pub extern "system" fn sq_p_key_alive_at(key: Option<&packet::Key>, - sig: Option<&packet::Signature>, - when: time_t) - -> bool -{ - let key = key.expect("Key is NULL"); - let sig = sig.expect("SIG is NULL"); - - sig.key_alive_at(key, time::at(time::Timespec::new(when as i64, 0))) -} - -/// Returns the key's creation time. -#[no_mangle] -pub extern "system" fn sq_p_key_creation_time(key: Option<&packet::Key>) - -> u32 -{ - let key = key.expect("Key is NULL"); - let ct = key.creation_time(); - - ct.to_timespec().sec as u32 -} - -/// Returns the key's public key algorithm. -#[no_mangle] -pub extern "system" fn sq_p_key_public_key_algo(key: Option<&packet::Key>) - -> c_int -{ - let key = key.expect("Key is NULL"); - let pk_algo : u8 = key.pk_algo().into(); - pk_algo as c_int -} - -/// Returns the public key's size in bits. -#[no_mangle] -pub extern "system" fn sq_p_key_public_key_bits(key: Option<&packet::Key>) - -> c_int -{ - use self::openpgp::crypto::mpis::PublicKey::*; - - let key = key.expect("Key is NULL"); - 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, - } -} - -/// 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. -#[no_mangle] -pub extern "system" fn sq_user_id_value(uid: Option<&Packet>, - value_len: Option<&mut size_t>) - -> *const uint8_t { - let uid = uid.expect("UserID is NULL"); - 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. -#[no_mangle] -pub extern "system" fn sq_user_attribute_value(ua: Option<&Packet>, - value_len: Option<&mut size_t>) - -> *const uint8_t { - let ua = ua.expect("UserAttribute is NULL"); - 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. -#[no_mangle] -pub extern "system" fn sq_skesk_decrypt(ctx: Option<&mut Context>, - skesk: Option<&Packet>, - password: *const uint8_t, - password_len: size_t, - algo: Option<&mut uint8_t>, // XXX - key: *mut uint8_t, - key_len: Option<&mut size_t>) - -> Status { - let ctx = ctx.expect("Context is NULL"); - let skesk = skesk.expect("SKESK is NULL"); - assert!(!password.is_null()); - let password = unsafe { - slice::from_raw_parts(password, password_len as usize) - }; - let algo = algo.expect("Algo is NULL"); - let key_len = key_len.expect("Key length is NULL"); - - 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) => fry_status!(ctx, 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. -#[no_mangle] -pub extern "system" fn sq_pkesk_recipient(pkesk: Option<&PKESK>) - -> *const KeyID { - let pkesk = pkesk.expect("PKESK is NULL"); - 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. -#[no_mangle] -pub extern "system" fn sq_pkesk_decrypt(ctx: Option<&mut Context>, - pkesk: Option<&PKESK>, - secret_key: Option<&packet::Key>, - algo: Option<&mut uint8_t>, // XXX - key: *mut uint8_t, - key_len: Option<&mut size_t>) - -> Status { - let ctx = ctx.expect("Context is NULL"); - let pkesk = pkesk.expect("PKESK is NULL"); - let secret_key = secret_key.expect("SECRET_KEY is NULL"); - let algo = algo.expect("Algo is NULL"); - let key_len = key_len.expect("Key length is NULL"); - - 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) => fry_status!(ctx, 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. -#[no_mangle] -pub extern "system" fn sq_packet_parser_from_reader<'a> - (ctx: Option<&mut Context>, reader: Option<&'a mut Box<'a + Read>>) - -> *mut PacketParserResult<'a> { - let ctx = ctx.expect("Context is NULL"); - let reader = reader.expect("Reader is NULL"); - fry_box!(ctx, PacketParser::from_reader(reader)) -} - -/// Starts parsing OpenPGP packets stored in a file named `path`. -/// -/// This function returns a `PacketParser` for the first packet in -/// the stream. -#[no_mangle] -pub extern "system" fn sq_packet_parser_from_file - (ctx: Option<&mut Context>, filename: *const c_char) - -> *mut PacketParserResult { - 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, PacketParser::from_file(&filename)) -} - -/// Starts parsing OpenPGP packets stored in a buffer. -/// -/// This function returns a `PacketParser` for the first packet in -/// the stream. -#[no_mangle] -pub extern "system" fn sq_packet_parser_from_bytes - (ctx: Option<&mut Context>, b: *const uint8_t, len: size_t) - -> *mut PacketParserResult { - let ctx = ctx.expect("Context is NULL"); - assert!(!b.is_null()); - let buf = unsafe { - slice::from_r