Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,081 changes: 993 additions & 88 deletions Cargo.lock

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ members = [
"cnm-cli",
"didcomm-test",
"pnm-cli",
"room-host",
"tests/e2e",
"vta-cli-common",
"vta-config",
Expand All @@ -25,6 +26,8 @@ members = [
"vtc-client",
"vtc-service",
"vti-common",
"vti-rooms",
"vti-rooms-dtg",
"vti-secrets",
"vti-webauthn",
]
Expand Down
3 changes: 3 additions & 0 deletions Dockerfile.nitro
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ COPY Cargo.toml Cargo.lock ./
COPY cnm-cli/ cnm-cli/
COPY didcomm-test/ didcomm-test/
COPY pnm-cli/ pnm-cli/
COPY room-host/ room-host/
COPY tests/ tests/
COPY vta-cli-common/ vta-cli-common/
COPY vta-config/ vta-config/
Expand All @@ -148,6 +149,8 @@ COPY vta-enclave/ vta-enclave/
COPY vtc-client/ vtc-client/
COPY vtc-service/ vtc-service/
COPY vti-common/ vti-common/
COPY vti-rooms/ vti-rooms/
COPY vti-rooms-dtg/ vti-rooms-dtg/
COPY vti-secrets/ vti-secrets/
COPY vti-webauthn/ vti-webauthn/

Expand Down
19 changes: 19 additions & 0 deletions deny.toml
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,25 @@ ignore = [
Drop when uniffi (0.28.x) removes its `paste` dependency.
""" },

{ id = "RUSTSEC-2026-0173", reason = """
proc-macro-error2 2.0.1 is unmaintained — the author has said so and
recommends migrating away. Build-time only, and twice removed from
anything we ship: it is a proc-macro, so it runs in the compiler and
links into no artifact, and its only path into this workspace is
vtc-client's optional, off-by-default `mls` feature —
openmls_rust_crypto -> hpke-rs -> libcrux-sha3 -> hax-lib ->
hax-lib-macros. A default build of every crate here does not resolve
it at all.

There is no version of this we can pick differently. OpenMLS 0.9 has
one production crypto provider and this is what it depends on; the
alternative is not a cleaner MLS but a hand-rolled group-key scheme,
which the data-rooms design note explicitly declines.

Drop when hax-lib moves off proc-macro-error2, or when OpenMLS's
provider stack stops reaching libcrux.
""" },

]

# License policy. Allow-list is derived from the actual licenses present
Expand Down
26 changes: 26 additions & 0 deletions docs/05-design-notes/data-rooms.md
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,32 @@ credentials — which BBS+ supports and the `rooms/*` presentation schema must
require, not merely permit. This is a spec-level requirement; discovered in
implementation it would be a silent authorization bypass.

**Which subject.** Implementation settled a detail the paragraph above hides:
the VMC binds to the chain's **root**, not its leaf. The first version compared
the leaf and it refused every agent — correctly, by its own rule, because *an
agent is not a member of anything*. Its human is. The chain's root is the grant
the room made, so its subject is the member whose standing the whole chain
descends from; `verify_chain` has already established that each link's issuer is
its parent's subject, so nothing below the root can escape it. Comparing the
root admits the agent and still refuses the pooling attack: a chain rooted at
Bob cannot be presented with Alice's membership, whoever holds the leaf.

### 4.3a A presentation is bound to its presenter, not bearer

A presentation names *what may be done*, never *who is doing it* — so an unbound
one is a bearer token, and anyone who observes one inherits everything it
confers. Every room operation therefore also carries the DID that signed the
request, established by the request document's own `eddsa-jcs-2022` proof, and
the chain's leaf must grant to that party.

Worth stating explicitly because the reference implementation does **not** do it
for you: `dtg_credentials::authority::verify_chain` takes a `presenter`, but
uses it only for the `audience` check on links that name one. Binding the leaf
is the verifier's job, and a verifier that assumed otherwise would authorize
every captured presentation. Rooms check it twice — once in the credential
verifier and once in `authorize` — so the property does not depend on every
future verifier implementation remembering it.

### 4.4 Presenting membership

- `open` / `attributed` — standard W3C VC presentation; the subject is
Expand Down
54 changes: 54 additions & 0 deletions room-host/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
[package]
name = "room-host"
description = "Stores data-room records for rooms it does not govern — a delivery service, not a community"
version = "0.1.0"
edition.workspace = true
publish = false
rust-version.workspace = true
license.workspace = true
repository.workspace = true

[[bin]]
name = "room-host"
path = "src/main.rs"

[dependencies]
# Storage, wire types and authorization. The whole of what hosting a room needs —
# no member lifecycle, no policy engine, no credential issuance, no admin UI.
vti-rooms = { path = "../vti-rooms", version = "0.1" }
# The store and AppError. Nothing else internal.
vti-common = { path = "../vti-common", version = "0.16" }
vti-rooms-dtg = { path = "../vti-rooms-dtg" }

axum = { workspace = true }
tokio = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
tracing = { workspace = true }
tracing-subscriber = { workspace = true }
clap = { workspace = true }
anyhow = "1"
affinidi-did-resolver-cache-sdk = { workspace = true }

# A room host and a VTC serve the same protocol, so they must speak the same
# wire form: requests and responses are Trust Task documents, not bare JSON.
trust-tasks-rs = { workspace = true }
trust-tasks-https = { workspace = true }
uuid = { workspace = true }

[dev-dependencies]
tempfile = "3"
tower = { version = "0.5", features = ["util"] }
vti-rooms-dtg = { path = "../vti-rooms-dtg", features = ["test-support"] }

# The `data_room` example drives this host with the real client, so it needs the
# client's MLS layer and a throwaway signer. None of this reaches the binary.
vtc-client = { path = "../vtc-client", features = ["mls"] }
vta-sdk = { path = "../vta-sdk" }
openmls_rust_crypto = "0.6"
ed25519-dalek = { workspace = true }
multibase = { workspace = true }
base64 = { workspace = true }
getrandom = "0.3"
reqwest = { workspace = true }
uuid = { workspace = true }
Loading
Loading