Skip to main content

pybergshamra

Python bindings for the Bergshamra XML Security library -- a pure-Rust implementation of XML Digital Signatures (XML-DSig), XML Encryption (XML-Enc), C14N canonicalization, and cryptographic primitives.

pybergshamra gives you a fast, correct, and memory-safe XML security toolkit from Python with no C dependencies to compile and no transitive native libraries to audit.

Version 0.9.2 (2026-09-28) uses Bergshamra 0.9.2 and Kryptering 0.6.0 from crates.io, with tsp-ltv 0.5.0 for certificate validation.

Features

  • XML Digital Signatures -- sign and verify (RSA, EC, Ed25519, HMAC, post-quantum)
  • XML Encryption -- encrypt and decrypt (AES-CBC/GCM, RSA-OAEP key transport)
  • C14N canonicalization -- inclusive, exclusive, with/without comments
  • Key management -- RSA, EC, Ed25519, X25519, HMAC, AES, 3DES, PKCS#12, X.509
  • Certificate validation -- X.509 chain building and verification with CRL support
  • Cryptographic primitives -- digest, PBKDF2, HKDF, ConcatKDF
  • Post-quantum signatures -- ML-DSA-44/65/87, SLH-DSA
  • HSM / PKCS#11 -- sign, verify, encrypt and decrypt with keys that never leave a hardware token (or SoftHSM2)
  • Anti-XSW protection -- strict verification mode
  • Zero Python dependencies -- ships as a single native extension

Security note: weak-digest X.509 policy

Starting with Bergshamra 0.5.x, X.509 certificate chains signed with weak digests (MD5, SHA-1, SHA-224) are rejected by default. pybergshamra is built with Bergshamra's legacy-algorithms feature enabled, so validate_cert_chain() and signature verification that builds an X.509 chain accept these legacy digests for backward compatibility with existing certificates. The policy is fixed at build time -- there is no per-call runtime toggle. To get strict, secure-by-default rejection of weak digests, build the extension yourself with the legacy-algorithms feature removed from the bergshamra-keys dependency in Cargo.toml.

PBKDF2 also now enforces the RFC 8018 minimum salt length of 8 bytes; shorter salts raise CryptoError.

Installation

python3 -m pip install pybergshamra

Or with uv:

uv add pybergshamra

Wheels are compiled from Rust via maturin. Python 3.10+ is required.

Quick start

Verify a signed XML document

import pybergshamra

xml = open("signed.xml").read()

manager = pybergshamra.KeysManager()
key = pybergshamra.load_x509_cert_pem(open("cert.pem", "rb").read())
manager.add_key(key)

ctx = pybergshamra.DsigContext(manager)
result = pybergshamra.verify(ctx, xml)

if result:
    print("Valid!", result.key_info.algorithm)
else:
    print("Invalid:", result.reason)

Sign an XML template

import pybergshamra

template = open("sign-template.xml").read()

manager = pybergshamra.KeysManager()
key = pybergshamra.load_rsa_private_pem(open("rsakey.pem", "rb").read())
manager.add_key(key)

ctx = pybergshamra.DsigContext(manager)
signed_xml = pybergshamra.sign(ctx, template)

Encrypt and decrypt

import pybergshamra

# Encrypt
manager = pybergshamra.KeysManager()
key = pybergshamra.load_x509_cert_pem(open("cert.pem", "rb").read())
manager.add_key(key)

ctx = pybergshamra.EncContext(manager)
encrypted_xml = pybergshamra.encrypt(ctx, template_xml, b"secret data")

# Decrypt
manager = pybergshamra.KeysManager()
key = pybergshamra.load_rsa_private_pem(open("rsakey.pem", "rb").read())
manager.add_key(key)

ctx = pybergshamra.EncContext(manager)
decrypted_xml = pybergshamra.decrypt(ctx, encrypted_xml)

Canonicalize XML

import pybergshamra
from pybergshamra import C14nMode

result = pybergshamra.canonicalize(xml_string, C14nMode.Exclusive)

Compute a digest

from pybergshamra import digest, Algorithm

h = digest(Algorithm.SHA256, b"hello world")
print(h.hex())

