Thanks for your detailed analysis, I am sure other readers will find it quite useful!
1) To what extent does the Secure Mail component handle these issues?
2) Does it implement "header protection"?
3) Which headers does it include in the encrypted/signed content?
I will try answering these 3 question at once:
The MailMessage
class (in Rebex.Mail
namespace) only supports the naïve "Sign & Encrypt" or "Encrypt & Sign".
The MimeMessage
class (in Rebex.Mime
namespace) is versatile enough to make it possible to produce messages that use the "triple-wrapping" approach and even messages that utilize S/MIME v3.1 header protection with a bit of extra work. The following code creates a message using "header protection", includes all the pre-encryption headers in the encrypted/signed content and copies the specified headers to the outer message:
using Rebex.Mail;
using Rebex.Mime.Headers;
using Rebex.Mime;
...
// get certificates
Certificate signer = ...
Certificate recipient = ...
// construct the message to protect and send
MailMessage message = new MailMessage();
message.From = "support@rebex.net";
message.To = "sales@rebex.net";
message.Subject = "Protected message";
message.BodyHtml = "<em>HTML</em> body";
message.BodyText = "text body";
// convert it to MimeMessage
MimeMessage inner = message.ToMimeMessage();
// wrap the MIME message in a message/rfc822 wrapper in
// order to apply S/MIME security services to these headers
// (accoding to RFC 3851)
MimeEntity wrapped = new MimeEntity();
wrapped.SetContent(inner);
// sign the wrapped message
//MimeEntity signed = new MimeEntity();
MimeMessage signed = new MimeMessage();
signed.SetSignedContent(wrapped, signer);
signed.Sign();
// encrypt the signed message
MimeMessage outer = new MimeMessage();
outer.SetEnvelopedContent(signed, recipient);
outer.Encrypt();
// copy the specified headers from
// the (protected) inner message headers
outer.From = inner.From;
outer.To = inner.To;
outer.Subject = inner.Subject;
outer.Date = inner.Date;
// save the outer (S&E with protected headers) message
// (or send it instead)
outer.Save(filePath);
Rationale: When we were writing Rebex Secure Mail in 2005&2006, we found out that major email clients lack proper support for S/MIME v3.1 header protection and some even lack support for simple "Encrypt & Sign" (Outlook Express only supported "Sign and Encrypt").
For this reason, we decided to postpone this for one of the future releases. And it looks like this situation has not improved much since - I just tested Outlook 2007 and Mozilla Thunderbird and although they are able to display a message with S/MIME v3.1 header protection, they don't perform any kind of validation and present the inner message as if it were an attachment.
4) How does it handle headers when decrypting or validating a signature?
5) Does it simply replace the "outer" headers with the "inner" headers when unwrapping?
6) Does it already check if the headers were altered?
7) Is is possible to check if such header information is present in signed/encrypted content (because if it isn't the message ultimately cannot be trusted, unless another solution - e.g. triple-wrapping - was used)?
The MailMessage
class is able to parse messages that utilize S/MIME v3.1 header protection, but it handles them just like Outlook or Thunderbird do - they present the inner message with protected headers as an attachment. No protected header checking is done out-of-the-box, but with a bit of extra code, you can perform all the checks you need:
// load the message
MailMessage outer = new MailMessage();
outer.Load(filePath);
// for the sake of simplicity, this code assumes that the input file
// is "Signed & Encrypted" with S/MIMEv3-style protected headers
// (production code should make sure this is the case first)
outer.Decrypt();
MailSignatureValidity validity = outer.ValidateSignature();
//...
// get inner message with protected headers
MailMessage inner = outer.Attachments[0].ContentMessage;
// get its body
string bodyText = inner.BodyText;
string bodyHtml = inner.BodyHtml;
// check whether the specified protected headers match
// the corresponding outer headers
string innerSender = (inner.Sender != null) ? inner.Sender.ToString() : "";
string outerSender = (outer.Sender != null) ? outer.Sender.ToString() : "";
if (innerSender != outerSender)
throw new ApplicationException("Protected Sender header doesn't match the outer header.");
if (inner.From.ToString() != outer.From.ToString())
throw new ApplicationException("Protected From header doesn't match the outer header.");
if (inner.To.ToString() != outer.To.ToString())
throw new ApplicationException("Protected To header doesn't match the outer header.");
if (inner.Subject != outer.Subject)
throw new ApplicationException("Protected Subject header doesn't match the outer header.");
//...
The MailMessage
class is also able to load triple-wrapped messages (these don't appear as attachments), but the inner headers and signatures are lost in the process.
The MimeMessage
class (in Rebex.Mime
namespace) is versatile enough to make it possible to load messages using both S/MIMEv3-style protected headers or triple-wrapping and makes all the signatures and headers accessible, but it doesn't perform any checks automatically.
We will strongly consider adding out-of-the-box support for S/MIME v3.1 header protection to one of the next releases of Rebex Secure Mail, although we won't produce such messages unless explicitly instructed to (for compatibility reasons -see above). Thanks for bringing this to our attention!