Пример #1
0
        private static XmlElement Smev3Signed(Stream message, string id)
        {
            var document = new XmlDocument();

            document.PreserveWhitespace = false;
            document.Load(message);

            var signedXml = new SmevSignedXml(document);

            using (var key = GostCryptoConfig.CreateGost3410AsymmetricAlgorithm())
            {
                var reference = new Reference();

                reference.Uri = "#" + id;
                reference.AddTransform(new XmlDsigExcC14NTransform());
                reference.AddTransform(new XmlDsigSmevTransform());

                signedXml.SigningKey = key;
                signedXml.SignedInfo.CanonicalizationMethod = SignedXml.XmlDsigExcC14NTransformUrl;

                if (GostCryptoConfig.ProviderType == ProviderTypes.CryptoPro256)
                {
                    signedXml.SignedInfo.SignatureMethod = SignedXml.XmlDsigGost3410_2012_256Url;
                    reference.DigestMethod = SignedXml.XmlDsigGost3411_2012_256Url;
                }
                else if (GostCryptoConfig.ProviderType == ProviderTypes.CryptoPro512)
                {
                    signedXml.SignedInfo.SignatureMethod = SignedXml.XmlDsigGost3410_2012_512Url;
                    reference.DigestMethod = SignedXml.XmlDsigGost3411_2012_512Url;
                }
                else
                {
                    signedXml.SignedInfo.SignatureMethod = SignedXml.XmlDsigGost3410UrlObsolete;
                    reference.DigestMethod = SignedXml.XmlDsigGost3411UrlObsolete;
                }

                signedXml.AddReference(reference);

                var keyInfo = new KeyInfo();
                keyInfo.AddClause(new KeyInfoX509Data(key.ContainerCertificate));
                signedXml.KeyInfo = keyInfo;
                signedXml.ComputeSignature("ds");
            }
            var smevSign = signedXml.GetXml("ds");

            return(smevSign);
        }
Пример #2
0
        private static XmlDocument SignSmevRequest(XmlDocument smevRequest, Gost3410AsymmetricAlgorithm signingCertificate)
        {
            // Создание подписчика XML-документа
            var signedXml = new SmevSignedXml(smevRequest);             // { GetIdElementHandler = GetSmevIdElement };

            // Установка ключа для создания подписи
            signedXml.SigningKey = signingCertificate;

            // Ссылка на узел, который нужно подписать, с указанием алгоритма хэширования ГОСТ Р 34.11-94 (в соответствии с методическими рекомендациями СМЭВ)
            var dataReference = new Reference {
                Uri = "#body", DigestMethod = SignedXml.XmlDsigGost3411UrlObsolete
            };

            // Метод преобразования, применяемый к данным перед их подписью (в соответствии с методическими рекомендациями СМЭВ)
            var dataTransform = new XmlDsigExcC14NTransform();

            dataReference.AddTransform(dataTransform);

            // Установка ссылки на узел
            signedXml.AddReference(dataReference);

            // Установка алгоритма нормализации узла SignedInfo (в соответствии с методическими рекомендациями СМЭВ)
            signedXml.SignedInfo.CanonicalizationMethod = SignedXml.XmlDsigExcC14NTransformUrl;

            // Установка алгоритма подписи ГОСТ Р 34.10-2001 (в соответствии с методическими рекомендациями СМЭВ)
            signedXml.SignedInfo.SignatureMethod = SignedXml.XmlDsigGost3410UrlObsolete;

            // Вычисление подписи
            signedXml.ComputeSignature();

            // Получение XML-представления подписи
            var signatureXml = signedXml.GetXml();

            // Добавление подписи в исходный документ
            smevRequest.GetElementsByTagName("ds:Signature")[0].PrependChild(smevRequest.ImportNode(signatureXml.GetElementsByTagName("SignatureValue")[0], true));
            smevRequest.GetElementsByTagName("ds:Signature")[0].PrependChild(smevRequest.ImportNode(signatureXml.GetElementsByTagName("SignedInfo")[0], true));
            smevRequest.GetElementsByTagName("wsse:BinarySecurityToken")[0].InnerText = Convert.ToBase64String(signingCertificate.ContainerCertificate.RawData);

            return(smevRequest);
        }
