From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shelley Vohr <shelley.vohr@gmail.com>
Date: Wed, 12 Feb 2020 15:08:04 -0800
Subject: fix: handle BoringSSL and OpenSSL incompatibilities

This patch corrects for imcompatibilities between OpenSSL, which Node.js uses,
and BoringSSL which Electron uses via Chromium. Each incompatibility typically has
~2 paths forward:
* Upstream a shim or adapted implementation to BoringSSL
* Alter Node.js functionality to something which both libraries can handle.

Where possible, we should seek to make this patch as minimal as possible.

Upstreams:
- https://github.com/nodejs/node/pull/39054
- https://github.com/nodejs/node/pull/39138
- https://github.com/nodejs/node/pull/39136

diff --git a/src/crypto/crypto_cipher.cc b/src/crypto/crypto_cipher.cc
index 99a16a667baa20138715b0901e3255e41f5f1052..a7f210031085a348f752e7e7e963d2f040bc2000 100644
--- a/src/crypto/crypto_cipher.cc
+++ b/src/crypto/crypto_cipher.cc
@@ -28,7 +28,8 @@ using v8::Value;
 namespace crypto {
 namespace {
 bool IsSupportedAuthenticatedMode(const EVP_CIPHER* cipher) {
-  switch (EVP_CIPHER_mode(cipher)) {
+  const int mode = EVP_CIPHER_mode(cipher);
+  switch (mode) {
   case EVP_CIPH_CCM_MODE:
   case EVP_CIPH_GCM_MODE:
 #ifndef OPENSSL_NO_OCB
@@ -1062,7 +1063,7 @@ void PublicKeyCipher::Cipher(const FunctionCallbackInfo<Value>& args) {
     if (EVP_PKEY_decrypt_init(ctx.get()) <= 0) {
       return ThrowCryptoError(env, ERR_get_error());
     }
-
+#ifndef OPENSSL_IS_BORINGSSL
     int rsa_pkcs1_implicit_rejection =
         EVP_PKEY_CTX_ctrl_str(ctx.get(), "rsa_pkcs1_implicit_rejection", "1");
     // From the doc -2 means that the option is not supported.
@@ -1078,6 +1079,7 @@ void PublicKeyCipher::Cipher(const FunctionCallbackInfo<Value>& args) {
           "RSA_PKCS1_PADDING is no longer supported for private decryption,"
           " this can be reverted with --security-revert=CVE-2023-46809");
     }
+#endif
   }
 
   const EVP_MD* digest = nullptr;
diff --git a/src/crypto/crypto_common.cc b/src/crypto/crypto_common.cc
index c6120a655ec853aef11c66ed37d7ca0ffb957dd3..a52ca15cb0ab592d4196d4bd0f1133240967d70c 100644
--- a/src/crypto/crypto_common.cc
+++ b/src/crypto/crypto_common.cc
@@ -158,7 +158,7 @@ const char* GetClientHelloALPN(const SSLPointer& ssl) {
   const unsigned char* buf;
   size_t len;
   size_t rem;
-
+#ifndef OPENSSL_IS_BORINGSSL
   if (!SSL_client_hello_get0_ext(
           ssl.get(),
           TLSEXT_TYPE_application_layer_protocol_negotiation,
@@ -171,13 +171,15 @@ const char* GetClientHelloALPN(const SSLPointer& ssl) {
   len = (buf[0] << 8) | buf[1];
   if (len + 2 != rem) return nullptr;
   return reinterpret_cast<const char*>(buf + 3);
+#endif
+  return nullptr;
 }
 
 const char* GetClientHelloServerName(const SSLPointer& ssl) {
   const unsigned char* buf;
   size_t len;
   size_t rem;
-
+#ifndef OPENSSL_IS_BORINGSSL
   if (!SSL_client_hello_get0_ext(
           ssl.get(),
           TLSEXT_TYPE_server_name,
@@ -199,15 +201,20 @@ const char* GetClientHelloServerName(const SSLPointer& ssl) {
   if (len + 2 > rem)
     return nullptr;
   return reinterpret_cast<const char*>(buf + 5);
+#endif
+  return nullptr;
 }
 
 const char* GetServerName(SSL* ssl) {
   return SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
 }
 
-bool SetGroups(SecureContext* sc, const char* groups) {
-  return SSL_CTX_set1_groups_list(sc->ctx().get(), groups) == 1;
-}
+ bool SetGroups(SecureContext* sc, const char* groups) {
+#ifndef OPENSSL_IS_BORINGSSL
+   return SSL_CTX_set1_groups_list(sc->ctx().get(), groups) == 1;
+#endif
+  return SSL_CTX_set1_curves_list(sc->ctx().get(), groups) == 1;
+ }
 
 const char* X509ErrorCode(long err) {  // NOLINT(runtime/int)
   const char* code = "UNSPECIFIED";
@@ -1044,14 +1051,14 @@ MaybeLocal<Array> GetClientHelloCiphers(
     Environment* env,
     const SSLPointer& ssl) {
   EscapableHandleScope scope(env->isolate());
-  const unsigned char* buf;
-  size_t len = SSL_client_hello_get0_ciphers(ssl.get(), &buf);
+  // const unsigned char* buf = nullptr;
+  size_t len = 0; // SSL_client_hello_get0_ciphers(ssl.get(), &buf);
   size_t count = len / 2;
   MaybeStackBuffer<Local<Value>, 16> ciphers(count);
   int j = 0;
   for (size_t n = 0; n < len; n += 2) {
-    const SSL_CIPHER* cipher = SSL_CIPHER_find(ssl.get(), buf);
-    buf += 2;
+    const SSL_CIPHER* cipher = nullptr; // SSL_CIPHER_find(ssl.get(), buf);
+    // buf += 2;
     Local<Object> obj = Object::New(env->isolate());
     if (!Set(env->context(),
              obj,
diff --git a/src/crypto/crypto_context.cc b/src/crypto/crypto_context.cc
index 6e5bbe07d0c337b36f3157c2e6404fdc91849fd1..7ec682833213de9054a8c30751436d12baaea235 100644
--- a/src/crypto/crypto_context.cc
+++ b/src/crypto/crypto_context.cc
@@ -63,7 +63,7 @@ inline X509_STORE* GetOrCreateRootCertStore() {
 // Caller responsible for BIO_free_all-ing the returned object.
 BIOPointer LoadBIO(Environment* env, Local<Value> v) {
   if (v->IsString() || v->IsArrayBufferView()) {
-    BIOPointer bio(BIO_new(BIO_s_secmem()));
+    BIOPointer bio(BIO_new(BIO_s_mem()));
     if (!bio) return nullptr;
     ByteSource bsrc = ByteSource::FromStringOrBuffer(env, v);
     if (bsrc.size() > INT_MAX) return nullptr;
@@ -861,10 +861,12 @@ void SecureContext::SetDHParam(const FunctionCallbackInfo<Value>& args) {
   // If the user specified "auto" for dhparams, the JavaScript layer will pass
   // true to this function instead of the original string. Any other string
   // value will be interpreted as custom DH parameters below.
+#ifndef OPENSSL_IS_BORINGSSL
   if (args[0]->IsTrue()) {
     CHECK(SSL_CTX_set_dh_auto(sc->ctx_.get(), true));
     return;
   }
+#endif
 
   DHPointer dh;
   {
diff --git a/src/crypto/crypto_dh.cc b/src/crypto/crypto_dh.cc
index 408d6be2a9cfdbcb52af285204c07c40bf74a5a9..9c3244a14bc286d60805bac5719df6595d802768 100644
--- a/src/crypto/crypto_dh.cc
+++ b/src/crypto/crypto_dh.cc
@@ -153,13 +153,11 @@ bool DiffieHellman::Init(BignumPointer&& bn_p, int g) {
 bool DiffieHellman::Init(const char* p, int p_len, int g) {
   dh_.reset(DH_new());
   if (p_len <= 0) {
-    ERR_put_error(ERR_LIB_BN, BN_F_BN_GENERATE_PRIME_EX,
-      BN_R_BITS_TOO_SMALL, __FILE__, __LINE__);
+    OPENSSL_PUT_ERROR(BN, BN_R_BITS_TOO_SMALL);
     return false;
   }
   if (g <= 1) {
-    ERR_put_error(ERR_LIB_DH, DH_F_DH_BUILTIN_GENPARAMS,
-      DH_R_BAD_GENERATOR, __FILE__, __LINE__);
+    OPENSSL_PUT_ERROR(DH, DH_R_BAD_GENERATOR);
     return false;
   }
   BIGNUM* bn_p =
@@ -177,21 +175,18 @@ bool DiffieHellman::Init(const char* p, int p_len, int g) {
 bool DiffieHellman::Init(const char* p, int p_len, const char* g, int g_len) {
   dh_.reset(DH_new());
   if (p_len <= 0) {
-    ERR_put_error(ERR_LIB_BN, BN_F_BN_GENERATE_PRIME_EX,
-      BN_R_BITS_TOO_SMALL, __FILE__, __LINE__);
+    OPENSSL_PUT_ERROR(BN, BN_R_BITS_TOO_SMALL);
     return false;
   }
   if (g_len <= 0) {
-    ERR_put_error(ERR_LIB_DH, DH_F_DH_BUILTIN_GENPARAMS,
-      DH_R_BAD_GENERATOR, __FILE__, __LINE__);
+    OPENSSL_PUT_ERROR(DH, DH_R_BAD_GENERATOR);
     return false;
   }
   BIGNUM* bn_g =
       BN_bin2bn(reinterpret_cast<const unsigned char*>(g), g_len, nullptr);
   if (BN_is_zero(bn_g) || BN_is_one(bn_g)) {
     BN_free(bn_g);
-    ERR_put_error(ERR_LIB_DH, DH_F_DH_BUILTIN_GENPARAMS,
-      DH_R_BAD_GENERATOR, __FILE__, __LINE__);
+    OPENSSL_PUT_ERROR(DH, DH_R_BAD_GENERATOR);
     return false;
   }
   BIGNUM* bn_p =
@@ -218,8 +213,10 @@ typedef BignumPointer (*StandardizedGroupInstantiator)();
 inline StandardizedGroupInstantiator FindDiffieHellmanGroup(const char* name) {
 #define V(n, p)                                                                \
   if (StringEqualNoCase(name, n)) return InstantiateStandardizedGroup<p>
+#ifndef OPENSSL_IS_BORINGSSL
   V("modp1", BN_get_rfc2409_prime_768);
   V("modp2", BN_get_rfc2409_prime_1024);
+#endif
   V("modp5", BN_get_rfc3526_prime_1536);
   V("modp14", BN_get_rfc3526_prime_2048);
   V("modp15", BN_get_rfc3526_prime_3072);
@@ -558,15 +555,20 @@ EVPKeyCtxPointer DhKeyGenTraits::Setup(DhKeyPairGenConfig* params) {
       return EVPKeyCtxPointer();
     }
 
+#ifndef OPENSSL_IS_BORINGSSL
     prime_fixed_value->release();
     bn_g.release();
 
     key_params = EVPKeyPointer(EVP_PKEY_new());
     CHECK(key_params);
     CHECK_EQ(EVP_PKEY_assign_DH(key_params.get(), dh.release()), 1);
+#else
+    return EVPKeyCtxPointer();
+#endif
   } else if (int* prime_size = std::get_if<int>(&params->params.prime)) {
     EVPKeyCtxPointer param_ctx(EVP_PKEY_CTX_new_id(EVP_PKEY_DH, nullptr));
     EVP_PKEY* raw_params = nullptr;
+#ifndef OPENSSL_IS_BORINGSSL
     if (!param_ctx ||
         EVP_PKEY_paramgen_init(param_ctx.get()) <= 0 ||
         EVP_PKEY_CTX_set_dh_paramgen_prime_len(
@@ -580,6 +582,9 @@ EVPKeyCtxPointer DhKeyGenTraits::Setup(DhKeyPairGenConfig* params) {
     }
 
     key_params = EVPKeyPointer(raw_params);
+#else
+    return EVPKeyCtxPointer();
+#endif
   } else {
     UNREACHABLE();
   }
diff --git a/src/crypto/crypto_dsa.cc b/src/crypto/crypto_dsa.cc
index 3fa4a415dc911a13afd90dfb31c1ed4ad0fd268f..fa48dffc31342c44a1c1207b9d4c3dc72ed93b60 100644
--- a/src/crypto/crypto_dsa.cc
+++ b/src/crypto/crypto_dsa.cc
@@ -40,7 +40,7 @@ namespace crypto {
 EVPKeyCtxPointer DsaKeyGenTraits::Setup(DsaKeyPairGenConfig* params) {
   EVPKeyCtxPointer param_ctx(EVP_PKEY_CTX_new_id(EVP_PKEY_DSA, nullptr));
   EVP_PKEY* raw_params = nullptr;
-
+#ifndef OPENSSL_IS_BORINGSSL
   if (!param_ctx ||
       EVP_PKEY_paramgen_init(param_ctx.get()) <= 0 ||
       EVP_PKEY_CTX_set_dsa_paramgen_bits(
@@ -55,7 +55,9 @@ EVPKeyCtxPointer DsaKeyGenTraits::Setup(DsaKeyPairGenConfig* params) {
       return EVPKeyCtxPointer();
     }
   }
-
+#else
+  return EVPKeyCtxPointer();
+#endif
   if (EVP_PKEY_paramgen(param_ctx.get(), &raw_params) <= 0)
     return EVPKeyCtxPointer();
 
diff --git a/src/crypto/crypto_keys.cc b/src/crypto/crypto_keys.cc
index c5dd2fb8fce40f2bf6f9a8543047ffb50cc08084..d850af9257cc194ee385130ce3cd2c0101b2455f 100644
--- a/src/crypto/crypto_keys.cc
+++ b/src/crypto/crypto_keys.cc
@@ -1241,6 +1241,7 @@ void KeyObjectHandle::GetAsymmetricKeyType(
 }
 
 bool KeyObjectHandle::CheckEcKeyData() const {
+#ifndef OPENSSL_IS_BORINGSSL
   MarkPopErrorOnReturn mark_pop_error_on_return;
 
   const ManagedEVPPKey& key = data_->GetAsymmetricKey();
@@ -1259,6 +1260,9 @@ bool KeyObjectHandle::CheckEcKeyData() const {
 #else
   return EVP_PKEY_public_check(ctx.get()) == 1;
 #endif
+#else
+  return true;
+#endif
 }
 
 void KeyObjectHandle::CheckEcKeyData(const FunctionCallbackInfo<Value>& args) {
diff --git a/src/crypto/crypto_random.cc b/src/crypto/crypto_random.cc
index 48154df7dc91ed7c0d65323199bc2f59dfc68135..6431e5c3062890975854780d15ecb84370b81770 100644
--- a/src/crypto/crypto_random.cc
+++ b/src/crypto/crypto_random.cc
@@ -140,7 +140,7 @@ Maybe<bool> RandomPrimeTraits::AdditionalConfig(
 
   params->bits = bits;
   params->safe = safe;
-  params->prime.reset(BN_secure_new());
+  params->prime.reset(BN_new());
   if (!params->prime) {
     THROW_ERR_CRYPTO_OPERATION_FAILED(env, "could not generate prime");
     return Nothing<bool>();
diff --git a/src/crypto/crypto_rsa.cc b/src/crypto/crypto_rsa.cc
index f222ab9cf5ccbc5dd3399b18d7688efda6672c93..349abd4d06e7f624a071b994271dedc31dc9229a 100644
--- a/src/crypto/crypto_rsa.cc
+++ b/src/crypto/crypto_rsa.cc
@@ -616,10 +616,11 @@ Maybe<bool> GetRsaKeyDetail(
       }
 
       if (params->saltLength != nullptr) {
-        if (ASN1_INTEGER_get_int64(&salt_length, params->saltLength) != 1) {
-          ThrowCryptoError(env, ERR_get_error(), "ASN1_INTEGER_get_in64 error");
-          return Nothing<bool>();
-        }
+        // TODO(codebytere): Upstream a shim to BoringSSL?
+        // if (ASN1_INTEGER_get_int64(&salt_length, params->saltLength) != 1) {
+        //   ThrowCryptoError(env, ERR_get_error(), "ASN1_INTEGER_get_in64 error");
+        //   return Nothing<bool>();
+        // }
       }
 
       if (target
diff --git a/src/crypto/crypto_util.cc b/src/crypto/crypto_util.cc
index 5734d8fdc5505e1586f571c19b840bd56e9c9f1f..3034b114e081e2b32dd5b71653927a41af7d48df 100644
--- a/src/crypto/crypto_util.cc
+++ b/src/crypto/crypto_util.cc
@@ -517,24 +517,15 @@ Maybe<bool> Decorate(Environment* env, Local<Object> obj,
     V(BIO)                                                                    \
     V(PKCS7)                                                                  \
     V(X509V3)                                                                 \
-    V(PKCS12)                                                                 \
     V(RAND)                                                                   \
-    V(DSO)                                                                    \
     V(ENGINE)                                                                 \
     V(OCSP)                                                                   \
     V(UI)                                                                     \
     V(COMP)                                                                   \
     V(ECDSA)                                                                  \
     V(ECDH)                                                                   \
-    V(OSSL_STORE)                                                             \
-    V(FIPS)                                                                   \
-    V(CMS)                                                                    \
-    V(TS)                                                                     \
     V(HMAC)                                                                   \
-    V(CT)                                                                     \
-    V(ASYNC)                                                                  \
-    V(KDF)                                                                    \
-    V(SM2)                                                                    \
+    V(HKDF)                                                                    \
     V(USER)                                                                   \
 
 #define V(name) case ERR_LIB_##name: lib = #name "_"; break;
@@ -715,7 +706,7 @@ void SecureBuffer(const FunctionCallbackInfo<Value>& args) {
   CHECK(args[0]->IsUint32());
   Environment* env = Environment::GetCurrent(args);
   uint32_t len = args[0].As<Uint32>()->Value();
-  void* data = OPENSSL_secure_zalloc(len);
+  void* data = OPENSSL_malloc(len);
   if (data == nullptr) {
     // There's no memory available for the allocation.
     // Return nothing.
@@ -726,7 +717,7 @@ void SecureBuffer(const FunctionCallbackInfo<Value>& args) {
           data,
           len,
           [](void* data, size_t len, void* deleter_data) {
-            OPENSSL_secure_clear_free(data, len);
+            OPENSSL_clear_free(data, len);
           },
           data);
   Local<ArrayBuffer> buffer = ArrayBuffer::New(env->isolate(), store);
@@ -734,10 +725,12 @@ void SecureBuffer(const FunctionCallbackInfo<Value>& args) {
 }
 
 void SecureHeapUsed(const FunctionCallbackInfo<Value>& args) {
+#ifndef OPENSSL_IS_BORINGSSL
   Environment* env = Environment::GetCurrent(args);
   if (CRYPTO_secure_malloc_initialized())
     args.GetReturnValue().Set(
         BigInt::New(env->isolate(), CRYPTO_secure_used()));
+#endif
 }
 }  // namespace
 
diff --git a/src/node.cc b/src/node.cc
index 524f80ee69ee5248e045a2b61faf5610c9ba4285..1d77a8b31cb0bfbeeeac594b6e1ac7dd303c902d 100644
--- a/src/node.cc
+++ b/src/node.cc
@@ -1027,7 +1027,8 @@ InitializeOncePerProcessInternal(const std::vector<std::string>& args,
   }
 
   if (!(flags & ProcessInitializationFlags::kNoInitOpenSSL)) {
-#if HAVE_OPENSSL && !defined(OPENSSL_IS_BORINGSSL)
+#if HAVE_OPENSSL
+#if !defined(OPENSSL_IS_BORINGSSL)
     auto GetOpenSSLErrorString = []() -> std::string {
       std::string ret;
       ERR_print_errors_cb(
@@ -1127,13 +1128,13 @@ InitializeOncePerProcessInternal(const std::vector<std::string>& args,
       CHECK(crypto::CSPRNG(buffer, length).is_ok());
       return true;
     });
-
+#endif // !defined(OPENSSL_IS_BORINGSSL)
     {
       std::string extra_ca_certs;
       if (credentials::SafeGetenv("NODE_EXTRA_CA_CERTS", &extra_ca_certs))
         crypto::UseExtraCaCerts(extra_ca_certs);
     }
-#endif  // HAVE_OPENSSL && !defined(OPENSSL_IS_BORINGSSL)
+#endif  // HAVE_OPENSSL
   }
 
   if (!(flags & ProcessInitializationFlags::kNoInitializeNodeV8Platform)) {
diff --git a/src/node_metadata.cc b/src/node_metadata.cc
index b88cfb98e75aca426224e19376b3ff4c23b92e53..b66f4e2b5cbd8f36af42f82a8921207302360e39 100644
--- a/src/node_metadata.cc
+++ b/src/node_metadata.cc
@@ -16,7 +16,7 @@
 #include "v8.h"
 #include "zlib_version.h"
 
-#if HAVE_OPENSSL
+#if HAVE_OPENSSL && !defined(OPENSSL_IS_BORINGSSL)
 #include <openssl/opensslv.h>
 #if NODE_OPENSSL_HAS_QUIC
 #include <openssl/quic.h>
diff --git a/src/node_metadata.h b/src/node_metadata.h
index cf051585e779e2b03bd7b95fe5008b89cc7f8162..9de49c6828468fdf846dcd4ad445390f14446099 100644
--- a/src/node_metadata.h
+++ b/src/node_metadata.h
@@ -6,7 +6,7 @@
 #include <string>
 #include "node_version.h"
 
-#if HAVE_OPENSSL
+#if 0
 #include <openssl/crypto.h>
 #if NODE_OPENSSL_HAS_QUIC
 #include <openssl/quic.h>
diff --git a/src/node_options.cc b/src/node_options.cc
index 5da6918af8c125259a89ce95bbbbc4fc475c4c69..a3d25cdd52f18e319ae3ac81437c8a0206b18690 100644
--- a/src/node_options.cc
+++ b/src/node_options.cc
@@ -6,7 +6,7 @@
 #include "node_external_reference.h"
 #include "node_internals.h"
 #include "node_sea.h"
-#if HAVE_OPENSSL
+#if HAVE_OPENSSL && !defined(OPENSSL_IS_BORINGSSL)
 #include "openssl/opensslv.h"
 #endif
 
diff --git a/src/node_options.h b/src/node_options.h
index 312fae8f759c5828d0770ceee845dc4754871436..207468a2177d36894c64cb37aac946af02c82549 100644
--- a/src/node_options.h
+++ b/src/node_options.h
@@ -11,7 +11,7 @@
 #include "node_mutex.h"
 #include "util.h"
 
-#if HAVE_OPENSSL
+#if 0
 #include "openssl/opensslv.h"
 #endif
 
