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

时间:2018-09-29 18:29:03

标签: python xml-signature

我需要验证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

我是一位经验丰富的程序员,但不是加密专家,所以很有可能我忘了一些琐碎的事情(对知识渊博的人而言)。 请指出正确的方向。

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

2 个答案:

答案 0 :(得分:0)

  

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

按照文档SignXML: XML Signature in Python中的示例进行操作:

  

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节点,如果签名无效,则引发异常。

  

class signxml.VerifyResult
  验证结果将返回签名数据,签名xml和签名xml

注意:需要阅读有关See what is signed and Establish trust!

的信息

相关Python elementtree find function reads Signature as empty (None)

答案 1 :(得分:0)

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

@stovfl的回答完全没有提到相关的问题:我需要针对非标准CA进行验证。

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

  • sigxml在普通xml.etree下将不起作用(对我来说);我不得不使用lxml.etree使用不同的语法。
  • 普通sigxml安装的
  • pip3 install sigxml会炸弹,并产生弃用错误;我必须使用pip3 install git+https://github.com/XML-Security/signxml.git从github获取最新的(非标记大师)。
  • sigxml网站上的示例完全忽略了strbytes的python3问题。
  • 用来签署我用来签署传出邮件的证书的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('===================')

我希望这对我所处环境中的任何人(或将来)都有帮助。