remove mmime

This commit is contained in:
dignifiedquire
2019-11-28 19:20:43 +01:00
parent 1f8d2531cc
commit dbd6303829
48 changed files with 2746 additions and 25814 deletions

View File

@@ -1,28 +1,12 @@
//! End-to-end encryption support.
use std::collections::HashSet;
use std::ptr;
use std::str::FromStr;
use libc::strlen;
use mmime::clist::*;
use mmime::mailimf::types::*;
use mmime::mailimf::types_helper::*;
use mmime::mailimf::*;
use mmime::mailmime::content::*;
use mmime::mailmime::types::*;
use mmime::mailmime::types_helper::*;
use mmime::mailmime::write_mem::*;
use mmime::mailmime::*;
use mmime::mailprivacy_prepare_mime;
use mmime::mmapstring::*;
use mmime::{mailmime_substitute, MAILIMF_NO_ERROR, MAIL_NO_ERROR};
use num_traits::FromPrimitive;
use crate::aheader::*;
use crate::config::Config;
use crate::context::Context;
use crate::dc_tools::*;
use crate::error::*;
use crate::key::*;
use crate::keyring::*;
@@ -31,7 +15,6 @@ use crate::peerstate::*;
use crate::pgp;
use crate::securejoin::handle_degrade_event;
use crate::wrapmime;
use crate::wrapmime::*;
// standard mime-version header aka b"Version: 1\r\n\x00"
static mut VERSION_CONTENT: [libc::c_char; 13] =
@@ -77,203 +60,203 @@ impl EncryptHelper {
e2ee_guaranteed: bool,
min_verified: PeerstateVerifiedStatus,
do_gossip: bool,
mut in_out_message: *mut Mailmime,
imffields_unprotected: *mut mailimf_fields,
) -> Result<bool> {
// libEtPan's pgp_encrypt_mime() takes the parent as the new root.
// We just expect the root as being given to this function.
ensure!(
!in_out_message.is_null() && unsafe { (*in_out_message).mm_parent.is_null() },
"corrupted inputs"
);
mut in_out_message: lettre_email::Email,
imffields_unprotected: Vec<lettre_email::Header>,
) -> Result<lettre_email::Email> {
unimplemented!()
// // libEtPan's pgp_encrypt_mime() takes the parent as the new root.
// // We just expect the root as being given to this function.
// ensure!(
// !in_out_message.is_null() && { (*in_out_message).mm_parent.is_null() },
// "corrupted inputs"
// );
if !(self.prefer_encrypt == EncryptPreference::Mutual || e2ee_guaranteed) {
return Ok(false);
}
// if !(self.prefer_encrypt == EncryptPreference::Mutual || e2ee_guaranteed) {
// return Ok(false);
// }
let context = &factory.context;
let mut keyring = Keyring::default();
let mut gossip_headers: Vec<String> = Vec::with_capacity(factory.recipients_addr.len());
// let context = &factory.context;
// let mut keyring = Keyring::default();
// let mut gossip_headers: Vec<String> = Vec::with_capacity(factory.recipients_addr.len());
// determine if we can and should encrypt
for recipient_addr in factory.recipients_addr.iter() {
if recipient_addr == &self.addr {
continue;
}
let peerstate = match Peerstate::from_addr(context, &context.sql, recipient_addr) {
Some(peerstate) => peerstate,
None => {
let msg = format!("peerstate for {} missing, cannot encrypt", recipient_addr);
if e2ee_guaranteed {
return Err(format_err!("{}", msg));
} else {
info!(context, "{}", msg);
return Ok(false);
}
}
};
// // determine if we can and should encrypt
// for recipient_addr in factory.recipients_addr.iter() {
// if recipient_addr == &self.addr {
// continue;
// }
// let peerstate = match Peerstate::from_addr(context, &context.sql, recipient_addr) {
// Some(peerstate) => peerstate,
// None => {
// let msg = format!("peerstate for {} missing, cannot encrypt", recipient_addr);
// if e2ee_guaranteed {
// return Err(format_err!("{}", msg));
// } else {
// info!(context, "{}", msg);
// return Ok(false);
// }
// }
// };
if peerstate.prefer_encrypt != EncryptPreference::Mutual && !e2ee_guaranteed {
info!(context, "peerstate for {} is no-encrypt", recipient_addr);
return Ok(false);
}
// if peerstate.prefer_encrypt != EncryptPreference::Mutual && !e2ee_guaranteed {
// info!(context, "peerstate for {} is no-encrypt", recipient_addr);
// return Ok(false);
// }
if let Some(key) = peerstate.peek_key(min_verified) {
keyring.add_owned(key.clone());
if do_gossip {
if let Some(header) = peerstate.render_gossip_header(min_verified) {
gossip_headers.push(header.to_string());
}
}
} else {
bail!(
"proper enc-key for {} missing, cannot encrypt",
recipient_addr
);
}
}
// if let Some(key) = peerstate.peek_key(min_verified) {
// keyring.add_owned(key.clone());
// if do_gossip {
// if let Some(header) = peerstate.render_gossip_header(min_verified) {
// gossip_headers.push(header.to_string());
// }
// }
// } else {
// bail!(
// "proper enc-key for {} missing, cannot encrypt",
// recipient_addr
// );
// }
// }
let sign_key = {
keyring.add_ref(&self.public_key);
let key = Key::from_self_private(context, self.addr.clone(), &context.sql);
ensure!(key.is_some(), "no own private key found");
// let sign_key = {
// keyring.add_ref(&self.public_key);
// let key = Key::from_self_private(context, self.addr.clone(), &context.sql);
// ensure!(key.is_some(), "no own private key found");
key
};
// key
// };
// encrypt message
unsafe {
mailprivacy_prepare_mime(in_out_message);
let mut part_to_encrypt = (*in_out_message).mm_data.mm_message.mm_msg_mime;
(*part_to_encrypt).mm_parent = ptr::null_mut();
let imffields_encrypted = mailimf_fields_new_empty();
// // encrypt message
// {
// mailprivacy_prepare_mime(in_out_message);
// let mut part_to_encrypt = (*in_out_message).mm_data.mm_message.mm_msg_mime;
// (*part_to_encrypt).mm_parent = ptr::null_mut();
// 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 = mailmime_new_simple(
MAILMIME_MESSAGE as libc::c_int,
mailmime_fields_new_empty(),
mailmime_get_content_message(),
imffields_encrypted,
part_to_encrypt,
);
// // 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_fields_new_empty(),
// mailmime_get_content_message(),
// imffields_encrypted,
// part_to_encrypt,
// );
for header in &gossip_headers {
wrapmime::new_custom_field(imffields_encrypted, "Autocrypt-Gossip", &header)
}
// for header in &gossip_headers {
// wrapmime::new_custom_field(imffields_encrypted, "Autocrypt-Gossip", &header)
// }
// 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
let mut cur = (*(*imffields_unprotected).fld_list).first;
while !cur.is_null() {
let field = (*cur).data as *mut mailimf_field;
let mut move_to_encrypted = false;
// // 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
// let mut cur = (*(*imffields_unprotected).fld_list).first;
// while !cur.is_null() {
// let field = (*cur).data as *mut mailimf_field;
// let mut move_to_encrypted = false;
if !field.is_null() {
if (*field).fld_type == MAILIMF_FIELD_SUBJECT as libc::c_int {
move_to_encrypted = true;
} else if (*field).fld_type == MAILIMF_FIELD_OPTIONAL_FIELD as libc::c_int {
let opt_field = (*field).fld_data.fld_optional_field;
if !opt_field.is_null() && !(*opt_field).fld_name.is_null() {
let fld_name = to_string_lossy((*opt_field).fld_name);
if fld_name.starts_with("Secure-Join")
|| (fld_name.starts_with("Chat-") && fld_name != "Chat-Version")
{
move_to_encrypted = true;
}
}
}
}
// if !field.is_null() {
// if (*field).fld_type == MAILIMF_FIELD_SUBJECT as libc::c_int {
// move_to_encrypted = true;
// } else if (*field).fld_type == MAILIMF_FIELD_OPTIONAL_FIELD as libc::c_int {
// let opt_field = (*field).fld_data.fld_optional_field;
// if !opt_field.is_null() && !(*opt_field).fld_name.is_null() {
// let fld_name = to_string_lossy((*opt_field).fld_name);
// if fld_name.starts_with("Secure-Join")
// || (fld_name.starts_with("Chat-") && fld_name != "Chat-Version")
// {
// move_to_encrypted = true;
// }
// }
// }
// }
if move_to_encrypted {
mailimf_fields_add(imffields_encrypted, field);
cur = clist_delete((*imffields_unprotected).fld_list, cur);
} else {
cur = (*cur).next;
}
}
// if move_to_encrypted {
// mailimf_fields_add(imffields_encrypted, field);
// cur = clist_delete((*imffields_unprotected).fld_list, cur);
// } else {
// cur = (*cur).next;
// }
// }
let subject = mailimf_subject_new("...".strdup());
mailimf_fields_add(imffields_unprotected, mailimf_field_new_subject(subject));
// let subject = mailimf_subject_new("...".strdup());
// mailimf_fields_add(imffields_unprotected, mailimf_field_new_subject(subject));
wrapmime::append_ct_param(
(*part_to_encrypt).mm_content_type,
"protected-headers",
"v1",
)?;
let plain = mmap_string_new(b"\x00" as *const u8 as *const libc::c_char);
let mut col = 0;
mailmime_write_mem(plain, &mut col, message_to_encrypt);
mailmime_free(message_to_encrypt);
// wrapmime::append_ct_param(
// (*part_to_encrypt).mm_content_type,
// "protected-headers",
// "v1",
// )?;
// let plain = mmap_string_new(b"\x00" as *const u8 as *const libc::c_char);
// let mut col = 0;
// mailmime_write_mem(plain, &mut col, message_to_encrypt);
// mailmime_free(message_to_encrypt);
ensure!(
!(*plain).str_0.is_null() && (*plain).len > 0,
"could not write/allocate"
);
// ensure!(
// !(*plain).str_0.is_null() && (*plain).len > 0,
// "could not write/allocate"
// );
let ctext = pgp::pk_encrypt(
std::slice::from_raw_parts((*plain).str_0 as *const u8, (*plain).len),
&keyring,
sign_key.as_ref(),
);
mmap_string_free(plain);
// let ctext = pgp::pk_encrypt(
// std::slice::from_raw_parts((*plain).str_0 as *const u8, (*plain).len),
// &keyring,
// sign_key.as_ref(),
// );
// mmap_string_free(plain);
let ctext_v = ctext?;
// let ctext_v = ctext?;
// create MIME-structure that will contain the encrypted text
let mut encrypted_part = new_data_part(
ptr::null_mut(),
0 as libc::size_t,
"multipart/encrypted",
MAILMIME_MECHANISM_BASE64,
)?;
let content = (*encrypted_part).mm_content_type;
wrapmime::append_ct_param(content, "protocol", "application/pgp-encrypted")?;
// // create MIME-structure that will contain the encrypted text
// let mut encrypted_part = new_data_part(
// ptr::null_mut(),
// 0 as libc::size_t,
// "multipart/encrypted",
// MAILMIME_MECHANISM_BASE64,
// )?;
// let content = (*encrypted_part).mm_content_type;
// wrapmime::append_ct_param(content, "protocol", "application/pgp-encrypted")?;
let version_mime = 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);
// let version_mime = 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
// 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,
)?;
// // 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)?;
// 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)
}
// Ok(true)
// }
}
}
pub fn try_decrypt(
context: &Context,
in_out_message: *mut Mailmime,
) -> Result<(bool, HashSet<String>, HashSet<String>)> {
// just a pointer into mailmime structure, must not be freed
let imffields = mailmime_find_mailimf_fields(in_out_message);
ensure!(
!in_out_message.is_null() && !imffields.is_null(),
"corrupt invalid mime inputs"
);
mail: &mailparse::ParsedMail<'_>,
) -> Result<(Option<Vec<u8>>, HashSet<String>, HashSet<String>)> {
use mailparse::MailHeaderMap;
let from = wrapmime::get_field_from(imffields)?;
let message_time = wrapmime::get_field_date(imffields)?;
let from = mail.headers.get_first_value("From")?.unwrap_or_default();
let message_time = mail
.headers
.get_first_value("Date")?
.and_then(|v| v.parse().ok())
.unwrap_or_default();
let mut peerstate = None;
let autocryptheader = Aheader::from_imffields(&from, imffields);
let autocryptheader = Aheader::from_imffields(&from, &mail.headers);
if message_time > 0 {
peerstate = Peerstate::from_addr(context, &context.sql, &from);
@@ -282,9 +265,7 @@ pub fn try_decrypt(
if let Some(ref header) = autocryptheader {
peerstate.apply_header(&header, message_time);
peerstate.save_to_db(&context.sql, false)?;
} else if message_time > peerstate.last_seen_autocrypt
&& !contains_report(in_out_message)
{
} else if message_time > peerstate.last_seen_autocrypt && !contains_report(mail) {
peerstate.degrade_encryption(message_time);
peerstate.save_to_db(&context.sql, false)?;
}
@@ -297,10 +278,9 @@ pub fn try_decrypt(
/* possibly perform decryption */
let mut private_keyring = Keyring::default();
let mut public_keyring_for_validate = Keyring::default();
let mut encrypted = false;
let mut signatures = HashSet::default();
let mut out_mail = None;
let mut gossipped_addr = HashSet::default();
let mut signatures = HashSet::default();
let self_addr = context.get_config(Config::ConfiguredAddr);
if let Some(self_addr) = self_addr {
@@ -320,61 +300,60 @@ pub fn try_decrypt(
}
}
let mut gossip_headers = ptr::null_mut();
encrypted = decrypt_if_autocrypt_message(
out_mail = decrypt_if_autocrypt_message(
context,
in_out_message,
mail,
&private_keyring,
&public_keyring_for_validate,
&mut signatures,
&mut gossip_headers,
)?;
if !gossip_headers.is_null() {
gossipped_addr =
update_gossip_peerstates(context, message_time, imffields, gossip_headers)?;
unsafe { mailimf_fields_free(gossip_headers) };
}
// TODO:
// if !gossip_headers.is_empty() {
// gossipped_addr =
// update_gossip_peerstates(context, message_time, imffields, gossip_headers)?;
// }
}
}
Ok((encrypted, signatures, gossipped_addr))
Ok((out_mail, signatures, gossipped_addr))
}
fn new_data_part(
data: *mut libc::c_void,
data_bytes: libc::size_t,
content_type: &str,
default_encoding: u32,
) -> Result<*mut Mailmime> {
let content = new_content_type(&content_type)?;
let mut encoding = ptr::null_mut();
if wrapmime::content_type_needs_encoding(content) {
encoding = unsafe { mailmime_mechanism_new(default_encoding as i32, ptr::null_mut()) };
ensure!(!encoding.is_null(), "failed to create encoding");
}
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)
}
// fn new_data_part(
// data: *mut libc::c_void,
// data_bytes: libc::size_t,
// content_type: &str,
// default_encoding: u32,
// ) -> Result<*mut Mailmime> {
// let content = new_content_type(&content_type)?;
// let mut encoding = ptr::null_mut();
// if wrapmime::content_type_needs_encoding(content) {
// encoding = { mailmime_mechanism_new(default_encoding as i32, ptr::null_mut()) };
// 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) };
// }
// }
//
// Ok(mime)
// }
/// Load public key from database or generate a new one.
///
@@ -423,204 +402,158 @@ fn load_or_generate_self_public_key(context: &Context, self_addr: impl AsRef<str
}
}
fn update_gossip_peerstates(
// fn update_gossip_peerstates(
// context: &Context,
// message_time: i64,
// imffields: *mut mailimf_fields,
// gossip_headers: *const mailimf_fields,
// ) -> Result<HashSet<String>> {
// // XXX split the parsing from the modification part
// let mut recipients: Option<HashSet<String>> = None;
// let mut gossipped_addr: HashSet<String> = Default::default();
// for cur_data in { (*(*gossip_headers).fld_list).into_iter() } {
// let field = cur_data as *mut mailimf_field;
// if field.is_null() {
// continue;
// }
// let field = { *field };
// if field.fld_type == MAILIMF_FIELD_OPTIONAL_FIELD as libc::c_int {
// let optional_field = { field.fld_data.fld_optional_field };
// if optional_field.is_null() {
// continue;
// }
// let optional_field = { *optional_field };
// if !optional_field.fld_name.is_null()
// && to_string_lossy(optional_field.fld_name) == "Autocrypt-Gossip"
// {
// let value = to_string_lossy(optional_field.fld_value);
// let gossip_header = Aheader::from_str(&value);
// if let Ok(ref header) = gossip_header {
// if recipients.is_none() {
// recipients = Some(mailimf_get_recipients(imffields));
// }
// if recipients.as_ref().unwrap().contains(&header.addr) {
// let mut peerstate =
// Peerstate::from_addr(context, &context.sql, &header.addr);
// if let Some(ref mut peerstate) = peerstate {
// peerstate.apply_gossip(header, message_time);
// peerstate.save_to_db(&context.sql, false)?;
// } else {
// let p = Peerstate::from_gossip(context, header, message_time);
// p.save_to_db(&context.sql, true)?;
// peerstate = Some(p);
// }
// if let Some(peerstate) = peerstate {
// if peerstate.degrade_event.is_some() {
// handle_degrade_event(context, &peerstate)?;
// }
// }
// gossipped_addr.insert(header.addr.clone());
// } else {
// info!(
// context,
// "Ignoring gossipped \"{}\" as the address is not in To/Cc list.",
// &header.addr,
// );
// }
// }
// }
// }
// }
// Ok(gossipped_addr)
// }
fn decrypt_if_autocrypt_message<'a>(
context: &Context,
message_time: i64,
imffields: *mut mailimf_fields,
gossip_headers: *const mailimf_fields,
) -> Result<HashSet<String>> {
// XXX split the parsing from the modification part
let mut recipients: Option<HashSet<String>> = None;
let mut gossipped_addr: HashSet<String> = Default::default();
for cur_data in unsafe { (*(*gossip_headers).fld_list).into_iter() } {
let field = cur_data as *mut mailimf_field;
if field.is_null() {
continue;
}
let field = unsafe { *field };
if field.fld_type == MAILIMF_FIELD_OPTIONAL_FIELD as libc::c_int {
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()
&& to_string_lossy(optional_field.fld_name) == "Autocrypt-Gossip"
{
let value = to_string_lossy(optional_field.fld_value);
let gossip_header = Aheader::from_str(&value);
if let Ok(ref header) = gossip_header {
if recipients.is_none() {
recipients = Some(mailimf_get_recipients(imffields));
}
if recipients.as_ref().unwrap().contains(&header.addr) {
let mut peerstate =
Peerstate::from_addr(context, &context.sql, &header.addr);
if let Some(ref mut peerstate) = peerstate {
peerstate.apply_gossip(header, message_time);
peerstate.save_to_db(&context.sql, false)?;
} else {
let p = Peerstate::from_gossip(context, header, message_time);
p.save_to_db(&context.sql, true)?;
peerstate = Some(p);
}
if let Some(peerstate) = peerstate {
if peerstate.degrade_event.is_some() {
handle_degrade_event(context, &peerstate)?;
}
}
gossipped_addr.insert(header.addr.clone());
} else {
info!(
context,
"Ignoring gossipped \"{}\" as the address is not in To/Cc list.",
&header.addr,
);
}
}
}
}
}
Ok(gossipped_addr)
}
fn decrypt_if_autocrypt_message(
context: &Context,
mime_undetermined: *mut Mailmime,
mail: &mailparse::ParsedMail<'a>,
private_keyring: &Keyring,
public_keyring_for_validate: &Keyring,
ret_valid_signatures: &mut HashSet<String>,
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 then modifies the
passed in mime structure in place. The returned bool is false
if it was not an Autocrypt message.
) -> Result<Option<Vec<u8>>> {
// The returned bool is true if we detected an Autocrypt-encrypted
// 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 of AC-messages.
Errors are returned for failures related to decryption of AC-messages.
*/
ensure!(!mime_undetermined.is_null(), "Invalid mime reference");
let (mime, encrypted_data_part) = match wrapmime::get_autocrypt_mime(mime_undetermined) {
let encrypted_data_part = match wrapmime::get_autocrypt_mime(mail) {
Err(_) => {
// not a proper autocrypt message, abort and ignore
return Ok(false);
return Ok(None);
}
Ok(res) => res,
};
let decrypted_mime = decrypt_part(
let decrypted = decrypt_part(
context,
encrypted_data_part,
private_keyring,
public_keyring_for_validate,
ret_valid_signatures,
)?;
// decrypted_mime is a dangling pointer which we now put into mailmime's Ownership
unsafe {
mailmime_substitute(mime, decrypted_mime);
mailmime_free(mime);
}
// 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.is_empty() {
let mut dummy: libc::size_t = 0;
let mut test: *mut mailimf_fields = ptr::null_mut();
if mailimf_envelope_and_optional_fields_parse(
(*decrypted_mime).mm_mime_start,
(*decrypted_mime).mm_length,
&mut dummy,
&mut test,
) == MAILIMF_NO_ERROR as libc::c_int
&& !test.is_null()
{
*ret_gossip_headers = test;
}
}
}
// {
// if (*ret_gossip_headers).is_null() && !ret_valid_signatures.is_empty() {
// let mut dummy: libc::size_t = 0;
// let mut test: *mut mailimf_fields = ptr::null_mut();
// if mailimf_envelope_and_optional_fields_parse(
// (*decrypted_mime).mm_mime_start,
// (*decrypted_mime).mm_length,
// &mut dummy,
// &mut test,
// ) == MAILIMF_NO_ERROR as libc::c_int
// && !test.is_null()
// {
// *ret_gossip_headers = test;
// }
// }
// }
Ok(true)
Ok(decrypted)
}
/// Returns Ok(None) if nothing encrypted was found.
fn decrypt_part(
_context: &Context,
mime: *mut Mailmime,
mail: &mailparse::ParsedMail<'_>,
private_keyring: &Keyring,
public_keyring_for_validate: &Keyring,
ret_valid_signatures: &mut HashSet<String>,
) -> Result<*mut Mailmime> {
let mime_data: *mut mailmime_data;
let mut mime_transfer_encoding = MAILMIME_MECHANISM_BINARY as libc::c_int;
) -> Result<Option<Vec<u8>>> {
ensure!(
wrapmime::has_decryptable_data(mail),
"No decryptable data found"
);
unsafe {
mime_data = (*mime).mm_data.mm_single;
}
if !wrapmime::has_decryptable_data(mime_data) {
return Ok(ptr::null_mut());
}
if let Some(enc) = wrapmime::get_mime_transfer_encoding(mime) {
mime_transfer_encoding = enc;
}
let data: Vec<u8> = wrapmime::decode_dt_data(mime_data, mime_transfer_encoding)?;
let mut ret_decrypted_mime = ptr::null_mut();
let data = mail.get_body_raw()?;
if has_decrypted_pgp_armor(&data) {
// we should only have one decryption happening
ensure!(ret_valid_signatures.is_empty(), "corrupt signatures");
let plain = match pgp::pk_decrypt(
let plain = pgp::pk_decrypt(
&data,
&private_keyring,
&public_keyring_for_validate,
Some(ret_valid_signatures),
) {
Ok(plain) => {
ensure!(!ret_valid_signatures.is_empty(), "no valid signatures");
plain
}
Err(err) => bail!("could not decrypt: {}", err),
};
let plain_bytes = plain.len();
let plain_buf = plain.as_ptr() as *const libc::c_char;
)?;
let mut index = 0;
let mut decrypted_mime = ptr::null_mut();
if unsafe {
mailmime_parse(
plain_buf as *const _,
plain_bytes,
&mut index,
&mut decrypted_mime,
)
} != MAIL_NO_ERROR as libc::c_int
|| decrypted_mime.is_null()
{
if !decrypted_mime.is_null() {
unsafe { mailmime_free(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);
ret_decrypted_mime = decrypted_mime;
}
ensure!(!ret_valid_signatures.is_empty(), "no valid signatures");
return Ok(Some(plain));
}
Ok(ret_decrypted_mime)
Ok(None)
}
fn has_decrypted_pgp_armor(input: &[u8]) -> bool {
@@ -644,36 +577,8 @@ fn has_decrypted_pgp_armor(input: &[u8]) -> bool {
/// However, Delta Chat itself has no problem with encrypted multipart/report
/// parts and MUAs should be encouraged to encrpyt multipart/reports as well so
/// that we could use the normal Autocrypt processing.
fn contains_report(mime: *mut Mailmime) -> bool {
assert!(!mime.is_null());
let mime = unsafe { *mime };
if mime.mm_type == MAILMIME_MULTIPLE as libc::c_int {
let tp_type = unsafe { (*(*mime.mm_content_type).ct_type).tp_type };
let ct_type =
unsafe { (*(*(*mime.mm_content_type).ct_type).tp_data.tp_composite_type).ct_type };
if tp_type == MAILMIME_TYPE_COMPOSITE_TYPE as libc::c_int
&& ct_type == MAILMIME_COMPOSITE_TYPE_MULTIPART as libc::c_int
&& to_string_lossy(unsafe { (*mime.mm_content_type).ct_subtype }) == "report"
{
return true;
}
for cur_data in unsafe { (*(*mime.mm_mime_fields).fld_list).into_iter() } {
if contains_report(cur_data as *mut Mailmime) {
return true;
}
}
} else if mime.mm_type == MAILMIME_MESSAGE as libc::c_int {
let m = unsafe { mime.mm_data.mm_message.mm_msg_mime };
if contains_report(m) {
return true;
}
}
false
fn contains_report(mail: &mailparse::ParsedMail<'_>) -> bool {
mail.ctype.mimetype == "multipart/report"
}
/// Ensures a private key exists for the configured user.
@@ -699,7 +604,6 @@ pub fn ensure_secret_key_exists(context: &Context) -> Result<String> {
#[cfg(test)]
mod tests {
use super::*;
use libc::free;
use crate::test_utils::*;
@@ -720,46 +624,46 @@ mod tests {
}
}
#[test]
fn test_mailmime_parse() {
let plain = b"Chat-Disposition-Notification-To: holger@deltachat.de
Chat-Group-ID: CovhGgau8M-
Chat-Group-Name: Delta Chat Dev
Subject: =?utf-8?Q?Chat=3A?= Delta Chat =?utf-8?Q?Dev=3A?= sidenote for
=?utf-8?Q?all=3A?= rust core master ...
Content-Type: text/plain; charset=\"utf-8\"; protected-headers=\"v1\"
Content-Transfer-Encoding: quoted-printable
// #[test]
// fn test_mailmime_parse() {
// let plain = b"Chat-Disposition-Notification-To: holger@deltachat.de
// Chat-Group-ID: CovhGgau8M-
// Chat-Group-Name: Delta Chat Dev
// Subject: =?utf-8?Q?Chat=3A?= Delta Chat =?utf-8?Q?Dev=3A?= sidenote for
// =?utf-8?Q?all=3A?= rust core master ...
// Content-Type: text/plain; charset=\"utf-8\"; protected-headers=\"v1\"
// Content-Transfer-Encoding: quoted-printable
sidenote for all: rust core master is broken currently ... so dont recomm=
end to try to run with desktop or ios unless you are ready to hunt bugs
// sidenote for all: rust core master is broken currently ... so dont recomm=
// end to try to run with desktop or ios unless you are ready to hunt bugs
-- =20
Sent with my Delta Chat Messenger: https://delta.chat";
let plain_bytes = plain.len();
let plain_buf = plain.as_ptr() as *const libc::c_char;
// -- =20
// Sent with my Delta Chat Messenger: https://delta.chat";
// let plain_bytes = plain.len();
// let plain_buf = plain.as_ptr() as *const libc::c_char;
let mut index = 0;
let mut decrypted_mime = std::ptr::null_mut();
// let mut index = 0;
// let mut decrypted_mime = std::ptr::null_mut();
let res = unsafe {
mailmime_parse(
plain_buf as *const _,
plain_bytes,
&mut index,
&mut decrypted_mime,
)
};
unsafe {
let msg1 = (*decrypted_mime).mm_data.mm_message.mm_msg_mime;
let data = mailmime_transfer_decode(msg1).unwrap();
println!("{:?}", String::from_utf8_lossy(&data));
}
// let res = {
// mailmime_parse(
// plain_buf as *const _,
// plain_bytes,
// &mut index,
// &mut decrypted_mime,
// )
// };
// {
// let msg1 = (*decrypted_mime).mm_data.mm_message.mm_msg_mime;
// let data = mailmime_transfer_decode(msg1).unwrap();
// println!("{:?}", String::from_utf8_lossy(&data));
// }
assert_eq!(res, 0);
assert!(!decrypted_mime.is_null());
// assert_eq!(res, 0);
// assert!(!decrypted_mime.is_null());
unsafe { free(decrypted_mime as *mut _) };
}
// { free(decrypted_mime as *mut _) };
// }
mod load_or_generate_self_public_key {
use super::*;