Skip to content

Device testing software for phone refurbishers

Signing keys

Check a passport without asking us.

Every Device Passport carries a digital signature. The key that checks it is published here, the check runs on your own machine, and it keeps working whatever happens to the company that issued the passport — or to us.

What a signature is, in three sentences

When Passfone issues a passport it takes the finished record, reduces it to a short fingerprint, and signs that fingerprint with a private key held on our servers and nowhere else.

The matching public key is published on this page. It cannot create a signature — it can only tell you whether one is genuine.

So anybody can confirm that a record was signed by Passfone and has not been altered since, without our permission and without an account — and can still do it years from now, whatever has become of us.

What this does and does not prove

  • That this record was signed by Passfone and has not been changed by one character.
  • That the PDF you were sent is the PDF we issued — the record carries its fingerprint too.
  • It does not prove the phone is good. The passport says what was measured. Whether a Grade B phone at that price is a good buy is your judgement, not a signature’s.
  • It does not prove the measurements are independent. A passport is a record of what the seller’s own bench measured, issued under their name and their responsibility. Passfone makes that record fixed, attributable and impossible to edit afterwards — it does not stand behind the phone.
  • A signature proves the key signed it, not that the record still stands. A passport can be revoked after it was issued, and a signing key can in principle be stolen. The record at https://passfone.com/v1/verify/<number> is the authority on both. Offline checking is for when you cannot reach us, or want to prove nothing was altered years later — for a decision that matters today, check the number against us.

Our signing keys

JSON

Reading them from the published endpoint…

Checking one yourself

Two public URLs and about twenty lines. Nothing below needs an account, a key of your own, or our cooperation — save the file and it will still work years from now.

  1. 1Fetch the record: https://passfone.com/v1/verify/<number> — or api.passfone.com/v1/verify/<number>. It contains the signature, the fingerprint it covers, and which key signed it.
  2. 2Fetch the keys: api.passfone.com/.well-known/passfone-keys.json. Match kid from the record to a key here.
  3. 3Check the signature over the message passfone-report-v1:<fingerprint>, which is that exact text followed by the fingerprint — the one detail that turns a working check into a failing one.
Node.js · no dependencies
import { createPublicKey, verify } from 'node:crypto';

const number = process.argv[2];            // e.g. PF-29HZ-Q5C3
const api = 'https://api.passfone.com';

// 1. The record, as Passfone publishes it.
const r = await (await fetch(`${api}/v1/verify/${number}`)).json();

// 2. The key that signed it. Match r.kid — old keys stay listed for old passports.
const { keys } = await (await fetch(`${api}/.well-known/passfone-keys.json`)).json();
const k = keys.find((k) => k.kid === r.kid);

// 3. The check, on this machine. Nothing here asks Passfone whether it is valid.
const message = Buffer.from(`passfone-report-v1:${r.payload_sha256}`, 'utf8');
const key = createPublicKey({ key: { kty: 'OKP', crv: 'Ed25519', x: k.public_key }, format: 'jwk' });
const ok = verify(null, message, key, Buffer.from(r.signature, 'base64url'));

console.log(`${r.number}  ${ok ? 'signed by Passfone  ✓' : 'NOT VALID'}`);
console.log(`issued ${r.issued_at.slice(0, 10)} by ${r.issuer.name} · status: ${r.status}`);

Run against the specimen passport PF-29HZ-Q5C3, it prints:

PF-29HZ-Q5C3  signed by Passfone  ✓
issued 2026-09-11 by Passfone Demo · status: valid

Change one character of the fingerprint and it prints NOT VALID instead. That is the whole mechanism: there is no third answer, and no way to make a forgery print the first one without the private key.

If you want the raw format

The keys are served as JSON at api.passfone.com/.well-known/passfone-keys.json, cached for five minutes, and every key we have ever used is listed — retired ones included, so a passport signed years ago still checks out.

Keys are Ed25519 (RFC 8032). public_key is the 32-byte point, base64url, which is the x of an OKP JWK. Signatures are base64url over the UTF-8 message described above.