Independent verification

Verify the audit record yourself

The organisation delivers the evidence, the auditor performs the verification. That needs no access to the product, no server and no software written by us. The tools that ship with Windows, or openssl, are enough.

Three deliveries

Different questions, the same wrapper

Three separate packages exist because they answer three separate questions and are delivered at different times. Their wrapper is identical, so the auditor learns one procedure.

Package The question it answers Its data file
Evidence dossier
SQLChangeGuard-Evidence
The end to end story of the single request you sampled. Who asked for it, under which rule it was approved, who ran it, what the script was that day. Dossier.json
Dossier.pdf
Anchor package
SQLChangeGuard-Anchors
The daily anchors for a date range. Each anchor carries, under signature, the digest of the last record at the moment it was taken. It is delivered regularly, ahead of the audit. Anchors.json
Audit records package
SQLChangeGuard-AuditRecords
The raw audit rows for the record number range you choose. This is the only delivery that lets the claim inside an anchor be compared against today's records. Package.json

Why not a single file. The anchor has to have been delivered before the audit; its value comes from being early. An anchor that arrives together with the records is just two files produced at the same moment by the same party, and proves nothing. Merging all three into one file would destroy the only evidential value the anchor has.

Inside the package

Every zip carries the same five things

File What it is for
The data file Dossier.json, Anchors.json or Package.json. The evidence itself. Plain text JSON, readable by eye.
Manifest.json The package identity block: installation id, product version, range, and the SHA-256 digest of every file in the package. Removing a file from the package is caught by this list.
Manifest.sig The RSA signature over the bytes of Manifest.json, in Base64. The signature is over the bytes that were delivered, not over a recomputed copy.
PublicKey.pem The public half of the key that signed the manifest. When an anchor package spans a key change, the older keys ship separately as PublicKey-<id>.pem, because openssl reads only the first key out of a concatenated PEM file.
Verify.ps1 A script that runs the checks above for you. Its own digest is listed in the manifest, so a modified copy is caught. It is a convenience, not the evidence.

The signature parameters are fixed and stated in the evidence format specification: RSA (3072 bit minimum), SHA-256, PKCS#1 v1.5, PEM key, Base64 signature. When timestamping is on, the evidence dossier also carries Manifest.tsr; the stamp on an anchor travels inside the anchor envelope itself.

Verification

Four steps, four separate questions

The steps do not substitute for each other. One passing does not make another pass.

1. Have the files changed

You read the list in Manifest.json and recompute the SHA-256 digest of every file. A row that does not match means that file changed after the package was produced.

The question it answers: is the file in front of me the one that came out of the package?

2. Who did the manifest come from

Manifest.sig is checked against PublicKey.pem. If it passes, the manifest came from the installation that holds the matching private key and has not changed by a single byte since.

The question it answers: was this list really sealed with the organisation's own key?

3. Is the key the right key

You compute the fingerprint of the public key and compare it with the value the organisation published outside this package. Skip this step and step 2 proves nothing: anyone who ships a package with a key of their own also passes the signature check.

The question it answers: is the key that sealed this package the key the organisation declared?

4. Have the records changed since

The first three steps check the wrapper. The fourth looks at the records themselves and needs no key: chain linkage, the anchor comparison, and recomputing the content. All three are set out below.

The question it answers: could the records have been rewritten after the fact?

Three checks that need no key

What the auditor can do without asking the organisation for anything

The signing key of the audit chain stays inside the organisation and never leaves it. None of these three checks needs that key, so the auditor can run them alone.

Check A: chain linkage

Every row in the records package carries the digest of the row before it. You take two consecutive rows and check whether the previousHash of the later one equals the hash of the earlier one. This can be done entirely by hand, with nothing but the rows in the package.

Knowing the limit of this check matters. It compares digest values only; it does not compute whether a digest really belongs to the content beside it, because that needs the secret key. So it catches an inserted row and a deleted row, but on its own it cannot catch a content edit.

Check B: the anchor comparison

You hold an anchor package from last month, received at the time. One anchor in it says: "on that day my last record was number 41,207 and its digest is this." That sentence is signed and it was delivered on that day.

Today you ask for a records package covering record 41,207 and compare the hash of that row against the value in the anchor. If they match, that record has not changed since the day the anchor was delivered.

The strength of this check rests entirely on the anchor having been delivered to you earlier. An anchor that arrives on the same day as the records proves nothing; both files were produced at the same moment. That is why anchor delivery is not left until audit time but happens on a schedule. Each export is itself an audit event and is recorded, so a regular delivery habit can be shown from those records afterwards. If no range is given, the package starts where the previous delivery ended, leaving no gap between two deliveries.

Check C: recomputing the content

