How to verify a certificate without Needine
Everything the verification page checks can be repeated with standard tools and without relying on Needine. All you need is the certificate's JSON export.
1. Download the JSON export
On the certificate page, click “Export JSON”. The file contains the signed content, the signature, the Merkle proofs and the timestamp token.
2. Check integrity and signature
The SHA-256 of certificate.canonicalPayload must equal canonicalPayloadHash, and the Ed25519 signature must verify over that hash with a key Needine publishes at /.well-known/needine-keys.json.
3. Check the blockchain anchor
Applying blockchain.merkleProof to canonicalPayloadHash must give blockchain.merkleRoot. Then getAnchor(onChainAnchorId) on the contract on Arbitrum One must return that same root; any block explorer shows it.
4. Check the RFC 3161 timestamp
Applying qualifiedTimestamp.merkleProof to canonicalPayloadHash must give qualifiedTimestamp.merkleRoot. Save the 32 bytes of that root and the token, and verify them with OpenSSL:
# root.bin: the 32 bytes of qualifiedTimestamp.merkleRoot · token.tst: qualifiedTimestamp.tokenBase64
node -e "const t=require('./certificate.json').qualifiedTimestamp, fs=require('fs');
fs.writeFileSync('root.bin', Buffer.from(t.merkleRoot, 'hex'));
fs.writeFileSync('token.tst', Buffer.from(t.tokenBase64, 'base64'))"
# tsa-chain.pem: the certificate chain of the timestamp authority
openssl ts -verify -token_in -in token.tst -data root.bin -CAfile tsa-chain.pem5. Check whether the authority was qualified
Look up the authority that signed the token in the EU trusted lists: a qualified time-stamping service (QTST) appears with status “granted” on the date of the stamp. The authority Needine uses today is not qualified, and the verification page says so. Use the official browser or validate the token with the European Commission's DSS tool.
6. Or do it all with our SDKs
The SDKs run the same checks locally: signature, Merkle proofs, RFC 3161 token and EU trusted lists.
npm install @needine/sdk
import { readFileSync } from "fs";
import { verifyBundle, verifyBundleTimestamp, verifyBundleQualification } from "@needine/sdk";
const bundle = JSON.parse(readFileSync("certificate.json", "utf8"));
const { keys } = await (await fetch("https://api.needine.com/.well-known/needine-keys.json")).json();
verifyBundle(bundle, keys); // integrity, signature, Merkle proofs
await verifyBundleTimestamp(bundle); // RFC 3161 token
await verifyBundleQualification(bundle); // EU trusted listspip install "needine-sdk[verify]" from needine import verify_bundle result = verify_bundle(bundle, keys) # integrity, signature, Merkle proofs
Needine takes no part in any of these checks: if Needine disappeared, the proof would remain verifiable.