Пример #3
0
        private static bool VerifySmevRequestSignature(XmlDocument signedSmevRequest)
        {
            // Создание подписчика XML-документа
            var signedXml = new SmevSignedXml(signedSmevRequest);             // { GetIdElementHandler = GetSmevIdElement };

            // Поиск узла с подписью
            var nodeList = signedSmevRequest.GetElementsByTagName("Signature", SignedXml.XmlDsigNamespaceUrl);

            // Загрузка найденной подписи
            signedXml.LoadXml((XmlElement)nodeList[0]);

            // Поиск ссылки на BinarySecurityToken
            var references = signedXml.KeyInfo.GetXml().GetElementsByTagName("Reference", WsSecurityExtNamespace);

            if (references.Count > 0)
            {
                // Определение ссылки на сертификат (ссылка на узел документа)
                var binaryTokenReference = ((XmlElement)references[0]).GetAttribute("URI");

                if (!String.IsNullOrEmpty(binaryTokenReference) && binaryTokenReference[0] == '#')
                {
                    // Поиск элемента с закодированным в Base64 сертификатом
                    var binaryTokenElement = signedXml.GetIdElement(signedSmevRequest, binaryTokenReference.Substring(1));

                    if (binaryTokenElement != null)
                    {
                        // Загрузка сертификата, который был использован для подписи
                        var signingCertificate = new X509Certificate(Convert.FromBase64String(binaryTokenElement.InnerText));

                        // Проверка подписи
                        return(signedXml.CheckSignature(signingCertificate.PublicKey.Key));
                    }
                }
            }

            return(false);
        }
Пример #4
0
        static void SignXmlFile(string FileName, string SignedFileName, X509Certificate2 Certificate)
        {
            // Создаем новый документ XML.
            XmlDocument doc = new XmlDocument();

            // Читаем документ из файла.
            doc.Load(new XmlTextReader(FileName));

            // Создаём объект SmevSignedXml - наследник класса SignedXml с перегруженным GetIdElement
            // для корректной обработки атрибута wsu:Id.
            SmevSignedXml signedXml = new SmevSignedXml(doc);

            // Задаём ключ подписи для документа SmevSignedXml.
            signedXml.SigningKey = Certificate.PrivateKey;

            // Создаем ссылку на подписываемый узел XML. В данном примере и в методических
            // рекомендациях СМЭВ подписываемый узел soapenv:Body помечен идентификатором "body".
            Reference reference = new Reference();

            reference.Uri = "#body";

            // Задаём алгоритм хэширования подписываемого узла - ГОСТ Р 34.11-94. Необходимо
            // использовать устаревший идентификатор данного алгоритма, т.к. именно такой
            // идентификатор используется в СМЭВ.
#pragma warning disable 612
            //warning CS0612: 'CryptoPro.Sharpei.Xml.CPSignedXml.XmlDsigGost3411UrlObsolete' is obsolete
            reference.DigestMethod = CryptoPro.Sharpei.Xml.CPSignedXml.XmlDsigGost3411UrlObsolete;
#pragma warning restore 612

            // Добавляем преобразование для приведения подписываемого узла к каноническому виду
            // по алгоритму http://www.w3.org/2001/10/xml-exc-c14n# в соответствии с методическими
            // рекомендациями СМЭВ.
            XmlDsigExcC14NTransform c14 = new XmlDsigExcC14NTransform();
            reference.AddTransform(c14);

            // Добавляем ссылку на подписываемый узел.
            signedXml.AddReference(reference);

            // Задаём преобразование для приведения узла ds:SignedInfo к каноническому виду
            // по алгоритму http://www.w3.org/2001/10/xml-exc-c14n# в соответствии с методическими
            // рекомендациями СМЭВ.
            signedXml.SignedInfo.CanonicalizationMethod = SignedXml.XmlDsigExcC14NTransformUrl;

            // Задаём алгоритм подписи - ГОСТ Р 34.10-2001. Необходимо использовать устаревший
            // идентификатор данного алгоритма, т.к. именно такой идентификатор используется в
            // СМЭВ.
#pragma warning disable 612
            //warning CS0612: 'CryptoPro.Sharpei.Xml.CPSignedXml.XmlDsigGost3411UrlObsolete' is obsolete
            signedXml.SignedInfo.SignatureMethod = CryptoPro.Sharpei.Xml.CPSignedXml.XmlDsigGost3410UrlObsolete;
#pragma warning restore 612

            // Вычисляем подпись.
            signedXml.ComputeSignature();

            // Получаем представление подписи в виде XML.
            XmlElement xmlDigitalSignature = signedXml.GetXml();

            // Добавляем необходимые узлы подписи в исходный документ в заготовленное место.
            doc.GetElementsByTagName("ds:Signature")[0].PrependChild(
                doc.ImportNode(xmlDigitalSignature.GetElementsByTagName("SignatureValue")[0], true));
            doc.GetElementsByTagName("ds:Signature")[0].PrependChild(
                doc.ImportNode(xmlDigitalSignature.GetElementsByTagName("SignedInfo")[0], true));

            // Добавляем сертификат в исходный документ в заготовленный узел
            // wsse:BinarySecurityToken.
            doc.GetElementsByTagName("wsse:BinarySecurityToken")[0].InnerText =
                Convert.ToBase64String(Certificate.RawData);

            // Сохраняем подписанный документ в файл.
            using (XmlTextWriter xmltw = new XmlTextWriter(SignedFileName,
                                                           new UTF8Encoding(false)))
            {
                doc.WriteTo(xmltw);
            }
        }
