From 294abc2ffcda213b544c345aaa60efd8c98df118 Mon Sep 17 00:00:00 2001
From: James M Snell <jasnell@gmail.com>
Date: Wed, 8 Jan 2025 17:01:14 -0800
Subject: [PATCH] src: update ECKeyPointer in ncrypto

PR-URL: https://github.com/nodejs/node/pull/56526
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
---
 deps/ncrypto/ncrypto.cc     | 120 ++++++++++++++++++++++++++++++++++++
 deps/ncrypto/ncrypto.h      |  52 +++++++++++++++-
 src/crypto/crypto_common.cc |   4 +-
 src/crypto/crypto_common.h  |   8 ---
 src/crypto/crypto_ec.cc     |  92 +++++++++++++--------------
 src/crypto/crypto_keys.cc   |  14 ++---
 src/crypto/crypto_sig.cc    |   5 +-
 src/crypto/crypto_x509.cc   |   5 +-
 8 files changed, 227 insertions(+), 73 deletions(-)

diff --git a/deps/ncrypto/ncrypto.cc b/deps/ncrypto/ncrypto.cc
index 5200fdb68ed8ac..fa0cf58062d897 100644
--- a/deps/ncrypto/ncrypto.cc
+++ b/deps/ncrypto/ncrypto.cc
@@ -1790,6 +1790,21 @@ BIOPointer EVPKeyPointer::derPublicKey() const {
   return bio;
 }
 
