@@ -47,10 +47,19 @@ const {
4747 getFipsCrypto,
4848 getFipsCryptoGeneration,
4949 KmacJob,
50- getPqcKeyTypes ,
50+ isKeyAlgorithmAvailable ,
5151} = internalBinding ( 'crypto' ) ;
5252
53- const isFips = getFipsCrypto ( ) === 1 ;
53+ let fips ;
54+ let fipsGeneration ;
55+ function isFips ( ) {
56+ const generation = getFipsCryptoGeneration ( ) ;
57+ if ( fipsGeneration !== generation ) {
58+ fips = getFipsCrypto ( ) === 1 ;
59+ fipsGeneration = generation ;
60+ }
61+ return fips ;
62+ }
5463
5564const { getOptionValue } = require ( 'internal/options' ) ;
5665
@@ -119,6 +128,9 @@ let _hashCache;
119128let _macCache ;
120129if ( isBuildingSnapshot ( ) ) {
121130 addSerializeCallback ( ( ) => {
131+ fips = undefined ;
132+ fipsGeneration = undefined ;
133+ supportedAlgorithmsGeneration = undefined ;
122134 _hashCache = undefined ;
123135 _macCache = undefined ;
124136 } ) ;
@@ -495,53 +507,69 @@ const kAlgorithmDefinitions = {
495507 } ,
496508} ;
497509
498- // Conditionally supported algorithms
499- const pqcKeyTypes = getPqcKeyTypes ( ) ;
500-
501- const conditionalAlgorithms = {
502- 'AES-OCB' : ! ! hasAesOcbMode ,
503- 'Argon2d' : ! ! Argon2Job ,
504- 'Argon2i' : ! ! Argon2Job ,
505- 'Argon2id' : ! ! Argon2Job ,
506- 'ChaCha20-Poly1305' : process . features . openssl_is_boringssl ||
507- ArrayPrototypeIncludes ( getCiphers ( ) , 'chacha20-poly1305' ) ,
508- 'cSHAKE128' : ! process . features . openssl_is_boringssl ||
509- ArrayPrototypeIncludes ( getHashes ( ) , 'shake128' ) ,
510- 'cSHAKE256' : ! process . features . openssl_is_boringssl ||
511- ArrayPrototypeIncludes ( getHashes ( ) , 'shake256' ) ,
512- 'Ed448' : ! process . features . openssl_is_boringssl ,
513- 'KMAC128' : ! ! KmacJob ,
514- 'KMAC256' : ! ! KmacJob ,
515- 'KT128' : ! isFips ,
516- 'KT256' : ! isFips ,
517- 'ML-DSA-44' : ArrayPrototypeIncludes ( pqcKeyTypes , 'ML-DSA-44' ) ,
518- 'ML-DSA-65' : ArrayPrototypeIncludes ( pqcKeyTypes , 'ML-DSA-65' ) ,
519- 'ML-DSA-87' : ArrayPrototypeIncludes ( pqcKeyTypes , 'ML-DSA-87' ) ,
520- 'ML-KEM-512' : ArrayPrototypeIncludes ( pqcKeyTypes , 'ML-KEM-512' ) ,
521- 'ML-KEM-768' : ArrayPrototypeIncludes ( pqcKeyTypes , 'ML-KEM-768' ) ,
522- 'ML-KEM-1024' : ArrayPrototypeIncludes ( pqcKeyTypes , 'ML-KEM-1024' ) ,
523- 'MLKEM768-P256' : ! isFips && ArrayPrototypeIncludes ( pqcKeyTypes , 'ML-KEM-768' ) &&
524- ( ! process . features . openssl_is_boringssl ||
525- ( ArrayPrototypeIncludes ( getHashes ( ) , 'sha3-256' ) &&
526- ArrayPrototypeIncludes ( getHashes ( ) , 'shake256' ) ) ) ,
527- 'MLKEM768-X25519' : ! isFips && ArrayPrototypeIncludes ( pqcKeyTypes , 'ML-KEM-768' ) &&
528- ( ! process . features . openssl_is_boringssl ||
529- ( ArrayPrototypeIncludes ( getHashes ( ) , 'sha3-256' ) &&
530- ArrayPrototypeIncludes ( getHashes ( ) , 'shake256' ) ) ) ,
531- 'MLKEM1024-P384' : ! isFips && ArrayPrototypeIncludes ( pqcKeyTypes , 'ML-KEM-1024' ) &&
532- ( ! process . features . openssl_is_boringssl ||
533- ( ArrayPrototypeIncludes ( getHashes ( ) , 'sha3-256' ) &&
534- ArrayPrototypeIncludes ( getHashes ( ) , 'shake256' ) ) ) ,
535- 'SHA3-256' : ! process . features . openssl_is_boringssl ||
536- ArrayPrototypeIncludes ( getHashes ( ) , 'sha3-256' ) ,
537- 'SHA3-384' : ! process . features . openssl_is_boringssl ||
538- ArrayPrototypeIncludes ( getHashes ( ) , 'sha3-384' ) ,
539- 'SHA3-512' : ! process . features . openssl_is_boringssl ||
540- ArrayPrototypeIncludes ( getHashes ( ) , 'sha3-512' ) ,
541- 'TurboSHAKE128' : ! isFips ,
542- 'TurboSHAKE256' : ! isFips ,
543- 'X448' : ! process . features . openssl_is_boringssl ,
544- } ;
510+ function has ( algorithms , name ) {
511+ return ArrayPrototypeIncludes ( algorithms , name ) ;
512+ }
513+
514+ // Re-evaluated when the active FIPS state changes.
515+ function getConditionalAlgorithms ( ) {
516+ const mlKem768 = isKeyAlgorithmAvailable ( 'ML-KEM-768' ) ;
517+ const mlKem1024 = isKeyAlgorithmAvailable ( 'ML-KEM-1024' ) ;
518+ const ciphers = getCiphers ( ) ;
519+ const hashes = getHashes ( ) ;
520+ const macs = getMacs ( ) ;
521+
522+ const fips = isFips ( ) ;
523+
524+ return {
525+ 'AES-OCB' : ! ! hasAesOcbMode &&
526+ ( has ( ciphers , 'aes-128-ocb' ) ||
527+ has ( ciphers , 'aes-192-ocb' ) ||
528+ has ( ciphers , 'aes-256-ocb' ) ) ,
529+ 'Argon2d' : ! ! Argon2Job && ! fips ,
530+ 'Argon2i' : ! ! Argon2Job && ! fips ,
531+ 'Argon2id' : ! ! Argon2Job && ! fips ,
532+ 'ChaCha20-Poly1305' : process . features . openssl_is_boringssl ||
533+ has ( ciphers , 'chacha20-poly1305' ) ,
534+ 'cSHAKE128' : has ( hashes , 'shake128' ) ,
535+ 'cSHAKE256' : has ( hashes , 'shake256' ) ,
536+ 'Ed25519' : isKeyAlgorithmAvailable ( 'Ed25519' ) ,
537+ 'Ed448' : isKeyAlgorithmAvailable ( 'Ed448' ) ,
538+ 'KMAC128' : ! ! KmacJob && has ( macs , 'kmac128' ) ,
539+ 'KMAC256' : ! ! KmacJob && has ( macs , 'kmac256' ) ,
540+ 'KT128' : ! fips ,
541+ 'KT256' : ! fips ,
542+ 'ML-DSA-44' : isKeyAlgorithmAvailable ( 'ML-DSA-44' ) ,
543+ 'ML-DSA-65' : isKeyAlgorithmAvailable ( 'ML-DSA-65' ) ,
544+ 'ML-DSA-87' : isKeyAlgorithmAvailable ( 'ML-DSA-87' ) ,
545+ 'ML-KEM-512' : isKeyAlgorithmAvailable ( 'ML-KEM-512' ) ,
546+ 'ML-KEM-768' : mlKem768 ,
547+ 'ML-KEM-1024' : mlKem1024 ,
548+ 'MLKEM768-P256' : ! fips && mlKem768 &&
549+ ( ! process . features . openssl_is_boringssl ||
550+ ( has ( hashes , 'sha3-256' ) &&
551+ has ( hashes , 'shake256' ) ) ) ,
552+ 'MLKEM768-X25519' : ! fips && mlKem768 &&
553+ ( ! process . features . openssl_is_boringssl ||
554+ ( has ( hashes , 'sha3-256' ) &&
555+ has ( hashes , 'shake256' ) ) ) ,
556+ 'MLKEM1024-P384' : ! fips && mlKem1024 &&
557+ ( ! process . features . openssl_is_boringssl ||
558+ ( has ( hashes , 'sha3-256' ) &&
559+ has ( hashes , 'shake256' ) ) ) ,
560+ 'SHA-1' : has ( hashes , 'sha1' ) ,
561+ 'SHA-256' : has ( hashes , 'sha256' ) ,
562+ 'SHA-384' : has ( hashes , 'sha384' ) ,
563+ 'SHA-512' : has ( hashes , 'sha512' ) ,
564+ 'SHA3-256' : has ( hashes , 'sha3-256' ) ,
565+ 'SHA3-384' : has ( hashes , 'sha3-384' ) ,
566+ 'SHA3-512' : has ( hashes , 'sha3-512' ) ,
567+ 'TurboSHAKE128' : ! fips ,
568+ 'TurboSHAKE256' : ! fips ,
569+ 'X25519' : isKeyAlgorithmAvailable ( 'X25519' ) ,
570+ 'X448' : isKeyAlgorithmAvailable ( 'X448' ) ,
571+ } ;
572+ }
545573
546574// Experimental algorithms
547575const experimentalAlgorithms = [
@@ -578,6 +606,7 @@ const experimentalAlgorithms = [
578606// Also builds a parallel Map<UPPERCASED_NAME, canonicalName> per operation
579607// for O(1) case-insensitive algorithm name lookup in normalizeAlgorithm.
580608function createSupportedAlgorithms ( algorithmDefs ) {
609+ const conditionalAlgorithms = getConditionalAlgorithms ( ) ;
581610 // Detached below rather than declared `__proto__: null`: V8 puts that
582611 // literal form in dictionary mode, slowing every registry lookup.
583612 const result = { } ;
@@ -625,8 +654,16 @@ function createSupportedAlgorithms(algorithmDefs) {
625654 return { algorithms : result , nameMap } ;
626655}
627656
628- const { algorithms : kSupportedAlgorithms , nameMap : kAlgorithmNameMap } =
629- createSupportedAlgorithms ( kAlgorithmDefinitions ) ;
657+ let supportedAlgorithms ;
658+ let supportedAlgorithmsGeneration ;
659+ function getSupportedAlgorithms ( ) {
660+ const generation = getFipsCryptoGeneration ( ) ;
661+ if ( supportedAlgorithmsGeneration !== generation ) {
662+ supportedAlgorithms = createSupportedAlgorithms ( kAlgorithmDefinitions ) ;
663+ supportedAlgorithmsGeneration = generation ;
664+ }
665+ return supportedAlgorithms ;
666+ }
630667
631668const simpleAlgorithmDictionaries = {
632669 AesCbcParams : { iv : 'BufferSource' } ,
@@ -688,7 +725,7 @@ function validateMaxBufferLength(data, name, max = kMaxBufferLength) {
688725}
689726
690727function validateKmacKeyLength ( length ) {
691- if ( ( length < 32 || length % 8 ) && isFips )
728+ if ( ( length < 32 || length % 8 ) && isFips ( ) )
692729 throw lazyDOMException ( 'Invalid key length' , 'NotSupportedError' ) ;
693730}
694731
@@ -751,16 +788,16 @@ function normalizeAlgorithm(algorithm, op) {
751788
752789 webidl ??= require ( 'internal/crypto/webidl' ) ;
753790
754- // 1.
755- const registeredAlgorithms = kSupportedAlgorithms [ op ] ;
756791 // 2. 3.
757792 const initialAlg = webidl . converters . Algorithm ( algorithm ,
758793 kNormalizeAlgorithmOpts ) ;
794+ const { algorithms, nameMap } = getSupportedAlgorithms ( ) ;
795+ const registeredAlgorithms = algorithms [ op ] ;
759796 // 4.
760797 let algName = initialAlg . name ;
761798
762799 // 5. Case-insensitive lookup via pre-built Map (O(1) instead of O(n)).
763- const canonicalName = kAlgorithmNameMap [ op ] ?. get (
800+ const canonicalName = nameMap [ op ] ?. get (
764801 StringPrototypeToUpperCase ( algName ) ) ;
765802 if ( canonicalName === undefined )
766803 throw lazyDOMException ( 'Unrecognized algorithm name' , 'NotSupportedError' ) ;
@@ -1197,7 +1234,9 @@ module.exports = {
11971234 toBuf,
11981235
11991236 kNamedCurveAliases,
1200- kSupportedAlgorithms,
1237+ get kSupportedAlgorithms ( ) {
1238+ return getSupportedAlgorithms ( ) . algorithms ;
1239+ } ,
12011240 isFips,
12021241 normalizeAlgorithm,
12031242 normalizeHashName,
0 commit comments