Skip to content

Transparency log

Everything we sign, in public

Every Content Credentials signature, time-stamp and signed check result Kennmarq.com hands out is first written to this log. The log can only grow, and we sign a root over all of it every hour while it grows, at least once a day. Anyone can check that a file's signature is in it, and that nothing was ever removed, changed or backdated, us included.

Latest signed root

Entries
374
Signed
(root 96)
Root hash
264b1ee55014b2441437014d730e3e88eaf118b6ce1338beb4090591daded29c
Key ID
3b51f0f999b77a04bd96b2b86fa783237f5f33f29c55275a7e5a06ad7230829e
Signature
MEYCIQCB2TSnaNbENqR76gLDND1ueVHoUcYTA3s193IujqcW4AIhALsTYZqhEaFpXjlOGA3Rtv3L+gVwvx9xrIukbCSQ7dls

381 entries in the log now. As JSON: https://api.kennmarq.com/v1/log/root

What goes in

  • Signatures: for each file marked through the API, its manifest's label and the SHA-256 of the file, of its signature, of the signing certificate and of the time-stamp inside the signature. For a file marked in local mode, which never reaches us, its hard binding stands in for its SHA-256.
  • Time-stamps: for each token from our time-stamp server, its serial, its time, its SHA-256 and the hash it stamps.
  • Audit-log anchors: each organisation's audit log is hash-chained; its latest hash goes in here, under a pseudonym only its members can recognise, so its history can't be rewritten unseen.
  • Signed check results: for each result of POST /v1/verify we sign, its SHA-256, the checked file's SHA-256 and our checker key's ID.

Never in it: organisation names or IDs, file names or contents, watermark IDs, models, apps or titles, addresses or people. Whoever holds a file can find its entry; nobody else learns anything from the log.

Check it yourself

  1. Find a file's entry by its manifest's label, or by the X-Log-Index the API returned with it: GET /v1/log/proof/urn:c2pa:… answers with the entry and the hashes that connect it to a signed root.
  2. Check that the entry matches the file (its SHA-256, its manifest's label), and fold the proof up to the root.
  3. Check the root's signature with our public key, below.
  4. Keep the roots you've seen. GET /v1/log/consistency proves any later root still starts with every entry of an earlier one.

The API reference has the exact formats, and the few lines of shell and Python that do each check. The tree is RFC 9162's (Certificate Transparency), and roots are signed like RFC 6962's tree heads, so existing tools and libraries apply.

Verify the latest root with OpenSSL (and jq)
curl -s "https://api.kennmarq.com/v1/log/key?format=pem" -o log-key.pem
curl -s "https://api.kennmarq.com/v1/log/root" -o root.json
printf '0001%016x%016x%s' "$(jq .timestamp root.json)" "$(jq .tree_size root.json)" \
  "$(jq -r .root_hash root.json)" | xxd -r -p > tree-head.bin
jq -r .signature root.json | base64 --decode > signature.der
openssl dgst -sha256 -verify log-key.pem -signature signature.der tree-head.bin

Recent roots

The ten most recent signed roots
RootSignedEntriesRoot hash
96374264b1ee55014b2441437014d730e3e88eaf118b6ce1338beb4090591daded29c
9536826d4828ac190591c76fc79a8a1152c90bb6efc6f5c67e4454f676d163c8fd569
9436780ac6ea3fc0970ca4fd4596254ba14c94012cc88c89f56e555c6852fb4f04f1d
93366f5006059d9f1b0916fb9b50530341f4e2bb890237f13e5183f5afc40f41a2a30
92351897f23ae30be3c5591a91ae9e7378e4911562f0b8cbc3110c66a4270b90ef7d5
91345ca4f6ca697a43d16038757a01d26d28e9b46b286b8599db17c808df55c468487
90344ec87e5a4a94c011a30e2a1bfbae9c9b4212a7a9ba97d36922bd6a087c0c67c42
893436aa46d0cedc3148d9897a18023419f639dd54a8bda755849db1f9f7e18fe0565
88331acffc0c7b3b768a51d53df32626ede643ee8a244b5fffd0325707505def1e5b7
87325770fcf19ff2f56c641645c3bab5660dd77a8a4789259f4da84fae0a220443f29

Every root, newest first: GET /v1/log/roots.

Our log key

ECDSA P-256 with SHA-256. Key ID 3b51f0f999b77a04bd96b2b86fa783237f5f33f29c55275a7e5a06ad7230829e, the SHA-256 of the key below in DER. It signs tree heads and nothing else, and it lives in AWS KMS, which never lets it out.

PEM
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE42CpuoaS4/rNCAyQ08euvOtCa9X3
Zuq7bXjiCyeh4C0O92Ey6CbvOtfkS11IoLLFWFzzXrcpi/0L2vDeXsufyw==
-----END PUBLIC KEY-----
Our time-stamps are our own word, not a third party's: that's why every one of them is here. The time in a stamp and the time its entry was logged sit side by side, and once a root covers them, neither can change.