diff --git a/mmime/src/display.rs b/mmime/src/display.rs index d274d81be..8851c4eb5 100644 --- a/mmime/src/display.rs +++ b/mmime/src/display.rs @@ -1,4 +1,3 @@ - use crate::clist::*; use crate::mailimf::types::*; diff --git a/mmime/src/lib.rs b/mmime/src/lib.rs index c3a868375..4b75c5165 100644 --- a/mmime/src/lib.rs +++ b/mmime/src/lib.rs @@ -19,29 +19,24 @@ pub mod charconv; pub mod chash; pub mod clist; +pub mod display; pub mod mailimf; pub mod mailmime; pub mod mmapstring; pub mod other; -pub mod display; pub use self::charconv::*; pub use self::chash::*; pub use self::clist::*; +pub use self::display::*; pub use self::mailimf::*; pub use self::mailmime::*; pub use self::mmapstring::*; pub use self::other::*; -pub use self::display::*; - #[cfg(test)] mod tests { use super::*; - use crate::mailimf::types::*; - use crate::mailmime::types::*; - - use std::ffi::CStr; #[test] fn mailmime_parse_test() { diff --git a/mmime/src/mailmime/types.rs b/mmime/src/mailmime/types.rs index a894e0b04..0308c8124 100644 --- a/mmime/src/mailmime/types.rs +++ b/mmime/src/mailmime/types.rs @@ -154,7 +154,6 @@ pub struct unnamed_6 { pub dt_data: *const libc::c_char, pub dt_length: size_t, } - pub type unnamed_7 = libc::c_uint; pub const MAILMIME_MESSAGE: unnamed_7 = 3; pub const MAILMIME_MULTIPLE: unnamed_7 = 2; diff --git a/src/dc_mimeparser.rs b/src/dc_mimeparser.rs index a958f3338..9a9cc0b20 100644 --- a/src/dc_mimeparser.rs +++ b/src/dc_mimeparser.rs @@ -890,7 +890,6 @@ impl<'a> Drop for MimeParser<'a> { if !self.mimeroot.is_null() { unsafe { mailmime_free(self.mimeroot) }; } - unsafe { self.e2ee_helper.thanks() }; } } @@ -1057,7 +1056,8 @@ unsafe fn mailmime_get_mime_type(mime: *mut Mailmime) -> (libc::c_int, Viewtype, Some("alternative") => DC_MIMETYPE_MP_ALTERNATIVE, Some("related") => DC_MIMETYPE_MP_RELATED, Some("encrypted") => { - // apparently try_decrypt failed to decrypt + // maybe try_decrypt failed to decrypt + // or it wasn't in proper Autocrypt format DC_MIMETYPE_MP_NOT_DECRYPTABLE } Some("signed") => DC_MIMETYPE_MP_SIGNED, diff --git a/src/dc_receive_imf.rs b/src/dc_receive_imf.rs index adfbda27a..ed325a4e2 100644 --- a/src/dc_receive_imf.rs +++ b/src/dc_receive_imf.rs @@ -1648,7 +1648,7 @@ fn check_verified_properties( to_ids_str, ), params![], - |row| Ok((row.get::<_, String>(0)?, row.get::<_, i32>(1)?)), + |row| Ok((row.get::<_, String>(0)?, row.get::<_, i32>(1).unwrap_or(0))), |rows| { rows.collect::, _>>() .map_err(Into::into) @@ -1672,7 +1672,7 @@ fn check_verified_properties( || peerstate.verified_key_fingerprint != peerstate.public_key_fingerprint && peerstate.verified_key_fingerprint != peerstate.gossip_key_fingerprint { - info!(context, "{} has verfied {}.", contact.get_addr(), to_addr,); + info!(context, "{} has verified {}.", contact.get_addr(), to_addr,); let fp = peerstate.gossip_key_fingerprint.clone(); if let Some(fp) = fp { peerstate.set_verified(0, &fp, 2); diff --git a/src/e2ee.rs b/src/e2ee.rs index 3ff8a2b0a..2e5c25a15 100644 --- a/src/e2ee.rs +++ b/src/e2ee.rs @@ -1,13 +1,11 @@ //! End-to-end encryption support. -use std::any::Any; use std::collections::HashSet; use std::ffi::CStr; use std::ptr; use std::str::FromStr; -use libc::{free, strcmp, strlen, strncmp}; -use mmime::display::display_mime; +use libc::{strcmp, strlen, strncmp}; use mmime::clist::*; use mmime::mailimf::types::*; use mmime::mailimf::types_helper::*; @@ -289,8 +287,6 @@ impl EncryptHelper { #[derive(Debug, Default)] pub struct E2eeHelper { - cdata_to_free: Option>, - // for decrypting only pub encrypted: bool, pub signatures: HashSet, @@ -298,14 +294,6 @@ pub struct E2eeHelper { } impl E2eeHelper { - /// Frees data referenced by "mailmime" but not freed by mailmime_free(). After calling this function, - /// in_out_message cannot be used any longer! - pub unsafe fn thanks(&mut self) { - if let Some(data) = self.cdata_to_free.take() { - free(Box::into_raw(data) as *mut _) - } - } - pub unsafe fn try_decrypt( &mut self, context: &Context, @@ -318,6 +306,8 @@ impl E2eeHelper { let mut private_keyring = Keyring::default(); let mut public_keyring_for_validate = Keyring::default(); let mut gossip_headers: *mut mailimf_fields = ptr::null_mut(); + + // XXX do wrapmime:: helper for the next block if !(in_out_message.is_null() || imffields.is_null()) { let mut field = mailimf_find_field(imffields, MAILIMF_FIELD_FROM as libc::c_int); @@ -410,7 +400,6 @@ impl E2eeHelper { } } } - //mailmime_print(in_out_message); if !gossip_headers.is_null() { mailimf_fields_free(gossip_headers); } @@ -505,6 +494,7 @@ unsafe fn update_gossip_peerstates( imffields: *mut mailimf_fields, gossip_headers: *const mailimf_fields, ) -> HashSet { + // XXX split the parsing from the modification part let mut recipients: Option> = None; let mut gossipped_addr: HashSet = Default::default(); @@ -569,57 +559,29 @@ fn decrypt_if_autocrypt_message( ret_gossip_headers: *mut *mut mailimf_fields, ) -> Result<(bool)> { /* The returned bool is true if we detected an Autocrypt-encrypted - message and successfully decrypted it. Decryption modifies the - passed in mime structure in place. The returned bool is false + message and successfully decrypted it. Decryption then modifies the + passed in mime structure in place. The returned bool is false if it was not an Autocrypt message. - Errors are returned for failures related to decryption. + + Errors are returned for failures related to decryption of AC-messages. */ ensure!(!mime_undetermined.is_null(), "Invalid mime reference"); - let mime: *mut Mailmime; - unsafe { - println!("****** INCOMING MSG BEGIN"); - display_mime(mime_undetermined); - println!("****** INCOMING MSG END"); - - if (*mime_undetermined).mm_type != MAILMIME_MESSAGE as libc::c_int { + + let (mime, encrypted_data_part) = match wrapmime::get_autocrypt_mime(mime_undetermined) { + Err(_) => { + // not a proper autocrypt message, abort and ignore return Ok(false); } - mime = (*mime_undetermined).mm_data.mm_message.mm_msg_mime; - - if (*mime).mm_type != MAILMIME_MULTIPLE as libc::c_int - || "encrypted" != wrapmime::get_ct_subtype(mime).unwrap_or_default() - { - return Ok(false); - } - } - info!(context, "found OpenPGP-encrypted message"); - // we may have a proper Multipart/Encrypted Autocrypt Level 1 message - // XXX: more precise check we have exactly this specified OpenPGP-mime structure - // https://tools.ietf.org/html/rfc3156.html#section-4 + Ok(res) => res, + }; - let mut parts: Vec<*mut libc::c_void> = Vec::new(); - unsafe { - parts.extend((*(*mime).mm_data.mm_multipart.mm_mp_list).into_iter()); - } - ensure!(parts.len() == 2, "Invalid Autocrypt Level 1 Mime Parts"); - - info!(context, "decrypt_if_autocrypt_message found AC-encrypted message"); - - // ensure protocol-parameter "application/pgp-encrypted") - // ensure wrapmime::get_content_type(parts[1])) == "application/octetstream" - - let encrypted_mime_payload = parts[1] as *mut mmime::mailmime::types::Mailmime; - - let decrypted_mime = match decrypt_part( + let decrypted_mime = decrypt_part( context, - encrypted_mime_payload, + encrypted_data_part, private_keyring, public_keyring_for_validate, ret_valid_signatures, - ) { - Ok(res) => res, - Err(err) => bail!("decrypt_part failed: {}", err), - }; + )?; /* decrypted_mime is a dangling pointer which we now put into mailmime's Ownership */ unsafe { @@ -627,7 +589,9 @@ fn decrypt_if_autocrypt_message( mailmime_free(mime); } - /* finally, let's return any gossip headers */ + /* finally, let's also return gossip headers + XXX better return parsed headers so that upstream + does not need to dive into mmime-stuff again. */ unsafe { if (*ret_gossip_headers).is_null() && ret_valid_signatures.len() > 0 { let mut dummy: libc::size_t = 0; @@ -660,7 +624,7 @@ fn decrypt_part( unsafe { mime_data = (*mime).mm_data.mm_single; } - if !wrapmime::has_decryptable_data_(mime_data) { + if !wrapmime::has_decryptable_data(mime_data) { return Ok(ptr::null_mut()); } @@ -671,17 +635,15 @@ fn decrypt_part( let (decoded_data, decoded_data_bytes) = wrapmime::decode_dt_data(mime_data, mime_transfer_encoding)?; /* encrypted, non-NULL decoded data in decoded_data now ... - Note that we need to take care of freeing decoded_data ourself. - Once decryption is finished we unref() can do this, so our caller does not - need to care for it. - + Note that we need to take care of freeing decoded_data ourself, + after encryption has been attempted. */ let mut ret_decrypted_mime = ptr::null_mut(); unsafe { if has_decrypted_pgp_armor(decoded_data, decoded_data_bytes as libc::c_int) { /* we should only have one decryption happening */ - assert!(ret_valid_signatures.is_empty(), "corrupted"); + ensure!(ret_valid_signatures.is_empty(), "corrupt signatures"); let plain = match dc_pgp_pk_decrypt( std::slice::from_raw_parts(decoded_data as *const u8, decoded_data_bytes), @@ -689,7 +651,10 @@ fn decrypt_part( &public_keyring_for_validate, Some(ret_valid_signatures), ) { - Ok(plain) => plain, + Ok(plain) => { + ensure!(!ret_valid_signatures.is_empty(), "no valid signatures"); + plain + } Err(err) => { mmap_string_unref(decoded_data); bail!("could not decrypt: {}", err) @@ -800,6 +765,7 @@ pub fn ensure_secret_key_exists(context: &Context) -> Result { #[cfg(test)] mod tests { use super::*; + use libc::free; use crate::test_utils::*; diff --git a/src/wrapmime.rs b/src/wrapmime.rs index f2b75a902..ac3b704cb 100644 --- a/src/wrapmime.rs +++ b/src/wrapmime.rs @@ -37,14 +37,48 @@ pub fn get_ct_subtype(mime: *mut Mailmime) -> Option { if !ct.is_null() && !(*ct).ct_subtype.is_null() { println!("ct_subtype: {}", to_string((*ct).ct_subtype)); - Some(to_string((*ct).ct_subtype)) + Some(to_string((*ct).ct_subtype)) } else { None } } } -pub fn has_decryptable_data_(mime_data: *mut mailmime_data) -> bool { +pub fn get_autocrypt_mime( + mime_undetermined: *mut Mailmime, +) -> Result<(*mut Mailmime, *mut Mailmime), Error> { + /* return Result with two mime pointers: + First mime pointer is to the multipart-mime message + (which is replaced with a decrypted version later) + Second one is to the encrypted payload. + For non-autocrypt message an Error is returned. + */ + unsafe { + ensure!( + (*mime_undetermined).mm_type == MAILMIME_MESSAGE as libc::c_int, + "Not a root mime message" + ); + let mime = (*mime_undetermined).mm_data.mm_message.mm_msg_mime; + + ensure!( + (*mime).mm_type == MAILMIME_MULTIPLE as libc::c_int + && "encrypted" == get_ct_subtype(mime).unwrap_or_default(), + "Not a multipart/encrypted message" + ); + let parts: Vec<_> = (*(*mime).mm_data.mm_multipart.mm_mp_list) + .into_iter() + .map(|c| c as *mut Mailmime) + .collect(); + ensure!(parts.len() == 2, "Invalid Autocrypt Level 1 Mime Parts"); + // XXX ensure protocol-parameter "application/pgp-encrypted") + // XXX ensure wrapmime::get_content_type(parts[1])) == "application/octetstream" + // a proper OpenPGP multipart/encrypted Autocrypt Level 1 message + // https://tools.ietf.org/html/rfc3156.html#section-4 + Ok((mime, parts[1])) + } +} + +pub fn has_decryptable_data(mime_data: *mut mailmime_data) -> bool { /* MAILMIME_DATA_FILE indicates, the data is in a file; AFAIK this is not used on parsing */ unsafe { (*mime_data).dt_type == MAILMIME_DATA_TEXT as libc::c_int