Skip to main content

ndn_protocol/
data.rs

1//! [`Data`], the packet returned in response to an [`Interest`].
2//!
3//! Like [`Interest`], `Data` is generic over its content
4//! type, so a payload can be carried either as raw [`Bytes`] or as a
5//! concrete type that implements
6//! [`ndn_tlv::TlvEncode`]/[`ndn_tlv::TlvDecode`].
7
8use bytes::{Buf, Bytes};
9use derive_more::{AsMut, AsRef, Display, From, Into};
10use ndn_tlv::{find_tlv, NonNegativeInteger, Tlv, TlvDecode, TlvEncode, VarNum};
11use sha2::{Digest, Sha256};
12
13use crate::{
14    error::VerifyError,
15    signature::{SignMethod, SignatureVerifier, ValidityPeriod},
16    Interest, Name, NameComponent, SignatureInfo, SignatureType, SignatureValue,
17};
18
19/// What kind of content a [`Data`] packet carries -- see the associated
20/// constants ([`ContentType::BLOB`], [`ContentType::LINK`], etc.) for the
21/// well-known values.
22#[derive(Debug, Tlv, PartialEq, Eq, Clone, Hash, Display, Default, From, Into, AsRef, AsMut)]
23#[tlv(24)]
24#[display(fmt = "{}", content_type)]
25pub struct ContentType {
26    /// The raw content type number.
27    pub content_type: NonNegativeInteger,
28}
29
30/// How long, in milliseconds, this Data should be considered fresh for
31/// after being received. A consumer requiring fresh Data (see
32/// [`MustBeFresh`](crate::MustBeFresh)) won't accept it once this expires.
33#[derive(
34    Debug,
35    Tlv,
36    PartialEq,
37    Eq,
38    Clone,
39    Hash,
40    PartialOrd,
41    Ord,
42    Display,
43    Default,
44    From,
45    Into,
46    AsRef,
47    AsMut,
48)]
49#[tlv(25)]
50#[display(fmt = "{}", freshness_period)]
51pub struct FreshnessPeriod {
52    /// The freshness period in milliseconds.
53    pub freshness_period: NonNegativeInteger,
54}
55
56/// The name component of the final (last) piece of a segmented object,
57/// letting a consumer detect when it has fetched every segment.
58#[derive(Debug, Tlv, PartialEq, Eq, Clone, Hash, From, Into, AsRef, AsMut)]
59#[tlv(26)]
60pub struct FinalBlockId {
61    /// The final segment's name component.
62    pub final_block_id: NameComponent,
63}
64
65/// The Data packet's payload.
66#[derive(Debug, Tlv, PartialEq, Eq, Clone, Hash, Default, From, AsRef, AsMut)]
67#[tlv(21)]
68pub struct Content<T> {
69    /// The payload itself.
70    pub data: T,
71}
72
73/// Metadata describing a [`Data`] packet's content: its [`ContentType`],
74/// [`FreshnessPeriod`], and [`FinalBlockId`], all optional.
75#[derive(Debug, Tlv, PartialEq, Eq, Default, Clone, Hash)]
76#[tlv(20)]
77pub struct MetaInfo {
78    /// What kind of content this is.
79    pub content_type: Option<ContentType>,
80    /// How long the content stays fresh for.
81    pub freshness_period: Option<FreshnessPeriod>,
82    /// The final segment's name component, for segmented content.
83    pub final_block_id: Option<FinalBlockId>,
84}
85
86/// The packet returned in response to a matching [`Interest`].
87///
88/// `T` is the type the content decodes/encodes as; use [`Bytes`] to work
89/// with the raw payload, or a type implementing
90/// [`ndn_tlv::TlvEncode`]/[`ndn_tlv::TlvDecode`] to work with it directly.
91#[derive(Debug, Tlv, PartialEq, Eq, Clone, Hash)]
92#[tlv(6)]
93pub struct Data<T> {
94    name: Name,
95    meta_info: Option<MetaInfo>,
96    content: Option<Content<T>>,
97    signature_info: Option<SignatureInfo>,
98    signature_value: Option<SignatureValue>,
99}
100
101impl ContentType {
102    /// Regular, opaque application data.
103    pub const BLOB: Self = Self::new(0);
104    /// A link to other Data.
105    pub const LINK: Self = Self::new(1);
106    /// A public key.
107    pub const KEY: Self = Self::new(2);
108    /// A negative acknowledgement, indicating an Interest could not be satisfied.
109    pub const NACK: Self = Self::new(3);
110
111    /// Creates a `ContentType` from a raw type number.
112    pub const fn new(typ: u64) -> Self {
113        Self {
114            content_type: NonNegativeInteger::new(typ),
115        }
116    }
117}
118
119impl FreshnessPeriod {
120    /// Creates a `FreshnessPeriod` of `period` milliseconds.
121    pub fn new(period: u64) -> Self {
122        Self {
123            freshness_period: NonNegativeInteger::new(period),
124        }
125    }
126}
127
128impl Data<Bytes> {
129    /// Decodes the raw content into a concrete type `U`, converting a `Data<Bytes>` into the
130    /// corresponding `Data<U>`.
131    ///
132    /// If decoding fails, or there was no content to begin with, the
133    /// returned Data simply has none.
134    pub fn decode_content<U>(self) -> Data<U>
135    where
136        U: TlvDecode,
137    {
138        Data {
139            content: self
140                .content
141                .and_then(|mut x| U::decode(&mut x.data).ok())
142                .map(|data| Content { data }),
143            name: self.name,
144            meta_info: self.meta_info,
145            signature_info: self.signature_info,
146            signature_value: self.signature_value,
147        }
148    }
149}
150
151impl<T> Data<T>
152where
153    T: TlvEncode,
154{
155    /// Creates a new, unsigned Data packet for `name` carrying `content`,
156    /// with its content type defaulted to [`ContentType::BLOB`].
157    pub const fn new(name: Name, content: T) -> Self {
158        Data {
159            name,
160            meta_info: Some(MetaInfo {
161                content_type: Some(ContentType {
162                    content_type: NonNegativeInteger::U8(0),
163                }),
164                freshness_period: None,
165                final_block_id: None,
166            }),
167            content: Some(Content { data: content }),
168            signature_info: None,
169            signature_value: None,
170        }
171    }
172
173    /// The Data packet's name.
174    pub fn name(&self) -> &Name {
175        &self.name
176    }
177
178    /// Sets the Data packet's name.
179    pub fn set_name(&mut self, name: Name) -> &mut Self {
180        self.name = name;
181        self
182    }
183
184    /// The Data packet's [`MetaInfo`], if set.
185    pub fn meta_info(&self) -> &Option<MetaInfo> {
186        &self.meta_info
187    }
188
189    /// Sets the Data packet's [`MetaInfo`], or clears it if `None`.
190    pub fn set_meta_info(&mut self, meta_info: Option<MetaInfo>) -> &mut Self {
191        self.meta_info = meta_info;
192        self
193    }
194
195    /// The Data packet's content, if set.
196    pub fn content(&self) -> Option<&T> {
197        self.content.as_ref().map(|x| &x.data)
198    }
199
200    /// Sets the Data packet's content, or clears it if `None`.
201    pub fn set_content(&mut self, content: Option<T>) -> &mut Self {
202        self.content = content.map(|data| Content { data });
203        self
204    }
205
206    /// Encodes the content to its raw TLV bytes, the inverse of
207    /// [`Data::decode_content`].
208    pub fn encode_content(self) -> Data<Bytes> {
209        Data {
210            name: self.name,
211            meta_info: self.meta_info,
212            content: self.content.map(|x| Content {
213                data: x.data.encode(),
214            }),
215            signature_info: self.signature_info,
216            signature_value: self.signature_value,
217        }
218    }
219
220    fn signable_portion(&self) -> Bytes {
221        let mut data = self.encode();
222        let _ = VarNum::decode(&mut data);
223        let _ = VarNum::decode(&mut data);
224
225        let mut end = data.clone();
226        let _ = find_tlv::<SignatureValue>(&mut end, false);
227
228        data.truncate(data.len() - end.remaining());
229        data
230    }
231
232    fn sign_internal<S>(&mut self, sign_method: &S, signature_info: SignatureInfo)
233    where
234        S: SignMethod,
235    {
236        self.signature_info = Some(signature_info);
237
238        let mut signed_portion = self.encode();
239
240        // Skip TLV-Type and TLV-Length
241        let _ = VarNum::decode(&mut signed_portion);
242        let _ = VarNum::decode(&mut signed_portion);
243
244        let signature = sign_method.sign(&signed_portion);
245        self.signature_value = Some(SignatureValue::new(signature));
246    }
247
248    /// Signs the Data packet with `sign_method`.
249    pub fn sign<S>(&mut self, sign_method: &mut S)
250    where
251        S: SignMethod,
252    {
253        self.sign_internal(
254            sign_method,
255            SignatureInfo::new(
256                SignatureType::new(VarNum::from(sign_method.signature_type())),
257                sign_method.certificate().map(|x| x.name_locator()),
258                None,
259            ),
260        )
261    }
262
263    /// Signs the Data packet with `sign_method`, additionally recording a
264    /// [`ValidityPeriod`] the signature is only considered valid within.
265    /// Used to sign certificates, which need an expiry.
266    pub fn sign_cert<S>(&mut self, sign_method: &S, validity_period: ValidityPeriod)
267    where
268        S: SignMethod,
269    {
270        self.sign_internal(
271            sign_method,
272            SignatureInfo::new(
273                SignatureType::new(VarNum::from(sign_method.signature_type())),
274                sign_method.certificate().map(|x| x.name_locator()),
275                Some(validity_period),
276            ),
277        )
278    }
279
280    /// The signature info added by [`Data::sign`]/[`Data::sign_cert`], if the Data is signed.
281    pub fn signature_info(&self) -> Option<&SignatureInfo> {
282        self.signature_info.as_ref()
283    }
284
285    /// Whether the Data packet carries a signature.
286    pub fn is_signed(&self) -> bool {
287        self.signature_info.is_some()
288    }
289
290    /// Returns whether this Data satisfies `interest` by name, respecting
291    /// [`CanBePrefix`](crate::CanBePrefix) and an implicit digest
292    /// component, if present.
293    ///
294    /// This only checks the name; it doesn't check
295    /// [`MustBeFresh`](crate::MustBeFresh), since freshness depends on
296    /// when the Data was received, which this packet doesn't know.
297    pub fn matches_interest<D>(&self, interest: &Interest<D>) -> bool
298    where
299        D: TlvEncode + TlvDecode,
300    {
301        // If `name` contains an ImplicitSha256DigestComponent, check that it's correct
302        if let Some(NameComponent::ImplicitSha256DigestComponent(component)) =
303            interest.name().components.last()
304        {
305            let mut hasher = Sha256::new();
306            hasher.update(self.encode());
307            let hash = hasher.finalize();
308            let hash: &[u8] = &hash;
309            if &component.name != hash {
310                return false;
311            }
312        }
313
314        // If CanBePrefix is set, just check if name is a prefix
315        if interest.can_be_prefix() {
316            self.name.has_prefix(interest.name())
317        } else {
318            for (c1, c2) in self.name().iter().zip(interest.name().iter()) {
319                if matches!(c2, NameComponent::ImplicitSha256DigestComponent(_)) {
320                    continue;
321                }
322                if c1 != c2 {
323                    return false;
324                }
325            }
326            true
327        }
328    }
329
330    /// Verify the signature of this Data packet with the given SignMethod
331    pub fn verify<S>(&self, sign_method: &S) -> Result<(), VerifyError>
332    where
333        S: SignatureVerifier,
334        S: ?Sized,
335    {
336        let Some(ref signature_value) = self.signature_value else {
337            return Err(VerifyError::MissingSignatureInfo);
338        };
339
340        let signable_portion = self.signable_portion();
341
342        let success = sign_method.verify(&signable_portion, signature_value.as_ref());
343
344        success.then_some(()).ok_or(VerifyError::InvalidSignature)
345    }
346}
347
348#[cfg(test)]
349mod tests {
350    use base64::Engine;
351    use bytes::Bytes;
352    use ndn_tlv::TlvDecode;
353
354    use crate::{Content, Data, Name, RsaCertificate, SafeBag, SignatureSha256WithRsa};
355
356    #[test]
357    fn rsa_signature() {
358        const SAFEBAG: &[u8] = b"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\
392g==";
393
394        let safebag_data = base64::engine::general_purpose::STANDARD
395            .decode(SAFEBAG)
396            .unwrap();
397        let safebag = SafeBag::decode(&mut Bytes::from(safebag_data)).unwrap();
398
399        let cert = RsaCertificate::from_safebag(safebag, "test").unwrap();
400
401        let mut data = Data {
402            name: Name::from_str("ndn:/test/test/asd").unwrap(),
403            meta_info: None,
404            content: Some(Content { data: () }),
405            signature_info: None,
406            signature_value: None,
407        };
408
409        let mut signer = SignatureSha256WithRsa::new(cert.clone());
410        data.sign(&mut signer);
411
412        assert!(data.verify(&signer).is_ok());
413    }
414}