首页 > 解决方案 > Outlook 无法打开 s/mime 签名的邮件

问题描述

我需要使用 s/mime 对电子邮件进行数字签名。我为我的附件创建了一个分离的签名,但 Outlook 无法打开它:“无法打开此项目。基础安全系统无法找到您的数字 ID 名称”。证书已安装在此 PC 上,并且需要在此代码中进行调整:

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);

标签: c#smtpclientsignsmimeskpsmtpmessage

解决方案


最后,问题出在 AlternateView 中指定的 mediaType 中,正确的方法是:

AlternateView alternateView = new AlternateView(stream, "multipart/signed; protocol=\"application/pkcs7-signature\"; boundary=\"__multipart-signed-boundary__\"");
alternateView.TransferEncoding = TransferEncoding.SevenBit;

并且感谢jdweng,我需要签署的不是附件,而是带有标题的附件(首先__multipart-signed-boundary带有附件)


推荐阅读