public VerifierResponse VerifyXmlSignature( SignatureType mode, XmlDocument message, string certificateFilePath = null, string certificateThumb = null, string nodeId = null, bool isVerifyCertificateChain = false) { SignedXml signedXml = new SignedXml(message); Signer.Smev2SignedXml smev2SignedXml = null; X509Certificate2 cert = null; bool isCerFile; if ((isCerFile = !string.IsNullOrEmpty(certificateFilePath)) || !string.IsNullOrEmpty(certificateThumb)) { //means we are testing signature on external certificate if (isCerFile) { cert = new X509Certificate2(); try { cert.Import(certificateFilePath); } catch (Exception e) { throw ExceptionFactory.GetException( ExceptionType.CertificateImportException, certificateFilePath, e.Message); } } else { //throws if not found ICertificateProcessor cp = new CertificateProcessor(); cert = cp.SearchCertificateByThumbprint(certificateThumb); } } XmlNodeList signaturesInDoc = message.GetElementsByTagName( "Signature", SignedXml.XmlDsigNamespaceUrl ); var signatures = signaturesInDoc .Cast <XmlElement>() .ToDictionary( (elt) => { XNamespace ns = elt.GetXElement().Name.Namespace; return(elt.GetXElement().Descendants(ns + "Reference").First().Attributes("URI").First() .Value.Replace("#", "")); }, (elt => elt) ); if (!string.IsNullOrEmpty(nodeId) && !signatures.ContainsKey(nodeId)) { throw ExceptionFactory.GetException(ExceptionType.ReferencedSignatureNotFound, nodeId); } if (signaturesInDoc.Count == 0) { throw ExceptionFactory.GetException(ExceptionType.NoSignaturesFound); } switch (mode) { case SignatureType.Smev2BaseDetached: smev2SignedXml = new Signer.Smev2SignedXml(message); try { smev2SignedXml.LoadXml( !string.IsNullOrEmpty(nodeId) ? signatures[nodeId] : signatures["body"]); } catch (Exception e) { throw ExceptionFactory.GetException(ExceptionType.CertificateContentCorrupted, e.Message); } XmlNodeList referenceList = smev2SignedXml.KeyInfo .GetXml() .GetElementsByTagName("Reference", Signer.WsSecurityWsseNamespaceUrl); if (referenceList.Count == 0) { throw ExceptionFactory.GetException(ExceptionType.Smev2CertificateReferenceNotFound); } string binaryTokenReference = ((XmlElement)referenceList[0]).GetAttribute("URI"); if (string.IsNullOrEmpty(binaryTokenReference) || binaryTokenReference[0] != '#') { throw ExceptionFactory.GetException(ExceptionType.Smev2MalformedCertificateReference); } XmlElement binaryTokenElement = smev2SignedXml.GetIdElement( message, binaryTokenReference.Substring(1)); if (binaryTokenElement == null) { throw ExceptionFactory.GetException( ExceptionType.Smev2CertificateNotFound, binaryTokenReference.Substring(1)); } try { cert = new X509Certificate2(Convert.FromBase64String(binaryTokenElement.InnerText)); } catch (Exception e) { throw ExceptionFactory.GetException(ExceptionType.Smev2CertificateCorrupted, e.Message); } break; case SignatureType.Smev2ChargeEnveloped: if (signaturesInDoc.Count > 1) { throw ExceptionFactory.GetException( ExceptionType.ChargeTooManySignaturesFound, signaturesInDoc.Count); } if (!ChargeStructureOk(message)) { throw ExceptionFactory.GetException(ExceptionType.ChargeMalformedDocument); } try { signedXml.LoadXml(signatures.First().Value); } catch (Exception e) { throw ExceptionFactory.GetException(ExceptionType.CertificateContentCorrupted, e.Message); } break; case SignatureType.Smev2SidebysideDetached: case SignatureType.Smev3BaseDetached: case SignatureType.Smev3SidebysideDetached: try { XmlDsigSmevTransform smevTransform = new XmlDsigSmevTransform(); signedXml.SafeCanonicalizationMethods.Add(smevTransform.Algorithm); signedXml.LoadXml( !string.IsNullOrEmpty(nodeId) ? signatures[nodeId] : signatures.First().Value); } catch (Exception e) { throw ExceptionFactory.GetException(ExceptionType.CertificateContentCorrupted, e.Message); } break; case SignatureType.Pkcs7String: case SignatureType.Pkcs7StringAllCert: case SignatureType.Pkcs7StringNoCert: case SignatureType.SigDetached: case SignatureType.SigDetachedAllCert: case SignatureType.SigDetachedNoCert: throw new NotSupportedException( $"Detached signature verification is not supported by this method. Use {nameof(VerifyDetachedSignature)} method instead."); case SignatureType.Unknown: case SignatureType.Smev3Ack: case SignatureType.Rsa2048Sha256String: case SignatureType.RsaSha256String: throw ExceptionFactory.GetException(ExceptionType.UnsupportedSignatureType, mode); default: throw new ArgumentOutOfRangeException(nameof(mode), mode, null); } var isSignatureValid = smev2SignedXml?.CheckSignature(cert.PublicKey.Key) ?? (cert == null ? signedXml.CheckSignature() : signedXml.CheckSignature(cert, true) ); var isCertificateChainValid = cert?.Verify() ?? true; StringBuilder verificationMessage = new StringBuilder(); if (!isSignatureValid) { verificationMessage.AppendLine("Signature is invalid"); } if (!isCertificateChainValid) { verificationMessage.AppendLine("Certificate chain is invalid"); } var verifierResponse = new VerifierResponse() { IsCertificateChainValid = isCertificateChainValid, IsSignatureMathematicallyValid = isSignatureValid, IsSignatureSigningDateValid = true, // we do not check this for this type of signature Message = verificationMessage.ToString() }; return(verifierResponse); }
public static XmlDocument SignXmlFileSmev3(XmlDocument doc, X509Certificate2 certificate, string signingNodeId, bool assignDs, bool isAck = false, bool isSidebyside = false) { XmlNamespaceManager nsm = new XmlNamespaceManager(doc.NameTable); nsm.AddNamespace("ns", "urn://x-artefacts-smev-gov-ru/services/message-exchange/types/1.1"); nsm.AddNamespace("ns1", "urn://x-artefacts-smev-gov-ru/services/message-exchange/types/basic/1.1"); nsm.AddNamespace("ds", "http://www.w3.org/2000/09/xmldsig#"); SignedXml sxml = new SignedXml(doc) { SigningKey = certificate.PrivateKey }; //=====================================================================================REFERENCE TRASFORMS Reference reference = new Reference { Uri = "#" + signingNodeId, #pragma warning disable 612 //Расчет хеш-суммы ГОСТ Р 34.11-94 http://www.w3.org/2001/04/xmldsig-more#gostr3411 DigestMethod = CryptoPro.Sharpei.Xml.CPSignedXml.XmlDsigGost3411UrlObsolete #pragma warning disable 612 }; XmlDsigExcC14NTransform excC14n = new XmlDsigExcC14NTransform(); reference.AddTransform(excC14n); XmlDsigSmevTransform smevTransform = new XmlDsigSmevTransform(); reference.AddTransform(smevTransform); if (isAck) { XmlDsigEnvelopedSignatureTransform enveloped = new XmlDsigEnvelopedSignatureTransform(); reference.AddTransform(enveloped); } sxml.AddReference(reference); //=========================================================================================CREATE SIGNATURE sxml.SignedInfo.CanonicalizationMethod = SignedXml.XmlDsigExcC14NTransformUrl; //Формирование подписи ГОСТ Р 34.10-2001 http://www.w3.org/2001/04/xmldsig-more#gostr34102001-gostr3411 sxml.SignedInfo.SignatureMethod = CryptoPro.Sharpei.Xml.CPSignedXml.XmlDsigGost3410UrlObsolete; KeyInfo keyInfo = new KeyInfo(); KeyInfoX509Data X509KeyInfo = new KeyInfoX509Data(certificate); keyInfo.AddClause(X509KeyInfo); sxml.KeyInfo = keyInfo; sxml.ComputeSignature(); XmlElement signature = sxml.GetXml(); //==================================================================================================add ds: if (assignDs) { _assignNsPrefix(signature, "ds"); XmlElement xmlSignedInfo = signature.SelectSingleNode("ds:SignedInfo", nsm) as XmlElement; XmlDocument document = new XmlDocument(); document.PreserveWhitespace = false; document.LoadXml(xmlSignedInfo.OuterXml); //create new canonicalization object based on original one Transform canonicalizationMethodObject = sxml.SignedInfo.CanonicalizationMethodObject; canonicalizationMethodObject.LoadInput(document); //get new hshing object based on original one SignatureDescription description = CryptoConfig.CreateFromName(sxml.SignedInfo.SignatureMethod) as SignatureDescription; if (description == null) { throw new CryptographicException( $"Не удалось создать объект SignatureDescription по имени [{sxml.SignedInfo.SignatureMethod}]"); } HashAlgorithm hash = description.CreateDigest(); if (hash == null) { throw new CryptographicException( $"Не удалось создать объект HashAlgorithm из SignatureDescription по имени [{sxml.SignedInfo.SignatureMethod}]"); } //compute new SignedInfo digest value byte[] hashVal = canonicalizationMethodObject.GetDigestedOutput(hash); //compute new signature XmlElement xmlSignatureValue = signature.SelectSingleNode("ds:SignatureValue", nsm) as XmlElement; xmlSignatureValue.InnerText = Convert.ToBase64String(description.CreateFormatter(sxml.SigningKey).CreateSignature(hashVal)); } //=============================================================================APPEND SIGNATURE TO DOCUMENT if (!isSidebyside) { doc.GetElementsByTagName("CallerInformationSystemSignature", "urn://x-artefacts-smev-gov-ru/services/message-exchange/types/1.1")[0].InnerXml = ""; doc.GetElementsByTagName("CallerInformationSystemSignature", "urn://x-artefacts-smev-gov-ru/services/message-exchange/types/1.1")[0].AppendChild(signature); } else { getNodeWithAttributeValue(doc.ChildNodes, signingNodeId)?.ParentNode?.AppendChild(signature); } return(doc); }
public static bool Signed(string file, string sigFile, X509Certificate2 certificate, bool MessageID = true) { //------------------------------------------- // Создаем новый документ XML. XmlDocument doc = new XmlDocument { PreserveWhitespace = true }; // Читаем документ из файла. XmlTextReader XmlTxtRead = new XmlTextReader(file); doc.Load(XmlTxtRead); XmlTxtRead.Close(); // Создаём объект SmevSignedXml - наследник класса SignedXml с перегруженным GetIdElement // для корректной обработки атрибута wsu:Id. _SignedXml _signedXml = new _SignedXml(doc) { // Задаём ключ подписи для документа SmevSignedXml. SigningKey = certificate.PrivateKey }; //------------------------------------------- string IdMessageTypeSelector = ""; if (doc.GetElementsByTagName("MessageTypeSelector", "*")[0] != null) { IdMessageTypeSelector = doc.GetElementsByTagName("MessageTypeSelector", "*")[0].Attributes["Id"].Value; } if (doc.GetElementsByTagName("AckTargetMessage", "*")[0] != null) { IdMessageTypeSelector = doc.GetElementsByTagName("AckTargetMessage", "*")[0].Attributes["Id"].Value; } if (doc.GetElementsByTagName("SenderProvidedResponseData", "*")[0] != null) { IdMessageTypeSelector = doc.GetElementsByTagName("SenderProvidedResponseData", "*")[0].Attributes["Id"].Value; } if (doc.GetElementsByTagName("Timestamp", "*")[0] != null) { if (doc.GetElementsByTagName("Timestamp", "*")[0].Attributes["Id"] != null) { IdMessageTypeSelector = doc.GetElementsByTagName("Timestamp", "*")[0].Attributes["Id"].Value; } } if (doc.GetElementsByTagName("SenderProvidedRequestData", "*")[0] != null) { IdMessageTypeSelector = doc.GetElementsByTagName("SenderProvidedRequestData", "*")[0].Attributes["Id"].Value; } // Создаем ссылку на подписываемый узел XML. В данном примере и в методических // рекомендациях СМЭВ подписываемый узел soapenv:Body помечен идентификатором "body". Reference reference = new Reference { Uri = "#" + IdMessageTypeSelector }; // Задаём алгоритм хэширования подписываемого узла - ГОСТ Р 34.11-94. Необходимо // использовать устаревший идентификатор данного алгоритма, т.к. именно такой // идентификатор используется в СМЭВ. if (certificate.GetKeyAlgorithm() != "1.2.643.7.1.1.1.1") { reference.DigestMethod = CPSignedXml.XmlDsigGost3411Url;//ГОСТ Р 34.11-94 } else { reference.DigestMethod = CPSignedXml.XmlDsigGost3411_2012_256Url;//ГОСТ Р 34.11-2012 256бит } // Добавляем преобразование для приведения подписываемого узла к каноническому виду // по алгоритму http://www.w3.org/2001/10/xml-exc-c14n# в соответствии с методическими // рекомендациями СМЭВ. XmlDsigExcC14NTransform c14 = new XmlDsigExcC14NTransform(); reference.AddTransform(c14); _signedXml.AddReference(reference); // Добавляем преобразование для приведения подписываемого узла к каноническому виду // по алгоритму urn://smev-gov-ru/xmldsig/transform в соответствии с методическими // рекомендациями СМЭВ. XmlDsigSmevTransform dsig = new XmlDsigSmevTransform(); reference.AddTransform(dsig); _signedXml.AddReference(reference); // Задаём преобразование для приведения узла ds:SignedInfo к каноническому виду // по алгоритму http://www.w3.org/2001/10/xml-exc-c14n# в соответствии с методическими // рекомендациями СМЭВ. _signedXml.SignedInfo.CanonicalizationMethod = SignedXml.XmlDsigExcC14NTransformUrl; // Задаём алгоритм подписи - ГОСТ Р 34.10-2001. Необходимо использовать устаревший // идентификатор данного алгоритма, т.к. именно такой идентификатор используется в // СМЭВ. if (certificate.GetKeyAlgorithm() != "1.2.643.7.1.1.1.1") { _signedXml.SignedInfo.SignatureMethod = CPSignedXml.XmlDsigGost3410Url;//ГОСТ Р 34.10-2001 } else { _signedXml.SignedInfo.SignatureMethod = CPSignedXml.XmlDsigGost3410_2012_256Url;//ГОСТ Р 34.10-2012 256бит } // Create a new KeyInfo object. KeyInfo keyInfo = new KeyInfo(); // Load the certificate into a KeyInfoX509Data object // and add it to the KeyInfo object. keyInfo.AddClause(new KeyInfoX509Data(certificate)); // Add the KeyInfo object to the SignedXml object. _signedXml.KeyInfo = keyInfo; if (doc.GetElementsByTagName("Timestamp", "*")[0] != null) { //Добавляем время doc.GetElementsByTagName("Timestamp", "*")[0].InnerText = DateTime.Now.ToString("yyyy-MM-ddTHH:mm:ss.fffzzzzz"); } if (MessageID) { if (doc.GetElementsByTagName("MessageID", "*")[0] != null) { //Добавляем UUID doc.GetElementsByTagName("MessageID", "*")[0].InnerText = GuidGenerator.GenerateTimeBasedGuid().ToString(); } } // Вычисляем подпись. _signedXml.ComputeSignature("ds"); // Получаем представление подписи в виде XML. XmlElement xmlDigitalSignature = _signedXml.GetXml("ds"); doc.GetElementsByTagName("CallerInformationSystemSignature", "*")[0].PrependChild( doc.ImportNode(xmlDigitalSignature, true) ); XmlTextWriter xmltw = new XmlTextWriter(sigFile, new UTF8Encoding(false)); doc.WriteTo(xmltw); xmltw.Close(); return(true); }
/// <summary> /// Подпись xml файла /// </summary> static void SignXmlFile(string FileName, string SignedFileName, AsymmetricAlgorithm Key, X509Certificate Certificate) { // Создаем новый XML документ. XmlDocument doc = new XmlDocument(); // Пробельные символы участвуют в вычислении подписи и должны быть сохранены для совместимости с другими реализациями. doc.PreserveWhitespace = true; // Читаем документ из файла. doc.Load(new XmlTextReader(FileName)); // Создаем объект SignedXml по XML документу. SignedXml signedXml = new SignedXml(doc); // Добавляем ключ в SignedXml документ. signedXml.SigningKey = Key; // Создаем ссылку на node для подписи. // При подписи всего документа проставляем "". Reference reference = new Reference(); reference.Uri = ""; // Явно проставляем алгоритм хэширования, // по умолчанию SHA1. reference.DigestMethod = SignedXml.XmlDsigGost3411_2012_256Url; // Добавляем transform на подписываемые данные // для удаления вложенной подписи. XmlDsigEnvelopedSignatureTransform env = new XmlDsigEnvelopedSignatureTransform(); reference.AddTransform(env); // Добавляем СМЭВ трансформ. // начиная с .NET 4.5.1 для проверки подписи, необходимо добавить этот трансформ в довернные: // signedXml.SafeCanonicalizationMethods.Add("urn://smev-gov-ru/xmldsig/transform"); XmlDsigSmevTransform smev = new XmlDsigSmevTransform(); reference.AddTransform(smev); // Добавляем transform для канонизации. XmlDsigC14NTransform c14 = new XmlDsigC14NTransform(); reference.AddTransform(c14); // Добавляем ссылку на подписываемые данные signedXml.AddReference(reference); // Создаем объект KeyInfo. KeyInfo keyInfo = new KeyInfo(); // Добавляем сертификат в KeyInfo keyInfo.AddClause(new KeyInfoX509Data(Certificate)); // Добавляем KeyInfo в SignedXml. signedXml.KeyInfo = keyInfo; // Вычисляем подпись. signedXml.ComputeSignature(); // Получаем XML представление подписи и сохраняем его // в отдельном node. XmlElement xmlDigitalSignature = signedXml.GetXml(); // Добавляем node подписи в XML документ. doc.DocumentElement.AppendChild(doc.ImportNode( xmlDigitalSignature, true)); // При наличии стартовой XML декларации ее удаляем // (во избежание повторного сохранения) if (doc.FirstChild is XmlDeclaration) { doc.RemoveChild(doc.FirstChild); } // Сохраняем подписанный документ в файле. using (XmlTextWriter xmltw = new XmlTextWriter(SignedFileName, new UTF8Encoding(false))) { xmltw.WriteStartDocument(); doc.WriteTo(xmltw); } }
static XmlDocument SignXmlFile(XmlDocument doc, AsymmetricAlgorithm Key, X509Certificate Certificate) { // Создаем объект SignedXml по XML документу. SignedXml signedXml = new SignedXml(doc); // Добавляем ключ в SignedXml документ. signedXml.SigningKey = Key; // Создаем ссылку на node для подписи. // При подписи всего документа проставляем "". Reference reference = new Reference(); reference.Uri = ""; // Явно проставляем алгоритм хэширования, // по умолчанию SHA1. reference.DigestMethod = SignedXml.XmlDsigGost3411_2012_256Url; // Добавляем transform на подписываемые данные // для удаления вложенной подписи. XmlDsigEnvelopedSignatureTransform env = new XmlDsigEnvelopedSignatureTransform(); reference.AddTransform(env); // Добавляем СМЭВ трансформ. // начиная с .NET 4.5.1 для проверки подписи, необходимо добавить этот трансформ в довернные: // signedXml.SafeCanonicalizationMethods.Add("urn://smev-gov-ru/xmldsig/transform"); XmlDsigSmevTransform smev = new XmlDsigSmevTransform(); reference.AddTransform(smev); // Добавляем transform для канонизации. XmlDsigC14NTransform c14 = new XmlDsigC14NTransform(); reference.AddTransform(c14); // Добавляем ссылку на подписываемые данные signedXml.AddReference(reference); // Создаем объект KeyInfo. KeyInfo keyInfo = new KeyInfo(); // Добавляем сертификат в KeyInfo keyInfo.AddClause(new KeyInfoX509Data(Certificate)); // Добавляем KeyInfo в SignedXml. signedXml.KeyInfo = keyInfo; // Можно явно проставить алгоритм подписи: ГОСТ Р 34.10. // Если сертификат ключа подписи ГОСТ Р 34.10 // и алгоритм ключа подписи не задан, то будет использован // XmlDsigGost3410Url // signedXml.SignedInfo.SignatureMethod = // CPSignedXml.XmlDsigGost3410_2012_256Url; // Вычисляем подпись. signedXml.ComputeSignature(); // Получаем XML представление подписи и сохраняем его // в отдельном node. XmlElement xmlDigitalSignature = signedXml.GetXml(); // Добавляем node подписи в XML документ. doc.DocumentElement.AppendChild(doc.ImportNode( xmlDigitalSignature, true)); // При наличии стартовой XML декларации ее удаляем // (во избежание повторного сохранения) if (doc.FirstChild is XmlDeclaration) { doc.RemoveChild(doc.FirstChild); } return(doc); }