From 12b81dfc9336e79146b9709ef3f336a739808f61 Mon Sep 17 00:00:00 2001 From: Filip Skokan Date: Tue, 1 Apr 2025 08:29:29 +0200 Subject: [PATCH] crypto: fix output of privateDecrypt with zero-length data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit closes #57553 closes #57572 closes #57558 PR-URL: https://github.com/nodejs/node/pull/57575 Reviewed-By: James M Snell Reviewed-By: Luigi Pinca Reviewed-By: Yagiz Nizipli Reviewed-By: Tobias Nießen Reviewed-By: Darshan Sen --- deps/ncrypto/ncrypto.cc | 2 +- test/parallel/test-crypto-oaep-zero-length.js | 56 +++++++++++++++++++ 2 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 test/parallel/test-crypto-oaep-zero-length.js diff --git a/deps/ncrypto/ncrypto.cc b/deps/ncrypto/ncrypto.cc index 884a4ab7c60..faf9cf00e84 100644 --- a/deps/ncrypto/ncrypto.cc +++ b/deps/ncrypto/ncrypto.cc @@ -215,7 +215,7 @@ Buffer DataPointer::release() { DataPointer DataPointer::resize(size_t len) { size_t actual_len = std::min(len_, len); auto buf = release(); - if (actual_len == len_) return DataPointer(buf); + if (actual_len == len_) return DataPointer(buf.data, actual_len); buf.data = OPENSSL_realloc(buf.data, actual_len); buf.len = actual_len; return DataPointer(buf); diff --git a/test/parallel/test-crypto-oaep-zero-length.js b/test/parallel/test-crypto-oaep-zero-length.js new file mode 100644 index 00000000000..5194ce25454 --- /dev/null +++ b/test/parallel/test-crypto-oaep-zero-length.js @@ -0,0 +1,56 @@ +'use strict'; +const common = require('../common'); + +if (!common.hasCrypto) + common.skip('missing crypto'); + +const fixtures = require('../common/fixtures'); +const assert = require('assert'); +const crypto = require('crypto'); + +const { subtle } = globalThis.crypto; + +// Regression test for https://github.com/nodejs/node/issues/57553. +{ + const privateKey = crypto.createPrivateKey(fixtures.readKey('rsa_private.pem', 'ascii')); + const publicKey = crypto.createPublicKey(fixtures.readKey('rsa_public.pem', 'ascii')); + + const data = Buffer.alloc(0); + { + + const ciphertext = crypto.publicEncrypt({ + padding: crypto.constants.RSA_PKCS1_OAEP_PADDING, + key: publicKey, + }, data); + + const plaintext = crypto.privateDecrypt({ + padding: crypto.constants.RSA_PKCS1_OAEP_PADDING, + key: privateKey + }, ciphertext); + + assert.deepStrictEqual(plaintext, data); + } + + { + const ciphertext = crypto.publicEncrypt(publicKey, data); + const plaintext = crypto.privateDecrypt(privateKey, ciphertext); + + assert.deepStrictEqual(plaintext, data); + } + + { + (async () => { + const pkcs8 = privateKey.export({ format: 'der', type: 'pkcs8' }); + const spki = publicKey.export({ format: 'der', type: 'spki' }); + + const kp = { + privateKey: await subtle.importKey('pkcs8', pkcs8, { name: 'RSA-OAEP', hash: 'SHA-1' }, false, ['decrypt']), + publicKey: await subtle.importKey('spki', spki, { name: 'RSA-OAEP', hash: 'SHA-1' }, false, ['encrypt']), + }; + + const ciphertext = await subtle.encrypt('RSA-OAEP', kp.publicKey, data); + const plaintext = await subtle.decrypt('RSA-OAEP', kp.privateKey, ciphertext); + assert.deepStrictEqual(plaintext, data.buffer); + })().then(common.mustCall()); + } +}