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
393
Signed
(root 100)
Root hash
9f888d851064ed660d9d08398c6279593f7013efdce91e74ac2dbf705abd9083
Key ID
3b51f0f999b77a04bd96b2b86fa783237f5f33f29c55275a7e5a06ad7230829e
Signature
MEUCIQCSqmS/zysess44u+1E+K2C+rxrSochc8xWVDhyJIaoIQIgNqepBPpycXQbt2oW3nYDf66XU9suWvpzYj+Nd/pSO9M=

400 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
1003939f888d851064ed660d9d08398c6279593f7013efdce91e74ac2dbf705abd9083
993873c6f9b07c6d05178519ec5d0b76089941db724d1b4dbbf664a9f5ee6336f8f37
98386dc65aedb48a3517947a5a4d48a15bce9a2a229f8e1994b08cec65e455fa0a66c
97385ca0fe21020b36ecf91137b7e08acb38a4733692ee0c5bbb2752e55b14082758b
96374264b1ee55014b2441437014d730e3e88eaf118b6ce1338beb4090591daded29c
9536826d4828ac190591c76fc79a8a1152c90bb6efc6f5c67e4454f676d163c8fd569
9436780ac6ea3fc0970ca4fd4596254ba14c94012cc88c89f56e555c6852fb4f04f1d
93366f5006059d9f1b0916fb9b50530341f4e2bb890237f13e5183f5afc40f41a2a30
92351897f23ae30be3c5591a91ae9e7378e4911562f0b8cbc3110c66a4270b90ef7d5
91345ca4f6ca697a43d16038757a01d26d28e9b46b286b8599db17c808df55c468487

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.