1pub mod anti_tamper;
98pub mod container;
99pub mod crypto;
100pub mod encrypted_store;
101pub mod error;
102pub mod generator;
103pub mod guard;
104pub mod hardware;
105pub mod keys;
106pub mod license;
107pub mod sneakernet;
108pub mod state_manager;
109pub mod support_bundle;
110pub mod unlock;
111pub mod verifier;
112pub mod witness;
113
114#[cfg(feature = "online-check")]
115pub mod online_check;
116
117pub use anti_tamper::{
119 ClockStatus, HardwareFingerprint, LicenseState, MatchResult, STATE_HMAC_PREFIX,
120};
121pub use container::{ContainerBinding, InstanceIdSource, RuntimeEnvironment};
122pub use encrypted_store::{
123 validate_passphrase, EncryptedKeyStore, ENCRYPTED_STORE_VERSION, MIN_PASSPHRASE_LENGTH,
124};
125pub use error::{LicenseError, Result};
126pub use generator::{CryptoGenerator, LicenseGenerator};
127pub use guard::{
128 require_license, require_license_with_verifier, validate_license_bytes, ValidatedLicense,
129};
130pub use hardware::{
131 default_hardware_environment, detect_hardware, DefaultHardwareEnvironment,
132 FixedHardwareEnvironment, HardwareEnvironment, HardwareInfo,
133};
134pub use keys::{parse_private_key, parse_public_key, CryptoKeyPair, KeyPair, KeySize};
135pub use license::{HardwareBinding, LicenseData, LicenseDataBuilder, LicenseFormat, SignedLicense};
136pub use state_manager::{StateManager, StateObservations};
137pub use verifier::{detect_license_format, CryptoVerifier, LicenseVerifier, ValidationResult};
138
139pub use crypto::{algorithm_ids, CryptoRegistry, EncryptionAlgorithm, SignatureAlgorithm};
141
142pub use witness::{
144 ClockAttestation, ClockStatusAttestation, EnvironmentAttestation, ExpirationAttestation,
145 ExpirationIssue, HardwareAttestation, SecurityAnomaly, SecurityAttestation, SecurityWitness,
146 StateFileAttestation, StateFileObservation, StateFileStatus, WitnessConfig,
147};
148
149pub use sneakernet::{
151 detect_format as detect_sneakernet_format, ActivationRequest, ActivationRequestBuilder,
152 ActivationResponse, SneakernetFormat, MAX_SNEAKERNET_JSON_PAYLOAD, REQUEST_MAGIC,
153 REQUEST_TEXT_PREFIX, REQUEST_TEXT_SUFFIX, REQUEST_VERSION, RESPONSE_MAGIC,
154 RESPONSE_TEXT_PREFIX, RESPONSE_TEXT_SUFFIX, RESPONSE_VERSION,
155};
156
157pub use support_bundle::{
159 ClockState, ClockStatusSummary, EnvironmentInfo, HardwareMatchStatus, HardwareSummary,
160 LicenseStatusSummary, RuntimeEnvironmentSummary, StateFileLocation, StateFileLocationStatus,
161 StateFileSummary, SupportBundle, SupportBundleBuilder, VerificationEvent,
162 VerificationEventType, BUNDLE_VERSION, ENCRYPTED_BUNDLE_MAGIC,
163};
164
165pub use unlock::{
167 generate_challenge_from_state, get_lockout_status, validate_response_code, LockoutStatus,
168 UnlockChallenge, UnlockResult, UnlockType,
169};
170
171#[cfg(feature = "online-check")]
172pub use online_check::{
173 check_revocation, check_revocation_batch, check_revocation_by_serial, sync_report,
174 OnlineCheckConfig, RevocationCheckResult, RevocationStatus, SyncReport, SyncResponse,
175};
176
177pub const VERSION: &str = env!("CARGO_PKG_VERSION");
179
180pub fn embedded_public_key() -> Option<&'static str> {
189 option_env!("LICENZ_PUBLIC_KEY")
190}
191
192#[cfg(test)]
193mod tests {
194 use super::*;
195
196 #[test]
197 fn test_full_workflow() {
198 let keypair = KeyPair::generate(KeySize::Bits2048).unwrap();
200
201 let generator = LicenseGenerator::new(keypair.private_key().clone());
203 let verifier = LicenseVerifier::new(keypair.public_key);
204
205 let data = LicenseData::builder()
207 .id("TEST-001")
208 .serial("SN-12345")
209 .customer_id("TEST-CUSTOMER")
210 .product_id("TEST-PRODUCT")
211 .valid_days(365)
212 .feature("basic")
213 .feature("premium")
214 .build()
215 .unwrap();
216
217 let signed = generator.generate(data).unwrap();
219
220 assert!(verifier.validate(&signed).is_ok());
222
223 assert!(signed.data.has_feature("basic"));
225 assert!(signed.data.has_feature("PREMIUM")); assert!(!signed.data.has_feature("enterprise"));
227 }
228
229 #[test]
230 fn test_hardware_binding() {
231 let binding = HardwareBinding::new()
232 .with_mac_address("AA:BB:CC:DD:EE:FF")
233 .with_hostname("test-server")
234 .with_disk_id("DISK-001");
235
236 assert!(!binding.is_empty());
237 assert_eq!(binding.mac_addresses.len(), 1);
238 assert_eq!(binding.hostnames.len(), 1);
239 assert_eq!(binding.disk_ids.len(), 1);
240 }
241
242 #[test]
243 fn test_validated_license_guard() {
244 let keypair = KeyPair::generate(KeySize::Bits2048).unwrap();
245 let generator = LicenseGenerator::new(keypair.private_key().clone());
246
247 let data = LicenseData::builder()
248 .id("GUARD-TEST")
249 .serial("SN-GUARD")
250 .customer_id("Guard Customer")
251 .product_id("GuardApp")
252 .valid_days(365)
253 .feature("test_feature")
254 .build()
255 .unwrap();
256
257 let signed = generator.generate(data).unwrap();
258 let binary = generator.export_binary(&signed).unwrap();
259 let public_key = keypair.export_public_pem().unwrap();
260
261 let validated = validate_license_bytes(&binary, &public_key).unwrap();
263
264 assert_eq!(validated.customer_id, "Guard Customer");
265 assert!(validated.has_feature("test_feature"));
266 }
267
268 #[test]
269 fn test_crypto_workflow_ed25519() {
270 let keypair = CryptoKeyPair::generate(algorithm_ids::ED25519).unwrap();
272
273 let generator = CryptoGenerator::from_keypair(&keypair);
275
276 let data = LicenseData::builder()
278 .id("ED25519-TEST")
279 .serial("SN-ED25519")
280 .customer_id("Ed25519 Customer")
281 .product_id("Ed25519 Product")
282 .valid_days(365)
283 .feature("feature1")
284 .feature("feature2")
285 .build()
286 .unwrap();
287
288 let signed = generator.generate(data).unwrap();
290 assert_eq!(signed.algorithm, algorithm_ids::ED25519);
291
292 let binary = generator.export_binary(&signed).unwrap();
294
295 let mut keys = std::collections::HashMap::new();
297 keys.insert(
298 algorithm_ids::ED25519.to_string(),
299 keypair.public_key_pem.clone(),
300 );
301 let verifier = CryptoVerifier::new(keys);
302
303 let parsed = verifier.parse_license(&binary).unwrap();
305 assert!(verifier.validate(&parsed).is_ok());
306
307 assert!(parsed.data.has_feature("feature1"));
309 assert!(parsed.data.has_feature("FEATURE2")); }
311
312 #[test]
313 fn test_crypto_workflow_multi_algorithm() {
314 let rsa_keypair = CryptoKeyPair::generate(algorithm_ids::RSA_SHA256).unwrap();
318 let ed25519_keypair = CryptoKeyPair::generate(algorithm_ids::ED25519).unwrap();
319
320 let mut keys = std::collections::HashMap::new();
322 keys.insert(
323 algorithm_ids::RSA_SHA256.to_string(),
324 rsa_keypair.public_key_pem.clone(),
325 );
326 keys.insert(
327 algorithm_ids::ED25519.to_string(),
328 ed25519_keypair.public_key_pem.clone(),
329 );
330 let verifier = CryptoVerifier::new(keys);
331
332 let rsa_generator = CryptoGenerator::from_keypair(&rsa_keypair);
334 let rsa_data = LicenseData::builder()
335 .id("RSA-LEGACY-001")
336 .serial("SN-RSA-LEGACY")
337 .customer_id("Legacy RSA Customer")
338 .product_id("PROD-001")
339 .valid_days(365)
340 .build()
341 .unwrap();
342 let rsa_license = rsa_generator.generate(rsa_data).unwrap();
343
344 let ed25519_generator = CryptoGenerator::from_keypair(&ed25519_keypair);
346 let ed25519_data = LicenseData::builder()
347 .id("ED25519-NEW-001")
348 .serial("SN-ED25519-NEW")
349 .customer_id("New Ed25519 Customer")
350 .product_id("PROD-001")
351 .valid_days(365)
352 .build()
353 .unwrap();
354 let ed25519_license = ed25519_generator.generate(ed25519_data).unwrap();
355
356 assert!(verifier.validate(&rsa_license).is_ok());
358 assert!(verifier.validate(&ed25519_license).is_ok());
359
360 assert_eq!(rsa_license.algorithm, algorithm_ids::RSA_SHA256);
362 assert_eq!(ed25519_license.algorithm, algorithm_ids::ED25519);
363 }
364
365 #[test]
366 fn test_backward_compatibility_rsa() {
367 let keypair = KeyPair::generate(KeySize::Bits2048).unwrap();
369 let generator = LicenseGenerator::new(keypair.private_key().clone());
370 let verifier = LicenseVerifier::new(keypair.public_key);
371
372 let data = LicenseData::builder()
373 .id("LEGACY-RSA-TEST")
374 .serial("SN-LEGACY-RSA")
375 .customer_id("Legacy Customer")
376 .product_id("Legacy Product")
377 .valid_days(365)
378 .build()
379 .unwrap();
380
381 let signed = generator.generate(data).unwrap();
382
383 assert_eq!(signed.algorithm, "RSA-SHA256");
385
386 assert!(verifier.validate(&signed).is_ok());
388
389 let binary = generator.export_binary(&signed).unwrap();
391 let parsed = verifier.parse_license(&binary).unwrap();
392 assert!(verifier.validate(&parsed).is_ok());
393 }
394
395 #[test]
396 fn test_algorithm_registry() {
397 let supported = CryptoRegistry::supported_signature_algorithms();
399 assert!(supported.contains(&algorithm_ids::RSA_SHA256));
400 assert!(supported.contains(&algorithm_ids::ED25519));
401
402 let rsa = CryptoRegistry::get_signature_algorithm(algorithm_ids::RSA_SHA256).unwrap();
404 assert_eq!(rsa.algorithm_id(), algorithm_ids::RSA_SHA256);
405
406 let ed25519 = CryptoRegistry::get_signature_algorithm(algorithm_ids::ED25519).unwrap();
407 assert_eq!(ed25519.algorithm_id(), algorithm_ids::ED25519);
408
409 let default = CryptoRegistry::default_signature_algorithm();
411 assert_eq!(default.algorithm_id(), algorithm_ids::RSA_SHA256);
412 }
413}