ℹ Test log — do not submit to real browsers or CT monitors. Log IDs and keys are stable per deployment. SCTs are valid and the Merkle tree is maintained, but this log is not trusted by any browser, OS, or CT auditor.

Available Log Identities

One identity is selected at random per add-pre-chain request. The returned SCT's id field identifies which log "signed" it. All identities share a single API endpoint and a single global Merkle tree.

Log Name Operator Log ID (base64) MMD
Meerkat Bousannoun CT 2025 Bousannoun Certificate Transparency iwnHdSIcKx8Ghz4kbh8q6pXRm1W8R4ELzhB+zQsYcCs= 24 h
Chalhoub CT 2026h2 Ganfous Errdaief GMBH QbqhGVKRrVFvtBi5Me9culXIlDi/9a7JupvFgD6bWfU= 24 h
Meerkat Dhibi CT 2026h1 Dhibi Digital Trust fH1x8dROT9Kw0LwQMvc4xYjq7PJMyzypx4yZjy58efM= 24 h
Meerkat Farhoud CT 2025 Farhoud CT Authority hvxltxKBcrAnEDZHWgf6nMYy07hkovBzcnZg2WBSD68= 24 h
Meerkat Habhoub CT 2026 Habhoub Certificate Logs N4FkhYpvMuQqv/rBV+ifYqOB2M516xKaivOkxHdzHVk= 24 h
Finally the ninth CT LOG Harhour GMBH nb4XK1iOYM2Lk+khiyBUXuycsZcqzV5WpQG4ifKluuA= 24 h
Meerkat Kablouti CT 2025h1 Kablouti Certificate Services hTHSlyqT8WJPI8sY3+w8rATgCEhtul+mdijguxKrOt4= 24 h
Meerkat Karkoub CT 2025h2 Karkoub Trust Infrastructure Y/QMWnvgbCTNukIqMBNwqx8BH3V4NyA2/TyklEhpFH8= 24 h
Meerkat Sal7ouf CT 2026h1 Sal7ouf Digital Logs bzp3sBRXyfGvWrmAJtkBhiCPhUFlW65qSRgce7ghsSY= 24 h
Meerkat Sardouk CT 2025h2 Sardouk Log Services B9HDwAipkqj3Rc8AB0cfPPxCwro9whPdosOHWztOovM= 24 h

API Base URL: https://thameur.org/ct/v1  Âˇ  Log ID = SHA-256(SubjectPublicKeyInfo DER of the log's ECDSA P-256 public key)

API Endpoints

MethodPathDescription
POST/ct/v1/add-pre-chainSubmit a precertificate chain. Returns a signed SCT and persists the entry. Primary endpoint.
GET/ct/v1/get-sthReturns a signed tree head reflecting the current Merkle tree size and root hash.
GET/ct/v1/get-rootsReturns base64 DER of accepted root and issuing CA certificates.
GET/ct/v1/get-entriesReturns persisted log entries for a given leaf index range.
GET/ct/v1/get-proof-by-hashReturns a Merkle audit proof for a given leaf hash.

POST /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, selects a random log identity, signs the SCT, and persists the entry in the Merkle tree.

Request body:

// Content-Type: application/json { "chain": [ "<base64-DER-precertificate>", // required — must contain OID 1.3.6.1.4.1.11129.2.4.3 "<base64-DER-issuing-CA-cert>" // optional — falls back to Meerkat Issuing CA if omitted ] }

Request fields:

FieldTypeNotes
chain[0]requiredBase64-encoded DER precertificate. Must contain the CT poison extension (OID 1.3.6.1.4.1.11129.2.4.3, critical).
chain[1]optionalBase64-encoded DER issuing CA certificate. Used to compute the issuer_key_hash. If absent, the Meerkat Issuing CA cert is used.
chain[2…N]optionalAdditional intermediate CA certificates up to the accepted root (max 10 total). Stored in extra_data for get-entries.

Success response (HTTP 200):

