pub mod anti_tamper;
pub mod container;
pub mod crypto;
pub mod encrypted_store;
pub mod error;
pub mod generator;
pub mod guard;
pub mod hardware;
pub mod keys;
pub mod license;
pub mod sneakernet;
pub mod state_manager;
pub mod support_bundle;
pub mod unlock;
pub mod verifier;
pub mod witness;
#[cfg(feature = "online-check")]
pub mod online_check;
pub use anti_tamper::{
ClockStatus, HardwareFingerprint, LicenseState, MatchResult, STATE_HMAC_PREFIX,
};
pub use container::{ContainerBinding, InstanceIdSource, RuntimeEnvironment};
pub use encrypted_store::{
validate_passphrase, EncryptedKeyStore, ENCRYPTED_STORE_VERSION, MIN_PASSPHRASE_LENGTH,
};
pub use error::{LicenseError, Result};
pub use generator::{CryptoGenerator, LicenseGenerator};
pub use guard::{
require_license, require_license_with_verifier, validate_license_bytes, ValidatedLicense,
};
pub use hardware::{
default_hardware_environment, detect_hardware, DefaultHardwareEnvironment,
FixedHardwareEnvironment, HardwareEnvironment, HardwareInfo,
};
pub use keys::{parse_private_key, parse_public_key, CryptoKeyPair, KeyPair, KeySize};
pub use license::{HardwareBinding, LicenseData, LicenseDataBuilder, LicenseFormat, SignedLicense};
pub use state_manager::{StateManager, StateObservations};
pub use verifier::{detect_license_format, CryptoVerifier, LicenseVerifier, ValidationResult};
pub use crypto::{algorithm_ids, CryptoRegistry, EncryptionAlgorithm, SignatureAlgorithm};
pub use witness::{
ClockAttestation, ClockStatusAttestation, EnvironmentAttestation, ExpirationAttestation,
ExpirationIssue, HardwareAttestation, SecurityAnomaly, SecurityAttestation, SecurityWitness,
StateFileAttestation, StateFileObservation, StateFileStatus, WitnessConfig,
};
pub use sneakernet::{
detect_format as detect_sneakernet_format, ActivationRequest, ActivationRequestBuilder,
ActivationResponse, SneakernetFormat, MAX_SNEAKERNET_JSON_PAYLOAD, REQUEST_MAGIC,
REQUEST_TEXT_PREFIX, REQUEST_TEXT_SUFFIX, REQUEST_VERSION, RESPONSE_MAGIC,
RESPONSE_TEXT_PREFIX, RESPONSE_TEXT_SUFFIX, RESPONSE_VERSION,
};
pub use support_bundle::{
ClockState, ClockStatusSummary, EnvironmentInfo, HardwareMatchStatus, HardwareSummary,
LicenseStatusSummary, RuntimeEnvironmentSummary, StateFileLocation, StateFileLocationStatus,
StateFileSummary, SupportBundle, SupportBundleBuilder, VerificationEvent,
VerificationEventType, BUNDLE_VERSION, ENCRYPTED_BUNDLE_MAGIC,
};
pub use unlock::{
generate_challenge_from_state, get_lockout_status, validate_response_code, LockoutStatus,
UnlockChallenge, UnlockResult, UnlockType,
};
#[cfg(feature = "online-check")]
pub use online_check::{
check_revocation, check_revocation_batch, check_revocation_by_serial, sync_report,
OnlineCheckConfig, RevocationCheckResult, RevocationStatus, SyncReport, SyncResponse,
};
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
pub fn embedded_public_key() -> Option<&'static str> {
option_env!("LICENZ_PUBLIC_KEY")
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_full_workflow() {
let keypair = KeyPair::generate(KeySize::Bits2048).unwrap();
let generator = LicenseGenerator::new(keypair.private_key().clone());
let verifier = LicenseVerifier::new(keypair.public_key);
let data = LicenseData::builder()
.id("TEST-001")
.serial("SN-12345")
.customer_id("TEST-CUSTOMER")
.product_id("TEST-PRODUCT")
.valid_days(365)
.feature("basic")
.feature("premium")
.build()
.unwrap();
let signed = generator.generate(data).unwrap();
assert!(verifier.validate(&signed).is_ok());
assert!(signed.data.has_feature("basic"));
assert!(signed.data.has_feature("PREMIUM")); assert!(!signed.data.has_feature("enterprise"));
}
#[test]
fn test_hardware_binding() {
let binding = HardwareBinding::new()
.with_mac_address("AA:BB:CC:DD:EE:FF")
.with_hostname("test-server")
.with_disk_id("DISK-001");
assert!(!binding.is_empty());
assert_eq!(binding.mac_addresses.len(), 1);
assert_eq!(binding.hostnames.len(), 1);
assert_eq!(binding.disk_ids.len(), 1);
}
#[test]
fn test_validated_license_guard() {
let keypair = KeyPair::generate(KeySize::Bits2048).unwrap();
let generator = LicenseGenerator::new(keypair.private_key().clone());
let data = LicenseData::builder()
.id("GUARD-TEST")
.serial("SN-GUARD")
.customer_id("Guard Customer")
.product_id("GuardApp")
.valid_days(365)
.feature("test_feature")
.build()
.unwrap();
let signed = generator.generate(data).unwrap();
let binary = generator.export_binary(&signed).unwrap();
let public_key = keypair.export_public_pem().unwrap();
let validated = validate_license_bytes(&binary, &public_key).unwrap();
assert_eq!(validated.customer_id, "Guard Customer");
assert!(validated.has_feature("test_feature"));
}
#[test]
fn test_crypto_workflow_ed25519() {
let keypair = CryptoKeyPair::generate(algorithm_ids::ED25519).unwrap();
let generator = CryptoGenerator::from_keypair(&keypair);
let data = LicenseData::builder()
.id("ED25519-TEST")
.serial("SN-ED25519")
.customer_id("Ed25519 Customer")
.product_id("Ed25519 Product")
.valid_days(365)
.feature("feature1")
.feature("feature2")
.build()
.unwrap();
let signed = generator.generate(data).unwrap();
assert_eq!(signed.algorithm, algorithm_ids::ED25519);
let binary = generator.export_binary(&signed).unwrap();
let mut keys = std::collections::HashMap::new();
keys.insert(
algorithm_ids::ED25519.to_string(),
keypair.public_key_pem.clone(),
);
let verifier = CryptoVerifier::new(keys);
let parsed = verifier.parse_license(&binary).unwrap();
assert!(verifier.validate(&parsed).is_ok());
assert!(parsed.data.has_feature("feature1"));
assert!(parsed.data.has_feature("FEATURE2")); }
#[test]
fn test_crypto_workflow_multi_algorithm() {
let rsa_keypair = CryptoKeyPair::generate(algorithm_ids::RSA_SHA256).unwrap();
let ed25519_keypair = CryptoKeyPair::generate(algorithm_ids::ED25519).unwrap();
let mut keys = std::collections::HashMap::new();
keys.insert(
algorithm_ids::RSA_SHA256.to_string(),
rsa_keypair.public_key_pem.clone(),
);
keys.insert(
algorithm_ids::ED25519.to_string(),
ed25519_keypair.public_key_pem.clone(),
);
let verifier = CryptoVerifier::new(keys);
let rsa_generator = CryptoGenerator::from_keypair(&rsa_keypair);
let rsa_data = LicenseData::builder()
.id("RSA-LEGACY-001")
.serial("SN-RSA-LEGACY")
.customer_id("Legacy RSA Customer")
.product_id("PROD-001")
.valid_days(365)
.build()
.unwrap();
let rsa_license = rsa_generator.generate(rsa_data).unwrap();
let ed25519_generator = CryptoGenerator::from_keypair(&ed25519_keypair);
let ed25519_data = LicenseData::builder()
.id("ED25519-NEW-001")
.serial("SN-ED25519-NEW")
.customer_id("New Ed25519 Customer")
.product_id("PROD-001")
.valid_days(365)
.build()
.unwrap();
let ed25519_license = ed25519_generator.generate(ed25519_data).unwrap();
assert!(verifier.validate(&rsa_license).is_ok());
assert!(verifier.validate(&ed25519_license).is_ok());
assert_eq!(rsa_license.algorithm, algorithm_ids::RSA_SHA256);
assert_eq!(ed25519_license.algorithm, algorithm_ids::ED25519);
}
#[test]
fn test_backward_compatibility_rsa() {
let keypair = KeyPair::generate(KeySize::Bits2048).unwrap();
let generator = LicenseGenerator::new(keypair.private_key().clone());
let verifier = LicenseVerifier::new(keypair.public_key);
let data = LicenseData::builder()
.id("LEGACY-RSA-TEST")
.serial("SN-LEGACY-RSA")
.customer_id("Legacy Customer")
.product_id("Legacy Product")
.valid_days(365)
.build()
.unwrap();
let signed = generator.generate(data).unwrap();
assert_eq!(signed.algorithm, "RSA-SHA256");
assert!(verifier.validate(&signed).is_ok());
let binary = generator.export_binary(&signed).unwrap();
let parsed = verifier.parse_license(&binary).unwrap();
assert!(verifier.validate(&parsed).is_ok());
}
#[test]
fn test_algorithm_registry() {
let supported = CryptoRegistry::supported_signature_algorithms();
assert!(supported.contains(&algorithm_ids::RSA_SHA256));
assert!(supported.contains(&algorithm_ids::ED25519));
let rsa = CryptoRegistry::get_signature_algorithm(algorithm_ids::RSA_SHA256).unwrap();
assert_eq!(rsa.algorithm_id(), algorithm_ids::RSA_SHA256);
let ed25519 = CryptoRegistry::get_signature_algorithm(algorithm_ids::ED25519).unwrap();
assert_eq!(ed25519.algorithm_id(), algorithm_ids::ED25519);
let default = CryptoRegistry::default_signature_algorithm();
assert_eq!(default.algorithm_id(), algorithm_ids::RSA_SHA256);
}
}