dsf_core/wire/
mod.rs

1//! Wire provides a container type to map byte data to fixed fields (and vice versa)
2//! to support wire encoding and decoding.
3
4#[cfg(feature = "alloc")]
5use alloc::prelude::v1::*;
6
7use crate::base::{BaseError, Body, Header, PrivateOptions};
8use crate::crypto;
9use crate::options::{Options, OptionsList};
10use crate::types::*;
11
12use crate::base::Base;
13
14/// Header provides a low-cost header abstraction for encoding/decoding
15pub mod header;
16
17/// Builder provides methods to construct a container using a mutable buffer and base types
18pub mod builder;
19pub use builder::Builder;
20
21/// Container provides methods to access underlying wire object fields
22pub mod container;
23pub use container::Container;
24
25impl<'a, T: AsRef<[u8]>> Container<T> {
26    /// Parses a data array into a base object using the pub_key and sec_key functions to locate
27    /// keys for validation and decyption
28    pub fn parse<P, S>(
29        data: T,
30        mut pub_key_s: P,
31        mut sec_key_s: S,
32    ) -> Result<(Base, usize), BaseError>
33    where
34        P: FnMut(&Id) -> Option<PublicKey>,
35        S: FnMut(&Id) -> Option<SecretKey>,
36    {
37        let mut verified = false;
38
39        // Build container over buffer
40        let (container, n) = Container::from(data);
41        let header = container.header();
42
43        // Fetch page flags
44        let flags = header.flags();
45
46        // Fetch page ID
47        let id: Id = container.id().into();
48
49        // Fetch signature for page
50        let signature: Signature = container.signature().into();
51
52        // Validate primary types immediately if pubkey is known
53        if !flags.contains(Flags::SECONDARY) {
54            // Lookup public key
55            if let Some(key) = (pub_key_s)(&id) {
56                // Check ID matches key
57                if id != crypto::hash(&key).unwrap() {
58                    return Err(BaseError::PublicKeyIdMismatch);
59                }
60
61                // Validate message body against key
62                verified = crypto::pk_validate(&key, &signature, container.signed())
63                    .map_err(|_e| BaseError::ValidateError)?;
64
65                // Stop processing if signature is invalid
66                if !verified {
67                    info!("Invalid signature with known pubkey");
68                    return Err(BaseError::InvalidSignature);
69                }
70            }
71        }
72
73        // Fetch public options
74        let mut peer_id = None;
75        let mut pub_key = None;
76        let mut parent = None;
77
78        let public_options: Vec<_> = container
79            .public_options()
80            .filter_map(|o| match &o {
81                Options::PeerId(v) => {
82                    peer_id = Some(v.peer_id.clone());
83                    None
84                }
85                Options::PubKey(v) => {
86                    pub_key = Some(v.public_key.clone());
87                    None
88                }
89                Options::PrevSig(v) => {
90                    parent = Some(v.sig.clone());
91                    None
92                }
93                _ => Some(o),
94            })
95            .collect();
96
97        // Look for signing ID
98        let signing_id: Id = match (flags.contains(Flags::SECONDARY), &peer_id) {
99            (false, _) => Ok(container.id().into()),
100            (true, Some(id)) => Ok(id.clone()),
101            _ => Err(BaseError::NoPeerId),
102        }?;
103
104        // Fetch public key
105        let public_key: Option<PublicKey> = match ((pub_key_s)(&signing_id), &pub_key) {
106            (Some(key), _) => Some(key),
107            (None, Some(key)) => Some(key.clone()),
108            _ => {
109                warn!(
110                    "Missing public key for message: {:?} signing id: {:?}",
111                    id, signing_id
112                );
113                None
114            }
115        };
116
117        // Late validation for self-signed objects from unknown sources
118        match (verified, public_key) {
119            (false, Some(public_key)) => {
120                // Check ID matches key
121                if signing_id != crypto::hash(&public_key).unwrap() {
122                    error!("Public key mismatch for object from {:?}", id);
123                    return Err(BaseError::PublicKeyIdMismatch);
124                }
125
126                // Verify body
127                verified = crypto::pk_validate(&public_key, &signature, container.signed())
128                    .map_err(|_e| BaseError::ValidateError)?;
129
130                // Stop processing on verification error
131                if !verified {
132                    info!("Invalid signature for self-signed object from {:?}", id);
133                    return Err(BaseError::InvalidSignature);
134                }
135            }
136            (false, None) => {
137                error!("No signature or key for object from {:?}", id);
138                return Err(BaseError::ValidateError.into());
139            }
140            _ => (),
141        }
142
143        let mut body_data = container.body().to_vec();
144        let mut private_options_data = container.private_options().to_vec();
145
146        // Handle body decryption or parsing
147        let body = match (flags.contains(Flags::ENCRYPTED), sec_key_s(&id)) {
148            (true, Some(sk)) if body_data.len() > 0 => {
149                // Decrypt body
150                let n = crypto::sk_decrypt2(&sk, &mut body_data)
151                    .map_err(|_e| BaseError::InvalidSignature)?;
152                body_data = (&body_data[..n]).to_vec();
153
154                Body::Cleartext(body_data)
155            }
156            (true, None) if body_data.len() > 0 => {
157                debug!("No encryption key found for data");
158
159                Body::Encrypted(body_data)
160            }
161            (false, _) if body_data.len() > 0 => Body::Cleartext(body_data),
162            _ => Body::None,
163        };
164
165        // Handle private_options decryption or parsing
166        let private_options = match (flags.contains(Flags::ENCRYPTED), sec_key_s(&id)) {
167            (true, Some(sk)) if private_options_data.len() > 0 => {
168                // Decrypt private options
169                let n = crypto::sk_decrypt2(&sk, &mut private_options_data)
170                    .map_err(|_e| BaseError::InvalidSignature)?;
171                private_options_data = (&private_options_data[..n]).to_vec();
172
173                // Decode private options
174                let (private_options, _n) = Options::parse_vec(&private_options_data)?;
175
176                PrivateOptions::Cleartext(private_options)
177            }
178            (true, None) if private_options_data.len() > 0 => {
179                debug!("No encryption key found for data");
180
181                PrivateOptions::Encrypted(private_options_data)
182            }
183            _ => PrivateOptions::None,
184        };
185
186        // Return page and options
187        Ok((
188            Base {
189                id,
190                header: Header::new(
191                    header.application_id(),
192                    header.kind(),
193                    header.index(),
194                    header.flags(),
195                ),
196                body,
197
198                private_options,
199                public_options,
200
201                parent,
202                peer_id: peer_id.clone(),
203                public_key: pub_key.clone(),
204
205                signature: Some(signature),
206                verified,
207
208                raw: Some(container.raw().to_vec()),
209            },
210            n,
211        ))
212    }
213}
214
215impl<'a, T: AsRef<[u8]> + AsMut<[u8]>> Container<T> {
216    pub fn encode(
217        buff: T,
218        base: &Base,
219        signing_key: &PrivateKey,
220        encryption_key: Option<&SecretKey>,
221    ) -> (Self, usize) {
222        // Setup base builder with header and ID
223        let bb = Builder::new(buff).id(base.id()).header(base.header());
224
225        // Check encryption key exists if required
226        let encryption_key = match (base.flags().contains(Flags::ENCRYPTED), encryption_key) {
227            (true, Some(k)) => Some(k),
228            (true, None) => panic!("Attempted to encrypt object with no secret key"),
229            _ => None,
230        };
231
232        // Write body
233        let bb = bb.body(base.body(), encryption_key).unwrap();
234
235        // Write private options
236        let mut bb = bb
237            .private_options(base.private_options(), encryption_key)
238            .unwrap();
239
240        // Write public options
241        // Add public key option if specified
242        if let Some(k) = &base.public_key {
243            bb.public_option(&Options::pub_key(k.clone())).unwrap();
244        }
245
246        if let Some(s) = &base.parent {
247            bb.public_option(&Options::prev_sig(s)).unwrap();
248        }
249
250        if let Some(i) = &base.peer_id {
251            bb.public_option(&Options::peer_id(i.clone())).unwrap();
252        }
253
254        let opts = OptionsList::<_, &[u8]>::Cleartext(base.public_options());
255        let bb = bb.public_options(&opts).unwrap();
256
257        // Sign object
258        let c = bb.sign(signing_key).unwrap();
259        let len = c.len;
260
261        (c, len)
262    }
263}
264
265#[cfg(test)]
266mod test {}