1use chrono::{DateTime, Utc};
8use serde::{Deserialize, Serialize};
9
10#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
17#[non_exhaustive]
18pub struct CryptoProperties {
19 pub asset_type: CryptoAssetType,
21 pub oid: Option<String>,
23 pub algorithm_properties: Option<AlgorithmProperties>,
25 pub certificate_properties: Option<CertificateProperties>,
27 pub related_crypto_material_properties: Option<RelatedCryptoMaterialProperties>,
29 pub protocol_properties: Option<ProtocolProperties>,
31}
32
33impl CryptoProperties {
34 #[must_use]
36 pub fn new(asset_type: CryptoAssetType) -> Self {
37 Self {
38 asset_type,
39 oid: None,
40 algorithm_properties: None,
41 certificate_properties: None,
42 related_crypto_material_properties: None,
43 protocol_properties: None,
44 }
45 }
46
47 #[must_use]
48 pub fn with_oid(mut self, oid: String) -> Self {
49 self.oid = Some(oid);
50 self
51 }
52
53 #[must_use]
54 pub fn with_algorithm_properties(mut self, props: AlgorithmProperties) -> Self {
55 self.algorithm_properties = Some(props);
56 self
57 }
58
59 #[must_use]
60 pub fn with_certificate_properties(mut self, props: CertificateProperties) -> Self {
61 self.certificate_properties = Some(props);
62 self
63 }
64
65 #[must_use]
66 pub fn with_related_crypto_material_properties(
67 mut self,
68 props: RelatedCryptoMaterialProperties,
69 ) -> Self {
70 self.related_crypto_material_properties = Some(props);
71 self
72 }
73
74 #[must_use]
75 pub fn with_protocol_properties(mut self, props: ProtocolProperties) -> Self {
76 self.protocol_properties = Some(props);
77 self
78 }
79}
80
81#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
85#[non_exhaustive]
86pub enum CryptoAssetType {
87 Algorithm,
88 Certificate,
89 RelatedCryptoMaterial,
90 Protocol,
91 Other(String),
92}
93
94impl std::fmt::Display for CryptoAssetType {
95 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
96 match self {
97 Self::Algorithm => write!(f, "algorithm"),
98 Self::Certificate => write!(f, "certificate"),
99 Self::RelatedCryptoMaterial => write!(f, "related-crypto-material"),
100 Self::Protocol => write!(f, "protocol"),
101 Self::Other(s) => write!(f, "{s}"),
102 }
103 }
104}
105
106#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
110#[non_exhaustive]
111pub struct AlgorithmProperties {
112 pub primitive: CryptoPrimitive,
114 pub algorithm_family: Option<String>,
116 pub parameter_set_identifier: Option<String>,
118 pub mode: Option<CryptoMode>,
120 pub padding: Option<CryptoPadding>,
122 pub crypto_functions: Vec<CryptoFunction>,
124 pub execution_environment: Option<ExecutionEnvironment>,
126 pub implementation_platform: Option<ImplementationPlatform>,
128 pub certification_level: Vec<CertificationLevel>,
130 pub classical_security_level: Option<u32>,
132 pub nist_quantum_security_level: Option<u8>,
134 pub elliptic_curve: Option<String>,
136}
137
138impl AlgorithmProperties {
139 #[must_use]
141 pub fn new(primitive: CryptoPrimitive) -> Self {
142 Self {
143 primitive,
144 algorithm_family: None,
145 parameter_set_identifier: None,
146 mode: None,
147 padding: None,
148 crypto_functions: Vec::new(),
149 execution_environment: None,
150 implementation_platform: None,
151 certification_level: Vec::new(),
152 classical_security_level: None,
153 nist_quantum_security_level: None,
154 elliptic_curve: None,
155 }
156 }
157
158 #[must_use]
161 pub fn is_quantum_safe(&self) -> bool {
162 self.nist_quantum_security_level.is_some_and(|l| l > 0)
163 }
164
165 #[must_use]
167 pub fn is_hybrid_pqc(&self) -> bool {
168 self.primitive == CryptoPrimitive::Combiner
169 }
170
171 #[must_use]
175 pub fn is_weak(&self) -> bool {
176 const WEAK_FAMILIES: &[&str] = &[
178 "MD5", "MD4", "MD2", "SHA-1", "DES", "3DES", "TDEA", "RC2", "RC4", "BLOWFISH", "IDEA",
179 "CAST5",
180 ];
181
182 if let Some(family) = &self.algorithm_family {
183 let upper = family.to_uppercase();
184 if WEAK_FAMILIES.iter().any(|w| upper == *w) {
185 return true;
186 }
187 }
188 false
189 }
190
191 #[must_use]
194 pub fn is_weak_by_name(&self, component_name: &str) -> bool {
195 if self.is_weak() {
196 return true;
197 }
198 let upper = component_name.to_uppercase();
200 upper.starts_with("MD5")
201 || upper.starts_with("MD4")
202 || upper.starts_with("SHA-1")
203 || upper.starts_with("DES")
204 || upper.starts_with("3DES")
205 || upper.starts_with("RC4")
206 || upper.starts_with("RC2")
207 || upper.starts_with("BLOWFISH")
208 }
209
210 #[must_use]
212 pub fn effective_security_bits(&self) -> Option<u32> {
213 self.classical_security_level
214 }
215
216 #[must_use]
217 pub fn with_algorithm_family(mut self, family: String) -> Self {
218 self.algorithm_family = Some(family);
219 self
220 }
221
222 #[must_use]
223 pub fn with_parameter_set_identifier(mut self, id: String) -> Self {
224 self.parameter_set_identifier = Some(id);
225 self
226 }
227
228 #[must_use]
229 pub fn with_mode(mut self, mode: CryptoMode) -> Self {
230 self.mode = Some(mode);
231 self
232 }
233
234 #[must_use]
235 pub fn with_padding(mut self, padding: CryptoPadding) -> Self {
236 self.padding = Some(padding);
237 self
238 }
239
240 #[must_use]
241 pub fn with_crypto_functions(mut self, funcs: Vec<CryptoFunction>) -> Self {
242 self.crypto_functions = funcs;
243 self
244 }
245
246 #[must_use]
247 pub fn with_execution_environment(mut self, env: ExecutionEnvironment) -> Self {
248 self.execution_environment = Some(env);
249 self
250 }
251
252 #[must_use]
253 pub fn with_implementation_platform(mut self, platform: ImplementationPlatform) -> Self {
254 self.implementation_platform = Some(platform);
255 self
256 }
257
258 #[must_use]
259 pub fn with_certification_level(mut self, levels: Vec<CertificationLevel>) -> Self {
260 self.certification_level = levels;
261 self
262 }
263
264 #[must_use]
265 pub fn with_classical_security_level(mut self, bits: u32) -> Self {
266 self.classical_security_level = Some(bits);
267 self
268 }
269
270 #[must_use]
271 pub fn with_nist_quantum_security_level(mut self, level: u8) -> Self {
272 self.nist_quantum_security_level = Some(level);
273 self
274 }
275
276 #[must_use]
277 pub fn with_elliptic_curve(mut self, curve: String) -> Self {
278 self.elliptic_curve = Some(curve);
279 self
280 }
281}
282
283#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
287#[non_exhaustive]
288pub struct CertificateProperties {
289 pub subject_name: Option<String>,
291 pub issuer_name: Option<String>,
293 pub not_valid_before: Option<DateTime<Utc>>,
295 pub not_valid_after: Option<DateTime<Utc>>,
297 pub signature_algorithm_ref: Option<String>,
299 pub subject_public_key_ref: Option<String>,
301 pub certificate_format: Option<String>,
303 pub certificate_extension: Option<String>,
305}
306
307impl CertificateProperties {
308 #[must_use]
309 pub fn new() -> Self {
310 Self {
311 subject_name: None,
312 issuer_name: None,
313 not_valid_before: None,
314 not_valid_after: None,
315 signature_algorithm_ref: None,
316 subject_public_key_ref: None,
317 certificate_format: None,
318 certificate_extension: None,
319 }
320 }
321
322 #[must_use]
324 pub fn is_expired(&self) -> bool {
325 self.not_valid_after
326 .is_some_and(|expiry| expiry < Utc::now())
327 }
328
329 #[must_use]
331 pub fn is_expiring_soon(&self, days: u32) -> bool {
332 self.not_valid_after.is_some_and(|expiry| {
333 let threshold = Utc::now() + chrono::Duration::days(i64::from(days));
334 expiry <= threshold && expiry > Utc::now()
335 })
336 }
337
338 #[must_use]
341 pub fn validity_days(&self) -> Option<i64> {
342 self.not_valid_after
343 .map(|expiry| (expiry - Utc::now()).num_days())
344 }
345
346 #[must_use]
347 pub fn with_subject_name(mut self, name: String) -> Self {
348 self.subject_name = Some(name);
349 self
350 }
351
352 #[must_use]
353 pub fn with_issuer_name(mut self, name: String) -> Self {
354 self.issuer_name = Some(name);
355 self
356 }
357
358 #[must_use]
359 pub fn with_not_valid_before(mut self, dt: DateTime<Utc>) -> Self {
360 self.not_valid_before = Some(dt);
361 self
362 }
363
364 #[must_use]
365 pub fn with_not_valid_after(mut self, dt: DateTime<Utc>) -> Self {
366 self.not_valid_after = Some(dt);
367 self
368 }
369
370 #[must_use]
371 pub fn with_signature_algorithm_ref(mut self, r: String) -> Self {
372 self.signature_algorithm_ref = Some(r);
373 self
374 }
375
376 #[must_use]
377 pub fn with_subject_public_key_ref(mut self, r: String) -> Self {
378 self.subject_public_key_ref = Some(r);
379 self
380 }
381
382 #[must_use]
383 pub fn with_certificate_format(mut self, fmt: String) -> Self {
384 self.certificate_format = Some(fmt);
385 self
386 }
387
388 #[must_use]
389 pub fn with_certificate_extension(mut self, ext: String) -> Self {
390 self.certificate_extension = Some(ext);
391 self
392 }
393}
394
395impl Default for CertificateProperties {
396 fn default() -> Self {
397 Self::new()
398 }
399}
400
401#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
405#[non_exhaustive]
406pub struct RelatedCryptoMaterialProperties {
407 pub material_type: CryptoMaterialType,
409 pub id: Option<String>,
411 pub state: Option<CryptoMaterialState>,
413 pub size: Option<u32>,
415 pub algorithm_ref: Option<String>,
417 pub secured_by: Option<SecuredBy>,
419 pub format: Option<String>,
421 pub creation_date: Option<DateTime<Utc>>,
423 pub activation_date: Option<DateTime<Utc>>,
425 pub update_date: Option<DateTime<Utc>>,
427 pub expiration_date: Option<DateTime<Utc>>,
429}
430
431impl RelatedCryptoMaterialProperties {
432 #[must_use]
433 pub fn new(material_type: CryptoMaterialType) -> Self {
434 Self {
435 material_type,
436 id: None,
437 state: None,
438 size: None,
439 algorithm_ref: None,
440 secured_by: None,
441 format: None,
442 creation_date: None,
443 activation_date: None,
444 update_date: None,
445 expiration_date: None,
446 }
447 }
448
449 #[must_use]
450 pub fn with_id(mut self, id: String) -> Self {
451 self.id = Some(id);
452 self
453 }
454
455 #[must_use]
456 pub fn with_state(mut self, state: CryptoMaterialState) -> Self {
457 self.state = Some(state);
458 self
459 }
460
461 #[must_use]
462 pub fn with_size(mut self, bits: u32) -> Self {
463 self.size = Some(bits);
464 self
465 }
466
467 #[must_use]
468 pub fn with_algorithm_ref(mut self, r: String) -> Self {
469 self.algorithm_ref = Some(r);
470 self
471 }
472
473 #[must_use]
474 pub fn with_secured_by(mut self, secured: SecuredBy) -> Self {
475 self.secured_by = Some(secured);
476 self
477 }
478
479 #[must_use]
480 pub fn with_format(mut self, fmt: String) -> Self {
481 self.format = Some(fmt);
482 self
483 }
484
485 #[must_use]
486 pub fn with_creation_date(mut self, dt: DateTime<Utc>) -> Self {
487 self.creation_date = Some(dt);
488 self
489 }
490
491 #[must_use]
492 pub fn with_activation_date(mut self, dt: DateTime<Utc>) -> Self {
493 self.activation_date = Some(dt);
494 self
495 }
496
497 #[must_use]
498 pub fn with_expiration_date(mut self, dt: DateTime<Utc>) -> Self {
499 self.expiration_date = Some(dt);
500 self
501 }
502}
503
504#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
508#[non_exhaustive]
509pub struct ProtocolProperties {
510 pub protocol_type: ProtocolType,
512 pub version: Option<String>,
514 pub cipher_suites: Vec<CipherSuite>,
516 pub ikev2_transform_types: Option<Ikev2TransformTypes>,
518 pub crypto_ref_array: Vec<String>,
520}
521
522impl ProtocolProperties {
523 #[must_use]
524 pub fn new(protocol_type: ProtocolType) -> Self {
525 Self {
526 protocol_type,
527 version: None,
528 cipher_suites: Vec::new(),
529 ikev2_transform_types: None,
530 crypto_ref_array: Vec::new(),
531 }
532 }
533
534 #[must_use]
535 pub fn with_version(mut self, version: String) -> Self {
536 self.version = Some(version);
537 self
538 }
539
540 #[must_use]
541 pub fn with_cipher_suites(mut self, suites: Vec<CipherSuite>) -> Self {
542 self.cipher_suites = suites;
543 self
544 }
545
546 #[must_use]
547 pub fn with_ikev2_transform_types(mut self, types: Ikev2TransformTypes) -> Self {
548 self.ikev2_transform_types = Some(types);
549 self
550 }
551
552 #[must_use]
553 pub fn with_crypto_ref_array(mut self, refs: Vec<String>) -> Self {
554 self.crypto_ref_array = refs;
555 self
556 }
557}
558
559#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
563pub struct CipherSuite {
564 pub name: Option<String>,
566 pub algorithms: Vec<String>,
568 pub identifiers: Vec<String>,
570}
571
572#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
574pub struct Ikev2TransformTypes {
575 pub encr: Vec<String>,
577 pub prf: Vec<String>,
579 pub integ: Vec<String>,
581 pub ke: Vec<String>,
583}
584
585#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
587pub struct SecuredBy {
588 pub mechanism: String,
590 pub algorithm_ref: Option<String>,
592}
593
594#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
598#[non_exhaustive]
599pub enum CryptoPrimitive {
600 Ae,
602 BlockCipher,
604 StreamCipher,
606 Hash,
608 Mac,
610 Signature,
612 Pke,
614 Kem,
616 Kdf,
618 KeyAgree,
620 Xof,
622 Drbg,
624 Combiner,
626 Other(String),
627 Unknown,
628}
629
630impl std::fmt::Display for CryptoPrimitive {
631 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
632 match self {
633 Self::Ae => write!(f, "ae"),
634 Self::BlockCipher => write!(f, "block-cipher"),
635 Self::StreamCipher => write!(f, "stream-cipher"),
636 Self::Hash => write!(f, "hash"),
637 Self::Mac => write!(f, "mac"),
638 Self::Signature => write!(f, "signature"),
639 Self::Pke => write!(f, "pke"),
640 Self::Kem => write!(f, "kem"),
641 Self::Kdf => write!(f, "kdf"),
642 Self::KeyAgree => write!(f, "key-agree"),
643 Self::Xof => write!(f, "xof"),
644 Self::Drbg => write!(f, "drbg"),
645 Self::Combiner => write!(f, "combiner"),
646 Self::Other(s) => write!(f, "{s}"),
647 Self::Unknown => write!(f, "unknown"),
648 }
649 }
650}
651
652#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
654#[non_exhaustive]
655pub enum CryptoMode {
656 Ecb,
657 Cbc,
658 Ofb,
659 Cfb,
660 Ctr,
661 Gcm,
662 Ccm,
663 Xts,
664 Other(String),
665}
666
667impl std::fmt::Display for CryptoMode {
668 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
669 match self {
670 Self::Ecb => write!(f, "ecb"),
671 Self::Cbc => write!(f, "cbc"),
672 Self::Ofb => write!(f, "ofb"),
673 Self::Cfb => write!(f, "cfb"),
674 Self::Ctr => write!(f, "ctr"),
675 Self::Gcm => write!(f, "gcm"),
676 Self::Ccm => write!(f, "ccm"),
677 Self::Xts => write!(f, "xts"),
678 Self::Other(s) => write!(f, "{s}"),
679 }
680 }
681}
682
683#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
685#[non_exhaustive]
686pub enum CryptoPadding {
687 Pkcs5,
688 Oaep,
689 Pss,
690 Other(String),
691}
692
693impl std::fmt::Display for CryptoPadding {
694 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
695 match self {
696 Self::Pkcs5 => write!(f, "pkcs5"),
697 Self::Oaep => write!(f, "oaep"),
698 Self::Pss => write!(f, "pss"),
699 Self::Other(s) => write!(f, "{s}"),
700 }
701 }
702}
703
704#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
706#[non_exhaustive]
707pub enum CryptoFunction {
708 Keygen,
709 Encrypt,
710 Decrypt,
711 Sign,
712 Verify,
713 Digest,
714 Tag,
715 KeyDerive,
716 Encapsulate,
717 Decapsulate,
718 Wrap,
719 Unwrap,
720 Other(String),
721}
722
723impl std::fmt::Display for CryptoFunction {
724 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
725 match self {
726 Self::Keygen => write!(f, "keygen"),
727 Self::Encrypt => write!(f, "encrypt"),
728 Self::Decrypt => write!(f, "decrypt"),
729 Self::Sign => write!(f, "sign"),
730 Self::Verify => write!(f, "verify"),
731 Self::Digest => write!(f, "digest"),
732 Self::Tag => write!(f, "tag"),
733 Self::KeyDerive => write!(f, "keyderive"),
734 Self::Encapsulate => write!(f, "encapsulate"),
735 Self::Decapsulate => write!(f, "decapsulate"),
736 Self::Wrap => write!(f, "wrap"),
737 Self::Unwrap => write!(f, "unwrap"),
738 Self::Other(s) => write!(f, "{s}"),
739 }
740 }
741}
742
743#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
745#[non_exhaustive]
746pub enum ExecutionEnvironment {
747 SoftwarePlainRam,
748 SoftwareEncryptedRam,
749 SoftwareTee,
750 Hardware,
751 Other(String),
752}
753
754impl std::fmt::Display for ExecutionEnvironment {
755 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
756 match self {
757 Self::SoftwarePlainRam => write!(f, "software-plain-ram"),
758 Self::SoftwareEncryptedRam => write!(f, "software-encrypted-ram"),
759 Self::SoftwareTee => write!(f, "software-tee"),
760 Self::Hardware => write!(f, "hardware"),
761 Self::Other(s) => write!(f, "{s}"),
762 }
763 }
764}
765
766#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
768#[non_exhaustive]
769pub enum ImplementationPlatform {
770 X86_32,
771 X86_64,
772 Armv7A,
773 Armv7M,
774 Armv8A,
775 S390x,
776 Generic,
777 Other(String),
778}
779
780impl std::fmt::Display for ImplementationPlatform {
781 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
782 match self {
783 Self::X86_32 => write!(f, "x86_32"),
784 Self::X86_64 => write!(f, "x86_64"),
785 Self::Armv7A => write!(f, "armv7-a"),
786 Self::Armv7M => write!(f, "armv7-m"),
787 Self::Armv8A => write!(f, "armv8-a"),
788 Self::S390x => write!(f, "s390x"),
789 Self::Generic => write!(f, "generic"),
790 Self::Other(s) => write!(f, "{s}"),
791 }
792 }
793}
794
795#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
797#[non_exhaustive]
798pub enum CertificationLevel {
799 None,
800 Fips140_1L1,
801 Fips140_1L2,
802 Fips140_1L3,
803 Fips140_1L4,
804 Fips140_2L1,
805 Fips140_2L2,
806 Fips140_2L3,
807 Fips140_2L4,
808 Fips140_3L1,
809 Fips140_3L2,
810 Fips140_3L3,
811 Fips140_3L4,
812 CcEal1,
813 CcEal2,
814 CcEal3,
815 CcEal4,
816 CcEal5,
817 CcEal6,
818 CcEal7,
819 Other(String),
820}
821
822impl std::fmt::Display for CertificationLevel {
823 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
824 match self {
825 Self::None => write!(f, "none"),
826 Self::Fips140_1L1 => write!(f, "fips140-1-l1"),
827 Self::Fips140_1L2 => write!(f, "fips140-1-l2"),
828 Self::Fips140_1L3 => write!(f, "fips140-1-l3"),
829 Self::Fips140_1L4 => write!(f, "fips140-1-l4"),
830 Self::Fips140_2L1 => write!(f, "fips140-2-l1"),
831 Self::Fips140_2L2 => write!(f, "fips140-2-l2"),
832 Self::Fips140_2L3 => write!(f, "fips140-2-l3"),
833 Self::Fips140_2L4 => write!(f, "fips140-2-l4"),
834 Self::Fips140_3L1 => write!(f, "fips140-3-l1"),
835 Self::Fips140_3L2 => write!(f, "fips140-3-l2"),
836 Self::Fips140_3L3 => write!(f, "fips140-3-l3"),
837 Self::Fips140_3L4 => write!(f, "fips140-3-l4"),
838 Self::CcEal1 => write!(f, "cc-eal1"),
839 Self::CcEal2 => write!(f, "cc-eal2"),
840 Self::CcEal3 => write!(f, "cc-eal3"),
841 Self::CcEal4 => write!(f, "cc-eal4"),
842 Self::CcEal5 => write!(f, "cc-eal5"),
843 Self::CcEal6 => write!(f, "cc-eal6"),
844 Self::CcEal7 => write!(f, "cc-eal7"),
845 Self::Other(s) => write!(f, "{s}"),
846 }
847 }
848}
849
850#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
852#[non_exhaustive]
853pub enum CryptoMaterialType {
854 PublicKey,
855 PrivateKey,
856 SymmetricKey,
857 SecretKey,
858 KeyPair,
859 Ciphertext,
860 Signature,
861 Digest,
862 Iv,
863 Nonce,
864 Seed,
865 Salt,
866 SharedSecret,
867 Tag,
868 Password,
869 Credential,
870 Token,
871 Other(String),
872 Unknown,
873}
874
875impl std::fmt::Display for CryptoMaterialType {
876 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
877 match self {
878 Self::PublicKey => write!(f, "public-key"),
879 Self::PrivateKey => write!(f, "private-key"),
880 Self::SymmetricKey => write!(f, "symmetric-key"),
881 Self::SecretKey => write!(f, "secret-key"),
882 Self::KeyPair => write!(f, "key-pair"),
883 Self::Ciphertext => write!(f, "ciphertext"),
884 Self::Signature => write!(f, "signature"),
885 Self::Digest => write!(f, "digest"),
886 Self::Iv => write!(f, "initialization-vector"),
887 Self::Nonce => write!(f, "nonce"),
888 Self::Seed => write!(f, "seed"),
889 Self::Salt => write!(f, "salt"),
890 Self::SharedSecret => write!(f, "shared-secret"),
891 Self::Tag => write!(f, "tag"),
892 Self::Password => write!(f, "password"),
893 Self::Credential => write!(f, "credential"),
894 Self::Token => write!(f, "token"),
895 Self::Other(s) => write!(f, "{s}"),
896 Self::Unknown => write!(f, "unknown"),
897 }
898 }
899}
900
901#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
903#[non_exhaustive]
904pub enum CryptoMaterialState {
905 PreActivation,
906 Active,
907 Suspended,
908 Deactivated,
909 Compromised,
910 Destroyed,
911}
912
913impl std::fmt::Display for CryptoMaterialState {
914 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
915 match self {
916 Self::PreActivation => write!(f, "pre-activation"),
917 Self::Active => write!(f, "active"),
918 Self::Suspended => write!(f, "suspended"),
919 Self::Deactivated => write!(f, "deactivated"),
920 Self::Compromised => write!(f, "compromised"),
921 Self::Destroyed => write!(f, "destroyed"),
922 }
923 }
924}
925
926#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
928#[non_exhaustive]
929pub enum ProtocolType {
930 Tls,
931 Dtls,
932 Ipsec,
933 Ssh,
934 Srtp,
935 Wireguard,
936 Ikev1,
937 Ikev2,
938 Zrtp,
939 Mikey,
940 Other(String),
941 Unknown,
942}
943
944impl std::fmt::Display for ProtocolType {
945 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
946 match self {
947 Self::Tls => write!(f, "tls"),
948 Self::Dtls => write!(f, "dtls"),
949 Self::Ipsec => write!(f, "ipsec"),
950 Self::Ssh => write!(f, "ssh"),
951 Self::Srtp => write!(f, "srtp"),
952 Self::Wireguard => write!(f, "wireguard"),
953 Self::Ikev1 => write!(f, "ikev1"),
954 Self::Ikev2 => write!(f, "ikev2"),
955 Self::Zrtp => write!(f, "zrtp"),
956 Self::Mikey => write!(f, "mikey"),
957 Self::Other(s) => write!(f, "{s}"),
958 Self::Unknown => write!(f, "unknown"),
959 }
960 }
961}
962
963#[cfg(test)]
966mod tests {
967 use super::*;
968
969 #[test]
970 fn algorithm_is_quantum_safe() {
971 let algo =
972 AlgorithmProperties::new(CryptoPrimitive::Kem).with_nist_quantum_security_level(5);
973 assert!(algo.is_quantum_safe());
974
975 let classical =
976 AlgorithmProperties::new(CryptoPrimitive::Pke).with_nist_quantum_security_level(0);
977 assert!(!classical.is_quantum_safe());
978
979 let unknown = AlgorithmProperties::new(CryptoPrimitive::Pke);
980 assert!(!unknown.is_quantum_safe());
981 }
982
983 #[test]
984 fn algorithm_is_hybrid_pqc() {
985 let hybrid = AlgorithmProperties::new(CryptoPrimitive::Combiner);
986 assert!(hybrid.is_hybrid_pqc());
987
988 let normal = AlgorithmProperties::new(CryptoPrimitive::Kem);
989 assert!(!normal.is_hybrid_pqc());
990 }
991
992 #[test]
993 fn algorithm_is_weak() {
994 let md5 = AlgorithmProperties::new(CryptoPrimitive::Hash)
995 .with_algorithm_family("MD5".to_string());
996 assert!(md5.is_weak());
997
998 let sha1 = AlgorithmProperties::new(CryptoPrimitive::Hash)
999 .with_algorithm_family("SHA-1".to_string());
1000 assert!(sha1.is_weak());
1001
1002 let des = AlgorithmProperties::new(CryptoPrimitive::BlockCipher)
1003 .with_algorithm_family("DES".to_string());
1004 assert!(des.is_weak());
1005
1006 let rc4 = AlgorithmProperties::new(CryptoPrimitive::StreamCipher)
1007 .with_algorithm_family("RC4".to_string());
1008 assert!(rc4.is_weak());
1009
1010 let aes =
1011 AlgorithmProperties::new(CryptoPrimitive::Ae).with_algorithm_family("AES".to_string());
1012 assert!(!aes.is_weak());
1013
1014 let ml_kem = AlgorithmProperties::new(CryptoPrimitive::Kem)
1015 .with_algorithm_family("ML-KEM".to_string());
1016 assert!(!ml_kem.is_weak());
1017 }
1018
1019 #[test]
1020 fn certificate_expiry() {
1021 let expired = CertificateProperties::new()
1022 .with_not_valid_after(Utc::now() - chrono::Duration::days(1));
1023 assert!(expired.is_expired());
1024 assert!(!expired.is_expiring_soon(90));
1025
1026 let valid = CertificateProperties::new()
1027 .with_not_valid_after(Utc::now() + chrono::Duration::days(365));
1028 assert!(!valid.is_expired());
1029 assert!(!valid.is_expiring_soon(90));
1030
1031 let expiring = CertificateProperties::new()
1032 .with_not_valid_after(Utc::now() + chrono::Duration::days(30));
1033 assert!(!expiring.is_expired());
1034 assert!(expiring.is_expiring_soon(90));
1035 }
1036
1037 #[test]
1038 fn certificate_validity_days() {
1039 let no_expiry = CertificateProperties::new();
1040 assert!(no_expiry.validity_days().is_none());
1041
1042 let expired = CertificateProperties::new()
1043 .with_not_valid_after(Utc::now() - chrono::Duration::days(10));
1044 assert!(expired.validity_days().unwrap() < 0);
1045
1046 let future = CertificateProperties::new()
1047 .with_not_valid_after(Utc::now() + chrono::Duration::days(100));
1048 let days = future.validity_days().unwrap();
1049 assert!(days >= 99 && days <= 100);
1050 }
1051
1052 #[test]
1053 fn crypto_properties_builder() {
1054 let props = CryptoProperties::new(CryptoAssetType::Algorithm)
1055 .with_oid("2.16.840.1.101.3.4.1.46".to_string())
1056 .with_algorithm_properties(
1057 AlgorithmProperties::new(CryptoPrimitive::Ae)
1058 .with_algorithm_family("AES".to_string())
1059 .with_mode(CryptoMode::Gcm)
1060 .with_classical_security_level(256)
1061 .with_nist_quantum_security_level(1),
1062 );
1063
1064 assert_eq!(props.asset_type, CryptoAssetType::Algorithm);
1065 assert_eq!(props.oid.as_deref(), Some("2.16.840.1.101.3.4.1.46"));
1066 let algo = props.algorithm_properties.unwrap();
1067 assert_eq!(algo.primitive, CryptoPrimitive::Ae);
1068 assert_eq!(algo.algorithm_family.as_deref(), Some("AES"));
1069 assert_eq!(algo.mode, Some(CryptoMode::Gcm));
1070 assert_eq!(algo.classical_security_level, Some(256));
1071 assert!(algo.is_quantum_safe());
1072 assert!(!algo.is_weak());
1073 }
1074
1075 #[test]
1076 fn display_impls() {
1077 assert_eq!(CryptoAssetType::Algorithm.to_string(), "algorithm");
1078 assert_eq!(
1079 CryptoAssetType::RelatedCryptoMaterial.to_string(),
1080 "related-crypto-material"
1081 );
1082 assert_eq!(CryptoPrimitive::Kem.to_string(), "kem");
1083 assert_eq!(CryptoPrimitive::Combiner.to_string(), "combiner");
1084 assert_eq!(CryptoMode::Gcm.to_string(), "gcm");
1085 assert_eq!(CryptoFunction::Encapsulate.to_string(), "encapsulate");
1086 assert_eq!(CryptoMaterialType::PublicKey.to_string(), "public-key");
1087 assert_eq!(CryptoMaterialState::Compromised.to_string(), "compromised");
1088 assert_eq!(ProtocolType::Tls.to_string(), "tls");
1089 assert_eq!(CertificationLevel::Fips140_3L1.to_string(), "fips140-3-l1");
1090 assert_eq!(ExecutionEnvironment::Hardware.to_string(), "hardware");
1091 assert_eq!(ImplementationPlatform::X86_64.to_string(), "x86_64");
1092 }
1093
1094 #[test]
1095 fn protocol_builder() {
1096 let proto = ProtocolProperties::new(ProtocolType::Tls)
1097 .with_version("1.3".to_string())
1098 .with_cipher_suites(vec![CipherSuite {
1099 name: Some("TLS_AES_256_GCM_SHA384".to_string()),
1100 algorithms: vec!["algo/aes-256-gcm".to_string()],
1101 identifiers: vec!["0x13".to_string(), "0x02".to_string()],
1102 }]);
1103
1104 assert_eq!(proto.protocol_type, ProtocolType::Tls);
1105 assert_eq!(proto.version.as_deref(), Some("1.3"));
1106 assert_eq!(proto.cipher_suites.len(), 1);
1107 }
1108
1109 #[test]
1110 fn related_material_builder() {
1111 let key = RelatedCryptoMaterialProperties::new(CryptoMaterialType::PublicKey)
1112 .with_id("test-id".to_string())
1113 .with_state(CryptoMaterialState::Active)
1114 .with_size(2048)
1115 .with_algorithm_ref("algo/rsa-2048".to_string())
1116 .with_secured_by(SecuredBy {
1117 mechanism: "HSM".to_string(),
1118 algorithm_ref: Some("algo/aes-256".to_string()),
1119 });
1120
1121 assert_eq!(key.material_type, CryptoMaterialType::PublicKey);
1122 assert_eq!(key.state, Some(CryptoMaterialState::Active));
1123 assert_eq!(key.size, Some(2048));
1124 assert!(key.secured_by.is_some());
1125 }
1126}