# Synta Python Bindings — Complete Catalog
**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)*
- [Overview](#overview)
- [Module layout](#module-layout)
- [Top-level `synta` module](#top-level-synta-module)
- [Constants and enumerations](#constants-and-enumerations)
- [Free functions](#free-functions)
- [Decoder](#decoder)
- [Constructor](#constructor)
- [Primitive decode methods](#primitive-decode-methods)
- [Structured / container decode methods](#structured-container-decode-methods)
- [Introspection helpers](#introspection-helpers)
- [Encoder](#encoder)
- [Constructor](#constructor-1)
- [Primitive encode methods — raw values](#primitive-encode-methods-raw-values)
- [Primitive encode methods — typed objects](#primitive-encode-methods-typed-objects)
- [Container / tagging encode methods](#container-tagging-encode-methods)
- [Finalisation](#finalisation)
- [Primitive type classes](#primitive-type-classes)
- [Integer](#integer)
- [OctetString](#octetstring)
- [BitString](#bitstring)
- [Boolean](#boolean)
- [Real](#real)
- [Null](#null)
- [UtcTime](#utctime)
- [GeneralizedTime](#generalizedtime)
- [String types](#string-types)
- [TaggedElement](#taggedelement)
- [RawElement](#rawelement)
- [ObjectIdentifier](#objectidentifier)
- [Certificate](#certificate)
- [CertificationRequest](#certificationrequest)
- [CertificateList](#certificatelist)
- [OCSPResponse](#ocspresponse)
- [PKCS#7 and PKCS#12 loader functions](#pkcs7-and-pkcs12-loader-functions)
- [`synta.cms` submodule](#syntacms-submodule)
- [EncryptedData](#encrypteddata)
- [Content-type OID constants](#content-type-oid-constants)
- [Content-encryption algorithm OID constants](#content-encryption-algorithm-oid-constants)
- [`synta.oids` submodule](#syntaoids-submodule)
- [Algorithm OIDs](#algorithm-oids)
- [Hash algorithm OIDs](#hash-algorithm-oids)
- [SLH-DSA OIDs (FIPS 205)](#slh-dsa-oids-fips-205)
- [Prefix OIDs](#prefix-oids)
- [X.509v3 extension OIDs](#x509v3-extension-oids)
- [Extended Key Usage (EKU) OIDs](#extended-key-usage-eku-oids)
- [PKINIT OIDs (RFC 4556 / RFC 8636)](#pkinit-oids-rfc-4556-rfc-8636)
- [Microsoft PKI OIDs](#microsoft-pki-oids)
- [PKCS#9 attribute OIDs (RFC 2985 / RFC 5652 / RFC 2986 / RFC 7292)](#pkcs9-attribute-oids-rfc-2985-rfc-5652-rfc-2986-rfc-7292)
- [`synta.oids.attr` — DN attribute OIDs](#syntaoidsattr-dn-attribute-oids)
- [`synta.general_name` submodule](#syntageneral_name-submodule)
- [Typical dispatch pattern](#typical-dispatch-pattern)
- [`synta.krb5` submodule](#syntakrb5-submodule)
- [Principal-name type constants](#principal-name-type-constants)
- [Krb5PrincipalName](#krb5principalname)
- [PKINIT protocol classes](#pkinit-protocol-classes)
- [EncryptionKey](#encryptionkey)
- [Checksum](#checksum)
- [KDFAlgorithmId](#kdfalgorithmid)
- [IssuerAndSerialNumber](#issuerandserialnumber)
- [ExternalPrincipalIdentifier](#externalprincipalidentifier)
- [PKAuthenticator](#pkauthenticator)
- [AuthPack](#authpack)
- [PaPkAsReq](#papkasreq)
- [DHRepInfo](#dhrepinfo)
- [KDCDHKeyInfo](#kdcdhkeyinfo)
- [ReplyKeyPack](#replykeypack)
- [PaPkAsRep](#papkasrep)
- [`synta.pkixalgs` submodule](#syntapkixalgs-submodule)
- [DssParms](#dssparms)
- [DssSigValue](#dsssigvalue)
- [EcdsaSigValue](#ecdsasigvalue)
- [ECParameters](#ecparameters)
- [OID constants (`synta.pkixalgs`)](#oid-constants-syntapkixalgs)
- [`synta.ac` submodule](#syntaac-submodule)
- [AttributeCertificate](#attributecertificate)
- [OID constants (`synta.ac`)](#oid-constants-syntaac)
- [`synta.crmf` submodule](#syntacrmf-submodule)
- [CertReqMessages](#certreqmessages)
- [CertReqMsg](#certreqmsg)
- [OID constants (`synta.crmf`)](#oid-constants-syntacrmf)
- [`synta.cmp` submodule](#syntacmp-submodule)
- [CMPMessage](#cmpmessage)
- [OID constants (`synta.cmp`)](#oid-constants-syntacmp)
- [`synta.x509` submodule](#syntax509-submodule)
- [TrustStore](#truststore)
- [VerificationPolicy](#verificationpolicy)
- [CrlStore](#crlstore)
- [verify_server_certificate](#verifyservercertificate)
- [verify_client_certificate](#verifyclientcertificate)
- [Exceptions](#exceptions)
- [Example programs](#example-programs)
- [1. [`examples/example_pem_helpers.py`](../examples/example_pem_helpers.py) — PEM ↔ DER conversion](#1-examplesexamplepemhelperspy-pem-der-conversion)
- [2. [`examples/example_certificate_fields.py`](../examples/example_certificate_fields.py) — All Certificate properties](#2-examplesexamplecertificatefieldspy-all-certificate-properties)
- [3. [`examples/example_certificate_extensions.py`](../examples/example_certificate_extensions.py) — Extension access and SAN parsing](#3-examplesexamplecertificateextensionspy-extension-access-and-san-parsing)
- [4. [`examples/example_certificate_pyca.py`](../examples/example_certificate_pyca.py) — PyCA interoperability](#4-examplesexamplecertificatepycapy-pyca-interoperability)
- [5. [`examples/example_csr.py`](../examples/example_csr.py) — PKCS#10 CSR parsing](#5-examplesexample_csrpy-pkcs10-csr-parsing)
- [6. [`examples/example_crl.py`](../examples/example_crl.py) — CRL parsing](#6-examplesexample_crlpy-crl-parsing)
- [7. [`examples/example_ocsp.py`](../examples/example_ocsp.py) — OCSP response parsing](#7-examplesexample_ocsppy-ocsp-response-parsing)
- [8. [`examples/example_pkcs7.py`](../examples/example_pkcs7.py) — PKCS#7 certificate bundles](#8-examplesexample_pkcs7py-pkcs7-certificate-bundles)
- [9. [`examples/example_pkcs12.py`](../examples/example_pkcs12.py) — PKCS#12 archive parsing and creation](#9-examplesexample_pkcs12py-pkcs12-archive-parsing-and-creation)
- [10. [`examples/example_pki_blocks.py`](../examples/example_pki_blocks.py) — Format-agnostic PKI reader](#10-examplesexamplepkiblockspy-format-agnostic-pki-reader)
- [11. [`examples/example_objectidentifier.py`](../examples/example_objectidentifier.py) — ObjectIdentifier constructors and operations](#11-examplesexample_objectidentifierpy-objectidentifier-constructors-and-operations)
- [12. [`examples/example_oids_catalog.py`](../examples/example_oids_catalog.py) — `synta.oids` constant groups](#12-examplesexampleoidscatalogpy-syntaoids-constant-groups)
- [13. [`examples/example_time_types.py`](../examples/example_time_types.py) — UtcTime and GeneralizedTime](#13-examplesexampletimetypespy-utctime-and-generalizedtime)
- [14. [`examples/example_integer_advanced.py`](../examples/example_integer_advanced.py) — Integer edge cases and bigint](#14-examplesexampleintegeradvancedpy-integer-edge-cases-and-bigint)
- [15. [`examples/example_string_types_advanced.py`](../examples/example_string_types_advanced.py) — Alternative string constructors](#15-examplesexamplestringtypes_advancedpy-alternative-string-constructors)
- [16. [`examples/example_decoder_advanced.py`](../examples/example_decoder_advanced.py) — Advanced Decoder operations](#16-examplesexampledecoderadvancedpy-advanced-decoder-operations)
- [17. [`examples/example_encoder_advanced.py`](../examples/example_encoder_advanced.py) — Advanced Encoder operations](#17-examplesexampleencoderadvancedpy-advanced-encoder-operations)
- [18. [`examples/example_krb5_principal.py`](../examples/example_krb5_principal.py) — Kerberos principal names](#18-examplesexamplekrb5principalpy-kerberos-principal-names)
- [19. [`examples/example_krb5_pkinit.py`](../examples/example_krb5_pkinit.py) — PKINIT protocol classes](#19-examplesexamplekrb5pkinitpy-pkinit-protocol-classes)
- [20. [`examples/example_error_handling.py`](../examples/example_error_handling.py) — Exception catalogue](#20-examplesexampleerrorhandlingpy-exception-catalogue)
- [21. [`examples/example_cms_encrypted_data.py`](../examples/example_cms_encrypted_data.py) — CMS EncryptedData round-trip](#21-examplesexamplecmsencrypted_datapy-cms-encrypteddata-round-trip)
- [22. [`examples/example_x509_verify.py`](../examples/example_x509_verify.py) — X.509 certificate chain verification](#22-examplesexamplex509verifypy-x509-certificate-chain-verification)
---
## Overview
The `synta` Python package is implemented as a PyO3 extension module (`_synta.abi3.so`)
built from three Rust crates:
| `synta` | `Encoding`, `Decoder`, `Encoder`, all primitive types |
| `synta-certificate` | `ObjectIdentifier`, `Certificate`, `CertificationRequest`, `CertificateList`, `OCSPResponse`, `synta.oids`, PKCS#7/12 loaders, `synta.pkixalgs`, `synta.ac`, `synta.crmf`, `synta.cmp`; `OpensslSignatureVerifier` |
| `synta-krb5` (via `synta-python`) | `synta.krb5` submodule: `Krb5PrincipalName` + PKINIT classes |
| `synta-x509-verification` (via `synta-python`) | `synta.x509` submodule: `TrustStore`, `CrlStore`, `VerificationPolicy`, `verify_server_certificate`, `verify_client_certificate` |
The package surface is defined in `python/synta/__init__.py`, which re-exports
everything from `_synta` and makes `synta.krb5` and `synta.oids` available
without an explicit sub-import.
---
## Module layout
```
synta # top-level package
├── Encoder # ASN.1 encoder
├── SyntaError # exception class
├── __version__ # str, e.g. "0.1.0"
│
├── Integer # primitive types
├── OctetString
├── ObjectIdentifier
├── BitString
├── Boolean
├── Real
├── Null
├── UtcTime
├── GeneralizedTime
├── Utf8String
├── PrintableString
├── IA5String
├── NumericString
├── TeletexString
├── VisibleString
├── GeneralString
├── UniversalString
├── BmpString
├── TaggedElement
├── RawElement
│
├── Certificate # PKI types
├── CertificationRequest
├── CertificateList
├── OCSPResponse
│
├── pem_to_der() # PEM helpers
├── der_to_pem()
│
├── load_der_pkcs7_certificates() # PKCS#7 / PKCS#12 loaders
├── load_pem_pkcs7_certificates()
├── load_pkcs12_certificates()
├── load_pkcs12_keys()
├── load_pkcs12()
├── read_pki_blocks()
│
├── general_name # synta.general_name submodule
│ ├── OTHER_NAME, RFC822_NAME, DNS_NAME, X400_ADDRESS
│ ├── DIRECTORY_NAME, EDI_PARTY_NAME, URI
│ ├── IP_ADDRESS, REGISTERED_ID
│ └── (integer tag constants for GeneralName CHOICE, RFC 5280 §4.2.1.6)
│
├── oids # synta.oids submodule
│ ├── RSA_ENCRYPTION, SHA256_WITH_RSA, ...
│ ├── EC_PUBLIC_KEY, EC_CURVE_P256, ...
│ ├── ED25519, ED448, ML_DSA_44, ...
│ ├── SUBJECT_ALT_NAME, BASIC_CONSTRAINTS, ...
│ ├── KP_SERVER_AUTH, KP_CLIENT_AUTH, ...
│ ├── ID_PKINIT_SAN, ID_PKINIT_KPCLIENT_AUTH, ...
│ ├── ID_MS_SAN_UPN, ID_MS_KP_SMARTCARD_LOGON, ...
│ └── attr # synta.oids.attr submodule
│ ├── COMMON_NAME, ORGANIZATION, COUNTRY, ...
│ └── ...
│
├── krb5 # synta.krb5 submodule
│ ├── KRB5_PRINCIPAL_NAME_OID
│ ├── NT_UNKNOWN, NT_PRINCIPAL, NT_SRV_INST, ...
│ ├── Krb5PrincipalName
│ ├── EncryptionKey
│ ├── Checksum
│ ├── KDFAlgorithmId
│ ├── IssuerAndSerialNumber
│ ├── ExternalPrincipalIdentifier
│ ├── PKAuthenticator
│ ├── AuthPack
│ ├── PaPkAsReq
│ ├── DHRepInfo
│ ├── KDCDHKeyInfo
│ ├── ReplyKeyPack
│ └── PaPkAsRep
│
├── pkixalgs # synta.pkixalgs submodule (RFC 3279)
│ ├── DssParms, DssSigValue, EcdsaSigValue, ECParameters
│ └── ID_DSA, ID_EC_PUBLIC_KEY, ECDSA_WITH_SHA256, PRIME256V1, ...
│
├── ac # synta.ac submodule (RFC 5755)
│ ├── AttributeCertificate
│ └── ID_AT_ROLE, ID_AT_CLEARANCE, ID_PE_AC_AUDIT_IDENTITY, ...
│
├── crmf # synta.crmf submodule (RFC 4211)
│ ├── CertReqMessages, CertReqMsg
│ └── ID_REG_CTRL_REG_TOKEN, ID_REG_CTRL_AUTHENTICATOR, ...
│
├── cmp # synta.cmp submodule (RFC 9810)
│ ├── CMPMessage
│ └── ID_PASSWORD_BASED_MAC, ID_DHBASED_MAC, ID_KP_CM_KGA, ...
│
└── x509 # synta.x509 submodule (RFC 5280 / CABF path validation)
├── TrustStore # trusted root CA store (DER bytes)
├── CrlStore # CRL revocation checking store (DER bytes)
├── VerificationPolicy # server_names, name_match, validation_time, max_chain_depth, profile
├── X509VerificationError # raised on any chain or policy failure
├── verify_server_certificate(leaf, intermediates, store, policy, crls=None) → list[bytes]
└── verify_client_certificate(leaf, intermediates, store, policy, crls=None) → list[bytes]
```
---
## Top-level `synta` module
### Constants and enumerations
| `Encoding.DER` | `Encoding` | Distinguished Encoding Rules |
| `Encoding.BER` | `Encoding` | Basic Encoding Rules |
| `Encoding.CER` | `Encoding` | Canonical Encoding Rules |
| `SyntaError` | exception class | Raised on ASN.1 parse or encode failures |
| `__version__` | `str` | Package version string (from `Cargo.toml`) |
### Free functions
| `pem_to_der(data: bytes)` | `list[bytes]` | Decode one or more PEM blocks to DER. Always returns a list (one entry per block); no block → `ValueError`. |
| `der_to_pem(der: bytes, label: str)` | `bytes` | Wrap DER bytes in a `-----BEGIN {label}-----` / `-----END {label}-----` block. |
| `load_der_pkcs7_certificates(data: bytes)` | `list[Certificate]` | Extract certificates from a DER/BER PKCS#7 SignedData blob. |
| `load_pem_pkcs7_certificates(data: bytes)` | `list[Certificate]` | Decode PEM, then extract certificates from each PKCS#7 block. |
| `load_pkcs12_certificates(data: bytes, password: bytes = None)` | `list[Certificate]` | Extract certificates from a PKCS#12 archive. Encrypted bags require the `openssl` Cargo feature. |
| `load_pkcs12_keys(data: bytes, password: bytes = None)` | `list[bytes]` | Extract PKCS#8 private key DER blobs from a PKCS#12 archive. |
| `load_pkcs12(data: bytes, password: bytes = None)` | `tuple[list[Certificate], list[bytes]]` | Extract both certificates and keys from a PKCS#12 archive in one call. |
| `create_pkcs12(certificates: list[Certificate \| bytes], private_key: PrivateKey \| bytes = None, password: bytes = None)` | `bytes` | Build a DER-encoded PKCS#12 PFX archive. Each certificate may be a `Certificate` object or DER bytes; `private_key` may be a `PrivateKey` or DER bytes. Encryption requires the `openssl` Cargo feature. |
| `read_pki_blocks(data: bytes, password: bytes = None)` | `list[tuple[str, bytes]]` | Auto-detect format (PEM, PKCS#7, PKCS#12, raw DER) and return `(label, der_bytes)` tuples. Labels: `"CERTIFICATE"` or `"PRIVATE KEY"`. |
| `parse_general_names(san_der: bytes)` | `list[tuple[int, bytes]]` | Parse a DER `SEQUENCE OF GeneralName` into `(tag_number, content)` pairs. Use `synta.general_name` constants to dispatch on `tag_number`. |
| `parse_name_attrs(name_der: bytes)` | `list[tuple[str, str]]` | Walk a DER Name SEQUENCE and return `(dotted_oid, value_str)` pairs in traversal order. |
---
## Decoder
### Constructor
```python
Decoder(data: bytes, encoding: Encoding)
```
Creates a streaming decoder over `data`. The internal position starts at 0.
Each `decode_*` call advances the position past the decoded element.
### Primitive decode methods
| `decode_integer()` | `Integer` | INTEGER | `0x02` |
| `decode_octet_string()` | `OctetString` | OCTET STRING | `0x04` |
| `decode_oid()` | `ObjectIdentifier` | OBJECT IDENTIFIER | `0x06` |
| `decode_bit_string()` | `BitString` | BIT STRING | `0x03` |
| `decode_boolean()` | `Boolean` | BOOLEAN | `0x01` |
| `decode_utc_time()` | `UtcTime` | UTCTime | `0x17` |
| `decode_generalized_time()` | `GeneralizedTime` | GeneralizedTime | `0x18` |
| `decode_null()` | `Null` | NULL | `0x05` |
| `decode_real()` | `Real` | REAL | `0x09` |
| `decode_utf8_string()` | `Utf8String` | UTF8String | `0x0c` |
| `decode_printable_string()` | `PrintableString` | PrintableString | `0x13` |
| `decode_ia5_string()` | `IA5String` | IA5String | `0x16` |
| `decode_numeric_string()` | `NumericString` | NumericString | `0x12` |
| `decode_teletex_string()` | `TeletexString` | TeletexString / T61String | `0x14` |
| `decode_visible_string()` | `VisibleString` | VisibleString | `0x1a` |
| `decode_general_string()` | `GeneralString` | GeneralString | `0x1b` |
| `decode_universal_string()` | `UniversalString` | UniversalString | `0x1c` |
| `decode_bmp_string()` | `BmpString` | BMPString | `0x1e` |
| `decode_any()` | any Python object | any element | — |
| `decode_any_str()` | `str` | any string type | — |
`decode_any()` dispatches on the tag at the current position:
- SEQUENCE / SET → `list`
- known primitives → typed object (e.g. `Integer`, `Boolean`)
- tagged elements → `TaggedElement`
- unknown universal tags → `RawElement`
`decode_any_str()` reads one TLV and decodes it as a native Python `str`,
applying the correct encoding for each of the nine ASN.1 string types:
| 12 | UTF8String | UTF-8 (lossy) |
| 18 | NumericString | UTF-8 |
| 19 | PrintableString | UTF-8 |
| 20 | TeletexString / T61String | Latin-1 (each byte → U+0000–U+00FF) |
| 22 | IA5String | UTF-8 |
| 26 | VisibleString | UTF-8 |
| 27 | GeneralString | UTF-8 |
| 28 | UniversalString | UCS-4 big-endian |
| 30 | BMPString | UCS-2 big-endian |
Raises `ValueError` for any other tag; raises `EOFError` if the decoder is empty.
This is the single-call replacement for the duck-typing probe on `decode_any()`:
```python
# Before — three-way probe:
val = decoder.decode_any()
if hasattr(val, 'as_str'):
s = val.as_str()
elif hasattr(val, 'to_bytes'):
s = val.to_bytes().decode('latin-1')
else:
raise ValueError(f"not a string: {type(val)}")
# After — one call, correct encoding for all nine types:
s = decoder.decode_any_str()
```
### Structured / container decode methods
| `decode_sequence` | `()` | `Decoder` | Consume a SEQUENCE TLV; return child decoder over its contents. |
| `decode_set` | `()` | `Decoder` | Consume a SET TLV; return child decoder over its contents. |
| `decode_explicit_tag` | `(tag_num: int)` | `Decoder` | Strip an explicit context-specific tag `[tag_num]`; return child decoder over the content. |
| `decode_implicit_tag` | `(tag_num: int, tag_class: str)` | `Decoder` | Strip an implicit tag; return child decoder over the **value bytes only** (no tag/length). `tag_class` is `"Context"`, `"Application"`, `"Private"`, or `"Universal"`. |
| `decode_raw_tlv` | `()` | `bytes` | Read the next complete TLV (tag + length + value) as raw bytes and advance past it. |
### Introspection helpers
| `peek_tag()` | `tuple[int, str, bool]` | `(tag_number, tag_class, is_constructed)` — does **not** advance the position. Raises `EOFError` if no data remains. |
| `remaining_bytes()` | `bytes` | All bytes from the current position to the end. Useful after `decode_implicit_tag` to retrieve bare primitive value bytes. |
| `is_empty()` | `bool` | `True` when the current position equals the data length. |
| `position()` | `int` | Current byte offset. |
| `remaining()` | `int` | Number of bytes left. |
---
## Encoder
### Constructor
```python
Encoder(encoding: Encoding)
```
Creates a new in-memory encoder. Elements are appended in call order.
Call `finish()` to retrieve the accumulated bytes.
### Primitive encode methods — raw values
| `encode_integer` | `(value: int)` | INTEGER — accepts any Python `int` (arbitrary magnitude via bigint path) |
| `encode_octet_string` | `(data: bytes)` | OCTET STRING |
| `encode_oid` | `(value: ObjectIdentifier)` | OBJECT IDENTIFIER |
| `encode_bit_string` | `(value: BitString)` | BIT STRING |
| `encode_boolean` | `(value: bool)` | BOOLEAN |
| `encode_utc_time` | `(value: UtcTime)` | UTCTime |
| `encode_generalized_time` | `(value: GeneralizedTime)` | GeneralizedTime |
| `encode_real` | `(value: float)` | REAL |
| `encode_null` | `()` | NULL |
| `encode_utf8_string` | `(value: str)` | UTF8String |
| `encode_printable_string` | `(value: str)` | PrintableString — raises `ValueError` for invalid chars |
| `encode_ia5_string` | `(value: str)` | IA5String — raises `ValueError` for non-ASCII |
| `encode_numeric_string` | `(value: str)` | NumericString — raises `ValueError` for non-digit/non-space |
| `encode_teletex_string` | `(data: bytes)` | TeletexString / T61String |
| `encode_visible_string` | `(value: str)` | VisibleString — raises `ValueError` for invalid chars |
| `encode_general_string` | `(data: bytes)` | GeneralString |
| `encode_universal_string` | `(value: str)` | UniversalString (UCS-4 BE) |
| `encode_bmp_string` | `(value: str)` | BMPString (UCS-2 BE) — raises `ValueError` for non-BMP code points |
### Primitive encode methods — typed objects
Each primitive type has an `_object` variant that accepts the corresponding
Python wrapper instead of a raw value.
| `encode_integer_object` | `Integer` |
| `encode_octet_string_object` | `OctetString` |
| `encode_oid_object` | `ObjectIdentifier` (alias for `encode_oid`) |
| `encode_bit_string_object` | `BitString` (alias for `encode_bit_string`) |
| `encode_boolean_object` | `Boolean` |
| `encode_utc_time_object` | `UtcTime` (alias for `encode_utc_time`) |
| `encode_generalized_time_object` | `GeneralizedTime` (alias for `encode_generalized_time`) |
| `encode_real_object` | `Real` |
| `encode_null_object` | `Null` |
| `encode_utf8_string_object` | `Utf8String` |
| `encode_printable_string_object` | `PrintableString` |
| `encode_ia5_string_object` | `IA5String` |
| `encode_numeric_string_object` | `NumericString` |
| `encode_teletex_string_object` | `TeletexString` |
| `encode_visible_string_object` | `VisibleString` |
| `encode_general_string_object` | `GeneralString` |
| `encode_universal_string_object` | `UniversalString` |
| `encode_bmp_string_object` | `BmpString` |
### Container / tagging encode methods
| `encode_sequence` | `(inner_bytes: bytes)` | Wrap `inner_bytes` with SEQUENCE TLV (tag `0x30`). |
| `encode_set` | `(inner_bytes: bytes)` | Wrap `inner_bytes` with SET TLV (tag `0x31`). |
| `encode_explicit_tag` | `(tag_num: int, tag_class: str, inner_bytes: bytes)` | Wrap `inner_bytes` in an explicit constructed tag. `tag_class`: `"Context"`, `"Application"`, `"Private"`. |
| `encode_implicit_tag` | `(tag_num: int, tag_class: str, is_constructed: bool, value_bytes: bytes)` | Emit an implicit tag over raw value bytes. Set `is_constructed=True` for SEQUENCE/SET underlying types. |
### Finalisation
| `finish()` | `bytes` | Consume the encoder and return the accumulated DER/BER bytes. The encoder is reset and can be reused (rarely needed). |
---
## Primitive type classes
### Integer
```python
Integer(value: int) # constructor — i64 range only
Integer.from_bytes(data: bytes) -> Integer # big-endian two's complement
Integer.from_u64(value: int) -> Integer # unsigned 64-bit
```
| `to_int()` | `int` | Convert to Python `int` via i64; raises `OverflowError` if too large. |
| `to_i128()` | `int` | Convert via i128; raises `OverflowError` if too large. |
| `to_bytes()` | `bytes` | Raw big-endian two's complement bytes. |
Special methods: `__repr__`, `__str__`.
### OctetString
```python
OctetString(data: bytes)
```
| `to_bytes()` | `bytes` |
| `__len__()` | `int` |
| `__eq__(other)` | `bool` |
### BitString
```python
BitString(data: bytes, unused_bits: int) # unused_bits in 0–7
```
| `to_bytes()` | `bytes` | Raw content bytes (excluding unused-bits octet). |
| `unused_bits()` | `int` | Number of padding bits in the last byte. |
| `bit_len()` | `int` | Total significant bits (`len(data) * 8 - unused_bits`). |
| `__len__()` | `int` | Same as `bit_len()`. |
| `__eq__(other)` | `bool` | |
### Boolean
```python
Boolean(value: bool)
```
| `value()` | `bool` |
| `__bool__()` | `bool` |
### Real
```python
Real(value: float)
```
| `value()` | `float` | |
| `is_infinite()` | `bool` | `True` for ±∞ |
| `is_nan()` | `bool` | `True` for NaN |
| `is_finite()` | `bool` | `True` for finite, non-NaN |
| `__float__()` | `float` | Enables `float(r)` |
| `__eq__`, `__hash__` | | Hash consistent with IEEE 754 (`NaN != NaN`, `-0.0 == 0.0`) |
### Null
```python
Null()
```
`__repr__` returns `"Null()"`. All `Null()` instances compare equal.
### UtcTime
```python
UtcTime(year: int, month: int, day: int, hour: int, minute: int, second: int)
```
Year must be in the range 1950–2049. Raises `ValueError` on invalid input.
Properties: `year`, `month`, `day`, `hour`, `minute`, `second` (all `int`).
`__str__` returns the canonical YYMMDDHHMMSSZ form.
### GeneralizedTime
```python
GeneralizedTime(year: int, month: int, day: int, hour: int, minute: int, second: int,
milliseconds: int | None = None)
```
Properties: `year`, `month`, `day`, `hour`, `minute`, `second` (int), `milliseconds` (`int | None`).
`__str__` returns the canonical YYYYMMDDHHMMSS[.fff]Z form.
### String types
All string types expose `.as_str() -> str` and support `__str__`, `__eq__`, `__len__`.
Types whose character sets are subsets of ASCII raise `ValueError` on construction if
invalid characters are supplied.
| `Utf8String` | `(value: str)` | Unicode | |
| `PrintableString` | `(value: str)` | `A–Z a–z 0–9 ' ( ) + , - . / : = ?` | |
| `IA5String` | `(value: str)` | ASCII (0x00–0x7f) | |
| `NumericString` | `(value: str)` | Digits and space | |
| `TeletexString` | `(data: bytes)` | Arbitrary bytes | Also: `TeletexString.from_latin1(str)`, `from_str(str)`. `.to_bytes()` returns raw bytes. |
| `VisibleString` | `(value: str)` | Printable ASCII (0x21–0x7e) | |
| `GeneralString` | `(data: bytes)` | Arbitrary bytes | Also: `GeneralString.from_ascii(str)` (ASCII only, raises `ValueError` for > U+007F), `from_str(str)`. `.to_bytes()` returns raw bytes. |
| `UniversalString` | `(value: str)` | Unicode (UCS-4 BE) | Also: `UniversalString.from_bytes(data: bytes)`. |
| `BmpString` | `(value: str)` | BMP only (U+0000–U+FFFF) | Also: `BmpString.from_bytes(data: bytes)`. Raises `ValueError` for non-BMP code points. |
### TaggedElement
Returned by `Decoder.decode_any()` for explicitly-tagged or application/private-tagged values.
| `tag_number` | `int` | The tag number |
| `tag_class` | `str` | `"Universal"`, `"Context"`, `"Application"`, or `"Private"` |
| `is_constructed` | `bool` | `True` for constructed (e.g. wrapped SEQUENCE) |
| `value` | any | The inner decoded element |
### RawElement
Returned by `Decoder.decode_any()` for unknown universal tags (enables forward-compatible parsing).
| `tag_number` | `int` | |
| `tag_class` | `str` | |
| `is_constructed` | `bool` | |
| `data` | `bytes` | Raw content bytes (no tag or length) |
---
## ObjectIdentifier
```python
ObjectIdentifier(oid_str: str) # from dotted-decimal, e.g. "2.5.4.3"
ObjectIdentifier.from_components(comps: list[int]) # from arc list
ObjectIdentifier.from_der_value(data: bytes) # from implicit-tag content bytes (tag+length stripped)
```
| `components()` | `tuple[int, ...]` | OID arc components |
| `__str__()` | `str` | Dotted-decimal notation (cached) |
| `__repr__()` | `str` | `ObjectIdentifier('2.5.4.3')` |
| `__eq__(other)` | `bool` | Compares against another `ObjectIdentifier` or a dotted `str` |
| `__hash__()` | `int` | Consistent with `hash(str(oid))` so `oid in {"2.5.4.3"}` works |
`ObjectIdentifier` instances are **frozen** (immutable, thread-safe).
---
## Certificate
Represents an RFC 5280 X.509 v3 certificate. Parsing is lazy: `from_der` performs
only a 4-operation shallow scan; the full decode happens on first field access.
```python
Certificate.from_der(data: bytes) -> Certificate
Certificate.full_from_der(data: bytes) -> Certificate # eager: full decode at construction
Certificate.from_pem(data: bytes) -> Certificate | list[Certificate]
Certificate.to_pem(cert_or_list) -> bytes # static method
Certificate.from_pyca(pyca_cert) -> Certificate # requires `cryptography`
cert.to_pyca() -> cryptography.x509.Certificate # requires `cryptography`
```
| `serial_number` | `int` | Serial number as Python int (arbitrary size) |
| `version` | `int \| None` | Version field (0=v1, 1=v2, 2=v3) |
| `issuer` | `str` | RFC 4514 DN string |
| `issuer_raw_der` | `bytes` | Raw DER of issuer Name SEQUENCE |
| `subject` | `str` | RFC 4514 DN string |
| `subject_raw_der` | `bytes` | Raw DER of subject Name SEQUENCE |
| `not_before` | `str` | Validity notBefore as string |
| `not_after` | `str` | Validity notAfter as string |
| `signature_algorithm` | `str` | Algorithm name or dotted OID |
| `signature_algorithm_oid` | `ObjectIdentifier` | |
| `signature_algorithm_params` | `bytes \| None` | DER-encoded parameters or `None` |
| `signature_value` | `bytes` | Raw signature bytes |
| `public_key_algorithm` | `str` | Algorithm name or dotted OID |
| `public_key_algorithm_oid` | `ObjectIdentifier` | |
| `public_key_algorithm_params` | `bytes \| None` | DER-encoded parameters (curve OID for EC) or `None` |
| `public_key` | `bytes` | Raw subject public key bytes |
| `tbs_bytes` | `bytes` | DER bytes of TBSCertificate (the signed region) |
| `extensions_der` | `bytes \| None` | DER SEQUENCE OF Extension, or `None` for v1/v2 certs |
| `to_der()` | `()` | `bytes` | Original DER bytes (zero-copy) |
| `get_extension_value_der` | `(oid: str \| ObjectIdentifier)` | `bytes \| None` | Return the extnValue content bytes for the named extension OID, or `None` if absent. |
| `subject_alt_names()` | `()` | `list[tuple[int, bytes]]` | Return SAN entries as `(tag_number, content)` pairs. Use `synta.general_name` constants for dispatch. Returns `[]` when no SAN extension is present. |
All properties are cached after first access.
---
## CertificationRequest
Represents an RFC 2986 PKCS#10 Certificate Signing Request.
```python
CertificationRequest.from_der(data: bytes) -> CertificationRequest
CertificationRequest.from_pem(data: bytes) -> CertificationRequest | list[CertificationRequest]
CertificationRequest.to_pem(csr_or_list) -> bytes
```
| `version` | `int` | CSR version (always 0 = v1 per RFC 2986) |
| `subject` | `str` | RFC 4514 DN string |
| `subject_raw_der` | `bytes` | Raw DER of subject Name SEQUENCE |
| `signature_algorithm` | `str` | Algorithm name or dotted OID |
| `signature_algorithm_oid` | `ObjectIdentifier` | |
| `signature` | `bytes` | Raw signature bytes |
| `public_key_algorithm` | `str` | Algorithm name or dotted OID |
| `public_key_algorithm_oid` | `ObjectIdentifier` | |
| `public_key` | `bytes` | Raw subject public key bytes |
| `to_der()` | `()` | `bytes` | Original DER bytes |
---
## CertificateList
Represents an RFC 5280 Certificate Revocation List.
```python
CertificateList.from_der(data: bytes) -> CertificateList
CertificateList.from_pem(data: bytes) -> CertificateList | list[CertificateList]
CertificateList.to_pem(crl_or_list) -> bytes
```
| `issuer` | `str` | RFC 4514 DN string |
| `issuer_raw_der` | `bytes` | Raw DER of issuer Name SEQUENCE |
| `this_update` | `str` | thisUpdate time as string |
| `next_update` | `str \| None` | nextUpdate time as string, or `None` if absent |
| `signature_algorithm` | `str` | Algorithm name or dotted OID |
| `signature_algorithm_oid` | `ObjectIdentifier` | |
| `signature_value` | `bytes` | Raw signature bytes |
| `revoked_count` | `int` | Number of revoked certificate entries |
| `to_der()` | `()` | `bytes` | Original DER bytes |
---
## OCSPResponse
Represents an RFC 6960 OCSP Response (outer envelope only).
```python
OCSPResponse.from_der(data: bytes) -> OCSPResponse
OCSPResponse.from_pem(data: bytes) -> OCSPResponse | list[OCSPResponse]
OCSPResponse.to_pem(resp_or_list) -> bytes
```
| `status` | `str` | Response status: `"successful"`, `"malformedRequest"`, `"internalError"`, `"tryLater"`, `"sigRequired"`, `"unauthorized"` |
| `response_type_oid` | `ObjectIdentifier \| None` | OID of the responseBytes contentType, or `None` for non-successful responses |
| `response_bytes` | `bytes \| None` | Raw content of the responseBytes OCTET STRING, or `None` |
| `to_der()` | `()` | `bytes` | Original DER bytes |
---
## PKCS#7 and PKCS#12 loader functions
```python
load_der_pkcs7_certificates(data: bytes) -> list[Certificate]
```
Parse a DER or BER PKCS#7 SignedData blob and return its embedded certificates.
```python
load_pem_pkcs7_certificates(data: bytes) -> list[Certificate]
```
Decode PEM block(s), then extract certificates from each PKCS#7 payload.
```python
load_pkcs12_certificates(data: bytes, password: bytes = None) -> list[Certificate]
```
Extract certificates from a PKCS#12 / PFX archive. Pass `password=b""` or omit for
unencrypted archives. Encrypted bags require the `openssl` Cargo feature.
Non-certificate bag types (`keyBag`, `pkcs8ShroudedKeyBag`, `crlBag`, `secretBag`)
are silently skipped.
```python
load_pkcs12_keys(data: bytes, password: bytes = None) -> list[bytes]
```
Extract PKCS#8 private keys from a PKCS#12 archive. Returns a list of raw
DER-encoded `OneAsymmetricKey` blobs, one per `keyBag` (unencrypted) and
`pkcs8ShroudedKeyBag` (decrypted with the `openssl` Cargo feature) entry.
`certBag`, `crlBag`, and `secretBag` entries are silently skipped.
```python
load_pkcs12(data: bytes, password: bytes = None) -> tuple[list[Certificate], list[bytes]]
```
Extract both certificates and private keys from a PKCS#12 archive in a single call.
Returns `(certs, keys)` where `certs` is a `list[Certificate]` and `keys` is a
`list[bytes]` of DER-encoded PKCS#8 structures.
```python
create_pkcs12(
certificates: list[Certificate | bytes],
private_key: PrivateKey | bytes | None = None,
password: bytes | None = None,
) -> bytes
```
Build a DER-encoded PKCS#12 PFX archive. Each element of `certificates` may be a
`Certificate` object or raw DER `bytes`; both types may appear in the same list.
`private_key` may be a `PrivateKey` object or DER-encoded PKCS#8 `bytes`. When
`password` is `None` or omitted, the archive is created without encryption. When
`password` is provided and the library is built with the `openssl` Cargo feature,
PBES2/PBKDF2-SHA256/AES-256-CBC with 600,000 iterations is used. Without the
`openssl` feature, supplying a password raises `ValueError`. `TypeError` is raised
for unrecognised element types in either `certificates` or `private_key`.
```python
read_pki_blocks(data: bytes, password: bytes = None) -> list[tuple[str, bytes]]
```
Auto-detect format (PEM, PKCS#7, PKCS#12, raw DER certificate) and return
`(label, der_bytes)` pairs. Label semantics:
- PEM input: label matches the PEM block type (e.g. `"CERTIFICATE"`, `"PRIVATE KEY"`);
PKCS#7 blocks are expanded and each embedded cert is returned as `"CERTIFICATE"`.
- Binary PKCS#7 and raw DER: always `"CERTIFICATE"`.
- Binary PKCS#12: `"CERTIFICATE"` for `certBag` entries; `"PRIVATE KEY"` for
`keyBag` and `pkcs8ShroudedKeyBag` entries.
---
## `synta.cms` submodule
The `synta.cms` submodule provides CMS `EncryptedData` (RFC 5652 §8) support:
symmetric encryption and decryption of arbitrary content using AES-CBC.
Encryption and decryption require the `openssl` Cargo feature.
```python
from synta.cms import (
EncryptedData,
ID_DATA, ID_ENCRYPTED_DATA,
ID_AES128_CBC, ID_AES192_CBC, ID_AES256_CBC,
)
```
### EncryptedData
Represents a CMS `EncryptedData` SEQUENCE (RFC 5652 §8).
```python
EncryptedData.from_der(data: bytes) -> EncryptedData
```
Parse a DER- or BER-encoded `EncryptedData` SEQUENCE. Raises `ValueError` if
the outer SEQUENCE envelope is malformed.
```python
EncryptedData.create(
plaintext: bytes,
key: bytes,
algorithm_oid: ObjectIdentifier | str,
content_type_oid: ObjectIdentifier | str | None = None,
) -> EncryptedData
```
Encrypt `plaintext` under `key` using the cipher identified by `algorithm_oid`
and return the resulting `EncryptedData`. A fresh random IV is generated for
every call. `content_type_oid` defaults to `ID_DATA`
(`1.2.840.113549.1.7.1`). Both OID arguments accept an `ObjectIdentifier`
instance or a dotted-decimal string. Raises `NotImplementedError` if the
library was not built with the `openssl` Cargo feature.
```python
EncryptedData.decrypt(key: bytes) -> bytes
```
Decrypt the encapsulated ciphertext under `key` and return the recovered
plaintext. Raises `ValueError` on key-length mismatch; `NotImplementedError`
if built without the `openssl` feature.
```python
EncryptedData.to_der() -> bytes
```
Return the DER encoding of this `EncryptedData` SEQUENCE (the bytes originally
passed to `from_der`, or the freshly built DER from `create`).
**Properties:**
| `version` | `int` | Version integer (always `0` for RFC 5652 §8 content) |
| `content_type` | `ObjectIdentifier` | OID of the embedded content type (typically `ID_DATA`) |
| `content_encryption_algorithm_oid` | `ObjectIdentifier` | OID of the content-encryption algorithm (e.g. `ID_AES128_CBC`) |
| `content_encryption_algorithm_params` | `bytes \| None` | DER-encoded algorithm parameters; for CBC ciphers this is an OCTET STRING (`\x04\x10<iv>`) carrying the 16-byte IV |
| `encrypted_content` | `bytes \| None` | Raw ciphertext bytes (`encryptedContent [0] IMPLICIT OCTET STRING`) |
| `unprotected_attrs` | `bytes \| None` | Raw DER bytes of the `unprotectedAttrs [1] IMPLICIT` field, or `None` if absent |
### Content-type OID constants
| `ID_DATA` | `1.2.840.113549.1.7.1` | id-data |
| `ID_SIGNED_DATA` | `1.2.840.113549.1.7.2` | id-signedData |
| `ID_ENVELOPED_DATA` | `1.2.840.113549.1.7.3` | id-envelopedData |
| `ID_DIGESTED_DATA` | `1.2.840.113549.1.7.5` | id-digestedData |
| `ID_ENCRYPTED_DATA` | `1.2.840.113549.1.7.6` | id-encryptedData |
| `ID_CT_AUTH_DATA` | `1.2.840.113549.1.9.16.1.2` | id-ct-authData |
### Content-encryption algorithm OID constants
Passed as `algorithm_oid` to `EncryptedData.create`; also returned by the
`content_encryption_algorithm_oid` property.
| `ID_AES128_CBC` | `2.16.840.1.101.3.4.1.2` | 16 bytes |
| `ID_AES192_CBC` | `2.16.840.1.101.3.4.1.22` | 24 bytes |
| `ID_AES256_CBC` | `2.16.840.1.101.3.4.1.42` | 32 bytes |
---
## `synta.oids` submodule
All constants are `ObjectIdentifier` instances (frozen, hashable).
### Algorithm OIDs
| `RSA_ENCRYPTION` | 1.2.840.113549.1.1.1 | PKCS #1 |
| `MD5_WITH_RSA` | 1.2.840.113549.1.1.4 | PKCS #1 |
| `SHA1_WITH_RSA` | 1.2.840.113549.1.1.5 | PKCS #1 |
| `SHA256_WITH_RSA` | 1.2.840.113549.1.1.11 | RFC 4055 |
| `SHA384_WITH_RSA` | 1.2.840.113549.1.1.12 | RFC 4055 |
| `SHA512_WITH_RSA` | 1.2.840.113549.1.1.13 | RFC 4055 |
| `EC_PUBLIC_KEY` | 1.2.840.10045.2.1 | RFC 5480 |
| `ECDSA_WITH_SHA1` | 1.2.840.10045.4.1 | ANSI X9.62 |
| `ECDSA_WITH_SHA256` | 1.2.840.10045.4.3.2 | RFC 5758 |
| `ECDSA_WITH_SHA384` | 1.2.840.10045.4.3.3 | RFC 5758 |
| `ECDSA_WITH_SHA512` | 1.2.840.10045.4.3.4 | RFC 5758 |
| `ED25519` | 1.3.101.112 | RFC 8410 |
| `ED448` | 1.3.101.113 | RFC 8410 |
| `ML_DSA_44` | 2.16.840.1.101.3.4.3.17 | FIPS 204 |
| `ML_DSA_65` | 2.16.840.1.101.3.4.3.18 | FIPS 204 |
| `ML_DSA_87` | 2.16.840.1.101.3.4.3.19 | FIPS 204 |
| `ML_KEM_512` | 2.16.840.1.101.3.4.4.1 | FIPS 203 |
| `ML_KEM_768` | 2.16.840.1.101.3.4.4.2 | FIPS 203 |
| `ML_KEM_1024` | 2.16.840.1.101.3.4.4.3 | FIPS 203 |
| `EC_CURVE_P256` | 1.2.840.10045.3.1.7 | NIST P-256 |
| `EC_CURVE_P384` | 1.3.132.0.34 | NIST P-384 |
| `EC_CURVE_P521` | 1.3.132.0.35 | NIST P-521 |
| `EC_CURVE_SECP256K1` | 1.3.132.0.10 | Bitcoin curve |
### Hash algorithm OIDs
| `SHA224` | 2.16.840.1.101.3.4.2.4 | FIPS 180-4 |
| `SHA256` | 2.16.840.1.101.3.4.2.1 | FIPS 180-4 |
| `SHA384` | 2.16.840.1.101.3.4.2.2 | FIPS 180-4 |
| `SHA512` | 2.16.840.1.101.3.4.2.3 | FIPS 180-4 |
| `SHA512_224` | 2.16.840.1.101.3.4.2.5 | FIPS 180-4 |
| `SHA512_256` | 2.16.840.1.101.3.4.2.6 | FIPS 180-4 |
| `SHA3_224` | 2.16.840.1.101.3.4.2.7 | FIPS 202 |
| `SHA3_256` | 2.16.840.1.101.3.4.2.8 | FIPS 202 |
| `SHA3_384` | 2.16.840.1.101.3.4.2.9 | FIPS 202 |
| `SHA3_512` | 2.16.840.1.101.3.4.2.10 | FIPS 202 |
| `SHAKE128` | 2.16.840.1.101.3.4.2.11 | FIPS 202 |
| `SHAKE256` | 2.16.840.1.101.3.4.2.12 | FIPS 202 |
### SLH-DSA OIDs (FIPS 205)
`SLH_DSA_SHA2_128F`, `SLH_DSA_SHA2_128S`, `SLH_DSA_SHA2_192F`, `SLH_DSA_SHA2_192S`,
`SLH_DSA_SHA2_256F`, `SLH_DSA_SHA2_256S`, `SLH_DSA_SHAKE_128F`, `SLH_DSA_SHAKE_128S`,
`SLH_DSA_SHAKE_192F`, `SLH_DSA_SHAKE_192S`, `SLH_DSA_SHAKE_256F`, `SLH_DSA_SHAKE_256S`.
### Prefix OIDs
These are prefix arcs for use with `oid.components()` rather than exact match.
| `RSA` | 1.2.840.113549.1.1 | All PKCS#1 signature algorithms |
| `ECDSA_SIG` | 1.2.840.10045.4 | All ECDSA signature algorithms |
| `ECDSA_KEY` | 1.2.840.10045.2 | EC public-key types |
| `DSA` | 1.2.840.10040.4 | DSA and DSA-with-hash algorithms |
```python
# Example: match any RSA algorithm
import synta.oids as oids
if cert.signature_algorithm_oid.components()[:len(oids.RSA.components())] == oids.RSA.components():
print("RSA family")
```
### X.509v3 extension OIDs
| `SUBJECT_ALT_NAME` | 2.5.29.17 | RFC 5280 |
| `ISSUER_ALT_NAME` | 2.5.29.18 | RFC 5280 |
| `BASIC_CONSTRAINTS` | 2.5.29.19 | RFC 5280 |
| `KEY_USAGE` | 2.5.29.15 | RFC 5280 |
| `EXTENDED_KEY_USAGE` | 2.5.29.37 | RFC 5280 |
| `SUBJECT_KEY_IDENTIFIER` | 2.5.29.14 | RFC 5280 |
| `AUTHORITY_KEY_IDENTIFIER` | 2.5.29.35 | RFC 5280 |
| `CERTIFICATE_POLICIES` | 2.5.29.32 | RFC 5280 |
| `CRL_DISTRIBUTION_POINTS` | 2.5.29.31 | RFC 5280 |
| `AUTHORITY_INFO_ACCESS` | 1.3.6.1.5.5.7.1.1 | RFC 5280 |
| `CT_PRECERT_SCTS` | 1.3.6.1.4.1.11129.2.4.2 | RFC 6962 |
### Extended Key Usage (EKU) OIDs
| `KP_SERVER_AUTH` | 1.3.6.1.5.5.7.3.1 | TLS server authentication |
| `KP_CLIENT_AUTH` | 1.3.6.1.5.5.7.3.2 | TLS client authentication |
| `KP_CODE_SIGNING` | 1.3.6.1.5.5.7.3.3 | Code signing |
| `KP_EMAIL_PROTECTION` | 1.3.6.1.5.5.7.3.4 | S/MIME |
| `KP_TIME_STAMPING` | 1.3.6.1.5.5.7.3.8 | RFC 3161 TSA |
| `KP_OCSP_SIGNING` | 1.3.6.1.5.5.7.3.9 | OCSP responder |
| `ANY_EXTENDED_KEY_USAGE` | 2.5.29.37.0 | Match any EKU |
### PKINIT OIDs (RFC 4556 / RFC 8636)
| `ID_PKINIT_SAN` | 1.3.6.1.5.2.2 | KRB5PrincipalName OtherName type-id |
| `ID_PKINIT_KPCLIENT_AUTH` | 1.3.6.1.5.2.3.4 | PKINIT client auth EKU |
| `ID_PKINIT_KPKDC` | 1.3.6.1.5.2.3.5 | PKINIT KDC EKU |
| `ID_PKINIT_AUTH_DATA` | 1.3.6.1.5.2.3.1 | PA-PK-AS-REQ content type |
| `ID_PKINIT_DHKEY_DATA` | 1.3.6.1.5.2.3.2 | DH key data content type |
| `ID_PKINIT_RKEY_DATA` | 1.3.6.1.5.2.3.3 | Reply key pack content type |
| `ID_PKINIT_KDF` | 1.3.6.1.5.2.3.6 | KDF algorithm arc (RFC 8636) |
| `ID_PKINIT_KDF_AH_SHA1` | 1.3.6.1.5.2.3.6.1 | PKINIT KDF with SHA-1 |
| `ID_PKINIT_KDF_AH_SHA256` | 1.3.6.1.5.2.3.6.2 | PKINIT KDF with SHA-256 |
| `ID_PKINIT_KDF_AH_SHA384` | 1.3.6.1.5.2.3.6.4 | PKINIT KDF with SHA-384 |
| `ID_PKINIT_KDF_AH_SHA512` | 1.3.6.1.5.2.3.6.3 | PKINIT KDF with SHA-512 |
### Microsoft PKI OIDs
| `ID_MS_SAN_UPN` | 1.3.6.1.4.1.311.20.2.3 | `szOID_NT_PRINCIPAL_NAME` — UPN in OtherName |
| `ID_MS_CERTIFICATE_TEMPLATE_NAME` | 1.3.6.1.4.1.311.20.2 | `szOID_CERTIFICATE_TEMPLATE_NAME` (v1) |
| `ID_MS_CERTIFICATE_TEMPLATE` | 1.3.6.1.4.1.311.21.7 | `szOID_CERTIFICATE_TEMPLATE` (v2) |
| `ID_MS_KP_SMARTCARD_LOGON` | 1.3.6.1.4.1.311.20.2.2 | `szOID_MS_KP_SMARTCARD_LOGON` EKU |
| `ID_MS_NTDS_REPLICATION` | 1.3.6.1.4.1.311.25.1 | `szOID_NTDS_REPLICATION` EKU |
### PKCS#9 attribute OIDs (RFC 2985 / RFC 5652 / RFC 2986 / RFC 7292)
These are the signed-attribute OIDs used in CMS (RFC 5652 §11), CSR request
attributes (RFC 2986), and PKCS#12 bag attributes (RFC 7292).
| `PKCS9_EMAIL_ADDRESS` | 1.2.840.113549.1.9.1 | emailAddress |
| `PKCS9_CONTENT_TYPE` | 1.2.840.113549.1.9.3 | id-contentType (CMS signed attribute) |
| `PKCS9_MESSAGE_DIGEST` | 1.2.840.113549.1.9.4 | id-messageDigest (CMS signed attribute) |
| `PKCS9_SIGNING_TIME` | 1.2.840.113549.1.9.5 | id-signingTime (CMS signed attribute) |
| `PKCS9_COUNTERSIGNATURE` | 1.2.840.113549.1.9.6 | id-countersignature |
| `PKCS9_CHALLENGE_PASSWORD` | 1.2.840.113549.1.9.7 | id-challengePassword (PKCS#10 CSR) |
| `PKCS9_EXTENSION_REQUEST` | 1.2.840.113549.1.9.14 | id-extensionRequest (PKCS#10 CSR) |
| `PKCS9_FRIENDLY_NAME` | 1.2.840.113549.1.9.20 | id-friendlyName (PKCS#12 bag attribute) |
| `PKCS9_LOCAL_KEY_ID` | 1.2.840.113549.1.9.21 | id-localKeyId (PKCS#12 bag attribute) |
### `synta.oids.attr` — DN attribute OIDs
| `COMMON_NAME` | 2.5.4.3 | CN |
| `ORGANIZATION` | 2.5.4.10 | O |
| `ORG_UNIT` | 2.5.4.11 | OU |
| `COUNTRY` | 2.5.4.6 | C |
| `STATE` | 2.5.4.8 | ST |
| `LOCALITY` | 2.5.4.7 | L |
| `STREET` | 2.5.4.9 | street |
| `SERIAL_NUMBER` | 2.5.4.5 | serialNumber |
| `EMAIL_ADDRESS` | 1.2.840.113549.1.9.1 | emailAddress |
| `GIVEN_NAME` | 2.5.4.42 | givenName |
| `SURNAME` | 2.5.4.4 | SN |
| `TITLE` | 2.5.4.12 | title |
| `INITIALS` | 2.5.4.43 | initials |
| `ORG_IDENTIFIER` | 2.5.4.97 | organizationIdentifier |
| `USER_ID` | 0.9.2342.19200300.100.1.1 | uid |
| `DOMAIN_COMPONENT` | 0.9.2342.19200300.100.1.25 | dc |
---
## `synta.general_name` submodule
Integer constants for the `GeneralName` CHOICE type (RFC 5280 §4.2.1.6).
These are the `tag_number` values returned by `Certificate.subject_alt_names()`
and `synta.parse_general_names()`.
```python
import synta.general_name as gn
```
| `OTHER_NAME` | 0 | `otherName` | Full `OtherNameValue` TLV (constructed) |
| `RFC822_NAME` | 1 | `rfc822Name` | Raw IA5String bytes (e-mail address) |
| `DNS_NAME` | 2 | `dNSName` | Raw IA5String bytes (DNS host name) |
| `X400_ADDRESS` | 3 | `x400Address` | (rarely used) |
| `DIRECTORY_NAME` | 4 | `directoryName` | Complete Name SEQUENCE TLV — pass to `parse_name_attrs()` |
| `EDI_PARTY_NAME` | 5 | `ediPartyName` | (rarely used) |
| `URI` | 6 | `uniformResourceIdentifier` | Raw IA5String bytes (URI) |
| `IP_ADDRESS` | 7 | `iPAddress` | 4 bytes (IPv4) or 16 bytes (IPv6) |
| `REGISTERED_ID` | 8 | `registeredID` | Raw OID value bytes |
### Typical dispatch pattern
```python
import ipaddress
import synta
import synta.general_name as gn
for tag_num, content in cert.subject_alt_names():
if tag_num == gn.DNS_NAME:
print("DNS:", content.decode("ascii"))
elif tag_num == gn.IP_ADDRESS:
print("IP:", ipaddress.ip_address(content))
elif tag_num == gn.RFC822_NAME:
print("email:", content.decode("ascii"))
elif tag_num == gn.URI:
print("URI:", content.decode("ascii"))
elif tag_num == gn.DIRECTORY_NAME:
attrs = synta.parse_name_attrs(content) # [(oid_str, value_str), …]
print("DirName:", attrs)
```
The same constants apply when calling `synta.parse_general_names(san_der)` directly
on raw extnValue bytes obtained from `cert.get_extension_value_der(synta.oids.SUBJECT_ALT_NAME)`.
---
## `synta.krb5` submodule
### Principal-name type constants
Integer constants from RFC 4120 §6.2 and later:
| `NT_UNKNOWN` | 0 | Unknown |
| `NT_PRINCIPAL` | 1 | User/host principal |
| `NT_SRV_INST` | 2 | Service + instance (e.g. `krbtgt`) |
| `NT_SRV_HST` | 3 | Service + hostname |
| `NT_SRV_XHST` | 4 | Service + host (remaining components) |
| `NT_UID` | 5 | Unique ID |
| `NT_X500_PRINCIPAL` | 6 | Encoded X.500 DN |
| `NT_SMTP_NAME` | 7 | SMTP email address |
| `NT_ENTERPRISE` | 10 | Enterprise (UPN-style), RFC 6806 |
| `NT_WELLKNOWN` | 11 | Well-known (anonymous), RFC 8062 |
| `NT_SRV_HST_DOMAIN` | 12 | Host-based service, Windows MS-SFU |
Also: `KRB5_PRINCIPAL_NAME_OID` — `ObjectIdentifier("1.3.6.1.5.2.2")` — the
`id-pkinit-san` OID for `KRB5PrincipalName` OtherName entries.
### Krb5PrincipalName
RFC 4556 §3.2.2 `KRB5PrincipalName` SEQUENCE.
```python
Krb5PrincipalName(realm: str, name_type: int, components: list[str])
Krb5PrincipalName.from_der(data: bytes) -> Krb5PrincipalName
```
All string arguments must be ASCII; raises `ValueError` otherwise.
| `realm` | `str` | Kerberos realm (e.g. `"EXAMPLE.COM"`) |
| `name_type` | `int` | One of the `NT_*` constants |
| `components` | `list[str]` | Name-string components |
| `to_der()` | `bytes` | DER encode the `KRB5PrincipalName` SEQUENCE |
| `__repr__`, `__eq__` | | |
### PKINIT protocol classes
All PKINIT classes are **frozen** (immutable). Each class provides a
`from_der(data: bytes)` static method for parsing, and a `to_der()` method
for serialisation (where the encoding is well-defined).
#### EncryptionKey
RFC 3961 §2 `EncryptionKey`.
| `key_type` | `int` — encryption type (etype) |
| `key_value` | `bytes` — raw key material |
```python
EncryptionKey.from_der(data: bytes) -> EncryptionKey
```
#### Checksum
RFC 3961 §4 `Checksum`.
| `checksum_type` | `int` — checksum type |
| `checksum` | `bytes` — raw checksum bytes |
```python
Checksum.from_der(data: bytes) -> Checksum
```
#### KDFAlgorithmId
RFC 8636 §3.1 KDF algorithm identifier.
| `oid` | `ObjectIdentifier` — KDF algorithm OID |
```python
KDFAlgorithmId.from_der(data: bytes) -> KDFAlgorithmId
```
#### IssuerAndSerialNumber
RFC 4556 §3.2.2 certificate identifier.
| `issuer_raw_der` | `bytes` — DER of issuer Name SEQUENCE |
| `serial_number` | `bytes` — raw big-endian serial number bytes |
```python
IssuerAndSerialNumber.from_der(data: bytes) -> IssuerAndSerialNumber
```
#### ExternalPrincipalIdentifier
RFC 4556 §3.2.2 — identifies a client certificate by one of three optional methods.
| `subjectName` | `bytes \| None` — DER of subject Name |
| `issuerAndSerialNumber` | `bytes \| None` — DER of IssuerAndSerialNumber |
| `subjectKeyIdentifier` | `bytes \| None` — raw SKI bytes |
```python
ExternalPrincipalIdentifier.from_der(data: bytes) -> ExternalPrincipalIdentifier
```
#### PKAuthenticator
RFC 4556 §3.2.1 — client proof of liveness in AS-REQ.
| `cusec` | `int` — microseconds component of client time |
| `ctime` | `str` — client time as string |
| `nonce` | `int` — nonce value |
| `paChecksum` | `bytes \| None` — SHA-1 checksum of AS-REQ |
| `freshnessToken` | `bytes \| None` — RFC 8070 freshness token |
```python
PKAuthenticator.from_der(data: bytes) -> PKAuthenticator
```
#### AuthPack
RFC 4556 §3.2.1 — the content type signed by the client.
| `pkAuthenticator` | `PKAuthenticator` |
| `clientPublicValue` | `bytes \| None` — client DH public key (SubjectPublicKeyInfo DER) |
| `supportedCMSTypes` | `list[bytes]` — list of AlgorithmIdentifier DER blobs |
| `clientDHNonce` | `bytes \| None` — client DH nonce |
| `supportedKDFs` | `list[KDFAlgorithmId] \| None` — RFC 8636 KDF list |
```python
AuthPack.from_der(data: bytes) -> AuthPack
```
#### PaPkAsReq
RFC 4556 §3.2.2 — PKINIT pre-authentication request.
| `signed_auth_pack` | `bytes` — SignedData DER (contains `AuthPack`) |
| `trusted_certifiers` | `list[ExternalPrincipalIdentifier] \| None` |
| `kdc_pk_id` | `bytes \| None` — raw SKI bytes identifying the KDC certificate |
```python
PaPkAsReq.from_der(data: bytes) -> PaPkAsReq
```
#### DHRepInfo
RFC 4556 §3.2.4 — KDC Diffie-Hellman reply data.
| `dh_signed_data` | `bytes` — SignedData DER (contains `KDCDHKeyInfo`) |
| `server_dh_nonce` | `bytes \| None` — KDC DH nonce |
```python
DHRepInfo.from_der(data: bytes) -> DHRepInfo
```
#### KDCDHKeyInfo
RFC 4556 §3.2.4 — KDC DH public key and nonce.
| `subjectPublicKey` | `bytes` — KDC DH public key bits |
| `nonce` | `int` — nonce value |
| `dhKeyExpiration` | `str \| None` — optional expiry time |
```python
KDCDHKeyInfo.from_der(data: bytes) -> KDCDHKeyInfo
```
#### ReplyKeyPack
RFC 4556 §3.2.3 — session key and checksum from KDC (Diffie-Hellman-less path).
| `replyKey` | `EncryptionKey` — the session key |
| `asChecksum` | `Checksum` — checksum over the AS-REQ |
```python
ReplyKeyPack.from_der(data: bytes) -> ReplyKeyPack
```
#### PaPkAsRep
RFC 4556 §3.2.4 — PKINIT pre-authentication reply (CHOICE type).
| `variant` | `str` — `"dhInfo"` or `"encKeyPack"` |
| `value` | `bytes` — DER of the chosen alternative |
```python
PaPkAsRep.from_der(data: bytes) -> PaPkAsRep
```
---
## `synta.pkixalgs` submodule
RFC 3279 algorithm parameter types. Import with `import synta.pkixalgs`.
### DssParms
DSA domain parameters (RFC 3279 §2.3.2). Holds the `p`, `q`, `g` integers for a DSA
public key, decoded from the `parameters` field of an `AlgorithmIdentifier` whose OID
is `id-dsa`.
| `from_der(data)` | `DssParms` | Parse a DER-encoded `Dss-Parms` SEQUENCE |
| `to_der()` | `bytes` | DER encoding of this `Dss-Parms` SEQUENCE |
| `p` | `bytes` | Prime modulus (big-endian two's-complement) |
| `q` | `bytes` | Prime divisor |
| `g` | `bytes` | Generator |
### DssSigValue
DSA signature value (RFC 3279 §2.2.2). Contains the `(r, s)` integer pair produced
by the DSA signing operation.
| `from_der(data)` | `DssSigValue` | Parse a DER-encoded `Dss-Sig-Value` SEQUENCE |
| `to_der()` | `bytes` | DER encoding |
| `r` | `bytes` | Signature integer `r` (big-endian two's-complement) |
| `s` | `bytes` | Signature integer `s` |
### EcdsaSigValue
ECDSA signature value (RFC 3279 §2.2.3, X9.62). Contains the `(r, s)` integer pair
produced by the ECDSA signing operation.
| `from_der(data)` | `EcdsaSigValue` | Parse a DER-encoded `ECDSA-Sig-Value` SEQUENCE |
| `to_der()` | `bytes` | DER encoding |
| `r` | `bytes` | Signature integer `r` |
| `s` | `bytes` | Signature integer `s` |
### ECParameters
EC domain parameters CHOICE (RFC 3279 §2.3.5, X9.62). Represents the three-arm CHOICE:
`namedCurve` (OID), `ecParameters` (explicit domain params), or `implicitlyCA` (NULL).
| `from_der(data)` | `ECParameters` | Parse a DER-encoded `ECParameters` CHOICE |
| `to_der()` | `bytes` | DER encoding |
| `arm` | `str` | Active arm: `"namedCurve"`, `"ecParameters"`, or `"implicitlyCA"` |
| `named_curve_oid` | `ObjectIdentifier \| None` | Named-curve OID; `None` if arm is not `"namedCurve"` |
### OID constants (`synta.pkixalgs`)
| `ID_DSA` | `1.2.840.10040.4.1` | DSA public key |
| `ID_DSA_WITH_SHA1` | `1.2.840.10040.4.3` | DSA with SHA-1 |
| `DHPUBLICNUMBER` | `1.2.840.10046.2.1` | DH public key |
| `ID_EC_PUBLIC_KEY` | `1.2.840.10045.2.1` | EC public key |
| `ECDSA_WITH_SHA1` | `1.2.840.10045.4.1` | ECDSA with SHA-1 |
| `ECDSA_WITH_SHA256` | `1.2.840.10045.4.3.2` | ECDSA with SHA-256 |
| `ECDSA_WITH_SHA384` | `1.2.840.10045.4.3.3` | ECDSA with SHA-384 |
| `ECDSA_WITH_SHA512` | `1.2.840.10045.4.3.4` | ECDSA with SHA-512 |
| `PRIME192V1` | `1.2.840.10045.3.1.1` | NIST P-192 / secp192r1 |
| `PRIME256V1` | `1.2.840.10045.3.1.7` | NIST P-256 / secp256r1 |
| `SECP224R1` | `1.3.132.0.33` | NIST P-224 |
| `SECP384R1` | `1.3.132.0.34` | NIST P-384 |
| `SECP521R1` | `1.3.132.0.35` | NIST P-521 |
---
## `synta.ac` submodule
RFC 5755 Attribute Certificate v2 types. Import with `import synta.ac`.
### AttributeCertificate
An Attribute Certificate (AC) binds a set of attributes (roles, clearances,
service-authentication information) to a holder identified by reference to their
Public Key Certificate (PKC), without requiring re-issuance of the PKC.
| `from_der(data)` | `AttributeCertificate` | Parse a DER-encoded `AttributeCertificate` SEQUENCE |
| `to_der()` | `bytes` | DER encoding |
| `version` | `int` | `AttCertVersion` integer (always `1` for v2 per RFC 5755) |
| `serial_number` | `bytes` | Certificate serial number as big-endian bytes |
| `not_before` | `str` | Validity start as GeneralizedTime string, e.g. `"20240101120000Z"` |
| `not_after` | `str` | Validity end as GeneralizedTime string |
| `signature_algorithm_oid` | `ObjectIdentifier` | Signature algorithm OID |
| `signature` | `bytes` | Raw signature bytes (bit-string value, zero-byte padding stripped) |
| `holder_der` | `bytes` | DER bytes of the `Holder` SEQUENCE |
| `issuer_der` | `bytes` | DER bytes of the `AttCertIssuer` CHOICE |
| `attributes_der` | `bytes` | DER bytes of the `SEQUENCE OF Attribute` attributes field |
### OID constants (`synta.ac`)
| `ID_PE_AC_AUDIT_IDENTITY` | Audit identity extension (RFC 5755 §4.4.1) |
| `ID_PE_AA_CONTROLS` | AA controls extension (RFC 5755 §4.4.2) |
| `ID_PE_AC_PROXYING` | AC proxying extension (RFC 5755 §4.4.3) |
| `ID_CE_TARGET_INFORMATION` | Target information extension (RFC 5755 §4.3.2) |
| `ID_ACA_AUTHENTICATION_INFO` | Authentication information attribute |
| `ID_ACA_ACCESS_IDENTITY` | Access identity attribute |
| `ID_ACA_CHARGING_IDENTITY` | Charging identity attribute |
| `ID_ACA_GROUP` | Group attribute |
| `ID_ACA_ENC_ATTRS` | Encrypted attributes |
| `ID_AT_ROLE` | Role attribute type |
| `ID_AT_CLEARANCE` | Clearance attribute type |
---
## `synta.crmf` submodule
RFC 4211 Certificate Request Message Format types. Import with `import synta.crmf`.
### CertReqMessages
A batch of Certificate Request Messages (`SEQUENCE OF CertReqMsg`, RFC 4211 §3).
| `from_der(data)` | `CertReqMessages` | Parse a DER-encoded `CertReqMessages` SEQUENCE OF |
| `to_der()` | `bytes` | DER encoding |
| `requests` | `list[CertReqMsg]` | List of `CertReqMsg` objects |
| `__len__()` | `int` | Number of requests in the batch |
| `__iter__()` | iterator | Iterate over `CertReqMsg` objects |
| `__getitem__(index)` | `CertReqMsg` | Access a specific request by zero-based index |
### CertReqMsg
A single certificate request message (RFC 4211 §4). Obtained by indexing or iterating
a `CertReqMessages` object.
| `cert_req_id` | `int` | The `certReqId` integer identifying this request in the batch |
| `cert_template_der` | `bytes` | DER bytes of the `CertTemplate` SEQUENCE (all fields optional) |
| `popo_type` | `str \| None` | Active `ProofOfPossession` arm name, or `None` if absent; one of `"raVerified"`, `"signature"`, `"keyEncipherment"`, `"keyAgreement"` |
| `popo_der` | `bytes \| None` | DER bytes of the `ProofOfPossession` CHOICE, or `None` |
| `subject_der` | `bytes \| None` | DER bytes of the `subject` `Name` from `CertTemplate`, or `None` |
| `issuer_der` | `bytes \| None` | DER bytes of the `issuer` `Name` from `CertTemplate`, or `None` |
### OID constants (`synta.crmf`)
| `ID_REG_CTRL_REG_TOKEN` | Registration token control (RFC 4211 §6.1) |
| `ID_REG_CTRL_AUTHENTICATOR` | Authenticator control (RFC 4211 §6.2) |
| `ID_REG_CTRL_PKI_PUBLICATION_INFO` | PKI publication info control (RFC 4211 §6.3) |
| `ID_REG_CTRL_PKI_ARCHIVE_OPTIONS` | PKI archive options control (RFC 4211 §6.4) |
| `ID_REG_CTRL_OLD_CERT_ID` | Old certificate ID control (RFC 4211 §6.5) |
| `ID_REG_CTRL_PROTOCOL_ENCR_KEY` | Protocol encryption key control (RFC 4211 §6.6) |
| `ID_REG_INFO_UTF8_PAIRS` | UTF-8 pairs registration info (RFC 4211 §7.1) |
| `ID_REG_INFO_CERT_REQ` | Certificate request registration info (RFC 4211 §7.2) |
---
## `synta.cmp` submodule
RFC 9810 Certificate Management Protocol v3 types. Import with `import synta.cmp`.
### CMPMessage
A CMP `PKIMessage` (RFC 9810 §5.1) — the top-level CMP envelope carrying a `PKIHeader`
and a `PKIBody`. Use `body_type` to identify the message type and `body_der` to decode
the body payload with the appropriate submodule.
| `from_der(data)` | `CMPMessage` | Parse a DER-encoded `PKIMessage` SEQUENCE |
| `to_der()` | `bytes` | DER encoding |
| `pvno` | `int` | CMP protocol version number (`pvno`; `2` for CMP v2/v3) |
| `body_type` | `str` | Active `PKIBody` arm in lowercase: `"ir"`, `"ip"`, `"cr"`, `"cp"`, `"rr"`, `"rp"`, `"pkiconf"`, `"error"`, `"certConf"`, `"genm"`, `"genp"`, etc. |
| `body_der` | `bytes \| None` | DER bytes of the `PKIBody` content; `None` for `"pkiconf"` (NULL). For `"ir"`/`"cr"` arms this is a `CertReqMessages` SEQUENCE OF |
| `sender_der` | `bytes` | DER bytes of the `sender` `GeneralName` field |
| `recipient_der` | `bytes` | DER bytes of the `recipient` `GeneralName` field |
| `transaction_id` | `bytes \| None` | `transactionID` bytes, or `None` |
| `sender_nonce` | `bytes \| None` | `senderNonce` bytes, or `None` |
| `recip_nonce` | `bytes \| None` | `recipNonce` bytes, or `None` |
| `protection_alg_oid` | `ObjectIdentifier \| None` | OID of the `protectionAlg` `AlgorithmIdentifier`, or `None` |
| `message_time` | `str \| None` | `messageTime` as a GeneralizedTime string, or `None` |
### OID constants (`synta.cmp`)
| `ID_PASSWORD_BASED_MAC` | Password-based MAC algorithm (RFC 9810 Appendix D) |
| `ID_DHBASED_MAC` | DH-based MAC algorithm |
| `ID_KEM_BASED_MAC` | KEM-based MAC algorithm |
| `ID_KP_CM_KGA` | CMP key-generation authority key purpose (RFC 9810 §4) |
| `ID_REG_CTRL_ALT_CERT_TEMPLATE` | Alternate certificate template control |
| `ID_REG_CTRL_ALG_ID` | Algorithm ID control |
| `ID_REG_CTRL_RSA_KEY_LEN` | RSA key length control |
---
## `synta.x509` submodule
RFC 5280 §6 + CABF Baseline Requirements certificate chain verification.
Import as:
```python
import synta.x509 as x509
```
### TrustStore
```python
class TrustStore:
def __init__(self, certs_der: list[bytes]) -> None: ...
@property
def len(self) -> int: ...
def __repr__(self) -> str: ...
```
| `certs_der` | `list[bytes]` | DER-encoded trusted root CA certificates (one entry per certificate) |
```python
import synta
import synta.x509 as x509
with open("roots.pem", "rb") as f:
pem_data = f.read()
ders = synta.pem_to_der(pem_data) # list[bytes]: one entry per PEM block
store = x509.TrustStore(ders)
print(store.len) # number of roots loaded
```
### VerificationPolicy
```python
class VerificationPolicy:
def __init__(
self,
*,
server_names: list[str] | None = None,
name_match: str | None = None,
validation_time: int | None = None,
max_chain_depth: int = 8,
profile: str | None = None,
) -> None: ...
def __repr__(self) -> str: ...
```
| `server_names` | `list[str]` | `[]` | DNS hostnames or IP literals; empty = skip SAN matching |
| `name_match` | `str` | `"any"` | `"any"` — at least one name must match; `"all"` — every name must match |
| `validation_time` | `int \| None` | `None` (now) | Unix epoch seconds for validity window check |
| `max_chain_depth` | `int` | `8` | Maximum number of intermediate CAs |
| `profile` | `str \| None` | `"webpki"` | `"webpki"` (CABF BRs) or `"rfc5280"` (strict RFC 5280) |
### CrlStore
```python
class CrlStore:
def __init__(self, crl_ders: list[bytes]) -> None: ...
@property
def len(self) -> int: ...
def __repr__(self) -> str: ...
```
| `crl_ders` | `list[bytes]` | DER-encoded CRLs (one entry per CRL) |
Pass a populated `CrlStore` to `verify_server_certificate` or `verify_client_certificate`
via the `crls` keyword argument. Certificates whose issuing CA has no matching CRL are
treated as not-revoked (soft-fail); a well-signed, in-date CRL that lists the
certificate's serial number causes `X509VerificationError` (hard-fail).
```python
import synta
import synta.x509 as x509
# From a PEM-encoded CRL file:
crl_ders = synta.pem_to_der(open("issuing-ca.crl", "rb").read())
crl_store = x509.CrlStore(crl_ders)
# From DER directly:
crl_store = x509.CrlStore([open("issuing-ca.crl.der", "rb").read()])
store = x509.TrustStore([root_der])
policy = x509.VerificationPolicy(server_names=["example.com"])
chain = x509.verify_server_certificate(leaf_der, [], store, policy, crls=crl_store)
```
### verify_server_certificate
```python
def verify_server_certificate(
leaf_der: bytes,
intermediates_der: list[bytes],
trust_store: TrustStore,
policy: VerificationPolicy | None = None,
crls: CrlStore | None = None,
) -> list[bytes]: ...
```
Returns the validated chain as `list[bytes]`, root-first (`chain[0]` is the trust anchor,
`chain[-1]` is the leaf). Raises `X509VerificationError` if the chain cannot be built
or fails a policy check.
### verify_client_certificate
```python
def verify_client_certificate(
leaf_der: bytes,
intermediates_der: list[bytes],
trust_store: TrustStore,
policy: VerificationPolicy | None = None,
crls: CrlStore | None = None,
) -> list[bytes]: ...
```
Like `verify_server_certificate` but enforces the `clientAuth` EKU and skips SAN matching.
The `server_names` field of `VerificationPolicy` is ignored.
| `synta.x509.X509VerificationError` | Chain cannot be built, policy check fails, or certificate is expired, untrusted, or has an invalid name |
| `synta.EOFError` | Truncated DER in `leaf_der`, `intermediates_der`, or `crl_ders` |
| `ValueError` | Malformed DER tag, length, or encoding |
---
## Exceptions
| `synta.SyntaError` | ASN.1 parse or encode failure (wraps the Rust `synta::Error`) |
| `synta.x509.X509VerificationError` | Certificate chain verification failure (see `synta.x509` submodule) |
| `ValueError` | Invalid arguments (e.g. invalid OID string, bad charset for PrintableString, wrong password format) |
| `OverflowError` | `Integer.to_int()` / `to_i128()` when the value does not fit |
| `EOFError` | `Decoder.peek_tag()` when no data remains |
| `ImportError` | `Certificate.to_pyca()` / `from_pyca()` when `cryptography` is not installed |
---
## Example programs
Twenty-two runnable programs in `examples/` exercise every binding documented
above. Each program is self-contained and runs with `uv run python3
examples/example_<name>.py` from the repository root.
### 1. [`examples/example_pem_helpers.py`](../examples/example_pem_helpers.py) — PEM ↔ DER conversion
Bindings: `pem_to_der`, `der_to_pem`, `Certificate.from_pem`, `Certificate.to_pem`,
`CertificationRequest.from_pem`, `CertificationRequest.to_pem`,
`CertificateList.from_pem`, `CertificateList.to_pem`.
- Round-trip a single PEM certificate block through `pem_to_der` / `der_to_pem` (`pem_to_der` always returns `list[bytes]`).
- Show `pem_to_der` with a multi-block PEM chain.
- Use `Certificate.from_pem` on a single block and on a two-certificate chain.
- Use `Certificate.to_pem` on a single cert and a list of certs.
### 2. [`examples/example_certificate_fields.py`](../examples/example_certificate_fields.py) — All Certificate properties
Bindings: `Certificate.from_der`, `Certificate.full_from_der`, all `Certificate`
properties (`serial_number`, `version`, `issuer`, `issuer_raw_der`, `subject`,
`subject_raw_der`, `not_before`, `not_after`, `signature_algorithm`,
`signature_algorithm_oid`, `signature_algorithm_params`, `signature_value`,
`public_key_algorithm`, `public_key_algorithm_oid`, `public_key_algorithm_params`,
`public_key`, `tbs_bytes`), and `Certificate.to_der()` method.
- Parse the same certificate with `from_der` (lazy) and `full_from_der` (eager).
- Print every property with its Python type.
- Verify `to_der()` round-trip (re-parse the returned bytes).
- Show `signature_algorithm_params` is `None` for Ed25519 and non-`None` for RSA.
### 3. [`examples/example_certificate_extensions.py`](../examples/example_certificate_extensions.py) — Extension access and SAN parsing
Bindings: `Certificate.subject_alt_names`, `Certificate.extensions_der`,
`Certificate.get_extension_value_der`, `synta.general_name` tag constants,
`synta.parse_general_names`, `synta.parse_name_attrs`,
`synta.oids.SUBJECT_ALT_NAME`, `synta.oids.BASIC_CONSTRAINTS`,
`synta.oids.SUBJECT_KEY_IDENTIFIER`, `Decoder.decode_sequence`, `Decoder.peek_tag`,
`Decoder.decode_implicit_tag`, `Decoder.decode_explicit_tag`,
`Decoder.remaining_bytes`, `Decoder.decode_raw_tlv`, `Decoder.is_empty`.
- Call `cert.subject_alt_names()` for high-level SAN access; dispatch on
`synta.general_name` constants (`gn.DNS_NAME`, `gn.IP_ADDRESS`, etc.);
use `ipaddress.ip_address(content)` for IP rendering.
- Verify that a certificate without a SAN extension returns an empty list.
- Access `extensions_der` and iterate the raw extension TLVs.
- Look up individual extensions by `get_extension_value_der`.
- Parse SAN entries manually with `peek_tag` / `decode_implicit_tag`
as a lower-level alternative to `subject_alt_names()`.
- Demonstrate `peek_tag` for CHOICE dispatch; `remaining_bytes` for primitive implicit values.
- Look up BasicConstraints and decode the cA BOOLEAN.
### 4. [`examples/example_certificate_pyca.py`](../examples/example_certificate_pyca.py) — PyCA interoperability
Bindings: `Certificate.to_pyca`, `Certificate.from_pyca`.
- Parse a DER certificate with synta, then call `.to_pyca()` for cryptographic operations.
- Load a PyCA certificate, convert to synta with `from_pyca()`, and compare fields.
- Show `ImportError` message when `cryptography` is absent (caught and printed).
### 5. [`examples/example_csr.py`](../examples/example_csr.py) — PKCS#10 CSR parsing
Bindings: `CertificationRequest.from_der`, `CertificationRequest.from_pem`,
`CertificationRequest.to_pem`, and all `CertificationRequest` properties.
- Parse a CSR from DER and print every field.
- Round-trip through PEM with `from_pem` / `to_pem`.
- Verify `subject_raw_der` by re-decoding it as a raw Name SEQUENCE.
### 6. [`examples/example_crl.py`](../examples/example_crl.py) — CRL parsing
Bindings: `CertificateList.from_der`, `CertificateList.from_pem`,
`CertificateList.to_pem`, and all `CertificateList` properties.
- Parse a CRL and print issuer, dates, algorithm, revoked count.
- Show `next_update` is `None` for CRLs that omit the field.
- Round-trip through `to_pem` / `from_pem`.
### 7. [`examples/example_ocsp.py`](../examples/example_ocsp.py) — OCSP response parsing
Bindings: `OCSPResponse.from_der`, `OCSPResponse.from_pem`, `OCSPResponse.to_pem`,
and all `OCSPResponse` properties.
- Parse a successful OCSP response; print `status`, `response_type_oid`, length of `response_bytes`.
- Parse a non-successful response (e.g. `tryLater`); confirm `response_bytes` is `None`.
- Round-trip through `to_pem` / `from_pem`.
### 8. [`examples/example_pkcs7.py`](../examples/example_pkcs7.py) — PKCS#7 certificate bundles
Bindings: `load_der_pkcs7_certificates`, `load_pem_pkcs7_certificates`.
- Load a `.p7b` file and print the subject of each extracted certificate.
- Demonstrate PEM-encoded PKCS#7 with `load_pem_pkcs7_certificates`.
- Show `ValueError` for non-PKCS#7 input.
### 9. [`examples/example_pkcs12.py`](../examples/example_pkcs12.py) — PKCS#12 archive parsing and creation
Bindings: `load_pkcs12_certificates`, `load_pkcs12_keys`, `load_pkcs12`,
`create_pkcs12`.
- Parse a password-less PKCS#12 file; print subjects of extracted certificates.
- Extract private keys using `load_pkcs12_keys`; show raw PKCS#8 DER length.
- Extract both with `load_pkcs12`; show the `(certs, keys)` tuple.
- Parse an AES-256-CBC encrypted PKCS#12 with a password.
- Show `ValueError` for wrong password (encrypted case, with `openssl` feature).
- Build a PFX from extracted certificates using `create_pkcs12` without a password.
- Build a password-protected PFX with `create_pkcs12` (requires `openssl` feature).
- Build a cert+key PFX bundle.
- Roundtrip: build an archive then parse it back and verify the extracted certificates.
### 10. [`examples/example_pki_blocks.py`](../examples/example_pki_blocks.py) — Format-agnostic PKI reader
Bindings: `read_pki_blocks`.
- Pass PEM, DER, PKCS#7, and PKCS#12 bytes to `read_pki_blocks` and print the
`(label, len(der))` tuples returned.
- Show PKCS#12 password handling.
### 11. [`examples/example_objectidentifier.py`](../examples/example_objectidentifier.py) — ObjectIdentifier constructors and operations
Bindings: `ObjectIdentifier(str)`, `ObjectIdentifier.from_components`,
`ObjectIdentifier.from_der_value`, `ObjectIdentifier.components`,
`ObjectIdentifier.__eq__`, `ObjectIdentifier.__hash__`,
`Decoder.decode_oid`, `Encoder.encode_oid`, `Encoder.encode_oid_object`.
- Construct OIDs via all three constructors; verify they compare equal.
- Show `__eq__` working against a dotted string.
- Use OIDs as dict keys (demonstrate hashability).
- Round-trip through `encode_oid` / `decode_oid`.
- Show `from_der_value` with the raw content bytes from an implicit-tag context.
### 12. [`examples/example_oids_catalog.py`](../examples/example_oids_catalog.py) — `synta.oids` constant groups
Bindings: every constant in `synta.oids` and `synta.oids.attr`,
plus the helper functions `identify_signature_algorithm`,
`identify_public_key_algorithm`.
- Print algorithm OIDs (RSA, EC, EdDSA, ML-DSA, ML-KEM).
- Print hash OIDs (SHA-2, SHA-3).
- Print SLH-DSA OIDs.
- Print prefix OIDs and demonstrate `components()`-based prefix matching.
- Print X.509v3 extension OIDs.
- Print EKU OIDs.
- Print PKINIT OIDs.
- Print MS PKI OIDs.
- Print all nine PKCS#9 attribute OIDs (`PKCS9_EMAIL_ADDRESS`, `PKCS9_CONTENT_TYPE`,
`PKCS9_MESSAGE_DIGEST`, `PKCS9_SIGNING_TIME`, `PKCS9_COUNTERSIGNATURE`,
`PKCS9_CHALLENGE_PASSWORD`, `PKCS9_EXTENSION_REQUEST`, `PKCS9_FRIENDLY_NAME`,
`PKCS9_LOCAL_KEY_ID`).
- Print every `synta.oids.attr` DN attribute OID with its RFC 4514 label.
### 13. [`examples/example_time_types.py`](../examples/example_time_types.py) — UtcTime and GeneralizedTime
Bindings: `UtcTime(…)`, `UtcTime` properties (`year`, `month`, `day`, `hour`,
`minute`, `second`), `GeneralizedTime(…)`, `GeneralizedTime` properties,
`Encoder.encode_utc_time`, `Encoder.encode_utc_time_object`,
`Encoder.encode_generalized_time`, `Encoder.encode_generalized_time_object`,
`Decoder.decode_utc_time`, `Decoder.decode_generalized_time`.
- Construct both time types and inspect every property.
- Round-trip each through encode / decode; verify string representations.
- Show millisecond sub-second precision on `GeneralizedTime`.
- Show `ValueError` for out-of-range UTCTime year (< 1950 or > 2049).
- Demonstrate `encode_utc_time_object` and `encode_generalized_time_object` variants.
### 14. [`examples/example_integer_advanced.py`](../examples/example_integer_advanced.py) — Integer edge cases and bigint
Bindings: `Integer(int)`, `Integer.from_bytes`, `Integer.from_u64`,
`Integer.to_int`, `Integer.to_i128`, `Integer.to_bytes`,
`Encoder.encode_integer` (bigint path), `Encoder.encode_integer_object`.
- Construct integers via all three constructors.
- Show `to_int()` succeeds for small values; raises `OverflowError` for 20-byte serials.
- Use `to_i128()` for up to 16-byte values (i128 max = 2¹²⁷−1); show `OverflowError` beyond that.
- Use `to_bytes()` for arbitrary-precision big-endian representation.
- Encode a 20-byte certificate serial number via `encode_integer(large_python_int)`.
- Verify `encode_integer_object` round-trip.
### 15. [`examples/example_string_types_advanced.py`](../examples/example_string_types_advanced.py) — Alternative string constructors
Bindings: `TeletexString.from_latin1`, `TeletexString.from_str`,
`GeneralString.from_ascii`, `GeneralString.from_str`,
`UniversalString.from_bytes`, `BmpString.from_bytes`,
plus `to_bytes()` / `as_str()` on each.
- Construct `TeletexString` from bytes and Latin-1 strings; `GeneralString` from bytes and ASCII strings.
- Construct `UniversalString` and `BmpString` from raw UCS-4/UCS-2 byte buffers.
- Show `ValueError` when non-BMP code points are passed to `BmpString`.
- Round-trip each through the encoder / decoder.
### 16. [`examples/example_decoder_advanced.py`](../examples/example_decoder_advanced.py) — Advanced Decoder operations
Bindings: `Decoder.decode_set`, `Decoder.peek_tag`, `Decoder.decode_raw_tlv`,
`Decoder.remaining_bytes`, `Decoder.decode_implicit_tag`, `Decoder.position`,
`Decoder.remaining`, `Decoder.is_empty`, `Decoder.decode_any_str`.
- Build a hand-crafted SET and decode it with `decode_set`.
- Use `peek_tag` in a loop to drive CHOICE dispatch.
- Capture unknown elements with `decode_raw_tlv`.
- Use `decode_implicit_tag` + `remaining_bytes` to decode a primitive implicit type
(e.g. `[2] IMPLICIT IA5String` for a dNSName GeneralName).
- Show `position()` and `remaining()` advancing through multi-element input.
- Use `decode_any_str()` to decode a mixed-string SEQUENCE without tag inspection.
### 17. [`examples/example_encoder_advanced.py`](../examples/example_encoder_advanced.py) — Advanced Encoder operations
Bindings: `Encoder.encode_implicit_tag`, `Encoder.encode_set`,
`Encoder.encode_explicit_tag`, `Encoder.encode_sequence`,
and all `_object` variants not demonstrated elsewhere.
- Build a SET containing two PrintableStrings using `encode_set`.
- Encode an implicit context tag `[2] IMPLICIT IA5String` (dNSName).
- Encode a nested structure: SEQUENCE { [0] EXPLICIT SEQUENCE { INTEGER } }.
- Demonstrate every `_object` encode variant with a typed object sourced from a decode.
- Show `ValueError` for unknown tag class strings.
### 18. [`examples/example_krb5_principal.py`](../examples/example_krb5_principal.py) — Kerberos principal names
Bindings: `synta.krb5.Krb5PrincipalName`, `synta.krb5.KRB5_PRINCIPAL_NAME_OID`,
and every `NT_*` constant.
- Construct `Krb5PrincipalName` instances for each name type (`NT_PRINCIPAL`,
`NT_SRV_INST`, `NT_SRV_HST`, `NT_ENTERPRISE`, `NT_WELLKNOWN`).
- Encode each with `to_der()` and decode back with `from_der()`.
- Verify realm, name_type, and components survive the round-trip.
- Show `__eq__` and `__repr__`.
- Print `KRB5_PRINCIPAL_NAME_OID` and demonstrate it matches `synta.oids.ID_PKINIT_SAN`.
- Show `ValueError` for non-ASCII realm or component.
### 19. [`examples/example_krb5_pkinit.py`](../examples/example_krb5_pkinit.py) — PKINIT protocol classes
Bindings: `EncryptionKey`, `Checksum`, `KDFAlgorithmId`, `IssuerAndSerialNumber`,
`ExternalPrincipalIdentifier`, `PKAuthenticator`, `AuthPack`, `PaPkAsReq`,
`DHRepInfo`, `KDCDHKeyInfo`, `ReplyKeyPack`, `PaPkAsRep`.
For each class: parse hand-crafted DER bytes with `from_der`, access every property,
and print a summary of key values.
### 20. [`examples/example_error_handling.py`](../examples/example_error_handling.py) — Exception catalogue
Bindings: `synta.SyntaError`, `ValueError`, `OverflowError`, `EOFError`.
- Inspect `SyntaError` as a module exception class (MRO, `issubclass` check).
- Demonstrate `EOFError` from empty input, tag-only input, and truncated value in `Decoder`.
- Demonstrate `ValueError` from tag mismatch (decoding BOOLEAN as INTEGER).
- Demonstrate `ValueError` from DER constraint violations (non-canonical BOOLEAN, non-minimal INTEGER).
- Demonstrate `OverflowError` from `Integer.to_int()` and `to_i128()` on values exceeding the target type.
- Demonstrate `ValueError` from constructor validation: `BmpString` with a non-BMP character,
`GeneralizedTime` with an invalid month, `ObjectIdentifier` with a malformed string,
`Krb5PrincipalName` with a non-ASCII realm, `GeneralString.from_ascii` with a non-ASCII character.
### 21. [`examples/example_cms_encrypted_data.py`](../examples/example_cms_encrypted_data.py) — CMS EncryptedData round-trip
Bindings: `synta.cms.EncryptedData`, `synta.cms.ID_AES128_CBC`,
`synta.cms.ID_AES192_CBC`, `synta.cms.ID_AES256_CBC`.
Requires the `openssl` Cargo feature (`maturin develop --features openssl`).
- Create an `EncryptedData` with `EncryptedData.create` (AES-128-CBC) and inspect
all properties: `version`, `content_type`, `content_encryption_algorithm_oid`,
`content_encryption_algorithm_params` (IV extraction), `encrypted_content`.
- Decrypt → replace text in plaintext → re-encrypt with a fresh random IV;
verify the round-trip with `to_der()` / `from_der()`.
- Encrypt with each of AES-128/192/256-CBC using `ID_AES128_CBC`,
`ID_AES192_CBC`, `ID_AES256_CBC`; confirm random IV differs across calls.
- Verify synta-produced ciphertext with `openssl enc -d` (synta → openssl
interop).
- Inspect the `EncryptedData` DER structure with `openssl asn1parse`.
- Encrypt raw bytes with `openssl enc -e`, wrap in an `EncryptedData` DER
by hand, parse with `from_der`, and decrypt with synta (openssl → synta
interop).
### 22. [`examples/example_x509_verify.py`](../examples/example_x509_verify.py) — X.509 certificate chain verification
Bindings: `synta.x509.TrustStore`, `synta.x509.VerificationPolicy`,
`synta.x509.verify_server_certificate`, `synta.x509.verify_client_certificate`,
`synta.x509.X509VerificationError`.
Requires the `openssl` Cargo feature (`maturin develop --features openssl`).
- Build a self-signed root CA DER in memory with `openssl req -x509` and load it
into a `TrustStore`; print `store.len` and `repr(store)`.
- Verify a leaf certificate signed by that root with `verify_server_certificate`;
print the chain length and each certificate's subject with
`synta.Certificate.from_der`.
- Demonstrate `VerificationPolicy` variants: single name, multi-name `any`, multi-name
`all`, fixed `validation_time`, `max_chain_depth`, `profile="rfc5280"`.
- Demonstrate client certificate verification with `verify_client_certificate`.
- Show that `X509VerificationError` is raised when the trust store does not contain
the issuer, the server name does not match the SAN, and the validation time is
outside the validity window.