SignXML: XML Signature and XAdES in Python#

SignXML is an implementation of the W3C XML Signature standard in Python. This standard (also known as “XMLDSig”) is used to provide payload security in SAML 2.0, XAdES, and WS-Security, among other uses. The standard is defined in the W3C Recommendation XML Signature Syntax and Processing Version 1.1. SignXML implements all of the required components of the Version 1.1 standard, and most recommended ones. Its features are:

  • Use of a libxml2-based XML parser configured to defend against common XML attacks when verifying signatures

  • Extensions to allow signing with and verifying X.509 certificate chains, including hostname/CN validation

  • Extensions to sign and verify XAdES signatures

  • Support for exclusive XML canonicalization with inclusive prefixes (InclusiveNamespaces PrefixList, required to verify signatures generated by some SAML implementations)

  • Modern Python compatibility (3.7-3.11+ and PyPy)

  • Well-supported, portable, reliable dependencies: lxml, cryptography, pyOpenSSL

  • Comprehensive testing (including the XMLDSig interoperability suite) and continuous integration

  • Simple interface with useful, ergonomic, and secure defaults (no network calls, XSLT or XPath transforms)

  • Compactness, readability, and extensibility

Installation#

pip install signxml

Note: SignXML depends on lxml and cryptography, which in turn depend on OpenSSL, LibXML, and Python tools to interface with them. You can install those as follows:

OS

Command

Ubuntu

apt-get install --no-install-recommends python3-pip python3-wheel python3-setuptools python3-openssl python3-lxml

Red Hat, Amazon Linux, CentOS

yum install python3-pip python3-pyOpenSSL python3-lxml

Mac OS

Install Homebrew, then run brew install python.

Synopsis#

SignXML uses the lxml ElementTree API to work with XML data.

from lxml import etree
from signxml import XMLSigner, XMLVerifier

data_to_sign = "<Test/>"
cert = open("cert.pem").read()
key = open("privkey.pem").read()
root = etree.fromstring(data_to_sign)
signed_root = XMLSigner().sign(root, key=key, cert=cert)
verified_data = XMLVerifier().verify(signed_root).signed_xml

To make this example self-sufficient for test purposes:

  • Generate a test certificate and key using openssl req -x509 -nodes -subj "/CN=test" -days 1 -newkey rsa -keyout privkey.pem -out cert.pem (run yum install openssl on Red Hat).

  • Pass the x509_cert=cert keyword argument to XMLVerifier.verify(). (In production, ensure this is replaced with the correct configuration for the trusted CA or certificate - this determines which signatures your application trusts.)

Verifying SAML assertions#

Assuming metadata.xml contains SAML metadata for the assertion source:

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

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>.

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.

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, On Breaking SAML: Be Whoever You Want to Be, Duo Finds SAML Vulnerabilities Affecting Multiple Implementations

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.

XML signature construction 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():

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=...).

See the API documentation for more details.

XML representation details: Configuring namespace prefixes and whitespace#

Some applications require a particular namespace prefix configuration - for example, a number of applications assume that the http://www.w3.org/2000/09/xmldsig# namespace is set as the default, unprefixed namespace instead of using the customary ds: prefix. While in normal use namespace prefix naming is an insignificant representation detail, it can be significant in some XML canonicalization and signature configurations. To configure the namespace prefix map when generating a signature, set the XMLSigner.namespaces attribute:

signer = signxml.XMLSigner(...)
signer.namespaces = {None: signxml.namespaces.ds}
signed_root = signer.sign(...)

Similarly, whitespace in the signed document is significant for XML canonicalization and signature purposes. Do not pretty-print the XML after generating the signature, since this can unfortunately render the signature invalid.

XML parsing security and compatibility with xml.etree.ElementTree#

SignXML uses the lxml ElementTree library, not the ElementTree from Python’s standard library, to work with XML. lxml is used due to its superior resistance to XML attacks, as well as XML canonicalization and namespace organization features. It is recommended that you pass XML string input directly to signxml before further parsing, and use lxml to work with untrusted XML input in general. If you do pass xml.etree.ElementTree objects to SignXML, you should be aware of differences in XML namespace handling between the two libraries. See the following references for more information:

XAdES signatures#

XAdES (“XML Advanced Electronic Signatures”) is a standard for attaching metadata to XML Signature objects. This standard is endorsed by the European Union as the implementation for its eSignature regulations.

SignXML supports signing and verifying documents using XAdES signatures:

from signxml import DigestAlgorithm
from signxml.xades import (XAdESSigner, XAdESVerifier, XAdESVerifyResult,
                           XAdESSignaturePolicy, XAdESDataObjectFormat)
