Приложение №5 к Правилам корпоративного электронного документооборота «Личный кабинет. Клиент инфраструктуры обслуживания» Программный модуль подготовки данных для РКС Программный модуль подготовки данных для РКС представлен в виде исходного текста, предназначенного для последующей компиляции (сборки) Исполняемого модуля подготовки данных для РКС (далее Модуль). Цель представления Модуля в исходном виде – доказательство связи между выполняемыми Модулем операциями и получаемым результатом. Получение Модуля 1. Модуль может быть получен путем компиляции исходного текста Программного модуля РКС Организатора с использованием компилятора Microsoft C#, поставляемого в составе пакета Microsoft .NET Framework 2.0. Инструкция по компиляции Программного модуля приводится в пункте 4 настоящего приложения. 1.1. Условия выполнения Модуля 2. Для выполнения Модуля и процедуры разбора конфликтной ситуации необходимо работоспособный компьютер, удовлетворяющий следующим минимальным требованиям: 2.1. 2.2. 3. 3.1. подготовить 2.1.1. Процессор: Intel 512MHz; 2.1.2. Объем оперативной памяти – 512МБ; 2.1.3. Объем дискового пространства: 40ГБ; 2.1.4. Порт USB 1.0; 2.1.5. Клавиатура, Мышь. 2.1.6. Операционная система: Microsoft Windows XP SP2 или Microsoft Windows 2003 Server Enterprise Edition SP2. Для правильной работы модуля на компьютере должны быть установлены следующие программные продукты: 2.2.1. Microsoft Internet Explorer версии 6.0; 2.2.2. MSXML 6.0 Service Pack 1 (Microsoft XML Core Services); 2.2.3. Microsoft .NET Framework 2.0. Описание работы Модуль применяется к одному файлу спорного документа. В результате работы Модуля формируется (в формате HTML) файл «Перечень электронных цифровых подписей формата XML-ЭЦП в спорном документе» (сохраняется в той же папке, что и спорный документ под именем <файл спорного документа>-Signature.txt), и последовательность файлов (файл данных, файл ЭЦП и файл сертификата, включенного в элемент XML-ЭЦП) для последующей передачи сертифицированному средству проверки подлинности ЭЦП, формирующему отчеты о результате проверки согласно п.2.4.1.2 Приложения №6 Правил. 3.2. В случае поступления на вход документа, не являющегося файлом формата XML, или файла с элементом XMLЭЦП без идентификатора (атрибут «Id» элемента Signature) Модуль создает запись в файле перечня элементов XMLЭЦП о нарушенной структуре файла спорного документа, и проверка ЭЦП в таком документе считается невозможной. 3.3. 4. Инструкция по компиляции Модуля Для получения Модуля следует использовать приводимую ниже схему: 4.1. Сохранить Исходный текст в файл с именем FrsdExtractSign.cs; 4.2. Выполнить в командной строке следующие команды, находясь в папке, где создан файл FrsdExtractSign.cs: set cscompiler=<путь к компилятору Microsoft .NET Framework 2.0> %cscompiler% /debug- /optimize+ /unsafe /out:FrsdExtractSign.exe FrsdExtractSign.cs Здесь использованы следующие обозначения: <путь к компилятору Microsoft .NET Framework 2.0> – путь, указывающий на исполняемый модуль компилятора языка C#, включенного в среду Microsoft .NET Framework 2.0. 1 Приложение №5 к Правилам корпоративного электронного документооборота «Личный кабинет. Клиент инфраструктуры обслуживания» Результатом работы компилятора является исполняемый модуль FrsdExtractSign.exe. 5. Инструкция по выполнению Модуля Для применения Модуля к спорному документу следует: Скопировать файл спорного документа, имеющий имя, обозначаемое ниже <спорный документ>, в папку, где создан Модуль FrsdExtractSign.exe; 5.1. Применить Модуль FrsdExtractSign.exe к спорному документу, используя следующую инструкцию командной строки (текущей папкой должна являться папка, где создан Модуль FrsdExtractSign.exe): 5.2. FrsdExtractSign.exe <спорный документ> 6. using using using using using using using using using Исходный текст System; System.Collections; System.Collections.Specialized; System.IO; System.Runtime.InteropServices; System.Security.Cryptography; System.Text; System.Xml; Frsd.Algorithms; namespace Frsd { namespace Algorithms { /// <summary> /// Приведение элемента XML-документа к стандартной текстовой форме. /// </summary> public class Alg_1_8_1 { // ---// Вспомогательные методы public const string XmlnsNs = "http://www.w3.org/2000/xmlns/"; public void CollectNamespaces(StringDictionary nsDict, XmlNode E) { CollectNamespacesForChild(nsDict, E); } public void CollectNamespacesForChild(StringDictionary nsDict, XmlNode E) { string ns = E.NamespaceURI; nsDict[ns] = ns; XmlAttributeCollection attributes = E.Attributes; for (int k = 0; k < attributes.Count; ++k) { string nsURI1 = attributes[k].NamespaceURI; if (nsURI1 != XmlnsNs) nsDict[nsURI1] = nsURI1; } for (XmlNode node = E.FirstChild; node != null; node = node.NextSibling) { if (node.NodeType == XmlNodeType.Element) { CollectNamespaces(nsDict, node); } } } string EncodeAttribute(string attrValue) { string v = attrValue; // v = v.Replace("\"", "&quot;"); v = v.Replace("<", "&lt;"); v = v.Replace(">", "&gt;"); // 2 Приложение №5 к Правилам корпоративного электронного документооборота «Личный кабинет. Клиент инфраструктуры обслуживания» return v; } // ---// Преобразование к стандартной форме public HashAlgorithm Hasher = null; public Stream Output = null; void AddBlock(byte[] data) { if (Hasher != null) Hasher.TransformBlock(data, 0, data.Length, data, 0); if (Output != null) Output.Write(data, 0, data.Length); } void AddFinalBlock(byte[] data) { if (Hasher != null) Hasher.TransformFinalBlock(data, 0, data.Length); if (Output != null) Output.Write(data, 0, data.Length); } public void Transform(XmlElement E) { StringDictionary nsDict = new StringDictionary(); CollectNamespaces(nsDict, E); string[] nsArray = new string[nsDict.Keys.Count]; int j = 0; foreach (DictionaryEntry pair in nsDict) { nsArray[j] = (string)pair.Value; ++j; } nsArray = new Alg_1_8_4().Sort(nsArray); // StringDictionary nsPrefixes = new StringDictionary(); for (j = 0; j < nsArray.Length; ++j) { nsPrefixes[nsArray[j]] = String.Format("ns{0}", j + 1); } // TransformChild(E, nsPrefixes, nsDict, true); } public void TransformChild(XmlElement E, StringDictionary nsPrefixes, StringDictionary nsDict,bool isRoot) { int i; // // Атрибуты // string ATTRIBUTES = ""; { string[] attributes = new string[E.Attributes.Count]; int attrN = 0; StringDictionary attrValues = new StringDictionary(); for (i = 0; i < E.Attributes.Count; ++i) { XmlAttribute A = E.Attributes[i]; string name = A.Name; string localName = A.LocalName; string nsURI = A.NamespaceURI; if ((nsURI != XmlnsNs) && (!((localName == "xmlns") && (nsURI == "")))) { string nsPrefix = nsPrefixes[nsURI]; string attribute = nsPrefix + ":" + localName; attributes[attrN] = attribute; ++attrN; attrValues[attribute] = A.Value; } } string[] a2 = new string[attrN]; for (i = 0; i < attrN; ++i) a2[i] = attributes[i]; attributes = new Alg_1_8_4().Sort(a2); // for (i = 0; i < attrN; ++i) { if (i > 0) ATTRIBUTES += " "; 3 Приложение №5 к Правилам корпоративного электронного документооборота «Личный кабинет. Клиент инфраструктуры обслуживания» string attribute = attributes[i]; string attrValue = attrValues[attribute]; ATTRIBUTES += attribute + "=\"" + EncodeAttribute(attrValue) + "\""; } // attrValues.Clear(); } // string tagName = E.LocalName; string EnsURI = E.NamespaceURI; // string head = ""; string tail = ""; // if (isRoot) { string PR = ""; string[] nsArray = new string[nsPrefixes.Count]; int j = 0; foreach (DictionaryEntry pair in nsPrefixes) { nsArray[j] = (string)pair.Key; ++j; } nsArray = new Alg_1_8_4().Sort(nsArray); for (j = 0; j < nsArray.Length; ++j) { if (j > 0) PR += " "; string ns = nsArray[j]; PR += "xmlns:" + nsPrefixes[ns] + "=\"" + nsDict[ns] + "\""; } // string nsPrefix = nsPrefixes[EnsURI]; if (ATTRIBUTES == "") { head = "<" + nsPrefix + ":" + E.LocalName + " " + PR + ">"; tail = "</" + nsPrefix + ":" + E.LocalName + ">"; } else { head = "<" + nsPrefix + ":" + E.LocalName + " " + PR + " " + ATTRIBUTES + ">"; tail = "</" + nsPrefix + ":" + E.LocalName + ">"; } } else { string nsPrefix = nsPrefixes[EnsURI]; if (ATTRIBUTES == "") { head = "<" + nsPrefix + ":" + E.LocalName + ">"; tail = "</" + nsPrefix + ":" + E.LocalName + ">"; } else { head = "<" + nsPrefix + ":" + E.LocalName + " " + ATTRIBUTES + ">"; tail = "</" + nsPrefix + ":" + E.LocalName + ">"; } } { byte[] headData = Encoding.UTF8.GetBytes(head); AddBlock(headData); } // // Дочерние элементы и текстовые узлы // for (XmlNode node = E.FirstChild; node != null; node = node.NextSibling) { XmlNodeType nodeType = node.NodeType; if (nodeType == XmlNodeType.Text) { string v1 = ((XmlText)node).Value; v1 = v1.Trim(); string v2 = ""; for (int j = 0; j < v1.Length; ++j) { if ((UInt32)v1[j] > 15) v2 += new string(v1[j], 1); } { 4 Приложение №5 к Правилам корпоративного электронного документооборота «Личный кабинет. Клиент инфраструктуры обслуживания» byte[] textData; textData = Encoding.UTF8.GetBytes(v2); AddBlock(textData); } } else if (nodeType == XmlNodeType.Element) { TransformChild((XmlElement)node, nsPrefixes, nsDict, false); } } { byte[] tailData; tailData = Encoding.UTF8.GetBytes(tail); if (isRoot) { AddFinalBlock(tailData); } else { AddBlock(tailData); } } } public byte[] TransformFile(string path) { XmlDocument doc = new XmlDocument(); doc.Load(path); // MemoryStream ms = new MemoryStream(); Output = ms; Transform(doc.DocumentElement); byte[] data = new byte[ms.Length]; ms.Position = 0; ms.Read(data, 0, data.Length); // return data; } } /// <summary> /// Хеш-функция SHA1. /// </summary> public class Alg_1_8_2 { public HashAlgorithm NewHashAlgorithm { get { SHA1 shaM = new SHA1Managed(); return shaM; } } } /// <summary> /// Текстовая сортировка. /// </summary> public class Alg_1_8_4 { public string[] Sort(string[] A) { string[] array = A; // for (int i = 0; i < array.Length-1; ++i) { string x = array[i]; // // Находим минимальный элемент среди array[i+1],...,array[array.Length-1] // int min_k = i+1; string m_y = array[i+1]; // 5 Приложение №5 к Правилам корпоративного электронного документооборота «Личный кабинет. Клиент инфраструктуры обслуживания» for (int k = i+2; k < array.Length; ++k) { if (LessThan(array[k],m_y)) { min_k = k; m_y = array[k]; } } // if (LessThan(m_y,x)) { array[i] = m_y; array[min_k] = x; } } // return array; } public bool LessThan(string x,string y) { for (int i = 0; (i < x.Length) && (i < y.Length); ++i) { if (CharLessThan(x[i],y[i])) return true; // x < y if (CharLessThan(y[i],x[i])) return false; // x > y } if (x.Length < y.Length) return true; // x < y if (x.Length > y.Length) return false; // x > y return false; // Строки x и y совпадают } public bool CharLessThan(char X,char Y) { string russianABC = RussianABC(); string latinABC = LatinABC(); string digits = Digits(); // int Xclass = 0; int Yclass = 0; // if (digits.IndexOf(X.ToString()) != -1) Xclass = 1; if (latinABC.IndexOf(X.ToString()) != -1) Xclass = 2; if (russianABC.IndexOf(X.ToString()) != -1) Xclass = 3; // if (digits.IndexOf(Y.ToString()) != -1) Yclass = 1; if (latinABC.IndexOf(Y.ToString()) != -1) Yclass = 2; if (russianABC.IndexOf(Y.ToString()) != -1) Yclass = 3; // if (Xclass < Yclass) return true; // X < Y if (Xclass > Yclass) return false; // X > Y // if (Xclass == 1) { int Xpos = digits.IndexOf(X.ToString()); int Ypos = digits.IndexOf(Y.ToString()); return Xpos < Ypos; } else if (Xclass == 2) { int Xpos = latinABC.IndexOf(X.ToString()); int Ypos = latinABC.IndexOf(Y.ToString()); return Xpos < Ypos; } else if (Xclass == 2) { int Xpos = latinABC.IndexOf(X.ToString()); int Ypos = latinABC.IndexOf(Y.ToString()); return Xpos < Ypos; } else // (Xclass == 0) { long Xcode = (long)X; long Ycode = (long)Y; return Xcode < Ycode; } } string RussianABC() 6 Приложение №5 к Правилам корпоративного электронного документооборота «Личный кабинет. Клиент инфраструктуры обслуживания» { return "АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЬЫЪЭЮЯабвгдеёжзийклмнопрстуфхцчшщьыъэюя"; } string LatinABC() { return "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; } string Digits() { return "0123456789"; } } /// <summary> /// Подкотовка данных для РКС, связанной с проверкой элемента подписи XMLdsig. /// </summary> public class Alg_1_8_6 { // ---// Анализ подписи XMLdsig public enum Reason { SIGNATURE_OK = 0, SIGNATURE_NOT_FOUND = 1, BAD_SIGNATURE = 2 } string PrepareResult(Reason reason,string description) { string mainResult = ""; // if (reason == Reason.SIGNATURE_OK) mainResult = "OK"; else if (reason == Reason.SIGNATURE_NOT_FOUND) mainResult = "Не удалось обнаружить элемент подписи"; else if (reason == Reason.BAD_SIGNATURE) mainResult = "Элемент подписи имеет неверный формат"; // if (description != "" && mainResult != "OK") mainResult += ": " + description; // return mainResult; } bool ReturnEmptyData(out byte[] data, out byte[] signature, out XmlElement extra) { data = new byte[0]; signature = new byte[0]; extra = null; return false; } public unsafe bool AnalyzeExtractData(XmlElement Signature_E, bool verify, out byte[] certificate, out byte[] data, out byte[] signature, out XmlElement extra, out string reason) { int k; // XmlNamespaceManager nsmgr = new XmlNamespaceManager(Signature_E.OwnerDocument.NameTable); nsmgr.AddNamespace("dsig", "http://www.w3.org/2000/09/xmldsig#"); // // Идентификатор подписи // string Signature_Id = Signature_E.GetAttribute("Id"); string Signature_URI = "#" + Signature_Id; // XmlNodeList Property_L = Signature_E.SelectNodes("//dsig:SignatureProperty", nsmgr); for (k = 0; k < Property_L.Count; ++k) { string uri = ((XmlElement)Property_L[k]).GetAttribute("Target"); if (uri != Signature_URI) 7 Приложение №5 к Правилам корпоративного электронного документооборота «Личный кабинет. Клиент инфраструктуры обслуживания» { reason = "Ошибка в формате элемента подписи XMLdsig"; certificate = new byte[0]; return ReturnEmptyData(out data, out signature, out extra); } } // // Сертификат // certificate = System.Convert.FromBase64String( Signature_E.SelectSingleNode("//dsig:X509Certificate", nsmgr).InnerText ); // // Дополнительные параметры подписи // extra = (XmlElement)Signature_E .SelectSingleNode("dsig:Object/dsig:SignatureProperties", nsmgr); // // Проверяем узлы Refernce // XmlNodeList Reference_L = Signature_E .SelectNodes("dsig:SignedInfo/dsig:Reference", nsmgr); // for (k = 0; k < Reference_L.Count; ++k) { XmlElement Reference_E = (XmlElement)Reference_L[k]; // bool enveloped = false; XmlNodeList Transform_L = Reference_E .SelectNodes("dsig:Transforms/dsig:Transform", nsmgr); for (int t_i = 0; t_i < Transform_L.Count; ++t_i) { string trAlgorithm = ((XmlElement)Transform_L[t_i]) .GetAttribute("Algorithm"); // if (trAlgorithm == "http://www.w3.org/2000/09/xmldsig#enveloped-signature") { enveloped = true; } else { reason = "Неподдерживаемый алгоритм преобразования: " + trAlgorithm.ToString(); return ReturnEmptyData(out data, out signature, out extra); } } // string uri = Reference_E.GetAttribute("URI"); if (!uri.StartsWith("#")) { reason = String.Format("Ошибка в URI: {0}", uri); return ReturnEmptyData(out data, out signature, out extra); } string search = ""; if (uri.StartsWith("#xpointer")) { search = uri.Substring("#xpointer(".Length); search = search.Substring(0, search.Length - 1); } else { string Id = uri.Substring(1, uri.Length - 1); search = String.Format("//*[@Id='{0}']", Id); } XmlNodeList L = Signature_E.OwnerDocument.SelectNodes(search, nsmgr); if (L.Count == 0) { reason = "Не найден элемент XPath='{" + search + "}' для Reference"; return ReturnEmptyData(out data, out signature, out extra); } if (L.Count > 1) { reason = "Найдено более одного элемента XPath='{" + search + "}' для Reference"; return ReturnEmptyData(out data, out signature, out extra); } XmlElement E = (XmlElement)(L[0].Clone()); if (enveloped) 8 Приложение №5 к Правилам корпоративного электронного документооборота «Личный кабинет. Клиент инфраструктуры обслуживания» { int j; XmlNodeList child_L = E.SelectNodes("node()"); int tail = -1; for (j = 0; j < child_L.Count; ++j) { XmlNode child = child_L[j]; if (child.NodeType == XmlNodeType.Element) { XmlElement child_E = (XmlElement)child; if ((child_E.LocalName == "Signature") && (child_E.NamespaceURI == "http://www.w3.org/2000/09/xmldsig#")) { if (!child_E.HasAttribute("Id")) { reason = "Отсутствует атрибут Id у элемента Signature"; return ReturnEmptyData(out data, out signature, out extra); } if (child_E.GetAttribute("Id") == Signature_Id) tail = j; } } } if (tail != -1) { j = child_L.Count - 1; while (j >= tail) { E.RemoveChild(child_L[j]); --j; } } } // Alg_1_8_1 alg = new Alg_1_8_1(); alg.Hasher = new Alg_1_8_2().NewHashAlgorithm; alg.Transform(E); string hash64 = Convert.ToBase64String(alg.Hasher.Hash).Trim(); // XmlElement DigestValue_E = (XmlElement)Reference_E.SelectSingleNode("dsig:DigestValue", nsmgr); if (DigestValue_E.InnerText != hash64) { reason = "Хеш-код '" + DigestValue_E.InnerText + "' ошибочен"; return ReturnEmptyData(out data, out signature, out extra); } } // XmlElement SignatureValue_E = (XmlElement)Signature_E.SelectSingleNode("dsig:SignatureValue", nsmgr); // signature = System.Convert.FromBase64String( SignatureValue_E.InnerText ); // MemoryStream ms2 = new MemoryStream(); Alg_1_8_1 alg1 = new Alg_1_8_1(); alg1.Output = ms2; alg1.Transform( (XmlElement)Signature_E.SelectSingleNode("dsig:SignedInfo", nsmgr) ); data = new byte[ms2.Length]; ms2.Position = 0; ms2.Read(data, 0, data.Length); // string textToSign = System.Text.Encoding.UTF8.GetString(data); // reason = "Данные для проверки подлинности ЭЦП подготовлены"; return true; } public unsafe string PrepareForReferee(XmlDocument doc, string Signature_Id, out DateTime t) { XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable); nsmgr.AddNamespace("dsig", "http://www.w3.org/2000/09/xmldsig#"); nsmgr.AddNamespace("dse", "http://cabinet.frsd.ru/schema/xmldsigext-frsd/rel-1/"); // 9 Приложение №5 к Правилам корпоративного электронного документооборота «Личный кабинет. Клиент инфраструктуры обслуживания» // Элемент подписи XMLdsig // Reason reason = Reason.SIGNATURE_OK; // string search = String.Format("//dsig:Signature[@Id='{0}']", Signature_Id); XmlNodeList Signature_L = doc.SelectNodes(search, nsmgr); if (Signature_L.Count == 0) { reason = Reason.SIGNATURE_NOT_FOUND; } if (Signature_L.Count > 1) { reason = Reason.SIGNATURE_NOT_FOUND; } if (reason != Reason.SIGNATURE_OK) { t = DateTime.Now; return PrepareResult(reason,""); } // // Анализируем обнаруженный элемент подписи XMLdsig // XmlElement Signature_E = (XmlElement)Signature_L[0]; // byte[] certificate; byte[] data; byte[] signature; XmlElement extra; string r1; // bool result = false; try { result = AnalyzeExtractData(Signature_E, false, // не проверяем, передаем АРМ РКС out certificate, out data, out signature, out extra, out r1); // if (!result) { t = DateTime.Now; return PrepareResult(Reason.BAD_SIGNATURE, ""); } } catch (Exception e) { t = DateTime.Now; return PrepareResult(Reason.BAD_SIGNATURE, e.ToString()); } // string signaturePath = Signature_Id; if (!Directory.Exists(signaturePath)) Directory.CreateDirectory(signaturePath); // FileStream writer; string path; // // Записываем сертификат // path = signaturePath + "\\author.cer"; writer = File.Open(path,FileMode.Create,FileAccess.Write); writer.Write(certificate,0,(int)certificate.Length); writer.Close(); // // Записываем данные // path = signaturePath + "\\signed.data"; writer = File.Open(path,FileMode.Create,FileAccess.Write); writer.Write(data,0,(int)data.Length); writer.Close(); // // Записываем подпись // path = signaturePath + "\\cms.sign"; writer = File.Open(path,FileMode.Create,FileAccess.Write); writer.Write(signature,0,(int)signature.Length); writer.Close(); // string datetime_s = ((XmlElement)extra 10 Приложение №5 к Правилам корпоративного электронного документооборота «Личный кабинет. Клиент инфраструктуры обслуживания» .SelectSingleNode("dsig:SignatureProperty/dse:Events", nsmgr)) .GetAttribute("SignatureTime"); year = System.Convert.ToInt32(datetime_s.Substring(0,4), 10); month = System.Convert.ToInt32(datetime_s.Substring(5, 2), 10); day = System.Convert.ToInt32(datetime_s.Substring(8, 2), 10); hour = System.Convert.ToInt32(datetime_s.Substring(11, 2), 10); minute = System.Convert.ToInt32(datetime_s.Substring(14, 2), 10); second = System.Convert.ToInt32(datetime_s.Substring(17, 2), 10); new DateTime(year,month,day,hour,minute,second,0); int int int int int int t = // return PrepareResult(reason,""); } } /// <summary> /// Подготовка данных для РКС, связанной с проверкой ЭЦП в спорном документе. /// </summary> public class Alg_1_8_7 { public enum Reason { SIGNATURES_OK = 0, BAD_SIGNATURE_FOUND = 1, CORRUPTED_SIGNATURE_FOUND = 2, BAD_XML = 3 } // ---// Вспомогательные методы static XmlDocument CurrentDoc; static XmlNamespaceManager NsMgr { get { if (m_NsMgr == null) { m_NsMgr = new XmlNamespaceManager(CurrentDoc.NameTable); m_NsMgr.AddNamespace("dsig", "http://www.w3.org/2000/09/xmldsig#"); } return m_NsMgr; } } static XmlNamespaceManager m_NsMgr; StringDictionary Signature_Ids = new StringDictionary(); const string tab = " "; public string PrepareReport(Reason commonReason, StringDictionary results, StringDictionary times, string docPath) { string report; // // Элементы подписи // string signatureElementsPartH = "Элементы XML-ЭЦП:\n"; string signatureElementsPart = signatureElementsPartH; // if (commonReason == Reason.SIGNATURES_OK) { foreach (DictionaryEntry pair in results) { string Signature_Id = Signature_Ids[(string)pair.Key]; string t_s = times[Signature_Id]; // string signaturePath = Path.GetFullPath(Signature_Id); // signatureElementsPart += tab + "Элемент XML-ЭЦП " + Signature_Id + "\n" + tab + tab + "Время создания: " + t_s + " UTC\n" + tab + tab + tab + "Файл подписи: " + signaturePath + "\\cms.sign\n" + tab + tab + tab + "Файл данных: " + signaturePath + "\\signed.data\n" + tab + tab + tab + "Файл сертификата: " + 11 Приложение №5 к Правилам корпоративного электронного документооборота «Личный кабинет. Клиент инфраструктуры обслуживания» signaturePath + "\\author.cer\n" + tab + tab + tab + "Файл сертификата Удостоверяющего центра: " + signaturePath + "\\ca.cer\n" + tab + tab + tab + "Файл списка отозванных сертификатов: " + signaturePath + "\\cacrl.crl\n"; } // if (signatureElementsPart == signatureElementsPartH) { signatureElementsPart = tab + "Элементы XML-ЭЦП не обнаружены\n"; } } else { signatureElementsPart = ""; } // // Файл документа // string docFileName = Path.GetFileName(docPath); string docName = Path.GetFileNameWithoutExtension(docPath); string docFullPath = Path.GetFullPath(docFileName); string reportFileName = docName + "-Signatures.txt"; // // Файл перечня подписей формата XMLdsig // string mainResult = ""; if (commonReason == Reason.SIGNATURES_OK) mainResult = ""; else if (commonReason == Reason.BAD_SIGNATURE_FOUND) mainResult = "Обнаружен элемент подписи неверного формата"; else if (commonReason == Reason.BAD_XML) mainResult = "Структура документа нарушена"; // string time_s = System.DateTime.Now.ToString("dd.MM.yyyy, HH:mm:ss"); report = @" Перечень электронных цифровых подписей формата XML-ЭЦП в спорном документе Время создания перечня: " + time_s + @" Спорный документ: " + docFullPath + @" " + mainResult + @" " + signatureElementsPart + @" "; // FileStream writer = File.Open(reportFileName,FileMode.Create,FileAccess.Write); byte[] reportText = Encoding.GetEncoding("windows-1251").GetBytes(report); writer.Write(reportText,0,(int)reportText.Length); writer.Close(); // return report; } // ---// Подготовка спорного документа для РКС public string AnalyzeSignatures(XmlDocument doc,string docPath) { CurrentDoc = doc; // StringDictionary results = new StringDictionary(); StringDictionary times = new StringDictionary(); // // Перебираем элементы подписи XMLdsig // XmlNodeList Signature_L = doc.SelectNodes("//dsig:Signature",NsMgr); // for (int k = 0; k < Signature_L.Count; ++k) { // Анализируем элемент подписи XMLdsig // XmlElement Signature_E = (XmlElement)Signature_L[0]; if (! Signature_E.HasAttribute("Id")) { return PrepareReport(Reason.BAD_SIGNATURE_FOUND, results, times, docPath); } 12 Приложение №5 к Правилам корпоративного электронного документооборота «Личный кабинет. Клиент инфраструктуры обслуживания» string Signature_Id = Signature_E.GetAttribute("Id"); // DateTime t; // string result = ""; try { result = new Alg_1_8_6().PrepareForReferee(doc, Signature_Id, out t); // if (result == "OK") times[Signature_Id] = t.ToString("dd.MM.yyyy, HH:mm:ss"); else times[Signature_Id] = ""; } catch (Exception e) { result = "Элемент подпись имеет неверный формат: " + e.ToString(); // times[Signature_Id] = ""; } // results[Signature_Id] = result; Signature_Ids[Signature_Id] = Signature_Id; } // return PrepareReport(Reason.SIGNATURES_OK, results, times, docPath); } public string AnalyzeFileSignatures(string docPath) { XmlDocument doc = new XmlDocument(); try { doc.Load(docPath); } catch (Exception) { return PrepareReport(Reason.BAD_XML, null, null, ""); } // return AnalyzeSignatures(doc, docPath); } } } } namespace FrsdConflict { class FrsdConflictApp { public static void Main(string[] args) { string path = args[0]; // new Alg_1_8_7().AnalyzeFileSignatures(path); } } } 13