Skip to main content

runar_keys/
mobile.rs

1//! Mobile Key Manager - Certificate Authority Operations
2//!
3//! This module implements the mobile-side key management system that acts as
4//! a Certificate Authority for issuing node certificates and managing user keys.
5
6use crate::certificate::{
7    CertificateAuthority, CertificateValidator, EcdsaKeyPair, X509Certificate,
8};
9use crate::derivation::derive_agreement_from_master;
10use crate::error::{KeyError, Result};
11use crate::{log_debug, log_error, log_info};
12use p256::elliptic_curve::sec1::ToEncodedPoint;
13use p256::SecretKey as P256SecretKey;
14use pkcs8::{DecodePrivateKey, EncodePrivateKey};
15use runar_common::compact_ids::compact_id;
16use runar_common::logging::Logger;
17use serde::{Deserialize, Serialize};
18use std::collections::HashMap;
19use std::sync::Arc;
20
21/// Setup token from a node requesting a certificate
22#[derive(Debug, Clone, Serialize, Deserialize)]
23pub struct SetupToken {
24    /// Node's public key for identity
25    pub node_public_key: Vec<u8>,
26    /// Node's ECIES agreement public key (P-256)
27    pub node_agreement_public_key: Vec<u8>,
28    /// Node's certificate signing request (CSR) in DER format
29    pub csr_der: Vec<u8>,
30    /// Node identifier string
31    pub node_id: String,
32}
33
34/// Secure message containing certificate and CA information for a node
35#[derive(Debug, Clone, Serialize, Deserialize)]
36pub struct NodeCertificateMessage {
37    /// The signed certificate for the node
38    pub node_certificate: X509Certificate,
39    /// The CA certificate for validation
40    pub ca_certificate: X509Certificate,
41    /// Additional metadata
42    pub metadata: CertificateMetadata,
43}
44
45/// Certificate metadata
46#[derive(Debug, Clone, Serialize, Deserialize)]
47pub struct CertificateMetadata {
48    /// Issue timestamp
49    pub issued_at: u64,
50    /// Validity period in days
51    pub validity_days: u32,
52    /// Certificate purpose
53    pub purpose: String,
54}
55
56/// Network key information for secure node communication
57#[derive(Debug, Clone, Serialize, Deserialize)]
58pub struct NetworkKeyMessage {
59    /// Network identifier
60    pub network_id: String,
61    /// Network public key
62    pub network_public_key: Vec<u8>,
63    /// Encrypted network data key
64    pub encrypted_network_key: Vec<u8>,
65    /// Key derivation information
66    pub key_derivation_info: String,
67}
68
69/// Envelope encrypted data structure
70#[derive(Debug, Clone, Serialize, Deserialize)]
71pub struct EnvelopeEncryptedData {
72    /// The encrypted data payload
73    pub encrypted_data: Vec<u8>,
74    /// Network ID this data belongs to
75    pub network_id: Option<String>,
76    /// Envelope key encrypted with network key (always required)
77    pub network_encrypted_key: Vec<u8>,
78    /// Envelope key encrypted with each profile key
79    pub profile_encrypted_keys: HashMap<String, Vec<u8>>,
80}
81
82/// Mobile Key Manager that acts as a Certificate Authority
83pub struct MobileKeyManager {
84    /// Certificate Authority for issuing certificates
85    certificate_authority: CertificateAuthority,
86    /// Certificate validator
87    certificate_validator: CertificateValidator,
88    /// User root signing key - Master key for the user (never leaves mobile)
89    user_root_key: Option<EcdsaKeyPair>,
90    /// User root agreement key (derived deterministically)
91    user_root_agreement: Option<P256SecretKey>,
92    /// User profile signing keys indexed by profile ID
93    user_profile_keys: HashMap<String, EcdsaKeyPair>,
94    /// User profile agreement keys indexed by profile ID
95    user_profile_agreements: HashMap<String, P256SecretKey>,
96    /// Mapping from human-readable label → compact-id for quick reuse
97    label_to_pid: HashMap<String, String>,
98    /// Network agreement keys indexed by network ID - for envelope encryption and decryption
99    network_data_keys: HashMap<String, P256SecretKey>,
100    // network public keys indexed by network ID - for envelope encryption
101    network_public_keys: HashMap<String, Vec<u8>>,
102    /// Issued certificates tracking
103    issued_certificates: HashMap<String, X509Certificate>,
104    /// Monotonically-increasing certificate serial number used as the X.509
105    /// serial for node certificates. Persisted so restarts keep the sequence
106    /// and avoid duplicate serial numbers.
107    serial_counter: u64,
108    /// Logger instance
109    logger: Arc<Logger>,
110}
111
112/// Serializable snapshot of the MobileKeyManager. This allows persisting
113/// all cryptographic material so a restored instance can continue to operate
114/// without regenerating or losing keys.
115#[derive(Debug, Clone, Serialize, Deserialize)]
116pub struct MobileKeyManagerState {
117    ca_key_pair: EcdsaKeyPair,
118    ca_certificate: X509Certificate,
119    user_root_key: Option<EcdsaKeyPair>,
120    // Stored as PKCS#8 DER bytes for portability
121    user_root_agreement: Option<Vec<u8>>,
122    user_profile_keys: HashMap<String, EcdsaKeyPair>,
123    user_profile_agreements: HashMap<String, Vec<u8>>,
124    label_to_pid: HashMap<String, String>,
125    network_data_keys: HashMap<String, Vec<u8>>,
126    network_public_keys: HashMap<String, Vec<u8>>,
127    issued_certificates: HashMap<String, X509Certificate>,
128    serial_counter: u64,
129}
130
131impl MobileKeyManager {
132    /// Create a new Mobile Key Manager
133    pub fn new(logger: Arc<Logger>) -> Result<Self> {
134        // Create Certificate Authority with user identity
135        let ca_subject = "CN=Runar User CA,O=Runar,C=US";
136        let certificate_authority = CertificateAuthority::new(ca_subject)?;
137        let certificate_validator =
138            CertificateValidator::new(vec![certificate_authority.ca_certificate().clone()]);
139
140        Ok(Self {
141            certificate_authority,
142            certificate_validator,
143            user_root_key: None,
144            user_root_agreement: None,
145            user_profile_keys: HashMap::new(),
146            user_profile_agreements: HashMap::new(),
147            label_to_pid: HashMap::new(),
148            network_data_keys: HashMap::new(),
149            network_public_keys: HashMap::new(),
150            issued_certificates: HashMap::new(),
151            serial_counter: 1, // Start at 1 to avoid 0
152            logger,
153        })
154    }
155
156    /// Convert a compact ID to a DNS-safe format by replacing invalid characters
157    fn dns_safe_node_id(&self, node_id: &str) -> String {
158        node_id
159            .chars()
160            .map(|c| match c {
161                '-' => 'x',                    // Replace hyphen with 'x'
162                '_' => 'y',                    // Replace underscore with 'y'
163                c if c.is_alphanumeric() => c, // Keep alphanumeric
164                _ => 'z',                      // Replace any other invalid chars with 'z'
165            })
166            .collect()
167    }
168
169    pub fn install_network_public_key(&mut self, network_public_key: &[u8]) -> Result<()> {
170        let network_id = compact_id(network_public_key);
171        self.network_public_keys
172            .insert(network_id.clone(), network_public_key.to_vec());
173
174        log_info!(
175            self.logger,
176            "Network public key installed with ID: {network_id}"
177        );
178        Ok(())
179    }
180
181    /// Initialize user root key - Master key that never leaves the mobile device
182    pub fn initialize_user_root_key(&mut self) -> Result<Vec<u8>> {
183        if self.user_root_key.is_some() {
184            return Err(KeyError::KeyAlreadyInitialized(
185                "User root key already initialized".to_string(),
186            ));
187        }
188
189        let root_key = EcdsaKeyPair::new()?;
190
191        // Derive agreement key from master signing key deterministically
192        let agreement_secret = derive_agreement_from_master(
193            &root_key.signing_key().to_bytes(),
194            b"runar-v1:user-root:agreement",
195        )?;
196        self.user_root_key = Some(root_key);
197        self.user_root_agreement = Some(agreement_secret);
198        log_info!(
199            self.logger,
200            "User root key initialized (private key secured on mobile)"
201        );
202
203        // Return the agreement public key bytes for ECIES recipients
204        let agr_pub = self
205            .user_root_agreement
206            .as_ref()
207            .unwrap()
208            .public_key()
209            .to_encoded_point(false)
210            .as_bytes()
211            .to_vec();
212
213        Ok(agr_pub)
214    }
215
216    /// Get the user root public key
217    pub fn get_user_root_public_key(&self) -> Result<Vec<u8>> {
218        let root_agreement = self.user_root_agreement.as_ref().ok_or_else(|| {
219            KeyError::KeyNotFound("User root agreement key not initialized".to_string())
220        })?;
221        Ok(root_agreement
222            .public_key()
223            .to_encoded_point(false)
224            .as_bytes()
225            .to_vec())
226    }
227
228    /// Derive a user profile agreement key from the root key using HKDF-SHA-256.
229    ///
230    /// - IKM: raw 32-byte scalar of the user root signing key
231    /// - info: "runar-v1:profile:agreement:{label}[:{counter}]"
232    /// - output: 32-byte scalar interpreted as P-256 SecretKey (with rejection sampling)
233    pub fn derive_user_profile_key(&mut self, label: &str) -> Result<Vec<u8>> {
234        // Fast-path: if we already derived a key for this label return it.
235        if let Some(pid) = self.label_to_pid.get(label) {
236            if let Some(agr) = self.user_profile_agreements.get(pid) {
237                let pubkey = agr.public_key();
238                return Ok(pubkey.to_encoded_point(false).as_bytes().to_vec());
239            }
240        }
241
242        use hkdf::Hkdf;
243        use sha2::Sha256;
244
245        // Ensure the root key exists.
246        let root_key = self
247            .user_root_key
248            .as_ref()
249            .ok_or_else(|| KeyError::KeyNotFound("User root key not initialized".to_string()))?;
250
251        // Extract the raw 32-byte scalar of the root private key as IKM
252        let root_scalar_bytes = root_key.signing_key().to_bytes();
253
254        // Derive a profile-specific agreement scalar using HKDF-SHA-256 with rejection sampling
255        let hk = Hkdf::<Sha256>::new(
256            Some(b"RunarKeyDerivationSalt/v1"),
257            root_scalar_bytes.as_slice(),
258        );
259        let mut counter: u32 = 0;
260        let profile_agreement = loop {
261            let info = if counter == 0 {
262                format!("runar-v1:profile:agreement:{label}")
263            } else {
264                format!("runar-v1:profile:agreement:{label}:{counter}")
265            };
266            let mut candidate_bytes = [0u8; 32];
267            hk.expand(info.as_bytes(), &mut candidate_bytes)
268                .map_err(|e| KeyError::KeyDerivationError(format!("HKDF expansion failed: {e}")))?;
269            match P256SecretKey::from_slice(&candidate_bytes) {
270                Ok(sk) => break sk,
271                Err(_) => {
272                    counter = counter.saturating_add(1);
273                    continue;
274                }
275            }
276        };
277        let public_key = profile_agreement
278            .public_key()
279            .to_encoded_point(false)
280            .as_bytes()
281            .to_vec();
282        let pid = compact_id(&public_key);
283        // Signing key not required for profile; store only agreement
284        self.user_profile_agreements
285            .insert(pid.clone(), profile_agreement);
286        self.label_to_pid.insert(label.to_string(), pid.clone());
287
288        log_info!(self.logger, "User profile key derived using HKDF for label '{label}' (attempts: {counter}, id: {pid})");
289
290        Ok(public_key)
291    }
292
293    pub fn get_network_public_key(&self, network_id: &str) -> Result<Vec<u8>> {
294        // Check both network_data_keys and network_public_keys
295        if let Some(network_key) = self.network_data_keys.get(network_id) {
296            Ok(network_key
297                .public_key()
298                .to_encoded_point(false)
299                .as_bytes()
300                .to_vec())
301        } else if let Some(network_public_key) = self.network_public_keys.get(network_id) {
302            Ok(network_public_key.clone())
303        } else {
304            Err(KeyError::KeyNotFound(format!(
305                "Network public key not found for network: {network_id}"
306            )))
307        }
308    }
309
310    /// Generate a network data key for envelope encryption and return the network ID (compact Base64 public key)
311    pub fn generate_network_data_key(&mut self) -> Result<String> {
312        let network_key = P256SecretKey::random(&mut rand::thread_rng());
313        let public_key = network_key
314            .public_key()
315            .to_encoded_point(false)
316            .as_bytes()
317            .to_vec();
318        let network_id = compact_id(&public_key);
319
320        self.network_data_keys
321            .insert(network_id.clone(), network_key);
322        log_info!(
323            self.logger,
324            "Network data key generated with ID: {network_id}"
325        );
326
327        Ok(network_id)
328    }
329
330    /// Create an envelope key for per-object encryption
331    /// Envelope keys are ephemeral - generated fresh for each object
332    pub fn create_envelope_key(&self) -> Result<Vec<u8>> {
333        // Derive a fresh 32-byte symmetric key from the user-root master using HKDF-SHA-384 and a random nonce label
334        use hkdf::Hkdf;
335        use rand::RngCore;
336        use sha2::Sha256;
337        let root_key = self
338            .user_root_key
339            .as_ref()
340            .ok_or_else(|| KeyError::KeyNotFound("User root key not initialized".to_string()))?;
341        let ikm = root_key.signing_key().to_bytes();
342        let mut nonce = [0u8; 16];
343        rand::thread_rng().fill_bytes(&mut nonce);
344        let hk = Hkdf::<Sha256>::new(Some(b"RunarKeyDerivationSalt/v1"), ikm.as_slice());
345        let mut envelope_key = [0u8; 32];
346        let mut info = b"runar-v1:user-root:storage:envelope:".to_vec();
347        info.extend_from_slice(&nonce);
348        hk.expand(&info, &mut envelope_key)
349            .map_err(|e| KeyError::KeyDerivationError(format!("HKDF expansion failed: {e}")))?;
350        Ok(envelope_key.to_vec())
351    }
352
353    /// Encrypt data with envelope encryption
354    /// This implements the envelope encryption pattern:
355    /// 1. Generate ephemeral envelope key
356    /// 2. Encrypt data with envelope key
357    /// 3. Encrypt envelope key with network/profile keys
358    pub fn encrypt_with_envelope(
359        &self,
360        data: &[u8],
361        network_id: Option<&str>,
362        profile_public_keys: Vec<Vec<u8>>,
363    ) -> Result<EnvelopeEncryptedData> {
364        // Generate ephemeral envelope key
365        let envelope_key = self.create_envelope_key()?;
366
367        // Encrypt data with envelope key (using AES-GCM)
368        let encrypted_data = self.encrypt_with_symmetric_key(data, &envelope_key)?;
369
370        // Encrypt envelope key for network (optional)
371        let mut network_encrypted_key = Vec::new();
372        if let Some(network_id) = network_id {
373            // Check both network_data_keys and network_public_keys
374            let network_public_key_bytes = self.get_network_public_key(network_id)?;
375
376            network_encrypted_key =
377                self.encrypt_key_with_ecdsa(&envelope_key, &network_public_key_bytes)?;
378        }
379
380        // Encrypt envelope key for each profile
381        let mut profile_encrypted_keys = HashMap::new();
382        for profile_public_key in profile_public_keys {
383            let encrypted_key = self.encrypt_key_with_ecdsa(&envelope_key, &profile_public_key)?;
384            let profile_id = compact_id(&profile_public_key);
385            profile_encrypted_keys.insert(profile_id, encrypted_key);
386        }
387
388        Ok(EnvelopeEncryptedData {
389            encrypted_data,
390            network_id: network_id.map(|s| s.to_string()),
391            network_encrypted_key,
392            profile_encrypted_keys,
393        })
394    }
395
396    /// Decrypt envelope-encrypted data using profile key
397    pub fn decrypt_with_profile(
398        &self,
399        envelope_data: &EnvelopeEncryptedData,
400        profile_id: &str,
401    ) -> Result<Vec<u8>> {
402        let profile_agreement = self
403            .user_profile_agreements
404            .get(profile_id)
405            .ok_or_else(|| KeyError::KeyNotFound(format!("Profile key not found: {profile_id}")))?;
406
407        let encrypted_envelope_key = envelope_data
408            .profile_encrypted_keys
409            .get(profile_id)
410            .ok_or_else(|| {
411                KeyError::KeyNotFound(format!("Envelope key not found for profile: {profile_id}"))
412            })?;
413
414        let envelope_key =
415            self.decrypt_key_with_agreement(encrypted_envelope_key, profile_agreement)?;
416        self.decrypt_with_symmetric_key(&envelope_data.encrypted_data, &envelope_key)
417    }
418
419    /// Decrypt envelope-encrypted data using network key
420    pub fn decrypt_with_network(&self, envelope_data: &EnvelopeEncryptedData) -> Result<Vec<u8>> {
421        let network_id = envelope_data
422            .network_id
423            .as_ref()
424            .ok_or_else(|| KeyError::DecryptionError("Envelope missing network_id".to_string()))?;
425
426        let network_key = self.network_data_keys.get(network_id).ok_or_else(|| {
427            KeyError::KeyNotFound(format!(
428                "Network key pair not found for network: {network_id}"
429            ))
430        })?;
431
432        let encrypted_envelope_key = &envelope_data.network_encrypted_key;
433
434        if encrypted_envelope_key.is_empty() {
435            return Err(KeyError::DecryptionError(
436                "Envelope missing network_encrypted_key".to_string(),
437            ));
438        }
439
440        let envelope_key = self.decrypt_key_with_agreement(encrypted_envelope_key, network_key)?;
441        self.decrypt_with_symmetric_key(&envelope_data.encrypted_data, &envelope_key)
442    }
443
444    // Helper methods for symmetric encryption using AES-256-GCM
445    fn encrypt_with_symmetric_key(&self, data: &[u8], key: &[u8]) -> Result<Vec<u8>> {
446        use aes_gcm::{aead::Aead, Aes256Gcm, KeyInit, Nonce};
447        use rand::{thread_rng, RngCore};
448
449        if key.len() != 32 {
450            return Err(KeyError::SymmetricCipherError(
451                "Key must be 32 bytes for AES-256".to_string(),
452            ));
453        }
454
455        let cipher = Aes256Gcm::new_from_slice(key)
456            .map_err(|e| KeyError::SymmetricCipherError(format!("Failed to create cipher: {e}")))?;
457        let mut nonce = [0u8; 12];
458        thread_rng().fill_bytes(&mut nonce);
459
460        let ciphertext = cipher
461            .encrypt(Nonce::from_slice(&nonce), data)
462            .map_err(|e| KeyError::EncryptionError(format!("AES-GCM encryption failed: {e}")))?;
463
464        // Prepend nonce to ciphertext
465        let mut result = nonce.to_vec();
466        result.extend_from_slice(&ciphertext);
467        Ok(result)
468    }
469
470    fn decrypt_with_symmetric_key(&self, encrypted_data: &[u8], key: &[u8]) -> Result<Vec<u8>> {
471        use aes_gcm::{aead::Aead, Aes256Gcm, KeyInit, Nonce};
472
473        if key.len() != 32 {
474            return Err(KeyError::SymmetricCipherError(
475                "Key must be 32 bytes for AES-256".to_string(),
476            ));
477        }
478
479        if encrypted_data.len() < 12 {
480            return Err(KeyError::DecryptionError(
481                "Encrypted data too short (missing nonce)".to_string(),
482            ));
483        }
484
485        let cipher = Aes256Gcm::new_from_slice(key)
486            .map_err(|e| KeyError::SymmetricCipherError(format!("Failed to create cipher: {e}")))?;
487        let nonce = &encrypted_data[..12];
488        let ciphertext = &encrypted_data[12..];
489
490        cipher
491            .decrypt(Nonce::from_slice(nonce), ciphertext)
492            .map_err(|e| KeyError::DecryptionError(format!("AES-GCM decryption failed: {e}")))
493    }
494
495    /// Internal ECIES encryption using a recipient's agreement public key
496    fn encrypt_key_with_ecdsa(
497        &self,
498        data: &[u8],
499        recipient_public_key_bytes: &[u8],
500    ) -> Result<Vec<u8>> {
501        use hkdf::Hkdf;
502        use p256::ecdh::EphemeralSecret;
503        use p256::elliptic_curve::sec1::ToEncodedPoint;
504        use p256::PublicKey;
505        use rand::thread_rng;
506        use sha2::Sha256;
507
508        // Generate ephemeral key pair for ECDH
509        let ephemeral_secret = EphemeralSecret::random(&mut thread_rng());
510        let ephemeral_public = ephemeral_secret.public_key();
511
512        // Convert recipient's public key bytes to PublicKey
513        let recipient_public_key =
514            PublicKey::from_sec1_bytes(recipient_public_key_bytes).map_err(|e| {
515                KeyError::InvalidKeyFormat(format!("Failed to parse recipient public key: {e}"))
516            })?;
517
518        // Perform ECDH key exchange
519        let shared_secret = ephemeral_secret.diffie_hellman(&recipient_public_key);
520        let shared_secret_bytes = shared_secret.raw_secret_bytes();
521
522        // Derive encryption key using HKDF-SHA-256
523        let hk = Hkdf::<Sha256>::new(None, shared_secret_bytes.as_slice());
524        let mut encryption_key = [0u8; 32];
525        hk.expand(b"runar-v1:ecies:envelope-key", &mut encryption_key)
526            .map_err(|e| KeyError::KeyDerivationError(format!("HKDF expansion failed: {e}")))?;
527
528        // Encrypt the data using AES-GCM
529        let encrypted_data = self.encrypt_with_symmetric_key(data, &encryption_key)?;
530
531        // Return ephemeral public key (97 bytes uncompressed) + encrypted data
532        let ephemeral_public_bytes = ephemeral_public.to_encoded_point(false);
533        let mut result = ephemeral_public_bytes.as_bytes().to_vec();
534        result.extend_from_slice(&encrypted_data);
535        Ok(result)
536    }
537
538    /// Internal ECIES decryption using our agreement private key
539    fn decrypt_key_with_agreement(
540        &self,
541        encrypted_data: &[u8],
542        agreement_secret: &p256::SecretKey,
543    ) -> Result<Vec<u8>> {
544        use hkdf::Hkdf;
545        use p256::ecdh::diffie_hellman;
546        use p256::PublicKey;
547        use sha2::Sha256;
548
549        // Extract ephemeral public key (65 bytes uncompressed) and encrypted data
550        if encrypted_data.len() < 65 {
551            return Err(KeyError::DecryptionError(
552                "Encrypted data too short for ECIES".to_string(),
553            ));
554        }
555
556        let ephemeral_public_bytes = &encrypted_data[..65];
557        let encrypted_payload = &encrypted_data[65..];
558
559        // Reconstruct ephemeral public key
560        let ephemeral_public = PublicKey::from_sec1_bytes(ephemeral_public_bytes).map_err(|e| {
561            KeyError::DecryptionError(format!("Failed to parse ephemeral public key: {e}"))
562        })?;
563
564        // Use our agreement key for ECDH
565        let shared_secret = diffie_hellman(
566            agreement_secret.to_nonzero_scalar(),
567            ephemeral_public.as_affine(),
568        );
569        let shared_secret_bytes = shared_secret.raw_secret_bytes();
570
571        // Derive encryption key using HKDF-SHA-256
572        let hk = Hkdf::<Sha256>::new(None, shared_secret_bytes);
573        let mut encryption_key = [0u8; 32];
574        hk.expand(b"runar-v1:ecies:envelope-key", &mut encryption_key)
575            .map_err(|e| KeyError::KeyDerivationError(format!("HKDF expansion failed: {e}")))?;
576
577        // Decrypt the data using AES-GCM
578        self.decrypt_with_symmetric_key(encrypted_payload, &encryption_key)
579    }
580
581    /// Initialize user identity and generate root keys
582    pub fn initialize_user_identity(&mut self) -> Result<Vec<u8>> {
583        // This now delegates to the new user root key method
584        self.initialize_user_root_key()
585    }
586
587    /// Get the user CA certificate
588    pub fn get_ca_certificate(&self) -> &X509Certificate {
589        self.certificate_authority.ca_certificate()
590    }
591
592    /// Get the CA public key bytes
593    pub fn get_ca_public_key(&self) -> Vec<u8> {
594        self.certificate_authority
595            .ca_public_key()
596            .to_encoded_point(true)
597            .as_bytes()
598            .to_vec()
599    }
600
601    /// Process a setup token from a node and issue a certificate
602    pub fn process_setup_token(
603        &mut self,
604        setup_token: &SetupToken,
605    ) -> Result<NodeCertificateMessage> {
606        let node_id = &setup_token.node_id;
607        log_info!(self.logger, "Processing setup token for node: {node_id}");
608
609        // Validate the CSR format
610        if setup_token.csr_der.is_empty() {
611            log_error!(self.logger, "Empty CSR in setup token");
612            return Err(KeyError::InvalidOperation(
613                "Empty CSR in setup token".to_string(),
614            ));
615        }
616
617        // ----- Validate CSR subject: CN must equal the claimed node_id -----
618        {
619            use openssl::nid::Nid;
620            use openssl::x509::X509Req;
621
622            let csr = X509Req::from_der(&setup_token.csr_der).map_err(|e| {
623                KeyError::CertificateError(format!(
624                    "Failed to parse CSR DER for subject validation: {e}"
625                ))
626            })?;
627
628            let mut cn_matches = false;
629            let dns_safe_node_id = self.dns_safe_node_id(node_id);
630            for entry in csr.subject_name().entries_by_nid(Nid::COMMONNAME) {
631                if let Ok(data) = entry.data().as_utf8() {
632                    if data.to_string() == dns_safe_node_id {
633                        cn_matches = true;
634                        break;
635                    }
636                }
637            }
638
639            if !cn_matches {
640                return Err(KeyError::InvalidOperation(format!(
641                    "CSR CN does not match node ID '{node_id}' (DNS-safe: '{dns_safe_node_id}')",
642                )));
643            }
644        }
645
646        let validity_days = 365; // 1-year validity
647
648        let node_certificate = self
649            .certificate_authority
650            .sign_certificate_request_with_serial(
651                &setup_token.csr_der,
652                validity_days,
653                Some(self.serial_counter),
654            )?;
655
656        // Increment serial for next issuance
657        self.serial_counter = self.serial_counter.wrapping_add(1);
658
659        // Store the issued certificate
660        self.issued_certificates
661            .insert(setup_token.node_id.clone(), node_certificate.clone());
662
663        // Create metadata
664        let metadata = CertificateMetadata {
665            issued_at: std::time::SystemTime::now()
666                .duration_since(std::time::UNIX_EPOCH)
667                .map_err(|e| KeyError::InvalidOperation(format!("System time error: {e}")))?
668                .as_secs(),
669            validity_days,
670            purpose: "Node TLS Certificate".to_string(),
671        };
672
673        // Create the message
674        Ok(NodeCertificateMessage {
675            node_certificate,
676            ca_certificate: self.certificate_authority.ca_certificate().clone(),
677            metadata,
678        })
679    }
680
681    // Removed create_node_certificate method - using proper CSR flow only
682    // This method was a workaround that violated the certificate security model
683
684    /// Get statistics about the mobile key manager
685    pub fn get_statistics(&self) -> MobileKeyManagerStatistics {
686        MobileKeyManagerStatistics {
687            issued_certificates_count: self.issued_certificates.len(),
688            user_profile_keys_count: self.user_profile_keys.len(),
689            network_keys_count: self.network_data_keys.len(),
690            ca_certificate_subject: self
691                .certificate_authority
692                .ca_certificate()
693                .subject()
694                .to_string(),
695        }
696    }
697
698    /// Create a network key message for a node with proper encryption
699    pub fn create_network_key_message(
700        &self,
701        network_id: &str,
702        node_agreement_public_key: &[u8],
703    ) -> Result<NetworkKeyMessage> {
704        let network_key = self.network_data_keys.get(network_id).ok_or_else(|| {
705            KeyError::KeyNotFound(format!(
706                "Network key pair not found for network: {network_id}"
707            ))
708        })?;
709
710        // Encrypt the raw 32-byte scalar for the node's agreement public key
711        let network_scalar = network_key.to_bytes().to_vec();
712        let encrypted_network_key =
713            self.encrypt_key_with_ecdsa(&network_scalar, node_agreement_public_key)?;
714
715        let node_id = compact_id(node_agreement_public_key);
716        log_info!(
717            self.logger,
718            "Network key encrypted for node {node_id} with ECIES"
719        );
720
721        Ok(NetworkKeyMessage {
722            network_id: network_id.to_string(),
723            network_public_key: network_key
724                .public_key()
725                .to_encoded_point(false)
726                .as_bytes()
727                .to_vec(),
728            encrypted_network_key,
729            key_derivation_info: format!("Network key for node {node_id} (ECIES encrypted)"),
730        })
731    }
732
733    /// Validate a certificate issued by this CA
734    pub fn validate_certificate(&self, certificate: &X509Certificate) -> Result<()> {
735        self.certificate_validator.validate_certificate(certificate)
736    }
737
738    /// Get issued certificate by node ID
739    pub fn get_issued_certificate(&self, node_id: &str) -> Option<&X509Certificate> {
740        self.issued_certificates.get(node_id)
741    }
742
743    /// List all issued certificates
744    pub fn list_issued_certificates(&self) -> Vec<(String, &X509Certificate)> {
745        self.issued_certificates
746            .iter()
747            .map(|(node_id, cert)| (node_id.clone(), cert))
748            .collect()
749    }
750
751    /// Encrypt data for a specific profile (legacy method for compatibility)
752    pub fn encrypt_for_profile(&self, data: &[u8], profile_id: &str) -> Result<Vec<u8>> {
753        let profile_key_pair = self.user_profile_keys.get(profile_id).ok_or_else(|| {
754            KeyError::KeyNotFound(format!(
755                "Profile public key not found for profile: {profile_id}"
756            ))
757        })?;
758        // Use envelope encryption with just this profile
759        let envelope_data = MobileKeyManager::encrypt_with_envelope(
760            self,
761            data,
762            None,
763            vec![profile_key_pair.public_key_bytes()],
764        )?;
765        // Return just the encrypted data for compatibility
766        Ok(envelope_data.encrypted_data)
767    }
768
769    /// Encrypt data for a network (legacy method for compatibility)  
770    pub fn encrypt_for_network(&self, data: &[u8], network_id: &str) -> Result<Vec<u8>> {
771        // Use envelope encryption with just this network
772        let envelope_data =
773            MobileKeyManager::encrypt_with_envelope(self, data, Some(network_id), vec![])?;
774        // Return just the encrypted data for compatibility
775        Ok(envelope_data.encrypted_data)
776    }
777
778    /// Generate a user profile key (legacy method name for compatibility)
779    pub fn generate_user_profile_key(&mut self, profile_id: &str) -> Result<Vec<u8>> {
780        self.derive_user_profile_key(profile_id)
781    }
782
783    /// Encrypt a message for a node using its public key (ECIES)
784    pub fn encrypt_message_for_node(
785        &self,
786        message: &[u8],
787        node_agreement_public_key: &[u8],
788    ) -> Result<Vec<u8>> {
789        let message_len = message.len();
790        log_debug!(
791            self.logger,
792            "Encrypting message for node ({message_len} bytes)"
793        );
794        self.encrypt_key_with_ecdsa(message, node_agreement_public_key)
795    }
796
797    /// Decrypt a message from a node using the user's root key (ECIES)
798    pub fn decrypt_message_from_node(&self, encrypted_message: &[u8]) -> Result<Vec<u8>> {
799        let encrypted_message_len = encrypted_message.len();
800        log_debug!(
801            self.logger,
802            "Decrypting message from node ({encrypted_message_len} bytes)"
803        );
804        let root_agreement = self.user_root_agreement.as_ref().ok_or_else(|| {
805            KeyError::KeyNotFound("User root agreement key not initialized".to_string())
806        })?;
807        self.decrypt_key_with_agreement(encrypted_message, root_agreement)
808    }
809
810    // ---------------------------------------------------------------------
811    // Persistence helpers
812    // ---------------------------------------------------------------------
813
814    /// Export all cryptographic material for persistence.
815    pub fn export_state(&self) -> MobileKeyManagerState {
816        MobileKeyManagerState {
817            ca_key_pair: self.certificate_authority.ca_key_pair().clone(),
818            ca_certificate: self.certificate_authority.ca_certificate().clone(),
819            user_root_key: self.user_root_key.clone(),
820            user_root_agreement: self
821                .user_root_agreement
822                .as_ref()
823                .map(|k| k.to_pkcs8_der().unwrap().as_bytes().to_vec()),
824            user_profile_keys: self.user_profile_keys.clone(),
825            user_profile_agreements: self
826                .user_profile_agreements
827                .iter()
828                .map(|(id, sk)| (id.clone(), sk.to_pkcs8_der().unwrap().as_bytes().to_vec()))
829                .collect(),
830            label_to_pid: self.label_to_pid.clone(),
831            network_data_keys: self
832                .network_data_keys
833                .iter()
834                .map(|(id, sk)| (id.clone(), sk.to_pkcs8_der().unwrap().as_bytes().to_vec()))
835                .collect(),
836            network_public_keys: self.network_public_keys.clone(),
837            issued_certificates: self.issued_certificates.clone(),
838            serial_counter: self.serial_counter,
839        }
840    }
841
842    /// Restore a MobileKeyManager from a previously exported state.
843    pub fn from_state(state: MobileKeyManagerState, logger: Arc<Logger>) -> Result<Self> {
844        let certificate_authority = CertificateAuthority::from_existing(
845            state.ca_key_pair.clone(),
846            state.ca_certificate.clone(),
847        );
848
849        let certificate_validator = CertificateValidator::new(vec![state.ca_certificate.clone()]);
850
851        log_info!(logger, "Mobile Key Manager state imported");
852
853        Ok(Self {
854            certificate_authority,
855            certificate_validator,
856            user_root_key: state.user_root_key,
857            user_root_agreement: state
858                .user_root_agreement
859                .and_then(|der| P256SecretKey::from_pkcs8_der(&der).ok()),
860            user_profile_keys: state.user_profile_keys,
861            user_profile_agreements: state
862                .user_profile_agreements
863                .into_iter()
864                .filter_map(|(id, der)| P256SecretKey::from_pkcs8_der(&der).ok().map(|k| (id, k)))
865                .collect(),
866            label_to_pid: state.label_to_pid,
867            network_data_keys: state
868                .network_data_keys
869                .into_iter()
870                .filter_map(|(id, der)| P256SecretKey::from_pkcs8_der(&der).ok().map(|k| (id, k)))
871                .collect(),
872            network_public_keys: state.network_public_keys,
873            issued_certificates: state.issued_certificates,
874            serial_counter: state.serial_counter,
875            logger,
876        })
877    }
878}
879
880impl crate::EnvelopeCrypto for MobileKeyManager {
881    fn encrypt_with_envelope(
882        &self,
883        data: &[u8],
884        network_id: Option<&str>,
885        profile_public_keys: Vec<Vec<u8>>,
886    ) -> crate::Result<crate::mobile::EnvelopeEncryptedData> {
887        MobileKeyManager::encrypt_with_envelope(self, data, network_id, profile_public_keys)
888    }
889
890    fn decrypt_envelope_data(
891        &self,
892        env: &crate::mobile::EnvelopeEncryptedData,
893    ) -> crate::Result<Vec<u8>> {
894        // Try profiles first
895        for pid in env.profile_encrypted_keys.keys() {
896            if let Ok(pt) = self.decrypt_with_profile(env, pid) {
897                return Ok(pt);
898            }
899        }
900        self.decrypt_with_network(env)
901    }
902}
903
904/// Statistics about the mobile key manager
905#[derive(Debug, Clone)]
906pub struct MobileKeyManagerStatistics {
907    pub issued_certificates_count: usize,
908    pub user_profile_keys_count: usize,
909    pub network_keys_count: usize,
910    pub ca_certificate_subject: String,
911}
912
913// Default implementation removed to avoid expect() call
914// Use MobileKeyManager::new(logger) instead for explicit error handling