При использовании реализованного в статье решения, файл отсоединенной электронной подписи не проходил проверку на валидность на сайте «Госуслуги» и в установленной у заказчика программе «КриптоПро».
Разработать функцию, осуществляющую экспорт документов с открепленной электронной подписью. В результате ее выполнения из Directum должны выгружаться два файла: файл документа и файл отсоединенной электронной подписи формата .sig. Оба файла должны пройти проверку на валидность в специализированном ПО (например, КриптоАРМ).
Также необходимо разработать функцию, осуществляющую импорт документов с открепленной электронной подписью. В результате ее выполнения в Directum должен создаваться подписанный электронный документ, содержимое которого получено из файла документа, а подпись – из файла отсоединенной подписи формата ‘.sig’.
При использовании реализованной в статье функции ExportSignaturesFromEDocVer файл отсоединенной электронной подписи не проходил проверку на сайте «Госуслуги» и в «КриптоПро». Выяснилось, что в нашем случае функция неверно получала тело подписи из базы данных, вследствие чего было решено реализовать второй вариант экспорта отсоединенной подписи, описанный в статье: через чтение ESD-файла.
Кроме того, из функции была удалена возможность выгрузки нескольких подписей, так как по требованиям заказчика необходимо было на выходе иметь один файл подписи, а не несколько.
Вопрос выгрузки нескольких отсоединенных подписей в один файл остался открытым.
В результате экспорт был реализован следующим образом:
if DocVersion.Signed and DocVersion.SignatureType = stApproving
DocVersion.Export(DocPath)
if PDFVersion.Note == "со штампом"
PDFVersion.Export(PDFPath)
endif
TempPath = Format("%s\%s"; ArrayOf(GetTempFolder(); "ExportSign.esd"))
Doc.Export(i+1; TempPath; ; ; True; )
XMLDoc = CreateObject("MSXml.DomDocument")
XMLDoc.Load(TempPath) //Считывание ESD-документа
Root = XMLDoc.selectSingleNode("StructuredElectronicObject") //Получение корневого тега
SignaturesRoot = Root.selectSingleNode("DigitalSignatures") //Получение корневого тега раздела с подписями
FirstSignature = SignaturesRoot.selectSingleNode("DigitalSignature") //Получение первой подписи из набора
FirstSignatureBody = FirstSignature.selectSingleNode("Data") //Получение тела подписи
FirstSignatureValue = FirstSignatureBody.text
SignPath = Format("%s%s.doc.1.sig"; ArrayOf(Path; DocName))
WriteFile(SignPath; ; FirstSignatureValue)
DeleteFile(TempPath)
else
ShowMessage("Не найдена версия документа, подписанная утверждающей подписью")
endif
Предложенное в упомянутой выше статье решение производило импорт файла формата ‘.p7s’, что не подходило по требованиям заказчика, но при дальнейшем изучении форматов ‘.p7s’ и ‘.sig’ было выяснено, что подпись можно выгружать в файл формата ‘.sig’.
При использовании функции CreateEDocWithSigFromFile в чистом виде для импорта документа в формате ‘.doc’ и файла отсоединенной подписи формата ‘.p7s’ возникли другие трудности. В результате выполнения функции создавался документ с корректным содержимым, но недействительной подписью:
Причиной такого поведения стали комментарии «-----BEGIN CMS-----» и «-----END CMS-----», добавляемые некоторыми программами при экспорте отсоединенной электронной подписи в текст подписи. Программный поиск и удаление этих комментариев решило проблему с некорректным чтением электронной подписи системой.
Функция из статьи может импортировать файл с несколькими файлами подписей, но в нашем случае заказчику этот функционал не был необходим, поэтому он был исключен из итоговой функции.
После всех изменений функция CreateEDocWithSigFromFile приняла следующий вид:
Result = nil
if Assigned(DocPath)
if FileExists(DocPath)
if FileSize(DocPath) > 0
// Определить Приложение-редактор
Extension = ExtractFileDriveDirNameExt(DocPath; 'E')
Editor = GetEditorCodeByExtension(UpperCase(Extension))
ESDFilePath = GetTempFolder() & '\ImportedESD.esd'
ESDTemplate =
'<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<StructuredElectronicObject Version="2.0" MetadataID="" MetadataVersion="">
<Header Type="Document" Name="" Extension="%0:s" Modified="" Organization="" Number="" Date=""/>
<ExtAttributes>
<ID Name="ID" Type="Integer" IsNull="false" Value=""/>
<VersionNumber Name="VersionNumber" Type="Integer" IsNull="false" Value="1"/>
</ExtAttributes>
<AccessRights/>
<Links/>
<Contents>%1:s</Contents>
<DigitalSignatures>
%2:s
</DigitalSignatures>
</StructuredElectronicObject>'
DigitalSignatureTemplate =
'<DigitalSignature Signed="" CertificateIssuedTo="" CryptoProvider="Capicom Encryption" Version="2.0" SignatureType="Approving">
<Attributes>
<Comment Name="Comment" Type="String" IsNull="false" Value=""/>
<SignedByUserName Name="SignedByUserName" Type="String" IsNull="false" Value=""/>
<InTheNameOfUserName Name="InTheNameOfUserName" Type="String" IsNull="false" Value=""/>
</Attributes>
<Data>%0:s</Data>
</DigitalSignature>'
// Добавить информацию об ЭП
ESDXML = CreateObject("MSXML.DOMDocument")
// CAPICOM кодирует ЭП в base64 2 раза, поэтому нужно проверить, в каком формате пришла ЭП. Если в base64, то закодировать 1 раз, иначе 2
RegExp = CreateObject("VBScript.RegExp")
RegExp.IgnoreCase = TRUE
RegExp.Global = TRUE
RegExp.Pattern = '^([A-Za-z0-9+/\n\r=])+$'
DigitalSignaturesString = ''
foreach SignaturePath in CArrayElement(Signatures)
if FileExists(SignaturePath)
// Проверить размер тела ЭП
if FileSize(SignaturePath) > 0
StringSign = ReadFile(SignaturePath)
if RegExp.Test(StringSign)
BinarySignBase64 = MimeEncodeString(StringSign)
else
BinarySign = LoadFile(SignaturePath)
BinarySignBase64 = MimeEncodeString(MimeEncodeBinary(BinarySign))
endif
DigitalSignature = ESDXML.CreateCDataSection(BinarySignBase64)
NewDigitalSignatureNode = Format(DigitalSignatureTemplate; DigitalSignature.xml)
DigitalSignaturesString = AddSubString(NewDigitalSignatureNode; DigitalSignaturesString; CR)
else
Raise(CreateException(''; 'ЭП нулевого размера: ' & SignaturePath; ecException))
endif
else
Raise(CreateException(''; 'Не найден файл ЭП при импорте документа: ' & SignaturePath; ecException))
endif
endforeach
RegExp = nil
BinaryFileBody = LoadFile(DocPath)
BinaryFileBodyCData = ESDXML.CreateCDataSection(MimeEncodeBinary(BinaryFileBody))
ESDFullXML = Format(ESDTemplate; ArrayOf(Extension; BinaryFileBodyCData.xml; DigitalSignaturesString))
ESDXML.LoadXML(ESDFullXML)
ESDXML.Save(ESDFilePath)
EDoc = EDocuments.CreateNewFromFile(DocType; DocKind; Editor; ESDFilePath; TRUE)
DeleteFile(ESDFilePath)
if Assigned(RCC)
RCC:IReference
EDoc.Дата4 = RCC.Дата2
EDoc.Дополнение = RCC.Дополнение2
EDoc.Организация = RCC.Организация
EDoc.Дополнение3 = RCC.Содержание
endif
try
EDoc.Save()
except
EDoc.Form.ShowModal()
endexcept
Result = EDoc
else
Raise(CreateException(''; 'Файл документа нулевого размера: ' & DocPath; ecException))
endif
else
Raise(CreateException(''; 'Не найден файл: ' & DocPath; ecException))
endif
endif
Вопрос к фразе "Вопрос выгрузки нескольких отсоединенных подписей в один файл остается открытым." Не уверен, что понимаю, о чем она. Не решена какая-то техническая задача? Хотите объединить несколько ЭП в один файл? А это вообще корректно? Как потом с ними работать?
Алексей, изначально было пожелание сделать экспорт нескольких подписей в один файл. В качестве примера заказчик приводил аналогичный функционал в КриптоПро, и предложенный пример из этой программы корректно распознавался на Госуслугах. Но на текущий момент эта задача отложена, так как вероятность того, что документ, для которого разработан экспорт, будет иметь несколько подписей, мала. Кроме того нам пока действительно непонятно, насколько это корректно и как осуществить такое объединение в Directum.
День добрый! А полный текст функции экспорта после Ваших изменений как выглядит? И если я правильно понимаю, то функция формирует файл с прикрепленной цифровой подписью?
Авторизуйтесь, чтобы написать комментарий