Skip to content

Commit 4749640

Browse files
tniessenMylesBorins
authored andcommitted
crypto: reduce memory usage of SignFinal
The fixed-size buffer on the stack is unnecessary and way too large for most applications. This change removes it and allocates the required memory directly instead of copying into heap later. PR-URL: #23427 Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Refael Ackermann <[email protected]>
1 parent ffb4087 commit 4749640

File tree

3 files changed

+50
-41
lines changed

3 files changed

+50
-41
lines changed

‎src/node_crypto.cc‎

Lines changed: 38 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343

4444
#include<algorithm>
4545
#include<memory>
46+
#include<utility>
4647
#include<vector>
4748

4849
staticconstint X509_NAME_FLAGS = ASN1_STRFLGS_ESC_CTRL
@@ -3530,46 +3531,51 @@ void Sign::SignUpdate(const FunctionCallbackInfo<Value>& args){
35303531
sign->CheckThrow(err);
35313532
}
35323533

3533-
staticintNode_SignFinal(EVPMDPointer&& mdctx, unsignedchar* md,
3534-
unsignedint* sig_len,
3535-
const EVPKeyPointer& pkey,int padding,
3536-
int pss_salt_len){
3534+
staticMallocedBuffer<unsignedchar> Node_SignFinal(EVPMDPointer&& mdctx,
3535+
const EVPKeyPointer& pkey,
3536+
int padding,
3537+
int pss_salt_len){
35373538
unsignedchar m[EVP_MAX_MD_SIZE];
35383539
unsignedint m_len;
35393540

3540-
*sig_len = 0;
35413541
if (!EVP_DigestFinal_ex(mdctx.get(), m, &m_len))
3542-
return0;
3542+
return MallocedBuffer<unsignedchar>();
3543+
3544+
int signed_sig_len = EVP_PKEY_size(pkey.get());
3545+
CHECK_GE(signed_sig_len, 0);
3546+
size_t sig_len = static_cast<size_t>(signed_sig_len);
3547+
MallocedBuffer<unsignedchar> sig(sig_len);
35433548

3544-
size_t sltmp = static_cast<size_t>(EVP_PKEY_size(pkey.get()));
35453549
EVPKeyCtxPointer pkctx(EVP_PKEY_CTX_new(pkey.get(), nullptr));
35463550
if (pkctx &&
35473551
EVP_PKEY_sign_init(pkctx.get()) > 0 &&
35483552
ApplyRSAOptions(pkey, pkctx.get(), padding, pss_salt_len) &&
35493553
EVP_PKEY_CTX_set_signature_md(pkctx.get(),
35503554
EVP_MD_CTX_md(mdctx.get())) > 0 &&
3551-
EVP_PKEY_sign(pkctx.get(), md, &sltmp, m, m_len) > 0){
3552-
*sig_len = sltmp;
3553-
return1;
3555+
EVP_PKEY_sign(pkctx.get(), sig.data, &sig_len, m, m_len) > 0){
3556+
sig.Truncate(sig_len);
3557+
returnsig;
35543558
}
3555-
return0;
3559+
3560+
return MallocedBuffer<unsignedchar>();
35563561
}
35573562

3558-
SignBase::Error Sign::SignFinal(constchar* key_pem,
3559-
int key_pem_len,
3560-
constchar* passphrase,
3561-
unsignedchar* sig,
3562-
unsignedint* sig_len,
3563-
int padding,
3564-
int salt_len){
3563+
std::pair<SignBase::Error, MallocedBuffer<unsignedchar>> Sign::SignFinal(
3564+
constchar* key_pem,
3565+
int key_pem_len,
3566+
constchar* passphrase,
3567+
int padding,
3568+
int salt_len){
3569+
MallocedBuffer<unsignedchar> buffer;
3570+
35653571
if (!mdctx_)
3566-
returnkSignNotInitialised;
3572+
returnstd::make_pair(kSignNotInitialised, std::move(buffer));
35673573

35683574
EVPMDPointer mdctx = std::move(mdctx_);
35693575

35703576
BIOPointer bp(BIO_new_mem_buf(const_cast<char*>(key_pem), key_pem_len));
35713577
if (!bp)
3572-
returnkSignPrivateKey;
3578+
returnstd::make_pair(kSignPrivateKey, std::move(buffer));
35733579

35743580
EVPKeyPointer pkey(PEM_read_bio_PrivateKey(bp.get(),
35753581
nullptr,
@@ -3580,7 +3586,7 @@ SignBase::Error Sign::SignFinal(const char* key_pem,
35803586
// without `pkey` being set to nullptr;
35813587
// cf. the test of `test_bad_rsa_privkey.pem` for an example.
35823588
if (!pkey || 0 != ERR_peek_error())
3583-
returnkSignPrivateKey;
3589+
returnstd::make_pair(kSignPrivateKey, std::move(buffer));
35843590

35853591
#ifdef NODE_FIPS_MODE
35863592
/* Validate DSA2 parameters from FIPS 186-4 */
@@ -3604,10 +3610,9 @@ SignBase::Error Sign::SignFinal(const char* key_pem,
36043610
}
36053611
#endif// NODE_FIPS_MODE
36063612

3607-
if (Node_SignFinal(std::move(mdctx), sig, sig_len, pkey, padding, salt_len))
3608-
returnkSignOk;
3609-
else
3610-
returnkSignPrivateKey;
3613+
buffer = Node_SignFinal(std::move(mdctx), pkey, padding, salt_len);
3614+
Error error = buffer.is_empty() ? kSignPrivateKey : kSignOk;
3615+
returnstd::make_pair(error, std::move(buffer));
36113616
}
36123617

36133618

@@ -3631,22 +3636,22 @@ void Sign::SignFinal(const FunctionCallbackInfo<Value>& args){
36313636
int salt_len = args[3].As<Int32>()->Value();
36323637

36333638
ClearErrorOnReturn clear_error_on_return;
3634-
unsignedchar md_value[8192];
3635-
unsignedint md_len = sizeof(md_value);
36363639

3637-
Error err = sign->SignFinal(
3640+
std::pair<Error, MallocedBuffer<unsignedchar>> ret = sign->SignFinal(
36383641
buf,
36393642
buf_len,
36403643
len >= 2 && !args[1]->IsNull() ? *passphrase : nullptr,
3641-
md_value,
3642-
&md_len,
36433644
padding,
36443645
salt_len);
3645-
if (err != kSignOk)
3646-
return sign->CheckThrow(err);
3646+
3647+
if (std::get<Error>(ret) != kSignOk)
3648+
return sign->CheckThrow(std::get<Error>(ret));
3649+
3650+
MallocedBuffer<unsignedchar> sig =
3651+
std::move(std::get<MallocedBuffer<unsignedchar>>(ret));
36473652

36483653
Local<Object> rc =
3649-
Buffer::Copy(env, reinterpret_cast<char*>(md_value), md_len)
3654+
Buffer::New(env, reinterpret_cast<char*>(sig.release()), sig.size)
36503655
.ToLocalChecked();
36513656
args.GetReturnValue().Set(rc);
36523657
}

‎src/node_crypto.h‎

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -518,13 +518,12 @@ class Sign : public SignBase{
518518
public:
519519
staticvoidInitialize(Environment* env, v8::Local<v8::Object> target);
520520

521-
Error SignFinal(constchar* key_pem,
522-
int key_pem_len,
523-
constchar* passphrase,
524-
unsignedchar* sig,
525-
unsignedint* sig_len,
526-
int padding,
527-
int saltlen);
521+
std::pair<Error, MallocedBuffer<unsignedchar>> SignFinal(
522+
constchar* key_pem,
523+
int key_pem_len,
524+
constchar* passphrase,
525+
int padding,
526+
int saltlen);
528527

529528
protected:
530529
staticvoidNew(const v8::FunctionCallbackInfo<v8::Value>& args);

‎src/util.h‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -439,9 +439,14 @@ struct MallocedBuffer{
439439
return ret;
440440
}
441441

442+
voidTruncate(size_t new_size){
443+
CHECK(new_size <= size);
444+
size = new_size;
445+
}
446+
442447
inlineboolis_empty() const{return data == nullptr}
443448

444-
MallocedBuffer() : data(nullptr){}
449+
MallocedBuffer() : data(nullptr), size(0){}
445450
explicitMallocedBuffer(size_t size) : data(Malloc<T>(size)), size(size){}
446451
MallocedBuffer(T* data, size_t size) : data(data), size(size){}
447452
MallocedBuffer(MallocedBuffer&& other) : data(other.data), size(other.size){

0 commit comments

Comments
(0)