Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

src,crypto: remove AllocatedBuffer from crypto_cipher.cc #40400

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
86 changes: 55 additions & 31 deletions src/crypto/crypto_cipher.cc
Expand Up @@ -12,6 +12,8 @@
namespace node {

using v8::Array;
using v8::ArrayBuffer;
using v8::BackingStore;
using v8::FunctionCallbackInfo;
using v8::FunctionTemplate;
using v8::HandleScope;
Expand Down Expand Up @@ -720,7 +722,7 @@ void CipherBase::SetAAD(const FunctionCallbackInfo<Value>& args) {
CipherBase::UpdateResult CipherBase::Update(
const char* data,
size_t len,
AllocatedBuffer* out) {
std::unique_ptr<BackingStore>* out) {
if (!ctx_ || len > INT_MAX)
return kErrorState;
MarkPopErrorOnReturn mark_pop_error_on_return;
Expand All @@ -747,15 +749,22 @@ CipherBase::UpdateResult CipherBase::Update(
return kErrorState;
}

*out = AllocatedBuffer::AllocateManaged(env(), buf_len);
{
NoArrayBufferZeroFillScope no_zero_fill_scope(env()->isolate_data());
*out = ArrayBuffer::NewBackingStore(env()->isolate(), buf_len);
}

int r = EVP_CipherUpdate(ctx_.get(),
reinterpret_cast<unsigned char*>(out->data()),
static_cast<unsigned char*>((*out)->Data()),
&buf_len,
reinterpret_cast<const unsigned char*>(data),
len);

CHECK_LE(static_cast<size_t>(buf_len), out->size());
out->Resize(buf_len);
CHECK_LE(static_cast<size_t>(buf_len), (*out)->ByteLength());
if (buf_len == 0)
*out = ArrayBuffer::NewBackingStore(env()->isolate(), 0);
else
*out = BackingStore::Reallocate(env()->isolate(), std::move(*out), buf_len);

// When in CCM mode, EVP_CipherUpdate will fail if the authentication tag is
// invalid. In that case, remember the error and throw in final().
Expand All @@ -770,7 +779,7 @@ void CipherBase::Update(const FunctionCallbackInfo<Value>& args) {
Decode<CipherBase>(args, [](CipherBase* cipher,
const FunctionCallbackInfo<Value>& args,
const char* data, size_t size) {
AllocatedBuffer out;
std::unique_ptr<BackingStore> out;
Environment* env = Environment::GetCurrent(args);

if (UNLIKELY(size > INT_MAX))
Expand All @@ -786,8 +795,9 @@ void CipherBase::Update(const FunctionCallbackInfo<Value>& args) {
return;
}

CHECK(out.data() != nullptr || out.size() == 0);
args.GetReturnValue().Set(out.ToBuffer().FromMaybe(Local<Value>()));
Local<ArrayBuffer> ab = ArrayBuffer::New(env->isolate(), std::move(out));
args.GetReturnValue().Set(
Buffer::New(env, ab, 0, ab->ByteLength()).FromMaybe(Local<Value>()));
});
}

Expand All @@ -806,36 +816,40 @@ void CipherBase::SetAutoPadding(const FunctionCallbackInfo<Value>& args) {
args.GetReturnValue().Set(b); // Possibly report invalid state failure
}

bool CipherBase::Final(AllocatedBuffer* out) {
bool CipherBase::Final(std::unique_ptr<BackingStore>* out) {
if (!ctx_)
return false;

const int mode = EVP_CIPHER_CTX_mode(ctx_.get());

*out = AllocatedBuffer::AllocateManaged(
env(),
static_cast<size_t>(EVP_CIPHER_CTX_block_size(ctx_.get())));
{
NoArrayBufferZeroFillScope no_zero_fill_scope(env()->isolate_data());
*out = ArrayBuffer::NewBackingStore(env()->isolate(),
static_cast<size_t>(EVP_CIPHER_CTX_block_size(ctx_.get())));
}

if (kind_ == kDecipher && IsSupportedAuthenticatedMode(ctx_.get())) {
if (kind_ == kDecipher && IsSupportedAuthenticatedMode(ctx_.get()))
MaybePassAuthTagToOpenSSL();
}

// In CCM mode, final() only checks whether authentication failed in update().
// EVP_CipherFinal_ex must not be called and will fail.
bool ok;
if (kind_ == kDecipher && mode == EVP_CIPH_CCM_MODE) {
ok = !pending_auth_failed_;
*out = AllocatedBuffer::AllocateManaged(env(), 0); // Empty buffer.
*out = ArrayBuffer::NewBackingStore(env()->isolate(), 0);
} else {
int out_len = out->size();
int out_len = (*out)->ByteLength();
ok = EVP_CipherFinal_ex(ctx_.get(),
reinterpret_cast<unsigned char*>(out->data()),
static_cast<unsigned char*>((*out)->Data()),
&out_len) == 1;

if (out_len >= 0)
out->Resize(out_len);
else
*out = AllocatedBuffer(); // *out will not be used.
CHECK_LE(static_cast<size_t>(out_len), (*out)->ByteLength());
if (out_len > 0) {
*out =
BackingStore::Reallocate(env()->isolate(), std::move(*out), out_len);
} else {
*out = ArrayBuffer::NewBackingStore(env()->isolate(), 0);
}

if (ok && kind_ == kCipher && IsAuthenticatedMode()) {
// In GCM mode, the authentication tag length can be specified in advance,
Expand Down Expand Up @@ -864,7 +878,7 @@ void CipherBase::Final(const FunctionCallbackInfo<Value>& args) {
if (cipher->ctx_ == nullptr)
return THROW_ERR_CRYPTO_INVALID_STATE(env);

AllocatedBuffer out;
std::unique_ptr<BackingStore> out;

// Check IsAuthenticatedMode() first, Final() destroys the EVP_CIPHER_CTX.
const bool is_auth_mode = cipher->IsAuthenticatedMode();
Expand All @@ -878,7 +892,9 @@ void CipherBase::Final(const FunctionCallbackInfo<Value>& args) {
return ThrowCryptoError(env, ERR_get_error(), msg);
}

args.GetReturnValue().Set(out.ToBuffer().FromMaybe(Local<Value>()));
Local<ArrayBuffer> ab = ArrayBuffer::New(env->isolate(), std::move(out));
args.GetReturnValue().Set(
Buffer::New(env, ab, 0, ab->ByteLength()).FromMaybe(Local<Value>()));
}

template <PublicKeyCipher::Operation operation,
Expand All @@ -891,7 +907,7 @@ bool PublicKeyCipher::Cipher(
const EVP_MD* digest,
const ArrayBufferOrViewContents<unsigned char>& oaep_label,
const ArrayBufferOrViewContents<unsigned char>& data,
AllocatedBuffer* out) {
std::unique_ptr<BackingStore>* out) {
EVPKeyCtxPointer ctx(EVP_PKEY_CTX_new(pkey.get(), nullptr));
if (!ctx)
return false;
Expand Down Expand Up @@ -927,18 +943,26 @@ bool PublicKeyCipher::Cipher(
return false;
}

*out = AllocatedBuffer::AllocateManaged(env, out_len);
{
NoArrayBufferZeroFillScope no_zero_fill_scope(env->isolate_data());
*out = ArrayBuffer::NewBackingStore(env->isolate(), out_len);
}

if (EVP_PKEY_cipher(
ctx.get(),
reinterpret_cast<unsigned char*>(out->data()),
static_cast<unsigned char*>((*out)->Data()),
&out_len,
data.data(),
data.size()) <= 0) {
return false;
}

out->Resize(out_len);
CHECK_LE(out_len, (*out)->ByteLength());
if (out_len > 0)
*out = BackingStore::Reallocate(env->isolate(), std::move(*out), out_len);
else
*out = ArrayBuffer::NewBackingStore(env->isolate(), 0);

return true;
}

Expand Down Expand Up @@ -977,15 +1001,15 @@ void PublicKeyCipher::Cipher(const FunctionCallbackInfo<Value>& args) {
return THROW_ERR_OUT_OF_RANGE(env, "oaep_label is too big");
}

AllocatedBuffer out;
std::unique_ptr<BackingStore> out;
if (!Cipher<operation, EVP_PKEY_cipher_init, EVP_PKEY_cipher>(
env, pkey, padding, digest, oaep_label, buf, &out)) {
return ThrowCryptoError(env, ERR_get_error());
}

Local<Value> result;
if (out.ToBuffer().ToLocal(&result))
args.GetReturnValue().Set(result);
Local<ArrayBuffer> ab = ArrayBuffer::New(env->isolate(), std::move(out));
args.GetReturnValue().Set(
Buffer::New(env, ab, 0, ab->ByteLength()).FromMaybe(Local<Value>()));
}

} // namespace crypto
Expand Down
8 changes: 4 additions & 4 deletions src/crypto/crypto_cipher.h
Expand Up @@ -5,7 +5,6 @@

#include "crypto/crypto_keys.h"
#include "crypto/crypto_util.h"
#include "allocated_buffer-inl.h"
#include "base_object.h"
#include "env.h"
#include "memory_tracker.h"
Expand Down Expand Up @@ -60,8 +59,9 @@ class CipherBase : public BaseObject {
bool InitAuthenticated(const char* cipher_type, int iv_len,
unsigned int auth_tag_len);
bool CheckCCMMessageLength(int message_len);
UpdateResult Update(const char* data, size_t len, AllocatedBuffer* out);
bool Final(AllocatedBuffer* out);
UpdateResult Update(const char* data, size_t len,
std::unique_ptr<v8::BackingStore>* out);
bool Final(std::unique_ptr<v8::BackingStore>* out);
bool SetAutoPadding(bool auto_padding);

bool IsAuthenticatedMode() const;
Expand Down Expand Up @@ -114,7 +114,7 @@ class PublicKeyCipher {
const EVP_MD* digest,
const ArrayBufferOrViewContents<unsigned char>& oaep_label,
const ArrayBufferOrViewContents<unsigned char>& data,
AllocatedBuffer* out);
std::unique_ptr<v8::BackingStore>* out);

template <Operation operation,
EVP_PKEY_cipher_init_t EVP_PKEY_cipher_init,
Expand Down