Check the report without us.
Paste an Armada attestation below. Your browser recomputes its hash, checks the signature against our published key, and walks the chain back through earlier scans. Nothing is uploaded, and you don't need to contact us.
One record, or the whole chain as an array. Whitespace does not matter. Field order does, because the field order is part of what was hashed.
Check against a different key
If someone hands you a key out of band and you would rather trust that one than the copy on this page, paste it here. Leave it empty to use the published key.
What the check answers.
Does the hash describe this content?
Your browser rebuilds the hash from the record's fields: client, timestamp, score, tier, catalog version, every control state and, from catalog 2026.11, the domain the email check read. Change one character and the hash won't match. This is the check that matters most, because a valid signature means nothing if the hash doesn't match what you're reading.
Did the holder of the private key sign it?
The signature is ECDSA P-256 over SHA-256 and verifies against the public key on this page. Anyone can check a signature with the public key. Nobody can forge one without the private key, which never appears on this site.
Is a scan missing from the history?
Each record carries the hash of the one before it. Paste a chain and the checker follows the links. If a scan is deleted from the middle, every later record fails.
Which of these did a machine measure, and which did a person claim?
Most of the catalog has no Microsoft telemetry behind it, so a provider can record a declaration instead: a named person, a date, an expiry. The checker lists declarations apart from measured controls and never adds them to the score. Expired ones are still shown and labeled, but not counted. On every record that has declarations, the checker notes what the signature does and doesn't prove about them.
Was this a real tenant or a test fixture?
Every attestation has a graphMode field. From catalog 2026.10 it's part of the hash, so relabeling a test run as a live scan fails verification. Older records still carry the field and still verify, and the checker tells you the flag wasn't covered on those.
What this page does not prove yet.
Armada is pre-launch. Here is what a passing check does and doesn't mean today.
The signing key is a development key.
The app generates the private key and stores it on disk, not in hardware. A passing check proves the record hasn't changed since signing. It doesn't prove the key couldn't have been misused. Before any live client tenant is signed, the key moves to Azure Key Vault and the key on this page will be replaced.
A signature says nothing about whether the reading was right.
Cryptography proves a record hasn't changed. It can't prove Microsoft Graph returned correct data or that we read it correctly. That's covered on the control catalog.
No client tenant has been scanned.
The sample chain on this page is a real signature over real evaluator output, run against test fixtures. The record and the result both say so.
You are running our JavaScript.
A verifier served by the company being verified is convenient, but it shouldn't be your only check. The algorithm is written out below and the key is downloadable, so you can check a record with your own tools and get the same answer.
Published, so it can be pinned.
This is the current signing key. Download it and keep a copy. If it ever changes without a public notice, email us.
-----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE9WO8ORWLAJOGgt0HQDkG+WsPZHlR VjWAC/jpzm1D2xoUaNOmfI4UZVH6J+avBR/M629/V+kF6aGIcK4TWg0b/Q== -----END PUBLIC KEY-----
The algorithm, written out.
Two SHA-256 digests and one signature check. The field order below is part of the hash, so the JSON has to be rebuilt in exactly this order to reproduce it.
2026.07 controlsHash = SHA256( JSON({ states, catalogVersion }) )
2026.08 controlsHash = SHA256( JSON({ states, catalogVersion, controlVersions }) )
2026.09 controlsHash = SHA256( JSON({ states, catalogVersion, controlVersions, declarations }) )
The checker reads each record's format from the fields it carries instead of assuming the current one, so older reports keep verifying. Both published samples are on this page: an old record and a current one, both valid.
hash = SHA256( JSON({ prevHash, clientId, stamp, score, tierKey, controlsHash }) )
ECDSA_P256_SHA256_verify( publicKey, signature, ascii(hash) )
The signed message is the hexadecimal hash string itself, not its raw bytes. The signature is DER encoded and base64 wrapped.
With openssl, offline
printf '%s' "$HASH" > hash.txt printf '%s' "$SIGNATURE_B64" | base64 -d > sig.der openssl dgst -sha256 -verify attestation-signing-key.pub.pem -signature sig.der hash.txt
Prints Verified OK when the signature matches. Recompute the two digests in step 01 and 02 separately and confirm that $HASH is the hash of the content, or you have only checked half of it.
Where the algorithm lives
The signing side is api/src/lib/attestation.js and api/src/lib/signing.js in the product. The checker on this page is assets/verify.js, unminified and commented. The engine test suite checks the published sample chain against the published key on every run.
Holding a report and want it checked?
If your IT provider gave you an assessment made with Armada and something looks wrong, write to us. We'll help you check it, even if the answer is bad news for our customer.