Xml-заголовок, подписанный алгоритмами SHA 384
Я пытаюсь отправить подписанный xml-запрос в какой-то сторонний java-сервис. Запрос был подписан сертификатом подписи, предоставленным третьей стороной.
Сторонняя служба java ожидает, что входящий запрос будет подписан алгоритмами SHA384.
Наш запрос не выполняется в службе java с ошибкой значение digest1 не соответствует (то есть проверка подписи становится неудачной)
Ниже приведен подписанный XML код:
Что я уже пробовал:
публичный класс RsaPkCs1Sha384SignatureDescription : SignatureDescription
{
общественные RsaPkCs1Sha384SignatureDescription()
{
KeyAlgorithm = typeof(RSACryptoServiceProvider).Полное имя;
DigestAlgorithm = typeof(SHA384CryptoServiceProvider).Полное имя;
FormatterAlgorithm = typeof(RSAPKCS1SignatureFormatter).Полное имя;
DeformatterAlgorithm = typeof(RSAPKCS1SignatureDeformatter).Полное имя;
}
public override AsymmetricSignatureDeformatter CreateDeformatter(ключ AsymmetricAlgorithm)
{
var sigProcessor = (AsymmetricSignatureDeformatter)CryptoConfig.CreateFromName(DeformatterAlgorithm);
сигпроцессор.SetKey(ключ);
сигпроцессор.SetHashAlgorithm("SHA384");
возврат sigProcessor;
}
public override AsymmetricSignatureFormatter CreateFormatter(ключ AsymmetricAlgorithm)
{
var sigProcessor = (AsymmetricSignatureFormatter)CryptoConfig.CreateFromName(FormatterAlgorithm);
сигпроцессор.SetKey(ключ);
сигпроцессор.SetHashAlgorithm("SHA384");
возврат sigProcessor;
}
}
внутренний класс CustomSignedXml
{
// Резюме:
// Представляет единый идентификатор ресурса (URI) для описания конверта soap
// трансформация. Это поле постоянно.
общественные константные строки xmlSoapEnvelopeUrl = "http://schemas.xmlsoap.org/soap/envelope/";
// Резюме:
// Представляет единый идентификатор ресурса (URI) для описания безопасности soap
// трансформация. Это поле постоянно.
общественные константные строки xmlSoapSecurityUrl = "http://schemas.xmlsoap.org/soap/security/2000-12";
// Резюме:
/ Представляет универсальный код ресурса (URI) пространства имен для программы ВС
// трансформация. Это поле постоянно.
общественные константные строки xmlOasisWSSSecurityUtilUrl = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd";
// Резюме:
/ Представляет универсальный код ресурса (URI) пространства имен с расширением ВС
// трансформация. Это поле постоянно.
общественные константные строки xmlOasisWSSSecurityExtUrl = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";
// Эта функция расширяет переопределенный метод GetIdElement объекта
// базовый класс SignedXML для поиска атрибута "id" в дополнение к
// атрибут "Id" по умолчанию.
общественные константные строки rsaSHA256Url = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256";
общественные константные строки rsaSHA384Url = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha384";
общественные константные строки SHA256Url = "http://www.w3.org/2001/04/xmlenc#sha256";
строки общественные константные SHA384Url = "http://www.w3.org/2001/04/xmldsig-more#sha384";
public const string Base64Binary = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary";
public const string ValueType = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3";
общественные константные строки EnvelopeSoap = "http://www.w3.org/2003/05/soap-envelope";
}
внутренний класс SignedXmlWithId : SignedXml
{
общественные SignedXmlWithId(в формате XML в XmlDocument) : база данных(XML) { }
общественные SignedXmlWithId(отображает отображает) : основание(отображает) { }
общественного переопределить отображает GetIdElement(объект XmlDocument DOC, в строке ID )
{
// проверьте, является ли это стандартным идентификатором ссылки
XmlElement idElem = база.GetIdElement(документ, удостоверение личности);
if (idElem == null)
{
XmlNamespaceManager nsManager = новый XmlNamespaceManager(doc.NameTable);
nsManager.Addnamespace дает("УАЗу", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd");
Идель = док.SelectSingleNode("//*[@wsu:Id=\"" + id + "\"]", nsManager) как XmlElement;
}
возвращение иделем;
}
}
[Упорядочиваемый]
внутренний класс SecurityTokenReference : KeyInfoClause
{
частная строка m_id, referenceAttributeValue;
частный XmlDocument m_doc;
закрытый Ключinfox509data m_keyX509Data = новый Ключinfox509data();
public SecurityTokenReference(string id, string referenceAttribute, XmlDocument doc)
{
m_id = идентификатор;
m_doc = док;
referenceAttributeValue = referenceAttribute;
}
общественного переопределить отображает GetXml()
{
XNamespace ca = CustomSignedXml.xmlOasisWSSSecurityExtUrl;
XmlElement element = m_doc.CreateElement("wsse", "SecurityTokenReference", CustomSignedXml.xmlSoapEnvelopeUrl);
XmlAttribute idAttrib = m_doc.CreateAttribute("wsu", "Id", CustomSignedXml.xmlOasisWSSSecurityUtilUrl);
idAttrib.Значение = m_id;
элемент.Атрибуты.Добавить(idAttrib);
XmlElement xElement = m_doc.CreateElement("wsse", "Reference", CustomSignedXml.xmlSoapEnvelopeUrl);
элемент.Префикс = "wsse";
Отображает referenceAttribute = m_doc.CreateAttribute("Ури", "");
атрибут referenceAttribute.Значение = referenceAttributeValue;
Отображает referenceValueType = m_doc.CreateAttribute("Велоэтапе", "");
referenceValueType.Value = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3";
элемент XElement.Атрибуты.Добавить(referenceAttribute);
элемент XElement.Атрибуты.Добавить(referenceValueType);
элемент.AppendChild(xElement);
возвращаемый элемент;
}
открытый Ключinfox509data KeyX509Data { get { return m_keyX509Data; } }
общественного переопределить недействительными LoadXml(элемент отображает )
{
m_id = элемент.GetAttribute("Id", CustomSignedXml.xmlOasisWSSSecurityUtilUrl);
}
}
публичный класс SignedXML
{
частная строка только для чтения clientCertificatePassword;
частная чтения строки certificatePath;
частный сертификат X509Certificate2;
частная строка BodyId = "Id-" + Guid.Метод newguid().Метод toString().Заменить("-", "");
частная строка TimeStampAttribute = "TS-" + Guid.Метод newguid().Метод toString().Заменить("-", "");
частная строка BinarySecurityAttribute = "X509-" + Guid.Метод newguid().Метод toString().Заменить("-", "");
частная строка SignatureId = "SIG-" + Guid.Метод newguid().Метод toString().Заменить("-", "");
частная строка keyInfoId = "KI-" + Guid.Метод newguid().Метод toString().Заменить("-", "");
частная строка SecurityToken = "STR-" + Guid.Метод newguid().Метод toString().Заменить("-", "");
общественные метода signedxml()
{
ReadCertificate();
}
private RSA GenerateSigningKey(XmlDocument doc)
{
Сертификат X509Certificate2 = ReadCertificate();
var key = (RSACryptoServiceProvider)сертификат.Закрытый ключ;
var enhCsp = new RSACryptoServiceProvider().CspKeyContainerInfo;
ВАР cspparams = новый cspparameters используется(enhCsp.Providertype используется, enhCsp.Имя_поставщика, ключ.CspKeyContainerInfo.KeyContainerName);
RSACryptoServiceProvider rsaKey = новый RSACryptoServiceProvider(4096, cspparams);
по ключу RSA.PersistKeyInCsp = false;
вернуться ключу RSA;
}
частная x509certificate2 с ReadCertificate()
{
X509Store store = новый X509Store(имя магазина.Мой, Расположение Магазина.Локальная машина);
магазин.Open(OpenFlags.Только Для Чтения | OpenFlags.OpenExistingOnly);
X509Certificate2Collection collection = (X509Certificate2Collection)магазин.Сертификаты;
X509Certificate2Collection fcollection = (X509Certificate2Collection)коллекция.Найти(Типа X509findtype.FindByTimeValid, Даты И Времени.А теперь-ложь);
X509Certificate2Collection scollection = X509Certificate2UI.SelectFromCollection(fcollection, "Sign", "Select certificate", X509SelectionFlag.SingleSelection);
if (scollection != null && scollection.Количество == 1)
{
сертификат = scollection[0];
если (сертификат.HasPrivateKey == false)
{
бросьте новое исключение("сертификат не имеет закрытого ключа.");
}
}
магазин.Закрывать();
возвратный сертификат;
}
частный недействительными MakeSecurityElement(арт объект XmlDocument объект XmlDocument)
{
экспортный ВАР = это.сертификат.Экспорт(X509ContentType.Cert);
var exportCertificate = конвертировать.ToBase64String(экспорт);
Отображает xmlElementSecurity = объект XmlDocument.CreateElement("wsse", "Security", CustomSignedXml.xmlOasisWSSSecurityExtUrl);
xmlElementSecurity.Атрибуты.SetNamedItem(CreateAttribute(xmlDocument, "soap", "mustUnderstand", "true", CustomSignedXml.EnvelopeSoap));
xmlElementSecurity.SetAttribute("xmlns:wsse", CustomSignedXml.xmlOasisWSSSecurityExtUrl);
xmlElementSecurity.SetAttribute("xmlns:wsu", CustomSignedXml.xmlOasisWSSSecurityUtilUrl);
Отображает xmlElementBinarySecurityTokeny = объект XmlDocument.CreateElement("wsse", "BinarySecurityToken", CustomSignedXml.xmlSoapEnvelopeUrl);
xmlElementBinarySecurityTokeny.Через свойство innerText = exportCertificate;
xmlElementBinarySecurityTokeny.Атрибуты.SetNamedItem(CreateAttribute(xmlDocument, "wsu", "Id", BinarySecurityAttribute, CustomSignedXml.xmlOasisWSSSecurityUtilUrl));
xmlElementBinarySecurityTokeny.Атрибуты.SetNamedItem(CreateAttribute(xmlDocument, "", "EncodingType", CustomSignedXml.Base64Binary, ""));
xmlElementBinarySecurityTokeny.Атрибуты.SetNamedItem(CreateAttribute(xmlDocument, "", "ValueType", CustomSignedXml.ValueType, ""));
Отображает xmlElementTimestamp = объект XmlDocument.Метод createElement("УАЗу", "метка времени", CustomSignedXml.xmlOasisWSSSecurityUtilUrl);
xmlElementTimestamp.Атрибуты.SetNamedItem(CreateAttribute(xmlDocument, "wsu", "Id", TimeStampAttribute, CustomSignedXml.xmlOasisWSSSecurityUtilUrl));
Отображает xmlElementCreated = объект XmlDocument.CreateElement("wsu", "Created", CustomSignedXml.xmlOasisWSSSecurityUtilUrl);
xmlElementCreated.Через Свойство InnerText = Датавремя.Сейчас.Метод toString("гггг-мм-ддтчч:мм:ссz");
xmlElementTimestamp.Метода appendChild(xmlElementCreated);
xmlElementSecurity.Метода appendChild(xmlElementBinarySecurityTokeny);
xmlElementSecurity.Метода appendChild(xmlElementTimestamp);
объект XmlDocument.GetElementsByTagName("soap:Header")[0].InsertBefore(xmlElementSecurity, xmlDocument.GetElementsByTagName("soap:Header")[0].FirstChild);
объект XmlDocument.GetElementsByTagName("мыло:тело").Пункт(0).Атрибуты.SetNamedItem(CreateAttribute(xmlDocument, "wsu", "Id", BodyId, CustomSignedXml.xmlOasisWSSSecurityUtilUrl));
объект XmlDocument.PreserveWhitespace = true;
}
общественные объект XmlDocument SignXMLHeader(объект XmlDocument объект XmlDocument)
{
CryptoConfig.AddAlgorithm(typeof(RsaPkCs1Sha384SignatureDescription), "http://www.w3.org/2001/04/xmldsig-more#rsa-sha384");
MakeSecurityElement(арт объект XmlDocument);
BinarySecurityAttribute = "#" + BinarySecurityAttribute;
TimeStampAttribute = "#" + TimeStampAttribute;
BodyId = "#" + BodyId;
var signingKey = GenerateSigningKey(xmlDocument);
SignedXmlWithId signedXml = новый SignedXmlWithId(xmlDocument);
подписанный документ.SignedInfo.CanonicalizationMethod = SignedXml.XmlDsigExcC14NTransformUrl;
XmlDsigExcC14NTransform canMethod = (XmlDsigExcC14NTransform)signedXml.SignedInfo.CanonicalizationMethodObject;
канметод.InclusiveNamespacesPrefixList = "мыло";
подписанный документ.SigningKey = ключ подписи;
подписанный документ.Подпись.Id = SignatureId;
подписанный документ.SignedInfo.SignatureMethod = CustomSignedXml.rsaSHA384Url;
SecurityTokenReference tokenRef = новый SecurityTokenReference(securitytoken, в, BinarySecurityAttribute, объект XmlDocument);
tokenRef.KeyX509Data.AddSubjectKeyId(Идентификатор GUID.Метод newguid().Метод toString().Заменить("-", ""));
tokenRef.KeyX509Data.AddIssuerSerial(сертификат.Эмитент, сертификат.GetSerialNumberString());
Reference referenceBody = новая ссылка(BodyId);
Reference referenceTimeStamp = новая ссылка(атрибут TimeStampAttribute);
Reference referenceBinarySecurity = новая ссылка(BinarySecurityAttribute);
XmlDsigExcC14NTransform reference1TransForm = новый XmlDsigExcC14NTransform();
reference1TransForm.InclusiveNamespacesPrefixList = "";
XmlDsigExcC14NTransform reference2TransForm = новый XmlDsigExcC14NTransform();
reference2TransForm.InclusiveNamespacesPrefixList = "wsse soap";
XmlDsigExcC14NTransform reference3TransForm = новый XmlDsigExcC14NTransform();
reference3TransForm.InclusiveNamespacesPrefixList = "мыло";
referenceBody.AddTransform(reference1TransForm);
referenceTimeStamp.AddTransform(reference2TransForm);
referenceBinarySecurity.AddTransform(reference3TransForm);
referenceBody.DigestMethod = CustomSignedXml.SHA384Url;
referenceTimeStamp.DigestMethod = CustomSignedXml.SHA384Url;
referenceBinarySecurity.DigestMethod = CustomSignedXml.SHA384Url;
подписанный документ.Добавить ссылку(referenceBody);
подписанный документ.Добавить ссылку(referenceTimeStamp);
подписанный документ.Добавить ссылку(referenceBinarySecurity);
То KeyInfo-то KeyInfo = новый то KeyInfo();
то KeyInfo.Id = keyInfoId;
то KeyInfo.AddClause(tokenRef);
подписанный документ.То KeyInfo = то KeyInfo;
подписанный документ.ComputeSignature();
Отображает xmlDigitalSignature = метода signedxml.GetXml();
foreach (узел XmlNode в xmlDigitalSignature.SelectNodes("descendant-or-self::*[namespace-uri()='http://www.w3.org/2000/09/xmldsig#']"))
узел.Префикс = "ds";
foreach (узел XmlNode в xmlDigitalSignature.SelectNodes("descendant-or-self::*[namespace-uri()='http://www.w3.org/2001/10/xml-exc-c14n#']"))
узел.Префикс = "ec";
метода signedxml.LoadXml(xmlDigitalSignature);
подписанный документ.SignedInfo.Список литературы.Четкий();
подписанный документ.ComputeSignature();
XmlNodeList xmlNodeList = xmlDocument.GetElementsByTagName("wsse:безопасность");
Руководство руководство = xmlNodeList[0];
узел XmlNode.Метод insertbefore(xmlDigitalSignature, руководство.Возвращение null);
VerifyDetachedSignature(xmlDocument, signingKey);
вернуть объект XmlDocument;
}
private XmlAttribute CreateAttribute(XmlDocument xmlDocument, string prefix, string attributeName, string attributeValue, string namespaceURI)
{
Отображает отображает = объект XmlDocument.CreateAttribute(префикс, имя атрибута, namespaceURI);
отображает.Value = attributeValue;
вернуться отображает;
}
// Проверьте подпись XML - файла и верните результат.
public static Boolean VerifyDetachedSignature(XmlDocument xmlDocument, ключ RSA)
{
// Создайте новый объект SignedXml и передайте его
// класс XML - документа.
Метода signedxml метода signedxml = новая метода signedxml();
// Найдите узел "подпись" и создайте новый
/ Объект / XmlNodeList.
XmlNodeList nodeList = xmlDocument.GetElementsByTagName("ds:подпись");
// Загрузите узел подписи.
signedXml.LoadXml((XmlElement)nodeList[0]);
// Проверьте подпись и верните результат.
var result = signedXml.CheckSignature(Ключ);
возвращаемый результат;
}
}
публичный класс ConsumeProxy
{
только для чтения строка ServicePath;
только для чтения X509Certificate2 x509Certificate;
публичный сертификат ConsumeProxy(X509Certificate2)
{
ServicePath = ManageConfigurationItem.ServicePath;
сертификат x509 сертификат;
}
публичная строка ConsumeProxy(string Xml)
{
XmlDocument soapEnvelopeXml = новый XmlDocument();
soapEnvelopeXml.LoadXml(Xml);
Класса HttpWebRequest запросы WebRequest = CreateWebRequest();
веб-запрос.UserAgent = "Образец Сертификата Клиента";
//Servicepointmanager и.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(delegate { return true; });
использование (Stream stream = webRequest.GetRequestStream())
{
soapEnvelopeXml.Сохранить(трансляция);
использование (WebResponse response = webRequest.GetResponse())
{
using (StreamReader rd = new StreamReader(response.GetResponseStream()))
{
вернуться РД.ReadToEnd();
}
}
}
}
частный HttpWebRequest CreateWebRequest()
{
Uri myUri = новый Uri(ServicePath, UriKind.Абсолютный);
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Создать(myUri);
веб-запрос.ContentType = "application/soap+xml; charset=\"utf-8\"";
веб-запрос.Метод = "сообщение";
веб-запрос.Полномочие.Учетные Данные = System.Net.CredentialCache.Свойство defaultcredentials;
веб-запрос.Значении clientcertificates.Добавить(x509Certificate);
вернуться в WebRequest;
}
}
общественности частичного класс form1 : форма
{
открытый form1()
{
метод InitializeComponent();
}
частная SHA384_Click недействительным(объект отправителя, EventArgs в электронной)
{
Подписанный документ();
}
общественного недействительными метода signedxml()
{
строка path = Environment.Текущей каталог + "/test1.xml";
строка xml = файл.ReadAllText(путь);
Объект XmlDocument XmlDocument объект = новый объект XmlDocument();
объект XmlDocument.LoadXml(в формате XML);
Метода signedxml метода signedxml = новая метода signedxml();
Объект XmlDocument signedXmlDocument = метода signedxml.SignXMLHeader(объект XmlDocument);
строка testXML = signedXmlDocument.OuterXml;
}
}