mirror of
https://github.com/chatmail/core.git
synced 2026-05-08 09:26:29 +03:00
another rustification of encrypt()
This commit is contained in:
395
src/e2ee.rs
395
src/e2ee.rs
@@ -61,11 +61,7 @@ impl E2eeHelper {
|
|||||||
do_gossip: bool,
|
do_gossip: bool,
|
||||||
mut in_out_message: *mut mailmime,
|
mut in_out_message: *mut mailmime,
|
||||||
) -> Result<bool> {
|
) -> Result<bool> {
|
||||||
let mut col: libc::c_int = 0i32;
|
/* libEtPan's pgp_encrypt_mime() takes the parent as the new root. We just expect the root as being given to this function. */
|
||||||
let mut do_encrypt = false;
|
|
||||||
let mut keyring = Keyring::default();
|
|
||||||
let mut peerstates: Vec<Peerstate> = Vec::new();
|
|
||||||
|
|
||||||
if in_out_message.is_null() || !(*in_out_message).mm_parent.is_null() {
|
if in_out_message.is_null() || !(*in_out_message).mm_parent.is_null() {
|
||||||
bail!("invalid inputs");
|
bail!("invalid inputs");
|
||||||
}
|
}
|
||||||
@@ -81,227 +77,220 @@ impl E2eeHelper {
|
|||||||
Err(err) => {
|
Err(err) => {
|
||||||
bail!("Failed to load own public key: {}", err);
|
bail!("Failed to load own public key: {}", err);
|
||||||
}
|
}
|
||||||
Ok(public_key) => public_key
|
Ok(public_key) => public_key,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* libEtPan's pgp_encrypt_mime() takes the parent as the new root. We just expect the root as being given to this function. */
|
let e2ee = context.sql.get_config_int(&context, "e2ee_enabled");
|
||||||
let prefer_encrypt = if 0
|
|
||||||
!= context
|
let prefer_encrypt = if 0 != e2ee.unwrap_or_default() {
|
||||||
.sql
|
|
||||||
.get_config_int(context, "e2ee_enabled")
|
|
||||||
.unwrap_or_default()
|
|
||||||
{
|
|
||||||
EncryptPreference::Mutual
|
EncryptPreference::Mutual
|
||||||
} else {
|
} else {
|
||||||
EncryptPreference::NoPreference
|
EncryptPreference::NoPreference
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let mut encryption_successfull = false;
|
||||||
|
let mut do_encrypt = false;
|
||||||
|
let mut keyring = Keyring::default();
|
||||||
|
let mut peerstates: Vec<Peerstate> = Vec::new();
|
||||||
|
|
||||||
let plain: *mut MMAPString = mmap_string_new(b"\x00" as *const u8 as *const libc::c_char);
|
/*only for random-seed*/
|
||||||
/*only for random-seed*/
|
if prefer_encrypt == EncryptPreference::Mutual || e2ee_guaranteed {
|
||||||
if prefer_encrypt == EncryptPreference::Mutual || e2ee_guaranteed {
|
do_encrypt = true;
|
||||||
do_encrypt = true;
|
for recipient_addr in recipients_addr.iter() {
|
||||||
for recipient_addr in recipients_addr.iter() {
|
if *recipient_addr != addr {
|
||||||
if *recipient_addr != addr {
|
let peerstate = Peerstate::from_addr(context, &context.sql, &recipient_addr);
|
||||||
let peerstate =
|
if peerstate.is_some()
|
||||||
Peerstate::from_addr(context, &context.sql, &recipient_addr);
|
&& (peerstate.as_ref().unwrap().prefer_encrypt == EncryptPreference::Mutual
|
||||||
if peerstate.is_some()
|
|| e2ee_guaranteed)
|
||||||
&& (peerstate.as_ref().unwrap().prefer_encrypt
|
{
|
||||||
== EncryptPreference::Mutual
|
let peerstate = peerstate.unwrap();
|
||||||
|| e2ee_guaranteed)
|
info!(context, "dc_e2ee_encrypt {} has peerstate", recipient_addr);
|
||||||
{
|
if let Some(key) = peerstate.peek_key(min_verified as usize) {
|
||||||
let peerstate = peerstate.unwrap();
|
keyring.add_owned(key.clone());
|
||||||
info!(context, "dc_e2ee_encrypt {} has peerstate", recipient_addr);
|
peerstates.push(peerstate);
|
||||||
if let Some(key) = peerstate.peek_key(min_verified as usize) {
|
|
||||||
keyring.add_owned(key.clone());
|
|
||||||
peerstates.push(peerstate);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
info!(
|
|
||||||
context,
|
|
||||||
"dc_e2ee_encrypt {} HAS NO peerstate {}",
|
|
||||||
recipient_addr,
|
|
||||||
peerstate.is_some()
|
|
||||||
);
|
|
||||||
do_encrypt = false;
|
|
||||||
/* if we cannot encrypt to a single recipient, we cannot encrypt the message at all */
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
info!(
|
||||||
|
context,
|
||||||
|
"dc_e2ee_encrypt {} HAS NO peerstate {}",
|
||||||
|
recipient_addr,
|
||||||
|
peerstate.is_some()
|
||||||
|
);
|
||||||
|
do_encrypt = false;
|
||||||
|
/* if we cannot encrypt to a single recipient, we cannot encrypt the message at all */
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let sign_key = if do_encrypt {
|
}
|
||||||
keyring.add_ref(&public_key);
|
let sign_key = if do_encrypt {
|
||||||
let key = Key::from_self_private(context, addr.clone(), &context.sql);
|
keyring.add_ref(&public_key);
|
||||||
|
let key = Key::from_self_private(context, addr.clone(), &context.sql);
|
||||||
|
|
||||||
if key.is_none() {
|
if key.is_none() {
|
||||||
do_encrypt = false;
|
|
||||||
}
|
|
||||||
key
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
if force_unencrypted {
|
|
||||||
do_encrypt = false;
|
do_encrypt = false;
|
||||||
}
|
}
|
||||||
/*just a pointer into mailmime structure, must not be freed*/
|
key
|
||||||
let imffields_unprotected = mailmime_find_mailimf_fields(in_out_message);
|
} else {
|
||||||
if !imffields_unprotected.is_null() {
|
None
|
||||||
/* encrypt message, if possible */
|
};
|
||||||
if do_encrypt {
|
if force_unencrypted {
|
||||||
mailprivacy_prepare_mime(in_out_message);
|
do_encrypt = false;
|
||||||
let mut part_to_encrypt: *mut mailmime =
|
}
|
||||||
(*in_out_message).mm_data.mm_message.mm_msg_mime;
|
/*just a pointer into mailmime structure, must not be freed*/
|
||||||
(*part_to_encrypt).mm_parent = ptr::null_mut();
|
let imffields_unprotected = mailmime_find_mailimf_fields(in_out_message);
|
||||||
let imffields_encrypted: *mut mailimf_fields = mailimf_fields_new_empty();
|
if imffields_unprotected.is_null() {
|
||||||
/* mailmime_new_message_data() calls mailmime_fields_new_with_version() which would add the unwanted MIME-Version:-header */
|
bail!("could not find mime fields");
|
||||||
let message_to_encrypt: *mut mailmime = mailmime_new(
|
}
|
||||||
MAILMIME_MESSAGE as libc::c_int,
|
/* encrypt message, if possible */
|
||||||
ptr::null(),
|
if do_encrypt {
|
||||||
0 as libc::size_t,
|
mailprivacy_prepare_mime(in_out_message);
|
||||||
mailmime_fields_new_empty(),
|
let mut part_to_encrypt: *mut mailmime =
|
||||||
mailmime_get_content_message(),
|
(*in_out_message).mm_data.mm_message.mm_msg_mime;
|
||||||
ptr::null_mut(),
|
(*part_to_encrypt).mm_parent = ptr::null_mut();
|
||||||
ptr::null_mut(),
|
let imffields_encrypted: *mut mailimf_fields = mailimf_fields_new_empty();
|
||||||
ptr::null_mut(),
|
/* mailmime_new_message_data() calls mailmime_fields_new_with_version() which would add the unwanted MIME-Version:-header */
|
||||||
ptr::null_mut(),
|
let message_to_encrypt: *mut mailmime = mailmime_new(
|
||||||
imffields_encrypted,
|
MAILMIME_MESSAGE as libc::c_int,
|
||||||
part_to_encrypt,
|
ptr::null(),
|
||||||
);
|
0 as libc::size_t,
|
||||||
if do_gossip {
|
mailmime_fields_new_empty(),
|
||||||
for peerstate in peerstates {
|
mailmime_get_content_message(),
|
||||||
peerstate.render_gossip_header(min_verified as usize).map(|header| {
|
ptr::null_mut(),
|
||||||
wrapmime::new_custom_field(
|
ptr::null_mut(),
|
||||||
imffields_encrypted,
|
ptr::null_mut(),
|
||||||
"Autocrypt-Gossip",
|
ptr::null_mut(),
|
||||||
&header
|
imffields_encrypted,
|
||||||
)
|
part_to_encrypt,
|
||||||
});
|
);
|
||||||
}
|
if do_gossip {
|
||||||
}
|
for peerstate in peerstates {
|
||||||
/* memoryhole headers */
|
peerstate
|
||||||
// XXX we can't use clist's into_iter()
|
.render_gossip_header(min_verified as usize)
|
||||||
// because the loop body also removes items
|
.map(|header| {
|
||||||
let mut cur: *mut clistiter = (*(*imffields_unprotected).fld_list).first;
|
wrapmime::new_custom_field(
|
||||||
while !cur.is_null() {
|
imffields_encrypted,
|
||||||
let field: *mut mailimf_field = (*cur).data as *mut mailimf_field;
|
"Autocrypt-Gossip",
|
||||||
let mut move_to_encrypted = false;
|
&header,
|
||||||
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
|
/* memoryhole headers */
|
||||||
|
// XXX 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;
|
||||||
|
while !cur.is_null() {
|
||||||
|
let field: *mut mailimf_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-")
|
||||||
{
|
{
|
||||||
let opt_field = (*field).fld_data.fld_optional_field;
|
move_to_encrypted = true;
|
||||||
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-")
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let subject: *mut mailimf_subject = mailimf_subject_new("...".strdup());
|
|
||||||
mailimf_fields_add(
|
|
||||||
imffields_unprotected,
|
|
||||||
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(
|
|
||||||
(*part_to_encrypt).mm_content_type,
|
|
||||||
"protected-headers",
|
|
||||||
"v1",
|
|
||||||
)?;
|
|
||||||
mailmime_write_mem(plain, &mut col, message_to_encrypt);
|
|
||||||
if (*plain).str_0.is_null() || (*plain).len <= 0 {
|
|
||||||
bail!("could not write/allocate");
|
|
||||||
}
|
|
||||||
if let Ok(ctext_v) = dc_pgp_pk_encrypt(
|
|
||||||
std::slice::from_raw_parts((*plain).str_0 as *const u8, (*plain).len),
|
|
||||||
&keyring,
|
|
||||||
sign_key.as_ref(),
|
|
||||||
) {
|
|
||||||
let ctext_bytes = ctext_v.len();
|
|
||||||
let ctext = ctext_v.strdup();
|
|
||||||
self.cdata_to_free = Some(Box::new(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",
|
|
||||||
-1,
|
|
||||||
);
|
|
||||||
let content: *mut mailmime_content = (*encrypted_part).mm_content_type;
|
|
||||||
wrapmime::append_ct_param(
|
|
||||||
content,
|
|
||||||
"protocol",
|
|
||||||
"application/pgp-encrypted",
|
|
||||||
)?;
|
|
||||||
static mut VERSION_CONTENT: [libc::c_char; 13] =
|
|
||||||
[86, 101, 114, 115, 105, 111, 110, 58, 32, 49, 13, 10, 0];
|
|
||||||
let version_mime: *mut mailmime = new_data_part(
|
|
||||||
VERSION_CONTENT.as_mut_ptr() as *mut libc::c_void,
|
|
||||||
strlen(VERSION_CONTENT.as_mut_ptr()),
|
|
||||||
"application/pgp-encrypted",
|
|
||||||
MAILMIME_MECHANISM_7BIT as i32,
|
|
||||||
);
|
|
||||||
mailmime_smart_add_part(encrypted_part, version_mime);
|
|
||||||
let ctext_part: *mut mailmime = new_data_part(
|
|
||||||
ctext as *mut libc::c_void,
|
|
||||||
ctext_bytes,
|
|
||||||
"application/octet-stream",
|
|
||||||
MAILMIME_MECHANISM_7BIT as i32,
|
|
||||||
);
|
|
||||||
mailmime_smart_add_part(encrypted_part, ctext_part);
|
|
||||||
(*in_out_message).mm_data.mm_message.mm_msg_mime = encrypted_part;
|
|
||||||
(*encrypted_part).mm_parent = in_out_message;
|
|
||||||
mailmime_free(message_to_encrypt);
|
|
||||||
if !plain.is_null() {
|
|
||||||
mmap_string_free(plain);
|
|
||||||
}
|
|
||||||
return Ok(true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let aheader = Aheader::new(addr, public_key, prefer_encrypt).to_string();
|
if move_to_encrypted {
|
||||||
new_custom_field(imffields_unprotected, "Autocrypt", &aheader);
|
mailimf_fields_add(imffields_encrypted, field);
|
||||||
|
cur = clist_delete((*imffields_unprotected).fld_list, cur);
|
||||||
|
} else {
|
||||||
|
cur = (*cur).next;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if !plain.is_null() {
|
let subject: *mut mailimf_subject = mailimf_subject_new("...".strdup());
|
||||||
|
mailimf_fields_add(
|
||||||
|
imffields_unprotected,
|
||||||
|
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(
|
||||||
|
(*part_to_encrypt).mm_content_type,
|
||||||
|
"protected-headers",
|
||||||
|
"v1",
|
||||||
|
)?;
|
||||||
|
let plain: *mut MMAPString =
|
||||||
|
mmap_string_new(b"\x00" as *const u8 as *const libc::c_char);
|
||||||
|
let mut col: libc::c_int = 0i32;
|
||||||
|
mailmime_write_mem(plain, &mut col, message_to_encrypt);
|
||||||
|
if (*plain).str_0.is_null() || (*plain).len <= 0 {
|
||||||
|
bail!("could not write/allocate");
|
||||||
|
}
|
||||||
|
let ctext = dc_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);
|
mmap_string_free(plain);
|
||||||
|
|
||||||
|
if let Ok(ctext_v) = ctext {
|
||||||
|
let ctext_bytes = ctext_v.len();
|
||||||
|
let ctext = ctext_v.strdup();
|
||||||
|
self.cdata_to_free = Some(Box::new(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",
|
||||||
|
-1,
|
||||||
|
);
|
||||||
|
let content: *mut mailmime_content = (*encrypted_part).mm_content_type;
|
||||||
|
wrapmime::append_ct_param(content, "protocol", "application/pgp-encrypted")?;
|
||||||
|
static mut VERSION_CONTENT: [libc::c_char; 13] =
|
||||||
|
[86, 101, 114, 115, 105, 111, 110, 58, 32, 49, 13, 10, 0];
|
||||||
|
let version_mime: *mut mailmime = new_data_part(
|
||||||
|
VERSION_CONTENT.as_mut_ptr() as *mut libc::c_void,
|
||||||
|
strlen(VERSION_CONTENT.as_mut_ptr()),
|
||||||
|
"application/pgp-encrypted",
|
||||||
|
MAILMIME_MECHANISM_7BIT as i32,
|
||||||
|
);
|
||||||
|
mailmime_smart_add_part(encrypted_part, version_mime);
|
||||||
|
let ctext_part: *mut mailmime = new_data_part(
|
||||||
|
ctext as *mut libc::c_void,
|
||||||
|
ctext_bytes,
|
||||||
|
"application/octet-stream",
|
||||||
|
MAILMIME_MECHANISM_7BIT as i32,
|
||||||
|
);
|
||||||
|
mailmime_smart_add_part(encrypted_part, ctext_part);
|
||||||
|
(*in_out_message).mm_data.mm_message.mm_msg_mime = encrypted_part;
|
||||||
|
(*encrypted_part).mm_parent = in_out_message;
|
||||||
|
mailmime_free(message_to_encrypt);
|
||||||
|
encryption_successfull = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(false)
|
let aheader = Aheader::new(addr, public_key, prefer_encrypt).to_string();
|
||||||
|
new_custom_field(imffields_unprotected, "Autocrypt", &aheader);
|
||||||
|
Ok(encryption_successfull)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn decrypt(&mut self, context: &Context, in_out_message: *mut mailmime) {
|
pub unsafe fn decrypt(&mut self, context: &Context, in_out_message: *mut mailmime) {
|
||||||
|
|||||||
@@ -56,7 +56,6 @@ pub fn new_custom_field(fields: *mut mailimf_fields, name: &str, value: &str) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn build_body_text(text: &str) -> Result<*mut mailmime, Error> {
|
pub fn build_body_text(text: &str) -> Result<*mut mailmime, Error> {
|
||||||
let mime_fields: *mut mailmime_fields;
|
let mime_fields: *mut mailmime_fields;
|
||||||
let message_part: *mut mailmime;
|
let message_part: *mut mailmime;
|
||||||
|
|||||||
Reference in New Issue
Block a user