mirror of
https://github.com/chatmail/core.git
synced 2026-04-17 21:46:35 +03:00
144 lines
4.2 KiB
Rust
144 lines
4.2 KiB
Rust
use std::ffi::CString;
|
|
use std::io::Cursor;
|
|
use std::slice;
|
|
|
|
use libc::c_char;
|
|
use pgp::composed::{from_armor_many, from_bytes_many, PublicOrSecret};
|
|
use pgp::types::KeyTrait;
|
|
|
|
use crate::pgp::cvec;
|
|
|
|
pub type public_or_secret_key = PublicOrSecret;
|
|
|
|
/// Creates an in-memory representation of a PGP key, based on the armor file given.
|
|
/// The returned pointer should be stored, and reused when calling methods "on" this key.
|
|
/// When done with it [rpgp_key_drop] should be called, to free the memory.
|
|
#[allow(dead_code)]
|
|
pub unsafe fn rpgp_key_from_armor(raw: *const u8, len: libc::size_t) -> *mut public_or_secret_key {
|
|
assert!(!raw.is_null());
|
|
assert!(len > 0);
|
|
|
|
let bytes = slice::from_raw_parts(raw, len);
|
|
let (mut keys, _headers) = try_ffi!(from_armor_many(Cursor::new(bytes)), "failed to parse");
|
|
|
|
let key = try_ffi!(
|
|
try_ffi!(
|
|
keys.nth(0).ok_or_else(|| format_err!("no valid key found")),
|
|
"failed to parse key"
|
|
),
|
|
"failed to parse key"
|
|
);
|
|
|
|
try_ffi!(key.verify(), "failed to verify key");
|
|
|
|
Box::into_raw(Box::new(key))
|
|
}
|
|
|
|
/// Creates an in-memory representation of a PGP key, based on the serialized bytes given.
|
|
pub unsafe extern "C" fn rpgp_key_from_bytes(
|
|
raw: *const u8,
|
|
len: libc::size_t,
|
|
) -> *mut public_or_secret_key {
|
|
assert!(!raw.is_null());
|
|
assert!(len > 0);
|
|
|
|
let bytes = slice::from_raw_parts(raw, len);
|
|
let mut keys = from_bytes_many(Cursor::new(bytes));
|
|
|
|
let key = try_ffi!(
|
|
try_ffi!(
|
|
keys.nth(0).ok_or_else(|| format_err!("no valid key found")),
|
|
"failed to parse key"
|
|
),
|
|
"failed to parse key"
|
|
);
|
|
|
|
try_ffi!(key.verify(), "failed to verify key");
|
|
|
|
Box::into_raw(Box::new(key))
|
|
}
|
|
|
|
/// Returns the KeyID for the passed in key. The caller is responsible to call [rpgp_string_drop] with the returned memory, to free it.
|
|
#[allow(dead_code)]
|
|
pub unsafe fn rpgp_key_id(key_ptr: *mut public_or_secret_key) -> *mut c_char {
|
|
assert!(!key_ptr.is_null());
|
|
|
|
let key = &*key_ptr;
|
|
let id = try_ffi!(
|
|
CString::new(hex::encode(&key.key_id())),
|
|
"failed to allocate string"
|
|
);
|
|
|
|
id.into_raw()
|
|
}
|
|
|
|
/// Returns the Fingerprint for the passed in key. The caller is responsible to call [rpgp_cvec_drop] with the returned memory, to free it.
|
|
pub unsafe fn rpgp_key_fingerprint(key_ptr: *mut public_or_secret_key) -> *mut cvec {
|
|
assert!(!key_ptr.is_null());
|
|
|
|
let key = &*key_ptr;
|
|
let fingerprint = key.fingerprint();
|
|
|
|
Box::into_raw(Box::new(fingerprint.into()))
|
|
}
|
|
|
|
/// Returns `true` if this key is a public key, false otherwise.
|
|
pub unsafe fn rpgp_key_is_public(key_ptr: *mut public_or_secret_key) -> bool {
|
|
assert!(!key_ptr.is_null());
|
|
|
|
(&*key_ptr).is_public()
|
|
}
|
|
|
|
/// Returns `true` if this key is a secret key, false otherwise.
|
|
pub unsafe fn rpgp_key_is_secret(key_ptr: *mut public_or_secret_key) -> bool {
|
|
assert!(!key_ptr.is_null());
|
|
|
|
(&*key_ptr).is_secret()
|
|
}
|
|
|
|
/// Frees the memory of the passed in key, making the pointer invalid after this method was called.
|
|
pub unsafe fn rpgp_key_drop(key_ptr: *mut public_or_secret_key) {
|
|
assert!(!key_ptr.is_null());
|
|
|
|
let _key = &*key_ptr;
|
|
// Drop
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
use std::ffi::CStr;
|
|
|
|
use crate::pgp::{
|
|
rpgp_create_x25519_skey, rpgp_cvec_data, rpgp_cvec_drop, rpgp_cvec_len, rpgp_skey_to_bytes,
|
|
};
|
|
|
|
#[test]
|
|
fn test_fingerprint() {
|
|
let user_id = CStr::from_bytes_with_nul(b"<hello@world.com>\0").unwrap();
|
|
|
|
unsafe {
|
|
// Create the actual key
|
|
let skey = rpgp_create_x25519_skey(user_id.as_ptr());
|
|
|
|
// Serialize secret key into bytes
|
|
let skey_bytes = rpgp_skey_to_bytes(skey);
|
|
|
|
let key = rpgp_key_from_bytes(rpgp_cvec_data(skey_bytes), rpgp_cvec_len(skey_bytes));
|
|
assert!(rpgp_key_is_secret(key));
|
|
|
|
let fingerprint1 = rpgp_key_fingerprint(key);
|
|
|
|
// get fingerprint directly
|
|
let mut fingerprint2: cvec = (&*skey).fingerprint().into();
|
|
|
|
assert_eq!(*fingerprint1, fingerprint2);
|
|
|
|
// cleanup
|
|
rpgp_cvec_drop(skey_bytes);
|
|
rpgp_cvec_drop(fingerprint1);
|
|
rpgp_cvec_drop(&mut fingerprint2);
|
|
}
|
|
}
|
|
}
|