CodamAIDocs
Topicdone

Timestamps and anchors

How CRMS anchors the journals of all tenants with an RFC 3161 timestamp, what the anchor check finds, and how you replace the timestamping key without losing old anchors.

Variants
anchor intactjournal not anchored yetcertificate expires sooncertificate expiredkey replaced, old certificate trusted

What this is about

A hash chain in your own database can be recomputed by anyone who controls the database. They change an entry and recompute all following hashes consistently. The chain alone does not notice.

A timestamp helps against this: a signed statement that a certain hash already existed at a certain time. At fixed intervals CRMS has the latest entries of all journals stamped. This is called anchoring, and the result is an anchor.

How the journals are built is described in The two hash chains.

An anchoring pass

  1. 1
    CRMS→Database
    reads the head of the system journal and the head of every tenant's journal, each in its own context
  2. 2
    CRMS
    builds one Merkle tree from all heads and computes its root
  3. 3
    CRMS
    has the root stamped by the timestamp authority (RFC 3161)
  4. 4
    CRMS→Database
    stores the anchor in the system database
  5. 5
    CRMS→Database
    puts each journal's proof path into that journal's database
    Result: Every tenant holds the proof for its own journal
  • How often: every CODAMAI_CRMS_ANCHOR_INTERVAL (default PT1H, so hourly). The first pass starts one minute after the start.
  • Which tenants: all that CIAS knows, suspended and closed ones too. Their journals have to stay anchored as well.
  • If a tenant cannot be reached: it is left out and the others are anchored. The next pass tries again.
  • Who runs it: every instance with CODAMAI_CRMS_SCHEDULING_ENABLED=true (default). With several instances, leave it on in exactly one.

The Merkle tree

A Merkle tree combines many hashes into a single one, the root. Two hashes at a time are hashed together until only one is left. So one timestamp is enough for all tenants, however many there are.

flowchart BT
  A["Leaf: system"] --> AB["Node"]
  B["Leaf: acme"] --> AB
  C["Leaf: beta"] --> CD["Node"]
  D["Leaf: gamma"] --> CD
  AB --> R["Root → timestamp"]
  CD --> R
  • A leaf is the canonical JSON {journal, sequence, hash} of the journal head. The leaves are sorted by journal, so the same heads always give the same root.
  • The tree follows RFC 6962: leaves get the byte 0x00 before hashing, nodes 0x01.
  • A journal’s proof path is the list of neighbor hashes on the way from the leaf to the root. With it, a tenant shows that its journal head is inside the stamped root, without seeing the other journals.

What the anchor check finds

The anchor check takes a journal’s newest proof path and checks it station by station. Together with verifying the chain itself, it also finds a journal that was recomputed consistently.

Anchor check of a journal
  1. CRMS
    Proof
    Is there a proof path for this journal?
    ↳ no journal-not-anchored
  2. CRMS
    Anchor
    Is the named anchor in the system database?
    ↳ no anchor-missing
  3. CRMS
    Entry
    Is the journal entry at the anchored position still the same one?
    ↳ no anchor-entry-mismatch – rewritten
  4. CRMS
    Path
    Does the proof path lead to the anchor's root?
    ↳ no anchor-proof-invalid
  5. CRMS
    Timestamp
    Is the timestamp on the root valid?
    ↳ no anchor-timestamp-invalid
  6. The journal is proven up to the anchored entry

These results are keys in a check result, not error answers.

The timestamp authority

A timestamp authority (TSA) signs hashes together with a time. CRMS brings its own, which works according to RFC 3161:

  • Its key comes as a PKCS#12 file, Base64 encoded, from CODAMAI_CRMS_TSA_KEYSTORE, the password from CODAMAI_CRMS_TSA_KEYSTORE_PASSWORD. Without a key, CRMS does not start.
  • The certificate must carry the usage timeStamping, marked as critical. Otherwise CRMS does not start.
  • The time comes from the system clock. Keep it synchronized, for example with NTP.
  • Every timestamp has a random 128-bit serial number and carries the certificate it was signed with.

Which timestamp CRMS trusts

A timestamp is verified against the certificate that signed it. That certificate must be trusted, and it must have been valid at the time of the stamp.

Signed with the current certificate?Certificate in the trust list?Issued by a certificate in the list?Is the stamp accepted?
yes––yes
noyes–yes
nonoyesyes
nononono

The trust list is CODAMAI_CRMS_TSA_TRUSTED_CERTIFICATES: PEM certificates one after the other, or that PEM as Base64 if the environment takes no line breaks. The certificates are public, but they always come from the configuration, never from the database. Otherwise the database administration could add a certificate of its own and stamp a rewritten history.

Expiry of the certificate

Depending on the certificate's validity

When: more than 60 days until it expires

CRMS starts and stamps as usual.

Result: Anchors are created as planned

When: fewer than 60 days until it expires

The start warns in the log with the expiry date. The anchoring pass warns as well, at most once a day.

Result: Anchors are still created. Replace the key now

When: the certificate is not valid at start

The start fails and names the certificate's validity dates.

Result: CRMS does not run

When: the certificate expires while CRMS runs

Every anchoring pass is refused with timestamp-certificate-expired. The journals stay intact, only no new anchor is added.

Result: No anchor until a valid key is deployed

Replacing the key

  1. 1
    Admin
    creates a new timestamping key with timeStamping as a critical usage
  2. 2
    Admin
    exports the current certificate as PEM first
  3. 3
    Admin
    puts the new key into CODAMAI_CRMS_TSA_KEYSTORE and appends the old certificate to CODAMAI_CRMS_TSA_TRUSTED_CERTIFICATES
  4. 4
    CRMS
    stamps with the new key from the next pass on. Nothing is stamped again
    Result: Old and new anchors stay verifiable

With a certificate authority of your own, you list that authority’s certificate instead. Then every timestamping certificate it issues is accepted, and a replacement needs no change to the list.

An overview of the variables is in Configuration.

Pitfalls

Next

Search