1#![no_std]
139#![forbid(unsafe_code)]
140
141use core::fmt;
142use core::sync::atomic::{AtomicU8, Ordering};
143
144#[derive(Debug, Clone, Copy, PartialEq, Eq)]
146#[repr(u8)]
147pub enum State {
148 PowerOff = 0,
150 SelfTest = 1,
153 Operational = 2,
156 Error = 3,
162 IntegrityUnverified = 4,
176}
177
178impl State {
179 const fn from_u8(raw: u8) -> Self {
180 match raw {
181 0 => Self::PowerOff,
182 1 => Self::SelfTest,
183 2 => Self::Operational,
184 4 => Self::IntegrityUnverified,
185 _ => Self::Error,
191 }
192 }
193}
194
195impl fmt::Display for State {
196 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
197 let s = match self {
198 Self::PowerOff => "PowerOff",
199 Self::SelfTest => "SelfTest",
200 Self::Operational => "Operational",
201 Self::Error => "Error",
202 Self::IntegrityUnverified => "IntegrityUnverified",
203 };
204 f.write_str(s)
205 }
206}
207
208static STATE: AtomicU8 = AtomicU8::new(State::PowerOff as u8);
211
212pub fn state() -> State {
214 State::from_u8(STATE.load(Ordering::Acquire))
215}
216
217pub fn is_operational() -> bool {
220 state() == State::Operational
221}
222
223pub fn require_operational() -> Result<(), Error> {
228 let current = state();
229 if current == State::Operational {
230 Ok(())
231 } else {
232 Err(Error::NotOperational { current })
233 }
234}
235
236#[derive(Debug, Clone, Copy, PartialEq, Eq)]
243pub enum Error {
244 NotOperational {
247 current: State,
249 },
250 SelfTestFailed {
253 test: &'static str,
256 },
257 ConditionalTestFailed {
260 reason: &'static str,
262 },
263 IntegrityNotAttested,
271 AlreadyInitialized,
277 InvalidInput,
285 AlgorithmRestricted {
291 service: Service,
293 },
294 NotImplemented,
301}
302
303impl fmt::Display for Error {
304 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
305 match self {
306 Self::NotOperational { current } => {
307 write!(f, "FIPS module not operational (state = {current})")
308 }
309 Self::SelfTestFailed { test } => {
310 write!(f, "FIPS power-up self-test failed: {test}")
311 }
312 Self::ConditionalTestFailed { reason } => {
313 write!(f, "FIPS conditional self-test failed: {reason}")
314 }
315 Self::IntegrityNotAttested => f.write_str(
316 "this module did not check itself at startup, so it cannot tell whether this \
317 copy is the one that was built and signed. That does not mean the module is \
318 damaged: the program that started it skipped the check.",
319 ),
320 Self::AlreadyInitialized => f.write_str("FIPS module already initialized"),
321 Self::InvalidInput => f.write_str("invalid input to FIPS service"),
322 Self::AlgorithmRestricted { service } => {
323 write!(
324 f,
325 "algorithm {service} is not permitted under the {} profile",
326 active_profile()
327 )
328 }
329 Self::NotImplemented => f.write_str("algorithm not yet implemented"),
330 }
331 }
332}
333
334#[derive(Debug, Clone, Copy, PartialEq, Eq)]
343pub struct SelfTestFailure;
344
345impl fmt::Display for SelfTestFailure {
346 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
347 f.write_str("self-test failure")
348 }
349}
350
351pub trait SelfTest {
363 const NAME: &'static str;
366
367 fn run() -> Result<(), SelfTestFailure>;
371}
372
373#[derive(Debug, Clone, Copy)]
386pub struct KatEntry {
387 pub name: &'static str,
391 pub run: fn() -> Result<(), SelfTestFailure>,
393}
394
395pub fn initialize_with_tests(integrity: &[KatEntry], tests: &[KatEntry]) -> Result<(), Error> {
414 let cas = STATE.compare_exchange(
417 State::PowerOff as u8,
418 State::SelfTest as u8,
419 Ordering::AcqRel,
420 Ordering::Acquire,
421 );
422 if cas.is_err() {
423 while STATE.load(Ordering::Acquire) == State::SelfTest as u8 {
428 core::hint::spin_loop();
429 }
430 let current = state();
431 if current == State::Operational {
432 return Err(Error::AlreadyInitialized);
433 }
434 return Err(Error::NotOperational { current });
438 }
439
440 if integrity.is_empty() {
455 STATE.store(State::IntegrityUnverified as u8, Ordering::Release);
456 return Err(Error::IntegrityNotAttested);
457 }
458
459 for entry in integrity.iter().chain(tests) {
460 if (entry.run)().is_err() {
461 STATE.store(State::Error as u8, Ordering::Release);
465 return Err(Error::SelfTestFailed { test: entry.name });
466 }
467 }
468
469 STATE.store(State::Operational as u8, Ordering::Release);
475 Ok(())
476}
477
478pub fn enter_error_state(_reason: &'static str) {
490 STATE.store(State::Error as u8, Ordering::Release);
491}
492
493#[derive(Debug, Clone, Copy, PartialEq, Eq)]
507#[repr(u8)]
508pub enum AlgorithmProfile {
509 Unrestricted = 0,
513 Cnsa2 = 1,
521 Cnsa1 = 2,
528 Migration = 3,
538}
539
540impl AlgorithmProfile {
541 const fn from_u8(raw: u8) -> Self {
542 match raw {
543 0 => Self::Unrestricted,
544 2 => Self::Cnsa1,
545 3 => Self::Migration,
546 _ => Self::Cnsa2,
549 }
550 }
551}
552
553impl fmt::Display for AlgorithmProfile {
554 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
555 let s = match self {
556 Self::Unrestricted => "Unrestricted",
557 Self::Cnsa2 => "CNSA 2.0",
558 Self::Cnsa1 => "CNSA 1.0",
559 Self::Migration => "Migration (CNSA 1.0 + CNSA 2.0)",
560 };
561 f.write_str(s)
562 }
563}
564
565static PROFILE: AtomicU8 = AtomicU8::new(AlgorithmProfile::Unrestricted as u8);
568
569pub fn active_profile() -> AlgorithmProfile {
571 AlgorithmProfile::from_u8(PROFILE.load(Ordering::Acquire))
572}
573
574pub fn initialize_with_profile(
586 integrity: &[KatEntry],
587 tests: &[KatEntry],
588 profile: AlgorithmProfile,
589) -> Result<(), Error> {
590 PROFILE.store(profile as u8, Ordering::Release);
596 initialize_with_tests(integrity, tests)
597}
598
599#[derive(Debug, Clone, Copy, PartialEq, Eq)]
610#[repr(u16)]
611#[allow(missing_docs)]
612pub enum Service {
613 Sha1 = 0,
615 Sha224 = 1,
616 Sha256 = 2,
617 Sha384 = 3,
618 Sha512 = 4,
619 Sha512_224 = 5,
620 Sha512_256 = 6,
621
622 Sha3_224 = 10,
623 Sha3_256 = 11,
624 Sha3_384 = 12,
625 Sha3_512 = 13,
626
627 Shake128 = 20,
629 Shake256 = 21,
630 CShake128 = 22,
631 CShake256 = 23,
632 Kmac128 = 24,
633 Kmac256 = 25,
634 KmacXof128 = 26,
635 KmacXof256 = 27,
636 TupleHash128 = 28,
637 TupleHash256 = 29,
638 TupleHashXof128 = 30,
639 TupleHashXof256 = 31,
640 ParallelHash128 = 32,
641 ParallelHash256 = 33,
642 ParallelHashXof128 = 34,
643 ParallelHashXof256 = 35,
644
645 HmacSha1 = 40,
647 HmacSha224 = 41,
648 HmacSha256 = 42,
649 HmacSha384 = 43,
650 HmacSha512 = 44,
651 HmacSha512_224 = 45,
652 HmacSha512_256 = 46,
653 HmacSha3_224 = 47,
654 HmacSha3_256 = 48,
655 HmacSha3_384 = 49,
656 HmacSha3_512 = 50,
657
658 CmacAes128 = 60,
660 CmacAes192 = 61,
661 CmacAes256 = 62,
662
663 Aes128Ecb = 70,
665 Aes128Cbc = 71,
666 Aes128Ctr = 72,
667 Aes128Gcm = 73,
668 Aes128Ccm = 74,
669 Aes128Kw = 75,
670 Aes128Kwp = 76,
671 Aes192Ecb = 80,
672 Aes192Cbc = 81,
673 Aes192Ctr = 82,
674 Aes192Gcm = 83,
675 Aes192Ccm = 84,
676 Aes192Kw = 85,
677 Aes192Kwp = 86,
678 Aes256Ecb = 90,
679 Aes256Cbc = 91,
680 Aes256Ctr = 92,
681 Aes256Gcm = 93,
682 Aes256Ccm = 94,
683 Aes256Kw = 95,
684 Aes256Kwp = 96,
685
686 Aes128 = 97,
693 Aes192 = 98,
695 Aes256 = 99,
697
698 CtrDrbgAes128 = 100,
700 CtrDrbgAes192 = 101,
701 CtrDrbgAes256 = 102,
702 HashDrbgSha256 = 103,
703 HashDrbgSha384 = 104,
704 HashDrbgSha512 = 105,
705 HmacDrbgSha256 = 106,
706 HmacDrbgSha384 = 107,
707 HmacDrbgSha512 = 108,
708
709 HkdfSha1 = 120,
711 HkdfSha256 = 121,
712 HkdfSha384 = 122,
713 HkdfSha512 = 123,
714 KbkdfHmacSha256 = 130,
715 KbkdfHmacSha384 = 131,
716 KbkdfHmacSha512 = 132,
717 KbkdfCmacAes128 = 133,
718 KbkdfCmacAes192 = 134,
719 KbkdfCmacAes256 = 135,
720 Pbkdf2HmacSha1 = 140,
721 Pbkdf2HmacSha224 = 141,
722 Pbkdf2HmacSha256 = 142,
723 Pbkdf2HmacSha384 = 143,
724 Pbkdf2HmacSha512 = 144,
725
726 RsaKeygen2048 = 150,
728 RsaPkcs1v15Sign2048 = 151,
729 RsaPssSign2048 = 152,
730 RsaOaep2048 = 153,
731 RsaPkcs1v15Verify2048 = 154,
732 RsaPssVerify2048 = 155,
733 RsaKeygen3072 = 160,
734 RsaPkcs1v15Sign3072 = 161,
735 RsaPssSign3072 = 162,
736 RsaOaep3072 = 163,
737 RsaPkcs1v15Verify3072 = 164,
738 RsaPssVerify3072 = 165,
739 RsaKeygen4096 = 170,
740 RsaPkcs1v15Sign4096 = 171,
741 RsaPssSign4096 = 172,
742 RsaOaep4096 = 173,
743 RsaPkcs1v15Verify4096 = 174,
744 RsaPssVerify4096 = 175,
745
746 EcdsaP256Sign = 200,
748 EcdsaP256Verify = 201,
749 EcdsaP256Keygen = 202,
750 EcdsaP384Sign = 210,
751 EcdsaP384Verify = 211,
752 EcdsaP384Keygen = 212,
753
754 EcdhP256 = 220,
756 EcdhP384 = 221,
757
758 Ed25519Sign = 230,
760 Ed25519Verify = 231,
761 Ed25519Keygen = 232,
762
763 Tls12Kdf = 240,
765 Tls13Kdf = 241,
766
767 MlKem1024Encaps = 300,
769 MlKem1024Decaps = 301,
770 MlKem1024Keygen = 302,
771 MlKem512Encaps = 303,
772 MlKem512Decaps = 304,
773 MlKem512Keygen = 305,
774 MlKem768Encaps = 306,
775 MlKem768Decaps = 307,
776 MlKem768Keygen = 308,
777
778 MlDsa87Sign = 310,
780 MlDsa87Verify = 311,
781 MlDsa87Keygen = 312,
782 MlDsa44Sign = 313,
783 MlDsa44Verify = 314,
784 MlDsa44Keygen = 315,
785 MlDsa65Sign = 316,
786 MlDsa65Verify = 317,
787 MlDsa65Keygen = 318,
788
789 SlhDsaSha2256sKeygen = 320,
794 SlhDsaSha2256sSign = 321,
795 SlhDsaSha2256sVerify = 322,
796 SlhDsaSha2128sKeygen = 323,
797 SlhDsaSha2128sSign = 324,
798 SlhDsaSha2128sVerify = 325,
799 SlhDsaSha2128fKeygen = 326,
800 SlhDsaSha2128fSign = 327,
801 SlhDsaSha2128fVerify = 328,
802 SlhDsaSha2192sKeygen = 329,
803 SlhDsaSha2192sSign = 330,
804 SlhDsaSha2192sVerify = 331,
805 SlhDsaSha2192fKeygen = 332,
806 SlhDsaSha2192fSign = 333,
807 SlhDsaSha2192fVerify = 334,
808 SlhDsaSha2256fKeygen = 335,
809 SlhDsaSha2256fSign = 336,
810 SlhDsaSha2256fVerify = 337,
811 SlhDsaShake128sKeygen = 338,
812 SlhDsaShake128sSign = 339,
813 SlhDsaShake128sVerify = 340,
814 SlhDsaShake128fKeygen = 341,
815 SlhDsaShake128fSign = 342,
816 SlhDsaShake128fVerify = 343,
817 SlhDsaShake192sKeygen = 344,
818 SlhDsaShake192sSign = 345,
819 SlhDsaShake192sVerify = 346,
820 SlhDsaShake192fKeygen = 347,
821 SlhDsaShake192fSign = 348,
822 SlhDsaShake192fVerify = 349,
823 SlhDsaShake256sKeygen = 350,
824 SlhDsaShake256sSign = 351,
825 SlhDsaShake256sVerify = 352,
826 SlhDsaShake256fKeygen = 353,
827 SlhDsaShake256fSign = 354,
828 SlhDsaShake256fVerify = 355,
829
830 LmsSha256M32H5W1Sign = 500,
841 LmsSha256M32H5W1Verify = 501,
842 LmsSha256M32H5W2Sign = 502,
843 LmsSha256M32H5W2Verify = 503,
844 LmsSha256M32H5W4Sign = 504,
845 LmsSha256M32H5W4Verify = 505,
846 LmsSha256M32H5W8Sign = 506,
847 LmsSha256M32H5W8Verify = 507,
848 LmsSha256M32H10W1Sign = 508,
849 LmsSha256M32H10W1Verify = 509,
850 LmsSha256M32H10W2Sign = 510,
851 LmsSha256M32H10W2Verify = 511,
852 LmsSha256M32H10W4Sign = 512,
853 LmsSha256M32H10W4Verify = 513,
854 LmsSha256M32H10W8Sign = 514,
855 LmsSha256M32H10W8Verify = 515,
856 LmsSha256M32H15W1Sign = 516,
857 LmsSha256M32H15W1Verify = 517,
858 LmsSha256M32H15W2Sign = 518,
859 LmsSha256M32H15W2Verify = 519,
860 LmsSha256M32H15W4Sign = 520,
861 LmsSha256M32H15W4Verify = 521,
862 LmsSha256M32H15W8Sign = 522,
863 LmsSha256M32H15W8Verify = 523,
864 LmsSha256M32H20W1Sign = 524,
865 LmsSha256M32H20W1Verify = 525,
866 LmsSha256M32H20W2Sign = 526,
867 LmsSha256M32H20W2Verify = 527,
868 LmsSha256M32H20W4Sign = 528,
869 LmsSha256M32H20W4Verify = 529,
870 LmsSha256M32H20W8Sign = 530,
871 LmsSha256M32H20W8Verify = 531,
872 LmsSha256M32H25W1Sign = 532,
873 LmsSha256M32H25W1Verify = 533,
874 LmsSha256M32H25W2Sign = 534,
875 LmsSha256M32H25W2Verify = 535,
876 LmsSha256M32H25W4Sign = 536,
877 LmsSha256M32H25W4Verify = 537,
878 LmsSha256M32H25W8Sign = 538,
879 LmsSha256M32H25W8Verify = 539,
880
881 LmsSha256M24H5W1Sign = 540,
883 LmsSha256M24H5W1Verify = 541,
884 LmsSha256M24H5W2Sign = 542,
885 LmsSha256M24H5W2Verify = 543,
886 LmsSha256M24H5W4Sign = 544,
887 LmsSha256M24H5W4Verify = 545,
888 LmsSha256M24H5W8Sign = 546,
889 LmsSha256M24H5W8Verify = 547,
890 LmsSha256M24H10W1Sign = 548,
891 LmsSha256M24H10W1Verify = 549,
892 LmsSha256M24H10W2Sign = 550,
893 LmsSha256M24H10W2Verify = 551,
894 LmsSha256M24H10W4Sign = 552,
895 LmsSha256M24H10W4Verify = 553,
896 LmsSha256M24H10W8Sign = 554,
897 LmsSha256M24H10W8Verify = 555,
898 LmsSha256M24H15W1Sign = 556,
899 LmsSha256M24H15W1Verify = 557,
900 LmsSha256M24H15W2Sign = 558,
901 LmsSha256M24H15W2Verify = 559,
902 LmsSha256M24H15W4Sign = 560,
903 LmsSha256M24H15W4Verify = 561,
904 LmsSha256M24H15W8Sign = 562,
905 LmsSha256M24H15W8Verify = 563,
906 LmsSha256M24H20W1Sign = 564,
907 LmsSha256M24H20W1Verify = 565,
908 LmsSha256M24H20W2Sign = 566,
909 LmsSha256M24H20W2Verify = 567,
910 LmsSha256M24H20W4Sign = 568,
911 LmsSha256M24H20W4Verify = 569,
912 LmsSha256M24H20W8Sign = 570,
913 LmsSha256M24H20W8Verify = 571,
914 LmsSha256M24H25W1Sign = 572,
915 LmsSha256M24H25W1Verify = 573,
916 LmsSha256M24H25W2Sign = 574,
917 LmsSha256M24H25W2Verify = 575,
918 LmsSha256M24H25W4Sign = 576,
919 LmsSha256M24H25W4Verify = 577,
920 LmsSha256M24H25W8Sign = 578,
921 LmsSha256M24H25W8Verify = 579,
922
923 LmsShakeM32H5W1Sign = 580,
925 LmsShakeM32H5W1Verify = 581,
926 LmsShakeM32H5W2Sign = 582,
927 LmsShakeM32H5W2Verify = 583,
928 LmsShakeM32H5W4Sign = 584,
929 LmsShakeM32H5W4Verify = 585,
930 LmsShakeM32H5W8Sign = 586,
931 LmsShakeM32H5W8Verify = 587,
932 LmsShakeM32H10W1Sign = 588,
933 LmsShakeM32H10W1Verify = 589,
934 LmsShakeM32H10W2Sign = 590,
935 LmsShakeM32H10W2Verify = 591,
936 LmsShakeM32H10W4Sign = 592,
937 LmsShakeM32H10W4Verify = 593,
938 LmsShakeM32H10W8Sign = 594,
939 LmsShakeM32H10W8Verify = 595,
940 LmsShakeM32H15W1Sign = 596,
941 LmsShakeM32H15W1Verify = 597,
942 LmsShakeM32H15W2Sign = 598,
943 LmsShakeM32H15W2Verify = 599,
944 LmsShakeM32H15W4Sign = 600,
945 LmsShakeM32H15W4Verify = 601,
946 LmsShakeM32H15W8Sign = 602,
947 LmsShakeM32H15W8Verify = 603,
948 LmsShakeM32H20W1Sign = 604,
949 LmsShakeM32H20W1Verify = 605,
950 LmsShakeM32H20W2Sign = 606,
951 LmsShakeM32H20W2Verify = 607,
952 LmsShakeM32H20W4Sign = 608,
953 LmsShakeM32H20W4Verify = 609,
954 LmsShakeM32H20W8Sign = 610,
955 LmsShakeM32H20W8Verify = 611,
956 LmsShakeM32H25W1Sign = 612,
957 LmsShakeM32H25W1Verify = 613,
958 LmsShakeM32H25W2Sign = 614,
959 LmsShakeM32H25W2Verify = 615,
960 LmsShakeM32H25W4Sign = 616,
961 LmsShakeM32H25W4Verify = 617,
962 LmsShakeM32H25W8Sign = 618,
963 LmsShakeM32H25W8Verify = 619,
964
965 LmsShakeM24H5W1Sign = 620,
967 LmsShakeM24H5W1Verify = 621,
968 LmsShakeM24H5W2Sign = 622,
969 LmsShakeM24H5W2Verify = 623,
970 LmsShakeM24H5W4Sign = 624,
971 LmsShakeM24H5W4Verify = 625,
972 LmsShakeM24H5W8Sign = 626,
973 LmsShakeM24H5W8Verify = 627,
974 LmsShakeM24H10W1Sign = 628,
975 LmsShakeM24H10W1Verify = 629,
976 LmsShakeM24H10W2Sign = 630,
977 LmsShakeM24H10W2Verify = 631,
978 LmsShakeM24H10W4Sign = 632,
979 LmsShakeM24H10W4Verify = 633,
980 LmsShakeM24H10W8Sign = 634,
981 LmsShakeM24H10W8Verify = 635,
982 LmsShakeM24H15W1Sign = 636,
983 LmsShakeM24H15W1Verify = 637,
984 LmsShakeM24H15W2Sign = 638,
985 LmsShakeM24H15W2Verify = 639,
986 LmsShakeM24H15W4Sign = 640,
987 LmsShakeM24H15W4Verify = 641,
988 LmsShakeM24H15W8Sign = 642,
989 LmsShakeM24H15W8Verify = 643,
990 LmsShakeM24H20W1Sign = 644,
991 LmsShakeM24H20W1Verify = 645,
992 LmsShakeM24H20W2Sign = 646,
993 LmsShakeM24H20W2Verify = 647,
994 LmsShakeM24H20W4Sign = 648,
995 LmsShakeM24H20W4Verify = 649,
996 LmsShakeM24H20W8Sign = 650,
997 LmsShakeM24H20W8Verify = 651,
998 LmsShakeM24H25W1Sign = 652,
999 LmsShakeM24H25W1Verify = 653,
1000 LmsShakeM24H25W2Sign = 654,
1001 LmsShakeM24H25W2Verify = 655,
1002 LmsShakeM24H25W4Sign = 656,
1003 LmsShakeM24H25W4Verify = 657,
1004 LmsShakeM24H25W8Sign = 658,
1005 LmsShakeM24H25W8Verify = 659,
1006
1007 XmssVerify = 371,
1010
1011 Dh3072 = 380,
1014}
1015
1016impl fmt::Display for Service {
1017 #[allow(clippy::too_many_lines)]
1021 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1022 let name = match self {
1023 Self::Sha1 => "SHA-1",
1024 Self::Sha224 => "SHA-224",
1025 Self::Sha256 => "SHA-256",
1026 Self::Sha384 => "SHA-384",
1027 Self::Sha512 => "SHA-512",
1028 Self::Sha512_224 => "SHA-512/224",
1029 Self::Sha512_256 => "SHA-512/256",
1030 Self::Sha3_224 => "SHA3-224",
1031 Self::Sha3_256 => "SHA3-256",
1032 Self::Sha3_384 => "SHA3-384",
1033 Self::Sha3_512 => "SHA3-512",
1034 Self::Shake128 => "SHAKE128",
1035 Self::Shake256 => "SHAKE256",
1036 Self::CShake128 => "cSHAKE128",
1037 Self::CShake256 => "cSHAKE256",
1038 Self::Kmac128 => "KMAC128",
1039 Self::Kmac256 => "KMAC256",
1040 Self::KmacXof128 => "KMACXOF128",
1041 Self::KmacXof256 => "KMACXOF256",
1042 Self::TupleHash128 => "TupleHash128",
1043 Self::TupleHash256 => "TupleHash256",
1044 Self::TupleHashXof128 => "TupleHashXOF128",
1045 Self::TupleHashXof256 => "TupleHashXOF256",
1046 Self::ParallelHash128 => "ParallelHash128",
1047 Self::ParallelHash256 => "ParallelHash256",
1048 Self::ParallelHashXof128 => "ParallelHashXOF128",
1049 Self::ParallelHashXof256 => "ParallelHashXOF256",
1050 Self::HmacSha1 => "HMAC-SHA-1",
1051 Self::HmacSha224 => "HMAC-SHA-224",
1052 Self::HmacSha256 => "HMAC-SHA-256",
1053 Self::HmacSha384 => "HMAC-SHA-384",
1054 Self::HmacSha512 => "HMAC-SHA-512",
1055 Self::HmacSha512_224 => "HMAC-SHA-512/224",
1056 Self::HmacSha512_256 => "HMAC-SHA-512/256",
1057 Self::HmacSha3_224 => "HMAC-SHA3-224",
1058 Self::HmacSha3_256 => "HMAC-SHA3-256",
1059 Self::HmacSha3_384 => "HMAC-SHA3-384",
1060 Self::HmacSha3_512 => "HMAC-SHA3-512",
1061 Self::CmacAes128 => "CMAC-AES-128",
1062 Self::CmacAes192 => "CMAC-AES-192",
1063 Self::CmacAes256 => "CMAC-AES-256",
1064 Self::Aes128Ecb => "AES-128-ECB",
1065 Self::Aes128Cbc => "AES-128-CBC",
1066 Self::Aes128Ctr => "AES-128-CTR",
1067 Self::Aes128Gcm => "AES-128-GCM",
1068 Self::Aes128Ccm => "AES-128-CCM",
1069 Self::Aes128Kw => "AES-128-KW",
1070 Self::Aes128Kwp => "AES-128-KWP",
1071 Self::Aes192Ecb => "AES-192-ECB",
1072 Self::Aes192Cbc => "AES-192-CBC",
1073 Self::Aes192Ctr => "AES-192-CTR",
1074 Self::Aes192Gcm => "AES-192-GCM",
1075 Self::Aes192Ccm => "AES-192-CCM",
1076 Self::Aes192Kw => "AES-192-KW",
1077 Self::Aes192Kwp => "AES-192-KWP",
1078 Self::Aes256Ecb => "AES-256-ECB",
1079 Self::Aes256Cbc => "AES-256-CBC",
1080 Self::Aes256Ctr => "AES-256-CTR",
1081 Self::Aes256Gcm => "AES-256-GCM",
1082 Self::Aes256Ccm => "AES-256-CCM",
1083 Self::Aes256Kw => "AES-256-KW",
1084 Self::Aes256Kwp => "AES-256-KWP",
1085 Self::Aes128 => "AES-128",
1086 Self::Aes192 => "AES-192",
1087 Self::Aes256 => "AES-256",
1088 Self::CtrDrbgAes128 => "CTR_DRBG-AES-128",
1089 Self::CtrDrbgAes192 => "CTR_DRBG-AES-192",
1090 Self::CtrDrbgAes256 => "CTR_DRBG-AES-256",
1091 Self::HashDrbgSha256 => "Hash_DRBG-SHA-256",
1092 Self::HashDrbgSha384 => "Hash_DRBG-SHA-384",
1093 Self::HashDrbgSha512 => "Hash_DRBG-SHA-512",
1094 Self::HmacDrbgSha256 => "HMAC_DRBG-SHA-256",
1095 Self::HmacDrbgSha384 => "HMAC_DRBG-SHA-384",
1096 Self::HmacDrbgSha512 => "HMAC_DRBG-SHA-512",
1097 Self::HkdfSha1 => "HKDF-SHA-1",
1098 Self::HkdfSha256 => "HKDF-SHA-256",
1099 Self::HkdfSha384 => "HKDF-SHA-384",
1100 Self::HkdfSha512 => "HKDF-SHA-512",
1101 Self::KbkdfHmacSha256 => "KBKDF-HMAC-SHA-256",
1102 Self::KbkdfHmacSha384 => "KBKDF-HMAC-SHA-384",
1103 Self::KbkdfHmacSha512 => "KBKDF-HMAC-SHA-512",
1104 Self::KbkdfCmacAes128 => "KBKDF-CMAC-AES-128",
1105 Self::KbkdfCmacAes192 => "KBKDF-CMAC-AES-192",
1106 Self::KbkdfCmacAes256 => "KBKDF-CMAC-AES-256",
1107 Self::Pbkdf2HmacSha1 => "PBKDF2-HMAC-SHA-1",
1108 Self::Pbkdf2HmacSha224 => "PBKDF2-HMAC-SHA-224",
1109 Self::Pbkdf2HmacSha256 => "PBKDF2-HMAC-SHA-256",
1110 Self::Pbkdf2HmacSha384 => "PBKDF2-HMAC-SHA-384",
1111 Self::Pbkdf2HmacSha512 => "PBKDF2-HMAC-SHA-512",
1112 Self::RsaKeygen2048 => "RSA-2048 keygen",
1113 Self::RsaPkcs1v15Sign2048 => "RSA-PKCS1v1.5-Sign-2048",
1114 Self::RsaPssSign2048 => "RSA-PSS-Sign-2048",
1115 Self::RsaOaep2048 => "RSA-OAEP-2048",
1116 Self::RsaPkcs1v15Verify2048 => "RSA-PKCS1v1.5-Verify-2048",
1117 Self::RsaPssVerify2048 => "RSA-PSS-Verify-2048",
1118 Self::RsaKeygen3072 => "RSA-3072 keygen",
1119 Self::RsaPkcs1v15Sign3072 => "RSA-PKCS1v1.5-Sign-3072",
1120 Self::RsaPssSign3072 => "RSA-PSS-Sign-3072",
1121 Self::RsaOaep3072 => "RSA-OAEP-3072",
1122 Self::RsaPkcs1v15Verify3072 => "RSA-PKCS1v1.5-Verify-3072",
1123 Self::RsaPssVerify3072 => "RSA-PSS-Verify-3072",
1124 Self::RsaKeygen4096 => "RSA-4096 keygen",
1125 Self::RsaPkcs1v15Sign4096 => "RSA-PKCS1v1.5-Sign-4096",
1126 Self::RsaPssSign4096 => "RSA-PSS-Sign-4096",
1127 Self::RsaOaep4096 => "RSA-OAEP-4096",
1128 Self::RsaPkcs1v15Verify4096 => "RSA-PKCS1v1.5-Verify-4096",
1129 Self::RsaPssVerify4096 => "RSA-PSS-Verify-4096",
1130 Self::EcdsaP256Sign => "ECDSA-P256 sign",
1131 Self::EcdsaP256Verify => "ECDSA-P256 verify",
1132 Self::EcdsaP256Keygen => "ECDSA-P256 keygen",
1133 Self::EcdsaP384Sign => "ECDSA-P384 sign",
1134 Self::EcdsaP384Verify => "ECDSA-P384 verify",
1135 Self::EcdsaP384Keygen => "ECDSA-P384 keygen",
1136 Self::EcdhP256 => "ECDH-P256",
1137 Self::EcdhP384 => "ECDH-P384",
1138 Self::Ed25519Sign => "Ed25519 sign",
1139 Self::Ed25519Verify => "Ed25519 verify",
1140 Self::Ed25519Keygen => "Ed25519 keygen",
1141 Self::Tls12Kdf => "TLS 1.2 KDF",
1142 Self::Tls13Kdf => "TLS 1.3 KDF",
1143 Self::MlKem1024Encaps => "ML-KEM-1024 encaps",
1144 Self::MlKem1024Decaps => "ML-KEM-1024 decaps",
1145 Self::MlKem1024Keygen => "ML-KEM-1024 keygen",
1146 Self::MlKem512Encaps => "ML-KEM-512 encaps",
1147 Self::MlKem512Decaps => "ML-KEM-512 decaps",
1148 Self::MlKem512Keygen => "ML-KEM-512 keygen",
1149 Self::MlKem768Encaps => "ML-KEM-768 encaps",
1150 Self::MlKem768Decaps => "ML-KEM-768 decaps",
1151 Self::MlKem768Keygen => "ML-KEM-768 keygen",
1152 Self::MlDsa87Sign => "ML-DSA-87 sign",
1153 Self::MlDsa87Verify => "ML-DSA-87 verify",
1154 Self::MlDsa87Keygen => "ML-DSA-87 keygen",
1155 Self::MlDsa44Sign => "ML-DSA-44 sign",
1156 Self::MlDsa44Verify => "ML-DSA-44 verify",
1157 Self::MlDsa44Keygen => "ML-DSA-44 keygen",
1158 Self::MlDsa65Sign => "ML-DSA-65 sign",
1159 Self::MlDsa65Verify => "ML-DSA-65 verify",
1160 Self::MlDsa65Keygen => "ML-DSA-65 keygen",
1161 Self::SlhDsaSha2256sKeygen => "SLH-DSA-SHA2-256s keygen",
1162 Self::SlhDsaSha2256sSign => "SLH-DSA-SHA2-256s sign",
1163 Self::SlhDsaSha2256sVerify => "SLH-DSA-SHA2-256s verify",
1164 Self::SlhDsaSha2128sKeygen => "SLH-DSA-SHA2-128s keygen",
1165 Self::SlhDsaSha2128sSign => "SLH-DSA-SHA2-128s sign",
1166 Self::SlhDsaSha2128sVerify => "SLH-DSA-SHA2-128s verify",
1167 Self::SlhDsaSha2128fKeygen => "SLH-DSA-SHA2-128f keygen",
1168 Self::SlhDsaSha2128fSign => "SLH-DSA-SHA2-128f sign",
1169 Self::SlhDsaSha2128fVerify => "SLH-DSA-SHA2-128f verify",
1170 Self::SlhDsaSha2192sKeygen => "SLH-DSA-SHA2-192s keygen",
1171 Self::SlhDsaSha2192sSign => "SLH-DSA-SHA2-192s sign",
1172 Self::SlhDsaSha2192sVerify => "SLH-DSA-SHA2-192s verify",
1173 Self::SlhDsaSha2192fKeygen => "SLH-DSA-SHA2-192f keygen",
1174 Self::SlhDsaSha2192fSign => "SLH-DSA-SHA2-192f sign",
1175 Self::SlhDsaSha2192fVerify => "SLH-DSA-SHA2-192f verify",
1176 Self::SlhDsaSha2256fKeygen => "SLH-DSA-SHA2-256f keygen",
1177 Self::SlhDsaSha2256fSign => "SLH-DSA-SHA2-256f sign",
1178 Self::SlhDsaSha2256fVerify => "SLH-DSA-SHA2-256f verify",
1179 Self::SlhDsaShake128sKeygen => "SLH-DSA-SHAKE-128s keygen",
1180 Self::SlhDsaShake128sSign => "SLH-DSA-SHAKE-128s sign",
1181 Self::SlhDsaShake128sVerify => "SLH-DSA-SHAKE-128s verify",
1182 Self::SlhDsaShake128fKeygen => "SLH-DSA-SHAKE-128f keygen",
1183 Self::SlhDsaShake128fSign => "SLH-DSA-SHAKE-128f sign",
1184 Self::SlhDsaShake128fVerify => "SLH-DSA-SHAKE-128f verify",
1185 Self::SlhDsaShake192sKeygen => "SLH-DSA-SHAKE-192s keygen",
1186 Self::SlhDsaShake192sSign => "SLH-DSA-SHAKE-192s sign",
1187 Self::SlhDsaShake192sVerify => "SLH-DSA-SHAKE-192s verify",
1188 Self::SlhDsaShake192fKeygen => "SLH-DSA-SHAKE-192f keygen",
1189 Self::SlhDsaShake192fSign => "SLH-DSA-SHAKE-192f sign",
1190 Self::SlhDsaShake192fVerify => "SLH-DSA-SHAKE-192f verify",
1191 Self::SlhDsaShake256sKeygen => "SLH-DSA-SHAKE-256s keygen",
1192 Self::SlhDsaShake256sSign => "SLH-DSA-SHAKE-256s sign",
1193 Self::SlhDsaShake256sVerify => "SLH-DSA-SHAKE-256s verify",
1194 Self::SlhDsaShake256fKeygen => "SLH-DSA-SHAKE-256f keygen",
1195 Self::SlhDsaShake256fSign => "SLH-DSA-SHAKE-256f sign",
1196 Self::SlhDsaShake256fVerify => "SLH-DSA-SHAKE-256f verify",
1197 Self::LmsSha256M32H5W1Sign => "LMS SHA-256 M=32 H=5 W=1 sign",
1198 Self::LmsSha256M32H5W1Verify => "LMS SHA-256 M=32 H=5 W=1 verify",
1199 Self::LmsSha256M32H5W2Sign => "LMS SHA-256 M=32 H=5 W=2 sign",
1200 Self::LmsSha256M32H5W2Verify => "LMS SHA-256 M=32 H=5 W=2 verify",
1201 Self::LmsSha256M32H5W4Sign => "LMS SHA-256 M=32 H=5 W=4 sign",
1202 Self::LmsSha256M32H5W4Verify => "LMS SHA-256 M=32 H=5 W=4 verify",
1203 Self::LmsSha256M32H5W8Sign => "LMS SHA-256 M=32 H=5 W=8 sign",
1204 Self::LmsSha256M32H5W8Verify => "LMS SHA-256 M=32 H=5 W=8 verify",
1205 Self::LmsSha256M32H10W1Sign => "LMS SHA-256 M=32 H=10 W=1 sign",
1206 Self::LmsSha256M32H10W1Verify => "LMS SHA-256 M=32 H=10 W=1 verify",
1207 Self::LmsSha256M32H10W2Sign => "LMS SHA-256 M=32 H=10 W=2 sign",
1208 Self::LmsSha256M32H10W2Verify => "LMS SHA-256 M=32 H=10 W=2 verify",
1209 Self::LmsSha256M32H10W4Sign => "LMS SHA-256 M=32 H=10 W=4 sign",
1210 Self::LmsSha256M32H10W4Verify => "LMS SHA-256 M=32 H=10 W=4 verify",
1211 Self::LmsSha256M32H10W8Sign => "LMS SHA-256 M=32 H=10 W=8 sign",
1212 Self::LmsSha256M32H10W8Verify => "LMS SHA-256 M=32 H=10 W=8 verify",
1213 Self::LmsSha256M32H15W1Sign => "LMS SHA-256 M=32 H=15 W=1 sign",
1214 Self::LmsSha256M32H15W1Verify => "LMS SHA-256 M=32 H=15 W=1 verify",
1215 Self::LmsSha256M32H15W2Sign => "LMS SHA-256 M=32 H=15 W=2 sign",
1216 Self::LmsSha256M32H15W2Verify => "LMS SHA-256 M=32 H=15 W=2 verify",
1217 Self::LmsSha256M32H15W4Sign => "LMS SHA-256 M=32 H=15 W=4 sign",
1218 Self::LmsSha256M32H15W4Verify => "LMS SHA-256 M=32 H=15 W=4 verify",
1219 Self::LmsSha256M32H15W8Sign => "LMS SHA-256 M=32 H=15 W=8 sign",
1220 Self::LmsSha256M32H15W8Verify => "LMS SHA-256 M=32 H=15 W=8 verify",
1221 Self::LmsSha256M32H20W1Sign => "LMS SHA-256 M=32 H=20 W=1 sign",
1222 Self::LmsSha256M32H20W1Verify => "LMS SHA-256 M=32 H=20 W=1 verify",
1223 Self::LmsSha256M32H20W2Sign => "LMS SHA-256 M=32 H=20 W=2 sign",
1224 Self::LmsSha256M32H20W2Verify => "LMS SHA-256 M=32 H=20 W=2 verify",
1225 Self::LmsSha256M32H20W4Sign => "LMS SHA-256 M=32 H=20 W=4 sign",
1226 Self::LmsSha256M32H20W4Verify => "LMS SHA-256 M=32 H=20 W=4 verify",
1227 Self::LmsSha256M32H20W8Sign => "LMS SHA-256 M=32 H=20 W=8 sign",
1228 Self::LmsSha256M32H20W8Verify => "LMS SHA-256 M=32 H=20 W=8 verify",
1229 Self::LmsSha256M32H25W1Sign => "LMS SHA-256 M=32 H=25 W=1 sign",
1230 Self::LmsSha256M32H25W1Verify => "LMS SHA-256 M=32 H=25 W=1 verify",
1231 Self::LmsSha256M32H25W2Sign => "LMS SHA-256 M=32 H=25 W=2 sign",
1232 Self::LmsSha256M32H25W2Verify => "LMS SHA-256 M=32 H=25 W=2 verify",
1233 Self::LmsSha256M32H25W4Sign => "LMS SHA-256 M=32 H=25 W=4 sign",
1234 Self::LmsSha256M32H25W4Verify => "LMS SHA-256 M=32 H=25 W=4 verify",
1235 Self::LmsSha256M32H25W8Sign => "LMS SHA-256 M=32 H=25 W=8 sign",
1236 Self::LmsSha256M32H25W8Verify => "LMS SHA-256 M=32 H=25 W=8 verify",
1237 Self::LmsSha256M24H5W1Sign => "LMS SHA-256 M=24 H=5 W=1 sign",
1238 Self::LmsSha256M24H5W1Verify => "LMS SHA-256 M=24 H=5 W=1 verify",
1239 Self::LmsSha256M24H5W2Sign => "LMS SHA-256 M=24 H=5 W=2 sign",
1240 Self::LmsSha256M24H5W2Verify => "LMS SHA-256 M=24 H=5 W=2 verify",
1241 Self::LmsSha256M24H5W4Sign => "LMS SHA-256 M=24 H=5 W=4 sign",
1242 Self::LmsSha256M24H5W4Verify => "LMS SHA-256 M=24 H=5 W=4 verify",
1243 Self::LmsSha256M24H5W8Sign => "LMS SHA-256 M=24 H=5 W=8 sign",
1244 Self::LmsSha256M24H5W8Verify => "LMS SHA-256 M=24 H=5 W=8 verify",
1245 Self::LmsSha256M24H10W1Sign => "LMS SHA-256 M=24 H=10 W=1 sign",
1246 Self::LmsSha256M24H10W1Verify => "LMS SHA-256 M=24 H=10 W=1 verify",
1247 Self::LmsSha256M24H10W2Sign => "LMS SHA-256 M=24 H=10 W=2 sign",
1248 Self::LmsSha256M24H10W2Verify => "LMS SHA-256 M=24 H=10 W=2 verify",
1249 Self::LmsSha256M24H10W4Sign => "LMS SHA-256 M=24 H=10 W=4 sign",
1250 Self::LmsSha256M24H10W4Verify => "LMS SHA-256 M=24 H=10 W=4 verify",
1251 Self::LmsSha256M24H10W8Sign => "LMS SHA-256 M=24 H=10 W=8 sign",
1252 Self::LmsSha256M24H10W8Verify => "LMS SHA-256 M=24 H=10 W=8 verify",
1253 Self::LmsSha256M24H15W1Sign => "LMS SHA-256 M=24 H=15 W=1 sign",
1254 Self::LmsSha256M24H15W1Verify => "LMS SHA-256 M=24 H=15 W=1 verify",
1255 Self::LmsSha256M24H15W2Sign => "LMS SHA-256 M=24 H=15 W=2 sign",
1256 Self::LmsSha256M24H15W2Verify => "LMS SHA-256 M=24 H=15 W=2 verify",
1257 Self::LmsSha256M24H15W4Sign => "LMS SHA-256 M=24 H=15 W=4 sign",
1258 Self::LmsSha256M24H15W4Verify => "LMS SHA-256 M=24 H=15 W=4 verify",
1259 Self::LmsSha256M24H15W8Sign => "LMS SHA-256 M=24 H=15 W=8 sign",
1260 Self::LmsSha256M24H15W8Verify => "LMS SHA-256 M=24 H=15 W=8 verify",
1261 Self::LmsSha256M24H20W1Sign => "LMS SHA-256 M=24 H=20 W=1 sign",
1262 Self::LmsSha256M24H20W1Verify => "LMS SHA-256 M=24 H=20 W=1 verify",
1263 Self::LmsSha256M24H20W2Sign => "LMS SHA-256 M=24 H=20 W=2 sign",
1264 Self::LmsSha256M24H20W2Verify => "LMS SHA-256 M=24 H=20 W=2 verify",
1265 Self::LmsSha256M24H20W4Sign => "LMS SHA-256 M=24 H=20 W=4 sign",
1266 Self::LmsSha256M24H20W4Verify => "LMS SHA-256 M=24 H=20 W=4 verify",
1267 Self::LmsSha256M24H20W8Sign => "LMS SHA-256 M=24 H=20 W=8 sign",
1268 Self::LmsSha256M24H20W8Verify => "LMS SHA-256 M=24 H=20 W=8 verify",
1269 Self::LmsSha256M24H25W1Sign => "LMS SHA-256 M=24 H=25 W=1 sign",
1270 Self::LmsSha256M24H25W1Verify => "LMS SHA-256 M=24 H=25 W=1 verify",
1271 Self::LmsSha256M24H25W2Sign => "LMS SHA-256 M=24 H=25 W=2 sign",
1272 Self::LmsSha256M24H25W2Verify => "LMS SHA-256 M=24 H=25 W=2 verify",
1273 Self::LmsSha256M24H25W4Sign => "LMS SHA-256 M=24 H=25 W=4 sign",
1274 Self::LmsSha256M24H25W4Verify => "LMS SHA-256 M=24 H=25 W=4 verify",
1275 Self::LmsSha256M24H25W8Sign => "LMS SHA-256 M=24 H=25 W=8 sign",
1276 Self::LmsSha256M24H25W8Verify => "LMS SHA-256 M=24 H=25 W=8 verify",
1277 Self::LmsShakeM32H5W1Sign => "LMS SHAKE M=32 H=5 W=1 sign",
1278 Self::LmsShakeM32H5W1Verify => "LMS SHAKE M=32 H=5 W=1 verify",
1279 Self::LmsShakeM32H5W2Sign => "LMS SHAKE M=32 H=5 W=2 sign",
1280 Self::LmsShakeM32H5W2Verify => "LMS SHAKE M=32 H=5 W=2 verify",
1281 Self::LmsShakeM32H5W4Sign => "LMS SHAKE M=32 H=5 W=4 sign",
1282 Self::LmsShakeM32H5W4Verify => "LMS SHAKE M=32 H=5 W=4 verify",
1283 Self::LmsShakeM32H5W8Sign => "LMS SHAKE M=32 H=5 W=8 sign",
1284 Self::LmsShakeM32H5W8Verify => "LMS SHAKE M=32 H=5 W=8 verify",
1285 Self::LmsShakeM32H10W1Sign => "LMS SHAKE M=32 H=10 W=1 sign",
1286 Self::LmsShakeM32H10W1Verify => "LMS SHAKE M=32 H=10 W=1 verify",
1287 Self::LmsShakeM32H10W2Sign => "LMS SHAKE M=32 H=10 W=2 sign",
1288 Self::LmsShakeM32H10W2Verify => "LMS SHAKE M=32 H=10 W=2 verify",
1289 Self::LmsShakeM32H10W4Sign => "LMS SHAKE M=32 H=10 W=4 sign",
1290 Self::LmsShakeM32H10W4Verify => "LMS SHAKE M=32 H=10 W=4 verify",
1291 Self::LmsShakeM32H10W8Sign => "LMS SHAKE M=32 H=10 W=8 sign",
1292 Self::LmsShakeM32H10W8Verify => "LMS SHAKE M=32 H=10 W=8 verify",
1293 Self::LmsShakeM32H15W1Sign => "LMS SHAKE M=32 H=15 W=1 sign",
1294 Self::LmsShakeM32H15W1Verify => "LMS SHAKE M=32 H=15 W=1 verify",
1295 Self::LmsShakeM32H15W2Sign => "LMS SHAKE M=32 H=15 W=2 sign",
1296 Self::LmsShakeM32H15W2Verify => "LMS SHAKE M=32 H=15 W=2 verify",
1297 Self::LmsShakeM32H15W4Sign => "LMS SHAKE M=32 H=15 W=4 sign",
1298 Self::LmsShakeM32H15W4Verify => "LMS SHAKE M=32 H=15 W=4 verify",
1299 Self::LmsShakeM32H15W8Sign => "LMS SHAKE M=32 H=15 W=8 sign",
1300 Self::LmsShakeM32H15W8Verify => "LMS SHAKE M=32 H=15 W=8 verify",
1301 Self::LmsShakeM32H20W1Sign => "LMS SHAKE M=32 H=20 W=1 sign",
1302 Self::LmsShakeM32H20W1Verify => "LMS SHAKE M=32 H=20 W=1 verify",
1303 Self::LmsShakeM32H20W2Sign => "LMS SHAKE M=32 H=20 W=2 sign",
1304 Self::LmsShakeM32H20W2Verify => "LMS SHAKE M=32 H=20 W=2 verify",
1305 Self::LmsShakeM32H20W4Sign => "LMS SHAKE M=32 H=20 W=4 sign",
1306 Self::LmsShakeM32H20W4Verify => "LMS SHAKE M=32 H=20 W=4 verify",
1307 Self::LmsShakeM32H20W8Sign => "LMS SHAKE M=32 H=20 W=8 sign",
1308 Self::LmsShakeM32H20W8Verify => "LMS SHAKE M=32 H=20 W=8 verify",
1309 Self::LmsShakeM32H25W1Sign => "LMS SHAKE M=32 H=25 W=1 sign",
1310 Self::LmsShakeM32H25W1Verify => "LMS SHAKE M=32 H=25 W=1 verify",
1311 Self::LmsShakeM32H25W2Sign => "LMS SHAKE M=32 H=25 W=2 sign",
1312 Self::LmsShakeM32H25W2Verify => "LMS SHAKE M=32 H=25 W=2 verify",
1313 Self::LmsShakeM32H25W4Sign => "LMS SHAKE M=32 H=25 W=4 sign",
1314 Self::LmsShakeM32H25W4Verify => "LMS SHAKE M=32 H=25 W=4 verify",
1315 Self::LmsShakeM32H25W8Sign => "LMS SHAKE M=32 H=25 W=8 sign",
1316 Self::LmsShakeM32H25W8Verify => "LMS SHAKE M=32 H=25 W=8 verify",
1317 Self::LmsShakeM24H5W1Sign => "LMS SHAKE M=24 H=5 W=1 sign",
1318 Self::LmsShakeM24H5W1Verify => "LMS SHAKE M=24 H=5 W=1 verify",
1319 Self::LmsShakeM24H5W2Sign => "LMS SHAKE M=24 H=5 W=2 sign",
1320 Self::LmsShakeM24H5W2Verify => "LMS SHAKE M=24 H=5 W=2 verify",
1321 Self::LmsShakeM24H5W4Sign => "LMS SHAKE M=24 H=5 W=4 sign",
1322 Self::LmsShakeM24H5W4Verify => "LMS SHAKE M=24 H=5 W=4 verify",
1323 Self::LmsShakeM24H5W8Sign => "LMS SHAKE M=24 H=5 W=8 sign",
1324 Self::LmsShakeM24H5W8Verify => "LMS SHAKE M=24 H=5 W=8 verify",
1325 Self::LmsShakeM24H10W1Sign => "LMS SHAKE M=24 H=10 W=1 sign",
1326 Self::LmsShakeM24H10W1Verify => "LMS SHAKE M=24 H=10 W=1 verify",
1327 Self::LmsShakeM24H10W2Sign => "LMS SHAKE M=24 H=10 W=2 sign",
1328 Self::LmsShakeM24H10W2Verify => "LMS SHAKE M=24 H=10 W=2 verify",
1329 Self::LmsShakeM24H10W4Sign => "LMS SHAKE M=24 H=10 W=4 sign",
1330 Self::LmsShakeM24H10W4Verify => "LMS SHAKE M=24 H=10 W=4 verify",
1331 Self::LmsShakeM24H10W8Sign => "LMS SHAKE M=24 H=10 W=8 sign",
1332 Self::LmsShakeM24H10W8Verify => "LMS SHAKE M=24 H=10 W=8 verify",
1333 Self::LmsShakeM24H15W1Sign => "LMS SHAKE M=24 H=15 W=1 sign",
1334 Self::LmsShakeM24H15W1Verify => "LMS SHAKE M=24 H=15 W=1 verify",
1335 Self::LmsShakeM24H15W2Sign => "LMS SHAKE M=24 H=15 W=2 sign",
1336 Self::LmsShakeM24H15W2Verify => "LMS SHAKE M=24 H=15 W=2 verify",
1337 Self::LmsShakeM24H15W4Sign => "LMS SHAKE M=24 H=15 W=4 sign",
1338 Self::LmsShakeM24H15W4Verify => "LMS SHAKE M=24 H=15 W=4 verify",
1339 Self::LmsShakeM24H15W8Sign => "LMS SHAKE M=24 H=15 W=8 sign",
1340 Self::LmsShakeM24H15W8Verify => "LMS SHAKE M=24 H=15 W=8 verify",
1341 Self::LmsShakeM24H20W1Sign => "LMS SHAKE M=24 H=20 W=1 sign",
1342 Self::LmsShakeM24H20W1Verify => "LMS SHAKE M=24 H=20 W=1 verify",
1343 Self::LmsShakeM24H20W2Sign => "LMS SHAKE M=24 H=20 W=2 sign",
1344 Self::LmsShakeM24H20W2Verify => "LMS SHAKE M=24 H=20 W=2 verify",
1345 Self::LmsShakeM24H20W4Sign => "LMS SHAKE M=24 H=20 W=4 sign",
1346 Self::LmsShakeM24H20W4Verify => "LMS SHAKE M=24 H=20 W=4 verify",
1347 Self::LmsShakeM24H20W8Sign => "LMS SHAKE M=24 H=20 W=8 sign",
1348 Self::LmsShakeM24H20W8Verify => "LMS SHAKE M=24 H=20 W=8 verify",
1349 Self::LmsShakeM24H25W1Sign => "LMS SHAKE M=24 H=25 W=1 sign",
1350 Self::LmsShakeM24H25W1Verify => "LMS SHAKE M=24 H=25 W=1 verify",
1351 Self::LmsShakeM24H25W2Sign => "LMS SHAKE M=24 H=25 W=2 sign",
1352 Self::LmsShakeM24H25W2Verify => "LMS SHAKE M=24 H=25 W=2 verify",
1353 Self::LmsShakeM24H25W4Sign => "LMS SHAKE M=24 H=25 W=4 sign",
1354 Self::LmsShakeM24H25W4Verify => "LMS SHAKE M=24 H=25 W=4 verify",
1355 Self::LmsShakeM24H25W8Sign => "LMS SHAKE M=24 H=25 W=8 sign",
1356 Self::LmsShakeM24H25W8Verify => "LMS SHAKE M=24 H=25 W=8 verify",
1357 Self::XmssVerify => "XMSS verify",
1358 Self::Dh3072 => "DH-3072",
1359 };
1360 f.write_str(name)
1361 }
1362}
1363
1364pub fn require_allowed(service: Service) -> Result<(), Error> {
1380 let profile = active_profile();
1381 if is_allowed(profile, service) {
1382 Ok(())
1383 } else {
1384 Err(Error::AlgorithmRestricted { service })
1385 }
1386}
1387
1388const fn is_allowed(profile: AlgorithmProfile, service: Service) -> bool {
1391 match profile {
1392 AlgorithmProfile::Unrestricted => true,
1393 AlgorithmProfile::Cnsa2 => is_cnsa2_allowed(service),
1394 AlgorithmProfile::Cnsa1 => is_cnsa1_allowed(service),
1395 AlgorithmProfile::Migration => is_cnsa1_allowed(service) || is_cnsa2_allowed(service),
1401 }
1402}
1403
1404const fn is_lms_service(service: Service) -> bool {
1413 lms_block_contains(service as u16)
1414}
1415
1416const fn lms_block_contains(discriminant: u16) -> bool {
1425 discriminant >= Service::LmsSha256M32H5W1Sign as u16
1426 && discriminant <= Service::LmsShakeM24H25W8Verify as u16
1427}
1428
1429const fn is_cnsa2_allowed(service: Service) -> bool {
1441 matches!(
1442 service,
1443 Service::Aes256Ecb
1445 | Service::Aes256Cbc
1446 | Service::Aes256Ctr
1447 | Service::Aes256Gcm
1448 | Service::Aes256Ccm
1449 | Service::Aes256Kw
1450 | Service::Aes256Kwp
1451 | Service::Aes256
1452 | Service::Sha384
1454 | Service::Sha512
1455 | Service::HmacSha384
1461 | Service::HmacSha512
1462 | Service::CmacAes256
1464 | Service::CtrDrbgAes256
1466 | Service::HashDrbgSha384
1467 | Service::HashDrbgSha512
1468 | Service::HmacDrbgSha384
1469 | Service::HmacDrbgSha512
1470 | Service::HkdfSha384
1472 | Service::HkdfSha512
1473 | Service::KbkdfHmacSha384
1474 | Service::KbkdfHmacSha512
1475 | Service::KbkdfCmacAes256
1476 | Service::MlKem1024Encaps
1481 | Service::MlKem1024Decaps
1482 | Service::MlKem1024Keygen
1483 | Service::MlDsa87Sign
1484 | Service::MlDsa87Verify
1485 | Service::MlDsa87Keygen
1486 | Service::XmssVerify
1489 )
1490 || is_lms_service(service)
1497}
1498
1499const fn is_cnsa1_allowed(service: Service) -> bool {
1526 matches!(
1527 service,
1528 Service::Aes256
1530 | Service::Aes256Ecb
1531 | Service::Aes256Cbc
1532 | Service::Aes256Ctr
1533 | Service::Aes256Gcm
1534 | Service::Aes256Ccm
1535 | Service::Aes256Kw
1536 | Service::Aes256Kwp
1537 | Service::EcdhP384
1539 | Service::EcdsaP384Keygen
1541 | Service::EcdsaP384Sign
1542 | Service::EcdsaP384Verify
1543 | Service::Sha384
1545 | Service::Dh3072
1547 | Service::RsaKeygen3072
1549 | Service::RsaKeygen4096
1550 | Service::RsaOaep3072
1551 | Service::RsaOaep4096
1552 | Service::RsaPkcs1v15Sign3072
1554 | Service::RsaPkcs1v15Sign4096
1555 | Service::RsaPkcs1v15Verify3072
1556 | Service::RsaPkcs1v15Verify4096
1557 | Service::RsaPssSign3072
1558 | Service::RsaPssSign4096
1559 | Service::RsaPssVerify3072
1560 | Service::RsaPssVerify4096
1561 | Service::CtrDrbgAes256
1565 | Service::HashDrbgSha384
1566 | Service::HmacDrbgSha384
1567 | Service::HmacSha384
1568 | Service::CmacAes256
1569 | Service::HkdfSha384
1570 | Service::KbkdfHmacSha384
1571 | Service::KbkdfCmacAes256
1572 )
1573}
1574
1575#[cfg(test)]
1604pub(crate) mod state_lock {
1605 use super::{AlgorithmProfile, Ordering, PROFILE, STATE, State};
1606
1607 static STATE_LOCK: std::sync::Mutex<()> = std::sync::Mutex::new(());
1608
1609 #[must_use]
1612 pub(crate) struct StateGuard(
1613 #[allow(dead_code)]
1616 std::sync::MutexGuard<'static, ()>,
1617 );
1618
1619 impl StateGuard {
1620 #[allow(clippy::unused_self)]
1624 pub(crate) fn reset(&self) {
1625 STATE.store(State::PowerOff as u8, Ordering::Release);
1626 PROFILE.store(AlgorithmProfile::Unrestricted as u8, Ordering::Release);
1627 }
1628 }
1629
1630 pub(crate) fn reset_for_test() -> StateGuard {
1647 let guard = StateGuard(
1648 STATE_LOCK
1649 .lock()
1650 .unwrap_or_else(std::sync::PoisonError::into_inner),
1651 );
1652 guard.reset();
1653 guard
1654 }
1655}
1656
1657#[cfg(test)]
1658extern crate alloc;
1659
1660#[cfg(test)]
1661extern crate std;
1662
1663#[cfg(test)]
1664#[allow(clippy::unwrap_used, clippy::panic)]
1665mod tests {
1666 use super::state_lock::reset_for_test;
1667 use super::{
1668 AlgorithmProfile, Error, KatEntry, SelfTest, SelfTestFailure, Service, State,
1669 active_profile, enter_error_state, initialize_with_profile, initialize_with_tests,
1670 is_allowed, is_lms_service, is_operational, lms_block_contains, require_allowed,
1671 require_operational, state,
1672 };
1673 use alloc::string::ToString;
1674
1675 const UNSIGNED_TEST_BINARY: &[KatEntry] = &[KatEntry {
1683 name: "integrity not verifiable in an unsigned test binary",
1684 run: || Ok(()),
1685 }];
1686
1687 #[allow(clippy::unnecessary_wraps)]
1691 fn always_pass() -> Result<(), SelfTestFailure> {
1692 Ok(())
1693 }
1694 fn always_fail() -> Result<(), SelfTestFailure> {
1695 Err(SelfTestFailure)
1696 }
1697
1698 #[test]
1703 fn initial_state_is_power_off() {
1704 let _guard = reset_for_test();
1705 assert_eq!(state(), State::PowerOff);
1706 assert!(!is_operational());
1707 }
1708
1709 #[test]
1710 fn initialize_transitions_to_operational() {
1711 let _guard = reset_for_test();
1712 initialize_with_tests(UNSIGNED_TEST_BINARY, &[]).unwrap();
1713 assert_eq!(state(), State::Operational);
1714 assert!(is_operational());
1715 require_operational().unwrap();
1716 }
1717
1718 #[test]
1719 fn second_initialize_reports_already_initialized() {
1720 let _guard = reset_for_test();
1721 initialize_with_tests(UNSIGNED_TEST_BINARY, &[]).unwrap();
1722 match initialize_with_tests(UNSIGNED_TEST_BINARY, &[]) {
1723 Err(Error::AlreadyInitialized) => {}
1724 other => panic!("expected AlreadyInitialized, got {other:?}"),
1725 }
1726 }
1727
1728 #[test]
1729 fn require_operational_rejects_power_off() {
1730 let _guard = reset_for_test();
1731 match require_operational() {
1732 Err(Error::NotOperational {
1733 current: State::PowerOff,
1734 }) => {}
1735 other => panic!("expected NotOperational{{PowerOff}}, got {other:?}"),
1736 }
1737 }
1738
1739 #[test]
1740 fn enter_error_state_is_terminal_for_require_operational() {
1741 let _guard = reset_for_test();
1742 initialize_with_tests(UNSIGNED_TEST_BINARY, &[]).unwrap();
1743 assert!(is_operational());
1744 enter_error_state("unit-test forced failure");
1745 assert_eq!(state(), State::Error);
1746 match require_operational() {
1747 Err(Error::NotOperational {
1748 current: State::Error,
1749 }) => {}
1750 other => panic!("expected NotOperational{{Error}}, got {other:?}"),
1751 }
1752 }
1753
1754 #[test]
1755 fn state_display_is_stable() {
1756 assert_eq!(State::PowerOff.to_string(), "PowerOff");
1759 assert_eq!(State::SelfTest.to_string(), "SelfTest");
1760 assert_eq!(State::Operational.to_string(), "Operational");
1761 assert_eq!(State::Error.to_string(), "Error");
1762 }
1763
1764 #[test]
1765 fn registry_runs_passing_tests_and_reaches_operational() {
1766 let _guard = reset_for_test();
1767 let tests = [
1768 KatEntry {
1769 name: "dummy-pass-a",
1770 run: always_pass,
1771 },
1772 KatEntry {
1773 name: "dummy-pass-b",
1774 run: always_pass,
1775 },
1776 ];
1777 initialize_with_tests(UNSIGNED_TEST_BINARY, &tests).unwrap();
1778 assert_eq!(state(), State::Operational);
1779 }
1780
1781 #[test]
1782 fn registry_failing_test_latches_error_and_returns_name() {
1783 let _guard = reset_for_test();
1784 let tests = [
1785 KatEntry {
1786 name: "dummy-pass",
1787 run: always_pass,
1788 },
1789 KatEntry {
1790 name: "dummy-fail",
1791 run: always_fail,
1792 },
1793 KatEntry {
1795 name: "dummy-unreached",
1796 run: always_pass,
1797 },
1798 ];
1799 match initialize_with_tests(UNSIGNED_TEST_BINARY, &tests) {
1800 Err(Error::SelfTestFailed { test: "dummy-fail" }) => {}
1801 other => panic!("expected SelfTestFailed{{dummy-fail}}, got {other:?}"),
1802 }
1803 assert_eq!(state(), State::Error);
1804 assert!(matches!(
1806 require_operational(),
1807 Err(Error::NotOperational {
1808 current: State::Error
1809 })
1810 ));
1811 }
1812
1813 struct DummyTest;
1816 impl SelfTest for DummyTest {
1817 const NAME: &'static str = "dummy-trait-vector";
1818 fn run() -> Result<(), SelfTestFailure> {
1819 Ok(())
1820 }
1821 }
1822
1823 #[test]
1824 fn dummy_self_test_trait_is_usable() {
1825 assert_eq!(DummyTest::NAME, "dummy-trait-vector");
1826 DummyTest::run().unwrap();
1827 }
1828
1829 #[test]
1834 fn default_profile_is_unrestricted() {
1835 let _guard = reset_for_test();
1836 assert_eq!(active_profile(), AlgorithmProfile::Unrestricted);
1837 }
1838
1839 #[test]
1840 fn initialize_with_profile_sets_cnsa2() {
1841 let _guard = reset_for_test();
1842 initialize_with_profile(UNSIGNED_TEST_BINARY, &[], AlgorithmProfile::Cnsa2).unwrap();
1843 assert_eq!(active_profile(), AlgorithmProfile::Cnsa2);
1844 assert!(is_operational());
1845 }
1846
1847 #[test]
1848 fn initialize_with_profile_sets_cnsa1() {
1849 let _guard = reset_for_test();
1850 initialize_with_profile(UNSIGNED_TEST_BINARY, &[], AlgorithmProfile::Cnsa1).unwrap();
1851 assert_eq!(active_profile(), AlgorithmProfile::Cnsa1);
1852 assert!(is_operational());
1853 }
1854
1855 #[test]
1856 fn unrestricted_allows_all_services() {
1857 let spot = [
1859 Service::Sha1,
1860 Service::Sha256,
1861 Service::Aes128Ecb,
1862 Service::Aes256Gcm,
1863 Service::CtrDrbgAes128,
1864 Service::EcdsaP256Sign,
1865 Service::Ed25519Sign,
1866 Service::RsaPssSign2048,
1867 Service::MlKem1024Encaps,
1868 Service::LmsSha256M32H10W4Sign,
1869 Service::Dh3072,
1870 Service::SlhDsaSha2256sSign,
1871 ];
1872 for svc in spot {
1873 assert!(
1874 is_allowed(AlgorithmProfile::Unrestricted, svc),
1875 "{svc} should be allowed in Unrestricted"
1876 );
1877 }
1878 }
1879
1880 #[test]
1881 fn cnsa2_allows_aes256_and_pq() {
1882 let allowed = [
1883 Service::Aes256Gcm,
1884 Service::Aes256Cbc,
1885 Service::Sha384,
1886 Service::Sha512,
1887 Service::HmacSha384,
1888 Service::HmacSha512,
1889 Service::CtrDrbgAes256,
1890 Service::HashDrbgSha384,
1891 Service::HmacDrbgSha512,
1892 Service::MlKem1024Encaps,
1893 Service::MlKem1024Decaps,
1894 Service::MlKem1024Keygen,
1895 Service::MlDsa87Sign,
1896 Service::MlDsa87Verify,
1897 Service::MlDsa87Keygen,
1898 Service::LmsSha256M32H10W4Sign,
1899 Service::LmsSha256M32H10W4Verify,
1900 Service::XmssVerify,
1901 ];
1902 for svc in allowed {
1903 assert!(
1904 is_allowed(AlgorithmProfile::Cnsa2, svc),
1905 "{svc} should be allowed in CNSA 2.0"
1906 );
1907 }
1908 }
1909
1910 #[test]
1918 fn cnsa2_refuses_the_keccak_family() {
1919 let refused = [
1920 Service::Shake256,
1921 Service::CShake256,
1922 Service::Kmac256,
1923 Service::KmacXof256,
1924 Service::TupleHash256,
1925 Service::TupleHashXof256,
1926 Service::ParallelHash256,
1927 Service::ParallelHashXof256,
1928 Service::Sha3_384,
1929 Service::Sha3_512,
1930 Service::HmacSha3_384,
1931 Service::HmacSha3_512,
1932 ];
1933 for svc in refused {
1934 assert!(
1935 !is_allowed(AlgorithmProfile::Cnsa2, svc),
1936 "{svc} is not in CNSA 2.0 and must be refused"
1937 );
1938 }
1939 assert!(is_allowed(AlgorithmProfile::Cnsa2, Service::Sha384));
1942 assert!(is_allowed(
1944 AlgorithmProfile::Cnsa2,
1945 Service::MlKem1024Encaps
1946 ));
1947 }
1948
1949 #[test]
1950 fn cnsa2_blocks_classical_and_small_keys() {
1951 let blocked = [
1952 Service::Sha1,
1953 Service::Sha224,
1954 Service::Sha256,
1955 Service::Sha512_224,
1956 Service::Sha512_256,
1957 Service::Sha3_224,
1958 Service::Sha3_256,
1959 Service::Shake128,
1960 Service::Kmac128,
1961 Service::Aes128Ecb,
1962 Service::Aes128Gcm,
1963 Service::Aes192Cbc,
1964 Service::CtrDrbgAes128,
1965 Service::CtrDrbgAes192,
1966 Service::HashDrbgSha256,
1967 Service::HmacDrbgSha256,
1968 Service::HmacSha1,
1969 Service::HmacSha256,
1970 Service::CmacAes128,
1971 Service::CmacAes192,
1972 Service::EcdsaP256Sign,
1973 Service::EcdsaP256Verify,
1974 Service::EcdhP256,
1975 Service::Ed25519Sign,
1976 Service::Ed25519Verify,
1977 Service::RsaPssSign2048,
1978 Service::RsaOaep2048,
1979 Service::SlhDsaSha2128sSign,
1981 Service::MlDsa44Sign,
1982 Service::MlDsa44Verify,
1983 Service::MlDsa44Keygen,
1984 Service::MlDsa65Sign,
1985 Service::MlDsa65Verify,
1986 Service::MlDsa65Keygen,
1987 ];
1988 for svc in blocked {
1989 assert!(
1990 !is_allowed(AlgorithmProfile::Cnsa2, svc),
1991 "{svc} should be BLOCKED in CNSA 2.0"
1992 );
1993 }
1994 }
1995
1996 const ALL_SERVICES: [Service; 336] = [
2006 Service::Sha1,
2007 Service::Sha224,
2008 Service::Sha256,
2009 Service::Sha384,
2010 Service::Sha512,
2011 Service::Sha512_224,
2012 Service::Sha512_256,
2013 Service::Sha3_224,
2014 Service::Sha3_256,
2015 Service::Sha3_384,
2016 Service::Sha3_512,
2017 Service::Shake128,
2018 Service::Shake256,
2019 Service::CShake128,
2020 Service::CShake256,
2021 Service::Kmac128,
2022 Service::Kmac256,
2023 Service::KmacXof128,
2024 Service::KmacXof256,
2025 Service::TupleHash128,
2026 Service::TupleHash256,
2027 Service::TupleHashXof128,
2028 Service::TupleHashXof256,
2029 Service::ParallelHash128,
2030 Service::ParallelHash256,
2031 Service::ParallelHashXof128,
2032 Service::ParallelHashXof256,
2033 Service::HmacSha1,
2034 Service::HmacSha224,
2035 Service::HmacSha256,
2036 Service::HmacSha384,
2037 Service::HmacSha512,
2038 Service::HmacSha512_224,
2039 Service::HmacSha512_256,
2040 Service::HmacSha3_224,
2041 Service::HmacSha3_256,
2042 Service::HmacSha3_384,
2043 Service::HmacSha3_512,
2044 Service::CmacAes128,
2045 Service::CmacAes192,
2046 Service::CmacAes256,
2047 Service::Aes128Ecb,
2048 Service::Aes128Cbc,
2049 Service::Aes128Ctr,
2050 Service::Aes128Gcm,
2051 Service::Aes128Ccm,
2052 Service::Aes128Kw,
2053 Service::Aes128Kwp,
2054 Service::Aes192Ecb,
2055 Service::Aes192Cbc,
2056 Service::Aes192Ctr,
2057 Service::Aes192Gcm,
2058 Service::Aes192Ccm,
2059 Service::Aes192Kw,
2060 Service::Aes192Kwp,
2061 Service::Aes256Ecb,
2062 Service::Aes256Cbc,
2063 Service::Aes256Ctr,
2064 Service::Aes256Gcm,
2065 Service::Aes256Ccm,
2066 Service::Aes256Kw,
2067 Service::Aes256Kwp,
2068 Service::Aes128,
2069 Service::Aes192,
2070 Service::Aes256,
2071 Service::CtrDrbgAes128,
2072 Service::CtrDrbgAes192,
2073 Service::CtrDrbgAes256,
2074 Service::HashDrbgSha256,
2075 Service::HashDrbgSha384,
2076 Service::HashDrbgSha512,
2077 Service::HmacDrbgSha256,
2078 Service::HmacDrbgSha384,
2079 Service::HmacDrbgSha512,
2080 Service::HkdfSha1,
2081 Service::HkdfSha256,
2082 Service::HkdfSha384,
2083 Service::HkdfSha512,
2084 Service::KbkdfHmacSha256,
2085 Service::KbkdfHmacSha384,
2086 Service::KbkdfHmacSha512,
2087 Service::KbkdfCmacAes128,
2088 Service::KbkdfCmacAes192,
2089 Service::KbkdfCmacAes256,
2090 Service::Pbkdf2HmacSha1,
2091 Service::Pbkdf2HmacSha224,
2092 Service::Pbkdf2HmacSha256,
2093 Service::Pbkdf2HmacSha384,
2094 Service::Pbkdf2HmacSha512,
2095 Service::RsaKeygen2048,
2096 Service::RsaPkcs1v15Sign2048,
2097 Service::RsaPssSign2048,
2098 Service::RsaOaep2048,
2099 Service::RsaPkcs1v15Verify2048,
2100 Service::RsaPssVerify2048,
2101 Service::RsaKeygen3072,
2102 Service::RsaPkcs1v15Sign3072,
2103 Service::RsaPssSign3072,
2104 Service::RsaOaep3072,
2105 Service::RsaPkcs1v15Verify3072,
2106 Service::RsaPssVerify3072,
2107 Service::RsaKeygen4096,
2108 Service::RsaPkcs1v15Sign4096,
2109 Service::RsaPssSign4096,
2110 Service::RsaOaep4096,
2111 Service::RsaPkcs1v15Verify4096,
2112 Service::RsaPssVerify4096,
2113 Service::EcdsaP256Sign,
2114 Service::EcdsaP256Verify,
2115 Service::EcdsaP256Keygen,
2116 Service::EcdsaP384Sign,
2117 Service::EcdsaP384Verify,
2118 Service::EcdsaP384Keygen,
2119 Service::EcdhP256,
2120 Service::EcdhP384,
2121 Service::Ed25519Sign,
2122 Service::Ed25519Verify,
2123 Service::Ed25519Keygen,
2124 Service::Tls12Kdf,
2125 Service::Tls13Kdf,
2126 Service::MlKem1024Encaps,
2127 Service::MlKem1024Decaps,
2128 Service::MlKem1024Keygen,
2129 Service::MlKem512Encaps,
2130 Service::MlKem512Decaps,
2131 Service::MlKem512Keygen,
2132 Service::MlKem768Encaps,
2133 Service::MlKem768Decaps,
2134 Service::MlKem768Keygen,
2135 Service::MlDsa87Sign,
2136 Service::MlDsa87Verify,
2137 Service::MlDsa87Keygen,
2138 Service::MlDsa44Sign,
2139 Service::MlDsa44Verify,
2140 Service::MlDsa44Keygen,
2141 Service::MlDsa65Sign,
2142 Service::MlDsa65Verify,
2143 Service::MlDsa65Keygen,
2144 Service::SlhDsaSha2256sKeygen,
2145 Service::SlhDsaSha2256sSign,
2146 Service::SlhDsaSha2256sVerify,
2147 Service::SlhDsaSha2128sKeygen,
2148 Service::SlhDsaSha2128sSign,
2149 Service::SlhDsaSha2128sVerify,
2150 Service::SlhDsaSha2128fKeygen,
2151 Service::SlhDsaSha2128fSign,
2152 Service::SlhDsaSha2128fVerify,
2153 Service::SlhDsaSha2192sKeygen,
2154 Service::SlhDsaSha2192sSign,
2155 Service::SlhDsaSha2192sVerify,
2156 Service::SlhDsaSha2192fKeygen,
2157 Service::SlhDsaSha2192fSign,
2158 Service::SlhDsaSha2192fVerify,
2159 Service::SlhDsaSha2256fKeygen,
2160 Service::SlhDsaSha2256fSign,
2161 Service::SlhDsaSha2256fVerify,
2162 Service::SlhDsaShake128sKeygen,
2163 Service::SlhDsaShake128sSign,
2164 Service::SlhDsaShake128sVerify,
2165 Service::SlhDsaShake128fKeygen,
2166 Service::SlhDsaShake128fSign,
2167 Service::SlhDsaShake128fVerify,
2168 Service::SlhDsaShake192sKeygen,
2169 Service::SlhDsaShake192sSign,
2170 Service::SlhDsaShake192sVerify,
2171 Service::SlhDsaShake192fKeygen,
2172 Service::SlhDsaShake192fSign,
2173 Service::SlhDsaShake192fVerify,
2174 Service::SlhDsaShake256sKeygen,
2175 Service::SlhDsaShake256sSign,
2176 Service::SlhDsaShake256sVerify,
2177 Service::SlhDsaShake256fKeygen,
2178 Service::SlhDsaShake256fSign,
2179 Service::SlhDsaShake256fVerify,
2180 Service::LmsSha256M32H5W1Sign,
2181 Service::LmsSha256M32H5W1Verify,
2182 Service::LmsSha256M32H5W2Sign,
2183 Service::LmsSha256M32H5W2Verify,
2184 Service::LmsSha256M32H5W4Sign,
2185 Service::LmsSha256M32H5W4Verify,
2186 Service::LmsSha256M32H5W8Sign,
2187 Service::LmsSha256M32H5W8Verify,
2188 Service::LmsSha256M32H10W1Sign,
2189 Service::LmsSha256M32H10W1Verify,
2190 Service::LmsSha256M32H10W2Sign,
2191 Service::LmsSha256M32H10W2Verify,
2192 Service::LmsSha256M32H10W4Sign,
2193 Service::LmsSha256M32H10W4Verify,
2194 Service::LmsSha256M32H10W8Sign,
2195 Service::LmsSha256M32H10W8Verify,
2196 Service::LmsSha256M32H15W1Sign,
2197 Service::LmsSha256M32H15W1Verify,
2198 Service::LmsSha256M32H15W2Sign,
2199 Service::LmsSha256M32H15W2Verify,
2200 Service::LmsSha256M32H15W4Sign,
2201 Service::LmsSha256M32H15W4Verify,
2202 Service::LmsSha256M32H15W8Sign,
2203 Service::LmsSha256M32H15W8Verify,
2204 Service::LmsSha256M32H20W1Sign,
2205 Service::LmsSha256M32H20W1Verify,
2206 Service::LmsSha256M32H20W2Sign,
2207 Service::LmsSha256M32H20W2Verify,
2208 Service::LmsSha256M32H20W4Sign,
2209 Service::LmsSha256M32H20W4Verify,
2210 Service::LmsSha256M32H20W8Sign,
2211 Service::LmsSha256M32H20W8Verify,
2212 Service::LmsSha256M32H25W1Sign,
2213 Service::LmsSha256M32H25W1Verify,
2214 Service::LmsSha256M32H25W2Sign,
2215 Service::LmsSha256M32H25W2Verify,
2216 Service::LmsSha256M32H25W4Sign,
2217 Service::LmsSha256M32H25W4Verify,
2218 Service::LmsSha256M32H25W8Sign,
2219 Service::LmsSha256M32H25W8Verify,
2220 Service::LmsSha256M24H5W1Sign,
2221 Service::LmsSha256M24H5W1Verify,
2222 Service::LmsSha256M24H5W2Sign,
2223 Service::LmsSha256M24H5W2Verify,
2224 Service::LmsSha256M24H5W4Sign,
2225 Service::LmsSha256M24H5W4Verify,
2226 Service::LmsSha256M24H5W8Sign,
2227 Service::LmsSha256M24H5W8Verify,
2228 Service::LmsSha256M24H10W1Sign,
2229 Service::LmsSha256M24H10W1Verify,
2230 Service::LmsSha256M24H10W2Sign,
2231 Service::LmsSha256M24H10W2Verify,
2232 Service::LmsSha256M24H10W4Sign,
2233 Service::LmsSha256M24H10W4Verify,
2234 Service::LmsSha256M24H10W8Sign,
2235 Service::LmsSha256M24H10W8Verify,
2236 Service::LmsSha256M24H15W1Sign,
2237 Service::LmsSha256M24H15W1Verify,
2238 Service::LmsSha256M24H15W2Sign,
2239 Service::LmsSha256M24H15W2Verify,
2240 Service::LmsSha256M24H15W4Sign,
2241 Service::LmsSha256M24H15W4Verify,
2242 Service::LmsSha256M24H15W8Sign,
2243 Service::LmsSha256M24H15W8Verify,
2244 Service::LmsSha256M24H20W1Sign,
2245 Service::LmsSha256M24H20W1Verify,
2246 Service::LmsSha256M24H20W2Sign,
2247 Service::LmsSha256M24H20W2Verify,
2248 Service::LmsSha256M24H20W4Sign,
2249 Service::LmsSha256M24H20W4Verify,
2250 Service::LmsSha256M24H20W8Sign,
2251 Service::LmsSha256M24H20W8Verify,
2252 Service::LmsSha256M24H25W1Sign,
2253 Service::LmsSha256M24H25W1Verify,
2254 Service::LmsSha256M24H25W2Sign,
2255 Service::LmsSha256M24H25W2Verify,
2256 Service::LmsSha256M24H25W4Sign,
2257 Service::LmsSha256M24H25W4Verify,
2258 Service::LmsSha256M24H25W8Sign,
2259 Service::LmsSha256M24H25W8Verify,
2260 Service::LmsShakeM32H5W1Sign,
2261 Service::LmsShakeM32H5W1Verify,
2262 Service::LmsShakeM32H5W2Sign,
2263 Service::LmsShakeM32H5W2Verify,
2264 Service::LmsShakeM32H5W4Sign,
2265 Service::LmsShakeM32H5W4Verify,
2266 Service::LmsShakeM32H5W8Sign,
2267 Service::LmsShakeM32H5W8Verify,
2268 Service::LmsShakeM32H10W1Sign,
2269 Service::LmsShakeM32H10W1Verify,
2270 Service::LmsShakeM32H10W2Sign,
2271 Service::LmsShakeM32H10W2Verify,
2272 Service::LmsShakeM32H10W4Sign,
2273 Service::LmsShakeM32H10W4Verify,
2274 Service::LmsShakeM32H10W8Sign,
2275 Service::LmsShakeM32H10W8Verify,
2276 Service::LmsShakeM32H15W1Sign,
2277 Service::LmsShakeM32H15W1Verify,
2278 Service::LmsShakeM32H15W2Sign,
2279 Service::LmsShakeM32H15W2Verify,
2280 Service::LmsShakeM32H15W4Sign,
2281 Service::LmsShakeM32H15W4Verify,
2282 Service::LmsShakeM32H15W8Sign,
2283 Service::LmsShakeM32H15W8Verify,
2284 Service::LmsShakeM32H20W1Sign,
2285 Service::LmsShakeM32H20W1Verify,
2286 Service::LmsShakeM32H20W2Sign,
2287 Service::LmsShakeM32H20W2Verify,
2288 Service::LmsShakeM32H20W4Sign,
2289 Service::LmsShakeM32H20W4Verify,
2290 Service::LmsShakeM32H20W8Sign,
2291 Service::LmsShakeM32H20W8Verify,
2292 Service::LmsShakeM32H25W1Sign,
2293 Service::LmsShakeM32H25W1Verify,
2294 Service::LmsShakeM32H25W2Sign,
2295 Service::LmsShakeM32H25W2Verify,
2296 Service::LmsShakeM32H25W4Sign,
2297 Service::LmsShakeM32H25W4Verify,
2298 Service::LmsShakeM32H25W8Sign,
2299 Service::LmsShakeM32H25W8Verify,
2300 Service::LmsShakeM24H5W1Sign,
2301 Service::LmsShakeM24H5W1Verify,
2302 Service::LmsShakeM24H5W2Sign,
2303 Service::LmsShakeM24H5W2Verify,
2304 Service::LmsShakeM24H5W4Sign,
2305 Service::LmsShakeM24H5W4Verify,
2306 Service::LmsShakeM24H5W8Sign,
2307 Service::LmsShakeM24H5W8Verify,
2308 Service::LmsShakeM24H10W1Sign,
2309 Service::LmsShakeM24H10W1Verify,
2310 Service::LmsShakeM24H10W2Sign,
2311 Service::LmsShakeM24H10W2Verify,
2312 Service::LmsShakeM24H10W4Sign,
2313 Service::LmsShakeM24H10W4Verify,
2314 Service::LmsShakeM24H10W8Sign,
2315 Service::LmsShakeM24H10W8Verify,
2316 Service::LmsShakeM24H15W1Sign,
2317 Service::LmsShakeM24H15W1Verify,
2318 Service::LmsShakeM24H15W2Sign,
2319 Service::LmsShakeM24H15W2Verify,
2320 Service::LmsShakeM24H15W4Sign,
2321 Service::LmsShakeM24H15W4Verify,
2322 Service::LmsShakeM24H15W8Sign,
2323 Service::LmsShakeM24H15W8Verify,
2324 Service::LmsShakeM24H20W1Sign,
2325 Service::LmsShakeM24H20W1Verify,
2326 Service::LmsShakeM24H20W2Sign,
2327 Service::LmsShakeM24H20W2Verify,
2328 Service::LmsShakeM24H20W4Sign,
2329 Service::LmsShakeM24H20W4Verify,
2330 Service::LmsShakeM24H20W8Sign,
2331 Service::LmsShakeM24H20W8Verify,
2332 Service::LmsShakeM24H25W1Sign,
2333 Service::LmsShakeM24H25W1Verify,
2334 Service::LmsShakeM24H25W2Sign,
2335 Service::LmsShakeM24H25W2Verify,
2336 Service::LmsShakeM24H25W4Sign,
2337 Service::LmsShakeM24H25W4Verify,
2338 Service::LmsShakeM24H25W8Sign,
2339 Service::LmsShakeM24H25W8Verify,
2340 Service::XmssVerify,
2341 Service::Dh3072,
2342 ];
2343
2344 const EXPECTED_CNSA1: [Service; 34] = [
2347 Service::Sha384,
2348 Service::HmacSha384,
2349 Service::CmacAes256,
2350 Service::Aes256Ecb,
2351 Service::Aes256Cbc,
2352 Service::Aes256Ctr,
2353 Service::Aes256Gcm,
2354 Service::Aes256Ccm,
2355 Service::Aes256Kw,
2356 Service::Aes256Kwp,
2357 Service::Aes256,
2358 Service::CtrDrbgAes256,
2359 Service::HashDrbgSha384,
2360 Service::HmacDrbgSha384,
2361 Service::HkdfSha384,
2362 Service::KbkdfHmacSha384,
2363 Service::KbkdfCmacAes256,
2364 Service::RsaKeygen3072,
2365 Service::RsaPkcs1v15Sign3072,
2366 Service::RsaPssSign3072,
2367 Service::RsaOaep3072,
2368 Service::RsaPkcs1v15Verify3072,
2369 Service::RsaPssVerify3072,
2370 Service::RsaKeygen4096,
2371 Service::RsaPkcs1v15Sign4096,
2372 Service::RsaPssSign4096,
2373 Service::RsaOaep4096,
2374 Service::RsaPkcs1v15Verify4096,
2375 Service::RsaPssVerify4096,
2376 Service::EcdsaP384Sign,
2377 Service::EcdsaP384Verify,
2378 Service::EcdsaP384Keygen,
2379 Service::EcdhP384,
2380 Service::Dh3072,
2381 ];
2382
2383 const EXPECTED_CNSA2_NON_LMS: [Service; 30] = [
2386 Service::Sha384,
2387 Service::Sha512,
2388 Service::HmacSha384,
2389 Service::HmacSha512,
2390 Service::CmacAes256,
2391 Service::Aes256Ecb,
2392 Service::Aes256Cbc,
2393 Service::Aes256Ctr,
2394 Service::Aes256Gcm,
2395 Service::Aes256Ccm,
2396 Service::Aes256Kw,
2397 Service::Aes256Kwp,
2398 Service::Aes256,
2399 Service::CtrDrbgAes256,
2400 Service::HashDrbgSha384,
2401 Service::HashDrbgSha512,
2402 Service::HmacDrbgSha384,
2403 Service::HmacDrbgSha512,
2404 Service::HkdfSha384,
2405 Service::HkdfSha512,
2406 Service::KbkdfHmacSha384,
2407 Service::KbkdfHmacSha512,
2408 Service::KbkdfCmacAes256,
2409 Service::MlKem1024Encaps,
2410 Service::MlKem1024Decaps,
2411 Service::MlKem1024Keygen,
2412 Service::MlDsa87Sign,
2413 Service::MlDsa87Verify,
2414 Service::MlDsa87Keygen,
2415 Service::XmssVerify,
2416 ];
2417
2418 fn assert_exact_membership(profile: AlgorithmProfile, expected: &[Service], allow_lms: bool) {
2421 for svc in ALL_SERVICES {
2422 let want = expected.iter().any(|e| *e as u16 == svc as u16)
2423 || (allow_lms && is_lms_service(svc));
2424 assert_eq!(
2425 is_allowed(profile, svc),
2426 want,
2427 "{svc} under {profile}: gate says {}, suite says {want}",
2428 is_allowed(profile, svc)
2429 );
2430 }
2431 }
2432
2433 #[test]
2443 fn every_profile_round_trips_through_the_active_profile() {
2444 for profile in [
2445 AlgorithmProfile::Unrestricted,
2446 AlgorithmProfile::Cnsa2,
2447 AlgorithmProfile::Cnsa1,
2448 AlgorithmProfile::Migration,
2449 ] {
2450 assert_eq!(
2451 AlgorithmProfile::from_u8(profile as u8),
2452 profile,
2453 "{profile} did not survive the round trip through its discriminant"
2454 );
2455 }
2456
2457 for raw in [4u8, 9, 200, 255] {
2461 assert_ne!(
2462 AlgorithmProfile::from_u8(raw),
2463 AlgorithmProfile::Unrestricted,
2464 "unknown discriminant {raw} must not open the module"
2465 );
2466 }
2467 }
2468
2469 #[test]
2475 fn migration_gates_as_itself_through_require_allowed() {
2476 let guard = reset_for_test();
2477 guard.reset();
2478 initialize_with_profile(UNSIGNED_TEST_BINARY, &[], AlgorithmProfile::Migration).unwrap();
2479 assert_eq!(active_profile(), AlgorithmProfile::Migration);
2480
2481 assert!(
2483 require_allowed(Service::EcdsaP384Sign).is_ok(),
2484 "ECDSA P-384 is in CNSA 1.0 and must pass under Migration"
2485 );
2486 assert!(
2487 require_allowed(Service::Dh3072).is_ok(),
2488 "DH-3072 is in CNSA 1.0 and must pass under Migration"
2489 );
2490 assert!(
2492 require_allowed(Service::MlKem1024Encaps).is_ok(),
2493 "ML-KEM-1024 is in CNSA 2.0 and must pass under Migration"
2494 );
2495 assert!(require_allowed(Service::Sha256).is_err());
2497 }
2498
2499 #[test]
2502 fn profile_membership_is_exact() {
2503 assert_eq!(
2504 ALL_SERVICES.len(),
2505 336,
2506 "Service enumeration drift — a variant was added without listing it"
2507 );
2508
2509 assert_exact_membership(AlgorithmProfile::Cnsa1, &EXPECTED_CNSA1, false);
2510 assert_exact_membership(AlgorithmProfile::Cnsa2, &EXPECTED_CNSA2_NON_LMS, true);
2511
2512 for svc in ALL_SERVICES {
2515 let want = is_allowed(AlgorithmProfile::Cnsa1, svc)
2516 || is_allowed(AlgorithmProfile::Cnsa2, svc);
2517 assert_eq!(
2518 is_allowed(AlgorithmProfile::Migration, svc),
2519 want,
2520 "{svc}: Migration must permit exactly the union"
2521 );
2522 }
2523
2524 for svc in ALL_SERVICES {
2527 assert!(is_allowed(AlgorithmProfile::Unrestricted, svc));
2528 }
2529 }
2530
2531 #[test]
2538 fn migration_is_the_union_of_both_suites() {
2539 for svc in [
2541 Service::EcdsaP384Sign,
2542 Service::EcdhP384,
2543 Service::RsaPssSign3072,
2544 Service::Dh3072,
2545 ] {
2546 assert!(
2547 is_allowed(AlgorithmProfile::Migration, svc),
2548 "{svc} (CNSA 1.0) must pass"
2549 );
2550 assert!(
2551 !is_allowed(AlgorithmProfile::Cnsa2, svc),
2552 "{svc} is not CNSA 2.0"
2553 );
2554 }
2555
2556 for svc in [
2558 Service::MlKem1024Encaps,
2559 Service::MlDsa87Sign,
2560 Service::XmssVerify,
2561 Service::Sha512,
2562 Service::LmsSha256M32H10W4Sign,
2563 ] {
2564 assert!(
2565 is_allowed(AlgorithmProfile::Migration, svc),
2566 "{svc} (CNSA 2.0) must pass"
2567 );
2568 assert!(
2569 !is_allowed(AlgorithmProfile::Cnsa1, svc),
2570 "{svc} is not CNSA 1.0"
2571 );
2572 }
2573
2574 for svc in [Service::Aes256Gcm, Service::Sha384, Service::HmacSha384] {
2577 assert!(is_allowed(AlgorithmProfile::Cnsa1, svc));
2578 assert!(is_allowed(AlgorithmProfile::Cnsa2, svc));
2579 assert!(is_allowed(AlgorithmProfile::Migration, svc));
2580 }
2581
2582 for svc in [
2585 Service::Sha1,
2586 Service::Sha256,
2587 Service::Aes128Gcm,
2588 Service::RsaPssSign2048,
2589 Service::EcdsaP256Sign,
2590 Service::Ed25519Sign,
2591 Service::Sha3_384,
2593 Service::Shake256,
2594 Service::Kmac256,
2595 ] {
2596 assert!(
2597 !is_allowed(AlgorithmProfile::Migration, svc),
2598 "{svc} is in neither suite and must be refused"
2599 );
2600 assert!(is_allowed(AlgorithmProfile::Unrestricted, svc));
2603 }
2604 }
2605
2606 #[test]
2607 fn cnsa1_allows_the_2016_suite() {
2608 let allowed = [
2609 Service::Aes256Gcm,
2610 Service::Sha384,
2611 Service::EcdsaP384Sign,
2612 Service::EcdsaP384Verify,
2613 Service::EcdsaP384Keygen,
2614 Service::EcdhP384,
2615 Service::RsaPssSign3072,
2616 Service::RsaOaep3072,
2617 Service::RsaPssSign4096,
2618 Service::Dh3072,
2619 Service::HmacSha384,
2621 Service::CtrDrbgAes256,
2622 Service::HashDrbgSha384,
2623 Service::KbkdfHmacSha384,
2624 ];
2625 for svc in allowed {
2626 assert!(
2627 is_allowed(AlgorithmProfile::Cnsa1, svc),
2628 "{svc} should be allowed in CNSA 1.0"
2629 );
2630 }
2631 }
2632
2633 #[test]
2634 fn cnsa1_blocks_small_keys_and_ed25519() {
2635 let blocked = [
2636 Service::Sha1,
2637 Service::Sha224,
2638 Service::Aes128Ecb,
2639 Service::Aes192Gcm,
2640 Service::CtrDrbgAes128,
2641 Service::EcdsaP256Sign,
2642 Service::EcdhP256,
2643 Service::Ed25519Sign,
2644 Service::Ed25519Verify,
2645 Service::RsaPssSign2048,
2646 Service::RsaOaep2048,
2647 Service::Sha256,
2653 Service::HmacSha256,
2654 Service::HashDrbgSha256,
2655 Service::HkdfSha256,
2656 Service::Sha512,
2658 Service::HmacSha512,
2659 Service::Sha3_256,
2661 Service::Shake256,
2662 Service::MlKem1024Encaps,
2664 Service::MlDsa87Sign,
2665 Service::XmssVerify,
2666 Service::LmsSha256M32H10W4Sign,
2667 ];
2668 for svc in blocked {
2669 assert!(
2670 !is_allowed(AlgorithmProfile::Cnsa1, svc),
2671 "{svc} should be BLOCKED in CNSA 1.0"
2672 );
2673 }
2674 }
2675
2676 #[allow(clippy::too_many_lines)]
2680 fn lms_all_160() -> [Service; 160] {
2681 [
2682 Service::LmsSha256M32H5W1Sign,
2684 Service::LmsSha256M32H5W1Verify,
2685 Service::LmsSha256M32H5W2Sign,
2686 Service::LmsSha256M32H5W2Verify,
2687 Service::LmsSha256M32H5W4Sign,
2688 Service::LmsSha256M32H5W4Verify,
2689 Service::LmsSha256M32H5W8Sign,
2690 Service::LmsSha256M32H5W8Verify,
2691 Service::LmsSha256M32H10W1Sign,
2692 Service::LmsSha256M32H10W1Verify,
2693 Service::LmsSha256M32H10W2Sign,
2694 Service::LmsSha256M32H10W2Verify,
2695 Service::LmsSha256M32H10W4Sign,
2696 Service::LmsSha256M32H10W4Verify,
2697 Service::LmsSha256M32H10W8Sign,
2698 Service::LmsSha256M32H10W8Verify,
2699 Service::LmsSha256M32H15W1Sign,
2700 Service::LmsSha256M32H15W1Verify,
2701 Service::LmsSha256M32H15W2Sign,
2702 Service::LmsSha256M32H15W2Verify,
2703 Service::LmsSha256M32H15W4Sign,
2704 Service::LmsSha256M32H15W4Verify,
2705 Service::LmsSha256M32H15W8Sign,
2706 Service::LmsSha256M32H15W8Verify,
2707 Service::LmsSha256M32H20W1Sign,
2708 Service::LmsSha256M32H20W1Verify,
2709 Service::LmsSha256M32H20W2Sign,
2710 Service::LmsSha256M32H20W2Verify,
2711 Service::LmsSha256M32H20W4Sign,
2712 Service::LmsSha256M32H20W4Verify,
2713 Service::LmsSha256M32H20W8Sign,
2714 Service::LmsSha256M32H20W8Verify,
2715 Service::LmsSha256M32H25W1Sign,
2716 Service::LmsSha256M32H25W1Verify,
2717 Service::LmsSha256M32H25W2Sign,
2718 Service::LmsSha256M32H25W2Verify,
2719 Service::LmsSha256M32H25W4Sign,
2720 Service::LmsSha256M32H25W4Verify,
2721 Service::LmsSha256M32H25W8Sign,
2722 Service::LmsSha256M32H25W8Verify,
2723 Service::LmsSha256M24H5W1Sign,
2725 Service::LmsSha256M24H5W1Verify,
2726 Service::LmsSha256M24H5W2Sign,
2727 Service::LmsSha256M24H5W2Verify,
2728 Service::LmsSha256M24H5W4Sign,
2729 Service::LmsSha256M24H5W4Verify,
2730 Service::LmsSha256M24H5W8Sign,
2731 Service::LmsSha256M24H5W8Verify,
2732 Service::LmsSha256M24H10W1Sign,
2733 Service::LmsSha256M24H10W1Verify,
2734 Service::LmsSha256M24H10W2Sign,
2735 Service::LmsSha256M24H10W2Verify,
2736 Service::LmsSha256M24H10W4Sign,
2737 Service::LmsSha256M24H10W4Verify,
2738 Service::LmsSha256M24H10W8Sign,
2739 Service::LmsSha256M24H10W8Verify,
2740 Service::LmsSha256M24H15W1Sign,
2741 Service::LmsSha256M24H15W1Verify,
2742 Service::LmsSha256M24H15W2Sign,
2743 Service::LmsSha256M24H15W2Verify,
2744 Service::LmsSha256M24H15W4Sign,
2745 Service::LmsSha256M24H15W4Verify,
2746 Service::LmsSha256M24H15W8Sign,
2747 Service::LmsSha256M24H15W8Verify,
2748 Service::LmsSha256M24H20W1Sign,
2749 Service::LmsSha256M24H20W1Verify,
2750 Service::LmsSha256M24H20W2Sign,
2751 Service::LmsSha256M24H20W2Verify,
2752 Service::LmsSha256M24H20W4Sign,
2753 Service::LmsSha256M24H20W4Verify,
2754 Service::LmsSha256M24H20W8Sign,
2755 Service::LmsSha256M24H20W8Verify,
2756 Service::LmsSha256M24H25W1Sign,
2757 Service::LmsSha256M24H25W1Verify,
2758 Service::LmsSha256M24H25W2Sign,
2759 Service::LmsSha256M24H25W2Verify,
2760 Service::LmsSha256M24H25W4Sign,
2761 Service::LmsSha256M24H25W4Verify,
2762 Service::LmsSha256M24H25W8Sign,
2763 Service::LmsSha256M24H25W8Verify,
2764 Service::LmsShakeM32H5W1Sign,
2766 Service::LmsShakeM32H5W1Verify,
2767 Service::LmsShakeM32H5W2Sign,
2768 Service::LmsShakeM32H5W2Verify,
2769 Service::LmsShakeM32H5W4Sign,
2770 Service::LmsShakeM32H5W4Verify,
2771 Service::LmsShakeM32H5W8Sign,
2772 Service::LmsShakeM32H5W8Verify,
2773 Service::LmsShakeM32H10W1Sign,
2774 Service::LmsShakeM32H10W1Verify,
2775 Service::LmsShakeM32H10W2Sign,
2776 Service::LmsShakeM32H10W2Verify,
2777 Service::LmsShakeM32H10W4Sign,
2778 Service::LmsShakeM32H10W4Verify,
2779 Service::LmsShakeM32H10W8Sign,
2780 Service::LmsShakeM32H10W8Verify,
2781 Service::LmsShakeM32H15W1Sign,
2782 Service::LmsShakeM32H15W1Verify,
2783 Service::LmsShakeM32H15W2Sign,
2784 Service::LmsShakeM32H15W2Verify,
2785 Service::LmsShakeM32H15W4Sign,
2786 Service::LmsShakeM32H15W4Verify,
2787 Service::LmsShakeM32H15W8Sign,
2788 Service::LmsShakeM32H15W8Verify,
2789 Service::LmsShakeM32H20W1Sign,
2790 Service::LmsShakeM32H20W1Verify,
2791 Service::LmsShakeM32H20W2Sign,
2792 Service::LmsShakeM32H20W2Verify,
2793 Service::LmsShakeM32H20W4Sign,
2794 Service::LmsShakeM32H20W4Verify,
2795 Service::LmsShakeM32H20W8Sign,
2796 Service::LmsShakeM32H20W8Verify,
2797 Service::LmsShakeM32H25W1Sign,
2798 Service::LmsShakeM32H25W1Verify,
2799 Service::LmsShakeM32H25W2Sign,
2800 Service::LmsShakeM32H25W2Verify,
2801 Service::LmsShakeM32H25W4Sign,
2802 Service::LmsShakeM32H25W4Verify,
2803 Service::LmsShakeM32H25W8Sign,
2804 Service::LmsShakeM32H25W8Verify,
2805 Service::LmsShakeM24H5W1Sign,
2807 Service::LmsShakeM24H5W1Verify,
2808 Service::LmsShakeM24H5W2Sign,
2809 Service::LmsShakeM24H5W2Verify,
2810 Service::LmsShakeM24H5W4Sign,
2811 Service::LmsShakeM24H5W4Verify,
2812 Service::LmsShakeM24H5W8Sign,
2813 Service::LmsShakeM24H5W8Verify,
2814 Service::LmsShakeM24H10W1Sign,
2815 Service::LmsShakeM24H10W1Verify,
2816 Service::LmsShakeM24H10W2Sign,
2817 Service::LmsShakeM24H10W2Verify,
2818 Service::LmsShakeM24H10W4Sign,
2819 Service::LmsShakeM24H10W4Verify,
2820 Service::LmsShakeM24H10W8Sign,
2821 Service::LmsShakeM24H10W8Verify,
2822 Service::LmsShakeM24H15W1Sign,
2823 Service::LmsShakeM24H15W1Verify,
2824 Service::LmsShakeM24H15W2Sign,
2825 Service::LmsShakeM24H15W2Verify,
2826 Service::LmsShakeM24H15W4Sign,
2827 Service::LmsShakeM24H15W4Verify,
2828 Service::LmsShakeM24H15W8Sign,
2829 Service::LmsShakeM24H15W8Verify,
2830 Service::LmsShakeM24H20W1Sign,
2831 Service::LmsShakeM24H20W1Verify,
2832 Service::LmsShakeM24H20W2Sign,
2833 Service::LmsShakeM24H20W2Verify,
2834 Service::LmsShakeM24H20W4Sign,
2835 Service::LmsShakeM24H20W4Verify,
2836 Service::LmsShakeM24H20W8Sign,
2837 Service::LmsShakeM24H20W8Verify,
2838 Service::LmsShakeM24H25W1Sign,
2839 Service::LmsShakeM24H25W1Verify,
2840 Service::LmsShakeM24H25W2Sign,
2841 Service::LmsShakeM24H25W2Verify,
2842 Service::LmsShakeM24H25W4Sign,
2843 Service::LmsShakeM24H25W4Verify,
2844 Service::LmsShakeM24H25W8Sign,
2845 Service::LmsShakeM24H25W8Verify,
2846 ]
2847 }
2848
2849 #[test]
2850 fn lms_gating_is_exhaustive_across_all_160_variants() {
2851 let all_160 = lms_all_160();
2859 assert_eq!(all_160.len(), 160, "LMS enumeration drift");
2860
2861 for svc in all_160 {
2862 assert!(
2864 is_allowed(AlgorithmProfile::Unrestricted, svc),
2865 "{svc} must be allowed in Unrestricted"
2866 );
2867
2868 assert!(
2871 is_allowed(AlgorithmProfile::Cnsa2, svc),
2872 "{svc} must be allowed in CNSA 2.0"
2873 );
2874
2875 assert!(
2878 !is_allowed(AlgorithmProfile::Cnsa1, svc),
2879 "{svc} is not in CNSA 1.0 and must be refused"
2880 );
2881
2882 assert!(
2884 is_allowed(AlgorithmProfile::Migration, svc),
2885 "{svc} must be allowed in Migration"
2886 );
2887 }
2888 }
2889
2890 #[test]
2891 fn lms_discriminant_block_is_contiguous_and_pure() {
2892 let mut discriminants = [0u16; 160];
2898 for (slot, svc) in discriminants.iter_mut().zip(lms_all_160()) {
2899 *slot = svc as u16;
2900 }
2901 discriminants.sort_unstable();
2902
2903 let mut compared = 0usize;
2907 for pair in discriminants.windows(2) {
2908 let [lo, hi] = pair else {
2909 unreachable!("windows(2) yields two-element slices")
2910 };
2911 assert!(hi > lo, "duplicate LMS discriminant {lo}");
2912 compared += 1;
2913 }
2914 assert_eq!(compared, 159, "distinctness sweep did not run in full");
2915
2916 let (Some(&first), Some(&last)) = (discriminants.first(), discriminants.last()) else {
2917 unreachable!("the array holds 160 elements")
2918 };
2919 assert_eq!(first, 500, "LMS block does not start at 500");
2920 assert_eq!(last, 659, "LMS block does not end at 659");
2921 assert_eq!(last - first + 1, 160, "LMS block is not contiguous");
2924
2925 for svc in lms_all_160() {
2926 assert!(is_lms_service(svc), "{svc} must be inside the LMS range");
2927 }
2928
2929 for svc in [
2932 Service::SlhDsaShake256fVerify,
2933 Service::XmssVerify,
2934 Service::Dh3072,
2935 ] {
2936 assert!(!is_lms_service(svc), "{svc} must be outside the LMS range");
2937 }
2938 }
2939
2940 #[test]
2941 fn slh_dsa_gating_is_exhaustive_across_all_36_variants() {
2942 let all_36 = [
2950 Service::SlhDsaSha2256sKeygen,
2952 Service::SlhDsaSha2256sSign,
2953 Service::SlhDsaSha2256sVerify,
2954 Service::SlhDsaSha2128sKeygen,
2955 Service::SlhDsaSha2128sSign,
2956 Service::SlhDsaSha2128sVerify,
2957 Service::SlhDsaSha2128fKeygen,
2958 Service::SlhDsaSha2128fSign,
2959 Service::SlhDsaSha2128fVerify,
2960 Service::SlhDsaSha2192sKeygen,
2961 Service::SlhDsaSha2192sSign,
2962 Service::SlhDsaSha2192sVerify,
2963 Service::SlhDsaSha2192fKeygen,
2964 Service::SlhDsaSha2192fSign,
2965 Service::SlhDsaSha2192fVerify,
2966 Service::SlhDsaSha2256fKeygen,
2967 Service::SlhDsaSha2256fSign,
2968 Service::SlhDsaSha2256fVerify,
2969 Service::SlhDsaShake128sKeygen,
2971 Service::SlhDsaShake128sSign,
2972 Service::SlhDsaShake128sVerify,
2973 Service::SlhDsaShake128fKeygen,
2974 Service::SlhDsaShake128fSign,
2975 Service::SlhDsaShake128fVerify,
2976 Service::SlhDsaShake192sKeygen,
2977 Service::SlhDsaShake192sSign,
2978 Service::SlhDsaShake192sVerify,
2979 Service::SlhDsaShake192fKeygen,
2980 Service::SlhDsaShake192fSign,
2981 Service::SlhDsaShake192fVerify,
2982 Service::SlhDsaShake256sKeygen,
2983 Service::SlhDsaShake256sSign,
2984 Service::SlhDsaShake256sVerify,
2985 Service::SlhDsaShake256fKeygen,
2986 Service::SlhDsaShake256fSign,
2987 Service::SlhDsaShake256fVerify,
2988 ];
2989 assert_eq!(all_36.len(), 36, "SLH-DSA enumeration drift");
2990
2991 for svc in all_36 {
2992 assert!(
2994 is_allowed(AlgorithmProfile::Unrestricted, svc),
2995 "{svc} must be allowed in Unrestricted"
2996 );
2997
2998 assert!(
3000 !is_allowed(AlgorithmProfile::Cnsa1, svc),
3001 "{svc} must be BLOCKED in CNSA 1.0"
3002 );
3003
3004 assert!(
3008 !is_allowed(AlgorithmProfile::Cnsa2, svc),
3009 "{svc} must be BLOCKED in CNSA 2.0"
3010 );
3011 }
3012 }
3013
3014 #[test]
3015 fn require_allowed_returns_restricted_error_under_cnsa2() {
3016 let _guard = reset_for_test();
3017 initialize_with_profile(UNSIGNED_TEST_BINARY, &[], AlgorithmProfile::Cnsa2).unwrap();
3018 match require_allowed(Service::Aes128Ecb) {
3019 Err(Error::AlgorithmRestricted {
3020 service: Service::Aes128Ecb,
3021 }) => {}
3022 other => panic!("expected AlgorithmRestricted(Aes128Ecb), got {other:?}"),
3023 }
3024 }
3025
3026 #[test]
3027 fn require_allowed_passes_permitted_services() {
3028 let _guard = reset_for_test();
3029 initialize_with_profile(UNSIGNED_TEST_BINARY, &[], AlgorithmProfile::Cnsa2).unwrap();
3030 require_allowed(Service::Aes256Gcm).unwrap();
3031 require_allowed(Service::Sha384).unwrap();
3032 require_allowed(Service::MlKem1024Encaps).unwrap();
3033 }
3034
3035 #[test]
3036 fn require_allowed_passes_everything_in_unrestricted() {
3037 let _guard = reset_for_test();
3038 initialize_with_tests(UNSIGNED_TEST_BINARY, &[]).unwrap();
3039 require_allowed(Service::Sha1).unwrap();
3041 require_allowed(Service::Aes128Ecb).unwrap();
3042 require_allowed(Service::Ed25519Sign).unwrap();
3043 require_allowed(Service::MlKem1024Encaps).unwrap();
3044 }
3045
3046 #[test]
3052 fn require_allowed_refuses_every_slh_dsa_service_under_cnsa2() {
3053 let guard = reset_for_test();
3054 for profile in [AlgorithmProfile::Cnsa2, AlgorithmProfile::Cnsa1] {
3055 guard.reset();
3056 initialize_with_profile(UNSIGNED_TEST_BINARY, &[], profile).unwrap();
3057 for svc in [
3058 Service::SlhDsaSha2256sKeygen,
3059 Service::SlhDsaSha2256sSign,
3060 Service::SlhDsaSha2256sVerify,
3061 Service::SlhDsaShake128fVerify,
3062 ] {
3063 match require_allowed(svc) {
3064 Err(Error::AlgorithmRestricted { service }) => assert_eq!(service, svc),
3065 other => {
3066 panic!("expected AlgorithmRestricted({svc}) under {profile}, got {other:?}")
3067 }
3068 }
3069 }
3070 }
3071 }
3072
3073 #[test]
3081 fn require_allowed_admits_lms_m24_under_cnsa2_and_migration() {
3082 let guard = reset_for_test();
3083 for profile in [AlgorithmProfile::Cnsa2, AlgorithmProfile::Migration] {
3084 guard.reset();
3085 initialize_with_profile(UNSIGNED_TEST_BINARY, &[], profile).unwrap();
3086 for svc in [
3087 Service::LmsSha256M24H5W1Sign,
3088 Service::LmsSha256M24H25W8Verify,
3089 Service::LmsShakeM24H10W4Sign,
3090 Service::LmsShakeM24H25W8Verify,
3091 ] {
3092 require_allowed(svc)
3093 .unwrap_or_else(|e| panic!("{svc} must be allowed under {profile}: {e:?}"));
3094 }
3095 }
3096 }
3097
3098 #[test]
3105 fn lms_block_boundaries_are_exact() {
3106 assert!(!lms_block_contains(499), "499 is below the LMS block");
3107 assert!(lms_block_contains(500), "500 is the first LMS discriminant");
3108 assert!(lms_block_contains(659), "659 is the last LMS discriminant");
3109 assert!(!lms_block_contains(660), "660 is above the LMS block");
3110
3111 assert_eq!(Service::LmsSha256M32H5W1Sign as u16, 500);
3113 assert_eq!(Service::LmsShakeM24H25W8Verify as u16, 659);
3114 }
3115
3116 #[test]
3121 fn require_allowed_distinguishes_cnsa1_from_cnsa2() {
3122 let guard = reset_for_test();
3123
3124 initialize_with_profile(UNSIGNED_TEST_BINARY, &[], AlgorithmProfile::Cnsa1).unwrap();
3125 require_allowed(Service::EcdsaP384Sign)
3126 .unwrap_or_else(|e| panic!("P-384 ECDSA must be permitted under CNSA 1.0: {e:?}"));
3127
3128 guard.reset();
3129 initialize_with_profile(UNSIGNED_TEST_BINARY, &[], AlgorithmProfile::Cnsa2).unwrap();
3130 match require_allowed(Service::EcdsaP384Sign) {
3131 Err(Error::AlgorithmRestricted {
3132 service: Service::EcdsaP384Sign,
3133 }) => {}
3134 other => panic!("expected P-384 ECDSA refused under CNSA 2.0, got {other:?}"),
3135 }
3136 }
3137
3138 #[test]
3139 fn algorithm_profile_display() {
3140 assert_eq!(AlgorithmProfile::Unrestricted.to_string(), "Unrestricted");
3141 assert_eq!(AlgorithmProfile::Cnsa2.to_string(), "CNSA 2.0");
3142 assert_eq!(AlgorithmProfile::Cnsa1.to_string(), "CNSA 1.0");
3143 }
3144
3145 #[test]
3146 fn algorithm_restricted_error_display() {
3147 let _guard = reset_for_test();
3148 initialize_with_profile(UNSIGNED_TEST_BINARY, &[], AlgorithmProfile::Cnsa2).unwrap();
3149 let err = Error::AlgorithmRestricted {
3150 service: Service::Aes128Ecb,
3151 };
3152 let msg = err.to_string();
3153 assert!(msg.contains("AES-128-ECB"), "got: {msg}");
3154 assert!(msg.contains("CNSA 2.0"), "got: {msg}");
3155 }
3156
3157 #[test]
3158 fn not_implemented_error_display() {
3159 let err = Error::NotImplemented;
3160 assert_eq!(err.to_string(), "algorithm not yet implemented");
3161 }
3162
3163 #[test]
3164 fn service_display_is_stable() {
3165 assert_eq!(Service::Sha256.to_string(), "SHA-256");
3167 assert_eq!(Service::Aes256Gcm.to_string(), "AES-256-GCM");
3168 assert_eq!(Service::MlKem1024Encaps.to_string(), "ML-KEM-1024 encaps");
3169 assert_eq!(Service::Ed25519Sign.to_string(), "Ed25519 sign");
3170 }
3171}