<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="../assets/xml/rss.xsl" media="all"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Konstantin Shemyak - Tech Notes (Posts about XML)</title><link>https://technotes.shemyak.com/</link><description></description><atom:link href="https://technotes.shemyak.com/categories/xml.xml" rel="self" type="application/rss+xml"></atom:link><language>en</language><copyright>Contents © 2021 &lt;a href="mailto:konstantin@shemyak.com"&gt;Konstantin Shemyak&lt;/a&gt; </copyright><lastBuildDate>Fri, 02 Apr 2021 15:51:34 GMT</lastBuildDate><generator>Nikola (getnikola.com)</generator><docs>http://blogs.law.harvard.edu/tech/rss</docs><item><title>XML Signatures and Python ElementTree</title><link>https://technotes.shemyak.com/posts/xml-signatures-and-python-elementtree/</link><dc:creator>Konstantin Shemyak</dc:creator><description>&lt;div&gt;&lt;h3&gt;I just need to sign XML...&lt;/h3&gt;
&lt;p&gt;Python has a standard library module to handle XML, and there seems to be exactly one library for the signing part: &lt;code&gt;signxml&lt;/code&gt;.
So it should be straighforward:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;xml.etree&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ElementTree&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;ET&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;signxml&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;XMLSigner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;XMLVerifier&lt;/span&gt;

&lt;span class="n"&gt;cert&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"rb"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"cert.pem"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"key.pem"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;

&lt;span class="n"&gt;xml_obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ET&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fromstring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;Test/&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;signed_xml_obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;XMLSigner&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xml_obj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;XMLVerifier&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;verify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;signed_xml_obj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x509_cert&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;cert&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;


&lt;p&gt;Simple?&lt;/p&gt;
&lt;p&gt;But the receiver tells you that your signature does not verify?&lt;/p&gt;
&lt;p&gt;The solution code is at the &lt;a href="https://technotes.shemyak.com/posts/xml-signatures-and-python-elementtree/#tldr"&gt;end of the article&lt;/a&gt;. The rest explains what is happening.&lt;/p&gt;
&lt;p&gt;An optional parameter of the &lt;code&gt;sign()&lt;/code&gt; method specifies &lt;strong&gt;type of the XML signature&lt;/strong&gt;, which
can be &lt;em&gt;enveloped&lt;/em&gt;, &lt;em&gt;enveloping&lt;/em&gt;, or &lt;em&gt;detached&lt;/em&gt;. This article covers only the default
case of &lt;em&gt;enveloped&lt;/em&gt; signature.&lt;/p&gt;
&lt;h3&gt;...and send it forward&lt;/h3&gt;
&lt;p&gt;When you sign something, usually it is for the purpose of verifying the signature by someone else.
Unless that someone else has access to your Python object, we need to serialize the latter:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="n"&gt;data_serialized&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ET&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tostring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;signed_xml_obj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="o"&gt;#&lt;/span&gt; &lt;span class="n"&gt;Sending&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="k"&gt;data&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;

&lt;span class="n"&gt;XMLVerifier&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;verify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data_serialized&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x509_cert&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;cert&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;


&lt;p&gt;And this is not simple any more, because verification of the serialized data fails:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="n"&gt;Traceback&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;most&lt;/span&gt; &lt;span class="n"&gt;recent&lt;/span&gt; &lt;span class="k"&gt;call&lt;/span&gt; &lt;span class="k"&gt;last&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="ss"&gt;"/path/to/python3.6/site-packages/signxml/__init__.py"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="mi"&gt;729&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;verify&lt;/span&gt;
    &lt;span class="n"&gt;verify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;signing_cert&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;raw_signature&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;signed_info_c14n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;signature_digest_method&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="ss"&gt;"/path/to/python3.6/site-packages/OpenSSL/crypto.py"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="mi"&gt;2928&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;verify&lt;/span&gt;
    &lt;span class="n"&gt;_raise_current_error&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="ss"&gt;"/path/to/python3.6/site-packages/OpenSSL/_util.py"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="mi"&gt;54&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;exception_from_error_queue&lt;/span&gt;
    &lt;span class="n"&gt;raise&lt;/span&gt; &lt;span class="n"&gt;exception_type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;OpenSSL&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="s1"&gt;'rsa routines'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'int_rsa_verify'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'bad signature'&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;

