1use 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#[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 pub content_type: NonNegativeInteger,
28}
29
30#[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 pub freshness_period: NonNegativeInteger,
54}
55
56#[derive(Debug, Tlv, PartialEq, Eq, Clone, Hash, From, Into, AsRef, AsMut)]
59#[tlv(26)]
60pub struct FinalBlockId {
61 pub final_block_id: NameComponent,
63}
64
65#[derive(Debug, Tlv, PartialEq, Eq, Clone, Hash, Default, From, AsRef, AsMut)]
67#[tlv(21)]
68pub struct Content<T> {
69 pub data: T,
71}
72
73#[derive(Debug, Tlv, PartialEq, Eq, Default, Clone, Hash)]
76#[tlv(20)]
77pub struct MetaInfo {
78 pub content_type: Option<ContentType>,
80 pub freshness_period: Option<FreshnessPeriod>,
82 pub final_block_id: Option<FinalBlockId>,
84}
85
86#[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 pub const BLOB: Self = Self::new(0);
104 pub const LINK: Self = Self::new(1);
106 pub const KEY: Self = Self::new(2);
108 pub const NACK: Self = Self::new(3);
110
111 pub const fn new(typ: u64) -> Self {
113 Self {
114 content_type: NonNegativeInteger::new(typ),
115 }
116 }
117}
118
119impl FreshnessPeriod {
120 pub fn new(period: u64) -> Self {
122 Self {
123 freshness_period: NonNegativeInteger::new(period),
124 }
125 }
126}
127
128impl Data<Bytes> {
129 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 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 pub fn name(&self) -> &Name {
175 &self.name
176 }
177
178 pub fn set_name(&mut self, name: Name) -> &mut Self {
180 self.name = name;
181 self
182 }
183
184 pub fn meta_info(&self) -> &Option<MetaInfo> {
186 &self.meta_info
187 }
188
189 pub fn set_meta_info(&mut self, meta_info: Option<MetaInfo>) -> &mut Self {
191 self.meta_info = meta_info;
192 self
193 }
194
195 pub fn content(&self) -> Option<&T> {
197 self.content.as_ref().map(|x| &x.data)
198 }
199
200 pub fn set_content(&mut self, content: Option<T>) -> &mut Self {
202 self.content = content.map(|data| Content { data });
203 self
204 }
205
206 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 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 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 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 pub fn signature_info(&self) -> Option<&SignatureInfo> {
282 self.signature_info.as_ref()
283 }
284
285 pub fn is_signed(&self) -> bool {
287 self.signature_info.is_some()
288 }
289
290 pub fn matches_interest<D>(&self, interest: &Interest<D>) -> bool
298 where
299 D: TlvEncode + TlvDecode,
300 {
301 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 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 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}