C # Поддержка подписи RSA SHA 256 для отдельных элементов XML
Я столкнулся с блокировщиком в .NET Framework версии 4.5 для подписи XML с помощью цифровых подписей.
Моя проблема основана на необходимости подписывать отдельные элементы XML сертификатом X.509 с помощью алгоритма RSA SHA-256. Я прочитал много постов .NET по этой теме, и кажется, что есть решение, изначально разработанное в классе RSRKCS1SHA256SignatureDescription.cs проекта безопасности CLR. RSAPKCS1SHA256SignatureDescription, разумеется, с тех пор был включен в среду выполнения .net, а начиная с .NET 4.5 теперь доступен в распределенном двоичном файле System.Deployment.dll. Я пытался использовать вышеуказанное решение в .NET для подписи определенных элементов XML с помощью RSA SHA-256, однако пока не достиг успеха.
Я пытаюсь подписать сообщение SOAP, соответствующее стандарту Oasis ebms, токеном WSSE. Пожалуйста, имейте в виду, что класс написан для обслуживания Soap With Attachments (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;
}
}
}
Метод Sign в моем классе SignatureSupportUtility должен быть достаточным для подписи отдельных элементов XML или всего сообщения, однако я продолжаю получать исключение криптографии, утверждающее, что SHA-256 не поддерживается. Я думаю, что это исключение не должно быть действительным, учитывая, что RSAPKCS1SHA256SignatureDescription.cs зарегистрирован. Однако, учитывая, что класс SignedXML не включает в себя пространство имен для SHA-256 и только SHA-128, я начинаю сомневаться в том, что SHA 256 поддерживается независимо от регистрации.
Может ли кто-нибудь посоветовать мне, как лучше решить мою проблему и как можно подписать XML с помощью сертификата X.509 с помощью алгоритма RSA SHA 256?