diff --git a/node.gyp b/node.gyp index bd1006c48a17f2..6b554d75d89077 100644 --- a/node.gyp +++ b/node.gyp @@ -1275,6 +1275,7 @@ 'sources': [ 'test/cctest/test_crypto_clienthello.cc', 'test/cctest/test_node_crypto.cc', + 'test/cctest/test_node_crypto_env.cc', ] }], ['v8_enable_inspector==1', { diff --git a/src/crypto/crypto_context.cc b/src/crypto/crypto_context.cc index d4aa76d1d8c50e..838ee2a68dffc5 100644 --- a/src/crypto/crypto_context.cc +++ b/src/crypto/crypto_context.cc @@ -62,18 +62,16 @@ inline X509_STORE* GetOrCreateRootCertStore() { // Takes a string or buffer and loads it into a BIO. // Caller responsible for BIO_free_all-ing the returned object. BIOPointer LoadBIO(Environment* env, Local v) { - HandleScope scope(env->isolate()); - - if (v->IsString()) { - Utf8Value s(env->isolate(), v); - return NodeBIO::NewFixed(*s, s.length()); - } - - if (v->IsArrayBufferView()) { - ArrayBufferViewContents buf(v.As()); - return NodeBIO::NewFixed(buf.data(), buf.length()); + if (v->IsString() || v->IsArrayBufferView()) { + BIOPointer bio(BIO_new(BIO_s_secmem())); + if (!bio) return nullptr; + ByteSource bsrc = ByteSource::FromStringOrBuffer(env, v); + if (bsrc.size() > INT_MAX) return nullptr; + int written = BIO_write(bio.get(), bsrc.data(), bsrc.size()); + if (written < 0) return nullptr; + if (static_cast(written) != bsrc.size()) return nullptr; + return bio; } - return nullptr; } diff --git a/test/cctest/test_node_crypto_env.cc b/test/cctest/test_node_crypto_env.cc new file mode 100644 index 00000000000000..b42cdc107e8a94 --- /dev/null +++ b/test/cctest/test_node_crypto_env.cc @@ -0,0 +1,31 @@ +#include "crypto/crypto_bio.h" +#include "gtest/gtest.h" +#include "node_options.h" +#include "node_test_fixture.h" +#include "openssl/err.h" + +using v8::Local; +using v8::String; + +/* + * This test verifies that an object created by LoadBIO supports BIO_tell + * and BIO_seek, otherwise PEM_read_bio_PrivateKey fails on some keys + * (if OpenSSL needs to rewind pointer between pem_read_bio_key() + * and pem_read_bio_key_legacy() inside PEM_read_bio_PrivateKey). + */ +class NodeCryptoEnv : public EnvironmentTestFixture {}; + +TEST_F(NodeCryptoEnv, LoadBIO) { + v8::HandleScope handle_scope(isolate_); + Argv argv; + Env env{handle_scope, argv}; + // just put a random string into BIO + Local key = String::NewFromUtf8(isolate_, "abcdef").ToLocalChecked(); + node::crypto::BIOPointer bio(node::crypto::LoadBIO(*env, key)); +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + BIO_seek(bio.get(), 2); + ASSERT_EQ(BIO_tell(bio.get()), 2); +#endif + ASSERT_EQ(ERR_peek_error(), 0UL) << "There should not have left " + "any errors on the OpenSSL error stack\n"; +}