skip to content

What does a signed certificate timestamp from a Certificate Transparency log promise, and why is it not proof of inclusion?

level: middleimportance: must knowfreq 55%

answer

  1. a promise, not a receipt
  2. signed at submission, before the tree
  3. Maximum Merge Delay bounds the promise
  4. signature checks offline, inclusion does not
  5. inclusion needs an audit path

basics

~20 s

A signed certificate timestamp is a log's signed promise to append that entry within its published Maximum Merge Delay. It proves submission and a log signature, not that the entry is in the tree — that needs an audit path against a signed tree head.

solid answer

~50 s

A `SignedCertificateTimestamp` carries the `log_id`, a timestamp and the log's signature over the submitted precertificate or certificate. Its meaning is a **promise**: the log undertakes to incorporate that entry into its Merkle tree within its published **Maximum Merge Delay**, the window it advertises for merging. A client can check that signature entirely offline with the log's public key — no network call, no round trip, no leak of which site is being visited — which is exactly why the handshake can afford the check. What the signature cannot tell the client is whether the merge actually happened. Establishing that requires an **inclusion proof**: an audit path from the entry's leaf hash to the Merkle Tree Hash inside a **Signed Tree Head**, fetched from the log. Clients on the connection path generally do not do this.

code

json · 7 lines
json
{
  "sct_version": 0,
  "id": "<base64 log_id, the hash of the log public key>",
  "timestamp": 1694102400000,
  "extensions": "",
  "signature": "<base64 signature made by the log>"
}

go deeper

for a junior

Recall that the timestamp is signed by the log, not by the certificate authority, and that it is evidence the certificate was submitted for publication.

for a middle

Explain the promise-versus-proof split: an offline signature check on the connection path, an audit path against a signed tree head for anyone who wants inclusion.

for a senior

Bring out why the split exists — a network fetch on the handshake path costs latency and leaks browsing history — and what the Maximum Merge Delay actually bounds.

for a principal

Judge how much assurance the promise is worth to you, and whether the auditing that would convert it into proof is a cost your estate should carry or delegate.

## What the object actually is A `SignedCertificateTimestamp` (SCT) is a small signed structure a Certificate Transparency log hands back when something is submitted to it. Its fields are the log's identity (`log_id`, derived from the log's public key), a timestamp in milliseconds, an extensions field, and a signature made by the **log's** key over the submitted entry and that timestamp. Note which signature this is — the branch is full of them. It is not the issuer's signature over the `TBSCertificate`, and not a requester's proof-of-possession signature over a certification request. It is the *log* signing, and what it signs is a statement about its own future behaviour. ## A promise, with a published deadline The statement is: *I have received this entry and I will incorporate it into my tree within my Maximum Merge Delay.* The **Maximum Merge Delay (MMD)** is a parameter each log publishes; public log programmes require it to be short, and it is the size of the window in which the promise is outstanding. Inside that window an honest log has simply not merged yet; outside it, a log that still cannot produce the entry has broken a signed commitment. That structure is deliberate. Merging into a Merkle tree and publishing a new **Signed Tree Head** is a batch operation; issuance cannot wait on it. So CT splits the guarantee in two: an immediate, cheap, offline-checkable promise for the connection path, and a slower, provable inclusion check for whoever is auditing. ## Why a promise is enough during the handshake What a client gets from verifying the SCT signature: - **No network dependency.** The log's public key is already in the client's CT policy set, so the check is local. A connection never blocks on a log being reachable. - **No privacy leak.** Asking a log *is this certificate in your tree?* tells the log which site the user is visiting. Avoiding that question on the connection path is a design goal, not an oversight. - **Non-repudiable evidence.** A signature the log cannot disown is retained. If the entry never appears, that signature is what an auditor presents. What the client does **not** get: any assurance the entry is in the tree at that moment. The strength of the check is the log's accountability, not immediate verification. | check | what it costs | what it establishes | |---|---|---| | verify the SCT signature | local, log public key only | the log signed a promise for this entry | | verify an inclusion proof | fetch a tree head and an audit path | the entry is in the tree that head commits to | ## Turning the promise into a proof For whoever does want inclusion rather than a promise, the sequence is: 1. Fetch a current **Signed Tree Head** from the log with `get-sth` — it carries the tree size and the Merkle Tree Hash the log commits to. 2. Compute the `MerkleTreeLeaf` hash for the entry, from the same bytes that were submitted. 3. Ask `get-proof-by-hash` for the audit path for that leaf hash under that tree size. 4. Recompute the root from the leaf hash and the path, and compare it to the hash in the tree head. If that recomputation matches, the entry is in the tree that head commits to. If the log cannot supply a path once the MMD has passed, the SCT and the log's own signature are evidence the log misbehaved — and the remedy is at the log-programme level, where a log that misbehaves stops being recognised. ## Consequences people get wrong - **An accepted certificate is not a verified-as-logged certificate.** It is a certificate accompanied by promises from logs the client's policy recognises. - **The timestamp is not the certificate's validity.** The SCT's timestamp is when the log received the submission; `notBefore` and `notAfter` inside the certificate are a separate window with a separate meaning. - **Distrusting a log is retrospective.** Clients that already accepted connections on the strength of that log's promises are not protected after the fact. - **The promise says nothing about legitimacy.** A log merges whatever is submitted that chains to a recognised authority; it never judges whether the issuance should have happened. The honest one-line summary: an SCT tells you *this certificate was made public, and a log staked its signature on that* — which is a meaningful property, and a different one from *this certificate is in the log right now*.

  • Why do clients not simply fetch an inclusion proof for every signed certificate timestamp they see?
    Two reasons. It puts a network round trip to a third party on the connection path, so a slow or unreachable log would break browsing. And the query itself is a privacy leak: asking a log about one certificate tells the log operator which site the user is visiting. Proposals to close the gap route it through indirect channels rather than a direct lookup.
  • What happens in practice if a log never merges an entry it issued a timestamp for?
    The SCT is signed, non-repudiable evidence of a broken promise. Once the Maximum Merge Delay has passed and the log still cannot produce an audit path, that evidence goes to the log programmes, which stop recognising the log. Clients that already accepted connections on its promises get nothing retroactively — the sanction is forward-looking.
  • Is the timestamp inside an SCT the moment the certificate became valid?
    No. It records when the log received the submission, which happens before issuance for a precertificate. The certificate's own usable window is `notBefore` to `notAfter` inside it, and the two can differ. Treating the SCT timestamp as a validity boundary is a common confusion between two unrelated clocks.

It is a stamped acknowledgement from a records office saying your document will appear in the next published register. The stamp is worth something because the office signed it — but it is not the same as opening the register and finding the entry.

saying these in an interview costs you the question

  • Says an SCT proves the certificate is present in the log.
  • Thinks the client fetches an inclusion proof during the handshake.
  • Treats the SCT timestamp as the certificate's notBefore.
  • Believes the certificate authority signs the SCT.
  • Assumes a connecting client detects a log that breaks its merge promise.
  • Thinks a log vets whether the issuance was legitimate before merging.