signature_policy = XAdESSignaturePolicy(
    Identifier="MyPolicyIdentifier",
    Description="Hello XAdES",
    DigestMethod=DigestAlgorithm.SHA256,
    DigestValue="Ohixl6upD6av8N7pEvDABhEL6hM=",
)
data_object_format = XAdESDataObjectFormat(
    Description="My XAdES signature",
    MimeType="text/xml",
)
signer = XAdESSigner(
    signature_policy=signature_policy,
    claimed_roles=["signer"],
    data_object_format=data_object_format,
    c14n_algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315",
)
signed_doc = signer.sign(doc, key=private_key, cert=certificate)
verifier = XAdESVerifier()
verify_results = verifier.verify(
    signed_doc, x509_cert=certificate, expect_references=3, expect_signature_policy=signature_policy
)
for verify_result in verify_results:
    if isinstance(verify_result, XAdESVerifyResult):
        verify_result.signed_properties  # use this to access parsed XAdES properties

Authors#

License#

Copyright 2014-2023, Andrey Kislyuk and SignXML contributors. Licensed under the terms of the Apache License, Version 2.0. Distribution of the LICENSE and NOTICE files with source copies of this package and derivative works is REQUIRED as specified by the Apache License.

https://github.com/XML-Security/signxml/workflows/Test%20suite/badge.svg https://codecov.io/github/XML-Security/signxml/coverage.svg?branch=master https://img.shields.io/pypi/v/signxml.svg https://img.shields.io/pypi/l/signxml.svg

API documentation#

Use signxml.XMLSigner and signxml.XMLVerifier to sign and verify XML Signatures, respectively. See SignXML documentation for examples.

class signxml.XMLSigner(method=SignatureConstructionMethod.enveloped, signature_algorithm=SignatureMethod.RSA_SHA256, digest_algorithm=DigestAlgorithm.SHA256, c14n_algorithm=CanonicalizationMethod.CANONICAL_XML_1_1)[source]#

Create a new XML Signature Signer object, which can be used to hold configuration information and sign multiple pieces of data.

Parameters:
signature_annotators: List#

A list of callables that will be called at signature creation time to annotate the content to be signed before signing. You can use this to register a custom signature decorator as follows:

def my_annotator(sig_root, signing_settings):
    ...
    sig_root.append(my_custom_node)

signer = XMLSigner()
signer.signature_annotators.append(my_annotator)
signed = signer.sign(data, ...)
check_deprecated_methods()[source]#
sign(data, *, key=None, passphrase=None, cert=None, reference_uri=None, key_name=None, key_info=None, id_attribute=None, always_add_key_value=False, inclusive_ns_prefixes=None, signature_properties=None)[source]#

Sign the data and return the root element of the resulting XML tree.

Parameters:
  • data (String, file-like object, or XML ElementTree Element API compatible object) – Data to sign

  • key (str | bytes | RSAPrivateKey | DSAPrivateKey | EllipticCurvePrivateKey | None) – Key to be used for signing. When signing with a certificate or RSA/DSA/ECDSA key, this can be a string/bytes containing a PEM-formatted key, or a cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey, cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKey, or cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateKey object. When signing with a HMAC, this should be a string containing the shared secret.

  • passphrase (bytes | None) – Passphrase to use to decrypt the key, if any.

  • cert (str | List[str] | List[X509] | None) – X.509 certificate to use for signing. This should be a string containing a PEM-formatted certificate, or an array of strings or OpenSSL.crypto.X509 objects containing the certificate and a chain of intermediate certificates.

  • reference_uri (str | List[str] | List[SignatureReference] | None) – Custom reference URI or list of reference URIs to incorporate into the signature. When method is set to detached or enveloped, reference URIs are set to this value and only the referenced elements are signed. To specify extra options specific to each reference URI, pass a list of one or more SignatureReference objects.

  • key_name (str | None) – Add a KeyName element in the KeyInfo element that may be used by the signer to communicate a key identifier to the recipient. Typically, KeyName contains an identifier related to the key pair used to sign the message.

  • key_info (_Element | None) – A custom KeyInfo element to insert in the signature. Use this to supply <wsse:SecurityTokenReference> or other custom key references. An example value can be found here: https://github.com/XML-Security/signxml/blob/master/test/wsse_keyinfo.xml

  • id_attribute (str | None) – Name of the attribute whose value URI refers to. By default, SignXML will search for “Id”, then “ID”.

  • always_add_key_value (bool) – Write the key value to the KeyInfo element even if a X509 certificate is present. Use of this parameter is discouraged, as it introduces an ambiguity and a security hazard. The public key used to sign the document is already encoded in the certificate (which is in X509Data), so the verifier must either ignore KeyValue or make sure it matches what’s in the certificate. This parameter is provided for compatibility purposes only.

  • inclusive_ns_prefixes (List[str] | None) –

    Provide a list of XML namespace prefixes whose declarations should be preserved when canonicalizing the signature (InclusiveNamespaces PrefixList).

    To specify this value separately for reference canonicalizaition, pass a list of one or more SignatureReference objects as the reference_uri keyword argument, and set the inclusive_ns_prefixes attribute on those objects.

  • signature_properties (_Element | List[_Element] | None) – One or more Elements that are to be included in the SignatureProperies section when using the detached method.

Returns:

A lxml.etree._Element object representing the root of the XML tree containing the signature and the payload data.

Return type:

_Element

To specify the location of an enveloped signature within data, insert a <ds:Signature Id="placeholder"></ds:Signature> 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.

