Python XML Signature library
Project description
SignXML: XML Signature in Python
================================
*SignXML* is an implementation of the W3C `XML Signature <http://en.wikipedia.org/wiki/XML_Signature>`_ standard in
Python. This standard (also known as XMLDSig and `RFC 3275 <http://www.ietf.org/rfc/rfc3275.txt>`_) is used to provide
payload security in `SAML 2.0 <http://en.wikipedia.org/wiki/SAML_2.0>`_ and
`WS-Security <https://en.wikipedia.org/wiki/WS-Security>`_, among other uses. Three versions of the
standard exist (`Version 1 "Second Edition" <http://www.w3.org/TR/xmldsig-core/>`_, `Version 1.1
<http://www.w3.org/TR/xmldsig-core1/>`_, and `Version 2.0 <http://www.w3.org/TR/xmldsig-core2>`_). *SignXML* implements
all of the required components of the standard, and most recommended ones. Its features are:
* Use of `defusedxml.lxml <https://bitbucket.org/tiran/defusedxml>`_ to defend against common XML-based attacks when
verifying signatures
* Extensions to allow signing with and verifying X.509 certificate chains, including hostname/CN validation
* Support for exclusive XML canonicalization with inclusive prefixes (`InclusiveNamespaces PrefixList
<http://www.w3.org/TR/xml-exc-c14n/#def-InclusiveNamespaces-PrefixList>`_, required to verify signatures generated by
some SAML implementations)
* Modern Python compatibility (2.7-3.5+ and PyPy)
* Well-supported, portable, reliable dependencies: `lxml <https://github.com/lxml/lxml>`_, `defusedxml
<https://bitbucket.org/tiran/defusedxml>`_, `cryptography <https://github.com/pyca/cryptography>`_, `eight
<https://github.com/kislyuk/eight>`_, `pyOpenSSL <https://github.com/pyca/pyopenssl>`_
* Comprehensive testing (including the XMLDSig interoperability suite) and `continuous integration
<https://travis-ci.org/XML-Security/signxml>`_
* Simple interface with useful defaults
* Compactness, readability, and extensibility
Installation
------------
::
pip install signxml
Note: SignXML depends on `lxml <https://github.com/lxml/lxml>`_ and `cryptography
<https://github.com/pyca/cryptography>`_, which in turn depend on `OpenSSL <https://www.openssl.org/>`_, `LibXML
<http://xmlsoft.org/>`_, and Python tools to interface with them. You can install those as follows:
+--------------+---------+---------------------------------------------------------------------------------------------+
| OS | Python | Command |
+==============+=========+=============================================================================================+
| Ubuntu 16.04 | Python 2| apt-get install python-dev python-cffi libxml2-dev libxslt1-dev libssl-dev |
| | | python-lxml python-cryptography python-openssl python-certifi python-defusedxml |
+--------------+---------+---------------------------------------------------------------------------------------------+
| Ubuntu 16.04 | Python 3| apt-get install python3-dev python3-cffi libxml2-dev libxslt1-dev libssl-dev |
| | | python3-lxml python3-cryptography python3-openssl python3-certifi python3-defusedxml |
+--------------+---------+---------------------------------------------------------------------------------------------+
| Ubuntu 14.04 | Python 2| apt-get install python-dev python-cffi libxml2-dev libxslt1-dev libssl-dev |
+--------------+---------+---------------------------------------------------------------------------------------------+
| Ubuntu 14.04 | Python 3| apt-get install python3-dev python3-cffi libxml2-dev libxslt1-dev libssl-dev |
+--------------+---------+---------------------------------------------------------------------------------------------+
| Ubuntu 12.04 | Python 2| apt-get install python-dev libxml2-dev libxslt1-dev libssl-dev; pip install cffi |
+--------------+---------+---------------------------------------------------------------------------------------------+
| Red Hat | Python 2| yum install python-devel python-cffi libxml2-devel libxslt1-devel openssl-devel |
+--------------+---------+---------------------------------------------------------------------------------------------+
| Red Hat | Python 3| yum install python3-devel python3-cffi libxml2-devel libxslt1-devel openssl-devel |
+--------------+---------+---------------------------------------------------------------------------------------------+
| OS X/Homebrew| | xcode-select --install; brew install openssl; |
| | | export LDFLAGS="-L$(brew --prefix openssl)/lib" CFLAGS="-I$(brew --prefix openssl)/include" |
+--------------+---------+---------------------------------------------------------------------------------------------+
Synopsis
--------
SignXML uses the ElementTree API (also supported by lxml) to work with XML data.
.. code-block:: python
from signxml import XMLSigner, XMLVerifier
cert = open("example.pem").read()
key = open("example.key").read()
root = ElementTree.fromstring(signature_data)
signed_root = XMLSigner().sign(root, key=key, cert=cert)
verified_data = XMLVerifier().verify(signed_root).signed_xml
.. _verifying-saml-assertions:
Verifying SAML assertions
~~~~~~~~~~~~~~~~~~~~~~~~~
Assuming ``metadata.xml`` contains SAML metadata for the assertion source:
.. code-block:: python
from lxml import etree
from base64 import b64decode
from signxml import XMLVerifier
with open("metadata.xml", "rb") as fh:
cert = etree.parse(fh).find("//ds:X509Certificate").text
assertion_data = XMLVerifier().verify(b64decode(assertion_body), x509_cert=cert).signed_xml
.. admonition:: Signing SAML assertions
The SAML assertion schema specifies a location for the enveloped XML signature (between ``<Issuer>`` and
``<Subject>``). To sign a SAML assertion in a schema-compliant way, insert a signature placeholder tag at that location
before calling XMLSigner: ``<ds:Signature Id="placeholder"></ds:Signature>``.
.. admonition:: See what is signed
It is important to understand and follow the best practice rule of "See what is signed" when verifying XML
signatures. The gist of this rule is: if your application neglects to verify that the information it trusts is
what was actually signed, the attacker can supply a valid signature but point you to malicious data that wasn't signed
by that signature. Failure to follow this rule can lead to vulnerability against attacks like
`SAML signature wrapping <https://www.usenix.org/system/files/conference/usenixsecurity12/sec12-final91.pdf>`_.
In SignXML, you can ensure that the information signed is what you expect to be signed by only trusting the
data returned by the ``verify()`` method. The ``signed_xml`` attribute of the return value is the XML node or string that
was signed.
**Recommended reading:** `W3C XML Signature Best Practices for Applications <http://www.w3.org/TR/xmldsig-bestpractices/#practices-applications>`_, `OWASP: On Breaking SAML: Be Whoever You Want to Be <https://www.owasp.org/images/2/28/Breaking_SAML_Be_Whoever_You_Want_to_Be_-_Juraj_Somorovsky%2BChristian_Mainka.pdf>`_
.. admonition:: Establish trust
If you do not supply any keyword arguments to ``verify()``, the default behavior is to trust **any** valid XML
signature generated using a valid X.509 certificate trusted by your system's CA store. This means anyone can
get an SSL certificate and generate a signature that you will trust. To establish trust in the signer, use the
``x509_cert`` argument to specify a certificate that was pre-shared out-of-band (e.g. via SAML metadata, as
shown in *Verifying SAML assertions*), or ``cert_subject_name`` to specify a
subject name that must be in the signing X.509 certificate given by the signature (verified as if it were a
domain name), or ``ca_pem_file``/``ca_path`` to give a custom CA.
Example: Signing and verifying a SAML assertion
"""""""""""""""""""""""""""""""""""""""""""""""
.. code-block:: python
TODO
XML signature methods: enveloped, detached, enveloping
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The XML Signature specification defines three ways to compose a signature with the data being signed: enveloped,
detached, and enveloping signature. Enveloped is the default method. To specify the type of signature that you want to
generate, pass the ``method`` argument to ``sign()``:
.. code-block:: python
signed_root = XMLSigner(method=signxml.methods.detached).sign(root, key=key, cert=cert)
verified_data = XMLVerifier().verify(signed_root).signed_xml
For detached signatures, the code above will use the ``Id`` or ``ID`` attribute of ``root`` to generate a relative URI
(``<Reference URI="#value"``). You can also override the value of ``URI`` by passing a ``reference_uri`` argument to
``sign()``. To verify a detached signature that refers to an external entity, pass a callable resolver in
``XMLVerifier().verify(data, uri_resolver=...)``.
Example: Signing and verifying a SOAP WS-Security envelope
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
.. code-block:: python
TODO
See the `API documentation <https://signxml.readthedocs.io/en/latest/#id3>`_ for more.
Authors
-------
* Andrey Kislyuk
Links
-----
* `Project home page (GitHub) <https://github.com/XML-Security/signxml>`_
* `Documentation (Read the Docs) <https://signxml.readthedocs.io/en/latest/>`_
* `Package distribution (PyPI) <https://pypi.python.org/pypi/signxml>`_
* `Change log <https://github.com/XML-Security/signxml/blob/master/Changes.rst>`_
* `List of W3C XML Signature standards and drafts <http://www.w3.org/TR/#tr_XML_Signature>`_
* `W3C Recommendation: XML Signature Syntax and Processing (Second Edition) <http://www.w3.org/TR/xmldsig-core/>`_
* `W3C Recommendation: XML Signature Syntax and Processing Version 1.1 <http://www.w3.org/TR/xmldsig-core1>`_
* `W3C Working Group Note: XML Signature Syntax and Processing Version 2.0 <http://www.w3.org/TR/xmldsig-core2>`_
* `W3C Working Group Note: XML Security 2.0 Requirements and Design Considerations <https://www.w3.org/TR/2013/NOTE-xmlsec-reqs2-20130411/>`_
* `W3C Working Group Note: XML Signature Best Practices <http://www.w3.org/TR/xmldsig-bestpractices/>`_
* `XML-Signature Interoperability <http://www.w3.org/Signature/2001/04/05-xmldsig-interop.html>`_
* `W3C Working Group Note: Test Cases for C14N 1.1 and XMLDSig Interoperability <http://www.w3.org/TR/xmldsig2ed-tests/>`_
* `XMLSec: Related links <https://www.aleksey.com/xmlsec/related.html>`_
* `OWASP SAML Security Cheat Sheet <https://www.owasp.org/index.php/SAML_Security_Cheat_Sheet>`_
Bugs
~~~~
Please report bugs, issues, feature requests, etc. on `GitHub <https://github.com/XML-Security/signxml/issues>`_.
License
-------
Licensed under the terms of the `Apache License, Version 2.0 <http://www.apache.org/licenses/LICENSE-2.0>`_.
.. image:: https://img.shields.io/travis/XML-Security/signxml.svg
:target: https://travis-ci.org/XML-Security/signxml
.. image:: https://codecov.io/github/XML-Security/signxml/coverage.svg?branch=master
:target: https://codecov.io/github/XML-Security/signxml?branch=master
.. image:: https://img.shields.io/pypi/v/signxml.svg
:target: https://pypi.python.org/pypi/signxml
.. image:: https://img.shields.io/pypi/l/signxml.svg
:target: https://pypi.python.org/pypi/signxml
.. image:: https://readthedocs.org/projects/signxml/badge/?version=latest
:target: https://signxml.readthedocs.io/
================================
*SignXML* is an implementation of the W3C `XML Signature <http://en.wikipedia.org/wiki/XML_Signature>`_ standard in
Python. This standard (also known as XMLDSig and `RFC 3275 <http://www.ietf.org/rfc/rfc3275.txt>`_) is used to provide
payload security in `SAML 2.0 <http://en.wikipedia.org/wiki/SAML_2.0>`_ and
`WS-Security <https://en.wikipedia.org/wiki/WS-Security>`_, among other uses. Three versions of the
standard exist (`Version 1 "Second Edition" <http://www.w3.org/TR/xmldsig-core/>`_, `Version 1.1
<http://www.w3.org/TR/xmldsig-core1/>`_, and `Version 2.0 <http://www.w3.org/TR/xmldsig-core2>`_). *SignXML* implements
all of the required components of the standard, and most recommended ones. Its features are:
* Use of `defusedxml.lxml <https://bitbucket.org/tiran/defusedxml>`_ to defend against common XML-based attacks when
verifying signatures
* Extensions to allow signing with and verifying X.509 certificate chains, including hostname/CN validation
* Support for exclusive XML canonicalization with inclusive prefixes (`InclusiveNamespaces PrefixList
<http://www.w3.org/TR/xml-exc-c14n/#def-InclusiveNamespaces-PrefixList>`_, required to verify signatures generated by
some SAML implementations)
* Modern Python compatibility (2.7-3.5+ and PyPy)
* Well-supported, portable, reliable dependencies: `lxml <https://github.com/lxml/lxml>`_, `defusedxml
<https://bitbucket.org/tiran/defusedxml>`_, `cryptography <https://github.com/pyca/cryptography>`_, `eight
<https://github.com/kislyuk/eight>`_, `pyOpenSSL <https://github.com/pyca/pyopenssl>`_
* Comprehensive testing (including the XMLDSig interoperability suite) and `continuous integration
<https://travis-ci.org/XML-Security/signxml>`_
* Simple interface with useful defaults
* Compactness, readability, and extensibility
Installation
------------
::
pip install signxml
Note: SignXML depends on `lxml <https://github.com/lxml/lxml>`_ and `cryptography
<https://github.com/pyca/cryptography>`_, which in turn depend on `OpenSSL <https://www.openssl.org/>`_, `LibXML
<http://xmlsoft.org/>`_, and Python tools to interface with them. You can install those as follows:
+--------------+---------+---------------------------------------------------------------------------------------------+
| OS | Python | Command |
+==============+=========+=============================================================================================+
| Ubuntu 16.04 | Python 2| apt-get install python-dev python-cffi libxml2-dev libxslt1-dev libssl-dev |
| | | python-lxml python-cryptography python-openssl python-certifi python-defusedxml |
+--------------+---------+---------------------------------------------------------------------------------------------+
| Ubuntu 16.04 | Python 3| apt-get install python3-dev python3-cffi libxml2-dev libxslt1-dev libssl-dev |
| | | python3-lxml python3-cryptography python3-openssl python3-certifi python3-defusedxml |
+--------------+---------+---------------------------------------------------------------------------------------------+
| Ubuntu 14.04 | Python 2| apt-get install python-dev python-cffi libxml2-dev libxslt1-dev libssl-dev |
+--------------+---------+---------------------------------------------------------------------------------------------+
| Ubuntu 14.04 | Python 3| apt-get install python3-dev python3-cffi libxml2-dev libxslt1-dev libssl-dev |
+--------------+---------+---------------------------------------------------------------------------------------------+
| Ubuntu 12.04 | Python 2| apt-get install python-dev libxml2-dev libxslt1-dev libssl-dev; pip install cffi |
+--------------+---------+---------------------------------------------------------------------------------------------+
| Red Hat | Python 2| yum install python-devel python-cffi libxml2-devel libxslt1-devel openssl-devel |
+--------------+---------+---------------------------------------------------------------------------------------------+
| Red Hat | Python 3| yum install python3-devel python3-cffi libxml2-devel libxslt1-devel openssl-devel |
+--------------+---------+---------------------------------------------------------------------------------------------+
| OS X/Homebrew| | xcode-select --install; brew install openssl; |
| | | export LDFLAGS="-L$(brew --prefix openssl)/lib" CFLAGS="-I$(brew --prefix openssl)/include" |
+--------------+---------+---------------------------------------------------------------------------------------------+
Synopsis
--------
SignXML uses the ElementTree API (also supported by lxml) to work with XML data.
.. code-block:: python
from signxml import XMLSigner, XMLVerifier
cert = open("example.pem").read()
key = open("example.key").read()
root = ElementTree.fromstring(signature_data)
signed_root = XMLSigner().sign(root, key=key, cert=cert)
verified_data = XMLVerifier().verify(signed_root).signed_xml
.. _verifying-saml-assertions:
Verifying SAML assertions
~~~~~~~~~~~~~~~~~~~~~~~~~
Assuming ``metadata.xml`` contains SAML metadata for the assertion source:
.. code-block:: python
from lxml import etree
from base64 import b64decode
from signxml import XMLVerifier
with open("metadata.xml", "rb") as fh:
cert = etree.parse(fh).find("//ds:X509Certificate").text
assertion_data = XMLVerifier().verify(b64decode(assertion_body), x509_cert=cert).signed_xml
.. admonition:: Signing SAML assertions
The SAML assertion schema specifies a location for the enveloped XML signature (between ``<Issuer>`` and
``<Subject>``). To sign a SAML assertion in a schema-compliant way, insert a signature placeholder tag at that location
before calling XMLSigner: ``<ds:Signature Id="placeholder"></ds:Signature>``.
.. admonition:: See what is signed
It is important to understand and follow the best practice rule of "See what is signed" when verifying XML
signatures. The gist of this rule is: if your application neglects to verify that the information it trusts is
what was actually signed, the attacker can supply a valid signature but point you to malicious data that wasn't signed
by that signature. Failure to follow this rule can lead to vulnerability against attacks like
`SAML signature wrapping <https://www.usenix.org/system/files/conference/usenixsecurity12/sec12-final91.pdf>`_.
In SignXML, you can ensure that the information signed is what you expect to be signed by only trusting the
data returned by the ``verify()`` method. The ``signed_xml`` attribute of the return value is the XML node or string that
was signed.
**Recommended reading:** `W3C XML Signature Best Practices for Applications <http://www.w3.org/TR/xmldsig-bestpractices/#practices-applications>`_, `OWASP: On Breaking SAML: Be Whoever You Want to Be <https://www.owasp.org/images/2/28/Breaking_SAML_Be_Whoever_You_Want_to_Be_-_Juraj_Somorovsky%2BChristian_Mainka.pdf>`_
.. admonition:: Establish trust
If you do not supply any keyword arguments to ``verify()``, the default behavior is to trust **any** valid XML
signature generated using a valid X.509 certificate trusted by your system's CA store. This means anyone can
get an SSL certificate and generate a signature that you will trust. To establish trust in the signer, use the
``x509_cert`` argument to specify a certificate that was pre-shared out-of-band (e.g. via SAML metadata, as
shown in *Verifying SAML assertions*), or ``cert_subject_name`` to specify a
subject name that must be in the signing X.509 certificate given by the signature (verified as if it were a
domain name), or ``ca_pem_file``/``ca_path`` to give a custom CA.
Example: Signing and verifying a SAML assertion
"""""""""""""""""""""""""""""""""""""""""""""""
.. code-block:: python
TODO
XML signature methods: enveloped, detached, enveloping
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The XML Signature specification defines three ways to compose a signature with the data being signed: enveloped,
detached, and enveloping signature. Enveloped is the default method. To specify the type of signature that you want to
generate, pass the ``method`` argument to ``sign()``:
.. code-block:: python
signed_root = XMLSigner(method=signxml.methods.detached).sign(root, key=key, cert=cert)
verified_data = XMLVerifier().verify(signed_root).signed_xml
For detached signatures, the code above will use the ``Id`` or ``ID`` attribute of ``root`` to generate a relative URI
(``<Reference URI="#value"``). You can also override the value of ``URI`` by passing a ``reference_uri`` argument to
``sign()``. To verify a detached signature that refers to an external entity, pass a callable resolver in
``XMLVerifier().verify(data, uri_resolver=...)``.
Example: Signing and verifying a SOAP WS-Security envelope
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
.. code-block:: python
TODO
See the `API documentation <https://signxml.readthedocs.io/en/latest/#id3>`_ for more.
Authors
-------
* Andrey Kislyuk
Links
-----
* `Project home page (GitHub) <https://github.com/XML-Security/signxml>`_
* `Documentation (Read the Docs) <https://signxml.readthedocs.io/en/latest/>`_
* `Package distribution (PyPI) <https://pypi.python.org/pypi/signxml>`_
* `Change log <https://github.com/XML-Security/signxml/blob/master/Changes.rst>`_
* `List of W3C XML Signature standards and drafts <http://www.w3.org/TR/#tr_XML_Signature>`_
* `W3C Recommendation: XML Signature Syntax and Processing (Second Edition) <http://www.w3.org/TR/xmldsig-core/>`_
* `W3C Recommendation: XML Signature Syntax and Processing Version 1.1 <http://www.w3.org/TR/xmldsig-core1>`_
* `W3C Working Group Note: XML Signature Syntax and Processing Version 2.0 <http://www.w3.org/TR/xmldsig-core2>`_
* `W3C Working Group Note: XML Security 2.0 Requirements and Design Considerations <https://www.w3.org/TR/2013/NOTE-xmlsec-reqs2-20130411/>`_
* `W3C Working Group Note: XML Signature Best Practices <http://www.w3.org/TR/xmldsig-bestpractices/>`_
* `XML-Signature Interoperability <http://www.w3.org/Signature/2001/04/05-xmldsig-interop.html>`_
* `W3C Working Group Note: Test Cases for C14N 1.1 and XMLDSig Interoperability <http://www.w3.org/TR/xmldsig2ed-tests/>`_
* `XMLSec: Related links <https://www.aleksey.com/xmlsec/related.html>`_
* `OWASP SAML Security Cheat Sheet <https://www.owasp.org/index.php/SAML_Security_Cheat_Sheet>`_
Bugs
~~~~
Please report bugs, issues, feature requests, etc. on `GitHub <https://github.com/XML-Security/signxml/issues>`_.
License
-------
Licensed under the terms of the `Apache License, Version 2.0 <http://www.apache.org/licenses/LICENSE-2.0>`_.
.. image:: https://img.shields.io/travis/XML-Security/signxml.svg
:target: https://travis-ci.org/XML-Security/signxml
.. image:: https://codecov.io/github/XML-Security/signxml/coverage.svg?branch=master
:target: https://codecov.io/github/XML-Security/signxml?branch=master
.. image:: https://img.shields.io/pypi/v/signxml.svg
:target: https://pypi.python.org/pypi/signxml
.. image:: https://img.shields.io/pypi/l/signxml.svg
:target: https://pypi.python.org/pypi/signxml
.. image:: https://readthedocs.org/projects/signxml/badge/?version=latest
:target: https://signxml.readthedocs.io/
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
signxml-2.2.3.tar.gz
(29.5 kB
view hashes)
Built Distribution
Close
Hashes for signxml-2.2.3-py2.py3-none-any.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 90407409416a6f908b09532b6068d565cbcdd62b287ae4e2c17a7da2af30b9aa |
|
MD5 | c27f2b4540fcfe815ff6d83d8b5b12db |
|
BLAKE2b-256 | 2c0feb2d90573ac2e5f5de7f37ce757a920c3053525eed825eae58856f6969c4 |