releases

VPN Works 0.10.0 Signs Every Ledger Checkpoint With a Key No Plugin Can Read

VPN Works 0.10.0 signs the Ledger. The kernel holds a key, one per machine, and signs each checkpoint and the end of a run’s sealed record. Ledger never sees the key. Anyone with the public key can check a ledger, and one written again after a checkpoint fails right there.

Ledger has sealed each run’s events into a hash chain since 0.5.0. A chain shows any edit, as long as nobody computes it again. Someone who could rewrite the whole file, hashes and all, was caught only by copies kept elsewhere: the checkpoint copies in the trace, or the last hash Ledger prints at the end.

Signatures close that. Recomputing hashes is easy. Making a signature without the key isn’t.

Signed ledgers in 0.10.0: Ledger in its sandbox asking the kernel to sign each checkpoint, the kernel holding the key, the ledger file with its signature lines, vpnw verify with the public key, and what the tests did to a real run’s ledger

How It Works

vpnw guard --plugin ledger --policy agent.toml -- ./my-agent
vpnw key                                                  # this machine's public key
vpnw verify r-3f9a1c.ledger --key vpnw-ed25519:J+BD…      # on any machine

The first time Ledger runs, vpnw makes a signing key for the machine and prints its public key. From then on every checkpoint and the end line get a signature line right after them, and the ledger’s header names the key. On the machine that ran it, vpnw verify checks against that machine’s key without being asked. Anywhere else, give it the public key with --key.

The key stays in the kernel. Ledger asks for signatures through a new permission, sign, and the kernel signs only in the plugin’s own name and for the run it is part of. So no plugin can use it to vouch for another plugin, or for another run. Any plugin can ask for sign; Ledger is just the first to use it.

What the Tests Showed

The tests take a real run’s ledger and attack it four ways. 10 of 10 checks passed. The results

  • One event after the first checkpoint changed, the whole chain computed again, the old signatures left in place: CHANGED at checkpoint 2, which no longer matches its signature.
  • All 6 signature lines taken out: CHANGED, checkpoint 1 has no signature.
  • The whole ledger signed again with a forger’s own key: CHANGED, signed by another key.
  • The ledger written again with no signatures at all: CHANGED, since this machine signs its ledgers.

The same ledger, untouched, checked out intact on a second machine given only the public key.

What the Review Found

An independent review went through the release twice and found six problems. Each is a test now.

  • A plain verify trusted too little. Without --key, verify on the machine that ran a ledger passed one written again unsigned, or signed with another key. Now it checks against the machine’s own key.
  • A damaged key file did the same. Now verify stops and asks for --key.
  • An honest run looked tampered. A run killed after its end line, before the signature, came out CHANGED. It’s cut short now, as a run killed anywhere else is.
  • Two first runs at once. Two commands making the key at the same moment could fail. The key file is written whole, then put in place.
  • One key, two spellings. A key written another valid way made an honest ledger fail. Only one spelling counts now.
  • A wrong line in the report about the hash you kept.

The review also caught the docs promising something vpnw can’t do: keeping the key out of the watched program’s reach. They now say what the signatures hold against.

Measured

What 0.10.0
Signed ledger checks, with the real binary 10 of 10 passed
Agent session with Budget and Ledger 7 of 7 steps passed
Exit checks 23 of 23 passed
Faults thrown by Lab 36, all handled
Test functions 280 passed, 0 failed
Ways out of the sealed sandbox 17 of 17 blocked, IPv6 included
Statements covered 85.4%

How it was measured: test/results

What It Doesn’t Do Yet

The key is a file of yours, and the program being watched runs as your user. vpnw limits the network, not files, so while it runs the program could read the key. Signatures hold against everyone who can’t read it: whoever holds the ledger later, a reviewer, another user of the machine. Against the program itself, keep the last hash or the trace somewhere it can’t reach, as before.

An unsigned ledger from 0.9 now needs vpnw verify --unsigned on a machine that has a key, because an unsigned ledger is exactly what a rewrite would look like. Ledger · Roadmap · Download