Sign with a key on an HSM (PKCS#11)

Key material stays on the token; pybergshamra talks to it over PKCS#11 (tested against SoftHSM2). Algorithms are given as W3C URIs from Algorithm; ECDSA also needs an ec_curve because the URI does not encode the curve.

Starting with 0.9.2, opening a session rejects an existing token login. Reuse the authenticated session for multiple operations, or close all sessions and operation objects before logging in again.

import pybergshamra
from pybergshamra import Algorithm

provider = pybergshamra.Pkcs11Provider.with_token(
    "/usr/lib/softhsm/libsofthsm2.so",
    "production-signing-token",
    token_serial="11429933786539",  # optional when the label is unique
)
session = provider.open_session("1234")  # user PIN

# Sign an XML template with an RSA key on the token
manager = pybergshamra.KeysManager()
sign_ctx = pybergshamra.DsigContext(manager)
sign_ctx.set_hsm_signer(
    pybergshamra.Pkcs11Signer(session, "my-rsa-key", Algorithm.RSA_SHA256)
)
signed_xml = pybergshamra.sign(sign_ctx, template_xml)

# Verify with the matching public key on the token
verify_ctx = pybergshamra.DsigContext(manager)
verify_ctx.set_hsm_verifier(
    pybergshamra.Pkcs11Verifier(session, "my-rsa-key", Algorithm.RSA_SHA256)
)
assert bool(pybergshamra.verify(verify_ctx, signed_xml))

Use Pkcs11Provider.with_slot_id(module, slot_id) when the deployment pins slots directly. The plain Pkcs11Provider(module) constructor remains available for single-token deployments and fails closed if multiple initialized tokens are visible. provider.slot_id reports the selected slot.

EncContext exposes the same idea for encryption via set_hsm_decryptor(), set_hsm_key_unwrapper(), set_hsm_encryptor(), and set_hsm_key_wrapper(), each taking an allow-list of permitted algorithm URIs. The HSM operation classes (Pkcs11Signer, Pkcs11Verifier, Pkcs11Decryptor, Pkcs11Encryptor, Pkcs11KeyWrapper) also expose direct sign()/verify()/decrypt()/ encrypt()/wrap()/unwrap() methods for standalone use.

Run bash hsm-test/setup.sh to provision a local SoftHSM2 token, then SOFTHSM2_CONF=hsm-test/softhsm2.local.conf pytest tests/test_hsm.py to exercise the PKCS#11 path. The CI hsm job does the same on every PR.

API overview

Class / function Purpose
Algorithm W3C XML Security algorithm URI constants
Key A cryptographic key (RSA, EC, HMAC, AES, Ed25519, etc.)
KeyUsage Key usage mode (Sign, Verify, Encrypt, Decrypt, Any)
KeysManager() Key store for managing keys and certificates
DsigContext(manager) Configuration for XML-DSig sign/verify
EncContext(manager) Configuration for XML-Enc encrypt/decrypt
C14nMode Canonicalization mode (Inclusive, Exclusive, etc.)
VerifyResult Result of signature verification
verify(ctx, xml) Verify the first <Signature> in document order
verify_document(ctx, document) Verify a pyuppsala.Document through owned XML
verify_all(ctx, xml) Verify every <Signature> in document order
verify_all_document(ctx, document) Verify every signature in a pyuppsala.Document
sign(ctx, template) Sign an XML template
sign_document(ctx, document) Sign a template in a pyuppsala.Document in place
sign_enveloped(ctx, xml, ...) Build and sign an enveloped <Signature> in one step
sign_enveloped_document(ctx, document, ...) Build and sign in a pyuppsala.Document in place
encrypt(ctx, template, data) Encrypt data with an XML template
decrypt(ctx, xml) Decrypt an XML document
canonicalize(xml, mode) Canonicalize an XML document
digest(uri, data) Compute a message digest
validate_cert_chain(...) Validate an X.509 certificate chain
parse_pkcs12(data, password) Parse a PKCS#12 container into raw keys + certs
Pkcs11Provider / Pkcs11Session Load a PKCS#11 module and open a token session
Pkcs11Signer / Pkcs11Verifier HSM-backed XML-DSig signing / verification
Pkcs11Decryptor / Pkcs11Encryptor / Pkcs11KeyWrapper HSM-backed XML-Enc key transport / key wrap

The *_document APIs require pyuppsala 0.11.0 or newer. They serialize at the Python-extension boundary and safely import successful signing results back into the original document, including a preserved DOCTYPE; no Rust DOM pointers cross shared libraries. Install both packages with pip install 'pybergshamra[documents]'.

DsigContext(manager) uses secure defaults (trusted_keys_only, strict_verification, hmac_min_out_len=160, and required local reference digests) recommended for federated identity. Use DsigContext(manager, secure_defaults=False) or DsigContext.permissive(manager) only when inline KeyInfo and relaxed structure checks are intentional. Each VerifiedReference now also reports digest_verified so callers can tell whether a reference's digest was actually checked. | load_key_file(path) | Load a key from file (auto-detect format) | | load_rsa_private_pem(data) | Load an RSA private key from PEM | | load_x509_cert_pem(data) | Load an X.509 certificate from PEM | | load_hmac_key(data) | Create an HMAC key from raw bytes | | load_aes_key(data) | Create an AES key from raw bytes | | load_pem_auto(data) | Auto-detect PEM type and load |

See the full API reference for all 28 key loaders, algorithm constants, and configuration options.

Exceptions

Exception Raised when
BergshamraError Base exception for all errors
XmlError XML parsing or structure error
CryptoError Cryptographic operation failure
KeyLoadError Key loading failure
AlgorithmError Unsupported algorithm
EncryptionError Encryption/decryption failure
CertificateError Certificate validation failure

All exceptions inherit from BergshamraError, which inherits from Exception.

Migrating from python-xmlsec

pybergshamra (together with pyuppsala for XML building) is a complete replacement for python-xmlsec with zero C dependencies. See the migration guide for side-by-side examples.

Type stubs

A pybergshamra.pyi file is included for full IDE auto-completion and type-checking with mypy/pyright.

Development

# Clone the repository
git clone https://github.com/kushaldas/pybergshamra.git
cd pybergshamra

# Set up the environment with uv
uv sync

# Build the native extension in development mode
uv run maturin develop

# Run the test suite
uv run pytest

# Build a release wheel
uv run maturin build --release

License

BSD-2-Clause

Metadata

Release files for pybergshamra 0.9.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pybergshamra 0.9.2
File Size Uploaded Provenance
pybergshamra-0.9.2.tar.gz 109.2 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for pybergshamra 0.9.2
File Interpreter ABI Platform
pybergshamra-0.9.2-cp310-abi3-manylinux_2_28_x86_64.whl CPython 3.10 abi3 Linux glibc 2.28+ x86-64 Details

Total release size: 2.5 MB

Release files / pybergshamra-0.9.2.tar.gz

Download URL pybergshamra-0.9.2.tar.gz
Size 109.2 kB
Tags Source
SHA-256 checksum
How to use checksums
47a4f1a03f1a1c149fe1b406b143904087987e40e9a9f67a767f05586701d5bf
BLAKE2b-256 checksum
How to use checksums
c8a123b3cd559d9277f8e60f5f2137b73dbe5e83fdd823b7abcb6eb48d7cc88a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 28, 2026.

Transparency log

Release files / pybergshamra-0.9.2-cp310-abi3-manylinux_2_28_x86_64.whl

Download URL pybergshamra-0.9.2-cp310-abi3-manylinux_2_28_x86_64.whl
Size 2.4 MB
Tags CPython 3.10 Linux glibc 2.28+ x86-64 abi3
SHA-256 checksum
How to use checksums
88d4fc557a6e402c2dbc35b55fc40aa2a7e32ce196204b766cea2122cc0cbdbf
BLAKE2b-256 checksum
How to use checksums
e2a6dcf3a22b35628c14f179d8c8132205fbccc976df772a7ebb360a99446d0a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 28, 2026.

Transparency log

Security for pybergshamra 0.9.2

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for pybergshamra-0.9.2.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 28, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page