&lt;span class="n"&gt;During&lt;/span&gt; &lt;span class="n"&gt;handling&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;above&lt;/span&gt; &lt;span class="k"&gt;exception&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;another&lt;/span&gt; &lt;span class="k"&gt;exception&lt;/span&gt; &lt;span class="n"&gt;occurred&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

&lt;span class="n"&gt;Traceback&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;most&lt;/span&gt; &lt;span class="n"&gt;recent&lt;/span&gt; &lt;span class="k"&gt;call&lt;/span&gt; &lt;span class="k"&gt;last&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="ss"&gt;"1.py"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="n"&gt;XMLVerifier&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;verify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data_serialized&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x509_cert&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;cert&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="ss"&gt;"/path/to/python3.6/site-packages/signxml/__init__.py"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="mi"&gt;735&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;verify&lt;/span&gt;
    &lt;span class="n"&gt;raise&lt;/span&gt; &lt;span class="n"&gt;InvalidSignature&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;"Signature verification failed: {}"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reason&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;signxml&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exceptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;InvalidSignature&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Signature&lt;/span&gt; &lt;span class="n"&gt;verification&lt;/span&gt; &lt;span class="n"&gt;failed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;bad&lt;/span&gt; &lt;span class="n"&gt;signature&lt;/span&gt;
&lt;/pre&gt;


&lt;p&gt;So, did the serialization break the signature?
"When nothing helps, read the instructions". Documentation of &lt;code&gt;signxml&lt;/code&gt;
&lt;a href="https://signxml.readthedocs.io/en/latest/#signxml.XMLSigner"&gt;tells&lt;/a&gt; that
the return value of &lt;code&gt;sign()&lt;/code&gt; is an &lt;code&gt;lxml.etree.Element&lt;/code&gt; object, not an &lt;code&gt;xml.etree.ElementTree&lt;/code&gt; object.&lt;/p&gt;
&lt;p&gt;Next try is the serialization with &lt;code&gt;lxml&lt;/code&gt;:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;lxml&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;etree&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;lxml_ET&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;xml.etree&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ElementTree&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;ET&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;signxml&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;XMLSigner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;XMLVerifier&lt;/span&gt;

&lt;span class="n"&gt;cert&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"rb"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"cert.pem"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"key.pem"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;

&lt;span class="n"&gt;xml_obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ET&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fromstring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;Test/&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;signed_xml_obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;XMLSigner&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xml_obj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;data_serialized&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lxml_ET&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tostring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;signed_xml_obj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Sending the data...&lt;/span&gt;

&lt;span class="n"&gt;XMLVerifier&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;verify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data_serialized&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x509_cert&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;cert&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;


&lt;p&gt;The moment of happiness, this works. Simple?&lt;/p&gt;
&lt;p&gt;Good if this works for you. But we are sending the serialized XML somewhere faraway and 
the receiver might first deserialize it, and verify the signature after that on a
deserialized version. (Which is not smart, but is probably out of your control.)
And do it with ElementTree.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;lxml&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;etree&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;lxml_ET&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;xml.etree&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ElementTree&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;ET&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;signxml&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;XMLSigner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;XMLVerifier&lt;/span&gt;

&lt;span class="n"&gt;cert&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"rb"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"cert.pem"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"key.pem"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;

&lt;span class="n"&gt;xml_obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ET&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fromstring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;Test/&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;signed_xml_obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;XMLSigner&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xml_obj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;data_serialized&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lxml_ET&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tostring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;signed_xml_obj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Sending the data...&lt;/span&gt;

&lt;span class="n"&gt;data_parsed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ET&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fromstring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data_serialized&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;XMLVerifier&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;verify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data_parsed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x509_cert&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;cert&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;