class signxml.SignatureReference(URI, c14n_method=None, inclusive_ns_prefixes=None)[source]#

A container representing a signature reference (pointer to data covered by the signature). A signature can include one or more references. The integrity of each reference is attested by including the digest (hash) of its value.

URI: str#

The reference URI, for example #elementId to refer to an element whose Id attribute is set to elementId.

c14n_method: CanonicalizationMethod | None = None#

Use this parameter to set a canonicalization method for the reference value that is distinct from that for the signature itself.

inclusive_ns_prefixes: List | None = None#

When using exclusive XML canonicalization, use this parameter to provide a list of XML namespace prefixes whose declarations should be preserved when canonicalizing the reference value (InclusiveNamespaces PrefixList).

class signxml.XMLVerifier[source]#

Create a new XML Signature Verifier object, which can be used to verify multiple pieces of data.

verify(data, *, x509_cert=None, cert_subject_name=None, cert_resolver=None, ca_pem_file=None, ca_path=None, hmac_key=None, validate_schema=True, parser=None, uri_resolver=None, id_attribute=None, expect_config=SignatureConfiguration(require_x509=True, location='.//', expect_references=1, signature_methods=frozenset({SignatureMethod.DSA_SHA256, SignatureMethod.RSA_SHA224, SignatureMethod.ECDSA_SHA3_224, SignatureMethod.HMAC_SHA384, SignatureMethod.SHA512_RSA_MGF1, SignatureMethod.ECDSA_SHA3_256, SignatureMethod.SHA3_256_RSA_MGF1, SignatureMethod.SHA3_224_RSA_MGF1, SignatureMethod.ECDSA_SHA3_384, SignatureMethod.HMAC_SHA512, SignatureMethod.SHA3_384_RSA_MGF1, SignatureMethod.SHA3_512_RSA_MGF1, SignatureMethod.HMAC_SHA256, SignatureMethod.ECDSA_SHA224, SignatureMethod.ECDSA_SHA512, SignatureMethod.ECDSA_SHA3_512, SignatureMethod.RSA_SHA512, SignatureMethod.RSA_SHA256, SignatureMethod.HMAC_SHA224, SignatureMethod.SHA224_RSA_MGF1, SignatureMethod.SHA384_RSA_MGF1, SignatureMethod.ECDSA_SHA256, SignatureMethod.RSA_SHA384, SignatureMethod.ECDSA_SHA384, SignatureMethod.SHA256_RSA_MGF1}), digest_algorithms=frozenset({DigestAlgorithm.SHA512, DigestAlgorithm.SHA224, DigestAlgorithm.SHA384, DigestAlgorithm.SHA3_384, DigestAlgorithm.SHA3_256, DigestAlgorithm.SHA3_224, DigestAlgorithm.SHA256, DigestAlgorithm.SHA3_512}), ignore_ambiguous_key_info=False), **deprecated_kwargs)[source]#

Verify the XML signature supplied in the data and return a list of VerifyResult data structures representing the data signed by the signature, or raise an exception if the signature is not valid. By default, this requires the signature to be generated using a valid X.509 certificate. To enable other means of signature validation, set expect_config to a configuration with the require_x509 parameter set to False.

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.

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 return value is the XML node or string that was signed. Also, depending on the canonicalization method used by the signature, comments in the XML data may not be subject to signing, so may need to be untrusted. If so, they are excised from the return value of verify().

Recommended reading: http://www.w3.org/TR/xmldsig-bestpractices/#practices-applications

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.

Parameters:
  • data (String, file-like object, or XML ElementTree Element API compatible object) – Signature data to verify

  • x509_cert (str | X509 | None) – A trusted external X.509 certificate, given as a PEM-formatted string or OpenSSL.crypto.X509 object, to use for verification. Overrides any X.509 certificate information supplied by the signature. If left set to None, requires that the signature supply a valid X.509 certificate chain that validates against the known certificate authorities. Implies require_x509=True.

  • cert_subject_name (str | None) – Subject Common Name to check the signing X.509 certificate against. Implies require_x509=True.

  • cert_resolver (Callable | None) – Function to use to resolve trusted X.509 certificates when X509IssuerSerial and X509Digest references are found in the signature. The function is called with the keyword arguments x509_issuer_name, x509_serial_number and x509_digest, and is expected to return an iterable of one or more strings containing a PEM-formatted certificate and a chain of intermediate certificates, if needed. Implies require_x509=True.

  • ca_pem_file (str | bytes | None) – Filename of a PEM file containing certificate authority information to use when verifying certificate-based signatures.

  • ca_path (str | None) – Path to a directory containing PEM-formatted certificate authority files to use when verifying certificate-based signatures. If neither ca_pem_file nor ca_path is given, the Mozilla CA bundle provided by certifi will be loaded.

  • hmac_key (str | None) – If using HMAC, a string containing the shared secret.

  • validate_schema (bool) – Whether to validate data against the XML Signature schema.

  • parser (lxml.etree.XMLParser compatible parser) – Custom XML parser instance to use when parsing data. The default parser arguments used by SignXML are: resolve_entities=False. See https://lxml.de/FAQ.html#how-do-i-use-lxml-safely-as-a-web-service-endpoint.

  • uri_resolver (Callable | None) – Function to use to resolve reference URIs that are not empty and don’t start with “#” (such references are only expected in detached signatures; if you don’t expect such signatures, leave this unset to prevent them from validating). The function is called with a single string argument containing the URI to be resolved, and is expected to return a lxml.etree._Element node or bytes.

  • id_attribute (str | None) – Name of the attribute whose value URI refers to. By default, SignXML will search for “Id”, then “ID”.

  • expect_config (SignatureConfiguration) – Expected signature configuration. Pass a SignatureConfiguration object to describe expected properties of the verified signature. Signatures with unexpected configurations will fail validation.

  • deprecated_kwargs – Direct application of the parameters require_x509, expect_references, and ignore_ambiguous_key_info is deprecated. Use expect_config instead.

