Browse Source

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 <ohtsu@iij.ad.jp>
Reviewed-By: Ben Noorhduis <info@bnoordhuis.nl>
process-exit-stdio-flushing
Fedor Indutny 9 years ago
parent
commit
da3f425506
  1. 43
      src/node_crypto.cc
  2. 21
      test/parallel/test-crypto-pbkdf2.js

43
src/node_crypto.cc

@ -19,6 +19,7 @@
#include "CNNICHashWhitelist.inc" #include "CNNICHashWhitelist.inc"
#include <errno.h> #include <errno.h>
#include <limits.h> // INT_MAX
#include <math.h> #include <math.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -4955,12 +4956,12 @@ class PBKDF2Request : public AsyncWrap {
PBKDF2Request(Environment* env, PBKDF2Request(Environment* env,
Local<Object> object, Local<Object> object,
const EVP_MD* digest, const EVP_MD* digest,
ssize_t passlen, int passlen,
char* pass, char* pass,
ssize_t saltlen, int saltlen,
char* salt, char* salt,
ssize_t iter, int iter,
ssize_t keylen) int keylen)
: AsyncWrap(env, object, AsyncWrap::PROVIDER_CRYPTO), : AsyncWrap(env, object, AsyncWrap::PROVIDER_CRYPTO),
digest_(digest), digest_(digest),
error_(0), error_(0),
@ -4989,7 +4990,7 @@ class PBKDF2Request : public AsyncWrap {
return digest_; return digest_;
} }
inline ssize_t passlen() const { inline int passlen() const {
return passlen_; return passlen_;
} }
@ -4997,7 +4998,7 @@ class PBKDF2Request : public AsyncWrap {
return pass_; return pass_;
} }
inline ssize_t saltlen() const { inline int saltlen() const {
return saltlen_; return saltlen_;
} }
@ -5005,7 +5006,7 @@ class PBKDF2Request : public AsyncWrap {
return salt_; return salt_;
} }
inline ssize_t keylen() const { inline int keylen() const {
return keylen_; return keylen_;
} }
@ -5013,7 +5014,7 @@ class PBKDF2Request : public AsyncWrap {
return key_; return key_;
} }
inline ssize_t iter() const { inline int iter() const {
return iter_; return iter_;
} }
@ -5046,13 +5047,13 @@ class PBKDF2Request : public AsyncWrap {
private: private:
const EVP_MD* digest_; const EVP_MD* digest_;
int error_; int error_;
ssize_t passlen_; int passlen_;
char* pass_; char* pass_;
ssize_t saltlen_; int saltlen_;
char* salt_; char* salt_;
ssize_t keylen_; int keylen_;
char* key_; char* key_;
ssize_t iter_; int iter_;
}; };
@ -5109,10 +5110,11 @@ void PBKDF2(const FunctionCallbackInfo<Value>& args) {
const char* type_error = nullptr; const char* type_error = nullptr;
char* pass = nullptr; char* pass = nullptr;
char* salt = nullptr; char* salt = nullptr;
ssize_t passlen = -1; int passlen = -1;
ssize_t saltlen = -1; int saltlen = -1;
double keylen = -1; double raw_keylen = -1;
ssize_t iter = -1; int keylen = -1;
int iter = -1;
PBKDF2Request* req = nullptr; PBKDF2Request* req = nullptr;
Local<Object> obj; Local<Object> obj;
@ -5164,12 +5166,15 @@ void PBKDF2(const FunctionCallbackInfo<Value>& args) {
goto err; goto err;
} }
keylen = args[3]->NumberValue(); raw_keylen = args[3]->NumberValue();
if (keylen < 0 || isnan(keylen) || isinf(keylen)) { if (raw_keylen < 0.0 || isnan(raw_keylen) || isinf(raw_keylen) ||
raw_keylen > INT_MAX) {
type_error = "Bad key length"; type_error = "Bad key length";
goto err; goto err;
} }
keylen = static_cast<int>(raw_keylen);
if (args[4]->IsString()) { if (args[4]->IsString()) {
node::Utf8Value digest_name(env->isolate(), args[4]); node::Utf8Value digest_name(env->isolate(), args[4]);
digest = EVP_get_digestbyname(*digest_name); digest = EVP_get_digestbyname(*digest_name);
@ -5192,7 +5197,7 @@ void PBKDF2(const FunctionCallbackInfo<Value>& args) {
saltlen, saltlen,
salt, salt,
iter, iter,
static_cast<ssize_t>(keylen)); keylen);
if (args[5]->IsFunction()) { if (args[5]->IsFunction()) {
obj->Set(env->ondone_string(), args[5]); obj->Set(env->ondone_string(), args[5]);

21
test/parallel/test-crypto-pbkdf2.js

@ -63,27 +63,24 @@ assert.throws(function() {
// Should not work with Infinity key length // Should not work with Infinity key length
assert.throws(function() { assert.throws(function() {
crypto.pbkdf2('password', 'salt', 1, Infinity, 'sha256', common.fail); crypto.pbkdf2('password', 'salt', 1, Infinity, 'sha256', common.fail);
}, function(err) { }, /Bad key length/);
return err instanceof Error && err.message === 'Bad key length';
});
// Should not work with negative Infinity key length // Should not work with negative Infinity key length
assert.throws(function() { assert.throws(function() {
crypto.pbkdf2('password', 'salt', 1, -Infinity, 'sha256', common.fail); crypto.pbkdf2('password', 'salt', 1, -Infinity, 'sha256', common.fail);
}, function(err) { }, /Bad key length/);
return err instanceof Error && err.message === 'Bad key length';
});
// Should not work with NaN key length // Should not work with NaN key length
assert.throws(function() { assert.throws(function() {
crypto.pbkdf2('password', 'salt', 1, NaN, 'sha256', common.fail); crypto.pbkdf2('password', 'salt', 1, NaN, 'sha256', common.fail);
}, function(err) { }, /Bad key length/);
return err instanceof Error && err.message === 'Bad key length';
});
// Should not work with negative key length // Should not work with negative key length
assert.throws(function() { assert.throws(function() {
crypto.pbkdf2('password', 'salt', 1, -1, 'sha256', common.fail); crypto.pbkdf2('password', 'salt', 1, -1, 'sha256', common.fail);
}, function(err) { }, /Bad key length/);
return err instanceof Error && err.message === '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/);

Loading…
Cancel
Save