# CRL and OCSP Builders
`CertificateListBuilder`, `OCSPResponseBuilder`, `OCSPSingleResponse`, `OCSPRequestBuilder`,
and `OCSPCertIDSpec` are top-level `synta` exports for constructing DER-encoded X.509 CRL
and OCSP structures. All builders follow the same pattern: accumulate parameters, produce
a DER-encoded blob, sign it externally if required, then call `assemble` to wrap the
signature into the final structure.
## CertificateListBuilder
Fluent builder for RFC 5280 §5 `TBSCertList`.
```python
class CertificateListBuilder:
def __init__(self) -> None: ...
def issuer(self, name_der: bytes) -> CertificateListBuilder: ...
# Set the issuer Name from pre-encoded DER bytes.
def this_update(self, time: str) -> CertificateListBuilder: ...
# Set thisUpdate ("YYYYMMDDHHmmssZ" or "YYMMDDHHmmssZ").
def next_update(self, time: str) -> CertificateListBuilder: ...
# Set optional nextUpdate (same format as this_update).
def revoke(
self,
serial: bytes,
revocation_date: str,
reason: int | None = None,
) -> CertificateListBuilder: ...
# Add a revoked certificate entry.
# serial is the big-endian DER INTEGER value bytes.
# reason is an optional CRL reason code (0–10).
def signature_algorithm(self, alg_der: bytes) -> CertificateListBuilder: ...
# Set the AlgorithmIdentifier DER for TBSCertList.signature.
def build(self) -> bytes: ...
# Build the DER-encoded TBSCertList SEQUENCE.
# Raises ValueError if any required field is absent or encoding fails.
@staticmethod
def assemble(tbs_der: bytes, sig_alg_der: bytes, signature: bytes) -> bytes: ...
# Assemble a complete DER-encoded CertificateList.
# tbs_der: TBSCertList bytes from build().
# sig_alg_der: outer AlgorithmIdentifier SEQUENCE TLV.
# signature: raw signature bytes (BIT STRING value).
# Raises ValueError if DER encoding fails.
```
### Example
```python,ignore
import synta
name_der = synta.NameBuilder().common_name("Test CA").build()
alg_der = bytes.fromhex("300d06092a864886f70d01010b0500") # sha256WithRSAEncryption
tbs = (
synta.CertificateListBuilder()
.issuer(name_der)
.signature_algorithm(alg_der)
.this_update("20240101120000Z")
.revoke(bytes([1]), "20231201000000Z", 1) # reason 1 = keyCompromise
.build()
)
# Sign tbs externally, then assemble:
# crl_der = synta.CertificateListBuilder.assemble(tbs, alg_der, sig_bytes)
```
---
## OCSPSingleResponse
Parameters for a single OCSP response entry. Pass an instance to
`OCSPResponseBuilder.add_response`.
```python
class OCSPSingleResponse:
def __init__(
self,
hash_algorithm_der: bytes,
issuer_name_hash: bytes,
issuer_key_hash: bytes,
serial: bytes,
status: int,
this_update: str,
next_update: str | None = None,
) -> None: ...
# hash_algorithm_der: pre-encoded AlgorithmIdentifier DER TLV (e.g. SHA-1).
# issuer_name_hash: raw hash of the issuer Name DER bytes.
# issuer_key_hash: raw hash of the issuer subjectPublicKey BIT STRING value.
# serial: big-endian DER INTEGER value bytes of the target certificate.
# status: 0 = good, 1 = revoked, 2 = unknown.
# this_update: "YYYYMMDDHHmmssZ" format.
# next_update: optional "YYYYMMDDHHmmssZ" format.
```
---
## OCSPResponseBuilder
Fluent builder for RFC 6960 §4.2.1 `ResponseData`. Set exactly one of `responder_name` or
`responder_key_hash` before calling `build_tbs`.
```python
class OCSPResponseBuilder:
def __init__(self) -> None: ...
def responder_name(self, name_der: bytes) -> OCSPResponseBuilder: ...
# Set responderID byName from a pre-encoded DER Name SEQUENCE TLV.
def responder_key_hash(self, key_hash: bytes) -> OCSPResponseBuilder: ...
# Set responderID byKey from raw key-hash bytes (OCTET STRING value).
def produced_at(self, time: str) -> OCSPResponseBuilder: ...
# Set producedAt time ("YYYYMMDDHHmmssZ").
def add_response(self, response: OCSPSingleResponse) -> OCSPResponseBuilder: ...
# Add a SingleResponse entry built with OCSPSingleResponse.
def build_tbs(self) -> bytes: ...
# Build the DER-encoded ResponseData SEQUENCE.
# Raises ValueError if any required field is absent or encoding fails.
@staticmethod
def assemble(tbs_der: bytes, sig_alg_der: bytes, signature: bytes) -> bytes: ...
# Assemble a complete DER-encoded OCSPResponse.
# tbs_der: ResponseData bytes from build_tbs().
# sig_alg_der: outer AlgorithmIdentifier SEQUENCE TLV.
# signature: raw signature bytes (BIT STRING value).
# Raises ValueError if DER encoding fails.
```
### Example
```python,ignore
import synta, hashlib
# AlgorithmIdentifier for SHA-1 (id-sha1, no parameters)
SHA1_ALG_DER = bytes.fromhex("300702050002014c") # simplified; use a real encoder in production
resp = synta.OCSPSingleResponse(
hash_algorithm_der=SHA1_ALG_DER,
issuer_name_hash=hashlib.sha1(issuer_name_der).digest(),
issuer_key_hash=hashlib.sha1(issuer_key_bytes).digest(),
serial=b"\x01", # serial number DER INTEGER value
status=0, # good
this_update="20240101120000Z",
next_update="20240201120000Z",
)
tbs = (
synta.OCSPResponseBuilder()
.responder_key_hash(hashlib.sha1(issuer_key_bytes).digest())
.produced_at("20240101120000Z")
.add_response(resp)
.build_tbs()
)
# Sign tbs externally, then assemble:
# ocsp_der = synta.OCSPResponseBuilder.assemble(tbs, sig_alg_der, sig_bytes)
```
See also [X.509 Extension Value Builders](ext-builders.md), [OCSP](ocsp.md), and
[Certificate, CSR, and Name Builders](cert-builders.md) for the `NameBuilder` used in
`CertificateListBuilder.issuer()`.
---
## OCSPCertIDSpec
Parameters for a single entry in an OCSP request (one certificate to check).
Pass an instance to `OCSPRequestBuilder.add_request`.
```python
class OCSPCertIDSpec:
def __init__(
self,
hash_algorithm_der: bytes,
issuer_name_hash: bytes,
issuer_key_hash: bytes,
serial: bytes,
) -> None: ...
# hash_algorithm_der: pre-encoded AlgorithmIdentifier DER TLV (e.g. SHA-1).
# issuer_name_hash: raw hash of the issuer Name DER bytes.
# issuer_key_hash: raw hash of the issuer subjectPublicKey BIT STRING value.
# serial: big-endian DER INTEGER value bytes of the certificate serial number.
```
---
## OCSPRequestBuilder
Fluent builder for RFC 6960 §4.1.1 `OCSPRequest`.
`build_tbs` produces the complete unsigned `OCSPRequest` DER blob (inner
`TBSRequest` wrapped in the outer `SEQUENCE`), ready for direct submission to
an OCSP responder. For signed requests, use `build_tbs_inner` to obtain the
bare `TBSRequest` bytes for external signing, then call `assemble` to produce
the complete signed `OCSPRequest`.
```python
class OCSPRequestBuilder:
def __init__(self) -> None: ...
def add_request(self, spec: OCSPCertIDSpec) -> OCSPRequestBuilder: ...
# Add a Request entry (one certificate whose status is being queried).
# spec: an OCSPCertIDSpec instance.
def requestor_name(self, name_der: bytes) -> OCSPRequestBuilder: ...
# Set the optional requestorName from a pre-encoded DER GeneralName TLV.
def build_tbs(self) -> bytes: ...
# Build the complete DER-encoded unsigned OCSPRequest SEQUENCE.
# The returned bytes can be submitted directly to an OCSP responder.
# Raises ValueError if no request entry was added, or if encoding fails.
def build_tbs_inner(self) -> bytes: ...
# Build the DER-encoded inner TBSRequest SEQUENCE for signing.
# Sign these bytes externally, then pass the result to assemble().
# Raises ValueError if no request entry was added, or if encoding fails.
@staticmethod
def assemble(tbs_der: bytes, sig_alg_der: bytes, signature: bytes) -> bytes: ...
# Assemble a complete DER-encoded signed OCSPRequest.
# tbs_der: TBSRequest bytes from build_tbs_inner().
# sig_alg_der: outer AlgorithmIdentifier SEQUENCE TLV.
# signature: raw signature bytes (BIT STRING value).
# Raises ValueError if DER encoding fails.
```
### Example — unsigned request (most common)
```python,ignore
import synta, hashlib
# AlgorithmIdentifier for SHA-1 (id-sha1, no parameters)
SHA1_ALG = bytes.fromhex("300906052b0e03021a0500")
name_der = synta.NameBuilder().common_name("Example CA").build()
name_hash = hashlib.sha1(name_der).digest()
key_hash = bytes(20) # 20-byte placeholder; use real issuer SPKI hash in production
serial = bytes([0x01])
spec = synta.OCSPCertIDSpec(
hash_algorithm_der=SHA1_ALG,
issuer_name_hash=name_hash,
issuer_key_hash=key_hash,
serial=serial,
)
# Build the complete unsigned OCSPRequest
ocsp_der = (
synta.OCSPRequestBuilder()
.add_request(spec)
.build_tbs()
)
# Submit ocsp_der to an OCSP responder via HTTP POST
```
### Example — signed request
```python,ignore
import synta, hashlib
SHA1_ALG = bytes.fromhex("300906052b0e03021a0500")
SHA256_WITH_RSA = bytes.fromhex("300d06092a864886f70d01010b0500")
name_hash = hashlib.sha1(issuer_name_der).digest()
key_hash = hashlib.sha1(issuer_key_bytes).digest()
spec = synta.OCSPCertIDSpec(
hash_algorithm_der=SHA1_ALG,
issuer_name_hash=name_hash,
issuer_key_hash=key_hash,
serial=serial_bytes,
)
# Obtain inner TBSRequest for signing
tbs_inner = (
synta.OCSPRequestBuilder()
.requestor_name(requestor_name_der) # optional: DER GeneralName TLV
.add_request(spec)
.build_tbs_inner()
)
# Sign tbs_inner externally, then assemble:
# ocsp_der = synta.OCSPRequestBuilder.assemble(tbs_inner, SHA256_WITH_RSA, sig_bytes)
```
See also [OCSP](ocsp.md), [X.509 Extension Value Builders](ext-builders.md), and
[Certificate, CSR, and Name Builders](cert-builders.md) for the `NameBuilder` used above.