The two checks above share one gap: both look only at digest values. Someone who changes the content of a record and leaves its digest field untouched would pass both. The link holds, the anchor holds, nothing shows.

So the records carry a second chain, and that one is keyless. The auditor recomputes the value from the content of the record on their own machine and compares it with what the row says. A mismatch means that record's content changed.

The objection that a keyless value can be computed by an attacker too is correct and beside the point. This chain draws its strength not from secrecy but from its end value sitting in an anchor already delivered to you. An attacker can recompute the chain but cannot change the old value in your drawer. Git commit digests and certificate transparency logs work the same way.

The exact definition of the calculation is in the evidence format specification, together with a test vector: a given input with its expected output, so you can write your own verifier and check that it works.

The product runs this comparison itself rather than waiting for you. The audit integrity job compares previously signed anchors against the current records every day, and writes the result into the manifest of the anchor package. Because the manifest is signed, hiding a finding breaks the signature.
Commands

Run it on your own machine

Unzip the package and run these inside the folder. Nothing connects to the product and nothing goes over the network.

On Windows, with PowerShell

# File digests and the signature. The script inside the package does both. powershell -ExecutionPolicy Bypass -File .\Verify.ps1 # To compute the digest of a single file by hand: (Get-FileHash Anchors.json -Algorithm SHA256).Hash.ToLower()

On any system, with openssl

# The manifest signature openssl dgst -sha256 -verify PublicKey.pem -signature Manifest.sig Manifest.json # The public key fingerprint (SHA-256 over the SPKI DER bytes). # Do NOT pipe openssl into openssl in PowerShell. The pipe is a text stream # there, it corrupts the binary DER and yields a WRONG value with no error. openssl pkey -pubin -in PublicKey.pem -outform DER -out pub.der openssl dgst -sha256 pub.der

The script is not part of the evidence. Verify.ps1 ships inside the package it checks. An auditor who wants independence should run the commands by hand at least once. The authoritative procedure is not in the script but in the evidence format specification, which is available on request and which the delivered packages follow.

For the auditor

Exactly what to request from the organisation

With these four items in hand the whole verification can be done. The order matters.

  1. The fingerprint of the public key, in writing and independent of any package. Requested once, valid until the key changes. Without it the signature check collapses into a self certifying exercise.
  2. The anchor package, on a schedule and ahead of the audit. Monthly or quarterly. An anchor requested on audit day carries no evidential weight; its value comes from having been delivered early.
  3. The evidence dossiers for the requests you sampled. Give the request numbers yourself. Letting the organisation choose turns the evidence into a selection.
  4. The records package, for the number range covered by the anchor you hold. You read the range off the anchor and ask for it. This is the only delivery that lets you run Checks B and C. Start the range one record earlier: verifying the first row in the package needs the value of the one before it.

You can ask for a fifth item: the evidence format specification. The authoritative description of the verification is in that document rather than in the script inside the package; it is available on request and the delivered packages follow it.

The honest boundary

What this verification proves, and what it does not

It proves

  • The package has not changed since it was produced.
  • It came from the installation holding the declared key.
  • The records have not changed since the date of the anchor you already held.
  • No record was inserted in the middle.
  • The content of the records has not changed. You compute this yourself rather than asking the organisation.

It does not prove

  • That what was written was true that day. A seal shows the entry is early, not that it is correct.
  • The existence of an action that produced no record at all. An intervention made outside the product is surfaced by the database level trail, not by the seal.
  • That an anchor never delivered was not deleted. With the sealed copy switched off, deletion is only visible against earlier deliveries; the package does not hide this, it states it in the manifest.

This is the difference between tamper evident and tamper proof. We do not promise a record that cannot be altered; we produce one where alteration shows. The second can be verified, the first can only be asserted.

Timestamping

Letting a third party state the date

A signature shows where a package came from, not when. The date is written from the organisation's own server clock, and that clock can be changed.

RFC 3161 timestamping closes that gap. When it is switched on, the digest of the package is sent to an external timestamp authority and the response is placed in the package as Manifest.tsr. The date is then stated by a third party rather than by the organisation.

The only thing that leaves the network is the digest. The record itself never goes to the timestamp authority under any circumstances. The feature is governed by a single master switch; when it is turned off no network call is made at all and the product keeps working without internet access.

The configuration that ships with the product has the feature on and points at a free public authority, so an installation can be seen working end to end on day one. In production that address should be replaced with the organisation's own contracted or internal authority: a public service makes no commitment and ties the evidence chain to something outside the organisation.

If the authority cannot be reached the work does not stop, the package is produced without a stamp, and the gap is not hidden: the file is omitted, the stamp field in the anchor envelope stays empty and a warning is written to the log. On such a package the auditor can see that the date is the organisation's own assertion.

Next