//! Transferable public keys. //! //! Wraps [`sequoia-openpgp::TPK`] and [related functionality]. //! //! [`sequoia-openpgp::TPK`]: ../../sequoia_openpgp/struct.TPK.html //! [related functionality]: ../../sequoia_openpgp/tpk/index.html use std::ptr; use std::slice; use libc::{c_char, c_int, size_t, time_t, uint8_t}; extern crate sequoia_openpgp as openpgp; use self::openpgp::{ Policy, autocrypt::Autocrypt, crypto, constants::ReasonForRevocation, parse::{ PacketParserResult, Parse, }, tpk::{ CipherSuite, KeyIter, TPKBuilder, TPKParser, UserIDBinding, UserIDBindingIter, }, }; use ::error::Status; use super::fingerprint::Fingerprint; use super::packet::key::Key; use super::packet::Packet; use super::packet::signature::Signature; use super::packet_pile::PacketPile; use super::tsk::TSK; use super::revocation_status::RevocationStatus; use Maybe; use RefRaw; use MoveFromRaw; use MoveIntoRaw; use MoveResultIntoRaw; /// A transferable public key (TPK). /// /// A TPK (see [RFC 4880, section 11.1]) can be used to verify /// signatures and encrypt data. It can be stored in a keystore and /// uploaded to keyservers. /// /// TPKs are always canonicalized in the sense that only elements /// (user id, user attribute, subkey) with at least one valid /// self-signature are preserved. Also, invalid self-signatures are /// dropped. The self-signatures are sorted so that the newest /// self-signature comes first. User IDs are sorted so that the first /// `UserID` is the primary User ID. Third-party certifications are /// *not* validated, as the keys are not available; they are simply /// passed through as is. /// /// [RFC 4880, section 11.1]: https://tools.ietf.org/html/rfc4880#section-11.1 #[::ffi_wrapper_type( prefix = "pgp_", name = "tpk", derive = "Clone, Debug, Display, PartialEq, Parse, Serialize")] pub struct TPK(openpgp::TPK); /// Returns the first TPK found in `m`. /// /// Consumes `m`. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" fn pgp_tpk_from_packet_pile(errp: Option<&mut *mut ::error::Error>, m: *mut PacketPile) -> Maybe { openpgp::TPK::from_packet_pile(m.move_from_raw()).move_into_raw(errp) } /// Returns the first TPK found in the packet parser. /// /// Consumes the packet parser result. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" fn pgp_tpk_from_packet_parser(errp: Option<&mut *mut ::error::Error>, ppr: *mut PacketParserResult) -> Maybe { let ppr = ffi_param_move!(ppr); openpgp::TPK::from_packet_parser(*ppr).move_into_raw(errp) } /// 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`. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" fn pgp_tpk_merge(errp: Option<&mut *mut ::error::Error>, tpk: *mut TPK, other: *mut TPK) -> Maybe { let tpk = tpk.move_from_raw(); let other = other.move_from_raw(); tpk.merge(other).move_into_raw(errp) } /// 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. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" fn pgp_tpk_merge_packets(errp: Option<&mut *mut ::error::Error>, tpk: *mut TPK, packets: *mut *mut Packet, packets_len: size_t) -> Maybe { let tpk = tpk.move_from_raw(); let packets = unsafe { slice::from_raw_parts_mut(packets, packets_len) }; let packets = packets.iter_mut().map(|&mut p| p.move_from_raw()).collect(); tpk.merge_packets(packets).move_into_raw(errp) } /// Returns the fingerprint. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" fn pgp_tpk_fingerprint(tpk: *const TPK) -> *mut Fingerprint { let tpk = tpk.ref_raw(); tpk.fingerprint().move_into_raw() } /// Derives a [`TSK`] object from this key. /// /// This object writes out secret keys during serialization. /// /// [`TSK`]: tpk/struct.TSK.html #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" fn pgp_tpk_as_tsk(tpk: *const TPK) -> *mut TSK<'static> { tpk.ref_raw().as_tsk().move_into_raw() } /// Returns a reference to the TPK's primary key. /// /// The tpk still owns the key. The caller must not modify the key. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" fn pgp_tpk_primary(tpk: *const TPK) -> *const Key { tpk.ref_raw().primary().move_into_raw() } /// Returns the TPK's revocation status as of a given time. /// /// 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. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" fn pgp_tpk_revocation_status_at(tpk: *const TPK, when: time_t) -> *mut RevocationStatus<'static> { let when = when as i64; let when = if when == 0 { time::now() } else { time::at(time::Timespec::new(when, 0)) }; tpk.ref_raw().revocation_status(&when as &Policy).move_into_raw() } /// Returns the TPK's current 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. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" fn pgp_tpk_revocation_status(tpk: *const TPK) -> *mut RevocationStatus<'static> { tpk.ref_raw().revocation_status(None).move_into_raw() } 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 /// /// pgp_tpk_builder_t builder; /// pgp_tpk_t tpk; /// pgp_signature_t revocation; /// pgp_key_t primary_key; /// pgp_key_pair_t primary_keypair; /// pgp_signer_t primary_signer; /// /// builder = pgp_tpk_builder_new (); /// pgp_tpk_builder_set_cipher_suite (&builder, PGP_TPK_CIPHER_SUITE_CV25519); /// pgp_tpk_builder_generate (NULL, builder, &tpk, &revocation); /// assert (tpk); /// assert (revocation); /// pgp_signature_free (revocation); /* Free the generated one. */ /// /// primary_key = pgp_tpk_primary (tpk); /// primary_keypair = pgp_key_into_key_pair (NULL, pgp_key_clone (primary_key)); /// pgp_key_free (primary_key); /// assert (primary_keypair); /// primary_signer = pgp_key_pair_as_signer (primary_keypair); /// revocation = pgp_tpk_revoke (NULL, tpk, primary_signer, /// PGP_REASON_FOR_REVOCATION_KEY_COMPROMISED, /// "It was the maid :/"); /// assert (revocation); /// pgp_signer_free (primary_signer); /// pgp_key_pair_free (primary_keypair); /// /// pgp_packet_t packet = pgp_signature_into_packet (revocation); /// tpk = pgp_tpk_merge_packets (NULL, tpk, &packet, 1); /// assert (tpk); /// /// pgp_revocation_status_t rs = pgp_tpk_revocation_status (tpk); /// assert (pgp_revocation_status_variant (rs) == PGP_REVOCATION_STATUS_REVOKED); /// pgp_revocation_status_free (rs); /// /// pgp_tpk_free (tpk); /// ``` #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" fn pgp_tpk_revoke(errp: Option<&mut *mut ::error::Error>, tpk: *const TPK, primary_signer: *mut Box, code: c_int, reason: Option<&c_char>) -> Maybe { ffi_make_fry_from_errp!(errp); let tpk = tpk.ref_raw(); let signer = ffi_param_ref_mut!(primary_signer); let code = int_to_reason_for_revocation(code); let reason = if let Some(reason) = reason { ffi_param_cstr!(reason as *const c_char).to_bytes() } else { b"" }; tpk.revoke(signer.as_mut(), code, reason).move_into_raw(errp) } /// Adds a revocation certificate to the tpk. /// /// This function consumes the tpk. /// /// # Example /// /// ```c /// #include /// #include /// /// pgp_tpk_builder_t builder; /// pgp_tpk_t tpk; /// pgp_signature_t revocation; /// pgp_key_t primary_key; /// pgp_key_pair_t primary_keypair; /// pgp_signer_t primary_signer; /// /// builder = pgp_tpk_builder_new (); /// pgp_tpk_builder_set_cipher_suite (&builder, PGP_TPK_CIPHER_SUITE_CV25519); /// pgp_tpk_builder_generate (NULL, builder, &tpk, &revocation); /// assert (tpk); /// assert (revocation); /// pgp_signature_free (revocation); /* Free the generated one. */ /// /// primary_key = pgp_tpk_primary (tpk); /// primary_keypair = pgp_key_into_key_pair (NULL, pgp_key_clone (primary_key)); /// pgp_key_free (primary_key); /// assert (primary_keypair); /// primary_signer = pgp_key_pair_as_signer (primary_keypair); /// tpk = pgp_tpk_revoke_in_place (NULL, tpk, primary_signer, /// PGP_REASON_FOR_REVOCATION_KEY_COMPROMISED, /// "It was the maid :/"); /// assert (tpk); /// pgp_signer_free (primary_signer); /// pgp_key_pair_free (primary_keypair); /// /// pgp_revocation_status_t rs = pgp_tpk_revocation_status (tpk); /// assert (pgp_revocation_status_variant (rs) == PGP_REVOCATION_STATUS_REVOKED); /// pgp_revocation_status_free (rs); /// /// pgp_tpk_free (tpk); /// ``` #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" fn pgp_tpk_revoke_in_place(errp: Option<&mut *mut ::error::Error>, tpk: *mut TPK, primary_signer: *mut Box, code: c_int, reason: Option<&c_char>) -> Maybe { let tpk = tpk.move_from_raw(); let signer = ffi_param_ref_mut!(primary_signer); let code = int_to_reason_for_revocation(code); let reason = if let Some(reason) = reason { ffi_param_cstr!(reason as *const c_char).to_bytes() } else { b"" }; tpk.revoke_in_place(signer.as_mut(), code, reason).move_into_raw(errp) } /// Returns whether the TPK has expired. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" fn pgp_tpk_expired(tpk: *const TPK) -> c_int { let tpk = tpk.ref_raw(); tpk.expired(None) as c_int } /// Returns whether the TPK has expired. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" fn pgp_tpk_expired_at(tpk: *const TPK, when: time_t) -> c_int { let tpk = tpk.ref_raw(); tpk.expired(&time::at(time::Timespec::new(when as i64, 0)) as &Policy) as c_int } /// Returns whether the TPK is alive. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" fn pgp_tpk_alive(tpk: *const TPK) -> c_int { let tpk = tpk.ref_raw(); tpk.alive(None) as c_int } /// Returns whether the TPK is alive at the specified time. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" fn pgp_tpk_alive_at(tpk: *const TPK, when: time_t) -> c_int { let tpk = tpk.ref_raw(); tpk.alive(&time::at(time::Timespec::new(when as i64, 0)) as &Policy) 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`. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" fn pgp_tpk_set_expiry(errp: Option<&mut *mut ::error::Error>, tpk: *mut TPK, primary_signer: *mut Box, expiry: u32) -> Maybe { let tpk = tpk.move_from_raw(); let signer = ffi_param_ref_mut!(primary_signer); tpk.set_expiry(signer.as_mut(), Some(time::Duration::seconds(expiry as i64))) .move_into_raw(errp) } /// Returns whether the TPK includes any secret key material. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" fn pgp_tpk_is_tsk(tpk: *const TPK) -> c_int { let tpk = tpk.ref_raw(); tpk.is_tsk() as c_int } /// Returns an iterator over the TPK's user id bindings. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" fn pgp_tpk_primary_user_id(tpk: *const TPK) -> *mut c_char { let tpk = tpk.ref_raw(); if let Some(binding) = tpk.userids().nth(0) { ffi_return_string!(binding.userid().value()) } else { ptr::null_mut() } } /* 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. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" fn pgp_user_id_binding_user_id( binding: *const UserIDBinding) -> *mut c_char { let binding = ffi_param_ref!(binding); ffi_return_maybe_string!(binding.userid().value()) } /// Returns a reference to the self-signature, if any. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" fn pgp_user_id_binding_selfsig( binding: *const UserIDBinding) -> Maybe { let binding = ffi_param_ref!(binding); binding.binding_signature().move_into_raw() } /* UserIDBindingIter */ /// Returns an iterator over the TPK's user id bindings. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" fn pgp_tpk_user_id_binding_iter(tpk: *const TPK) -> *mut UserIDBindingIter<'static> { let tpk = tpk.ref_raw(); box_raw!(tpk.userids()) } /// Frees a pgp_user_id_binding_iter_t. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" fn pgp_user_id_binding_iter_free( iter: Option<&mut UserIDBindingIter>) { ffi_free!(iter) } /// Returns the next `UserIDBinding`. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" fn pgp_user_id_binding_iter_next<'a>( iter: *mut UserIDBindingIter<'a>) -> Option<&'a UserIDBinding> { let iter = ffi_param_ref_mut!(iter); iter.next() } /* tpk::KeyIter. */ /// Wrapers a KeyIter for export via the FFI. pub struct KeyIterWrapper<'a> { iter: KeyIter<'a>, // Whether next has been called. next_called: bool, } /// Returns an iterator over the TPK's live, non-revoked keys. /// /// That is, this returns an iterator over the primary key and any /// subkeys, along with the corresponding signatures. /// /// Note: since a primary key is different from a subkey, the iterator /// is over `Key`s and not `SubkeyBindings`. Since the primary key /// has no binding signature, the signature carrying the primary key's /// key flags is returned (either a direct key signature, or the /// self-signature on the primary User ID). There are corner cases /// where no such signature exists (e.g. partial TPKs), therefore this /// iterator may return `None` for the primary key's signature. /// /// A valid `Key` has at least one good self-signature. /// /// To return all keys, use `pgp_tpk_key_iter_all()`. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" fn pgp_tpk_key_iter_valid(tpk: *const TPK) -> *mut KeyIterWrapper<'static> { let tpk = tpk.ref_raw(); box_raw!(KeyIterWrapper { iter: tpk.keys_valid(), next_called: false, }) } /// Returns an iterator over all `Key`s in a TPK. /// /// Compare with `pgp_tpk_key_iter_valid`, which filters out expired /// and revoked keys by default. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" fn pgp_tpk_key_iter_all(tpk: *const TPK) -> *mut KeyIterWrapper<'static> { let tpk = tpk.ref_raw(); box_raw!(KeyIterWrapper { iter: tpk.keys_all(), next_called: false, }) } /// Frees a pgp_tpk_key_iter_t. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" fn pgp_tpk_key_iter_free( iter: Option<&mut KeyIterWrapper>) { ffi_free!(iter) } /// Changes the iterator to only return keys that are certification /// capable. /// /// If you call this function and, e.g., the `signing_capable` /// function, the *union* of the values is used. That is, the /// iterator will return keys that are certification capable *or* /// signing capable. /// /// Note: you may not call this function after starting to iterate. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" fn pgp_tpk_key_iter_certification_capable<'a>( iter_wrapper: *mut KeyIterWrapper<'a>) { let iter_wrapper = ffi_param_ref_mut!(iter_wrapper); if iter_wrapper.next_called { panic!("Can't change KeyIter filter after iterating."); } use std::mem; let tmp = mem::replace(&mut iter_wrapper.iter, KeyIter::empty()); iter_wrapper.iter = tmp.certification_capable(); } /// Changes the iterator to only return keys that are certification /// capable. /// /// If you call this function and, e.g., the `signing_capable` /// function, the *union* of the values is used. That is, the /// iterator will return keys that are certification capable *or* /// signing capable. /// /// Note: you may not call this function after starting to iterate. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" fn pgp_tpk_key_iter_signing_capable<'a>( iter_wrapper: *mut KeyIterWrapper<'a>) { let iter_wrapper = ffi_param_ref_mut!(iter_wrapper); if iter_wrapper.next_called { panic!("Can't change KeyIter filter after iterating."); } use std::mem; let tmp = mem::replace(&mut iter_wrapper.iter, KeyIter::empty()); iter_wrapper.iter = tmp.signing_capable(); } /// Changes the iterator to only return keys that are alive. /// /// If you call this function (or `pgp_tpk_key_iter_alive_at`), only /// the last value is used. /// /// Note: you may not call this function after starting to iterate. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" fn pgp_tpk_key_iter_alive<'a>( iter_wrapper: *mut KeyIterWrapper<'a>) { let iter_wrapper = ffi_param_ref_mut!(iter_wrapper); if iter_wrapper.next_called { panic!("Can't change KeyIter filter after iterating."); } use std::mem; let tmp = mem::replace(&mut iter_wrapper.iter, KeyIter::empty()); iter_wrapper.iter = tmp.alive(); } /// Changes the iterator to only return keys that are alive at the /// specified time. /// /// If you call this function (or `pgp_tpk_key_iter_alive`), only the /// last value is used. /// /// Note: you may not call this function after starting to iterate. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" fn pgp_tpk_key_iter_alive_at<'a>( iter_wrapper: *mut KeyIterWrapper<'a>, when: time_t) { let iter_wrapper = ffi_param_ref_mut!(iter_wrapper); if iter_wrapper.next_called { panic!("Can't change KeyIter filter after iterating."); } use std::mem; let tmp = mem::replace(&mut iter_wrapper.iter, KeyIter::empty()); iter_wrapper.iter = tmp.alive_at(time::at(time::Timespec::new(when as i64, 0))); } /// Changes the iterator to only return keys whose revocation status /// matches `revoked`. /// /// Note: you may not call this function after starting to iterate. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" fn pgp_tpk_key_iter_revoked<'a>( iter_wrapper: *mut KeyIterWrapper<'a>, revoked: bool) { let iter_wrapper = ffi_param_ref_mut!(iter_wrapper); if iter_wrapper.next_called { panic!("Can't change KeyIter filter after iterating."); } use std::mem; let tmp = mem::replace(&mut iter_wrapper.iter, KeyIter::empty()); iter_wrapper.iter = tmp.revoked(Some(revoked)); } /// Changes the iterator to only return keys that have secret keys (or /// not). /// /// Note: you may not call this function after starting to iterate. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" fn pgp_tpk_key_iter_secret<'a>( iter_wrapper: *mut KeyIterWrapper<'a>, secret: bool) { let iter_wrapper = ffi_param_ref_mut!(iter_wrapper); if iter_wrapper.next_called { panic!("Can't change KeyIter filter after iterating."); } use std::mem; let tmp = mem::replace(&mut iter_wrapper.iter, KeyIter::empty()); iter_wrapper.iter = tmp.secret(Some(secret)); } /// Changes the iterator to only return keys that have unencrypted /// secret keys (or not). /// /// Note: you may not call this function after starting to iterate. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" fn pgp_tpk_key_iter_unencrypted_secret<'a>( iter_wrapper: *mut KeyIterWrapper<'a>, unencrypted_secret: bool) { let iter_wrapper = ffi_param_ref_mut!(iter_wrapper); if iter_wrapper.next_called { panic!("Can't change KeyIter filter after iterating."); } use std::mem; let tmp = mem::replace(&mut iter_wrapper.iter, KeyIter::empty()); iter_wrapper.iter = tmp.unencrypted_secret(Some(unencrypted_secret)); } /// 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. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" fn pgp_tpk_key_iter_next<'a>( iter_wrapper: *mut KeyIterWrapper<'a>, sigo: Option<&mut Maybe>, rso: Option<&mut *mut RevocationStatus<'a>>) -> Maybe { let iter_wrapper = ffi_param_ref_mut!(iter_wrapper); iter_wrapper.next_called = true; if let Some((sig, rs, key)) = iter_wrapper.iter.next() { if let Some(ptr) = sigo { *ptr = sig.move_into_raw(); } if let Some(ptr) = rso { *ptr = rs.move_into_raw(); } Some(key).move_into_raw() } else { None } } /// Wrappers a TPKParser for export via the FFI. pub struct TPKParserWrapper<'a> { parser: TPKParser<'a, std::vec::IntoIter>, } /// Returns a TPKParser. /// /// A `TPKParser` parses a keyring, which is simply zero or more TPKs /// concatenated together. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" fn pgp_tpk_parser_from_bytes(errp: Option<&mut *mut ::error::Error>, buf: *mut uint8_t, len: size_t) -> *mut TPKParserWrapper<'static> { ffi_make_fry_from_errp!(errp); let buf : &[u8] = unsafe { std::slice::from_raw_parts(buf, len) }; box_raw!(TPKParserWrapper { parser: ffi_try!(TPKParser::from_bytes(buf)) }) } /// Returns a TPKParser. /// /// A `TPKParser` parses a keyring, which is simply zero or more TPKs /// concatenated together. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" fn pgp_tpk_parser_from_packet_parser(ppr: *mut PacketParserResult<'static>) -> *mut TPKParserWrapper<'static> { let ppr = ffi_param_move!(ppr); let parser = TPKParser::from_packet_parser(*ppr); box_raw!(TPKParserWrapper { parser: parser }) } /// Returns the next TPK, if any. /// /// If there is an error parsing the TPK, it is returned in *errp. /// /// If this function returns NULL and does not set *errp, then the end /// of the file was reached. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" fn pgp_tpk_parser_next(errp: Option<&mut *mut ::error::Error>, parser: *mut TPKParserWrapper) -> *mut TPK { ffi_make_fry_from_errp!(errp); let wrapper : &mut TPKParserWrapper = ffi_param_ref_mut!(parser); match wrapper.parser.next() { Some(tpkr) => ffi_try!(tpkr).move_into_raw(), None => ::std::ptr::null_mut(), } } /// Frees a pgp_tpk_parser_t. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" fn pgp_tpk_parser_free(parser: Option<&mut TPKParserWrapper>) { ffi_free!(parser) } /* TPKBuilder */ /// Creates a default `pgp_tpk_builder_t`. /// /// # Example /// /// ```c /// #include /// #include /// /// pgp_tpk_builder_t builder; /// pgp_tpk_t tpk; /// pgp_signature_t revocation; /// /// builder = pgp_tpk_builder_new (); /// pgp_tpk_builder_set_cipher_suite (&builder, PGP_TPK_CIPHER_SUITE_CV25519); /// pgp_tpk_builder_add_userid (&builder, "some@example.org"); /// pgp_tpk_builder_add_signing_subkey (&builder); /// pgp_tpk_builder_add_encryption_subkey (&builder); /// pgp_tpk_builder_generate (NULL, builder, &tpk, &revocation); /// assert (tpk); /// assert (revocation); /// /// /* Use the TPK. */ /// /// pgp_signature_free (revocation); /// pgp_tpk_free (tpk); /// ``` #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" fn pgp_tpk_builder_new() -> *mut TPKBuilder { box_raw!(TPKBuilder::new()) } /// Generates a general-purpose key. /// /// The key's primary key is certification- and signature-capable. /// The key has one subkey, an encryption-capable subkey. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" fn pgp_tpk_builder_general_purpose(cs: c_int, uid: *const c_char) -> *mut TPKBuilder { let uid = if uid.is_null() { None } else { Some(ffi_param_cstr!(uid).to_string_lossy()) }; box_raw!(TPKBuilder::general_purpose( Some(int_to_cipher_suite(cs)), uid)) } /// Generates a key compliant to [Autocrypt Level 1]. /// /// Autocrypt requires a user id, however, if `uid` is NULL, a TPK is /// created without any user ids. It is then the caller's /// responsibility to ensure that a user id is added later. /// /// `uid` must contain valid UTF-8. If it does not contain valid /// UTF-8, then the invalid code points are silently replaced with /// `U+FFFD REPLACEMENT CHARACTER`. /// /// [Autocrypt Level 1]: https://autocrypt.org/level1.html #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" fn pgp_tpk_builder_autocrypt(uid: *const c_char) -> *mut TPKBuilder { let uid = if uid.is_null() { None } else { Some(ffi_param_cstr!(uid).to_string_lossy()) }; box_raw!(TPKBuilder::autocrypt(Autocrypt::V1, uid)) } /// Frees an `pgp_tpk_builder_t`. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" fn pgp_tpk_builder_free(tpkb: Option<&mut TPKBuilder>) { ffi_free!(tpkb) } fn int_to_cipher_suite(cs: c_int) -> CipherSuite { use self::CipherSuite::*; match cs { 0 => Cv25519, 1 => RSA3k, 2 => P256, 3 => P384, 4 => P521, 5 => RSA2k, n => panic!("Bad ciphersuite: {}", n), } } /// Sets the encryption and signature algorithms for primary and all /// subkeys. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" fn pgp_tpk_builder_set_cipher_suite (tpkb: *mut *mut TPKBuilder, cs: c_int) { let tpkb = ffi_param_ref_mut!(tpkb); let tpkb_ = ffi_param_move!(*tpkb); let cs = int_to_cipher_suite(cs); 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. /// /// `uid` must contain valid UTF-8. If it does not contain valid /// UTF-8, then the invalid code points are silently replaced with /// `U+FFFD REPLACEMENT CHARACTER`. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" fn pgp_tpk_builder_add_userid (tpkb: *mut *mut TPKBuilder, uid: *const c_char) { let tpkb = ffi_param_ref_mut!(tpkb); let tpkb_ = ffi_param_move!(*tpkb); let uid = ffi_param_cstr!(uid).to_string_lossy(); let tpkb_ = tpkb_.add_userid(uid); *tpkb = box_raw!(tpkb_); } /// Adds a signing capable subkey. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" fn pgp_tpk_builder_add_signing_subkey (tpkb: *mut *mut TPKBuilder) { let tpkb = ffi_param_ref_mut!(tpkb); let tpkb_ = ffi_param_move!(*tpkb); let tpkb_ = tpkb_.add_signing_subkey(); *tpkb = box_raw!(tpkb_); } /// Adds an encryption capable subkey. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" fn pgp_tpk_builder_add_encryption_subkey (tpkb: *mut *mut TPKBuilder) { let tpkb = ffi_param_ref_mut!(tpkb); let tpkb_ = ffi_param_move!(*tpkb); let tpkb_ = tpkb_.add_encryption_subkey(); *tpkb = box_raw!(tpkb_); } /// Adds an certification capable subkey. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" fn pgp_tpk_builder_add_certification_subkey (tpkb: *mut *mut TPKBuilder) { let tpkb = ffi_param_ref_mut!(tpkb); let tpkb_ = ffi_param_move!(*tpkb); let tpkb_ = tpkb_.add_certification_subkey(); *tpkb = box_raw!(tpkb_); } /// Generates the actual TPK. /// /// Consumes `tpkb`. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" fn pgp_tpk_builder_generate (errp: Option<&mut *mut ::error::Error>, tpkb: *mut TPKBuilder, tpk_out: *mut Maybe, revocation_out: *mut *mut Signature) -> Status { let tpk_out = ffi_param_ref_mut!(tpk_out); let revocation_out = ffi_param_ref_mut!(revocation_out); let tpkb = ffi_param_move!(tpkb); match tpkb.generate() { Ok((tpk, revocation)) => { *tpk_out = Some(tpk).move_into_raw(); *revocation_out = revocation.move_into_raw(); Status::Success }, Err(e) => { *tpk_out = None; Err::<(), failure::Error>(e).move_into_raw(errp) }, } }