xmlsign
Format XML
Example
main.py
1 '''
2 pip install signxml lxml
3 # generate the x509 cert and private key
4 openssl req -new -x509 -days 3650 -nodes -out cert.pem -keyout privkey.pem
5
6 apt install libxml2-utils
7
8 xmllint --schema ./test.xsd ./test_signed.xml
9 xmllint --schema ./test.xsd ./test.xml
10
11 '''
12
13 from signxml import XMLVerifier, XMLSigner, methods, XMLSignatureProcessor
14 from lxml import etree
15
16 XML_SIG_NS = ns = {"ds":"http://www.w3.org/2000/09/xmldsig#"}
17 X509_CERT = "//ds:X509Certificate"
18 PUB_KEY = "cert.pem"
19 PRIV_KEY = "privkey.pem"
20
21 def get_x509_cert(xml_signed_root):
22 assert(type(xml_signed_root) is str)
23 extracted_x509_cert = etree.fromstring(xml_signed_root).xpath(X509_CERT, namespaces=XML_SIG_NS)[0].text
24 return extracted_x509_cert
25
26 def sign_payload1():
27 print "\n payload1"
28 payload = open("payload1.xml").read()
29 cert = open(PUB_KEY).read()
30 key = open(PRIV_KEY).read()
31 root = etree.fromstring(payload)
32 signed_root = XMLSigner().sign(root, key=key, cert=cert)
33 xml_signed_root = etree.tostring(signed_root)
34 open("payload1_signed.xml", "wb").write(xml_signed_root)
35 extracted_x509_cert = get_x509_cert(xml_signed_root)
36 verified_data = XMLVerifier().verify(xml_signed_root, x509_cert=extracted_x509_cert).signed_xml
37
38 def sign_payload2():
39 print "\n payload2"
40 payload = open("payload2.xml").read()
41 cert = open(PUB_KEY).read()
42 key = open(PRIV_KEY).read()
43 root = etree.fromstring(payload)
44 signer = XMLSigner(method=methods.enveloped, signature_algorithm="rsa-sha256",
45 digest_algorithm="sha256", c14n_algorithm=XMLSignatureProcessor.default_c14n_algorithm)
46 signed_root = signer.sign(root, key=key, cert=cert, reference_uri="#tosign", id_attribute="id")
47 xml_signed_root = etree.tostring(signed_root)
48 xml_signed_root = xml_signed_root.replace("7676767", "1111111") # introduce change in data not signed
49 open("payload2_signed.xml", "wb").write(xml_signed_root)
50 extracted_x509_cert = get_x509_cert(xml_signed_root)
51 verified_data = XMLVerifier().verify(xml_signed_root, x509_cert=extracted_x509_cert).signed_xml
52
53 def sign_payload2_detached_nocert_insignature():
54 print "\n payload2 detached no cert in signature"
55 payload = open("payload2.xml").read()
56 cert = open(PUB_KEY).read()
57 key = open(PRIV_KEY).read()
58 root = etree.fromstring(payload)
59 signer = XMLSigner(method=methods.detached, signature_algorithm="rsa-sha256",
60 digest_algorithm="sha256", c14n_algorithm=XMLSignatureProcessor.default_c14n_algorithm)
61 signature = signer.sign(root, key=key, cert=None, reference_uri="#tosign", id_attribute="id")
62 root.insert(0, signature) # insert as first child of the XML node
63 xml_signed_root = etree.tostring(root)
64 xml_signed_root = xml_signed_root.replace("7676767", "1111111") # introduce change in data not signed
65 open("payload2_signed_nocert.xml", "wb").write(xml_signed_root)
66 verified_data = XMLVerifier().verify(xml_signed_root, x509_cert=cert).signed_xml
67
68 def sign_payload2_detached_cert_insignature():
69 print "\n payload2 detached"
70 payload = open("payload2.xml").read()
71 cert = open(PUB_KEY).read()
72 key = open(PRIV_KEY).read()
73 root = etree.fromstring(payload)
74 signer = XMLSigner(method=methods.detached, signature_algorithm="rsa-sha256",
75 digest_algorithm="sha256", c14n_algorithm=XMLSignatureProcessor.default_c14n_algorithm)
76 signature = signer.sign(root, key=key, cert=cert, reference_uri="#tosign", id_attribute="id")
77 root.insert(0, signature) # insert as first child of the root XML node
78 xml_signed_root = etree.tostring(root)
79 xml_signed_root = xml_signed_root.replace("7676767", "1111111") # introduce change in data not signed
80 open("payload2_signed_cert.xml", "wb").write(xml_signed_root)
81 extracted_x509_cert = get_x509_cert(xml_signed_root)
82 verified_data = XMLVerifier().verify(xml_signed_root, x509_cert=extracted_x509_cert).signed_xml
83
84 def sign_test_detached_cert_insignature():
85 print "\n test detached"
86 payload = open("test.xml").read()
87 cert = open(PUB_KEY).read()
88 key = open(PRIV_KEY).read()
89 root = etree.fromstring(payload)
90 signer = XMLSigner(method=methods.detached, signature_algorithm="rsa-sha256",
91 digest_algorithm="sha256", c14n_algorithm=XMLSignatureProcessor.default_c14n_algorithm)
92 signature = signer.sign(root, key=key, cert=cert, reference_uri="#tosign", id_attribute="Id")
93 nrelems = len(root.getchildren())
94 root.insert(nrelems, signature) # insert as the last child of the root XML node
95 xml_signed_root = etree.tostring(root)
96 open("test_signed.xml", "wb").write(xml_signed_root)
97 extracted_x509_cert = get_x509_cert(xml_signed_root)
98 verified_data = XMLVerifier().verify(xml_signed_root, x509_cert=extracted_x509_cert).signed_xml
99
100 if __name__ == '__main__':
101 sign_payload1()
102 sign_payload2()
103 sign_payload2_detached_nocert_insignature()
104 sign_payload2_detached_cert_insignature()
105 sign_test_detached_cert_insignature()
payload1.xml
payload2.xml
test.xsd
1 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
2 xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
3
4 <xs:import namespace="http://www.w3.org/2000/09/xmldsig#"
5 schemaLocation="./xmldsig-core-schema.xsd" />
6
7 <xs:element name="a" type="AType" />
8 <xs:complexType name="AType" mixed="true">
9 <xs:sequence>
10 <xs:element name="b" type="CType" />
11 <xs:element ref="ds:Signature" minOccurs="0" />
12 </xs:sequence>
13 </xs:complexType>
14
15 <xs:complexType name="CType" mixed="true">
16 <xs:sequence>
17 <xs:element name="c" type="xs:string" />
18 </xs:sequence>
19 <xs:attribute name="Id" type="xs:ID" use="optional" />
20 </xs:complexType>
21 </xs:schema>
test.xml
Check signed XML
1 # check_signed_xml.py
2 from signxml import XMLVerifier
3 from lxml import etree
4 import sys
5
6 XML_SIG_NS = ns = {"ds":"http://www.w3.org/2000/09/xmldsig#"}
7 X509_CERT = "//ds:X509Certificate"
8
9 if __name__ == '__main__':
10 print("Checking file %s" % (sys.argv[1]))
11 xml_data = open(sys.argv[1]).read()
12 try:
13 extracted_x509_cert = etree.fromstring(xml_data).xpath(X509_CERT, namespaces=XML_SIG_NS)
14 if len(extracted_x509_cert) > 0:
15 verified_data = XMLVerifier().verify(xml_data, x509_cert=extracted_x509_cert[0].text).signed_xml
16 print "Trusted data\n"+etree.tostring(verified_data)
17 else:
18 verified_data = XMLVerifier().verify(xml_data, require_x509=False).signed_xml
19 print "Trusted data\n"+etree.tostring(verified_data)
20 print("OK")
21 except Exception as ex:
22 print("Exception: %s" % (str(ex)))
23 print("Has error")