= 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") }}}