Skip to main content

ndn_protocol/
interest.rs

1//! [`Interest`], the packet used to request [`Data`](crate::Data) by name.
2//!
3//! An `Interest` is a [`Name`] plus a handful of optional selectors and,
4//! for signed Interests, application parameters and a signature. It's
5//! generic over its application parameters type, so a payload can be
6//! carried either as raw [`Bytes`] or as a concrete type that implements
7//! [`ndn_tlv::TlvEncode`]/[`ndn_tlv::TlvDecode`].
8
9use bytes::{Buf, BufMut, Bytes, BytesMut};
10use derive_more::{AsMut, AsRef, Constructor, From, Into};
11use ndn_tlv::{find_tlv, NonNegativeInteger, Tlv, TlvDecode, TlvEncode, VarNum};
12use rand::{Rng, SeedableRng};
13use sha2::{Digest, Sha256};
14
15use crate::{
16    error::{SignError, VerifyError},
17    name::ParametersSha256DigestComponent,
18    signature::{
19        InterestSignatureInfo, InterestSignatureValue, SignMethod, SignatureNonce, SignatureSeqNum,
20        SignatureVerifier,
21    },
22    Name, NameComponent, SignatureType,
23};
24
25/// A marker element allowing the Interest to match Data whose name has this
26/// Interest's name as a prefix, rather than requiring an exact match.
27#[derive(Debug, Tlv, PartialEq, Eq, Clone, Copy, Constructor, Hash, Default)]
28#[tlv(33)]
29pub struct CanBePrefix;
30
31/// A marker element requiring the forwarder to return only Data that isn't
32/// stale, i.e. still within its [`FreshnessPeriod`](crate::FreshnessPeriod).
33#[derive(Debug, Tlv, PartialEq, Eq, Clone, Copy, Constructor, Hash, Default)]
34#[tlv(18)]
35pub struct MustBeFresh;
36
37/// Suggests a name for the forwarder to use when deciding where to forward
38/// this Interest, as a hint rather than a hard requirement.
39#[derive(Debug, Tlv, PartialEq, Eq, Clone, PartialOrd, Ord, Hash, Constructor)]
40#[tlv(30)]
41pub struct ForwardingHint {
42    name: Name,
43}
44
45/// A random value that lets a forwarder detect duplicate/looping Interests.
46#[derive(Debug, Tlv, PartialEq, Eq, Clone, Copy, Constructor, From, Into, AsRef, AsMut, Hash)]
47#[tlv(10)]
48pub struct Nonce {
49    nonce: [u8; 4],
50}
51
52/// How long, in milliseconds, the Interest stays pending at a forwarder
53/// while it waits for matching Data.
54#[derive(
55    Debug,
56    Tlv,
57    PartialEq,
58    Eq,
59    Clone,
60    Copy,
61    Constructor,
62    From,
63    Into,
64    AsRef,
65    AsMut,
66    Hash,
67    PartialOrd,
68    Ord,
69)]
70#[tlv(12)]
71pub struct InterestLifetime {
72    lifetime: NonNegativeInteger,
73}
74
75/// The maximum number of forwarder hops this Interest may still travel,
76/// decremented by each forwarder it passes through.
77#[derive(
78    Debug,
79    Tlv,
80    PartialEq,
81    Eq,
82    Clone,
83    Copy,
84    Constructor,
85    From,
86    Into,
87    AsRef,
88    AsMut,
89    Hash,
90    PartialOrd,
91    Ord,
92)]
93#[tlv(34)]
94pub struct HopLimit {
95    limit: u8,
96}
97
98/// The Interest's application-defined payload.
99///
100/// Present only on signed Interests (or Interests that will be signed):
101/// its encoding is what [`Interest::make_parameters_digest`] hashes into
102/// the name's `ParametersSha256DigestComponent`.
103#[derive(Debug, Tlv, PartialEq, Eq, Hash, From, AsRef, AsMut, Constructor, Clone)]
104#[tlv(36)]
105pub struct ApplicationParameters<T> {
106    data: T,
107}
108
109/// A request for [`Data`](crate::Data) matching a [`Name`], optionally
110/// carrying application parameters and a signature.
111///
112/// `T` is the type application parameters decode/encode as; use `()` for
113/// Interests that don't carry any, [`Bytes`] to work with the raw payload,
114/// or a type implementing [`ndn_tlv::TlvEncode`]/[`ndn_tlv::TlvDecode`] to
115/// work with it directly.
116#[derive(Debug, Tlv, PartialEq, Eq, Hash, Clone)]
117#[tlv(5)]
118pub struct Interest<T> {
119    pub(crate) name: Name,
120    can_be_prefix: Option<CanBePrefix>,
121    must_be_fresh: Option<MustBeFresh>,
122    forwarding_hint: Option<ForwardingHint>,
123    nonce: Option<Nonce>,
124    interest_lifetime: Option<InterestLifetime>,
125    hop_limit: Option<HopLimit>,
126    application_parameters: Option<ApplicationParameters<T>>,
127    signature_info: Option<InterestSignatureInfo>,
128    signature_value: Option<InterestSignatureValue>,
129}
130
131/// Options controlling what [`Interest::sign`]/[`Interest::sign_checked`] include
132/// in the signature.
133#[derive(Debug, PartialEq, Eq, Clone, Copy, Constructor, Hash)]
134pub struct SignSettings {
135    /// Whether to include a signing timestamp.
136    pub include_time: bool,
137    /// Whether to include a signing sequence number.
138    pub include_seq_num: bool,
139    /// The length, in bytes, of the random signing nonce. `0` omits the nonce.
140    pub nonce_length: usize,
141}
142
143impl Default for SignSettings {
144    fn default() -> Self {
145        Self {
146            include_time: true,
147            include_seq_num: false,
148            nonce_length: 8,
149        }
150    }
151}
152
153impl Interest<Bytes> {
154    /// Decodes the raw application parameters into a concrete type `T`, converting an
155    /// `Interest<Bytes>` into the curresponding `Interest<T>`.
156    ///
157    /// If decoding fails, or there were no application parameters to begin
158    /// with, the returned Interest simply has none.
159    pub fn decode_application_parameters<T>(self) -> Interest<T>
160    where
161        T: TlvDecode,
162    {
163        Interest {
164            application_parameters: self
165                .application_parameters
166                .and_then(|mut x| T::decode(&mut x.data).ok())
167                .map(ApplicationParameters::new),
168            name: self.name,
169            can_be_prefix: self.can_be_prefix,
170            must_be_fresh: self.must_be_fresh,
171            forwarding_hint: self.forwarding_hint,
172            nonce: self.nonce,
173            interest_lifetime: self.interest_lifetime,
174            hop_limit: self.hop_limit,
175            signature_info: self.signature_info,
176            signature_value: self.signature_value,
177        }
178    }
179}
180
181impl<AppParamTy> Interest<AppParamTy> {
182    /// Drops the application parameters, returning an `Interest<()>`.
183    pub fn remove_application_parameters(self) -> Interest<()> {
184        Interest {
185            application_parameters: None,
186            name: self.name,
187            can_be_prefix: self.can_be_prefix,
188            must_be_fresh: self.must_be_fresh,
189            forwarding_hint: self.forwarding_hint,
190            nonce: self.nonce,
191            interest_lifetime: self.interest_lifetime,
192            hop_limit: self.hop_limit,
193            signature_info: self.signature_info,
194            signature_value: self.signature_value,
195        }
196    }
197}
198
199impl<AppParamTy> Interest<AppParamTy>
200where
201    AppParamTy: TlvEncode,
202{
203    /// Creates the `ParametersSha256DigestComponent` part of the name.
204    ///
205    /// The component will be automatically added to the name when signing the interest, so this is
206    /// only useful for unsigned interests.
207    pub fn make_parameters_digest(data: AppParamTy) -> ParametersSha256DigestComponent {
208        let mut hasher = Sha256::new();
209        hasher.update(VarNum::from(ApplicationParameters::<AppParamTy>::TYP).encode());
210        hasher.update(VarNum::from(data.size()).encode());
211        hasher.update(&data.encode());
212        ParametersSha256DigestComponent {
213            name: hasher.finalize().into(),
214        }
215    }
216
217    /// Adds a `ParametersSha256DigestComponent` to the end of the name
218    ///
219    /// The component will be automatically added to the name when signing the interest, so this is
220    /// only useful for unsigned interests.
221    ///
222    /// Empty application parameters will be set if none are set currently.
223    /// Any existing `ParametersSha256DigestComponent` will be removed.
224    pub fn add_parameters_digest(&mut self) -> &mut Self
225    where
226        AppParamTy: Default,
227        AppParamTy: Clone,
228    {
229        if self.application_parameters.is_none() {
230            self.application_parameters = Some(ApplicationParameters {
231                data: AppParamTy::default(),
232            });
233        }
234
235        self.add_parameters_digest_unchecked()
236    }
237
238    /// Adds a `ParametersSha256DigestComponent` to the end of the name, assuming application
239    /// parameters already exist
240    ///
241    /// The component will be automatically added to the name when signing the interest, so this is
242    /// only useful for unsigned interests.
243    ///
244    /// Any existing `ParametersSha256DigestComponent` will be removed.
245    pub fn add_parameters_digest_unchecked(&mut self) -> &mut Self
246    where
247        AppParamTy: Clone,
248    {
249        self.name
250            .components
251            .retain(|x| !matches!(x, NameComponent::ParametersSha256DigestComponent(_)));
252
253        self.name
254            .components
255            .push(NameComponent::ParametersSha256DigestComponent(
256                Self::make_parameters_digest(
257                    self.application_parameters.as_ref().unwrap().data.clone(),
258                ),
259            ));
260        self
261    }
262
263    fn signable_portion(&self) -> Bytes {
264        let mut bytes = self.encode();
265        let _ = VarNum::decode(&mut bytes);
266        let _ = VarNum::decode(&mut bytes);
267        let _ = find_tlv::<ApplicationParameters<AppParamTy>>(&mut bytes, false);
268
269        let mut end = bytes.clone();
270        let _ = find_tlv::<InterestSignatureValue>(&mut end, false);
271        bytes.truncate(bytes.remaining() - end.remaining());
272
273        let mut signature_buffer =
274            BytesMut::with_capacity(self.name.inner_size() + bytes.remaining());
275        for component in &self.name.components {
276            if !matches!(component, NameComponent::ParametersSha256DigestComponent(_)) {
277                signature_buffer.put(component.encode());
278            }
279        }
280        signature_buffer.put(&mut bytes);
281        signature_buffer.freeze()
282    }
283
284    fn parameters_digest(&self) -> [u8; 32] {
285        let mut data = self.encode();
286        let _ = VarNum::decode(&mut data);
287        let _ = VarNum::decode(&mut data);
288        let _ = find_tlv::<ApplicationParameters<AppParamTy>>(&mut data, false);
289        let mut hasher = Sha256::new();
290        hasher.update(&data);
291        hasher.finalize().into()
292    }
293
294    /// Signs the Interest with `sign_method`, setting empty application
295    /// parameters first if none are set yet.
296    pub fn sign<T>(&mut self, sign_method: &mut T, settings: SignSettings)
297    where
298        T: SignMethod,
299        AppParamTy: Default,
300    {
301        if self.application_parameters.is_none() {
302            self.set_application_parameters(Some(AppParamTy::default()));
303        }
304
305        self.sign_checked(sign_method, settings)
306            .expect("sign_checked failed from sign")
307    }
308
309    /// Signs the Interest with `sign_method`, adding a signature info,
310    /// signature value, and `ParametersSha256DigestComponent` to the name.
311    ///
312    /// Fails if the Interest has no application parameters set --
313    /// signed Interests are required to carry some, even if empty. see
314    /// [`Interest::sign`] for a version that sets empty ones automatically.
315    pub fn sign_checked<T>(
316        &mut self,
317        sign_method: &mut T,
318        settings: SignSettings,
319    ) -> Result<(), SignError>
320    where
321        T: SignMethod,
322    {
323        // Delete existing params-sha256
324        self.name
325            .components
326            .retain(|x| !matches!(x, NameComponent::ParametersSha256DigestComponent(_)));
327        if self.application_parameters.is_none() {
328            return Err(SignError::MissingApplicationParameters);
329        }
330
331        // Generate nonce
332        let nonce = if settings.nonce_length > 0 {
333            let mut rng = rand::rngs::StdRng::from_entropy();
334            let mut data = BytesMut::with_capacity(settings.nonce_length);
335            for _ in 0..settings.nonce_length {
336                data.put_u8(rng.gen());
337            }
338            Some(SignatureNonce::new(data.freeze()))
339        } else {
340            None
341        };
342
343        // Generate sequence number
344        let seq_num = sign_method.next_seq_num();
345
346        self.signature_info = Some(InterestSignatureInfo {
347            signature_type: SignatureType::new(sign_method.signature_type().into()),
348            key_locator: sign_method.certificate().map(|x| x.name_locator()),
349            nonce,
350            time: settings.include_time.then(|| sign_method.time()),
351            seq_num: settings
352                .include_seq_num
353                .then(|| SignatureSeqNum::new(seq_num.into())),
354        });
355
356        // Create signature
357        self.signature_value = Some(InterestSignatureValue::new(
358            sign_method.sign(&self.signable_portion()),
359        ));
360
361        // Add new params-sha256
362        self.name
363            .components
364            .push(NameComponent::ParametersSha256DigestComponent(
365                ParametersSha256DigestComponent {
366                    name: self.parameters_digest(),
367                },
368            ));
369        Ok(())
370    }
371
372    fn verify_param_digest(&self) -> Result<(), VerifyError> {
373        if self.is_signed() {
374            if self.application_parameters.is_none() {
375                return Err(VerifyError::MissingApplicationParameters);
376            }
377
378            let Some(NameComponent::ParametersSha256DigestComponent(param_digest)) =
379                self.name.components.last()
380            else {
381                return Err(VerifyError::InvalidParameterDigest);
382            };
383
384            if param_digest.name != self.parameters_digest() {
385                return Err(VerifyError::InvalidParameterDigest);
386            }
387            Ok(())
388        } else {
389            if self.application_parameters.is_some() {
390                // Not signed, application parameters present - check parameter digest
391                for component in &self.name.components {
392                    if let NameComponent::ParametersSha256DigestComponent(component) = component {
393                        if component.name == self.parameters_digest() {
394                            return Ok(());
395                        } else {
396                            return Err(VerifyError::InvalidParameterDigest);
397                        }
398                    }
399                }
400                // No digest present
401                Err(VerifyError::InvalidParameterDigest)
402            } else {
403                // Not signed, no application parameters - nothing to check
404                Ok(())
405            }
406        }
407    }
408
409    /// Verify the interest with a given signature verifier
410    ///
411    /// Returns `Ok(())` if the signature and the `ParametersSha256DigestComponent` of the name are
412    /// valid
413    pub fn verify<T>(&self, verifier: &T) -> Result<(), VerifyError>
414    where
415        T: SignatureVerifier,
416        T: ?Sized,
417    {
418        self.verify_param_digest()?;
419
420        if self.signature_info.is_none() {
421            // Not signed
422            return Ok(());
423        }
424
425        let Some(ref sig_value) = self.signature_value else {
426            // Signature missing
427            return Err(VerifyError::InvalidSignature);
428        };
429
430        verifier
431            .verify(&self.signable_portion(), sig_value.as_ref())
432            .then_some(())
433            .ok_or(VerifyError::InvalidSignature)
434    }
435
436    /// Encodes the application parameters to their raw TLV bytes, the
437    /// inverse of [`Interest::decode_application_parameters`].
438    pub fn encode_application_parameters(self) -> Interest<Bytes> {
439        Interest {
440            name: self.name,
441            can_be_prefix: self.can_be_prefix,
442            must_be_fresh: self.must_be_fresh,
443            forwarding_hint: self.forwarding_hint,
444            nonce: self.nonce,
445            interest_lifetime: self.interest_lifetime,
446            hop_limit: self.hop_limit,
447            application_parameters: self.application_parameters.map(|params| {
448                ApplicationParameters {
449                    data: params.data.encode(),
450                }
451            }),
452            signature_info: self.signature_info,
453            signature_value: self.signature_value,
454        }
455    }
456}
457
458impl Interest<()> {
459    /// Same as [`Interest::new`], for callers that need to spell out that
460    /// `T` is `()` for type inference to work.
461    pub fn new_u(name: Name) -> Self {
462        Self::new(name)
463    }
464}
465
466impl<AppParamTy> Interest<AppParamTy> {
467    /// Creates a new, unsigned Interest for `name` with no selectors set.
468    pub fn new(name: Name) -> Self {
469        Self {
470            name,
471            can_be_prefix: None,
472            must_be_fresh: None,
473            forwarding_hint: None,
474            nonce: None,
475            interest_lifetime: None,
476            hop_limit: None,
477            application_parameters: None,
478            signature_info: None,
479            signature_value: None,
480        }
481    }
482
483    /// Sets the Interest's name.
484    pub fn set_name(&mut self, name: Name) -> &mut Self {
485        self.name = name;
486        self
487    }
488
489    /// The Interest's name.
490    pub fn name(&self) -> &Name {
491        &self.name
492    }
493
494    /// Sets whether the Interest can be satisfied by Data whose name has
495    /// this Interest's name as a prefix (see [`CanBePrefix`]).
496    pub fn set_can_be_prefix(&mut self, can_be_prefix: bool) -> &mut Self {
497        self.can_be_prefix = can_be_prefix.then_some(CanBePrefix);
498        self
499    }
500
501    /// Whether [`CanBePrefix`] is set.
502    pub fn can_be_prefix(&self) -> bool {
503        self.can_be_prefix.is_some()
504    }
505
506    /// Sets whether the Interest requires fresh Data (see [`MustBeFresh`]).
507    pub fn set_must_be_fresh(&mut self, must_be_fresh: bool) -> &mut Self {
508        self.must_be_fresh = must_be_fresh.then_some(MustBeFresh);
509        self
510    }
511
512    /// Whether [`MustBeFresh`] is set.
513    pub fn must_be_fresh(&self) -> bool {
514        self.must_be_fresh.is_some()
515    }
516
517    /// Sets the forwarding hint, or clears it if `None` (see [`ForwardingHint`]).
518    pub fn set_forwarding_hint(&mut self, forwarding_hint: Option<Name>) -> &mut Self {
519        self.forwarding_hint = forwarding_hint.map(|name| ForwardingHint { name });
520        self
521    }
522
523    /// The forwarding hint's name, if set.
524    pub fn forwarding_hint(&self) -> Option<&Name> {
525        self.forwarding_hint.as_ref().map(|x| &x.name)
526    }
527
528    /// Sets the nonce, or clears it if `None` (see [`Nonce`]).
529    pub fn set_nonce(&mut self, nonce: Option<[u8; 4]>) -> &mut Self {
530        self.nonce = nonce.map(|nonce| Nonce { nonce });
531        self
532    }
533
534    /// The nonce, if set.
535    pub fn nonce(&self) -> Option<&[u8; 4]> {
536        self.nonce.as_ref().map(|x| &x.nonce)
537    }
538
539    /// Sets the interest lifetime in milliseconds, or clears it if `None`
540    /// (see [`InterestLifetime`]).
541    pub fn set_interest_lifetime(
542        &mut self,
543        interest_lifetime: Option<NonNegativeInteger>,
544    ) -> &mut Self {
545        self.interest_lifetime = interest_lifetime.map(|lifetime| InterestLifetime { lifetime });
546        self
547    }
548
549    /// The interest lifetime in milliseconds, if set.
550    pub fn interest_lifetime(&self) -> Option<NonNegativeInteger> {
551        self.interest_lifetime.as_ref().map(|x| x.lifetime)
552    }
553
554    /// Sets the hop limit, or clears it if `None` (see [`HopLimit`]).
555    pub fn set_hop_limit(&mut self, hop_limit: Option<u8>) -> &mut Self {
556        self.hop_limit = hop_limit.map(|limit| HopLimit { limit });
557        self
558    }
559
560    /// The hop limit, if set.
561    pub fn hop_limit(&self) -> Option<u8> {
562        self.hop_limit.as_ref().map(|x| x.limit)
563    }
564
565    /// Sets the application parameters, or clears them if `None`.
566    pub fn set_application_parameters(&mut self, params: Option<AppParamTy>) -> &mut Self {
567        self.application_parameters = params.map(|data| ApplicationParameters { data });
568        self
569    }
570
571    /// The application parameters, if set.
572    pub fn application_parameters(&self) -> Option<&AppParamTy> {
573        self.application_parameters.as_ref().map(|x| &x.data)
574    }
575
576    /// The signature info added by [`Interest::sign`]/[`Interest::sign_checked`], if the Interest is signed.
577    pub fn signature_info(&self) -> Option<&InterestSignatureInfo> {
578        self.signature_info.as_ref()
579    }
580
581    /// Whether the Interest carries a signature.
582    pub fn is_signed(&self) -> bool {
583        self.signature_info.is_some()
584    }
585}
586
587#[cfg(test)]
588mod tests {
589    use base64::Engine;
590
591    use crate::{signature::DigestSha256, RsaCertificate, SafeBag, SignatureSha256WithRsa};
592
593    use super::*;
594
595    #[test]
596    fn simple_usage() {
597        let mut interest = Interest::<()>::new(Name::from_str("ndn:/hello/world").unwrap());
598        interest
599            .set_can_be_prefix(true)
600            .set_hop_limit(Some(20))
601            .set_interest_lifetime(Some(10_000u16.into()));
602
603        assert_eq!(
604            interest,
605            Interest {
606                name: Name::from_str("ndn:/hello/world").unwrap(),
607                can_be_prefix: Some(CanBePrefix),
608                must_be_fresh: None,
609                forwarding_hint: None,
610                nonce: None,
611                interest_lifetime: Some(InterestLifetime {
612                    lifetime: 10_000u16.into()
613                }),
614                hop_limit: Some(HopLimit { limit: 20 }),
615                application_parameters: None,
616                signature_info: None,
617                signature_value: None,
618            }
619        );
620    }
621
622    #[test]
623    fn sha256_interest() {
624        let mut interest = Interest::<()>::new(Name::from_str("ndn:/hello/world").unwrap());
625        let mut signer = DigestSha256::new();
626        interest.sign(
627            &mut signer,
628            SignSettings {
629                include_time: false,
630                nonce_length: 0,
631                include_seq_num: true,
632            },
633        );
634        assert!(interest.verify(&mut signer).is_ok());
635
636        let name_components = [
637            8, 5, b'h', b'e', b'l', b'l', b'o', 8, 5, b'w', b'o', b'r', b'l', b'd', //
638        ];
639
640        let app_params_plus = [
641            36, 0, // ApplicationParameters
642            44, 6, // SignatureInfo
643            27, 1, 0, // Signature Type
644            42, 1, 0, // seq num
645        ];
646
647        let mut hasher = Sha256::new();
648        hasher.update(name_components);
649        hasher.update(app_params_plus);
650        let signature = hasher.finalize();
651
652        hasher = Sha256::new();
653        hasher.update(app_params_plus);
654        hasher.update([46, 32]);
655        hasher.update(signature);
656        let param_digest = hasher.finalize();
657
658        let mut full_record = Vec::new();
659        full_record.extend([5, 94]);
660        full_record.extend([7, 48]);
661        full_record.extend(name_components);
662        full_record.extend([2, 32]);
663        full_record.extend(param_digest);
664        full_record.extend(app_params_plus);
665        full_record.extend([46, 32]);
666        full_record.extend(signature);
667
668        assert_eq!(<Vec<u8>>::from(interest.encode()), full_record);
669    }
670
671    #[test]
672    fn rsa_interest() {
673        const SAFEBAG: &[u8] = b"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\
707g==";
708
709        let safebag_data = base64::engine::general_purpose::STANDARD
710            .decode(SAFEBAG)
711            .unwrap();
712        let safebag = SafeBag::decode(&mut Bytes::from(safebag_data)).unwrap();
713
714        let cert = RsaCertificate::from_safebag(safebag, "test").unwrap();
715        let mut signer = SignatureSha256WithRsa::new(cert.clone());
716
717        let mut interest = Interest::<()>::new(Name::from_str("ndn:/test/test/asd").unwrap());
718        interest.sign(&mut signer, SignSettings::default());
719
720        assert!(interest.verify(&signer).is_ok());
721    }
722}