{ "sct_version": 0, // always 0 (v1) "id": "<base64 32-byte log ID>", // SHA-256(SPKI) of this request's log identity "timestamp": 1747217000000, // Unix milliseconds (uint64) "extensions": "", // always empty "signature": "<base64 DigitallySigned>" // see SCT Structure below }

GET /ct/v1/get-sth

Returns a freshly signed Signed Tree Head. The tree_size and sha256_root_hash reflect the current state of the Merkle tree across all persisted entries. A randomly selected log key signs the STH on each call.

{ "tree_size": 42, // number of entries in the log "timestamp": 1747217000000, "sha256_root_hash": "<base64 32-byte MTH>", // RFC 6962 §2.1 Merkle Tree Hash "tree_head_signature": "<base64 DigitallySigned>" }

GET /ct/v1/get-roots

{ "certificates": [ "<base64 DER Meerkat Root CA>", "<base64 DER Meerkat Issuing CA>" ] }

GET /ct/v1/get-entries?start=<n>&end=<m>

Returns persisted log entries for leaf indices [start, end] inclusive (0-indexed). Maximum 1 000 entries per request.

ParameterTypeNotes
startrequiredFirst leaf index to return (0-based).
endrequiredLast leaf index to return (inclusive). Clamped to start + 999.
{ "entries": [ { "leaf_input": "<base64 MerkleTreeLeaf>", // RFC 6962 §3.4 leaf structure "extra_data": "<base64 PrecertChainEntry>" // RFC 6962 §3.1: precert + issuer chain }, ... ] }

GET /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.

ParameterTypeNotes
hashrequiredBase64 of SHA-256(0x00 || MerkleTreeLeaf) — the leaf hash.
tree_sizeoptionalSnapshot tree size to prove against. Defaults to current tree size.
{ "leaf_index": 5, "audit_path": [ "<base64 32-byte sibling hash>", "<base64 32-byte sibling hash>" ... ] }

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)

All entries share a single global tree regardless of which log identity signed each SCT. Leaf hashes and interior node hashes follow the RFC 6962 / RFC 6979 conventions:

Node typeHash computation
Empty treeSHA-256("")
Leaf nodeSHA-256(0x00 || MerkleTreeLeaf) — stored as leaf_hash
Interior nodeSHA-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):

FieldSizeValue
version / leaf_type1 + 1 byte0x00 0x00 (v1, certificate_timestamp / timestamped_entry)
timestamp8 bytesuint64 big-endian milliseconds since epoch
entry_type2 bytes0x00 0x01 (precert_entry)
issuer_key_hash32 bytesSHA-256 of issuer SubjectPublicKeyInfo DER
tbs_certificate length3 bytesuint24 big-endian byte count of the TBS
tbs_certificatevariableDER TBSCertificate with CT poison extension removed
extensions length2 bytes0x00 0x00 (no extensions)

Error Responses

All errors return JSON with error_code (HTTP status) and error_message.

HTTPCause
400Missing 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.
404Unknown endpoint; hash not found in the log.
405Wrong HTTP method (e.g. GET on add-pre-chain).
503No active CT log identities with keys — issue keys from the admin panel.
500DER 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 add-pre-chain

curl -s -X POST https://thameur.org/ct/v1/add-pre-chain \ -H 'Content-Type: application/json' \ -d '{ "chain": [ "'"$(openssl x509 -in precert.pem -outform DER | base64 -w0)"'", "'"$(openssl x509 -in issuing-ca.pem -outform DER | base64 -w0)"'" ] }' | jq .

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

  • Randomisation: Each add-pre-chain request picks one of 10 ECDSA P-256 key pairs at random. The id in the SCT uniquely identifies which log "signed" it. The global Merkle tree is shared across all identities.
  • Persistence: Every submitted precertificate is stored in the database. get-entries returns the actual MerkleTreeLeaf and PrecertChainEntry for each stored entry. get-sth reflects the real tree size and Merkle root.
  • 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.

We use only essential cookies and local browser storage for preferences and security. See our Privacy Policy for details.

⚠

Confirm action