From a702a040433e5dbebe48587127d0e32fd78aaa90 Mon Sep 17 00:00:00 2001 From: Manos Pitsidianakis Date: Fri, 16 Oct 2020 12:46:10 +0300 Subject: [PATCH] melib/attachments: add SMIME signature variant --- melib/src/email/attachment_types.rs | 3 +++ melib/src/email/attachments.rs | 11 ++++++++--- melib/src/email/pgp.rs | 19 ++++++++++--------- src/components/mail/pgp.rs | 3 ++- src/components/mail/view.rs | 4 +++- src/components/mail/view/envelope.rs | 12 +++--------- 6 files changed, 29 insertions(+), 23 deletions(-) diff --git a/melib/src/email/attachment_types.rs b/melib/src/email/attachment_types.rs index 0dcf5dbb..74d4e1fb 100644 --- a/melib/src/email/attachment_types.rs +++ b/melib/src/email/attachment_types.rs @@ -198,6 +198,7 @@ pub enum ContentType { }, MessageRfc822, PGPSignature, + CMSSignature, Other { tag: Vec, name: Option, @@ -275,6 +276,7 @@ impl PartialEq<&str> for ContentType { "multipart/signed", ) => true, (ContentType::PGPSignature, "application/pgp-signature") => true, + (ContentType::CMSSignature, "application/pkcs7-signature") => true, (ContentType::MessageRfc822, "message/rfc822") => true, (ContentType::Other { tag, .. }, _) => { other.eq_ignore_ascii_case(&String::from_utf8_lossy(&tag)) @@ -292,6 +294,7 @@ impl Display for ContentType { ContentType::Multipart { kind: k, .. } => k.fmt(f), ContentType::Other { ref tag, .. } => write!(f, "{}", String::from_utf8_lossy(tag)), ContentType::PGPSignature => write!(f, "application/pgp-signature"), + ContentType::CMSSignature => write!(f, "application/pkcs7-signature"), ContentType::MessageRfc822 => write!(f, "message/rfc822"), ContentType::OctetStream { .. } => write!(f, "application/octet-stream"), } diff --git a/melib/src/email/attachments.rs b/melib/src/email/attachments.rs index 6c6c4aa4..964183ba 100644 --- a/melib/src/email/attachments.rs +++ b/melib/src/email/attachments.rs @@ -202,6 +202,10 @@ impl AttachmentBuilder { && cst.eq_ignore_ascii_case(b"pgp-signature") { self.content_type = ContentType::PGPSignature; + } else if ct.eq_ignore_ascii_case(b"application") + && cst.eq_ignore_ascii_case(b"pkcs7-signature") + { + self.content_type = ContentType::CMSSignature; } else { let mut name: Option = None; for (n, v) in params { @@ -384,6 +388,7 @@ impl fmt::Display for Attachment { } } ContentType::PGPSignature => write!(f, "pgp signature [{}]", self.mime_type()), + ContentType::CMSSignature => write!(f, "S/MIME signature [{}]", self.mime_type()), ContentType::OctetStream { .. } | ContentType::Other { .. } => { if let Some(name) = self.filename() { write!( @@ -548,7 +553,7 @@ impl Attachment { fn get_text_recursive(&self, text: &mut Vec) { match self.content_type { - ContentType::Text { .. } | ContentType::PGPSignature => { + ContentType::Text { .. } | ContentType::PGPSignature | ContentType::CMSSignature => { text.extend(decode(self, None)); } ContentType::Multipart { @@ -720,7 +725,7 @@ impl Attachment { ret.push_str(&format!("Content-Type: {}\r\n\r\n", a.content_type)); ret.push_str(&String::from_utf8_lossy(a.body())); } - ContentType::PGPSignature => { + ContentType::CMSSignature | ContentType::PGPSignature => { ret.push_str(&format!("Content-Type: {}\r\n\r\n", a.content_type)); ret.push_str(&String::from_utf8_lossy(a.body())); } @@ -808,7 +813,7 @@ fn decode_rec_helper<'a, 'b>(a: &'a Attachment, filter: &mut Option>) ContentType::OctetStream { ref name } => { name.clone().unwrap_or_else(|| a.mime_type()).into_bytes() } - ContentType::PGPSignature => Vec::new(), + ContentType::CMSSignature | ContentType::PGPSignature => Vec::new(), ContentType::MessageRfc822 => { if a.content_disposition.kind.is_inline() { let b = AttachmentBuilder::new(a.body()).build(); diff --git a/melib/src/email/pgp.rs b/melib/src/email/pgp.rs index d3dd2ced..4f569053 100644 --- a/melib/src/email/pgp.rs +++ b/melib/src/email/pgp.rs @@ -20,7 +20,6 @@ */ /*! Verification of OpenPGP signatures */ -use crate::email::parser::BytesExt; use crate::email::{ attachment_types::{ContentType, MultipartType}, attachments::Attachment, @@ -88,7 +87,7 @@ pub fn convert_attachment_to_rfc_spec(input: &[u8]) -> Vec { ret } -pub fn verify_signature(a: &Attachment) -> Result<(Vec, &[u8])> { +pub fn verify_signature(a: &Attachment) -> Result<(Vec, &Attachment)> { match a.content_type { ContentType::Multipart { kind: MultipartType::Signed, @@ -107,7 +106,10 @@ pub fn verify_signature(a: &Attachment) -> Result<(Vec, &[u8])> { let signed_part: Vec = if let Some(v) = parts .iter() .zip(part_boundaries.iter()) - .find(|(p, _)| p.content_type != ContentType::PGPSignature) + .find(|(p, _)| { + p.content_type != ContentType::PGPSignature + && p.content_type != ContentType::CMSSignature + }) .map(|(_, s)| convert_attachment_to_rfc_spec(s.display_bytes(a.body()))) { v @@ -116,12 +118,11 @@ pub fn verify_signature(a: &Attachment) -> Result<(Vec, &[u8])> { "multipart/signed attachment without a signed part".to_string(), )); }; - let signature = if let Some(sig) = parts - .iter() - .find(|s| s.content_type == ContentType::PGPSignature) - .map(|a| a.body()) - { - sig.trim() + let signature = if let Some(sig) = parts.iter().find(|s| { + s.content_type == ContentType::PGPSignature + || s.content_type == ContentType::CMSSignature + }) { + sig } else { return Err(MeliError::new( "multipart/signed attachment without a signature part".to_string(), diff --git a/src/components/mail/pgp.rs b/src/components/mail/pgp.rs index c378ca46..da31d671 100644 --- a/src/components/mail/pgp.rs +++ b/src/components/mail/pgp.rs @@ -25,6 +25,7 @@ use melib::email::{ }; use melib::error::*; use melib::gpgme::*; +use melib::parser::BytesExt; use std::future::Future; use std::pin::Pin; @@ -38,7 +39,7 @@ pub async fn verify(a: Attachment) -> Result<()> { let (data, sig) = melib_pgp::verify_signature(&a).chain_err_summary(|| "Could not verify signature.")?; let mut ctx = Context::new()?; - let sig = ctx.new_data_mem(&sig)?; + let sig = ctx.new_data_mem(&sig.body().trim())?; let data = ctx.new_data_mem(&data)?; ctx.verify(sig, data)?.await } diff --git a/src/components/mail/view.rs b/src/components/mail/view.rs index 121bbaf1..bce7e692 100644 --- a/src/components/mail/view.rs +++ b/src/components/mail/view.rs @@ -1797,7 +1797,9 @@ impl Component for MailView { } } - ContentType::Text { .. } | ContentType::PGPSignature => { + ContentType::Text { .. } + | ContentType::PGPSignature + | ContentType::CMSSignature => { self.mode = ViewMode::Attachment(lidx); self.initialised = false; self.dirty = true; diff --git a/src/components/mail/view/envelope.rs b/src/components/mail/view/envelope.rs index 19a45f55..d8477657 100644 --- a/src/components/mail/view/envelope.rs +++ b/src/components/mail/view/envelope.rs @@ -419,7 +419,9 @@ impl Component for EnvelopeView { ))); } - ContentType::Text { .. } => { + ContentType::Text { .. } + | ContentType::PGPSignature + | ContentType::CMSSignature => { self.mode = ViewMode::Attachment(lidx); self.dirty = true; } @@ -479,14 +481,6 @@ impl Component for EnvelopeView { )); return true; } - ContentType::PGPSignature => { - context.replies.push_back(UIEvent::StatusEvent( - StatusEvent::DisplayMessage( - "Signatures aren't supported yet".to_string(), - ), - )); - return true; - } } } else { context.replies.push_back(UIEvent::StatusEvent(