Пример #5
0
        // Проверяет подписи в файле XML.
        static void VerifyXmlFile(string SignedFileName)
        {
            // Создаем новый документ XML.
            XmlDocument xmlDocument = new XmlDocument();

            // Форматируем документ с сохранением всех пробельных символов, т.к. они
            // важны при проверке подписи.
            xmlDocument.PreserveWhitespace = true;

            // Загружаем подписанный документ XML из файла.
            xmlDocument.Load(SignedFileName);

            // Ищем все узлы ds:Signature и сохраняем их в объекте XmlNodeList
            XmlNodeList nodeList = xmlDocument.GetElementsByTagName(
                "Signature", SignedXml.XmlDsigNamespaceUrl);

            Console.WriteLine("Найдено подписей: {0}.", nodeList.Count);

            // Проверяем все подписи.
            for (int curSignature = 0; curSignature < nodeList.Count; curSignature++)
            {
                // Создаём объект SmevSignedXml - наследник класса SignedXml с перегруженным
                // GetIdElement для корректной обработки атрибута wsu:Id.
                SmevSignedXml signedXml = new SmevSignedXml(xmlDocument);

                // Загружаем узел с подписью.
                signedXml.LoadXml((XmlElement)nodeList[curSignature]);

                // Получаем идентификатор ссылки на узел wsse:BinarySecurityToken,
                // содержащий сертификат подписи.
                XmlNodeList referenceList = signedXml.KeyInfo.GetXml().GetElementsByTagName(
                    "Reference", WSSecurityWSSENamespaceUrl);
                if (referenceList.Count == 0)
                {
                    throw new XmlException("Не удалось найти ссылку на сертификат");
                }

                // Ищем среди аттрибутов ссылку на сертификат.
                string binaryTokenReference = ((XmlElement)referenceList[0]).GetAttribute("URI");

                // Ссылка должна быть на узел внутри данного документа XML, т.е. она имеет вид
                // #ID, где ID - идентификатор целевого узла
                if (string.IsNullOrEmpty(binaryTokenReference) || binaryTokenReference[0] != '#')
                {
                    throw new XmlException("Не удалось найти ссылку на сертификат");
                }

                // Получаем узел BinarySecurityToken с закодированным в base64 сертификатом
                XmlElement binaryTokenElement = signedXml.GetIdElement(
                    xmlDocument, binaryTokenReference.Substring(1));
                if (binaryTokenElement == null)
                {
                    throw new XmlException("Не удалось найти сертификат");
                }

                // Создаём объект X509Certificate2
                X509Certificate2 cert =
                    new X509Certificate2(Convert.FromBase64String(binaryTokenElement.InnerText));

                // Проверяем подпись.
                // ВНИМАНИЕ! Проверка сертификата в данном примере не осуществляется. Её необходимо
                // реализовать самостоятельно в соответствии с требованиями к подписи проверяемого
                // типа сообщения СМЭВ.
                bool result = signedXml.CheckSignature(cert.PublicKey.Key);

                // Выводим результат проверки подписи в консоль
                if (result)
                {
                    Console.WriteLine("Подпись №{0} верна.", curSignature + 1);
                }
                else
                {
                    Console.WriteLine("Подпись №{0} не верна.", curSignature + 1);
                }
            }
        }
Пример #6
0
        /// <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);
            }
        }