4

I need to verify an xml signature contained in the answer to a POST request.

The signature is defined by:

<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>                                                                                                                                                            

and is against a custom CA.

I have no way to change the answer (it is issued by a State Agency) and all my attempts to verify against the certificate supposedly used to sign did result in errors.

One of my attempts has been using the following short test program:

#!/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)                                                                                                                                                         

This results in:

Signature verification failed: wrong signature length

Other variations have different errors including:

Signature verification failed: invalid padding

and:

unable to get local issuer certificate

I am a seasoned programmer, but NOT a cryptography expert, so it's quite likely I forgot something trivial (to the knowledgeable). Please point me in the right direction.

Note:: if required I can provide a full example (of failure) as certificate/answer are not "secret".

ZioByte
  • 2,690
  • 1
  • 32
  • 68

2 Answers2

3

Unfortunately things are always a bit more complex than expected.

Answer from @stovfl completely missed the relevant point: I need to verify against a non-standard CA.

I already was struggling to use sigxml package, and I had to overcome the following problems:

  • sigxml will not work (for me) with plain xml.etree; I had to use lxml.etree with a different syntax.
  • sigxml installed by plain pip3 install sigxml would bomb with a deprecation error; I had to get latest (non-tagged master) from github with pip3 install git+https://github.com/XML-Security/signxml.git.
  • Examples on sigxml site completely disregard python3 issues with str vs. bytes.
  • CA Authority used to sign the Certificate I used to sign the outgoing message is different from the CA Authority used to sign response (I have no way to change this!).

This story has an Happy Ending though.

The following test program works (for me):

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

I hope this will help whoever is (or will be) in my situation.

ZioByte
  • 2,690
  • 1
  • 32
  • 68
0

Question: I need to verify an xml signature contained in the answer to a POST request.

Do it, like the example in the Documentation SignXML: XML Signature in Python:

SignXML uses the ElementTree API (also supported by lxml) to work with XML data.

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(...)
Verify the XML signature supplied in the data and return the XML node signed by the signature, or raise an exception if the signature is not valid.

class signxml.VerifyResult
The results of a verification return the signed data, the signed xml and the signature xml

Note: Necessarily read about See what is signed and Establish trust!

Relevant: Python elementtree find function reads Signature as empty (None)

stovfl
  • 14,998
  • 7
  • 24
  • 51