diff --git a/docs/POSTBOX_E2EE_ARCHITECTURE.md b/docs/POSTBOX_E2EE_ARCHITECTURE.md index 6729049..3019ec0 100644 --- a/docs/POSTBOX_E2EE_ARCHITECTURE.md +++ b/docs/POSTBOX_E2EE_ARCHITECTURE.md @@ -1,9 +1,12 @@ # Postbox End-To-End Encryption Architecture -This document records the strategic encryption target for GovOPlaN postboxes. -It does not require the first postbox implementation to ship full E2EE, but it -defines the architecture so early data models and APIs do not make the stronger -model impossible. +This document records the encryption boundary for GovOPlaN postboxes. Postbox +now implements the server-side contracts for three selectable profiles: +unencrypted content, institution-managed server envelopes, and externally +produced E2EE envelopes. The E2EE contract is operational—the server rejects +plaintext and retains ciphertext, signed manifests, wrapped keys, and digest +evidence—but a reviewed browser/device client and private-key custody provider +remain separately deployed responsibilities. The core principle is that a postbox can become a trusted administrative communication channel without requiring the server to see plaintext content. @@ -35,6 +38,54 @@ Algorithm choices should remain replaceable behind a crypto profile. The first profile should prefer standard, reviewed primitives such as HPKE for key wrapping and AEAD encryption for content. +## Product Profiles And Default + +The content-protection policy is configurable per exact Postbox or immutable +template revision: + +- `server_envelope_v1` is the recommended default. An institution-selected + Encryption vault controls server-readable envelopes and their migration + evidence. It is not end-to-end encryption. +- `external_e2ee_v1` is server-blind. An approved client or producer supplies + the ciphertext reference, signed manifest, wrapped recipient keys, key epoch, + and SHA-256 plaintext digest. GovOPlaN has no private key that can decrypt it. +- `plaintext_v1` stores clear content for institutions that explicitly choose + that boundary. + +Operational metadata—including subject, routing, participants, +classifications, timestamps, attachment references, receipts, and retention +state—remains visible under every profile. Administrators therefore choose a +content-protection boundary, not a metadata-anonymity profile. + +The standard policy grants new incumbents history since assignment, uses key +rewrapping for ordinary rotation and content re-encryption after compromise, +requires two-person institutional recovery and dual-control hand-over, +emergency, export, and destruction, requires strong external identity, and +limits vacancy escalation to metadata. Deployments may select other policy +values rather than inheriting a decision from GovOPlaN. + +## Governed Profile Changes + +A profile transition applies to new messages immediately and increments the +Postbox key epoch. Retained history can remain under the previous profile or be +migrated. The transition ledger records source and target profiles/vaults, +authority route, consent and key-holder evidence, quorum, reason, immutable +configuration snapshot, per-message source and target digest, and outcome. + +Plaintext and managed-envelope migrations can use the server-side Encryption +capability. Managed decrypt, export, and re-encryption operations also create +Encryption migration records so old envelopes are disposed of through the +governed provider contract. Any transition to or from E2EE pauses each retained +message for an approved client transform. The client must return plaintext or +ciphertext as appropriate, plus evidence and the original content digest; +Postbox verifies digest continuity before changing the stored representation. +Leaving E2EE requires user-consent evidence, while changing managed history +requires institutional key-holder evidence. Dual control can require both. + +This transition mechanism cannot revoke plaintext already decrypted, copied, +printed, or exported. Administrators must explicitly acknowledge that residual +disclosure before a transition is accepted. + ## Identity And Device Keys The platform should distinguish: diff --git a/src/govoplan_core/core/postbox.py b/src/govoplan_core/core/postbox.py index aa18004..feca51f 100644 --- a/src/govoplan_core/core/postbox.py +++ b/src/govoplan_core/core/postbox.py @@ -172,6 +172,10 @@ class PostboxDirectoryEntryRef: template_revision_id: str | None = None holder_count: int = 0 vacant: bool = True + encryption_profile: str = "plaintext_v1" + key_epoch: int = 1 + encryption_vault_id: str | None = None + protection_policy: Mapping[str, object] = field(default_factory=dict) access: PostboxAccessDecisionRef | None = None resource_revision: int = 1 etag: str | None = None @@ -260,6 +264,9 @@ class PostboxMessageAuthoringRequest: idempotency_key: str subject: str body_text: str | None = None + ciphertext_ref: str | None = None + signed_manifest_ref: str | None = None + wrapped_keys: tuple[PostboxWrappedKeyRef, ...] = () classification: str = "internal" participants: tuple[PostboxParticipantRef, ...] = () attachments: tuple[PostboxAttachmentRef, ...] = ()