Python XML Security Library Bindings

1.3.17 · active · verified Thu Apr 09

The `xmlsec` library provides Python bindings for the XML Security Library, enabling XML digital signatures, encryption, and other security operations on XML documents. It is actively maintained with frequent updates, often focused on ensuring compatibility with specific versions of the underlying `lxml` and `libxml2` libraries. The current version is 1.3.17.

Warnings

Install

Imports

Quickstart

This quickstart demonstrates how to digitally sign an XML document and then verify its signature using `xmlsec` and `lxml`. It involves creating an XML structure, adding a signature template, loading a private key and certificate, signing the document, and finally verifying the signature. Make sure to replace `private_key.pem` and `certificate.pem` with your actual key and certificate files in a production environment.

import xmlsec
from lxml import etree
import os

# Initialize xmlsec library
xmlsec.init()

# Define paths for key and certificate files
# In a real application, replace these with your actual key and cert paths.
# For this example to run, ensure these files exist or create dummy ones:
# Example: openssl genrsa -out private_key.pem 2048
# Example: openssl req -new -x509 -key private_key.pem -out certificate.pem -days 365
key_file = os.environ.get('XMLSEC_PRIVATE_KEY_PATH', 'private_key.pem')
cert_file = os.environ.get('XMLSEC_CERTIFICATE_PATH', 'certificate.pem')

# Basic check for dummy files for quickstart execution
if not os.path.exists(key_file) or not os.path.exists(cert_file):
    print(f"Warning: '{key_file}' and '{cert_file}' not found. "
          "Please generate dummy key/cert files for this quickstart to run.")
    # Minimal dummy content for illustration, DO NOT USE IN PRODUCTION
    with open(key_file, 'w') as f: f.write("-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n")
    with open(cert_file, 'w') as f: f.write("-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----\n")

try:
    # Create an XML document using lxml
    root = etree.Element("Data")
    etree.SubElement(root, "Item", id="item1").text = "Value1"
    
    # Add a signature template to the root element
    signature_node = xmlsec.template.add_signature(root, xmlsec.constants.TransformExclC14N)
    
    # Add SignedInfo element, reference the entire document
    signed_info_node = xmlsec.template.ensure_signed_info(signature_node, 
                                                            xmlsec.constants.TransformExclC14N, 
                                                            xmlsec.constants.TransformRsaSha1)
    xmlsec.template.add_reference(signed_info_node, xmlsec.constants.TransformSha1, uri="#xpointer(/)")
    
    # Add KeyInfo element with certificate
    key_info_node = xmlsec.template.ensure_key_info(signature_node)
    xmlsec.template.add_x509_data(key_info_node)
    xmlsec.template.add_x509_certificate(key_info_node) # Include the certificate itself
    
    # Create a KeysManager and load the private key for signing
    manager = xmlsec.KeysManager()
    signing_key = xmlsec.Key.from_file(key_file, xmlsec.KeyFormatPEM)
    # Add the certificate to the key object for inclusion in KeyInfo
    signing_key.add_cert_from_file(cert_file, xmlsec.KeyFormatPEM)
    manager.add_key(signing_key)

    # Create a SignatureContext and set the signing key
    ctx = xmlsec.SignatureContext(manager)
    ctx.key = signing_key
    
    # Sign the XML document
    print("Signing XML document...")
    ctx.sign(signature_node)
    
    signed_xml_str = etree.tostring(root, pretty_print=True, encoding='unicode')
    print("Signed XML:\n", signed_xml_str)

    # Verify the signature
    print("\nVerifying signature...")
    verify_ctx = xmlsec.SignatureContext(manager) # Use the same manager with loaded key/cert
    
    if verify_ctx.verify(signature_node):
        print("Signature is valid!")
    else:
        print("Signature verification FAILED.")

finally:
    # Shutdown xmlsec library
    xmlsec.shutdown()

view raw JSON →