Skip to content

nqchk(3)

nqchk — check a capsule folder against its seal

libnoqtis, -lnoqtis

#include <noqtis.h>

int
nqchk(const char *dir, const uint8_t *trust, size_t trustlen, nqrep **rep);

() checks the capsule in the folder dir (noqtis-capsule(5)) and stores in *rep a report with one row per check (nqrep(3)). It runs every check it can, rather than stopping at the first failure, so the report says everything that is wrong.

It reads noqtis.sig (at most 1 MiB, never through a link) and checks that it is canonical JSON with exactly the seal's fields; reads noqtis.json (at most 512 MiB; the size is checked before reading and again if the file grows while it is read) and checks that its SHA-256 is the seal's ‘manifest_sha256’; verifies the signature over the exact manifest bytes with the seal's algorithm and context; lists the folder; and reads the manifest one entry at a time in its canonical layout, checking each listed file (present, a regular file, size, SHA-256, SHA3-256) as it goes, the sort order and duplicates. Finally it reports every regular file present but not listed, every link, special file or refused name, and listed paths that differ only in case.

trust is the public key the capsule must be sealed with, trustlen bytes in the algorithm's encoding: the seal's key must equal it, and the signature is verified with it. With trust NULL (and trustlen 0), the key inside the seal is used, and the report's ‘key’ row says the key was not pinned: the capsule is then shown unchanged since it was sealed, but not who sealed it.

() is nqchkt(3) with no TSA trust anchors. A seal that carries a timestamp therefore fails its ‘timestamp’ row here (with the imprint still checked against the signature): a timestamp that cannot be checked is never passed silently.

Memory use is the manifest bytes once (the signature covers them, so they must be in memory to be verified), the folder listing (about 100 bytes per file), the report (one row per file) and constant state per entry; the manifest is never parsed into a tree.

Every check passed. *rep holds the report.
[NQEVRFY]
At least one check failed; *rep still holds the report, which says which.
[NQEARG]
dir or rep is NULL, or trust is NULL with a nonzero trustlen. No report.
[NQEMEM]
The allocation hook returned NULL. No report.

With no report, *rep is set to NULL. Free a report with nqrepfree() (nqrep(3)).

nqrep *rep = NULL;
int rc = nqchk("results", pk, sizeof pk, &rep);
if (rc == NQOK)
  puts("unchanged since sealed by that key");
else if (rc == NQEVRFY)
  puts("changed or not sealed by that key: see the report");
nqrepfree(rep);

noqtis-check(1), nqchkt(3), nqrep(3), nqseal(3), noqtis-capsule(5)