mirror of
https://github.com/chatmail/core.git
synced 2026-04-17 13:36:30 +03:00
refactor: emove double abstraction in handling keys and interactions with rpgp
This commit is contained in:
@@ -12,7 +12,6 @@ pkg-config = "0.3"
|
||||
c2rust-bitfields = "0.1.0"
|
||||
libc = "0.2.51"
|
||||
pgp = "0.2.0"
|
||||
failure = "0.1.5"
|
||||
hex = "0.3.2"
|
||||
sha2 = "0.8.0"
|
||||
rand = "0.6.5"
|
||||
|
||||
@@ -407,7 +407,7 @@ unsafe fn log_msglist(context: &dc_context_t, msglist: *mut dc_array_t) {
|
||||
}
|
||||
unsafe fn log_contactlist(context: &dc_context_t, contacts: *mut dc_array_t) {
|
||||
let mut contact: *mut dc_contact_t;
|
||||
let peerstate: *mut dc_apeerstate_t = dc_apeerstate_new(context);
|
||||
let mut peerstate = dc_apeerstate_new(context);
|
||||
if !dc_array_search_id(contacts, 1i32 as uint32_t, 0 as *mut size_t) {
|
||||
dc_array_add_id(contacts, 1i32 as uint32_t);
|
||||
}
|
||||
@@ -444,18 +444,21 @@ unsafe fn log_contactlist(context: &dc_context_t, contacts: *mut dc_array_t) {
|
||||
b"addr unset\x00" as *const u8 as *const libc::c_char
|
||||
},
|
||||
);
|
||||
let peerstate_ok: libc::c_int =
|
||||
dc_apeerstate_load_by_addr(peerstate, &context.sql.clone().read().unwrap(), addr);
|
||||
let peerstate_ok: libc::c_int = dc_apeerstate_load_by_addr(
|
||||
&mut peerstate,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
addr,
|
||||
);
|
||||
if 0 != peerstate_ok && contact_id != 1i32 as libc::c_uint {
|
||||
let pe: *mut libc::c_char;
|
||||
match (*peerstate).prefer_encrypt {
|
||||
match peerstate.prefer_encrypt {
|
||||
1 => pe = dc_strdup(b"mutual\x00" as *const u8 as *const libc::c_char),
|
||||
0 => pe = dc_strdup(b"no-preference\x00" as *const u8 as *const libc::c_char),
|
||||
20 => pe = dc_strdup(b"reset\x00" as *const u8 as *const libc::c_char),
|
||||
_ => {
|
||||
pe = dc_mprintf(
|
||||
b"unknown-value (%i)\x00" as *const u8 as *const libc::c_char,
|
||||
(*peerstate).prefer_encrypt,
|
||||
peerstate.prefer_encrypt,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -485,7 +488,7 @@ unsafe fn log_contactlist(context: &dc_context_t, contacts: *mut dc_array_t) {
|
||||
}
|
||||
i += 1
|
||||
}
|
||||
dc_apeerstate_unref(peerstate);
|
||||
dc_apeerstate_unref(&mut peerstate);
|
||||
}
|
||||
static mut s_is_auth: libc::c_int = 0i32;
|
||||
|
||||
|
||||
@@ -512,7 +512,7 @@ pub const DC_STR_COUNT: usize = 66;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)]
|
||||
#[repr(u8)]
|
||||
pub enum Key {
|
||||
pub enum KeyType {
|
||||
Public = 0,
|
||||
Private = 1,
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ use std::str::FromStr;
|
||||
use std::{fmt, str};
|
||||
|
||||
use mmime::mailimf_types::*;
|
||||
use num_traits::ToPrimitive;
|
||||
|
||||
use crate::constants::*;
|
||||
use crate::dc_contact::*;
|
||||
@@ -50,12 +49,12 @@ impl str::FromStr for EncryptPreference {
|
||||
/// Parse and create [Autocrypt-headers](https://autocrypt.org/en/latest/level1.html#the-autocrypt-header).
|
||||
pub struct Aheader {
|
||||
pub addr: String,
|
||||
pub public_key: *mut dc_key_t,
|
||||
pub public_key: Key,
|
||||
pub prefer_encrypt: EncryptPreference,
|
||||
}
|
||||
|
||||
impl Aheader {
|
||||
pub fn new(addr: String, public_key: *mut dc_key_t, prefer_encrypt: EncryptPreference) -> Self {
|
||||
pub fn new(addr: String, public_key: Key, prefer_encrypt: EncryptPreference) -> Self {
|
||||
Aheader {
|
||||
addr,
|
||||
public_key,
|
||||
@@ -122,7 +121,7 @@ impl fmt::Display for Aheader {
|
||||
// adds a whitespace every 78 characters, this allows libEtPan to
|
||||
// wrap the lines according to RFC 5322
|
||||
// (which may insert a linebreak before every whitespace)
|
||||
let keydata = dc_key_render_base64_string(self.public_key, 78);
|
||||
let keydata = self.public_key.to_base64(78);
|
||||
write!(
|
||||
fmt,
|
||||
"addr={}; prefer-encrypt={}; keydata={}",
|
||||
@@ -157,19 +156,13 @@ impl str::FromStr for Aheader {
|
||||
}
|
||||
};
|
||||
|
||||
let public_key = match attributes.remove("keydata") {
|
||||
Some(raw) => {
|
||||
let key = unsafe { dc_key_new() };
|
||||
unsafe {
|
||||
dc_key_set_from_base64(
|
||||
key,
|
||||
CString::new(raw).unwrap().as_ptr(),
|
||||
Key::Public.to_i32().unwrap(),
|
||||
)
|
||||
};
|
||||
key
|
||||
}
|
||||
let public_key = match attributes
|
||||
.remove("keydata")
|
||||
.and_then(|raw| Key::from_base64(&raw, KeyType::Public))
|
||||
{
|
||||
Some(key) => key,
|
||||
None => {
|
||||
println!("invalid key");
|
||||
return Err(());
|
||||
}
|
||||
};
|
||||
@@ -196,22 +189,12 @@ impl str::FromStr for Aheader {
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Aheader {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
dc_key_unref(self.public_key);
|
||||
}
|
||||
self.public_key = std::ptr::null_mut();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::pgp as rpgp;
|
||||
|
||||
fn rawkey() -> String {
|
||||
"mDMEWFUX7RYJKwYBBAHaRw8BAQdACHq6FkRGsHqBMsNpD7d+aQ2jtxVwTO+Y4NhBaQyHaMj+0HWFsaWNlQHRlc3RzdWl0ZS5hdXRvY3J5cHQub3JniJAEExYIADgWIQQmqmdR/XZoxC+kkkr8dE2p/nPD1AUCWFUX7QIbAwULCQgHAgYVCAkKCwIEFgIDAQIeAQIXgAAKCRD8dE2p/nPD1EqOAP0WUDKwko001X7XTSYbWGWmXfR9P1Aw6917EnkVQMsp3gEA86Ii8ArL3jd+E2qS5JSysx/qiVhuTSwWzmC5K6zKdg+4OARYVRfuEgorBgEEAZdVAQUBAQdAv1A88FoCfwz0zSh6NNnUuKuz1p3ctJ3kXMGotsVYjA0DAQgHiHgEGBYIACAWIQQmqmdR/XZoxC+kkkr8dE2p/nPD1AUCWFUX7gIbDAAKCRD8dE2p/nPD1FTOAP4nS14sX7a/nBXBKWAh/oX8iVtkhmZqjy9tG21BcNqb+wEAq73H4+1ncnkscR3Nu4GYzNRSD3NXq68tEESK28kYvw4=".into()
|
||||
"xsBNBFzG3j0BCAC6iNhT8zydvCXi8LI/gFnkadMbfmSE/rTJskRRra/utGbLyDta/yTrJgWL7O3y/g4HdDW/dN2z26Y6W13IMzx9gLInn1KQZChtqWAcr/ReUucXcymwcfg1mdkBGk3TSLeLihN6CJx8Wsv8ig+kgAzte4f5rqEEAJVQ9WZHuti7UiYs6oRzqTo06CRe9owVXxzdMf0VDQtf7ZFm9dpzKKbhH7Lu8880iiotQ9/yRCkDGp9fNThsrLdZiK6OIAcIBAqi2rI89aS1dAmnRbktQieCx5izzyYkR1KvVL3gTTllHOzfKVEC2asmtWu2e4se/+O4WMIS1eGrn7GeWVb0Vwc5ABEBAAHNETxhQEBiLmV4YW1wbGUuZGU+wsCJBBABCAAzAhkBBQJcxt5FAhsDBAsJCAcGFQgJCgsCAxYCARYhBI4xxYKBgH3ANh5cufaKrc9mtiMLAAoJEPaKrc9mtiML938H/18F+3Wf9/JaAy/8hCO1v4S2PVBhxaKCokaNFtkfaMRne2l087LscCFPiFNyb4mv6Z3YeK8Xpxlp2sI0ecvdiqLUOGfnxS6tQrj+83EjtIrZ/hXOk1h121QFWH9Zg2VNHtODXjAgdLDC0NWUrclR0ZOqEDQHeo0ibTILdokVfXFN25wakPmGaYJP2y729cb1ve7RzvIvwn+Dddfxo3ao72rBfLi7l4NQ4S0KsY4cw+/6l5bRCKYCP77wZtvCwUvfVVosLdT43agtSiBI49+ayqvZ8OCvSJa61i+v81brTiEy9GBod4eAp45Ibsuemkw+gon4ZOvUXHTjwFB+h63MrozOwE0EXMbePQEIAL/vauf1zK8JgCu3V+G+SOX0iWw5xUlCPX+ERpBbWfwu3uAqn4wYXD3JDE/fVAF668xiV4eTPtlSUd5h0mn+G7uXMMOtkb+20SoEt50f8zw8TrL9t+ZsV11GKZWJpCar5AhXWsn6EEi8I2hLL5vn55ZZmHuGgN4jjmkRl3ToKCLhaXwTBjCJem7N5EH7F75wErEITa55v4Lb4Nfca7vnvtYrI1OA446xa8gHra0SINelTD09/JM/Fw4sWVPBaRZmJK/Tnu79N23No9XBUubmFPv1pNexZsQclicnTpt/BEWhiun7d6lfGB63K1aoHRTR1pcrWvBuALuuz0gqar2zlI0AEQEAAcLAdgQYAQgAIAUCXMbeRQIbDBYhBI4xxYKBgH3ANh5cufaKrc9mtiMLAAoJEPaKrc9mtiMLKSEIAIyLCRO2OyZ0IYRvRPpMn4p7E+7Pfcz/0mSkOy+1hshgJnqivXurm8zwGrwdMqeV4eslKR9H1RUdWGUQJNbtwmmjrt5DHpIhYHl5t3FpCBaGbV20Omo00Q38lBl9MtrmZkZw+ktEk6X+0xCKssMF+2MADkSOIufbR5HrDVB89VZOHCO9DeXvCUUAw2hyJiL/LHmLzJ40zYoTmb+F//f0k0j+tRdbkefyRoCmwG7YGiT+2hnCdgcezswnzah5J3ZKlrg7jOGo1LxtbvNUzxNBbC6S/aNgwm6qxo7xegRhmEl5uZ16zwyj4qz+xkjGy25Of5mWfUDoNw7OT7sjUbHOOMc=".into()
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -225,7 +208,6 @@ mod tests {
|
||||
|
||||
assert_eq!(h.addr, "me@mail.com");
|
||||
assert_eq!(h.prefer_encrypt, EncryptPreference::Mutual);
|
||||
assert!(!h.public_key.is_null());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -235,7 +217,6 @@ mod tests {
|
||||
|
||||
assert_eq!(h.addr, "me@mail.com");
|
||||
assert_eq!(h.prefer_encrypt, EncryptPreference::NoPreference);
|
||||
assert!(!h.public_key.is_null());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -253,32 +234,22 @@ mod tests {
|
||||
|
||||
let ah = Aheader::from_str(fixed_header).expect("failed to parse");
|
||||
assert_eq!(ah.addr, "a@b.example.org");
|
||||
// assert_eq!(unsafe { (*ah.public_key).bytes }, 1212);
|
||||
assert!(valid_key(ah.public_key as *const _));
|
||||
assert_eq!(ah.prefer_encrypt, EncryptPreference::Mutual);
|
||||
|
||||
let rendered = ah.to_string();
|
||||
assert_eq!(rendered, fixed_header);
|
||||
|
||||
let ah = Aheader::from_str(" _foo; __FOO=BAR ;;; addr = a@b.example.org ;\r\n prefer-encrypt = mutual ; keydata = RG VsdGEgQ\r\n2hhdA==").expect("failed to parse");
|
||||
let ah = Aheader::from_str(&format!(" _foo; __FOO=BAR ;;; addr = a@b.example.org ;\r\n prefer-encrypt = mutual ; keydata = {}", rawkey())).expect("failed to parse");
|
||||
assert_eq!(ah.addr, "a@b.example.org");
|
||||
assert_eq!(unsafe { (*ah.public_key).bytes }, 10);
|
||||
assert_eq!(ah.prefer_encrypt, EncryptPreference::Mutual);
|
||||
assert_eq!(
|
||||
unsafe {
|
||||
CStr::from_ptr((*ah.public_key).binary as *const _)
|
||||
.to_str()
|
||||
.unwrap()
|
||||
},
|
||||
"Delta Chat"
|
||||
);
|
||||
|
||||
Aheader::from_str(
|
||||
"addr=a@b.example.org; prefer-encrypt=ignoreUnknownValues; keydata=RGVsdGEgQ2hhdA==",
|
||||
)
|
||||
Aheader::from_str(&format!(
|
||||
"addr=a@b.example.org; prefer-encrypt=ignoreUnknownValues; keydata={}",
|
||||
rawkey()
|
||||
))
|
||||
.expect("failed to parse");
|
||||
|
||||
Aheader::from_str("addr=a@b.example.org; keydata=RGVsdGEgQ2hhdA==")
|
||||
Aheader::from_str(&format!("addr=a@b.example.org; keydata={}", rawkey()))
|
||||
.expect("failed to parse");
|
||||
}
|
||||
|
||||
@@ -290,29 +261,4 @@ mod tests {
|
||||
assert!(Aheader::from_str(" ;;").is_err());
|
||||
assert!(Aheader::from_str("addr=a@t.de; unknwon=1; keydata=jau").is_err());
|
||||
}
|
||||
|
||||
fn valid_key(raw_key: *const dc_key_t) -> bool {
|
||||
let mut key_is_valid = false;
|
||||
unsafe {
|
||||
if !(raw_key.is_null() || (*raw_key).binary.is_null() || (*raw_key).bytes <= 0i32) {
|
||||
let key = rpgp::rpgp_key_from_bytes(
|
||||
(*raw_key).binary as *const _,
|
||||
(*raw_key).bytes as usize,
|
||||
);
|
||||
|
||||
if (*raw_key).type_0 == 0i32 && 0 != rpgp::rpgp_key_is_public(key) as libc::c_int {
|
||||
key_is_valid = true;
|
||||
} else if (*raw_key).type_0 == 1i32
|
||||
&& 0 != rpgp::rpgp_key_is_secret(key) as libc::c_int
|
||||
{
|
||||
key_is_valid = true;
|
||||
}
|
||||
if !key.is_null() {
|
||||
rpgp::rpgp_key_drop(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
key_is_valid
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ use std::ffi::{CStr, CString};
|
||||
|
||||
use num_traits::ToPrimitive;
|
||||
|
||||
use crate::constants::*;
|
||||
use crate::dc_aheader::*;
|
||||
use crate::dc_chat::*;
|
||||
use crate::dc_context::dc_context_t;
|
||||
@@ -17,7 +18,6 @@ use crate::x::*;
|
||||
* @class dc_apeerstate_t
|
||||
* Library-internal.
|
||||
*/
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct dc_apeerstate_t<'a> {
|
||||
pub context: &'a dc_context_t,
|
||||
@@ -25,151 +25,143 @@ pub struct dc_apeerstate_t<'a> {
|
||||
pub last_seen: time_t,
|
||||
pub last_seen_autocrypt: time_t,
|
||||
pub prefer_encrypt: libc::c_int,
|
||||
pub public_key: *mut dc_key_t,
|
||||
pub public_key: Option<Key>,
|
||||
pub public_key_fingerprint: *mut libc::c_char,
|
||||
pub gossip_key: *mut dc_key_t,
|
||||
pub gossip_key: Option<Key>,
|
||||
pub gossip_timestamp: time_t,
|
||||
pub gossip_key_fingerprint: *mut libc::c_char,
|
||||
pub verified_key: *mut dc_key_t,
|
||||
// TODO: this should be a reference to either the public_key or verified_key
|
||||
pub verified_key: Option<Key>,
|
||||
pub verified_key_fingerprint: *mut libc::c_char,
|
||||
pub to_save: libc::c_int,
|
||||
pub degrade_event: libc::c_int,
|
||||
}
|
||||
|
||||
/* the returned pointer is ref'd and must be unref'd after usage */
|
||||
pub unsafe fn dc_apeerstate_new<'a>(context: &'a dc_context_t) -> *mut dc_apeerstate_t<'a> {
|
||||
let mut peerstate: *mut dc_apeerstate_t;
|
||||
peerstate = calloc(1, ::std::mem::size_of::<dc_apeerstate_t>()) as *mut dc_apeerstate_t;
|
||||
if peerstate.is_null() {
|
||||
exit(43i32);
|
||||
pub fn dc_apeerstate_new<'a>(context: &'a dc_context_t) -> dc_apeerstate_t<'a> {
|
||||
dc_apeerstate_t {
|
||||
context,
|
||||
addr: std::ptr::null_mut(),
|
||||
last_seen: 0,
|
||||
last_seen_autocrypt: 0,
|
||||
prefer_encrypt: 0,
|
||||
public_key: None,
|
||||
public_key_fingerprint: std::ptr::null_mut(),
|
||||
gossip_key: None,
|
||||
gossip_key_fingerprint: std::ptr::null_mut(),
|
||||
gossip_timestamp: 0,
|
||||
verified_key: None,
|
||||
verified_key_fingerprint: std::ptr::null_mut(),
|
||||
to_save: 0,
|
||||
degrade_event: 0,
|
||||
}
|
||||
(*peerstate).context = context;
|
||||
|
||||
peerstate
|
||||
}
|
||||
|
||||
pub unsafe fn dc_apeerstate_unref(peerstate: *mut dc_apeerstate_t) {
|
||||
pub unsafe fn dc_apeerstate_unref(peerstate: &mut dc_apeerstate_t) {
|
||||
dc_apeerstate_empty(peerstate);
|
||||
free(peerstate as *mut libc::c_void);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* dc_apeerstate_t represents the state of an Autocrypt peer - Load/save
|
||||
******************************************************************************/
|
||||
unsafe fn dc_apeerstate_empty(mut peerstate: *mut dc_apeerstate_t) {
|
||||
if peerstate.is_null() {
|
||||
return;
|
||||
}
|
||||
(*peerstate).last_seen = 0i32 as time_t;
|
||||
(*peerstate).last_seen_autocrypt = 0i32 as time_t;
|
||||
(*peerstate).prefer_encrypt = 0i32;
|
||||
(*peerstate).to_save = 0i32;
|
||||
free((*peerstate).addr as *mut libc::c_void);
|
||||
(*peerstate).addr = 0 as *mut libc::c_char;
|
||||
free((*peerstate).public_key_fingerprint as *mut libc::c_void);
|
||||
(*peerstate).public_key_fingerprint = 0 as *mut libc::c_char;
|
||||
free((*peerstate).gossip_key_fingerprint as *mut libc::c_void);
|
||||
(*peerstate).gossip_key_fingerprint = 0 as *mut libc::c_char;
|
||||
free((*peerstate).verified_key_fingerprint as *mut libc::c_void);
|
||||
(*peerstate).verified_key_fingerprint = 0 as *mut libc::c_char;
|
||||
dc_key_unref((*peerstate).public_key);
|
||||
(*peerstate).public_key = 0 as *mut dc_key_t;
|
||||
(*peerstate).gossip_timestamp = 0i32 as time_t;
|
||||
dc_key_unref((*peerstate).gossip_key);
|
||||
(*peerstate).gossip_key = 0 as *mut dc_key_t;
|
||||
dc_key_unref((*peerstate).verified_key);
|
||||
(*peerstate).verified_key = 0 as *mut dc_key_t;
|
||||
(*peerstate).degrade_event = 0i32;
|
||||
unsafe fn dc_apeerstate_empty(peerstate: &mut dc_apeerstate_t) {
|
||||
peerstate.last_seen = 0i32 as time_t;
|
||||
peerstate.last_seen_autocrypt = 0i32 as time_t;
|
||||
peerstate.prefer_encrypt = 0i32;
|
||||
peerstate.to_save = 0i32;
|
||||
free(peerstate.addr as *mut libc::c_void);
|
||||
peerstate.addr = 0 as *mut libc::c_char;
|
||||
free(peerstate.public_key_fingerprint as *mut libc::c_void);
|
||||
peerstate.public_key_fingerprint = 0 as *mut libc::c_char;
|
||||
free(peerstate.gossip_key_fingerprint as *mut libc::c_void);
|
||||
peerstate.gossip_key_fingerprint = 0 as *mut libc::c_char;
|
||||
free(peerstate.verified_key_fingerprint as *mut libc::c_void);
|
||||
peerstate.verified_key_fingerprint = 0 as *mut libc::c_char;
|
||||
|
||||
peerstate.public_key = None;
|
||||
peerstate.gossip_timestamp = 0i32 as time_t;
|
||||
peerstate.gossip_key = None;
|
||||
peerstate.verified_key = None;
|
||||
peerstate.degrade_event = 0i32;
|
||||
}
|
||||
|
||||
// TODO should return bool /rtn
|
||||
pub unsafe fn dc_apeerstate_init_from_header(
|
||||
mut peerstate: *mut dc_apeerstate_t,
|
||||
peerstate: &mut dc_apeerstate_t,
|
||||
header: &Aheader,
|
||||
message_time: time_t,
|
||||
) -> libc::c_int {
|
||||
if peerstate.is_null() {
|
||||
return 0i32;
|
||||
}
|
||||
dc_apeerstate_empty(peerstate);
|
||||
(*peerstate).addr = dc_strdup(CString::new(header.addr.clone()).unwrap().as_ptr());
|
||||
(*peerstate).last_seen = message_time;
|
||||
(*peerstate).last_seen_autocrypt = message_time;
|
||||
(*peerstate).to_save |= 0x2i32;
|
||||
(*peerstate).prefer_encrypt = header.prefer_encrypt.to_i32().unwrap();
|
||||
(*peerstate).public_key = dc_key_new();
|
||||
dc_key_set_from_key((*peerstate).public_key, header.public_key);
|
||||
peerstate.addr = dc_strdup(CString::new(header.addr.clone()).unwrap().as_ptr());
|
||||
peerstate.last_seen = message_time;
|
||||
peerstate.last_seen_autocrypt = message_time;
|
||||
peerstate.to_save |= 0x2i32;
|
||||
peerstate.prefer_encrypt = header.prefer_encrypt.to_i32().unwrap();
|
||||
peerstate.public_key = Some(header.public_key.clone());
|
||||
dc_apeerstate_recalc_fingerprint(peerstate);
|
||||
|
||||
1
|
||||
}
|
||||
|
||||
// TODO should return bool /rtn
|
||||
pub unsafe fn dc_apeerstate_recalc_fingerprint(mut peerstate: *mut dc_apeerstate_t) -> libc::c_int {
|
||||
let mut success: libc::c_int = 0i32;
|
||||
pub unsafe fn dc_apeerstate_recalc_fingerprint(peerstate: &mut dc_apeerstate_t) -> libc::c_int {
|
||||
let mut old_public_fingerprint: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut old_gossip_fingerprint: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
if !peerstate.is_null() {
|
||||
if !(*peerstate).public_key.is_null() {
|
||||
old_public_fingerprint = (*peerstate).public_key_fingerprint;
|
||||
(*peerstate).public_key_fingerprint =
|
||||
dc_key_get_fingerprint((*peerstate).context, (*peerstate).public_key);
|
||||
if old_public_fingerprint.is_null()
|
||||
|| *old_public_fingerprint.offset(0isize) as libc::c_int == 0i32
|
||||
|| (*peerstate).public_key_fingerprint.is_null()
|
||||
|| *(*peerstate).public_key_fingerprint.offset(0isize) as libc::c_int == 0i32
|
||||
|| strcasecmp(old_public_fingerprint, (*peerstate).public_key_fingerprint) != 0i32
|
||||
|
||||
if let Some(ref public_key) = peerstate.public_key {
|
||||
old_public_fingerprint = peerstate.public_key_fingerprint;
|
||||
peerstate.public_key_fingerprint = public_key.fingerprint_c();
|
||||
if old_public_fingerprint.is_null()
|
||||
|| *old_public_fingerprint.offset(0isize) as libc::c_int == 0i32
|
||||
|| peerstate.public_key_fingerprint.is_null()
|
||||
|| *peerstate.public_key_fingerprint.offset(0isize) as libc::c_int == 0i32
|
||||
|| strcasecmp(old_public_fingerprint, peerstate.public_key_fingerprint) != 0i32
|
||||
{
|
||||
peerstate.to_save |= 0x2i32;
|
||||
if !old_public_fingerprint.is_null()
|
||||
&& 0 != *old_public_fingerprint.offset(0isize) as libc::c_int
|
||||
{
|
||||
(*peerstate).to_save |= 0x2i32;
|
||||
if !old_public_fingerprint.is_null()
|
||||
&& 0 != *old_public_fingerprint.offset(0isize) as libc::c_int
|
||||
{
|
||||
(*peerstate).degrade_event |= 0x2i32
|
||||
}
|
||||
peerstate.degrade_event |= 0x2i32;
|
||||
}
|
||||
}
|
||||
if !(*peerstate).gossip_key.is_null() {
|
||||
old_gossip_fingerprint = (*peerstate).gossip_key_fingerprint;
|
||||
(*peerstate).gossip_key_fingerprint =
|
||||
dc_key_get_fingerprint((*peerstate).context, (*peerstate).gossip_key);
|
||||
if old_gossip_fingerprint.is_null()
|
||||
|| *old_gossip_fingerprint.offset(0isize) as libc::c_int == 0i32
|
||||
|| (*peerstate).gossip_key_fingerprint.is_null()
|
||||
|| *(*peerstate).gossip_key_fingerprint.offset(0isize) as libc::c_int == 0i32
|
||||
|| strcasecmp(old_gossip_fingerprint, (*peerstate).gossip_key_fingerprint) != 0i32
|
||||
}
|
||||
|
||||
if let Some(ref gossip_key) = peerstate.gossip_key {
|
||||
old_gossip_fingerprint = peerstate.gossip_key_fingerprint;
|
||||
peerstate.gossip_key_fingerprint = gossip_key.fingerprint_c();
|
||||
|
||||
if old_gossip_fingerprint.is_null()
|
||||
|| *old_gossip_fingerprint.offset(0isize) as libc::c_int == 0i32
|
||||
|| peerstate.gossip_key_fingerprint.is_null()
|
||||
|| *peerstate.gossip_key_fingerprint.offset(0isize) as libc::c_int == 0i32
|
||||
|| strcasecmp(old_gossip_fingerprint, peerstate.gossip_key_fingerprint) != 0i32
|
||||
{
|
||||
peerstate.to_save |= 0x2i32;
|
||||
if !old_gossip_fingerprint.is_null()
|
||||
&& 0 != *old_gossip_fingerprint.offset(0isize) as libc::c_int
|
||||
{
|
||||
(*peerstate).to_save |= 0x2i32;
|
||||
if !old_gossip_fingerprint.is_null()
|
||||
&& 0 != *old_gossip_fingerprint.offset(0isize) as libc::c_int
|
||||
{
|
||||
(*peerstate).degrade_event |= 0x2i32
|
||||
}
|
||||
peerstate.degrade_event |= 0x2i32
|
||||
}
|
||||
}
|
||||
success = 1i32
|
||||
}
|
||||
|
||||
free(old_public_fingerprint as *mut libc::c_void);
|
||||
free(old_gossip_fingerprint as *mut libc::c_void);
|
||||
|
||||
success
|
||||
1
|
||||
}
|
||||
|
||||
// TODO should return bool /rtn
|
||||
pub unsafe fn dc_apeerstate_init_from_gossip(
|
||||
mut peerstate: *mut dc_apeerstate_t,
|
||||
peerstate: &mut dc_apeerstate_t,
|
||||
gossip_header: &Aheader,
|
||||
message_time: time_t,
|
||||
) -> libc::c_int {
|
||||
if peerstate.is_null() {
|
||||
return 0i32;
|
||||
}
|
||||
dc_apeerstate_empty(peerstate);
|
||||
(*peerstate).addr = dc_strdup(CString::new(gossip_header.addr.clone()).unwrap().as_ptr());
|
||||
(*peerstate).gossip_timestamp = message_time;
|
||||
(*peerstate).to_save |= 0x2i32;
|
||||
(*peerstate).gossip_key = dc_key_new();
|
||||
dc_key_set_from_key((*peerstate).gossip_key, gossip_header.public_key);
|
||||
peerstate.addr = dc_strdup(CString::new(gossip_header.addr.clone()).unwrap().as_ptr());
|
||||
peerstate.gossip_timestamp = message_time;
|
||||
peerstate.to_save |= 0x2i32;
|
||||
peerstate.gossip_key = Some(gossip_header.public_key.clone());
|
||||
dc_apeerstate_recalc_fingerprint(peerstate);
|
||||
|
||||
1
|
||||
@@ -177,31 +169,26 @@ pub unsafe fn dc_apeerstate_init_from_gossip(
|
||||
|
||||
// TODO should return bool /rtn
|
||||
pub unsafe fn dc_apeerstate_degrade_encryption(
|
||||
mut peerstate: *mut dc_apeerstate_t,
|
||||
peerstate: &mut dc_apeerstate_t,
|
||||
message_time: time_t,
|
||||
) -> libc::c_int {
|
||||
if peerstate.is_null() {
|
||||
return 0i32;
|
||||
if peerstate.prefer_encrypt == 1i32 {
|
||||
peerstate.degrade_event |= 0x1i32
|
||||
}
|
||||
if (*peerstate).prefer_encrypt == 1i32 {
|
||||
(*peerstate).degrade_event |= 0x1i32
|
||||
}
|
||||
(*peerstate).prefer_encrypt = 20i32;
|
||||
(*peerstate).last_seen = message_time;
|
||||
(*peerstate).to_save |= 0x2i32;
|
||||
peerstate.prefer_encrypt = 20i32;
|
||||
peerstate.last_seen = message_time;
|
||||
peerstate.to_save |= 0x2i32;
|
||||
|
||||
1
|
||||
}
|
||||
|
||||
pub unsafe fn dc_apeerstate_apply_header(
|
||||
mut peerstate: *mut dc_apeerstate_t,
|
||||
peerstate: &mut dc_apeerstate_t,
|
||||
header: &Aheader,
|
||||
message_time: time_t,
|
||||
) {
|
||||
if peerstate.is_null()
|
||||
|| (*peerstate).addr.is_null()
|
||||
|| (*header.public_key).binary.is_null()
|
||||
|| CStr::from_ptr((*peerstate).addr)
|
||||
if peerstate.addr.is_null()
|
||||
|| CStr::from_ptr(peerstate.addr)
|
||||
.to_str()
|
||||
.unwrap()
|
||||
.to_lowercase()
|
||||
@@ -209,42 +196,39 @@ pub unsafe fn dc_apeerstate_apply_header(
|
||||
{
|
||||
return;
|
||||
}
|
||||
if message_time > (*peerstate).last_seen_autocrypt {
|
||||
(*peerstate).last_seen = message_time;
|
||||
(*peerstate).last_seen_autocrypt = message_time;
|
||||
(*peerstate).to_save |= 0x1i32;
|
||||
|
||||
if message_time > peerstate.last_seen_autocrypt {
|
||||
peerstate.last_seen = message_time;
|
||||
peerstate.last_seen_autocrypt = message_time;
|
||||
peerstate.to_save |= 0x1i32;
|
||||
if (header.prefer_encrypt == EncryptPreference::Mutual
|
||||
|| header.prefer_encrypt == EncryptPreference::NoPreference)
|
||||
&& header.prefer_encrypt.to_i32().unwrap() != (*peerstate).prefer_encrypt
|
||||
&& header.prefer_encrypt.to_i32().unwrap() != peerstate.prefer_encrypt
|
||||
{
|
||||
if (*peerstate).prefer_encrypt == 1i32
|
||||
if peerstate.prefer_encrypt == 1i32
|
||||
&& header.prefer_encrypt != EncryptPreference::Mutual
|
||||
{
|
||||
(*peerstate).degrade_event |= 0x1i32
|
||||
peerstate.degrade_event |= 0x1i32
|
||||
}
|
||||
(*peerstate).prefer_encrypt = header.prefer_encrypt.to_i32().unwrap();
|
||||
(*peerstate).to_save |= 0x2i32
|
||||
peerstate.prefer_encrypt = header.prefer_encrypt.to_i32().unwrap();
|
||||
peerstate.to_save |= 0x2i32
|
||||
}
|
||||
if (*peerstate).public_key.is_null() {
|
||||
(*peerstate).public_key = dc_key_new()
|
||||
}
|
||||
if 0 == dc_key_equals((*peerstate).public_key, (*header).public_key) {
|
||||
dc_key_set_from_key((*peerstate).public_key, (*header).public_key);
|
||||
|
||||
if peerstate.public_key.as_ref() == Some(&header.public_key) {
|
||||
peerstate.public_key = Some(header.public_key.clone());
|
||||
dc_apeerstate_recalc_fingerprint(peerstate);
|
||||
(*peerstate).to_save |= 0x2i32
|
||||
peerstate.to_save |= 0x2i32;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn dc_apeerstate_apply_gossip(
|
||||
mut peerstate: *mut dc_apeerstate_t,
|
||||
peerstate: &mut dc_apeerstate_t,
|
||||
gossip_header: &Aheader,
|
||||
message_time: time_t,
|
||||
) {
|
||||
if peerstate.is_null()
|
||||
|| (*peerstate).addr.is_null()
|
||||
|| (*(*gossip_header).public_key).binary.is_null()
|
||||
|| CStr::from_ptr((*peerstate).addr)
|
||||
if peerstate.addr.is_null()
|
||||
|| CStr::from_ptr(peerstate.addr)
|
||||
.to_str()
|
||||
.unwrap()
|
||||
.to_lowercase()
|
||||
@@ -252,93 +236,89 @@ pub unsafe fn dc_apeerstate_apply_gossip(
|
||||
{
|
||||
return;
|
||||
}
|
||||
if message_time > (*peerstate).gossip_timestamp {
|
||||
(*peerstate).gossip_timestamp = message_time;
|
||||
(*peerstate).to_save |= 0x1i32;
|
||||
if (*peerstate).gossip_key.is_null() {
|
||||
(*peerstate).gossip_key = dc_key_new()
|
||||
}
|
||||
if 0 == dc_key_equals((*peerstate).gossip_key, (*gossip_header).public_key) {
|
||||
dc_key_set_from_key((*peerstate).gossip_key, (*gossip_header).public_key);
|
||||
|
||||
if message_time > peerstate.gossip_timestamp {
|
||||
peerstate.gossip_timestamp = message_time;
|
||||
peerstate.to_save |= 0x1i32;
|
||||
if peerstate.gossip_key.as_ref() == Some(&gossip_header.public_key) {
|
||||
peerstate.gossip_key = Some(gossip_header.public_key.clone());
|
||||
dc_apeerstate_recalc_fingerprint(peerstate);
|
||||
(*peerstate).to_save |= 0x2i32
|
||||
peerstate.to_save |= 0x2i32
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub unsafe fn dc_apeerstate_render_gossip_header(
|
||||
peerstate: *const dc_apeerstate_t,
|
||||
peerstate: &dc_apeerstate_t,
|
||||
min_verified: libc::c_int,
|
||||
) -> *mut libc::c_char {
|
||||
if !(peerstate.is_null() || (*peerstate).addr.is_null()) {
|
||||
let addr = CStr::from_ptr((*peerstate).addr).to_str().unwrap().into();
|
||||
let key = dc_key_ref(dc_apeerstate_peek_key(peerstate, min_verified));
|
||||
let header = Aheader::new(addr, key, EncryptPreference::NoPreference);
|
||||
if peerstate.addr.is_null() {
|
||||
return std::ptr::null_mut();
|
||||
}
|
||||
|
||||
let addr = CStr::from_ptr(peerstate.addr).to_str().unwrap().into();
|
||||
if let Some(key) = dc_apeerstate_peek_key(peerstate, min_verified) {
|
||||
// TODO: avoid cloning
|
||||
let header = Aheader::new(addr, key.clone(), EncryptPreference::NoPreference);
|
||||
let rendered = header.to_string();
|
||||
let rendered_c = CString::new(rendered).unwrap();
|
||||
|
||||
libc::strdup(rendered_c.as_ptr())
|
||||
} else {
|
||||
std::ptr::null_mut()
|
||||
return libc::strdup(rendered_c.as_ptr());
|
||||
}
|
||||
|
||||
std::ptr::null_mut()
|
||||
}
|
||||
|
||||
pub unsafe fn dc_apeerstate_peek_key(
|
||||
peerstate: *const dc_apeerstate_t,
|
||||
pub unsafe fn dc_apeerstate_peek_key<'a>(
|
||||
peerstate: &'a dc_apeerstate_t<'a>,
|
||||
min_verified: libc::c_int,
|
||||
) -> *mut dc_key_t {
|
||||
if peerstate.is_null()
|
||||
|| !(*peerstate).public_key.is_null()
|
||||
&& ((*(*peerstate).public_key).binary.is_null()
|
||||
|| (*(*peerstate).public_key).bytes <= 0i32)
|
||||
|| !(*peerstate).gossip_key.is_null()
|
||||
&& ((*(*peerstate).gossip_key).binary.is_null()
|
||||
|| (*(*peerstate).gossip_key).bytes <= 0i32)
|
||||
|| !(*peerstate).verified_key.is_null()
|
||||
&& ((*(*peerstate).verified_key).binary.is_null()
|
||||
|| (*(*peerstate).verified_key).bytes <= 0i32)
|
||||
) -> Option<&'a Key> {
|
||||
if peerstate.public_key.is_none()
|
||||
&& !peerstate.gossip_key.is_none()
|
||||
&& !peerstate.verified_key.is_none()
|
||||
{
|
||||
return 0 as *mut dc_key_t;
|
||||
return None;
|
||||
}
|
||||
|
||||
if 0 != min_verified {
|
||||
return (*peerstate).verified_key;
|
||||
return peerstate.verified_key.as_ref();
|
||||
}
|
||||
if !(*peerstate).public_key.is_null() {
|
||||
return (*peerstate).public_key;
|
||||
if !peerstate.public_key.is_none() {
|
||||
return peerstate.public_key.as_ref();
|
||||
}
|
||||
(*peerstate).gossip_key
|
||||
|
||||
peerstate.gossip_key.as_ref()
|
||||
}
|
||||
|
||||
// TODO should return bool /rtn
|
||||
pub unsafe fn dc_apeerstate_set_verified(
|
||||
mut peerstate: *mut dc_apeerstate_t,
|
||||
peerstate: &mut dc_apeerstate_t,
|
||||
which_key: libc::c_int,
|
||||
fingerprint: *const libc::c_char,
|
||||
verified: libc::c_int,
|
||||
) -> libc::c_int {
|
||||
let mut success: libc::c_int = 0i32;
|
||||
if !(peerstate.is_null() || which_key != 0i32 && which_key != 1i32 || verified != 2i32) {
|
||||
if which_key == 1i32
|
||||
&& !(*peerstate).public_key_fingerprint.is_null()
|
||||
&& *(*peerstate).public_key_fingerprint.offset(0isize) as libc::c_int != 0i32
|
||||
&& *fingerprint.offset(0isize) as libc::c_int != 0i32
|
||||
&& strcasecmp((*peerstate).public_key_fingerprint, fingerprint) == 0i32
|
||||
let mut success: libc::c_int = 0;
|
||||
if !(which_key != 0 && which_key != 1 || verified != 2) {
|
||||
if which_key == 1
|
||||
&& !peerstate.public_key_fingerprint.is_null()
|
||||
&& *peerstate.public_key_fingerprint.offset(0isize) as libc::c_int != 0
|
||||
&& *fingerprint.offset(0isize) as libc::c_int != 0
|
||||
&& strcasecmp(peerstate.public_key_fingerprint, fingerprint) == 0
|
||||
{
|
||||
(*peerstate).to_save |= 0x2i32;
|
||||
(*peerstate).verified_key = dc_key_ref((*peerstate).public_key);
|
||||
(*peerstate).verified_key_fingerprint = dc_strdup((*peerstate).public_key_fingerprint);
|
||||
success = 1i32
|
||||
peerstate.to_save |= 0x2;
|
||||
peerstate.verified_key = peerstate.public_key.clone();
|
||||
peerstate.verified_key_fingerprint = dc_strdup(peerstate.public_key_fingerprint);
|
||||
success = 1
|
||||
}
|
||||
if which_key == 0i32
|
||||
&& !(*peerstate).gossip_key_fingerprint.is_null()
|
||||
&& *(*peerstate).gossip_key_fingerprint.offset(0isize) as libc::c_int != 0i32
|
||||
&& *fingerprint.offset(0isize) as libc::c_int != 0i32
|
||||
&& strcasecmp((*peerstate).gossip_key_fingerprint, fingerprint) == 0i32
|
||||
if which_key == 0
|
||||
&& !peerstate.gossip_key_fingerprint.is_null()
|
||||
&& *peerstate.gossip_key_fingerprint.offset(0isize) as libc::c_int != 0
|
||||
&& *fingerprint.offset(0isize) as libc::c_int != 0
|
||||
&& strcasecmp(peerstate.gossip_key_fingerprint, fingerprint) == 0
|
||||
{
|
||||
(*peerstate).to_save |= 0x2i32;
|
||||
(*peerstate).verified_key = dc_key_ref((*peerstate).gossip_key);
|
||||
(*peerstate).verified_key_fingerprint = dc_strdup((*peerstate).gossip_key_fingerprint);
|
||||
success = 1i32
|
||||
peerstate.to_save |= 0x2;
|
||||
peerstate.verified_key = peerstate.gossip_key.clone();
|
||||
peerstate.verified_key_fingerprint = dc_strdup(peerstate.gossip_key_fingerprint);
|
||||
success = 1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -347,24 +327,24 @@ pub unsafe fn dc_apeerstate_set_verified(
|
||||
|
||||
// TODO should return bool /rtn
|
||||
pub unsafe fn dc_apeerstate_load_by_addr(
|
||||
peerstate: *mut dc_apeerstate_t,
|
||||
peerstate: &mut dc_apeerstate_t,
|
||||
sql: &dc_sqlite3_t,
|
||||
addr: *const libc::c_char,
|
||||
) -> libc::c_int {
|
||||
let mut success: libc::c_int = 0i32;
|
||||
let mut success: libc::c_int = 0;
|
||||
let mut stmt: *mut sqlite3_stmt = 0 as *mut sqlite3_stmt;
|
||||
if !(peerstate.is_null() || addr.is_null()) {
|
||||
if !addr.is_null() {
|
||||
dc_apeerstate_empty(peerstate);
|
||||
stmt =
|
||||
dc_sqlite3_prepare(
|
||||
(*peerstate).context,
|
||||
peerstate.context,
|
||||
sql,
|
||||
b"SELECT addr, last_seen, last_seen_autocrypt, prefer_encrypted, public_key, gossip_timestamp, gossip_key, public_key_fingerprint, gossip_key_fingerprint, verified_key, verified_key_fingerprint FROM acpeerstates WHERE addr=? COLLATE NOCASE;\x00"
|
||||
as *const u8 as *const libc::c_char);
|
||||
sqlite3_bind_text(stmt, 1i32, addr, -1i32, None);
|
||||
if !(sqlite3_step(stmt) != 100i32) {
|
||||
sqlite3_bind_text(stmt, 1, addr, -1, None);
|
||||
if !(sqlite3_step(stmt) != 100) {
|
||||
dc_apeerstate_set_from_stmt(peerstate, stmt);
|
||||
success = 1i32
|
||||
success = 1
|
||||
}
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
@@ -372,56 +352,52 @@ pub unsafe fn dc_apeerstate_load_by_addr(
|
||||
}
|
||||
|
||||
unsafe fn dc_apeerstate_set_from_stmt(
|
||||
mut peerstate: *mut dc_apeerstate_t,
|
||||
mut peerstate: &mut dc_apeerstate_t,
|
||||
stmt: *mut sqlite3_stmt,
|
||||
) {
|
||||
(*peerstate).addr = dc_strdup(sqlite3_column_text(stmt, 0i32) as *mut libc::c_char);
|
||||
(*peerstate).last_seen = sqlite3_column_int64(stmt, 1i32) as time_t;
|
||||
(*peerstate).last_seen_autocrypt = sqlite3_column_int64(stmt, 2i32) as time_t;
|
||||
(*peerstate).prefer_encrypt = sqlite3_column_int(stmt, 3i32);
|
||||
(*peerstate).gossip_timestamp = sqlite3_column_int(stmt, 5i32) as time_t;
|
||||
(*peerstate).public_key_fingerprint =
|
||||
dc_strdup(sqlite3_column_text(stmt, 7i32) as *mut libc::c_char);
|
||||
(*peerstate).gossip_key_fingerprint =
|
||||
dc_strdup(sqlite3_column_text(stmt, 8i32) as *mut libc::c_char);
|
||||
(*peerstate).verified_key_fingerprint =
|
||||
dc_strdup(sqlite3_column_text(stmt, 10i32) as *mut libc::c_char);
|
||||
if sqlite3_column_type(stmt, 4i32) != 5i32 {
|
||||
(*peerstate).public_key = dc_key_new();
|
||||
dc_key_set_from_stmt((*peerstate).public_key, stmt, 4i32, 0i32);
|
||||
peerstate.addr = dc_strdup(sqlite3_column_text(stmt, 0) as *mut libc::c_char);
|
||||
peerstate.last_seen = sqlite3_column_int64(stmt, 1) as time_t;
|
||||
peerstate.last_seen_autocrypt = sqlite3_column_int64(stmt, 2) as time_t;
|
||||
peerstate.prefer_encrypt = sqlite3_column_int(stmt, 3);
|
||||
peerstate.gossip_timestamp = sqlite3_column_int(stmt, 5) as time_t;
|
||||
peerstate.public_key_fingerprint = dc_strdup(sqlite3_column_text(stmt, 7) as *mut libc::c_char);
|
||||
peerstate.gossip_key_fingerprint = dc_strdup(sqlite3_column_text(stmt, 8) as *mut libc::c_char);
|
||||
peerstate.verified_key_fingerprint =
|
||||
dc_strdup(sqlite3_column_text(stmt, 10) as *mut libc::c_char);
|
||||
|
||||
if sqlite3_column_type(stmt, 4) != 5 {
|
||||
peerstate.public_key = Key::from_stmt(stmt, 4, KeyType::Public);
|
||||
}
|
||||
if sqlite3_column_type(stmt, 6i32) != 5i32 {
|
||||
(*peerstate).gossip_key = dc_key_new();
|
||||
dc_key_set_from_stmt((*peerstate).gossip_key, stmt, 6i32, 0i32);
|
||||
if sqlite3_column_type(stmt, 6) != 5 {
|
||||
peerstate.gossip_key = Key::from_stmt(stmt, 6, KeyType::Public);
|
||||
}
|
||||
if sqlite3_column_type(stmt, 9) != 5 {
|
||||
peerstate.verified_key = Key::from_stmt(stmt, 9, KeyType::Public);
|
||||
}
|
||||
if sqlite3_column_type(stmt, 9i32) != 5i32 {
|
||||
(*peerstate).verified_key = dc_key_new();
|
||||
dc_key_set_from_stmt((*peerstate).verified_key, stmt, 9i32, 0i32);
|
||||
};
|
||||
}
|
||||
|
||||
// TODO should return bool /rtn
|
||||
pub unsafe fn dc_apeerstate_load_by_fingerprint(
|
||||
peerstate: *mut dc_apeerstate_t,
|
||||
peerstate: &mut dc_apeerstate_t,
|
||||
sql: &dc_sqlite3_t,
|
||||
fingerprint: *const libc::c_char,
|
||||
) -> libc::c_int {
|
||||
let mut success: libc::c_int = 0i32;
|
||||
let mut success: libc::c_int = 0;
|
||||
let mut stmt: *mut sqlite3_stmt = 0 as *mut sqlite3_stmt;
|
||||
if !(peerstate.is_null() || fingerprint.is_null()) {
|
||||
if !fingerprint.is_null() {
|
||||
dc_apeerstate_empty(peerstate);
|
||||
stmt =
|
||||
dc_sqlite3_prepare(
|
||||
(*peerstate).context,
|
||||
peerstate.context,
|
||||
sql,
|
||||
b"SELECT addr, last_seen, last_seen_autocrypt, prefer_encrypted, public_key, gossip_timestamp, gossip_key, public_key_fingerprint, gossip_key_fingerprint, verified_key, verified_key_fingerprint FROM acpeerstates WHERE public_key_fingerprint=? COLLATE NOCASE OR gossip_key_fingerprint=? COLLATE NOCASE ORDER BY public_key_fingerprint=? DESC;\x00"
|
||||
as *const u8 as *const libc::c_char);
|
||||
sqlite3_bind_text(stmt, 1i32, fingerprint, -1i32, None);
|
||||
sqlite3_bind_text(stmt, 2i32, fingerprint, -1i32, None);
|
||||
sqlite3_bind_text(stmt, 3i32, fingerprint, -1i32, None);
|
||||
if !(sqlite3_step(stmt) != 100i32) {
|
||||
sqlite3_bind_text(stmt, 1, fingerprint, -1, None);
|
||||
sqlite3_bind_text(stmt, 2, fingerprint, -1, None);
|
||||
sqlite3_bind_text(stmt, 3, fingerprint, -1, None);
|
||||
if sqlite3_step(stmt) == 100 {
|
||||
dc_apeerstate_set_from_stmt(peerstate, stmt);
|
||||
success = 1i32
|
||||
success = 1
|
||||
}
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
@@ -430,118 +406,99 @@ pub unsafe fn dc_apeerstate_load_by_fingerprint(
|
||||
|
||||
// TODO should return bool /rtn
|
||||
pub unsafe fn dc_apeerstate_save_to_db(
|
||||
peerstate: *const dc_apeerstate_t,
|
||||
peerstate: &dc_apeerstate_t,
|
||||
sql: &dc_sqlite3_t,
|
||||
create: libc::c_int,
|
||||
) -> libc::c_int {
|
||||
let current_block: u64;
|
||||
let mut success: libc::c_int = 0i32;
|
||||
let mut success: libc::c_int = 0;
|
||||
let mut stmt: *mut sqlite3_stmt = 0 as *mut sqlite3_stmt;
|
||||
if peerstate.is_null() || (*peerstate).addr.is_null() {
|
||||
return 0i32;
|
||||
if peerstate.addr.is_null() {
|
||||
return 0;
|
||||
}
|
||||
if 0 != create {
|
||||
stmt = dc_sqlite3_prepare(
|
||||
(*peerstate).context,
|
||||
peerstate.context,
|
||||
sql,
|
||||
b"INSERT INTO acpeerstates (addr) VALUES(?);\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
sqlite3_bind_text(stmt, 1i32, (*peerstate).addr, -1i32, None);
|
||||
sqlite3_bind_text(stmt, 1, peerstate.addr, -1, None);
|
||||
sqlite3_step(stmt);
|
||||
sqlite3_finalize(stmt);
|
||||
stmt = 0 as *mut sqlite3_stmt
|
||||
}
|
||||
if 0 != (*peerstate).to_save & 0x2i32 || 0 != create {
|
||||
if 0 != peerstate.to_save & 0x2 || 0 != create {
|
||||
stmt =
|
||||
dc_sqlite3_prepare(
|
||||
(*peerstate).context,sql,
|
||||
peerstate.context,sql,
|
||||
b"UPDATE acpeerstates SET last_seen=?, last_seen_autocrypt=?, prefer_encrypted=?, public_key=?, gossip_timestamp=?, gossip_key=?, public_key_fingerprint=?, gossip_key_fingerprint=?, verified_key=?, verified_key_fingerprint=? WHERE addr=?;\x00"
|
||||
as *const u8 as *const libc::c_char);
|
||||
sqlite3_bind_int64(stmt, 1i32, (*peerstate).last_seen as sqlite3_int64);
|
||||
sqlite3_bind_int64(
|
||||
stmt,
|
||||
2i32,
|
||||
(*peerstate).last_seen_autocrypt as sqlite3_int64,
|
||||
);
|
||||
sqlite3_bind_int64(stmt, 3i32, (*peerstate).prefer_encrypt as sqlite3_int64);
|
||||
sqlite3_bind_blob(
|
||||
stmt,
|
||||
4i32,
|
||||
if !(*peerstate).public_key.is_null() {
|
||||
(*(*peerstate).public_key).binary
|
||||
} else {
|
||||
0 as *mut libc::c_void
|
||||
},
|
||||
if !(*peerstate).public_key.is_null() {
|
||||
(*(*peerstate).public_key).bytes
|
||||
} else {
|
||||
0i32
|
||||
},
|
||||
None,
|
||||
);
|
||||
sqlite3_bind_int64(stmt, 5i32, (*peerstate).gossip_timestamp as sqlite3_int64);
|
||||
sqlite3_bind_blob(
|
||||
stmt,
|
||||
6i32,
|
||||
if !(*peerstate).gossip_key.is_null() {
|
||||
(*(*peerstate).gossip_key).binary
|
||||
} else {
|
||||
0 as *mut libc::c_void
|
||||
},
|
||||
if !(*peerstate).gossip_key.is_null() {
|
||||
(*(*peerstate).gossip_key).bytes
|
||||
} else {
|
||||
0i32
|
||||
},
|
||||
None,
|
||||
);
|
||||
sqlite3_bind_text(stmt, 7i32, (*peerstate).public_key_fingerprint, -1i32, None);
|
||||
sqlite3_bind_text(stmt, 8i32, (*peerstate).gossip_key_fingerprint, -1i32, None);
|
||||
sqlite3_bind_blob(
|
||||
stmt,
|
||||
9i32,
|
||||
if !(*peerstate).verified_key.is_null() {
|
||||
(*(*peerstate).verified_key).binary
|
||||
} else {
|
||||
0 as *mut libc::c_void
|
||||
},
|
||||
if !(*peerstate).verified_key.is_null() {
|
||||
(*(*peerstate).verified_key).bytes
|
||||
} else {
|
||||
0i32
|
||||
},
|
||||
None,
|
||||
);
|
||||
sqlite3_bind_text(
|
||||
stmt,
|
||||
10i32,
|
||||
(*peerstate).verified_key_fingerprint,
|
||||
-1i32,
|
||||
None,
|
||||
);
|
||||
sqlite3_bind_text(stmt, 11i32, (*peerstate).addr, -1i32, None);
|
||||
if sqlite3_step(stmt) != 101i32 {
|
||||
sqlite3_bind_int64(stmt, 1, peerstate.last_seen as sqlite3_int64);
|
||||
sqlite3_bind_int64(stmt, 2, peerstate.last_seen_autocrypt as sqlite3_int64);
|
||||
sqlite3_bind_int64(stmt, 3, peerstate.prefer_encrypt as sqlite3_int64);
|
||||
|
||||
if let Some(ref key) = peerstate.public_key {
|
||||
let b = key.to_bytes();
|
||||
sqlite3_bind_blob(
|
||||
stmt,
|
||||
4,
|
||||
b.as_ptr() as *const _,
|
||||
b.len() as libc::c_int,
|
||||
None,
|
||||
);
|
||||
} else {
|
||||
sqlite3_bind_blob(stmt, 4, std::ptr::null(), 0, None);
|
||||
}
|
||||
|
||||
sqlite3_bind_int64(stmt, 5, peerstate.gossip_timestamp as sqlite3_int64);
|
||||
if let Some(ref key) = peerstate.gossip_key {
|
||||
let b = key.to_bytes();
|
||||
sqlite3_bind_blob(
|
||||
stmt,
|
||||
6,
|
||||
b.as_ptr() as *const _,
|
||||
b.len() as libc::c_int,
|
||||
None,
|
||||
);
|
||||
} else {
|
||||
sqlite3_bind_blob(stmt, 6, std::ptr::null(), 0, None);
|
||||
}
|
||||
|
||||
sqlite3_bind_text(stmt, 7, peerstate.public_key_fingerprint, -1, None);
|
||||
sqlite3_bind_text(stmt, 8, peerstate.gossip_key_fingerprint, -1, None);
|
||||
if let Some(ref key) = peerstate.verified_key {
|
||||
let b = key.to_bytes();
|
||||
sqlite3_bind_blob(
|
||||
stmt,
|
||||
9,
|
||||
b.as_ptr() as *const _,
|
||||
b.len() as libc::c_int,
|
||||
None,
|
||||
);
|
||||
} else {
|
||||
sqlite3_bind_blob(stmt, 9, std::ptr::null(), 0, None);
|
||||
}
|
||||
|
||||
sqlite3_bind_text(stmt, 10, peerstate.verified_key_fingerprint, -1, None);
|
||||
sqlite3_bind_text(stmt, 11, peerstate.addr, -1, None);
|
||||
if sqlite3_step(stmt) != 101 {
|
||||
current_block = 7258450500457619456;
|
||||
} else {
|
||||
sqlite3_finalize(stmt);
|
||||
stmt = 0 as *mut sqlite3_stmt;
|
||||
current_block = 11913429853522160501;
|
||||
}
|
||||
} else if 0 != (*peerstate).to_save & 0x1i32 {
|
||||
} else if 0 != peerstate.to_save & 0x1 {
|
||||
stmt =
|
||||
dc_sqlite3_prepare(
|
||||
(*peerstate).context,sql,
|
||||
peerstate.context,sql,
|
||||
b"UPDATE acpeerstates SET last_seen=?, last_seen_autocrypt=?, gossip_timestamp=? WHERE addr=?;\x00"
|
||||
as *const u8 as *const libc::c_char);
|
||||
sqlite3_bind_int64(stmt, 1i32, (*peerstate).last_seen as sqlite3_int64);
|
||||
sqlite3_bind_int64(
|
||||
stmt,
|
||||
2i32,
|
||||
(*peerstate).last_seen_autocrypt as sqlite3_int64,
|
||||
);
|
||||
sqlite3_bind_int64(stmt, 3i32, (*peerstate).gossip_timestamp as sqlite3_int64);
|
||||
sqlite3_bind_text(stmt, 4i32, (*peerstate).addr, -1i32, None);
|
||||
if sqlite3_step(stmt) != 101i32 {
|
||||
sqlite3_bind_int64(stmt, 1, peerstate.last_seen as sqlite3_int64);
|
||||
sqlite3_bind_int64(stmt, 2, peerstate.last_seen_autocrypt as sqlite3_int64);
|
||||
sqlite3_bind_int64(stmt, 3, peerstate.gossip_timestamp as sqlite3_int64);
|
||||
sqlite3_bind_text(stmt, 4, peerstate.addr, -1, None);
|
||||
if sqlite3_step(stmt) != 101 {
|
||||
current_block = 7258450500457619456;
|
||||
} else {
|
||||
sqlite3_finalize(stmt);
|
||||
@@ -553,10 +510,10 @@ pub unsafe fn dc_apeerstate_save_to_db(
|
||||
}
|
||||
match current_block {
|
||||
11913429853522160501 => {
|
||||
if 0 != (*peerstate).to_save & 0x2i32 || 0 != create {
|
||||
dc_reset_gossiped_timestamp((*peerstate).context, 0i32 as uint32_t);
|
||||
if 0 != peerstate.to_save & 0x2 || 0 != create {
|
||||
dc_reset_gossiped_timestamp(peerstate.context, 0 as uint32_t);
|
||||
}
|
||||
success = 1i32
|
||||
success = 1
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
@@ -567,22 +524,22 @@ pub unsafe fn dc_apeerstate_save_to_db(
|
||||
|
||||
// TODO should return bool /rtn
|
||||
pub unsafe fn dc_apeerstate_has_verified_key(
|
||||
peerstate: *const dc_apeerstate_t,
|
||||
peerstate: &dc_apeerstate_t,
|
||||
fingerprints: *const dc_hash_t,
|
||||
) -> libc::c_int {
|
||||
if peerstate.is_null() || fingerprints.is_null() {
|
||||
return 0i32;
|
||||
if fingerprints.is_null() {
|
||||
return 0;
|
||||
}
|
||||
if !(*peerstate).verified_key.is_null()
|
||||
&& !(*peerstate).verified_key_fingerprint.is_null()
|
||||
if !peerstate.verified_key.is_some()
|
||||
&& !peerstate.verified_key_fingerprint.is_null()
|
||||
&& !dc_hash_find(
|
||||
fingerprints,
|
||||
(*peerstate).verified_key_fingerprint as *const libc::c_void,
|
||||
strlen((*peerstate).verified_key_fingerprint) as libc::c_int,
|
||||
peerstate.verified_key_fingerprint as *const libc::c_void,
|
||||
strlen(peerstate.verified_key_fingerprint) as libc::c_int,
|
||||
)
|
||||
.is_null()
|
||||
{
|
||||
return 1i32;
|
||||
return 1;
|
||||
}
|
||||
|
||||
0
|
||||
|
||||
@@ -769,8 +769,8 @@ pub unsafe fn dc_get_contact_encrinfo(
|
||||
let mut ret: dc_strbuilder_t;
|
||||
let loginparam: *mut dc_loginparam_t = dc_loginparam_new();
|
||||
let contact: *mut dc_contact_t = dc_contact_new(context);
|
||||
let peerstate: *mut dc_apeerstate_t = dc_apeerstate_new(context);
|
||||
let self_key: *mut dc_key_t = dc_key_new();
|
||||
let mut peerstate = dc_apeerstate_new(context);
|
||||
|
||||
let mut fingerprint_self: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut fingerprint_other_verified: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut fingerprint_other_unverified: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
@@ -785,7 +785,7 @@ pub unsafe fn dc_get_contact_encrinfo(
|
||||
dc_strbuilder_init(&mut ret, 0i32);
|
||||
if !(!dc_contact_load_from_db(contact, &context.sql.clone().read().unwrap(), contact_id)) {
|
||||
dc_apeerstate_load_by_addr(
|
||||
peerstate,
|
||||
&mut peerstate,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
(*contact).addr,
|
||||
);
|
||||
@@ -795,16 +795,15 @@ pub unsafe fn dc_get_contact_encrinfo(
|
||||
&context.sql.clone().read().unwrap(),
|
||||
b"configured_\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
dc_key_load_self_public(
|
||||
let mut self_key = Key::from_self_public(
|
||||
context,
|
||||
self_key,
|
||||
(*loginparam).addr,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
);
|
||||
if !dc_apeerstate_peek_key(peerstate, 0i32).is_null() {
|
||||
if dc_apeerstate_peek_key(&peerstate, 0).is_some() {
|
||||
p = dc_stock_str(
|
||||
context,
|
||||
if (*peerstate).prefer_encrypt == 1i32 {
|
||||
if peerstate.prefer_encrypt == 1i32 {
|
||||
34i32
|
||||
} else {
|
||||
25i32
|
||||
@@ -812,11 +811,10 @@ pub unsafe fn dc_get_contact_encrinfo(
|
||||
);
|
||||
dc_strbuilder_cat(&mut ret, p);
|
||||
free(p as *mut libc::c_void);
|
||||
if (*self_key).binary.is_null() {
|
||||
if self_key.is_none() {
|
||||
dc_ensure_secret_key_exists(context);
|
||||
dc_key_load_self_public(
|
||||
self_key = Key::from_self_public(
|
||||
context,
|
||||
self_key,
|
||||
(*loginparam).addr,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
);
|
||||
@@ -826,12 +824,17 @@ pub unsafe fn dc_get_contact_encrinfo(
|
||||
dc_strbuilder_cat(&mut ret, p);
|
||||
free(p as *mut libc::c_void);
|
||||
dc_strbuilder_cat(&mut ret, b":\x00" as *const u8 as *const libc::c_char);
|
||||
fingerprint_self = dc_key_get_formatted_fingerprint(context, self_key);
|
||||
fingerprint_other_verified =
|
||||
dc_key_get_formatted_fingerprint(context, dc_apeerstate_peek_key(peerstate, 2i32));
|
||||
fingerprint_other_unverified =
|
||||
dc_key_get_formatted_fingerprint(context, dc_apeerstate_peek_key(peerstate, 0i32));
|
||||
if strcmp((*loginparam).addr, (*peerstate).addr) < 0i32 {
|
||||
|
||||
fingerprint_self = self_key
|
||||
.map(|k| k.formatted_fingerprint_c())
|
||||
.unwrap_or(std::ptr::null_mut());
|
||||
fingerprint_other_verified = dc_apeerstate_peek_key(&peerstate, 2)
|
||||
.map(|k| k.formatted_fingerprint_c())
|
||||
.unwrap_or(std::ptr::null_mut());
|
||||
fingerprint_other_unverified = dc_apeerstate_peek_key(&peerstate, 0)
|
||||
.map(|k| k.formatted_fingerprint_c())
|
||||
.unwrap_or(std::ptr::null_mut());
|
||||
if strcmp((*loginparam).addr, peerstate.addr) < 0i32 {
|
||||
cat_fingerprint(
|
||||
&mut ret,
|
||||
(*loginparam).addr,
|
||||
@@ -840,14 +843,14 @@ pub unsafe fn dc_get_contact_encrinfo(
|
||||
);
|
||||
cat_fingerprint(
|
||||
&mut ret,
|
||||
(*peerstate).addr,
|
||||
peerstate.addr,
|
||||
fingerprint_other_verified,
|
||||
fingerprint_other_unverified,
|
||||
);
|
||||
} else {
|
||||
cat_fingerprint(
|
||||
&mut ret,
|
||||
(*peerstate).addr,
|
||||
peerstate.addr,
|
||||
fingerprint_other_verified,
|
||||
fingerprint_other_unverified,
|
||||
);
|
||||
@@ -871,10 +874,10 @@ pub unsafe fn dc_get_contact_encrinfo(
|
||||
}
|
||||
}
|
||||
|
||||
dc_apeerstate_unref(peerstate);
|
||||
dc_apeerstate_unref(&mut peerstate);
|
||||
dc_contact_unref(contact);
|
||||
dc_loginparam_unref(loginparam);
|
||||
dc_key_unref(self_key);
|
||||
|
||||
free(fingerprint_self as *mut libc::c_void);
|
||||
free(fingerprint_other_verified as *mut libc::c_void);
|
||||
free(fingerprint_other_unverified as *mut libc::c_void);
|
||||
@@ -1074,51 +1077,60 @@ pub unsafe fn dc_contact_is_blocked(contact: *const dc_contact_t) -> libc::c_int
|
||||
(*contact).blocked
|
||||
}
|
||||
|
||||
/// Check if a contact was verified. E.g. by a secure-join QR code scan
|
||||
/// and if the key has not changed since this verification.
|
||||
///
|
||||
/// The UI may draw a checkbox or something like that beside verified contacts.
|
||||
///
|
||||
/// Returns
|
||||
/// - 0: contact is not verified.
|
||||
/// - 2: SELF and contact have verified their fingerprints in both directions; in the UI typically checkmarks are shown.
|
||||
pub unsafe fn dc_contact_is_verified(contact: *mut dc_contact_t) -> libc::c_int {
|
||||
dc_contact_is_verified_ex(contact, 0 as *mut dc_apeerstate_t)
|
||||
dc_contact_is_verified_ex(contact, None)
|
||||
}
|
||||
|
||||
/// Same as dc_contact_is_verified() but allows speeding up things
|
||||
/// by adding the peerstate belonging to the contact.
|
||||
/// If you do not have the peerstate available, it is loaded automatically.
|
||||
pub unsafe fn dc_contact_is_verified_ex<'a>(
|
||||
contact: *mut dc_contact_t<'a>,
|
||||
mut peerstate: *mut dc_apeerstate_t<'a>,
|
||||
peerstate: Option<&dc_apeerstate_t<'a>>,
|
||||
) -> libc::c_int {
|
||||
let current_block: u64;
|
||||
let mut contact_verified: libc::c_int = 0i32;
|
||||
let mut peerstate_to_delete: *mut dc_apeerstate_t = 0 as *mut dc_apeerstate_t;
|
||||
if !(contact.is_null() || (*contact).magic != 0xc047ac7i32 as libc::c_uint) {
|
||||
if (*contact).id == 1i32 as libc::c_uint {
|
||||
contact_verified = 2i32
|
||||
} else {
|
||||
// we're always sort of secured-verified as we could verify the key on this device any time with the key on this device
|
||||
if peerstate.is_null() {
|
||||
peerstate_to_delete = dc_apeerstate_new((*contact).context);
|
||||
if 0 == dc_apeerstate_load_by_addr(
|
||||
peerstate_to_delete,
|
||||
&mut (*contact).context.sql.clone().read().unwrap(),
|
||||
(*contact).addr,
|
||||
) {
|
||||
current_block = 8667923638376902112;
|
||||
} else {
|
||||
peerstate = peerstate_to_delete;
|
||||
current_block = 13109137661213826276;
|
||||
}
|
||||
} else {
|
||||
current_block = 13109137661213826276;
|
||||
}
|
||||
match current_block {
|
||||
8667923638376902112 => {}
|
||||
_ => {
|
||||
contact_verified = if !(*peerstate).verified_key.is_null() {
|
||||
2i32
|
||||
} else {
|
||||
0i32
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if contact.is_null() || (*contact).magic != 0xc047ac7i32 as libc::c_uint {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// we're always sort of secured-verified as we could verify the key on this device any time with the key
|
||||
// on this device
|
||||
if (*contact).id == 1 as libc::c_uint {
|
||||
return 2;
|
||||
}
|
||||
|
||||
if let Some(peerstate) = peerstate {
|
||||
if peerstate.verified_key.is_some() {
|
||||
2
|
||||
} else {
|
||||
0
|
||||
}
|
||||
} else {
|
||||
let mut peerstate = dc_apeerstate_new((*contact).context);
|
||||
let mut res = 0;
|
||||
|
||||
if 0 != dc_apeerstate_load_by_addr(
|
||||
&mut peerstate,
|
||||
&mut (*contact).context.sql.clone().read().unwrap(),
|
||||
(*contact).addr,
|
||||
) {
|
||||
res = if peerstate.verified_key.is_some() {
|
||||
2
|
||||
} else {
|
||||
0
|
||||
};
|
||||
}
|
||||
dc_apeerstate_unref(&mut peerstate);
|
||||
|
||||
res
|
||||
}
|
||||
dc_apeerstate_unref(peerstate_to_delete);
|
||||
contact_verified
|
||||
}
|
||||
|
||||
// Working with e-mail-addresses
|
||||
|
||||
@@ -636,7 +636,6 @@ pub unsafe fn dc_get_info(context: &dc_context_t) -> *mut libc::c_char {
|
||||
let e2ee_enabled;
|
||||
let prv_key_cnt;
|
||||
let pub_key_cnt;
|
||||
let self_public = dc_key_new();
|
||||
let rpgp_enabled = 1;
|
||||
|
||||
let mut ret = dc_strbuilder_t {
|
||||
@@ -710,16 +709,15 @@ pub unsafe fn dc_get_info(context: &dc_context_t) -> *mut libc::c_char {
|
||||
sqlite3_step(stmt);
|
||||
pub_key_cnt = sqlite3_column_int(stmt, 0);
|
||||
sqlite3_finalize(stmt);
|
||||
if 0 != dc_key_load_self_public(
|
||||
context,
|
||||
self_public,
|
||||
(*l2).addr,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
) {
|
||||
fingerprint_str = dc_key_get_fingerprint(context, self_public)
|
||||
if let Some(key) =
|
||||
Key::from_self_public(context, (*l2).addr, &context.sql.clone().read().unwrap())
|
||||
{
|
||||
fingerprint_str = key.fingerprint_c();
|
||||
} else {
|
||||
fingerprint_str = dc_strdup(b"<Not yet calculated>\x00" as *const u8 as *const libc::c_char)
|
||||
fingerprint_str =
|
||||
dc_strdup(b"<Not yet calculated>\x00" as *const u8 as *const libc::c_char);
|
||||
}
|
||||
|
||||
l_readable_str = dc_loginparam_get_readable(l);
|
||||
l2_readable_str = dc_loginparam_get_readable(l2);
|
||||
inbox_watch = dc_sqlite3_get_config_int(
|
||||
@@ -858,7 +856,6 @@ pub unsafe fn dc_get_info(context: &dc_context_t) -> *mut libc::c_char {
|
||||
free(configured_sentbox_folder as *mut libc::c_void);
|
||||
free(configured_mvbox_folder as *mut libc::c_void);
|
||||
free(fingerprint_str as *mut libc::c_void);
|
||||
dc_key_unref(self_public);
|
||||
|
||||
ret.buf
|
||||
}
|
||||
|
||||
600
src/dc_e2ee.rs
600
src/dc_e2ee.rs
@@ -16,7 +16,6 @@ use mmime::{mailmime_substitute, MAILIMF_NO_ERROR, MAIL_NO_ERROR};
|
||||
|
||||
use crate::dc_aheader::*;
|
||||
use crate::dc_apeerstate::*;
|
||||
use crate::dc_array::*;
|
||||
use crate::dc_context::dc_context_t;
|
||||
use crate::dc_hash::*;
|
||||
use crate::dc_key::*;
|
||||
@@ -56,17 +55,14 @@ pub unsafe fn dc_e2ee_encrypt(
|
||||
mut in_out_message: *mut mailmime,
|
||||
mut helper: *mut dc_e2ee_helper_t,
|
||||
) {
|
||||
let current_block: u64;
|
||||
let mut current_block: u64 = 0;
|
||||
let mut col: libc::c_int = 0i32;
|
||||
let mut do_encrypt: libc::c_int = 0i32;
|
||||
/*just a pointer into mailmime structure, must not be freed*/
|
||||
let imffields_unprotected: *mut mailimf_fields;
|
||||
let keyring: *mut dc_keyring_t = dc_keyring_new();
|
||||
let sign_key: *mut dc_key_t = dc_key_new();
|
||||
let mut keyring = Keyring::default();
|
||||
let plain: *mut MMAPString = mmap_string_new(b"\x00" as *const u8 as *const libc::c_char);
|
||||
let mut ctext: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut ctext_bytes: size_t = 0i32 as size_t;
|
||||
let peerstates = dc_array_new(10i32 as size_t);
|
||||
let mut peerstates = Vec::new();
|
||||
if !helper.is_null() {
|
||||
memset(
|
||||
helper as *mut libc::c_void,
|
||||
@@ -78,8 +74,6 @@ pub unsafe fn dc_e2ee_encrypt(
|
||||
if !(recipients_addr.is_null()
|
||||
|| in_out_message.is_null()
|
||||
|| !(*in_out_message).mm_parent.is_null()
|
||||
|| keyring.is_null()
|
||||
|| sign_key.is_null()
|
||||
|| plain.is_null()
|
||||
|| helper.is_null())
|
||||
{
|
||||
@@ -103,9 +97,10 @@ pub unsafe fn dc_e2ee_encrypt(
|
||||
0 as *const libc::c_char,
|
||||
);
|
||||
|
||||
let public_key = dc_key_new();
|
||||
if !addr.is_null() {
|
||||
if 0 != load_or_generate_self_public_key(context, public_key, addr, in_out_message) {
|
||||
if let Some(public_key) =
|
||||
load_or_generate_self_public_key(context, addr, in_out_message)
|
||||
{
|
||||
/*only for random-seed*/
|
||||
if prefer_encrypt == EncryptPreference::Mutual || 0 != e2ee_guaranteed {
|
||||
do_encrypt = 1i32;
|
||||
@@ -118,22 +113,23 @@ pub unsafe fn dc_e2ee_encrypt(
|
||||
0 as *mut libc::c_void
|
||||
})
|
||||
as *const libc::c_char;
|
||||
let peerstate: *mut dc_apeerstate_t = dc_apeerstate_new(context);
|
||||
let mut key_to_use: *mut dc_key_t = 0 as *mut dc_key_t;
|
||||
let mut peerstate = dc_apeerstate_new(context);
|
||||
if !(strcasecmp(recipient_addr, addr) == 0i32) {
|
||||
if 0 != dc_apeerstate_load_by_addr(
|
||||
peerstate,
|
||||
&mut peerstate,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
recipient_addr,
|
||||
) && {
|
||||
key_to_use = dc_apeerstate_peek_key(peerstate, min_verified);
|
||||
!key_to_use.is_null()
|
||||
} && ((*peerstate).prefer_encrypt == 1i32 || 0 != e2ee_guaranteed)
|
||||
) && (peerstate.prefer_encrypt == 1i32 || 0 != e2ee_guaranteed)
|
||||
{
|
||||
dc_keyring_add(keyring, key_to_use);
|
||||
dc_array_add_ptr(peerstates, peerstate as *mut libc::c_void);
|
||||
if let Some(key_to_use) =
|
||||
dc_apeerstate_peek_key(&peerstate, min_verified)
|
||||
{
|
||||
// TODO: avoid clone
|
||||
keyring.add(key_to_use.clone());
|
||||
peerstates.push(peerstate);
|
||||
}
|
||||
} else {
|
||||
dc_apeerstate_unref(peerstate);
|
||||
dc_apeerstate_unref(&mut peerstate);
|
||||
do_encrypt = 0i32;
|
||||
/* if we cannot encrypt to a single recipient, we cannot encrypt the message at all */
|
||||
break;
|
||||
@@ -146,17 +142,19 @@ pub unsafe fn dc_e2ee_encrypt(
|
||||
}
|
||||
}
|
||||
}
|
||||
if 0 != do_encrypt {
|
||||
dc_keyring_add(keyring, public_key);
|
||||
if 0 == dc_key_load_self_private(
|
||||
context,
|
||||
sign_key,
|
||||
addr,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
) {
|
||||
do_encrypt = 0i32
|
||||
let sign_key = if 0 != do_encrypt {
|
||||
// TODO: avoid clone
|
||||
keyring.add(public_key.clone());
|
||||
let key =
|
||||
Key::from_self_private(context, addr, &context.sql.clone().read().unwrap());
|
||||
|
||||
if key.is_none() {
|
||||
do_encrypt = 0i32;
|
||||
}
|
||||
}
|
||||
key
|
||||
} else {
|
||||
None
|
||||
};
|
||||
if 0 != force_unencrypted {
|
||||
do_encrypt = 0i32
|
||||
}
|
||||
@@ -184,13 +182,12 @@ pub unsafe fn dc_e2ee_encrypt(
|
||||
part_to_encrypt,
|
||||
);
|
||||
if 0 != do_gossip {
|
||||
let iCnt: libc::c_int = dc_array_get_cnt(peerstates) as libc::c_int;
|
||||
let iCnt: libc::c_int = peerstates.len() as libc::c_int;
|
||||
if iCnt > 1i32 {
|
||||
let mut i: libc::c_int = 0i32;
|
||||
while i < iCnt {
|
||||
let p: *mut libc::c_char = dc_apeerstate_render_gossip_header(
|
||||
dc_array_get_ptr(peerstates, i as size_t)
|
||||
as *mut dc_apeerstate_t,
|
||||
&peerstates[i as usize],
|
||||
min_verified,
|
||||
);
|
||||
if !p.is_null() {
|
||||
@@ -303,66 +300,66 @@ pub unsafe fn dc_e2ee_encrypt(
|
||||
mailmime_write_mem(plain, &mut col, message_to_encrypt);
|
||||
if (*plain).str_0.is_null() || (*plain).len <= 0 {
|
||||
current_block = 14181132614457621749;
|
||||
} else if 0
|
||||
== dc_pgp_pk_encrypt(
|
||||
context,
|
||||
} else {
|
||||
if let Some(ctext_v) = dc_pgp_pk_encrypt(
|
||||
(*plain).str_0 as *const libc::c_void,
|
||||
(*plain).len,
|
||||
keyring,
|
||||
sign_key,
|
||||
1,
|
||||
&mut ctext as *mut *mut libc::c_char as *mut *mut libc::c_void,
|
||||
&mut ctext_bytes,
|
||||
)
|
||||
{
|
||||
/*use_armor*/
|
||||
current_block = 14181132614457621749;
|
||||
} else {
|
||||
(*helper).cdata_to_free = ctext as *mut libc::c_void;
|
||||
//char* t2=dc_null_terminate(ctext,ctext_bytes);printf("ENCRYPTED:\n%s\n",t2);free(t2); // DEBUG OUTPUT
|
||||
/* create MIME-structure that will contain the encrypted text */
|
||||
let mut encrypted_part: *mut mailmime = new_data_part(
|
||||
0 as *mut libc::c_void,
|
||||
0i32 as size_t,
|
||||
b"multipart/encrypted\x00" as *const u8 as *const libc::c_char
|
||||
as *mut libc::c_char,
|
||||
-1i32,
|
||||
);
|
||||
let content: *mut mailmime_content = (*encrypted_part).mm_content_type;
|
||||
clist_insert_after(
|
||||
(*content).ct_parameters,
|
||||
(*(*content).ct_parameters).last,
|
||||
mailmime_param_new_with_data(
|
||||
b"protocol\x00" as *const u8 as *const libc::c_char
|
||||
&keyring,
|
||||
sign_key.as_ref(),
|
||||
) {
|
||||
let ctext_bytes = ctext_v.len();
|
||||
let ctext_c = CString::new(ctext_v).unwrap();
|
||||
let ctext = libc::strdup(ctext_c.as_ptr());
|
||||
|
||||
(*helper).cdata_to_free = ctext as *mut libc::c_void;
|
||||
|
||||
/* create MIME-structure that will contain the encrypted text */
|
||||
let mut encrypted_part: *mut mailmime = new_data_part(
|
||||
0 as *mut libc::c_void,
|
||||
0i32 as size_t,
|
||||
b"multipart/encrypted\x00" as *const u8 as *const libc::c_char
|
||||
as *mut libc::c_char,
|
||||
-1i32,
|
||||
);
|
||||
let content: *mut mailmime_content =
|
||||
(*encrypted_part).mm_content_type;
|
||||
clist_insert_after(
|
||||
(*content).ct_parameters,
|
||||
(*(*content).ct_parameters).last,
|
||||
mailmime_param_new_with_data(
|
||||
b"protocol\x00" as *const u8 as *const libc::c_char
|
||||
as *mut libc::c_char,
|
||||
b"application/pgp-encrypted\x00" as *const u8
|
||||
as *const libc::c_char
|
||||
as *mut libc::c_char,
|
||||
) as *mut libc::c_void,
|
||||
);
|
||||
static mut version_content: [libc::c_char; 13] =
|
||||
[86, 101, 114, 115, 105, 111, 110, 58, 32, 49, 13, 10, 0];
|
||||
let version_mime: *mut mailmime = new_data_part(
|
||||
version_content.as_mut_ptr() as *mut libc::c_void,
|
||||
strlen(version_content.as_mut_ptr()),
|
||||
b"application/pgp-encrypted\x00" as *const u8
|
||||
as *const libc::c_char
|
||||
as *mut libc::c_char,
|
||||
) as *mut libc::c_void,
|
||||
);
|
||||
static mut version_content: [libc::c_char; 13] =
|
||||
[86, 101, 114, 115, 105, 111, 110, 58, 32, 49, 13, 10, 0];
|
||||
let version_mime: *mut mailmime = new_data_part(
|
||||
version_content.as_mut_ptr() as *mut libc::c_void,
|
||||
strlen(version_content.as_mut_ptr()),
|
||||
b"application/pgp-encrypted\x00" as *const u8 as *const libc::c_char
|
||||
as *mut libc::c_char,
|
||||
MAILMIME_MECHANISM_7BIT as libc::c_int,
|
||||
);
|
||||
mailmime_smart_add_part(encrypted_part, version_mime);
|
||||
let ctext_part: *mut mailmime = new_data_part(
|
||||
ctext as *mut libc::c_void,
|
||||
ctext_bytes,
|
||||
b"application/octet-stream\x00" as *const u8 as *const libc::c_char
|
||||
as *mut libc::c_char,
|
||||
MAILMIME_MECHANISM_7BIT as libc::c_int,
|
||||
);
|
||||
mailmime_smart_add_part(encrypted_part, ctext_part);
|
||||
(*in_out_message).mm_data.mm_message.mm_msg_mime = encrypted_part;
|
||||
(*encrypted_part).mm_parent = in_out_message;
|
||||
mailmime_free(message_to_encrypt);
|
||||
(*helper).encryption_successfull = 1i32;
|
||||
current_block = 13824533195664196414;
|
||||
MAILMIME_MECHANISM_7BIT as libc::c_int,
|
||||
);
|
||||
mailmime_smart_add_part(encrypted_part, version_mime);
|
||||
let ctext_part: *mut mailmime = new_data_part(
|
||||
ctext as *mut libc::c_void,
|
||||
ctext_bytes,
|
||||
b"application/octet-stream\x00" as *const u8
|
||||
as *const libc::c_char
|
||||
as *mut libc::c_char,
|
||||
MAILMIME_MECHANISM_7BIT as libc::c_int,
|
||||
);
|
||||
mailmime_smart_add_part(encrypted_part, ctext_part);
|
||||
(*in_out_message).mm_data.mm_message.mm_msg_mime = encrypted_part;
|
||||
(*encrypted_part).mm_parent = in_out_message;
|
||||
mailmime_free(message_to_encrypt);
|
||||
(*helper).encryption_successfull = 1i32;
|
||||
current_block = 13824533195664196414;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
current_block = 13824533195664196414;
|
||||
@@ -388,17 +385,13 @@ pub unsafe fn dc_e2ee_encrypt(
|
||||
}
|
||||
}
|
||||
|
||||
dc_keyring_unref(keyring);
|
||||
dc_key_unref(sign_key);
|
||||
if !plain.is_null() {
|
||||
mmap_string_free(plain);
|
||||
}
|
||||
let mut i_0 = (dc_array_get_cnt(peerstates) as isize) - 1;
|
||||
while i_0 >= 0 {
|
||||
dc_apeerstate_unref(dc_array_get_ptr(peerstates, i_0 as size_t) as *mut dc_apeerstate_t);
|
||||
i_0 -= 1
|
||||
|
||||
for peerstate in peerstates.iter_mut() {
|
||||
dc_apeerstate_unref(peerstate);
|
||||
}
|
||||
dc_array_unref(peerstates);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
@@ -513,123 +506,73 @@ unsafe fn new_data_part(
|
||||
/*******************************************************************************
|
||||
* Generate Keypairs
|
||||
******************************************************************************/
|
||||
// TODO should return bool /rtn
|
||||
unsafe fn load_or_generate_self_public_key(
|
||||
context: &dc_context_t,
|
||||
public_key: *mut dc_key_t,
|
||||
self_addr: *const libc::c_char,
|
||||
random_data_mime: *mut mailmime,
|
||||
) -> libc::c_int {
|
||||
let mut current_block: u64;
|
||||
_random_data_mime: *mut mailmime,
|
||||
) -> Option<Key> {
|
||||
/* avoid double creation (we unlock the database during creation) */
|
||||
static mut s_in_key_creation: libc::c_int = 0i32;
|
||||
let key_created: libc::c_int;
|
||||
let mut success: libc::c_int = 0i32;
|
||||
let mut key_creation_here: libc::c_int = 0i32;
|
||||
if !public_key.is_null() {
|
||||
if 0 == dc_key_load_self_public(
|
||||
context,
|
||||
public_key,
|
||||
self_addr,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
) {
|
||||
/* create the keypair - this may take a moment, however, as this is in a thread, this is no big deal */
|
||||
if 0 != s_in_key_creation {
|
||||
current_block = 10496152961502316708;
|
||||
} else {
|
||||
key_creation_here = 1i32;
|
||||
s_in_key_creation = 1i32;
|
||||
if !random_data_mime.is_null() {
|
||||
let random_data_mmap: *mut MMAPString;
|
||||
let mut col: libc::c_int = 0i32;
|
||||
random_data_mmap = mmap_string_new(b"\x00" as *const u8 as *const libc::c_char);
|
||||
if random_data_mmap.is_null() {
|
||||
current_block = 10496152961502316708;
|
||||
} else {
|
||||
mailmime_write_mem(random_data_mmap, &mut col, random_data_mime);
|
||||
mmap_string_free(random_data_mmap);
|
||||
current_block = 26972500619410423;
|
||||
}
|
||||
} else {
|
||||
current_block = 26972500619410423;
|
||||
}
|
||||
match current_block {
|
||||
10496152961502316708 => {}
|
||||
_ => {
|
||||
let private_key: *mut dc_key_t = dc_key_new();
|
||||
let start: libc::clock_t = clock();
|
||||
dc_log_info(
|
||||
context,
|
||||
0i32,
|
||||
b"Generating keypair with %i bits, e=%i ...\x00" as *const u8
|
||||
as *const libc::c_char,
|
||||
2048i32,
|
||||
65537i32,
|
||||
);
|
||||
key_created =
|
||||
dc_pgp_create_keypair(context, self_addr, public_key, private_key);
|
||||
if 0 == key_created {
|
||||
dc_log_warning(
|
||||
context,
|
||||
0i32,
|
||||
b"Cannot create keypair.\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
current_block = 10496152961502316708;
|
||||
} else if 0 == dc_pgp_is_valid_key(context, public_key)
|
||||
|| 0 == dc_pgp_is_valid_key(context, private_key)
|
||||
{
|
||||
dc_log_warning(
|
||||
context,
|
||||
0i32,
|
||||
b"Generated keys are not valid.\x00" as *const u8
|
||||
as *const libc::c_char,
|
||||
);
|
||||
current_block = 10496152961502316708;
|
||||
} else if 0
|
||||
== dc_key_save_self_keypair(
|
||||
context,
|
||||
public_key,
|
||||
private_key,
|
||||
self_addr,
|
||||
1i32,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
)
|
||||
{
|
||||
/*set default*/
|
||||
dc_log_warning(
|
||||
context,
|
||||
0i32,
|
||||
b"Cannot save keypair.\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
current_block = 10496152961502316708;
|
||||
} else {
|
||||
dc_log_info(
|
||||
context,
|
||||
0i32,
|
||||
b"Keypair generated in %.3f s.\x00" as *const u8
|
||||
as *const libc::c_char,
|
||||
clock().wrapping_sub(start) as libc::c_double
|
||||
/ 1000000i32 as libc::c_double,
|
||||
);
|
||||
dc_key_unref(private_key);
|
||||
current_block = 1118134448028020070;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
current_block = 1118134448028020070;
|
||||
}
|
||||
match current_block {
|
||||
10496152961502316708 => {}
|
||||
_ => success = 1i32,
|
||||
}
|
||||
}
|
||||
if 0 != key_creation_here {
|
||||
s_in_key_creation = 0i32
|
||||
|
||||
let mut key = Key::from_self_public(context, self_addr, &context.sql.clone().read().unwrap());
|
||||
if key.is_some() {
|
||||
return key;
|
||||
}
|
||||
|
||||
success
|
||||
/* create the keypair - this may take a moment, however, as this is in a thread, this is no big deal */
|
||||
if 0 != s_in_key_creation {
|
||||
return None;
|
||||
}
|
||||
let key_creation_here = 1;
|
||||
s_in_key_creation = 1;
|
||||
|
||||
let start: libc::clock_t = clock();
|
||||
dc_log_info(
|
||||
context,
|
||||
0i32,
|
||||
b"Generating keypair with %i bits, e=%i ...\x00" as *const u8 as *const libc::c_char,
|
||||
2048i32,
|
||||
65537i32,
|
||||
);
|
||||
|
||||
if let Some((public_key, private_key)) = dc_pgp_create_keypair(self_addr) {
|
||||
if !dc_key_save_self_keypair(
|
||||
context,
|
||||
&public_key,
|
||||
&private_key,
|
||||
self_addr,
|
||||
1i32,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
) {
|
||||
/*set default*/
|
||||
dc_log_warning(
|
||||
context,
|
||||
0i32,
|
||||
b"Cannot save keypair.\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
} else {
|
||||
dc_log_info(
|
||||
context,
|
||||
0i32,
|
||||
b"Keypair generated in %.3f s.\x00" as *const u8 as *const libc::c_char,
|
||||
clock().wrapping_sub(start) as libc::c_double / 1000000i32 as libc::c_double,
|
||||
);
|
||||
}
|
||||
|
||||
key = Some(public_key);
|
||||
} else {
|
||||
dc_log_warning(
|
||||
context,
|
||||
0i32,
|
||||
b"Cannot create keypair.\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
}
|
||||
|
||||
if 0 != key_creation_here {
|
||||
s_in_key_creation = 0;
|
||||
}
|
||||
|
||||
key
|
||||
}
|
||||
|
||||
/* returns 1 if sth. was decrypted, 0 in other cases */
|
||||
@@ -644,11 +587,11 @@ pub unsafe fn dc_e2ee_decrypt(
|
||||
/*just a pointer into mailmime structure, must not be freed*/
|
||||
let imffields: *mut mailimf_fields = mailmime_find_mailimf_fields(in_out_message);
|
||||
let mut message_time: time_t = 0i32 as time_t;
|
||||
let peerstate: *mut dc_apeerstate_t = dc_apeerstate_new(context);
|
||||
let mut peerstate = dc_apeerstate_new(context);
|
||||
let mut from: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut self_addr: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let private_keyring: *mut dc_keyring_t = dc_keyring_new();
|
||||
let public_keyring_for_validate: *mut dc_keyring_t = dc_keyring_new();
|
||||
let mut private_keyring = Keyring::default();
|
||||
let mut public_keyring_for_validate = Keyring::default();
|
||||
let mut gossip_headers: *mut mailimf_fields = 0 as *mut mailimf_fields;
|
||||
if !helper.is_null() {
|
||||
memset(
|
||||
@@ -677,30 +620,33 @@ pub unsafe fn dc_e2ee_decrypt(
|
||||
}
|
||||
}
|
||||
}
|
||||
let mut autocryptheader = Aheader::from_imffields(from, imffields);
|
||||
if let Some(ref header) = autocryptheader {
|
||||
if 0 == dc_pgp_is_valid_key(context, header.public_key) {
|
||||
autocryptheader = None;
|
||||
}
|
||||
}
|
||||
let autocryptheader = Aheader::from_imffields(from, imffields);
|
||||
if message_time > 0i32 as libc::c_long && !from.is_null() {
|
||||
if 0 != dc_apeerstate_load_by_addr(
|
||||
peerstate,
|
||||
&mut peerstate,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
from,
|
||||
) {
|
||||
if let Some(ref header) = autocryptheader {
|
||||
dc_apeerstate_apply_header(peerstate, header, message_time);
|
||||
dc_apeerstate_save_to_db(peerstate, &context.sql.clone().read().unwrap(), 0i32);
|
||||
} else if message_time > (*peerstate).last_seen_autocrypt
|
||||
dc_apeerstate_apply_header(&mut peerstate, header, message_time);
|
||||
dc_apeerstate_save_to_db(
|
||||
&mut peerstate,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
0i32,
|
||||
);
|
||||
} else if message_time > peerstate.last_seen_autocrypt
|
||||
&& 0 == contains_report(in_out_message)
|
||||
{
|
||||
dc_apeerstate_degrade_encryption(peerstate, message_time);
|
||||
dc_apeerstate_save_to_db(peerstate, &context.sql.clone().read().unwrap(), 0i32);
|
||||
dc_apeerstate_degrade_encryption(&mut peerstate, message_time);
|
||||
dc_apeerstate_save_to_db(
|
||||
&peerstate,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
0i32,
|
||||
);
|
||||
}
|
||||
} else if let Some(ref header) = autocryptheader {
|
||||
dc_apeerstate_init_from_header(peerstate, header, message_time);
|
||||
dc_apeerstate_save_to_db(peerstate, &context.sql.clone().read().unwrap(), 1i32);
|
||||
dc_apeerstate_init_from_header(&mut peerstate, header, message_time);
|
||||
dc_apeerstate_save_to_db(&peerstate, &context.sql.clone().read().unwrap(), 1i32);
|
||||
}
|
||||
}
|
||||
/* load private key for decryption */
|
||||
@@ -711,26 +657,24 @@ pub unsafe fn dc_e2ee_decrypt(
|
||||
0 as *const libc::c_char,
|
||||
);
|
||||
if !self_addr.is_null() {
|
||||
if !(0
|
||||
== dc_keyring_load_self_private_for_decrypting(
|
||||
context,
|
||||
private_keyring,
|
||||
self_addr,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
))
|
||||
{
|
||||
if (*peerstate).last_seen == 0i32 as libc::c_long {
|
||||
if private_keyring.load_self_private_for_decrypting(
|
||||
context,
|
||||
self_addr,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
) {
|
||||
if peerstate.last_seen == 0i32 as libc::c_long {
|
||||
dc_apeerstate_load_by_addr(
|
||||
peerstate,
|
||||
&mut peerstate,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
from,
|
||||
);
|
||||
}
|
||||
if 0 != (*peerstate).degrade_event {
|
||||
dc_handle_degrade_event(context, peerstate);
|
||||
if 0 != peerstate.degrade_event {
|
||||
dc_handle_degrade_event(context, &peerstate);
|
||||
}
|
||||
dc_keyring_add(public_keyring_for_validate, (*peerstate).gossip_key);
|
||||
dc_keyring_add(public_keyring_for_validate, (*peerstate).public_key);
|
||||
// TODO: avoid clone
|
||||
public_keyring_for_validate.add(peerstate.gossip_key.clone().unwrap());
|
||||
public_keyring_for_validate.add(peerstate.public_key.clone().unwrap());
|
||||
(*helper).signatures = malloc(::std::mem::size_of::<dc_hash_t>()) as *mut dc_hash_t;
|
||||
dc_hash_init((*helper).signatures, 3i32, 1i32);
|
||||
iterations = 0i32;
|
||||
@@ -739,8 +683,8 @@ pub unsafe fn dc_e2ee_decrypt(
|
||||
if 0 == decrypt_recursive(
|
||||
context,
|
||||
in_out_message,
|
||||
private_keyring,
|
||||
public_keyring_for_validate,
|
||||
&private_keyring,
|
||||
&public_keyring_for_validate,
|
||||
(*helper).signatures,
|
||||
&mut gossip_headers,
|
||||
&mut has_unencrypted_parts,
|
||||
@@ -764,9 +708,7 @@ pub unsafe fn dc_e2ee_decrypt(
|
||||
mailimf_fields_free(gossip_headers);
|
||||
}
|
||||
|
||||
dc_apeerstate_unref(peerstate);
|
||||
dc_keyring_unref(private_keyring);
|
||||
dc_keyring_unref(public_keyring_for_validate);
|
||||
dc_apeerstate_unref(&mut peerstate);
|
||||
free(from as *mut libc::c_void);
|
||||
free(self_addr as *mut libc::c_void);
|
||||
}
|
||||
@@ -802,63 +744,60 @@ unsafe fn update_gossip_peerstates(
|
||||
.unwrap();
|
||||
let gossip_header = Aheader::from_str(value);
|
||||
if let Ok(ref header) = gossip_header {
|
||||
if 0 != dc_pgp_is_valid_key(context, header.public_key) {
|
||||
if recipients.is_null() {
|
||||
recipients = mailimf_get_recipients(imffields)
|
||||
}
|
||||
if !dc_hash_find(
|
||||
recipients,
|
||||
CString::new(header.addr.clone()).unwrap().as_ptr()
|
||||
as *const libc::c_void,
|
||||
header.addr.len() as i32,
|
||||
)
|
||||
.is_null()
|
||||
{
|
||||
let peerstate: *mut dc_apeerstate_t = dc_apeerstate_new(context);
|
||||
if 0 == dc_apeerstate_load_by_addr(
|
||||
peerstate,
|
||||
if recipients.is_null() {
|
||||
recipients = mailimf_get_recipients(imffields)
|
||||
}
|
||||
if !dc_hash_find(
|
||||
recipients,
|
||||
CString::new(header.addr.clone()).unwrap().as_ptr() as *const libc::c_void,
|
||||
header.addr.len() as i32,
|
||||
)
|
||||
.is_null()
|
||||
{
|
||||
let mut peerstate = dc_apeerstate_new(context);
|
||||
if 0 == dc_apeerstate_load_by_addr(
|
||||
&mut peerstate,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
CString::new(header.addr.clone()).unwrap().as_ptr(),
|
||||
) {
|
||||
dc_apeerstate_init_from_gossip(&mut peerstate, header, message_time);
|
||||
dc_apeerstate_save_to_db(
|
||||
&mut peerstate,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
CString::new(header.addr.clone()).unwrap().as_ptr(),
|
||||
) {
|
||||
dc_apeerstate_init_from_gossip(peerstate, header, message_time);
|
||||
dc_apeerstate_save_to_db(
|
||||
peerstate,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
1i32,
|
||||
);
|
||||
} else {
|
||||
dc_apeerstate_apply_gossip(peerstate, header, message_time);
|
||||
dc_apeerstate_save_to_db(
|
||||
peerstate,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
0i32,
|
||||
);
|
||||
}
|
||||
if 0 != (*peerstate).degrade_event {
|
||||
dc_handle_degrade_event(context, peerstate);
|
||||
}
|
||||
dc_apeerstate_unref(peerstate);
|
||||
if gossipped_addr.is_null() {
|
||||
gossipped_addr =
|
||||
malloc(::std::mem::size_of::<dc_hash_t>()) as *mut dc_hash_t;
|
||||
dc_hash_init(gossipped_addr, 3i32, 1i32);
|
||||
}
|
||||
dc_hash_insert(
|
||||
gossipped_addr,
|
||||
CString::new(header.addr.clone()).unwrap().as_ptr()
|
||||
as *const libc::c_void,
|
||||
header.addr.len() as libc::c_int,
|
||||
1i32 as *mut libc::c_void,
|
||||
1i32,
|
||||
);
|
||||
} else {
|
||||
dc_log_info(
|
||||
context,
|
||||
dc_apeerstate_apply_gossip(&mut peerstate, header, message_time);
|
||||
dc_apeerstate_save_to_db(
|
||||
&mut peerstate,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
0i32,
|
||||
b"Ignoring gossipped \"%s\" as the address is not in To/Cc list.\x00"
|
||||
as *const u8 as *const libc::c_char,
|
||||
CString::new(header.addr.clone()).unwrap().as_ptr(),
|
||||
);
|
||||
}
|
||||
if 0 != peerstate.degrade_event {
|
||||
dc_handle_degrade_event(context, &peerstate);
|
||||
}
|
||||
dc_apeerstate_unref(&mut peerstate);
|
||||
if gossipped_addr.is_null() {
|
||||
gossipped_addr =
|
||||
malloc(::std::mem::size_of::<dc_hash_t>()) as *mut dc_hash_t;
|
||||
dc_hash_init(gossipped_addr, 3i32, 1i32);
|
||||
}
|
||||
dc_hash_insert(
|
||||
gossipped_addr,
|
||||
CString::new(header.addr.clone()).unwrap().as_ptr()
|
||||
as *const libc::c_void,
|
||||
header.addr.len() as libc::c_int,
|
||||
1i32 as *mut libc::c_void,
|
||||
);
|
||||
} else {
|
||||
dc_log_info(
|
||||
context,
|
||||
0i32,
|
||||
b"Ignoring gossipped \"%s\" as the address is not in To/Cc list.\x00"
|
||||
as *const u8 as *const libc::c_char,
|
||||
CString::new(header.addr.clone()).unwrap().as_ptr(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -881,8 +820,8 @@ unsafe fn update_gossip_peerstates(
|
||||
unsafe fn decrypt_recursive(
|
||||
context: &dc_context_t,
|
||||
mime: *mut mailmime,
|
||||
private_keyring: *const dc_keyring_t,
|
||||
public_keyring_for_validate: *const dc_keyring_t,
|
||||
private_keyring: &Keyring,
|
||||
public_keyring_for_validate: &Keyring,
|
||||
ret_valid_signatures: *mut dc_hash_t,
|
||||
ret_gossip_headers: *mut *mut mailimf_fields,
|
||||
ret_has_unencrypted_parts: *mut libc::c_int,
|
||||
@@ -986,10 +925,10 @@ unsafe fn decrypt_recursive(
|
||||
}
|
||||
|
||||
unsafe fn decrypt_part(
|
||||
context: &dc_context_t,
|
||||
_context: &dc_context_t,
|
||||
mime: *mut mailmime,
|
||||
private_keyring: *const dc_keyring_t,
|
||||
public_keyring_for_validate: *const dc_keyring_t,
|
||||
private_keyring: &Keyring,
|
||||
public_keyring_for_validate: &Keyring,
|
||||
ret_valid_signatures: *mut dc_hash_t,
|
||||
ret_decrypted_mime: *mut *mut mailmime,
|
||||
) -> libc::c_int {
|
||||
@@ -1002,8 +941,6 @@ unsafe fn decrypt_part(
|
||||
/* must not be free()'d */
|
||||
let mut decoded_data: *const libc::c_char = 0 as *const libc::c_char;
|
||||
let mut decoded_data_bytes: size_t = 0i32 as size_t;
|
||||
let mut plain_buf: *mut libc::c_void = 0 as *mut libc::c_void;
|
||||
let mut plain_bytes: size_t = 0i32 as size_t;
|
||||
let mut sth_decrypted: libc::c_int = 0i32;
|
||||
*ret_decrypted_mime = 0 as *mut mailmime;
|
||||
mime_data = (*mime).mm_data.mm_single;
|
||||
@@ -1081,22 +1018,18 @@ unsafe fn decrypt_part(
|
||||
0 as *mut dc_hash_t
|
||||
};
|
||||
/*if we already have fingerprints, do not add more; this ensures, only the fingerprints from the outer-most part are collected */
|
||||
if !(0
|
||||
== dc_pgp_pk_decrypt(
|
||||
context,
|
||||
decoded_data as *const libc::c_void,
|
||||
decoded_data_bytes,
|
||||
private_keyring,
|
||||
public_keyring_for_validate,
|
||||
1i32,
|
||||
&mut plain_buf,
|
||||
&mut plain_bytes,
|
||||
add_signatures,
|
||||
)
|
||||
|| plain_buf.is_null()
|
||||
|| plain_bytes <= 0)
|
||||
{
|
||||
//{char* t1=dc_null_terminate(plain_buf,plain_bytes);printf("\n**********\n%s\n**********\n",t1);free(t1);}
|
||||
|
||||
if let Some(plain) = dc_pgp_pk_decrypt(
|
||||
decoded_data as *const libc::c_void,
|
||||
decoded_data_bytes,
|
||||
&private_keyring,
|
||||
&public_keyring_for_validate,
|
||||
add_signatures,
|
||||
) {
|
||||
let plain_bytes = plain.len();
|
||||
let plain_c = CString::new(plain).unwrap();
|
||||
let plain_buf = libc::strdup(plain_c.as_ptr());
|
||||
|
||||
let mut index: size_t = 0i32 as size_t;
|
||||
let mut decrypted_mime: *mut mailmime = 0 as *mut mailmime;
|
||||
if mailmime_parse(
|
||||
@@ -1241,30 +1174,25 @@ pub unsafe fn dc_ensure_secret_key_exists(context: &dc_context_t) -> libc::c_int
|
||||
/* normally, the key is generated as soon as the first mail is send
|
||||
(this is to gain some extra-random-seed by the message content and the timespan between program start and message sending) */
|
||||
let mut success: libc::c_int = 0i32;
|
||||
let public_key: *mut dc_key_t = dc_key_new();
|
||||
let mut self_addr: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
if !public_key.is_null() {
|
||||
self_addr = dc_sqlite3_get_config(
|
||||
|
||||
let self_addr = dc_sqlite3_get_config(
|
||||
context,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
b"configured_addr\x00" as *const u8 as *const libc::c_char,
|
||||
0 as *const libc::c_char,
|
||||
);
|
||||
if self_addr.is_null() {
|
||||
dc_log_warning(
|
||||
context,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
b"configured_addr\x00" as *const u8 as *const libc::c_char,
|
||||
0 as *const libc::c_char,
|
||||
0i32,
|
||||
b"Cannot ensure secret key if context is not configured.\x00" as *const u8
|
||||
as *const libc::c_char,
|
||||
);
|
||||
if self_addr.is_null() {
|
||||
dc_log_warning(
|
||||
context,
|
||||
0i32,
|
||||
b"Cannot ensure secret key if context is not configured.\x00" as *const u8
|
||||
as *const libc::c_char,
|
||||
);
|
||||
} else if !(0
|
||||
== load_or_generate_self_public_key(context, public_key, self_addr, 0 as *mut mailmime))
|
||||
{
|
||||
/*no random text data for seeding available*/
|
||||
success = 1i32
|
||||
}
|
||||
} else if load_or_generate_self_public_key(context, self_addr, 0 as *mut mailmime).is_some() {
|
||||
/*no random text data for seeding available*/
|
||||
success = 1i32
|
||||
}
|
||||
dc_key_unref(public_key);
|
||||
|
||||
free(self_addr as *mut libc::c_void);
|
||||
|
||||
success
|
||||
|
||||
@@ -121,28 +121,11 @@ pub unsafe fn dc_hash_insert(
|
||||
let mut new_elem: *mut dc_hashelem_t;
|
||||
/* The hash function */
|
||||
let xHash: Option<unsafe fn(_: *const libc::c_void, _: libc::c_int) -> libc::c_int>;
|
||||
if 0 != pH.is_null() as libc::c_int as libc::c_long {
|
||||
__assert_rtn(
|
||||
(*::std::mem::transmute::<&[u8; 15], &[libc::c_char; 15]>(b"dc_hash_insert\x00"))
|
||||
.as_ptr(),
|
||||
b"../src/dc_hash.c\x00" as *const u8 as *const libc::c_char,
|
||||
429i32,
|
||||
b"pH!=0\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
} else {
|
||||
};
|
||||
assert!(!pH.is_null());
|
||||
xHash = hashFunction((*pH).keyClass as libc::c_int);
|
||||
if 0 != xHash.is_none() as libc::c_int as libc::c_long {
|
||||
__assert_rtn(
|
||||
(*::std::mem::transmute::<&[u8; 15], &[libc::c_char; 15]>(b"dc_hash_insert\x00"))
|
||||
.as_ptr(),
|
||||
b"../src/dc_hash.c\x00" as *const u8 as *const libc::c_char,
|
||||
431i32,
|
||||
b"xHash!=0\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
} else {
|
||||
};
|
||||
assert!(xHash.is_some(), "missing hashing function");
|
||||
hraw = xHash.expect("non-null function pointer")(pKey, nKey);
|
||||
|
||||
if 0 != !((*pH).htsize & (*pH).htsize - 1i32 == 0i32) as libc::c_int as libc::c_long {
|
||||
__assert_rtn(
|
||||
(*::std::mem::transmute::<&[u8; 15], &[libc::c_char; 15]>(b"dc_hash_insert\x00"))
|
||||
|
||||
270
src/dc_imex.rs
270
src/dc_imex.rs
@@ -1,9 +1,11 @@
|
||||
use std::ffi::{CStr, CString};
|
||||
|
||||
use mmime::mailmime_content::*;
|
||||
use mmime::mmapstring::*;
|
||||
use mmime::other::*;
|
||||
use rand::{thread_rng, Rng};
|
||||
|
||||
use crate::constants::Event;
|
||||
use crate::constants::*;
|
||||
use crate::dc_chat::*;
|
||||
use crate::dc_configure::*;
|
||||
use crate::dc_context::dc_context_t;
|
||||
@@ -288,11 +290,10 @@ pub unsafe extern "C" fn dc_render_setup_file(
|
||||
) -> *mut libc::c_char {
|
||||
let stmt: *mut sqlite3_stmt = 0 as *mut sqlite3_stmt;
|
||||
let mut self_addr: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let curr_private_key: *mut dc_key_t = dc_key_new();
|
||||
|
||||
let mut passphrase_begin: [libc::c_char; 8] = [0; 8];
|
||||
let mut encr_string: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut ret_setupfilecontent: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
if !(passphrase.is_null() || strlen(passphrase) < 2 || curr_private_key.is_null()) {
|
||||
if !(passphrase.is_null() || strlen(passphrase) < 2) {
|
||||
strncpy(passphrase_begin.as_mut_ptr(), passphrase, 2);
|
||||
passphrase_begin[2usize] = 0i32 as libc::c_char;
|
||||
/* create the payload */
|
||||
@@ -303,36 +304,30 @@ pub unsafe extern "C" fn dc_render_setup_file(
|
||||
b"configured_addr\x00" as *const u8 as *const libc::c_char,
|
||||
0 as *const libc::c_char,
|
||||
);
|
||||
dc_key_load_self_private(
|
||||
context,
|
||||
curr_private_key,
|
||||
self_addr,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
);
|
||||
let curr_private_key =
|
||||
Key::from_self_private(context, self_addr, &context.sql.clone().read().unwrap());
|
||||
let e2ee_enabled: libc::c_int = dc_sqlite3_get_config_int(
|
||||
context,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
b"e2ee_enabled\x00" as *const u8 as *const libc::c_char,
|
||||
1i32,
|
||||
);
|
||||
let payload_key_asc: *mut libc::c_char = dc_key_render_asc(
|
||||
curr_private_key,
|
||||
if 0 != e2ee_enabled {
|
||||
Some(("Autocrypt-Prefer-Encrypt", "mutual"))
|
||||
} else {
|
||||
None
|
||||
},
|
||||
);
|
||||
if !payload_key_asc.is_null() {
|
||||
if !(0
|
||||
== dc_pgp_symm_encrypt(
|
||||
context,
|
||||
passphrase,
|
||||
payload_key_asc as *const libc::c_void,
|
||||
strlen(payload_key_asc),
|
||||
&mut encr_string,
|
||||
))
|
||||
{
|
||||
|
||||
let headers = if 0 != e2ee_enabled {
|
||||
Some(("Autocrypt-Prefer-Encrypt", "mutual"))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
if let Some(payload_key_asc) = curr_private_key.map(|k| k.to_asc_c(headers)) {
|
||||
if let Some(encr) = dc_pgp_symm_encrypt(
|
||||
passphrase,
|
||||
payload_key_asc as *const libc::c_void,
|
||||
strlen(payload_key_asc),
|
||||
) {
|
||||
let encr_string_c = CString::new(encr).unwrap();
|
||||
let mut encr_string = libc::strdup(encr_string_c.as_ptr());
|
||||
|
||||
free(payload_key_asc as *mut libc::c_void);
|
||||
let replacement: *mut libc::c_char =
|
||||
dc_mprintf(b"-----BEGIN PGP MESSAGE-----\r\nPassphrase-Format: numeric9x4\r\nPassphrase-Begin: %s\x00"
|
||||
@@ -363,13 +358,13 @@ pub unsafe extern "C" fn dc_render_setup_file(
|
||||
setup_message_body, encr_string);
|
||||
free(setup_message_title as *mut libc::c_void);
|
||||
free(setup_message_body as *mut libc::c_void);
|
||||
free(encr_string as *mut libc::c_void);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
dc_key_unref(curr_private_key);
|
||||
free(encr_string as *mut libc::c_void);
|
||||
|
||||
free(self_addr as *mut libc::c_void);
|
||||
|
||||
ret_setupfilecontent
|
||||
@@ -503,8 +498,6 @@ unsafe fn set_self_key(
|
||||
let mut buf_preferencrypt: *const libc::c_char = 0 as *const libc::c_char;
|
||||
// - " -
|
||||
let mut buf_base64: *const libc::c_char = 0 as *const libc::c_char;
|
||||
let private_key: *mut dc_key_t = dc_key_new();
|
||||
let public_key: *mut dc_key_t = dc_key_new();
|
||||
let mut stmt: *mut sqlite3_stmt = 0 as *mut sqlite3_stmt;
|
||||
let mut self_addr: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
buf = dc_strdup(armored);
|
||||
@@ -525,99 +518,111 @@ unsafe fn set_self_key(
|
||||
0i32,
|
||||
b"File does not contain a private key.\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
} else if 0 == dc_key_set_from_base64(private_key, buf_base64, 1i32)
|
||||
|| 0 == dc_pgp_is_valid_key(context, private_key)
|
||||
|| 0 == dc_pgp_split_key(context, private_key, public_key)
|
||||
{
|
||||
dc_log_error(
|
||||
context,
|
||||
0i32,
|
||||
b"File does not contain a valid private key.\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
} else {
|
||||
stmt = dc_sqlite3_prepare(
|
||||
context,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
b"DELETE FROM keypairs WHERE public_key=? OR private_key=?;\x00" as *const u8
|
||||
as *const libc::c_char,
|
||||
);
|
||||
sqlite3_bind_blob(stmt, 1i32, (*public_key).binary, (*public_key).bytes, None);
|
||||
sqlite3_bind_blob(
|
||||
stmt,
|
||||
2i32,
|
||||
(*private_key).binary,
|
||||
(*private_key).bytes,
|
||||
None,
|
||||
);
|
||||
sqlite3_step(stmt);
|
||||
sqlite3_finalize(stmt);
|
||||
stmt = 0 as *mut sqlite3_stmt;
|
||||
if 0 != set_default {
|
||||
dc_sqlite3_execute(
|
||||
if let Some((private_key, public_key)) = Key::from_base64(
|
||||
CStr::from_ptr(buf_base64).to_str().unwrap(),
|
||||
KeyType::Private,
|
||||
)
|
||||
.and_then(|k| k.split_key().map(|pub_key| (k, pub_key)))
|
||||
{
|
||||
stmt = dc_sqlite3_prepare(
|
||||
context,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
b"UPDATE keypairs SET is_default=0;\x00" as *const u8 as *const libc::c_char,
|
||||
b"DELETE FROM keypairs WHERE public_key=? OR private_key=?;\x00" as *const u8
|
||||
as *const libc::c_char,
|
||||
);
|
||||
}
|
||||
self_addr = dc_sqlite3_get_config(
|
||||
context,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
b"configured_addr\x00" as *const u8 as *const libc::c_char,
|
||||
0 as *const libc::c_char,
|
||||
);
|
||||
if 0 == dc_key_save_self_keypair(
|
||||
context,
|
||||
public_key,
|
||||
private_key,
|
||||
self_addr,
|
||||
set_default,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
) {
|
||||
let bytes = public_key.to_bytes();
|
||||
sqlite3_bind_blob(
|
||||
stmt,
|
||||
1,
|
||||
bytes.as_ptr() as *const _,
|
||||
bytes.len() as libc::c_int,
|
||||
None,
|
||||
);
|
||||
let bytes = private_key.to_bytes();
|
||||
sqlite3_bind_blob(
|
||||
stmt,
|
||||
2,
|
||||
bytes.as_ptr() as *const _,
|
||||
bytes.len() as libc::c_int,
|
||||
None,
|
||||
);
|
||||
sqlite3_step(stmt);
|
||||
sqlite3_finalize(stmt);
|
||||
stmt = 0 as *mut sqlite3_stmt;
|
||||
if 0 != set_default {
|
||||
dc_sqlite3_execute(
|
||||
context,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
b"UPDATE keypairs SET is_default=0;\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
}
|
||||
self_addr = dc_sqlite3_get_config(
|
||||
context,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
b"configured_addr\x00" as *const u8 as *const libc::c_char,
|
||||
0 as *const libc::c_char,
|
||||
);
|
||||
if !dc_key_save_self_keypair(
|
||||
context,
|
||||
&public_key,
|
||||
&private_key,
|
||||
self_addr,
|
||||
set_default,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
) {
|
||||
dc_log_error(
|
||||
context,
|
||||
0i32,
|
||||
b"Cannot save keypair.\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
} else {
|
||||
if !buf_preferencrypt.is_null() {
|
||||
if strcmp(
|
||||
buf_preferencrypt,
|
||||
b"nopreference\x00" as *const u8 as *const libc::c_char,
|
||||
) == 0i32
|
||||
{
|
||||
dc_sqlite3_set_config_int(
|
||||
context,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
b"e2ee_enabled\x00" as *const u8 as *const libc::c_char,
|
||||
0i32,
|
||||
);
|
||||
} else if strcmp(
|
||||
buf_preferencrypt,
|
||||
b"mutual\x00" as *const u8 as *const libc::c_char,
|
||||
) == 0i32
|
||||
{
|
||||
dc_sqlite3_set_config_int(
|
||||
context,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
b"e2ee_enabled\x00" as *const u8 as *const libc::c_char,
|
||||
1i32,
|
||||
);
|
||||
}
|
||||
}
|
||||
success = 1;
|
||||
}
|
||||
} else {
|
||||
dc_log_error(
|
||||
context,
|
||||
0i32,
|
||||
b"Cannot save keypair.\x00" as *const u8 as *const libc::c_char,
|
||||
b"File does not contain a valid private key.\x00" as *const u8
|
||||
as *const libc::c_char,
|
||||
);
|
||||
} else {
|
||||
if !buf_preferencrypt.is_null() {
|
||||
if strcmp(
|
||||
buf_preferencrypt,
|
||||
b"nopreference\x00" as *const u8 as *const libc::c_char,
|
||||
) == 0i32
|
||||
{
|
||||
dc_sqlite3_set_config_int(
|
||||
context,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
b"e2ee_enabled\x00" as *const u8 as *const libc::c_char,
|
||||
0i32,
|
||||
);
|
||||
} else if strcmp(
|
||||
buf_preferencrypt,
|
||||
b"mutual\x00" as *const u8 as *const libc::c_char,
|
||||
) == 0i32
|
||||
{
|
||||
dc_sqlite3_set_config_int(
|
||||
context,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
b"e2ee_enabled\x00" as *const u8 as *const libc::c_char,
|
||||
1i32,
|
||||
);
|
||||
}
|
||||
}
|
||||
success = 1i32
|
||||
}
|
||||
}
|
||||
|
||||
sqlite3_finalize(stmt);
|
||||
free(buf as *mut libc::c_void);
|
||||
free(self_addr as *mut libc::c_void);
|
||||
dc_key_unref(private_key);
|
||||
dc_key_unref(public_key);
|
||||
|
||||
success
|
||||
}
|
||||
|
||||
pub unsafe fn dc_decrypt_setup_file(
|
||||
context: &dc_context_t,
|
||||
_context: &dc_context_t,
|
||||
passphrase: *const libc::c_char,
|
||||
filecontent: *const libc::c_char,
|
||||
) -> *mut libc::c_char {
|
||||
@@ -627,8 +632,7 @@ pub unsafe fn dc_decrypt_setup_file(
|
||||
let mut binary: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut binary_bytes: size_t = 0i32 as size_t;
|
||||
let mut indx: size_t = 0i32 as size_t;
|
||||
let mut plain: *mut libc::c_void = 0 as *mut libc::c_void;
|
||||
let mut plain_bytes = 0;
|
||||
|
||||
let mut payload: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
fc_buf = dc_strdup(filecontent);
|
||||
if !(0
|
||||
@@ -659,21 +663,14 @@ pub unsafe fn dc_decrypt_setup_file(
|
||||
|| binary_bytes == 0)
|
||||
{
|
||||
/* decrypt symmetrically */
|
||||
if !(0
|
||||
== dc_pgp_symm_decrypt(
|
||||
context,
|
||||
passphrase,
|
||||
binary as *const libc::c_void,
|
||||
binary_bytes,
|
||||
&mut plain,
|
||||
&mut plain_bytes,
|
||||
))
|
||||
if let Some(plain) =
|
||||
dc_pgp_symm_decrypt(passphrase, binary as *const libc::c_void, binary_bytes)
|
||||
{
|
||||
payload = strndup(plain as *const libc::c_char, plain_bytes as libc::c_ulong)
|
||||
payload = libc::strdup(CString::new(plain).unwrap().as_ptr());
|
||||
}
|
||||
}
|
||||
}
|
||||
free(plain);
|
||||
|
||||
free(fc_buf as *mut libc::c_void);
|
||||
if !binary.is_null() {
|
||||
mmap_string_unref(binary);
|
||||
@@ -1579,8 +1576,6 @@ unsafe fn export_self_keys(context: &dc_context_t, dir: *const libc::c_char) ->
|
||||
let mut export_errors: libc::c_int = 0i32;
|
||||
let mut id: libc::c_int;
|
||||
let mut is_default: libc::c_int;
|
||||
let public_key: *mut dc_key_t = dc_key_new();
|
||||
let private_key: *mut dc_key_t = dc_key_new();
|
||||
let stmt = dc_sqlite3_prepare(
|
||||
context,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
@@ -1590,14 +1585,23 @@ unsafe fn export_self_keys(context: &dc_context_t, dir: *const libc::c_char) ->
|
||||
if !stmt.is_null() {
|
||||
while sqlite3_step(stmt) == 100i32 {
|
||||
id = sqlite3_column_int(stmt, 0i32);
|
||||
dc_key_set_from_stmt(public_key, stmt, 1i32, 0i32);
|
||||
dc_key_set_from_stmt(private_key, stmt, 2i32, 1i32);
|
||||
let public_key = Key::from_stmt(stmt, 1, KeyType::Public);
|
||||
let private_key = Key::from_stmt(stmt, 2, KeyType::Private);
|
||||
|
||||
is_default = sqlite3_column_int(stmt, 3i32);
|
||||
if 0 == export_key_to_asc_file(context, dir, id, public_key, is_default) {
|
||||
export_errors += 1
|
||||
if let Some(key) = public_key {
|
||||
if 0 == export_key_to_asc_file(context, dir, id, &key, is_default) {
|
||||
export_errors += 1
|
||||
}
|
||||
} else {
|
||||
export_errors += 1;
|
||||
}
|
||||
if 0 == export_key_to_asc_file(context, dir, id, private_key, is_default) {
|
||||
export_errors += 1
|
||||
if let Some(key) = private_key {
|
||||
if 0 == export_key_to_asc_file(context, dir, id, &key, is_default) {
|
||||
export_errors += 1
|
||||
}
|
||||
} else {
|
||||
export_errors += 1;
|
||||
}
|
||||
}
|
||||
if export_errors == 0i32 {
|
||||
@@ -1605,8 +1609,6 @@ unsafe fn export_self_keys(context: &dc_context_t, dir: *const libc::c_char) ->
|
||||
}
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
dc_key_unref(public_key);
|
||||
dc_key_unref(private_key);
|
||||
|
||||
success
|
||||
}
|
||||
@@ -1619,7 +1621,7 @@ unsafe fn export_key_to_asc_file(
|
||||
context: &dc_context_t,
|
||||
dir: *const libc::c_char,
|
||||
id: libc::c_int,
|
||||
key: *const dc_key_t,
|
||||
key: &Key,
|
||||
is_default: libc::c_int,
|
||||
) -> libc::c_int {
|
||||
let mut success: libc::c_int = 0i32;
|
||||
@@ -1628,7 +1630,7 @@ unsafe fn export_key_to_asc_file(
|
||||
file_name = dc_mprintf(
|
||||
b"%s/%s-key-default.asc\x00" as *const u8 as *const libc::c_char,
|
||||
dir,
|
||||
if (*key).type_0 == 0i32 {
|
||||
if key.is_public() {
|
||||
b"public\x00" as *const u8 as *const libc::c_char
|
||||
} else {
|
||||
b"private\x00" as *const u8 as *const libc::c_char
|
||||
@@ -1638,7 +1640,7 @@ unsafe fn export_key_to_asc_file(
|
||||
file_name = dc_mprintf(
|
||||
b"%s/%s-key-%i.asc\x00" as *const u8 as *const libc::c_char,
|
||||
dir,
|
||||
if (*key).type_0 == 0i32 {
|
||||
if key.is_public() {
|
||||
b"public\x00" as *const u8 as *const libc::c_char
|
||||
} else {
|
||||
b"private\x00" as *const u8 as *const libc::c_char
|
||||
@@ -1653,7 +1655,7 @@ unsafe fn export_key_to_asc_file(
|
||||
file_name,
|
||||
);
|
||||
dc_delete_file(context, file_name);
|
||||
if 0 == dc_key_render_asc_to_file(key, file_name, context) {
|
||||
if !key.write_asc_to_file(file_name, context) {
|
||||
dc_log_error(
|
||||
context,
|
||||
0i32,
|
||||
|
||||
848
src/dc_key.rs
848
src/dc_key.rs
@@ -1,499 +1,443 @@
|
||||
use mmime::mailmime_content::*;
|
||||
use mmime::mmapstring::*;
|
||||
use mmime::other::*;
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
use std::ffi::CString;
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::io::Cursor;
|
||||
use std::slice;
|
||||
|
||||
use libc;
|
||||
use mmime::other::*;
|
||||
use pgp::composed::{Deserializable, SignedPublicKey, SignedSecretKey};
|
||||
use pgp::ser::Serialize;
|
||||
use pgp::types::{KeyTrait, SecretKeyTrait};
|
||||
|
||||
use crate::constants::*;
|
||||
use crate::dc_context::dc_context_t;
|
||||
use crate::dc_log::*;
|
||||
use crate::dc_pgp::*;
|
||||
use crate::dc_sqlite3::*;
|
||||
use crate::dc_strbuilder::*;
|
||||
use crate::dc_tools::*;
|
||||
use crate::types::*;
|
||||
use crate::x::*;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct dc_key_t {
|
||||
pub binary: *mut libc::c_void,
|
||||
pub bytes: libc::c_int,
|
||||
pub type_0: libc::c_int,
|
||||
pub _m_heap_refcnt: libc::c_int,
|
||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||
pub enum Key {
|
||||
Public(SignedPublicKey),
|
||||
Secret(SignedSecretKey),
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn toupper(mut _c: libc::c_int) -> libc::c_int {
|
||||
return __toupper(_c);
|
||||
}
|
||||
|
||||
pub unsafe fn dc_key_new() -> *mut dc_key_t {
|
||||
let mut key: *mut dc_key_t;
|
||||
key = calloc(1, ::std::mem::size_of::<dc_key_t>()) as *mut dc_key_t;
|
||||
if key.is_null() {
|
||||
exit(44i32);
|
||||
}
|
||||
(*key)._m_heap_refcnt = 1i32;
|
||||
|
||||
key
|
||||
}
|
||||
|
||||
pub unsafe fn dc_key_ref(mut key: *mut dc_key_t) -> *mut dc_key_t {
|
||||
if key.is_null() {
|
||||
return 0 as *mut dc_key_t;
|
||||
}
|
||||
(*key)._m_heap_refcnt += 1;
|
||||
|
||||
key
|
||||
}
|
||||
|
||||
pub unsafe fn dc_key_unref(mut key: *mut dc_key_t) {
|
||||
if key.is_null() {
|
||||
return;
|
||||
}
|
||||
(*key)._m_heap_refcnt -= 1;
|
||||
if (*key)._m_heap_refcnt != 0i32 {
|
||||
return;
|
||||
}
|
||||
dc_key_empty(key);
|
||||
free(key as *mut libc::c_void);
|
||||
}
|
||||
|
||||
unsafe fn dc_key_empty(mut key: *mut dc_key_t) {
|
||||
if key.is_null() {
|
||||
return;
|
||||
}
|
||||
if (*key).type_0 == 1i32 {
|
||||
dc_wipe_secret_mem((*key).binary, (*key).bytes as size_t);
|
||||
}
|
||||
free((*key).binary);
|
||||
(*key).binary = 0 as *mut libc::c_void;
|
||||
(*key).bytes = 0i32;
|
||||
(*key).type_0 = 0i32;
|
||||
}
|
||||
|
||||
pub unsafe fn dc_wipe_secret_mem(buf: *mut libc::c_void, buf_bytes: size_t) {
|
||||
if buf.is_null() || buf_bytes <= 0 {
|
||||
return;
|
||||
}
|
||||
memset(buf, 0i32, buf_bytes);
|
||||
}
|
||||
|
||||
// TODO should return bool /rtn
|
||||
pub unsafe fn dc_key_set_from_binary(
|
||||
mut key: *mut dc_key_t,
|
||||
data: *const libc::c_void,
|
||||
bytes: libc::c_int,
|
||||
type_0: libc::c_int,
|
||||
) -> libc::c_int {
|
||||
dc_key_empty(key);
|
||||
if key.is_null() || data == 0 as *mut libc::c_void || bytes <= 0i32 {
|
||||
return 0i32;
|
||||
}
|
||||
(*key).binary = malloc(bytes as size_t);
|
||||
if (*key).binary.is_null() {
|
||||
exit(40i32);
|
||||
}
|
||||
memcpy((*key).binary, data, bytes as size_t);
|
||||
(*key).bytes = bytes;
|
||||
(*key).type_0 = type_0;
|
||||
|
||||
1
|
||||
}
|
||||
|
||||
pub unsafe fn dc_key_set_from_key(key: *mut dc_key_t, o: *const dc_key_t) -> libc::c_int {
|
||||
dc_key_empty(key);
|
||||
if key.is_null() || o.is_null() {
|
||||
return 0i32;
|
||||
}
|
||||
|
||||
dc_key_set_from_binary(key, (*o).binary, (*o).bytes, (*o).type_0)
|
||||
}
|
||||
|
||||
// TODO should return bool /rtn
|
||||
pub unsafe fn dc_key_set_from_stmt(
|
||||
key: *mut dc_key_t,
|
||||
stmt: *mut sqlite3_stmt,
|
||||
index: libc::c_int,
|
||||
type_0: libc::c_int,
|
||||
) -> libc::c_int {
|
||||
dc_key_empty(key);
|
||||
if key.is_null() || stmt.is_null() {
|
||||
return 0i32;
|
||||
}
|
||||
|
||||
dc_key_set_from_binary(
|
||||
key,
|
||||
sqlite3_column_blob(stmt, index) as *mut libc::c_uchar as *const libc::c_void,
|
||||
sqlite3_column_bytes(stmt, index),
|
||||
type_0,
|
||||
)
|
||||
}
|
||||
|
||||
// TODO should return bool /rtn
|
||||
pub unsafe fn dc_key_set_from_base64(
|
||||
key: *mut dc_key_t,
|
||||
base64: *const libc::c_char,
|
||||
type_0: libc::c_int,
|
||||
) -> libc::c_int {
|
||||
let mut indx: size_t = 0i32 as size_t;
|
||||
let mut result_len: size_t = 0i32 as size_t;
|
||||
let mut result: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
dc_key_empty(key);
|
||||
if key.is_null() || base64.is_null() {
|
||||
return 0i32;
|
||||
}
|
||||
if mailmime_base64_body_parse(
|
||||
base64,
|
||||
strlen(base64),
|
||||
&mut indx,
|
||||
&mut result,
|
||||
&mut result_len,
|
||||
) != MAILIMF_NO_ERROR as libc::c_int
|
||||
|| result.is_null()
|
||||
|| result_len == 0
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
dc_key_set_from_binary(
|
||||
key,
|
||||
result as *const libc::c_void,
|
||||
result_len as libc::c_int,
|
||||
type_0,
|
||||
);
|
||||
mmap_string_unref(result);
|
||||
|
||||
1
|
||||
}
|
||||
|
||||
// TODO should return bool /rtn
|
||||
pub unsafe fn dc_key_equals(key: *const dc_key_t, o: *const dc_key_t) -> libc::c_int {
|
||||
if key.is_null()
|
||||
|| o.is_null()
|
||||
|| (*key).binary.is_null()
|
||||
|| (*key).bytes <= 0i32
|
||||
|| (*o).binary.is_null()
|
||||
|| (*o).bytes <= 0i32
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if (*key).bytes != (*o).bytes {
|
||||
return 0;
|
||||
}
|
||||
if (*key).type_0 != (*o).type_0 {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if memcmp((*key).binary, (*o).binary, (*o).bytes as size_t) == 0 {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
impl From<SignedPublicKey> for Key {
|
||||
fn from(key: SignedPublicKey) -> Self {
|
||||
Key::Public(key)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO should return bool /rtn
|
||||
pub unsafe fn dc_key_save_self_keypair(
|
||||
context: &dc_context_t,
|
||||
public_key: *const dc_key_t,
|
||||
private_key: *const dc_key_t,
|
||||
addr: *const libc::c_char,
|
||||
is_default: libc::c_int,
|
||||
sql: &dc_sqlite3_t,
|
||||
) -> libc::c_int {
|
||||
let mut success: libc::c_int = 0i32;
|
||||
let mut stmt: *mut sqlite3_stmt = 0 as *mut sqlite3_stmt;
|
||||
if !(public_key.is_null()
|
||||
|| private_key.is_null()
|
||||
|| addr.is_null()
|
||||
|| (*public_key).binary.is_null()
|
||||
|| (*private_key).binary.is_null())
|
||||
{
|
||||
stmt =
|
||||
impl From<SignedSecretKey> for Key {
|
||||
fn from(key: SignedSecretKey) -> Self {
|
||||
Key::Secret(key)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::TryInto<SignedSecretKey> for Key {
|
||||
type Error = ();
|
||||
|
||||
fn try_into(self) -> Result<SignedSecretKey, Self::Error> {
|
||||
match self {
|
||||
Key::Public(_) => Err(()),
|
||||
Key::Secret(key) => Ok(key),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> std::convert::TryInto<&'a SignedSecretKey> for &'a Key {
|
||||
type Error = ();
|
||||
|
||||
fn try_into(self) -> Result<&'a SignedSecretKey, Self::Error> {
|
||||
match self {
|
||||
Key::Public(_) => Err(()),
|
||||
Key::Secret(key) => Ok(key),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::TryInto<SignedPublicKey> for Key {
|
||||
type Error = ();
|
||||
|
||||
fn try_into(self) -> Result<SignedPublicKey, Self::Error> {
|
||||
match self {
|
||||
Key::Public(key) => Ok(key),
|
||||
Key::Secret(_) => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> std::convert::TryInto<&'a SignedPublicKey> for &'a Key {
|
||||
type Error = ();
|
||||
|
||||
fn try_into(self) -> Result<&'a SignedPublicKey, Self::Error> {
|
||||
match self {
|
||||
Key::Public(key) => Ok(key),
|
||||
Key::Secret(_) => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Key {
|
||||
pub fn is_public(&self) -> bool {
|
||||
match self {
|
||||
Key::Public(_) => true,
|
||||
Key::Secret(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_secret(&self) -> bool {
|
||||
!self.is_public()
|
||||
}
|
||||
|
||||
pub fn from_slice(bytes: &[u8], key_type: KeyType) -> Option<Self> {
|
||||
match key_type {
|
||||
KeyType::Public => SignedPublicKey::from_bytes(Cursor::new(bytes))
|
||||
.map(Into::into)
|
||||
.ok(),
|
||||
KeyType::Private => SignedSecretKey::from_bytes(Cursor::new(bytes))
|
||||
.map(Into::into)
|
||||
.ok(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_binary(
|
||||
data: *const libc::c_void,
|
||||
len: libc::c_int,
|
||||
key_type: KeyType,
|
||||
) -> Option<Self> {
|
||||
assert!(!data.is_null(), "missing data");
|
||||
assert!(len > 0);
|
||||
|
||||
let bytes = unsafe { slice::from_raw_parts(data as *const u8, len as usize) };
|
||||
Self::from_slice(bytes, key_type)
|
||||
}
|
||||
|
||||
pub fn from_stmt(
|
||||
stmt: *mut sqlite3_stmt,
|
||||
index: libc::c_int,
|
||||
key_type: KeyType,
|
||||
) -> Option<Self> {
|
||||
assert!(!stmt.is_null(), "missing statement");
|
||||
|
||||
let data = unsafe {
|
||||
sqlite3_column_blob(stmt, index) as *mut libc::c_uchar as *const libc::c_void
|
||||
};
|
||||
let len = unsafe { sqlite3_column_bytes(stmt, index) };
|
||||
|
||||
Self::from_binary(data, len, key_type)
|
||||
}
|
||||
|
||||
pub fn from_base64(encoded_data: &str, key_type: KeyType) -> Option<Self> {
|
||||
// strip newlines and other whitespace
|
||||
let cleaned: String = encoded_data.trim().split_whitespace().collect();
|
||||
let bytes = cleaned.as_bytes();
|
||||
|
||||
base64::decode(bytes)
|
||||
.ok()
|
||||
.and_then(|decoded| Self::from_slice(&decoded, key_type))
|
||||
}
|
||||
|
||||
pub fn from_self_public(
|
||||
context: &dc_context_t,
|
||||
self_addr: *const libc::c_char,
|
||||
sql: &dc_sqlite3_t,
|
||||
) -> Option<Self> {
|
||||
if self_addr.is_null() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let stmt = unsafe {
|
||||
dc_sqlite3_prepare(
|
||||
context,
|
||||
sql,
|
||||
b"INSERT INTO keypairs (addr, is_default, public_key, private_key, created) VALUES (?,?,?,?,?);\x00"
|
||||
as *const u8 as *const libc::c_char);
|
||||
sqlite3_bind_text(stmt, 1i32, addr, -1i32, None);
|
||||
sqlite3_bind_int(stmt, 2i32, is_default);
|
||||
sqlite3_bind_blob(stmt, 3i32, (*public_key).binary, (*public_key).bytes, None);
|
||||
sqlite3_bind_blob(
|
||||
stmt,
|
||||
4i32,
|
||||
(*private_key).binary,
|
||||
(*private_key).bytes,
|
||||
None,
|
||||
);
|
||||
sqlite3_bind_int64(stmt, 5i32, time(0 as *mut time_t) as sqlite3_int64);
|
||||
if !(sqlite3_step(stmt) != 101i32) {
|
||||
success = 1i32
|
||||
b"SELECT public_key FROM keypairs WHERE addr=? AND is_default=1;\x00" as *const u8
|
||||
as *const libc::c_char,
|
||||
)
|
||||
};
|
||||
unsafe { sqlite3_bind_text(stmt, 1, self_addr, -1, None) };
|
||||
|
||||
let key = if unsafe { sqlite3_step(stmt) } == 100 {
|
||||
Self::from_stmt(stmt, 0, KeyType::Public)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
unsafe { sqlite3_finalize(stmt) };
|
||||
|
||||
key
|
||||
}
|
||||
|
||||
pub fn from_self_private(
|
||||
context: &dc_context_t,
|
||||
self_addr: *const libc::c_char,
|
||||
sql: &dc_sqlite3_t,
|
||||
) -> Option<Self> {
|
||||
if self_addr.is_null() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let stmt = unsafe {
|
||||
dc_sqlite3_prepare(
|
||||
context,
|
||||
sql,
|
||||
b"SELECT private_key FROM keypairs WHERE addr=? AND is_default=1;\x00" as *const u8
|
||||
as *const libc::c_char,
|
||||
)
|
||||
};
|
||||
unsafe { sqlite3_bind_text(stmt, 1, self_addr, -1, None) };
|
||||
|
||||
let key = if unsafe { sqlite3_step(stmt) } == 100 {
|
||||
Self::from_stmt(stmt, 0, KeyType::Private)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
unsafe { sqlite3_finalize(stmt) };
|
||||
|
||||
key
|
||||
}
|
||||
|
||||
pub fn to_bytes(&self) -> Vec<u8> {
|
||||
match self {
|
||||
Key::Public(k) => k.to_bytes().unwrap(),
|
||||
Key::Secret(k) => k.to_bytes().unwrap(),
|
||||
}
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
|
||||
success
|
||||
pub fn to_base64(&self, break_every: usize) -> String {
|
||||
let buf = self.to_bytes();
|
||||
|
||||
let encoded = base64::encode(&buf);
|
||||
encoded
|
||||
.as_bytes()
|
||||
.chunks(break_every)
|
||||
.fold(String::new(), |mut res, buf| {
|
||||
// safe because we are using a base64 encoded string
|
||||
res += unsafe { std::str::from_utf8_unchecked(buf) };
|
||||
res += " ";
|
||||
res
|
||||
})
|
||||
.trim()
|
||||
.to_string()
|
||||
}
|
||||
|
||||
/// the result must be freed
|
||||
pub fn to_base64_c(&self, break_every: usize) -> *mut libc::c_char {
|
||||
let res = self.to_base64(break_every);
|
||||
let res_c = CString::new(res.trim()).unwrap();
|
||||
|
||||
// need to use strdup to allocate the result with malloc
|
||||
// so it can be `free`d later.
|
||||
unsafe { libc::strdup(res_c.as_ptr()) }
|
||||
}
|
||||
|
||||
pub fn to_armored_string(
|
||||
&self,
|
||||
headers: Option<&BTreeMap<String, String>>,
|
||||
) -> pgp::errors::Result<String> {
|
||||
match self {
|
||||
Key::Public(k) => k.to_armored_string(headers),
|
||||
Key::Secret(k) => k.to_armored_string(headers),
|
||||
}
|
||||
}
|
||||
|
||||
/// Each header line must be terminated by `\r\n`, the result must be freed.
|
||||
pub fn to_asc_c(&self, header: Option<(&str, &str)>) -> *mut libc::c_char {
|
||||
let headers = header.map(|(key, value)| {
|
||||
let mut m = BTreeMap::new();
|
||||
m.insert(key.to_string(), value.to_string());
|
||||
m
|
||||
});
|
||||
|
||||
let buf = self
|
||||
.to_armored_string(headers.as_ref())
|
||||
.expect("failed to serialize key");
|
||||
let buf_c = CString::new(buf).unwrap();
|
||||
|
||||
// need to use strdup to allocate the result with malloc
|
||||
// so it can be `free`d later.
|
||||
unsafe { libc::strdup(buf_c.as_ptr()) }
|
||||
}
|
||||
|
||||
pub fn write_asc_to_file(&self, file: *const libc::c_char, context: &dc_context_t) -> bool {
|
||||
if file.is_null() {
|
||||
return false;
|
||||
}
|
||||
|
||||
let file_content = self.to_asc_c(None);
|
||||
|
||||
let success = if 0
|
||||
== unsafe {
|
||||
dc_write_file(
|
||||
context,
|
||||
file,
|
||||
file_content as *const libc::c_void,
|
||||
strlen(file_content),
|
||||
)
|
||||
} {
|
||||
error!(context, 0, "Cannot write key to %s", file);
|
||||
false
|
||||
} else {
|
||||
true
|
||||
};
|
||||
|
||||
unsafe { free(file_content as *mut libc::c_void) };
|
||||
|
||||
success
|
||||
}
|
||||
|
||||
pub fn fingerprint(&self) -> String {
|
||||
match self {
|
||||
Key::Public(k) => hex::encode_upper(k.fingerprint()),
|
||||
Key::Secret(k) => hex::encode_upper(k.fingerprint()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fingerprint_c(&self) -> *mut libc::c_char {
|
||||
let res = CString::new(self.fingerprint()).unwrap();
|
||||
|
||||
unsafe { libc::strdup(res.as_ptr()) }
|
||||
}
|
||||
|
||||
pub fn formatted_fingerprint(&self) -> String {
|
||||
let rawhex = self.fingerprint();
|
||||
dc_format_fingerprint(&rawhex)
|
||||
}
|
||||
|
||||
pub fn formatted_fingerprint_c(&self) -> *mut libc::c_char {
|
||||
let res = CString::new(self.formatted_fingerprint()).unwrap();
|
||||
|
||||
unsafe { libc::strdup(res.as_ptr()) }
|
||||
}
|
||||
|
||||
pub fn split_key(&self) -> Option<Key> {
|
||||
match self {
|
||||
Key::Public(_) => None,
|
||||
Key::Secret(k) => {
|
||||
let pub_key = k.public_key();
|
||||
pub_key.sign(k, || "".into()).map(|k| Key::Public(k)).ok()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO should return bool /rtn
|
||||
pub unsafe fn dc_key_load_self_public(
|
||||
pub fn dc_key_save_self_keypair(
|
||||
context: &dc_context_t,
|
||||
key: *mut dc_key_t,
|
||||
self_addr: *const libc::c_char,
|
||||
public_key: &Key,
|
||||
private_key: &Key,
|
||||
addr: *const libc::c_char,
|
||||
is_default: libc::c_int,
|
||||
sql: &dc_sqlite3_t,
|
||||
) -> libc::c_int {
|
||||
let mut success: libc::c_int = 0i32;
|
||||
let mut stmt: *mut sqlite3_stmt = 0 as *mut sqlite3_stmt;
|
||||
if !(key.is_null() || self_addr.is_null()) {
|
||||
dc_key_empty(key);
|
||||
stmt = dc_sqlite3_prepare(
|
||||
context,
|
||||
sql,
|
||||
b"SELECT public_key FROM keypairs WHERE addr=? AND is_default=1;\x00" as *const u8
|
||||
as *const libc::c_char,
|
||||
);
|
||||
sqlite3_bind_text(stmt, 1i32, self_addr, -1i32, None);
|
||||
if !(sqlite3_step(stmt) != 100i32) {
|
||||
dc_key_set_from_stmt(key, stmt, 0i32, 0i32);
|
||||
success = 1i32
|
||||
}
|
||||
) -> bool {
|
||||
if addr.is_null() {
|
||||
return false;
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
|
||||
success
|
||||
}
|
||||
|
||||
// TODO should return bool /rtn
|
||||
pub unsafe fn dc_key_load_self_private(
|
||||
context: &dc_context_t,
|
||||
key: *mut dc_key_t,
|
||||
self_addr: *const libc::c_char,
|
||||
sql: &dc_sqlite3_t,
|
||||
) -> libc::c_int {
|
||||
let mut success: libc::c_int = 0i32;
|
||||
let mut stmt: *mut sqlite3_stmt = 0 as *mut sqlite3_stmt;
|
||||
if !(key.is_null() || self_addr.is_null()) {
|
||||
dc_key_empty(key);
|
||||
stmt = dc_sqlite3_prepare(
|
||||
context,
|
||||
sql,
|
||||
b"SELECT private_key FROM keypairs WHERE addr=? AND is_default=1;\x00" as *const u8
|
||||
as *const libc::c_char,
|
||||
);
|
||||
sqlite3_bind_text(stmt, 1i32, self_addr, -1i32, None);
|
||||
if !(sqlite3_step(stmt) != 100i32) {
|
||||
dc_key_set_from_stmt(key, stmt, 0i32, 1i32);
|
||||
success = 1i32;
|
||||
}
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
|
||||
success
|
||||
}
|
||||
|
||||
pub fn dc_key_render_base64_string(key: *const dc_key_t, break_every: usize) -> String {
|
||||
assert!(!key.is_null(), "missing key");
|
||||
|
||||
let key = unsafe { *key };
|
||||
let bytes = unsafe { slice::from_raw_parts(key.binary as *const u8, key.bytes as usize) };
|
||||
assert_eq!(bytes.len(), key.bytes as usize);
|
||||
|
||||
let buf = if key.type_0 == 0 {
|
||||
// public key
|
||||
let skey = SignedPublicKey::from_bytes(Cursor::new(bytes)).expect("invalid pub key");
|
||||
skey.to_bytes().expect("failed to serialize key")
|
||||
} else {
|
||||
// secret key
|
||||
let skey = SignedSecretKey::from_bytes(Cursor::new(bytes)).expect("invalid sec key");
|
||||
skey.to_bytes().expect("failed to serialize key")
|
||||
let stmt = unsafe {
|
||||
dc_sqlite3_prepare(
|
||||
context,
|
||||
sql,
|
||||
b"INSERT INTO keypairs (addr, is_default, public_key, private_key, created) VALUES (?,?,?,?,?);\x00"
|
||||
as *const u8 as *const libc::c_char
|
||||
)
|
||||
};
|
||||
|
||||
let encoded = base64::encode(&buf);
|
||||
encoded
|
||||
.as_bytes()
|
||||
.chunks(break_every)
|
||||
.fold(String::new(), |mut res, buf| {
|
||||
// safe because we are using a base64 encoded string
|
||||
res += unsafe { std::str::from_utf8_unchecked(buf) };
|
||||
res += " ";
|
||||
res
|
||||
})
|
||||
.trim()
|
||||
.to_string()
|
||||
unsafe {
|
||||
sqlite3_bind_text(stmt, 1, addr, -1, None);
|
||||
sqlite3_bind_int(stmt, 2, is_default)
|
||||
};
|
||||
let pub_bytes = public_key.to_bytes();
|
||||
let sec_bytes = private_key.to_bytes();
|
||||
unsafe {
|
||||
sqlite3_bind_blob(
|
||||
stmt,
|
||||
3,
|
||||
pub_bytes.as_ptr() as *const _,
|
||||
pub_bytes.len() as libc::c_int,
|
||||
None,
|
||||
)
|
||||
};
|
||||
unsafe {
|
||||
sqlite3_bind_blob(
|
||||
stmt,
|
||||
4,
|
||||
sec_bytes.as_ptr() as *const _,
|
||||
sec_bytes.len() as libc::c_int,
|
||||
None,
|
||||
)
|
||||
};
|
||||
unsafe { sqlite3_bind_int64(stmt, 5, time(0 as *mut time_t) as sqlite3_int64) };
|
||||
let success = if unsafe { sqlite3_step(stmt) } == 101 {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
unsafe { sqlite3_finalize(stmt) };
|
||||
|
||||
success
|
||||
}
|
||||
|
||||
/* the result must be freed */
|
||||
pub fn dc_key_render_base64(key: *const dc_key_t, break_every: usize) -> *mut libc::c_char {
|
||||
let res = dc_key_render_base64_string(key, break_every);
|
||||
let res_c = CString::new(res.trim()).unwrap();
|
||||
/// Make a fingerprint human-readable, in hex format.
|
||||
pub fn dc_format_fingerprint(fingerprint: &str) -> String {
|
||||
// split key into chunks of 4 with space, and 20 newline
|
||||
let mut res = String::new();
|
||||
|
||||
for (i, c) in fingerprint.chars().enumerate() {
|
||||
if i > 0 && i % 20 == 0 {
|
||||
res += "\n";
|
||||
} else if i > 0 && i % 4 == 0 {
|
||||
res += " ";
|
||||
}
|
||||
|
||||
res += &c.to_string();
|
||||
}
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
pub fn dc_format_fingerprint_c(fp: *const libc::c_char) -> *mut libc::c_char {
|
||||
let input = unsafe { CStr::from_ptr(fp).to_str().unwrap() };
|
||||
let res = dc_format_fingerprint(input);
|
||||
let res_c = CString::new(res).unwrap();
|
||||
|
||||
// need to use strdup to allocate the result with malloc
|
||||
// so it can be `free`d later.
|
||||
unsafe { libc::strdup(res_c.as_ptr()) }
|
||||
}
|
||||
|
||||
/// each header line must be terminated by `\r\n`, the result must be freed.
|
||||
pub fn dc_key_render_asc(key: *const dc_key_t, header: Option<(&str, &str)>) -> *mut libc::c_char {
|
||||
if key.is_null() {
|
||||
return std::ptr::null_mut();
|
||||
}
|
||||
|
||||
let key = unsafe { *key };
|
||||
|
||||
let headers = header.map(|(key, value)| {
|
||||
let mut m = BTreeMap::new();
|
||||
m.insert(key.to_string(), value.to_string());
|
||||
m
|
||||
});
|
||||
|
||||
let bytes = unsafe { slice::from_raw_parts(key.binary as *const u8, key.bytes as usize) };
|
||||
|
||||
let buf = if key.type_0 == 0 {
|
||||
// public key
|
||||
let skey = SignedPublicKey::from_bytes(Cursor::new(bytes)).expect("invalid key");
|
||||
skey.to_armored_string(headers.as_ref())
|
||||
.expect("failed to serialize key")
|
||||
} else {
|
||||
// secret key
|
||||
let skey = SignedSecretKey::from_bytes(Cursor::new(bytes)).expect("invalid key");
|
||||
skey.to_armored_string(headers.as_ref())
|
||||
.expect("failed to serialize key")
|
||||
};
|
||||
|
||||
let buf_c = CString::new(buf).unwrap();
|
||||
|
||||
// need to use strdup to allocate the result with malloc
|
||||
// so it can be `free`d later.
|
||||
unsafe { libc::strdup(buf_c.as_ptr()) }
|
||||
/// Bring a human-readable or otherwise formatted fingerprint back to the 40-characters-uppercase-hex format.
|
||||
pub fn dc_normalize_fingerprint(fp: &str) -> String {
|
||||
fp.to_uppercase()
|
||||
.chars()
|
||||
.filter(|&c| c >= '0' && c <= '9' || c >= 'A' && c <= 'F')
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub unsafe fn dc_key_render_asc_to_file(
|
||||
key: *const dc_key_t,
|
||||
file: *const libc::c_char,
|
||||
context: &dc_context_t,
|
||||
) -> libc::c_int {
|
||||
let mut success: libc::c_int = 0i32;
|
||||
let mut file_content: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
pub fn dc_normalize_fingerprint_c(fp: *const libc::c_char) -> *mut libc::c_char {
|
||||
let input = unsafe { CStr::from_ptr(fp).to_str().unwrap() };
|
||||
let res = dc_normalize_fingerprint(input);
|
||||
let res_c = CString::new(res).unwrap();
|
||||
|
||||
if !(key.is_null() || file.is_null()) {
|
||||
file_content = dc_key_render_asc(key, None);
|
||||
|
||||
if !file_content.is_null() {
|
||||
if 0 == dc_write_file(
|
||||
context,
|
||||
file,
|
||||
file_content as *const libc::c_void,
|
||||
strlen(file_content),
|
||||
) {
|
||||
dc_log_error(
|
||||
context,
|
||||
0i32,
|
||||
b"Cannot write key to %s\x00" as *const u8 as *const libc::c_char,
|
||||
file,
|
||||
);
|
||||
} else {
|
||||
success = 1i32
|
||||
}
|
||||
}
|
||||
}
|
||||
free(file_content as *mut libc::c_void);
|
||||
|
||||
success
|
||||
unsafe { libc::strdup(res_c.as_ptr()) }
|
||||
}
|
||||
|
||||
pub unsafe fn dc_format_fingerprint(fingerprint: *const libc::c_char) -> *mut libc::c_char {
|
||||
let mut i: libc::c_int = 0i32;
|
||||
let fingerprint_len: libc::c_int = strlen(fingerprint) as libc::c_int;
|
||||
let mut ret: dc_strbuilder_t = dc_strbuilder_t {
|
||||
buf: 0 as *mut libc::c_char,
|
||||
allocated: 0,
|
||||
free: 0,
|
||||
eos: 0 as *mut libc::c_char,
|
||||
};
|
||||
dc_strbuilder_init(&mut ret, 0i32);
|
||||
while 0 != *fingerprint.offset(i as isize) {
|
||||
dc_strbuilder_catf(
|
||||
&mut ret as *mut dc_strbuilder_t,
|
||||
b"%c\x00" as *const u8 as *const libc::c_char,
|
||||
*fingerprint.offset(i as isize) as libc::c_int,
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_normalize_fingerprint() {
|
||||
let fingerprint = dc_normalize_fingerprint(" 1234 567890 \n AbcD abcdef ABCDEF ");
|
||||
|
||||
assert_eq!(fingerprint, "1234567890ABCDABCDEFABCDEF");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_format_fingerprint() {
|
||||
let fingerprint = dc_format_fingerprint("1234567890ABCDABCDEFABCDEF1234567890ABCD");
|
||||
|
||||
assert_eq!(
|
||||
fingerprint,
|
||||
"1234 5678 90AB CDAB CDEF\nABCD EF12 3456 7890 ABCD"
|
||||
);
|
||||
i += 1;
|
||||
if i != fingerprint_len {
|
||||
if i % 20i32 == 0i32 {
|
||||
dc_strbuilder_cat(&mut ret, b"\n\x00" as *const u8 as *const libc::c_char);
|
||||
} else if i % 4i32 == 0i32 {
|
||||
dc_strbuilder_cat(&mut ret, b" \x00" as *const u8 as *const libc::c_char);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret.buf
|
||||
}
|
||||
|
||||
pub unsafe fn dc_normalize_fingerprint(in_0: *const libc::c_char) -> *mut libc::c_char {
|
||||
if in_0.is_null() {
|
||||
return 0 as *mut libc::c_char;
|
||||
}
|
||||
let mut out: dc_strbuilder_t = dc_strbuilder_t {
|
||||
buf: 0 as *mut libc::c_char,
|
||||
allocated: 0,
|
||||
free: 0,
|
||||
eos: 0 as *mut libc::c_char,
|
||||
};
|
||||
dc_strbuilder_init(&mut out, 0i32);
|
||||
let mut p1: *const libc::c_char = in_0;
|
||||
while 0 != *p1 {
|
||||
if *p1 as libc::c_int >= '0' as i32 && *p1 as libc::c_int <= '9' as i32
|
||||
|| *p1 as libc::c_int >= 'A' as i32 && *p1 as libc::c_int <= 'F' as i32
|
||||
|| *p1 as libc::c_int >= 'a' as i32 && *p1 as libc::c_int <= 'f' as i32
|
||||
{
|
||||
dc_strbuilder_catf(
|
||||
&mut out as *mut dc_strbuilder_t,
|
||||
b"%c\x00" as *const u8 as *const libc::c_char,
|
||||
toupper(*p1 as libc::c_int),
|
||||
);
|
||||
}
|
||||
p1 = p1.offset(1isize)
|
||||
}
|
||||
|
||||
out.buf
|
||||
}
|
||||
|
||||
pub unsafe fn dc_key_get_fingerprint(
|
||||
context: &dc_context_t,
|
||||
key: *const dc_key_t,
|
||||
) -> *mut libc::c_char {
|
||||
let mut fingerprint_buf: *mut uint8_t = 0 as *mut uint8_t;
|
||||
let mut fingerprint_bytes: size_t = 0i32 as size_t;
|
||||
let mut fingerprint_hex: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
if !key.is_null() {
|
||||
if !(0
|
||||
== dc_pgp_calc_fingerprint(context, key, &mut fingerprint_buf, &mut fingerprint_bytes))
|
||||
{
|
||||
fingerprint_hex = dc_binary_to_uc_hex(fingerprint_buf, fingerprint_bytes)
|
||||
}
|
||||
}
|
||||
free(fingerprint_buf as *mut libc::c_void);
|
||||
return if !fingerprint_hex.is_null() {
|
||||
fingerprint_hex
|
||||
} else {
|
||||
dc_strdup(0 as *const libc::c_char)
|
||||
};
|
||||
}
|
||||
|
||||
pub unsafe fn dc_key_get_formatted_fingerprint(
|
||||
context: &dc_context_t,
|
||||
key: *const dc_key_t,
|
||||
) -> *mut libc::c_char {
|
||||
let rawhex: *mut libc::c_char = dc_key_get_fingerprint(context, key);
|
||||
let formatted: *mut libc::c_char = dc_format_fingerprint(rawhex);
|
||||
free(rawhex as *mut libc::c_void);
|
||||
|
||||
formatted
|
||||
}
|
||||
|
||||
@@ -1,87 +1,49 @@
|
||||
use crate::constants::*;
|
||||
use crate::dc_context::dc_context_t;
|
||||
use crate::dc_key::*;
|
||||
use crate::dc_sqlite3::*;
|
||||
use crate::types::*;
|
||||
use crate::x::*;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct dc_keyring_t {
|
||||
pub keys: *mut *mut dc_key_t,
|
||||
pub count: libc::c_int,
|
||||
pub allocated: libc::c_int,
|
||||
#[derive(Default, Clone, Debug)]
|
||||
pub struct Keyring {
|
||||
keys: Vec<Key>,
|
||||
}
|
||||
|
||||
pub unsafe fn dc_keyring_new() -> *mut dc_keyring_t {
|
||||
let keyring: *mut dc_keyring_t;
|
||||
keyring = calloc(1, ::std::mem::size_of::<dc_keyring_t>()) as *mut dc_keyring_t;
|
||||
if keyring.is_null() {
|
||||
exit(42i32);
|
||||
impl Keyring {
|
||||
pub fn add(&mut self, key: Key) {
|
||||
self.keys.push(key);
|
||||
}
|
||||
|
||||
keyring
|
||||
}
|
||||
pub fn keys(&self) -> &[Key] {
|
||||
&self.keys
|
||||
}
|
||||
|
||||
pub unsafe fn dc_keyring_unref(keyring: *mut dc_keyring_t) {
|
||||
if keyring.is_null() {
|
||||
return;
|
||||
}
|
||||
let mut i: libc::c_int = 0i32;
|
||||
while i < (*keyring).count {
|
||||
dc_key_unref(*(*keyring).keys.offset(i as isize));
|
||||
i += 1
|
||||
}
|
||||
free((*keyring).keys as *mut libc::c_void);
|
||||
free(keyring as *mut libc::c_void);
|
||||
}
|
||||
|
||||
/* the reference counter of the key is increased by one */
|
||||
pub unsafe fn dc_keyring_add(mut keyring: *mut dc_keyring_t, to_add: *mut dc_key_t) {
|
||||
if keyring.is_null() || to_add.is_null() {
|
||||
return;
|
||||
}
|
||||
if (*keyring).count == (*keyring).allocated {
|
||||
let newsize = (*keyring).allocated * 2 + 10;
|
||||
(*keyring).keys = realloc(
|
||||
(*keyring).keys as *mut libc::c_void,
|
||||
(newsize as size_t).wrapping_mul(::std::mem::size_of::<*mut dc_key_t>()),
|
||||
) as *mut *mut dc_key_t;
|
||||
if (*keyring).keys.is_null() {
|
||||
exit(41i32);
|
||||
pub fn load_self_private_for_decrypting(
|
||||
&mut self,
|
||||
context: &dc_context_t,
|
||||
self_addr: *const libc::c_char,
|
||||
sql: &dc_sqlite3_t,
|
||||
) -> bool {
|
||||
// Can we prevent keyring and self_addr to be null?
|
||||
if self_addr.is_null() {
|
||||
return false;
|
||||
}
|
||||
(*keyring).allocated = newsize
|
||||
}
|
||||
let ref mut fresh0 = *(*keyring).keys.offset((*keyring).count as isize);
|
||||
*fresh0 = dc_key_ref(to_add);
|
||||
(*keyring).count += 1;
|
||||
}
|
||||
|
||||
// TODO should return bool? /rtn
|
||||
pub unsafe fn dc_keyring_load_self_private_for_decrypting(
|
||||
context: &dc_context_t,
|
||||
keyring: *mut dc_keyring_t,
|
||||
self_addr: *const libc::c_char,
|
||||
sql: &dc_sqlite3_t,
|
||||
) -> libc::c_int {
|
||||
// Can we prevent keyring and self_addr to be null?
|
||||
if keyring.is_null() || self_addr.is_null() {
|
||||
return 0i32;
|
||||
}
|
||||
let stmt: *mut sqlite3_stmt = dc_sqlite3_prepare(
|
||||
context,
|
||||
sql,
|
||||
b"SELECT private_key FROM keypairs ORDER BY addr=? DESC, is_default DESC;\x00" as *const u8
|
||||
as *const libc::c_char,
|
||||
);
|
||||
sqlite3_bind_text(stmt, 1i32, self_addr, -1i32, None);
|
||||
while sqlite3_step(stmt) == 100i32 {
|
||||
let key: *mut dc_key_t = dc_key_new();
|
||||
if 0 != dc_key_set_from_stmt(key, stmt, 0i32, 1i32) {
|
||||
dc_keyring_add(keyring, key);
|
||||
let stmt = unsafe {
|
||||
dc_sqlite3_prepare(
|
||||
context,
|
||||
sql,
|
||||
b"SELECT private_key FROM keypairs ORDER BY addr=? DESC, is_default DESC;\x00"
|
||||
as *const u8 as *const libc::c_char,
|
||||
)
|
||||
};
|
||||
unsafe { sqlite3_bind_text(stmt, 1, self_addr, -1, None) };
|
||||
while unsafe { sqlite3_step(stmt) == 100 } {
|
||||
if let Some(key) = Key::from_stmt(stmt, 0, KeyType::Private) {
|
||||
self.add(key);
|
||||
}
|
||||
}
|
||||
dc_key_unref(key);
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
unsafe { sqlite3_finalize(stmt) };
|
||||
|
||||
1
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
791
src/dc_pgp.rs
791
src/dc_pgp.rs
@@ -1,15 +1,23 @@
|
||||
use crate::dc_context::dc_context_t;
|
||||
use std::convert::TryInto;
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::io::Cursor;
|
||||
|
||||
use pgp::composed::{
|
||||
Deserializable, KeyType as PgpKeyType, Message, SecretKeyParamsBuilder, SignedPublicKey,
|
||||
SignedSecretKey, SubkeyParamsBuilder,
|
||||
};
|
||||
use pgp::crypto::{HashAlgorithm, SymmetricKeyAlgorithm};
|
||||
use pgp::types::{CompressionAlgorithm, KeyTrait, SecretKeyTrait, StringToKey};
|
||||
use rand::thread_rng;
|
||||
use sha2::{Digest, Sha256};
|
||||
|
||||
use crate::dc_hash::*;
|
||||
use crate::dc_key::*;
|
||||
use crate::dc_keyring::*;
|
||||
use crate::dc_log::*;
|
||||
use crate::dc_tools::*;
|
||||
use crate::pgp as rpgp;
|
||||
use crate::types::*;
|
||||
use crate::x::*;
|
||||
|
||||
pub unsafe fn dc_pgp_exit() {}
|
||||
|
||||
// TODO should return bool /rtn
|
||||
pub unsafe fn dc_split_armored_data(
|
||||
buf: *mut libc::c_char,
|
||||
@@ -129,617 +137,212 @@ pub unsafe fn dc_split_armored_data(
|
||||
success
|
||||
}
|
||||
|
||||
/* public key encryption */
|
||||
// TODO should return bool /rtn
|
||||
pub unsafe fn dc_pgp_create_keypair(
|
||||
context: &dc_context_t,
|
||||
addr: *const libc::c_char,
|
||||
ret_public_key: *mut dc_key_t,
|
||||
ret_private_key: *mut dc_key_t,
|
||||
) -> libc::c_int {
|
||||
let mut success: libc::c_int = 0i32;
|
||||
let skey: *mut rpgp::signed_secret_key;
|
||||
let mut pkey: *mut rpgp::signed_public_key = 0 as *mut rpgp::signed_public_key;
|
||||
let mut skey_bytes: *mut rpgp::cvec = 0 as *mut rpgp::cvec;
|
||||
let mut pkey_bytes: *mut rpgp::cvec = 0 as *mut rpgp::cvec;
|
||||
let user_id: *mut libc::c_char;
|
||||
user_id = dc_mprintf(b"<%s>\x00" as *const u8 as *const libc::c_char, addr);
|
||||
skey = rpgp::rpgp_create_rsa_skey(2048i32 as uint32_t, user_id);
|
||||
if !(0 != dc_pgp_handle_rpgp_error(context)) {
|
||||
skey_bytes = rpgp::rpgp_skey_to_bytes(skey);
|
||||
if !(0 != dc_pgp_handle_rpgp_error(context)) {
|
||||
pkey = rpgp::rpgp_skey_public_key(skey);
|
||||
if !(0 != dc_pgp_handle_rpgp_error(context)) {
|
||||
pkey_bytes = rpgp::rpgp_pkey_to_bytes(pkey);
|
||||
if !(0 != dc_pgp_handle_rpgp_error(context)) {
|
||||
dc_key_set_from_binary(
|
||||
ret_private_key,
|
||||
rpgp::rpgp_cvec_data(skey_bytes) as *const libc::c_void,
|
||||
rpgp::rpgp_cvec_len(skey_bytes) as libc::c_int,
|
||||
1i32,
|
||||
);
|
||||
if !(0 != dc_pgp_handle_rpgp_error(context)) {
|
||||
dc_key_set_from_binary(
|
||||
ret_public_key,
|
||||
rpgp::rpgp_cvec_data(pkey_bytes) as *const libc::c_void,
|
||||
rpgp::rpgp_cvec_len(pkey_bytes) as libc::c_int,
|
||||
0i32,
|
||||
);
|
||||
if !(0 != dc_pgp_handle_rpgp_error(context)) {
|
||||
success = 1i32
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* cleanup */
|
||||
if !skey.is_null() {
|
||||
rpgp::rpgp_skey_drop(skey);
|
||||
}
|
||||
if !skey_bytes.is_null() {
|
||||
rpgp::rpgp_cvec_drop(skey_bytes);
|
||||
}
|
||||
if !pkey.is_null() {
|
||||
rpgp::rpgp_pkey_drop(pkey);
|
||||
}
|
||||
if !pkey_bytes.is_null() {
|
||||
rpgp::rpgp_cvec_drop(pkey_bytes);
|
||||
}
|
||||
if !user_id.is_null() {
|
||||
free(user_id as *mut libc::c_void);
|
||||
}
|
||||
/// Create a new key pair.
|
||||
pub fn dc_pgp_create_keypair(addr: *const libc::c_char) -> Option<(Key, Key)> {
|
||||
let user_id = format!("<{}>", unsafe { CStr::from_ptr(addr).to_str().unwrap() });
|
||||
|
||||
success
|
||||
let key_params = SecretKeyParamsBuilder::default()
|
||||
.key_type(PgpKeyType::Rsa(2048))
|
||||
.can_create_certificates(true)
|
||||
.can_sign(true)
|
||||
.primary_user_id(user_id.into())
|
||||
.passphrase(None)
|
||||
.preferred_symmetric_algorithms(smallvec![
|
||||
SymmetricKeyAlgorithm::AES256,
|
||||
SymmetricKeyAlgorithm::AES192,
|
||||
SymmetricKeyAlgorithm::AES128,
|
||||
])
|
||||
.preferred_hash_algorithms(smallvec![
|
||||
HashAlgorithm::SHA2_256,
|
||||
HashAlgorithm::SHA2_384,
|
||||
HashAlgorithm::SHA2_512,
|
||||
HashAlgorithm::SHA2_224,
|
||||
HashAlgorithm::SHA1,
|
||||
])
|
||||
.preferred_compression_algorithms(smallvec![
|
||||
CompressionAlgorithm::ZLIB,
|
||||
CompressionAlgorithm::ZIP,
|
||||
])
|
||||
.subkey(
|
||||
SubkeyParamsBuilder::default()
|
||||
.key_type(PgpKeyType::Rsa(2048))
|
||||
.can_encrypt(true)
|
||||
.passphrase(None)
|
||||
.build()
|
||||
.unwrap(),
|
||||
)
|
||||
.build()
|
||||
.expect("invalid key params");
|
||||
|
||||
let key = key_params.generate().expect("invalid params");
|
||||
let private_key = key.sign(|| "".into()).expect("failed to sign secret key");
|
||||
|
||||
let public_key = private_key.public_key();
|
||||
let public_key = public_key
|
||||
.sign(&private_key, || "".into())
|
||||
.expect("failed to sign public key");
|
||||
|
||||
Some((Key::Public(public_key), Key::Secret(private_key)))
|
||||
}
|
||||
|
||||
/* returns 0 if there is no error, otherwise logs the error if a context is provided and returns 1*/
|
||||
// TODO should return bool /rtn
|
||||
pub unsafe fn dc_pgp_handle_rpgp_error(context: &dc_context_t) -> libc::c_int {
|
||||
let mut success: libc::c_int = 0i32;
|
||||
let len: libc::c_int;
|
||||
let mut msg: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
len = rpgp::rpgp_last_error_length();
|
||||
if !(len == 0i32) {
|
||||
msg = rpgp::rpgp_last_error_message();
|
||||
dc_log_info(
|
||||
context,
|
||||
0i32,
|
||||
b"[rpgp][error] %s\x00" as *const u8 as *const libc::c_char,
|
||||
msg,
|
||||
);
|
||||
success = 1i32
|
||||
}
|
||||
if !msg.is_null() {
|
||||
rpgp::rpgp_string_drop(msg);
|
||||
}
|
||||
|
||||
success
|
||||
}
|
||||
|
||||
// TODO should return bool /rtn
|
||||
pub unsafe fn dc_pgp_is_valid_key(context: &dc_context_t, raw_key: *const dc_key_t) -> libc::c_int {
|
||||
let mut key_is_valid: libc::c_int = 0i32;
|
||||
let mut key: *mut rpgp::public_or_secret_key = 0 as *mut rpgp::public_or_secret_key;
|
||||
if !(raw_key.is_null() || (*raw_key).binary.is_null() || (*raw_key).bytes <= 0i32) {
|
||||
key = rpgp::rpgp_key_from_bytes(
|
||||
(*raw_key).binary as *const uint8_t,
|
||||
(*raw_key).bytes as usize,
|
||||
);
|
||||
if !(0 != dc_pgp_handle_rpgp_error(context)) {
|
||||
if (*raw_key).type_0 == 0i32 && 0 != rpgp::rpgp_key_is_public(key) as libc::c_int {
|
||||
key_is_valid = 1i32
|
||||
} else if (*raw_key).type_0 == 1i32 && 0 != rpgp::rpgp_key_is_secret(key) as libc::c_int
|
||||
{
|
||||
key_is_valid = 1i32
|
||||
}
|
||||
}
|
||||
}
|
||||
if !key.is_null() {
|
||||
rpgp::rpgp_key_drop(key);
|
||||
}
|
||||
|
||||
key_is_valid
|
||||
}
|
||||
|
||||
// TODO should return bool /rtn
|
||||
pub unsafe fn dc_pgp_calc_fingerprint(
|
||||
context: &dc_context_t,
|
||||
raw_key: *const dc_key_t,
|
||||
ret_fingerprint: *mut *mut uint8_t,
|
||||
ret_fingerprint_bytes: *mut size_t,
|
||||
) -> libc::c_int {
|
||||
let mut success: libc::c_int = 0i32;
|
||||
let mut key: *mut rpgp::public_or_secret_key = 0 as *mut rpgp::public_or_secret_key;
|
||||
let mut fingerprint: *mut rpgp::cvec = 0 as *mut rpgp::cvec;
|
||||
if !(raw_key.is_null()
|
||||
|| ret_fingerprint.is_null()
|
||||
|| !(*ret_fingerprint).is_null()
|
||||
|| ret_fingerprint_bytes.is_null()
|
||||
|| *ret_fingerprint_bytes != 0
|
||||
|| (*raw_key).binary.is_null()
|
||||
|| (*raw_key).bytes <= 0i32)
|
||||
{
|
||||
key = rpgp::rpgp_key_from_bytes(
|
||||
(*raw_key).binary as *const uint8_t,
|
||||
(*raw_key).bytes as usize,
|
||||
);
|
||||
if !(0 != dc_pgp_handle_rpgp_error(context)) {
|
||||
fingerprint = rpgp::rpgp_key_fingerprint(key);
|
||||
if !(0 != dc_pgp_handle_rpgp_error(context)) {
|
||||
*ret_fingerprint_bytes = rpgp::rpgp_cvec_len(fingerprint) as size_t;
|
||||
*ret_fingerprint = malloc(*ret_fingerprint_bytes) as *mut uint8_t;
|
||||
memcpy(
|
||||
*ret_fingerprint as *mut libc::c_void,
|
||||
rpgp::rpgp_cvec_data(fingerprint) as *const libc::c_void,
|
||||
*ret_fingerprint_bytes,
|
||||
);
|
||||
success = 1i32
|
||||
}
|
||||
}
|
||||
}
|
||||
if !key.is_null() {
|
||||
rpgp::rpgp_key_drop(key);
|
||||
}
|
||||
if !fingerprint.is_null() {
|
||||
rpgp::rpgp_cvec_drop(fingerprint);
|
||||
}
|
||||
|
||||
success
|
||||
}
|
||||
|
||||
// TODO should return bool /rtn
|
||||
pub unsafe fn dc_pgp_split_key(
|
||||
context: &dc_context_t,
|
||||
private_in: *const dc_key_t,
|
||||
ret_public_key: *mut dc_key_t,
|
||||
) -> libc::c_int {
|
||||
let mut success: libc::c_int = 0i32;
|
||||
let mut key: *mut rpgp::signed_secret_key = 0 as *mut rpgp::signed_secret_key;
|
||||
let mut pub_key: *mut rpgp::signed_public_key = 0 as *mut rpgp::signed_public_key;
|
||||
let mut buf: *mut rpgp::cvec = 0 as *mut rpgp::cvec;
|
||||
if !(private_in.is_null() || ret_public_key.is_null()) {
|
||||
if (*private_in).type_0 != 1i32 {
|
||||
dc_log_warning(
|
||||
context,
|
||||
0i32,
|
||||
b"Split key: Given key is no private key.\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
} else {
|
||||
key = rpgp::rpgp_skey_from_bytes(
|
||||
(*private_in).binary as *const uint8_t,
|
||||
(*private_in).bytes as usize,
|
||||
);
|
||||
if !(0 != dc_pgp_handle_rpgp_error(context)) {
|
||||
pub_key = rpgp::rpgp_skey_public_key(key);
|
||||
if !(0 != dc_pgp_handle_rpgp_error(context)) {
|
||||
buf = rpgp::rpgp_pkey_to_bytes(pub_key);
|
||||
if !(0 != dc_pgp_handle_rpgp_error(context)) {
|
||||
dc_key_set_from_binary(
|
||||
ret_public_key,
|
||||
rpgp::rpgp_cvec_data(buf) as *const libc::c_void,
|
||||
rpgp::rpgp_cvec_len(buf) as libc::c_int,
|
||||
0i32,
|
||||
);
|
||||
success = 1i32
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if !key.is_null() {
|
||||
rpgp::rpgp_skey_drop(key);
|
||||
}
|
||||
if !pub_key.is_null() {
|
||||
rpgp::rpgp_pkey_drop(pub_key);
|
||||
}
|
||||
if !buf.is_null() {
|
||||
rpgp::rpgp_cvec_drop(buf);
|
||||
}
|
||||
|
||||
success
|
||||
}
|
||||
|
||||
// TODO should return bool /rtn
|
||||
pub unsafe fn dc_pgp_pk_encrypt(
|
||||
context: &dc_context_t,
|
||||
pub fn dc_pgp_pk_encrypt(
|
||||
plain_text: *const libc::c_void,
|
||||
plain_bytes: size_t,
|
||||
raw_public_keys_for_encryption: *const dc_keyring_t,
|
||||
raw_private_key_for_signing: *const dc_key_t,
|
||||
use_armor: libc::c_int,
|
||||
ret_ctext: *mut *mut libc::c_void,
|
||||
ret_ctext_bytes: *mut size_t,
|
||||
) -> libc::c_int {
|
||||
let mut current_block: u64;
|
||||
let mut i: libc::c_int;
|
||||
let mut success: libc::c_int = 0i32;
|
||||
let mut public_keys_len: libc::c_int = 0i32;
|
||||
let mut public_keys: *mut *mut rpgp::signed_public_key = 0 as *mut *mut rpgp::signed_public_key;
|
||||
let mut private_key: *mut rpgp::signed_secret_key = 0 as *mut rpgp::signed_secret_key;
|
||||
let mut encrypted: *mut rpgp::Message = 0 as *mut rpgp::Message;
|
||||
if !(plain_text == 0 as *mut libc::c_void
|
||||
|| plain_bytes == 0
|
||||
|| ret_ctext.is_null()
|
||||
|| ret_ctext_bytes.is_null()
|
||||
|| raw_public_keys_for_encryption.is_null()
|
||||
|| (*raw_public_keys_for_encryption).count <= 0i32
|
||||
|| use_armor == 0i32)
|
||||
{
|
||||
/* only support use_armor=1 */
|
||||
*ret_ctext = 0 as *mut libc::c_void;
|
||||
*ret_ctext_bytes = 0i32 as size_t;
|
||||
public_keys_len = (*raw_public_keys_for_encryption).count;
|
||||
public_keys = malloc(
|
||||
(::std::mem::size_of::<*mut rpgp::signed_public_key>())
|
||||
.wrapping_mul(public_keys_len as usize),
|
||||
) as *mut *mut rpgp::signed_public_key;
|
||||
/* setup secret key for signing */
|
||||
if !raw_private_key_for_signing.is_null() {
|
||||
private_key = rpgp::rpgp_skey_from_bytes(
|
||||
(*raw_private_key_for_signing).binary as *const uint8_t,
|
||||
(*raw_private_key_for_signing).bytes as usize,
|
||||
);
|
||||
if private_key.is_null() || 0 != dc_pgp_handle_rpgp_error(context) {
|
||||
dc_log_warning(
|
||||
context,
|
||||
0i32,
|
||||
b"No key for signing found.\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
current_block = 2132137392766895896;
|
||||
} else {
|
||||
current_block = 12800627514080957624;
|
||||
}
|
||||
} else {
|
||||
current_block = 12800627514080957624;
|
||||
}
|
||||
match current_block {
|
||||
2132137392766895896 => {}
|
||||
_ => {
|
||||
/* setup public keys for encryption */
|
||||
i = 0i32;
|
||||
loop {
|
||||
if !(i < public_keys_len) {
|
||||
current_block = 6057473163062296781;
|
||||
break;
|
||||
}
|
||||
let ref mut fresh0 = *public_keys.offset(i as isize);
|
||||
*fresh0 = rpgp::rpgp_pkey_from_bytes(
|
||||
(**(*raw_public_keys_for_encryption).keys.offset(i as isize)).binary
|
||||
as *const uint8_t,
|
||||
(**(*raw_public_keys_for_encryption).keys.offset(i as isize)).bytes
|
||||
as usize,
|
||||
);
|
||||
if 0 != dc_pgp_handle_rpgp_error(context) {
|
||||
current_block = 2132137392766895896;
|
||||
break;
|
||||
}
|
||||
i += 1
|
||||
}
|
||||
match current_block {
|
||||
2132137392766895896 => {}
|
||||
_ => {
|
||||
/* sign & encrypt */
|
||||
let op_clocks: libc::clock_t;
|
||||
let start: libc::clock_t = clock();
|
||||
if private_key.is_null() {
|
||||
encrypted = rpgp::rpgp_encrypt_bytes_to_keys(
|
||||
plain_text as *const uint8_t,
|
||||
plain_bytes as usize,
|
||||
public_keys as *const *const rpgp::signed_public_key,
|
||||
public_keys_len as usize,
|
||||
);
|
||||
if 0 != dc_pgp_handle_rpgp_error(context) {
|
||||
dc_log_warning(
|
||||
context,
|
||||
0i32,
|
||||
b"Encryption failed.\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
current_block = 2132137392766895896;
|
||||
} else {
|
||||
op_clocks = clock().wrapping_sub(start);
|
||||
dc_log_info(
|
||||
context,
|
||||
0i32,
|
||||
b"Message encrypted in %.3f ms.\x00" as *const u8
|
||||
as *const libc::c_char,
|
||||
op_clocks as libc::c_double * 1000.0f64
|
||||
/ 1000000i32 as libc::c_double,
|
||||
);
|
||||
current_block = 1538046216550696469;
|
||||
}
|
||||
} else {
|
||||
encrypted = rpgp::rpgp_sign_encrypt_bytes_to_keys(
|
||||
plain_text as *const uint8_t,
|
||||
plain_bytes as usize,
|
||||
public_keys as *const *const rpgp::signed_public_key,
|
||||
public_keys_len as usize,
|
||||
private_key,
|
||||
);
|
||||
if 0 != dc_pgp_handle_rpgp_error(context) {
|
||||
dc_log_warning(
|
||||
context,
|
||||
0i32,
|
||||
b"Signing and encrypting failed.\x00" as *const u8
|
||||
as *const libc::c_char,
|
||||
);
|
||||
current_block = 2132137392766895896;
|
||||
} else {
|
||||
op_clocks = clock().wrapping_sub(start);
|
||||
dc_log_info(
|
||||
context,
|
||||
0i32,
|
||||
b"Message signed and encrypted in %.3f ms.\x00" as *const u8
|
||||
as *const libc::c_char,
|
||||
op_clocks as libc::c_double * 1000.0f64
|
||||
/ 1000000i32 as libc::c_double,
|
||||
);
|
||||
current_block = 1538046216550696469;
|
||||
}
|
||||
}
|
||||
match current_block {
|
||||
2132137392766895896 => {}
|
||||
_ => {
|
||||
/* convert message to armored bytes and return values */
|
||||
let armored: *mut rpgp::cvec = rpgp::rpgp_msg_to_armored(encrypted);
|
||||
if !(0 != dc_pgp_handle_rpgp_error(context)) {
|
||||
*ret_ctext = rpgp::rpgp_cvec_data(armored) as *mut libc::c_void;
|
||||
*ret_ctext_bytes = rpgp::rpgp_cvec_len(armored) as size_t;
|
||||
free(armored as *mut libc::c_void);
|
||||
success = 1i32
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if !private_key.is_null() {
|
||||
rpgp::rpgp_skey_drop(private_key);
|
||||
}
|
||||
i = 0i32;
|
||||
while i < public_keys_len {
|
||||
rpgp::rpgp_pkey_drop(*public_keys.offset(i as isize));
|
||||
i += 1
|
||||
}
|
||||
if !encrypted.is_null() {
|
||||
rpgp::rpgp_msg_drop(encrypted);
|
||||
}
|
||||
public_keys_for_encryption: &Keyring,
|
||||
private_key_for_signing: Option<&Key>,
|
||||
) -> Option<String> {
|
||||
assert!(!plain_text.is_null() && !plain_bytes > 0, "invalid input");
|
||||
|
||||
success
|
||||
let bytes = unsafe { std::slice::from_raw_parts(plain_text as *const u8, plain_bytes) };
|
||||
let lit_msg = Message::new_literal_bytes("", bytes);
|
||||
let pkeys: Vec<&SignedPublicKey> = public_keys_for_encryption
|
||||
.keys()
|
||||
.iter()
|
||||
.filter_map(|key| key.try_into().ok())
|
||||
.collect();
|
||||
|
||||
let mut rng = thread_rng();
|
||||
|
||||
// TODO: measure time
|
||||
// TODO: better error handling
|
||||
let encrypted_msg = if let Some(private_key) = private_key_for_signing {
|
||||
let skey: &SignedSecretKey = private_key.try_into().unwrap();
|
||||
|
||||
lit_msg
|
||||
.sign(skey, || "".into(), Default::default())
|
||||
.and_then(|msg| msg.compress(CompressionAlgorithm::ZLIB))
|
||||
.and_then(|msg| msg.encrypt_to_keys(&mut rng, Default::default(), &pkeys))
|
||||
} else {
|
||||
lit_msg.encrypt_to_keys(&mut rng, Default::default(), &pkeys)
|
||||
};
|
||||
|
||||
encrypted_msg
|
||||
.and_then(|msg| msg.to_armored_string(None))
|
||||
.ok()
|
||||
}
|
||||
|
||||
// TODO should return bool /rtn
|
||||
pub unsafe fn dc_pgp_pk_decrypt(
|
||||
context: &dc_context_t,
|
||||
pub fn dc_pgp_pk_decrypt(
|
||||
ctext: *const libc::c_void,
|
||||
ctext_bytes: size_t,
|
||||
raw_private_keys_for_decryption: *const dc_keyring_t,
|
||||
raw_public_keys_for_validation: *const dc_keyring_t,
|
||||
use_armor: libc::c_int,
|
||||
ret_plain: *mut *mut libc::c_void,
|
||||
ret_plain_bytes: *mut size_t,
|
||||
private_keys_for_decryption: &Keyring,
|
||||
public_keys_for_validation: &Keyring,
|
||||
ret_signature_fingerprints: *mut dc_hash_t,
|
||||
) -> libc::c_int {
|
||||
let mut current_block: u64;
|
||||
let mut i: libc::c_int;
|
||||
let mut success: libc::c_int = 0i32;
|
||||
let mut encrypted: *mut rpgp::Message = 0 as *mut rpgp::Message;
|
||||
let mut decrypted: *mut rpgp::message_decrypt_result = 0 as *mut rpgp::message_decrypt_result;
|
||||
let mut private_keys_len: libc::c_int = 0i32;
|
||||
let mut public_keys_len: libc::c_int = 0i32;
|
||||
let mut private_keys: *mut *mut rpgp::signed_secret_key =
|
||||
0 as *mut *mut rpgp::signed_secret_key;
|
||||
let mut public_keys: *mut *mut rpgp::signed_public_key = 0 as *mut *mut rpgp::signed_public_key;
|
||||
if !(ctext == 0 as *mut libc::c_void
|
||||
|| ctext_bytes == 0
|
||||
|| ret_plain.is_null()
|
||||
|| ret_plain_bytes.is_null()
|
||||
|| raw_private_keys_for_decryption.is_null()
|
||||
|| (*raw_private_keys_for_decryption).count <= 0i32
|
||||
|| use_armor == 0i32)
|
||||
{
|
||||
/* only support use_armor=1 */
|
||||
*ret_plain = 0 as *mut libc::c_void;
|
||||
*ret_plain_bytes = 0i32 as size_t;
|
||||
private_keys_len = (*raw_private_keys_for_decryption).count;
|
||||
private_keys = malloc(
|
||||
(::std::mem::size_of::<*mut rpgp::signed_secret_key>())
|
||||
.wrapping_mul(private_keys_len as usize),
|
||||
) as *mut *mut rpgp::signed_secret_key;
|
||||
if !raw_public_keys_for_validation.is_null() {
|
||||
public_keys_len = (*raw_public_keys_for_validation).count;
|
||||
public_keys = malloc(
|
||||
(::std::mem::size_of::<*mut rpgp::signed_public_key>())
|
||||
.wrapping_mul(public_keys_len as usize),
|
||||
) as *mut *mut rpgp::signed_public_key
|
||||
}
|
||||
/* setup secret keys for decryption */
|
||||
i = 0i32;
|
||||
loop {
|
||||
if !(i < (*raw_private_keys_for_decryption).count) {
|
||||
current_block = 15904375183555213903;
|
||||
break;
|
||||
}
|
||||
let ref mut fresh1 = *private_keys.offset(i as isize);
|
||||
*fresh1 = rpgp::rpgp_skey_from_bytes(
|
||||
(**(*raw_private_keys_for_decryption).keys.offset(i as isize)).binary
|
||||
as *const uint8_t,
|
||||
(**(*raw_private_keys_for_decryption).keys.offset(i as isize)).bytes as usize,
|
||||
);
|
||||
if 0 != dc_pgp_handle_rpgp_error(context) {
|
||||
current_block = 11904635156640512504;
|
||||
break;
|
||||
}
|
||||
i += 1
|
||||
}
|
||||
match current_block {
|
||||
11904635156640512504 => {}
|
||||
_ => {
|
||||
/* setup public keys for validation */
|
||||
if !raw_public_keys_for_validation.is_null() {
|
||||
i = 0i32;
|
||||
loop {
|
||||
if !(i < (*raw_public_keys_for_validation).count) {
|
||||
current_block = 7172762164747879670;
|
||||
break;
|
||||
}
|
||||
let ref mut fresh2 = *public_keys.offset(i as isize);
|
||||
*fresh2 = rpgp::rpgp_pkey_from_bytes(
|
||||
(**(*raw_public_keys_for_validation).keys.offset(i as isize)).binary
|
||||
as *const uint8_t,
|
||||
(**(*raw_public_keys_for_validation).keys.offset(i as isize)).bytes
|
||||
as usize,
|
||||
);
|
||||
if 0 != dc_pgp_handle_rpgp_error(context) {
|
||||
current_block = 11904635156640512504;
|
||||
break;
|
||||
}
|
||||
i += 1
|
||||
}
|
||||
} else {
|
||||
current_block = 7172762164747879670;
|
||||
}
|
||||
match current_block {
|
||||
11904635156640512504 => {}
|
||||
_ => {
|
||||
/* decrypt */
|
||||
encrypted = rpgp::rpgp_msg_from_armor(
|
||||
ctext as *const uint8_t,
|
||||
ctext_bytes as usize,
|
||||
);
|
||||
if !(0 != dc_pgp_handle_rpgp_error(context)) {
|
||||
decrypted = rpgp::rpgp_msg_decrypt_no_pw(
|
||||
encrypted,
|
||||
private_keys as *const *const rpgp::signed_secret_key,
|
||||
private_keys_len as usize,
|
||||
public_keys as *const *const rpgp::signed_public_key,
|
||||
public_keys_len as usize,
|
||||
);
|
||||
if !(0 != dc_pgp_handle_rpgp_error(context)) {
|
||||
let decrypted_bytes: *mut rpgp::cvec =
|
||||
rpgp::rpgp_msg_to_bytes((*decrypted).message_ptr);
|
||||
if !(0 != dc_pgp_handle_rpgp_error(context)) {
|
||||
*ret_plain_bytes =
|
||||
rpgp::rpgp_cvec_len(decrypted_bytes) as size_t;
|
||||
*ret_plain =
|
||||
rpgp::rpgp_cvec_data(decrypted_bytes) as *mut libc::c_void;
|
||||
free(decrypted_bytes as *mut libc::c_void);
|
||||
if !ret_signature_fingerprints.is_null() {
|
||||
let mut j: uint32_t = 0i32 as uint32_t;
|
||||
let len: uint32_t = (*decrypted).valid_ids_len as uint32_t;
|
||||
while j < len {
|
||||
let fingerprint_hex: *mut libc::c_char =
|
||||
*(*decrypted).valid_ids_ptr.offset(j as isize);
|
||||
if !fingerprint_hex.is_null() {
|
||||
dc_hash_insert(
|
||||
ret_signature_fingerprints,
|
||||
fingerprint_hex as *const libc::c_void,
|
||||
strlen(fingerprint_hex) as libc::c_int,
|
||||
1i32 as *mut libc::c_void,
|
||||
);
|
||||
free(fingerprint_hex as *mut libc::c_void);
|
||||
}
|
||||
j = j.wrapping_add(1)
|
||||
}
|
||||
}
|
||||
success = 1i32
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
i = 0i32;
|
||||
while i < private_keys_len {
|
||||
rpgp::rpgp_skey_drop(*private_keys.offset(i as isize));
|
||||
i += 1
|
||||
}
|
||||
i = 0i32;
|
||||
while i < public_keys_len {
|
||||
rpgp::rpgp_pkey_drop(*public_keys.offset(i as isize));
|
||||
i += 1
|
||||
}
|
||||
if !encrypted.is_null() {
|
||||
rpgp::rpgp_msg_drop(encrypted);
|
||||
}
|
||||
if !decrypted.is_null() {
|
||||
rpgp::rpgp_message_decrypt_result_drop(decrypted);
|
||||
}
|
||||
) -> Option<Vec<u8>> {
|
||||
assert!(!ctext.is_null() && ctext_bytes > 0, "invalid input");
|
||||
|
||||
success
|
||||
let ctext = unsafe { std::slice::from_raw_parts(ctext as *const u8, ctext_bytes) };
|
||||
|
||||
// TODO: proper error handling
|
||||
if let Ok((msg, _)) = Message::from_armor_single(Cursor::new(ctext)) {
|
||||
let skeys: Vec<&SignedSecretKey> = private_keys_for_decryption
|
||||
.keys()
|
||||
.iter()
|
||||
.filter_map(|key| key.try_into().ok())
|
||||
.collect();
|
||||
|
||||
msg.decrypt(|| "".into(), || "".into(), &skeys[..])
|
||||
.and_then(|(mut decryptor, _)| {
|
||||
// TODO: how to handle the case when we detect multiple messages?
|
||||
decryptor.next().expect("no message")
|
||||
})
|
||||
.and_then(|dec_msg| {
|
||||
if !ret_signature_fingerprints.is_null()
|
||||
&& !public_keys_for_validation.keys().is_empty()
|
||||
{
|
||||
let pkeys: Vec<&SignedPublicKey> = public_keys_for_validation
|
||||
.keys()
|
||||
.iter()
|
||||
.filter_map(|key| key.try_into().ok())
|
||||
.collect();
|
||||
|
||||
for pkey in &pkeys {
|
||||
if dec_msg.verify(&pkey.primary_key).is_ok() {
|
||||
let fp_r = hex::encode_upper(pkey.fingerprint());
|
||||
let len = fp_r.len() as libc::c_int;
|
||||
let fp_c = CString::new(fp_r).unwrap();
|
||||
let fp = unsafe { libc::strdup(fp_c.as_ptr()) };
|
||||
|
||||
unsafe {
|
||||
dc_hash_insert(
|
||||
ret_signature_fingerprints,
|
||||
fp as *const _,
|
||||
len,
|
||||
1 as *mut _,
|
||||
)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
dec_msg.get_content()
|
||||
})
|
||||
.ok()
|
||||
.and_then(|content| content)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/* symm. encryption */
|
||||
// TODO should return bool /rtn
|
||||
pub unsafe fn dc_pgp_symm_encrypt(
|
||||
context: &dc_context_t,
|
||||
/// Symmetric encryption.
|
||||
pub fn dc_pgp_symm_encrypt(
|
||||
passphrase: *const libc::c_char,
|
||||
plain: *const libc::c_void,
|
||||
plain_bytes: size_t,
|
||||
ret_ctext_armored: *mut *mut libc::c_char,
|
||||
) -> libc::c_int {
|
||||
let mut success: libc::c_int = 0i32;
|
||||
let mut decrypted: *mut rpgp::Message = 0 as *mut rpgp::Message;
|
||||
if !(passphrase.is_null()
|
||||
|| plain == 0 as *mut libc::c_void
|
||||
|| plain_bytes == 0
|
||||
|| ret_ctext_armored.is_null())
|
||||
{
|
||||
decrypted = rpgp::rpgp_encrypt_bytes_with_password(
|
||||
plain as *const uint8_t,
|
||||
plain_bytes as usize,
|
||||
passphrase,
|
||||
);
|
||||
if !(0 != dc_pgp_handle_rpgp_error(context)) {
|
||||
*ret_ctext_armored = rpgp::rpgp_msg_to_armored_str(decrypted);
|
||||
if !(0 != dc_pgp_handle_rpgp_error(context)) {
|
||||
success = 1i32
|
||||
}
|
||||
}
|
||||
}
|
||||
if !decrypted.is_null() {
|
||||
rpgp::rpgp_msg_drop(decrypted);
|
||||
}
|
||||
) -> Option<String> {
|
||||
assert!(!passphrase.is_null(), "invalid passphrase");
|
||||
assert!(!plain.is_null() && !plain_bytes > 0, "invalid input");
|
||||
|
||||
success
|
||||
let pw = unsafe { CStr::from_ptr(passphrase).to_str().unwrap() };
|
||||
let bytes = unsafe { std::slice::from_raw_parts(plain as *const u8, plain_bytes) };
|
||||
|
||||
let mut rng = thread_rng();
|
||||
let lit_msg = Message::new_literal_bytes("", bytes);
|
||||
|
||||
let s2k = StringToKey::new_default(&mut rng);
|
||||
let msg = lit_msg.encrypt_with_password(&mut rng, s2k, Default::default(), || pw.into());
|
||||
|
||||
msg.and_then(|msg| msg.to_armored_string(None)).ok()
|
||||
}
|
||||
|
||||
// TODO should return bool /rtn
|
||||
pub unsafe fn dc_pgp_symm_decrypt(
|
||||
context: &dc_context_t,
|
||||
/// Symmetric decryption.
|
||||
pub fn dc_pgp_symm_decrypt(
|
||||
passphrase: *const libc::c_char,
|
||||
ctext: *const libc::c_void,
|
||||
ctext_bytes: size_t,
|
||||
ret_plain_text: *mut *mut libc::c_void,
|
||||
ret_plain_bytes: *mut size_t,
|
||||
) -> libc::c_int {
|
||||
let decrypted_bytes: *mut rpgp::cvec;
|
||||
let mut success: libc::c_int = 0i32;
|
||||
let encrypted: *mut rpgp::Message;
|
||||
let mut decrypted: *mut rpgp::Message = 0 as *mut rpgp::Message;
|
||||
encrypted = rpgp::rpgp_msg_from_bytes(ctext as *const uint8_t, ctext_bytes as usize);
|
||||
if !(0 != dc_pgp_handle_rpgp_error(context)) {
|
||||
decrypted = rpgp::rpgp_msg_decrypt_with_password(encrypted, passphrase);
|
||||
if !(0 != dc_pgp_handle_rpgp_error(context)) {
|
||||
decrypted_bytes = rpgp::rpgp_msg_to_bytes(decrypted);
|
||||
if !(0 != dc_pgp_handle_rpgp_error(context)) {
|
||||
*ret_plain_text = rpgp::rpgp_cvec_data(decrypted_bytes) as *mut libc::c_void;
|
||||
*ret_plain_bytes = rpgp::rpgp_cvec_len(decrypted_bytes) as size_t;
|
||||
free(decrypted_bytes as *mut libc::c_void);
|
||||
success = 1i32
|
||||
}
|
||||
}
|
||||
}
|
||||
if !encrypted.is_null() {
|
||||
rpgp::rpgp_msg_drop(encrypted);
|
||||
}
|
||||
if !decrypted.is_null() {
|
||||
rpgp::rpgp_msg_drop(decrypted);
|
||||
}
|
||||
) -> Option<Vec<u8>> {
|
||||
assert!(!passphrase.is_null(), "invalid passphrase");
|
||||
assert!(!ctext.is_null() && !ctext_bytes > 0, "invalid input");
|
||||
|
||||
success
|
||||
let pw = unsafe { CStr::from_ptr(passphrase).to_str().unwrap() };
|
||||
let bytes = unsafe { std::slice::from_raw_parts(ctext as *const u8, ctext_bytes) };
|
||||
|
||||
let enc_msg = Message::from_bytes(Cursor::new(bytes));
|
||||
|
||||
enc_msg
|
||||
.and_then(|msg| {
|
||||
let mut decryptor = msg
|
||||
.decrypt_with_password(|| pw.into())
|
||||
.expect("failed decryption");
|
||||
decryptor.next().expect("no message")
|
||||
})
|
||||
.and_then(|msg| msg.get_content())
|
||||
.ok()
|
||||
.and_then(|content| content)
|
||||
}
|
||||
|
||||
/// Calculate the SHA256 hash of the given bytes.
|
||||
pub fn dc_hash_sha256(bytes_ptr: *const u8, bytes_len: libc::size_t) -> (*mut u8, libc::size_t) {
|
||||
assert!(!bytes_ptr.is_null());
|
||||
assert!(bytes_len > 0);
|
||||
|
||||
let bytes = unsafe { std::slice::from_raw_parts(bytes_ptr, bytes_len) };
|
||||
let result = Sha256::digest(bytes);
|
||||
|
||||
let mut r = result.to_vec();
|
||||
r.shrink_to_fit();
|
||||
|
||||
let ptr = r.as_ptr();
|
||||
let len = r.len();
|
||||
std::mem::forget(r);
|
||||
|
||||
(ptr as *mut _, len)
|
||||
}
|
||||
|
||||
15
src/dc_qr.rs
15
src/dc_qr.rs
@@ -31,7 +31,7 @@ pub unsafe fn dc_check_qr(context: &dc_context_t, qr: *const libc::c_char) -> *m
|
||||
let mut name: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut invitenumber: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut auth: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let peerstate: *mut dc_apeerstate_t = dc_apeerstate_new(context);
|
||||
let mut peerstate = dc_apeerstate_new(context);
|
||||
let mut qr_parsed: *mut dc_lot_t = dc_lot_new();
|
||||
let mut chat_id: uint32_t = 0i32 as uint32_t;
|
||||
let mut device_msg: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
@@ -85,7 +85,7 @@ pub unsafe fn dc_check_qr(context: &dc_context_t, qr: *const libc::c_char) -> *m
|
||||
}
|
||||
dc_param_unref(param);
|
||||
}
|
||||
fingerprint = dc_normalize_fingerprint(payload);
|
||||
fingerprint = dc_normalize_fingerprint_c(payload);
|
||||
current_block = 5023038348526654800;
|
||||
} else if strncasecmp(
|
||||
qr,
|
||||
@@ -240,7 +240,7 @@ pub unsafe fn dc_check_qr(context: &dc_context_t, qr: *const libc::c_char) -> *m
|
||||
if !fingerprint.is_null() {
|
||||
if addr.is_null() || invitenumber.is_null() || auth.is_null() {
|
||||
if 0 != dc_apeerstate_load_by_fingerprint(
|
||||
peerstate,
|
||||
&mut peerstate,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
fingerprint,
|
||||
) {
|
||||
@@ -248,7 +248,7 @@ pub unsafe fn dc_check_qr(context: &dc_context_t, qr: *const libc::c_char) -> *m
|
||||
(*qr_parsed).id = dc_add_or_lookup_contact(
|
||||
context,
|
||||
0 as *const libc::c_char,
|
||||
(*peerstate).addr,
|
||||
peerstate.addr,
|
||||
0x80i32,
|
||||
0 as *mut libc::c_int,
|
||||
);
|
||||
@@ -262,10 +262,11 @@ pub unsafe fn dc_check_qr(context: &dc_context_t, qr: *const libc::c_char) -> *m
|
||||
device_msg = dc_mprintf(
|
||||
b"%s verified.\x00" as *const u8
|
||||
as *const libc::c_char,
|
||||
(*peerstate).addr,
|
||||
peerstate.addr,
|
||||
)
|
||||
} else {
|
||||
(*qr_parsed).text1 = dc_format_fingerprint(fingerprint);
|
||||
(*qr_parsed).text1 =
|
||||
dc_format_fingerprint_c(fingerprint);
|
||||
(*qr_parsed).state = 230i32
|
||||
}
|
||||
} else {
|
||||
@@ -323,7 +324,7 @@ pub unsafe fn dc_check_qr(context: &dc_context_t, qr: *const libc::c_char) -> *m
|
||||
}
|
||||
free(addr as *mut libc::c_void);
|
||||
free(fingerprint as *mut libc::c_void);
|
||||
dc_apeerstate_unref(peerstate);
|
||||
dc_apeerstate_unref(&mut peerstate);
|
||||
free(payload as *mut libc::c_void);
|
||||
free(name as *mut libc::c_void);
|
||||
free(invitenumber as *mut libc::c_void);
|
||||
|
||||
@@ -20,13 +20,13 @@ use crate::dc_mimeparser::*;
|
||||
use crate::dc_move::*;
|
||||
use crate::dc_msg::*;
|
||||
use crate::dc_param::*;
|
||||
use crate::dc_pgp::dc_hash_sha256;
|
||||
use crate::dc_securejoin::*;
|
||||
use crate::dc_sqlite3::*;
|
||||
use crate::dc_stock::*;
|
||||
use crate::dc_strbuilder::*;
|
||||
use crate::dc_strencode::*;
|
||||
use crate::dc_tools::*;
|
||||
use crate::pgp;
|
||||
use crate::types::*;
|
||||
use crate::x::*;
|
||||
|
||||
@@ -1756,7 +1756,7 @@ unsafe fn create_adhoc_grp_id(
|
||||
i += 1
|
||||
}
|
||||
/* make sha-256 from the string */
|
||||
let binary_hash: *mut crate::pgp::cvec = pgp::rpgp_hash_sha256(
|
||||
let (binary_hash, binary_hash_len) = dc_hash_sha256(
|
||||
member_cs.buf as *const uint8_t,
|
||||
strlen(member_cs.buf) as usize,
|
||||
);
|
||||
@@ -1768,11 +1768,11 @@ unsafe fn create_adhoc_grp_id(
|
||||
sprintf(
|
||||
&mut *ret.offset((i * 2i32) as isize) as *mut libc::c_char,
|
||||
b"%02x\x00" as *const u8 as *const libc::c_char,
|
||||
*pgp::rpgp_cvec_data(binary_hash).offset(i as isize) as libc::c_int,
|
||||
*binary_hash.offset(i as isize) as libc::c_int,
|
||||
);
|
||||
i += 1
|
||||
}
|
||||
pgp::rpgp_cvec_drop(binary_hash);
|
||||
let _v = Vec::from_raw_parts(binary_hash, binary_hash_len, binary_hash_len);
|
||||
}
|
||||
}
|
||||
dc_array_free_ptr(member_addrs);
|
||||
@@ -1861,7 +1861,7 @@ unsafe fn check_verified_properties(
|
||||
let mut current_block: u64;
|
||||
let mut everythings_okay: libc::c_int = 0i32;
|
||||
let contact: *mut dc_contact_t = dc_contact_new(context);
|
||||
let peerstate: *mut dc_apeerstate_t = dc_apeerstate_new(context);
|
||||
let mut peerstate = dc_apeerstate_new(context);
|
||||
let mut to_ids_str: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut q3: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut stmt: *mut sqlite3_stmt = 0 as *mut sqlite3_stmt;
|
||||
@@ -1884,10 +1884,10 @@ unsafe fn check_verified_properties(
|
||||
// and results in group-splits otherwise.
|
||||
if from_id != 1i32 as libc::c_uint {
|
||||
if 0 == dc_apeerstate_load_by_addr(
|
||||
peerstate,
|
||||
&mut peerstate,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
(*contact).addr,
|
||||
) || dc_contact_is_verified_ex(contact, peerstate) != 2i32
|
||||
) || dc_contact_is_verified_ex(contact, Some(&peerstate)) != 2i32
|
||||
{
|
||||
*failure_reason = dc_mprintf(
|
||||
b"%s. See \"Info\" for details.\x00" as *const u8 as *const libc::c_char,
|
||||
@@ -1898,7 +1898,7 @@ unsafe fn check_verified_properties(
|
||||
current_block = 14837890932895028253;
|
||||
} else if 0
|
||||
== dc_apeerstate_has_verified_key(
|
||||
peerstate,
|
||||
&&peerstate,
|
||||
(*(*mimeparser).e2ee_helper).signatures,
|
||||
)
|
||||
{
|
||||
@@ -1940,19 +1940,19 @@ unsafe fn check_verified_properties(
|
||||
)
|
||||
.is_null()
|
||||
&& 0 != dc_apeerstate_load_by_addr(
|
||||
peerstate,
|
||||
&mut peerstate,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
to_addr,
|
||||
)
|
||||
{
|
||||
if 0 == is_verified
|
||||
|| strcmp(
|
||||
(*peerstate).verified_key_fingerprint,
|
||||
(*peerstate).public_key_fingerprint,
|
||||
peerstate.verified_key_fingerprint,
|
||||
peerstate.public_key_fingerprint,
|
||||
) != 0i32
|
||||
&& strcmp(
|
||||
(*peerstate).verified_key_fingerprint,
|
||||
(*peerstate).gossip_key_fingerprint,
|
||||
peerstate.verified_key_fingerprint,
|
||||
peerstate.gossip_key_fingerprint,
|
||||
) != 0i32
|
||||
{
|
||||
dc_log_info(
|
||||
@@ -1962,14 +1962,10 @@ unsafe fn check_verified_properties(
|
||||
(*contact).addr,
|
||||
to_addr,
|
||||
);
|
||||
dc_apeerstate_set_verified(
|
||||
peerstate,
|
||||
0i32,
|
||||
(*peerstate).gossip_key_fingerprint,
|
||||
2i32,
|
||||
);
|
||||
let fp = peerstate.gossip_key_fingerprint;
|
||||
dc_apeerstate_set_verified(&mut peerstate, 0i32, fp, 2i32);
|
||||
dc_apeerstate_save_to_db(
|
||||
peerstate,
|
||||
&mut peerstate,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
0i32,
|
||||
);
|
||||
@@ -2002,7 +1998,7 @@ unsafe fn check_verified_properties(
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
dc_contact_unref(contact);
|
||||
dc_apeerstate_unref(peerstate);
|
||||
dc_apeerstate_unref(&mut peerstate);
|
||||
free(to_ids_str as *mut libc::c_void);
|
||||
sqlite3_free(q3 as *mut libc::c_void);
|
||||
return everythings_okay;
|
||||
|
||||
@@ -148,30 +148,23 @@ pub unsafe fn dc_get_securejoin_qr(
|
||||
}
|
||||
|
||||
unsafe fn get_self_fingerprint(context: &dc_context_t) -> *mut libc::c_char {
|
||||
let self_addr: *mut libc::c_char;
|
||||
let self_key: *mut dc_key_t = dc_key_new();
|
||||
let mut fingerprint: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
self_addr = dc_sqlite3_get_config(
|
||||
let self_addr = dc_sqlite3_get_config(
|
||||
context,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
b"configured_addr\x00" as *const u8 as *const libc::c_char,
|
||||
0 as *const libc::c_char,
|
||||
);
|
||||
if !(self_addr.is_null()
|
||||
|| 0 == dc_key_load_self_public(
|
||||
context,
|
||||
self_key,
|
||||
self_addr,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
))
|
||||
{
|
||||
fingerprint = dc_key_get_fingerprint(context, self_key);
|
||||
fingerprint.is_null();
|
||||
if self_addr.is_null() {
|
||||
return std::ptr::null_mut();
|
||||
}
|
||||
free(self_addr as *mut libc::c_void);
|
||||
dc_key_unref(self_key);
|
||||
|
||||
fingerprint
|
||||
if let Some(key) =
|
||||
Key::from_self_public(context, self_addr, &context.sql.clone().read().unwrap())
|
||||
{
|
||||
return key.fingerprint_c();
|
||||
}
|
||||
|
||||
std::ptr::null_mut()
|
||||
}
|
||||
|
||||
pub unsafe fn dc_join_securejoin(context: &dc_context_t, qr: *const libc::c_char) -> uint32_t {
|
||||
@@ -360,7 +353,7 @@ unsafe fn fingerprint_equals_sender(
|
||||
let mut fingerprint_equal: libc::c_int = 0i32;
|
||||
let contacts: *mut dc_array_t = dc_get_chat_contacts(context, contact_chat_id);
|
||||
let contact: *mut dc_contact_t = dc_contact_new(context);
|
||||
let peerstate: *mut dc_apeerstate_t = dc_apeerstate_new(context);
|
||||
let mut peerstate = dc_apeerstate_new(context);
|
||||
let mut fingerprint_normalized: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
if !(dc_array_get_cnt(contacts) != 1) {
|
||||
if !(!dc_contact_load_from_db(
|
||||
@@ -369,13 +362,13 @@ unsafe fn fingerprint_equals_sender(
|
||||
dc_array_get_id(contacts, 0i32 as size_t),
|
||||
) || 0
|
||||
== dc_apeerstate_load_by_addr(
|
||||
peerstate,
|
||||
&mut peerstate,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
(*contact).addr,
|
||||
))
|
||||
{
|
||||
fingerprint_normalized = dc_normalize_fingerprint(fingerprint);
|
||||
if strcasecmp(fingerprint_normalized, (*peerstate).public_key_fingerprint) == 0i32 {
|
||||
fingerprint_normalized = dc_normalize_fingerprint_c(fingerprint);
|
||||
if strcasecmp(fingerprint_normalized, peerstate.public_key_fingerprint) == 0i32 {
|
||||
fingerprint_equal = 1i32
|
||||
}
|
||||
}
|
||||
@@ -984,19 +977,19 @@ unsafe fn mark_peer_as_verified(
|
||||
let mut peerstate = dc_apeerstate_new(context);
|
||||
if !(0
|
||||
== dc_apeerstate_load_by_fingerprint(
|
||||
peerstate,
|
||||
&mut peerstate,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
fingerprint,
|
||||
))
|
||||
{
|
||||
if !(0 == dc_apeerstate_set_verified(peerstate, 1i32, fingerprint, 2i32)) {
|
||||
(*peerstate).prefer_encrypt = 1i32;
|
||||
(*peerstate).to_save |= 0x2i32;
|
||||
dc_apeerstate_save_to_db(peerstate, &context.sql.clone().read().unwrap(), 0i32);
|
||||
if !(0 == dc_apeerstate_set_verified(&mut peerstate, 1i32, fingerprint, 2i32)) {
|
||||
peerstate.prefer_encrypt = 1i32;
|
||||
peerstate.to_save |= 0x2i32;
|
||||
dc_apeerstate_save_to_db(&mut peerstate, &context.sql.clone().read().unwrap(), 0i32);
|
||||
success = 1i32
|
||||
}
|
||||
}
|
||||
dc_apeerstate_unref(peerstate);
|
||||
dc_apeerstate_unref(&mut peerstate);
|
||||
|
||||
success
|
||||
}
|
||||
@@ -1054,45 +1047,43 @@ unsafe fn encrypted_and_signed(
|
||||
1
|
||||
}
|
||||
|
||||
pub unsafe fn dc_handle_degrade_event(context: &dc_context_t, peerstate: *mut dc_apeerstate_t) {
|
||||
pub unsafe fn dc_handle_degrade_event(context: &dc_context_t, peerstate: &dc_apeerstate_t) {
|
||||
let stmt;
|
||||
let contact_id: uint32_t;
|
||||
let mut contact_chat_id: uint32_t = 0i32 as uint32_t;
|
||||
if !peerstate.is_null() {
|
||||
// - we do not issue an warning for DC_DE_ENCRYPTION_PAUSED as this is quite normal
|
||||
// - currently, we do not issue an extra warning for DC_DE_VERIFICATION_LOST - this always comes
|
||||
// together with DC_DE_FINGERPRINT_CHANGED which is logged, the idea is not to bother
|
||||
// with things they cannot fix, so the user is just kicked from the verified group
|
||||
// (and he will know this and can fix this)
|
||||
if 0 != (*peerstate).degrade_event & 0x2i32 {
|
||||
stmt = dc_sqlite3_prepare(
|
||||
|
||||
// - we do not issue an warning for DC_DE_ENCRYPTION_PAUSED as this is quite normal
|
||||
// - currently, we do not issue an extra warning for DC_DE_VERIFICATION_LOST - this always comes
|
||||
// together with DC_DE_FINGERPRINT_CHANGED which is logged, the idea is not to bother
|
||||
// with things they cannot fix, so the user is just kicked from the verified group
|
||||
// (and he will know this and can fix this)
|
||||
if 0 != peerstate.degrade_event & 0x2i32 {
|
||||
stmt = dc_sqlite3_prepare(
|
||||
context,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
b"SELECT id FROM contacts WHERE addr=?;\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
sqlite3_bind_text(stmt, 1i32, peerstate.addr, -1i32, None);
|
||||
sqlite3_step(stmt);
|
||||
contact_id = sqlite3_column_int(stmt, 0i32) as uint32_t;
|
||||
sqlite3_finalize(stmt);
|
||||
if !(contact_id == 0i32 as libc::c_uint) {
|
||||
dc_create_or_lookup_nchat_by_contact_id(
|
||||
context,
|
||||
&context.sql.clone().read().unwrap(),
|
||||
b"SELECT id FROM contacts WHERE addr=?;\x00" as *const u8 as *const libc::c_char,
|
||||
contact_id,
|
||||
2i32,
|
||||
&mut contact_chat_id,
|
||||
0 as *mut libc::c_int,
|
||||
);
|
||||
let msg: *mut libc::c_char = dc_stock_str_repl_string(context, 37i32, peerstate.addr);
|
||||
dc_add_device_msg(context, contact_chat_id, msg);
|
||||
free(msg as *mut libc::c_void);
|
||||
(context.cb)(
|
||||
context,
|
||||
Event::CHAT_MODIFIED,
|
||||
contact_chat_id as uintptr_t,
|
||||
0i32 as uintptr_t,
|
||||
);
|
||||
sqlite3_bind_text(stmt, 1i32, (*peerstate).addr, -1i32, None);
|
||||
sqlite3_step(stmt);
|
||||
contact_id = sqlite3_column_int(stmt, 0i32) as uint32_t;
|
||||
sqlite3_finalize(stmt);
|
||||
if !(contact_id == 0i32 as libc::c_uint) {
|
||||
dc_create_or_lookup_nchat_by_contact_id(
|
||||
context,
|
||||
contact_id,
|
||||
2i32,
|
||||
&mut contact_chat_id,
|
||||
0 as *mut libc::c_int,
|
||||
);
|
||||
let msg: *mut libc::c_char =
|
||||
dc_stock_str_repl_string(context, 37i32, (*peerstate).addr);
|
||||
dc_add_device_msg(context, contact_chat_id, msg);
|
||||
free(msg as *mut libc::c_void);
|
||||
(context.cb)(
|
||||
context,
|
||||
Event::CHAT_MODIFIED,
|
||||
contact_chat_id as uintptr_t,
|
||||
0i32 as uintptr_t,
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -914,16 +914,16 @@ pub unsafe fn dc_sqlite3_open(
|
||||
as *const libc::c_char,
|
||||
);
|
||||
while sqlite3_step(stmt) == 100 {
|
||||
let peerstate: *mut dc_apeerstate_t = dc_apeerstate_new(context);
|
||||
let mut peerstate = dc_apeerstate_new(context);
|
||||
if 0 != dc_apeerstate_load_by_addr(
|
||||
peerstate,
|
||||
&mut peerstate,
|
||||
sql,
|
||||
sqlite3_column_text(stmt, 0) as *const libc::c_char,
|
||||
) && 0 != dc_apeerstate_recalc_fingerprint(peerstate)
|
||||
) && 0 != dc_apeerstate_recalc_fingerprint(&mut peerstate)
|
||||
{
|
||||
dc_apeerstate_save_to_db(peerstate, sql, 0);
|
||||
dc_apeerstate_save_to_db(&mut peerstate, sql, 0);
|
||||
}
|
||||
dc_apeerstate_unref(peerstate);
|
||||
dc_apeerstate_unref(&mut peerstate);
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
}
|
||||
|
||||
@@ -14,16 +14,14 @@
|
||||
ptr_wrapping_offset_from
|
||||
)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate failure;
|
||||
#[macro_use]
|
||||
extern crate num_derive;
|
||||
#[macro_use]
|
||||
extern crate smallvec;
|
||||
|
||||
#[macro_use]
|
||||
pub mod dc_log;
|
||||
|
||||
mod pgp;
|
||||
|
||||
pub mod dc_aheader;
|
||||
|
||||
pub mod dc_apeerstate;
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
use std::slice;
|
||||
|
||||
/// Represents a vector, that can be passed to C land.
|
||||
/// Has to be deallocated using [rpgp_cvec_drop], otherwise leaks memory.
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct cvec {
|
||||
data: *mut u8,
|
||||
len: libc::size_t,
|
||||
}
|
||||
|
||||
impl PartialEq for cvec {
|
||||
fn eq(&self, other: &cvec) -> bool {
|
||||
if self.len != other.len {
|
||||
return false;
|
||||
}
|
||||
|
||||
unsafe {
|
||||
slice::from_raw_parts(self.data, self.len)
|
||||
== slice::from_raw_parts(other.data, other.len)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for cvec {}
|
||||
|
||||
impl Into<cvec> for Vec<u8> {
|
||||
fn into(mut self) -> cvec {
|
||||
self.shrink_to_fit();
|
||||
assert!(self.len() == self.capacity());
|
||||
|
||||
let res = cvec {
|
||||
data: self.as_mut_ptr(),
|
||||
len: self.len() as libc::size_t,
|
||||
};
|
||||
|
||||
// prevent deallocation in Rust
|
||||
std::mem::forget(self);
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<Vec<u8>> for cvec {
|
||||
fn into(self) -> Vec<u8> {
|
||||
unsafe { Vec::from_raw_parts(self.data, self.len, self.len) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the length of the data of the given [cvec].
|
||||
pub unsafe fn rpgp_cvec_len(cvec_ptr: *mut cvec) -> libc::size_t {
|
||||
assert!(!cvec_ptr.is_null());
|
||||
|
||||
let cvec = &*cvec_ptr;
|
||||
cvec.len
|
||||
}
|
||||
|
||||
/// Get a pointer to the data of the given [cvec].
|
||||
pub unsafe fn rpgp_cvec_data(cvec_ptr: *mut cvec) -> *const u8 {
|
||||
assert!(!cvec_ptr.is_null());
|
||||
|
||||
let cvec = &*cvec_ptr;
|
||||
cvec.data
|
||||
}
|
||||
|
||||
/// Free the given [cvec].
|
||||
pub unsafe fn rpgp_cvec_drop(cvec_ptr: *mut cvec) {
|
||||
assert!(!cvec_ptr.is_null());
|
||||
|
||||
let v = &*cvec_ptr;
|
||||
let _ = Vec::from_raw_parts(v.data, v.len, v.len);
|
||||
// Drop
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_cvec() {
|
||||
for i in 0..100 {
|
||||
let a = vec![i as u8; i * 10];
|
||||
let b: cvec = a.clone().into();
|
||||
let c: Vec<u8> = b.into();
|
||||
assert_eq!(a, c);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
use std::cell::RefCell;
|
||||
use std::ffi::CString;
|
||||
use std::ptr;
|
||||
|
||||
use failure::Error;
|
||||
use libc::{c_char, c_int};
|
||||
|
||||
thread_local! {
|
||||
static LAST_ERROR: RefCell<Option<Box<Error>>> = RefCell::new(None);
|
||||
}
|
||||
|
||||
/// Update the most recent error, clearing whatever may have been there before.
|
||||
pub fn update_last_error(err: Error) {
|
||||
{
|
||||
// Print a pseudo-backtrace for this error, following back each error's
|
||||
// cause until we reach the root error.
|
||||
let mut cause = err.as_fail().cause();
|
||||
while let Some(parent_err) = cause {
|
||||
cause = parent_err.cause();
|
||||
}
|
||||
}
|
||||
|
||||
LAST_ERROR.with(|prev| {
|
||||
*prev.borrow_mut() = Some(Box::new(err));
|
||||
});
|
||||
}
|
||||
|
||||
/// Retrieve the most recent error, clearing it in the process.
|
||||
pub fn take_last_error() -> Option<Box<Error>> {
|
||||
LAST_ERROR.with(|prev| prev.borrow_mut().take())
|
||||
}
|
||||
|
||||
/// Calculate the number of bytes in the last error's error message **not**
|
||||
/// including any trailing `null` characters.
|
||||
pub extern "C" fn rpgp_last_error_length() -> c_int {
|
||||
LAST_ERROR.with(|prev| match *prev.borrow() {
|
||||
Some(ref err) => err.to_string().len() as c_int + 1,
|
||||
None => 0,
|
||||
})
|
||||
}
|
||||
|
||||
/// Write the most recent error message into a caller-provided buffer as a UTF-8
|
||||
/// string, returning the number of bytes written.
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// This writes a **UTF-8** string into the buffer. Windows users may need to
|
||||
/// convert it to a UTF-16 "unicode" afterwards.
|
||||
///
|
||||
/// If there are no recent errors then this returns `0` (because we wrote 0
|
||||
/// bytes). `-1` is returned if there are any errors, for example when passed a
|
||||
/// null pointer or a buffer of insufficient size.
|
||||
pub unsafe fn rpgp_last_error_message() -> *mut c_char {
|
||||
let last_error = match take_last_error() {
|
||||
Some(err) => err,
|
||||
None => return ptr::null_mut(),
|
||||
};
|
||||
|
||||
let error_message = last_error.to_string();
|
||||
|
||||
CString::new(error_message)
|
||||
.expect("CString alloc failed")
|
||||
.into_raw()
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
use sha2::{Digest, Sha256};
|
||||
use std::slice;
|
||||
|
||||
use crate::pgp::cvec;
|
||||
|
||||
/// Calculate the SHA256 hash of the given bytes.
|
||||
pub unsafe fn rpgp_hash_sha256(bytes_ptr: *const u8, bytes_len: libc::size_t) -> *mut cvec {
|
||||
assert!(!bytes_ptr.is_null());
|
||||
assert!(bytes_len > 0);
|
||||
|
||||
let bytes = slice::from_raw_parts(bytes_ptr, bytes_len);
|
||||
let result = Sha256::digest(bytes);
|
||||
|
||||
Box::into_raw(Box::new(result.to_vec().into()))
|
||||
}
|
||||
143
src/pgp/key.rs
143
src/pgp/key.rs
@@ -1,143 +0,0 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
#[macro_export]
|
||||
macro_rules! try_ffi {
|
||||
($e:expr, $fmt:expr) => {
|
||||
match $e {
|
||||
Ok(v) => v,
|
||||
Err(err) => {
|
||||
$crate::pgp::errors::update_last_error(err.into());
|
||||
return std::ptr::null_mut();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -1,349 +0,0 @@
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::io::Cursor;
|
||||
use std::slice;
|
||||
|
||||
use libc::c_char;
|
||||
use pgp::composed::{Deserializable, SignedPublicKey, SignedSecretKey};
|
||||
use pgp::types::{CompressionAlgorithm, KeyTrait, StringToKey};
|
||||
use rand::thread_rng;
|
||||
|
||||
use crate::pgp::{cvec, signed_public_key, signed_secret_key, update_last_error};
|
||||
pub use pgp::composed::Message;
|
||||
pub type message = Message;
|
||||
|
||||
/// Parse an armored message.
|
||||
pub unsafe fn rpgp_msg_from_armor(msg_ptr: *const u8, msg_len: libc::size_t) -> *mut message {
|
||||
assert!(!msg_ptr.is_null());
|
||||
assert!(msg_len > 0);
|
||||
|
||||
let enc_msg = slice::from_raw_parts(msg_ptr, msg_len);
|
||||
|
||||
let (msg, _headers) = try_ffi!(
|
||||
Message::from_armor_single(Cursor::new(enc_msg)),
|
||||
"invalid message"
|
||||
);
|
||||
|
||||
Box::into_raw(Box::new(msg))
|
||||
}
|
||||
|
||||
/// Parse a message in bytes format.
|
||||
pub unsafe extern "C" fn rpgp_msg_from_bytes(
|
||||
msg_ptr: *const u8,
|
||||
msg_len: libc::size_t,
|
||||
) -> *mut message {
|
||||
assert!(!msg_ptr.is_null());
|
||||
assert!(msg_len > 0);
|
||||
|
||||
let enc_msg = slice::from_raw_parts(msg_ptr, msg_len);
|
||||
|
||||
let msg = try_ffi!(Message::from_bytes(Cursor::new(enc_msg)), "invalid message");
|
||||
|
||||
Box::into_raw(Box::new(msg))
|
||||
}
|
||||
|
||||
/// Decrypt the passed in message, using a password.
|
||||
pub unsafe fn rpgp_msg_decrypt_with_password(
|
||||
msg_ptr: *const message,
|
||||
password_ptr: *const c_char,
|
||||
) -> *mut message {
|
||||
assert!(!msg_ptr.is_null());
|
||||
assert!(!password_ptr.is_null());
|
||||
|
||||
let msg = &*msg_ptr;
|
||||
let password = CStr::from_ptr(password_ptr);
|
||||
let password_str = try_ffi!(password.to_str(), "invalid password");
|
||||
let mut decryptor = try_ffi!(
|
||||
msg.decrypt_with_password(|| password_str.into()),
|
||||
"failed to decrypt message"
|
||||
);
|
||||
let decrypted_msg = try_ffi!(
|
||||
try_ffi!(
|
||||
decryptor.next().ok_or_else(|| format_err!("")),
|
||||
"no message found"
|
||||
),
|
||||
"failed to decrypt message"
|
||||
);
|
||||
|
||||
Box::into_raw(Box::new(decrypted_msg))
|
||||
}
|
||||
|
||||
/// Decrypt the passed in message, without attempting to use a password.
|
||||
pub unsafe fn rpgp_msg_decrypt_no_pw(
|
||||
msg_ptr: *const message,
|
||||
skeys_ptr: *const *const signed_secret_key,
|
||||
skeys_len: libc::size_t,
|
||||
pkeys_ptr: *const *const signed_public_key,
|
||||
pkeys_len: libc::size_t,
|
||||
) -> *mut message_decrypt_result {
|
||||
assert!(!msg_ptr.is_null());
|
||||
assert!(!skeys_ptr.is_null());
|
||||
assert!(skeys_len > 0);
|
||||
|
||||
let msg = &*msg_ptr;
|
||||
let skeys_raw = slice::from_raw_parts(skeys_ptr, skeys_len);
|
||||
let skeys = skeys_raw
|
||||
.iter()
|
||||
.map(|k| {
|
||||
let v: &SignedSecretKey = &**k;
|
||||
v
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let pkeys = if pkeys_ptr.is_null() || pkeys_len == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(slice::from_raw_parts(pkeys_ptr, pkeys_len))
|
||||
};
|
||||
|
||||
let (mut decryptor, _) = try_ffi!(
|
||||
msg.decrypt(|| "".into(), || "".into(), &skeys[..]),
|
||||
"failed to decrypt message"
|
||||
);
|
||||
|
||||
// TODO: how to handle the case when we detect multiple messages?
|
||||
let dec_msg = try_ffi!(
|
||||
try_ffi!(
|
||||
decryptor.next().ok_or_else(|| format_err!("no message")),
|
||||
"no message found"
|
||||
),
|
||||
"failed to decrypt message"
|
||||
);
|
||||
|
||||
let (valid_ids_ptr, valid_ids_len) = if let Some(pkeys) = pkeys {
|
||||
let mut valid_ids = pkeys
|
||||
.iter()
|
||||
.filter_map(|pkey| match dec_msg.verify(&(**pkey).primary_key) {
|
||||
Ok(_) => Some(
|
||||
CString::new(hex::encode_upper(&(&**pkey).fingerprint()))
|
||||
.expect("failed to allocate")
|
||||
.into_raw(),
|
||||
),
|
||||
Err(_) => None,
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
valid_ids.shrink_to_fit();
|
||||
let res = (valid_ids.as_mut_ptr(), valid_ids.len());
|
||||
std::mem::forget(valid_ids);
|
||||
res
|
||||
} else {
|
||||
(std::ptr::null_mut(), 0)
|
||||
};
|
||||
|
||||
Box::into_raw(Box::new(message_decrypt_result {
|
||||
message_ptr: Box::into_raw(Box::new(dec_msg)),
|
||||
valid_ids_ptr,
|
||||
valid_ids_len,
|
||||
}))
|
||||
}
|
||||
|
||||
/// Message decryption result.
|
||||
#[repr(C)]
|
||||
pub struct message_decrypt_result {
|
||||
/// A pointer to the decrypted message.
|
||||
pub message_ptr: *mut message,
|
||||
/// Pointer to a list of fingerprints which verified the signature.
|
||||
pub valid_ids_ptr: *mut *mut c_char,
|
||||
pub valid_ids_len: libc::size_t,
|
||||
}
|
||||
|
||||
/// Free a [message_decrypt_result].
|
||||
pub unsafe fn rpgp_message_decrypt_result_drop(res_ptr: *mut message_decrypt_result) {
|
||||
assert!(!res_ptr.is_null());
|
||||
|
||||
let res = &*res_ptr;
|
||||
let _msg = &*res.message_ptr;
|
||||
let _ids = Vec::from_raw_parts(res.valid_ids_ptr, res.valid_ids_len, res.valid_ids_len);
|
||||
// Drop
|
||||
}
|
||||
|
||||
/// Returns the underlying data of the given message.
|
||||
/// Fails when the message is encrypted. Decompresses compressed messages.
|
||||
pub unsafe fn rpgp_msg_to_bytes(msg_ptr: *const message) -> *mut cvec {
|
||||
assert!(!msg_ptr.is_null());
|
||||
|
||||
let msg = &*msg_ptr;
|
||||
|
||||
let result = try_ffi!(msg.get_content(), "failed to extract content");
|
||||
match result {
|
||||
Some(data) => Box::into_raw(Box::new(data.into())),
|
||||
None => {
|
||||
update_last_error(format_err!("called on encrypted message").into());
|
||||
std::ptr::null_mut()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Encodes the message into its ascii armored representation.
|
||||
pub unsafe fn rpgp_msg_to_armored(msg_ptr: *const message) -> *mut cvec {
|
||||
assert!(!msg_ptr.is_null());
|
||||
|
||||
let msg = &*msg_ptr;
|
||||
|
||||
let result = try_ffi!(
|
||||
msg.to_armored_bytes(None),
|
||||
"failed to encode message to ASCII Armor"
|
||||
);
|
||||
|
||||
Box::into_raw(Box::new(result.into()))
|
||||
}
|
||||
|
||||
/// Encodes the message into its ascii armored representation, returning a string.
|
||||
pub unsafe fn rpgp_msg_to_armored_str(msg_ptr: *const message) -> *mut c_char {
|
||||
assert!(!msg_ptr.is_null());
|
||||
|
||||
let msg = &*msg_ptr;
|
||||
|
||||
let result = try_ffi!(
|
||||
msg.to_armored_string(None),
|
||||
"failed to encode message to ASCII Armor"
|
||||
);
|
||||
|
||||
CString::new(result).expect("allocation failed").into_raw()
|
||||
}
|
||||
|
||||
/// Free a [message], that was created by rpgp.
|
||||
pub unsafe fn rpgp_msg_drop(msg_ptr: *mut message) {
|
||||
assert!(!msg_ptr.is_null());
|
||||
|
||||
let _ = &*msg_ptr;
|
||||
// Drop
|
||||
}
|
||||
|
||||
/// Get the number of fingerprints of a given encrypted message.
|
||||
#[allow(dead_code)]
|
||||
pub unsafe fn rpgp_msg_recipients_len(msg_ptr: *mut message) -> u32 {
|
||||
assert!(!msg_ptr.is_null());
|
||||
|
||||
let msg = &*msg_ptr;
|
||||
|
||||
let list = msg.get_recipients();
|
||||
|
||||
list.len() as u32
|
||||
}
|
||||
|
||||
/// Get the fingerprint of a given encrypted message, by index, in hexformat.
|
||||
#[allow(dead_code)]
|
||||
pub unsafe fn rpgp_msg_recipients_get(msg_ptr: *mut message, i: u32) -> *mut c_char {
|
||||
assert!(!msg_ptr.is_null());
|
||||
|
||||
let msg = &*msg_ptr;
|
||||
|
||||
let list = msg.get_recipients();
|
||||
if (i as usize) < list.len() {
|
||||
CString::new(hex::encode(&list[i as usize]))
|
||||
.expect("allocation failure")
|
||||
.into_raw()
|
||||
} else {
|
||||
std::ptr::null_mut()
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn rpgp_encrypt_bytes_to_keys(
|
||||
bytes_ptr: *const u8,
|
||||
bytes_len: libc::size_t,
|
||||
pkeys_ptr: *const *const signed_public_key,
|
||||
pkeys_len: libc::size_t,
|
||||
) -> *mut message {
|
||||
assert!(!bytes_ptr.is_null());
|
||||
assert!(bytes_len > 0);
|
||||
assert!(!pkeys_ptr.is_null());
|
||||
assert!(pkeys_len > 0);
|
||||
|
||||
let pkeys_raw = slice::from_raw_parts(pkeys_ptr, pkeys_len);
|
||||
let pkeys = pkeys_raw
|
||||
.iter()
|
||||
.map(|k| {
|
||||
let v: &SignedPublicKey = &**k;
|
||||
v
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let bytes = slice::from_raw_parts(bytes_ptr, bytes_len);
|
||||
|
||||
let mut rng = thread_rng();
|
||||
let lit_msg = Message::new_literal_bytes("", bytes);
|
||||
|
||||
let msg = try_ffi!(
|
||||
lit_msg.encrypt_to_keys(&mut rng, Default::default(), &pkeys),
|
||||
"failed to encrypt"
|
||||
);
|
||||
|
||||
Box::into_raw(Box::new(msg))
|
||||
}
|
||||
|
||||
pub unsafe fn rpgp_sign_encrypt_bytes_to_keys(
|
||||
bytes_ptr: *const u8,
|
||||
bytes_len: libc::size_t,
|
||||
pkeys_ptr: *const *const signed_public_key,
|
||||
pkeys_len: libc::size_t,
|
||||
skey_ptr: *const signed_secret_key,
|
||||
) -> *mut message {
|
||||
assert!(!bytes_ptr.is_null());
|
||||
assert!(bytes_len > 0);
|
||||
assert!(!pkeys_ptr.is_null());
|
||||
assert!(pkeys_len > 0);
|
||||
assert!(!skey_ptr.is_null());
|
||||
|
||||
let pkeys_raw = slice::from_raw_parts(pkeys_ptr, pkeys_len);
|
||||
let pkeys = pkeys_raw
|
||||
.iter()
|
||||
.map(|k| {
|
||||
let v: &SignedPublicKey = &**k;
|
||||
v
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let skey = &*skey_ptr;
|
||||
|
||||
let bytes = slice::from_raw_parts(bytes_ptr, bytes_len);
|
||||
|
||||
let mut rng = thread_rng();
|
||||
|
||||
let lit_msg = Message::new_literal_bytes("", bytes);
|
||||
let signed_msg = try_ffi!(
|
||||
lit_msg.sign(&skey, || "".into(), Default::default()),
|
||||
"failed to sign"
|
||||
);
|
||||
|
||||
let compressed_msg = try_ffi!(
|
||||
signed_msg.compress(CompressionAlgorithm::ZLIB),
|
||||
"failed to compress"
|
||||
);
|
||||
|
||||
let encrypted_msg = try_ffi!(
|
||||
compressed_msg.encrypt_to_keys(&mut rng, Default::default(), &pkeys),
|
||||
"failed to encrypt"
|
||||
);
|
||||
|
||||
Box::into_raw(Box::new(encrypted_msg))
|
||||
}
|
||||
|
||||
pub unsafe fn rpgp_encrypt_bytes_with_password(
|
||||
bytes_ptr: *const u8,
|
||||
bytes_len: libc::size_t,
|
||||
password_ptr: *const c_char,
|
||||
) -> *mut message {
|
||||
assert!(!bytes_ptr.is_null());
|
||||
assert!(!password_ptr.is_null());
|
||||
assert!(bytes_len > 0);
|
||||
|
||||
let bytes = slice::from_raw_parts(bytes_ptr, bytes_len);
|
||||
|
||||
let mut rng = thread_rng();
|
||||
let lit_msg = Message::new_literal_bytes("", bytes);
|
||||
|
||||
let password = CStr::from_ptr(password_ptr);
|
||||
let password_str = try_ffi!(password.to_str(), "invalid password");
|
||||
|
||||
let s2k = StringToKey::new_default(&mut rng);
|
||||
|
||||
let msg = try_ffi!(
|
||||
lit_msg.encrypt_with_password(&mut rng, s2k, Default::default(), || {
|
||||
password_str.into()
|
||||
}),
|
||||
"failed to encrypt"
|
||||
);
|
||||
|
||||
Box::into_raw(Box::new(msg))
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
|
||||
mod c_vec;
|
||||
mod errors;
|
||||
mod hash;
|
||||
mod key;
|
||||
mod message;
|
||||
mod public_key;
|
||||
mod secret_key;
|
||||
|
||||
pub use self::c_vec::*;
|
||||
pub use self::errors::*;
|
||||
pub use self::hash::*;
|
||||
pub use self::key::*;
|
||||
pub use self::message::*;
|
||||
pub use self::public_key::*;
|
||||
pub use self::secret_key::*;
|
||||
|
||||
/// Free string, that was created by rpgp.
|
||||
pub unsafe fn rpgp_string_drop(p: *mut libc::c_char) {
|
||||
let _ = std::ffi::CString::from_raw(p);
|
||||
// Drop
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
use std::ffi::CString;
|
||||
use std::io::Cursor;
|
||||
use std::slice;
|
||||
|
||||
use libc::c_char;
|
||||
use pgp::composed::{Deserializable, SignedPublicKey};
|
||||
use pgp::ser::Serialize;
|
||||
use pgp::types::KeyTrait;
|
||||
|
||||
use crate::pgp::cvec;
|
||||
|
||||
pub type signed_public_key = SignedPublicKey;
|
||||
|
||||
/// Parse a serialized public key, into the native rPGP memory representation.
|
||||
pub unsafe fn rpgp_pkey_from_bytes(raw: *const u8, len: libc::size_t) -> *mut signed_public_key {
|
||||
assert!(!raw.is_null());
|
||||
assert!(len > 0);
|
||||
|
||||
let bytes = slice::from_raw_parts(raw, len);
|
||||
let key = try_ffi!(
|
||||
SignedPublicKey::from_bytes(Cursor::new(bytes)),
|
||||
"invalid public key"
|
||||
);
|
||||
|
||||
try_ffi!(key.verify(), "failed to verify key");
|
||||
|
||||
Box::into_raw(Box::new(key))
|
||||
}
|
||||
|
||||
/// Serialize the [signed_public_key] to bytes.
|
||||
pub unsafe extern "C" fn rpgp_pkey_to_bytes(pkey_ptr: *mut signed_public_key) -> *mut cvec {
|
||||
assert!(!pkey_ptr.is_null());
|
||||
|
||||
let pkey = &*pkey_ptr;
|
||||
|
||||
let mut res = Vec::new();
|
||||
try_ffi!(pkey.to_writer(&mut res), "failed to serialize key");
|
||||
|
||||
Box::into_raw(Box::new(res.into()))
|
||||
}
|
||||
|
||||
/// Get the key id of the given [signed_public_key].
|
||||
#[allow(dead_code)]
|
||||
pub unsafe fn rpgp_pkey_key_id(pkey_ptr: *mut signed_public_key) -> *mut c_char {
|
||||
assert!(!pkey_ptr.is_null());
|
||||
|
||||
let pkey = &*pkey_ptr;
|
||||
let id = try_ffi!(
|
||||
CString::new(hex::encode(&pkey.key_id())),
|
||||
"failed to allocate string"
|
||||
);
|
||||
|
||||
id.into_raw()
|
||||
}
|
||||
|
||||
/// Free the given [signed_public_key].
|
||||
pub unsafe fn rpgp_pkey_drop(pkey_ptr: *mut signed_public_key) {
|
||||
assert!(!pkey_ptr.is_null());
|
||||
|
||||
let _pkey = &*pkey_ptr;
|
||||
// Drop
|
||||
}
|
||||
@@ -1,194 +0,0 @@
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::io::Cursor;
|
||||
use std::slice;
|
||||
|
||||
use libc::c_char;
|
||||
use pgp::composed::{
|
||||
Deserializable, KeyType, SecretKeyParamsBuilder, SignedSecretKey, SubkeyParamsBuilder,
|
||||
};
|
||||
use pgp::crypto::{HashAlgorithm, SymmetricKeyAlgorithm};
|
||||
use pgp::errors::Result;
|
||||
use pgp::ser::Serialize;
|
||||
use pgp::types::{CompressionAlgorithm, KeyTrait, SecretKeyTrait};
|
||||
use smallvec::smallvec;
|
||||
|
||||
use crate::pgp::cvec;
|
||||
use crate::pgp::signed_public_key;
|
||||
|
||||
pub type signed_secret_key = SignedSecretKey;
|
||||
|
||||
/// Generates a new RSA key.
|
||||
pub unsafe fn rpgp_create_rsa_skey(bits: u32, user_id: *const c_char) -> *mut signed_secret_key {
|
||||
assert!(!user_id.is_null());
|
||||
|
||||
let user_id = CStr::from_ptr(user_id);
|
||||
let user_id_str = try_ffi!(user_id.to_str(), "invalid user id");
|
||||
|
||||
let key = try_ffi!(
|
||||
create_key(KeyType::Rsa(bits), KeyType::Rsa(bits), user_id_str),
|
||||
"failed to generate key"
|
||||
);
|
||||
|
||||
Box::into_raw(Box::new(key))
|
||||
}
|
||||
|
||||
/// Generates a new x25519 key.
|
||||
#[allow(dead_code)]
|
||||
pub unsafe fn rpgp_create_x25519_skey(user_id: *const c_char) -> *mut signed_secret_key {
|
||||
assert!(!user_id.is_null());
|
||||
|
||||
let user_id = CStr::from_ptr(user_id);
|
||||
let user_id_str = try_ffi!(user_id.to_str(), "invalid user id");
|
||||
let key = try_ffi!(
|
||||
create_key(KeyType::EdDSA, KeyType::ECDH, user_id_str),
|
||||
"failed to generate key"
|
||||
);
|
||||
|
||||
Box::into_raw(Box::new(key))
|
||||
}
|
||||
|
||||
/// Serialize a secret key into its byte representation.
|
||||
pub unsafe fn rpgp_skey_to_bytes(skey_ptr: *mut signed_secret_key) -> *mut cvec {
|
||||
assert!(!skey_ptr.is_null());
|
||||
|
||||
let skey = &*skey_ptr;
|
||||
|
||||
let mut res = Vec::new();
|
||||
try_ffi!(skey.to_writer(&mut res), "failed to serialize key");
|
||||
|
||||
Box::into_raw(Box::new(res.into()))
|
||||
}
|
||||
|
||||
/// Get the signed public key matching the given private key. Only works for non password protected keys.
|
||||
pub unsafe fn rpgp_skey_public_key(skey_ptr: *mut signed_secret_key) -> *mut signed_public_key {
|
||||
assert!(!skey_ptr.is_null());
|
||||
|
||||
let skey = &*skey_ptr;
|
||||
|
||||
let pkey = skey.public_key();
|
||||
let signed_pkey = try_ffi!(pkey.sign(&skey, || "".into()), "failed to sign key");
|
||||
|
||||
Box::into_raw(Box::new(signed_pkey))
|
||||
}
|
||||
|
||||
/// Returns the KeyID for the passed in key.
|
||||
#[allow(dead_code)]
|
||||
pub unsafe fn rpgp_skey_key_id(skey_ptr: *mut signed_secret_key) -> *mut c_char {
|
||||
assert!(!skey_ptr.is_null());
|
||||
|
||||
let key = &*skey_ptr;
|
||||
let id = try_ffi!(
|
||||
CString::new(hex::encode(&key.key_id())),
|
||||
"failed to allocate string"
|
||||
);
|
||||
|
||||
id.into_raw()
|
||||
}
|
||||
|
||||
/// Free the memory of a secret key.
|
||||
pub unsafe fn rpgp_skey_drop(skey_ptr: *mut signed_secret_key) {
|
||||
assert!(!skey_ptr.is_null());
|
||||
|
||||
let _skey = &*skey_ptr;
|
||||
// Drop
|
||||
}
|
||||
|
||||
/// Creates an in-memory representation of a Secret PGP key, based on the serialized bytes given.
|
||||
pub unsafe fn rpgp_skey_from_bytes(raw: *const u8, len: libc::size_t) -> *mut signed_secret_key {
|
||||
assert!(!raw.is_null());
|
||||
assert!(len > 0);
|
||||
|
||||
let bytes = slice::from_raw_parts(raw, len);
|
||||
let key = try_ffi!(
|
||||
SignedSecretKey::from_bytes(Cursor::new(bytes)),
|
||||
"invalid secret key"
|
||||
);
|
||||
try_ffi!(key.verify(), "failed to verify key");
|
||||
|
||||
Box::into_raw(Box::new(key))
|
||||
}
|
||||
|
||||
fn create_key(typ: KeyType, sub_typ: KeyType, user_id: &str) -> Result<SignedSecretKey> {
|
||||
let key_params = SecretKeyParamsBuilder::default()
|
||||
.key_type(typ)
|
||||
.can_create_certificates(true)
|
||||
.can_sign(true)
|
||||
.primary_user_id(user_id.into())
|
||||
.passphrase(None)
|
||||
.preferred_symmetric_algorithms(smallvec![
|
||||
SymmetricKeyAlgorithm::AES256,
|
||||
SymmetricKeyAlgorithm::AES192,
|
||||
SymmetricKeyAlgorithm::AES128,
|
||||
])
|
||||
.preferred_hash_algorithms(smallvec![
|
||||
HashAlgorithm::SHA2_256,
|
||||
HashAlgorithm::SHA2_384,
|
||||
HashAlgorithm::SHA2_512,
|
||||
HashAlgorithm::SHA2_224,
|
||||
HashAlgorithm::SHA1,
|
||||
])
|
||||
.preferred_compression_algorithms(smallvec![
|
||||
CompressionAlgorithm::ZLIB,
|
||||
CompressionAlgorithm::ZIP,
|
||||
])
|
||||
.subkey(
|
||||
SubkeyParamsBuilder::default()
|
||||
.key_type(sub_typ)
|
||||
.can_encrypt(true)
|
||||
.passphrase(None)
|
||||
.build()
|
||||
.unwrap(),
|
||||
)
|
||||
.build()?;
|
||||
|
||||
let key = key_params.generate()?;
|
||||
|
||||
key.sign(|| "".into())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::pgp::*;
|
||||
use std::ffi::CStr;
|
||||
use std::slice;
|
||||
|
||||
use pgp::composed::{Deserializable, SignedPublicKey, SignedSecretKey};
|
||||
|
||||
#[test]
|
||||
fn test_keygen_rsa() {
|
||||
let user_id = CStr::from_bytes_with_nul(b"<hello@world.com>\0").unwrap();
|
||||
|
||||
unsafe {
|
||||
/* Create the actual key */
|
||||
let skey = rpgp_create_rsa_skey(2048, user_id.as_ptr());
|
||||
|
||||
/* Serialize secret key into bytes */
|
||||
let skey_bytes = rpgp_skey_to_bytes(skey);
|
||||
|
||||
/* Get the public key */
|
||||
let pkey = rpgp_skey_public_key(skey);
|
||||
|
||||
/* Serialize public key into bytes */
|
||||
let pkey_bytes = rpgp_pkey_to_bytes(pkey);
|
||||
|
||||
let skey_bytes_vec =
|
||||
slice::from_raw_parts(rpgp_cvec_data(skey_bytes), rpgp_cvec_len(skey_bytes));
|
||||
let skey_back =
|
||||
SignedSecretKey::from_bytes(skey_bytes_vec).expect("invalid secret key");
|
||||
assert_eq!(&*skey, &skey_back);
|
||||
|
||||
let pkey_bytes_vec =
|
||||
slice::from_raw_parts(rpgp_cvec_data(pkey_bytes), rpgp_cvec_len(pkey_bytes));
|
||||
let pkey_back =
|
||||
SignedPublicKey::from_bytes(pkey_bytes_vec).expect("invalid public key");
|
||||
assert_eq!(&*pkey, &pkey_back);
|
||||
|
||||
/* cleanup */
|
||||
rpgp_skey_drop(skey);
|
||||
rpgp_cvec_drop(skey_bytes);
|
||||
rpgp_pkey_drop(pkey);
|
||||
rpgp_cvec_drop(pkey_bytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
739
tests/stress.rs
739
tests/stress.rs
@@ -2150,553 +2150,7 @@ unsafe fn stress_functions(context: &dc_context_t) {
|
||||
free(setupfile as *mut libc::c_void);
|
||||
free(setupcode as *mut libc::c_void);
|
||||
}
|
||||
let bad_key: *mut dc_key_t = dc_key_new();
|
||||
let mut bad_data: [libc::c_uchar; 4096] = [0; 4096];
|
||||
let mut i_0: libc::c_int = 0i32;
|
||||
while i_0 < 4096i32 {
|
||||
bad_data[i_0 as usize] = (i_0 & 0xffi32) as libc::c_uchar;
|
||||
i_0 += 1
|
||||
}
|
||||
let mut j: libc::c_int = 0i32;
|
||||
while j < 4096i32 / 40i32 {
|
||||
dc_key_set_from_binary(
|
||||
bad_key,
|
||||
&mut *bad_data.as_mut_ptr().offset(j as isize) as *mut libc::c_uchar
|
||||
as *const libc::c_void,
|
||||
4096i32 / 2i32 + j,
|
||||
if 0 != j & 1i32 { 0i32 } else { 1i32 },
|
||||
);
|
||||
if 0 != (0 != dc_pgp_is_valid_key(context, bad_key)) as libc::c_int as libc::c_long {
|
||||
__assert_rtn(
|
||||
(*::std::mem::transmute::<&[u8; 17], &[libc::c_char; 17]>(b"stress_functions\x00"))
|
||||
.as_ptr(),
|
||||
b"../cmdline/stress.c\x00" as *const u8 as *const libc::c_char,
|
||||
941i32,
|
||||
b"!dc_pgp_is_valid_key(context, bad_key)\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
} else {
|
||||
};
|
||||
j += 1
|
||||
}
|
||||
dc_key_unref(bad_key);
|
||||
let public_key: *mut dc_key_t = dc_key_new();
|
||||
let private_key: *mut dc_key_t = dc_key_new();
|
||||
dc_pgp_create_keypair(
|
||||
context,
|
||||
b"foo@bar.de\x00" as *const u8 as *const libc::c_char,
|
||||
public_key,
|
||||
private_key,
|
||||
);
|
||||
if 0 != (0 == dc_pgp_is_valid_key(context, public_key)) as libc::c_int as libc::c_long {
|
||||
__assert_rtn(
|
||||
(*::std::mem::transmute::<&[u8; 17], &[libc::c_char; 17]>(b"stress_functions\x00"))
|
||||
.as_ptr(),
|
||||
b"../cmdline/stress.c\x00" as *const u8 as *const libc::c_char,
|
||||
949i32,
|
||||
b"dc_pgp_is_valid_key(context, public_key)\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
} else {
|
||||
};
|
||||
if 0 != (0 == dc_pgp_is_valid_key(context, private_key)) as libc::c_int as libc::c_long {
|
||||
__assert_rtn(
|
||||
(*::std::mem::transmute::<&[u8; 17], &[libc::c_char; 17]>(b"stress_functions\x00"))
|
||||
.as_ptr(),
|
||||
b"../cmdline/stress.c\x00" as *const u8 as *const libc::c_char,
|
||||
950i32,
|
||||
b"dc_pgp_is_valid_key(context, private_key)\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
} else {
|
||||
};
|
||||
let test_key: *mut dc_key_t = dc_key_new();
|
||||
if 0 != (0 == dc_pgp_split_key(context, private_key, test_key)) as libc::c_int as libc::c_long {
|
||||
__assert_rtn(
|
||||
(*::std::mem::transmute::<&[u8; 17], &[libc::c_char; 17]>(b"stress_functions\x00"))
|
||||
.as_ptr(),
|
||||
b"../cmdline/stress.c\x00" as *const u8 as *const libc::c_char,
|
||||
956i32,
|
||||
b"dc_pgp_split_key(context, private_key, test_key)\x00" as *const u8
|
||||
as *const libc::c_char,
|
||||
);
|
||||
} else {
|
||||
};
|
||||
dc_key_unref(test_key);
|
||||
let public_key2: *mut dc_key_t = dc_key_new();
|
||||
let private_key2: *mut dc_key_t = dc_key_new();
|
||||
dc_pgp_create_keypair(
|
||||
context,
|
||||
b"two@zwo.de\x00" as *const u8 as *const libc::c_char,
|
||||
public_key2,
|
||||
private_key2,
|
||||
);
|
||||
if 0 != (0 != dc_key_equals(public_key, public_key2)) as libc::c_int as libc::c_long {
|
||||
__assert_rtn(
|
||||
(*::std::mem::transmute::<&[u8; 17], &[libc::c_char; 17]>(b"stress_functions\x00"))
|
||||
.as_ptr(),
|
||||
b"../cmdline/stress.c\x00" as *const u8 as *const libc::c_char,
|
||||
964i32,
|
||||
b"!dc_key_equals(public_key, public_key2)\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
} else {
|
||||
};
|
||||
let original_text: *const libc::c_char =
|
||||
b"This is a test\x00" as *const u8 as *const libc::c_char;
|
||||
let mut ctext_signed: *mut libc::c_void = 0 as *mut libc::c_void;
|
||||
let mut ctext_unsigned: *mut libc::c_void = 0 as *mut libc::c_void;
|
||||
let mut ctext_signed_bytes: size_t = 0i32 as size_t;
|
||||
let mut ctext_unsigned_bytes: size_t = 0;
|
||||
let mut plain_bytes: size_t = 0i32 as size_t;
|
||||
let keyring: *mut dc_keyring_t = dc_keyring_new();
|
||||
dc_keyring_add(keyring, public_key);
|
||||
dc_keyring_add(keyring, public_key2);
|
||||
let mut ok_0: libc::c_int = dc_pgp_pk_encrypt(
|
||||
context,
|
||||
original_text as *const libc::c_void,
|
||||
strlen(original_text),
|
||||
keyring,
|
||||
private_key,
|
||||
1i32,
|
||||
&mut ctext_signed as *mut *mut libc::c_void,
|
||||
&mut ctext_signed_bytes,
|
||||
);
|
||||
if 0 != !(0 != ok_0 && !ctext_signed.is_null() && ctext_signed_bytes > 0) as libc::c_int
|
||||
as libc::c_long
|
||||
{
|
||||
__assert_rtn(
|
||||
(*::std::mem::transmute::<&[u8; 17], &[libc::c_char; 17]>(b"stress_functions\x00"))
|
||||
.as_ptr(),
|
||||
b"../cmdline/stress.c\x00" as *const u8 as *const libc::c_char,
|
||||
975i32,
|
||||
b"ok && ctext_signed && ctext_signed_bytes>0\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
} else {
|
||||
};
|
||||
if 0 != !(strncmp(
|
||||
ctext_signed as *mut libc::c_char,
|
||||
b"-----BEGIN PGP MESSAGE-----\x00" as *const u8 as *const libc::c_char,
|
||||
27,
|
||||
) == 0i32) as libc::c_int as libc::c_long
|
||||
{
|
||||
__assert_rtn(
|
||||
(*::std::mem::transmute::<&[u8; 17], &[libc::c_char; 17]>(b"stress_functions\x00"))
|
||||
.as_ptr(),
|
||||
b"../cmdline/stress.c\x00" as *const u8 as *const libc::c_char,
|
||||
976i32,
|
||||
b"strncmp((char*)ctext_signed, \"-----BEGIN PGP MESSAGE-----\", 27)==0\x00" as *const u8
|
||||
as *const libc::c_char,
|
||||
);
|
||||
} else {
|
||||
};
|
||||
if 0 != !(*(ctext_signed as *mut libc::c_char)
|
||||
.offset(ctext_signed_bytes.wrapping_sub(1) as isize) as libc::c_int
|
||||
!= 0i32) as libc::c_int as libc::c_long
|
||||
{
|
||||
__assert_rtn(
|
||||
(*::std::mem::transmute::<&[u8; 17], &[libc::c_char; 17]>(b"stress_functions\x00"))
|
||||
.as_ptr(),
|
||||
b"../cmdline/stress.c\x00" as *const u8 as *const libc::c_char,
|
||||
977i32,
|
||||
b"((char*)ctext_signed)[ctext_signed_bytes-1]!=0\x00" as *const u8
|
||||
as *const libc::c_char,
|
||||
);
|
||||
} else {
|
||||
};
|
||||
ok_0 = dc_pgp_pk_encrypt(
|
||||
context,
|
||||
original_text as *const libc::c_void,
|
||||
strlen(original_text),
|
||||
keyring,
|
||||
0 as *const dc_key_t,
|
||||
1i32,
|
||||
&mut ctext_unsigned as *mut *mut libc::c_void,
|
||||
&mut ctext_unsigned_bytes,
|
||||
);
|
||||
if 0 != !(0 != ok_0 && !ctext_unsigned.is_null() && ctext_unsigned_bytes > 0) as libc::c_int
|
||||
as libc::c_long
|
||||
{
|
||||
__assert_rtn(
|
||||
(*::std::mem::transmute::<&[u8; 17], &[libc::c_char; 17]>(b"stress_functions\x00"))
|
||||
.as_ptr(),
|
||||
b"../cmdline/stress.c\x00" as *const u8 as *const libc::c_char,
|
||||
981i32,
|
||||
b"ok && ctext_unsigned && ctext_unsigned_bytes>0\x00" as *const u8
|
||||
as *const libc::c_char,
|
||||
);
|
||||
} else {
|
||||
};
|
||||
if 0 != !(strncmp(
|
||||
ctext_unsigned as *mut libc::c_char,
|
||||
b"-----BEGIN PGP MESSAGE-----\x00" as *const u8 as *const libc::c_char,
|
||||
27,
|
||||
) == 0i32) as libc::c_int as libc::c_long
|
||||
{
|
||||
__assert_rtn(
|
||||
(*::std::mem::transmute::<&[u8; 17], &[libc::c_char; 17]>(b"stress_functions\x00"))
|
||||
.as_ptr(),
|
||||
b"../cmdline/stress.c\x00" as *const u8 as *const libc::c_char,
|
||||
982i32,
|
||||
b"strncmp((char*)ctext_unsigned, \"-----BEGIN PGP MESSAGE-----\", 27)==0\x00"
|
||||
as *const u8 as *const libc::c_char,
|
||||
);
|
||||
} else {
|
||||
};
|
||||
if 0 != !(ctext_unsigned_bytes < ctext_signed_bytes) as libc::c_int as libc::c_long {
|
||||
__assert_rtn(
|
||||
(*::std::mem::transmute::<&[u8; 17], &[libc::c_char; 17]>(b"stress_functions\x00"))
|
||||
.as_ptr(),
|
||||
b"../cmdline/stress.c\x00" as *const u8 as *const libc::c_char,
|
||||
983i32,
|
||||
b"ctext_unsigned_bytes < ctext_signed_bytes\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
} else {
|
||||
};
|
||||
dc_keyring_unref(keyring);
|
||||
let keyring_0: *mut dc_keyring_t = dc_keyring_new();
|
||||
dc_keyring_add(keyring_0, private_key);
|
||||
let public_keyring: *mut dc_keyring_t = dc_keyring_new();
|
||||
dc_keyring_add(public_keyring, public_key);
|
||||
let public_keyring2: *mut dc_keyring_t = dc_keyring_new();
|
||||
dc_keyring_add(public_keyring2, public_key2);
|
||||
let mut plain_0: *mut libc::c_void = 0 as *mut libc::c_void;
|
||||
let mut valid_signatures: dc_hash_t = dc_hash_t {
|
||||
keyClass: 0,
|
||||
copyKey: 0,
|
||||
count: 0,
|
||||
first: 0 as *mut dc_hashelem_t,
|
||||
htsize: 0,
|
||||
ht: 0 as *mut _ht,
|
||||
};
|
||||
dc_hash_init(&mut valid_signatures, 3i32, 1i32);
|
||||
let mut ok_1: libc::c_int;
|
||||
ok_1 = dc_pgp_pk_decrypt(
|
||||
context,
|
||||
ctext_signed,
|
||||
ctext_signed_bytes,
|
||||
keyring_0,
|
||||
public_keyring,
|
||||
1i32,
|
||||
&mut plain_0,
|
||||
&mut plain_bytes,
|
||||
&mut valid_signatures,
|
||||
);
|
||||
if 0 != !(0 != ok_1 && !plain_0.is_null() && plain_bytes > 0) as libc::c_int as libc::c_long {
|
||||
__assert_rtn(
|
||||
(*::std::mem::transmute::<&[u8; 17], &[libc::c_char; 17]>(b"stress_functions\x00"))
|
||||
.as_ptr(),
|
||||
b"../cmdline/stress.c\x00" as *const u8 as *const libc::c_char,
|
||||
1004i32,
|
||||
b"ok && plain && plain_bytes>0\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
} else {
|
||||
};
|
||||
if 0 != !(strncmp(
|
||||
plain_0 as *mut libc::c_char,
|
||||
original_text,
|
||||
strlen(original_text),
|
||||
) == 0i32) as libc::c_int as libc::c_long
|
||||
{
|
||||
__assert_rtn(
|
||||
(*::std::mem::transmute::<&[u8; 17], &[libc::c_char; 17]>(b"stress_functions\x00"))
|
||||
.as_ptr(),
|
||||
b"../cmdline/stress.c\x00" as *const u8 as *const libc::c_char,
|
||||
1005i32,
|
||||
b"strncmp((char*)plain, original_text, strlen(original_text))==0\x00" as *const u8
|
||||
as *const libc::c_char,
|
||||
);
|
||||
} else {
|
||||
};
|
||||
if 0 != !(valid_signatures.count == 1i32) as libc::c_int as libc::c_long {
|
||||
__assert_rtn(
|
||||
(*::std::mem::transmute::<&[u8; 17], &[libc::c_char; 17]>(b"stress_functions\x00"))
|
||||
.as_ptr(),
|
||||
b"../cmdline/stress.c\x00" as *const u8 as *const libc::c_char,
|
||||
1006i32,
|
||||
b"dc_hash_cnt(&valid_signatures) == 1\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
} else {
|
||||
};
|
||||
free(plain_0);
|
||||
plain_0 = 0 as *mut libc::c_void;
|
||||
dc_hash_clear(&mut valid_signatures);
|
||||
ok_1 = dc_pgp_pk_decrypt(
|
||||
context,
|
||||
ctext_signed,
|
||||
ctext_signed_bytes,
|
||||
keyring_0,
|
||||
0 as *const dc_keyring_t,
|
||||
1i32,
|
||||
&mut plain_0,
|
||||
&mut plain_bytes,
|
||||
&mut valid_signatures,
|
||||
);
|
||||
if 0 != !(0 != ok_1 && !plain_0.is_null() && plain_bytes > 0) as libc::c_int as libc::c_long {
|
||||
__assert_rtn(
|
||||
(*::std::mem::transmute::<&[u8; 17], &[libc::c_char; 17]>(b"stress_functions\x00"))
|
||||
.as_ptr(),
|
||||
b"../cmdline/stress.c\x00" as *const u8 as *const libc::c_char,
|
||||
1011i32,
|
||||
b"ok && plain && plain_bytes>0\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
} else {
|
||||
};
|
||||
if 0 != !(strncmp(
|
||||
plain_0 as *mut libc::c_char,
|
||||
original_text,
|
||||
strlen(original_text),
|
||||
) == 0i32) as libc::c_int as libc::c_long
|
||||
{
|
||||
__assert_rtn(
|
||||
(*::std::mem::transmute::<&[u8; 17], &[libc::c_char; 17]>(b"stress_functions\x00"))
|
||||
.as_ptr(),
|
||||
b"../cmdline/stress.c\x00" as *const u8 as *const libc::c_char,
|
||||
1012i32,
|
||||
b"strncmp((char*)plain, original_text, strlen(original_text))==0\x00" as *const u8
|
||||
as *const libc::c_char,
|
||||
);
|
||||
} else {
|
||||
};
|
||||
if 0 != !(valid_signatures.count == 0i32) as libc::c_int as libc::c_long {
|
||||
__assert_rtn(
|
||||
(*::std::mem::transmute::<&[u8; 17], &[libc::c_char; 17]>(b"stress_functions\x00"))
|
||||
.as_ptr(),
|
||||
b"../cmdline/stress.c\x00" as *const u8 as *const libc::c_char,
|
||||
1013i32,
|
||||
b"dc_hash_cnt(&valid_signatures) == 0\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
} else {
|
||||
};
|
||||
free(plain_0);
|
||||
plain_0 = 0 as *mut libc::c_void;
|
||||
dc_hash_clear(&mut valid_signatures);
|
||||
ok_1 = dc_pgp_pk_decrypt(
|
||||
context,
|
||||
ctext_signed,
|
||||
ctext_signed_bytes,
|
||||
keyring_0,
|
||||
public_keyring2,
|
||||
1i32,
|
||||
&mut plain_0,
|
||||
&mut plain_bytes,
|
||||
&mut valid_signatures,
|
||||
);
|
||||
if 0 != !(0 != ok_1 && !plain_0.is_null() && plain_bytes > 0) as libc::c_int as libc::c_long {
|
||||
__assert_rtn(
|
||||
(*::std::mem::transmute::<&[u8; 17], &[libc::c_char; 17]>(b"stress_functions\x00"))
|
||||
.as_ptr(),
|
||||
b"../cmdline/stress.c\x00" as *const u8 as *const libc::c_char,
|
||||
1018i32,
|
||||
b"ok && plain && plain_bytes>0\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
} else {
|
||||
};
|
||||
if 0 != !(strncmp(
|
||||
plain_0 as *mut libc::c_char,
|
||||
original_text,
|
||||
strlen(original_text),
|
||||
) == 0i32) as libc::c_int as libc::c_long
|
||||
{
|
||||
__assert_rtn(
|
||||
(*::std::mem::transmute::<&[u8; 17], &[libc::c_char; 17]>(b"stress_functions\x00"))
|
||||
.as_ptr(),
|
||||
b"../cmdline/stress.c\x00" as *const u8 as *const libc::c_char,
|
||||
1019i32,
|
||||
b"strncmp((char*)plain, original_text, strlen(original_text))==0\x00" as *const u8
|
||||
as *const libc::c_char,
|
||||
);
|
||||
} else {
|
||||
};
|
||||
if 0 != !(valid_signatures.count == 0i32) as libc::c_int as libc::c_long {
|
||||
__assert_rtn(
|
||||
(*::std::mem::transmute::<&[u8; 17], &[libc::c_char; 17]>(b"stress_functions\x00"))
|
||||
.as_ptr(),
|
||||
b"../cmdline/stress.c\x00" as *const u8 as *const libc::c_char,
|
||||
1020i32,
|
||||
b"dc_hash_cnt(&valid_signatures) == 0\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
} else {
|
||||
};
|
||||
free(plain_0);
|
||||
plain_0 = 0 as *mut libc::c_void;
|
||||
dc_hash_clear(&mut valid_signatures);
|
||||
dc_keyring_add(public_keyring2, public_key);
|
||||
ok_1 = dc_pgp_pk_decrypt(
|
||||
context,
|
||||
ctext_signed,
|
||||
ctext_signed_bytes,
|
||||
keyring_0,
|
||||
public_keyring2,
|
||||
1i32,
|
||||
&mut plain_0,
|
||||
&mut plain_bytes,
|
||||
&mut valid_signatures,
|
||||
);
|
||||
if 0 != !(0 != ok_1 && !plain_0.is_null() && plain_bytes > 0) as libc::c_int as libc::c_long {
|
||||
__assert_rtn(
|
||||
(*::std::mem::transmute::<&[u8; 17], &[libc::c_char; 17]>(b"stress_functions\x00"))
|
||||
.as_ptr(),
|
||||
b"../cmdline/stress.c\x00" as *const u8 as *const libc::c_char,
|
||||
1026i32,
|
||||
b"ok && plain && plain_bytes>0\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
} else {
|
||||
};
|
||||
if 0 != !(strncmp(
|
||||
plain_0 as *mut libc::c_char,
|
||||
original_text,
|
||||
strlen(original_text),
|
||||
) == 0i32) as libc::c_int as libc::c_long
|
||||
{
|
||||
__assert_rtn(
|
||||
(*::std::mem::transmute::<&[u8; 17], &[libc::c_char; 17]>(b"stress_functions\x00"))
|
||||
.as_ptr(),
|
||||
b"../cmdline/stress.c\x00" as *const u8 as *const libc::c_char,
|
||||
1027i32,
|
||||
b"strncmp((char*)plain, original_text, strlen(original_text))==0\x00" as *const u8
|
||||
as *const libc::c_char,
|
||||
);
|
||||
} else {
|
||||
};
|
||||
if 0 != !(valid_signatures.count == 1i32) as libc::c_int as libc::c_long {
|
||||
__assert_rtn(
|
||||
(*::std::mem::transmute::<&[u8; 17], &[libc::c_char; 17]>(b"stress_functions\x00"))
|
||||
.as_ptr(),
|
||||
b"../cmdline/stress.c\x00" as *const u8 as *const libc::c_char,
|
||||
1028i32,
|
||||
b"dc_hash_cnt(&valid_signatures) == 1\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
} else {
|
||||
};
|
||||
free(plain_0);
|
||||
plain_0 = 0 as *mut libc::c_void;
|
||||
dc_hash_clear(&mut valid_signatures);
|
||||
ok_1 = dc_pgp_pk_decrypt(
|
||||
context,
|
||||
ctext_unsigned,
|
||||
ctext_unsigned_bytes,
|
||||
keyring_0,
|
||||
public_keyring,
|
||||
1i32,
|
||||
&mut plain_0,
|
||||
&mut plain_bytes,
|
||||
&mut valid_signatures,
|
||||
);
|
||||
if 0 != !(0 != ok_1 && !plain_0.is_null() && plain_bytes > 0) as libc::c_int as libc::c_long {
|
||||
__assert_rtn(
|
||||
(*::std::mem::transmute::<&[u8; 17], &[libc::c_char; 17]>(b"stress_functions\x00"))
|
||||
.as_ptr(),
|
||||
b"../cmdline/stress.c\x00" as *const u8 as *const libc::c_char,
|
||||
1033i32,
|
||||
b"ok && plain && plain_bytes>0\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
} else {
|
||||
};
|
||||
if 0 != !(strncmp(
|
||||
plain_0 as *mut libc::c_char,
|
||||
original_text,
|
||||
strlen(original_text),
|
||||
) == 0i32) as libc::c_int as libc::c_long
|
||||
{
|
||||
__assert_rtn(
|
||||
(*::std::mem::transmute::<&[u8; 17], &[libc::c_char; 17]>(b"stress_functions\x00"))
|
||||
.as_ptr(),
|
||||
b"../cmdline/stress.c\x00" as *const u8 as *const libc::c_char,
|
||||
1034i32,
|
||||
b"strncmp((char*)plain, original_text, strlen(original_text))==0\x00" as *const u8
|
||||
as *const libc::c_char,
|
||||
);
|
||||
} else {
|
||||
};
|
||||
free(plain_0);
|
||||
dc_hash_clear(&mut valid_signatures);
|
||||
dc_keyring_unref(keyring_0);
|
||||
dc_keyring_unref(public_keyring);
|
||||
dc_keyring_unref(public_keyring2);
|
||||
let keyring_1: *mut dc_keyring_t = dc_keyring_new();
|
||||
dc_keyring_add(keyring_1, private_key2);
|
||||
let public_keyring_0: *mut dc_keyring_t = dc_keyring_new();
|
||||
dc_keyring_add(public_keyring_0, public_key);
|
||||
let mut plain_1: *mut libc::c_void = 0 as *mut libc::c_void;
|
||||
let ok_2: libc::c_int = dc_pgp_pk_decrypt(
|
||||
context,
|
||||
ctext_signed,
|
||||
ctext_signed_bytes,
|
||||
keyring_1,
|
||||
public_keyring_0,
|
||||
1i32,
|
||||
&mut plain_1,
|
||||
&mut plain_bytes,
|
||||
0 as *mut dc_hash_t,
|
||||
);
|
||||
if 0 != !(0 != ok_2 && !plain_1.is_null() && plain_bytes > 0) as libc::c_int as libc::c_long {
|
||||
__assert_rtn(
|
||||
(*::std::mem::transmute::<&[u8; 17], &[libc::c_char; 17]>(b"stress_functions\x00"))
|
||||
.as_ptr(),
|
||||
b"../cmdline/stress.c\x00" as *const u8 as *const libc::c_char,
|
||||
1053i32,
|
||||
b"ok && plain && plain_bytes>0\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
} else {
|
||||
};
|
||||
if 0 != !(plain_bytes == strlen(original_text)) as libc::c_int as libc::c_long {
|
||||
__assert_rtn(
|
||||
(*::std::mem::transmute::<&[u8; 17], &[libc::c_char; 17]>(b"stress_functions\x00"))
|
||||
.as_ptr(),
|
||||
b"../cmdline/stress.c\x00" as *const u8 as *const libc::c_char,
|
||||
1054i32,
|
||||
b"plain_bytes == strlen(original_text)\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
} else {
|
||||
};
|
||||
if 0 != !(strncmp(plain_1 as *const libc::c_char, original_text, plain_bytes) == 0i32)
|
||||
as libc::c_int as libc::c_long
|
||||
{
|
||||
__assert_rtn(
|
||||
(*::std::mem::transmute::<&[u8; 17], &[libc::c_char; 17]>(b"stress_functions\x00"))
|
||||
.as_ptr(),
|
||||
b"../cmdline/stress.c\x00" as *const u8 as *const libc::c_char,
|
||||
1055i32,
|
||||
b"strncmp(plain, original_text, plain_bytes)==0\x00" as *const u8
|
||||
as *const libc::c_char,
|
||||
);
|
||||
} else {
|
||||
};
|
||||
free(plain_1);
|
||||
dc_keyring_unref(keyring_1);
|
||||
dc_keyring_unref(public_keyring_0);
|
||||
free(ctext_signed);
|
||||
free(ctext_unsigned);
|
||||
dc_key_unref(public_key2);
|
||||
dc_key_unref(private_key2);
|
||||
dc_key_unref(public_key);
|
||||
dc_key_unref(private_key);
|
||||
let fingerprint: *mut libc::c_char = dc_normalize_fingerprint(
|
||||
b" 1234 567890 \n AbcD abcdef ABCDEF \x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
if 0 != fingerprint.is_null() as libc::c_int as libc::c_long {
|
||||
__assert_rtn(
|
||||
(*::std::mem::transmute::<&[u8; 17], &[libc::c_char; 17]>(b"stress_functions\x00"))
|
||||
.as_ptr(),
|
||||
b"../cmdline/stress.c\x00" as *const u8 as *const libc::c_char,
|
||||
1076i32,
|
||||
b"fingerprint\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
} else {
|
||||
};
|
||||
if 0 != !(strcmp(
|
||||
fingerprint,
|
||||
b"1234567890ABCDABCDEFABCDEF\x00" as *const u8 as *const libc::c_char,
|
||||
) == 0i32) as libc::c_int as libc::c_long
|
||||
{
|
||||
__assert_rtn(
|
||||
(*::std::mem::transmute::<&[u8; 17], &[libc::c_char; 17]>(b"stress_functions\x00"))
|
||||
.as_ptr(),
|
||||
b"../cmdline/stress.c\x00" as *const u8 as *const libc::c_char,
|
||||
1077i32,
|
||||
b"strcmp(fingerprint, \"1234567890ABCDABCDEFABCDEF\") == 0\x00" as *const u8
|
||||
as *const libc::c_char,
|
||||
);
|
||||
} else {
|
||||
};
|
||||
free(fingerprint as *mut libc::c_void);
|
||||
|
||||
if 0 != dc_is_configured(context) {
|
||||
let qr: *mut libc::c_char = dc_get_securejoin_qr(context, 0i32 as uint32_t);
|
||||
if 0 != !(strlen(qr) > 55
|
||||
@@ -2781,6 +2235,197 @@ unsafe fn stress_functions(context: &dc_context_t) {
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_encryption_decryption() {
|
||||
unsafe {
|
||||
let mut bad_data: [libc::c_uchar; 4096] = [0; 4096];
|
||||
let mut i_0: libc::c_int = 0i32;
|
||||
while i_0 < 4096i32 {
|
||||
bad_data[i_0 as usize] = (i_0 & 0xffi32) as libc::c_uchar;
|
||||
i_0 += 1
|
||||
}
|
||||
let mut j: libc::c_int = 0i32;
|
||||
|
||||
while j < 4096 / 40 {
|
||||
let bad_key = Key::from_binary(
|
||||
&mut *bad_data.as_mut_ptr().offset(j as isize) as *mut libc::c_uchar
|
||||
as *const libc::c_void,
|
||||
4096 / 2 + j,
|
||||
if 0 != j & 1 {
|
||||
KeyType::Public
|
||||
} else {
|
||||
KeyType::Private
|
||||
},
|
||||
);
|
||||
|
||||
assert!(bad_key.is_none());
|
||||
j += 1
|
||||
}
|
||||
|
||||
let (public_key, private_key) =
|
||||
dc_pgp_create_keypair(b"foo@bar.de\x00" as *const u8 as *const libc::c_char).unwrap();
|
||||
|
||||
private_key.split_key().unwrap();
|
||||
|
||||
let (public_key2, private_key2) =
|
||||
dc_pgp_create_keypair(b"two@zwo.de\x00" as *const u8 as *const libc::c_char).unwrap();
|
||||
|
||||
assert_ne!(public_key, public_key2);
|
||||
|
||||
let original_text: *const libc::c_char =
|
||||
b"This is a test\x00" as *const u8 as *const libc::c_char;
|
||||
let mut keyring = Keyring::default();
|
||||
keyring.add(public_key.clone());
|
||||
keyring.add(public_key2.clone());
|
||||
|
||||
let ctext = dc_pgp_pk_encrypt(
|
||||
original_text as *const libc::c_void,
|
||||
strlen(original_text),
|
||||
&keyring,
|
||||
Some(&private_key),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert!(!ctext.is_empty());
|
||||
assert!(ctext.starts_with("-----BEGIN PGP MESSAGE-----"));
|
||||
|
||||
let ctext_signed_bytes = ctext.len();
|
||||
let ctext_signed = CString::new(ctext).unwrap();
|
||||
|
||||
let ctext = dc_pgp_pk_encrypt(
|
||||
original_text as *const libc::c_void,
|
||||
strlen(original_text),
|
||||
&keyring,
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
assert!(!ctext.is_empty());
|
||||
assert!(ctext.starts_with("-----BEGIN PGP MESSAGE-----"));
|
||||
|
||||
let ctext_unsigned_bytes = ctext.len();
|
||||
let ctext_unsigned = CString::new(ctext).unwrap();
|
||||
|
||||
let mut keyring = Keyring::default();
|
||||
keyring.add(private_key);
|
||||
|
||||
let mut public_keyring = Keyring::default();
|
||||
public_keyring.add(public_key.clone());
|
||||
|
||||
let mut public_keyring2 = Keyring::default();
|
||||
public_keyring2.add(public_key2.clone());
|
||||
|
||||
let mut valid_signatures = dc_hash_t {
|
||||
keyClass: 0,
|
||||
copyKey: 0,
|
||||
count: 0,
|
||||
first: 0 as *mut dc_hashelem_t,
|
||||
htsize: 0,
|
||||
ht: 0 as *mut _ht,
|
||||
};
|
||||
dc_hash_init(&mut valid_signatures, 3i32, 1i32);
|
||||
|
||||
let plain = dc_pgp_pk_decrypt(
|
||||
ctext_signed.as_ptr() as *const _,
|
||||
ctext_signed_bytes,
|
||||
&keyring,
|
||||
&public_keyring,
|
||||
&mut valid_signatures,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
std::str::from_utf8(&plain).unwrap(),
|
||||
CStr::from_ptr(original_text).to_str().unwrap()
|
||||
);
|
||||
assert_eq!(valid_signatures.count, 1);
|
||||
|
||||
dc_hash_clear(&mut valid_signatures);
|
||||
|
||||
let empty_keyring = Keyring::default();
|
||||
let plain = dc_pgp_pk_decrypt(
|
||||
ctext_signed.as_ptr() as *const _,
|
||||
ctext_signed_bytes,
|
||||
&keyring,
|
||||
&empty_keyring,
|
||||
&mut valid_signatures,
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
std::str::from_utf8(&plain).unwrap(),
|
||||
CStr::from_ptr(original_text).to_str().unwrap()
|
||||
);
|
||||
assert_eq!(valid_signatures.count, 0);
|
||||
|
||||
dc_hash_clear(&mut valid_signatures);
|
||||
|
||||
let plain = dc_pgp_pk_decrypt(
|
||||
ctext_signed.as_ptr() as *const _,
|
||||
ctext_signed_bytes,
|
||||
&keyring,
|
||||
&public_keyring2,
|
||||
&mut valid_signatures,
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
std::str::from_utf8(&plain).unwrap(),
|
||||
CStr::from_ptr(original_text).to_str().unwrap()
|
||||
);
|
||||
assert_eq!(valid_signatures.count, 0);
|
||||
|
||||
dc_hash_clear(&mut valid_signatures);
|
||||
|
||||
public_keyring2.add(public_key.clone());
|
||||
|
||||
let plain = dc_pgp_pk_decrypt(
|
||||
ctext_signed.as_ptr() as *const _,
|
||||
ctext_signed_bytes,
|
||||
&keyring,
|
||||
&public_keyring2,
|
||||
&mut valid_signatures,
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
std::str::from_utf8(&plain).unwrap(),
|
||||
CStr::from_ptr(original_text).to_str().unwrap()
|
||||
);
|
||||
assert_eq!(valid_signatures.count, 1);
|
||||
|
||||
dc_hash_clear(&mut valid_signatures);
|
||||
let plain = dc_pgp_pk_decrypt(
|
||||
ctext_unsigned.as_ptr() as *const _,
|
||||
ctext_unsigned_bytes,
|
||||
&keyring,
|
||||
&public_keyring,
|
||||
&mut valid_signatures,
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
std::str::from_utf8(&plain).unwrap(),
|
||||
CStr::from_ptr(original_text).to_str().unwrap()
|
||||
);
|
||||
|
||||
dc_hash_clear(&mut valid_signatures);
|
||||
|
||||
let mut keyring = Keyring::default();
|
||||
keyring.add(private_key2);
|
||||
let mut public_keyring = Keyring::default();
|
||||
public_keyring.add(public_key);
|
||||
|
||||
let plain = dc_pgp_pk_decrypt(
|
||||
ctext_signed.as_ptr() as *const _,
|
||||
ctext_signed_bytes,
|
||||
&keyring,
|
||||
&public_keyring,
|
||||
0 as *mut dc_hash_t,
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
std::str::from_utf8(&plain).unwrap(),
|
||||
CStr::from_ptr(original_text).to_str().unwrap()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "C" fn cb(
|
||||
_context: &dc_context_t,
|
||||
_event: Event,
|
||||
|
||||
Reference in New Issue
Block a user