From da3f4255065ec57b5a1ed2877fc52d1c52b1e2fd Mon Sep 17 00:00:00 2001 From: Fedor Indutny Date: Tue, 23 Feb 2016 15:53:45 -0500 Subject: [PATCH] crypto: PBKDF2 works with `int` not `ssize_t` Change types of all PBKDF2 params to `int` as they are `int` in `evp.h`. Check that `raw_keylen` fits into `int` before passing it to OpenSSL. Fix: #5396 PR-URL: https://github.com/nodejs/node/pull/5397 Reviewed-By: Shigeki Ohtsu Reviewed-By: Ben Noorhduis --- src/node_crypto.cc | 43 ++++++++++++++++------------- test/parallel/test-crypto-pbkdf2.js | 21 ++++++-------- 2 files changed, 33 insertions(+), 31 deletions(-) diff --git a/src/node_crypto.cc b/src/node_crypto.cc index 85fefe0bdf..986fe80db4 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -19,6 +19,7 @@ #include "CNNICHashWhitelist.inc" #include +#include // INT_MAX #include #include #include @@ -4955,12 +4956,12 @@ class PBKDF2Request : public AsyncWrap { PBKDF2Request(Environment* env, Local object, const EVP_MD* digest, - ssize_t passlen, + int passlen, char* pass, - ssize_t saltlen, + int saltlen, char* salt, - ssize_t iter, - ssize_t keylen) + int iter, + int keylen) : AsyncWrap(env, object, AsyncWrap::PROVIDER_CRYPTO), digest_(digest), error_(0), @@ -4989,7 +4990,7 @@ class PBKDF2Request : public AsyncWrap { return digest_; } - inline ssize_t passlen() const { + inline int passlen() const { return passlen_; } @@ -4997,7 +4998,7 @@ class PBKDF2Request : public AsyncWrap { return pass_; } - inline ssize_t saltlen() const { + inline int saltlen() const { return saltlen_; } @@ -5005,7 +5006,7 @@ class PBKDF2Request : public AsyncWrap { return salt_; } - inline ssize_t keylen() const { + inline int keylen() const { return keylen_; } @@ -5013,7 +5014,7 @@ class PBKDF2Request : public AsyncWrap { return key_; } - inline ssize_t iter() const { + inline int iter() const { return iter_; } @@ -5046,13 +5047,13 @@ class PBKDF2Request : public AsyncWrap { private: const EVP_MD* digest_; int error_; - ssize_t passlen_; + int passlen_; char* pass_; - ssize_t saltlen_; + int saltlen_; char* salt_; - ssize_t keylen_; + int keylen_; char* key_; - ssize_t iter_; + int iter_; }; @@ -5109,10 +5110,11 @@ void PBKDF2(const FunctionCallbackInfo& args) { const char* type_error = nullptr; char* pass = nullptr; char* salt = nullptr; - ssize_t passlen = -1; - ssize_t saltlen = -1; - double keylen = -1; - ssize_t iter = -1; + int passlen = -1; + int saltlen = -1; + double raw_keylen = -1; + int keylen = -1; + int iter = -1; PBKDF2Request* req = nullptr; Local obj; @@ -5164,12 +5166,15 @@ void PBKDF2(const FunctionCallbackInfo& args) { goto err; } - keylen = args[3]->NumberValue(); - if (keylen < 0 || isnan(keylen) || isinf(keylen)) { + raw_keylen = args[3]->NumberValue(); + if (raw_keylen < 0.0 || isnan(raw_keylen) || isinf(raw_keylen) || + raw_keylen > INT_MAX) { type_error = "Bad key length"; goto err; } + keylen = static_cast(raw_keylen); + if (args[4]->IsString()) { node::Utf8Value digest_name(env->isolate(), args[4]); digest = EVP_get_digestbyname(*digest_name); @@ -5192,7 +5197,7 @@ void PBKDF2(const FunctionCallbackInfo& args) { saltlen, salt, iter, - static_cast(keylen)); + keylen); if (args[5]->IsFunction()) { obj->Set(env->ondone_string(), args[5]); diff --git a/test/parallel/test-crypto-pbkdf2.js b/test/parallel/test-crypto-pbkdf2.js index cbea3dae4c..a05eb70a8b 100644 --- a/test/parallel/test-crypto-pbkdf2.js +++ b/test/parallel/test-crypto-pbkdf2.js @@ -63,27 +63,24 @@ assert.throws(function() { // Should not work with Infinity key length assert.throws(function() { crypto.pbkdf2('password', 'salt', 1, Infinity, 'sha256', common.fail); -}, function(err) { - return err instanceof Error && err.message === 'Bad key length'; -}); +}, /Bad key length/); // Should not work with negative Infinity key length assert.throws(function() { crypto.pbkdf2('password', 'salt', 1, -Infinity, 'sha256', common.fail); -}, function(err) { - return err instanceof Error && err.message === 'Bad key length'; -}); +}, /Bad key length/); // Should not work with NaN key length assert.throws(function() { crypto.pbkdf2('password', 'salt', 1, NaN, 'sha256', common.fail); -}, function(err) { - return err instanceof Error && err.message === 'Bad key length'; -}); +}, /Bad key length/); // Should not work with negative key length assert.throws(function() { crypto.pbkdf2('password', 'salt', 1, -1, 'sha256', common.fail); -}, function(err) { - return err instanceof Error && err.message === 'Bad key length'; -}); +}, /Bad key length/); + +// Should not work with key length that does not fit into 32 signed bits +assert.throws(function() { + crypto.pbkdf2('password', 'salt', 1, 4073741824, 'sha256', common.fail); +}, /Bad key length/);