#synta #asn-1 #python #extension #content #pyo3

synta-python

Python extension module for the synta ASN.1 library

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

MIT/Apache

7.5MB
62K SLoC

Rust 41K SLoC // 0.1% comments ASN.1 9K SLoC // 0.4% comments Python 9K SLoC // 0.4% comments Shell 2K SLoC // 0.2% comments RPM Specfile 274 SLoC // 0.0% comments

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 (registers synta.krb5 and synta.spnego)
  • synta-python-mtc_mtc.abi3.so (registers synta.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_UNKNOWNNT_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: PyDecoder holds a Py<PyBytes> reference and passes a &[u8] slice to the Rust decoder — no copy of the input buffer.
  • Python string caching: Certificate stores OnceLock<Py<PyString>> for each string field. The first access constructs the Python object; subsequent calls use clone_ref() (~0.3 µs for all fields together).
  • Zero-copy certificate fields: issuer, subject, and extensions are stored as raw DER byte spans inside the Rust Certificate; the Python binding wraps them in PyBytes on 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:

at your option.

Dependencies

~5–7MB
~149K SLoC