&lt;p&gt;And this fails with the same &lt;code&gt;InvalidSignature&lt;/code&gt;. Bump. Now reading the instructions does not help.&lt;/p&gt;
&lt;h3&gt;Debugging starts&lt;/h3&gt;
&lt;p&gt;We can check that the string representation of our &lt;strong&gt;signed&lt;/strong&gt; data "looks right" (although you never can be sure with the XML).
Compare it to &lt;code&gt;ElementTree.tostring(data_parsed)&lt;/code&gt; to note that they are not identical.
We do not know yet what is inside ElementTree object, but in its serialized string the signature will fail:&lt;/p&gt;
&lt;p&gt;Sent string:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;Test&amp;gt;&amp;lt;ds:Signature&lt;/span&gt; &lt;span class="na"&gt;xmlns:ds=&lt;/span&gt;&lt;span class="s"&gt;"http://www.w3.org/2000/09/xmldsig#"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;ds:SignedInfo&amp;gt;&amp;lt;ds:CanonicalizationMethod&lt;/span&gt; &lt;span class="na"&gt;Algorithm=&lt;/span&gt;&lt;span class="s"&gt;"http://www.w3.org/2006/12/xml-c14n11"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&amp;lt;ds:SignatureMethod&lt;/span&gt; &lt;span class="na"&gt;Algorithm=&lt;/span&gt;&lt;span class="s"&gt;"http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&amp;lt;ds:Reference&lt;/span&gt; &lt;span class="na"&gt;URI=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;ds:Transforms&amp;gt;&amp;lt;ds:Transform&lt;/span&gt; &lt;span class="na"&gt;Algorithm=&lt;/span&gt;&lt;span class="s"&gt;"http://www.w3.org/2000/09/xmldsig#enveloped-signature"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&amp;lt;ds:Transform&lt;/span&gt; &lt;span class="na"&gt;Algorithm=&lt;/span&gt;&lt;span class="s"&gt;"http://www.w3.org/2006/12/xml-c14n11"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&amp;lt;/ds:Transforms&amp;gt;&amp;lt;ds:DigestMethod&lt;/span&gt; &lt;span class="na"&gt;Algorithm=&lt;/span&gt;&lt;span class="s"&gt;"http://www.w3.org/2001/04/xmlenc#sha256"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&amp;lt;ds:DigestValue&amp;gt;&lt;/span&gt;KP3ncf09YSgkeTt+i4PR+W0AMvUTo7M8gu0z15piPMc=&lt;span class="nt"&gt;&amp;lt;/ds:DigestValue&amp;gt;&lt;/span&gt;....
&lt;/pre&gt;


&lt;p&gt;De-serialized ElementTree object:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;Test&lt;/span&gt; &lt;span class="na"&gt;xmlns:ns0=&lt;/span&gt;&lt;span class="s"&gt;"http://www.w3.org/2000/09/xmldsig#"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;ns0:Signature&amp;gt;&amp;lt;ns0:SignedInfo&amp;gt;&amp;lt;ns0:CanonicalizationMethod&lt;/span&gt; &lt;span class="na"&gt;Algorithm=&lt;/span&gt;&lt;span class="s"&gt;"http://www.w3.org/2006/12/xml-c14n11"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&amp;lt;ns0:SignatureMethod&lt;/span&gt; &lt;span class="na"&gt;Algorithm=&lt;/span&gt;&lt;span class="s"&gt;"http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&amp;lt;ns0:Reference&lt;/span&gt; &lt;span class="na"&gt;URI=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;ns0:Transforms&amp;gt;&amp;lt;ns0:Transform&lt;/span&gt; &lt;span class="na"&gt;Algorithm=&lt;/span&gt;&lt;span class="s"&gt;"http://www.w3.org/2000/09/xmldsig#enveloped-signature"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&amp;lt;ns0:Transform&lt;/span&gt; &lt;span class="na"&gt;Algorithm=&lt;/span&gt;&lt;span class="s"&gt;"http://www.w3.org/2006/12/xml-c14n11"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&amp;lt;/ns0:Transforms&amp;gt;&amp;lt;ns0:DigestMethod&lt;/span&gt; &lt;span class="na"&gt;Algorithm=&lt;/span&gt;&lt;span class="s"&gt;"http://www.w3.org/2001/04/xmlenc#sha256"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&amp;lt;ns0:DigestValue&amp;gt;&lt;/span&gt;KP3ncf09YSgkeTt+i4PR+W0AMvUTo7M8gu0z15piPMc=&lt;span class="nt"&gt;&amp;lt;/ns0:DigestValue&amp;gt;&lt;/span&gt;...
&lt;/pre&gt;


