Skip to content

Encrypt nodeApproval records + document plaintext bootstrapping records #205

Description

@LiranCohen

Follow-up from the encryption audit of the meshd DWN records. Splitting this out from the admin-dapp redesign (#204) because it is a protocol + key-delivery change, not a one-line encryption flag, and it belongs in its own focused PR.

Current encryption posture (audit result)

Encrypted (role-audience / recipient-delivered):

Plaintext (deliberate — see #2):

Never on the DWN: WireGuard private keys (derived locally from each node's vault).

The invite → node join flow is fully encrypted already; the items below only affect the owner-adds-own-device flow and the pre-key bootstrapping records.

#1 — Encrypt nodeApproval

nodeApproval is written plaintext (admin.ts, approveMeshdNodeRequest, owner-scoped branch; and Go writeNodeApprovalRefresh) and read plaintext by the joining device via Go FindOwnerNodeApproval (internal/mesh/owner_request.go:159, called from cmd/meshd/main.go:4277). It carries ownerDID, nodeDID, network name/CIDR/endpoint, meshIP, member/node record IDs, label, expiresAt.

The nodeApproval protocol path has no $keyAgreement/$encryption (only $size + $actions), so encryption: true would throw ("does not have encryption configured"). Encrypting it properly requires:

  1. Add encryption directives to the nodeApproval path in protocols/wireguard-mesh.json (+ the Go/TS InjectEncryptionDirectives that derive $keyAgreement).
  2. Role-audience key delivery to the recipient device (same machinery as node records: the DWN-less did:jwk device supplies its role-path key in the request, the owner mints $encryption/audience + provisions $encryption/delivery).
  3. Update the Go read path (FindOwnerNodeApproval) to decrypt instead of reading JSON directly, and update both writers (dashboard + writeNodeApprovalRefresh).

Scope is comparable to the node-record delivery work in #187/#192 — a real protocol+delivery change, not a flag.

#2 — Document the plaintext bootstrapping records

network and network/nodeRequest are plaintext by necessity: a joining device reads them before it has any keys (it needs the network CIDR/endpoint to bootstrap, and the join request is how it announces itself and delivers its own role keys). The HMAC join proof in nodeRequest is a keyed proof, not a secret. This is an intentional decision — capture it as code comments at the write sites (internal/mesh/preauth.go WritePreAuthNodeRequest, and the network write in admin.ts) plus a short note in the protocol docs, so it is not mistaken for a missed encryption.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions