martedì, dicembre 11, 2007

Send smime message from NET

Using the NET Framowork classes is not possible to send correct smime pkcs7 messages. In particular, SmtpClient class adds own headers before sending message. The result is a not valid smime message. See bug on connect.microsoft.com and some posts on newsgroup: this and this.

If you are curious you can check how SmtpClient works, using Reflector. You will found that SmtpClient adds those headers. Grrrr!!!

Waiting for a solution from MS, at the moment the only solution is to use a thirdparty component or some free open source Smtp class. Using Google you can found them. I choosed Axosoft classes.
Well, they are very simple and some minor bugs, but they are very usefull to do some tests.

The very first think to do is to add a new message type in the MessageType enum and the Smtp.SendEmail method:

case MessageType.PKCS7:
WriteBuffer(ns, "Content-Type: application/pkcs7-mime; smime-type=signed-data; name=\"smime.p7m\"" + "\r\n");
WriteBuffer(ns, "Content-Disposition: attachment; filename=\"smime.p7m\"" + "\r\n");
WriteBuffer(ns, "Content-Transfer-Encoding: base64" + "\r\n");
WriteBuffer(ns, "\r\n" + msg.EmailMessage + "\r\n.\r\n");
break;

The new MessageType.PKCS7 inform the Smtp.SendEmail method to insert the required header for smime message.



You can create a smime message in few simple steps:
- get the bytes of the message
- encode them as pkcs7 message using a certificate
- send the message using the new MessageType



string inFile = "data.txt";
byte[] origData = File.ReadAllBytes(inFile);
ContentInfo ci = new ContentInfo(origData);

X509Certificate2 cert = CertUtility.GetCertFromStore("Fabrizio", StoreName.My);

SignedCms signedCms = new SignedCms(contentInfo);
CmsSigner cmsSigner = new CmsSigner(cert);
signedCms.ComputeSignature(cmsSigner);
byte[] encodedData = signedCms.Encode();

Axosoft.Common.Utilities.Smtp smtpAx = new Axosoft.Common.Utilities.Smtp();
smtpAx.SmtpServer = "smtpserver";
Axosoft.Common.Utilities.MailMessage msgAx = new Axosoft.Common.Utilities.MailMessage();
msgAx.EmailFrom = "foo@foo";
msgAx.AddEmailTo("dest@dest");
msgAx.EmailSubject = "TEST " + DateTime.Now.ToString();
msgAx.EmailMessageType = Axosoft.Common.Utilities.MessageType.PKCS7;
msgAx.EmailMessage = Convert.ToBase64String(encodedData);
smtpAx.SendEmail(msgAx);