Raises:

signxml.exceptions.InvalidSignature

Return type:

VerifyResult | List[VerifyResult]

validate_schema(signature)[source]#
class signxml.VerifyResult(signed_data, signed_xml, signature_xml)[source]#

This is a dataclass representing structured data returned by signxml.XMLVerifier.verify(). The results of a verification contain the signed bytes, the parsed signed XML, and the parsed signature XML. Example usage:

verified_data = signxml.XMLVerifier().verify(input_data).signed_xml

signed_data: bytes#

The binary data as it was signed

signed_xml: _Element | None#

The signed data parsed as XML (or None if parsing failed)

signature_xml: _Element#

The signature element parsed as XML

class signxml.SignatureConfiguration(require_x509=True, location='.//', expect_references=1, signature_methods=frozenset({SignatureMethod.DSA_SHA256, SignatureMethod.ECDSA_SHA224, SignatureMethod.ECDSA_SHA256, SignatureMethod.ECDSA_SHA384, SignatureMethod.ECDSA_SHA3_224, SignatureMethod.ECDSA_SHA3_256, SignatureMethod.ECDSA_SHA3_384, SignatureMethod.ECDSA_SHA3_512, SignatureMethod.ECDSA_SHA512, SignatureMethod.HMAC_SHA224, SignatureMethod.HMAC_SHA256, SignatureMethod.HMAC_SHA384, SignatureMethod.HMAC_SHA512, SignatureMethod.RSA_SHA224, SignatureMethod.RSA_SHA256, SignatureMethod.RSA_SHA384, SignatureMethod.RSA_SHA512, SignatureMethod.SHA224_RSA_MGF1, SignatureMethod.SHA256_RSA_MGF1, SignatureMethod.SHA384_RSA_MGF1, SignatureMethod.SHA3_224_RSA_MGF1, SignatureMethod.SHA3_256_RSA_MGF1, SignatureMethod.SHA3_384_RSA_MGF1, SignatureMethod.SHA3_512_RSA_MGF1, SignatureMethod.SHA512_RSA_MGF1}), digest_algorithms=frozenset({DigestAlgorithm.SHA224, DigestAlgorithm.SHA256, DigestAlgorithm.SHA384, DigestAlgorithm.SHA3_224, DigestAlgorithm.SHA3_256, DigestAlgorithm.SHA3_384, DigestAlgorithm.SHA3_512, DigestAlgorithm.SHA512}), ignore_ambiguous_key_info=False)[source]#

A container holding signature settings that will be used to assert properties of the signature.

require_x509: bool = True#

If True, a valid X.509 certificate-based signature with an established chain of trust is required to pass validation. If False, other types of valid signatures (e.g. HMAC or RSA public key) are accepted.

location: str = './/'#

XPath location where the signature tag will be expected. By default, the signature tag is expected to be a child of the top level element (i.e. enveloped at the top level). If your signature is enveloping (i.e. the ds:Signature tag is itself the top level tag), it is recommended that you set this to ./. If your signature is nested elsewhere in the document, you can reference the full path as ./{ns}Tag1/{ns}Tag2/{ns}Tag3/. If you wish to search for the signature anywhere in the document, you can set this to .//.

expect_references: int | bool = 1#

Number of references to expect in the signature. If this is not 1, an array of VerifyResults is returned. If set to a non-integer, any number of references is accepted (otherwise a mismatch raises an error).

signature_methods: FrozenSet[SignatureMethod] = frozenset({SignatureMethod.DSA_SHA256, SignatureMethod.ECDSA_SHA224, SignatureMethod.ECDSA_SHA256, SignatureMethod.ECDSA_SHA384, SignatureMethod.ECDSA_SHA3_224, SignatureMethod.ECDSA_SHA3_256, SignatureMethod.ECDSA_SHA3_384, SignatureMethod.ECDSA_SHA3_512, SignatureMethod.ECDSA_SHA512, SignatureMethod.HMAC_SHA224, SignatureMethod.HMAC_SHA256, SignatureMethod.HMAC_SHA384, SignatureMethod.HMAC_SHA512, SignatureMethod.RSA_SHA224, SignatureMethod.RSA_SHA256, SignatureMethod.RSA_SHA384, SignatureMethod.RSA_SHA512, SignatureMethod.SHA224_RSA_MGF1, SignatureMethod.SHA256_RSA_MGF1, SignatureMethod.SHA384_RSA_MGF1, SignatureMethod.SHA3_224_RSA_MGF1, SignatureMethod.SHA3_256_RSA_MGF1, SignatureMethod.SHA3_384_RSA_MGF1, SignatureMethod.SHA3_512_RSA_MGF1, SignatureMethod.SHA512_RSA_MGF1})#

