Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/internal/crypto/webcrypto.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -1604,6 +1604,7 @@ class SubtleCrypto {
}

// Implements https://wicg.github.io/webcrypto-modern-algos/#SubtleCrypto-method-supports
// TODO(panva): Make supports() account for the active FIPS state.
static supports(operation, algorithm, lengthOrAdditionalAlgorithm = null) {
emitExperimentalWarning('The supports Web Crypto API method');
if (this !== SubtleCrypto) throw new ERR_INVALID_THIS('SubtleCrypto constructor');
Expand Down
14 changes: 12 additions & 2 deletions test/common/crypto.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -50,9 +50,14 @@ function assertApproximateSize(key, expectedSize) {
function testEncryptDecrypt(publicKey, privateKey) {
const message = 'Hello Node.js world!';
const plaintext = Buffer.from(message, 'utf8');
const withOaepHash = (key) => {
if (!hasFIPS(3)) return key;
if (key?.key !== undefined) return { ...key, oaepHash: 'sha256' };
return { key, oaepHash: 'sha256' };
};
for (const key of [publicKey, privateKey]) {
const ciphertext = publicEncrypt(key, plaintext);
const received = privateDecrypt(privateKey, ciphertext);
const ciphertext = publicEncrypt(withOaepHash(key), plaintext);
const received = privateDecrypt(withOaepHash(privateKey), ciphertext);
assert.strictEqual(received.toString('utf8'), message);
}
}
Expand DownExpand Up@@ -118,6 +123,10 @@ const hasOpenSSL = (major = 0, minor = 0, patch = 0) => {
return OPENSSL_VERSION_NUMBER >= opensslVersionNumber(major, minor, patch);
};

const hasFIPS = (major = 0, minor = 0, patch = 0) => {
return crypto.getFips() === 1 && hasOpenSSL(major, minor, patch);
};

let opensslCli = null;

module.exports = {
Expand All@@ -134,6 +143,7 @@ module.exports = {
sec1Exp,
sec1EncExp,
hasOpenSSL,
hasFIPS,
get hasOpenSSL3() {
return hasOpenSSL(3);
},
Expand Down
28 changes: 28 additions & 0 deletions test/fixtures/keys/Makefile
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,6 +8,7 @@ all: \
ca5-cert.pem \
ca6-cert.pem \
agent1-cert.pem \
agent1-fips.pfx \
agent1.pfx \
agent2-cert.pem \
agent3-cert.pem \
Expand DownExpand Up@@ -39,6 +40,7 @@ all: \
dsa_private_encrypted_1025.pem \
dsa_public_1025.pem \
ec-cert.pem \
ec-fips.pfx \
ec.pfx \
fake-cnnic-root-cert.pem \
intermediate-ca-cert.pem \
Expand DownExpand Up@@ -444,6 +446,20 @@ agent1.pfx: agent1-cert.pem agent1-key.pem ca1-cert.pem
-out agent1.pfx \
-password pass:sample

# PKCS12KDF is unavailable under FIPS properties. Use PBMAC1 with PBKDF2
# instead, alongside AES-256/PBKDF2 key protection.
agent1-fips.pfx: agent1-cert.pem agent1-key.pem ca1-cert.pem
openssl pkcs12 -export \
-keypbe AES-256-CBC \
-certpbe AES-256-CBC \
-iter 2048 \
-pbmac1_pbkdf2 \
-in agent1-cert.pem \
-inkey agent1-key.pem \
-certfile ca1-cert.pem \
-out agent1-fips.pfx \
-password pass:password

agent1-verify: agent1-cert.pem ca1-cert.pem
openssl verify -CAfile ca1-cert.pem agent1-cert.pem

Expand DownExpand Up@@ -787,6 +803,18 @@ ec.pfx: ec-cert.pem ec-key.pem
-out ec.pfx \
-password pass:

# See agent1-fips.pfx for why the FIPS fixture uses PBMAC1.
ec-fips.pfx: ec-cert.pem ec-key.pem
openssl pkcs12 -export \
-keypbe AES-256-CBC \
-certpbe AES-256-CBC \
-iter 2048 \
-pbmac1_pbkdf2 \
-in ec-cert.pem \
-inkey ec-key.pem \
-out ec-fips.pfx \
-password pass:password

dh512.pem:
openssl dhparam -out dh512.pem 512

Expand Down
Binary file addedtest/fixtures/keys/agent1-fips.pfx
Binary file not shown.
Binary file addedtest/fixtures/keys/ec-fips.pfx
Binary file not shown.
4 changes: 3 additions & 1 deletion test/parallel/test-crypto-argon2-job.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -4,10 +4,12 @@ const common = require('../common');
if (!common.hasCrypto)
common.skip('missing crypto');

const { hasOpenSSL } = require('../common/crypto');
const { hasFIPS, hasOpenSSL } = require('../common/crypto');

if (!hasOpenSSL(3, 2))
common.skip('requires OpenSSL >= 3.2');
if (hasFIPS(3))
common.skip('Argon2 is not available in FIPS mode');

// Exercises the native Argon2 job directly via internalBinding, bypassing
// the JS validators, to ensure that if invalid parameters ever reach the
Expand Down
13 changes: 12 additions & 1 deletion test/parallel/test-crypto-argon2.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -3,7 +3,7 @@ const common = require('../common');
if (!common.hasCrypto)
common.skip('missing crypto');

const { hasOpenSSL } = require('../common/crypto');
const { hasFIPS, hasOpenSSL } = require('../common/crypto');

if (!hasOpenSSL(3, 2))
common.skip('requires OpenSSL >= 3.2');
Expand All@@ -28,6 +28,17 @@ const secret = Buffer.alloc(8, 0x03);
const associatedData = Buffer.alloc(12, 0x04);
const defaults = { message, nonce, parallelism: 1, tagLength: 64, memory: 8, passes: 3 };

if (hasFIPS(3)) {
assert.throws(() => crypto.argon2Sync('argon2id', defaults), {
code: 'ERR_OSSL_EVP_UNSUPPORTED',
});
crypto.argon2('argon2id', defaults, common.mustCall((err, result) => {
assert.strictEqual(err?.code, 'ERR_OSSL_EVP_UNSUPPORTED');
assert.strictEqual(result, undefined);
}));
return;
}

const good = [
// Test vectors from RFC 9106 https://www.rfc-editor.org/rfc/rfc9106.html#name-test-vectors
// and OpenSSL 3.2 https://github.com/openssl/openssl/blob/6dfa998f7ea150f9c6d4e4727cf6d5c82a68a8da/test/recipes/30-test_evp_data/evpkdf_argon2.txt
Expand Down
61 changes: 43 additions & 18 deletions test/parallel/test-crypto-async-sign-verify.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -3,12 +3,14 @@ const common = require('../common');
if (!common.hasCrypto)
common.skip('missing crypto');

const { hasOpenSSL3 } = require('../common/crypto');
const { hasOpenSSL, hasFIPS } = require('../common/crypto');
const assert = require('assert');
const util = require('util');
const crypto = require('crypto');
const fixtures = require('../common/fixtures');

const fips3 = hasFIPS(3);

function test(
publicFixture,
privateFixture,
Expand DownExpand Up@@ -65,6 +67,15 @@ function test(
}
}

function testSignFailure(privateFixture, algorithm, options, code) {
const key = { key: fixtures.readKey(privateFixture), ...options };
const data = Buffer.from('Hello world');
assert.throws(() => crypto.sign(algorithm, data, key), { code });
crypto.sign(algorithm, data, key, common.mustCall((err) => {
assert.strictEqual(err?.code, code);
}));
}

// RSA w/ default padding
test('rsa_public.pem', 'rsa_private.pem', 'sha256', true);
test('rsa_public.pem', 'rsa_private.pem', 'sha256', true,
Expand DownExpand Up@@ -94,14 +105,19 @@ if (!process.features.openssl_is_boringssl) {
test('ed448_public.pem', 'ed448_private.pem', undefined, true);

// ECDSA w/ der signature encoding
test('ec_secp256k1_public.pem', 'ec_secp256k1_private.pem', 'sha384',
false);
test('ec_secp256k1_public.pem', 'ec_secp256k1_private.pem', 'sha384',
false, { dsaEncoding: 'der' });

// ECDSA w/ ieee-p1363 signature encoding
test('ec_secp256k1_public.pem', 'ec_secp256k1_private.pem', 'sha384', false,
{ dsaEncoding: 'ieee-p1363' });
if (fips3) {
testSignFailure('ec_secp256k1_private.pem', 'sha384', {},
'ERR_OSSL_EVP_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE');
} else {
test('ec_secp256k1_public.pem', 'ec_secp256k1_private.pem', 'sha384',
false);
test('ec_secp256k1_public.pem', 'ec_secp256k1_private.pem', 'sha384',
false, { dsaEncoding: 'der' });

// ECDSA w/ ieee-p1363 signature encoding
test('ec_secp256k1_public.pem', 'ec_secp256k1_private.pem', 'sha384', false,
{ dsaEncoding: 'ieee-p1363' });
}

// DSA w/ der signature encoding
test('dsa_public.pem', 'dsa_private.pem', 'sha256',
Expand DownExpand Up@@ -157,7 +173,7 @@ MCowBQYDK2VuAyEA6pwGRbadNQAI/tYN8+/p/0/hbsdHfOEGr1ADiLVk/Gc=

let expected = /no default digest/;
let expectedCode = 'ERR_OSSL_EVP_NO_DEFAULT_DIGEST';
if (hasOpenSSL3 || process.features.openssl_is_boringssl) {
if (hasOpenSSL(3) || process.features.openssl_is_boringssl) {
expected = /operation[\s_]not[\s_]supported[\s_]for[\s_]this[\s_]keytype/i;
expectedCode = 'ERR_OSSL_EVP_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE';
}
Expand All@@ -170,12 +186,21 @@ MCowBQYDK2VuAyEA6pwGRbadNQAI/tYN8+/p/0/hbsdHfOEGr1ADiLVk/Gc=
}

{
const { privateKey } = crypto.generateKeyPairSync('rsa', {
modulusLength: 512
});
crypto.sign('sha512', 'message', privateKey, common.mustCall((err) => {
assert.ok(err);
assert.match(err.message, /digest[\s_]too[\s_]big[\s_]for[\s_]rsa[\s_]key/i);
assert.match(err.code, /^ERR_OSSL_.*DIGEST_TOO_BIG_FOR_RSA_KEY$/);
}));
if (fips3) {
crypto.generateKeyPair('rsa', { modulusLength: 512 },
common.mustCall((err) => {
assert.strictEqual(
err?.code, 'ERR_OSSL_RSA_INVALID_MODULUS');
}));
} else {
const { privateKey } = crypto.generateKeyPairSync('rsa', {
modulusLength: 512
});
crypto.sign('sha512', 'message', privateKey, common.mustCall((err) => {
assert.ok(err);
assert.match(
err.message, /digest[\s_]too[\s_]big[\s_]for[\s_]rsa[\s_]key/i);
assert.match(err.code, /^ERR_OSSL_.*DIGEST_TOO_BIG_FOR_RSA_KEY$/);
}));
}
}
11 changes: 11 additions & 0 deletions test/parallel/test-crypto-authenticated-stream.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -6,6 +6,7 @@ if (!common.hasCrypto)

const assert = require('assert');
const crypto = require('crypto');
const { hasFIPS } = require('../common/crypto');
const fs = require('fs');
const stream = require('stream');
const tmpdir = require('../common/tmpdir');
Expand DownExpand Up@@ -120,6 +121,16 @@ function test(config) {
return;
}

if (hasFIPS(3)) {
assert.throws(() => crypto.createDecipheriv(
config.cipher, config.key, config.iv, {
authTagLength: config.authTagLength,
}), {
code: 'ERR_CRYPTO_UNSUPPORTED_OPERATION',
});
return;
}

direct(config);
mstream(config);
fstream(config);
Expand Down
51 changes: 37 additions & 14 deletions test/parallel/test-crypto-authenticated.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -29,9 +29,10 @@ const assert = require('assert');
const crypto = require('crypto');
const { inspect } = require('util');
const fixtures = require('../common/fixtures');
const { hasOpenSSL3 } = require('../common/crypto');
const { hasOpenSSL, hasFIPS } = require('../common/crypto');

const isFipsEnabled = crypto.getFips();
const isFipsEnabled = crypto.getFips() === 1;
const fips3 = hasFIPS(3);

//
// Test authenticated encryption modes.
Expand DownExpand Up@@ -559,6 +560,14 @@ for (const test of TEST_CASES) {
const ciphertext = Buffer.concat([cipher.update(plain), cipher.final()]);
const tag = cipher.getAuthTag();

if (fips3 && mode === 'ccm') {
assert.throws(() => crypto.createDecipheriv(
`aes-128-${mode}`, key, iv, opts), {
code: 'ERR_CRYPTO_UNSUPPORTED_OPERATION',
});
continue;
}

const decipher = crypto.createDecipheriv(`aes-128-${mode}`, key, iv, opts);
decipher.setAuthTag(tag);
assert.throws(() => {
Expand DownExpand Up@@ -636,15 +645,22 @@ for (const test of TEST_CASES) {
const cipher = crypto.createCipheriv('aes-128-ccm', key, iv, opts);
assert.throws(() => {
cipher.final();
}, hasOpenSSL3 ? {
}, hasOpenSSL(3) ? {
code: 'ERR_OSSL_TAG_NOT_SET'
} : {
message: /Unsupported state/
});
}
}

if (!process.features.openssl_is_boringssl) {
if (fips3) {
assert.throws(() => crypto.createCipheriv(
'chacha20-poly1305', Buffer.alloc(32), Buffer.alloc(12), {
authTagLength: 16,
}), {
code: 'ERR_OSSL_EVP_UNSUPPORTED',
});
} else if (!process.features.openssl_is_boringssl) {
const key = Buffer.alloc(32);
const iv = Buffer.alloc(12);

Expand All@@ -662,7 +678,7 @@ if (!process.features.openssl_is_boringssl) {

// ChaCha20-Poly1305 should respect the authTagLength option and should not
// require the authentication tag before calls to update() during decryption.
if (!process.features.openssl_is_boringssl) {
if (!fips3 && !process.features.openssl_is_boringssl) {
const key = Buffer.alloc(32);
const iv = Buffer.alloc(12);

Expand DownExpand Up@@ -713,7 +729,7 @@ if (!process.features.openssl_is_boringssl) {
// shorter tags as long as their length was valid according to NIST SP 800-38D.
// For ChaCha20-Poly1305, we intentionally deviate from that because there are
// no recommended or approved authentication tag lengths below 16 bytes.
if (!process.features.openssl_is_boringssl) {
if (!fips3 && !process.features.openssl_is_boringssl) {
const rfcTestCases = TEST_CASES.filter(({ algo, tampered }) => {
return algo === 'chacha20-poly1305' && tampered === false;
});
Expand DownExpand Up@@ -752,7 +768,7 @@ if (!process.features.openssl_is_boringssl) {
}

// https://github.com/nodejs/node/issues/45874
if (!process.features.openssl_is_boringssl) {
if (!fips3 && !process.features.openssl_is_boringssl) {
const rfcTestCases = TEST_CASES.filter(({ algo, tampered }) => {
return algo === 'chacha20-poly1305' && tampered === false;
});
Expand DownExpand Up@@ -798,13 +814,20 @@ if (ciphers.includes('aes-128-ccm')) {
const tag = cipher.getAuthTag();
assert.strictEqual(tag.length, 16);

const decipher = crypto.createDecipheriv('aes-128-ccm', key, nonce, {
authTagLength: 16,
});
decipher.setAuthTag(tag);
decipher.setAAD(Buffer.alloc(0), { plaintextLength: 0 });
decipher.update(new DataView(new ArrayBuffer(0)));
decipher.final();
if (fips3) {
assert.throws(() => crypto.createDecipheriv(
'aes-128-ccm', key, nonce, { authTagLength: 16 }), {
code: 'ERR_CRYPTO_UNSUPPORTED_OPERATION',
});
} else {
const decipher = crypto.createDecipheriv('aes-128-ccm', key, nonce, {
authTagLength: 16,
});
decipher.setAuthTag(tag);
decipher.setAAD(Buffer.alloc(0), { plaintextLength: 0 });
decipher.update(new DataView(new ArrayBuffer(0)));
decipher.final();
}
} else {
common.printSkipMessage('Skipping unsupported aes-128-ccm test');
}
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/internal/crypto/webcrypto.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -1604,6 +1604,7 @@ class SubtleCrypto {
}

// Implements https://wicg.github.io/webcrypto-modern-algos/#SubtleCrypto-method-supports
// TODO(panva): Make supports() account for the active FIPS state.
static supports(operation, algorithm, lengthOrAdditionalAlgorithm = null) {
emitExperimentalWarning('The supports Web Crypto API method');
if (this !== SubtleCrypto) throw new ERR_INVALID_THIS('SubtleCrypto constructor');
Expand Down
14 changes: 12 additions & 2 deletions test/common/crypto.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -50,9 +50,14 @@ function assertApproximateSize(key, expectedSize) {
function testEncryptDecrypt(publicKey, privateKey) {
const message = 'Hello Node.js world!';
const plaintext = Buffer.from(message, 'utf8');
const withOaepHash = (key) => {
if (!hasFIPS(3)) return key;
if (key?.key !== undefined) return { ...key, oaepHash: 'sha256' };
return { key, oaepHash: 'sha256' };
};
for (const key of [publicKey, privateKey]) {
const ciphertext = publicEncrypt(key, plaintext);
const received = privateDecrypt(privateKey, ciphertext);
const ciphertext = publicEncrypt(withOaepHash(key), plaintext);
const received = privateDecrypt(withOaepHash(privateKey), ciphertext);
assert.strictEqual(received.toString('utf8'), message);
}
}
Expand DownExpand Up@@ -118,6 +123,10 @@ const hasOpenSSL = (major = 0, minor = 0, patch = 0) => {
return OPENSSL_VERSION_NUMBER >= opensslVersionNumber(major, minor, patch);
};

const hasFIPS = (major = 0, minor = 0, patch = 0) => {
return crypto.getFips() === 1 && hasOpenSSL(major, minor, patch);
};

let opensslCli = null;

module.exports = {
Expand All@@ -134,6 +143,7 @@ module.exports = {
sec1Exp,
sec1EncExp,
hasOpenSSL,
hasFIPS,
get hasOpenSSL3() {
return hasOpenSSL(3);
},
Expand Down
28 changes: 28 additions & 0 deletions test/fixtures/keys/Makefile
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,6 +8,7 @@ all: \
ca5-cert.pem \
ca6-cert.pem \
agent1-cert.pem \
agent1-fips.pfx \
agent1.pfx \
agent2-cert.pem \
agent3-cert.pem \
Expand DownExpand Up@@ -39,6 +40,7 @@ all: \
dsa_private_encrypted_1025.pem \
dsa_public_1025.pem \
ec-cert.pem \
ec-fips.pfx \
ec.pfx \
fake-cnnic-root-cert.pem \
intermediate-ca-cert.pem \
Expand DownExpand Up@@ -444,6 +446,20 @@ agent1.pfx: agent1-cert.pem agent1-key.pem ca1-cert.pem
-out agent1.pfx \
-password pass:sample

# PKCS12KDF is unavailable under FIPS properties. Use PBMAC1 with PBKDF2
# instead, alongside AES-256/PBKDF2 key protection.
agent1-fips.pfx: agent1-cert.pem agent1-key.pem ca1-cert.pem
openssl pkcs12 -export \
-keypbe AES-256-CBC \
-certpbe AES-256-CBC \
-iter 2048 \
-pbmac1_pbkdf2 \
-in agent1-cert.pem \
-inkey agent1-key.pem \
-certfile ca1-cert.pem \
-out agent1-fips.pfx \
-password pass:password

agent1-verify: agent1-cert.pem ca1-cert.pem
openssl verify -CAfile ca1-cert.pem agent1-cert.pem

Expand DownExpand Up@@ -787,6 +803,18 @@ ec.pfx: ec-cert.pem ec-key.pem
-out ec.pfx \
-password pass:

# See agent1-fips.pfx for why the FIPS fixture uses PBMAC1.
ec-fips.pfx: ec-cert.pem ec-key.pem
openssl pkcs12 -export \
-keypbe AES-256-CBC \
-certpbe AES-256-CBC \
-iter 2048 \
-pbmac1_pbkdf2 \
-in ec-cert.pem \
-inkey ec-key.pem \
-out ec-fips.pfx \
-password pass:password

dh512.pem:
openssl dhparam -out dh512.pem 512

Expand Down
Binary file addedtest/fixtures/keys/agent1-fips.pfx
Binary file not shown.
Binary file addedtest/fixtures/keys/ec-fips.pfx
Binary file not shown.
4 changes: 3 additions & 1 deletion test/parallel/test-crypto-argon2-job.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -4,10 +4,12 @@ const common = require('../common');
if (!common.hasCrypto)
common.skip('missing crypto');

const { hasOpenSSL } = require('../common/crypto');
const { hasFIPS, hasOpenSSL } = require('../common/crypto');

if (!hasOpenSSL(3, 2))
common.skip('requires OpenSSL >= 3.2');
if (hasFIPS(3))
common.skip('Argon2 is not available in FIPS mode');

// Exercises the native Argon2 job directly via internalBinding, bypassing
// the JS validators, to ensure that if invalid parameters ever reach the
Expand Down
13 changes: 12 additions & 1 deletion test/parallel/test-crypto-argon2.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -3,7 +3,7 @@ const common = require('../common');
if (!common.hasCrypto)
common.skip('missing crypto');

const { hasOpenSSL } = require('../common/crypto');
const { hasFIPS, hasOpenSSL } = require('../common/crypto');

if (!hasOpenSSL(3, 2))
common.skip('requires OpenSSL >= 3.2');
Expand All@@ -28,6 +28,17 @@ const secret = Buffer.alloc(8, 0x03);
const associatedData = Buffer.alloc(12, 0x04);
const defaults = { message, nonce, parallelism: 1, tagLength: 64, memory: 8, passes: 3 };

if (hasFIPS(3)) {
assert.throws(() => crypto.argon2Sync('argon2id', defaults), {
code: 'ERR_OSSL_EVP_UNSUPPORTED',
});
crypto.argon2('argon2id', defaults, common.mustCall((err, result) => {
assert.strictEqual(err?.code, 'ERR_OSSL_EVP_UNSUPPORTED');
assert.strictEqual(result, undefined);
}));
return;
}

const good = [
// Test vectors from RFC 9106 https://www.rfc-editor.org/rfc/rfc9106.html#name-test-vectors
// and OpenSSL 3.2 https://github.com/openssl/openssl/blob/6dfa998f7ea150f9c6d4e4727cf6d5c82a68a8da/test/recipes/30-test_evp_data/evpkdf_argon2.txt
Expand Down
61 changes: 43 additions & 18 deletions test/parallel/test-crypto-async-sign-verify.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -3,12 +3,14 @@ const common = require('../common');
if (!common.hasCrypto)
common.skip('missing crypto');

const { hasOpenSSL3 } = require('../common/crypto');
const { hasOpenSSL, hasFIPS } = require('../common/crypto');
const assert = require('assert');
const util = require('util');
const crypto = require('crypto');
const fixtures = require('../common/fixtures');

const fips3 = hasFIPS(3);

function test(
publicFixture,
privateFixture,
Expand DownExpand Up@@ -65,6 +67,15 @@ function test(
}
}

function testSignFailure(privateFixture, algorithm, options, code) {
const key = { key: fixtures.readKey(privateFixture), ...options };
const data = Buffer.from('Hello world');
assert.throws(() => crypto.sign(algorithm, data, key), { code });
crypto.sign(algorithm, data, key, common.mustCall((err) => {
assert.strictEqual(err?.code, code);
}));
}

// RSA w/ default padding
test('rsa_public.pem', 'rsa_private.pem', 'sha256', true);
test('rsa_public.pem', 'rsa_private.pem', 'sha256', true,
Expand DownExpand Up@@ -94,14 +105,19 @@ if (!process.features.openssl_is_boringssl) {
test('ed448_public.pem', 'ed448_private.pem', undefined, true);

// ECDSA w/ der signature encoding
test('ec_secp256k1_public.pem', 'ec_secp256k1_private.pem', 'sha384',
false);
test('ec_secp256k1_public.pem', 'ec_secp256k1_private.pem', 'sha384',
false, { dsaEncoding: 'der' });

// ECDSA w/ ieee-p1363 signature encoding
test('ec_secp256k1_public.pem', 'ec_secp256k1_private.pem', 'sha384', false,
{ dsaEncoding: 'ieee-p1363' });
if (fips3) {
testSignFailure('ec_secp256k1_private.pem', 'sha384', {},
'ERR_OSSL_EVP_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE');
} else {
test('ec_secp256k1_public.pem', 'ec_secp256k1_private.pem', 'sha384',
false);
test('ec_secp256k1_public.pem', 'ec_secp256k1_private.pem', 'sha384',
false, { dsaEncoding: 'der' });

// ECDSA w/ ieee-p1363 signature encoding
test('ec_secp256k1_public.pem', 'ec_secp256k1_private.pem', 'sha384', false,
{ dsaEncoding: 'ieee-p1363' });
}

// DSA w/ der signature encoding
test('dsa_public.pem', 'dsa_private.pem', 'sha256',
Expand DownExpand Up@@ -157,7 +173,7 @@ MCowBQYDK2VuAyEA6pwGRbadNQAI/tYN8+/p/0/hbsdHfOEGr1ADiLVk/Gc=

let expected = /no default digest/;
let expectedCode = 'ERR_OSSL_EVP_NO_DEFAULT_DIGEST';
if (hasOpenSSL3 || process.features.openssl_is_boringssl) {
if (hasOpenSSL(3) || process.features.openssl_is_boringssl) {
expected = /operation[\s_]not[\s_]supported[\s_]for[\s_]this[\s_]keytype/i;
expectedCode = 'ERR_OSSL_EVP_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE';
}
Expand All@@ -170,12 +186,21 @@ MCowBQYDK2VuAyEA6pwGRbadNQAI/tYN8+/p/0/hbsdHfOEGr1ADiLVk/Gc=
}

{
const { privateKey } = crypto.generateKeyPairSync('rsa', {
modulusLength: 512
});
crypto.sign('sha512', 'message', privateKey, common.mustCall((err) => {
assert.ok(err);
assert.match(err.message, /digest[\s_]too[\s_]big[\s_]for[\s_]rsa[\s_]key/i);
assert.match(err.code, /^ERR_OSSL_.*DIGEST_TOO_BIG_FOR_RSA_KEY$/);
}));
if (fips3) {
crypto.generateKeyPair('rsa', { modulusLength: 512 },
common.mustCall((err) => {
assert.strictEqual(
err?.code, 'ERR_OSSL_RSA_INVALID_MODULUS');
}));
} else {
const { privateKey } = crypto.generateKeyPairSync('rsa', {
modulusLength: 512
});
crypto.sign('sha512', 'message', privateKey, common.mustCall((err) => {
assert.ok(err);
assert.match(
err.message, /digest[\s_]too[\s_]big[\s_]for[\s_]rsa[\s_]key/i);
assert.match(err.code, /^ERR_OSSL_.*DIGEST_TOO_BIG_FOR_RSA_KEY$/);
}));
}
}
11 changes: 11 additions & 0 deletions test/parallel/test-crypto-authenticated-stream.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -6,6 +6,7 @@ if (!common.hasCrypto)

const assert = require('assert');
const crypto = require('crypto');
const { hasFIPS } = require('../common/crypto');
const fs = require('fs');
const stream = require('stream');
const tmpdir = require('../common/tmpdir');
Expand DownExpand Up@@ -120,6 +121,16 @@ function test(config) {
return;
}

if (hasFIPS(3)) {
assert.throws(() => crypto.createDecipheriv(
config.cipher, config.key, config.iv, {
authTagLength: config.authTagLength,
}), {
code: 'ERR_CRYPTO_UNSUPPORTED_OPERATION',
});
return;
}

direct(config);
mstream(config);
fstream(config);
Expand Down
51 changes: 37 additions & 14 deletions test/parallel/test-crypto-authenticated.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -29,9 +29,10 @@ const assert = require('assert');
const crypto = require('crypto');
const { inspect } = require('util');
const fixtures = require('../common/fixtures');
const { hasOpenSSL3 } = require('../common/crypto');
const { hasOpenSSL, hasFIPS } = require('../common/crypto');

const isFipsEnabled = crypto.getFips();
const isFipsEnabled = crypto.getFips() === 1;
const fips3 = hasFIPS(3);

//
// Test authenticated encryption modes.
Expand DownExpand Up@@ -559,6 +560,14 @@ for (const test of TEST_CASES) {
const ciphertext = Buffer.concat([cipher.update(plain), cipher.final()]);
const tag = cipher.getAuthTag();

if (fips3 && mode === 'ccm') {
assert.throws(() => crypto.createDecipheriv(
`aes-128-${mode}`, key, iv, opts), {
code: 'ERR_CRYPTO_UNSUPPORTED_OPERATION',
});
continue;
}

const decipher = crypto.createDecipheriv(`aes-128-${mode}`, key, iv, opts);
decipher.setAuthTag(tag);
assert.throws(() => {
Expand DownExpand Up@@ -636,15 +645,22 @@ for (const test of TEST_CASES) {
const cipher = crypto.createCipheriv('aes-128-ccm', key, iv, opts);
assert.throws(() => {
cipher.final();
}, hasOpenSSL3 ? {
}, hasOpenSSL(3) ? {
code: 'ERR_OSSL_TAG_NOT_SET'
} : {
message: /Unsupported state/
});
}
}

if (!process.features.openssl_is_boringssl) {
if (fips3) {
assert.throws(() => crypto.createCipheriv(
'chacha20-poly1305', Buffer.alloc(32), Buffer.alloc(12), {
authTagLength: 16,
}), {
code: 'ERR_OSSL_EVP_UNSUPPORTED',
});
} else if (!process.features.openssl_is_boringssl) {
const key = Buffer.alloc(32);
const iv = Buffer.alloc(12);

Expand All@@ -662,7 +678,7 @@ if (!process.features.openssl_is_boringssl) {

// ChaCha20-Poly1305 should respect the authTagLength option and should not
// require the authentication tag before calls to update() during decryption.
if (!process.features.openssl_is_boringssl) {
if (!fips3 && !process.features.openssl_is_boringssl) {
const key = Buffer.alloc(32);
const iv = Buffer.alloc(12);

Expand DownExpand Up@@ -713,7 +729,7 @@ if (!process.features.openssl_is_boringssl) {
// shorter tags as long as their length was valid according to NIST SP 800-38D.
// For ChaCha20-Poly1305, we intentionally deviate from that because there are
// no recommended or approved authentication tag lengths below 16 bytes.
if (!process.features.openssl_is_boringssl) {
if (!fips3 && !process.features.openssl_is_boringssl) {
const rfcTestCases = TEST_CASES.filter(({ algo, tampered }) => {
return algo === 'chacha20-poly1305' && tampered === false;
});
Expand DownExpand Up@@ -752,7 +768,7 @@ if (!process.features.openssl_is_boringssl) {
}

// https://github.com/nodejs/node/issues/45874
if (!process.features.openssl_is_boringssl) {
if (!fips3 && !process.features.openssl_is_boringssl) {
const rfcTestCases = TEST_CASES.filter(({ algo, tampered }) => {
return algo === 'chacha20-poly1305' && tampered === false;
});
Expand DownExpand Up@@ -798,13 +814,20 @@ if (ciphers.includes('aes-128-ccm')) {
const tag = cipher.getAuthTag();
assert.strictEqual(tag.length, 16);

const decipher = crypto.createDecipheriv('aes-128-ccm', key, nonce, {
authTagLength: 16,
});
decipher.setAuthTag(tag);
decipher.setAAD(Buffer.alloc(0), { plaintextLength: 0 });
decipher.update(new DataView(new ArrayBuffer(0)));
decipher.final();
if (fips3) {
assert.throws(() => crypto.createDecipheriv(
'aes-128-ccm', key, nonce, { authTagLength: 16 }), {
code: 'ERR_CRYPTO_UNSUPPORTED_OPERATION',
});
} else {
const decipher = crypto.createDecipheriv('aes-128-ccm', key, nonce, {
authTagLength: 16,
});
decipher.setAuthTag(tag);
decipher.setAAD(Buffer.alloc(0), { plaintextLength: 0 });
decipher.update(new DataView(new ArrayBuffer(0)));
decipher.final();
}
} else {
common.printSkipMessage('Skipping unsupported aes-128-ccm test');
}
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/internal/crypto/webcrypto.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -1604,6 +1604,7 @@ class SubtleCrypto {
}

// Implements https://wicg.github.io/webcrypto-modern-algos/#SubtleCrypto-method-supports
// TODO(panva): Make supports() account for the active FIPS state.
static supports(operation, algorithm, lengthOrAdditionalAlgorithm = null) {
emitExperimentalWarning('The supports Web Crypto API method');
if (this !== SubtleCrypto) throw new ERR_INVALID_THIS('SubtleCrypto constructor');
Expand Down
14 changes: 12 additions & 2 deletions test/common/crypto.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -50,9 +50,14 @@ function assertApproximateSize(key, expectedSize) {
function testEncryptDecrypt(publicKey, privateKey) {
const message = 'Hello Node.js world!';
const plaintext = Buffer.from(message, 'utf8');
const withOaepHash = (key) => {
if (!hasFIPS(3)) return key;
if (key?.key !== undefined) return { ...key, oaepHash: 'sha256' };
return { key, oaepHash: 'sha256' };
};
for (const key of [publicKey, privateKey]) {
const ciphertext = publicEncrypt(key, plaintext);
const received = privateDecrypt(privateKey, ciphertext);
const ciphertext = publicEncrypt(withOaepHash(key), plaintext);
const received = privateDecrypt(withOaepHash(privateKey), ciphertext);
assert.strictEqual(received.toString('utf8'), message);
}
}
Expand DownExpand Up@@ -118,6 +123,10 @@ const hasOpenSSL = (major = 0, minor = 0, patch = 0) => {
return OPENSSL_VERSION_NUMBER >= opensslVersionNumber(major, minor, patch);
};

const hasFIPS = (major = 0, minor = 0, patch = 0) => {
return crypto.getFips() === 1 && hasOpenSSL(major, minor, patch);
};

let opensslCli = null;

module.exports = {
Expand All@@ -134,6 +143,7 @@ module.exports = {
sec1Exp,
sec1EncExp,
hasOpenSSL,
hasFIPS,
get hasOpenSSL3() {
return hasOpenSSL(3);
},
Expand Down
28 changes: 28 additions & 0 deletions test/fixtures/keys/Makefile
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,6 +8,7 @@ all: \
ca5-cert.pem \
ca6-cert.pem \
agent1-cert.pem \
agent1-fips.pfx \
agent1.pfx \
agent2-cert.pem \
agent3-cert.pem \
Expand DownExpand Up@@ -39,6 +40,7 @@ all: \
dsa_private_encrypted_1025.pem \
dsa_public_1025.pem \
ec-cert.pem \
ec-fips.pfx \
ec.pfx \
fake-cnnic-root-cert.pem \
intermediate-ca-cert.pem \
Expand DownExpand Up@@ -444,6 +446,20 @@ agent1.pfx: agent1-cert.pem agent1-key.pem ca1-cert.pem
-out agent1.pfx \
-password pass:sample

# PKCS12KDF is unavailable under FIPS properties. Use PBMAC1 with PBKDF2
# instead, alongside AES-256/PBKDF2 key protection.
agent1-fips.pfx: agent1-cert.pem agent1-key.pem ca1-cert.pem
openssl pkcs12 -export \
-keypbe AES-256-CBC \
-certpbe AES-256-CBC \
-iter 2048 \
-pbmac1_pbkdf2 \
-in agent1-cert.pem \
-inkey agent1-key.pem \
-certfile ca1-cert.pem \
-out agent1-fips.pfx \
-password pass:password

agent1-verify: agent1-cert.pem ca1-cert.pem
openssl verify -CAfile ca1-cert.pem agent1-cert.pem

Expand DownExpand Up@@ -787,6 +803,18 @@ ec.pfx: ec-cert.pem ec-key.pem
-out ec.pfx \
-password pass:

# See agent1-fips.pfx for why the FIPS fixture uses PBMAC1.
ec-fips.pfx: ec-cert.pem ec-key.pem
openssl pkcs12 -export \
-keypbe AES-256-CBC \
-certpbe AES-256-CBC \
-iter 2048 \
-pbmac1_pbkdf2 \
-in ec-cert.pem \
-inkey ec-key.pem \
-out ec-fips.pfx \
-password pass:password

dh512.pem:
openssl dhparam -out dh512.pem 512

Expand Down
Binary file addedtest/fixtures/keys/agent1-fips.pfx
Binary file not shown.
Binary file addedtest/fixtures/keys/ec-fips.pfx
Binary file not shown.
4 changes: 3 additions & 1 deletion test/parallel/test-crypto-argon2-job.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -4,10 +4,12 @@ const common = require('../common');
if (!common.hasCrypto)
common.skip('missing crypto');

const { hasOpenSSL } = require('../common/crypto');
const { hasFIPS, hasOpenSSL } = require('../common/crypto');

if (!hasOpenSSL(3, 2))
common.skip('requires OpenSSL >= 3.2');
if (hasFIPS(3))
common.skip('Argon2 is not available in FIPS mode');

// Exercises the native Argon2 job directly via internalBinding, bypassing
// the JS validators, to ensure that if invalid parameters ever reach the
Expand Down
13 changes: 12 additions & 1 deletion test/parallel/test-crypto-argon2.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -3,7 +3,7 @@ const common = require('../common');
if (!common.hasCrypto)
common.skip('missing crypto');

const { hasOpenSSL } = require('../common/crypto');
const { hasFIPS, hasOpenSSL } = require('../common/crypto');

if (!hasOpenSSL(3, 2))
common.skip('requires OpenSSL >= 3.2');
Expand All@@ -28,6 +28,17 @@ const secret = Buffer.alloc(8, 0x03);
const associatedData = Buffer.alloc(12, 0x04);
const defaults = { message, nonce, parallelism: 1, tagLength: 64, memory: 8, passes: 3 };

if (hasFIPS(3)) {
assert.throws(() => crypto.argon2Sync('argon2id', defaults), {
code: 'ERR_OSSL_EVP_UNSUPPORTED',
});
crypto.argon2('argon2id', defaults, common.mustCall((err, result) => {
assert.strictEqual(err?.code, 'ERR_OSSL_EVP_UNSUPPORTED');
assert.strictEqual(result, undefined);
}));
return;
}

const good = [
// Test vectors from RFC 9106 https://www.rfc-editor.org/rfc/rfc9106.html#name-test-vectors
// and OpenSSL 3.2 https://github.com/openssl/openssl/blob/6dfa998f7ea150f9c6d4e4727cf6d5c82a68a8da/test/recipes/30-test_evp_data/evpkdf_argon2.txt
Expand Down
61 changes: 43 additions & 18 deletions test/parallel/test-crypto-async-sign-verify.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -3,12 +3,14 @@ const common = require('../common');
if (!common.hasCrypto)
common.skip('missing crypto');

const { hasOpenSSL3 } = require('../common/crypto');
const { hasOpenSSL, hasFIPS } = require('../common/crypto');
const assert = require('assert');
const util = require('util');
const crypto = require('crypto');
const fixtures = require('../common/fixtures');

const fips3 = hasFIPS(3);

function test(
publicFixture,
privateFixture,
Expand DownExpand Up@@ -65,6 +67,15 @@ function test(
}
}

function testSignFailure(privateFixture, algorithm, options, code) {
const key = { key: fixtures.readKey(privateFixture), ...options };
const data = Buffer.from('Hello world');
assert.throws(() => crypto.sign(algorithm, data, key), { code });
crypto.sign(algorithm, data, key, common.mustCall((err) => {
assert.strictEqual(err?.code, code);
}));
}

// RSA w/ default padding
test('rsa_public.pem', 'rsa_private.pem', 'sha256', true);
test('rsa_public.pem', 'rsa_private.pem', 'sha256', true,
Expand DownExpand Up@@ -94,14 +105,19 @@ if (!process.features.openssl_is_boringssl) {
test('ed448_public.pem', 'ed448_private.pem', undefined, true);

// ECDSA w/ der signature encoding
test('ec_secp256k1_public.pem', 'ec_secp256k1_private.pem', 'sha384',
false);
test('ec_secp256k1_public.pem', 'ec_secp256k1_private.pem', 'sha384',
false, { dsaEncoding: 'der' });

// ECDSA w/ ieee-p1363 signature encoding
test('ec_secp256k1_public.pem', 'ec_secp256k1_private.pem', 'sha384', false,
{ dsaEncoding: 'ieee-p1363' });
if (fips3) {
testSignFailure('ec_secp256k1_private.pem', 'sha384', {},
'ERR_OSSL_EVP_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE');
} else {
test('ec_secp256k1_public.pem', 'ec_secp256k1_private.pem', 'sha384',
false);
test('ec_secp256k1_public.pem', 'ec_secp256k1_private.pem', 'sha384',
false, { dsaEncoding: 'der' });

// ECDSA w/ ieee-p1363 signature encoding
test('ec_secp256k1_public.pem', 'ec_secp256k1_private.pem', 'sha384', false,
{ dsaEncoding: 'ieee-p1363' });
}

// DSA w/ der signature encoding
test('dsa_public.pem', 'dsa_private.pem', 'sha256',
Expand DownExpand Up@@ -157,7 +173,7 @@ MCowBQYDK2VuAyEA6pwGRbadNQAI/tYN8+/p/0/hbsdHfOEGr1ADiLVk/Gc=

let expected = /no default digest/;
let expectedCode = 'ERR_OSSL_EVP_NO_DEFAULT_DIGEST';
if (hasOpenSSL3 || process.features.openssl_is_boringssl) {
if (hasOpenSSL(3) || process.features.openssl_is_boringssl) {
expected = /operation[\s_]not[\s_]supported[\s_]for[\s_]this[\s_]keytype/i;
expectedCode = 'ERR_OSSL_EVP_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE';
}
Expand All@@ -170,12 +186,21 @@ MCowBQYDK2VuAyEA6pwGRbadNQAI/tYN8+/p/0/hbsdHfOEGr1ADiLVk/Gc=
}

{
const { privateKey } = crypto.generateKeyPairSync('rsa', {
modulusLength: 512
});
crypto.sign('sha512', 'message', privateKey, common.mustCall((err) => {
assert.ok(err);
assert.match(err.message, /digest[\s_]too[\s_]big[\s_]for[\s_]rsa[\s_]key/i);
assert.match(err.code, /^ERR_OSSL_.*DIGEST_TOO_BIG_FOR_RSA_KEY$/);
}));
if (fips3) {
crypto.generateKeyPair('rsa', { modulusLength: 512 },
common.mustCall((err) => {
assert.strictEqual(
err?.code, 'ERR_OSSL_RSA_INVALID_MODULUS');
}));
} else {
const { privateKey } = crypto.generateKeyPairSync('rsa', {
modulusLength: 512
});
crypto.sign('sha512', 'message', privateKey, common.mustCall((err) => {
assert.ok(err);
assert.match(
err.message, /digest[\s_]too[\s_]big[\s_]for[\s_]rsa[\s_]key/i);
assert.match(err.code, /^ERR_OSSL_.*DIGEST_TOO_BIG_FOR_RSA_KEY$/);
}));
}
}
11 changes: 11 additions & 0 deletions test/parallel/test-crypto-authenticated-stream.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -6,6 +6,7 @@ if (!common.hasCrypto)

const assert = require('assert');
const crypto = require('crypto');
const { hasFIPS } = require('../common/crypto');
const fs = require('fs');
const stream = require('stream');
const tmpdir = require('../common/tmpdir');
Expand DownExpand Up@@ -120,6 +121,16 @@ function test(config) {
return;
}

if (hasFIPS(3)) {
assert.throws(() => crypto.createDecipheriv(
config.cipher, config.key, config.iv, {
authTagLength: config.authTagLength,
}), {
code: 'ERR_CRYPTO_UNSUPPORTED_OPERATION',
});
return;
}

direct(config);
mstream(config);
fstream(config);
Expand Down
51 changes: 37 additions & 14 deletions test/parallel/test-crypto-authenticated.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -29,9 +29,10 @@ const assert = require('assert');
const crypto = require('crypto');
const { inspect } = require('util');
const fixtures = require('../common/fixtures');
const { hasOpenSSL3 } = require('../common/crypto');
const { hasOpenSSL, hasFIPS } = require('../common/crypto');

const isFipsEnabled = crypto.getFips();
const isFipsEnabled = crypto.getFips() === 1;
const fips3 = hasFIPS(3);

//
// Test authenticated encryption modes.
Expand DownExpand Up@@ -559,6 +560,14 @@ for (const test of TEST_CASES) {
const ciphertext = Buffer.concat([cipher.update(plain), cipher.final()]);
const tag = cipher.getAuthTag();

if (fips3 && mode === 'ccm') {
assert.throws(() => crypto.createDecipheriv(
`aes-128-${mode}`, key, iv, opts), {
code: 'ERR_CRYPTO_UNSUPPORTED_OPERATION',
});
continue;
}

const decipher = crypto.createDecipheriv(`aes-128-${mode}`, key, iv, opts);
decipher.setAuthTag(tag);
assert.throws(() => {
Expand DownExpand Up@@ -636,15 +645,22 @@ for (const test of TEST_CASES) {
const cipher = crypto.createCipheriv('aes-128-ccm', key, iv, opts);
assert.throws(() => {
cipher.final();
}, hasOpenSSL3 ? {
}, hasOpenSSL(3) ? {
code: 'ERR_OSSL_TAG_NOT_SET'
} : {
message: /Unsupported state/
});
}
}

if (!process.features.openssl_is_boringssl) {
if (fips3) {
assert.throws(() => crypto.createCipheriv(
'chacha20-poly1305', Buffer.alloc(32), Buffer.alloc(12), {
authTagLength: 16,
}), {
code: 'ERR_OSSL_EVP_UNSUPPORTED',
});
} else if (!process.features.openssl_is_boringssl) {
const key = Buffer.alloc(32);
const iv = Buffer.alloc(12);

Expand All@@ -662,7 +678,7 @@ if (!process.features.openssl_is_boringssl) {

// ChaCha20-Poly1305 should respect the authTagLength option and should not
// require the authentication tag before calls to update() during decryption.
if (!process.features.openssl_is_boringssl) {
if (!fips3 && !process.features.openssl_is_boringssl) {
const key = Buffer.alloc(32);
const iv = Buffer.alloc(12);

Expand DownExpand Up@@ -713,7 +729,7 @@ if (!process.features.openssl_is_boringssl) {
// shorter tags as long as their length was valid according to NIST SP 800-38D.
// For ChaCha20-Poly1305, we intentionally deviate from that because there are
// no recommended or approved authentication tag lengths below 16 bytes.
if (!process.features.openssl_is_boringssl) {
if (!fips3 && !process.features.openssl_is_boringssl) {
const rfcTestCases = TEST_CASES.filter(({ algo, tampered }) => {
return algo === 'chacha20-poly1305' && tampered === false;
});
Expand DownExpand Up@@ -752,7 +768,7 @@ if (!process.features.openssl_is_boringssl) {
}

// https://github.com/nodejs/node/issues/45874
if (!process.features.openssl_is_boringssl) {
if (!fips3 && !process.features.openssl_is_boringssl) {
const rfcTestCases = TEST_CASES.filter(({ algo, tampered }) => {
return algo === 'chacha20-poly1305' && tampered === false;
});
Expand DownExpand Up@@ -798,13 +814,20 @@ if (ciphers.includes('aes-128-ccm')) {
const tag = cipher.getAuthTag();
assert.strictEqual(tag.length, 16);

const decipher = crypto.createDecipheriv('aes-128-ccm', key, nonce, {
authTagLength: 16,
});
decipher.setAuthTag(tag);
decipher.setAAD(Buffer.alloc(0), { plaintextLength: 0 });
decipher.update(new DataView(new ArrayBuffer(0)));
decipher.final();
if (fips3) {
assert.throws(() => crypto.createDecipheriv(
'aes-128-ccm', key, nonce, { authTagLength: 16 }), {
code: 'ERR_CRYPTO_UNSUPPORTED_OPERATION',
});
} else {
const decipher = crypto.createDecipheriv('aes-128-ccm', key, nonce, {
authTagLength: 16,
});
decipher.setAuthTag(tag);
decipher.setAAD(Buffer.alloc(0), { plaintextLength: 0 });
decipher.update(new DataView(new ArrayBuffer(0)));
decipher.final();
}
} else {
common.printSkipMessage('Skipping unsupported aes-128-ccm test');
}
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/internal/crypto/webcrypto.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -1604,6 +1604,7 @@ class SubtleCrypto {
}

// Implements https://wicg.github.io/webcrypto-modern-algos/#SubtleCrypto-method-supports
// TODO(panva): Make supports() account for the active FIPS state.
static supports(operation, algorithm, lengthOrAdditionalAlgorithm = null) {
emitExperimentalWarning('The supports Web Crypto API method');
if (this !== SubtleCrypto) throw new ERR_INVALID_THIS('SubtleCrypto constructor');
Expand Down
14 changes: 12 additions & 2 deletions test/common/crypto.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -50,9 +50,14 @@ function assertApproximateSize(key, expectedSize) {
function testEncryptDecrypt(publicKey, privateKey) {
const message = 'Hello Node.js world!';
const plaintext = Buffer.from(message, 'utf8');
const withOaepHash = (key) => {
if (!hasFIPS(3)) return key;
if (key?.key !== undefined) return { ...key, oaepHash: 'sha256' };
return { key, oaepHash: 'sha256' };
};
for (const key of [publicKey, privateKey]) {
const ciphertext = publicEncrypt(key, plaintext);
const received = privateDecrypt(privateKey, ciphertext);
const ciphertext = publicEncrypt(withOaepHash(key), plaintext);
const received = privateDecrypt(withOaepHash(privateKey), ciphertext);
assert.strictEqual(received.toString('utf8'), message);
}
}
Expand DownExpand Up@@ -118,6 +123,10 @@ const hasOpenSSL = (major = 0, minor = 0, patch = 0) => {
return OPENSSL_VERSION_NUMBER >= opensslVersionNumber(major, minor, patch);
};

const hasFIPS = (major = 0, minor = 0, patch = 0) => {
return crypto.getFips() === 1 && hasOpenSSL(major, minor, patch);
};

let opensslCli = null;

module.exports = {
Expand All@@ -134,6 +143,7 @@ module.exports = {
sec1Exp,
sec1EncExp,
hasOpenSSL,
hasFIPS,
get hasOpenSSL3() {
return hasOpenSSL(3);
},
Expand Down
28 changes: 28 additions & 0 deletions test/fixtures/keys/Makefile
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,6 +8,7 @@ all: \
ca5-cert.pem \
ca6-cert.pem \
agent1-cert.pem \
agent1-fips.pfx \
agent1.pfx \
agent2-cert.pem \
agent3-cert.pem \
Expand DownExpand Up@@ -39,6 +40,7 @@ all: \
dsa_private_encrypted_1025.pem \
dsa_public_1025.pem \
ec-cert.pem \
ec-fips.pfx \
ec.pfx \
fake-cnnic-root-cert.pem \
intermediate-ca-cert.pem \
Expand DownExpand Up@@ -444,6 +446,20 @@ agent1.pfx: agent1-cert.pem agent1-key.pem ca1-cert.pem
-out agent1.pfx \
-password pass:sample

# PKCS12KDF is unavailable under FIPS properties. Use PBMAC1 with PBKDF2
# instead, alongside AES-256/PBKDF2 key protection.
agent1-fips.pfx: agent1-cert.pem agent1-key.pem ca1-cert.pem
openssl pkcs12 -export \
-keypbe AES-256-CBC \
-certpbe AES-256-CBC \
-iter 2048 \
-pbmac1_pbkdf2 \
-in agent1-cert.pem \
-inkey agent1-key.pem \
-certfile ca1-cert.pem \
-out agent1-fips.pfx \
-password pass:password

agent1-verify: agent1-cert.pem ca1-cert.pem
openssl verify -CAfile ca1-cert.pem agent1-cert.pem

Expand DownExpand Up@@ -787,6 +803,18 @@ ec.pfx: ec-cert.pem ec-key.pem
-out ec.pfx \
-password pass:

# See agent1-fips.pfx for why the FIPS fixture uses PBMAC1.
ec-fips.pfx: ec-cert.pem ec-key.pem
openssl pkcs12 -export \
-keypbe AES-256-CBC \
-certpbe AES-256-CBC \
-iter 2048 \
-pbmac1_pbkdf2 \
-in ec-cert.pem \
-inkey ec-key.pem \
-out ec-fips.pfx \
-password pass:password

dh512.pem:
openssl dhparam -out dh512.pem 512

Expand Down
Binary file addedtest/fixtures/keys/agent1-fips.pfx
Binary file not shown.
Binary file addedtest/fixtures/keys/ec-fips.pfx
Binary file not shown.
4 changes: 3 additions & 1 deletion test/parallel/test-crypto-argon2-job.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -4,10 +4,12 @@ const common = require('../common');
if (!common.hasCrypto)
common.skip('missing crypto');

const { hasOpenSSL } = require('../common/crypto');
const { hasFIPS, hasOpenSSL } = require('../common/crypto');

if (!hasOpenSSL(3, 2))
common.skip('requires OpenSSL >= 3.2');
if (hasFIPS(3))
common.skip('Argon2 is not available in FIPS mode');

// Exercises the native Argon2 job directly via internalBinding, bypassing
// the JS validators, to ensure that if invalid parameters ever reach the
Expand Down
13 changes: 12 additions & 1 deletion test/parallel/test-crypto-argon2.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -3,7 +3,7 @@ const common = require('../common');
if (!common.hasCrypto)
common.skip('missing crypto');

const { hasOpenSSL } = require('../common/crypto');
const { hasFIPS, hasOpenSSL } = require('../common/crypto');

if (!hasOpenSSL(3, 2))
common.skip('requires OpenSSL >= 3.2');
Expand All@@ -28,6 +28,17 @@ const secret = Buffer.alloc(8, 0x03);
const associatedData = Buffer.alloc(12, 0x04);
const defaults = { message, nonce, parallelism: 1, tagLength: 64, memory: 8, passes: 3 };

if (hasFIPS(3)) {
assert.throws(() => crypto.argon2Sync('argon2id', defaults), {
code: 'ERR_OSSL_EVP_UNSUPPORTED',
});
crypto.argon2('argon2id', defaults, common.mustCall((err, result) => {
assert.strictEqual(err?.code, 'ERR_OSSL_EVP_UNSUPPORTED');
assert.strictEqual(result, undefined);
}));
return;
}

const good = [
// Test vectors from RFC 9106 https://www.rfc-editor.org/rfc/rfc9106.html#name-test-vectors
// and OpenSSL 3.2 https://github.com/openssl/openssl/blob/6dfa998f7ea150f9c6d4e4727cf6d5c82a68a8da/test/recipes/30-test_evp_data/evpkdf_argon2.txt
Expand Down
61 changes: 43 additions & 18 deletions test/parallel/test-crypto-async-sign-verify.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -3,12 +3,14 @@ const common = require('../common');
if (!common.hasCrypto)
common.skip('missing crypto');

const { hasOpenSSL3 } = require('../common/crypto');
const { hasOpenSSL, hasFIPS } = require('../common/crypto');
const assert = require('assert');
const util = require('util');
const crypto = require('crypto');
const fixtures = require('../common/fixtures');

const fips3 = hasFIPS(3);

function test(
publicFixture,
privateFixture,
Expand DownExpand Up@@ -65,6 +67,15 @@ function test(
}
}

function testSignFailure(privateFixture, algorithm, options, code) {
const key = { key: fixtures.readKey(privateFixture), ...options };
const data = Buffer.from('Hello world');
assert.throws(() => crypto.sign(algorithm, data, key), { code });
crypto.sign(algorithm, data, key, common.mustCall((err) => {
assert.strictEqual(err?.code, code);
}));
}

// RSA w/ default padding
test('rsa_public.pem', 'rsa_private.pem', 'sha256', true);
test('rsa_public.pem', 'rsa_private.pem', 'sha256', true,
Expand DownExpand Up@@ -94,14 +105,19 @@ if (!process.features.openssl_is_boringssl) {
test('ed448_public.pem', 'ed448_private.pem', undefined, true);

// ECDSA w/ der signature encoding
test('ec_secp256k1_public.pem', 'ec_secp256k1_private.pem', 'sha384',
false);
test('ec_secp256k1_public.pem', 'ec_secp256k1_private.pem', 'sha384',
false, { dsaEncoding: 'der' });

// ECDSA w/ ieee-p1363 signature encoding
test('ec_secp256k1_public.pem', 'ec_secp256k1_private.pem', 'sha384', false,
{ dsaEncoding: 'ieee-p1363' });
if (fips3) {
testSignFailure('ec_secp256k1_private.pem', 'sha384', {},
'ERR_OSSL_EVP_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE');
} else {
test('ec_secp256k1_public.pem', 'ec_secp256k1_private.pem', 'sha384',
false);
test('ec_secp256k1_public.pem', 'ec_secp256k1_private.pem', 'sha384',
false, { dsaEncoding: 'der' });

// ECDSA w/ ieee-p1363 signature encoding
test('ec_secp256k1_public.pem', 'ec_secp256k1_private.pem', 'sha384', false,
{ dsaEncoding: 'ieee-p1363' });
}

// DSA w/ der signature encoding
test('dsa_public.pem', 'dsa_private.pem', 'sha256',
Expand DownExpand Up@@ -157,7 +173,7 @@ MCowBQYDK2VuAyEA6pwGRbadNQAI/tYN8+/p/0/hbsdHfOEGr1ADiLVk/Gc=

let expected = /no default digest/;
let expectedCode = 'ERR_OSSL_EVP_NO_DEFAULT_DIGEST';
if (hasOpenSSL3 || process.features.openssl_is_boringssl) {
if (hasOpenSSL(3) || process.features.openssl_is_boringssl) {
expected = /operation[\s_]not[\s_]supported[\s_]for[\s_]this[\s_]keytype/i;
expectedCode = 'ERR_OSSL_EVP_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE';
}
Expand All@@ -170,12 +186,21 @@ MCowBQYDK2VuAyEA6pwGRbadNQAI/tYN8+/p/0/hbsdHfOEGr1ADiLVk/Gc=
}

{
const { privateKey } = crypto.generateKeyPairSync('rsa', {
modulusLength: 512
});
crypto.sign('sha512', 'message', privateKey, common.mustCall((err) => {
assert.ok(err);
assert.match(err.message, /digest[\s_]too[\s_]big[\s_]for[\s_]rsa[\s_]key/i);
assert.match(err.code, /^ERR_OSSL_.*DIGEST_TOO_BIG_FOR_RSA_KEY$/);
}));
if (fips3) {
crypto.generateKeyPair('rsa', { modulusLength: 512 },
common.mustCall((err) => {
assert.strictEqual(
err?.code, 'ERR_OSSL_RSA_INVALID_MODULUS');
}));
} else {
const { privateKey } = crypto.generateKeyPairSync('rsa', {
modulusLength: 512
});
crypto.sign('sha512', 'message', privateKey, common.mustCall((err) => {
assert.ok(err);
assert.match(
err.message, /digest[\s_]too[\s_]big[\s_]for[\s_]rsa[\s_]key/i);
assert.match(err.code, /^ERR_OSSL_.*DIGEST_TOO_BIG_FOR_RSA_KEY$/);
}));
}
}
11 changes: 11 additions & 0 deletions test/parallel/test-crypto-authenticated-stream.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -6,6 +6,7 @@ if (!common.hasCrypto)

const assert = require('assert');
const crypto = require('crypto');
const { hasFIPS } = require('../common/crypto');
const fs = require('fs');
const stream = require('stream');
const tmpdir = require('../common/tmpdir');
Expand DownExpand Up@@ -120,6 +121,16 @@ function test(config) {
return;
}

if (hasFIPS(3)) {
assert.throws(() => crypto.createDecipheriv(
config.cipher, config.key, config.iv, {
authTagLength: config.authTagLength,
}), {
code: 'ERR_CRYPTO_UNSUPPORTED_OPERATION',
});
return;
}

direct(config);
mstream(config);
fstream(config);
Expand Down
51 changes: 37 additions & 14 deletions test/parallel/test-crypto-authenticated.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -29,9 +29,10 @@ const assert = require('assert');
const crypto = require('crypto');
const { inspect } = require('util');
const fixtures = require('../common/fixtures');
const { hasOpenSSL3 } = require('../common/crypto');
const { hasOpenSSL, hasFIPS } = require('../common/crypto');

const isFipsEnabled = crypto.getFips();
const isFipsEnabled = crypto.getFips() === 1;
const fips3 = hasFIPS(3);

//
// Test authenticated encryption modes.
Expand DownExpand Up@@ -559,6 +560,14 @@ for (const test of TEST_CASES) {
const ciphertext = Buffer.concat([cipher.update(plain), cipher.final()]);
const tag = cipher.getAuthTag();

if (fips3 && mode === 'ccm') {
assert.throws(() => crypto.createDecipheriv(
`aes-128-${mode}`, key, iv, opts), {
code: 'ERR_CRYPTO_UNSUPPORTED_OPERATION',
});
continue;
}

const decipher = crypto.createDecipheriv(`aes-128-${mode}`, key, iv, opts);
decipher.setAuthTag(tag);
assert.throws(() => {
Expand DownExpand Up@@ -636,15 +645,22 @@ for (const test of TEST_CASES) {
const cipher = crypto.createCipheriv('aes-128-ccm', key, iv, opts);
assert.throws(() => {
cipher.final();
}, hasOpenSSL3 ? {
}, hasOpenSSL(3) ? {
code: 'ERR_OSSL_TAG_NOT_SET'
} : {
message: /Unsupported state/
});
}
}

if (!process.features.openssl_is_boringssl) {
if (fips3) {
assert.throws(() => crypto.createCipheriv(
'chacha20-poly1305', Buffer.alloc(32), Buffer.alloc(12), {
authTagLength: 16,
}), {
code: 'ERR_OSSL_EVP_UNSUPPORTED',
});
} else if (!process.features.openssl_is_boringssl) {
const key = Buffer.alloc(32);
const iv = Buffer.alloc(12);

Expand All@@ -662,7 +678,7 @@ if (!process.features.openssl_is_boringssl) {

// ChaCha20-Poly1305 should respect the authTagLength option and should not
// require the authentication tag before calls to update() during decryption.
if (!process.features.openssl_is_boringssl) {
if (!fips3 && !process.features.openssl_is_boringssl) {
const key = Buffer.alloc(32);
const iv = Buffer.alloc(12);

Expand DownExpand Up@@ -713,7 +729,7 @@ if (!process.features.openssl_is_boringssl) {
// shorter tags as long as their length was valid according to NIST SP 800-38D.
// For ChaCha20-Poly1305, we intentionally deviate from that because there are
// no recommended or approved authentication tag lengths below 16 bytes.
if (!process.features.openssl_is_boringssl) {
if (!fips3 && !process.features.openssl_is_boringssl) {
const rfcTestCases = TEST_CASES.filter(({ algo, tampered }) => {
return algo === 'chacha20-poly1305' && tampered === false;
});
Expand DownExpand Up@@ -752,7 +768,7 @@ if (!process.features.openssl_is_boringssl) {
}

// https://github.com/nodejs/node/issues/45874
if (!process.features.openssl_is_boringssl) {
if (!fips3 && !process.features.openssl_is_boringssl) {
const rfcTestCases = TEST_CASES.filter(({ algo, tampered }) => {
return algo === 'chacha20-poly1305' && tampered === false;
});
Expand DownExpand Up@@ -798,13 +814,20 @@ if (ciphers.includes('aes-128-ccm')) {
const tag = cipher.getAuthTag();
assert.strictEqual(tag.length, 16);

const decipher = crypto.createDecipheriv('aes-128-ccm', key, nonce, {
authTagLength: 16,
});
decipher.setAuthTag(tag);
decipher.setAAD(Buffer.alloc(0), { plaintextLength: 0 });
decipher.update(new DataView(new ArrayBuffer(0)));
decipher.final();
if (fips3) {
assert.throws(() => crypto.createDecipheriv(
'aes-128-ccm', key, nonce, { authTagLength: 16 }), {
code: 'ERR_CRYPTO_UNSUPPORTED_OPERATION',
});
} else {
const decipher = crypto.createDecipheriv('aes-128-ccm', key, nonce, {
authTagLength: 16,
});
decipher.setAuthTag(tag);
decipher.setAAD(Buffer.alloc(0), { plaintextLength: 0 });
decipher.update(new DataView(new ArrayBuffer(0)));
decipher.final();
}
} else {
common.printSkipMessage('Skipping unsupported aes-128-ccm test');
}
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/internal/crypto/webcrypto.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -1604,6 +1604,7 @@ class SubtleCrypto {
}

// Implements https://wicg.github.io/webcrypto-modern-algos/#SubtleCrypto-method-supports
// TODO(panva): Make supports() account for the active FIPS state.
static supports(operation, algorithm, lengthOrAdditionalAlgorithm = null) {
emitExperimentalWarning('The supports Web Crypto API method');
if (this !== SubtleCrypto) throw new ERR_INVALID_THIS('SubtleCrypto constructor');
Expand Down
14 changes: 12 additions & 2 deletions test/common/crypto.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -50,9 +50,14 @@ function assertApproximateSize(key, expectedSize) {
function testEncryptDecrypt(publicKey, privateKey) {
const message = 'Hello Node.js world!';
const plaintext = Buffer.from(message, 'utf8');
const withOaepHash = (key) => {
if (!hasFIPS(3)) return key;
if (key?.key !== undefined) return { ...key, oaepHash: 'sha256' };
return { key, oaepHash: 'sha256' };
};
for (const key of [publicKey, privateKey]) {
const ciphertext = publicEncrypt(key, plaintext);
const received = privateDecrypt(privateKey, ciphertext);
const ciphertext = publicEncrypt(withOaepHash(key), plaintext);
const received = privateDecrypt(withOaepHash(privateKey), ciphertext);
assert.strictEqual(received.toString('utf8'), message);
}
}
Expand DownExpand Up@@ -118,6 +123,10 @@ const hasOpenSSL = (major = 0, minor = 0, patch = 0) => {
return OPENSSL_VERSION_NUMBER >= opensslVersionNumber(major, minor, patch);
};

const hasFIPS = (major = 0, minor = 0, patch = 0) => {
return crypto.getFips() === 1 && hasOpenSSL(major, minor, patch);
};

let opensslCli = null;

module.exports = {
Expand All@@ -134,6 +143,7 @@ module.exports = {
sec1Exp,
sec1EncExp,
hasOpenSSL,
hasFIPS,
get hasOpenSSL3() {
return hasOpenSSL(3);
},
Expand Down
28 changes: 28 additions & 0 deletions test/fixtures/keys/Makefile
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,6 +8,7 @@ all: \
ca5-cert.pem \
ca6-cert.pem \
agent1-cert.pem \
agent1-fips.pfx \
agent1.pfx \
agent2-cert.pem \
agent3-cert.pem \
Expand DownExpand Up@@ -39,6 +40,7 @@ all: \
dsa_private_encrypted_1025.pem \
dsa_public_1025.pem \
ec-cert.pem \
ec-fips.pfx \
ec.pfx \
fake-cnnic-root-cert.pem \
intermediate-ca-cert.pem \
Expand DownExpand Up@@ -444,6 +446,20 @@ agent1.pfx: agent1-cert.pem agent1-key.pem ca1-cert.pem
-out agent1.pfx \
-password pass:sample

# PKCS12KDF is unavailable under FIPS properties. Use PBMAC1 with PBKDF2
# instead, alongside AES-256/PBKDF2 key protection.
agent1-fips.pfx: agent1-cert.pem agent1-key.pem ca1-cert.pem
openssl pkcs12 -export \
-keypbe AES-256-CBC \
-certpbe AES-256-CBC \
-iter 2048 \
-pbmac1_pbkdf2 \
-in agent1-cert.pem \
-inkey agent1-key.pem \
-certfile ca1-cert.pem \
-out agent1-fips.pfx \
-password pass:password

agent1-verify: agent1-cert.pem ca1-cert.pem
openssl verify -CAfile ca1-cert.pem agent1-cert.pem

Expand DownExpand Up@@ -787,6 +803,18 @@ ec.pfx: ec-cert.pem ec-key.pem
-out ec.pfx \
-password pass:

# See agent1-fips.pfx for why the FIPS fixture uses PBMAC1.
ec-fips.pfx: ec-cert.pem ec-key.pem
openssl pkcs12 -export \
-keypbe AES-256-CBC \
-certpbe AES-256-CBC \
-iter 2048 \
-pbmac1_pbkdf2 \
-in ec-cert.pem \
-inkey ec-key.pem \
-out ec-fips.pfx \
-password pass:password

dh512.pem:
openssl dhparam -out dh512.pem 512

Expand Down
Binary file addedtest/fixtures/keys/agent1-fips.pfx
Binary file not shown.
Binary file addedtest/fixtures/keys/ec-fips.pfx
Binary file not shown.
4 changes: 3 additions & 1 deletion test/parallel/test-crypto-argon2-job.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -4,10 +4,12 @@ const common = require('../common');
if (!common.hasCrypto)
common.skip('missing crypto');

const { hasOpenSSL } = require('../common/crypto');
const { hasFIPS, hasOpenSSL } = require('../common/crypto');

if (!hasOpenSSL(3, 2))
common.skip('requires OpenSSL >= 3.2');
if (hasFIPS(3))
common.skip('Argon2 is not available in FIPS mode');

// Exercises the native Argon2 job directly via internalBinding, bypassing
// the JS validators, to ensure that if invalid parameters ever reach the
Expand Down
13 changes: 12 additions & 1 deletion test/parallel/test-crypto-argon2.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -3,7 +3,7 @@ const common = require('../common');
if (!common.hasCrypto)
common.skip('missing crypto');

const { hasOpenSSL } = require('../common/crypto');
const { hasFIPS, hasOpenSSL } = require('../common/crypto');

if (!hasOpenSSL(3, 2))
common.skip('requires OpenSSL >= 3.2');
Expand All@@ -28,6 +28,17 @@ const secret = Buffer.alloc(8, 0x03);
const associatedData = Buffer.alloc(12, 0x04);
const defaults = { message, nonce, parallelism: 1, tagLength: 64, memory: 8, passes: 3 };

if (hasFIPS(3)) {
assert.throws(() => crypto.argon2Sync('argon2id', defaults), {
code: 'ERR_OSSL_EVP_UNSUPPORTED',
});
crypto.argon2('argon2id', defaults, common.mustCall((err, result) => {
assert.strictEqual(err?.code, 'ERR_OSSL_EVP_UNSUPPORTED');
assert.strictEqual(result, undefined);
}));
return;
}

const good = [
// Test vectors from RFC 9106 https://www.rfc-editor.org/rfc/rfc9106.html#name-test-vectors
// and OpenSSL 3.2 https://github.com/openssl/openssl/blob/6dfa998f7ea150f9c6d4e4727cf6d5c82a68a8da/test/recipes/30-test_evp_data/evpkdf_argon2.txt
Expand Down
61 changes: 43 additions & 18 deletions test/parallel/test-crypto-async-sign-verify.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -3,12 +3,14 @@ const common = require('../common');
if (!common.hasCrypto)
common.skip('missing crypto');

const { hasOpenSSL3 } = require('../common/crypto');
const { hasOpenSSL, hasFIPS } = require('../common/crypto');
const assert = require('assert');
const util = require('util');
const crypto = require('crypto');
const fixtures = require('../common/fixtures');

const fips3 = hasFIPS(3);

function test(
publicFixture,
privateFixture,
Expand DownExpand Up@@ -65,6 +67,15 @@ function test(
}
}

function testSignFailure(privateFixture, algorithm, options, code) {
const key = { key: fixtures.readKey(privateFixture), ...options };
const data = Buffer.from('Hello world');
assert.throws(() => crypto.sign(algorithm, data, key), { code });
crypto.sign(algorithm, data, key, common.mustCall((err) => {
assert.strictEqual(err?.code, code);
}));
}

// RSA w/ default padding
test('rsa_public.pem', 'rsa_private.pem', 'sha256', true);
test('rsa_public.pem', 'rsa_private.pem', 'sha256', true,
Expand DownExpand Up@@ -94,14 +105,19 @@ if (!process.features.openssl_is_boringssl) {
test('ed448_public.pem', 'ed448_private.pem', undefined, true);

// ECDSA w/ der signature encoding
test('ec_secp256k1_public.pem', 'ec_secp256k1_private.pem', 'sha384',
false);
test('ec_secp256k1_public.pem', 'ec_secp256k1_private.pem', 'sha384',
false, { dsaEncoding: 'der' });

// ECDSA w/ ieee-p1363 signature encoding
test('ec_secp256k1_public.pem', 'ec_secp256k1_private.pem', 'sha384', false,
{ dsaEncoding: 'ieee-p1363' });
if (fips3) {
testSignFailure('ec_secp256k1_private.pem', 'sha384', {},
'ERR_OSSL_EVP_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE');
} else {
test('ec_secp256k1_public.pem', 'ec_secp256k1_private.pem', 'sha384',
false);
test('ec_secp256k1_public.pem', 'ec_secp256k1_private.pem', 'sha384',
false, { dsaEncoding: 'der' });

// ECDSA w/ ieee-p1363 signature encoding
test('ec_secp256k1_public.pem', 'ec_secp256k1_private.pem', 'sha384', false,
{ dsaEncoding: 'ieee-p1363' });
}

// DSA w/ der signature encoding
test('dsa_public.pem', 'dsa_private.pem', 'sha256',
Expand DownExpand Up@@ -157,7 +173,7 @@ MCowBQYDK2VuAyEA6pwGRbadNQAI/tYN8+/p/0/hbsdHfOEGr1ADiLVk/Gc=

let expected = /no default digest/;
let expectedCode = 'ERR_OSSL_EVP_NO_DEFAULT_DIGEST';
if (hasOpenSSL3 || process.features.openssl_is_boringssl) {
if (hasOpenSSL(3) || process.features.openssl_is_boringssl) {
expected = /operation[\s_]not[\s_]supported[\s_]for[\s_]this[\s_]keytype/i;
expectedCode = 'ERR_OSSL_EVP_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE';
}
Expand All@@ -170,12 +186,21 @@ MCowBQYDK2VuAyEA6pwGRbadNQAI/tYN8+/p/0/hbsdHfOEGr1ADiLVk/Gc=
}

{
const { privateKey } = crypto.generateKeyPairSync('rsa', {
modulusLength: 512
});
crypto.sign('sha512', 'message', privateKey, common.mustCall((err) => {
assert.ok(err);
assert.match(err.message, /digest[\s_]too[\s_]big[\s_]for[\s_]rsa[\s_]key/i);
assert.match(err.code, /^ERR_OSSL_.*DIGEST_TOO_BIG_FOR_RSA_KEY$/);
}));
if (fips3) {
crypto.generateKeyPair('rsa', { modulusLength: 512 },
common.mustCall((err) => {
assert.strictEqual(
err?.code, 'ERR_OSSL_RSA_INVALID_MODULUS');
}));
} else {
const { privateKey } = crypto.generateKeyPairSync('rsa', {
modulusLength: 512
});
crypto.sign('sha512', 'message', privateKey, common.mustCall((err) => {
assert.ok(err);
assert.match(
err.message, /digest[\s_]too[\s_]big[\s_]for[\s_]rsa[\s_]key/i);
assert.match(err.code, /^ERR_OSSL_.*DIGEST_TOO_BIG_FOR_RSA_KEY$/);
}));
}
}
11 changes: 11 additions & 0 deletions test/parallel/test-crypto-authenticated-stream.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -6,6 +6,7 @@ if (!common.hasCrypto)

const assert = require('assert');
const crypto = require('crypto');
const { hasFIPS } = require('../common/crypto');
const fs = require('fs');
const stream = require('stream');
const tmpdir = require('../common/tmpdir');
Expand DownExpand Up@@ -120,6 +121,16 @@ function test(config) {
return;
}

if (hasFIPS(3)) {
assert.throws(() => crypto.createDecipheriv(
config.cipher, config.key, config.iv, {
authTagLength: config.authTagLength,
}), {
code: 'ERR_CRYPTO_UNSUPPORTED_OPERATION',
});
return;
}

direct(config);
mstream(config);
fstream(config);
Expand Down
51 changes: 37 additions & 14 deletions test/parallel/test-crypto-authenticated.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -29,9 +29,10 @@ const assert = require('assert');
const crypto = require('crypto');
const { inspect } = require('util');
const fixtures = require('../common/fixtures');
const { hasOpenSSL3 } = require('../common/crypto');
const { hasOpenSSL, hasFIPS } = require('../common/crypto');

const isFipsEnabled = crypto.getFips();
const isFipsEnabled = crypto.getFips() === 1;
const fips3 = hasFIPS(3);

//
// Test authenticated encryption modes.
Expand DownExpand Up@@ -559,6 +560,14 @@ for (const test of TEST_CASES) {
const ciphertext = Buffer.concat([cipher.update(plain), cipher.final()]);
const tag = cipher.getAuthTag();

if (fips3 && mode === 'ccm') {
assert.throws(() => crypto.createDecipheriv(
`aes-128-${mode}`, key, iv, opts), {
code: 'ERR_CRYPTO_UNSUPPORTED_OPERATION',
});
continue;
}

const decipher = crypto.createDecipheriv(`aes-128-${mode}`, key, iv, opts);
decipher.setAuthTag(tag);
assert.throws(() => {
Expand DownExpand Up@@ -636,15 +645,22 @@ for (const test of TEST_CASES) {
const cipher = crypto.createCipheriv('aes-128-ccm', key, iv, opts);
assert.throws(() => {
cipher.final();
}, hasOpenSSL3 ? {
}, hasOpenSSL(3) ? {
code: 'ERR_OSSL_TAG_NOT_SET'
} : {
message: /Unsupported state/
});
}
}

if (!process.features.openssl_is_boringssl) {
if (fips3) {
assert.throws(() => crypto.createCipheriv(
'chacha20-poly1305', Buffer.alloc(32), Buffer.alloc(12), {
authTagLength: 16,
}), {
code: 'ERR_OSSL_EVP_UNSUPPORTED',
});
} else if (!process.features.openssl_is_boringssl) {
const key = Buffer.alloc(32);
const iv = Buffer.alloc(12);

Expand All@@ -662,7 +678,7 @@ if (!process.features.openssl_is_boringssl) {

// ChaCha20-Poly1305 should respect the authTagLength option and should not
// require the authentication tag before calls to update() during decryption.
if (!process.features.openssl_is_boringssl) {
if (!fips3 && !process.features.openssl_is_boringssl) {
const key = Buffer.alloc(32);
const iv = Buffer.alloc(12);

Expand DownExpand Up@@ -713,7 +729,7 @@ if (!process.features.openssl_is_boringssl) {
// shorter tags as long as their length was valid according to NIST SP 800-38D.
// For ChaCha20-Poly1305, we intentionally deviate from that because there are
// no recommended or approved authentication tag lengths below 16 bytes.
if (!process.features.openssl_is_boringssl) {
if (!fips3 && !process.features.openssl_is_boringssl) {
const rfcTestCases = TEST_CASES.filter(({ algo, tampered }) => {
return algo === 'chacha20-poly1305' && tampered === false;
});
Expand DownExpand Up@@ -752,7 +768,7 @@ if (!process.features.openssl_is_boringssl) {
}

// https://github.com/nodejs/node/issues/45874
if (!process.features.openssl_is_boringssl) {
if (!fips3 && !process.features.openssl_is_boringssl) {
const rfcTestCases = TEST_CASES.filter(({ algo, tampered }) => {
return algo === 'chacha20-poly1305' && tampered === false;
});
Expand DownExpand Up@@ -798,13 +814,20 @@ if (ciphers.includes('aes-128-ccm')) {
const tag = cipher.getAuthTag();
assert.strictEqual(tag.length, 16);

const decipher = crypto.createDecipheriv('aes-128-ccm', key, nonce, {
authTagLength: 16,
});
decipher.setAuthTag(tag);
decipher.setAAD(Buffer.alloc(0), { plaintextLength: 0 });
decipher.update(new DataView(new ArrayBuffer(0)));
decipher.final();
if (fips3) {
assert.throws(() => crypto.createDecipheriv(
'aes-128-ccm', key, nonce, { authTagLength: 16 }), {
code: 'ERR_CRYPTO_UNSUPPORTED_OPERATION',
});
} else {
const decipher = crypto.createDecipheriv('aes-128-ccm', key, nonce, {
authTagLength: 16,
});
decipher.setAuthTag(tag);
decipher.setAAD(Buffer.alloc(0), { plaintextLength: 0 });
decipher.update(new DataView(new ArrayBuffer(0)));
decipher.final();
}
} else {
common.printSkipMessage('Skipping unsupported aes-128-ccm test');
}
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/internal/crypto/webcrypto.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -1604,6 +1604,7 @@ class SubtleCrypto {
}

// Implements https://wicg.github.io/webcrypto-modern-algos/#SubtleCrypto-method-supports
// TODO(panva): Make supports() account for the active FIPS state.
static supports(operation, algorithm, lengthOrAdditionalAlgorithm = null) {
emitExperimentalWarning('The supports Web Crypto API method');
if (this !== SubtleCrypto) throw new ERR_INVALID_THIS('SubtleCrypto constructor');
Expand Down
14 changes: 12 additions & 2 deletions test/common/crypto.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -50,9 +50,14 @@ function assertApproximateSize(key, expectedSize) {
function testEncryptDecrypt(publicKey, privateKey) {
const message = 'Hello Node.js world!';
const plaintext = Buffer.from(message, 'utf8');
const withOaepHash = (key) => {
if (!hasFIPS(3)) return key;
if (key?.key !== undefined) return { ...key, oaepHash: 'sha256' };
return { key, oaepHash: 'sha256' };
};
for (const key of [publicKey, privateKey]) {
const ciphertext = publicEncrypt(key, plaintext);
const received = privateDecrypt(privateKey, ciphertext);
const ciphertext = publicEncrypt(withOaepHash(key), plaintext);
const received = privateDecrypt(withOaepHash(privateKey), ciphertext);
assert.strictEqual(received.toString('utf8'), message);
}
}
Expand DownExpand Up@@ -118,6 +123,10 @@ const hasOpenSSL = (major = 0, minor = 0, patch = 0) => {
return OPENSSL_VERSION_NUMBER >= opensslVersionNumber(major, minor, patch);
};

const hasFIPS = (major = 0, minor = 0, patch = 0) => {
return crypto.getFips() === 1 && hasOpenSSL(major, minor, patch);
};

let opensslCli = null;

module.exports = {
Expand All@@ -134,6 +143,7 @@ module.exports = {
sec1Exp,
sec1EncExp,
hasOpenSSL,
hasFIPS,
get hasOpenSSL3() {
return hasOpenSSL(3);
},
Expand Down
28 changes: 28 additions & 0 deletions test/fixtures/keys/Makefile
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,6 +8,7 @@ all: \
ca5-cert.pem \
ca6-cert.pem \
agent1-cert.pem \
agent1-fips.pfx \
agent1.pfx \
agent2-cert.pem \
agent3-cert.pem \
Expand DownExpand Up@@ -39,6 +40,7 @@ all: \
dsa_private_encrypted_1025.pem \
dsa_public_1025.pem \
ec-cert.pem \
ec-fips.pfx \
ec.pfx \
fake-cnnic-root-cert.pem \
intermediate-ca-cert.pem \
Expand DownExpand Up@@ -444,6 +446,20 @@ agent1.pfx: agent1-cert.pem agent1-key.pem ca1-cert.pem
-out agent1.pfx \
-password pass:sample

# PKCS12KDF is unavailable under FIPS properties. Use PBMAC1 with PBKDF2
# instead, alongside AES-256/PBKDF2 key protection.
agent1-fips.pfx: agent1-cert.pem agent1-key.pem ca1-cert.pem
openssl pkcs12 -export \
-keypbe AES-256-CBC \
-certpbe AES-256-CBC \
-iter 2048 \
-pbmac1_pbkdf2 \
-in agent1-cert.pem \
-inkey agent1-key.pem \
-certfile ca1-cert.pem \
-out agent1-fips.pfx \
-password pass:password

agent1-verify: agent1-cert.pem ca1-cert.pem
openssl verify -CAfile ca1-cert.pem agent1-cert.pem

Expand DownExpand Up@@ -787,6 +803,18 @@ ec.pfx: ec-cert.pem ec-key.pem
-out ec.pfx \
-password pass:

# See agent1-fips.pfx for why the FIPS fixture uses PBMAC1.
ec-fips.pfx: ec-cert.pem ec-key.pem
openssl pkcs12 -export \
-keypbe AES-256-CBC \
-certpbe AES-256-CBC \
-iter 2048 \
-pbmac1_pbkdf2 \
-in ec-cert.pem \
-inkey ec-key.pem \
-out ec-fips.pfx \
-password pass:password

dh512.pem:
openssl dhparam -out dh512.pem 512

Expand Down
Binary file addedtest/fixtures/keys/agent1-fips.pfx
Binary file not shown.
Binary file addedtest/fixtures/keys/ec-fips.pfx
Binary file not shown.
4 changes: 3 additions & 1 deletion test/parallel/test-crypto-argon2-job.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -4,10 +4,12 @@ const common = require('../common');
if (!common.hasCrypto)
common.skip('missing crypto');

const { hasOpenSSL } = require('../common/crypto');
const { hasFIPS, hasOpenSSL } = require('../common/crypto');

if (!hasOpenSSL(3, 2))
common.skip('requires OpenSSL >= 3.2');
if (hasFIPS(3))
common.skip('Argon2 is not available in FIPS mode');

// Exercises the native Argon2 job directly via internalBinding, bypassing
// the JS validators, to ensure that if invalid parameters ever reach the
Expand Down
13 changes: 12 additions & 1 deletion test/parallel/test-crypto-argon2.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -3,7 +3,7 @@ const common = require('../common');
if (!common.hasCrypto)
common.skip('missing crypto');

const { hasOpenSSL } = require('../common/crypto');
const { hasFIPS, hasOpenSSL } = require('../common/crypto');

if (!hasOpenSSL(3, 2))
common.skip('requires OpenSSL >= 3.2');
Expand All@@ -28,6 +28,17 @@ const secret = Buffer.alloc(8, 0x03);
const associatedData = Buffer.alloc(12, 0x04);
const defaults = { message, nonce, parallelism: 1, tagLength: 64, memory: 8, passes: 3 };

if (hasFIPS(3)) {
assert.throws(() => crypto.argon2Sync('argon2id', defaults), {
code: 'ERR_OSSL_EVP_UNSUPPORTED',
});
crypto.argon2('argon2id', defaults, common.mustCall((err, result) => {
assert.strictEqual(err?.code, 'ERR_OSSL_EVP_UNSUPPORTED');
assert.strictEqual(result, undefined);
}));
return;
}

const good = [
// Test vectors from RFC 9106 https://www.rfc-editor.org/rfc/rfc9106.html#name-test-vectors
// and OpenSSL 3.2 https://github.com/openssl/openssl/blob/6dfa998f7ea150f9c6d4e4727cf6d5c82a68a8da/test/recipes/30-test_evp_data/evpkdf_argon2.txt
Expand Down
61 changes: 43 additions & 18 deletions test/parallel/test-crypto-async-sign-verify.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -3,12 +3,14 @@ const common = require('../common');
if (!common.hasCrypto)
common.skip('missing crypto');

const { hasOpenSSL3 } = require('../common/crypto');
const { hasOpenSSL, hasFIPS } = require('../common/crypto');
const assert = require('assert');
const util = require('util');
const crypto = require('crypto');
const fixtures = require('../common/fixtures');

const fips3 = hasFIPS(3);

function test(
publicFixture,
privateFixture,
Expand DownExpand Up@@ -65,6 +67,15 @@ function test(
}
}

function testSignFailure(privateFixture, algorithm, options, code) {
const key = { key: fixtures.readKey(privateFixture), ...options };
const data = Buffer.from('Hello world');
assert.throws(() => crypto.sign(algorithm, data, key), { code });
crypto.sign(algorithm, data, key, common.mustCall((err) => {
assert.strictEqual(err?.code, code);
}));
}

// RSA w/ default padding
test('rsa_public.pem', 'rsa_private.pem', 'sha256', true);
test('rsa_public.pem', 'rsa_private.pem', 'sha256', true,
Expand DownExpand Up@@ -94,14 +105,19 @@ if (!process.features.openssl_is_boringssl) {
test('ed448_public.pem', 'ed448_private.pem', undefined, true);

// ECDSA w/ der signature encoding
test('ec_secp256k1_public.pem', 'ec_secp256k1_private.pem', 'sha384',
false);
test('ec_secp256k1_public.pem', 'ec_secp256k1_private.pem', 'sha384',
false, { dsaEncoding: 'der' });

// ECDSA w/ ieee-p1363 signature encoding
test('ec_secp256k1_public.pem', 'ec_secp256k1_private.pem', 'sha384', false,
{ dsaEncoding: 'ieee-p1363' });
if (fips3) {
testSignFailure('ec_secp256k1_private.pem', 'sha384', {},
'ERR_OSSL_EVP_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE');
} else {
test('ec_secp256k1_public.pem', 'ec_secp256k1_private.pem', 'sha384',
false);
test('ec_secp256k1_public.pem', 'ec_secp256k1_private.pem', 'sha384',
false, { dsaEncoding: 'der' });

// ECDSA w/ ieee-p1363 signature encoding
test('ec_secp256k1_public.pem', 'ec_secp256k1_private.pem', 'sha384', false,
{ dsaEncoding: 'ieee-p1363' });
}

// DSA w/ der signature encoding
test('dsa_public.pem', 'dsa_private.pem', 'sha256',
Expand DownExpand Up@@ -157,7 +173,7 @@ MCowBQYDK2VuAyEA6pwGRbadNQAI/tYN8+/p/0/hbsdHfOEGr1ADiLVk/Gc=

let expected = /no default digest/;
let expectedCode = 'ERR_OSSL_EVP_NO_DEFAULT_DIGEST';
if (hasOpenSSL3 || process.features.openssl_is_boringssl) {
if (hasOpenSSL(3) || process.features.openssl_is_boringssl) {
expected = /operation[\s_]not[\s_]supported[\s_]for[\s_]this[\s_]keytype/i;
expectedCode = 'ERR_OSSL_EVP_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE';
}
Expand All@@ -170,12 +186,21 @@ MCowBQYDK2VuAyEA6pwGRbadNQAI/tYN8+/p/0/hbsdHfOEGr1ADiLVk/Gc=
}

{
const { privateKey } = crypto.generateKeyPairSync('rsa', {
modulusLength: 512
});
crypto.sign('sha512', 'message', privateKey, common.mustCall((err) => {
assert.ok(err);
assert.match(err.message, /digest[\s_]too[\s_]big[\s_]for[\s_]rsa[\s_]key/i);
assert.match(err.code, /^ERR_OSSL_.*DIGEST_TOO_BIG_FOR_RSA_KEY$/);
}));
if (fips3) {
crypto.generateKeyPair('rsa', { modulusLength: 512 },
common.mustCall((err) => {
assert.strictEqual(
err?.code, 'ERR_OSSL_RSA_INVALID_MODULUS');
}));
} else {
const { privateKey } = crypto.generateKeyPairSync('rsa', {
modulusLength: 512
});
crypto.sign('sha512', 'message', privateKey, common.mustCall((err) => {
assert.ok(err);
assert.match(
err.message, /digest[\s_]too[\s_]big[\s_]for[\s_]rsa[\s_]key/i);
assert.match(err.code, /^ERR_OSSL_.*DIGEST_TOO_BIG_FOR_RSA_KEY$/);
}));
}
}
11 changes: 11 additions & 0 deletions test/parallel/test-crypto-authenticated-stream.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -6,6 +6,7 @@ if (!common.hasCrypto)

const assert = require('assert');
const crypto = require('crypto');
const { hasFIPS } = require('../common/crypto');
const fs = require('fs');
const stream = require('stream');
const tmpdir = require('../common/tmpdir');
Expand DownExpand Up@@ -120,6 +121,16 @@ function test(config) {
return;
}

if (hasFIPS(3)) {
assert.throws(() => crypto.createDecipheriv(
config.cipher, config.key, config.iv, {
authTagLength: config.authTagLength,
}), {
code: 'ERR_CRYPTO_UNSUPPORTED_OPERATION',
});
return;
}

direct(config);
mstream(config);
fstream(config);
Expand Down
51 changes: 37 additions & 14 deletions test/parallel/test-crypto-authenticated.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -29,9 +29,10 @@ const assert = require('assert');
const crypto = require('crypto');
const { inspect } = require('util');
const fixtures = require('../common/fixtures');
const { hasOpenSSL3 } = require('../common/crypto');
const { hasOpenSSL, hasFIPS } = require('../common/crypto');

const isFipsEnabled = crypto.getFips();
const isFipsEnabled = crypto.getFips() === 1;
const fips3 = hasFIPS(3);

//
// Test authenticated encryption modes.
Expand DownExpand Up@@ -559,6 +560,14 @@ for (const test of TEST_CASES) {
const ciphertext = Buffer.concat([cipher.update(plain), cipher.final()]);
const tag = cipher.getAuthTag();

if (fips3 && mode === 'ccm') {
assert.throws(() => crypto.createDecipheriv(
`aes-128-${mode}`, key, iv, opts), {
code: 'ERR_CRYPTO_UNSUPPORTED_OPERATION',
});
continue;
}

const decipher = crypto.createDecipheriv(`aes-128-${mode}`, key, iv, opts);
decipher.setAuthTag(tag);
assert.throws(() => {
Expand DownExpand Up@@ -636,15 +645,22 @@ for (const test of TEST_CASES) {
const cipher = crypto.createCipheriv('aes-128-ccm', key, iv, opts);
assert.throws(() => {
cipher.final();
}, hasOpenSSL3 ? {
}, hasOpenSSL(3) ? {
code: 'ERR_OSSL_TAG_NOT_SET'
} : {
message: /Unsupported state/
});
}
}

if (!process.features.openssl_is_boringssl) {
if (fips3) {
assert.throws(() => crypto.createCipheriv(
'chacha20-poly1305', Buffer.alloc(32), Buffer.alloc(12), {
authTagLength: 16,
}), {
code: 'ERR_OSSL_EVP_UNSUPPORTED',
});
} else if (!process.features.openssl_is_boringssl) {
const key = Buffer.alloc(32);
const iv = Buffer.alloc(12);

Expand All@@ -662,7 +678,7 @@ if (!process.features.openssl_is_boringssl) {

// ChaCha20-Poly1305 should respect the authTagLength option and should not
// require the authentication tag before calls to update() during decryption.
if (!process.features.openssl_is_boringssl) {
if (!fips3 && !process.features.openssl_is_boringssl) {
const key = Buffer.alloc(32);
const iv = Buffer.alloc(12);

Expand DownExpand Up@@ -713,7 +729,7 @@ if (!process.features.openssl_is_boringssl) {
// shorter tags as long as their length was valid according to NIST SP 800-38D.
// For ChaCha20-Poly1305, we intentionally deviate from that because there are
// no recommended or approved authentication tag lengths below 16 bytes.
if (!process.features.openssl_is_boringssl) {
if (!fips3 && !process.features.openssl_is_boringssl) {
const rfcTestCases = TEST_CASES.filter(({ algo, tampered }) => {
return algo === 'chacha20-poly1305' && tampered === false;
});
Expand DownExpand Up@@ -752,7 +768,7 @@ if (!process.features.openssl_is_boringssl) {
}

// https://github.com/nodejs/node/issues/45874
if (!process.features.openssl_is_boringssl) {
if (!fips3 && !process.features.openssl_is_boringssl) {
const rfcTestCases = TEST_CASES.filter(({ algo, tampered }) => {
return algo === 'chacha20-poly1305' && tampered === false;
});
Expand DownExpand Up@@ -798,13 +814,20 @@ if (ciphers.includes('aes-128-ccm')) {
const tag = cipher.getAuthTag();
assert.strictEqual(tag.length, 16);

const decipher = crypto.createDecipheriv('aes-128-ccm', key, nonce, {
authTagLength: 16,
});
decipher.setAuthTag(tag);
decipher.setAAD(Buffer.alloc(0), { plaintextLength: 0 });
decipher.update(new DataView(new ArrayBuffer(0)));
decipher.final();
if (fips3) {
assert.throws(() => crypto.createDecipheriv(
'aes-128-ccm', key, nonce, { authTagLength: 16 }), {
code: 'ERR_CRYPTO_UNSUPPORTED_OPERATION',
});
} else {
const decipher = crypto.createDecipheriv('aes-128-ccm', key, nonce, {
authTagLength: 16,
});
decipher.setAuthTag(tag);
decipher.setAAD(Buffer.alloc(0), { plaintextLength: 0 });
decipher.update(new DataView(new ArrayBuffer(0)));
decipher.final();
}
} else {
common.printSkipMessage('Skipping unsupported aes-128-ccm test');
}
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/internal/crypto/webcrypto.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -1604,6 +1604,7 @@ class SubtleCrypto {
}

// Implements https://wicg.github.io/webcrypto-modern-algos/#SubtleCrypto-method-supports
// TODO(panva): Make supports() account for the active FIPS state.
static supports(operation, algorithm, lengthOrAdditionalAlgorithm = null) {
emitExperimentalWarning('The supports Web Crypto API method');
if (this !== SubtleCrypto) throw new ERR_INVALID_THIS('SubtleCrypto constructor');
Expand Down
14 changes: 12 additions & 2 deletions test/common/crypto.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -50,9 +50,14 @@ function assertApproximateSize(key, expectedSize) {
function testEncryptDecrypt(publicKey, privateKey) {
const message = 'Hello Node.js world!';
const plaintext = Buffer.from(message, 'utf8');
const withOaepHash = (key) => {
if (!hasFIPS(3)) return key;
if (key?.key !== undefined) return { ...key, oaepHash: 'sha256' };
return { key, oaepHash: 'sha256' };
};
for (const key of [publicKey, privateKey]) {
const ciphertext = publicEncrypt(key, plaintext);
const received = privateDecrypt(privateKey, ciphertext);
const ciphertext = publicEncrypt(withOaepHash(key), plaintext);
const received = privateDecrypt(withOaepHash(privateKey), ciphertext);
assert.strictEqual(received.toString('utf8'), message);
}
}
Expand DownExpand Up@@ -118,6 +123,10 @@ const hasOpenSSL = (major = 0, minor = 0, patch = 0) => {
return OPENSSL_VERSION_NUMBER >= opensslVersionNumber(major, minor, patch);
};

const hasFIPS = (major = 0, minor = 0, patch = 0) => {
return crypto.getFips() === 1 && hasOpenSSL(major, minor, patch);
};

let opensslCli = null;

module.exports = {
Expand All@@ -134,6 +143,7 @@ module.exports = {
sec1Exp,
sec1EncExp,
hasOpenSSL,
hasFIPS,
get hasOpenSSL3() {
return hasOpenSSL(3);
},
Expand Down
28 changes: 28 additions & 0 deletions test/fixtures/keys/Makefile
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,6 +8,7 @@ all: \
ca5-cert.pem \
ca6-cert.pem \
agent1-cert.pem \
agent1-fips.pfx \
agent1.pfx \
agent2-cert.pem \
agent3-cert.pem \
Expand DownExpand Up@@ -39,6 +40,7 @@ all: \
dsa_private_encrypted_1025.pem \
dsa_public_1025.pem \
ec-cert.pem \
ec-fips.pfx \
ec.pfx \
fake-cnnic-root-cert.pem \
intermediate-ca-cert.pem \
Expand DownExpand Up@@ -444,6 +446,20 @@ agent1.pfx: agent1-cert.pem agent1-key.pem ca1-cert.pem
-out agent1.pfx \
-password pass:sample

# PKCS12KDF is unavailable under FIPS properties. Use PBMAC1 with PBKDF2
# instead, alongside AES-256/PBKDF2 key protection.
agent1-fips.pfx: agent1-cert.pem agent1-key.pem ca1-cert.pem
openssl pkcs12 -export \
-keypbe AES-256-CBC \
-certpbe AES-256-CBC \
-iter 2048 \
-pbmac1_pbkdf2 \
-in agent1-cert.pem \
-inkey agent1-key.pem \
-certfile ca1-cert.pem \
-out agent1-fips.pfx \
-password pass:password

agent1-verify: agent1-cert.pem ca1-cert.pem
openssl verify -CAfile ca1-cert.pem agent1-cert.pem

Expand DownExpand Up@@ -787,6 +803,18 @@ ec.pfx: ec-cert.pem ec-key.pem
-out ec.pfx \
-password pass:

# See agent1-fips.pfx for why the FIPS fixture uses PBMAC1.
ec-fips.pfx: ec-cert.pem ec-key.pem
openssl pkcs12 -export \
-keypbe AES-256-CBC \
-certpbe AES-256-CBC \
-iter 2048 \
-pbmac1_pbkdf2 \
-in ec-cert.pem \
-inkey ec-key.pem \
-out ec-fips.pfx \
-password pass:password

dh512.pem:
openssl dhparam -out dh512.pem 512

Expand Down
Binary file addedtest/fixtures/keys/agent1-fips.pfx
Binary file not shown.
Binary file addedtest/fixtures/keys/ec-fips.pfx
Binary file not shown.
4 changes: 3 additions & 1 deletion test/parallel/test-crypto-argon2-job.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -4,10 +4,12 @@ const common = require('../common');
if (!common.hasCrypto)
common.skip('missing crypto');

const { hasOpenSSL } = require('../common/crypto');
const { hasFIPS, hasOpenSSL } = require('../common/crypto');

if (!hasOpenSSL(3, 2))
common.skip('requires OpenSSL >= 3.2');
if (hasFIPS(3))
common.skip('Argon2 is not available in FIPS mode');

// Exercises the native Argon2 job directly via internalBinding, bypassing
// the JS validators, to ensure that if invalid parameters ever reach the
Expand Down
13 changes: 12 additions & 1 deletion test/parallel/test-crypto-argon2.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -3,7 +3,7 @@ const common = require('../common');
if (!common.hasCrypto)
common.skip('missing crypto');

const { hasOpenSSL } = require('../common/crypto');
const { hasFIPS, hasOpenSSL } = require('../common/crypto');

if (!hasOpenSSL(3, 2))
common.skip('requires OpenSSL >= 3.2');
Expand All@@ -28,6 +28,17 @@ const secret = Buffer.alloc(8, 0x03);
const associatedData = Buffer.alloc(12, 0x04);
const defaults = { message, nonce, parallelism: 1, tagLength: 64, memory: 8, passes: 3 };

if (hasFIPS(3)) {
assert.throws(() => crypto.argon2Sync('argon2id', defaults), {
code: 'ERR_OSSL_EVP_UNSUPPORTED',
});
crypto.argon2('argon2id', defaults, common.mustCall((err, result) => {
assert.strictEqual(err?.code, 'ERR_OSSL_EVP_UNSUPPORTED');
assert.strictEqual(result, undefined);
}));
return;
}

const good = [
// Test vectors from RFC 9106 https://www.rfc-editor.org/rfc/rfc9106.html#name-test-vectors
// and OpenSSL 3.2 https://github.com/openssl/openssl/blob/6dfa998f7ea150f9c6d4e4727cf6d5c82a68a8da/test/recipes/30-test_evp_data/evpkdf_argon2.txt
Expand Down
61 changes: 43 additions & 18 deletions test/parallel/test-crypto-async-sign-verify.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -3,12 +3,14 @@ const common = require('../common');
if (!common.hasCrypto)
common.skip('missing crypto');

const { hasOpenSSL3 } = require('../common/crypto');
const { hasOpenSSL, hasFIPS } = require('../common/crypto');
const assert = require('assert');
const util = require('util');
const crypto = require('crypto');
const fixtures = require('../common/fixtures');

const fips3 = hasFIPS(3);

function test(
publicFixture,
privateFixture,
Expand DownExpand Up@@ -65,6 +67,15 @@ function test(
}
}

function testSignFailure(privateFixture, algorithm, options, code) {
const key = { key: fixtures.readKey(privateFixture), ...options };
const data = Buffer.from('Hello world');
assert.throws(() => crypto.sign(algorithm, data, key), { code });
crypto.sign(algorithm, data, key, common.mustCall((err) => {
assert.strictEqual(err?.code, code);
}));
}

// RSA w/ default padding
test('rsa_public.pem', 'rsa_private.pem', 'sha256', true);
test('rsa_public.pem', 'rsa_private.pem', 'sha256', true,
Expand DownExpand Up@@ -94,14 +105,19 @@ if (!process.features.openssl_is_boringssl) {
test('ed448_public.pem', 'ed448_private.pem', undefined, true);

// ECDSA w/ der signature encoding
test('ec_secp256k1_public.pem', 'ec_secp256k1_private.pem', 'sha384',
false);
test('ec_secp256k1_public.pem', 'ec_secp256k1_private.pem', 'sha384',
false, { dsaEncoding: 'der' });

// ECDSA w/ ieee-p1363 signature encoding
test('ec_secp256k1_public.pem', 'ec_secp256k1_private.pem', 'sha384', false,
{ dsaEncoding: 'ieee-p1363' });
if (fips3) {
testSignFailure('ec_secp256k1_private.pem', 'sha384', {},
'ERR_OSSL_EVP_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE');
} else {
test('ec_secp256k1_public.pem', 'ec_secp256k1_private.pem', 'sha384',
false);
test('ec_secp256k1_public.pem', 'ec_secp256k1_private.pem', 'sha384',
false, { dsaEncoding: 'der' });

// ECDSA w/ ieee-p1363 signature encoding
test('ec_secp256k1_public.pem', 'ec_secp256k1_private.pem', 'sha384', false,
{ dsaEncoding: 'ieee-p1363' });
}

// DSA w/ der signature encoding
test('dsa_public.pem', 'dsa_private.pem', 'sha256',
Expand DownExpand Up@@ -157,7 +173,7 @@ MCowBQYDK2VuAyEA6pwGRbadNQAI/tYN8+/p/0/hbsdHfOEGr1ADiLVk/Gc=

let expected = /no default digest/;
let expectedCode = 'ERR_OSSL_EVP_NO_DEFAULT_DIGEST';
if (hasOpenSSL3 || process.features.openssl_is_boringssl) {
if (hasOpenSSL(3) || process.features.openssl_is_boringssl) {
expected = /operation[\s_]not[\s_]supported[\s_]for[\s_]this[\s_]keytype/i;
expectedCode = 'ERR_OSSL_EVP_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE';
}
Expand All@@ -170,12 +186,21 @@ MCowBQYDK2VuAyEA6pwGRbadNQAI/tYN8+/p/0/hbsdHfOEGr1ADiLVk/Gc=
}

{
const { privateKey } = crypto.generateKeyPairSync('rsa', {
modulusLength: 512
});
crypto.sign('sha512', 'message', privateKey, common.mustCall((err) => {
assert.ok(err);
assert.match(err.message, /digest[\s_]too[\s_]big[\s_]for[\s_]rsa[\s_]key/i);
assert.match(err.code, /^ERR_OSSL_.*DIGEST_TOO_BIG_FOR_RSA_KEY$/);
}));
if (fips3) {
crypto.generateKeyPair('rsa', { modulusLength: 512 },
common.mustCall((err) => {
assert.strictEqual(
err?.code, 'ERR_OSSL_RSA_INVALID_MODULUS');
}));
} else {
const { privateKey } = crypto.generateKeyPairSync('rsa', {
modulusLength: 512
});
crypto.sign('sha512', 'message', privateKey, common.mustCall((err) => {
assert.ok(err);
assert.match(
err.message, /digest[\s_]too[\s_]big[\s_]for[\s_]rsa[\s_]key/i);
assert.match(err.code, /^ERR_OSSL_.*DIGEST_TOO_BIG_FOR_RSA_KEY$/);
}));
}
}
11 changes: 11 additions & 0 deletions test/parallel/test-crypto-authenticated-stream.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -6,6 +6,7 @@ if (!common.hasCrypto)

const assert = require('assert');
const crypto = require('crypto');
const { hasFIPS } = require('../common/crypto');
const fs = require('fs');
const stream = require('stream');
const tmpdir = require('../common/tmpdir');
Expand DownExpand Up@@ -120,6 +121,16 @@ function test(config) {
return;
}

if (hasFIPS(3)) {
assert.throws(() => crypto.createDecipheriv(
config.cipher, config.key, config.iv, {
authTagLength: config.authTagLength,
}), {
code: 'ERR_CRYPTO_UNSUPPORTED_OPERATION',
});
return;
}

direct(config);
mstream(config);
fstream(config);
Expand Down
51 changes: 37 additions & 14 deletions test/parallel/test-crypto-authenticated.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -29,9 +29,10 @@ const assert = require('assert');
const crypto = require('crypto');
const { inspect } = require('util');
const fixtures = require('../common/fixtures');
const { hasOpenSSL3 } = require('../common/crypto');
const { hasOpenSSL, hasFIPS } = require('../common/crypto');

const isFipsEnabled = crypto.getFips();
const isFipsEnabled = crypto.getFips() === 1;
const fips3 = hasFIPS(3);

//
// Test authenticated encryption modes.
Expand DownExpand Up@@ -559,6 +560,14 @@ for (const test of TEST_CASES) {
const ciphertext = Buffer.concat([cipher.update(plain), cipher.final()]);
const tag = cipher.getAuthTag();

if (fips3 && mode === 'ccm') {
assert.throws(() => crypto.createDecipheriv(
`aes-128-${mode}`, key, iv, opts), {
code: 'ERR_CRYPTO_UNSUPPORTED_OPERATION',
});
continue;
}

const decipher = crypto.createDecipheriv(`aes-128-${mode}`, key, iv, opts);
decipher.setAuthTag(tag);
assert.throws(() => {
Expand DownExpand Up@@ -636,15 +645,22 @@ for (const test of TEST_CASES) {
const cipher = crypto.createCipheriv('aes-128-ccm', key, iv, opts);
assert.throws(() => {
cipher.final();
}, hasOpenSSL3 ? {
}, hasOpenSSL(3) ? {
code: 'ERR_OSSL_TAG_NOT_SET'
} : {
message: /Unsupported state/
});
}
}

if (!process.features.openssl_is_boringssl) {
if (fips3) {
assert.throws(() => crypto.createCipheriv(
'chacha20-poly1305', Buffer.alloc(32), Buffer.alloc(12), {
authTagLength: 16,
}), {
code: 'ERR_OSSL_EVP_UNSUPPORTED',
});
} else if (!process.features.openssl_is_boringssl) {
const key = Buffer.alloc(32);
const iv = Buffer.alloc(12);

Expand All@@ -662,7 +678,7 @@ if (!process.features.openssl_is_boringssl) {

// ChaCha20-Poly1305 should respect the authTagLength option and should not
// require the authentication tag before calls to update() during decryption.
if (!process.features.openssl_is_boringssl) {
if (!fips3 && !process.features.openssl_is_boringssl) {
const key = Buffer.alloc(32);
const iv = Buffer.alloc(12);

Expand DownExpand Up@@ -713,7 +729,7 @@ if (!process.features.openssl_is_boringssl) {
// shorter tags as long as their length was valid according to NIST SP 800-38D.
// For ChaCha20-Poly1305, we intentionally deviate from that because there are
// no recommended or approved authentication tag lengths below 16 bytes.
if (!process.features.openssl_is_boringssl) {
if (!fips3 && !process.features.openssl_is_boringssl) {
const rfcTestCases = TEST_CASES.filter(({ algo, tampered }) => {
return algo === 'chacha20-poly1305' && tampered === false;
});
Expand DownExpand Up@@ -752,7 +768,7 @@ if (!process.features.openssl_is_boringssl) {
}

// https://github.com/nodejs/node/issues/45874
if (!process.features.openssl_is_boringssl) {
if (!fips3 && !process.features.openssl_is_boringssl) {
const rfcTestCases = TEST_CASES.filter(({ algo, tampered }) => {
return algo === 'chacha20-poly1305' && tampered === false;
});
Expand DownExpand Up@@ -798,13 +814,20 @@ if (ciphers.includes('aes-128-ccm')) {
const tag = cipher.getAuthTag();
assert.strictEqual(tag.length, 16);

const decipher = crypto.createDecipheriv('aes-128-ccm', key, nonce, {
authTagLength: 16,
});
decipher.setAuthTag(tag);
decipher.setAAD(Buffer.alloc(0), { plaintextLength: 0 });
decipher.update(new DataView(new ArrayBuffer(0)));
decipher.final();
if (fips3) {
assert.throws(() => crypto.createDecipheriv(
'aes-128-ccm', key, nonce, { authTagLength: 16 }), {
code: 'ERR_CRYPTO_UNSUPPORTED_OPERATION',
});
} else {
const decipher = crypto.createDecipheriv('aes-128-ccm', key, nonce, {
authTagLength: 16,
});
decipher.setAuthTag(tag);
decipher.setAAD(Buffer.alloc(0), { plaintextLength: 0 });
decipher.update(new DataView(new ArrayBuffer(0)));
decipher.final();
}
} else {
common.printSkipMessage('Skipping unsupported aes-128-ccm test');
}
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/internal/crypto/webcrypto.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -1604,6 +1604,7 @@ class SubtleCrypto {
}

// Implements https://wicg.github.io/webcrypto-modern-algos/#SubtleCrypto-method-supports
// TODO(panva): Make supports() account for the active FIPS state.
static supports(operation, algorithm, lengthOrAdditionalAlgorithm = null) {
emitExperimentalWarning('The supports Web Crypto API method');
if (this !== SubtleCrypto) throw new ERR_INVALID_THIS('SubtleCrypto constructor');
Expand Down
14 changes: 12 additions & 2 deletions test/common/crypto.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -50,9 +50,14 @@ function assertApproximateSize(key, expectedSize) {
function testEncryptDecrypt(publicKey, privateKey) {
const message = 'Hello Node.js world!';
const plaintext = Buffer.from(message, 'utf8');
const withOaepHash = (key) => {
if (!hasFIPS(3)) return key;
if (key?.key !== undefined) return { ...key, oaepHash: 'sha256' };
return { key, oaepHash: 'sha256' };
};
for (const key of [publicKey, privateKey]) {
const ciphertext = publicEncrypt(key, plaintext);
const received = privateDecrypt(privateKey, ciphertext);
const ciphertext = publicEncrypt(withOaepHash(key), plaintext);
const received = privateDecrypt(withOaepHash(privateKey), ciphertext);
assert.strictEqual(received.toString('utf8'), message);
}
}
Expand DownExpand Up@@ -118,6 +123,10 @@ const hasOpenSSL = (major = 0, minor = 0, patch = 0) => {
return OPENSSL_VERSION_NUMBER >= opensslVersionNumber(major, minor, patch);
};

const hasFIPS = (major = 0, minor = 0, patch = 0) => {
return crypto.getFips() === 1 && hasOpenSSL(major, minor, patch);
};

let opensslCli = null;

module.exports = {
Expand All@@ -134,6 +143,7 @@ module.exports = {
sec1Exp,
sec1EncExp,
hasOpenSSL,
hasFIPS,
get hasOpenSSL3() {
return hasOpenSSL(3);
},
Expand Down
28 changes: 28 additions & 0 deletions test/fixtures/keys/Makefile
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,6 +8,7 @@ all: \
ca5-cert.pem \
ca6-cert.pem \
agent1-cert.pem \
agent1-fips.pfx \
agent1.pfx \
agent2-cert.pem \
agent3-cert.pem \
Expand DownExpand Up@@ -39,6 +40,7 @@ all: \
dsa_private_encrypted_1025.pem \
dsa_public_1025.pem \
ec-cert.pem \
ec-fips.pfx \
ec.pfx \
fake-cnnic-root-cert.pem \
intermediate-ca-cert.pem \
Expand DownExpand Up@@ -444,6 +446,20 @@ agent1.pfx: agent1-cert.pem agent1-key.pem ca1-cert.pem
-out agent1.pfx \
-password pass:sample

# PKCS12KDF is unavailable under FIPS properties. Use PBMAC1 with PBKDF2
# instead, alongside AES-256/PBKDF2 key protection.
agent1-fips.pfx: agent1-cert.pem agent1-key.pem ca1-cert.pem
openssl pkcs12 -export \
-keypbe AES-256-CBC \
-certpbe AES-256-CBC \
-iter 2048 \
-pbmac1_pbkdf2 \
-in agent1-cert.pem \
-inkey agent1-key.pem \
-certfile ca1-cert.pem \
-out agent1-fips.pfx \
-password pass:password

agent1-verify: agent1-cert.pem ca1-cert.pem
openssl verify -CAfile ca1-cert.pem agent1-cert.pem

Expand DownExpand Up@@ -787,6 +803,18 @@ ec.pfx: ec-cert.pem ec-key.pem
-out ec.pfx \
-password pass:

# See agent1-fips.pfx for why the FIPS fixture uses PBMAC1.
ec-fips.pfx: ec-cert.pem ec-key.pem
openssl pkcs12 -export \
-keypbe AES-256-CBC \
-certpbe AES-256-CBC \
-iter 2048 \
-pbmac1_pbkdf2 \
-in ec-cert.pem \
-inkey ec-key.pem \
-out ec-fips.pfx \
-password pass:password

dh512.pem:
openssl dhparam -out dh512.pem 512

Expand Down
Binary file addedtest/fixtures/keys/agent1-fips.pfx
Binary file not shown.
Binary file addedtest/fixtures/keys/ec-fips.pfx
Binary file not shown.
4 changes: 3 additions & 1 deletion test/parallel/test-crypto-argon2-job.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -4,10 +4,12 @@ const common = require('../common');
if (!common.hasCrypto)
common.skip('missing crypto');

const { hasOpenSSL } = require('../common/crypto');
const { hasFIPS, hasOpenSSL } = require('../common/crypto');

if (!hasOpenSSL(3, 2))
common.skip('requires OpenSSL >= 3.2');
if (hasFIPS(3))
common.skip('Argon2 is not available in FIPS mode');

// Exercises the native Argon2 job directly via internalBinding, bypassing
// the JS validators, to ensure that if invalid parameters ever reach the
Expand Down
13 changes: 12 additions & 1 deletion test/parallel/test-crypto-argon2.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -3,7 +3,7 @@ const common = require('../common');
if (!common.hasCrypto)
common.skip('missing crypto');

const { hasOpenSSL } = require('../common/crypto');
const { hasFIPS, hasOpenSSL } = require('../common/crypto');

if (!hasOpenSSL(3, 2))
common.skip('requires OpenSSL >= 3.2');
Expand All@@ -28,6 +28,17 @@ const secret = Buffer.alloc(8, 0x03);
const associatedData = Buffer.alloc(12, 0x04);
const defaults = { message, nonce, parallelism: 1, tagLength: 64, memory: 8, passes: 3 };

if (hasFIPS(3)) {
assert.throws(() => crypto.argon2Sync('argon2id', defaults), {
code: 'ERR_OSSL_EVP_UNSUPPORTED',
});
crypto.argon2('argon2id', defaults, common.mustCall((err, result) => {
assert.strictEqual(err?.code, 'ERR_OSSL_EVP_UNSUPPORTED');
assert.strictEqual(result, undefined);
}));
return;
}

const good = [
// Test vectors from RFC 9106 https://www.rfc-editor.org/rfc/rfc9106.html#name-test-vectors
// and OpenSSL 3.2 https://github.com/openssl/openssl/blob/6dfa998f7ea150f9c6d4e4727cf6d5c82a68a8da/test/recipes/30-test_evp_data/evpkdf_argon2.txt
Expand Down
61 changes: 43 additions & 18 deletions test/parallel/test-crypto-async-sign-verify.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -3,12 +3,14 @@ const common = require('../common');
if (!common.hasCrypto)
common.skip('missing crypto');

const { hasOpenSSL3 } = require('../common/crypto');
const { hasOpenSSL, hasFIPS } = require('../common/crypto');
const assert = require('assert');
const util = require('util');
const crypto = require('crypto');
const fixtures = require('../common/fixtures');

const fips3 = hasFIPS(3);

function test(
publicFixture,
privateFixture,
Expand DownExpand Up@@ -65,6 +67,15 @@ function test(
}
}

function testSignFailure(privateFixture, algorithm, options, code) {
const key = { key: fixtures.readKey(privateFixture), ...options };
const data = Buffer.from('Hello world');
assert.throws(() => crypto.sign(algorithm, data, key), { code });
crypto.sign(algorithm, data, key, common.mustCall((err) => {
assert.strictEqual(err?.code, code);
}));
}

// RSA w/ default padding
test('rsa_public.pem', 'rsa_private.pem', 'sha256', true);
test('rsa_public.pem', 'rsa_private.pem', 'sha256', true,
Expand DownExpand Up@@ -94,14 +105,19 @@ if (!process.features.openssl_is_boringssl) {
test('ed448_public.pem', 'ed448_private.pem', undefined, true);

// ECDSA w/ der signature encoding
test('ec_secp256k1_public.pem', 'ec_secp256k1_private.pem', 'sha384',
false);
test('ec_secp256k1_public.pem', 'ec_secp256k1_private.pem', 'sha384',
false, { dsaEncoding: 'der' });

// ECDSA w/ ieee-p1363 signature encoding
test('ec_secp256k1_public.pem', 'ec_secp256k1_private.pem', 'sha384', false,
{ dsaEncoding: 'ieee-p1363' });
if (fips3) {
testSignFailure('ec_secp256k1_private.pem', 'sha384', {},
'ERR_OSSL_EVP_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE');
} else {
test('ec_secp256k1_public.pem', 'ec_secp256k1_private.pem', 'sha384',
false);
test('ec_secp256k1_public.pem', 'ec_secp256k1_private.pem', 'sha384',
false, { dsaEncoding: 'der' });

// ECDSA w/ ieee-p1363 signature encoding
test('ec_secp256k1_public.pem', 'ec_secp256k1_private.pem', 'sha384', false,
{ dsaEncoding: 'ieee-p1363' });
}

// DSA w/ der signature encoding
test('dsa_public.pem', 'dsa_private.pem', 'sha256',
Expand DownExpand Up@@ -157,7 +173,7 @@ MCowBQYDK2VuAyEA6pwGRbadNQAI/tYN8+/p/0/hbsdHfOEGr1ADiLVk/Gc=

let expected = /no default digest/;
let expectedCode = 'ERR_OSSL_EVP_NO_DEFAULT_DIGEST';
if (hasOpenSSL3 || process.features.openssl_is_boringssl) {
if (hasOpenSSL(3) || process.features.openssl_is_boringssl) {
expected = /operation[\s_]not[\s_]supported[\s_]for[\s_]this[\s_]keytype/i;
expectedCode = 'ERR_OSSL_EVP_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE';
}
Expand All@@ -170,12 +186,21 @@ MCowBQYDK2VuAyEA6pwGRbadNQAI/tYN8+/p/0/hbsdHfOEGr1ADiLVk/Gc=
}

{
const { privateKey } = crypto.generateKeyPairSync('rsa', {
modulusLength: 512
});
crypto.sign('sha512', 'message', privateKey, common.mustCall((err) => {
assert.ok(err);
assert.match(err.message, /digest[\s_]too[\s_]big[\s_]for[\s_]rsa[\s_]key/i);
assert.match(err.code, /^ERR_OSSL_.*DIGEST_TOO_BIG_FOR_RSA_KEY$/);
}));
if (fips3) {
crypto.generateKeyPair('rsa', { modulusLength: 512 },
common.mustCall((err) => {
assert.strictEqual(
err?.code, 'ERR_OSSL_RSA_INVALID_MODULUS');
}));
} else {
const { privateKey } = crypto.generateKeyPairSync('rsa', {
modulusLength: 512
});
crypto.sign('sha512', 'message', privateKey, common.mustCall((err) => {
assert.ok(err);
assert.match(
err.message, /digest[\s_]too[\s_]big[\s_]for[\s_]rsa[\s_]key/i);
assert.match(err.code, /^ERR_OSSL_.*DIGEST_TOO_BIG_FOR_RSA_KEY$/);
}));
}
}
11 changes: 11 additions & 0 deletions test/parallel/test-crypto-authenticated-stream.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -6,6 +6,7 @@ if (!common.hasCrypto)

const assert = require('assert');
const crypto = require('crypto');
const { hasFIPS } = require('../common/crypto');
const fs = require('fs');
const stream = require('stream');
const tmpdir = require('../common/tmpdir');
Expand DownExpand Up@@ -120,6 +121,16 @@ function test(config) {
return;
}

if (hasFIPS(3)) {
assert.throws(() => crypto.createDecipheriv(
config.cipher, config.key, config.iv, {
authTagLength: config.authTagLength,
}), {
code: 'ERR_CRYPTO_UNSUPPORTED_OPERATION',
});
return;
}

direct(config);
mstream(config);
fstream(config);
Expand Down
51 changes: 37 additions & 14 deletions test/parallel/test-crypto-authenticated.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -29,9 +29,10 @@ const assert = require('assert');
const crypto = require('crypto');
const { inspect } = require('util');
const fixtures = require('../common/fixtures');
const { hasOpenSSL3 } = require('../common/crypto');
const { hasOpenSSL, hasFIPS } = require('../common/crypto');

const isFipsEnabled = crypto.getFips();
const isFipsEnabled = crypto.getFips() === 1;
const fips3 = hasFIPS(3);

//
// Test authenticated encryption modes.
Expand DownExpand Up@@ -559,6 +560,14 @@ for (const test of TEST_CASES) {
const ciphertext = Buffer.concat([cipher.update(plain), cipher.final()]);
const tag = cipher.getAuthTag();

if (fips3 && mode === 'ccm') {
assert.throws(() => crypto.createDecipheriv(
`aes-128-${mode}`, key, iv, opts), {
code: 'ERR_CRYPTO_UNSUPPORTED_OPERATION',
});
continue;
}

const decipher = crypto.createDecipheriv(`aes-128-${mode}`, key, iv, opts);
decipher.setAuthTag(tag);
assert.throws(() => {
Expand DownExpand Up@@ -636,15 +645,22 @@ for (const test of TEST_CASES) {
const cipher = crypto.createCipheriv('aes-128-ccm', key, iv, opts);
assert.throws(() => {
cipher.final();
}, hasOpenSSL3 ? {
}, hasOpenSSL(3) ? {
code: 'ERR_OSSL_TAG_NOT_SET'
} : {
message: /Unsupported state/
});
}
}

if (!process.features.openssl_is_boringssl) {
if (fips3) {
assert.throws(() => crypto.createCipheriv(
'chacha20-poly1305', Buffer.alloc(32), Buffer.alloc(12), {
authTagLength: 16,
}), {
code: 'ERR_OSSL_EVP_UNSUPPORTED',
});
} else if (!process.features.openssl_is_boringssl) {
const key = Buffer.alloc(32);
const iv = Buffer.alloc(12);

Expand All@@ -662,7 +678,7 @@ if (!process.features.openssl_is_boringssl) {

// ChaCha20-Poly1305 should respect the authTagLength option and should not
// require the authentication tag before calls to update() during decryption.
if (!process.features.openssl_is_boringssl) {
if (!fips3 && !process.features.openssl_is_boringssl) {
const key = Buffer.alloc(32);
const iv = Buffer.alloc(12);

Expand DownExpand Up@@ -713,7 +729,7 @@ if (!process.features.openssl_is_boringssl) {
// shorter tags as long as their length was valid according to NIST SP 800-38D.
// For ChaCha20-Poly1305, we intentionally deviate from that because there are
// no recommended or approved authentication tag lengths below 16 bytes.
if (!process.features.openssl_is_boringssl) {
if (!fips3 && !process.features.openssl_is_boringssl) {
const rfcTestCases = TEST_CASES.filter(({ algo, tampered }) => {
return algo === 'chacha20-poly1305' && tampered === false;
});
Expand DownExpand Up@@ -752,7 +768,7 @@ if (!process.features.openssl_is_boringssl) {
}

// https://github.com/nodejs/node/issues/45874
if (!process.features.openssl_is_boringssl) {
if (!fips3 && !process.features.openssl_is_boringssl) {
const rfcTestCases = TEST_CASES.filter(({ algo, tampered }) => {
return algo === 'chacha20-poly1305' && tampered === false;
});
Expand DownExpand Up@@ -798,13 +814,20 @@ if (ciphers.includes('aes-128-ccm')) {
const tag = cipher.getAuthTag();
assert.strictEqual(tag.length, 16);

const decipher = crypto.createDecipheriv('aes-128-ccm', key, nonce, {
authTagLength: 16,
});
decipher.setAuthTag(tag);
decipher.setAAD(Buffer.alloc(0), { plaintextLength: 0 });
decipher.update(new DataView(new ArrayBuffer(0)));
decipher.final();
if (fips3) {
assert.throws(() => crypto.createDecipheriv(
'aes-128-ccm', key, nonce, { authTagLength: 16 }), {
code: 'ERR_CRYPTO_UNSUPPORTED_OPERATION',
});
} else {
const decipher = crypto.createDecipheriv('aes-128-ccm', key, nonce, {
authTagLength: 16,
});
decipher.setAuthTag(tag);
decipher.setAAD(Buffer.alloc(0), { plaintextLength: 0 });
decipher.update(new DataView(new ArrayBuffer(0)));
decipher.final();
}
} else {
common.printSkipMessage('Skipping unsupported aes-128-ccm test');
}
Loading
Loading