&lt;p&gt;So far we see two problems in the string produced from the &lt;code&gt;ElementTree&lt;/code&gt; object:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Namespace name &lt;code&gt;ds&lt;/code&gt; has been changed to &lt;code&gt;ns0&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Its declaration is not under the &lt;code&gt;&amp;lt;Signature&amp;gt;&lt;/code&gt; tag, but under the &lt;code&gt;&amp;lt;Test&amp;gt;&lt;/code&gt; tag.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;InvalidSignature&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;InvalidSignature&lt;/code&gt; exception we are getting is caused by the first problem.
&lt;code&gt;signxml&lt;/code&gt; first does &lt;a href="https://tools.ietf.org/html/rfc3275#section-3.2.2"&gt;signature validation&lt;/a&gt;,
where the signature value (read from the XML string in our case) is calculated over the
&lt;code&gt;&amp;lt;SignedInfo&amp;gt;&lt;/code&gt; XML element (&lt;em&gt;canonicalized&lt;/em&gt;, but we can skip this &lt;strong&gt;complicated&lt;/strong&gt; issue for now).
&lt;code&gt;&amp;lt;SignedInfo&amp;gt;&lt;/code&gt; has changed as &lt;code&gt;ds&lt;/code&gt; has been replaced by where-did-it-come-from &lt;code&gt;ns0&lt;/code&gt;, so the
signature does not match.&lt;/p&gt;
&lt;p&gt;The solution is &lt;a href="https://docs.python.org/3/library/xml.etree.elementtree.html#xml.etree.ElementTree.register_namespace"&gt;register_namespace(prefix, uri)&lt;/a&gt;
function of &lt;code&gt;ElementTree&lt;/code&gt;. Its documentation reads: 
&lt;em&gt;(...) Tags and attributes in this namespace will be serialized with the given prefix, if at all possible.&lt;/em&gt;
That's what we need (the author needs to understand why &lt;code&gt;ElementTree&lt;/code&gt; is not made to get this from our XML string).
The function must be called before verification, not necessarily before the parsing; as the documentation says,
&lt;em&gt;(...) any existing mapping for either the given prefix or the namespace URI will be removed.&lt;/em&gt;&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;lxml&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;etree&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;lxml_ET&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;xml.etree&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ElementTree&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;ET&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;signxml&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;XMLSigner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;XMLVerifier&lt;/span&gt;

&lt;span class="n"&gt;cert&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"rb"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"cert.pem"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"key.pem"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;

&lt;span class="n"&gt;xml_obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ET&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fromstring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;Test/&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;signed_xml_obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;XMLSigner&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xml_obj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;data_serialized&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lxml_ET&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tostring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;signed_xml_obj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Sending the data...&lt;/span&gt;

&lt;span class="n"&gt;data_parsed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ET&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fromstring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data_serialized&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;ET&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;register_namespace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"ds"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"http://www.w3.org/2000/09/xmldsig#"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;XMLVerifier&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;verify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data_parsed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x509_cert&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;cert&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;


&lt;p&gt;Now if we inspect &lt;code&gt;ET.tostring(data_parsed)&lt;/code&gt;, we'll see the correct &lt;code&gt;ds&lt;/code&gt; namespace in use.
The result?&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nv"&gt;Traceback&lt;/span&gt; &lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;most&lt;/span&gt; &lt;span class="nv"&gt;recent&lt;/span&gt; &lt;span class="k"&gt;call&lt;/span&gt; &lt;span class="nl"&gt;last&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;:
  &lt;span class="nv"&gt;File&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1.py&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;, &lt;span class="nv"&gt;line&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;, &lt;span class="nv"&gt;in&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;module&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nv"&gt;XMLVerifier&lt;/span&gt;&lt;span class="ss"&gt;()&lt;/span&gt;.&lt;span class="nv"&gt;verify&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;data_parsed&lt;/span&gt;, &lt;span class="nv"&gt;x509_cert&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;cert&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;
  &lt;span class="nv"&gt;File&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/path/to/python3.6/site-packages/signxml/__init__.py&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;, &lt;span class="nv"&gt;line&lt;/span&gt; &lt;span class="mi"&gt;765&lt;/span&gt;, &lt;span class="nv"&gt;in&lt;/span&gt; &lt;span class="nv"&gt;verify&lt;/span&gt;
    &lt;span class="nv"&gt;raise&lt;/span&gt; &lt;span class="nv"&gt;InvalidDigest&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Digest mismatch for reference {}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;.&lt;span class="nv"&gt;format&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;len&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;verify_results&lt;/span&gt;&lt;span class="ss"&gt;)))&lt;/span&gt;
&lt;span class="nv"&gt;signxml&lt;/span&gt;.&lt;span class="nv"&gt;exceptions&lt;/span&gt;.&lt;span class="nv"&gt;InvalidDigest&lt;/span&gt;: &lt;span class="nv"&gt;Digest&lt;/span&gt; &lt;span class="nv"&gt;mismatch&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nv"&gt;reference&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/pre&gt;