Set of acceptable signature methods (signature algorithms). Any signature generated using an algorithm not listed here will fail verification.

digest_algorithms: FrozenSet[DigestAlgorithm] = frozenset({DigestAlgorithm.SHA224, DigestAlgorithm.SHA256, DigestAlgorithm.SHA384, DigestAlgorithm.SHA3_224, DigestAlgorithm.SHA3_256, DigestAlgorithm.SHA3_384, DigestAlgorithm.SHA3_512, DigestAlgorithm.SHA512})#

Set of acceptable digest algorithms. Any signature or reference transform generated using an algorithm not listed here will cause verification to fail.

ignore_ambiguous_key_info: bool = False#

Ignore the presence of a KeyValue element when X509Data is present in the signature and used for verifying. The presence of both elements is an ambiguity and a security hazard. The public key used to sign the document is already encoded in the certificate (which is in X509Data), so the verifier must either ignore KeyValue or make sure it matches what’s in the certificate. SignXML does not implement the functionality necessary to match the keys, and throws an InvalidInput error instead. Set this to True to bypass the error and validate the signature using X509Data only.

class signxml.DigestAlgorithm(value)[source]#

An enumeration of digest algorithms supported by SignXML. See the Algorithm Identifiers and Implementation Requirements section of the XML Signature 1.1 standard for details.

SHA224 = 'http://www.w3.org/2001/04/xmldsig-more#sha224'#
SHA384 = 'http://www.w3.org/2001/04/xmldsig-more#sha384'#
SHA256 = 'http://www.w3.org/2001/04/xmlenc#sha256'#
SHA512 = 'http://www.w3.org/2001/04/xmlenc#sha512'#
SHA3_224 = 'http://www.w3.org/2007/05/xmldsig-more#sha3-224'#
SHA3_256 = 'http://www.w3.org/2007/05/xmldsig-more#sha3-256'#
SHA3_384 = 'http://www.w3.org/2007/05/xmldsig-more#sha3-384'#
SHA3_512 = 'http://www.w3.org/2007/05/xmldsig-more#sha3-512'#
SHA1 = 'http://www.w3.org/2000/09/xmldsig#sha1'#

See SHA1 deprecation.

property implementation: Callable#

The cryptography callable that implements the specified algorithm.

class signxml.SignatureMethod(value)[source]#

An enumeration of signature methods (also referred to as signature algorithms) supported by SignXML. See the Algorithm Identifiers and Implementation Requirements section of the XML Signature 1.1 standard for details.

RSA_SHA256 = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256'#

The RSASSA-PKCS1-v1_5 algorithm described in RFC 3447. This is the default, most widely supported signature method.

RSA_SHA224 = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha224'#
RSA_SHA384 = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha384'#
RSA_SHA512 = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha512'#
ECDSA_SHA224 = 'http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha224'#
ECDSA_SHA256 = 'http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256'#
ECDSA_SHA384 = 'http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha384'#
ECDSA_SHA512 = 'http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha512'#
ECDSA_SHA3_224 = 'http://www.w3.org/2021/04/xmldsig-more#ecdsa-sha3-224'#
ECDSA_SHA3_256 = 'http://www.w3.org/2021/04/xmldsig-more#ecdsa-sha3-256'#
ECDSA_SHA3_384 = 'http://www.w3.org/2021/04/xmldsig-more#ecdsa-sha3-384'#
ECDSA_SHA3_512 = 'http://www.w3.org/2021/04/xmldsig-more#ecdsa-sha3-512'#
DSA_SHA256 = 'http://www.w3.org/2009/xmldsig11#dsa-sha256'#
HMAC_SHA224 = 'http://www.w3.org/2001/04/xmldsig-more#hmac-sha224'#
HMAC_SHA256 = 'http://www.w3.org/2001/04/xmldsig-more#hmac-sha256'#
HMAC_SHA384 = 'http://www.w3.org/2001/04/xmldsig-more#hmac-sha384'#
HMAC_SHA512 = 'http://www.w3.org/2001/04/xmldsig-more#hmac-sha512'#
SHA3_224_RSA_MGF1 = 'http://www.w3.org/2007/05/xmldsig-more#sha3-224-rsa-MGF1'#
SHA3_256_RSA_MGF1 = 'http://www.w3.org/2007/05/xmldsig-more#sha3-256-rsa-MGF1'#
SHA3_384_RSA_MGF1 = 'http://www.w3.org/2007/05/xmldsig-more#sha3-384-rsa-MGF1'#
SHA3_512_RSA_MGF1 = 'http://www.w3.org/2007/05/xmldsig-more#sha3-512-rsa-MGF1'#
SHA224_RSA_MGF1 = 'http://www.w3.org/2007/05/xmldsig-more#sha224-rsa-MGF1'#
SHA256_RSA_MGF1 = 'http://www.w3.org/2007/05/xmldsig-more#sha256-rsa-MGF1'#
SHA384_RSA_MGF1 = 'http://www.w3.org/2007/05/xmldsig-more#sha384-rsa-MGF1'#
SHA512_RSA_MGF1 = 'http://www.w3.org/2007/05/xmldsig-more#sha512-rsa-MGF1'#
DSA_SHA1 = 'http://www.w3.org/2000/09/xmldsig#dsa-sha1'#

