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".
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
.sigxml
site completely disregard python3 issues with str
vs. bytes
.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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With