I need to digitally sign email using s/mime. I've created a detached signature for my attachment but outlook can't open it: "Cannot open this item. Your Digital ID name cannot be found by the underlying security system". Certificate is installed on this PC and there is smth need to be tweaked in this code:
const int CHARS_IN_LINE = 64;
StringBuilder message = new StringBuilder();
message.AppendLine("Content-Type: multipart/signed; protocol=\"application/pkcs7-signature\";");
message.AppendLine(" boundary=\"__multipart-signed-boundary__\"");
message.AppendLine("Content-Transfer-Encoding: 7bit");
message.AppendLine("MIME-Version: 1.0");
message.AppendLine("Subject: " + tbMessageSubject.Text);
message.AppendLine();
message.AppendLine("--__multipart-signed-boundary__");
message.AppendLine("Content-Type: text/xml; charset=\"windows - 1251\"");
message.AppendLine("Content-Disposition: attachment; ");
message.AppendLine(" filename=\"" + Path.GetFileName(filename) + "\"");
message.AppendLine("Content-Transfer-Encoding: base64");
message.AppendLine();
var dataToSign = File.ReadAllBytes(filePath);
var base64Data = Convert.ToBase64String(dataToSign, Base64FormattingOptions.None);
var base64DataSb = new StringBuilder(base64Data);
for (int i = CHARS_IN_LINE; i < base64DataSb.Length; i += CHARS_IN_LINE + 2) // \r\n
base64DataSb.Insert(i, "\r\n");
message.AppendLine(base64DataSb.ToString());
message.AppendLine("--__multipart-signed-boundary__");
message.AppendLine("Content-Type: application/pkcs7-signature; name=\"smime.p7m\"");
message.AppendLine("Content-Transfer-Encoding: base64");
message.AppendLine("Content-Disposition: attachment; filename=smime.p7s");
message.AppendLine();
CmsSigner signer = new CmsSigner(clientCert);
SignedCms cms = new SignedCms(new ContentInfo(dataToSign), true);
cms.ComputeSignature(signer);
var signature = cms.Encode();
var base64Signature = Convert.ToBase64String(signature, Base64FormattingOptions.None);
var base64Sb = new StringBuilder(base64Signature);
for (int i = CHARS_IN_LINE; i < base64Sb.Length; i += CHARS_IN_LINE + 2) // \r\n
base64Sb.Insert(i, "\r\n");
message.AppendLine(base64Sb.ToString());
message.AppendLine();
message.AppendLine("--__multipart-signed-boundary__--");
message.AppendLine(".");
var stream = new MemoryStream(Encoding.ASCII.GetBytes(message.ToString()));
MailMessage mail = new MailMessage();
mail.From = new MailAddress(tbEmailFrom.Text);
mail.To.Add(new MailAddress(tbEmailTo.Text));
AlternateView alternateView = new AlternateView(stream, "application/pkcs7-mime; smime-type=signed-data; name=smime.p7m");
alternateView.TransferEncoding = TransferEncoding.SevenBit;
mail.AlternateViews.Add(alternateView);
SmtpClient client = new SmtpClient(host, port);
client.EnableSsl = chbUseSSL.Checked;
client.Send(mail);
Finally, the issue was in specified mediaType in AlternateView, the correct way:
and thanks to jdweng, I was need to sign not the attachment, but the attachment with it's headers (first
__multipart-signed-boundary
with attachment)