我遇到了 .NET Framework 4.5 版的阻止程序,用于使用数字签名对 XML 进行签名。
我的问题是基于需要使用 RSA SHA-256 算法使用 X.509 证书对单个 XML 元素进行签名。我已经阅读了许多关于此主题的 .NET 帖子,并且似乎最初在 CLR 安全项目 RSAPKCS1SHA256SignatureDescription.cs 类中开发了一个解决方案。RSAPKCS1SHA256SignatureDescription 当然已经被合并到 .net 运行时中,并且从 .NET 4.5 开始,现在可以在分布式二进制 System.Deployment.dll 下使用。我曾尝试在 .NET 中使用上述解决方案使用 RSA SHA-256 对特定的 XML 元素进行签名,但尚未取得任何成功。
我正在尝试使用 WSSE 令牌签署符合 Oasis ebms 标准的 SOAP 消息。请注意,该课程是为迎合带附件的肥皂 (SwA) 和签署个人附件而编写的。我的代码如下
我的代码如下:
using System;
using System.Collections.Generic;
using System.IO;
using System.IdentityModel.Tokens;
using System.Security;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Security.Cryptography.Xml;
using System.ServiceModel.Channels;
using System.ServiceModel.Security;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Serialization;
using System.Deployment.Internal.CodeSigning;
namespace TestCSharpX509CertificateRSSHA256
{
public class SignatureSupportUtility
{
private bool IsSignatureContentTransform
{
get
{
return true;
//get IsSignatureContentTransform
}
}
public SignatureSupportUtility()
{
Register();
}
private static void Register()
{
CryptoConfig.AddAlgorithm(typeof(RSAPKCS1SHA256SignatureDescription), "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256");
}
private void Sign(Message message, string[] elementIdsToSign, string[] attachmentsToSign, string wssNamespace, X509Certificate2 certificate)
{
//Prepare XML to encrypt and sign
var element = this.PrepareEncyrptSign(message);
bool signEntireDocument = true;
string elementToBeSigned = string.Empty;
var signedMessage = new XmlDocument();
signedMessage.AppendChild(signedMessage.ImportNode(element, true));
SignatureType signAs = SignatureType.InternallyDetached;
signedMessage.PreserveWhitespace = false;
OverrideSignedXml signedXml = new OverrideSignedXml(signedMessage);
signedXml.SignedInfo.CanonicalizationMethod = SignedXml.XmlDsigExcC14NTransformUrl;
if (elementIdsToSign != null && elementIdsToSign.Length > 0)
{
bool isContentTransform = this.IsSignatureContentTransform;
foreach (string s in elementIdsToSign)
{
// Create a reference to be signed.
Reference reference = new Reference(string.Format("#{0}", s));
reference.AddTransform(new XmlDsigExcC14NTransform());
reference.DigestMethod = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256";
// Add the reference to the SignedXml object.
signedXml.AddReference(reference);
}
signEntireDocument = false;
}
// Reference attachments to sign
if (attachmentsToSign != null && attachmentsToSign.Length > 0)
{
bool isContentTransform = this.IsSignatureContentTransform;
foreach (string attachmentId in attachmentsToSign)
{
// Create a reference to be signed.
Reference reference = new Reference(string.Format("{0}{1}", Constants.CidUriScheme, attachmentId));
reference.DigestMethod = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256";
if (isContentTransform)
{
AttachmentContentSignatureTransform env = new AttachmentContentSignatureTransform();
reference.AddTransform(env);
}
else
{
AttachmentCompleteSignatureTransform env = new AttachmentCompleteSignatureTransform();
reference.AddTransform(env);
}
// Add the reference to the SignedXml object.
signedXml.AddReference(reference);
}
signEntireDocument = false;
}
if (signEntireDocument)
{
Reference reference = new Reference();
reference.Uri = "";
reference.DigestMethod = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256";
XmlDsigEnvelopedSignatureTransform env = new XmlDsigEnvelopedSignatureTransform();
reference.AddTransform(env);
signedXml.AddReference(reference);
signAs = SignatureType.Enveloped;
}
string x509CertificateReferenceId = string.Format("{0}-{1}", Constants.IdAttributeName, Guid.NewGuid().ToString("N"));
KeyInfo keyInfo = new KeyInfo();
keyInfo.AddClause(new KeyInfoX509SecurityTokenReference(string.Format("#{0}", x509CertificateReferenceId), wssNamespace));
signedXml.KeyInfo = keyInfo;
signedXml.SignedInfo.SignatureMethod = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256";
RSA key = (RSACryptoServiceProvider)certificate.PrivateKey;
signedXML.SigningKey = key;
CidWebRequest.Message = message;
signedXml.ComputeSignature();
var xmlSignature = signedXml.GetXml();
XmlDocument unsignedEnvelopeDoc = new XmlDocument();
unsignedEnvelopeDoc.LoadXml(message.MessageAsString); }}}
using System;
using System.Collections.Generic;
using System.IO;
using System.IdentityModel.Tokens;
using System.Security;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Security.Cryptography.Xml;
using System.ServiceModel.Channels;
using System.ServiceModel.Security;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Serialization;
using System.Deployment.Internal.CodeSigning;
namespace TestCSharpX509CertificateRSSHA256
{
public sealed class OverrideSignedXml : SignedXml
{
public OverrideSignedXml()
: base()
{
}
public OverrideSignedXml(XmlDocument doc)
: base(doc)
{
}
public override XmlElement GetIdElement(XmlDocument document, string idValue)
{
XmlElement element = base.GetIdElement(document, idValue);
if (element == null)
{
XmlNamespaceManager nsmgr = new XmlNamespaceManager(document.NameTable);
nsmgr.AddNamespace("wsu", ="http://docs.oasis-open. org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
element = document.SelectSingleNode("//*[@wsu:Id=\"" + idValue + "\"]", nsmgr) as XmlElement;
}
return element;
}
}
}
我的 SignatureSupportUtility 类中的 Sign 方法应该足以对单个 XML 元素或整个消息进行签名,但是我不断收到声称不支持 SHA-256 的 Cryptography 异常。我认为这个异常应该是无效的,因为 RSAPKCS1SHA256SignatureDescription.cs 已注册。然而,观察到 SignedXML 类不包括 SHA-256 的命名空间而只有 SHA-128,我开始怀疑是否支持 SHA 256,无论注册如何。
有人可以告诉我如何最好地解决我的问题并能够通过 RSA SHA 256 算法使用 X.509 证书签署 XML 吗?