Skip to main content

pg_core/client/
mod.rs

1//! PostGuard client API.
2//!
3//! Used for:
4//! - Encrypting, signing, packing metadata (*sealing*),
5//! - Decrypting, verifying, unpacking metadata (*unsealing*).
6
7mod header;
8
9pub use header::{Algorithm, Header, Mode, RecipientHeader};
10
11#[cfg(feature = "rust")]
12pub mod rust;
13
14#[cfg(feature = "web")]
15pub mod web;
16
17use crate::artifacts::VerifyingKey;
18use crate::identity::Policy;
19use crate::util::*;
20use crate::{artifacts::SigningKeyExt, consts::*};
21use header::SignatureExt;
22use ibs::gg::Verifier;
23use serde::{Deserialize, Serialize};
24
25/// Returns a copy of a signing key whose policy is canonicalized.
26///
27/// The policy travels into the container, where a verifier derives the signer's
28/// identity from it. Canonicalizing it here means that identity matches the one
29/// the PKG derived when it issued this key — including for a verifier that
30/// predates the rule and derives the header bytes as they stand.
31pub(crate) fn canonical_signing_key(key: &SigningKeyExt) -> SigningKeyExt {
32    let mut key = key.clone();
33    key.policy.canonicalize();
34
35    key
36}
37
38/// A Sealer is used to encrypt and sign data using PostGuard.
39#[derive(Debug)]
40pub struct Sealer<'r, R, C> {
41    // The prebuilt header.
42    header: Header,
43
44    // An exclusive reference to a random number generator.
45    rng: &'r mut R,
46
47    // The flavor-specific configuration.
48    config: C,
49
50    // The public signing key. Used to sign public data, such as the header.
51    // The signature and claims are visible to outsiders.
52    pub_sign_key: SigningKeyExt,
53
54    // An optional private signing key.
55    // The signature and claims are encrypted and not visible to outsiders.
56    priv_sign_key: Option<SigningKeyExt>,
57}
58
59impl<'r, R, C> Sealer<'r, R, C> {
60    /// Add a private signing key and policy.
61    ///
62    /// This policy is safe to include private data as it is encrypted after signing.
63    pub fn with_priv_signing_key(mut self, mut priv_sign_key: SigningKeyExt) -> Self {
64        // See `canonical_signing_key`; this policy reaches the wire too.
65        priv_sign_key.policy.canonicalize();
66
67        self.priv_sign_key = Some(priv_sign_key);
68        self
69    }
70}
71
72/// An Unsealer is used to decrypt and verify data using PostGuard.
73///
74/// Unsealing is a two-step process:
75///
76/// 1. First the header is read. This yields information for whom the message is encrypted. Using
77///    this information the user can retrieve a user secret key.
78///
79/// 2. Then, the user has input the user secret key and the recipient for which decryption should
80///    take place.
81///
82/// Step 1 does *not* authenticate the sender. The [`pub_id`] read there is claimed, not bound to
83/// the ciphertext; only the [`VerificationResult`] returned by step 2 can carry a bound sender,
84/// and then only against a party on the wire and only for a container that carries the AEAD-side
85/// copy of the policy. Do not display step 1's identity as a verified sender.
86///
87/// [`pub_id`]: Unsealer#structfield.pub_id
88#[derive(Debug)]
89pub struct Unsealer<R, C: UnsealerConfig> {
90    /// The version found before the raw header.
91    pub version: u16,
92
93    /// The parsed header.
94    pub header: Header,
95
96    /// The sender identity *claimed* in the header.
97    ///
98    /// The header signature over it verifies, but nothing binds it to the ciphertext until
99    /// `unseal` returns: a container's header signature can be replaced by any party the PKG will
100    /// issue a signing key to (see <https://github.com/encryption4all/postguard/issues/338>). The
101    /// closest to a bound answer is the `public` field of the [`VerificationResult`] that `unseal`
102    /// returns, which catches that swap only for a container carrying the AEAD-side copy of the
103    /// policy and only against a party who does not hold the DEM key.
104    pub pub_id: Policy,
105
106    // The input.
107    r: R,
108
109    // The implementation-specific configuration.
110    config: C,
111
112    // The message verifier.
113    verifier: Verifier,
114
115    // The message verifier key.
116    vk: VerifyingKey,
117}
118
119/// Sender verification result.
120#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
121pub struct VerificationResult {
122    /// The public signing verified claims.
123    pub public: Policy,
124
125    /// The private signing verified claims.
126    #[serde(skip_serializing_if = "Option::is_none")]
127    pub private: Option<Policy>,
128}
129
130/// Sealer configuration.
131///
132/// This trait is sealed, you cannot implement it yourself.
133#[doc(hidden)]
134pub trait SealerConfig: sealed::SealerConfig {}
135
136/// Unsealer configuration.
137///
138/// This trait is sealed, you cannot implement it yourself.
139#[doc(hidden)]
140pub trait UnsealerConfig: sealed::UnsealerConfig {}
141
142pub(crate) mod sealed {
143    pub trait UnsealerConfig {}
144    pub trait SealerConfig {}
145}
146
147#[cfg(any(feature = "stream", target_arch = "wasm32"))]
148impl From<futures::io::Error> for crate::error::Error {
149    fn from(e: futures::io::Error) -> Self {
150        Self::FuturesIO(e)
151    }
152}
153
154#[cfg(feature = "stream")]
155fn stream_mode_checked(h: &Header) -> Result<(u32, (u64, Option<u64>)), crate::error::Error> {
156    let (segment_size, size_hint) = match h {
157        Header {
158            mode:
159                Mode::Streaming {
160                    segment_size,
161                    size_hint,
162                },
163            ..
164        } => (segment_size, size_hint),
165        _ => return Err(crate::error::Error::ModeNotSupported(h.mode)),
166    };
167
168    if *segment_size > MAX_SYMMETRIC_CHUNK_SIZE {
169        return Err(crate::error::Error::ConstraintViolation);
170    }
171
172    Ok((*segment_size, *size_hint))
173}