diff options
author | Neal H. Walfield <neal@pep.foundation> | 2018-11-22 10:32:14 +0100 |
---|---|---|
committer | Neal H. Walfield <neal@pep.foundation> | 2018-11-22 10:36:05 +0100 |
commit | fce58a063f8c2aeeaef783f45ec089cfcc753102 (patch) | |
tree | 9733d1552daf4fdc2985353cac7393886c830226 /ffi | |
parent | f9725cdcd471a5dbf1d61aef4f40cf229e0c04c1 (diff) |
ffi: Wrap TPK.
- In particular, add sq_tpk_primary, sq_tpk_revocation_status,
sq_tpk_revoke, sq_tpk_revoke_in_place, sq_tpk_expired,
sq_tpk_set_expiry, and sq_tpk_is_tsk.
Diffstat (limited to 'ffi')
-rw-r--r-- | ffi/include/sequoia/openpgp.h | 89 | ||||
-rw-r--r-- | ffi/src/openpgp.rs | 127 |
2 files changed, 216 insertions, 0 deletions
diff --git a/ffi/include/sequoia/openpgp.h b/ffi/include/sequoia/openpgp.h index 64e6a1db..f898c2a3 100644 --- a/ffi/include/sequoia/openpgp.h +++ b/ffi/include/sequoia/openpgp.h @@ -514,6 +514,37 @@ sq_keyid_t sq_signature_issuer(sq_signature_t sig); /*/ sq_fingerprint_t sq_signature_issuer_fingerprint(sq_signature_t sig); +typedef enum sq_reason_for_revocation { + /*/ + /// No reason specified (key revocations or cert revocations) + /*/ + SQ_REASON_FOR_REVOCATION_UNSPECIFIED, + + /*/ + /// Key is superseded (key revocations) + /*/ + SQ_REASON_FOR_REVOCATION_KEY_SUPERSEDED, + + /*/ + /// Key material has been compromised (key revocations) + /*/ + SQ_REASON_FOR_REVOCATION_KEY_COMPROMISED, + + /*/ + /// Key is retired and no longer used (key revocations) + /*/ + SQ_REASON_FOR_REVOCATION_KEY_RETIRED, + + /*/ + /// User ID information is no longer valid (cert revocations) + /*/ + SQ_REASON_FOR_REVOCATION_UID_RETIRED, + + /* Dummy value to make sure the enumeration has a defined size. Do + not use this value. */ + SQ_REASON_FOR_REVOCATION_FORCE_WIDTH = INT_MAX, +} sq_reason_for_revocation_t; + /* openpgp::tpk. */ @@ -619,6 +650,64 @@ sq_fingerprint_t sq_tpk_fingerprint (const sq_tpk_t tpk); /*/ sq_tsk_t sq_tpk_into_tsk (sq_tpk_t tpk); +/*/ +/// Returns a reference to the TPK's primary key. +/// +/// The tpk still owns the key. The caller should neither modify nor +/// free the key. +/*/ +sq_p_key_t sq_tpk_primary (sq_tpk_t tpk); + +/*/ +/// 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. +/*/ +sq_revocation_status_t sq_tpk_revocation_status (sq_tpk_t tpk); + +/*/ +/// Writes a revocation certificate to the writer. +/// +/// This function consumes the writer. It does *not* consume tpk. +/*/ +sq_status_t sq_tpk_revoke (sq_context_t ctx, + sq_tpk_t tpk, sq_reason_for_revocation_t code, + const char *reason, sq_writer_t writer); + +/*/ +/// Adds a revocation certificate to the tpk. +/// +/// This function consumes the tpk. +/*/ +sq_tpk_t sq_tpk_revoke_in_place (sq_context_t ctx, + sq_tpk_t tpk, + sq_reason_for_revocation_t code, + const char *reason); + +/*/ +/// Returns whether the TPK has expired. +/*/ +int sq_tpk_expired(sq_tpk_t tpk); + +/*/ +/// 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`. +/*/ +sq_tpk_t sq_tpk_set_expiry(sq_context_t ctx, + sq_tpk_t tpk, + uint32_t expiry); + +/*/ +/// Returns whether the TPK includes any secret key material. +/*/ +int sq_tpk_is_tsk(sq_tpk_t tpk); + /* TPKBuilder */ typedef struct sq_tpk_builder *sq_tpk_builder_t; diff --git a/ffi/src/openpgp.rs b/ffi/src/openpgp.rs index 1d23ad61..b740e571 100644 --- a/ffi/src/openpgp.rs +++ b/ffi/src/openpgp.rs @@ -31,6 +31,7 @@ use self::openpgp::parse::{PacketParserResult, PacketParser, PacketParserEOF}; use self::openpgp::serialize::Serialize; use self::openpgp::constants::{ DataFormat, + ReasonForRevocation, }; use super::build_hasher; @@ -821,6 +822,132 @@ pub extern "system" fn sq_tpk_into_tsk(tpk: *mut 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. +#[no_mangle] +pub extern "system" fn sq_tpk_revoke (ctx: Option<&mut Context>, + tpk: *mut TPK, + code: c_int, + reason: Option<*const c_char>) + -> *mut packet::Signature +{ + 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(code, reason)) +} + +/// Adds a revocation certificate to the tpk. +/// +/// This function consumes the tpk. +#[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 +} + +/// 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 +} + fn revocation_status_to_int(rs: &RevocationStatus) -> c_int { match rs { RevocationStatus::Revoked(_) => 0, |