SHA1 deprecation: SHA1 based algorithms are not secure for use in digital signatures. They are included for legacy compatibility only and disabled by default. To verify SHA1 based signatures, use:

XMLVerifier().verify(
    expect_config=SignatureConfiguration(
        signature_methods=...,
        digest_algorithms=...
    )
)
HMAC_SHA1 = 'http://www.w3.org/2000/09/xmldsig#hmac-sha1'#

See SHA1 deprecation.

RSA_SHA1 = 'http://www.w3.org/2000/09/xmldsig#rsa-sha1'#

See SHA1 deprecation.

ECDSA_SHA1 = 'http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha1'#

See SHA1 deprecation.

SHA1_RSA_MGF1 = 'http://www.w3.org/2007/05/xmldsig-more#sha1-rsa-MGF1'#

See SHA1 deprecation.

class signxml.CanonicalizationMethod(value)[source]#

An enumeration of XML canonicalization methods (also referred to as canonicalization algorithms) supported by SignXML. See the Algorithm Identifiers and Implementation Requirements section of the XML Signature 1.1 standard for details.

CANONICAL_XML_1_0 = 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315'#
CANONICAL_XML_1_0_WITH_COMMENTS = 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments'#
CANONICAL_XML_1_1 = 'http://www.w3.org/2006/12/xml-c14n11'#
CANONICAL_XML_1_1_WITH_COMMENTS = 'http://www.w3.org/2006/12/xml-c14n11#WithComments'#
EXCLUSIVE_XML_CANONICALIZATION_1_0 = 'http://www.w3.org/2001/10/xml-exc-c14n#'#
EXCLUSIVE_XML_CANONICALIZATION_1_0_WITH_COMMENTS = 'http://www.w3.org/2001/10/xml-exc-c14n#WithComments'#
class signxml.SignatureConstructionMethod(value)[source]#

An enumeration of signature construction methods supported by SignXML, used to specify the method when signing. See the list of signature types under XML Signature Syntax and Processing Version 2.0, Definitions.

enveloped = 'http://www.w3.org/2000/09/xmldsig#enveloped-signature'#

The signature is over the XML content that contains the signature as an element. The content provides the root XML document element. This is the most common XML signature type in modern applications.

enveloping = 'enveloping-signature'#

The signature is over content found within an Object element of the signature itself. The Object (or its content) is identified via a Reference (via a URI fragment identifier or transform).

detached = 'detached-signature'#

The signature is over content external to the Signature element, and can be identified via a URI or transform. Consequently, the signature is “detached” from the content it signs. This definition typically applies to separate data objects, but it also includes the instance where the Signature and data object reside within the same XML document but are sibling elements.

exception signxml.InvalidCertificate[source]#

Raised when certificate validation fails.

exception signxml.InvalidDigest[source]#

Raised when digest validation fails (causing the signature to be untrusted).

exception signxml.InvalidInput[source]#
exception signxml.InvalidSignature[source]#

Raised when signature validation fails.

signxml.methods#

alias of SignatureConstructionMethod

XAdES API documentation#

XAdES (“XML Advanced Electronic Signatures”) is a standard for attaching metadata to XML Signature objects. This standard is endorsed by the European Union as the implementation for its eSignature regulations. While a W3C publication from 2003 exists on the standard, that page is out of date and further development was undertaken by ETSI. ETSI’s approach to standards document publication and versioning is best described as idiosyncratic, with many documents produced over time with confusing terminology and naming. Documents are only available as PDFs, and there is no apparent way to track all publications on a given standard. The most recent and straighforward description of the standard appears to be in the following two documents:

XAdES metadata is attached to the XML Signature object as sub-elements under the ds:Signature/ds:Object path. The elements required by each XAdES “level” (profile) are summarized in section 6.3 of the first document above, on pages 50-56.

In SignXML, use signxml.xades.XAdESSigner and signxml.xades.XAdESVerifier to sign and verify XAdES signatures, respectively. See XAdES Signatures for examples.

class signxml.xades.XAdESSigner(signature_policy=None, claimed_roles=None, data_object_format=None, **xml_signer_args)[source]#

Create a new XAdES Signature Signer object, which can be used to hold configuration information and sign multiple pieces of data. This is a subclass of signxml.XMLSigner; all of its configuration semantics are supported.