&lt;h3&gt;InvalidDigest&lt;/h3&gt;
&lt;p&gt;Now &lt;code&gt;signxml&lt;/code&gt; has successfully verified &lt;code&gt;&amp;lt;SignatureValue&amp;gt;&lt;/code&gt; over the &lt;code&gt;&amp;lt;SignedInfo&amp;gt;&lt;/code&gt;
(in &lt;em&gt;canonicalized&lt;/em&gt; form, but again we may skip this topic for now).
The "digest mismatch", about which &lt;code&gt;signxml&lt;/code&gt; is complaining now, is between the calculated digest over the
&lt;strong&gt;original XML document&lt;/strong&gt; (in canonicalized form...) and the digest string read from the &lt;code&gt;&amp;lt;DigestValue&amp;gt;&lt;/code&gt;
element under the &lt;code&gt;&amp;lt;Signagure&amp;gt;&lt;/code&gt;. It is caused by the "Problem 2" mentioned above.
&lt;code&gt;DigestValue&lt;/code&gt; is &lt;code&gt;KP3ncf09YSgkeTt+i4PR+W0AMvUTo7M8gu0z15piPMc=&lt;/code&gt;,
and it was, in fact, made over the string &lt;code&gt;&amp;lt;Test&amp;gt;&amp;lt;/Test&amp;gt;&lt;/code&gt;:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;$ echo -n '&lt;span class="nt"&gt;&amp;lt;Test&amp;gt;&amp;lt;/Test&amp;gt;&lt;/span&gt;' | openssl sha256 -binary | base64
KP3ncf09YSgkeTt+i4PR+W0AMvUTo7M8gu0z15piPMc=
&lt;/pre&gt;


&lt;p&gt;But in the deserialized ElementTree object the XML string became
&lt;code&gt;&amp;lt;Test xmlns:ds="http://www.w3.org/2000/09/xmldsig#"&amp;gt;&amp;lt;/Test&amp;gt;&lt;/code&gt;, which of course produces a different SHA-256 digest.
It is possible to see (with a debugger) that &lt;code&gt;verify()&lt;/code&gt; tries to match the digest of &lt;strong&gt;this&lt;/strong&gt; string.&lt;/p&gt;
&lt;p&gt;Such modification of the original XML looks like result of some of &lt;em&gt;canonicalization&lt;/em&gt;
transforms, but I have not found it in the specs.
The &lt;a href="https://www.w3.org/TR/xml-c14n11/#Example-SETags"&gt;examples given&lt;/a&gt; show that the
namespace declarations are not moved out of the tag inside which they are used.&lt;/p&gt;
&lt;p&gt;If we want the receiver of our XML string to be able to parse it with ElementTree
and then to successfully verify, we have no other option but to sign exactly
such string. I.e. we must produce such argument for &lt;code&gt;sign()&lt;/code&gt; which, when canonicalized,
produces the string &lt;code&gt;&amp;lt;Test xmlns:ds="http://www.w3.org/2000/09/xmldsig#"&amp;gt;&amp;lt;/Test&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Understanding how to do this requires knowledge about how ElementTree stores its XML objects.
What is important here is that it represents namespaces by string prefixes of the tags under them.
Because of this, if we only &lt;strong&gt;declare&lt;/strong&gt; a namespace, it will not be saved.
We must create some elements under this namespace &lt;strong&gt;and&lt;/strong&gt; call &lt;code&gt;register_namespace()&lt;/code&gt;.
Let's create element &lt;code&gt;ds:foo&lt;/code&gt;. To be valid XML, the string must represent just
one root XML element, so add an element &lt;code&gt;&amp;lt;wrapper&amp;gt;&lt;/code&gt;:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;lxml&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;etree&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;lxml_ET&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;xml.etree&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ElementTree&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;ET&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;signxml&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;XMLSigner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;XMLVerifier&lt;/span&gt;

&lt;span class="n"&gt;cert&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"rb"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"cert.pem"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"key.pem"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;

&lt;span class="n"&gt;ET&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;register_namespace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"ds"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"http://www.w3.org/2000/09/xmldsig#"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;xml_obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ET&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fromstring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;wrapper&amp;gt;&amp;lt;ds:foo xmlns:ds=&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;http://www.w3.org/2000/09/xmldsig#&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;/&amp;gt;&amp;lt;Test/&amp;gt;&amp;lt;/wrapper&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;signed_xml_obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;XMLSigner&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xml_obj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;data_serialized&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lxml_ET&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tostring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;signed_xml_obj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Sending the data...&lt;/span&gt;

