Compare commits

...

6 Commits

Author SHA1 Message Date
dignifiedquire
2ba25f9f77 bring back memory leak 2019-09-28 12:42:53 -06:00
dignifiedquire
e23704486a fix argument passing in mmime 2019-09-28 12:10:14 -06:00
holger krekel
feee340f4d better bubble up DB errors and guard one unwrap() where a crash occured during integration test run
(and possibly also related to #633)
2019-09-28 12:48:41 +02:00
holger krekel
a5cde0d137 fix a merge-issue, and a double-if, and a wrong guard 2019-09-28 12:16:03 +02:00
dignifiedquire
b08a2b4d2c Merge remote-tracking branch 'origin/master' into safe-e2ee 2019-09-27 20:10:03 -06:00
dignifiedquire
3b6e1b0aae refactor(e2ee): reduce unsafe spread 2019-09-27 20:01:47 -06:00
7 changed files with 425 additions and 392 deletions

View File

@@ -888,6 +888,7 @@ pub unsafe fn mailimf_fields_new(mut fld_list: *mut clist) -> *mut mailimf_field
(*fields).fld_list = fld_list; (*fields).fld_list = fld_list;
return fields; return fields;
} }
#[no_mangle] #[no_mangle]
pub unsafe fn mailimf_field_new( pub unsafe fn mailimf_field_new(
mut fld_type: libc::c_int, mut fld_type: libc::c_int,
@@ -947,6 +948,20 @@ pub unsafe fn mailimf_field_new(
} }
return field; return field;
} }
#[no_mangle]
pub unsafe fn mailimf_field_new_subject(fld_subject: *mut mailimf_subject) -> *mut mailimf_field {
let mut field: *mut mailimf_field = 0 as *mut mailimf_field;
field = malloc(::std::mem::size_of::<mailimf_field>() as libc::size_t) as *mut mailimf_field;
if field.is_null() {
return 0 as *mut mailimf_field;
}
(*field).fld_type = MAILIMF_FIELD_SUBJECT as libc::c_int;
(*field).fld_data.fld_subject = fld_subject;
field
}
#[no_mangle] #[no_mangle]
pub unsafe fn mailimf_orig_date_new( pub unsafe fn mailimf_orig_date_new(
mut dt_date_time: *mut mailimf_date_time, mut dt_date_time: *mut mailimf_date_time,

View File

@@ -708,6 +708,28 @@ pub unsafe fn mailmime_new(
return mime; return mime;
} }
pub unsafe fn mailmime_new_simple(
mut mm_type: libc::c_int,
mut mm_mime_fields: *mut mailmime_fields,
mut mm_content_type: *mut mailmime_content,
mut mm_fields: *mut mailimf_fields,
mut mm_msg_mime: *mut Mailmime,
) -> *mut Mailmime {
mailmime_new(
mm_type,
std::ptr::null(),
0,
mm_mime_fields,
mm_content_type,
std::ptr::null_mut(),
std::ptr::null_mut(),
std::ptr::null_mut(),
std::ptr::null_mut(),
mm_fields,
mm_msg_mime,
)
}
pub unsafe fn mailmime_free(mut mime: *mut Mailmime) { pub unsafe fn mailmime_free(mut mime: *mut Mailmime) {
match (*mime).mm_type { match (*mime).mm_type {
1 => { 1 => {

View File

@@ -5,7 +5,6 @@ use std::ptr;
use charset::Charset; use charset::Charset;
use deltachat_derive::{FromSql, ToSql}; use deltachat_derive::{FromSql, ToSql};
use libc::{strcmp, strlen, strncmp}; use libc::{strcmp, strlen, strncmp};
use mmime::clist::*;
use mmime::mailimf::types::*; use mmime::mailimf::types::*;
use mmime::mailimf::*; use mmime::mailimf::*;
use mmime::mailmime::content::*; use mmime::mailmime::content::*;
@@ -21,7 +20,7 @@ use crate::context::Context;
use crate::dc_simplify::*; use crate::dc_simplify::*;
use crate::dc_strencode::*; use crate::dc_strencode::*;
use crate::dc_tools::*; use crate::dc_tools::*;
use crate::e2ee::*; use crate::e2ee;
use crate::error::Error; use crate::error::Error;
use crate::location; use crate::location;
use crate::param::*; use crate::param::*;
@@ -38,7 +37,9 @@ pub struct MimeParser<'a> {
pub subject: Option<String>, pub subject: Option<String>,
pub is_send_by_messenger: bool, pub is_send_by_messenger: bool,
pub decrypting_failed: bool, pub decrypting_failed: bool,
pub e2ee_helper: E2eeHelper, pub encrypted: bool,
pub signatures: HashSet<String>,
pub gossipped_addr: HashSet<String>,
pub is_forwarded: bool, pub is_forwarded: bool,
pub reports: Vec<*mut Mailmime>, pub reports: Vec<*mut Mailmime>,
pub is_system_message: SystemMessage, pub is_system_message: SystemMessage,
@@ -92,7 +93,9 @@ impl<'a> MimeParser<'a> {
subject: None, subject: None,
is_send_by_messenger: false, is_send_by_messenger: false,
decrypting_failed: false, decrypting_failed: false,
e2ee_helper: Default::default(), encrypted: false,
signatures: Default::default(),
gossipped_addr: Default::default(),
is_forwarded: false, is_forwarded: false,
context, context,
reports: Vec::new(), reports: Vec::new(),
@@ -113,7 +116,11 @@ impl<'a> MimeParser<'a> {
); );
if r == MAILIMF_NO_ERROR as libc::c_int && !self.mimeroot.is_null() { if r == MAILIMF_NO_ERROR as libc::c_int && !self.mimeroot.is_null() {
self.e2ee_helper.try_decrypt(self.context, self.mimeroot)?; let (encrypted, signatures, gossipped_addr) =
e2ee::try_decrypt(self.context, self.mimeroot)?;
self.encrypted = encrypted;
self.signatures = signatures;
self.gossipped_addr = gossipped_addr;
self.parse_mime_recursive(self.mimeroot); self.parse_mime_recursive(self.mimeroot);
if let Some(field) = self.lookup_field("Subject") { if let Some(field) = self.lookup_field("Subject") {
@@ -794,9 +801,9 @@ impl<'a> MimeParser<'a> {
} }
fn do_add_single_part(&mut self, mut part: Part) { fn do_add_single_part(&mut self, mut part: Part) {
if self.e2ee_helper.encrypted && self.e2ee_helper.signatures.len() > 0 { if self.encrypted && self.signatures.len() > 0 {
part.param.set_int(Param::GuranteeE2ee, 1); part.param.set_int(Param::GuranteeE2ee, 1);
} else if self.e2ee_helper.encrypted { } else if self.encrypted {
part.param.set_int(Param::ErroneousE2ee, 0x2); part.param.set_int(Param::ErroneousE2ee, 0x2);
} }
self.parts.push(part); self.parts.push(part);
@@ -1204,50 +1211,61 @@ pub unsafe fn mailmime_transfer_decode(mime: *mut Mailmime) -> Result<Vec<u8>, E
Err(format_err!("Failed to to decode")) Err(format_err!("Failed to to decode"))
} }
pub unsafe fn mailimf_get_recipients(imffields: *mut mailimf_fields) -> HashSet<String> { pub fn mailimf_get_recipients(imffields: *mut mailimf_fields) -> HashSet<String> {
/* returned addresses are normalized. */ /* returned addresses are normalized. */
let mut recipients: HashSet<String> = Default::default(); let mut recipients: HashSet<String> = Default::default();
for cur in (*(*imffields).fld_list).into_iter() { for cur in unsafe { (*(*imffields).fld_list).into_iter() } {
let fld = cur as *mut mailimf_field; let fld = cur as *mut mailimf_field;
let fld_to: *mut mailimf_to; let fld_to: *mut mailimf_to;
let fld_cc: *mut mailimf_cc; let fld_cc: *mut mailimf_cc;
let mut addr_list: *mut mailimf_address_list = ptr::null_mut(); let mut addr_list: *mut mailimf_address_list = ptr::null_mut();
if fld.is_null() {
continue;
}
let fld = unsafe { *fld };
// TODO match on enums /rtn // TODO match on enums /rtn
match (*fld).fld_type { match fld.fld_type {
13 => { 13 => {
fld_to = (*fld).fld_data.fld_to; fld_to = unsafe { fld.fld_data.fld_to };
if !fld_to.is_null() { if !fld_to.is_null() {
addr_list = (*fld_to).to_addr_list addr_list = unsafe { (*fld_to).to_addr_list };
} }
} }
14 => { 14 => {
fld_cc = (*fld).fld_data.fld_cc; fld_cc = unsafe { fld.fld_data.fld_cc };
if !fld_cc.is_null() { if !fld_cc.is_null() {
addr_list = (*fld_cc).cc_addr_list addr_list = unsafe { (*fld_cc).cc_addr_list };
} }
} }
_ => {} _ => {}
} }
if !addr_list.is_null() { if !addr_list.is_null() {
for cur2 in (*(*addr_list).ad_list).into_iter() { for cur2 in unsafe { &(*(*addr_list).ad_list) } {
let adr = cur2 as *mut mailimf_address; let adr = cur2 as *mut mailimf_address;
if !adr.is_null() { if adr.is_null() {
if (*adr).ad_type == MAILIMF_ADDRESS_MAILBOX as libc::c_int { continue;
mailimf_get_recipients_add_addr(&mut recipients, (*adr).ad_data.ad_mailbox); }
} else if (*adr).ad_type == MAILIMF_ADDRESS_GROUP as libc::c_int { let adr = unsafe { *adr };
let group: *mut mailimf_group = (*adr).ad_data.ad_group;
if !group.is_null() && !(*group).grp_mb_list.is_null() { if adr.ad_type == MAILIMF_ADDRESS_MAILBOX as libc::c_int {
for cur3 in (*(*(*group).grp_mb_list).mb_list).into_iter() { mailimf_get_recipients_add_addr(&mut recipients, unsafe {
mailimf_get_recipients_add_addr( adr.ad_data.ad_mailbox
&mut recipients, });
cur3 as *mut mailimf_mailbox, } else if adr.ad_type == MAILIMF_ADDRESS_GROUP as libc::c_int {
); let group = unsafe { adr.ad_data.ad_group };
} if !group.is_null() && unsafe { !(*group).grp_mb_list.is_null() } {
for cur3 in unsafe { &(*(*(*group).grp_mb_list).mb_list) } {
mailimf_get_recipients_add_addr(
&mut recipients,
cur3 as *mut mailimf_mailbox,
);
} }
} }
} }
@@ -1266,30 +1284,26 @@ fn mailimf_get_recipients_add_addr(recipients: &mut HashSet<String>, mb: *mut ma
} }
/*the result is a pointer to mime, must not be freed*/ /*the result is a pointer to mime, must not be freed*/
pub unsafe fn mailimf_find_field( pub fn mailimf_find_field(
header: *mut mailimf_fields, header: *mut mailimf_fields,
wanted_fld_type: libc::c_int, wanted_fld_type: libc::c_int,
) -> *mut mailimf_field { ) -> *mut mailimf_field {
if header.is_null() || (*header).fld_list.is_null() { if header.is_null() {
return ptr::null_mut(); return ptr::null_mut();
} }
let mut cur1: *mut clistiter = (*(*header).fld_list).first;
while !cur1.is_null() { let header = unsafe { (*header) };
let field: *mut mailimf_field = (if !cur1.is_null() { if header.fld_list.is_null() {
(*cur1).data return ptr::null_mut();
} else { }
ptr::null_mut()
}) as *mut mailimf_field; for cur in unsafe { &(*header.fld_list) } {
let field = cur as *mut mailimf_field;
if !field.is_null() { if !field.is_null() {
if (*field).fld_type == wanted_fld_type { if unsafe { (*field).fld_type } == wanted_fld_type {
return field; return field;
} }
} }
cur1 = if !cur1.is_null() {
(*cur1).next
} else {
ptr::null_mut()
}
} }
ptr::null_mut() ptr::null_mut()

View File

@@ -610,7 +610,7 @@ unsafe fn add_parts(
let icnt = mime_parser.parts.len(); let icnt = mime_parser.parts.len();
let mut txt_raw = None; let mut txt_raw = None;
let is_ok = context context
.sql .sql
.prepare( .prepare(
"INSERT INTO msgs \ "INSERT INTO msgs \
@@ -697,13 +697,10 @@ unsafe fn add_parts(
Ok(()) Ok(())
}, },
) )
.is_ok(); .map_err(|err| {
cleanup(mime_in_reply_to, mime_references);
if !is_ok { err
// i/o error - there is nothing more we can do - in other cases, we try to write at least an empty record })?;
cleanup(mime_in_reply_to, mime_references);
bail!("Cannot write DB.");
}
info!( info!(
context, context,
@@ -1609,10 +1606,7 @@ fn check_verified_properties(
) -> Result<()> { ) -> Result<()> {
let contact = Contact::load_from_db(context, from_id)?; let contact = Contact::load_from_db(context, from_id)?;
ensure!( ensure!(mimeparser.encrypted, "This message is not encrypted.");
mimeparser.e2ee_helper.encrypted,
"This message is not encrypted."
);
// ensure, the contact is verified // ensure, the contact is verified
// and the message is signed with a verified key of the sender. // and the message is signed with a verified key of the sender.
@@ -1633,7 +1627,7 @@ fn check_verified_properties(
if let Some(peerstate) = peerstate { if let Some(peerstate) = peerstate {
ensure!( ensure!(
peerstate.has_verified_key(&mimeparser.e2ee_helper.signatures), peerstate.has_verified_key(&mimeparser.signatures),
"The message was sent with non-verified encryption." "The message was sent with non-verified encryption."
); );
} }
@@ -1660,7 +1654,7 @@ fn check_verified_properties(
let mut peerstate = Peerstate::from_addr(context, &context.sql, &to_addr); let mut peerstate = Peerstate::from_addr(context, &context.sql, &to_addr);
// mark gossiped keys (if any) as verified // mark gossiped keys (if any) as verified
if mimeparser.e2ee_helper.gossipped_addr.contains(&to_addr) && peerstate.is_some() { if mimeparser.gossipped_addr.contains(&to_addr) && peerstate.is_some() {
let peerstate = peerstate.as_mut().unwrap(); let peerstate = peerstate.as_mut().unwrap();
// if we're here, we know the gossip key is verified: // if we're here, we know the gossip key is verified:

View File

@@ -217,26 +217,26 @@ pub(crate) fn dc_str_to_color(s: impl AsRef<str>) -> u32 {
/* date/time tools */ /* date/time tools */
/* the result is UTC or DC_INVALID_TIMESTAMP */ /* the result is UTC or DC_INVALID_TIMESTAMP */
pub(crate) unsafe fn dc_timestamp_from_date(date_time: *mut mailimf_date_time) -> i64 { pub(crate) fn dc_timestamp_from_date(date_time: *mut mailimf_date_time) -> i64 {
let sec = (*date_time).dt_sec; assert!(!date_time.is_null());
let min = (*date_time).dt_min; let dt = unsafe { *date_time };
let hour = (*date_time).dt_hour;
let day = (*date_time).dt_day; let sec = dt.dt_sec;
let month = (*date_time).dt_month; let min = dt.dt_min;
let year = (*date_time).dt_year; let hour = dt.dt_hour;
let day = dt.dt_day;
let month = dt.dt_month;
let year = dt.dt_year;
let ts = chrono::NaiveDateTime::new( let ts = chrono::NaiveDateTime::new(
chrono::NaiveDate::from_ymd(year, month as u32, day as u32), chrono::NaiveDate::from_ymd(year, month as u32, day as u32),
chrono::NaiveTime::from_hms(hour as u32, min as u32, sec as u32), chrono::NaiveTime::from_hms(hour as u32, min as u32, sec as u32),
); );
let (zone_hour, zone_min) = if (*date_time).dt_zone >= 0 { let (zone_hour, zone_min) = if dt.dt_zone >= 0 {
((*date_time).dt_zone / 100, (*date_time).dt_zone % 100) (dt.dt_zone / 100, dt.dt_zone % 100)
} else { } else {
( (-(-dt.dt_zone / 100), -(-dt.dt_zone % 100))
-(-(*date_time).dt_zone / 100),
-(-(*date_time).dt_zone % 100),
)
}; };
ts.timestamp() - (zone_hour * 3600 + zone_min * 60) as i64 ts.timestamp() - (zone_hour * 3600 + zone_min * 60) as i64

View File

@@ -1,11 +1,10 @@
//! End-to-end encryption support. //! End-to-end encryption support.
use std::collections::HashSet; use std::collections::HashSet;
use std::ffi::CStr;
use std::ptr; use std::ptr;
use std::str::FromStr; use std::str::FromStr;
use libc::{strcmp, strlen, strncmp}; use libc::strlen;
use mmime::clist::*; use mmime::clist::*;
use mmime::mailimf::types::*; use mmime::mailimf::types::*;
use mmime::mailimf::types_helper::*; use mmime::mailimf::types_helper::*;
@@ -18,6 +17,7 @@ use mmime::mailmime::*;
use mmime::mailprivacy_prepare_mime; use mmime::mailprivacy_prepare_mime;
use mmime::mmapstring::*; use mmime::mmapstring::*;
use mmime::{mailmime_substitute, MAILIMF_NO_ERROR, MAIL_NO_ERROR}; use mmime::{mailmime_substitute, MAILIMF_NO_ERROR, MAIL_NO_ERROR};
use num_traits::FromPrimitive;
use crate::aheader::*; use crate::aheader::*;
use crate::config::Config; use crate::config::Config;
@@ -47,12 +47,12 @@ pub struct EncryptHelper {
impl EncryptHelper { impl EncryptHelper {
pub fn new(context: &Context) -> Result<EncryptHelper> { pub fn new(context: &Context) -> Result<EncryptHelper> {
let e2ee = context.sql.get_config_int(&context, "e2ee_enabled"); let prefer_encrypt = context
let prefer_encrypt = if 0 != e2ee.unwrap_or_default() { .sql
EncryptPreference::Mutual .get_config_int(&context, "e2ee_enabled")
} else { .and_then(EncryptPreference::from_i32)
EncryptPreference::NoPreference .unwrap_or_default();
};
let addr = match context.get_config(Config::ConfiguredAddr) { let addr = match context.get_config(Config::ConfiguredAddr) {
None => { None => {
bail!("addr not configured!"); bail!("addr not configured!");
@@ -61,6 +61,7 @@ impl EncryptHelper {
}; };
let public_key = load_or_generate_self_public_key(context, &addr)?; let public_key = load_or_generate_self_public_key(context, &addr)?;
Ok(EncryptHelper { Ok(EncryptHelper {
prefer_encrypt, prefer_encrypt,
addr, addr,
@@ -83,11 +84,13 @@ impl EncryptHelper {
mut in_out_message: *mut Mailmime, mut in_out_message: *mut Mailmime,
imffields_unprotected: *mut mailimf_fields, imffields_unprotected: *mut mailimf_fields,
) -> Result<bool> { ) -> Result<bool> {
/* libEtPan's pgp_encrypt_mime() takes the parent as the new root. // libEtPan's pgp_encrypt_mime() takes the parent as the new root.
We just expect the root as being given to this function. */ // We just expect the root as being given to this function.
if in_out_message.is_null() || unsafe { !(*in_out_message).mm_parent.is_null() } { ensure!(
bail!("corrupted inputs"); !in_out_message.is_null() && unsafe { (*in_out_message).mm_parent.is_null() },
} "corrupted inputs"
);
if !(self.prefer_encrypt == EncryptPreference::Mutual || e2ee_guaranteed) { if !(self.prefer_encrypt == EncryptPreference::Mutual || e2ee_guaranteed) {
return Ok(false); return Ok(false);
} }
@@ -106,13 +109,14 @@ impl EncryptHelper {
None => { None => {
let msg = format!("peerstate for {} missing, cannot encrypt", recipient_addr); let msg = format!("peerstate for {} missing, cannot encrypt", recipient_addr);
if e2ee_guaranteed { if e2ee_guaranteed {
bail!("{}", msg); return Err(format_err!("{}", msg));
} else { } else {
info!(context, "{}", msg); info!(context, "{}", msg);
return Ok(false); return Ok(false);
} }
} }
}; };
if peerstate.prefer_encrypt != EncryptPreference::Mutual && !e2ee_guaranteed { if peerstate.prefer_encrypt != EncryptPreference::Mutual && !e2ee_guaranteed {
info!(context, "peerstate for {} is no-encrypt", recipient_addr); info!(context, "peerstate for {} is no-encrypt", recipient_addr);
return Ok(false); return Ok(false);
@@ -136,30 +140,24 @@ impl EncryptHelper {
let sign_key = { let sign_key = {
keyring.add_ref(&self.public_key); keyring.add_ref(&self.public_key);
let key = Key::from_self_private(context, self.addr.clone(), &context.sql); let key = Key::from_self_private(context, self.addr.clone(), &context.sql);
if key.is_none() { ensure!(key.is_some(), "no own private key found");
bail!("no own private key found")
}
key key
}; };
/* encrypt message */ // encrypt message
unsafe { unsafe {
mailprivacy_prepare_mime(in_out_message); mailprivacy_prepare_mime(in_out_message);
let mut part_to_encrypt: *mut Mailmime = let mut part_to_encrypt = (*in_out_message).mm_data.mm_message.mm_msg_mime;
(*in_out_message).mm_data.mm_message.mm_msg_mime;
(*part_to_encrypt).mm_parent = ptr::null_mut(); (*part_to_encrypt).mm_parent = ptr::null_mut();
let imffields_encrypted: *mut mailimf_fields = mailimf_fields_new_empty(); let imffields_encrypted = mailimf_fields_new_empty();
/* mailmime_new_message_data() calls mailmime_fields_new_with_version() which would add the unwanted MIME-Version:-header */
let message_to_encrypt: *mut Mailmime = mailmime_new( // mailmime_new_message_data() calls mailmime_fields_new_with_version()
// which would add the unwanted MIME-Version:-header
let message_to_encrypt = mailmime_new_simple(
MAILMIME_MESSAGE as libc::c_int, MAILMIME_MESSAGE as libc::c_int,
ptr::null(),
0 as libc::size_t,
mailmime_fields_new_empty(), mailmime_fields_new_empty(),
mailmime_get_content_message(), mailmime_get_content_message(),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
imffields_encrypted, imffields_encrypted,
part_to_encrypt, part_to_encrypt,
); );
@@ -168,12 +166,13 @@ impl EncryptHelper {
wrapmime::new_custom_field(imffields_encrypted, "Autocrypt-Gossip", &header) wrapmime::new_custom_field(imffields_encrypted, "Autocrypt-Gossip", &header)
} }
/* memoryhole headers: move some headers into encrypted part */ // memoryhole headers: move some headers into encrypted part
// XXX note we can't use clist's into_iter() because the loop body also removes items // XXX note we can't use clist's into_iter() because the loop body also removes items
let mut cur: *mut clistiter = (*(*imffields_unprotected).fld_list).first; let mut cur = (*(*imffields_unprotected).fld_list).first;
while !cur.is_null() { while !cur.is_null() {
let field: *mut mailimf_field = (*cur).data as *mut mailimf_field; let field = (*cur).data as *mut mailimf_field;
let mut move_to_encrypted = false; let mut move_to_encrypted = false;
if !field.is_null() { if !field.is_null() {
if (*field).fld_type == MAILIMF_FIELD_SUBJECT as libc::c_int { if (*field).fld_type == MAILIMF_FIELD_SUBJECT as libc::c_int {
move_to_encrypted = true; move_to_encrypted = true;
@@ -189,6 +188,7 @@ impl EncryptHelper {
} }
} }
} }
if move_to_encrypted { if move_to_encrypted {
mailimf_fields_add(imffields_encrypted, field); mailimf_fields_add(imffields_encrypted, field);
cur = clist_delete((*imffields_unprotected).fld_list, cur); cur = clist_delete((*imffields_unprotected).fld_list, cur);
@@ -196,48 +196,24 @@ impl EncryptHelper {
cur = (*cur).next; cur = (*cur).next;
} }
} }
let subject: *mut mailimf_subject = mailimf_subject_new("...".strdup());
mailimf_fields_add( let subject = mailimf_subject_new("...".strdup());
imffields_unprotected, mailimf_fields_add(imffields_unprotected, mailimf_field_new_subject(subject));
mailimf_field_new(
MAILIMF_FIELD_SUBJECT as libc::c_int,
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
subject,
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
),
);
wrapmime::append_ct_param( wrapmime::append_ct_param(
(*part_to_encrypt).mm_content_type, (*part_to_encrypt).mm_content_type,
"protected-headers", "protected-headers",
"v1", "v1",
)?; )?;
let plain: *mut MMAPString = let plain = mmap_string_new(b"\x00" as *const u8 as *const libc::c_char);
mmap_string_new(b"\x00" as *const u8 as *const libc::c_char); let mut col = 0;
let mut col: libc::c_int = 0i32;
mailmime_write_mem(plain, &mut col, message_to_encrypt); mailmime_write_mem(plain, &mut col, message_to_encrypt);
mailmime_free(message_to_encrypt); mailmime_free(message_to_encrypt);
if (*plain).str_0.is_null() || (*plain).len <= 0 {
bail!("could not write/allocate"); ensure!(
} !(*plain).str_0.is_null() && (*plain).len > 0,
"could not write/allocate"
);
let ctext = dc_pgp_pk_encrypt( let ctext = dc_pgp_pk_encrypt(
std::slice::from_raw_parts((*plain).str_0 as *const u8, (*plain).len), std::slice::from_raw_parts((*plain).str_0 as *const u8, (*plain).len),
@@ -246,165 +222,148 @@ impl EncryptHelper {
); );
mmap_string_free(plain); mmap_string_free(plain);
if let Ok(ctext_v) = ctext { let ctext_v = ctext?;
/* create MIME-structure that will contain the encrypted text */
let mut encrypted_part: *mut Mailmime = new_data_part(
ptr::null_mut(),
0 as libc::size_t,
"multipart/encrypted",
MAILMIME_MECHANISM_BASE64,
)?;
let content: *mut mailmime_content = (*encrypted_part).mm_content_type;
wrapmime::append_ct_param(content, "protocol", "application/pgp-encrypted")?;
let version_mime: *mut Mailmime = new_data_part(
VERSION_CONTENT.as_mut_ptr() as *mut libc::c_void,
strlen(VERSION_CONTENT.as_mut_ptr()),
"application/pgp-encrypted",
MAILMIME_MECHANISM_7BIT,
)?;
mailmime_smart_add_part(encrypted_part, version_mime);
// we assume that ctext_v is not dropped until the end // create MIME-structure that will contain the encrypted text
// of this if-scope let mut encrypted_part = new_data_part(
let ctext_part: *mut Mailmime = new_data_part( ptr::null_mut(),
ctext_v.as_ptr() as *mut libc::c_void, 0 as libc::size_t,
ctext_v.len(), "multipart/encrypted",
"application/octet-stream", MAILMIME_MECHANISM_BASE64,
MAILMIME_MECHANISM_7BIT, )?;
)?; let content = (*encrypted_part).mm_content_type;
mailmime_smart_add_part(encrypted_part, ctext_part); wrapmime::append_ct_param(content, "protocol", "application/pgp-encrypted")?;
(*in_out_message).mm_data.mm_message.mm_msg_mime = encrypted_part;
(*encrypted_part).mm_parent = in_out_message; let version_mime = new_data_part(
let gossiped = !&gossip_headers.is_empty(); VERSION_CONTENT.as_mut_ptr() as *mut libc::c_void,
factory.finalize_mime_message(in_out_message, true, gossiped)?; strlen(VERSION_CONTENT.as_mut_ptr()),
Ok(true) "application/pgp-encrypted",
} else { MAILMIME_MECHANISM_7BIT,
bail!("encryption failed") )?;
} mailmime_smart_add_part(encrypted_part, version_mime);
// we assume that ctext_v is not dropped until the end
// of this if-scope
let ctext_part = new_data_part(
ctext_v.as_ptr() as *mut libc::c_void,
ctext_v.len(),
"application/octet-stream",
MAILMIME_MECHANISM_7BIT,
)?;
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;
let gossiped = !&gossip_headers.is_empty();
factory.finalize_mime_message(in_out_message, true, gossiped)?;
Ok(true)
} }
} }
} }
#[derive(Debug, Default)] pub fn try_decrypt(
pub struct E2eeHelper { context: &Context,
// for decrypting only in_out_message: *mut Mailmime,
pub encrypted: bool, ) -> Result<(bool, HashSet<String>, HashSet<String>)> {
pub signatures: HashSet<String>, let mut encrypted = false;
pub gossipped_addr: HashSet<String>, let mut signatures = HashSet::default();
} let mut gossipped_addr = HashSet::default();
impl E2eeHelper { // just a pointer into mailmime structure, must not be freed
pub unsafe fn try_decrypt( let imffields = unsafe { mailmime_find_mailimf_fields(in_out_message) };
&mut self, let mut message_time = 0;
context: &Context, let mut from = None;
in_out_message: *mut Mailmime, let mut private_keyring = Keyring::default();
) -> Result<()> { let mut public_keyring_for_validate = Keyring::default();
/*just a pointer into mailmime structure, must not be freed*/ let mut gossip_headers = ptr::null_mut();
let imffields: *mut mailimf_fields = mailmime_find_mailimf_fields(in_out_message);
let mut message_time = 0;
let mut from = None;
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 // XXX do wrapmime:: helper for the next block
if !(in_out_message.is_null() || imffields.is_null()) { if !(in_out_message.is_null() || imffields.is_null()) {
let mut field = mailimf_find_field(imffields, MAILIMF_FIELD_FROM as libc::c_int); let mut field = mailimf_find_field(imffields, MAILIMF_FIELD_FROM as libc::c_int);
if !field.is_null() && !(*field).fld_data.fld_from.is_null() { if !field.is_null() && unsafe { !(*field).fld_data.fld_from.is_null() } {
from = mailimf_find_first_addr((*(*field).fld_data.fld_from).frm_mb_list) let mb_list = unsafe { (*(*field).fld_data.fld_from).frm_mb_list };
} from = mailimf_find_first_addr(mb_list);
}
field = mailimf_find_field(imffields, MAILIMF_FIELD_ORIG_DATE as libc::c_int); field = mailimf_find_field(imffields, MAILIMF_FIELD_ORIG_DATE as libc::c_int);
if !field.is_null() && !(*field).fld_data.fld_orig_date.is_null() { if !field.is_null() && unsafe { !(*field).fld_data.fld_orig_date.is_null() } {
let orig_date: *mut mailimf_orig_date = (*field).fld_data.fld_orig_date; let orig_date = unsafe { (*field).fld_data.fld_orig_date };
if !orig_date.is_null() {
message_time = dc_timestamp_from_date((*orig_date).dt_date_time); if !orig_date.is_null() {
if message_time != 0 && message_time > time() { let dt = unsafe { (*orig_date).dt_date_time };
message_time = time() message_time = dc_timestamp_from_date(dt);
} if message_time != 0 && message_time > time() {
message_time = time()
} }
} }
let mut peerstate = None; }
let autocryptheader = from let mut peerstate = None;
.as_ref() let autocryptheader = from
.and_then(|from| Aheader::from_imffields(from, imffields)); .as_ref()
if message_time > 0 { .and_then(|from| Aheader::from_imffields(from, imffields));
if let Some(ref from) = from { if message_time > 0 {
peerstate = Peerstate::from_addr(context, &context.sql, from); if let Some(ref from) = from {
peerstate = Peerstate::from_addr(context, &context.sql, from);
if let Some(ref mut peerstate) = peerstate { if let Some(ref mut peerstate) = peerstate {
if let Some(ref header) = autocryptheader { if let Some(ref header) = autocryptheader {
peerstate.apply_header(&header, message_time); peerstate.apply_header(&header, message_time);
peerstate.save_to_db(&context.sql, false)?; peerstate.save_to_db(&context.sql, false).unwrap();
} else if message_time > peerstate.last_seen_autocrypt } else if message_time > peerstate.last_seen_autocrypt
&& !contains_report(in_out_message) && !contains_report(in_out_message)
{ {
peerstate.degrade_encryption(message_time); peerstate.degrade_encryption(message_time);
peerstate.save_to_db(&context.sql, false)?; peerstate.save_to_db(&context.sql, false).unwrap();
}
} else if let Some(ref header) = autocryptheader {
let p = Peerstate::from_header(context, header, message_time);
p.save_to_db(&context.sql, true)?;
peerstate = Some(p);
} }
} else if let Some(ref header) = autocryptheader {
let p = Peerstate::from_header(context, header, message_time);
p.save_to_db(&context.sql, true).unwrap();
peerstate = Some(p);
} }
} }
/* load private key for decryption */ }
let self_addr = context.get_config(Config::ConfiguredAddr); /* load private key for decryption */
if let Some(self_addr) = self_addr { let self_addr = context.get_config(Config::ConfiguredAddr);
if private_keyring.load_self_private_for_decrypting( if let Some(self_addr) = self_addr {
if private_keyring.load_self_private_for_decrypting(context, self_addr, &context.sql) {
if peerstate.as_ref().map(|p| p.last_seen).unwrap_or_else(|| 0) == 0 {
peerstate =
Peerstate::from_addr(&context, &context.sql, &from.unwrap_or_default());
}
if let Some(ref peerstate) = peerstate {
if peerstate.degrade_event.is_some() {
handle_degrade_event(context, &peerstate)?;
}
if let Some(ref key) = peerstate.gossip_key {
public_keyring_for_validate.add_ref(key);
}
if let Some(ref key) = peerstate.public_key {
public_keyring_for_validate.add_ref(key);
}
}
encrypted = decrypt_if_autocrypt_message(
context, context,
self_addr, in_out_message,
&context.sql, &private_keyring,
) { &public_keyring_for_validate,
if peerstate.as_ref().map(|p| p.last_seen).unwrap_or_else(|| 0) == 0 { &mut signatures,
peerstate = &mut gossip_headers,
Peerstate::from_addr(&context, &context.sql, &from.unwrap_or_default()); )?;
} if !gossip_headers.is_null() {
if let Some(ref peerstate) = peerstate { gossipped_addr =
if peerstate.degrade_event.is_some() { update_gossip_peerstates(context, message_time, imffields, gossip_headers)?;
handle_degrade_event(context, &peerstate)?;
}
if let Some(ref key) = peerstate.gossip_key {
public_keyring_for_validate.add_ref(key);
}
if let Some(ref key) = peerstate.public_key {
public_keyring_for_validate.add_ref(key);
}
}
match decrypt_if_autocrypt_message(
context,
in_out_message,
&private_keyring,
&public_keyring_for_validate,
&mut self.signatures,
&mut gossip_headers,
) {
Ok(res) => {
self.encrypted = res;
}
Err(err) => {
bail!("failed to decrypt: {}", err);
}
}
if !gossip_headers.is_null() {
self.gossipped_addr = update_gossip_peerstates(
context,
message_time,
imffields,
gossip_headers,
)?;
}
} }
} }
} }
if !gossip_headers.is_null() {
mailimf_fields_free(gossip_headers);
}
Ok(())
} }
if !gossip_headers.is_null() {
unsafe { mailimf_fields_free(gossip_headers) };
}
Ok((encrypted, signatures, gossipped_addr))
} }
fn new_data_part( fn new_data_part(
@@ -414,31 +373,34 @@ fn new_data_part(
default_encoding: u32, default_encoding: u32,
) -> Result<*mut Mailmime> { ) -> Result<*mut Mailmime> {
let content = new_content_type(&content_type)?; let content = new_content_type(&content_type)?;
unsafe { let mut encoding = ptr::null_mut();
let mut encoding: *mut mailmime_mechanism = ptr::null_mut(); if wrapmime::content_type_needs_encoding(content) {
if wrapmime::content_type_needs_encoding(content) { encoding = unsafe { mailmime_mechanism_new(default_encoding as i32, ptr::null_mut()) };
encoding = mailmime_mechanism_new(default_encoding as i32, ptr::null_mut()); ensure!(!encoding.is_null(), "failed to create encoding");
ensure!(!encoding.is_null(), "failed to create encoding");
}
let mime_fields = mailmime_fields_new_with_data(
encoding,
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
);
ensure!(!mime_fields.is_null(), "internal mime error");
let mime = mailmime_new_empty(content, mime_fields);
ensure!(!mime.is_null(), "internal mime error");
if (*mime).mm_type == MAILMIME_SINGLE as libc::c_int {
if !data.is_null() && data_bytes > 0 {
mailmime_set_body_text(mime, data as *mut libc::c_char, data_bytes);
}
}
return Ok(mime);
} }
let mime_fields = {
unsafe {
mailmime_fields_new_with_data(
encoding,
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
)
}
};
ensure!(!mime_fields.is_null(), "internal mime error");
let mime = unsafe { mailmime_new_empty(content, mime_fields) };
ensure!(!mime.is_null(), "internal mime error");
if unsafe { (*mime).mm_type } == MAILMIME_SINGLE as libc::c_int {
if !data.is_null() && data_bytes > 0 {
unsafe { mailmime_set_body_text(mime, data as *mut libc::c_char, data_bytes) };
}
}
Ok(mime)
} }
/// Load public key from database or generate a new one. /// Load public key from database or generate a new one.
@@ -488,7 +450,7 @@ fn load_or_generate_self_public_key(context: &Context, self_addr: impl AsRef<str
} }
} }
unsafe fn update_gossip_peerstates( fn update_gossip_peerstates(
context: &Context, context: &Context,
message_time: i64, message_time: i64,
imffields: *mut mailimf_fields, imffields: *mut mailimf_fields,
@@ -498,21 +460,27 @@ unsafe fn update_gossip_peerstates(
let mut recipients: Option<HashSet<String>> = None; let mut recipients: Option<HashSet<String>> = None;
let mut gossipped_addr: HashSet<String> = Default::default(); let mut gossipped_addr: HashSet<String> = Default::default();
for cur_data in (*(*gossip_headers).fld_list).into_iter() { for cur_data in unsafe { (*(*gossip_headers).fld_list).into_iter() } {
let field: *mut mailimf_field = cur_data as *mut _; let field = cur_data as *mut mailimf_field;
if (*field).fld_type == MAILIMF_FIELD_OPTIONAL_FIELD as libc::c_int { if field.is_null() {
let optional_field = (*field).fld_data.fld_optional_field; continue;
if !optional_field.is_null() }
&& !(*optional_field).fld_name.is_null()
&& strcasecmp( let field = unsafe { *field };
(*optional_field).fld_name,
b"Autocrypt-Gossip\x00" as *const u8 as *const libc::c_char, if field.fld_type == MAILIMF_FIELD_OPTIONAL_FIELD as libc::c_int {
) == 0i32 let optional_field = unsafe { field.fld_data.fld_optional_field };
if optional_field.is_null() {
continue;
}
let optional_field = unsafe { *optional_field };
if !optional_field.fld_name.is_null()
&& as_str(optional_field.fld_name) == "Autocrypt-Gossip"
{ {
let value = CStr::from_ptr((*optional_field).fld_value) let value = to_string_lossy(optional_field.fld_value);
.to_str() let gossip_header = Aheader::from_str(&value);
.unwrap();
let gossip_header = Aheader::from_str(value);
if let Ok(ref header) = gossip_header { if let Ok(ref header) = gossip_header {
if recipients.is_none() { if recipients.is_none() {
recipients = Some(mailimf_get_recipients(imffields)); recipients = Some(mailimf_get_recipients(imffields));
@@ -582,16 +550,15 @@ fn decrypt_if_autocrypt_message(
public_keyring_for_validate, public_keyring_for_validate,
ret_valid_signatures, ret_valid_signatures,
)?; )?;
/* decrypted_mime is a dangling pointer which we now put into // decrypted_mime is a dangling pointer which we now put into mailmime's Ownership
mailmime's Ownership */
unsafe { unsafe {
mailmime_substitute(mime, decrypted_mime); mailmime_substitute(mime, decrypted_mime);
mailmime_free(mime); mailmime_free(mime);
} }
/* finally, let's also return gossip headers // finally, let's also return gossip headers
XXX better return parsed headers so that upstream // XXX better return parsed headers so that upstream
does not need to dive into mmime-stuff again. */ // does not need to dive into mmime-stuff again.
unsafe { unsafe {
if (*ret_gossip_headers).is_null() && ret_valid_signatures.len() > 0 { if (*ret_gossip_headers).is_null() && ret_valid_signatures.len() > 0 {
let mut dummy: libc::size_t = 0; let mut dummy: libc::size_t = 0;
@@ -604,11 +571,12 @@ fn decrypt_if_autocrypt_message(
) == MAILIMF_NO_ERROR as libc::c_int ) == MAILIMF_NO_ERROR as libc::c_int
&& !test.is_null() && !test.is_null()
{ {
*ret_gossip_headers = test *ret_gossip_headers = test;
} }
} }
} }
return Ok(true);
Ok(true)
} }
fn decrypt_part( fn decrypt_part(
@@ -634,74 +602,75 @@ fn decrypt_part(
let (decoded_data, decoded_data_bytes) = let (decoded_data, decoded_data_bytes) =
wrapmime::decode_dt_data(mime_data, mime_transfer_encoding)?; 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, // encrypted, non-NULL decoded data in decoded_data now ...
after encryption has been attempted. // 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(); let mut ret_decrypted_mime = ptr::null_mut();
unsafe { ensure!(!decoded_data.is_null(), "Missing data");
if has_decrypted_pgp_armor(decoded_data, decoded_data_bytes as libc::c_int) { let data = unsafe { std::slice::from_raw_parts(decoded_data as *const u8, decoded_data_bytes) };
/* we should only have one decryption happening */ if has_decrypted_pgp_armor(data) {
ensure!(ret_valid_signatures.is_empty(), "corrupt signatures"); // we should only have one decryption happening
ensure!(ret_valid_signatures.is_empty(), "corrupt signatures");
let plain = match dc_pgp_pk_decrypt( let plain = match dc_pgp_pk_decrypt(
std::slice::from_raw_parts(decoded_data as *const u8, decoded_data_bytes), data,
&private_keyring, &private_keyring,
&public_keyring_for_validate, &public_keyring_for_validate,
Some(ret_valid_signatures), Some(ret_valid_signatures),
) { ) {
Ok(plain) => { Ok(plain) => {
ensure!(!ret_valid_signatures.is_empty(), "no valid signatures"); ensure!(!ret_valid_signatures.is_empty(), "no valid signatures");
plain plain
} }
Err(err) => { Err(err) => {
mmap_string_unref(decoded_data); unsafe { mmap_string_unref(decoded_data) };
bail!("could not decrypt: {}", err) bail!("could not decrypt: {}", err)
} }
}; };
let plain_bytes = plain.len(); let plain_bytes = plain.len();
let plain_buf = plain.as_ptr() as *const libc::c_char; let plain_buf = plain.as_ptr() as *const libc::c_char;
let mut index: libc::size_t = 0; let mut index = 0;
let mut decrypted_mime: *mut Mailmime = ptr::null_mut(); let mut decrypted_mime = ptr::null_mut();
if mailmime_parse( if unsafe {
mailmime_parse(
plain_buf as *const _, plain_buf as *const _,
plain_bytes, plain_bytes,
&mut index, &mut index,
&mut decrypted_mime, &mut decrypted_mime,
) != MAIL_NO_ERROR as libc::c_int )
|| decrypted_mime.is_null() } != MAIL_NO_ERROR as libc::c_int
{ || decrypted_mime.is_null()
if !decrypted_mime.is_null() { {
mailmime_free(decrypted_mime); if !decrypted_mime.is_null() {
} unsafe { mailmime_free(decrypted_mime) };
} else {
ret_decrypted_mime = decrypted_mime;
} }
} else {
// decrypted_mime points into `plain`.
// FIXME(@dignifiedquire): this still leaks memory I believe, as mailmime_free
// does not free the underlying buffer. But for now we have to live with it
std::mem::forget(plain); std::mem::forget(plain);
ret_decrypted_mime = decrypted_mime;
} }
mmap_string_unref(decoded_data);
} }
unsafe { mmap_string_unref(decoded_data) };
Ok(ret_decrypted_mime) Ok(ret_decrypted_mime)
} }
unsafe fn has_decrypted_pgp_armor(str__: *const libc::c_char, mut str_bytes: libc::c_int) -> bool { fn has_decrypted_pgp_armor(input: &[u8]) -> bool {
let str_end: *const libc::c_uchar = (str__ as *const libc::c_uchar).offset(str_bytes as isize); if let Some(index) = input.iter().position(|b| *b > b' ') {
let mut p: *const libc::c_uchar = str__ as *const libc::c_uchar; if input.len() - index > 26 {
while p < str_end { let start = index;
if *p as libc::c_int > ' ' as i32 { let end = start + 27;
break;
return &input[start..end] == b"-----BEGIN PGP MESSAGE-----";
} }
p = p.offset(1isize);
str_bytes -= 1
} }
str_bytes > 27i32
&& strncmp( false
p as *const libc::c_char,
b"-----BEGIN PGP MESSAGE-----\x00" as *const u8 as *const libc::c_char,
27,
) == 0
} }
/// Check if a MIME structure contains a multipart/report part. /// Check if a MIME structure contains a multipart/report part.
@@ -712,29 +681,31 @@ unsafe fn has_decrypted_pgp_armor(str__: *const libc::c_char, mut str_bytes: lib
/// However, Delta Chat itself has no problem with encrypted multipart/report /// However, Delta Chat itself has no problem with encrypted multipart/report
/// parts and MUAs should be encouraged to encrpyt multipart/reports as well so /// parts and MUAs should be encouraged to encrpyt multipart/reports as well so
/// that we could use the normal Autocrypt processing. /// that we could use the normal Autocrypt processing.
unsafe fn contains_report(mime: *mut Mailmime) -> bool { fn contains_report(mime: *mut Mailmime) -> bool {
if (*mime).mm_type == MAILMIME_MULTIPLE as libc::c_int { assert!(!mime.is_null());
if (*(*(*mime).mm_content_type).ct_type).tp_type let mime = unsafe { *mime };
== MAILMIME_TYPE_COMPOSITE_TYPE as libc::c_int
&& (*(*(*(*mime).mm_content_type).ct_type) if mime.mm_type == MAILMIME_MULTIPLE as libc::c_int {
.tp_data let tp_type = unsafe { (*(*mime.mm_content_type).ct_type).tp_type };
.tp_composite_type) let ct_type =
.ct_type unsafe { (*(*(*mime.mm_content_type).ct_type).tp_data.tp_composite_type).ct_type };
== MAILMIME_COMPOSITE_TYPE_MULTIPART as libc::c_int
&& strcmp( if tp_type == MAILMIME_TYPE_COMPOSITE_TYPE as libc::c_int
(*(*mime).mm_content_type).ct_subtype, && ct_type == MAILMIME_COMPOSITE_TYPE_MULTIPART as libc::c_int
b"report\x00" as *const u8 as *const libc::c_char, && as_str(unsafe { (*mime.mm_content_type).ct_subtype }) == "report"
) == 0i32
{ {
return true; return true;
} }
for cur_data in (*(*(*mime).mm_mime_fields).fld_list).into_iter() {
for cur_data in unsafe { (*(*mime.mm_mime_fields).fld_list).into_iter() } {
if contains_report(cur_data as *mut Mailmime) { if contains_report(cur_data as *mut Mailmime) {
return true; return true;
} }
} }
} else if (*mime).mm_type == MAILMIME_MESSAGE as libc::c_int { } else if mime.mm_type == MAILMIME_MESSAGE as libc::c_int {
if contains_report((*mime).mm_data.mm_message.mm_msg_mime) { let m = unsafe { mime.mm_data.mm_message.mm_msg_mime };
if contains_report(m) {
return true; return true;
} }
} }
@@ -869,4 +840,22 @@ Sent with my Delta Chat Messenger: https://delta.chat";
assert_eq!(res0.unwrap(), res1.unwrap()); assert_eq!(res0.unwrap(), res1.unwrap());
} }
} }
#[test]
fn test_has_decrypted_pgp_armor() {
let data = b" -----BEGIN PGP MESSAGE-----";
assert_eq!(has_decrypted_pgp_armor(data), true);
let data = b" \n-----BEGIN PGP MESSAGE-----";
assert_eq!(has_decrypted_pgp_armor(data), true);
let data = b" -----BEGIN PGP MESSAGE---";
assert_eq!(has_decrypted_pgp_armor(data), false);
let data = b" -----BEGIN PGP MESSAGE-----";
assert_eq!(has_decrypted_pgp_armor(data), true);
let data = b"blas";
assert_eq!(has_decrypted_pgp_armor(data), false);
}
} }

View File

@@ -413,7 +413,7 @@ pub fn handle_securejoin_handshake(
could_not_establish_secure_connection( could_not_establish_secure_connection(
context, context,
contact_chat_id, contact_chat_id,
if mimeparser.e2ee_helper.encrypted { if mimeparser.encrypted {
"No valid signature." "No valid signature."
} else { } else {
"Not encrypted." "Not encrypted."
@@ -693,17 +693,16 @@ fn mark_peer_as_verified(context: &Context, fingerprint: impl AsRef<str>) -> Res
******************************************************************************/ ******************************************************************************/
fn encrypted_and_signed(mimeparser: &MimeParser, expected_fingerprint: impl AsRef<str>) -> bool { fn encrypted_and_signed(mimeparser: &MimeParser, expected_fingerprint: impl AsRef<str>) -> bool {
if !mimeparser.e2ee_helper.encrypted { if !mimeparser.encrypted {
warn!(mimeparser.context, "Message not encrypted.",); warn!(mimeparser.context, "Message not encrypted.",);
false false
} else if mimeparser.e2ee_helper.signatures.len() <= 0 { } else if mimeparser.signatures.len() <= 0 {
warn!(mimeparser.context, "Message not signed.",); warn!(mimeparser.context, "Message not signed.",);
false false
} else if expected_fingerprint.as_ref().is_empty() { } else if expected_fingerprint.as_ref().is_empty() {
warn!(mimeparser.context, "Fingerprint for comparison missing.",); warn!(mimeparser.context, "Fingerprint for comparison missing.",);
false false
} else if !mimeparser } else if !mimeparser
.e2ee_helper
.signatures .signatures
.contains(expected_fingerprint.as_ref()) .contains(expected_fingerprint.as_ref())
{ {