| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent fd7e904 commit 66ee479
20 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -20,6 +20,7 @@ const { | |||
| 20 | 20 | normalizeHashName, | |
| 21 | 21 | numBitsToBytes, | |
| 22 | 22 | truncateToBitLength, | |
| 23 | + validateKmacKeyLength, | ||
| 23 | 24 | } = require('internal/crypto/util'); | |
| 24 | 25 | ||
| 25 | 26 | const { | |
@@ -60,6 +61,9 @@ function normalizeKeyLength(handle, algorithm) { | |||
| 60 | 61 | length = algorithm.length; | |
| 61 | 62 | } | |
| 62 | 63 | ||
| 64 | + if (algorithm.name === 'KMAC128' || algorithm.name === 'KMAC256') | ||
| 65 | + validateKmacKeyLength(length); | ||
| 66 | + | ||
| 63 | 67 | return { handle, length }; | |
| 64 | 68 | } | |
| 65 | 69 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -47,9 +47,12 @@ const { | |||
| 47 | 47 | EVP_PKEY_ML_KEM_1024, | |
| 48 | 48 | kKeyVariantAES_OCB_128: hasAesOcbMode, | |
| 49 | 49 | Argon2Job, | |
| 50 | + getFipsCrypto, | ||
| 50 | 51 | KmacJob, | |
| 51 | 52 | } = internalBinding('crypto'); | |
| 52 | 53 | ||
| 54 | + const isFips = getFipsCrypto() === 1; | ||
| 55 | + | ||
| 53 | 56 | const { getOptionValue } = require('internal/options'); | |
| 54 | 57 | ||
| 55 | 58 | const { | |
@@ -415,6 +418,8 @@ const conditionalAlgorithms = { | |||
| 415 | 418 | 'Ed448': !process.features.openssl_is_boringssl, | |
| 416 | 419 | 'KMAC128': !!KmacJob, | |
| 417 | 420 | 'KMAC256': !!KmacJob, | |
| 421 | + 'KT128': !isFips, | ||
| 422 | + 'KT256': !isFips, | ||
| 418 | 423 | 'ML-DSA-44': !!EVP_PKEY_ML_DSA_44, | |
| 419 | 424 | 'ML-DSA-65': !!EVP_PKEY_ML_DSA_65, | |
| 420 | 425 | 'ML-DSA-87': !!EVP_PKEY_ML_DSA_87, | |
@@ -427,6 +432,8 @@ const conditionalAlgorithms = { | |||
| 427 | 432 | ArrayPrototypeIncludes(getHashes(), 'sha3-384'), | |
| 428 | 433 | 'SHA3-512': !process.features.openssl_is_boringssl || | |
| 429 | 434 | ArrayPrototypeIncludes(getHashes(), 'sha3-512'), | |
| 435 | + 'TurboSHAKE128': !isFips, | ||
| 436 | + 'TurboSHAKE256': !isFips, | ||
| 430 | 437 | 'X448': !process.features.openssl_is_boringssl, | |
| 431 | 438 | }; | |
| 432 | 439 | ||
@@ -571,6 +578,11 @@ function validateMaxBufferLength(data, name, max = kMaxBufferLength) { | |||
| 571 | 578 | } | |
| 572 | 579 | } | |
| 573 | 580 | ||
| 581 | + function validateKmacKeyLength(length) { | ||
| 582 | + if ((length < 32 || length % 8) && isFips) | ||
| 583 | + throw lazyDOMException('Invalid key length', 'NotSupportedError'); | ||
| 584 | + } | ||
| 585 | + | ||
| 574 | 586 | /** | |
| 575 | 587 | * Converts a bit length to the number of bytes needed to contain it. | |
| 576 | 588 | * Non-byte lengths are rounded up to the next byte. | |
@@ -1088,6 +1100,7 @@ module.exports = { | |||
| 1088 | 1100 | ||
| 1089 | 1101 | kNamedCurveAliases, | |
| 1090 | 1102 | kSupportedAlgorithms, | |
| 1103 | + isFips, | ||
| 1091 | 1104 | normalizeAlgorithm, | |
| 1092 | 1105 | normalizeHashName, | |
| 1093 | 1106 | hasAnyNotIn, | |
@@ -1097,6 +1110,7 @@ module.exports = { | |||
| 1097 | 1110 | jobPromiseThen, | |
| 1098 | 1111 | cleanupWebCryptoResult, | |
| 1099 | 1112 | prepareWebCryptoResult, | |
| 1113 | + validateKmacKeyLength, | ||
| 1100 | 1114 | validateMaxBufferLength, | |
| 1101 | 1115 | numBitsToBytes, | |
| 1102 | 1116 | truncateToBitLength, | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -9,7 +9,6 @@ const { | |||
| 9 | 9 | StringPrototypeSplit, | |
| 10 | 10 | StringPrototypeStartsWith, | |
| 11 | 11 | StringPrototypeToLowerCase, | |
| 12 | - TypedArrayPrototypeGetLength, | ||
| 13 | 12 | } = primordials; | |
| 14 | 13 | ||
| 15 | 14 | const { | |
@@ -28,8 +27,10 @@ const { | |||
| 28 | 27 | validateMaxBufferLength, | |
| 29 | 28 | getBufferSourceByteLength, | |
| 30 | 29 | getBufferSourceBytes, | |
| 30 | + isFips, | ||
| 31 | 31 | kNamedCurveAliases, | |
| 32 | 32 | numBitsToBytes, | |
| 33 | + validateKmacKeyLength, | ||
| 33 | 34 | } = require('internal/crypto/util'); | |
| 34 | 35 | const { | |
| 35 | 36 | converters: webidl, | |
@@ -276,30 +277,39 @@ function validateCShakeOutputLength(V) { | |||
| 276 | 277 | } | |
| 277 | 278 | } | |
| 278 | 279 | ||
| 279 | - function bufferSourceEqualsAscii(V, string) { | ||
| 280 | - if (getBufferSourceByteLength(V) !== string.length) return false; | ||
| 281 | - | ||
| 282 | - const bytes = getBufferSourceBytes(V); | ||
| 283 | - const length = TypedArrayPrototypeGetLength(bytes); | ||
| 284 | - for (let i = 0; i < length; i++) { | ||
| 285 | - if (bytes[i] !== StringPrototypeCharCodeAt(string, i)) return false; | ||
| 286 | - } | ||
| 287 | - return true; | ||
| 288 | - } | ||
| 280 | + const kCShakeFunctionNames = ['KMAC', 'TupleHash', 'ParallelHash']; | ||
| 289 | 281 | ||
| 290 | 282 | function validateCShakeFunctionName(V) { | |
| 291 | - if (getBufferSourceByteLength(V) === 0 || | ||
| 292 | - bufferSourceEqualsAscii(V, 'KMAC') || | ||
| 293 | - bufferSourceEqualsAscii(V, 'TupleHash') || | ||
| 294 | - bufferSourceEqualsAscii(V, 'ParallelHash')) { | ||
| 295 | - return; | ||
| 283 | + const length = getBufferSourceByteLength(V); | ||
| 284 | + if (length === 0) return; | ||
| 285 | + | ||
| 286 | + if (!isFips) { | ||
| 287 | + const bytes = getBufferSourceBytes(V); | ||
| 288 | + for (let i = 0; i < kCShakeFunctionNames.length; i++) { | ||
| 289 | + const functionName = kCShakeFunctionNames[i]; | ||
| 290 | + if (length !== functionName.length) continue; | ||
| 291 | + | ||
| 292 | + let j = 0; | ||
| 293 | + for (; j < length; j++) { | ||
| 294 | + if (bytes[j] !== StringPrototypeCharCodeAt(functionName, j)) break; | ||
| 295 | + } | ||
| 296 | + if (j === length) return; | ||
| 297 | + } | ||
| 296 | 298 | } | |
| 297 | 299 | ||
| 298 | 300 | throw lazyDOMException( | |
| 299 | 301 | 'Unsupported CShakeParams functionName', | |
| 300 | 302 | 'NotSupportedError'); | |
| 301 | 303 | } | |
| 302 | 304 | ||
| 305 | + function validateCShakeCustomization(V) { | ||
| 306 | + if (isFips && getBufferSourceByteLength(V) !== 0) | ||
| 307 | + throw lazyDOMException( | ||
| 308 | + 'Unsupported CShakeParams customization', | ||
| 309 | + 'NotSupportedError'); | ||
| 310 | + validateMaxBufferLength(V, 'CShakeParams.customization', 512); | ||
| 311 | + } | ||
| 312 | + | ||
| 303 | 313 | converters.RsaPssParams = createDictionaryConverter( | |
| 304 | 314 | 'RsaPssParams', [ | |
| 305 | 315 | dictAlgorithm, | |
@@ -457,7 +467,7 @@ converters.CShakeParams = createDictionaryConverter( | |||
| 457 | 467 | { | |
| 458 | 468 | key: 'customization', | |
| 459 | 469 | converter: converters.BufferSource, | |
| 460 | - validator: (V, opts) => validateMaxBufferLength(V, 'CShakeParams.customization', 512), | ||
| 470 | + validator: validateCShakeCustomization, | ||
| 461 | 471 | }, | |
| 462 | 472 | ], | |
| 463 | 473 | ]); | |
@@ -743,6 +753,7 @@ for (let i = 0; i < kKmacDictionaries.length; i++) { | |||
| 743 | 753 | key: 'length', | |
| 744 | 754 | converter: (V, opts) => | |
| 745 | 755 | converters['unsigned long'](V, enforceRangeOptions(opts)), | |
| 756 | + validator: validateKmacKeyLength, | ||
| 746 | 757 | }, | |
| 747 | 758 | ], | |
| 748 | 759 | ]); | |
@@ -756,6 +767,12 @@ converters.KmacParams = createDictionaryConverter( | |||
| 756 | 767 | key: 'outputLength', | |
| 757 | 768 | converter: (V, opts) => | |
| 758 | 769 | converters['unsigned long'](V, enforceRangeOptions(opts)), | |
| 770 | + validator: (V) => { | ||
| 771 | + if ((V === 0 || V % 8) && isFips) | ||
| 772 | + throw lazyDOMException( | ||
| 773 | + 'Invalid KmacParams outputLength', | ||
| 774 | + 'NotSupportedError'); | ||
| 775 | + }, | ||
| 759 | 776 | required: true, | |
| 760 | 777 | }, | |
| 761 | 778 | { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -812,6 +812,11 @@ Maybe<void> CShakeTraits::AdditionalConfig( | |||
| 812 | 812 | CShakeConfig* params) { | |
| 813 | 813 | Environment* env = Environment::GetCurrent(args); | |
| 814 | 814 | ||
| 815 | + if (IsFipsEnabled()) { | ||
| 816 | + THROW_ERR_CRYPTO_UNSUPPORTED_OPERATION(env); | ||
| 817 | + return Nothing<void>(); | ||
| 818 | + } | ||
| 819 | + | ||
| 815 | 820 | CHECK(args[offset]->IsString()); // Algorithm name | |
| 816 | 821 | Utf8Value algorithm_name(env->isolate(), args[offset]); | |
| 817 | 822 | std::string_view algorithm_str = algorithm_name.ToStringView(); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -151,6 +151,8 @@ bool DeriveBitsWithCShake(const KmacConfig& params, | |||
| 151 | 151 | const void* key_data, | |
| 152 | 152 | size_t key_size, | |
| 153 | 153 | ByteSource* out) { | |
| 154 | + if (IsFipsEnabled()) return false; | ||
| 155 | + | ||
| 154 | 156 | const size_t key_length_bytes = NumBitsToBytes(params.key_length); | |
| 155 | 157 | if (key_size < key_length_bytes) return false; | |
| 156 | 158 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -428,6 +428,11 @@ Maybe<void> TurboShakeTraits::AdditionalConfig( | |||
| 428 | 428 | TurboShakeConfig* params) { | |
| 429 | 429 | Environment* env = Environment::GetCurrent(args); | |
| 430 | 430 | ||
| 431 | + if (IsFipsEnabled()) { | ||
| 432 | + THROW_ERR_CRYPTO_UNSUPPORTED_OPERATION(env); | ||
| 433 | + return Nothing<void>(); | ||
| 434 | + } | ||
| 435 | + | ||
| 431 | 436 | // args[offset + 0] = algorithm name (string) | |
| 432 | 437 | CHECK(args[offset]->IsString()); | |
| 433 | 438 | Utf8Value algorithm_name(env->isolate(), args[offset]); | |
@@ -535,6 +540,11 @@ Maybe<void> KangarooTwelveTraits::AdditionalConfig( | |||
| 535 | 540 | KangarooTwelveConfig* params) { | |
| 536 | 541 | Environment* env = Environment::GetCurrent(args); | |
| 537 | 542 | ||
| 543 | + if (IsFipsEnabled()) { | ||
| 544 | + THROW_ERR_CRYPTO_UNSUPPORTED_OPERATION(env); | ||
| 545 | + return Nothing<void>(); | ||
| 546 | + } | ||
| 547 | + | ||
| 538 | 548 | // args[offset + 0] = algorithm name (string) | |
| 539 | 549 | CHECK(args[offset]->IsString()); | |
| 540 | 550 | Utf8Value algorithm_name(env->isolate(), args[offset]); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -146,6 +146,11 @@ bool InitCryptoOnce(Isolate* isolate) { | |||
| 146 | 146 | // be part of a larger mutex for global OpenSSL state. | |
| 147 | 147 | static Mutex fips_mutex; | |
| 148 | 148 | ||
| 149 | + bool IsFipsEnabled() { | ||
| 150 | + Mutex::ScopedLock fips_lock(fips_mutex); | ||
| 151 | + return ncrypto::isFipsEnabled(); | ||
| 152 | + } | ||
| 153 | + | ||
| 149 | 154 | void InitCryptoOnce() { | |
| 150 | 155 | Mutex::ScopedLock lock(per_process::cli_options_mutex); | |
| 151 | 156 | Mutex::ScopedLock fips_lock(fips_mutex); | |
@@ -223,8 +228,7 @@ void InitCryptoOnce() { | |||
| 223 | 228 | ||
| 224 | 229 | void GetFipsCrypto(const FunctionCallbackInfo<Value>& args) { | |
| 225 | 230 | Mutex::ScopedLock lock(per_process::cli_options_mutex); | |
| 226 | - Mutex::ScopedLock fips_lock(fips_mutex); | ||
| 227 | - args.GetReturnValue().Set(ncrypto::isFipsEnabled() ? 1 : 0); | ||
| 231 | + args.GetReturnValue().Set(IsFipsEnabled() ? 1 : 0); | ||
| 228 | 232 | } | |
| 229 | 233 | ||
| 230 | 234 | void SetFipsCrypto(const FunctionCallbackInfo<Value>& args) { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -66,6 +66,7 @@ constexpr T NumBitsToBytes(T bits) { | |||
| 66 | 66 | // what went wrong, or std::nullopt when there was nothing to do or the | |
| 67 | 67 | // options were applied successfully. | |
| 68 | 68 | std::optional<std::string> ProcessFipsOptions(); | |
| 69 | + bool IsFipsEnabled(); | ||
| 69 | 70 | ||
| 70 | 71 | bool InitCryptoOnce(v8::Isolate* isolate); | |
| 71 | 72 | void InitCryptoOnce(); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -14,6 +14,7 @@ const { | |||
| 14 | 14 | } = require('crypto'); | |
| 15 | 15 | const { hasFIPS } = require('../common/crypto'); | |
| 16 | 16 | const { kSupportedAlgorithms } = require('internal/crypto/util'); | |
| 17 | + const fips = hasFIPS(); | ||
| 17 | 18 | const rejectsXCurves = hasFIPS(3, 5); | |
| 18 | 19 | ||
| 19 | 20 | const hashes = Object.keys(kSupportedAlgorithms.digest).filter((name) => { | |
@@ -135,14 +136,24 @@ function macInvalid(algorithm, invalidLengthMessage, allowZeroKey = false) { | |||
| 135 | 136 | const key = createSecretKey(randomBytes(32)); | |
| 136 | 137 | const usages = ['sign', 'verify']; | |
| 137 | 138 | ||
| 138 | - if (allowZeroKey) { | ||
| 139 | + if (allowZeroKey && !fips) { | ||
| 139 | 140 | const zeroKey = createSecretKey(Buffer.alloc(0)) | |
| 140 | 141 | .toCryptoKey(algorithm, true, usages); | |
| 141 | 142 | assert.strictEqual(zeroKey.algorithm.length, 0); | |
| 142 | 143 | ||
| 143 | 144 | const explicitZeroKey = createSecretKey(Buffer.alloc(0)) | |
| 144 | 145 | .toCryptoKey({ ...algorithm, length: 0 }, true, usages); | |
| 145 | 146 | assert.strictEqual(explicitZeroKey.algorithm.length, 0); | |
| 147 | + } else if (allowZeroKey) { | ||
| 148 | + for (const zeroAlgorithm of [algorithm, { ...algorithm, length: 0 }]) { | ||
| 149 | + assert.throws(() => { | ||
| 150 | + createSecretKey(Buffer.alloc(0)) | ||
| 151 | + .toCryptoKey(zeroAlgorithm, true, usages); | ||
| 152 | + }, { | ||
| 153 | + name: 'NotSupportedError', | ||
| 154 | + message: 'Invalid key length', | ||
| 155 | + }); | ||
| 156 | + } | ||
| 146 | 157 | } else { | |
| 147 | 158 | assert.throws(() => { | |
| 148 | 159 | createSecretKey(Buffer.alloc(0)).toCryptoKey(algorithm, true, usages); | |
@@ -157,12 +168,15 @@ function macInvalid(algorithm, invalidLengthMessage, allowZeroKey = false) { | |||
| 157 | 168 | message: 'Usages cannot be empty when importing a secret key.' | |
| 158 | 169 | }); | |
| 159 | 170 | ||
| 160 | - assert.throws(() => { | ||
| 161 | - key.toCryptoKey({ ...algorithm, length: 0 }, true, usages); | ||
| 162 | - }, { | ||
| 163 | - name: 'DataError', | ||
| 164 | - message: invalidLengthMessage, | ||
| 165 | - }); | ||
| 171 | + assert.throws( | ||
| 172 | + () => key.toCryptoKey({ ...algorithm, length: 0 }, true, usages), | ||
| 173 | + allowZeroKey && fips ? { | ||
| 174 | + name: 'NotSupportedError', | ||
| 175 | + message: 'Invalid key length', | ||
| 176 | + } : { | ||
| 177 | + name: 'DataError', | ||
| 178 | + message: invalidLengthMessage, | ||
| 179 | + }); | ||
| 166 | 180 | } | |
| 167 | 181 | ||
| 168 | 182 | function hmacVectors() { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -283,7 +283,7 @@ const fips4 = hasFIPS(4); | |||
| 283 | 283 | })().then(common.mustCall()); | |
| 284 | 284 | } | |
| 285 | 285 | ||
| 286 | - if (hasOpenSSL(3)) { | ||
| 286 | + if (hasOpenSSL(3) && !hasFIPS()) { | ||
| 287 | 287 | (async () => { | |
| 288 | 288 | const derivedKeyAlgorithm = { name: 'KMAC128', length: 0 }; | |
| 289 | 289 | const usages = ['sign']; | |
@@ -325,11 +325,7 @@ if (hasOpenSSL(3)) { | |||
| 325 | 325 | name: 'KMAC128', | |
| 326 | 326 | outputLength: 256, | |
| 327 | 327 | }, derived, new Uint8Array()); | |
| 328 | - if (fips4) { | ||
| 329 | - await assert.rejects(signature, { name: 'OperationError' }); | ||
| 330 | - } else { | ||
| 331 | - assert.strictEqual((await signature).byteLength, 32); | ||
| 332 | - } | ||
| 328 | + assert.strictEqual((await signature).byteLength, 32); | ||
| 333 | 329 | } | |
| 334 | 330 | })().then(common.mustCall()); | |
| 335 | 331 | } | |
| Back | FazBrowse Home | New Git URL |
0 commit comments