&lt;span class="n"&gt;data_parsed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ET&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fromstring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data_serialized&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;XMLVerifier&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;verify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data_parsed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x509_cert&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;cert&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;


&lt;p&gt;Now the &lt;code&gt;ds&lt;/code&gt; namespace is available in the ElementTree object passed to &lt;code&gt;sign()&lt;/code&gt;.
When &lt;code&gt;sign()&lt;/code&gt; is called, it performs &lt;strong&gt;canonicalization&lt;/strong&gt; which puts the namespace
declaration for &lt;code&gt;ds&lt;/code&gt; under the first tag in the document. Addition of the signature,
which brings in this namespace, already does not change anything inside our &lt;code&gt;&amp;lt;Test&amp;gt;&lt;/code&gt; element.&lt;/p&gt;
&lt;h3&gt;Almost Done&lt;/h3&gt;
&lt;p&gt;The signagure verifies, but we have added content to the XML we are signing - and
also signed it! 
&lt;code&gt;verify().signed_data&lt;/code&gt; will return the content with our additions.
Probably, software which signs things (even XML) with &lt;strong&gt;such&lt;/strong&gt; side effects
would not gain wide acceptance :-)&lt;/p&gt;
&lt;p&gt;This is solved - by luck or by intention - with the possibility provided by &lt;code&gt;signxml&lt;/code&gt;
to specify the location of the enveloped signature.
As the &lt;a href="https://signxml.readthedocs.io/en/latest/#signxml.XMLSigner"&gt;documentation&lt;/a&gt; says,&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;To specify the location of an enveloped signature within data, insert a 
&lt;signature id="placeholder"&gt;&lt;/signature&gt; element in data 
(where “ds” is the “http://www.w3.org/2000/09/xmldsig#” namespace). 
This element will be replaced by the generated signature, and excised when generating the digest.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Such insert will introduce the &lt;code&gt;ds&lt;/code&gt; namespace into the &lt;code&gt;xml_obj&lt;/code&gt;,
but no any new elements outside of the &lt;code&gt;&amp;lt;ds:Signature&amp;gt;&lt;/code&gt; element.
So we'll not add anything to the content which is signed.&lt;/p&gt;
&lt;p&gt;&lt;a name="tldr"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;lxml&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;etree&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;lxml_ET&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;xml.etree&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ElementTree&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;ET&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;signxml&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;XMLSigner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;XMLVerifier&lt;/span&gt;

&lt;span class="n"&gt;cert&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"rb"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"cert.pem"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"key.pem"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;

&lt;span class="n"&gt;ET&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;register_namespace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"ds"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"http://www.w3.org/2000/09/xmldsig#"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;xml_obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ET&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fromstring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;Test&amp;gt;&amp;lt;ds:Signature xmlns:ds=&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;http://www.w3.org/2000/09/xmldsig#&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; Id=&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;placeholder&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;&amp;gt;&amp;lt;/ds:Signature&amp;gt;&amp;lt;/Test&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;signed_xml_obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;XMLSigner&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xml_obj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;data_serialized&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lxml_ET&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tostring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;signed_xml_obj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Sending the data...&lt;/span&gt;

&lt;span class="n"&gt;data_parsed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ET&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fromstring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data_serialized&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;XMLVerifier&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;verify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data_parsed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x509_cert&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;cert&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;


&lt;p&gt;Such signed serialized data can be also parsed by &lt;code&gt;lxml.etree&lt;/code&gt; and successfully verified.&lt;/p&gt;
&lt;p&gt;Do not forget that if the receiver is using ElementTree, they must call 
&lt;code&gt;ElementTree.register_namespace("ds", "http://www.w3.org/2000/09/xmldsig#")&lt;/code&gt; 
before calling &lt;code&gt;XMLSigner().verify()&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Afterword&lt;/h3&gt;
&lt;p&gt;After reading this post, you should have no doubts that 
&lt;a href="http://www.cs.auckland.ac.nz/~pgut001/pubs/xmlsec.txt"&gt;XML signing is broken&lt;/a&gt;.&lt;/p&gt;&lt;/div&gt;</description><category>Python</category><category>signature</category><category>XML</category><guid>https://technotes.shemyak.com/posts/xml-signatures-and-python-elementtree/</guid><pubDate>Sun, 16 Jun 2019 13:00:00 GMT</pubDate></item></channel></rss>