X.509 Extension Value Builders
synta.ext provides DER-encoding helpers for the most common X.509 v3 extension values.
Each function returns the raw extnValue bytes (the content inside the OCTET STRING wrapper
in the Extension SEQUENCE). Import with import synta.ext as ext.
subject_key_identifier and authority_key_identifier require the openssl Cargo feature.
basic_constraints, key_usage, and the three builder classes do not.
Key identifier method constants
Pass one of these to subject_key_identifier or authority_key_identifier:
| Constant | Value | Hash | Input | Output length | Specification |
|---|---|---|---|---|---|
KEYID_RFC5280 | 0 | SHA-1 | BIT STRING value of subjectPublicKey | 20 bytes | RFC 5280 §4.2.1.2 |
KEYID_RFC7093M1 | 1 | SHA-256 | BIT STRING value of subjectPublicKey | 20 bytes (truncated) | RFC 7093 §2 m1 |
KEYID_RFC7093M2 | 2 | SHA-384 | BIT STRING value of subjectPublicKey | 20 bytes (truncated) | RFC 7093 §2 m2 |
KEYID_RFC7093M3 | 3 | SHA-512 | BIT STRING value of subjectPublicKey | 20 bytes (truncated) | RFC 7093 §2 m3 |
KEYID_RFC7093M4 | 4 | SHA-256 | full SubjectPublicKeyInfo DER | 32 bytes | RFC 7093 §2 m4 |
Key usage bitmask constants
OR these together and pass the result to key_usage():
| Constant | Mask | Named bit (RFC 5280 §4.2.1.3) |
|---|---|---|
KU_DIGITAL_SIGNATURE | 0x001 | digitalSignature |
KU_NON_REPUDIATION | 0x002 | contentCommitment |
KU_KEY_ENCIPHERMENT | 0x004 | keyEncipherment |
KU_DATA_ENCIPHERMENT | 0x008 | dataEncipherment |
KU_KEY_AGREEMENT | 0x010 | keyAgreement |
KU_KEY_CERT_SIGN | 0x020 | keyCertSign |
KU_CRL_SIGN | 0x040 | cRLSign |
KU_ENCIPHER_ONLY | 0x080 | encipherOnly |
KU_DECIPHER_ONLY | 0x100 | decipherOnly |
Functions
def basic_constraints(ca: bool = False, path_length: int | None = None) -> bytes: ...
Encode a BasicConstraints extension value (OID 2.5.29.19). Returns the DER SEQUENCE bytes.
When ca is False the cA field is omitted (DER DEFAULT-FALSE rule). path_length is
ignored when ca is False.
def key_usage(bits: int) -> bytes: ...
Encode a KeyUsage extension value (OID 2.5.29.15). bits is an integer formed by OR-ing
KU_* constants. Returns the DER BIT STRING bytes.
def subject_key_identifier(spki_der: bytes, method: int = KEYID_RFC5280) -> bytes: ...
Encode a SubjectKeyIdentifier extension value (OID 2.5.29.14). spki_der must be a complete
DER-encoded SubjectPublicKeyInfo. method selects the key-identifier algorithm. Returns the
DER OCTET STRING value. Raises ValueError if spki_der cannot be decoded.
def authority_key_identifier(issuer_spki_der: bytes, method: int = KEYID_RFC5280) -> bytes: ...
Encode an AuthorityKeyIdentifier extension value (OID 2.5.29.35). Sets only the
keyIdentifier [0] field. Returns the DER AuthorityKeyIdentifier SEQUENCE bytes.
Fluent builder classes
Three builder classes accumulate entries and produce the complete DER extnValue on
.build(). No openssl Cargo feature is required.
SubjectAlternativeNameBuilder (alias: SAN)
class SubjectAlternativeNameBuilder:
def __init__(self) -> None: ...
def dns_name(self, name: str) -> SubjectAlternativeNameBuilder: ...
def rfc822_name(self, email: str) -> SubjectAlternativeNameBuilder: ...
def uri(self, uri: str) -> SubjectAlternativeNameBuilder: ...
def ip_address(self, addr: bytes) -> SubjectAlternativeNameBuilder: ...
# Pass 4 bytes for IPv4 or 16 bytes for IPv6.
def directory_name(self, name_der: bytes) -> SubjectAlternativeNameBuilder: ...
# name_der is the DER TLV of a Name SEQUENCE.
def registered_id(self, oid_comps: list[int]) -> SubjectAlternativeNameBuilder: ...
def build(self) -> bytes: ...
# Return the DER GeneralNames SEQUENCE. Raises ValueError on encoding error.
SAN = SubjectAlternativeNameBuilder # short alias
AuthorityInformationAccessBuilder (alias: AIA)
class AuthorityInformationAccessBuilder:
def __init__(self) -> None: ...
def ocsp(self, uri: str) -> AuthorityInformationAccessBuilder: ...
def ca_issuers(self, uri: str) -> AuthorityInformationAccessBuilder: ...
def build(self) -> bytes: ...
AIA = AuthorityInformationAccessBuilder # short alias
ExtendedKeyUsageBuilder (alias: EKU)
class ExtendedKeyUsageBuilder:
def __init__(self) -> None: ...
def server_auth(self) -> ExtendedKeyUsageBuilder: ... # id-kp-serverAuth
def client_auth(self) -> ExtendedKeyUsageBuilder: ... # id-kp-clientAuth
def code_signing(self) -> ExtendedKeyUsageBuilder: ... # id-kp-codeSigning
def email_protection(self) -> ExtendedKeyUsageBuilder: ... # id-kp-emailProtection
def time_stamping(self) -> ExtendedKeyUsageBuilder: ... # id-kp-timeStamping
def ocsp_signing(self) -> ExtendedKeyUsageBuilder: ... # id-kp-OCSPSigning
def add_oid(self, oid: str | ObjectIdentifier) -> ExtendedKeyUsageBuilder: ...
def build(self) -> bytes: ...
EKU = ExtendedKeyUsageBuilder # short alias
Usage
import synta
import synta.ext as ext
# Parse a CA certificate to extract its SubjectPublicKeyInfo DER
ca_der = open("ca.der", "rb").read()
ca_cert = synta.Certificate.from_der(ca_der)
spki_der = ca_cert.subject_public_key_info_raw_der
# ── BasicConstraints (OID 2.5.29.19) ──────────────────────────────────────────
# End-entity certificate: empty SEQUENCE → 30 00
ee_bc = ext.basic_constraints()
# CA with no path-length limit: cA = TRUE → 30 03 01 01 ff
ca_bc = ext.basic_constraints(ca=True)
# CA with pathLen = 0 → 30 06 01 01 ff 02 01 00
ca_pl0 = ext.basic_constraints(ca=True, path_length=0)
# ── KeyUsage (OID 2.5.29.15) ──────────────────────────────────────────────────
# Typical CA key usage: keyCertSign | cRLSign | digitalSignature
ku = ext.key_usage(ext.KU_KEY_CERT_SIGN | ext.KU_CRL_SIGN | ext.KU_DIGITAL_SIGNATURE)
# TLS server key usage: digitalSignature | keyEncipherment
ku_server = ext.key_usage(ext.KU_DIGITAL_SIGNATURE | ext.KU_KEY_ENCIPHERMENT)
# ── SubjectKeyIdentifier (OID 2.5.29.14) ──────────────────────────────────────
# RFC 5280 default: SHA-1 of the BIT STRING value of subjectPublicKey
ski = ext.subject_key_identifier(spki_der)
# RFC 7093 method 1: SHA-256 of BIT STRING value, truncated to 160 bits
ski_m1 = ext.subject_key_identifier(spki_der, method=ext.KEYID_RFC7093M1)
# RFC 7093 method 4: SHA-256 of the full SubjectPublicKeyInfo DER
ski_m4 = ext.subject_key_identifier(spki_der, method=ext.KEYID_RFC7093M4)
# ── AuthorityKeyIdentifier (OID 2.5.29.35) ────────────────────────────────────
aki = ext.authority_key_identifier(spki_der)
aki_m1 = ext.authority_key_identifier(spki_der, method=ext.KEYID_RFC7093M1)
# ── Fluent builders ───────────────────────────────────────────────────────────
san = ext.SAN().dns_name("www.example.com").dns_name("example.com").build()
aia = ext.AIA().ocsp("http://ocsp.example.com").ca_issuers("http://ca.example.com/ca.crt").build()
eku = ext.EKU().server_auth().client_auth().build()
See also CRL and OCSP Builders for building complete CRL and OCSP response structures.