signxml

4.4.0 · active · verified Fri Apr 10

signxml is a Python library that implements the W3C XML Signature standard (XMLDSig), used for payload security in standards like SAML 2.0, XAdES, EBICS, and WS-Security. It provides features for signing and verifying XML documents, including support for X.509 certificate chains and XAdES signatures. The library is actively maintained with regular releases, supporting modern Python versions (3.9-3.13+).

Warnings

Install

Imports

Quickstart

This quickstart demonstrates basic XML signing and verification using `XMLSigner` and `XMLVerifier`. It includes placeholder instructions for generating a test certificate and key using OpenSSL. In production, always load certificates and keys securely and explicitly configure trust for verification. It also highlights the best practice of verifying the `signed_xml` attribute and asserting the signature's expected location.

from lxml import etree
from signxml import XMLSigner, XMLVerifier, SignatureConfiguration
import os

# --- Setup: Generate test certificate and key (requires OpenSSL) ---
# openssl req -x509 -nodes -subj "/CN=test" -days 1 -newkey rsa -keyout privkey.pem -out cert.pem
# In a real application, you would load these from secure storage.

# Ensure cert.pem and privkey.pem exist in the current directory for this example to run.
if not (os.path.exists('cert.pem') and os.path.exists('privkey.pem')):
    print("Please generate 'cert.pem' and 'privkey.pem' using OpenSSL as described in the comments.")
    exit()

cert = open("cert.pem").read()
key = open("privkey.pem").read()

# --- Signing an XML document ---
data_to_sign = "<Test><Data>Hello World!</Data></Test>"
root = etree.fromstring(data_to_sign)

signer = XMLSigner()
signed_root = signer.sign(root, key=key, cert=cert)

print("\n--- Signed XML ---")
print(etree.tostring(signed_root, pretty_print=True).decode())

# --- Verifying the signed XML document ---
verifier = XMLVerifier()

try:
    # It's crucial to explicitly provide the trusted certificate or CA for verification
    # and to ensure the returned data is what was expected to prevent signature wrapping attacks.
    verified_data = verifier.verify(signed_root, x509_cert=cert).signed_xml
    
    print("\n--- Verification Successful! ---")
    print("Signed data content:", etree.tostring(verified_data, pretty_print=False).decode())
    
    # Optionally, assert the signature location (best practice for SAML etc.)
    config = SignatureConfiguration(location='./')
    verifier.verify(signed_root, x509_cert=cert, expect_config=config)
    print("Signature location asserted successfully.")

except Exception as e:
    print(f"\n--- Verification Failed: {e} ---")

view raw JSON →