Transport and Security
This page is normative
This page is considered a core part of the Vultron Protocol. This is a normative section of the documentation.
The whole specification on one page
The specification is also published as a single page that holds every section and annex in order, for printing or for searching the whole text at once.
This page holds section 14.7 of the Vultron Protocol Specification, part of its Requirements Catalog. Each row is one requirement, and the rest of the documentation links a requirement to its row here.
14.7 Transport and Security
The requirements on transport and security: the Hypertext Transfer Protocol (HTTP) transport, the inbox endpoint, the outbox, message signing, and encryption.
HTTP Protocol Requirements
HTTP protocol requirements for the Vultron API, covering status codes, headers, and content negotiation.
Content-Type Validation
Response Headers
Inbox Endpoint
The inbox endpoint is the primary entry point for actor-to-actor communication in Vultron. It receives ActivityStreams activities via HTTP POST, validates them, and queues them for asynchronous processing.
Activity Validation
Activity Addressing
| ID | Priority | Requirement | Related |
|---|---|---|---|
IE-11-001 |
MUST | The inbox endpoint MUST refuse any Activity whose addressing fields (to, cc, bto, bcc) are all non-empty and none of them names the receiving actor. Per-actor DataLayer isolation (ADR-0073) makes each actor's store the authoritative answer to "whose replica is this?". That invariant is only trustworthy if the store's owner was the intended recipient of every Activity it processed. Which HTTP response carries the refusal is this codebase's choice, not a protocol rule: it answers HTTP 400 in place of the 202 (IE-07-002, project), so the sender learns of the refusal from the answer to its own delivery. |
Depends on: IE-07-002 — the HTTP status that carries the refusal is this codebase's choice |
IE-11-004 |
MUST NOT | The inbox endpoint MUST NOT write anything to the receiving actor's store for an Activity that IE-11-001 refuses. A record of a misaddressed Activity would make the store hold an activity that its owner was not meant to receive. The store would then no longer answer "whose replica is this?" with certainty (ADR-0073). |
Extends: IE-11-001 |
IE-11-002 |
MUST | The inbox endpoint MUST accept Activities whose addressing fields (to, cc, bto, bcc) are all absent or unresolvable (Liberal Accept). An address is unresolvable if it cannot be confirmed to refer to a specific individual actor — for example, a collection URI such as {case_id}/participants.Requiring explicit addressing would break flows where Activities are sent without formal addressing (e.g., internal relay, legacy senders). The narrowest thing that can be refused is provable exclusion; uncertainty defaults to acceptance. Fan-out deliveries using collection URIs (e.g. {case_id}/participants) cannot be resolved to individual actors at inbox processing time and must therefore be accepted. |
|
IE-11-003 |
MUST | The inbox endpoint MUST consider all four addressing fields — to, cc, bto, bcc — when determining whether the receiving actor is named as a recipient. A match on any one field is sufficient. ActivityStreams has several audience properties, and Vultron decides which of them count as addressing, so the rule is Vultron's own. Vultron defines no use for audience on any object or activity, so an actor named only there is not addressed. Vultron sets only to (OX-08), but another implementation can name this actor only in cc, bto or bcc. If the inbox checks only to, it refuses that activity wrongly. HP-10 decides what an address only in cc means. |
Outbox
Requirements for actor outboxes, which hold response activities generated by handlers. Covers outbox structure, population, delivery, local and federated dispatch, idempotency, outbound reference dehydration, and outbox addressing rules.
Undelivered-Activity Correlation
Requirements linking a permanently undelivered activity back to the canonical case ledger entry that recorded the event the activity carries, so that divergence between the canonical log and a participant's replica is observable rather than silent. Derived from CONCERN-2657 and ADR-0080.
Signing
Requirements for signing the activities an actor sends and verifying the activities it receives, using object-level proofs carried inside the activity (FEP-8b32) so that a proof stays checkable after a relay or a ledger commit. HTTP Signatures and production key handling are out of scope here (ENC-01, OX-10).
Proofs on Sent Activities
| ID | Priority | Requirement | Related |
|---|---|---|---|
SIG-01-001 |
MUST | Every activity an actor sends MUST carry a proof made with its author's key.A receiver cannot otherwise tell who wrote an activity, so any client could post an activity in another actor's name (#509). The proof sits inside the activity, so it still shows who wrote the content after the CASE_MANAGER relays it or commits it to the ledger, which a signature on one HTTP delivery cannot show. |
|
SIG-01-002 |
MUST | A proof MUST be a DataIntegrityProof using the eddsa-jcs-2022 cryptosuite, with proofPurpose assertionMethod and a verificationMethod naming a key in its author's actor profile.Signer and verifier must agree on one proof form, or a correct proof is refused. FEP-8b32 with eddsa-jcs-2022 (Ed25519 over the RFC 8785 canonical form) is the form ActivityPub implementations use for object integrity, and naming the key by the author's profile tells the receiver where to get it (SIG-02-001). |
Extends: SIG-01-001 |
SIG-01-003 |
MUST | A proof MUST cover the whole activity as sent, every nested object included, except the proof itself.A proof that covers only part of an activity lets anyone change the rest without detection. The objects nested in an activity carry most of what a receiver acts on, such as a report's content or a ledger entry's snapshot. |
Key Discovery
Verification and Refusal
| ID | Priority | Requirement | Related |
|---|---|---|---|
SIG-03-001 |
MUST | A receiver MUST verify an activity's proof before it acts on any of the activity's content.Content acted on before verification has already been trusted: a forged activity could change state, be stored or be relayed before its refusal. Verifying first means a refused activity leaves nothing behind. |
|
SIG-03-002 |
MUST | A receiver MUST refuse an activity whose proof is missing or does not verify.Verification that admits an unsigned activity protects nothing, since a forger simply leaves the proof out. The refusal holds in every deployment, test and demo: a switch that turns it off becomes the way a test passes and a deployment is left open. |
Depends on: SIG-03-001 |
Proofs in the Case Ledger
Encryption
Requirements for encrypted messaging and actor key management using ActivityPub extension conventions. Ensures that sensitive vulnerability information can be protected in transit between actors.
Key Management
| ID | Priority | Requirement | Related |
|---|---|---|---|
ENC-01-001 |
MUST | Each actor MUST generate a unique asymmetric key pair when its identity is first provisioned. Key material binds to an actor identity, not to a case. An actor that enacts CVDRole.CASE_MANAGER for several cases uses one key pair for all of them, so per-case key separation is a consequence of deployment topology rather than a key-binding rule. Regenerating a key pair would invalidate any peer's cached public key and break encrypted communication mid-case. See notes/encryption.md for the topology discussion. |
Implements: VP-15-004 |
ENC-01-002 |
MUST | Each actor MUST publish its public key in its actor profile as a Multikey listed under assertionMethod.Peers need an actor's public key to verify the proofs it signs (SIG-02-001). assertionMethod is where an FEP-8b32 verifier looks for the key a proof's verificationMethod names, so no separate key-exchange channel is needed. |
|
ENC-01-004 |
MUST NOT | An implementation MUST store each private key securely, and MUST NOT write one to a log or include it in an API response. Anyone who obtains an actor's private key can read messages encrypted to it, including embargoed vul details, and can forge activities in its name. Logs and API responses are copied and retained widely, so a key that appears in them must be treated as disclosed. |
|
ENC-01-005 |
MUST | An actor's asymmetric key pair MUST be persisted and reused across process restarts for the lifetime of that actor identity. Regenerating on restart would invalidate any peer's cached public key and break encrypted communication mid-case. |
Refines: ENC-01-001 |
ENC-01-006 |
MUST NOT | A new key pair MUST NOT be generated on process resumption for an existing actor identity. Generating a new key pair on restart breaks any encrypted channel established with the previous key, invalidating cached public keys held by case participants. |
Refines: ENC-01-001 |
Message Encryption
| ID | Priority | Requirement | Related |
|---|---|---|---|
ENC-02-001 |
MAY | Case participants MAY encrypt messages sent to the CASE_MANAGER using an encryption key the CASE_MANAGER publishes in its actor profile. Messages to the CASE_MANAGER can carry embargoed vul details that intermediaries must not read in transit. Encryption is optional because transport security can be enough for a deployment and no encryption scheme is yet standardized (ENC-02-002). |
Implements: VP-15-004 |
ENC-02-002 |
SHOULD | When sending messages to case participants, the CASE_MANAGER SHOULD encrypt each outbound message individually to an encryption key the recipient publishes in its actor profile. The specific encryption scheme (e.g., ECDH key agreement + AES-256-GCM, RSA-OAEP) is intentionally deferred pending a protocol-level agreement. Until a scheme is standardized, the choice is implementation-defined; interoperability between independently-built implementations is not yet a requirement. |
Implements: VP-15-004 |