12 releases
| new 0.2.2 | May 9, 2026 |
|---|---|
| 0.2.1 | May 2, 2026 |
| 0.1.12 | Apr 30, 2026 |
| 0.1.1 | Mar 23, 2026 |
#2132 in Cryptography
7.5MB
62K
SLoC
synta-python
Table of Contents generated with DocToc
Python extension module crate for the synta ASN.1 library.
Overview
This crate builds the _synta native extension module using PyO3 and
maturin. It exposes the synta ASN.1 encoder/decoder and the
synta-certificate X.509 parser to Python 3.8+ through a low-overhead Rust-native API.
The resulting module is imported as synta._synta and re-exported through the synta
Python package. Two companion cdylib crates provide subsystem modules:
synta-python-krb5→_krb5.abi3.so(registerssynta.krb5andsynta.spnego)synta-python-mtc→_mtc.abi3.so(registerssynta.mtc)
End-users should refer to python/README.md and docs/python/src/introduction.md for usage documentation.
Module Structure
| Source file | Contents |
|---|---|
src/lib.rs |
Module registration, Encoding enum, pem_to_der, der_to_pem, top-level exports |
src/decoder.rs |
Decoder class wrapping synta::Decoder; includes decode_any_str() |
src/encoder.rs |
Encoder class wrapping synta::Encoder |
src/types.rs |
Python wrappers for all ASN.1 primitive types |
src/error.rs |
SyntaError Python exception (defined in _synta only) |
src/certificate.rs |
PKI types: ObjectIdentifier, Certificate, CertificationRequest, CertificateList, OCSPResponse, PKCS loaders, synta.oids / synta.oids.attr submodules |
src/x509_verification.rs |
synta.x509 submodule: TrustStore, VerificationPolicy, X509VerificationError, verify_server_certificate, verify_client_certificate |
src/certificate/pkixalgs.rs |
synta.pkixalgs submodule: DssParms, DssSigValue, EcdsaSigValue, ECParameters, DSA/DH/EC/ECDSA OID constants (RFC 3279) |
src/certificate/ac.rs |
synta.ac submodule: AttributeCertificate, RFC 5755 extension and attribute-type OID constants |
src/certificate/crmf.rs |
synta.crmf submodule: CertReqMessages, CertReqMsg, registration-control OID constants (RFC 4211) |
src/certificate/cmp.rs |
synta.cmp submodule: CMPMessage, MAC algorithm and key-purpose OID constants (RFC 9810) |
src/crypto.rs |
synta.crypto submodule: HMAC, PBKDF2, AES-CBC, AES-GCM, 3DES-CBC, PKCS#7 padding, Fernet, HKDF, streaming HMAC, OTP |
Kerberos and SPNEGO types (Krb5PrincipalName, PKINIT classes, NT_*/ETYPE_* constants,
NegTokenInit, etc.) live in the companion crate synta-python-krb5. Merkle Tree
Certificate types live in synta-python-mtc.
All _synta PyO3 bindings live in synta-python. The synta-certificate and
synta-x509-verification Rust library crates have no PyO3 dependency; their types are
wrapped in src/certificate.rs and src/x509_verification.rs respectively.
Python module hierarchy
synta top-level module (_synta extension)
├── Encoding enum: DER / BER / CER
├── SyntaError exception
├── Decoder / Encoder streaming ASN.1 codec
├── Integer, OctetString, BitString, Boolean, Real, Null
├── UtcTime, GeneralizedTime
├── Utf8String, PrintableString, IA5String, NumericString,
│ TeletexString, VisibleString, GeneralString,
│ UniversalString, BmpString
├── TaggedElement, RawElement
├── ObjectIdentifier OID type (from synta-certificate)
├── Certificate, CertificationRequest,
│ CertificateList, OCSPResponse
├── load_der_pkcs7_certificates, load_pem_pkcs7_certificates,
│ load_pkcs12_certificates, load_pkcs12_keys, load_pkcs12,
│ read_pki_blocks, create_pkcs12
├── PrivateKey private key (PKCS#8); from_der, to_der, to_pkcs8_encrypted, from_pkcs8_encrypted
├── CertificateBuilder build and sign DER certificates
├── CsrBuilder build and sign PKCS#10 CSR DER
├── parse_general_names parse SEQUENCE OF GeneralName → list[tuple[int, bytes]]
├── parse_name_attrs parse Name DER → list[tuple[str, str]]
├── pem_to_der, der_to_pem
├── synta.general_name GeneralName tag constants
│ ├── OTHER_NAME (0), RFC822_NAME (1), DNS_NAME (2), X400_ADDRESS (3)
│ ├── DIRECTORY_NAME (4), EDI_PARTY_NAME (5), URI (6)
│ └── IP_ADDRESS (7), REGISTERED_ID (8)
├── synta.krb5 Kerberos V5 / PKINIT submodule [_krb5.abi3.so]
│ ├── Krb5PrincipalName
│ ├── EncryptionKey, Checksum, KDFAlgorithmId
│ ├── IssuerAndSerialNumber, ExternalPrincipalIdentifier
│ ├── PKAuthenticator, AuthPack, PaPkAsReq
│ ├── DHRepInfo, KDCDHKeyInfo, ReplyKeyPack, PaPkAsRep
│ ├── KRB5_PRINCIPAL_NAME_OID
│ └── NT_UNKNOWN … NT_SRV_HST_DOMAIN
├── synta.spnego GSSAPI SPNEGO submodule [_krb5.abi3.so]
│ ├── NegTokenInit, NegTokenResp, NegotiationToken
│ ├── NEG_STATE_* constants
│ └── SPNEGO_OID
├── synta.mtc Merkle Tree Certificates submodule [_mtc.abi3.so]
│ ├── ProofNode, Subtree, SubtreeProof, InclusionProof
│ ├── LogID, CosignerID, Checkpoint, SubtreeSignature
│ ├── TbsCertificateLogEntry, MerkleTreeCertEntry
│ └── LandmarkID, StandaloneCertificate, LandmarkCertificate
├── synta.pkixalgs RFC 3279 algorithm parameter types
│ ├── DssParms, DssSigValue, EcdsaSigValue
│ ├── ECParameters (namedCurve / ecParameters / implicitlyCA)
│ └── DSA, DH, EC, ECDSA, named-curve OID constants
├── synta.ac RFC 5755 Attribute Certificate v2
│ ├── AttributeCertificate
│ └── RFC 5755 extension and attribute-type OID constants
├── synta.crmf RFC 4211 Certificate Request Message Format
│ ├── CertReqMessages, CertReqMsg
│ └── Registration-control OID constants
├── synta.cmp RFC 9810 Certificate Management Protocol v3
│ ├── CMPMessage
│ └── MAC algorithm and key-purpose OID constants
├── synta.cms CMS (RFC 5652) and CMS-KEM (RFC 9629) types
│ ├── ContentInfo parse DER ContentInfo wrapper
│ ├── SignedData, SignerInfo signed-data inspection
│ ├── EnvelopedData encrypted-for-recipients data; .create(plaintext, recipients)
│ ├── EnvelopedDataBuilder chainable builder
│ ├── EncryptedData symmetric encrypted data
│ ├── DigestedData, AuthenticatedData
│ ├── IssuerAndSerialNumber, KEMRecipientInfo, CMSORIforKEMOtherInfo
│ └── ID_DATA, ID_SIGNED_DATA, ID_ENVELOPED_DATA, …
├── synta.crypto symmetric cryptography primitives
│ ├── Fernet authenticated encryption (AES-128-CBC + HMAC-SHA256)
│ ├── HmacDigest incremental HMAC computation
│ ├── hmac_digest, hmac_verify — one-shot HMAC
│ ├── pbkdf2_hmac PBKDF2 key derivation
│ ├── aes_cbc_encrypt, aes_cbc_decrypt — AES-CBC
│ ├── aes_gcm_encrypt, aes_gcm_decrypt — AES-GCM (AEAD; 12-byte nonce, 16-byte tag)
│ ├── des3_cbc_encrypt, des3_cbc_decrypt — 3DES-EDE-CBC
│ ├── pkcs7_pad, pkcs7_unpad — PKCS#7 block padding helpers
│ └── hkdf_extract, hkdf_expand — HKDF (RFC 5869)
├── synta.x509 RFC 5280 / CABF X.509 certificate chain verification
│ ├── TrustStore trusted root CA store
│ ├── VerificationPolicy validation parameters (names, profile, time, depth, OCSP)
│ ├── OcspStore OCSP response cache for revocation checking
│ ├── X509VerificationError raised on chain or policy failure
│ ├── verify_server_certificate(leaf, intermediates, store, policy) → list[bytes]
│ └── verify_client_certificate(leaf, intermediates, store, policy) → list[bytes]
└── synta.oids well-known OID constants
├── ML_DSA_44/65/87, ML_KEM_512/768/1024
├── SLH_DSA_SHA2_*/SHAKE_* (12 variants)
├── ED25519, ED448
├── RSA_ENCRYPTION, SHA*_WITH_RSA, RSA
├── EC_PUBLIC_KEY, ECDSA_WITH_SHA*, ECDSA, EC_CURVE_*
├── SHA224/256/384/512, SHA512_224/256
├── SHA3_224/256/384/512, SHAKE128/256
├── SUBJECT_KEY_IDENTIFIER, KEY_USAGE, SUBJECT_ALT_NAME, …
├── KP_SERVER_AUTH, KP_CLIENT_AUTH, …
├── PKINIT_SAN, PKINIT_KP_CLIENT_AUTH, …
├── MS_SAN_UPN, MS_CERTIFICATE_TEMPLATE, …
├── PKCS9_EMAIL_ADDRESS, PKCS9_CONTENT_TYPE, …
├── identify_signature_algorithm(oid) -> str
├── identify_public_key_algorithm(oid) -> str | None
├── ec_curve_short_name(oid) -> str | None
└── synta.oids.attr DN attribute OIDs
└── COMMON_NAME, COUNTRY, STATE, LOCALITY, ORGANIZATION, …
Building
The primary extension module is built with maturin. The workspace pyproject.toml points to this
crate automatically.
# Install maturin (once)
pip install maturin
# Development install into active virtualenv
maturin develop
# Build release wheel
maturin build --release
# Install built wheel
pip install target/wheels/synta-*.whl
To build the subsystem modules for local development (run after maturin develop):
EXT=$(python3 -c "import sysconfig; print(sysconfig.get_config_var('EXT_SUFFIX'))")
cargo build --release -p synta-python-krb5 --features openssl
cp target/release/lib_krb5.so "python/synta/_krb5${EXT}"
cargo build --release -p synta-python-mtc --features openssl
cp target/release/lib_mtc.so "python/synta/_mtc${EXT}"
Requirements:
- Rust toolchain (1.70 or later)
- Python 3.8 or later (abi3 stable ABI; compatible with CPython 3.8–3.14+)
- maturin 1.x
Testing
# Run the Python test suite from the workspace root
python -m pytest tests/python/
# Or via the CI helper script (builds all three modules automatically)
./contrib/ci/local-ci.sh python-test
Dependencies
| Crate | Role |
|---|---|
synta |
Core ASN.1 encoder/decoder |
synta-certificate |
X.509 PKI types + OID constants + OpenSSL signature verifier |
synta-x509-verification |
RFC 5280 / CABF certificate chain validation (synta.x509) |
synta-python-common |
Shared rlib: error bridging, submodule registration |
pyo3 0.26 |
Python/Rust interop (abi3-py38 feature) |
openssl 0.10 |
OpenSSL bindings for signature verification (synta.x509, synta.cms) |
Performance Design
- Input bytes are borrowed:
PyDecoderholds aPy<PyBytes>reference and passes a&[u8]slice to the Rust decoder — no copy of the input buffer. - Python string caching:
CertificatestoresOnceLock<Py<PyString>>for each string field. The first access constructs the Python object; subsequent calls useclone_ref()(~0.3 µs for all fields together). - Zero-copy certificate fields:
issuer,subject, andextensionsare stored as raw DER byte spans inside the RustCertificate; the Python binding wraps them inPyByteson first access. - Lazy decode: field values are decoded on demand rather than at parse time.
See docs/performance.md and python/README.md for benchmark numbers.
Cargo Features
| Feature | Default | Description |
|---|---|---|
extension-module |
yes (maturin) | Required by PyO3 for native extension module builds; set automatically by maturin |
abi3-py38 |
yes (maturin) | Targets the stable Python 3.8 ABI; compatible with CPython 3.8–3.14+ |
openssl |
yes | OpenSSL-backed crypto: PKCS#12 decryption (load_pkcs12_certificates with password, create_pkcs12 with password), CMS EnvelopedData.create / EnvelopedDataBuilder.build, EncryptedData.create / decrypt, PrivateKey.to_pkcs8_encrypted / from_pkcs8_encrypted, synta.x509 chain verification |
deprecated-pkcs12-algorithms |
no | Enables legacy PKCS#12 decryption algorithms (3DES, RC2) — requires openssl |
License
Licensed under either of:
- Apache License, Version 2.0 (LICENSE-APACHE)
- MIT license (LICENSE-MIT)
at your option.
Dependencies
~5–7MB
~149K SLoC