Как подписать XML-документ с помощью Python?
Я делаю проект на Django (полный Python), а именно систему продаж. Сейчас я хочу включить в систему электронное выставление счетов, сосредоточившись пока только на электронном товарном чеке. В моей стране регулирующий орган требует, чтобы для отправки счета-фактуры он был оформлен в XML-файл (с определенным форматом), затем он должен быть подписан цифровым сертификатом компании, упакован в .zip-файл и отправлен на тестовый веб-сервис организации. Но я не знаю, как сделать подпись, используя только Python.
Я изучал вопрос и заметил, что большинство из них предпочитают использовать такие языки, как Java или C#. Я также нашел библиотеки lxml
и cryptography
, с помощью которых я могу сделать подпись, но когда я отправляю ее в веб-сервис, я получаю ошибку:
Error of the web service: The entered electronic document has been altered - Detail: Incorrect reference digest value
Я пытался выяснить, как исправить эту ошибку, я не знаю, связано ли это с тем, как я подписываю XML-документ, или с методом, который я использую.
Я делюсь с вами кодом, чтобы дать вам представление о том, что я использовал:
А это тестовый XML-документ:
Вам нужно будет вставить узел подписи шаблона в xml-документ. Шаблон содержит подробную информацию о том, как подписать этот документ.
Затем вы просто указываете xmlsec подписать его. Он выведет правильный xml.
реализация на python из pip install xmlsec
примеров на python
Вот как вы заполняете подпись:
from lxml import etree
import xmlsec
def sign_xml(xml_path, private_key_path, signed_xml_path):
with open(xml_path) as fp:
template = etree.parse(fp).getroot()
signature_node = xmlsec.tree.find_node(template, xmlsec.constants.NodeSignature)
assert signature_node
ctx = xmlsec.SignatureContext()
key = xmlsec.Key.from_file(private_key_path, xmlsec.constants.KeyDataFormatPem)
ctx.key = key
ctx.sign(signature_node)
with open(signed_xml_path, 'wb') as out:
out.write(etree.tostring(template))
Я предоставляю вам самим настроить шаблон подписи и добавить его в свой xml-документ, но я просто скопировал его из их документации (см. выше, раздел 2.1)
Вы можете использовать rsa, pip install rsa
и позаботиться о пространстве имен:
Если вам нужно включить метаданные (например, название организации), вам придется создать сертификат X.509 вручную или использовать внешний инструмент, такой как OpenSSL, для создания сертификата с этой информацией.