Certificate
Certificate represents an RFC 5280 X.509 v3 certificate. Parsing is lazy: from_der
performs only a 4-operation shallow scan (outer SEQUENCE TLV + TBSCertificate SEQUENCE TLV);
the full RFC 5280 decode is deferred to the first field access, after which every property
is cached in an OnceLock and returned in O(1) on subsequent calls.
Construction
Certificate.from_der(data: bytes) -> Certificate
Parse a DER-encoded X.509 certificate. Performs a shallow 4-operation structural scan on construction; the full decode is deferred to the first field access.
Certificate.full_from_der(data: bytes) -> Certificate
Parse and perform a complete RFC 5280 decode immediately. All field getters are on the warm path from the first call. Use when benchmarking full parse cost or when latency on the first field access must be avoided.
Certificate.from_pem(data: bytes) -> Certificate | list[Certificate]
Parse a PEM-encoded certificate. Returns a single Certificate for a single PEM block, or
a list[Certificate] when multiple blocks are present.
Certificate.to_pem(cert_or_list) -> bytes
Encode one or more Certificate objects back to PEM.
Certificate.from_pyca(pyca_cert: object) -> Certificate
Convert a cryptography.x509.Certificate to a synta.Certificate by serialising to DER
and calling from_der. Raises ImportError if the cryptography package is not installed.
cert.to_pyca() -> cryptography.x509.Certificate
Return a cryptography.x509.Certificate backed by the same DER bytes (no re-encoding).
Use for cryptographic operations not directly supported by synta. Raises ImportError if
the cryptography package is not installed.
Properties
All properties are cached after first access. to_der skips the lock entirely (direct
reference to the stored bytes, no copy).
Identity
| Property | Type | Description |
|---|---|---|
serial_number | int | Arbitrary-precision Python int (RFC 5280: up to 20 bytes) |
version | int | None | Version field: None = 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 |
Validity
| Property | Type | Description |
|---|---|---|
not_before | str | "YYMMDDHHMMSSZ" (UTCTime) or "YYYYMMDDHHMMSSZ" (GeneralizedTime) |
not_after | str | Same format as not_before |
Signature
| Property | Type | Description |
|---|---|---|
signature_algorithm | str | Human-readable algorithm name (e.g. "RSA", "ECDSA", "ML-DSA-65") or dotted OID for unrecognised algorithms |
signature_algorithm_oid | ObjectIdentifier | Always machine-readable dotted OID |
signature_algorithm_params | bytes | None | DER-encoded parameters, or None when absent (e.g. Ed25519) |
signature_value | bytes | Raw signature bytes (BIT STRING value, unused-bit prefix stripped) |
Subject Public Key
| Property | Type | Description |
|---|---|---|
public_key_algorithm | str | Human-readable name or dotted OID |
public_key_algorithm_oid | ObjectIdentifier | Dotted OID (e.g. "1.2.840.10045.2.1" for id-ecPublicKey) |
public_key_algorithm_params | bytes | None | DER parameters (curve OID for EC; None for RSA/EdDSA) |
public_key | bytes | Raw SubjectPublicKeyInfo BIT STRING content (unused-bit byte stripped) |
subject_public_key_info_raw_der | bytes | Full SubjectPublicKeyInfo SEQUENCE DER (for SKI/AKI computation) |
Raw DER Spans
| Property / Method | Type | Description |
|---|---|---|
to_der() | bytes | Complete original certificate DER (zero-copy) |
tbs_bytes | bytes | TBSCertificate DER — the bytes that were signed |
issuer_raw_der | bytes | Issuer Name SEQUENCE DER |
subject_raw_der | bytes | Subject Name SEQUENCE DER |
extensions_der | bytes | None | SEQUENCE OF Extension DER, or None for v1/v2 |
Methods
| Method | Signature | Returns | Description |
|---|---|---|---|
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. Scans in O(n) over the already-parsed Extension list. Raises ValueError for invalid OID strings. |
subject_alt_names() | () | list[tuple[int, bytes]] | SAN entries as (tag_number, content) pairs. Returns [] when no SAN extension is present. Use synta.general_name constants to dispatch on tag_number. |
general_names | (oid: str | ObjectIdentifier) | list[tuple[int, bytes]] | Decode any extension whose value is SEQUENCE OF GeneralName. |
certificate_policies() | () | list[PolicyInformation] | Decode the CertificatePolicies extension (OID 2.5.29.32). Returns [] when absent. |
verify_issued_by | (issuer: Certificate) | None | Verify this certificate was signed by issuer. Raises ValueError on failure. |
fingerprint | (algorithm: str) | bytes | Certificate fingerprint using the named hash (e.g. "sha256"). Raises ValueError for unknown algorithms. |
Full class stub
class Certificate:
@staticmethod
def from_der(data: bytes) -> Certificate: ...
@staticmethod
def full_from_der(data: bytes) -> Certificate: ...
@staticmethod
def from_pyca(pyca_cert: object) -> Certificate: ...
def to_pyca(self) -> object: ...
def __repr__(self) -> str: ...
# Identity
serial_number: int
version: int | None
issuer: str
issuer_raw_der: bytes
subject: str
subject_raw_der: bytes
# Validity
not_before: str
not_after: str
# Signature
signature_algorithm: str
signature_algorithm_oid: ObjectIdentifier
signature_algorithm_params: bytes | None
signature_value: bytes
# Subject public key
public_key_algorithm: str
public_key_algorithm_oid: ObjectIdentifier
public_key_algorithm_params: bytes | None
public_key: bytes
subject_public_key_info_raw_der: bytes
# Raw DER spans
def to_der(self) -> bytes: ...
tbs_bytes: bytes
extensions_der: bytes | None
# Methods
def get_extension_value_der(self, oid: str) -> bytes | None: ...
def subject_alt_names(self) -> list[tuple[int, bytes]]: ...
def verify_issued_by(self, issuer: Certificate) -> None: ...
def fingerprint(self, algorithm: str) -> bytes: ...
Usage
import synta
# Parse a DER-encoded certificate
with open('cert.der', 'rb') as f:
cert = synta.Certificate.from_der(f.read())
# Identity fields
print(cert.subject) # RFC 4514-style DN string
print(cert.issuer) # RFC 4514-style DN string
print(cert.serial_number) # Python int (arbitrary precision)
print(cert.version) # None (v1), 1 (v2), or 2 (v3)
# Validity
print(cert.not_before) # String, e.g. "230101000000Z"
print(cert.not_after) # String, e.g. "320101000000Z"
# Signature algorithm
print(cert.signature_algorithm) # Human-readable name or dotted OID
print(cert.signature_algorithm_oid) # Dotted OID string (always machine-readable)
print(cert.signature_algorithm_params) # DER bytes or None (e.g. None for Ed25519)
print(cert.signature_value) # Raw signature bytes
# Subject public key
print(cert.public_key_algorithm) # Human-readable name or dotted OID
print(cert.public_key_algorithm_oid) # Dotted OID string
print(cert.public_key_algorithm_params) # DER bytes or None (EC: curve OID)
print(cert.public_key) # Raw SubjectPublicKeyInfo bit-string bytes
# Raw DER spans
print(cert.to_der()) # Complete original certificate DER bytes
print(cert.tbs_bytes) # TBSCertificate DER (the bytes that were signed)
print(cert.issuer_raw_der) # Issuer Name SEQUENCE DER
print(cert.subject_raw_der) # Subject Name SEQUENCE DER
print(cert.extensions_der) # Extensions SEQUENCE OF DER, or None for v1/v2
# Look up a single extension by OID — returns the extnValue OCTET STRING
# content (the DER-encoded extension-specific structure), or None if absent.
san_der = cert.get_extension_value_der("2.5.29.17") # SubjectAltName
bc_der = cert.get_extension_value_der("2.5.29.19") # BasicConstraints
eku_der = cert.get_extension_value_der("2.5.29.37") # ExtendedKeyUsage
SAN access
import ipaddress
import synta.general_name as gn
# High-level: subject_alt_names() combines extension lookup and GeneralName parsing
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)
Iterating extensions manually
# Iterate all extensions when you need every extension
ext_der = cert.extensions_der
if ext_der:
dec = synta.Decoder(ext_der, synta.Encoding.DER)
exts = dec.decode_sequence()
while not exts.is_empty():
ext_tlv = exts.decode_raw_tlv() # bytes covering one Extension TLV
Signature verification
# Verify a certificate was signed by a CA certificate
ca_cert = synta.Certificate.from_der(open("ca.der", "rb").read())
end_cert = synta.Certificate.from_der(open("end.der", "rb").read())
try:
end_cert.verify_issued_by(ca_cert)
print("Signature valid")
except ValueError as e:
print(f"Invalid: {e}")
See also:
- CSR for PKCS#10 certificate signing requests
- GeneralName for
synta.general_nametag constants - PyCA Interoperability for converting to/from
cryptography - X.509 Path Validation for chain verification