проверка подписи XML против пользовательского CA - PullRequest
0 голосов
/ 29 сентября 2018

Мне нужно проверить подпись xml, содержащуюся в ответе на запрос POST.

Подпись определяется как:

<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">                                                                                                                   
<SignedInfo>                                                                                                                                                             
  <CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>                                                                                  
  <SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>                                                                                       
  <Reference URI="">                                                                                                                                                     
    <Transforms>                                                                                                                                                         
      <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>                                                                                     
      <Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>                                                                                           
    </Transforms>                                                                                                                                                        
    <DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>                                                                                                  
    <DigestValue>htti3M3ikfm2RooDTNo3Kv7g0K2ongShUfCDUAWpytc=</DigestValue>                                                                                              
  </Reference>                                                                                                                                                           
</SignedInfo>                                                                                                                                                            

и относится к пользовательскому CA.

У меня нет возможности изменить ответ (он выдается государственным агентством), и все мои попытки сверки с сертификатом, который якобы использовался для подписи, привели к ошибкам.

Одна из моих попыток былаиспользуя следующую короткую тестовую программу:

#!/usr/bin/python3                                                                                                                                                       

import signxml                                                                                                                                                           

cf = 'certificate.cer'                                                                                                                                                          
with open(cf, 'r') as fi:                                                                                                                                                
    cer = fi.read()                                                                                                                                                      

ver = signxml.XMLVerifier()                                                                                                                                              

f = 'response.xml'                                                                                                                                 
with open(f, 'rb') as fi:                                                                                                                                            
    xml = fi.read()                                                                                                                                                  
try:                                                                                                                                                                 
    vd = ver.verify(xml, x509_cert=cer)                                                                                                                              
    print('OK')                                                                                                                                                      
except signxml.exceptions.InvalidSignature as e:                                                                                                                     
    print(e)                                                                                                                                                         

Это приводит к:

Signature verification failed: wrong signature length

Другие варианты имеют различные ошибки, включая:

Signature verification failed: invalid padding

и:

unable to get local issuer certificate

Я опытный программист, но НЕ специалист по криптографии, так что вполне вероятно, что я забыл что-то тривиальное (для знающих).Пожалуйста, направьте меня в правильном направлении.

Примечание: : при необходимости я могу привести полный пример (сбоя), поскольку сертификат / ответ не являются "секретными".

Ответы [ 2 ]

0 голосов
/ 30 сентября 2018

К сожалению, все всегда немного сложнее, чем ожидалось.

Ответ от @stovfl полностью упустил важный момент: мне нужно проверить на нестандартный CA.

Я уже былизо всех сил пытался использовать sigxml пакет, и мне пришлось преодолеть следующие проблемы:

  • sigxml не будет работать (для меня) с простым xml.etree;Я должен был использовать lxml.etree с другим синтаксисом.
  • sigxml, установленный обычным pip3 install sigxml, будет бомбить с ошибкой устаревания;Мне пришлось получить последнюю версию (без тега master) из github с pip3 install git+https://github.com/XML-Security/signxml.git.
  • Примеры на сайте sigxml полностью игнорируют проблемы python3 с str против bytes.
  • Орган ЦС, использованный для подписи сертификата, который я использовал для подписи исходящего сообщения, отличается от ЦС, который использовался для подписи ответа (у меня нет возможности изменить это!).

У этой истории есть счастливый конец.

Следующая тестовая программа работает (для меня):

from signxml import XMLSigner, XMLVerifier, InvalidCertificate
from lxml import etree

outCAroot = 'outCAroot.pem'
inCAroot = 'inCAroot.pem'
cert = open("example.pem").read().encode()
key = open("example.key").read().encode()
file_name = 'test.tosend'
resp_name = 'test.rsp'

xml = etree.parse(file_name)  # (data_to_sign)
signer = XMLSigner(c14n_algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315')
signed_xml = signer.sign(xml, key=key, cert=cert)
try:
    result = XMLVerifier().verify(signed_xml, ca_pem_file=outCAroot)
except InvalidCertificate as e:
    print(e)
else:
    print('outgoing signature Ok.')

# here I send signed_xml to remote server and get the response (NO ERRORS!)

answer_xml = etree.parse(resp_name)  # (signed answer)
try:
    result = XMLVerifier().verify(answer_xml, ca_pem_file=inCAroot)
except InvalidCertificate as e:
    print(e)
else:
    print('incoming signature Ok.')
    print('===================')
    print(result.signed_data.decode())
    print('===================')

Я надеюсь, что это поможет тому, кто (или будет) в моей ситуации.

0 голосов
/ 29 сентября 2018

Вопрос : мне нужно проверить подпись xml, содержащуюся в ответе на запрос POST.

Сделайте это, как в примере в документации SignXML: Подпись XML в Python :

SignXML использует API ElementTree (также поддерживается lxml) для работы с данными XML.

from signxml import XMLSigner, XMLVerifier
from xml.etree import ElementTree

cert = open("example.pem").read()
key = open("example.key").read()
xml = ElementTree.parse(file_name) #(data_to_sign)
signed_xml = XMLSigner().sign(xml, key=key, cert=cert)
result = XMLVerifier().verify(signed_xml)

XMLVerifier (). Verify (...)
Проверка подписи XML, предоставленной в данных, и возврат узла XML, подписанного подписью, или создание исключения, если подпись недействительна.

класс signxml.VerifyResult
В результате проверки возвращаются подписанные данные, подписанный xml и подпись xml

Примечание : Обязательно прочитайте о Посмотрите, что подписано и Установите доверие !

Соответствует : Python elementtree функция поиска читает подпись как пустую (нет)

...