Skip to main content

Trust boundaries and data

A trust boundary is a line where data leaves the control of one party and enters another's. Certichain is designed so that the most sensitive data never crosses the lines it does not need to cross, and so that a verifier can check the result without trusting the operator. This page maps the boundaries. The Threat model and Privacy design pages go through attacks and data handling in detail.

What crosses each boundary​

FromToWhat crossesWhat never crosses
WalletAppAddresses, signatures, transaction hashesPrivate keys
AppChain (through the wallet)Issuer address, salted subject commitment, document SHA-256, salted metadata hash, record type, dates, nonce, EIP-712 signature, status reason codes and note hashes, enrolment commitmentsNames, student ids, documents, CIDs, document keys, salts, plaintext notes
AppServerThe encrypted container, the claimed document hash, the issuer's SIWE message and signature, the session cookie; for API callers, credential ids and (for file checks) a VC or Open Badge export, which carries no CID and no keyThe plaintext document, the document key, salts, holder details
ServerPinning serviceThe encrypted container and its metadata (document hash, issuer address), which are public on chain anywayAnything decryptable
AppRPC providereth_call and eth_getLogs requests; the provider learns which ids and addresses a visitor looks upKeys, documents, package contents
AppGatewayA request for a CIDThe document key (a capability link keeps the key in the URL fragment, which browsers do not send)
HolderVerifierWhatever the holder chooses: a link or id; a VC or Open Badge export (no CID, no key); a disclosure file with chosen fields; a compact QR code; or the full packageAnything the holder does not hand over
Safe and guardianChainAdmin and guardian transactions, all public eventsNothing private

The credential package is the one file that carries everything (details, salts, CID and the document key). It is the holder's to keep. Sharing a package shares the ability to open the document; the sharing flows give narrower options.

What each party relies on​

PartyRelies onDoes not need to rely on
VerifierThe chain's consensus; the RPC endpoint it reads through (or its own node); the code it runs (the website, the offline script or the SDK); the admin's choice of which issuers are registeredThe operator's server, the pinning service, the issuer's website, any account
HolderThe issuer to issue correctly; the pinning service to keep the encrypted file available (or their own copy); their own deviceThe operator to keep their data private: the server never had it in plaintext
IssuerIts wallet and key custody; the website code it signs through; the server to accept uploadsThe operator to store a database of its records: everything is on chain or with the holder
API and SDK usersThe API signer key they pinned, the freshness and data-age fields in each signed answerThe transport or any proxy in between
OperatorVercel, the pinning service, Redis, the RPC providers, the Safe ownersHolding any personal data

Integrity anchors​

A few values tie everything together. If they match, the rest can be checked.

  • The credential id is the EIP-712 digest of the signed credential struct under a domain that names the chain id and the registry address. The same fields on another chain or another registry give a different id, so an id cannot be replayed elsewhere.
  • The document hash is the SHA-256 of the plaintext file. It is anchored on chain, recorded in the container header, and recomputed by the verify page when a verifier chooses a file.
  • The subject commitment and metadata hash are salted hashes. Only someone holding the salt (the holder, or a verifier the holder gave the package or a disclosure to) can recompute and compare them.
  • The issuer signature is carried in the CredentialSigned event and in the package, and checked against the issuer's address (or through ERC-1271 for contract wallets).
  • Signed server answers carry the signer address that clients pin (NEXT_PUBLIC_API_SIGNER, NEXT_PUBLIC_STATUS_LIST_PUBLISHER), so a verifier can tell an answer from this deployment from any other.

If one part is compromised​

This table states the design intent at the architecture level. The threat model lists the mitigations and residual risks in full.

Compromised partWhat an attacker could doWhat still holds
The hosted website codeServe altered JavaScript that misreports checks or captures data typed into it from then onThe chain records; verification through the offline script, another front end or a block explorer; documents already stored stay encrypted
The server routesRefuse or delay uploads; sign false API answers or status lists if the signer keys leakChain state; anyone reading the chain directly; containers stay unreadable
An RPC providerReturn wrong or stale reads to the browsers that use itThe chain itself; a verifier can switch provider or use the signed API
The pinning serviceLose or withhold encrypted filesVerification, which does not need the file; the holder's own copy; the second pin provider once configured
An issuer keyIssue or revoke in that issuer's nameOther issuers; the admin or guardian can suspend the issuer at once; on contract version 0.5.0 the key can be retired in favour of a successor
The guardian keyPause new issuance (a denial of service)Every credential, status and verification
Safe owners (two of three)Register or remove issuers and change rolesEvery past record; with the timelock in charge, a public delay before any admin action runs

Session and role checks at the server boundary​

The server does not trust a session for longer than it must. An issuer-only route (src/lib/server/issuer-session.ts) checks, in order: the per-IP budget, a valid signed session cookie, and that the wallet's issuer registration was confirmed on chain within the last five minutes (ROLE_RECHECK_SEC); otherwise it re-reads the registry. A registry outage is answered as unavailable, never as "allowed". See Sign-in and sessions and Security controls.

Source files​

  • src/lib/eip712.ts, src/lib/commitments.ts, src/lib/credential-package.ts
  • src/lib/doc-crypto/container.ts, src/lib/doc-crypto/capability.ts
  • src/lib/server/issuer-session.ts, src/lib/server/session.ts, src/lib/server/upload-container.ts
  • src/lib/api/envelope.ts
  • blockchain/contracts/v03/CredentialRegistry.sol