Skip to content

Commit 54cd268

Browse files
mhdawsonRafaelGSS
authored andcommittedFeb 14, 2024
crypto: disable PKCS#1 padding for privateDecrypt
Refs: https://hackerone.com/bugs?subject=nodejs&report_id=2269177 Disable RSA_PKCS1_PADDING for crypto.privateDecrypt() in order to protect against the Marvin attack. Includes a security revert flag that can be used to restore support. Signed-off-by: Michael Dawson <[email protected]> PR-URL: nodejs-private/node-private#525 Refs: https://hackerone.com/bugs?subject=nodejs&report_id=2269177 Reviewed-By: Rafael Gonzaga <[email protected]> CVE-ID: CVE-2023-46809
1 parent b43171c commit 54cd268

File tree

2 files changed

+56
-12
lines changed

2 files changed

+56
-12
lines changed
 

‎src/crypto/crypto_cipher.cc

+26
Original file line numberDiff line numberDiff line change
@@ -1043,6 +1043,32 @@ void PublicKeyCipher::Cipher(const FunctionCallbackInfo<Value>& args) {
10431043
uint32_t padding;
10441044
if (!args[offset + 1]->Uint32Value(env->context()).To(&padding)) return;
10451045

1046+
if (EVP_PKEY_cipher == EVP_PKEY_decrypt &&
1047+
operation == PublicKeyCipher::kPrivate && padding == RSA_PKCS1_PADDING) {
1048+
EVPKeyCtxPointer ctx(EVP_PKEY_CTX_new(pkey.get(), nullptr));
1049+
CHECK(ctx);
1050+
1051+
if (EVP_PKEY_decrypt_init(ctx.get()) <= 0) {
1052+
return ThrowCryptoError(env, ERR_get_error());
1053+
}
1054+
1055+
int rsa_pkcs1_implicit_rejection =
1056+
EVP_PKEY_CTX_ctrl_str(ctx.get(), "rsa_pkcs1_implicit_rejection", "1");
1057+
// From the doc -2 means that the option is not supported.
1058+
// The default for the option is enabled and if it has been
1059+
// specifically disabled we want to respect that so we will
1060+
// not throw an error if the option is supported regardless
1061+
// of how it is set. The call to set the value
1062+
// will not affect what is used since a different context is
1063+
// used in the call if the option is supported
1064+
if (rsa_pkcs1_implicit_rejection <= 0) {
1065+
return THROW_ERR_INVALID_ARG_VALUE(
1066+
env,
1067+
"RSA_PKCS1_PADDING is no longer supported for private decryption,"
1068+
" this can be reverted with --security-revert=CVE-2024-PEND");
1069+
}
1070+
}
1071+
10461072
const EVP_MD* digest = nullptr;
10471073
if (args[offset + 2]->IsString()) {
10481074
const Utf8Value oaep_str(env->isolate(), args[offset + 2]);

‎test/parallel/test-crypto-rsa-dsa.js

+30-12
Original file line numberDiff line numberDiff line change
@@ -221,19 +221,37 @@ function test_rsa(padding, encryptOaepHash, decryptOaepHash) {
221221
oaepHash: encryptOaepHash
222222
}, bufferToEncrypt);
223223

224-
let decryptedBuffer = crypto.privateDecrypt({
225-
key: rsaKeyPem,
226-
padding: padding,
227-
oaepHash: decryptOaepHash
228-
}, encryptedBuffer);
229-
assert.deepStrictEqual(decryptedBuffer, input);
230224

231-
decryptedBuffer = crypto.privateDecrypt({
232-
key: rsaPkcs8KeyPem,
233-
padding: padding,
234-
oaepHash: decryptOaepHash
235-
}, encryptedBuffer);
236-
assert.deepStrictEqual(decryptedBuffer, input);
225+
if (padding === constants.RSA_PKCS1_PADDING) {
226+
assert.throws(() => {
227+
crypto.privateDecrypt({
228+
key: rsaKeyPem,
229+
padding: padding,
230+
oaepHash: decryptOaepHash
231+
}, encryptedBuffer);
232+
}, { code: 'ERR_INVALID_ARG_VALUE' });
233+
assert.throws(() => {
234+
crypto.privateDecrypt({
235+
key: rsaPkcs8KeyPem,
236+
padding: padding,
237+
oaepHash: decryptOaepHash
238+
}, encryptedBuffer);
239+
}, { code: 'ERR_INVALID_ARG_VALUE' });
240+
} else {
241+
let decryptedBuffer = crypto.privateDecrypt({
242+
key: rsaKeyPem,
243+
padding: padding,
244+
oaepHash: decryptOaepHash
245+
}, encryptedBuffer);
246+
assert.deepStrictEqual(decryptedBuffer, input);
247+
248+
decryptedBuffer = crypto.privateDecrypt({
249+
key: rsaPkcs8KeyPem,
250+
padding: padding,
251+
oaepHash: decryptOaepHash
252+
}, encryptedBuffer);
253+
assert.deepStrictEqual(decryptedBuffer, input);
254+
}
237255
}
238256

239257
test_rsa('RSA_NO_PADDING');

0 commit comments

Comments
 (0)
Please sign in to comment.