Meerkat Testing CT Log
A fully RFC 6962-compliant Certificate Transparency log for testing.
10 independent log identities, each with its own URL prefix, ECDSA P-256 key pair, and Merkle tree.
Accepts precertificate chains, returns cryptographically valid SCTs, and persists every entry —
get-entries and get-proof-by-hash are fully implemented per log.
Available Log Identities
Each identity is a fully independent CT log. Submit to the log's own /{slug}/ct/v1/add-pre-chain endpoint to receive an SCT signed by that log's key. The returned SCT's id field identifies which log signed it.
| Log Name | Operator | Base URL | Log ID (base64) | MMD |
|---|---|---|---|---|
| Meerkat Bousannoun CT 2025 | Bousannoun Certificate Transparency | https://thameur.org/bousannoun/ct/v1/ |
iwnHdSIcKx8Ghz4kbh8q6pXRm1W8R4ELzhB+zQsYcCs= | 24 h |
| Chalhoub CT 2026h2 | Ganfous Errdaief GMBH | https://thameur.org/chalhoub/ct/v1/ |
QbqhGVKRrVFvtBi5Me9culXIlDi/9a7JupvFgD6bWfU= | 24 h |
| Meerkat Dhibi CT 2026h1 | Dhibi Digital Trust | https://thameur.org/dhibi/ct/v1/ |
fH1x8dROT9Kw0LwQMvc4xYjq7PJMyzypx4yZjy58efM= | 24 h |
| Meerkat Farhoud CT 2025 | Farhoud CT Authority | https://thameur.org/farhoud/ct/v1/ |
hvxltxKBcrAnEDZHWgf6nMYy07hkovBzcnZg2WBSD68= | 24 h |
| Meerkat Habhoub CT 2026 | Habhoub Certificate Logs | https://thameur.org/habhoub/ct/v1/ |
N4FkhYpvMuQqv/rBV+ifYqOB2M516xKaivOkxHdzHVk= | 24 h |
| Finally the ninth CT LOG | Harhour GMBH | https://thameur.org/harhour/ct/v1/ |
nb4XK1iOYM2Lk+khiyBUXuycsZcqzV5WpQG4ifKluuA= | 24 h |
| Meerkat Kablouti CT 2025h1 | Kablouti Certificate Services | https://thameur.org/kablouti/ct/v1/ |
hTHSlyqT8WJPI8sY3+w8rATgCEhtul+mdijguxKrOt4= | 24 h |
| Meerkat Karkoub CT 2025h2 | Karkoub Trust Infrastructure | https://thameur.org/karkoub/ct/v1/ |
Y/QMWnvgbCTNukIqMBNwqx8BH3V4NyA2/TyklEhpFH8= | 24 h |
| Meerkat Sal7ouf CT 2026h1 | Sal7ouf Digital Logs | https://thameur.org/sal7ouf/ct/v1/ |
bzp3sBRXyfGvWrmAJtkBhiCPhUFlW65qSRgce7ghsSY= | 24 h |
| Meerkat Sardouk CT 2025h2 | Sardouk Log Services | https://thameur.org/sardouk/ct/v1/ |
B9HDwAipkqj3Rc8AB0cfPPxCwro9whPdosOHWztOovM= | 24 h |
Log ID = SHA-256(SubjectPublicKeyInfo DER of the log's ECDSA P-256 public key)
API Endpoints
Replace {slug} with the log slug (e.g. kablouti). Each log has its own independent Merkle tree.
| Method | Path | Description |
|---|---|---|
| POST | /{slug}/ct/v1/add-pre-chain | Submit a precertificate chain. Returns a signed SCT and persists the entry in this log's Merkle tree. Primary endpoint. |
| GET | /{slug}/ct/v1/get-sth | Returns a signed tree head for this log's Merkle tree. |
| GET | /{slug}/ct/v1/get-roots | Returns base64 DER of accepted root and issuing CA certificates. |
| GET | /{slug}/ct/v1/get-entries | Returns persisted log entries for a given leaf index range within this log. |
| GET | /{slug}/ct/v1/get-proof-by-hash | Returns a Merkle audit proof for a given leaf hash within this log's tree. |
POST /{slug}/ct/v1/add-pre-chain
Accepts a JSON body containing the precertificate chain (RFC 6962 §4.1). Validates the CT poison extension, strips it from the TBSCertificate, computes the issuer key hash, signs the SCT with the log's key, and persists the entry in this log's Merkle tree.
Request body:
Request fields:
| Field | Type | Notes |
|---|---|---|
| chain[0] | required | Base64-encoded DER precertificate. Must contain the CT poison extension (OID 1.3.6.1.4.1.11129.2.4.3, critical). |
| chain[1] | optional | Base64-encoded DER issuing CA certificate. Used to compute the issuer_key_hash. If absent, the Meerkat Issuing CA cert is used. |
| chain[2…N] | optional | Additional intermediate CA certificates up to the accepted root (max 10 total). Stored in extra_data for get-entries. |
Success response (HTTP 200):
GET /{slug}/ct/v1/get-sth
Returns a freshly signed Signed Tree Head for this log's Merkle tree. The tree_size and sha256_root_hash reflect the current state of entries submitted to this specific log.
GET /{slug}/ct/v1/get-roots
GET /{slug}/ct/v1/get-entries?start=<n>&end=<m>
Returns persisted log entries for leaf indices [start, end] inclusive within this log's own tree (0-indexed). Maximum 1 000 entries per request.
| Parameter | Type | Notes |
|---|---|---|
| start | required | First leaf index to return (0-based, within this log). |
| end | required | Last leaf index to return (inclusive). Clamped to start + 999. |
GET /{slug}/ct/v1/get-proof-by-hash?hash=<base64>&tree_size=<n>
Returns a Merkle audit proof (RFC 6962 §4.5) for the leaf identified by its hash within this log's tree.
| Parameter | Type | Notes |
|---|---|---|
| hash | required | Base64 of SHA-256(0x00 || MerkleTreeLeaf) — the leaf hash. |
| tree_size | optional | Snapshot tree size to prove against. Defaults to current tree size for this log. |
Verify the proof with the STH root hash: reconstruct the path hash from leaf → root by applying SHA-256(0x01 || left || right) at each level, and compare the final hash against sha256_root_hash from get-sth.
Merkle Tree (RFC 6962 §2.1)
Each log maintains its own independent Merkle tree. Leaf hashes and interior node hashes follow RFC 6962 §2.1 conventions:
| Node type | Hash computation |
|---|---|
| Empty tree | SHA-256("") |
| Leaf node | SHA-256(0x00 || MerkleTreeLeaf) — stored as leaf_hash |
| Interior node | SHA-256(0x01 || left_child || right_child) |
SCT & Signed Data Structure
The signature field contains a base64-encoded DigitallySigned struct (RFC 6962 §3.2). The signed data for a precert_entry is identical to the MerkleTreeLeaf wire format — both start with 0x00 0x00 (version + signature_type / leaf_type):
| Field | Size | Value |
|---|---|---|
| version / leaf_type | 1 + 1 byte | 0x00 0x00 (v1, certificate_timestamp / timestamped_entry) |
| timestamp | 8 bytes | uint64 big-endian milliseconds since epoch |
| entry_type | 2 bytes | 0x00 0x01 (precert_entry) |
| issuer_key_hash | 32 bytes | SHA-256 of issuer SubjectPublicKeyInfo DER |
| tbs_certificate length | 3 bytes | uint24 big-endian byte count of the TBS |
| tbs_certificate | variable | DER TBSCertificate with CT poison extension removed |
| extensions length | 2 bytes | 0x00 0x00 (no extensions) |
Error Responses
All errors return JSON with error_code (HTTP status) and error_message.
| HTTP | Cause |
|---|---|
| 400 | Missing or malformed chain field; base64 decode failure; chain[0] is not a valid X.509 certificate; CT poison extension not present; invalid hash or start/end parameters; leaf not within tree_size snapshot. |
| 404 | Unknown slug; unknown endpoint; hash not found in this log. |
| 405 | Wrong HTTP method (e.g. GET on add-pre-chain). |
| 503 | Log slug is active but has no keys — issue keys from the admin panel. |
| 500 | DER parsing failure; ECDSA signing error. |
Integration Guide
Step 1 — Issue a precertificate
Use the Meerkat Certificate Factory "Issue Precertificate" button, or issue one via your own CA pipeline with the CT poison extension (OID 1.3.6.1.4.1.11129.2.4.3, critical, value = ASN.1 NULL 05 00).
Step 2 — Submit to a specific log's add-pre-chain
Submit the same precertificate to multiple log slugs to collect independent SCTs from different log identities.
Step 3 — Verify inclusion with get-proof-by-hash
The leaf hash is SHA-256(0x00 || leaf_input) where leaf_input is the MerkleTreeLeaf bytes from the SCT. Pass the base64 leaf hash to get-proof-by-hash, then reconstruct the root from the audit path and compare against get-sth.
Embed the SCT in a certificate extension
The SCT can be embedded in the final certificate as a SignedCertificateTimestampList (OID 1.3.6.1.4.1.11129.2.4.2), or delivered via a TLS extension, or via OCSP stapling. Encoding of the SCT list is described in RFC 6962 §3.3.
Technical Notes
- Independent logs: Each slug is a completely separate CT log with its own ECDSA P-256 key pair and its own Merkle tree. There is no shared state between logs.
- Persistence: Every submitted precertificate is stored in the database scoped to the target log.
get-entriesreturns entries only for the queried log.get-sthreflects the real tree size and Merkle root for that log. - Poison stripping: The TBSCertificate submitted in the chain has the CT poison extension (OID 1.3.6.1.4.1.11129.2.4.3) removed before it is hashed into the signed data, per RFC 6962 §3.2.
- IssuerKeyHash: Computed as SHA-256 of the SubjectPublicKeyInfo DER of the issuing CA certificate (chain[1], or the Meerkat Issuing CA if absent).
- CORS: All endpoints respond with
Access-Control-Allow-Origin: *for browser-based testing.