/// <summary> /// Метод нахождения префикса /// </summary> /// <param name="element"></param> /// <param name="isTypeBasic"></param> /// <returns></returns> private string FindPrefix(XmlElement element, bool isTypeBasic) { try { log.LogDebug("Пытаемся получить значение префикса."); string prefix = SoapDSigUtil.FindPrefix(element, NamespaceUri.Smev3Types); if (!isTypeBasic) { prefix = (string.Compare(prefix, "xmlns", StringComparison.InvariantCultureIgnoreCase) == 0) ? string.Empty : prefix; } else { prefix = (string.IsNullOrEmpty(prefix) || string.Compare(prefix, "xmlns", true) == 0) ? "typesBasic" : prefix; } log.LogDebug($"Значение префикса успешно получено: {prefix}."); return(prefix); } catch (Exception ex) { throw new Exception($"Ошибка при попытке получить значение префикса. {ex.Message}."); } }
/// <summary> /// /// </summary> /// <param name="document"></param> /// <param name="idValue"></param> /// <returns></returns> public override XmlElement GetIdElement(XmlDocument document, string idValue) { XmlNamespaceManager nsmgr = new XmlNamespaceManager(document.NameTable); XmlElement element = null; if (string.IsNullOrEmpty(idValue) == false) { string prefix = SoapDSigUtil.FindPrefix(document.DocumentElement, this.NamespaceForReference); if (string.IsNullOrEmpty(prefix)) { prefix = "wsu"; } nsmgr.AddNamespace(prefix, this.NamespaceForReference); string findString = string.Format("//*[(@Id='{0}' and namespace-uri()='{1}') or (@{2}:Id='{0}')]", idValue, this.NamespaceForReference, prefix); element = document.SelectSingleNode(findString, nsmgr) as XmlElement; } else if (document.DocumentElement != null) { element = document.DocumentElement; } return(element); }
/// <summary> /// Метод подписи XML подписью органа власти /// </summary> /// <param name="doc"></param> /// <param name="certificate"></param> /// <returns></returns> private XmlDocument SignMessage2XX(XmlDocument xml, IntPtr certificate) { try { // Удаляем тэг Actor string message = string.Empty; try { log.LogDebug("Пытаемся удалить атрибут 'Actor'."); message = SoapDSigUtil.RemoveActor(xml); log.LogDebug("Атрибут 'Actor' успешно удален."); } catch (Exception ex) { throw new Exception($"Ошибка при попытке удалить атрибут 'Actor'. {ex.Message}."); } XmlDocument doc = new XmlDocument() { PreserveWhitespace = true }; try { doc.LoadXml(message); } catch (Exception ex) { throw new Exception($"Ошибка при формировании XML после удаления атрибута 'Actor'. {ex.Message}."); } try { log.LogDebug("Получаем значение тэга для подписи."); this.tagForSign = this.FindSmevTagForSign(doc); log.LogDebug($"Значение тэга для подписи получено. {tagForSign}."); } catch (Exception ex) { throw new Exception($"Ошибка при попытке получить тэг с элементом для подписи. {ex.Message}."); } SmevSignedXml signedXml = new SmevSignedXml(doc); try { log.LogDebug($"Выполняем добавление элемента Reference в XML."); signedXml = (SmevSignedXml)SmevXmlHelper.AddReference(doc, signedXml, certificate, SignWithId, mrVersion, ElemForSign, ref idCounter, tagForSign, tagForSignNamespaceUri, namespaceIdAttr: NamespaceUri.OasisWSSecurityUtility ); log.LogDebug($"Добавление элемента Reference в XML выполнено успешно."); } catch (Exception ex) { throw new Exception($"Ошибка при попытке добавить элемент Reference. {ex.Message}."); } signedXml.NamespaceForReference = NamespaceUri.OasisWSSecurityUtility; signedXml.SignedInfo.CanonicalizationMethod = SignedXml.XmlDsigExcC14NTransformUrl; try { log.LogDebug($"Пытаемся получить значение SignatureMethod."); signedXml.SignedInfo.SignatureMethod = SignServiceUtils.GetSignatureMethod(SignServiceUtils.GetAlgId(certificate)); log.LogDebug($"Значение SignatureMethod успешно получено: {signedXml.SignedInfo.SignatureMethod}."); } catch (Exception ex) { throw new Exception($"Ошибка при попытке получить значение метода подписи. {ex.Message}."); } XmlElement keyInfoElem = doc.CreateElement("KeyInfo", NamespaceUri.WSXmlDSig); XmlElement binaryTokenElem = doc.CreateElement("wsse", "BinarySecurityToken", NamespaceUri.OasisWSSecuritySecext); XmlElement tokenReferenceElem = doc.CreateElement("wsse", "SecurityTokenReference", NamespaceUri.OasisWSSecuritySecext); XmlElement referenceElem = doc.CreateElement("wsse", "Reference", NamespaceUri.OasisWSSecuritySecext); string certId = "uuid-" + Guid.NewGuid().ToString(); XmlAttribute idAttr = doc.CreateAttribute("u", "Id", NamespaceUri.OasisWSSecurityUtility); XmlAttribute valueTypeTokenAttr = doc.CreateAttribute("ValueType"); XmlAttribute encodingTypeTokenAttr = doc.CreateAttribute("EncodingType"); idAttr.Value = certId; valueTypeTokenAttr.Value = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3"; encodingTypeTokenAttr.Value = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary"; binaryTokenElem.Attributes.Append((XmlAttribute)doc.ImportNode(idAttr, true)); binaryTokenElem.Attributes.Append((XmlAttribute)doc.ImportNode(valueTypeTokenAttr, true)); binaryTokenElem.Attributes.Append((XmlAttribute)doc.ImportNode(encodingTypeTokenAttr, true)); X509Certificate2 cert = SignServiceUtils.GetX509Certificate2(certificate); binaryTokenElem.InnerText = Convert.ToBase64String(cert.RawData); XmlAttribute valueTypeAttr = doc.CreateAttribute("ValueType"); valueTypeAttr.Value = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3"; referenceElem.Attributes.Append((XmlAttribute)doc.ImportNode(valueTypeAttr, true)); XmlAttribute uriAttr = doc.CreateAttribute("URI"); uriAttr.Value = "#" + certId; referenceElem.Attributes.Append((XmlAttribute)doc.ImportNode(uriAttr, true)); tokenReferenceElem.PrependChild(doc.ImportNode(referenceElem, true)); keyInfoElem.PrependChild(doc.ImportNode(tokenReferenceElem, true)); try { KeyInfoNode keyNode = new KeyInfoNode(tokenReferenceElem); KeyInfo keyInfo = new KeyInfo(); keyInfo.AddClause(keyNode); signedXml.KeyInfo = keyInfo; } catch (Exception ex) { throw new Exception($"Ошибка при формировании элемента KeyInfo. {ex.Message}."); } try { log.LogDebug($"Пытаемся вычислить подпись."); signedXml.ComputeSignatureWithoutPrivateKey(xmldsigPrefix, certificate); log.LogDebug($"Вычисление подписи выполнено успешно."); } catch (Exception ex) { throw new Exception($"Ошибка при попытке вычислить подпись для XML. {ex.Message}."); } XmlElement signatureElem = null; try { log.LogDebug("Пытаемся получить элемент с подписью."); signatureElem = signedXml.GetXml(xmldsigPrefix); log.LogDebug("Элемент с подписью успешно получен."); } catch (Exception ex) { throw new Exception($"Ошибка при попытке получить элемент содержащий подпись. {ex.Message}."); } try { log.LogDebug("Пытаемся добавить подпись в XML содержимое."); FillSignatureElement(doc, signatureElem, certificate, binaryTokenElem); log.LogDebug("Подпись успешно добавлена."); } catch (Exception ex) { throw new Exception($"Ошибка при попытке заполнить XML информацией о подписи. {ex.Message}."); } try { log.LogDebug("Пытаемся добавить атрибут 'Actor'."); SoapDSigUtil.AddActor(doc); log.LogDebug("Атрибут 'Actor' успешно добавлен."); } catch (Exception ex) { throw new Exception($"Ошибка при попытке добавить атрибут 'Actor'. {ex.Message}."); } return(doc); } catch (Exception ex) { log.LogError($"Ошибка при попытке подписать XML. {ex.Message}."); throw new CryptographicException($"Ошибка при попытке подписать XML для версии {mrText[mrVersion]}. {ex.Message}."); } finally { SignServiceUtils.FreeHandleCertificate(certificate); } }