Skip to content
Alpha — Odal Node is in active development. APIs, schemas, and docs may and will change before 1.0.

Security & cryptography

A Digital Product Passport is only worth the trust you can place in it. The core’s security model exists to answer one question for anyone who meets a passport — a consumer, a recycler, a market-surveillance authority: is this genuine, unaltered, and issued by who it claims to be? It answers with open, audited cryptography and without depending on Odal being online — or existing.

A passport is a signed proof, not a record

When a passport is published, the validated data is wrapped as a W3C Verifiable Credential and signed with the issuer’s own Ed25519 key. The signature covers the exact bytes of the passport: change a single value afterwards and verification fails. A passport is therefore not a database entry you have to take on faith — it is a proof that carries its own evidence.

The trust root is the issuer’s own domain

A signature only means something if you know whose key made it. The core anchors identity with did:web: the issuer publishes their public key as a small document at a well-known address on their own domain (/.well-known/did.json). Verifying a passport is then an ordinary web lookup — fetch the issuer’s key, check the signature.

The trust inherits from DNS and HTTPS — the same infrastructure that already secures the issuer’s website. There is no blockchain, no central authority that has to stay online, and no role for Odal in the verification path. What this guarantees is authenticity (the named issuer signed it), integrity (it has not been altered), and binding (it refers to the specific product). What it deliberately does not guarantee is that the issuer’s figures are correct — the core provides the proof, not the truth behind it.

Rotating keys without breaking the past

Signing keys change over time — a key is retired, a new one takes over. The core treats this as a routine, non-destructive operation. Retired keys are kept in the issuer’s identity document, and every signature names the exact key that produced it. A new key signs new passports; passports signed by an older key still verify against that older key.

This matters because a passport must stay verifiable for the regulation’s full retention window — ten years or more. Rotating a key never invalidates anything already published, and never requires reprinting a label.

Keys are protected at rest

A signing key is generated from the operating system’s own randomness — never derived from a password, so never guessable. The private key is then stored encrypted, never in the clear:

  • The passphrase that unlocks the store is put through Argon2id, a deliberately slow, memory-hard function, to produce the encryption key. This makes guessing the passphrase by brute force impractical even with the file in hand.
  • That key encrypts the store with AES-256-GCM, an authenticated cipher — so the contents are both hidden and protected against modification.
  • A separate integrity check (HMAC) covers the whole file, so tampering is detected — including an attempt to downgrade the protection to a weaker scheme.
  • Key material is wiped from memory as soon as it is no longer needed.

The practical guarantee is simple: the encrypted key file on its own is useless without the passphrase. Where that store lives and how a running node guards it is covered in Operating a node securely.

Sector logic is isolated by construction

The rules that decide whether a product’s data is compliant change sector by sector and regulation by regulation — so they are deliberately not part of the trusted core. Each sector’s compliance logic is compiled to WebAssembly and runs inside a sandbox with no ambient capabilities: no filesystem, no network, no way to reach the host. Product data goes in as plain memory, a validation verdict comes out, and nothing else crosses the boundary. Execution is bounded too — a fixed memory cap and a metered CPU budget — so a plugin that misbehaves is stopped, not obeyed. And a plugin is signature-verified before it is ever loaded.

What this buys is a hard separation between judging data and vouching for it: a buggy or even hostile sector rule can fail a validation, but it can never touch the signing key, alter a passport, or forge a proof. New regulations arrive as new sandboxed plugins — the cryptographic guarantees on this page never depend on trusting them. The concrete runtime limits are described in Operating a node securely.

Binding the proof to the physical product

The QR code printed on a product is a GS1 Digital Link, and the node builds it from the signed passport’s own verified fields at the moment it is served — never from a stored, editable link. If the passport’s signature does not verify, no QR code is produced at all: the label path fails closed rather than print a code for data that cannot prove itself.

The serial number carried on the label is derived from the passport’s identity — fixed-length, GS1-conformant, and non-sequential, so a public label reveals nothing about production volumes. The result is that everything printed on the product traces back to the proof: a tampered passport cannot get a fresh label, and the label carries nothing a verifier cannot check.

Suspected vulnerabilities go to security@odal-node.io under coordinated disclosure — never a public issue first.