= xmlsign =
* https://pypi.org/project/signxml/
* https://www.w3.org/TR/xmldsig-core/xmldsig-core-schema.xsd
== Format XML ==
{{{#!highlight sh
sudo apt install libxml2-utils # install in debian
xmllint --format payload.xml # format XML
}}}
== Example ==
=== main.py ===
{{{#!highlight python
'''
pip install signxml lxml
# generate the x509 cert and private key
openssl req -new -x509 -days 3650 -nodes -out cert.pem -keyout privkey.pem
apt install libxml2-utils
xmllint --schema ./test.xsd ./test_signed.xml
xmllint --schema ./test.xsd ./test.xml
'''
from signxml import XMLVerifier, XMLSigner, methods, XMLSignatureProcessor
from lxml import etree
XML_SIG_NS = ns = {"ds":"http://www.w3.org/2000/09/xmldsig#"}
X509_CERT = "//ds:X509Certificate"
PUB_KEY = "cert.pem"
PRIV_KEY = "privkey.pem"
def get_x509_cert(xml_signed_root):
assert(type(xml_signed_root) is str)
extracted_x509_cert = etree.fromstring(xml_signed_root).xpath(X509_CERT, namespaces=XML_SIG_NS)[0].text
return extracted_x509_cert
def sign_payload1():
print "\n payload1"
payload = open("payload1.xml").read()
cert = open(PUB_KEY).read()
key = open(PRIV_KEY).read()
root = etree.fromstring(payload)
signed_root = XMLSigner().sign(root, key=key, cert=cert)
xml_signed_root = etree.tostring(signed_root)
open("payload1_signed.xml", "wb").write(xml_signed_root)
extracted_x509_cert = get_x509_cert(xml_signed_root)
verified_data = XMLVerifier().verify(xml_signed_root, x509_cert=extracted_x509_cert).signed_xml
def sign_payload2():
print "\n payload2"
payload = open("payload2.xml").read()
cert = open(PUB_KEY).read()
key = open(PRIV_KEY).read()
root = etree.fromstring(payload)
signer = XMLSigner(method=methods.enveloped, signature_algorithm="rsa-sha256",
digest_algorithm="sha256", c14n_algorithm=XMLSignatureProcessor.default_c14n_algorithm)
signed_root = signer.sign(root, key=key, cert=cert, reference_uri="#tosign", id_attribute="id")
xml_signed_root = etree.tostring(signed_root)
xml_signed_root = xml_signed_root.replace("7676767", "1111111") # introduce change in data not signed
open("payload2_signed.xml", "wb").write(xml_signed_root)
extracted_x509_cert = get_x509_cert(xml_signed_root)
verified_data = XMLVerifier().verify(xml_signed_root, x509_cert=extracted_x509_cert).signed_xml
def sign_payload2_detached_nocert_insignature():
print "\n payload2 detached no cert in signature"
payload = open("payload2.xml").read()
cert = open(PUB_KEY).read()
key = open(PRIV_KEY).read()
root = etree.fromstring(payload)
signer = XMLSigner(method=methods.detached, signature_algorithm="rsa-sha256",
digest_algorithm="sha256", c14n_algorithm=XMLSignatureProcessor.default_c14n_algorithm)
signature = signer.sign(root, key=key, cert=None, reference_uri="#tosign", id_attribute="id")
root.insert(0, signature) # insert as first child of the XML node
xml_signed_root = etree.tostring(root)
xml_signed_root = xml_signed_root.replace("7676767", "1111111") # introduce change in data not signed
open("payload2_signed_nocert.xml", "wb").write(xml_signed_root)
verified_data = XMLVerifier().verify(xml_signed_root, x509_cert=cert).signed_xml
def sign_payload2_detached_cert_insignature():
print "\n payload2 detached"
payload = open("payload2.xml").read()
cert = open(PUB_KEY).read()
key = open(PRIV_KEY).read()
root = etree.fromstring(payload)
signer = XMLSigner(method=methods.detached, signature_algorithm="rsa-sha256",
digest_algorithm="sha256", c14n_algorithm=XMLSignatureProcessor.default_c14n_algorithm)
signature = signer.sign(root, key=key, cert=cert, reference_uri="#tosign", id_attribute="id")
root.insert(0, signature) # insert as first child of the root XML node
xml_signed_root = etree.tostring(root)
xml_signed_root = xml_signed_root.replace("7676767", "1111111") # introduce change in data not signed
open("payload2_signed_cert.xml", "wb").write(xml_signed_root)
extracted_x509_cert = get_x509_cert(xml_signed_root)
verified_data = XMLVerifier().verify(xml_signed_root, x509_cert=extracted_x509_cert).signed_xml
def sign_test_detached_cert_insignature():
print "\n test detached"
payload = open("test.xml").read()
cert = open(PUB_KEY).read()
key = open(PRIV_KEY).read()
root = etree.fromstring(payload)
signer = XMLSigner(method=methods.detached, signature_algorithm="rsa-sha256",
digest_algorithm="sha256", c14n_algorithm=XMLSignatureProcessor.default_c14n_algorithm)
signature = signer.sign(root, key=key, cert=cert, reference_uri="#tosign", id_attribute="Id")
nrelems = len(root.getchildren())
root.insert(nrelems, signature) # insert as the last child of the root XML node
xml_signed_root = etree.tostring(root)
open("test_signed.xml", "wb").write(xml_signed_root)
extracted_x509_cert = get_x509_cert(xml_signed_root)
verified_data = XMLVerifier().verify(xml_signed_root, x509_cert=extracted_x509_cert).signed_xml
if __name__ == '__main__':
sign_payload1()
sign_payload2()
sign_payload2_detached_nocert_insignature()
sign_payload2_detached_cert_insignature()
sign_test_detached_cert_insignature()
}}}
=== payload1.xml ===
{{{#!highlight xml
7676767
}}}
=== payload2.xml ===
{{{#!highlight xml
7676767
klfljsdfjlsdkfksflfk
}}}
=== test.xsd ===
{{{#!highlight xml
}}}
=== test.xml ===
{{{#!highlight xml
test
}}}
== Check signed XML ==
{{{#!highlight python
# check_signed_xml.py
from signxml import XMLVerifier
from lxml import etree
import sys
XML_SIG_NS = ns = {"ds":"http://www.w3.org/2000/09/xmldsig#"}
X509_CERT = "//ds:X509Certificate"
if __name__ == '__main__':
print("Checking file %s" % (sys.argv[1]))
xml_data = open(sys.argv[1]).read()
try:
extracted_x509_cert = etree.fromstring(xml_data).xpath(X509_CERT, namespaces=XML_SIG_NS)
if len(extracted_x509_cert) > 0:
verified_data = XMLVerifier().verify(xml_data, x509_cert=extracted_x509_cert[0].text).signed_xml
print "Trusted data\n"+etree.tostring(verified_data)
else:
verified_data = XMLVerifier().verify(xml_data, require_x509=False).signed_xml
print "Trusted data\n"+etree.tostring(verified_data)
print("OK")
except Exception as ex:
print("Exception: %s" % (str(ex)))
print("Has error")
}}}