Security
This software keeps keys and evidence. This page states what it defends against, by what means, and the rules its maintainers follow.
Reporting a vulnerability
Please use the repository’s private vulnerability reporting, stating the affected version, the steps to reproduce, what you observed and the impact as you see it. Until a fix is released, please keep the details in the private channel.
These classes are handled first: a signature that bypasses the user’s confirmation; a check that answers “All passed” to a forged input; local data or keys read while locked; two conforming implementations reaching different verdicts on the same input.
Threat model
| Adversary | Defence |
|---|---|
| Someone who sits down at the machine while you are away | The passcode gate; a lock after five wrong tries; auto-lock when idle; the master key cleared from memory on lock. |
| Someone who obtains the disk or a backup file | Ledgers, settings, the queue, the identity registry and received grants are stored encrypted, and the key store is encrypted separately under the passcode; the machine settings read before unlocking and the exports meant for others are plain. What holds against offline guessing is the strength of the passcode and the backup password, and the scrypt (N=262144, r=8, p=1) every try has to run. |
| Someone who hands you forged records | Signatures, the ledger’s chain and the records on the blockchain confirm one another, and verification gives a result for each check. |
| Someone who fabricates evidence after the fact | An anchor gives an upper bound on time; a continuous ledger has every position already taken. |
| A node that lies | Readings from several nodes are compared; a single source is marked as such. |
| A web page or app that lures you into signing | The identity key is used in Zikaron alone, and the app signs in two of the four domains alone: zikaron/1 and zikaron/1-adoption. |
Out of scope: malicious software running on an unlocked machine, memory reads, and compromise of the operating system or hardware. For these, the software states its limits as they are.
Rules for keys
- Deterministic signatures
- RFC 6979 deterministic nonces with low-s values. One key signing the same bytes produces the same signature on every conforming tool.
- Four independent domains
- The domain literal is written inside the signed message, so a signature under one domain is valid in that domain alone. A new domain takes a literal wholly distinct from the existing ones.
- Sign what the app assembled
- The app signs content it assembled itself and the user has seen on a confirm card; the signing entry point is open to such content alone.
- Keys stay in memory briefly
- They are cleared after use. Logs and error messages carry addresses alone.
- Cryptography in one place
- Calls for elliptic curves, hashes and key derivation are gathered in designated modules, and other code goes through them.
Rules for reading the chain
- Failure is an absent answer
- When a node is out of reach, readings differ or a scan is interrupted, the conclusion is recorded as absent, and the interface shows it so. A network fault and a forged record have to be told apart at a glance.
- Green comes from a complete check
- A transaction in a block counts as “Confirming”; the green lamp lights once the ledger check’s report has read it.
- Leave the queue on a successful receipt
- An entry leaves the queue once its receipt confirms success; entries whose send failed or timed out stay queued. Deleting a record that is still unsent also takes it out of the queue.
- Check before resending
- Entries already on chain are kept out of the queue. After a restart, the app resumes waiting for the same transaction’s receipt.
- Certificates checked every time
- For
httpsnodes, the certificate chain and host name are checked on every connection. TLS uses rustls, with root certificates built into the app and kept apart from the system’s certificate store. - Bounded inputs
- Each chain read is limited to 30 seconds and a response of at most 64 MiB. Record kits fetched from a publish address travel over
httpsalone: 20 seconds and 32 MiB per file, at most 64 MiB per kit, and at most 3 same-origin redirects.
Privacy
- The app’s network requests go to these destinations alone: the nodes the user configured, the publish address the user entered, the https addresses the user gives when verifying, and the publish address carried in a grant file received (fetched again at each periodic re-verification). Beyond these, the app makes zero update checks and sends zero telemetry.
- Public nodes can see the addresses and contracts queried; the documents and the interface say so.
- Text inside an entry travels with the ledger (record kits, grant files, mirrors) and stays readable for good; the documents say so plainly.
- For short, guessable content, a fingerprint withstands a limited number of guesses; the documents remind users to add random content.
- File names and paths at signing stay on the machine, stored apart from the ledger; record names are written into entries and are public with them.
Dependencies and the supply chain
Cargo.lockis committed, and release builds use--locked.- Dependencies are kept few; the cores and storage use the standard library wherever they can.
- An upgrade of a cryptographic dependency gets its own pull request with a change note, and every conformance comparison is run again.
- A new dependency comes with its purpose, maintenance status and licence.
- Embedded fonts are released with their licence texts.
Rules for writing files
- Write a temporary file, sync it to disk, then rename it into place.
- Existing files are always kept: a backup, record kit or grant file that meets a taken name saves under a numbered name and says where; key files and the command line stop at a taken name.
- Read back and compare after writing, above all for key files and backups: report success once the read-back matches.
- Changes such as restoring a backup or changing the primary identity complete as one step: either all of it takes effect or everything stays as it was. A batch of signatures stops at the first failure and keeps what it has signed.
- Old data whose master key is gone, closed for good, is moved byte for byte into a
set-asidedirectory. - Key files are written with mode 0600.
Failures have to be visible
Whenever an operation falls through, the interface says so plainly. The costliest defect in software of this kind is a failure the user takes for a success: evidence believed to be on chain turns out, on the day it is needed, to be missing. When reviewing a pull request, ask of every new action: what does the user see when it fails?