针对自定义 CA 的 xml 签名验证



我需要验证 POST 请求答案中包含的 xml 签名。

签名由以下人员定义:

<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

我是一个经验丰富的程序员,但不是密码学专家,所以我很可能忘记了一些琐碎的事情(对知识渊博的人来说(。 请指出我正确的方向。

注意::如果需要,我可以提供一个完整的示例(失败(,因为证书/答案不是"秘密"。

不幸的是,事情总是比预期的要复杂一些。

@stovfl的回答完全错过了相关点:我需要针对非标准 CA 进行验证。

我已经在努力使用sigxml软件包,我必须克服以下问题:

  • sigxml不会(对我来说(使用普通xml.etree;我不得不使用具有不同语法的lxml.etree
  • sigxml由普通pip3 install sigxml安装会因弃用错误而爆炸;我必须从 github 获取最新的(未标记的母版(pip3 install git+https://github.com/XML-Security/signxml.git.
  • sigxml网站上的示例完全忽略了 python3 与strbytes.
  • 用于签署传出消息的 CA 颁发机构与用于签署响应的 CA 机构不同(我无法更改!

不过,这个故事有一个圆满的结局。

以下测试程序有效(对我来说(:

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('===================')

我希望这将帮助处于(或将要(处于我这种情况的任何人。

:我需要验证 POST 请求答案中包含的 xml 签名。

这样做,就像文档 SignXML:Python 中的 XML 签名中的示例一样:

SignXML使用ElementTree API(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 节点,或者在签名无效时引发异常。

类符号XML。验证结果 验证结果
返回签名数据、签名 xml 和签名 xml

注意:必须阅读有关查看已签名的内容建立信任

相关:Python 元素树查找函数将签名读取为空(无(

最新更新