Parameters:
  • signature_policy (XAdESSignaturePolicy | None) – If you need your XAdES signature to carry the SignaturePolicyIdentifier element, use this parameter to pass a XAdESSignaturePolicy object carrying strings and the digest method identifier for the element.

  • claimed_roles (List | None) – If you need your XAdES signature to carry the SignerRole/ClaimedRoles element, use this parameter to pass a list of strings to use as text for the ClaimedRole tags.

  • data_object_format (XAdESDataObjectFormat | None) – If you need your XAdES signature to carry the DataObjectFormat element, use this parameter to pass a XAdESDataObjectFormat object carrying the Description and MimeType strings for the element.

  • xml_signer_args – Parameters to pass to the signxml.XMLSigner constructor.

sign(data, *, key=None, passphrase=None, cert=None, reference_uri=None, key_name=None, key_info=None, id_attribute=None, always_add_key_value=False, inclusive_ns_prefixes=None, signature_properties=None)#

Sign the data and return the root element of the resulting XML tree.

Parameters:
  • data (String, file-like object, or XML ElementTree Element API compatible object) – Data to sign

  • key (str | bytes | RSAPrivateKey | DSAPrivateKey | EllipticCurvePrivateKey | None) – Key to be used for signing. When signing with a certificate or RSA/DSA/ECDSA key, this can be a string/bytes containing a PEM-formatted key, or a cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey, cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKey, or cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateKey object. When signing with a HMAC, this should be a string containing the shared secret.

  • passphrase (bytes | None) – Passphrase to use to decrypt the key, if any.

  • cert (str | List[str] | List[X509] | None) – X.509 certificate to use for signing. This should be a string containing a PEM-formatted certificate, or an array of strings or OpenSSL.crypto.X509 objects containing the certificate and a chain of intermediate certificates.

  • reference_uri (str | List[str] | List[SignatureReference] | None) – Custom reference URI or list of reference URIs to incorporate into the signature. When method is set to detached or enveloped, reference URIs are set to this value and only the referenced elements are signed. To specify extra options specific to each reference URI, pass a list of one or more SignatureReference objects.

  • key_name (str | None) – Add a KeyName element in the KeyInfo element that may be used by the signer to communicate a key identifier to the recipient. Typically, KeyName contains an identifier related to the key pair used to sign the message.

  • key_info (_Element | None) – A custom KeyInfo element to insert in the signature. Use this to supply <wsse:SecurityTokenReference> or other custom key references. An example value can be found here: https://github.com/XML-Security/signxml/blob/master/test/wsse_keyinfo.xml

  • id_attribute (str | None) – Name of the attribute whose value URI refers to. By default, SignXML will search for “Id”, then “ID”.

  • always_add_key_value (bool) – Write the key value to the KeyInfo element even if a X509 certificate is present. Use of this parameter is discouraged, as it introduces an ambiguity and a security hazard. The public key used to sign the document is already encoded in the certificate (which is in X509Data), so the verifier must either ignore KeyValue or make sure it matches what’s in the certificate. This parameter is provided for compatibility purposes only.

  • inclusive_ns_prefixes (List[str] | None) –

    Provide a list of XML namespace prefixes whose declarations should be preserved when canonicalizing the signature (InclusiveNamespaces PrefixList).

    To specify this value separately for reference canonicalizaition, pass a list of one or more SignatureReference objects as the reference_uri keyword argument, and set the inclusive_ns_prefixes attribute on those objects.

  • signature_properties (_Element | List[_Element] | None) – One or more Elements that are to be included in the SignatureProperies section when using the detached method.

Returns:

A lxml.etree._Element object representing the root of the XML tree containing the signature and the payload data.

Return type:

_Element

To specify the location of an enveloped signature within data, insert a <ds:Signature Id="placeholder"></ds:Signature> 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.

add_signing_time(signed_signature_properties, sig_root, signing_settings)[source]#
add_signing_certificate(signed_signature_properties, sig_root, signing_settings)[source]#
add_signature_policy_identifier(signed_signature_properties, sig_root, signing_settings)[source]#
add_signature_production_place(signed_signature_properties, sig_root, signing_settings)[source]#
add_signer_role(signed_signature_properties, sig_root, signing_settings)[source]#
add_data_object_format(signed_data_object_properties, sig_root, signing_settings)[source]#
class signxml.xades.XAdESDataObjectFormat(Description: str = 'Default XAdES payload description', MimeType: str = 'text/xml')[source]#
Description: str = 'Default XAdES payload description'#
MimeType: str = 'text/xml'#
class signxml.xades.XAdESSignaturePolicy(Identifier: str, Description: str, DigestMethod: signxml.algorithms.DigestAlgorithm, DigestValue: str)[source]#
Identifier: str#
Description: str#
DigestMethod: DigestAlgorithm#
DigestValue: str#
class signxml.xades.XAdESVerifier[source]#

Create a new XAdES Signature Verifier object, which can be used to verify multiple pieces of data.