+bool EVPKeyPointer::assign(const ECKeyPointer& eckey) {
+  if (!pkey_ || !eckey) return {};
+  return EVP_PKEY_assign_EC_KEY(pkey_.get(), eckey.get());
+}
+
+bool EVPKeyPointer::set(const ECKeyPointer& eckey) {
+  if (!pkey_ || !eckey) return false;
+  return EVP_PKEY_set1_EC_KEY(pkey_.get(), eckey);
+}
+
+EVPKeyPointer::operator const EC_KEY*() const {
+  if (!pkey_) return nullptr;
+  return EVP_PKEY_get0_EC_KEY(pkey_.get());
+}
+
 namespace {
 EVPKeyPointer::ParseKeyResult TryParsePublicKeyInner(const BIOPointer& bp,
                                                      const char* name,
@@ -2749,4 +2764,109 @@ bool ECPointPointer::mul(const EC_GROUP* group, const BIGNUM* priv_key) {
   return EC_POINT_mul(group, point_.get(), priv_key, nullptr, nullptr, nullptr);
 }
 
+// ============================================================================
+
+ECKeyPointer::ECKeyPointer() : key_(nullptr) {}
+
+ECKeyPointer::ECKeyPointer(EC_KEY* key) : key_(key) {}
+
+ECKeyPointer::ECKeyPointer(ECKeyPointer&& other) noexcept
+    : key_(other.release()) {}
+
+ECKeyPointer& ECKeyPointer::operator=(ECKeyPointer&& other) noexcept {
+  key_.reset(other.release());
+  return *this;
+}
+
+ECKeyPointer::~ECKeyPointer() {
+  reset();
+}
+
+void ECKeyPointer::reset(EC_KEY* key) {
+  key_.reset(key);
+}
+
+EC_KEY* ECKeyPointer::release() {
+  return key_.release();
+}
+
+ECKeyPointer ECKeyPointer::clone() const {
+  if (!key_) return {};
+  return ECKeyPointer(EC_KEY_dup(key_.get()));
+}
+
+bool ECKeyPointer::generate() {
+  if (!key_) return false;
+  return EC_KEY_generate_key(key_.get());
+}
+
+bool ECKeyPointer::setPublicKey(const ECPointPointer& pub) {
+  if (!key_) return false;
+  return EC_KEY_set_public_key(key_.get(), pub.get()) == 1;
+}
+
+bool ECKeyPointer::setPublicKeyRaw(const BignumPointer& x,
+                                   const BignumPointer& y) {
+  if (!key_) return false;
+  return EC_KEY_set_public_key_affine_coordinates(
+             key_.get(), x.get(), y.get()) == 1;
+}
+
+bool ECKeyPointer::setPrivateKey(const BignumPointer& priv) {
+  if (!key_) return false;
+  return EC_KEY_set_private_key(key_.get(), priv.get()) == 1;
+}
+
+const BIGNUM* ECKeyPointer::getPrivateKey() const {
+  if (!key_) return nullptr;
+  return GetPrivateKey(key_.get());
+}
+
+const BIGNUM* ECKeyPointer::GetPrivateKey(const EC_KEY* key) {
+  return EC_KEY_get0_private_key(key);
+}
+
+const EC_POINT* ECKeyPointer::getPublicKey() const {
+  if (!key_) return nullptr;
+  return GetPublicKey(key_.get());
+}
+
+const EC_POINT* ECKeyPointer::GetPublicKey(const EC_KEY* key) {
+  return EC_KEY_get0_public_key(key);
+}
+
+const EC_GROUP* ECKeyPointer::getGroup() const {
+  if (!key_) return nullptr;
+  return GetGroup(key_.get());
+}
+
+const EC_GROUP* ECKeyPointer::GetGroup(const EC_KEY* key) {
+  return EC_KEY_get0_group(key);
+}
+
+int ECKeyPointer::GetGroupName(const EC_KEY* key) {
+  const EC_GROUP* group = GetGroup(key);
+  return group ? EC_GROUP_get_curve_name(group) : 0;
+}
+
+bool ECKeyPointer::Check(const EC_KEY* key) {
+  return EC_KEY_check_key(key) == 1;
+}
+
+bool ECKeyPointer::checkKey() const {
+  if (!key_) return false;
+  return Check(key_.get());
+}
+
+ECKeyPointer ECKeyPointer::NewByCurveName(int nid) {
+  return ECKeyPointer(EC_KEY_new_by_curve_name(nid));
+}
+
+ECKeyPointer ECKeyPointer::New(const EC_GROUP* group) {
+  auto ptr = ECKeyPointer(EC_KEY_new());
+  if (!ptr) return {};
+  if (!EC_KEY_set_group(ptr.get(), group)) return {};
+  return ptr;
+}
+
 }  // namespace ncrypto
diff --git a/deps/ncrypto/ncrypto.h b/deps/ncrypto/ncrypto.h
index bbff3ea1a0ec3d..e5bf2b529bf239 100644
--- a/deps/ncrypto/ncrypto.h
+++ b/deps/ncrypto/ncrypto.h
@@ -28,6 +28,12 @@
 #include <openssl/fips.h>
 #endif  // OPENSSL_FIPS
 
+#if OPENSSL_VERSION_MAJOR >= 3
+#define OSSL3_CONST const
+#else
+#define OSSL3_CONST
+#endif
+
 #ifdef __GNUC__
 #define NCRYPTO_MUST_USE_RESULT __attribute__((warn_unused_result))
 #else
@@ -197,7 +203,6 @@ using DeleteFnPtr = typename FunctionDeleter<T, function>::Pointer;
 
 using BignumCtxPointer = DeleteFnPtr<BN_CTX, BN_CTX_free>;
 using BignumGenCallbackPointer = DeleteFnPtr<BN_GENCB, BN_GENCB_free>;
-using ECKeyPointer = DeleteFnPtr<EC_KEY, EC_KEY_free>;
 using EVPKeyCtxPointer = DeleteFnPtr<EVP_PKEY_CTX, EVP_PKEY_CTX_free>;
 using EVPMDCtxPointer = DeleteFnPtr<EVP_MD_CTX, EVP_MD_CTX_free>;
 using HMACCtxPointer = DeleteFnPtr<HMAC_CTX, HMAC_CTX_free>;
@@ -207,6 +212,7 @@ using RSAPointer = DeleteFnPtr<RSA, RSA_free>;
 using SSLSessionPointer = DeleteFnPtr<SSL_SESSION, SSL_SESSION_free>;
 
 class CipherCtxPointer;
+class ECKeyPointer;
 
 struct StackOfXASN1Deleter {
   void operator()(STACK_OF(ASN1_OBJECT) * p) const {
@@ -537,6 +543,10 @@ class EVPKeyPointer final {
   NCRYPTO_DISALLOW_COPY(EVPKeyPointer)
   ~EVPKeyPointer();
 
+  bool assign(const ECKeyPointer& eckey);
+  bool set(const ECKeyPointer& eckey);
+  operator const EC_KEY*() const;
+
   inline bool operator==(std::nullptr_t) const noexcept {
     return pkey_ == nullptr;
   }
@@ -898,6 +908,46 @@ class ECPointPointer final {
   DeleteFnPtr<EC_POINT, EC_POINT_free> point_;
 };
 
+class ECKeyPointer final {
+ public:
+  ECKeyPointer();
+  explicit ECKeyPointer(EC_KEY* key);
+  ECKeyPointer(ECKeyPointer&& other) noexcept;
+  ECKeyPointer& operator=(ECKeyPointer&& other) noexcept;
+  NCRYPTO_DISALLOW_COPY(ECKeyPointer)
+  ~ECKeyPointer();
+
+  inline bool operator==(std::nullptr_t) noexcept { return key_ == nullptr; }
+  inline operator bool() const { return key_ != nullptr; }
+  inline EC_KEY* get() const { return key_.get(); }
+  inline operator EC_KEY*() const { return key_.get(); }
+  void reset(EC_KEY* key = nullptr);
+  EC_KEY* release();
+
+  ECKeyPointer clone() const;
+  bool setPrivateKey(const BignumPointer& priv);
+  bool setPublicKey(const ECPointPointer& pub);
+  bool setPublicKeyRaw(const BignumPointer& x, const BignumPointer& y);
+  bool generate();
+  bool checkKey() const;
+
+  const EC_GROUP* getGroup() const;
+  const BIGNUM* getPrivateKey() const;
+  const EC_POINT* getPublicKey() const;
+
+  static ECKeyPointer New(const EC_GROUP* group);
+  static ECKeyPointer NewByCurveName(int nid);
+
+  static const EC_POINT* GetPublicKey(const EC_KEY* key);
+  static const BIGNUM* GetPrivateKey(const EC_KEY* key);
+  static const EC_GROUP* GetGroup(const EC_KEY* key);
+  static int GetGroupName(const EC_KEY* key);
+  static bool Check(const EC_KEY* key);
+
+ private:
+  DeleteFnPtr<EC_KEY, EC_KEY_free> key_;
+};
+
 #ifndef OPENSSL_NO_ENGINE
 class EnginePointer final {
  public:
diff --git a/src/crypto/crypto_common.cc b/src/crypto/crypto_common.cc
index 568f2889fe88ad..d94f6e1c82c4a6 100644
--- a/src/crypto/crypto_common.cc
+++ b/src/crypto/crypto_common.cc
@@ -28,6 +28,7 @@
 namespace node {
 
 using ncrypto::ClearErrorOnReturn;
+using ncrypto::ECKeyPointer;
 using ncrypto::EVPKeyPointer;
 using ncrypto::SSLPointer;
 using ncrypto::SSLSessionPointer;
@@ -271,8 +272,7 @@ MaybeLocal<Object> GetEphemeralKey(Environment* env, const SSLPointer& ssl) {
       {
         const char* curve_name;
         if (kid == EVP_PKEY_EC) {
-          OSSL3_CONST EC_KEY* ec = EVP_PKEY_get0_EC_KEY(key.get());
-          int nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec));
+          int nid = ECKeyPointer::GetGroupName(key);
           curve_name = OBJ_nid2sn(nid);
         } else {
           curve_name = OBJ_nid2sn(kid);
diff --git a/src/crypto/crypto_common.h b/src/crypto/crypto_common.h
index e3a8ebecf3c4e9..dba1cc14b1c486 100644
--- a/src/crypto/crypto_common.h
+++ b/src/crypto/crypto_common.h
@@ -11,14 +11,6 @@
 
 #include <string>
 
-// Some OpenSSL 1.1.1 functions unnecessarily operate on and return non-const
-// pointers, whereas the same functions in OpenSSL 3 use const pointers.
-#if OPENSSL_VERSION_MAJOR >= 3
-#define OSSL3_CONST const
-#else
-#define OSSL3_CONST
-#endif
-
 namespace node {
 namespace crypto {
 
diff --git a/src/crypto/crypto_ec.cc b/src/crypto/crypto_ec.cc
index 0ead8302b60602..5ccda6f0768873 100644
--- a/src/crypto/crypto_ec.cc
+++ b/src/crypto/crypto_ec.cc
@@ -112,9 +112,7 @@ void ECDH::GetCurves(const FunctionCallbackInfo<Value>& args) {
 }
 
 ECDH::ECDH(Environment* env, Local<Object> wrap, ECKeyPointer&& key)
-    : BaseObject(env, wrap),
-    key_(std::move(key)),
-    group_(EC_KEY_get0_group(key_.get())) {
+    : BaseObject(env, wrap), key_(std::move(key)), group_(key_.getGroup()) {
   MakeWeak();
   CHECK_NOT_NULL(group_);
 }
@@ -136,7 +134,7 @@ void ECDH::New(const FunctionCallbackInfo<Value>& args) {
   if (nid == NID_undef)
     return THROW_ERR_CRYPTO_INVALID_CURVE(env);
 
-  ECKeyPointer key(EC_KEY_new_by_curve_name(nid));
+  auto key = ECKeyPointer::NewByCurveName(nid);
   if (!key)
     return THROW_ERR_CRYPTO_OPERATION_FAILED(env,
       "Failed to create key using named curve");
@@ -150,8 +148,9 @@ void ECDH::GenerateKeys(const FunctionCallbackInfo<Value>& args) {
   ECDH* ecdh;
   ASSIGN_OR_RETURN_UNWRAP(&ecdh, args.This());
 
-  if (!EC_KEY_generate_key(ecdh->key_.get()))
+  if (!ecdh->key_.generate()) {
     return THROW_ERR_CRYPTO_OPERATION_FAILED(env, "Failed to generate key");
+  }
 }
 
 ECPointPointer ECDH::BufferToPoint(Environment* env,
@@ -230,8 +229,8 @@ void ECDH::GetPublicKey(const FunctionCallbackInfo<Value>& args) {
   ECDH* ecdh;
   ASSIGN_OR_RETURN_UNWRAP(&ecdh, args.This());
 
-  const EC_GROUP* group = EC_KEY_get0_group(ecdh->key_.get());
-  const EC_POINT* pub = EC_KEY_get0_public_key(ecdh->key_.get());
+  const auto group = ecdh->key_.getGroup();
+  const auto pub = ecdh->key_.getPublicKey();
   if (pub == nullptr)
     return THROW_ERR_CRYPTO_OPERATION_FAILED(env,
         "Failed to get ECDH public key");
@@ -253,7 +252,7 @@ void ECDH::GetPrivateKey(const FunctionCallbackInfo<Value>& args) {
   ECDH* ecdh;
   ASSIGN_OR_RETURN_UNWRAP(&ecdh, args.This());
 
-  const BIGNUM* b = EC_KEY_get0_private_key(ecdh->key_.get());
+  auto b = ecdh->key_.getPrivateKey();
   if (b == nullptr)
     return THROW_ERR_CRYPTO_OPERATION_FAILED(env,
         "Failed to get ECDH private key");
@@ -295,10 +294,10 @@ void ECDH::SetPrivateKey(const FunctionCallbackInfo<Value>& args) {
         "Private key is not valid for specified curve.");
   }
 
-  ECKeyPointer new_key(EC_KEY_dup(ecdh->key_.get()));
+  auto new_key = ecdh->key_.clone();
   CHECK(new_key);
 
-  int result = EC_KEY_set_private_key(new_key.get(), priv.get());
+  bool result = new_key.setPrivateKey(priv);
   priv.reset();
 
   if (!result) {
@@ -309,7 +308,7 @@ void ECDH::SetPrivateKey(const FunctionCallbackInfo<Value>& args) {
   MarkPopErrorOnReturn mark_pop_error_on_return;
   USE(&mark_pop_error_on_return);
 
-  const BIGNUM* priv_key = EC_KEY_get0_private_key(new_key.get());
+  auto priv_key = new_key.getPrivateKey();
   CHECK_NOT_NULL(priv_key);
 
   auto pub = ECPointPointer::New(ecdh->group_);
@@ -320,12 +319,13 @@ void ECDH::SetPrivateKey(const FunctionCallbackInfo<Value>& args) {
         "Failed to generate ECDH public key");
   }
 
-  if (!EC_KEY_set_public_key(new_key.get(), pub))
+  if (!new_key.setPublicKey(pub)) {
     return THROW_ERR_CRYPTO_OPERATION_FAILED(env,
         "Failed to set generated public key");
+  }
 
   ecdh->key_ = std::move(new_key);
-  ecdh->group_ = EC_KEY_get0_group(ecdh->key_.get());
+  ecdh->group_ = ecdh->key_.getGroup();
 }
 
 void ECDH::SetPublicKey(const FunctionCallbackInfo<Value>& args) {
@@ -344,8 +344,7 @@ void ECDH::SetPublicKey(const FunctionCallbackInfo<Value>& args) {
         "Failed to convert Buffer to EC_POINT");
   }
 
-  int r = EC_KEY_set_public_key(ecdh->key_.get(), pub);
-  if (!r) {
+  if (!ecdh->key_.setPublicKey(pub)) {
     return THROW_ERR_CRYPTO_OPERATION_FAILED(env,
         "Failed to set EC_POINT as the public key");
   }
@@ -367,8 +366,7 @@ bool ECDH::IsKeyValidForCurve(const BignumPointer& private_key) {
 
 bool ECDH::IsKeyPairValid() {
   MarkPopErrorOnReturn mark_pop_error_on_return;
-  USE(&mark_pop_error_on_return);
-  return 1 == EC_KEY_check_key(key_.get());
+  return key_.checkKey();
 }
 
 // Convert the input public key to compressed, uncompressed, or hybrid formats.
@@ -485,19 +483,19 @@ bool ECDHBitsTraits::DeriveBits(Environment* env,
       const EC_KEY* private_key;
       {
         Mutex::ScopedLock priv_lock(params.private_.mutex());
-        private_key = EVP_PKEY_get0_EC_KEY(m_privkey.get());
+        private_key = m_privkey;
       }
 
       Mutex::ScopedLock pub_lock(params.public_.mutex());
-      const EC_KEY* public_key = EVP_PKEY_get0_EC_KEY(m_pubkey.get());
+      const EC_KEY* public_key = m_pubkey;
 
-      const EC_GROUP* group = EC_KEY_get0_group(private_key);
+      const auto group = ECKeyPointer::GetGroup(private_key);
       if (group == nullptr)
         return false;
 
-      CHECK_EQ(EC_KEY_check_key(private_key), 1);
-      CHECK_EQ(EC_KEY_check_key(public_key), 1);
-      const EC_POINT* pub = EC_KEY_get0_public_key(public_key);
+      CHECK(ECKeyPointer::Check(private_key));
+      CHECK(ECKeyPointer::Check(public_key));
+      const auto pub = ECKeyPointer::GetPublicKey(public_key);
       int field_size = EC_GROUP_get_degree(group);
       len = (field_size + 7) / 8;
       ByteSource::Builder buf(len);
@@ -596,7 +594,7 @@ WebCryptoKeyExportStatus EC_Raw_Export(const KeyObjectData& key_data,
   CHECK(m_pkey);
   Mutex::ScopedLock lock(key_data.mutex());
 
-  const EC_KEY* ec_key = EVP_PKEY_get0_EC_KEY(m_pkey.get());
+  const EC_KEY* ec_key = m_pkey;
 
   if (ec_key == nullptr) {
     switch (key_data.GetKeyType()) {
@@ -618,8 +616,8 @@ WebCryptoKeyExportStatus EC_Raw_Export(const KeyObjectData& key_data,
   } else {
     if (key_data.GetKeyType() != kKeyTypePublic)
       return WebCryptoKeyExportStatus::INVALID_KEY_TYPE;
-    const EC_GROUP* group = EC_KEY_get0_group(ec_key);
-    const EC_POINT* point = EC_KEY_get0_public_key(ec_key);
+    const auto group = ECKeyPointer::GetGroup(ec_key);
+    const auto point = ECKeyPointer::GetPublicKey(ec_key);
     point_conversion_form_t form = POINT_CONVERSION_UNCOMPRESSED;
 
     // Get the allocated data size...
@@ -675,9 +673,8 @@ WebCryptoKeyExportStatus ECKeyExportTraits::DoExport(
         // the header is for all practical purposes a static 26 byte sequence
         // where only the second byte changes.
         Mutex::ScopedLock lock(key_data.mutex());
-        const EC_KEY* ec_key = EVP_PKEY_get0_EC_KEY(m_pkey.get());
-        const EC_GROUP* group = EC_KEY_get0_group(ec_key);
-        const EC_POINT* point = EC_KEY_get0_public_key(ec_key);
+        const auto group = ECKeyPointer::GetGroup(m_pkey);
+        const auto point = ECKeyPointer::GetPublicKey(m_pkey);
         const point_conversion_form_t form = POINT_CONVERSION_UNCOMPRESSED;
         const size_t need =
             EC_POINT_point2oct(group, point, form, nullptr, 0, nullptr);
@@ -686,17 +683,17 @@ WebCryptoKeyExportStatus ECKeyExportTraits::DoExport(
         const size_t have = EC_POINT_point2oct(
             group, point, form, data.data<unsigned char>(), need, nullptr);
         if (have == 0) return WebCryptoKeyExportStatus::FAILED;
-        ECKeyPointer ec(EC_KEY_new());
-        CHECK_EQ(1, EC_KEY_set_group(ec.get(), group));
+        auto ec = ECKeyPointer::New(group);
+        CHECK(ec);
         auto uncompressed = ECPointPointer::New(group);
         ncrypto::Buffer<const unsigned char> buffer{
             .data = data.data<unsigned char>(),
             .len = data.size(),
         };
         CHECK(uncompressed.setFromBuffer(buffer, group));
-        CHECK_EQ(1, EC_KEY_set_public_key(ec.get(), uncompressed));
+        CHECK(ec.setPublicKey(uncompressed));
         auto pkey = EVPKeyPointer::New();
-        CHECK_EQ(1, EVP_PKEY_set1_EC_KEY(pkey.get(), ec.get()));
+        CHECK(pkey.set(ec));
         auto bio = pkey.derPublicKey();
         if (!bio) return WebCryptoKeyExportStatus::FAILED;
         *out = ByteSource::FromBIO(bio);
@@ -715,11 +712,11 @@ Maybe<void> ExportJWKEcKey(Environment* env,
   const auto& m_pkey = key.GetAsymmetricKey();
   CHECK_EQ(m_pkey.id(), EVP_PKEY_EC);
 
-  const EC_KEY* ec = EVP_PKEY_get0_EC_KEY(m_pkey.get());
+  const EC_KEY* ec = m_pkey;
   CHECK_NOT_NULL(ec);
 
-  const EC_POINT* pub = EC_KEY_get0_public_key(ec);
-  const EC_GROUP* group = EC_KEY_get0_group(ec);
+  const auto pub = ECKeyPointer::GetPublicKey(ec);
+  const auto group = ECKeyPointer::GetGroup(ec);
 
   int degree_bits = EC_GROUP_get_degree(group);
   int degree_bytes =
@@ -785,7 +782,7 @@ Maybe<void> ExportJWKEcKey(Environment* env,
   }
 
   if (key.GetKeyType() == kKeyTypePrivate) {
-    const BIGNUM* pvt = EC_KEY_get0_private_key(ec);
+    auto pvt = ECKeyPointer::GetPrivateKey(ec);
     return SetEncodedValue(env, target, env->jwk_d_string(), pvt, degree_bytes);
   }
 
@@ -879,7 +876,7 @@ KeyObjectData ImportJWKEcKey(Environment* env,
 
   KeyType type = d_value->IsString() ? kKeyTypePrivate : kKeyTypePublic;
 
-  ECKeyPointer ec(EC_KEY_new_by_curve_name(nid));
+  auto ec = ECKeyPointer::NewByCurveName(nid);
   if (!ec) {
     THROW_ERR_CRYPTO_INVALID_JWK(env, "Invalid JWK EC key");
     return {};
@@ -888,24 +885,22 @@ KeyObjectData ImportJWKEcKey(Environment* env,
   ByteSource x = ByteSource::FromEncodedString(env, x_value.As<String>());
   ByteSource y = ByteSource::FromEncodedString(env, y_value.As<String>());
 
-  if (!EC_KEY_set_public_key_affine_coordinates(
-          ec.get(),
-          x.ToBN().get(),
-          y.ToBN().get())) {
+  if (!ec.setPublicKeyRaw(x.ToBN(), y.ToBN())) {
     THROW_ERR_CRYPTO_INVALID_JWK(env, "Invalid JWK EC key");
     return {};
   }
 
   if (type == kKeyTypePrivate) {
     ByteSource d = ByteSource::FromEncodedString(env, d_value.As<String>());
-    if (!EC_KEY_set_private_key(ec.get(), d.ToBN().get())) {
+    if (!ec.setPrivateKey(d.ToBN())) {
       THROW_ERR_CRYPTO_INVALID_JWK(env, "Invalid JWK EC key");
       return {};
     }
   }
 
   auto pkey = EVPKeyPointer::New();
-  CHECK_EQ(EVP_PKEY_set1_EC_KEY(pkey.get(), ec.get()), 1);
+  if (!pkey) return {};
+  CHECK(pkey.set(ec));
 
   return KeyObjectData::CreateAsymmetric(type, std::move(pkey));
 }
@@ -917,10 +912,10 @@ Maybe<void> GetEcKeyDetail(Environment* env,
   const auto& m_pkey = key.GetAsymmetricKey();
   CHECK_EQ(m_pkey.id(), EVP_PKEY_EC);
 
-  const EC_KEY* ec = EVP_PKEY_get0_EC_KEY(m_pkey.get());
+  const EC_KEY* ec = m_pkey;
   CHECK_NOT_NULL(ec);
 
-  const EC_GROUP* group = EC_KEY_get0_group(ec);
+  const auto group = ECKeyPointer::GetGroup(ec);
   int nid = EC_GROUP_get_curve_name(group);
 
   if (target
@@ -939,11 +934,10 @@ Maybe<void> GetEcKeyDetail(Environment* env,
 // https://github.com/chromium/chromium/blob/7af6cfd/components/webcrypto/algorithms/ecdsa.cc
 
 size_t GroupOrderSize(const EVPKeyPointer& key) {
-  const EC_KEY* ec = EVP_PKEY_get0_EC_KEY(key.get());
+  const EC_KEY* ec = key;
   CHECK_NOT_NULL(ec);
-  const EC_GROUP* group = EC_KEY_get0_group(ec);
   auto order = BignumPointer::New();
-  CHECK(EC_GROUP_get_order(group, order.get(), nullptr));
+  CHECK(EC_GROUP_get_order(ECKeyPointer::GetGroup(ec), order.get(), nullptr));
   return order.byteLength();
 }
 }  // namespace crypto
diff --git a/src/crypto/crypto_keys.cc b/src/crypto/crypto_keys.cc
index 30c463bf75f6b1..bedcf04d036478 100644
--- a/src/crypto/crypto_keys.cc
+++ b/src/crypto/crypto_keys.cc
@@ -20,7 +20,6 @@ namespace node {
 
 using ncrypto::BIOPointer;
 using ncrypto::ECKeyPointer;
-using ncrypto::ECPointPointer;
 using ncrypto::EVPKeyCtxPointer;
 using ncrypto::EVPKeyPointer;
 using ncrypto::MarkPopErrorOnReturn;
@@ -761,22 +760,21 @@ void KeyObjectHandle::InitECRaw(const FunctionCallbackInfo<Value>& args) {
   MarkPopErrorOnReturn mark_pop_error_on_return;
 
   int id = OBJ_txt2nid(*name);
-  ECKeyPointer eckey(EC_KEY_new_by_curve_name(id));
+  auto eckey = ECKeyPointer::NewByCurveName(id);
   if (!eckey)
     return args.GetReturnValue().Set(false);
 
-  const EC_GROUP* group = EC_KEY_get0_group(eckey.get());
-  ECPointPointer pub(ECDH::BufferToPoint(env, group, args[1]));
+  const auto group = eckey.getGroup();
+  auto pub = ECDH::BufferToPoint(env, group, args[1]);
 
-  if (!pub ||
-      !eckey ||
-      !EC_KEY_set_public_key(eckey.get(), pub.get())) {
+  if (!pub || !eckey || !eckey.setPublicKey(pub)) {
     return args.GetReturnValue().Set(false);
   }
 
   auto pkey = EVPKeyPointer::New();
-  if (!EVP_PKEY_assign_EC_KEY(pkey.get(), eckey.get()))
+  if (!pkey.assign(eckey)) {
     args.GetReturnValue().Set(false);
+  }
 
   eckey.release();  // Release ownership of the key
 
diff --git a/src/crypto/crypto_sig.cc b/src/crypto/crypto_sig.cc
index 9bfda29010c68d..abb8a804c1b508 100644
--- a/src/crypto/crypto_sig.cc
+++ b/src/crypto/crypto_sig.cc
@@ -15,6 +15,7 @@ namespace node {
 using ncrypto::BignumPointer;
 using ncrypto::ClearErrorOnReturn;
 using ncrypto::ECDSASigPointer;
+using ncrypto::ECKeyPointer;
 using ncrypto::EVPKeyCtxPointer;
 using ncrypto::EVPKeyPointer;
 using ncrypto::EVPMDCtxPointer;
@@ -135,9 +136,7 @@ unsigned int GetBytesOfRS(const EVPKeyPointer& pkey) {
     // Both r and s are computed mod q, so their width is limited by that of q.
     bits = BignumPointer::GetBitCount(DSA_get0_q(dsa_key));
   } else if (base_id == EVP_PKEY_EC) {
-    const EC_KEY* ec_key = EVP_PKEY_get0_EC_KEY(pkey.get());
-    const EC_GROUP* ec_group = EC_KEY_get0_group(ec_key);
-    bits = EC_GROUP_order_bits(ec_group);
+    bits = EC_GROUP_order_bits(ECKeyPointer::GetGroup(pkey));
   } else {
     return kNoDsaSignature;
   }
diff --git a/src/crypto/crypto_x509.cc b/src/crypto/crypto_x509.cc
index ccb7a3a0eeb7a9..3465454e4de4a7 100644
--- a/src/crypto/crypto_x509.cc
+++ b/src/crypto/crypto_x509.cc
@@ -19,6 +19,7 @@ using ncrypto::BignumPointer;
 using ncrypto::BIOPointer;
 using ncrypto::ClearErrorOnReturn;
 using ncrypto::DataPointer;
+using ncrypto::ECKeyPointer;
 using ncrypto::SSLPointer;
 using ncrypto::StackOfASN1;
 using ncrypto::X509Pointer;
@@ -697,7 +698,7 @@ MaybeLocal<Value> GetExponentString(Environment* env, const BIGNUM* e) {
 MaybeLocal<Value> GetECPubKey(Environment* env,
                               const EC_GROUP* group,
                               OSSL3_CONST EC_KEY* ec) {
-  const EC_POINT* pubkey = EC_KEY_get0_public_key(ec);
+  const auto pubkey = ECKeyPointer::GetPublicKey(ec);
   if (pubkey == nullptr) return Undefined(env->isolate());
 
   return ECPointToBuffer(env, group, pubkey, EC_KEY_get_conv_form(ec), nullptr)
@@ -779,7 +780,7 @@ MaybeLocal<Object> X509ToObject(Environment* env, const X509View& cert) {
       return {};
     }
   } else if (ec) {
-    const EC_GROUP* group = EC_KEY_get0_group(ec);
+    const auto group = ECKeyPointer::GetGroup(ec);
 
     if (!Set<Value>(
             env, info, env->bits_string(), GetECGroupBits(env, group)) ||