diff --git a/src/constants.rs b/src/constants.rs index 688f91821..6d96701bf 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -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, } diff --git a/src/dc_aheader.rs b/src/dc_aheader.rs index f42ed6d33..bb32e6354 100644 --- a/src/dc_aheader.rs +++ b/src/dc_aheader.rs @@ -50,12 +50,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 +122,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={}", @@ -158,17 +158,7 @@ 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 - } + Some(raw) => Key::from_base64(raw, KeyType::Public), None => { return Err(()); } @@ -196,15 +186,6 @@ 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::*; diff --git a/src/dc_apeerstate.rs b/src/dc_apeerstate.rs index 29758bffb..8ef3b359f 100644 --- a/src/dc_apeerstate.rs +++ b/src/dc_apeerstate.rs @@ -17,7 +17,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,130 +24,128 @@ 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, pub public_key_fingerprint: *mut libc::c_char, - pub gossip_key: *mut dc_key_t, + pub gossip_key: Option, 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, 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::()) 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 { +pub unsafe fn dc_apeerstate_recalc_fingerprint(peerstate: &mut dc_apeerstate_t) -> libc::c_int { let mut success: libc::c_int = 0i32; 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(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 - { - (*peerstate).to_save |= 0x2i32; - if !old_gossip_fingerprint.is_null() - && 0 != *old_gossip_fingerprint.offset(0isize) as libc::c_int - { - (*peerstate).degrade_event |= 0x2i32 - } - } - } - success = 1i32 } + if let Some(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.degrade_event |= 0x2i32 + } + } + } + success = 1i32; + free(old_public_fingerprint as *mut libc::c_void); free(old_gossip_fingerprint as *mut libc::c_void); @@ -157,19 +154,15 @@ pub unsafe fn dc_apeerstate_recalc_fingerprint(mut peerstate: *mut dc_apeerstate // 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 +170,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 +197,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 == Some(header.public_key) { + peerstate.public_key = Some(header.public_key); 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 +237,86 @@ 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 == 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); - let rendered = header.to_string(); - let rendered_c = CString::new(rendered).unwrap(); - - libc::strdup(rendered_c.as_ptr()) - } else { - std::ptr::null_mut() + if peerstate.addr.is_null() { + return std::ptr::null_mut(); } + + let addr = CStr::from_ptr(peerstate.addr).to_str().unwrap().into(); + let key = dc_apeerstate_peek_key(peerstate, min_verified).clone(); + let header = Aheader::new(addr, key, EncryptPreference::NoPreference); + let rendered = header.to_string(); + let rendered_c = CString::new(rendered).unwrap(); + + libc::strdup(rendered_c.as_ptr()) } -pub unsafe fn dc_apeerstate_peek_key( - peerstate: *const dc_apeerstate_t, +pub unsafe fn dc_apeerstate_peek_key<'a>( + peerstate: &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 = Some(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 = Some(peerstate.gossip_key.clone()); + peerstate.verified_key_fingerprint = dc_strdup(peerstate.gossip_key_fingerprint); + success = 1 } } @@ -347,24 +325,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 +350,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, 0); } - 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, 0); + } + if sqlite3_column_type(stmt, 9) != 5 { + peerstate.verified_key = Key::from_stmt(stmt, 9, 0); } - 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 +404,104 @@ 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_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); sqlite3_bind_blob( stmt, - 4i32, - if !(*peerstate).public_key.is_null() { - (*(*peerstate).public_key).binary + 4, + 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 + if !peerstate.public_key.is_null() { + (*peerstate.public_key).bytes } else { - 0i32 + 0 }, None, ); - sqlite3_bind_int64(stmt, 5i32, (*peerstate).gossip_timestamp as sqlite3_int64); + sqlite3_bind_int64(stmt, 5, peerstate.gossip_timestamp as sqlite3_int64); sqlite3_bind_blob( stmt, - 6i32, - if !(*peerstate).gossip_key.is_null() { - (*(*peerstate).gossip_key).binary + 6, + 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 + if !peerstate.gossip_key.is_null() { + (*peerstate.gossip_key).bytes } else { - 0i32 + 0 }, 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_text(stmt, 7, peerstate.public_key_fingerprint, -1, None); + sqlite3_bind_text(stmt, 8, peerstate.gossip_key_fingerprint, -1, None); sqlite3_bind_blob( stmt, - 9i32, - if !(*peerstate).verified_key.is_null() { - (*(*peerstate).verified_key).binary + 9, + 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 + if !peerstate.verified_key.is_null() { + (*peerstate.verified_key).bytes } else { - 0i32 + 0 }, 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_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 +513,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 +527,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 diff --git a/src/dc_contact.rs b/src/dc_contact.rs index 1762ac468..23175d03c 100644 --- a/src/dc_contact.rs +++ b/src/dc_contact.rs @@ -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,14 @@ 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(), + (*loginparam).addr & context.sql.clone().read().unwrap(), ); - if !dc_apeerstate_peek_key(peerstate, 0i32).is_null() { + if !dc_apeerstate_peek_key(&peerstate, 0).is_null() { p = dc_stock_str( context, - if (*peerstate).prefer_encrypt == 1i32 { + if peerstate.prefer_encrypt == 1i32 { 34i32 } else { 25i32 @@ -812,11 +810,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 +823,18 @@ 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 + .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, ); @@ -874,7 +877,7 @@ pub unsafe fn dc_get_contact_encrinfo( dc_apeerstate_unref(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); diff --git a/src/dc_context.rs b/src/dc_context.rs index 21b06a684..8433dfbaf 100644 --- a/src/dc_context.rs +++ b/src/dc_context.rs @@ -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"\x00" as *const u8 as *const libc::c_char) + fingerprint_str = + dc_strdup(b"\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 } diff --git a/src/dc_e2ee.rs b/src/dc_e2ee.rs index 2ef64a25c..7a33fe716 100644 --- a/src/dc_e2ee.rs +++ b/src/dc_e2ee.rs @@ -62,7 +62,6 @@ pub unsafe fn dc_e2ee_encrypt( /*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 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; @@ -79,7 +78,6 @@ pub unsafe fn dc_e2ee_encrypt( || 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 +101,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 +117,22 @@ 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 peerstate = dc_apeerstate_new(context); if !(strcasecmp(recipient_addr, addr) == 0i32) { if 0 != dc_apeerstate_load_by_addr( 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) + { + dc_keyring_add(keyring, key_to_use); + dc_array_add_ptr(peerstates, &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 +145,18 @@ pub unsafe fn dc_e2ee_encrypt( } } } - if 0 != do_encrypt { + let sign_key = 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 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 } @@ -309,7 +309,7 @@ pub unsafe fn dc_e2ee_encrypt( (*plain).str_0 as *const libc::c_void, (*plain).len, keyring, - sign_key, + &sign_key, 1, &mut ctext as *mut *mut libc::c_char as *mut *mut libc::c_void, &mut ctext_bytes, @@ -389,7 +389,6 @@ pub unsafe fn dc_e2ee_encrypt( } dc_keyring_unref(keyring); - dc_key_unref(sign_key); if !plain.is_null() { mmap_string_free(plain); } @@ -513,123 +512,87 @@ 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 { +) -> Option { let mut current_block: u64; /* 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; + } + 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(context, self_addr) { + 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, + ); + } 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, + ); + } 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 = 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 */ @@ -1241,30 +1204,26 @@ 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( + + 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 diff --git a/src/dc_imex.rs b/src/dc_imex.rs index b5a8aca02..5dcfff805 100644 --- a/src/dc_imex.rs +++ b/src/dc_imex.rs @@ -3,7 +3,7 @@ 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 +288,11 @@ 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,27 +303,22 @@ 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() { + + 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 !(0 == dc_pgp_symm_encrypt( context, @@ -368,7 +363,7 @@ pub unsafe extern "C" fn dc_render_setup_file( } } 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); @@ -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,93 +518,94 @@ 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(buf_base64, KeyType::Private) + .and_then(|k| dc_pgp_split_key(context, &k).map(|pk| (k, pk))) + { + 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(), - ) { + 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( + 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 0 == 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 } @@ -1579,8 +1573,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,13 +1582,14 @@ 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, 1i32, KeyType::Public); + let private_key = Key::from_stmt(stmt, 2i32, KeyType::Private); + is_default = sqlite3_column_int(stmt, 3i32); - if 0 == export_key_to_asc_file(context, dir, id, public_key, is_default) { + if 0 == export_key_to_asc_file(context, dir, id, &public_key, is_default) { export_errors += 1 } - if 0 == export_key_to_asc_file(context, dir, id, private_key, is_default) { + if 0 == export_key_to_asc_file(context, dir, id, &private_key, is_default) { export_errors += 1 } } @@ -1605,8 +1598,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 +1610,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; @@ -1653,7 +1644,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, diff --git a/src/dc_key.rs b/src/dc_key.rs index 3d91fbe5b..674fc88d9 100644 --- a/src/dc_key.rs +++ b/src/dc_key.rs @@ -1,16 +1,16 @@ -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::mailmime_content::*; +use mmime::mmapstring::*; +use mmime::other::*; use pgp::composed::{Deserializable, SignedPublicKey, SignedSecretKey}; use pgp::ser::Serialize; +use crate::constants::*; use crate::dc_context::dc_context_t; use crate::dc_log::*; use crate::dc_pgp::*; @@ -20,480 +20,296 @@ 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::()) 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 - } -} - -// 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 = - 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 +impl Key { + pub fn is_public(&self) -> bool { + match self { + Key::Public(_) => true, + Key::Secret(_) => false, } } - sqlite3_finalize(stmt); - success -} + pub fn is_secret(&self) -> bool { + !self.is_public() + } -// TODO should return bool /rtn -pub unsafe fn dc_key_load_self_public( - 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( + pub fn from_slice(bytes: &[u8], key_type: KeyType) -> Option { + match key_type { + KeyType::Public => SignedPublicKey::from_bytes(Cursor::new(bytes)) + .map(|k| Key::Public(k)) + .ok(), + KeyType::Secret => SignedSecretKey::from_bytes(Cursor::new(bytes)) + .map(|k| Key::Secret(k)) + .ok(), + } + } + + pub fn from_binary( + data: *const libc::c_void, + len: libc::c_int, + key_type: KeyType, + ) -> Option { + assert!(!data.is_null(), "missing data"); + assert!(len > 0); + + let bytes = unsafe { slice::from_raw_parts(data, len) }; + Self::from_slice(bytes, key_type) + } + + pub fn from_stmt( + stmt: *mut sqlite3_stmt, + index: libc::c_int, + key_type: KeyType, + ) -> Option { + 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 { + // TODO: strip newlines and other whitespace + let bytes = encoded_data.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 { + if self_addr.is_null() { + return None; + } + + let 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 - } + sqlite3_bind_text(stmt, 1, self_addr, -1, None); + + let key = if sqlite3_step(stmt) == 100 { + Self::from_stmt(stmt, 0, KeyType::Public); + } else { + None + }; + + sqlite3_finalize(stmt); + + key } - sqlite3_finalize(stmt); - success -} + pub fn from_self_private( + context: &dc_context_t, + self_addr: *const libc::c_char, + sql: &dc_sqlite3_t, + ) -> Option { + if self_addr.is_null() { + return None; + } -// 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( + let 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_bind_text(stmt, 1, self_addr, -1, None); + + let key = if sqlite3_step(stmt) == 100 { + Self::from_stmt(stmt, 0, KeyType::Secret) + } else { + None + }; + sqlite3_finalize(stmt); + + key } + + pub fn to_base64(&self, break_every: usize) -> String { + let buf = self.0.to_bytes().expect("failed to serialize key"); + + 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()) } + } + + /// 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 + .0 + .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(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 + }; + + free(file_content as *mut libc::c_void); + + success + } + + pub fn fingerprint(&self) -> String { + hex::encode_upper(self.0.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) -> String { + let res = CString::new(self.formatted_fingerprint()).unwrap(); + + unsafe { libc::strdup(res.as_ptr()) } + } +} + +pub fn dc_key_save_self_keypair( + context: &dc_context_t, + public_key: &Key, + private_key: &Key, + addr: *const libc::c_char, + is_default: libc::c_int, + sql: &dc_sqlite3_t, +) -> bool { + if addr.is_null() { + return 0; + } + + let stmt = 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, 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(); + sqlite3_bind_blob(stmt, 3, pub_bytes.as_ptr(), pub_bytes.len(), None); + sqlite3_bind_blob(stmt, 4, sec_bytes.as_ptr(), sec_bytes.len(), None); + sqlite3_bind_int64(stmt, 5, time(0 as *mut time_t) as sqlite3_int64); + let success = if sqlite3_step(stmt) == 101 { + true + } else { + false + }; + 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 encoded = base64::encode(&buf); - encoded +/// 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 + fingerprint .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() + .chunks(4) + .chunks(5) + .map(|chunk| chunk.join(" ")) + .join("\n") } -/* 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(); - - // need to use strdup to allocate the result with malloc - // so it can be `free`d later. - unsafe { libc::strdup(res_c.as_ptr()) } +/// Bring a human-readable or otherwise formatted fingerprint back to the 40-characters-uppercase-hex format. +pub unsafe fn dc_normalize_fingerprint(fp: &str) -> String { + fp.to_uppercase() + .chars() + .filter(|c| c >= '0' && c <= '9' || c >= 'A' && c <= 'F') + .join("") } -/// 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(); +#[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"); } - let key = unsafe { *key }; + #[test] + fn test_format_fingerprint() { + let fingerprint = dc_normalize_fingerprint("1234567890ABCDABCDEFABCDEF1234567890ABCD"); - 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()) } -} - -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; - - 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 -} - -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, + 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 } diff --git a/src/dc_keyring.rs b/src/dc_keyring.rs index b22b24810..a9aad8ba8 100644 --- a/src/dc_keyring.rs +++ b/src/dc_keyring.rs @@ -2,86 +2,41 @@ 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)] +#[derive(Default, Clone, Debug)] pub struct dc_keyring_t { - pub keys: *mut *mut dc_key_t, - pub count: libc::c_int, - pub allocated: libc::c_int, + keys: Vec, } -pub unsafe fn dc_keyring_new() -> *mut dc_keyring_t { - let keyring: *mut dc_keyring_t; - keyring = calloc(1, ::std::mem::size_of::()) as *mut dc_keyring_t; - if keyring.is_null() { - exit(42i32); +impl dc_keyring_t { + pub fn add(&mut self, key: Key) { + self.keys.push(key); } - keyring -} - -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 = 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, 1, self_addr, -1, None); + while sqlite3_step(stmt) == 100 { + if let Some(key) = Key::from_stmt(stmt, 0, 1) { + self.add(key); + } } - dc_key_unref(key); - } - sqlite3_finalize(stmt); + sqlite3_finalize(stmt); - 1 + true + } } diff --git a/src/dc_pgp.rs b/src/dc_pgp.rs index 453006456..082cb4541 100644 --- a/src/dc_pgp.rs +++ b/src/dc_pgp.rs @@ -289,11 +289,7 @@ pub unsafe fn dc_pgp_calc_fingerprint( } // 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 { +pub unsafe fn dc_pgp_split_key(context: &dc_context_t, private_in: *const dc_key_t) -> Option { 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; diff --git a/tests/stress.rs b/tests/stress.rs index ffaa84437..c63a852b2 100644 --- a/tests/stress.rs +++ b/tests/stress.rs @@ -2668,35 +2668,7 @@ unsafe fn stress_functions(context: &dc_context_t) { 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