ndn_packet/
signature.rs

1#[cfg(not(feature = "std"))]
2use alloc::sync::Arc;
3#[cfg(feature = "std")]
4use std::sync::Arc;
5
6use bytes::Bytes;
7
8use crate::{Name, PacketError, tlv_type};
9use ndn_tlv::TlvReader;
10
11/// NDN signature algorithm identifiers.
12#[derive(Clone, Copy, Debug, PartialEq, Eq)]
13pub enum SignatureType {
14    DigestSha256,
15    SignatureSha256WithRsa,
16    SignatureSha256WithEcdsa,
17    SignatureHmacWithSha256,
18    SignatureEd25519,
19    Other(u64),
20}
21
22impl SignatureType {
23    pub fn code(&self) -> u64 {
24        match self {
25            SignatureType::DigestSha256 => 0,
26            SignatureType::SignatureSha256WithRsa => 1,
27            SignatureType::SignatureSha256WithEcdsa => 3,
28            SignatureType::SignatureHmacWithSha256 => 4,
29            SignatureType::SignatureEd25519 => 5,
30            SignatureType::Other(c) => *c,
31        }
32    }
33
34    pub fn from_code(code: u64) -> Self {
35        match code {
36            0 => SignatureType::DigestSha256,
37            1 => SignatureType::SignatureSha256WithRsa,
38            3 => SignatureType::SignatureSha256WithEcdsa,
39            4 => SignatureType::SignatureHmacWithSha256,
40            5 => SignatureType::SignatureEd25519,
41            c => SignatureType::Other(c),
42        }
43    }
44}
45
46/// SignatureInfo TLV — algorithm and optional key locator.
47///
48/// The `KeyLocator` TLV may carry either a `Name` (0x07) referencing the
49/// signer's certificate, or a `KeyDigest` (0x1d) carrying a SHA-256 of the
50/// public key. Both forms are decoded; the unused field is `None`. At most
51/// one of `key_locator` or `key_digest` is populated for a given packet.
52///
53/// Also decodes the anti-replay fields from InterestSignatureInfo:
54/// SignatureNonce (0x26), SignatureTime (0x28), SignatureSeqNum (0x2A).
55#[derive(Clone, Debug)]
56pub struct SignatureInfo {
57    pub sig_type: SignatureType,
58    /// `KeyLocator` → `Name` form: the signer's certificate name.
59    pub key_locator: Option<Arc<Name>>,
60    /// `KeyLocator` → `KeyDigest` form: a hash of the signer's public key.
61    /// Implementations resolve this against a local certificate cache.
62    pub key_digest: Option<Bytes>,
63    /// Random nonce for anti-replay (NDN Packet Format v0.3 §5.4).
64    pub sig_nonce: Option<Bytes>,
65    /// Timestamp in milliseconds since Unix epoch (NDN Packet Format v0.3 §5.4).
66    pub sig_time: Option<u64>,
67    /// Monotonically increasing sequence number (NDN Packet Format v0.3 §5.4).
68    pub sig_seq_num: Option<u64>,
69}
70
71impl SignatureInfo {
72    pub fn decode(value: Bytes) -> Result<Self, PacketError> {
73        let mut reader = TlvReader::new(value);
74        let mut sig_type = SignatureType::Other(0);
75        let mut key_locator = None;
76        let mut key_digest = None;
77        let mut sig_nonce = None;
78        let mut sig_time = None;
79        let mut sig_seq_num = None;
80
81        while !reader.is_empty() {
82            let (typ, val) = reader.read_tlv()?;
83            match typ {
84                t if t == tlv_type::SIGNATURE_TYPE => {
85                    let mut code = 0u64;
86                    for &b in val.iter() {
87                        code = (code << 8) | b as u64;
88                    }
89                    sig_type = SignatureType::from_code(code);
90                }
91                t if t == tlv_type::KEY_LOCATOR => {
92                    // KeyLocator carries exactly one of Name (0x07) or
93                    // KeyDigest (0x1d). NDN Packet Format §3.2.5.
94                    let mut inner = TlvReader::new(val);
95                    if !inner.is_empty() {
96                        let (kt, kv) = inner.read_tlv()?;
97                        if kt == tlv_type::NAME {
98                            let name = Name::decode(kv)?;
99                            key_locator = Some(Arc::new(name));
100                        } else if kt == tlv_type::KEY_DIGEST {
101                            key_digest = Some(kv);
102                        }
103                    }
104                }
105                t if t == tlv_type::SIGNATURE_NONCE => {
106                    sig_nonce = Some(val);
107                }
108                t if t == tlv_type::SIGNATURE_TIME => {
109                    let mut ms = 0u64;
110                    for &b in val.iter() {
111                        ms = (ms << 8) | b as u64;
112                    }
113                    sig_time = Some(ms);
114                }
115                t if t == tlv_type::SIGNATURE_SEQ_NUM => {
116                    let mut n = 0u64;
117                    for &b in val.iter() {
118                        n = (n << 8) | b as u64;
119                    }
120                    sig_seq_num = Some(n);
121                }
122                _ => {}
123            }
124        }
125        Ok(Self {
126            sig_type,
127            key_locator,
128            key_digest,
129            sig_nonce,
130            sig_time,
131            sig_seq_num,
132        })
133    }
134}
135
136#[cfg(test)]
137mod tests {
138    use super::*;
139    use crate::name::build_name_value;
140    use ndn_tlv::TlvWriter;
141
142    fn build_sig_info(sig_type_code: u8, key_name_components: Option<&[&[u8]]>) -> bytes::Bytes {
143        let mut w = TlvWriter::new();
144        w.write_tlv(crate::tlv_type::SIGNATURE_TYPE, &[sig_type_code]);
145        if let Some(comps) = key_name_components {
146            w.write_nested(crate::tlv_type::KEY_LOCATOR, |w| {
147                let name_val = build_name_value(comps);
148                w.write_tlv(crate::tlv_type::NAME, &name_val);
149            });
150        }
151        w.finish()
152    }
153
154    // ── SignatureType code round-trips ─────────────────────────────────────────
155
156    #[test]
157    fn sig_type_known_codes() {
158        let cases = [
159            (SignatureType::DigestSha256, 0u64),
160            (SignatureType::SignatureSha256WithRsa, 1),
161            (SignatureType::SignatureSha256WithEcdsa, 3),
162            (SignatureType::SignatureHmacWithSha256, 4),
163            (SignatureType::SignatureEd25519, 5),
164        ];
165        for (sig_type, code) in cases {
166            assert_eq!(sig_type.code(), code, "{sig_type:?}");
167            assert_eq!(SignatureType::from_code(code), sig_type);
168        }
169    }
170
171    #[test]
172    fn sig_type_other_code_roundtrip() {
173        let t = SignatureType::Other(99);
174        assert_eq!(t.code(), 99);
175        assert_eq!(SignatureType::from_code(99), SignatureType::Other(99));
176    }
177
178    // ── SignatureInfo::decode ─────────────────────────────────────────────────
179
180    #[test]
181    fn decode_sig_type_only() {
182        let raw = build_sig_info(5, None);
183        let si = SignatureInfo::decode(raw).unwrap();
184        assert_eq!(si.sig_type, SignatureType::SignatureEd25519);
185        assert!(si.key_locator.is_none());
186    }
187
188    #[test]
189    fn decode_all_known_sig_types() {
190        for code in [0u8, 1, 3, 4, 5] {
191            let raw = build_sig_info(code, None);
192            let si = SignatureInfo::decode(raw).unwrap();
193            assert_eq!(si.sig_type.code(), code as u64);
194        }
195    }
196
197    #[test]
198    fn decode_with_key_locator() {
199        let raw = build_sig_info(5, Some(&[b"sensor", b"node1", b"KEY", b"abc"]));
200        let si = SignatureInfo::decode(raw).unwrap();
201        assert_eq!(si.sig_type, SignatureType::SignatureEd25519);
202        let kl = si.key_locator.expect("key_locator present");
203        assert_eq!(kl.len(), 4);
204        assert_eq!(kl.components()[0].value.as_ref(), b"sensor");
205        assert_eq!(kl.components()[3].value.as_ref(), b"abc");
206        assert!(
207            si.key_digest.is_none(),
208            "Name-form locator must not populate key_digest"
209        );
210    }
211
212    #[test]
213    fn decode_with_key_digest_locator() {
214        // KeyLocator → KeyDigest form: the 32-byte SHA-256 of the public key.
215        let digest = [0xABu8; 32];
216        let mut w = TlvWriter::new();
217        w.write_tlv(crate::tlv_type::SIGNATURE_TYPE, &[5]);
218        w.write_nested(crate::tlv_type::KEY_LOCATOR, |w| {
219            w.write_tlv(crate::tlv_type::KEY_DIGEST, &digest);
220        });
221        let si = SignatureInfo::decode(w.finish()).unwrap();
222        assert_eq!(si.sig_type, SignatureType::SignatureEd25519);
223        assert!(
224            si.key_locator.is_none(),
225            "KeyDigest form must not populate key_locator"
226        );
227        let kd = si.key_digest.expect("key_digest present");
228        assert_eq!(kd.len(), 32);
229        assert!(kd.iter().all(|&b| b == 0xAB));
230    }
231
232    #[test]
233    fn decode_empty_is_other_zero() {
234        // No fields — sig_type defaults to Other(0).
235        let si = SignatureInfo::decode(bytes::Bytes::new()).unwrap();
236        assert_eq!(si.sig_type, SignatureType::Other(0));
237        assert!(si.key_locator.is_none());
238    }
239
240    // ── Anti-replay fields ──────────────────────────────────────────────────
241
242    #[test]
243    fn decode_sig_nonce() {
244        let mut w = TlvWriter::new();
245        w.write_tlv(crate::tlv_type::SIGNATURE_TYPE, &[5]);
246        w.write_tlv(crate::tlv_type::SIGNATURE_NONCE, &[0xDE, 0xAD, 0xBE, 0xEF]);
247        let si = SignatureInfo::decode(w.finish()).unwrap();
248        assert_eq!(si.sig_nonce.as_deref(), Some(&[0xDE, 0xAD, 0xBE, 0xEF][..]));
249    }
250
251    #[test]
252    fn decode_sig_time() {
253        let mut w = TlvWriter::new();
254        w.write_tlv(crate::tlv_type::SIGNATURE_TYPE, &[5]);
255        let ts: u64 = 1_700_000_000_000; // millis
256        w.write_tlv(crate::tlv_type::SIGNATURE_TIME, &ts.to_be_bytes());
257        let si = SignatureInfo::decode(w.finish()).unwrap();
258        assert_eq!(si.sig_time, Some(ts));
259    }
260
261    #[test]
262    fn decode_sig_seq_num() {
263        let mut w = TlvWriter::new();
264        w.write_tlv(crate::tlv_type::SIGNATURE_TYPE, &[5]);
265        w.write_tlv(crate::tlv_type::SIGNATURE_SEQ_NUM, &42u64.to_be_bytes());
266        let si = SignatureInfo::decode(w.finish()).unwrap();
267        assert_eq!(si.sig_seq_num, Some(42));
268    }
269
270    #[test]
271    fn decode_all_anti_replay_fields() {
272        let mut w = TlvWriter::new();
273        w.write_tlv(crate::tlv_type::SIGNATURE_TYPE, &[5]);
274        w.write_tlv(crate::tlv_type::SIGNATURE_NONCE, &[0x01, 0x02]);
275        w.write_tlv(crate::tlv_type::SIGNATURE_TIME, &500u64.to_be_bytes());
276        w.write_tlv(crate::tlv_type::SIGNATURE_SEQ_NUM, &7u64.to_be_bytes());
277        let si = SignatureInfo::decode(w.finish()).unwrap();
278        assert_eq!(si.sig_nonce.as_deref(), Some(&[0x01, 0x02][..]));
279        assert_eq!(si.sig_time, Some(500));
280        assert_eq!(si.sig_seq_num, Some(7));
281    }
282
283    #[test]
284    fn decode_no_anti_replay_fields() {
285        let raw = build_sig_info(5, None);
286        let si = SignatureInfo::decode(raw).unwrap();
287        assert!(si.sig_nonce.is_none());
288        assert!(si.sig_time.is_none());
289        assert!(si.sig_seq_num.is_none());
290    }
291}