ndn_security/
manager.rs

1use std::sync::Arc;
2
3use bytes::Bytes;
4use ndn_packet::{Name, tlv_type};
5use ndn_tlv::TlvWriter;
6
7use crate::{
8    TrustError,
9    cert_cache::{CertCache, Certificate},
10    key_store::MemKeyStore,
11    signer::{Ed25519Signer, Signer},
12};
13
14/// High-level NDN security manager.
15///
16/// Owns a key store and certificate cache, and provides operations for:
17/// - Key pair generation
18/// - Self-signed certificate issuance (trust-anchor certificates)
19/// - Certificate issuance (signing a key Data packet with another key)
20/// - Trust anchor registration
21/// - Retrieving a signer for a key name
22///
23/// For production use, replace `MemKeyStore` with a file-backed store.
24pub struct SecurityManager {
25    keys: MemKeyStore,
26    cert_cache: CertCache,
27    /// Trust anchors — self-signed certs that are implicitly trusted.
28    anchors: dashmap::DashMap<Arc<Name>, Certificate>,
29}
30
31impl SecurityManager {
32    pub fn new() -> Self {
33        Self {
34            keys: MemKeyStore::new(),
35            cert_cache: CertCache::new(),
36            anchors: dashmap::DashMap::new(),
37        }
38    }
39
40    /// Generate a new Ed25519 key pair using a cryptographically random seed
41    /// and store it in the in-memory key store.
42    ///
43    /// `key_name` should follow NDN key naming convention:
44    /// `/<identity>/KEY/<key-id>`.
45    ///
46    /// Returns the key name on success.
47    pub fn generate_ed25519(&self, key_name: Name) -> Result<Name, TrustError> {
48        use ring::rand::{SecureRandom, SystemRandom};
49        let rng = SystemRandom::new();
50        let mut seed = [0u8; 32];
51        rng.fill(&mut seed)
52            .map_err(|_| TrustError::KeyStore("system RNG unavailable".into()))?;
53        let signer = Ed25519Signer::from_seed(&seed, key_name.clone());
54        self.keys.add(Arc::new(key_name.clone()), signer);
55        Ok(key_name)
56    }
57
58    /// Generate a new Ed25519 key from explicit raw seed bytes (for testing).
59    pub fn generate_ed25519_from_seed(
60        &self,
61        key_name: Name,
62        seed: &[u8; 32],
63    ) -> Result<Name, TrustError> {
64        let signer = Ed25519Signer::from_seed(seed, key_name.clone());
65        self.keys.add(Arc::new(key_name.clone()), signer);
66        Ok(key_name)
67    }
68
69    /// Issue a self-signed certificate (trust anchor).
70    ///
71    /// The certificate is inserted into both the cert cache and the anchor set.
72    /// `validity_ms` is the certificate lifetime in milliseconds; pass `u64::MAX`
73    /// for non-expiring anchors.
74    pub fn issue_self_signed(
75        &self,
76        key_name: &Name,
77        public_key_bytes: Bytes,
78        validity_ms: u64,
79    ) -> Result<Certificate, TrustError> {
80        let now_ns = now_ns();
81        let valid_until = if validity_ms == u64::MAX {
82            u64::MAX
83        } else {
84            now_ns + validity_ms * 1_000_000
85        };
86        let cert = Certificate {
87            name: Arc::new(key_name.clone()),
88            public_key: public_key_bytes,
89            valid_from: now_ns,
90            valid_until,
91            issuer: None,
92            signed_region: None,
93            sig_value: None,
94        };
95        self.cert_cache.insert(cert.clone());
96        self.anchors
97            .insert(Arc::new(key_name.clone()), cert.clone());
98        Ok(cert)
99    }
100
101    /// Issue a certificate for `subject_key` signed by `issuer_key`.
102    ///
103    /// Both keys must already exist in the key store. The issuer signs a
104    /// complete NDN certificate Data packet (TLV-encoded) whose Content
105    /// carries the subject's public key and validity period. The resulting
106    /// `Certificate` is stored in the cert cache; the full wire-format Data
107    /// packet is stored in `Certificate::wire`.
108    pub async fn certify(
109        &self,
110        subject_key_name: &Name,
111        subject_public_key: Bytes,
112        issuer_key_name: &Name,
113        validity_ms: u64,
114    ) -> Result<Certificate, TrustError> {
115        let issuer_signer = self.keys.get_signer_sync(issuer_key_name)?;
116
117        let now_ns = now_ns();
118        let valid_until = now_ns + validity_ms * 1_000_000;
119
120        // Encode and sign the full certificate Data packet.
121        let _wire = encode_cert_data(
122            subject_key_name,
123            &subject_public_key,
124            issuer_signer.as_ref(),
125            now_ns,
126            valid_until,
127        )
128        .await?;
129
130        let cert = Certificate {
131            name: Arc::new(subject_key_name.clone()),
132            public_key: subject_public_key,
133            valid_from: now_ns,
134            valid_until,
135            issuer: None,
136            signed_region: None,
137            sig_value: None,
138        };
139        self.cert_cache.insert(cert.clone());
140        Ok(cert)
141    }
142
143    /// Register a pre-existing certificate as a trust anchor.
144    pub fn add_trust_anchor(&self, cert: Certificate) {
145        self.anchors.insert(Arc::clone(&cert.name), cert.clone());
146        self.cert_cache.insert(cert);
147    }
148
149    /// Look up a trust anchor by key name.
150    pub fn trust_anchor(&self, key_name: &Name) -> Option<Certificate> {
151        self.anchors
152            .iter()
153            .find(|r| r.key().as_ref() == key_name)
154            .map(|r| r.value().clone())
155    }
156
157    /// List all trust anchor names.
158    pub fn trust_anchor_names(&self) -> Vec<Arc<Name>> {
159        self.anchors.iter().map(|r| Arc::clone(r.key())).collect()
160    }
161
162    /// Retrieve a signer for the given key name.
163    pub async fn get_signer(&self, key_name: &Name) -> Result<Arc<dyn Signer>, TrustError> {
164        use crate::key_store::KeyStore;
165        self.keys.get_signer(key_name).await
166    }
167
168    /// Retrieve a signer synchronously (for use in non-async contexts).
169    pub fn get_signer_sync(&self, key_name: &Name) -> Result<Arc<dyn Signer>, TrustError> {
170        self.keys.get_signer_sync(key_name)
171    }
172
173    /// Access the certificate cache (e.g., to pass to a `Validator`).
174    pub fn cert_cache(&self) -> &CertCache {
175        &self.cert_cache
176    }
177
178    /// Build a `SecurityManager` by loading an identity from a [`FilePib`].
179    ///
180    /// - Loads the signing key for `identity` from the PIB.
181    /// - If a certificate is present for that identity, inserts it into the
182    ///   cert cache.
183    /// - Loads all trust anchors stored in the PIB.
184    ///
185    /// [`FilePib`]: crate::pib::FilePib
186    pub fn from_pib(pib: &crate::pib::FilePib, identity: &Name) -> Result<Self, TrustError> {
187        let mgr = SecurityManager::new();
188
189        // Load the signing key.
190        let signer = pib.get_signer(identity)?;
191        mgr.keys.add(Arc::new(identity.clone()), signer);
192
193        // Load the identity's certificate if present.
194        if let Ok(cert) = pib.get_cert(identity) {
195            mgr.cert_cache.insert(cert);
196        }
197
198        // Load all trust anchors.
199        for anchor in pib.trust_anchors()? {
200            mgr.add_trust_anchor(anchor);
201        }
202
203        Ok(mgr)
204    }
205
206    /// Auto-initialize security state from a PIB directory.
207    ///
208    /// If the PIB has no keys, generates a new Ed25519 identity with a
209    /// self-signed certificate and stores it. If keys already exist,
210    /// loads the first identity found.
211    ///
212    /// Returns `(SecurityManager, bool)` where the bool is `true` if a
213    /// new identity was generated (useful for logging).
214    pub fn auto_init(
215        identity: &Name,
216        pib_path: &std::path::Path,
217    ) -> Result<(Self, bool), TrustError> {
218        use crate::pib::FilePib;
219
220        // Open or create the PIB.
221        let pib = if pib_path.exists() {
222            FilePib::open(pib_path)?
223        } else {
224            FilePib::new(pib_path)?
225        };
226
227        let existing_keys = pib.list_keys()?;
228        if !existing_keys.is_empty() {
229            // Load the first existing identity.
230            let key_name = &existing_keys[0];
231            let mgr = SecurityManager::from_pib(&pib, key_name)?;
232            return Ok((mgr, false));
233        }
234
235        // No keys — generate a new identity.
236        let key_name = append_key_component(identity);
237        let signer = pib.generate_ed25519(&key_name)?;
238
239        // Self-signed certificate: 1 year validity.
240        let pk = Bytes::copy_from_slice(&signer.public_key_bytes());
241        let now_ns = now_ns();
242        let one_year_ns = 365 * 24 * 3600 * 1_000_000_000u64;
243        let cert = Certificate {
244            name: Arc::new(key_name.clone()),
245            public_key: pk,
246            valid_from: now_ns,
247            valid_until: now_ns.saturating_add(one_year_ns),
248            issuer: Some(Arc::new(key_name.clone())), // self-signed
249            signed_region: None,
250            sig_value: None,
251        };
252        pib.store_cert(&key_name, &cert)?;
253        pib.add_trust_anchor(&key_name, &cert)?;
254
255        let mgr = SecurityManager::from_pib(&pib, &key_name)?;
256        Ok((mgr, true))
257    }
258}
259
260/// Append `/KEY/self` components to an identity name.
261fn append_key_component(identity: &Name) -> Name {
262    use ndn_packet::NameComponent;
263    let mut components: Vec<NameComponent> = identity.components().to_vec();
264    components.push(NameComponent::generic(Bytes::from_static(b"KEY")));
265    components.push(NameComponent::generic(Bytes::from_static(b"self")));
266    Name::from_components(components)
267}
268
269impl Default for SecurityManager {
270    fn default() -> Self {
271        Self::new()
272    }
273}
274
275/// Encode the signed region of an NDN certificate Data packet and sign it.
276///
277/// An NDN certificate is a regular Data packet whose:
278/// - Name follows the NDN key naming convention
279/// - Content is the subject's public key bytes
280/// - SignatureInfo contains `SignatureEd25519` and a `KeyLocator` pointing
281///   to the issuer's key name
282/// - SignatureValue is the Ed25519 signature over the signed region
283///   (Name through end of SignatureInfo)
284///
285/// Returns the full wire-format Data packet as `Bytes`.
286async fn encode_cert_data(
287    subject_key_name: &Name,
288    subject_public_key: &[u8],
289    issuer_signer: &dyn Signer,
290    valid_from_ns: u64,
291    valid_until_ns: u64,
292) -> Result<Bytes, TrustError> {
293    // Build the signed region: Name + MetaInfo + Content + SignatureInfo.
294    let mut signed = TlvWriter::new();
295
296    // Name
297    write_name(&mut signed, subject_key_name);
298
299    // MetaInfo: ContentType = KEY (2), FreshnessPeriod = 3600000 ms (1 h)
300    signed.write_nested(tlv_type::META_INFO, |w| {
301        w.write_tlv(tlv_type::CONTENT_TYPE, &2u64.to_be_bytes());
302        w.write_tlv(tlv_type::FRESHNESS_PERIOD, &3_600_000u64.to_be_bytes());
303    });
304
305    // Content: raw public key bytes + validity period
306    signed.write_nested(tlv_type::CONTENT, |w| {
307        w.write_tlv(0x00, subject_public_key); // raw key material
308
309        // Validity period sub-TLV
310        w.write_nested(tlv_type::VALIDITY_PERIOD, |w| {
311            w.write_tlv(tlv_type::NOT_BEFORE, &valid_from_ns.to_be_bytes());
312            w.write_tlv(tlv_type::NOT_AFTER, &valid_until_ns.to_be_bytes());
313        });
314    });
315
316    // SignatureInfo
317    let sig_type_code = issuer_signer.sig_type().code();
318    signed.write_nested(tlv_type::SIGNATURE_INFO, |w| {
319        w.write_tlv(tlv_type::SIGNATURE_TYPE, &[sig_type_code as u8]);
320        // KeyLocator: issuer key name
321        w.write_nested(tlv_type::KEY_LOCATOR, |w| {
322            write_name(w, issuer_signer.key_name());
323        });
324    });
325
326    let signed_region = signed.finish();
327
328    // Sign the region.
329    let signature = issuer_signer.sign(&signed_region).await?;
330
331    // Wrap everything in the outer Data TLV.
332    let mut outer = TlvWriter::new();
333    outer.write_nested(tlv_type::DATA, |w| {
334        // Write signed region verbatim.
335        w.write_raw(&signed_region);
336        // SignatureValue
337        w.write_tlv(tlv_type::SIGNATURE_VALUE, &signature);
338    });
339
340    Ok(outer.finish())
341}
342
343/// Write a `Name` TLV into a writer.
344fn write_name(w: &mut TlvWriter, name: &Name) {
345    w.write_nested(tlv_type::NAME, |w| {
346        for comp in name.components() {
347            w.write_tlv(comp.typ, &comp.value);
348        }
349    });
350}
351
352fn now_ns() -> u64 {
353    use std::time::{SystemTime, UNIX_EPOCH};
354    SystemTime::now()
355        .duration_since(UNIX_EPOCH)
356        .map(|d| d.as_nanos() as u64)
357        .unwrap_or(0)
358}
359
360#[cfg(test)]
361mod tests {
362    use super::*;
363    use ndn_packet::NameComponent;
364
365    fn key_name(s: &'static str) -> Name {
366        Name::from_components([NameComponent::generic(Bytes::from_static(s.as_bytes()))])
367    }
368
369    #[test]
370    fn generate_ed25519_stores_key() {
371        let mgr = SecurityManager::new();
372        let kn = key_name("mykey");
373        assert!(mgr.generate_ed25519(kn.clone()).is_ok());
374    }
375
376    #[test]
377    fn issue_self_signed_adds_anchor() {
378        let mgr = SecurityManager::new();
379        let kn = key_name("anchor");
380        let pk = Bytes::from_static(&[0xAB; 32]);
381        let cert = mgr.issue_self_signed(&kn, pk, u64::MAX).unwrap();
382        assert_eq!(*cert.name, kn);
383        assert!(mgr.trust_anchor(&kn).is_some());
384    }
385
386    #[test]
387    fn trust_anchor_not_present_returns_none() {
388        let mgr = SecurityManager::new();
389        let kn = key_name("missing");
390        assert!(mgr.trust_anchor(&kn).is_none());
391    }
392
393    #[test]
394    fn add_trust_anchor_inserts_into_cache() {
395        let mgr = SecurityManager::new();
396        let kn = key_name("ta");
397        let cert = Certificate {
398            name: Arc::new(kn.clone()),
399            public_key: Bytes::from_static(&[1u8; 32]),
400            valid_from: 0,
401            valid_until: u64::MAX,
402            issuer: None,
403            signed_region: None,
404            sig_value: None,
405        };
406        mgr.add_trust_anchor(cert.clone());
407        assert!(mgr.trust_anchor(&kn).is_some());
408        assert!(mgr.cert_cache().get(&Arc::new(kn)).is_some());
409    }
410
411    #[test]
412    fn trust_anchor_names_returns_all() {
413        let mgr = SecurityManager::new();
414        let kn1 = key_name("a");
415        let kn2 = key_name("b");
416        for kn in [&kn1, &kn2] {
417            mgr.add_trust_anchor(Certificate {
418                name: Arc::new(kn.clone()),
419                public_key: Bytes::from_static(&[0; 32]),
420                valid_from: 0,
421                valid_until: u64::MAX,
422                issuer: None,
423                signed_region: None,
424                sig_value: None,
425            });
426        }
427        let names = mgr.trust_anchor_names();
428        assert_eq!(names.len(), 2);
429    }
430
431    #[test]
432    fn generate_from_seed_and_retrieve() {
433        let mgr = SecurityManager::new();
434        let kn = key_name("seeded");
435        let seed = [7u8; 32];
436        mgr.generate_ed25519_from_seed(kn.clone(), &seed).unwrap();
437        // Key is stored; we can confirm by checking the key store state indirectly.
438        // (get_signer is async; tested separately)
439    }
440
441    #[tokio::test]
442    async fn get_signer_after_generate() {
443        let mgr = SecurityManager::new();
444        let kn = key_name("sigkey");
445        let seed = [9u8; 32];
446        mgr.generate_ed25519_from_seed(kn.clone(), &seed).unwrap();
447        let signer = mgr.get_signer(&kn).await.unwrap();
448        assert_eq!(signer.key_name(), &kn);
449    }
450
451    #[tokio::test]
452    async fn certify_produces_signed_cert() {
453        let mgr = SecurityManager::new();
454
455        // Generate issuer (CA) key.
456        let ca_name = key_name("ca");
457        let ca_seed = [1u8; 32];
458        mgr.generate_ed25519_from_seed(ca_name.clone(), &ca_seed)
459            .unwrap();
460
461        // Generate subject key.
462        let subj_name = key_name("subject");
463        let subj_seed = [2u8; 32];
464        mgr.generate_ed25519_from_seed(subj_name.clone(), &subj_seed)
465            .unwrap();
466
467        let subj_pk = Bytes::copy_from_slice(
468            &crate::signer::Ed25519Signer::from_seed(&subj_seed, subj_name.clone())
469                .public_key_bytes(),
470        );
471
472        // Issue certificate.
473        let cert = mgr
474            .certify(&subj_name, subj_pk.clone(), &ca_name, 60_000)
475            .await
476            .unwrap();
477
478        assert_eq!(*cert.name, subj_name);
479        assert_eq!(cert.public_key, subj_pk);
480        assert!(cert.valid_until > cert.valid_from);
481
482        // Certificate should be in the cache.
483        assert!(mgr.cert_cache().get(&Arc::new(subj_name)).is_some());
484    }
485
486    #[tokio::test]
487    async fn certify_fails_with_unknown_issuer() {
488        let mgr = SecurityManager::new();
489
490        let subj_name = key_name("subj");
491        let ca_name = key_name("unknown_ca");
492        let pk = Bytes::from_static(&[0xAA; 32]);
493
494        let result = mgr.certify(&subj_name, pk, &ca_name, 60_000).await;
495        assert!(result.is_err());
496    }
497
498    #[test]
499    fn auto_init_generates_on_empty_pib() {
500        let dir = tempfile::tempdir().unwrap();
501        let pib_path = dir.path().join("pib");
502        let identity = key_name("router1");
503
504        let (mgr, generated) = SecurityManager::auto_init(&identity, &pib_path).unwrap();
505        assert!(generated);
506        assert!(!mgr.trust_anchor_names().is_empty());
507
508        // Second call should load existing, not regenerate.
509        let (_mgr2, generated2) = SecurityManager::auto_init(&identity, &pib_path).unwrap();
510        assert!(!generated2);
511    }
512}