diff --git a/src/config.rs b/src/config.rs index 305e8765c..9bc0d775c 100644 --- a/src/config.rs +++ b/src/config.rs @@ -407,9 +407,6 @@ pub enum Config { #[strum(props(default = "1"))] SyncMsgs, - /// Make all outgoing messages with Autocrypt header "multipart/signed". - SignUnencrypted, - /// Let the core save all events to the database. /// This value is used internally to remember the MsgId of the logging xdc #[strum(props(default = "0"))] @@ -710,7 +707,6 @@ impl Context { | Config::Bot | Config::NotifyAboutWrongPw | Config::SyncMsgs - | Config::SignUnencrypted | Config::DisableIdle => { ensure!( matches!(value, None | Some("0") | Some("1")), diff --git a/src/context.rs b/src/context.rs index 801dfbce8..95ce3c777 100644 --- a/src/context.rs +++ b/src/context.rs @@ -991,12 +991,6 @@ impl Context { .await? .to_string(), ); - res.insert( - "sign_unencrypted", - self.get_config_int(Config::SignUnencrypted) - .await? - .to_string(), - ); res.insert( "debug_logging", self.get_config_int(Config::DebugLogging).await?.to_string(), diff --git a/src/e2ee.rs b/src/e2ee.rs index e7de11585..9a1f639bf 100644 --- a/src/e2ee.rs +++ b/src/e2ee.rs @@ -79,16 +79,6 @@ impl EncryptHelper { Ok(ctext) } - - /// Signs the passed-in `mail` using the private key from `context`. - /// Returns the payload and the signature. - pub async fn sign(self, context: &Context, mail: &MimePart<'static>) -> Result { - let sign_key = load_self_secret_key(context).await?; - let mut buffer = Vec::new(); - mail.clone().write_part(&mut buffer)?; - let signature = pgp::pk_calc_signature(buffer, &sign_key)?; - Ok(signature) - } } /// Ensures a private key exists for the configured user. diff --git a/src/mimefactory.rs b/src/mimefactory.rs index 3a07a750e..6793ea53c 100644 --- a/src/mimefactory.rs +++ b/src/mimefactory.rs @@ -1227,53 +1227,18 @@ impl MimeFactory { message.header(header, value) }); let message = MimePart::new("multipart/mixed", vec![message]); - let mut message = protected_headers + let message = protected_headers .iter() .fold(message, |message, (header, value)| { message.header(*header, value.clone()) }); - if skip_autocrypt || !context.get_config_bool(Config::SignUnencrypted).await? { - // Deduplicate unprotected headers that also are in the protected headers: - let protected: HashSet<&str> = - HashSet::from_iter(protected_headers.iter().map(|(header, _value)| *header)); - unprotected_headers.retain(|(header, _value)| !protected.contains(header)); + // Deduplicate unprotected headers that also are in the protected headers: + let protected: HashSet<&str> = + HashSet::from_iter(protected_headers.iter().map(|(header, _value)| *header)); + unprotected_headers.retain(|(header, _value)| !protected.contains(header)); - message - } else { - for (h, v) in &mut message.headers { - if h == "Content-Type" - && let mail_builder::headers::HeaderType::ContentType(ct) = v - { - let mut ct_new = ct.clone(); - ct_new = ct_new.attribute("protected-headers", "v1"); - if use_std_header_protection { - ct_new = ct_new.attribute("hp", "clear"); - } - *ct = ct_new; - break; - } - } - - let signature = encrypt_helper.sign(context, &message).await?; - MimePart::new( - "multipart/signed; protocol=\"application/pgp-signature\"; protected", - vec![ - message, - MimePart::new( - "application/pgp-signature; name=\"signature.asc\"", - signature, - ) - .header( - "Content-Description", - mail_builder::headers::raw::Raw::<'static>::new( - "OpenPGP digital signature", - ), - ) - .attachment("signature"), - ], - ) - } + message }; let MimeFactory { diff --git a/src/mimefactory/mimefactory_tests.rs b/src/mimefactory/mimefactory_tests.rs index 90de2d27a..f47dfc086 100644 --- a/src/mimefactory/mimefactory_tests.rs +++ b/src/mimefactory/mimefactory_tests.rs @@ -601,70 +601,6 @@ async fn test_selfavatar_unencrypted() -> anyhow::Result<()> { Ok(()) } -#[tokio::test(flavor = "multi_thread", worker_threads = 2)] -async fn test_selfavatar_unencrypted_signed() { - // create chat with bob, set selfavatar - let t = TestContext::new_alice().await; - t.set_config(Config::SignUnencrypted, Some("1")) - .await - .unwrap(); - let chat = t.create_chat_with_contact("bob", "bob@example.org").await; - - let file = t.dir.path().join("avatar.png"); - let bytes = include_bytes!("../../test-data/image/avatar64x64.png"); - tokio::fs::write(&file, bytes).await.unwrap(); - t.set_config(Config::Selfavatar, Some(file.to_str().unwrap())) - .await - .unwrap(); - - // send message to bob: that should get multipart/signed. - // `Subject:` is protected by copying it. - // make sure, `Subject:` stays in the outer header (imf header) - let mut msg = Message::new_text("this is the text!".to_string()); - - let sent_msg = t.send_msg(chat.id, &mut msg).await; - let mut payload = sent_msg.payload().splitn(4, "\r\n\r\n"); - - let part = payload.next().unwrap(); - assert_eq!(part.match_indices("multipart/signed").count(), 1); - assert_eq!(part.match_indices("From:").count(), 1); - assert_eq!(part.match_indices("Message-ID:").count(), 1); - assert_eq!(part.match_indices("Subject:").count(), 1); - assert_eq!(part.match_indices("Autocrypt:").count(), 1); - assert_eq!(part.match_indices("Chat-User-Avatar:").count(), 0); - - let part = payload.next().unwrap(); - assert_eq!( - part.match_indices("multipart/mixed; protected-headers=\"v1\"") - .count(), - 1 - ); - assert_eq!(part.match_indices("From:").count(), 1); - assert_eq!(part.match_indices("Message-ID:").count(), 0); - assert_eq!(part.match_indices("Subject:").count(), 1); - assert_eq!(part.match_indices("Autocrypt:").count(), 1); - assert_eq!(part.match_indices("Chat-User-Avatar:").count(), 0); - - let part = payload.next().unwrap(); - assert_eq!(part.match_indices("text/plain").count(), 1); - assert_eq!(part.match_indices("From:").count(), 0); - assert_eq!(part.match_indices("Message-ID:").count(), 1); - assert_eq!(part.match_indices("Chat-User-Avatar:").count(), 0); - assert_eq!(part.match_indices("Subject:").count(), 0); - - let body = payload.next().unwrap(); - assert_eq!(body.match_indices("this is the text!").count(), 1); - - let bob = TestContext::new_bob().await; - bob.recv_msg(&sent_msg).await; - let alice_id = Contact::lookup_id_by_addr(&bob.ctx, "alice@example.org", Origin::Unknown) - .await - .unwrap() - .unwrap(); - let alice_contact = Contact::get_by_id(&bob.ctx, alice_id).await.unwrap(); - assert_eq!(alice_contact.is_key_contact(), false); -} - /// Test that removed member address does not go into the `To:` field. #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_remove_member_bcc() -> Result<()> { diff --git a/src/mimeparser.rs b/src/mimeparser.rs index 04e618a85..f3d20762e 100644 --- a/src/mimeparser.rs +++ b/src/mimeparser.rs @@ -305,6 +305,7 @@ impl MimeMessage { // Parse hidden headers. let mimetype = mail.ctype.mimetype.parse::()?; let (part, mimetype) = + // We do not sign unencrypted messages ourselves, but are able to receive them. if mimetype.type_() == mime::MULTIPART && mimetype.subtype().as_str() == "signed" { if let Some(part) = mail.subparts.first() { // We don't remove "subject" from `headers` because currently just signed @@ -329,7 +330,6 @@ impl MimeMessage { (&mail, mimetype) } } else { - // Currently we do not sign unencrypted messages by default. (&mail, mimetype) }; if mimetype.type_() == mime::MULTIPART diff --git a/src/mimeparser/mimeparser_tests.rs b/src/mimeparser/mimeparser_tests.rs index b3f2e6bc9..8042fb8a1 100644 --- a/src/mimeparser/mimeparser_tests.rs +++ b/src/mimeparser/mimeparser_tests.rs @@ -2041,35 +2041,6 @@ async fn test_multiple_autocrypt_hdrs() -> Result<()> { Ok(()) } -/// Tests that timestamp of signed but not encrypted message is protected. -#[tokio::test(flavor = "multi_thread", worker_threads = 2)] -async fn test_protected_date() -> Result<()> { - let mut tcm = TestContextManager::new(); - let alice = &tcm.alice().await; - let bob = &tcm.bob().await; - - alice.set_config(Config::SignUnencrypted, Some("1")).await?; - - let alice_chat = alice.create_email_chat(bob).await; - let alice_msg_id = chat::send_text_msg(alice, alice_chat.id, "Hello!".to_string()).await?; - let alice_msg = Message::load_from_db(alice, alice_msg_id).await?; - assert_eq!(alice_msg.get_showpadlock(), false); - - let mut sent_msg = alice.pop_sent_msg().await; - sent_msg.payload = sent_msg.payload.replacen( - "Date:", - "Date: Wed, 17 Mar 2021 14:30:53 +0100 (CET)\r\nX-Not-Date:", - 1, - ); - let bob_msg = bob.recv_msg(&sent_msg).await; - assert_eq!(alice_msg.get_text(), bob_msg.get_text()); - - // Timestamp that the sender has put into the message - // should always be displayed as is on the receiver. - assert_eq!(alice_msg.get_timestamp(), bob_msg.get_timestamp()); - Ok(()) -} - #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_huge_image_becomes_file() -> Result<()> { let t = TestContext::new_alice().await; diff --git a/src/pgp.rs b/src/pgp.rs index 2b10da1a3..1417369aa 100644 --- a/src/pgp.rs +++ b/src/pgp.rs @@ -6,15 +6,15 @@ use std::io::Cursor; use anyhow::{Context as _, Result, ensure}; use deltachat_contact_tools::{EmailAddress, may_be_valid_addr}; use pgp::composed::{ - ArmorOptions, Deserializable, DetachedSignature, EncryptionCaps, KeyType as PgpKeyType, - MessageBuilder, SecretKeyParamsBuilder, SignedKeyDetails, SignedPublicKey, SignedPublicSubKey, - SignedSecretKey, SubkeyParamsBuilder, SubpacketConfig, + Deserializable, DetachedSignature, EncryptionCaps, KeyType as PgpKeyType, MessageBuilder, + SecretKeyParamsBuilder, SignedKeyDetails, SignedPublicKey, SignedPublicSubKey, SignedSecretKey, + SubkeyParamsBuilder, SubpacketConfig, }; use pgp::crypto::aead::{AeadAlgorithm, ChunkSize}; use pgp::crypto::ecc_curve::ECCCurve; use pgp::crypto::hash::HashAlgorithm; use pgp::crypto::sym::SymmetricKeyAlgorithm; -use pgp::packet::{Signature, SignatureConfig, SignatureType, Subpacket, SubpacketData}; +use pgp::packet::{Signature, Subpacket, SubpacketData}; use pgp::types::{ CompressionAlgorithm, Imprint, KeyDetails, KeyVersion, Password, SignedUser, SigningKey as _, StringToKey, @@ -202,47 +202,6 @@ pub async fn pk_encrypt( .await? } -/// Produces a detached signature for `plain` text using `private_key_for_signing`. -pub fn pk_calc_signature( - plain: Vec, - private_key_for_signing: &SignedSecretKey, -) -> Result { - let rng = thread_rng(); - - let mut config = SignatureConfig::from_key( - rng, - &private_key_for_signing.primary_key, - SignatureType::Binary, - )?; - - config.hashed_subpackets = vec![ - Subpacket::regular(SubpacketData::IssuerFingerprint( - private_key_for_signing.fingerprint(), - ))?, - Subpacket::critical(SubpacketData::SignatureCreationTime( - pgp::types::Timestamp::now(), - ))?, - ]; - config.unhashed_subpackets = vec![]; - if private_key_for_signing.version() <= KeyVersion::V4 { - config - .unhashed_subpackets - .push(Subpacket::regular(SubpacketData::IssuerKeyId( - private_key_for_signing.legacy_key_id(), - ))?); - } - - let signature = config.sign( - &private_key_for_signing.primary_key, - &Password::empty(), - plain.as_slice(), - )?; - - let sig = DetachedSignature::new(signature); - - Ok(sig.to_armored_string(ArmorOptions::default())?) -} - /// Returns fingerprints /// of all keys from the `public_keys_for_validation` keyring that /// have valid signatures in `msg` and corresponding intended recipient fingerprints