Skip to content

Commit 8e51d31

Browse files
bnoordhuisaddaleax
authored andcommitted
src: avoid heap allocation in hmac.digest()
Add a test that ensures the second call to .digest() returns an empty HMAC, like it did before. No comment on whether that is the right behavior or not. PR-URL: #14122 Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: James M Snell <[email protected]>
1 parent 8be9bd1 commit 8e51d31

File tree

3 files changed

+40
-18
lines changed

3 files changed

+40
-18
lines changed

src/node_crypto.cc

+5-17
Original file line numberDiff line numberDiff line change
@@ -3767,17 +3767,6 @@ void Hmac::HmacUpdate(const FunctionCallbackInfo<Value>& args) {
37673767
}
37683768

37693769

3770-
bool Hmac::HmacDigest(unsigned char** md_value, unsigned int* md_len) {
3771-
if (!initialised_)
3772-
return false;
3773-
*md_value = new unsigned char[EVP_MAX_MD_SIZE];
3774-
HMAC_Final(&ctx_, *md_value, md_len);
3775-
HMAC_CTX_cleanup(&ctx_);
3776-
initialised_ = false;
3777-
return true;
3778-
}
3779-
3780-
37813770
void Hmac::HmacDigest(const FunctionCallbackInfo<Value>& args) {
37823771
Environment* env = Environment::GetCurrent(args);
37833772

@@ -3794,13 +3783,13 @@ void Hmac::HmacDigest(const FunctionCallbackInfo<Value>& args) {
37943783
return env->ThrowError("hmac.digest() does not support UTF-16");
37953784
}
37963785

3797-
unsigned char* md_value = nullptr;
3786+
unsigned char md_value[EVP_MAX_MD_SIZE];
37983787
unsigned int md_len = 0;
37993788

3800-
bool r = hmac->HmacDigest(&md_value, &md_len);
3801-
if (!r) {
3802-
md_value = nullptr;
3803-
md_len = 0;
3789+
if (hmac->initialised_) {
3790+
HMAC_Final(&hmac->ctx_, md_value, &md_len);
3791+
HMAC_CTX_cleanup(&hmac->ctx_);
3792+
hmac->initialised_ = false;
38043793
}
38053794

38063795
Local<Value> error;
@@ -3810,7 +3799,6 @@ void Hmac::HmacDigest(const FunctionCallbackInfo<Value>& args) {
38103799
md_len,
38113800
encoding,
38123801
&error);
3813-
delete[] md_value;
38143802
if (rc.IsEmpty()) {
38153803
CHECK(!error.IsEmpty());
38163804
env->isolate()->ThrowException(error);

src/node_crypto.h

-1
Original file line numberDiff line numberDiff line change
@@ -494,7 +494,6 @@ class Hmac : public BaseObject {
494494
protected:
495495
void HmacInit(const char* hash_type, const char* key, int key_len);
496496
bool HmacUpdate(const char* data, int len);
497-
bool HmacDigest(unsigned char** md_value, unsigned int* md_len);
498497

499498
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
500499
static void HmacInit(const v8::FunctionCallbackInfo<v8::Value>& args);

test/parallel/test-crypto-hmac.js

+35
Original file line numberDiff line numberDiff line change
@@ -379,3 +379,38 @@ for (let i = 0, l = rfc2202_sha1.length; i < l; i++) {
379379
assert.throws(function() {
380380
crypto.createHmac('sha256', 'w00t').digest('ucs2');
381381
}, /^Error: hmac\.digest\(\) does not support UTF-16$/);
382+
383+
// Check initialized -> uninitialized state transition after calling digest().
384+
{
385+
const expected =
386+
'\u0010\u0041\u0052\u00c5\u00bf\u00dc\u00a0\u007b\u00c6\u0033' +
387+
'\u00ee\u00bd\u0046\u0019\u009f\u0002\u0055\u00c9\u00f4\u009d';
388+
{
389+
const h = crypto.createHmac('sha1', 'key').update('data');
390+
assert.deepStrictEqual(h.digest('buffer'), Buffer.from(expected, 'latin1'));
391+
assert.deepStrictEqual(h.digest('buffer'), Buffer.from(''));
392+
}
393+
{
394+
const h = crypto.createHmac('sha1', 'key').update('data');
395+
assert.deepStrictEqual(h.digest('latin1'), expected);
396+
assert.deepStrictEqual(h.digest('latin1'), '');
397+
}
398+
}
399+
400+
// Check initialized -> uninitialized state transition after calling digest().
401+
// Calls to update() omitted intentionally.
402+
{
403+
const expected =
404+
'\u00f4\u002b\u00b0\u00ee\u00b0\u0018\u00eb\u00bd\u0045\u0097' +
405+
'\u00ae\u0072\u0013\u0071\u001e\u00c6\u0007\u0060\u0084\u003f';
406+
{
407+
const h = crypto.createHmac('sha1', 'key');
408+
assert.deepStrictEqual(h.digest('buffer'), Buffer.from(expected, 'latin1'));
409+
assert.deepStrictEqual(h.digest('buffer'), Buffer.from(''));
410+
}
411+
{
412+
const h = crypto.createHmac('sha1', 'key');
413+
assert.deepStrictEqual(h.digest('latin1'), expected);
414+
assert.deepStrictEqual(h.digest('latin1'), '');
415+
}
416+
}

0 commit comments

Comments
 (0)