Reading a CT log entry
What a get-entries response actually contains, and why half of it looks like a certificate that nobody can use.
A certificate transparency log speaks plain HTTP. Ask a log for a slice of its tree and you get JSON back:
curl -s 'https://ct.googleapis.com/logs/us/argon2026h2/ct/v1/get-entries?start=0&end=0'
{
"entries": [
{
"leaf_input": "AAAAAAGR...",
"extra_data": "AAWZMIIF..."
}
]
}
Two base64 blobs, no field names, no hostnames. Everything useful is inside them.
leaf_input
leaf_input is a serialised MerkleTreeLeaf — the exact bytes the log hashed into its
Merkle tree. Decoded, the header is small and fixed:
| Bytes | Field | Note |
|---|---|---|
| 1 | version | 0 for RFC 6962 |
| 1 | leaf type | 0 = timestamped entry |
| 8 | timestamp | milliseconds since the epoch |
| 2 | entry type | 0 = X.509, 1 = precertificate |
The entry type decides how to read the rest. For an X.509 entry the leaf carries the DER certificate itself. For a precertificate entry it carries the issuer key hash and the TBS certificate with the poison extension stripped out — which means the bytes in the leaf never form a certificate you could serve.
extra_data
extra_data holds what the leaf left out: the issuing chain, and for precertificate
entries the full precertificate as submitted. If you want the chain up to the root, it
is here rather than in the leaf.
Why so many duplicates
Scan a live feed for a while and the same hostname shows up repeatedly. Three ordinary reasons:
- the precertificate and the final certificate are separate entries,
- CAs submit to several logs, and you are reading more than one,
- renewals are frequent — a 90-day certificate reappears every couple of months.
Deduplicating on the certificate’s SHA-256 fingerprint removes the third case but not the first two, because a precertificate and its certificate are genuinely different DER. Key on the tbsCertificate with the poison and SCT extensions removed if you want those to collapse into one.
Watch the tree, not just the entries
get-entries gives you content. get-sth gives you the signed tree head: size, root
hash, timestamp, signature. Two tree heads plus a consistency proof from
get-sth-consistency prove the log only appended between them.
Pulling entries without ever checking a tree head means you are trusting the log operator — which is the one thing CT was designed to avoid.