1use crate::crypto::{algorithm_ids, CryptoRegistry, SignatureAlgorithm};
21use crate::error::{LicenseError, Result};
22use crate::hardware::{
23 default_hardware_environment, verify_hardware_binding, FixedHardwareEnvironment,
24 HardwareBindingError, HardwareEnvironment, HardwareInfo,
25};
26use crate::keys::parse_public_key;
27use crate::license::{LicenseFormat, SignedLicense, BINARY_MAGIC, BINARY_VERSION};
28use base64::{engine::general_purpose::STANDARD as BASE64, Engine};
29use chrono::Utc;
30use rsa::pkcs1v15::VerifyingKey;
31use rsa::signature::Verifier;
32use rsa::RsaPublicKey;
33use sha2::Sha256;
34use std::path::Path;
35use std::sync::Arc;
36
37#[derive(Clone)]
39pub struct LicenseVerifier {
40 public_key: RsaPublicKey,
41 hardware_env: Arc<dyn HardwareEnvironment>,
42}
43
44impl LicenseVerifier {
45 pub fn new(public_key: RsaPublicKey) -> Self {
47 Self {
48 public_key,
49 hardware_env: default_hardware_environment(),
50 }
51 }
52
53 pub fn from_pem(pem: &str) -> Result<Self> {
55 let public_key = parse_public_key(pem)?;
56 Ok(Self::new(public_key))
57 }
58
59 pub fn from_pem_file(path: &Path) -> Result<Self> {
61 let pem = std::fs::read_to_string(path)?;
62 Self::from_pem(&pem)
63 }
64
65 pub fn with_hardware_info(mut self, info: HardwareInfo) -> Self {
67 self.hardware_env = Arc::new(FixedHardwareEnvironment(info));
68 self
69 }
70
71 pub fn with_hardware_environment(mut self, env: Arc<dyn HardwareEnvironment>) -> Self {
73 self.hardware_env = env;
74 self
75 }
76
77 fn get_hardware_info(&self) -> HardwareInfo {
78 self.hardware_env.snapshot()
79 }
80
81 pub fn load_license(&self, path: &Path) -> Result<SignedLicense> {
83 let bytes = std::fs::read(path)?;
84 self.parse_license(&bytes)
85 }
86
87 pub fn parse_license(&self, data: &[u8]) -> Result<SignedLicense> {
89 let format = detect_license_format(data);
90
91 match format {
92 LicenseFormat::Binary => self.parse_binary_license(data),
93 LicenseFormat::Json => self.parse_json_license(data),
94 }
95 }
96
97 fn parse_binary_license(&self, data: &[u8]) -> Result<SignedLicense> {
99 if data.len() < 9 {
100 return Err(LicenseError::InvalidLicenseFormat(
101 "Binary license too short".into(),
102 ));
103 }
104
105 if &data[0..4] != BINARY_MAGIC {
107 return Err(LicenseError::InvalidLicenseFormat(
108 "Invalid magic header".into(),
109 ));
110 }
111
112 let version = data[4];
114 if version > BINARY_VERSION {
115 return Err(LicenseError::InvalidLicenseFormat(format!(
116 "Unsupported license version: {}",
117 version
118 )));
119 }
120
121 let len = u32::from_le_bytes([data[5], data[6], data[7], data[8]]) as usize;
123
124 if data.len() < 9 + len {
125 return Err(LicenseError::InvalidLicenseFormat(
126 "Binary license data truncated".into(),
127 ));
128 }
129
130 serde_json::from_slice(&data[9..9 + len])
132 .map_err(|e| LicenseError::InvalidLicenseFormat(e.to_string()))
133 }
134
135 fn parse_json_license(&self, data: &[u8]) -> Result<SignedLicense> {
137 serde_json::from_slice(data).map_err(|e| LicenseError::InvalidLicenseFormat(e.to_string()))
138 }
139
140 pub fn verify_signature(&self, license: &SignedLicense) -> Result<()> {
142 let data_bytes = serde_json::to_vec(&license.data)
144 .map_err(|e| LicenseError::SerializationError(e.to_string()))?;
145
146 let signature_bytes = BASE64.decode(&license.signature).map_err(|e| {
148 LicenseError::InvalidLicenseFormat(format!("Invalid signature encoding: {}", e))
149 })?;
150
151 let verifying_key = VerifyingKey::<Sha256>::new(self.public_key.clone());
153
154 let signature =
156 rsa::pkcs1v15::Signature::try_from(signature_bytes.as_slice()).map_err(|e| {
157 LicenseError::VerificationFailed(format!("Invalid signature format: {}", e))
158 })?;
159
160 verifying_key.verify(&data_bytes, &signature).map_err(|e| {
162 LicenseError::VerificationFailed(format!("Signature verification failed: {}", e))
163 })
164 }
165
166 pub fn verify_expiration(&self, license: &SignedLicense) -> Result<()> {
168 let now = Utc::now();
169
170 if now < license.data.valid_from {
171 return Err(LicenseError::NotYetValid(
172 license
173 .data
174 .valid_from
175 .format("%Y-%m-%d %H:%M:%S UTC")
176 .to_string(),
177 ));
178 }
179
180 if now > license.data.valid_until {
181 return Err(LicenseError::LicenseExpired(
182 license
183 .data
184 .valid_until
185 .format("%Y-%m-%d %H:%M:%S UTC")
186 .to_string(),
187 ));
188 }
189
190 Ok(())
191 }
192
193 pub fn verify_hardware(&self, license: &SignedLicense) -> Result<()> {
195 let hardware = self.get_hardware_info();
196
197 verify_hardware_binding(&license.data.hardware_binding, &hardware).map_err(|e| {
198 tracing::debug!("Hardware binding check failed: {}", e);
199 match e {
200 HardwareBindingError::MacAddressMismatch { .. } => {
201 LicenseError::HardwareBindingMismatch {
202 field: "mac_address".to_string(),
203 }
204 }
205 HardwareBindingError::HostnameMismatch { .. } => {
206 LicenseError::HardwareBindingMismatch {
207 field: "hostname".to_string(),
208 }
209 }
210 HardwareBindingError::DiskIdMismatch { .. } => {
211 LicenseError::HardwareBindingMismatch {
212 field: "disk_id".to_string(),
213 }
214 }
215 HardwareBindingError::CustomMismatch { key, .. } => {
216 LicenseError::HardwareBindingMismatch { field: key }
217 }
218 }
219 })
220 }
221
222 pub fn validate(&self, license: &SignedLicense) -> Result<()> {
229 self.verify_signature(license)?;
230 self.verify_expiration(license)?;
231 self.verify_hardware(license)?;
232 Ok(())
233 }
234
235 pub fn load_and_validate(&self, path: &Path) -> Result<SignedLicense> {
237 let license = self.load_license(path)?;
238 self.validate(&license)?;
239 Ok(license)
240 }
241}
242
243pub fn detect_license_format(data: &[u8]) -> LicenseFormat {
245 if data.len() >= 4 && &data[0..4] == BINARY_MAGIC {
246 LicenseFormat::Binary
247 } else {
248 LicenseFormat::Json
249 }
250}
251
252#[derive(Debug, Clone)]
254pub struct ValidationResult {
255 pub is_valid: bool,
257
258 pub signature_valid: bool,
260
261 pub expiration_valid: bool,
263
264 pub hardware_valid: bool,
266
267 pub days_remaining: i64,
269
270 pub error: Option<String>,
272}
273
274impl LicenseVerifier {
275 pub fn validate_detailed(&self, license: &SignedLicense) -> ValidationResult {
277 let mut result = ValidationResult {
278 is_valid: false,
279 signature_valid: false,
280 expiration_valid: false,
281 hardware_valid: false,
282 days_remaining: license.data.days_remaining(),
283 error: None,
284 };
285
286 match self.verify_signature(license) {
288 Ok(_) => result.signature_valid = true,
289 Err(e) => {
290 result.error = Some(e.to_string());
291 return result;
292 }
293 }
294
295 match self.verify_expiration(license) {
297 Ok(_) => result.expiration_valid = true,
298 Err(e) => {
299 result.error = Some(e.to_string());
300 return result;
301 }
302 }
303
304 match self.verify_hardware(license) {
306 Ok(_) => result.hardware_valid = true,
307 Err(e) => {
308 result.error = Some(e.to_string());
309 return result;
310 }
311 }
312
313 result.is_valid = true;
314 result
315 }
316}
317
318#[derive(Clone)]
339pub struct CryptoVerifier {
340 public_keys: std::collections::HashMap<String, String>,
342 hardware_env: Arc<dyn HardwareEnvironment>,
343}
344
345impl CryptoVerifier {
346 pub fn new(public_keys: std::collections::HashMap<String, String>) -> Self {
351 Self {
352 public_keys,
353 hardware_env: default_hardware_environment(),
354 }
355 }
356
357 pub fn from_pem(pem: &str) -> Result<Self> {
362 let mut keys = std::collections::HashMap::new();
363
364 if parse_public_key(pem).is_ok() {
366 keys.insert(algorithm_ids::RSA_SHA256.to_string(), pem.to_string());
367 return Ok(Self::new(keys));
368 }
369
370 let ed25519_signer = crate::crypto::ed25519::Ed25519Signer::new();
373 let verify_result: Result<()> = ed25519_signer.verify(b"test", &[0u8; 64], pem);
374
375 match verify_result {
378 Ok(()) => {
379 keys.insert(algorithm_ids::ED25519.to_string(), pem.to_string());
381 return Ok(Self::new(keys));
382 }
383 Err(e) => {
384 let err_str = e.to_string();
385 if err_str.contains("verification failed")
386 || err_str.contains("Signature verification failed")
387 {
388 keys.insert(algorithm_ids::ED25519.to_string(), pem.to_string());
390 return Ok(Self::new(keys));
391 }
392 }
394 }
395
396 let pem_normalized = pem.replace("\\n", "\n");
398 if pem_normalized.contains("PUBLIC KEY") {
399 keys.insert(algorithm_ids::RSA_SHA256.to_string(), pem.to_string());
400 return Ok(Self::new(keys));
401 }
402
403 Err(LicenseError::InvalidKeyFormat(
404 "Could not determine public key type".into(),
405 ))
406 }
407
408 pub fn from_pem_file(path: &Path) -> Result<Self> {
410 let pem = std::fs::read_to_string(path)?;
411 Self::from_pem(&pem)
412 }
413
414 pub fn with_public_key(mut self, algorithm_id: &str, pem: &str) -> Self {
416 self.public_keys
417 .insert(algorithm_id.to_string(), pem.to_string());
418 self
419 }
420
421 pub fn with_hardware_info(mut self, info: HardwareInfo) -> Self {
423 self.hardware_env = Arc::new(FixedHardwareEnvironment(info));
424 self
425 }
426
427 pub fn with_hardware_environment(mut self, env: Arc<dyn HardwareEnvironment>) -> Self {
429 self.hardware_env = env;
430 self
431 }
432
433 fn get_hardware_info(&self) -> HardwareInfo {
434 self.hardware_env.snapshot()
435 }
436
437 fn get_public_key(&self, algorithm_id: &str) -> Result<&str> {
439 self.public_keys
440 .get(algorithm_id)
441 .map(|s| s.as_str())
442 .ok_or_else(|| {
443 LicenseError::InvalidKeyFormat(format!(
444 "No public key configured for algorithm: {}",
445 algorithm_id
446 ))
447 })
448 }
449
450 pub fn load_license(&self, path: &Path) -> Result<SignedLicense> {
452 let bytes = std::fs::read(path)?;
453 self.parse_license(&bytes)
454 }
455
456 pub fn parse_license(&self, data: &[u8]) -> Result<SignedLicense> {
458 let format = detect_license_format(data);
459
460 match format {
461 LicenseFormat::Binary => self.parse_binary_license(data),
462 LicenseFormat::Json => self.parse_json_license(data),
463 }
464 }
465
466 fn parse_binary_license(&self, data: &[u8]) -> Result<SignedLicense> {
468 if data.len() < 9 {
469 return Err(LicenseError::InvalidLicenseFormat(
470 "Binary license too short".into(),
471 ));
472 }
473
474 if &data[0..4] != BINARY_MAGIC {
476 return Err(LicenseError::InvalidLicenseFormat(
477 "Invalid magic header".into(),
478 ));
479 }
480
481 let version = data[4];
483 if version > BINARY_VERSION {
484 return Err(LicenseError::InvalidLicenseFormat(format!(
485 "Unsupported license version: {}",
486 version
487 )));
488 }
489
490 let len = u32::from_le_bytes([data[5], data[6], data[7], data[8]]) as usize;
492
493 if data.len() < 9 + len {
494 return Err(LicenseError::InvalidLicenseFormat(
495 "Binary license data truncated".into(),
496 ));
497 }
498
499 serde_json::from_slice(&data[9..9 + len])
501 .map_err(|e| LicenseError::InvalidLicenseFormat(e.to_string()))
502 }
503
504 fn parse_json_license(&self, data: &[u8]) -> Result<SignedLicense> {
506 serde_json::from_slice(data).map_err(|e| LicenseError::InvalidLicenseFormat(e.to_string()))
507 }
508
509 pub fn verify_signature(&self, license: &SignedLicense) -> Result<()> {
513 let data_bytes = serde_json::to_vec(&license.data)
515 .map_err(|e| LicenseError::SerializationError(e.to_string()))?;
516
517 let signature_bytes = BASE64.decode(&license.signature).map_err(|e| {
519 LicenseError::InvalidLicenseFormat(format!("Invalid signature encoding: {}", e))
520 })?;
521
522 let algorithm = CryptoRegistry::get_signature_algorithm(&license.algorithm)?;
524 let public_key_pem = self.get_public_key(&license.algorithm)?;
525
526 algorithm.verify(&data_bytes, &signature_bytes, public_key_pem)
528 }
529
530 pub fn verify_expiration(&self, license: &SignedLicense) -> Result<()> {
532 let now = Utc::now();
533
534 if now < license.data.valid_from {
535 return Err(LicenseError::NotYetValid(
536 license
537 .data
538 .valid_from
539 .format("%Y-%m-%d %H:%M:%S UTC")
540 .to_string(),
541 ));
542 }
543
544 if now > license.data.valid_until {
545 return Err(LicenseError::LicenseExpired(
546 license
547 .data
548 .valid_until
549 .format("%Y-%m-%d %H:%M:%S UTC")
550 .to_string(),
551 ));
552 }
553
554 Ok(())
555 }
556
557 pub fn verify_hardware(&self, license: &SignedLicense) -> Result<()> {
559 let hardware = self.get_hardware_info();
560
561 verify_hardware_binding(&license.data.hardware_binding, &hardware).map_err(|e| {
562 tracing::debug!("Hardware binding check failed: {}", e);
563 match e {
564 HardwareBindingError::MacAddressMismatch { .. } => {
565 LicenseError::HardwareBindingMismatch {
566 field: "mac_address".to_string(),
567 }
568 }
569 HardwareBindingError::HostnameMismatch { .. } => {
570 LicenseError::HardwareBindingMismatch {
571 field: "hostname".to_string(),
572 }
573 }
574 HardwareBindingError::DiskIdMismatch { .. } => {
575 LicenseError::HardwareBindingMismatch {
576 field: "disk_id".to_string(),
577 }
578 }
579 HardwareBindingError::CustomMismatch { key, .. } => {
580 LicenseError::HardwareBindingMismatch { field: key }
581 }
582 }
583 })
584 }
585
586 pub fn validate(&self, license: &SignedLicense) -> Result<()> {
593 self.verify_signature(license)?;
594 self.verify_expiration(license)?;
595 self.verify_hardware(license)?;
596 Ok(())
597 }
598
599 pub fn load_and_validate(&self, path: &Path) -> Result<SignedLicense> {
601 let license = self.load_license(path)?;
602 self.validate(&license)?;
603 Ok(license)
604 }
605
606 pub fn validate_detailed(&self, license: &SignedLicense) -> ValidationResult {
608 let mut result = ValidationResult {
609 is_valid: false,
610 signature_valid: false,
611 expiration_valid: false,
612 hardware_valid: false,
613 days_remaining: license.data.days_remaining(),
614 error: None,
615 };
616
617 match self.verify_signature(license) {
619 Ok(_) => result.signature_valid = true,
620 Err(e) => {
621 result.error = Some(e.to_string());
622 return result;
623 }
624 }
625
626 match self.verify_expiration(license) {
628 Ok(_) => result.expiration_valid = true,
629 Err(e) => {
630 result.error = Some(e.to_string());
631 return result;
632 }
633 }
634
635 match self.verify_hardware(license) {
637 Ok(_) => result.hardware_valid = true,
638 Err(e) => {
639 result.error = Some(e.to_string());
640 return result;
641 }
642 }
643
644 result.is_valid = true;
645 result
646 }
647}
648
649#[cfg(test)]
650mod tests {
651 use super::*;
652 use crate::generator::LicenseGenerator;
653 use crate::keys::{KeyPair, KeySize};
654 use crate::license::LicenseData;
655
656 fn create_test_keypair() -> KeyPair {
657 KeyPair::generate(KeySize::Bits2048).unwrap()
658 }
659
660 #[test]
661 fn test_license_verification() {
662 let keypair = create_test_keypair();
663 let generator = LicenseGenerator::new(keypair.private_key().clone());
664 let verifier = LicenseVerifier::new(keypair.public_key);
665
666 let data = LicenseData::builder()
667 .id("TEST-001")
668 .serial("SN-12345")
669 .customer_id("CUST-001")
670 .product_id("PROD-001")
671 .valid_days(365)
672 .build()
673 .unwrap();
674
675 let signed = generator.generate(data).unwrap();
676
677 assert!(verifier.verify_signature(&signed).is_ok());
678 assert!(verifier.verify_expiration(&signed).is_ok());
679 assert!(verifier.validate(&signed).is_ok());
680 }
681
682 #[test]
683 fn test_binary_round_trip() {
684 let keypair = create_test_keypair();
685 let generator = LicenseGenerator::new(keypair.private_key().clone());
686 let verifier = LicenseVerifier::new(keypair.public_key);
687
688 let data = LicenseData::builder()
689 .id("TEST-001")
690 .serial("SN-12345")
691 .customer_id("CUST-001")
692 .product_id("PROD-001")
693 .valid_days(365)
694 .feature("basic")
695 .feature("premium")
696 .build()
697 .unwrap();
698
699 let signed = generator.generate(data).unwrap();
700 let binary = generator.export_binary(&signed).unwrap();
701
702 let parsed = verifier.parse_license(&binary).unwrap();
703
704 assert_eq!(parsed.data.id, signed.data.id);
705 assert_eq!(parsed.data.serial, signed.data.serial);
706 assert_eq!(parsed.data.features.len(), 2);
707 }
708
709 #[test]
710 fn test_json_round_trip() {
711 let keypair = create_test_keypair();
712 let generator = LicenseGenerator::new(keypair.private_key().clone());
713 let verifier = LicenseVerifier::new(keypair.public_key);
714
715 let data = LicenseData::builder()
716 .id("TEST-001")
717 .serial("SN-12345")
718 .customer_id("CUST-001")
719 .product_id("PROD-001")
720 .valid_days(365)
721 .build()
722 .unwrap();
723
724 let signed = generator.generate(data).unwrap();
725 let json = generator.export_json(&signed).unwrap();
726
727 let parsed = verifier.parse_license(json.as_bytes()).unwrap();
728
729 assert_eq!(parsed.data.id, signed.data.id);
730 assert!(verifier.validate(&parsed).is_ok());
731 }
732
733 #[test]
736 fn test_crypto_verifier_rsa() {
737 use crate::generator::CryptoGenerator;
738 use crate::keys::CryptoKeyPair;
739
740 let keypair = CryptoKeyPair::generate(algorithm_ids::RSA_SHA256).unwrap();
741 let generator = CryptoGenerator::from_keypair(&keypair);
742
743 let mut keys = std::collections::HashMap::new();
744 keys.insert(
745 algorithm_ids::RSA_SHA256.to_string(),
746 keypair.public_key_pem.clone(),
747 );
748 let verifier = CryptoVerifier::new(keys);
749
750 let data = LicenseData::builder()
751 .id("CRYPTO-RSA-001")
752 .serial("SN-CRYPTO-RSA")
753 .customer_id("CUST-001")
754 .product_id("PROD-001")
755 .valid_days(365)
756 .build()
757 .unwrap();
758
759 let signed = generator.generate(data).unwrap();
760 assert_eq!(signed.algorithm, algorithm_ids::RSA_SHA256);
761
762 assert!(verifier.verify_signature(&signed).is_ok());
763 assert!(verifier.verify_expiration(&signed).is_ok());
764 assert!(verifier.validate(&signed).is_ok());
765 }
766
767 #[test]
768 fn test_crypto_verifier_ed25519() {
769 use crate::generator::CryptoGenerator;
770 use crate::keys::CryptoKeyPair;
771
772 let keypair = CryptoKeyPair::generate(algorithm_ids::ED25519).unwrap();
773 let generator = CryptoGenerator::from_keypair(&keypair);
774
775 let mut keys = std::collections::HashMap::new();
776 keys.insert(
777 algorithm_ids::ED25519.to_string(),
778 keypair.public_key_pem.clone(),
779 );
780 let verifier = CryptoVerifier::new(keys);
781
782 let data = LicenseData::builder()
783 .id("CRYPTO-ED25519-001")
784 .serial("SN-CRYPTO-ED25519")
785 .customer_id("CUST-001")
786 .product_id("PROD-001")
787 .valid_days(365)
788 .build()
789 .unwrap();
790
791 let signed = generator.generate(data).unwrap();
792 assert_eq!(signed.algorithm, algorithm_ids::ED25519);
793
794 assert!(verifier.verify_signature(&signed).is_ok());
795 assert!(verifier.verify_expiration(&signed).is_ok());
796 assert!(verifier.validate(&signed).is_ok());
797 }
798
799 #[test]
800 fn test_crypto_verifier_multi_algorithm() {
801 use crate::generator::CryptoGenerator;
802 use crate::keys::CryptoKeyPair;
803
804 let rsa_keypair = CryptoKeyPair::generate(algorithm_ids::RSA_SHA256).unwrap();
806 let ed25519_keypair = CryptoKeyPair::generate(algorithm_ids::ED25519).unwrap();
807
808 let rsa_generator = CryptoGenerator::from_keypair(&rsa_keypair);
810 let ed25519_generator = CryptoGenerator::from_keypair(&ed25519_keypair);
811
812 let mut keys = std::collections::HashMap::new();
814 keys.insert(
815 algorithm_ids::RSA_SHA256.to_string(),
816 rsa_keypair.public_key_pem.clone(),
817 );
818 keys.insert(
819 algorithm_ids::ED25519.to_string(),
820 ed25519_keypair.public_key_pem.clone(),
821 );
822 let verifier = CryptoVerifier::new(keys);
823
824 let rsa_data = LicenseData::builder()
826 .id("MULTI-RSA-001")
827 .serial("SN-MULTI-RSA")
828 .customer_id("CUST-001")
829 .product_id("PROD-001")
830 .valid_days(365)
831 .build()
832 .unwrap();
833 let rsa_license = rsa_generator.generate(rsa_data).unwrap();
834
835 let ed25519_data = LicenseData::builder()
837 .id("MULTI-ED25519-001")
838 .serial("SN-MULTI-ED25519")
839 .customer_id("CUST-001")
840 .product_id("PROD-001")
841 .valid_days(365)
842 .build()
843 .unwrap();
844 let ed25519_license = ed25519_generator.generate(ed25519_data).unwrap();
845
846 assert!(verifier.validate(&rsa_license).is_ok());
848 assert!(verifier.validate(&ed25519_license).is_ok());
849
850 assert_eq!(rsa_license.algorithm, algorithm_ids::RSA_SHA256);
852 assert_eq!(ed25519_license.algorithm, algorithm_ids::ED25519);
853 }
854
855 #[test]
856 fn test_crypto_verifier_binary_round_trip() {
857 use crate::generator::CryptoGenerator;
858 use crate::keys::CryptoKeyPair;
859
860 let keypair = CryptoKeyPair::generate(algorithm_ids::ED25519).unwrap();
861 let generator = CryptoGenerator::from_keypair(&keypair);
862
863 let mut keys = std::collections::HashMap::new();
864 keys.insert(
865 algorithm_ids::ED25519.to_string(),
866 keypair.public_key_pem.clone(),
867 );
868 let verifier = CryptoVerifier::new(keys);
869
870 let data = LicenseData::builder()
871 .id("BINARY-ED25519-001")
872 .serial("SN-BINARY-ED25519")
873 .customer_id("CUST-001")
874 .product_id("PROD-001")
875 .valid_days(365)
876 .feature("basic")
877 .feature("premium")
878 .build()
879 .unwrap();
880
881 let signed = generator.generate(data).unwrap();
882 let binary = generator.export_binary(&signed).unwrap();
883
884 let parsed = verifier.parse_license(&binary).unwrap();
885
886 assert_eq!(parsed.data.id, signed.data.id);
887 assert_eq!(parsed.data.serial, signed.data.serial);
888 assert_eq!(parsed.data.features.len(), 2);
889 assert_eq!(parsed.algorithm, algorithm_ids::ED25519);
890 assert!(verifier.validate(&parsed).is_ok());
891 }
892
893 #[test]
894 fn test_crypto_verifier_wrong_key() {
895 use crate::generator::CryptoGenerator;
896 use crate::keys::CryptoKeyPair;
897
898 let keypair = CryptoKeyPair::generate(algorithm_ids::ED25519).unwrap();
899 let wrong_keypair = CryptoKeyPair::generate(algorithm_ids::ED25519).unwrap();
900
901 let generator = CryptoGenerator::from_keypair(&keypair);
902
903 let mut keys = std::collections::HashMap::new();
905 keys.insert(
906 algorithm_ids::ED25519.to_string(),
907 wrong_keypair.public_key_pem.clone(),
908 );
909 let verifier = CryptoVerifier::new(keys);
910
911 let data = LicenseData::builder()
912 .id("WRONG-KEY-001")
913 .serial("SN-WRONG-KEY")
914 .customer_id("CUST-001")
915 .product_id("PROD-001")
916 .valid_days(365)
917 .build()
918 .unwrap();
919
920 let signed = generator.generate(data).unwrap();
921
922 assert!(verifier.verify_signature(&signed).is_err());
924 assert!(verifier.validate(&signed).is_err());
925 }
926
927 #[test]
928 fn test_crypto_verifier_missing_algorithm_key() {
929 use crate::generator::CryptoGenerator;
930 use crate::keys::CryptoKeyPair;
931
932 let keypair = CryptoKeyPair::generate(algorithm_ids::ED25519).unwrap();
933 let generator = CryptoGenerator::from_keypair(&keypair);
934
935 let rsa_keypair = CryptoKeyPair::generate(algorithm_ids::RSA_SHA256).unwrap();
937 let mut keys = std::collections::HashMap::new();
938 keys.insert(
939 algorithm_ids::RSA_SHA256.to_string(),
940 rsa_keypair.public_key_pem.clone(),
941 );
942 let verifier = CryptoVerifier::new(keys);
943
944 let data = LicenseData::builder()
945 .id("MISSING-ALG-001")
946 .serial("SN-MISSING-ALG")
947 .customer_id("CUST-001")
948 .product_id("PROD-001")
949 .valid_days(365)
950 .build()
951 .unwrap();
952
953 let signed = generator.generate(data).unwrap();
954
955 let result = verifier.verify_signature(&signed);
957 assert!(result.is_err());
958 assert!(result
959 .unwrap_err()
960 .to_string()
961 .contains("No public key configured"));
962 }
963
964 #[test]
965 fn test_crypto_verifier_detailed_validation() {
966 use crate::generator::CryptoGenerator;
967 use crate::keys::CryptoKeyPair;
968
969 let keypair = CryptoKeyPair::generate(algorithm_ids::ED25519).unwrap();
970 let generator = CryptoGenerator::from_keypair(&keypair);
971
972 let mut keys = std::collections::HashMap::new();
973 keys.insert(
974 algorithm_ids::ED25519.to_string(),
975 keypair.public_key_pem.clone(),
976 );
977 let verifier = CryptoVerifier::new(keys);
978
979 let data = LicenseData::builder()
980 .id("DETAILED-001")
981 .serial("SN-DETAILED")
982 .customer_id("CUST-001")
983 .product_id("PROD-001")
984 .valid_days(365)
985 .build()
986 .unwrap();
987
988 let signed = generator.generate(data).unwrap();
989
990 let result = verifier.validate_detailed(&signed);
991
992 assert!(result.is_valid);
993 assert!(result.signature_valid);
994 assert!(result.expiration_valid);
995 assert!(result.hardware_valid);
996 assert!(result.days_remaining > 0);
997 assert!(result.error.is_none());
998 }
999
1000 #[cfg(feature = "post-quantum")]
1002 mod pq_tests {
1003 use super::*;
1004 use crate::crypto::algorithm_ids;
1005 use crate::generator::CryptoGenerator;
1006 use crate::keys::CryptoKeyPair;
1007
1008 #[test]
1009 fn test_crypto_verifier_ml_dsa_65() {
1010 let keypair = CryptoKeyPair::generate(algorithm_ids::ML_DSA_65).unwrap();
1011 let generator = CryptoGenerator::from_keypair(&keypair);
1012
1013 let mut keys = std::collections::HashMap::new();
1014 keys.insert(
1015 algorithm_ids::ML_DSA_65.to_string(),
1016 keypair.public_key_pem.clone(),
1017 );
1018 let verifier = CryptoVerifier::new(keys);
1019
1020 let data = LicenseData::builder()
1021 .id("PQ-VERIFY-001")
1022 .serial("SN-PQ-VERIFY")
1023 .customer_id("CUST-001")
1024 .product_id("PROD-001")
1025 .valid_days(365)
1026 .feature("quantum-safe")
1027 .build()
1028 .unwrap();
1029
1030 let signed = generator.generate(data).unwrap();
1031 assert_eq!(signed.algorithm, algorithm_ids::ML_DSA_65);
1032
1033 assert!(verifier.verify_signature(&signed).is_ok());
1034 assert!(verifier.verify_expiration(&signed).is_ok());
1035 assert!(verifier.validate(&signed).is_ok());
1036 }
1037
1038 #[test]
1039 fn test_crypto_verifier_hybrid_ed25519_ml_dsa() {
1040 let keypair = CryptoKeyPair::generate(algorithm_ids::HYBRID_ED25519_ML_DSA_65).unwrap();
1041 let generator = CryptoGenerator::from_keypair(&keypair);
1042
1043 let mut keys = std::collections::HashMap::new();
1044 keys.insert(
1045 algorithm_ids::HYBRID_ED25519_ML_DSA_65.to_string(),
1046 keypair.public_key_pem.clone(),
1047 );
1048 let verifier = CryptoVerifier::new(keys);
1049
1050 let data = LicenseData::builder()
1051 .id("PQ-HYBRID-VERIFY-001")
1052 .serial("SN-PQ-HYBRID-VERIFY")
1053 .customer_id("CUST-001")
1054 .product_id("PROD-001")
1055 .valid_days(365)
1056 .feature("hybrid-security")
1057 .build()
1058 .unwrap();
1059
1060 let signed = generator.generate(data).unwrap();
1061 assert_eq!(signed.algorithm, algorithm_ids::HYBRID_ED25519_ML_DSA_65);
1062
1063 assert!(verifier.verify_signature(&signed).is_ok());
1064 assert!(verifier.validate(&signed).is_ok());
1065 }
1066
1067 #[test]
1068 fn test_crypto_verifier_hybrid_rsa_ml_dsa() {
1069 let keypair = CryptoKeyPair::generate(algorithm_ids::HYBRID_RSA_ML_DSA_65).unwrap();
1070 let generator = CryptoGenerator::from_keypair(&keypair);
1071
1072 let mut keys = std::collections::HashMap::new();
1073 keys.insert(
1074 algorithm_ids::HYBRID_RSA_ML_DSA_65.to_string(),
1075 keypair.public_key_pem.clone(),
1076 );
1077 let verifier = CryptoVerifier::new(keys);
1078
1079 let data = LicenseData::builder()
1080 .id("PQ-HYBRID-RSA-VERIFY-001")
1081 .serial("SN-PQ-HYBRID-RSA-VERIFY")
1082 .customer_id("CUST-001")
1083 .product_id("PROD-001")
1084 .valid_days(365)
1085 .build()
1086 .unwrap();
1087
1088 let signed = generator.generate(data).unwrap();
1089 assert_eq!(signed.algorithm, algorithm_ids::HYBRID_RSA_ML_DSA_65);
1090
1091 assert!(verifier.verify_signature(&signed).is_ok());
1092 assert!(verifier.validate(&signed).is_ok());
1093 }
1094
1095 #[test]
1096 fn test_pq_verifier_binary_round_trip() {
1097 let keypair = CryptoKeyPair::generate(algorithm_ids::ML_DSA_65).unwrap();
1098 let generator = CryptoGenerator::from_keypair(&keypair);
1099
1100 let mut keys = std::collections::HashMap::new();
1101 keys.insert(
1102 algorithm_ids::ML_DSA_65.to_string(),
1103 keypair.public_key_pem.clone(),
1104 );
1105 let verifier = CryptoVerifier::new(keys);
1106
1107 let data = LicenseData::builder()
1108 .id("PQ-BINARY-VERIFY-001")
1109 .serial("SN-PQ-BINARY-VERIFY")
1110 .customer_id("CUST-001")
1111 .product_id("PROD-001")
1112 .valid_days(365)
1113 .feature("quantum-safe")
1114 .feature("binary-format")
1115 .build()
1116 .unwrap();
1117
1118 let signed = generator.generate(data).unwrap();
1119 let binary = generator.export_binary(&signed).unwrap();
1120
1121 let parsed = verifier.parse_license(&binary).unwrap();
1122
1123 assert_eq!(parsed.data.id, signed.data.id);
1124 assert_eq!(parsed.algorithm, algorithm_ids::ML_DSA_65);
1125 assert!(verifier.validate(&parsed).is_ok());
1126 }
1127
1128 #[test]
1129 fn test_pq_verifier_wrong_key() {
1130 let keypair = CryptoKeyPair::generate(algorithm_ids::ML_DSA_65).unwrap();
1131 let wrong_keypair = CryptoKeyPair::generate(algorithm_ids::ML_DSA_65).unwrap();
1132
1133 let generator = CryptoGenerator::from_keypair(&keypair);
1134
1135 let mut keys = std::collections::HashMap::new();
1137 keys.insert(
1138 algorithm_ids::ML_DSA_65.to_string(),
1139 wrong_keypair.public_key_pem.clone(),
1140 );
1141 let verifier = CryptoVerifier::new(keys);
1142
1143 let data = LicenseData::builder()
1144 .id("PQ-WRONG-KEY-001")
1145 .serial("SN-PQ-WRONG-KEY")
1146 .customer_id("CUST-001")
1147 .product_id("PROD-001")
1148 .valid_days(365)
1149 .build()
1150 .unwrap();
1151
1152 let signed = generator.generate(data).unwrap();
1153
1154 assert!(verifier.verify_signature(&signed).is_err());
1156 }
1157
1158 #[test]
1159 fn test_pq_verifier_multi_algorithm() {
1160 let rsa_keypair = CryptoKeyPair::generate(algorithm_ids::RSA_SHA256).unwrap();
1162 let ed25519_keypair = CryptoKeyPair::generate(algorithm_ids::ED25519).unwrap();
1163 let ml_dsa_keypair = CryptoKeyPair::generate(algorithm_ids::ML_DSA_65).unwrap();
1164 let hybrid_keypair =
1165 CryptoKeyPair::generate(algorithm_ids::HYBRID_ED25519_ML_DSA_65).unwrap();
1166
1167 let mut keys = std::collections::HashMap::new();
1169 keys.insert(
1170 algorithm_ids::RSA_SHA256.to_string(),
1171 rsa_keypair.public_key_pem.clone(),
1172 );
1173 keys.insert(
1174 algorithm_ids::ED25519.to_string(),
1175 ed25519_keypair.public_key_pem.clone(),
1176 );
1177 keys.insert(
1178 algorithm_ids::ML_DSA_65.to_string(),
1179 ml_dsa_keypair.public_key_pem.clone(),
1180 );
1181 keys.insert(
1182 algorithm_ids::HYBRID_ED25519_ML_DSA_65.to_string(),
1183 hybrid_keypair.public_key_pem.clone(),
1184 );
1185 let verifier = CryptoVerifier::new(keys);
1186
1187 for (keypair, alg_name) in [
1189 (&rsa_keypair, "RSA"),
1190 (&ed25519_keypair, "Ed25519"),
1191 (&ml_dsa_keypair, "ML-DSA-65"),
1192 (&hybrid_keypair, "Hybrid"),
1193 ] {
1194 let generator = CryptoGenerator::from_keypair(keypair);
1195 let data = LicenseData::builder()
1196 .id(format!("MULTI-{}-001", alg_name))
1197 .serial(format!("SN-MULTI-{}", alg_name))
1198 .customer_id("CUST-001")
1199 .product_id("PROD-001")
1200 .valid_days(365)
1201 .build()
1202 .unwrap();
1203
1204 let signed = generator.generate(data).unwrap();
1205 assert!(
1206 verifier.validate(&signed).is_ok(),
1207 "Failed to verify {} license",
1208 alg_name
1209 );
1210 }
1211 }
1212
1213 #[test]
1214 fn test_pq_verifier_detailed_validation() {
1215 let keypair = CryptoKeyPair::generate(algorithm_ids::HYBRID_ED25519_ML_DSA_65).unwrap();
1216 let generator = CryptoGenerator::from_keypair(&keypair);
1217
1218 let mut keys = std::collections::HashMap::new();
1219 keys.insert(
1220 algorithm_ids::HYBRID_ED25519_ML_DSA_65.to_string(),
1221 keypair.public_key_pem.clone(),
1222 );
1223 let verifier = CryptoVerifier::new(keys);
1224
1225 let data = LicenseData::builder()
1226 .id("PQ-DETAILED-001")
1227 .serial("SN-PQ-DETAILED")
1228 .customer_id("CUST-001")
1229 .product_id("PROD-001")
1230 .valid_days(365)
1231 .build()
1232 .unwrap();
1233
1234 let signed = generator.generate(data).unwrap();
1235 let result = verifier.validate_detailed(&signed);
1236
1237 assert!(result.is_valid);
1238 assert!(result.signature_valid);
1239 assert!(result.expiration_valid);
1240 assert!(result.hardware_valid);
1241 assert!(result.days_remaining > 0);
1242 assert!(result.error.is_none());
1243 }
1244 }
1245}