verify(data, *, expect_signature_policy=None, expect_config=XAdESSignatureConfiguration(require_x509=True, location='.//', expect_references=3, signature_methods=frozenset({SignatureMethod.DSA_SHA256, SignatureMethod.RSA_SHA224, SignatureMethod.ECDSA_SHA3_224, SignatureMethod.HMAC_SHA384, SignatureMethod.SHA512_RSA_MGF1, SignatureMethod.ECDSA_SHA3_256, SignatureMethod.SHA3_256_RSA_MGF1, SignatureMethod.SHA3_224_RSA_MGF1, SignatureMethod.ECDSA_SHA3_384, SignatureMethod.HMAC_SHA512, SignatureMethod.SHA3_384_RSA_MGF1, SignatureMethod.SHA3_512_RSA_MGF1, SignatureMethod.HMAC_SHA256, SignatureMethod.ECDSA_SHA224, SignatureMethod.ECDSA_SHA512, SignatureMethod.ECDSA_SHA3_512, SignatureMethod.RSA_SHA512, SignatureMethod.RSA_SHA256, SignatureMethod.HMAC_SHA224, SignatureMethod.SHA224_RSA_MGF1, SignatureMethod.SHA384_RSA_MGF1, SignatureMethod.ECDSA_SHA256, SignatureMethod.RSA_SHA384, SignatureMethod.ECDSA_SHA384, SignatureMethod.SHA256_RSA_MGF1}), digest_algorithms=frozenset({DigestAlgorithm.SHA512, DigestAlgorithm.SHA224, DigestAlgorithm.SHA384, DigestAlgorithm.SHA3_384, DigestAlgorithm.SHA3_256, DigestAlgorithm.SHA3_224, DigestAlgorithm.SHA256, DigestAlgorithm.SHA3_512}), ignore_ambiguous_key_info=False), **xml_verifier_args)[source]#

Verify the XAdES signature supplied in the data and return a list of XAdESVerifyResult data structures representing the data signed by the signature, or raise an exception if the signature is not valid. This method is a wrapper around signxml.XMLVerifier.verify(); see its documentation for more details and arguments it supports.

Parameters:
  • expect_signature_policy (XAdESSignaturePolicy | None) – If you need to assert that the verified XAdES signature carries specific data in the SignaturePolicyIdentifier element, use this parameter to pass a XAdESSignaturePolicy object carrying strings and the digest method identifier for the element.

  • expect_config (XAdESSignatureConfiguration) – Expected signature configuration. Pass a XAdESSignatureConfiguration object to describe expected properties of the verified signature. Signatures with unexpected configurations will fail validation.

  • xml_verifier_args – Parameters to pass to signxml.XMLVerifier.verify().

Return type:

List[XAdESVerifyResult]

class signxml.xades.XAdESVerifyResult(signed_data, signed_xml, signature_xml, signed_properties)[source]#

A subclass of signxml.VerifyResult. See VerifyResult for attribute semantics not covered here.

signed_properties: _Element#

The XAdES SignedProperties element that was verified as signed by the signature

class signxml.xades.XAdESSignatureConfiguration(require_x509=True, location='.//', expect_references=3, signature_methods=frozenset({SignatureMethod.DSA_SHA256, SignatureMethod.ECDSA_SHA224, SignatureMethod.ECDSA_SHA256, SignatureMethod.ECDSA_SHA384, SignatureMethod.ECDSA_SHA3_224, SignatureMethod.ECDSA_SHA3_256, SignatureMethod.ECDSA_SHA3_384, SignatureMethod.ECDSA_SHA3_512, SignatureMethod.ECDSA_SHA512, SignatureMethod.HMAC_SHA224, SignatureMethod.HMAC_SHA256, SignatureMethod.HMAC_SHA384, SignatureMethod.HMAC_SHA512, SignatureMethod.RSA_SHA224, SignatureMethod.RSA_SHA256, SignatureMethod.RSA_SHA384, SignatureMethod.RSA_SHA512, SignatureMethod.SHA224_RSA_MGF1, SignatureMethod.SHA256_RSA_MGF1, SignatureMethod.SHA384_RSA_MGF1, SignatureMethod.SHA3_224_RSA_MGF1, SignatureMethod.SHA3_256_RSA_MGF1, SignatureMethod.SHA3_384_RSA_MGF1, SignatureMethod.SHA3_512_RSA_MGF1, SignatureMethod.SHA512_RSA_MGF1}), digest_algorithms=frozenset({DigestAlgorithm.SHA224, DigestAlgorithm.SHA256, DigestAlgorithm.SHA384, DigestAlgorithm.SHA3_224, DigestAlgorithm.SHA3_256, DigestAlgorithm.SHA3_384, DigestAlgorithm.SHA3_512, DigestAlgorithm.SHA512}), ignore_ambiguous_key_info=False)[source]#

A subclass of signxml.SignatureConfiguration, with default overrides as described below.

expect_references: int | bool = 3#

By default, XAdES signatures carry 3 references (the original data reference, the KeyInfo (X.509 certificate) reference, and the signed properties reference). Signatures can carry more references if more data or extensions are present. Specify the expected number of references here.

Change log#