Commit a2cd8aa883e for nodejs

commit a2cd8aa883e374e463ab3f9d34856fc0a128890d
Author: Filip Skokan <panva.ip@gmail.com>
Date:   Thu Aug 27 00:59:23 2026 +0200

    crypto,https,tls: end OpenSSL engine support

    OpenSSL removed support for engines in version 4. Remove the Node.js
    APIs, constants, native bindings, and implementation that depend on
    ENGINE.

    Keep recognizing the former TLS and HTTPS engine options so their use
    fails explicitly instead of appearing to work while being ignored.

    Move DEP0183 directly from Documentation-only to End-of-Life after
    reverting its unreleased Runtime deprecation.

    Signed-off-by: Filip Skokan <panva.ip@gmail.com>
    Assisted-by: Codex
    PR-URL: https://github.com/nodejs/node/pull/64777
    Fixes: https://github.com/nodejs/node/issues/56733
    Refs: https://github.com/nodejs/node/pull/64211
    Refs: https://github.com/nodejs/node/pull/63966
    Refs: https://github.com/nodejs/node/pull/53329
    Refs: https://github.com/nodejs/node/pull/48950
    Refs: https://github.com/nodejs/node/issues/45465
    Refs: https://github.com/nodejs/node/issues/42827
    Refs: https://github.com/nodejs/node/issues/47076
    Refs: https://github.com/nodejs/node/pull/62862
    Refs: https://github.com/nodejs/node/pull/38512
    Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
    Reviewed-By: James M Snell <jasnell@gmail.com>
    Reviewed-By: Richard Lau <richard.lau@ibm.com>
    Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>

diff --git a/deps/ncrypto/engine.cc b/deps/ncrypto/engine.cc
deleted file mode 100644
index 6b9514b8565..00000000000
--- a/deps/ncrypto/engine.cc
+++ /dev/null
@@ -1,105 +0,0 @@
-#include "ncrypto.h"
-
-#if !defined(OPENSSL_NO_ENGINE) && defined(NCRYPTO_ENGINE_COMPAT) &&           \
-    NCRYPTO_ENGINE_COMPAT
-#include <openssl/engine.h>
-#endif
-
-namespace ncrypto {
-
-// ============================================================================
-// Engine
-
-#ifndef OPENSSL_NO_ENGINE
-EnginePointer::EnginePointer(void* engine_, bool finish_on_exit_)
-    : engine(engine_), finish_on_exit(finish_on_exit_) {}
-
-EnginePointer::EnginePointer(EnginePointer&& other) noexcept
-    : engine(other.engine), finish_on_exit(other.finish_on_exit) {
-  other.release();
-}
-
-EnginePointer::~EnginePointer() {
-  reset();
-}
-
-EnginePointer& EnginePointer::operator=(EnginePointer&& other) noexcept {
-  if (this == &other) return *this;
-  this->~EnginePointer();
-  return *new (this) EnginePointer(std::move(other));
-}
-
-void EnginePointer::reset(void* engine_, bool finish_on_exit_) {
-  if (engine != nullptr) {
-    ENGINE* current = static_cast<ENGINE*>(engine);
-    if (finish_on_exit) {
-      // This also does the equivalent of ENGINE_free.
-      ENGINE_finish(current);
-    } else {
-      ENGINE_free(current);
-    }
-  }
-  engine = engine_;
-  finish_on_exit = finish_on_exit_;
-}
-
-void* EnginePointer::release() {
-  void* ret = engine;
-  engine = nullptr;
-  finish_on_exit = false;
-  return ret;
-}
-
-EnginePointer EnginePointer::getEngineByName(const char* name,
-                                             CryptoErrorList* errors) {
-  MarkPopErrorOnReturn mark_pop_error_on_return(errors);
-  EnginePointer engine(ENGINE_by_id(name));
-  if (!engine) {
-    // Engine not found, try loading dynamically.
-    engine = EnginePointer(ENGINE_by_id("dynamic"));
-    if (engine) {
-      ENGINE* current = static_cast<ENGINE*>(engine.engine);
-      if (!ENGINE_ctrl_cmd_string(current, "SO_PATH", name, 0) ||
-          !ENGINE_ctrl_cmd_string(current, "LOAD", nullptr, 0)) {
-        engine.reset();
-      }
-    }
-  }
-  return engine;
-}
-
-bool EnginePointer::setAsDefault(uint32_t flags, CryptoErrorList* errors) {
-  if (engine == nullptr) return false;
-  ClearErrorOnReturn clear_error_on_return(errors);
-  return ENGINE_set_default(static_cast<ENGINE*>(engine), flags) != 0;
-}
-
-bool EnginePointer::init(bool finish_on_exit) {
-  if (engine == nullptr) return false;
-  if (finish_on_exit) setFinishOnExit();
-  return ENGINE_init(static_cast<ENGINE*>(engine)) == 1;
-}
-
-EVPKeyPointer EnginePointer::loadPrivateKey(const char* key_name) {
-  if (engine == nullptr) return EVPKeyPointer();
-  return EVPKeyPointer(ENGINE_load_private_key(
-      static_cast<ENGINE*>(engine), key_name, nullptr, nullptr));
-}
-
-bool EnginePointer::setClientCertEngine(SSL_CTX* ctx) {
-  if (engine == nullptr || ctx == nullptr) return false;
-  return SSL_CTX_set_client_cert_engine(ctx, static_cast<ENGINE*>(engine)) == 1;
-}
-
-void EnginePointer::initEnginesOnce() {
-  static bool initialized = false;
-  if (!initialized) {
-    ENGINE_load_builtin_engines();
-    ENGINE_register_all_complete();
-    initialized = true;
-  }
-}
-
-#endif  // OPENSSL_NO_ENGINE
-
-}  // namespace ncrypto
diff --git a/deps/ncrypto/ncrypto.gyp b/deps/ncrypto/ncrypto.gyp
index 40f7760ed77..69eccf349f1 100644
--- a/deps/ncrypto/ncrypto.gyp
+++ b/deps/ncrypto/ncrypto.gyp
@@ -5,10 +5,6 @@
       'ncrypto.cc',
       'ncrypto.h',
     ],
-    'ncrypto_engine_sources': [
-      'engine.cc',
-      'ncrypto.h',
-    ],
     # OpenSSL may be configured with --api below 3.0. Keep 3.0 deprecation
     # checks where supported without exceeding its configured API level.
     'ncrypto_openssl3_api_compat':
@@ -17,11 +13,6 @@
       'OPENSSL_API_COMPAT=<(ncrypto_openssl3_api_compat)',
       'OPENSSL_NO_DEPRECATED',
     ],
-    'ncrypto_engine_defines': [
-      'OPENSSL_API_COMPAT=<(ncrypto_openssl3_api_compat)',
-      'OPENSSL_SUPPRESS_DEPRECATED',
-      'NCRYPTO_ENGINE_COMPAT=1',
-    ],
   },
   'targets': [
     {
@@ -46,9 +37,6 @@
       'conditions': [
         ['openssl_is_boringssl=="false"', {
           'defines': [ '<@(ncrypto_strict_defines)' ],
-          'dependencies': [
-            'ncrypto_engine',
-          ],
         }],
         ['node_shared_openssl=="false"', {
           'dependencies': [
@@ -58,27 +46,4 @@
       ]
     },
   ],
-  'conditions': [
-    ['openssl_is_boringssl=="false"', {
-      'targets': [
-        {
-          'target_name': 'ncrypto_engine',
-          'type': 'static_library',
-          'include_dirs': ['.'],
-          'defines': [
-            'NCRYPTO_BSSL_LIBDECREPIT_MISSING=<(ncrypto_bssl_libdecrepit_missing)',
-            '<@(ncrypto_engine_defines)',
-          ],
-          'sources': [ '<@(ncrypto_engine_sources)' ],
-          'conditions': [
-            ['node_shared_openssl=="false"', {
-              'dependencies': [
-                '../openssl/openssl.gyp:openssl'
-              ]
-            }],
-          ]
-        },
-      ],
-    }],
-  ],
 }
diff --git a/deps/ncrypto/ncrypto.h b/deps/ncrypto/ncrypto.h
index 2a84f4b2073..e45807ec179 100644
--- a/deps/ncrypto/ncrypto.h
+++ b/deps/ncrypto/ncrypto.h
@@ -23,11 +23,6 @@
 #include <string_view>
 #include <unordered_map>
 #include <vector>
-#if defined(NCRYPTO_ENGINE_COMPAT) && NCRYPTO_ENGINE_COMPAT &&                 \
-    !defined(OPENSSL_NO_ENGINE)
-#include <openssl/engine.h>
-#endif  // NCRYPTO_ENGINE_COMPAT && !OPENSSL_NO_ENGINE
-
 #ifndef OPENSSL_VERSION_PREREQ
 #define OPENSSL_VERSION_PREREQ(maj, min)                                       \
   (OPENSSL_VERSION_NUMBER >= (((maj) << 28) | ((min) << 20)))
@@ -2109,44 +2104,6 @@ class MacCache final {
 };
 #endif

-#ifndef OPENSSL_NO_ENGINE
-class EnginePointer final {
- public:
-  EnginePointer() = default;
-
-  explicit EnginePointer(void* engine_, bool finish_on_exit = false);
-  EnginePointer(EnginePointer&& other) noexcept;
-  EnginePointer& operator=(EnginePointer&& other) noexcept;
-  NCRYPTO_DISALLOW_COPY(EnginePointer)
-  ~EnginePointer();
-
-  inline operator bool() const { return engine != nullptr; }
-  inline void setFinishOnExit() { finish_on_exit = true; }
-
-  void reset(void* engine_ = nullptr, bool finish_on_exit_ = false);
-
-  bool setAsDefault(uint32_t flags, CryptoErrorList* errors = nullptr);
-  bool init(bool finish_on_exit = false);
-  EVPKeyPointer loadPrivateKey(const char* key_name);
-  bool setClientCertEngine(SSL_CTX* ctx);
-
-  void* release();
-
-  // Retrieve an OpenSSL Engine instance by name. If the name does not
-  // identify a valid named engine, the returned EnginePointer will be
-  // empty.
-  static EnginePointer getEngineByName(const char* name,
-                                       CryptoErrorList* errors = nullptr);
-
-  // Call once when initializing OpenSSL at startup for the process.
-  static void initEnginesOnce();
-
- private:
-  void* engine = nullptr;
-  bool finish_on_exit = false;
-};
-#endif  // !OPENSSL_NO_ENGINE
-
 // ============================================================================
 // FIPS
 bool isFipsEnabled();
diff --git a/deps/ncrypto/unofficial.gni b/deps/ncrypto/unofficial.gni
index dad4fbbf16f..7cb27d22b9b 100644
--- a/deps/ncrypto/unofficial.gni
+++ b/deps/ncrypto/unofficial.gni
@@ -26,11 +26,7 @@ template("ncrypto_gn_build") {
   source_set(target_name) {
     forward_variables_from(invoker, "*")
     public_configs = [ ":ncrypto_config" ]
-    defines = [
-      "NCRYPTO_ENGINE_COMPAT=1",
-      "OPENSSL_SUPPRESS_DEPRECATED",
-    ]
-    sources = gypi_values.ncrypto_sources + gypi_values.ncrypto_engine_sources
+    sources = gypi_values.ncrypto_sources
     deps = [ "$node_openssl_path" ]
   }
 }
diff --git a/doc/api/crypto.md b/doc/api/crypto.md
index 63b85c8ca70..76999281502 100644
--- a/doc/api/crypto.md
+++ b/doc/api/crypto.md
@@ -6601,42 +6601,6 @@ added: v15.6.0
   * `utilization` {number} The calculated ratio of `used` to `total`
     allocated bytes.

-### `crypto.setEngine(engine[, flags])`
-
-<!-- YAML
-added: v0.11.11
-changes:
-  - version:
-    - v22.4.0
-    - v20.16.0
-    pr-url: https://github.com/nodejs/node/pull/53329
-    description: Custom engine support in OpenSSL 3 is deprecated.
--->
-
-* `engine` {string}
-* `flags` {crypto.constants} **Default:** `crypto.constants.ENGINE_METHOD_ALL`
-
-Load and set the `engine` for some or all OpenSSL functions (selected by flags).
-Support for custom engines in OpenSSL is deprecated from OpenSSL 3.
-
-`engine` could be either an id or a path to the engine's shared library.
-
-The optional `flags` argument uses `ENGINE_METHOD_ALL` by default. The `flags`
-is a bit field taking one of or a mix of the following flags (defined in
-`crypto.constants`):
-
-* `crypto.constants.ENGINE_METHOD_RSA`
-* `crypto.constants.ENGINE_METHOD_DSA`
-* `crypto.constants.ENGINE_METHOD_DH`
-* `crypto.constants.ENGINE_METHOD_RAND`
-* `crypto.constants.ENGINE_METHOD_EC`
-* `crypto.constants.ENGINE_METHOD_CIPHERS`
-* `crypto.constants.ENGINE_METHOD_DIGESTS`
-* `crypto.constants.ENGINE_METHOD_PKEY_METHS`
-* `crypto.constants.ENGINE_METHOD_PKEY_ASN1_METHS`
-* `crypto.constants.ENGINE_METHOD_ALL`
-* `crypto.constants.ENGINE_METHOD_NONE`
-
 ### `crypto.setFips(bool)`

 <!-- YAML
@@ -7463,59 +7427,6 @@ See the [list of SSL OP Flags][] for details.
   </tr>
 </table>

-### OpenSSL engine constants
-
-<table>
-  <tr>
-    <th>Constant</th>
-    <th>Description</th>
-  </tr>
-  <tr>
-    <td><code>ENGINE_METHOD_RSA</code></td>
-    <td>Limit engine usage to RSA</td>
-  </tr>
-  <tr>
-    <td><code>ENGINE_METHOD_DSA</code></td>
-    <td>Limit engine usage to DSA</td>
-  </tr>
-  <tr>
-    <td><code>ENGINE_METHOD_DH</code></td>
-    <td>Limit engine usage to DH</td>
-  </tr>
-  <tr>
-    <td><code>ENGINE_METHOD_RAND</code></td>
-    <td>Limit engine usage to RAND</td>
-  </tr>
-  <tr>
-    <td><code>ENGINE_METHOD_EC</code></td>
-    <td>Limit engine usage to EC</td>
-  </tr>
-  <tr>
-    <td><code>ENGINE_METHOD_CIPHERS</code></td>
-    <td>Limit engine usage to CIPHERS</td>
-  </tr>
-  <tr>
-    <td><code>ENGINE_METHOD_DIGESTS</code></td>
-    <td>Limit engine usage to DIGESTS</td>
-  </tr>
-  <tr>
-    <td><code>ENGINE_METHOD_PKEY_METHS</code></td>
-    <td>Limit engine usage to PKEY_METHS</td>
-  </tr>
-  <tr>
-    <td><code>ENGINE_METHOD_PKEY_ASN1_METHS</code></td>
-    <td>Limit engine usage to PKEY_ASN1_METHS</td>
-  </tr>
-  <tr>
-    <td><code>ENGINE_METHOD_ALL</code></td>
-    <td></td>
-  </tr>
-  <tr>
-    <td><code>ENGINE_METHOD_NONE</code></td>
-    <td></td>
-  </tr>
-</table>
-
 ### Other OpenSSL constants

 <table>
diff --git a/doc/api/deprecations.md b/doc/api/deprecations.md
index 6c9fcecf319..7f16ec69c95 100644
--- a/doc/api/deprecations.md
+++ b/doc/api/deprecations.md
@@ -4111,6 +4111,9 @@ that are shorter than the default authentication tag length (i.e., shorter than

 <!-- YAML
 changes:
+  - version: REPLACEME
+    pr-url: https://github.com/nodejs/node/pull/64777
+    description: End-of-Life.
   - version:
     - v22.4.0
     - v20.16.0
@@ -4118,13 +4121,15 @@ changes:
     description: Documentation-only deprecation.
 -->

-Type: Documentation-only
+Type: End-of-Life

-OpenSSL 3 has deprecated support for custom engines with a recommendation to
-switch to its new provider model. The `clientCertEngine` option for
-`https.request()`, [`tls.createSecureContext()`][], and [`tls.createServer()`][];
-the `privateKeyEngine` and `privateKeyIdentifier` for [`tls.createSecureContext()`][];
-and [`crypto.setEngine()`][] all depend on this functionality from OpenSSL.
+The `crypto.setEngine()` API and the `crypto.constants.ENGINE_METHOD_*`
+constants have been removed. The `clientCertEngine` option for
+[`https.request()`][], [`tls.createSecureContext()`][], and
+[`tls.createServer()`][] and the `privateKeyEngine` and `privateKeyIdentifier`
+options for [`tls.createSecureContext()`][] now throw
+`ERR_CRYPTO_CUSTOM_ENGINE_NOT_SUPPORTED` when used. There is no direct
+replacement API in Node.js. OpenSSL's provider model replaces engines upstream.

 ### DEP0184: Instantiating `node:zlib` classes without `new`

@@ -4887,7 +4892,6 @@ Type: Documentation-only
 [`crypto.pbkdf2()`]: crypto.md#cryptopbkdf2password-salt-iterations-keylen-digest-callback
 [`crypto.randomBytes()`]: crypto.md#cryptorandombytessize-callback
 [`crypto.scrypt()`]: crypto.md#cryptoscryptpassword-salt-keylen-options-callback
-[`crypto.setEngine()`]: crypto.md#cryptosetengineengine-flags
 [`decipher.final()`]: crypto.md#decipherfinaloutputencoding
 [`decipher.setAuthTag()`]: crypto.md#deciphersetauthtagbuffer-encoding
 [`dirent.parentPath`]: fs.md#direntparentpath
diff --git a/doc/api/errors.md b/doc/api/errors.md
index 1d812bd0b33..834be04dcbb 100644
--- a/doc/api/errors.md
+++ b/doc/api/errors.md
@@ -911,9 +911,8 @@ Argon2 is not supported by the current version of OpenSSL being used.

 ### `ERR_CRYPTO_CUSTOM_ENGINE_NOT_SUPPORTED`

-An OpenSSL engine was requested (for example, through the `clientCertEngine` or
-`privateKeyEngine` TLS options) that is not supported by the version of OpenSSL
-being used, likely due to the compile-time flag `OPENSSL_NO_ENGINE`.
+An OpenSSL engine-based TLS or HTTPS option was used after support for custom
+engines reached End-of-Life in Node.js.

 <a id="ERR_CRYPTO_ECDH_INVALID_FORMAT"></a>

@@ -930,13 +929,6 @@ An invalid value for the `key` argument has been passed to the
 `crypto.ECDH()` class `computeSecret()` method. It means that the public
 key lies outside of the elliptic curve.

-<a id="ERR_CRYPTO_ENGINE_UNKNOWN"></a>
-
-### `ERR_CRYPTO_ENGINE_UNKNOWN`
-
-An invalid crypto engine identifier was passed to
-[`require('node:crypto').setEngine()`][].
-
 <a id="ERR_CRYPTO_FIPS_FORCED"></a>

 ### `ERR_CRYPTO_FIPS_FORCED`
@@ -3945,6 +3937,17 @@ removed: v15.0.0

 The native call from `process.cpuUsage` could not be processed.

+<a id="ERR_CRYPTO_ENGINE_UNKNOWN"></a>
+
+### `ERR_CRYPTO_ENGINE_UNKNOWN`
+
+<!-- YAML
+removed: REPLACEME
+-->
+
+An invalid crypto engine identifier was passed to
+`require('node:crypto').setEngine()`.
+
 <a id="ERR_CRYPTO_HASH_DIGEST_NO_UTF16"></a>

 ### `ERR_CRYPTO_HASH_DIGEST_NO_UTF16`
@@ -4840,7 +4843,6 @@ An error occurred trying to allocate memory. This should never happen.
 [`process.send()`]: process.md#processsendmessage-sendhandle-options-callback
 [`process.setUncaughtExceptionCaptureCallback()`]: process.md#processsetuncaughtexceptioncapturecallbackfn
 [`readable._read()`]: stream.md#readable_readsize
-[`require('node:crypto').setEngine()`]: crypto.md#cryptosetengineengine-flags
 [`require()`]: modules.md#requireid
 [`server.close()`]: net.md#serverclosecallback
 [`server.listen()`]: net.md#serverlisten
diff --git a/doc/api/https.md b/doc/api/https.md
index 74b759556c4..c4a95ee6749 100644
--- a/doc/api/https.md
+++ b/doc/api/https.md
@@ -427,6 +427,10 @@ a `timeout` of 5 seconds.
 <!-- YAML
 added: v0.3.6
 changes:
+  - version: REPLACEME
+    pr-url: https://github.com/nodejs/node/pull/64777
+    description: Using the `clientCertEngine` option now throws
+                 `ERR_CRYPTO_CUSTOM_ENGINE_NOT_SUPPORTED`.
   - version:
     - v22.4.0
     - v20.16.0
@@ -468,10 +472,9 @@ changes:
 Makes a request to a secure web server.

 The following additional `options` from [`tls.connect()`][] are also accepted:
-`ca`, `cert`, `ciphers`, `clientCertEngine` (deprecated), `crl`, `dhparam`, `ecdhCurve`,
-`honorCipherOrder`, `key`, `passphrase`, `pfx`, `rejectUnauthorized`,
-`secureOptions`, `secureProtocol`, `servername`, `sessionIdContext`,
-`highWaterMark`.
+`ca`, `cert`, `ciphers`, `crl`, `dhparam`, `ecdhCurve`, `honorCipherOrder`,
+`key`, `passphrase`, `pfx`, `rejectUnauthorized`, `secureOptions`,
+`secureProtocol`, `servername`, `sessionIdContext`, `highWaterMark`.

 `options` can be an object, a string, or a [`URL`][] object. If `options` is a
 string, it is automatically parsed with [`new URL()`][]. If it is a [`URL`][]
diff --git a/doc/api/permissions.md b/doc/api/permissions.md
index b236b33c31e..d02e443fbd8 100644
--- a/doc/api/permissions.md
+++ b/doc/api/permissions.md
@@ -503,8 +503,6 @@ There are constraints you need to know before using this system:
   expanded path is not covered by `--allow-fs-write`. Because the location is
   chosen by the operator, gaps like this are treated as regular bugs rather
   than vulnerabilities. Please report them through the regular issue tracker.
-* OpenSSL engines cannot be requested at runtime when the Permission
-  Model is enabled, affecting the built-in crypto, https, and tls modules.
 * Run-Time Loadable Extensions cannot be loaded when the Permission Model is
   enabled, affecting the sqlite module.
 * Using existing file descriptors via the `node:fs` module bypasses the
diff --git a/doc/api/tls.md b/doc/api/tls.md
index d518289d493..ab0fd534ff8 100644
--- a/doc/api/tls.md
+++ b/doc/api/tls.md
@@ -1988,6 +1988,11 @@ argument.
 <!-- YAML
 added: v0.11.13
 changes:
+  - version: REPLACEME
+    pr-url: https://github.com/nodejs/node/pull/64777
+    description: Using the `clientCertEngine`, `privateKeyEngine`, or
+                 `privateKeyIdentifier` option now throws
+                 `ERR_CRYPTO_CUSTOM_ENGINE_NOT_SUPPORTED`.
   - version:
      - v26.4.0
      - v24.19.0
@@ -2102,8 +2107,6 @@ changes:
     more information, see [Modifying the default TLS cipher suite][]. Permitted
     ciphers can be obtained via [`tls.getCiphers()`][]. Cipher names must be
     uppercased in order for OpenSSL to accept them.
-  * `clientCertEngine` {string} Name of an OpenSSL engine which can provide the
-    client certificate. **Deprecated.**
   * `crl` {string|string\[]|Buffer|Buffer\[]} PEM formatted CRLs (Certificate
     Revocation Lists).
   * `dhparam` {string|Buffer} `'auto'` or custom Diffie-Hellman parameters,
@@ -2134,12 +2137,6 @@ changes:
     occur in an array. `object.passphrase` is optional. Encrypted keys will be
     decrypted with `object.passphrase` if provided, or `options.passphrase` if
     it is not.
-  * `privateKeyEngine` {string} Name of an OpenSSL engine to get private key
-    from. Should be used together with `privateKeyIdentifier`. **Deprecated.**
-  * `privateKeyIdentifier` {string} Identifier of a private key managed by
-    an OpenSSL engine. Should be used together with `privateKeyEngine`.
-    Should not be set together with `key`, because both options define a
-    private key in different ways. **Deprecated.**
   * `maxVersion` {string} Optionally set the maximum TLS version to allow. One
     of `'TLSv1.3'`, `'TLSv1.2'`, `'TLSv1.1'`, or `'TLSv1'`. Cannot be specified
     along with the `secureProtocol` option; use one or the other.
@@ -2212,6 +2209,10 @@ permissible, use 2048 bits or larger for stronger security.
 <!-- YAML
 added: v0.3.2
 changes:
+  - version: REPLACEME
+    pr-url: https://github.com/nodejs/node/pull/64777
+    description: Using the `clientCertEngine` option now throws
+                 `ERR_CRYPTO_CUSTOM_ENGINE_NOT_SUPPORTED`.
   - version:
     - v22.4.0
     - v20.16.0
@@ -2262,8 +2263,6 @@ changes:
     If a string is returned that does not match one of the client's ALPN
     protocols, an error will be thrown. This option cannot be used with the
     `ALPNProtocols` option, and setting both options will throw an error.
-  * `clientCertEngine` {string} Name of an OpenSSL engine which can provide the
-    client certificate. **Deprecated.**
   * `enableTrace` {boolean} If `true`, [`tls.TLSSocket.enableTrace()`][] will be
     called on new connections. Tracing can be enabled after the secure
     connection is established, but this option must be used to trace the secure
diff --git a/lib/crypto.js b/lib/crypto.js
index 4261097b52b..6e6c3d0552f 100644
--- a/lib/crypto.js
+++ b/lib/crypto.js
@@ -124,7 +124,6 @@ const {
   getCurves,
   getHashes,
   getMacs,
-  setEngine,
   secureHeapUsed,
 } = require('internal/crypto/util');
 const Certificate = require('internal/crypto/certificate');
@@ -237,7 +236,6 @@ module.exports = {
   scrypt,
   scryptSync,
   sign: signOneShot,
-  setEngine,
   timingSafeEqual,
   getFips,
   setFips,
diff --git a/lib/https.js b/lib/https.js
index 454e923cc34..6be488aa753 100644
--- a/lib/https.js
+++ b/lib/https.js
@@ -49,6 +49,9 @@ const { ERR_PROXY_TUNNEL } = require('internal/errors').codes;
 assertCrypto();

 const tls = require('tls');
+const {
+  validateOpenSSLEngineOptions,
+} = require('internal/tls/secure-context');
 const kPerRequestCheckServerIdentity = Symbol('per-request checkServerIdentity');
 let perRequestCheckServerIdentityIndex = 0;
 const {
@@ -487,6 +490,7 @@ function Agent(options) {
     return new Agent(options);

   options = { __proto__: null, ...options };
+  validateOpenSSLEngineOptions(options);
   options.defaultPort ??= 443;
   options.protocol ??= 'https:';
   FunctionPrototypeCall(HttpAgent, this, options);
@@ -535,6 +539,7 @@ function getPfxAgentKey(pfx, passphrase) {
  * @returns {string}
  */
 Agent.prototype.getName = function getName(options = kEmptyObject) {
+  validateOpenSSLEngineOptions(options);
   let name = FunctionPrototypeCall(HttpAgent.prototype.getName, this, options);

   name += ':';
@@ -545,10 +550,6 @@ Agent.prototype.getName = function getName(options = kEmptyObject) {
   if (options.cert)
     name += options.cert;

-  name += ':';
-  if (options.clientCertEngine)
-    name += options.clientCertEngine;
-
   name += ':';
   if (options.ciphers)
     name += options.ciphers;
@@ -609,14 +610,6 @@ Agent.prototype.getName = function getName(options = kEmptyObject) {
   if (options.sigalgs)
     name += JSONStringify(options.sigalgs);

-  name += ':';
-  if (options.privateKeyIdentifier)
-    name += options.privateKeyIdentifier;
-
-  name += ':';
-  if (options.privateKeyEngine)
-    name += options.privateKeyEngine;
-
   if (options[kPerRequestCheckServerIdentity])
     name += `:${options[kPerRequestCheckServerIdentity]}`;

@@ -692,6 +685,7 @@ function request(...args) {
   if (args[0] && typeof args[0] !== 'function') {
     ObjectAssign(options, ArrayPrototypeShift(args));
   }
+  validateOpenSSLEngineOptions(options);

   if (options.checkServerIdentity !== undefined &&
       options.checkServerIdentity !== tls.checkServerIdentity &&
diff --git a/lib/internal/crypto/util.js b/lib/internal/crypto/util.js
index f915b103db4..52445eab767 100644
--- a/lib/internal/crypto/util.js
+++ b/lib/internal/crypto/util.js
@@ -40,7 +40,6 @@ const {
   getCurves: _getCurves,
   getHashes: _getHashes,
   getMacs: _getMacs,
-  setEngine: _setEngine,
   secureHeapUsed: _secureHeapUsed,
   getCachedAliases,
   getCachedMacAliases,
@@ -68,18 +67,10 @@ function isFips() {

 const { getOptionValue } = require('internal/options');

-const {
-  crypto: {
-    ENGINE_METHOD_ALL,
-  },
-} = internalBinding('constants');
-
 const normalizeHashName = require('internal/crypto/hashnames');

 const {
   codes: {
-    ERR_CRYPTO_CUSTOM_ENGINE_NOT_SUPPORTED,
-    ERR_CRYPTO_ENGINE_UNKNOWN,
     ERR_INVALID_ARG_TYPE,
   },
   hideStackFrames,
@@ -87,7 +78,6 @@ const {

 const {
   validateArray,
-  validateNumber,
   validateString,
 } = require('internal/validators');

@@ -212,22 +202,6 @@ const getMacs = cachedArrayByFipsGeneration(
 const getCurves = cachedArrayByFipsGeneration(
   () => filterDuplicateStrings(_getCurves()));

-function setEngine(id, flags) {
-  validateString(id, 'id');
-  if (flags)
-    validateNumber(flags, 'flags');
-  flags = flags >>> 0;
-
-  // Use provided engine for everything by default
-  if (flags === 0)
-    flags = ENGINE_METHOD_ALL;
-
-  if (typeof _setEngine !== 'function')
-    throw new ERR_CRYPTO_CUSTOM_ENGINE_NOT_SUPPORTED();
-  if (!_setEngine(id, flags))
-    throw new ERR_CRYPTO_ENGINE_UNKNOWN(id);
-}
-
 const getArrayBufferOrView = hideStackFrames((buffer, name, encoding) => {
   if (isAnyArrayBuffer(buffer))
     return buffer;
@@ -1279,7 +1253,6 @@ module.exports = {
   getMacs,
   getOptionalByteLength,
   kHandle,
-  setEngine,
   toBuf,

   kNamedCurveAliases,
diff --git a/lib/internal/errors.js b/lib/internal/errors.js
index ddd07a98209..88c4102eee4 100644
--- a/lib/internal/errors.js
+++ b/lib/internal/errors.js
@@ -1175,11 +1175,10 @@ E('ERR_CONSTRUCT_CALL_REQUIRED', 'Class constructor %s cannot be invoked without
 E('ERR_CONTEXT_NOT_INITIALIZED', 'context used is not initialized', Error);
 E('ERR_CRYPTO_ARGON2_NOT_SUPPORTED', 'Argon2 algorithm not supported', Error);
 E('ERR_CRYPTO_CUSTOM_ENGINE_NOT_SUPPORTED',
-  'Custom engines not supported by this OpenSSL', Error);
+  'Custom engines not supported by this version of Node.js', Error);
 E('ERR_CRYPTO_ECDH_INVALID_FORMAT', 'Invalid ECDH format: %s', TypeError);
 E('ERR_CRYPTO_ECDH_INVALID_PUBLIC_KEY',
   'Public key is not valid for specified curve', Error);
-E('ERR_CRYPTO_ENGINE_UNKNOWN', 'Engine "%s" was not found', Error);
 E('ERR_CRYPTO_FIPS_FORCED',
   'Cannot set FIPS mode, it was forced with --force-fips at startup.', Error);
 E('ERR_CRYPTO_FIPS_UNAVAILABLE', 'Cannot set FIPS mode in a non-FIPS build.',
diff --git a/lib/internal/tls/secure-context.js b/lib/internal/tls/secure-context.js
index 862d7501a1d..7c427cfbeb0 100644
--- a/lib/internal/tls/secure-context.js
+++ b/lib/internal/tls/secure-context.js
@@ -127,8 +127,26 @@ function processCiphers(ciphers, name) {
   return { cipherList, cipherSuites };
 }

+function validateOpenSSLEngineOptions(options) {
+  const {
+    clientCertEngine,
+    privateKeyEngine,
+    privateKeyIdentifier,
+  } = options;
+
+  // OpenSSL engine support moves directly from Documentation-only to
+  // End-of-Life. Keep recognizing these options so users cannot assume engines
+  // still work: their use must throw instead of being silently ignored.
+  if (clientCertEngine != null ||
+      privateKeyEngine != null ||
+      privateKeyIdentifier != null) {
+    throw new ERR_CRYPTO_CUSTOM_ENGINE_NOT_SUPPORTED();
+  }
+}
+
 function configSecureContext(context, options = kEmptyObject, name = 'options') {
   validateObject(options, name);
+  validateOpenSSLEngineOptions(options);

   const {
     allowPartialTrustChain,
@@ -136,15 +154,12 @@ function configSecureContext(context, options = kEmptyObject, name = 'options')
     cert,
     certificateCompression,
     ciphers = getDefaultCiphers(),
-    clientCertEngine,
     crl,
     dhparam,
     ecdhCurve = getDefaultEcdhCurve(),
     key,
     passphrase,
     pfx,
-    privateKeyIdentifier,
-    privateKeyEngine,
     sessionIdContext,
     sessionTimeout,
     sigalgs,
@@ -255,35 +270,6 @@ function configSecureContext(context, options = kEmptyObject, name = 'options')
     context.setSigalgs(sigalgs);
   }

-  if (privateKeyIdentifier !== undefined && privateKeyIdentifier !== null) {
-    if (privateKeyEngine === undefined || privateKeyEngine === null) {
-      // Engine is required when privateKeyIdentifier is present
-      throw new ERR_INVALID_ARG_VALUE(`${name}.privateKeyEngine`,
-                                      privateKeyEngine);
-    }
-    if (key) {
-      // Both data key and engine key can't be set at the same time
-      throw new ERR_INVALID_ARG_VALUE(`${name}.privateKeyIdentifier`,
-                                      privateKeyIdentifier);
-    }
-
-    if (typeof privateKeyIdentifier === 'string' &&
-        typeof privateKeyEngine === 'string') {
-      if (context.setEngineKey)
-        context.setEngineKey(privateKeyIdentifier, privateKeyEngine);
-      else
-        throw new ERR_CRYPTO_CUSTOM_ENGINE_NOT_SUPPORTED();
-    } else if (typeof privateKeyIdentifier !== 'string') {
-      throw new ERR_INVALID_ARG_TYPE(`${name}.privateKeyIdentifier`,
-                                     ['string', 'null', 'undefined'],
-                                     privateKeyIdentifier);
-    } else {
-      throw new ERR_INVALID_ARG_TYPE(`${name}.privateKeyEngine`,
-                                     ['string', 'null', 'undefined'],
-                                     privateKeyEngine);
-    }
-  }
-
   validateString(ecdhCurve, `${name}.ecdhCurve`);
   context.setECDHCurve(ecdhCurve);

@@ -329,17 +315,6 @@ function configSecureContext(context, options = kEmptyObject, name = 'options')
     }
   }

-  if (typeof clientCertEngine === 'string') {
-    if (typeof context.setClientCertEngine !== 'function')
-      throw new ERR_CRYPTO_CUSTOM_ENGINE_NOT_SUPPORTED();
-    else
-      context.setClientCertEngine(clientCertEngine);
-  } else if (clientCertEngine !== undefined && clientCertEngine !== null) {
-    throw new ERR_INVALID_ARG_TYPE(`${name}.clientCertEngine`,
-                                   ['string', 'null', 'undefined'],
-                                   clientCertEngine);
-  }
-
   if (ticketKeys !== undefined && ticketKeys !== null) {
     validateBuffer(ticketKeys, `${name}.ticketKeys`);
     if (ticketKeys.byteLength !== 48) {
@@ -359,4 +334,5 @@ function configSecureContext(context, options = kEmptyObject, name = 'options')

 module.exports = {
   configSecureContext,
+  validateOpenSSLEngineOptions,
 };
diff --git a/lib/internal/tls/wrap.js b/lib/internal/tls/wrap.js
index d339c4d774c..82f343de726 100644
--- a/lib/internal/tls/wrap.js
+++ b/lib/internal/tls/wrap.js
@@ -48,6 +48,9 @@ const EE = require('events');
 const net = require('net');
 const tls = require('tls');
 const common = require('internal/tls/common');
+const {
+  validateOpenSSLEngineOptions,
+} = require('internal/tls/secure-context');
 const { kReinitializeHandle } = require('internal/net');
 const JSStreamSocket = require('internal/js_stream_socket');
 const { Buffer } = require('buffer');
@@ -623,6 +626,7 @@ function initRead(tlsSocket, socket) {

 function TLSSocket(socket, opts) {
   const tlsOptions = { ...opts };
+  validateOpenSSLEngineOptions(tlsOptions);
   let enableTrace = tlsOptions.enableTrace;

   if (enableTrace == null) {
@@ -1458,7 +1462,6 @@ function tlsConnectionListener(rawSocket) {
 // - rejectUnauthorized. Boolean, default to true.
 // - key. string.
 // - cert: string.
-// - clientCertEngine: string.
 // - ca: string or array of strings.
 // - sessionTimeout: integer.
 //
@@ -1550,6 +1553,7 @@ exports.createServer = function createServer(options, listener) {

 Server.prototype.setSecureContext = function(options) {
   validateObject(options, 'options');
+  validateOpenSSLEngineOptions(options);

   if (options.pfx)
     this.pfx = options.pfx;
@@ -1571,11 +1575,6 @@ Server.prototype.setSecureContext = function(options) {
   else
     this.cert = undefined;

-  if (options.clientCertEngine)
-    this.clientCertEngine = options.clientCertEngine;
-  else
-    this.clientCertEngine = undefined;
-
   if (options.ca)
     this.ca = options.ca;
   else
@@ -1642,8 +1641,6 @@ Server.prototype.setSecureContext = function(options) {
   if (options.ticketKeys)
     this.ticketKeys = options.ticketKeys;

-  this.privateKeyIdentifier = options.privateKeyIdentifier;
-  this.privateKeyEngine = options.privateKeyEngine;
   this.certificateCompression = options.certificateCompression;

   this._sharedCreds = tls.createSecureContext({
@@ -1651,7 +1648,6 @@ Server.prototype.setSecureContext = function(options) {
     key: this.key,
     passphrase: this.passphrase,
     cert: this.cert,
-    clientCertEngine: this.clientCertEngine,
     ca: this.ca,
     ciphers: this.ciphers,
     sigalgs: this.sigalgs,
@@ -1666,8 +1662,6 @@ Server.prototype.setSecureContext = function(options) {
     sessionIdContext: this.sessionIdContext,
     ticketKeys: this.ticketKeys,
     sessionTimeout: this.sessionTimeout,
-    privateKeyIdentifier: this.privateKeyIdentifier,
-    privateKeyEngine: this.privateKeyEngine,
     certificateCompression: this.certificateCompression,
   });
 };
@@ -1865,6 +1859,7 @@ exports.connect = function connect(...args) {
     minDHSize: 1024,
     ...options,
   };
+  validateOpenSSLEngineOptions(options);

   if (!options.keepAlive)
     options.singleUse = true;
diff --git a/src/crypto/crypto_context.cc b/src/crypto/crypto_context.cc
index 4956d7f5908..beef99a8f1c 100644
--- a/src/crypto/crypto_context.cc
+++ b/src/crypto/crypto_context.cc
@@ -40,12 +40,8 @@ namespace node {
 using ncrypto::BIOPointer;
 using ncrypto::Cipher;
 using ncrypto::ClearErrorOnReturn;
-using ncrypto::CryptoErrorList;
 using ncrypto::DHPointer;
 using ncrypto::Digest;
-#ifndef OPENSSL_NO_ENGINE
-using ncrypto::EnginePointer;
-#endif  // !OPENSSL_NO_ENGINE
 using ncrypto::EVPKeyPointer;
 using ncrypto::KeyAlgorithm;
 using ncrypto::MarkPopErrorOnReturn;
@@ -1350,11 +1346,6 @@ Local<FunctionTemplate> SecureContext::GetConstructorTemplate(
     SetProtoMethodNoSideEffect(
         isolate, tmpl, "getIssuer", GetCertificate<false>);

-#ifndef OPENSSL_NO_ENGINE
-    SetProtoMethod(isolate, tmpl, "setEngineKey", SetEngineKey);
-    SetProtoMethod(isolate, tmpl, "setClientCertEngine", SetClientCertEngine);
-#endif  // !OPENSSL_NO_ENGINE
-
 #define SET_INTEGER_CONSTANTS(name, value)                                     \
   tmpl->Set(FIXED_ONE_BYTE_STRING(isolate, name),                              \
             Integer::NewFromUnsigned(isolate, value));
@@ -1689,11 +1680,6 @@ void SecureContext::RegisterExternalReferences(
   registry->Register(GetCertificate<true>);
   registry->Register(GetCertificate<false>);

-#ifndef OPENSSL_NO_ENGINE
-  registry->Register(SetEngineKey);
-  registry->Register(SetClientCertEngine);
-#endif  // !OPENSSL_NO_ENGINE
-
   registry->Register(CtxGetter);

   registry->Register(GetBundledRootCertificates);
@@ -1968,54 +1954,6 @@ void SecureContext::SetSigalgs(const FunctionCallbackInfo<Value>& args) {
     return ThrowCryptoError(env, ERR_get_error());
 }

-#ifndef OPENSSL_NO_ENGINE
-void SecureContext::SetEngineKey(const FunctionCallbackInfo<Value>& args) {
-  Environment* env = Environment::GetCurrent(args);
-
-  SecureContext* sc;
-  ASSIGN_OR_RETURN_UNWRAP(&sc, args.This());
-
-  CHECK_EQ(args.Length(), 2);
-
-  if (env->permission()->enabled()) [[unlikely]] {
-    return THROW_ERR_CRYPTO_CUSTOM_ENGINE_NOT_SUPPORTED(
-        env,
-        "Programmatic selection of OpenSSL engines is unsupported while the "
-        "experimental permission model is enabled");
-  }
-
-  CryptoErrorList errors;
-  Utf8Value engine_id(env->isolate(), args[1]);
-  auto engine = EnginePointer::getEngineByName(*engine_id, &errors);
-  if (!engine) {
-    Local<Value> exception;
-    if (errors.empty()) {
-      errors.add(getNodeCryptoErrorString(NodeCryptoError::ENGINE_NOT_FOUND,
-                                          *engine_id));
-    }
-    if (cryptoErrorListToException(env, errors).ToLocal(&exception))
-      env->isolate()->ThrowException(exception);
-    return;
-  }
-
-  if (!engine.init(true /* finish on exit*/)) {
-    return THROW_ERR_CRYPTO_OPERATION_FAILED(
-        env, "Failure to initialize engine");
-  }
-
-  Utf8Value key_name(env->isolate(), args[0]);
-  auto key = engine.loadPrivateKey(*key_name);
-
-  if (!key)
-    return ThrowCryptoError(env, ERR_get_error(), "ENGINE_load_private_key");
-
-  if (!SSL_CTX_use_PrivateKey(sc->ctx_.get(), key.get()))
-    return ThrowCryptoError(env, ERR_get_error(), "SSL_CTX_use_PrivateKey");
-
-  sc->private_key_engine_ = std::move(engine);
-}
-#endif  // !OPENSSL_NO_ENGINE
-
 Maybe<void> SecureContext::AddCert(Environment* env, BIOPointer&& bio) {
   ClearErrorOnReturn clear_error_on_return;
   // TODO(tniessen): this should be checked by the caller and not treated as ok
@@ -2534,53 +2472,6 @@ void SecureContext::LoadPKCS12(const FunctionCallbackInfo<Value>& args) {
   }
 }

-#ifndef OPENSSL_NO_ENGINE
-void SecureContext::SetClientCertEngine(
-    const FunctionCallbackInfo<Value>& args) {
-  Environment* env = Environment::GetCurrent(args);
-  CHECK_EQ(args.Length(), 1);
-  CHECK(args[0]->IsString());
-
-  SecureContext* sc;
-  ASSIGN_OR_RETURN_UNWRAP(&sc, args.This());
-
-  MarkPopErrorOnReturn mark_pop_error_on_return;
-
-  // SSL_CTX_set_client_cert_engine does not itself support multiple
-  // calls by cleaning up before overwriting the client_cert_engine
-  // internal context variable.
-  // Instead of trying to fix up this problem we in turn also do not
-  // support multiple calls to SetClientCertEngine.
-  CHECK(!sc->client_cert_engine_provided_);
-
-  if (env->permission()->enabled()) [[unlikely]] {
-    return THROW_ERR_CRYPTO_CUSTOM_ENGINE_NOT_SUPPORTED(
-        env,
-        "Programmatic selection of OpenSSL engines is unsupported while the "
-        "experimental permission model is enabled");
-  }
-
-  CryptoErrorList errors;
-  const Utf8Value engine_id(env->isolate(), args[0]);
-  auto engine = EnginePointer::getEngineByName(*engine_id, &errors);
-  if (!engine) {
-    Local<Value> exception;
-    if (errors.empty()) {
-      errors.add(getNodeCryptoErrorString(NodeCryptoError::ENGINE_NOT_FOUND,
-                                          *engine_id));
-    }
-    if (cryptoErrorListToException(env, errors).ToLocal(&exception))
-      env->isolate()->ThrowException(exception);
-    return;
-  }
-
-  // Note that this takes another reference to `engine`.
-  if (!engine.setClientCertEngine(sc->ctx_.get()))
-    return ThrowCryptoError(env, ERR_get_error());
-  sc->client_cert_engine_provided_ = true;
-}
-#endif  // !OPENSSL_NO_ENGINE
-
 void SecureContext::GetTicketKeys(const FunctionCallbackInfo<Value>& args) {
   SecureContext* wrap;
   ASSIGN_OR_RETURN_UNWRAP(&wrap, args.This());
diff --git a/src/crypto/crypto_context.h b/src/crypto/crypto_context.h
index 3a564f83827..285f8657eb4 100644
--- a/src/crypto/crypto_context.h
+++ b/src/crypto/crypto_context.h
@@ -118,9 +118,6 @@ class SecureContext final : public BaseObject {
   static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
   static void Init(const v8::FunctionCallbackInfo<v8::Value>& args);
   static void SetKey(const v8::FunctionCallbackInfo<v8::Value>& args);
-#ifndef OPENSSL_NO_ENGINE
-  static void SetEngineKey(const v8::FunctionCallbackInfo<v8::Value>& args);
-#endif  // !OPENSSL_NO_ENGINE
   static void SetCert(const v8::FunctionCallbackInfo<v8::Value>& args);
   static void AddCACert(const v8::FunctionCallbackInfo<v8::Value>& args);
   static void SetAllowPartialTrustChain(
@@ -147,10 +144,6 @@ class SecureContext final : public BaseObject {
   static void GetMaxProto(const v8::FunctionCallbackInfo<v8::Value>& args);
   static void Close(const v8::FunctionCallbackInfo<v8::Value>& args);
   static void LoadPKCS12(const v8::FunctionCallbackInfo<v8::Value>& args);
-#ifndef OPENSSL_NO_ENGINE
-  static void SetClientCertEngine(
-      const v8::FunctionCallbackInfo<v8::Value>& args);
-#endif  // !OPENSSL_NO_ENGINE
   static void GetTicketKeys(const v8::FunctionCallbackInfo<v8::Value>& args);
   static void SetTicketKeys(const v8::FunctionCallbackInfo<v8::Value>& args);
   static void EnableTicketKeyCallback(
@@ -200,10 +193,6 @@ class SecureContext final : public BaseObject {
   ncrypto::X509Pointer issuer_;
   // Non-owning cache for SSL_CTX_get_cert_store(ctx_.get())
   X509_STORE* own_cert_store_cache_ = nullptr;
-#ifndef OPENSSL_NO_ENGINE
-  bool client_cert_engine_provided_ = false;
-  ncrypto::EnginePointer private_key_engine_;
-#endif  // !OPENSSL_NO_ENGINE

   unsigned char ticket_key_name_[16];
   unsigned char ticket_key_aes_[16];
diff --git a/src/crypto/crypto_util.cc b/src/crypto/crypto_util.cc
index 8dd7a14e205..d8700e3c85b 100644
--- a/src/crypto/crypto_util.cc
+++ b/src/crypto/crypto_util.cc
@@ -38,9 +38,6 @@ using ncrypto::BignumPointer;
 using ncrypto::BIOPointer;
 using ncrypto::CryptoErrorList;
 using ncrypto::DataPointer;
-#ifndef OPENSSL_NO_ENGINE
-using ncrypto::EnginePointer;
-#endif  // !OPENSSL_NO_ENGINE
 using ncrypto::SSLPointer;
 using v8::Array;
 using v8::ArrayBuffer;
@@ -544,10 +541,6 @@ void InitCryptoOnce() {
   // Turn off compression. Saves memory and protects against CRIME attacks.
   // No-op with OPENSSL_NO_COMP builds of OpenSSL.
   sk_SSL_COMP_zero(SSL_COMP_get_compression_methods());
-
-#ifndef OPENSSL_NO_ENGINE
-  EnginePointer::initEnginesOnce();
-#endif  // !OPENSSL_NO_ENGINE
 }

 void GetFipsCrypto(const FunctionCallbackInfo<Value>& args) {
@@ -1030,28 +1023,6 @@ void ThrowCryptoError(Environment* env,
   env->isolate()->ThrowException(exception);
 }

-#ifndef OPENSSL_NO_ENGINE
-void SetEngine(const FunctionCallbackInfo<Value>& args) {
-  Environment* env = Environment::GetCurrent(args);
-  if (env->permission()->enabled()) [[unlikely]] {
-    return THROW_ERR_CRYPTO_CUSTOM_ENGINE_NOT_SUPPORTED(
-        env,
-        "Programmatic selection of OpenSSL engines is unsupported while the "
-        "experimental permission model is enabled");
-  }
-
-  CHECK(args.Length() >= 2 && args[0]->IsString());
-  uint32_t flags;
-  if (!args[1]->Uint32Value(env->context()).To(&flags)) return;
-
-  const node::Utf8Value engine_id(env->isolate(), args[0]);
-  // If the engine name is not known, calling setAsDefault on the
-  // empty engine pointer will be non-op that always returns false.
-  args.GetReturnValue().Set(
-      EnginePointer::getEngineByName(*engine_id).setAsDefault(flags));
-}
-#endif  // !OPENSSL_NO_ENGINE
-
 MaybeLocal<Value> EncodeBignum(Environment* env, const BIGNUM* bn, int size) {
   EscapableHandleScope scope(env->isolate());
   auto buf = BignumPointer::EncodePadded(bn, size);
@@ -1191,10 +1162,6 @@ void SecureHeapUsed(const FunctionCallbackInfo<Value>& args) {
 namespace Util {
 void Initialize(Environment* env, Local<Object> target) {
   Local<Context> context = env->context();
-#ifndef OPENSSL_NO_ENGINE
-  SetMethod(context, target, "setEngine", SetEngine);
-#endif  // !OPENSSL_NO_ENGINE
-
   SetMethodNoSideEffect(context, target, "getFipsCrypto", GetFipsCrypto);
   SetMethodNoSideEffect(
       context, target, "getFipsCryptoGeneration", GetFipsCryptoGeneration);
@@ -1214,10 +1181,6 @@ void Initialize(Environment* env, Local<Object> target) {
       context, target, "getOpenSSLSecLevelCrypto", GetOpenSSLSecLevelCrypto);
 }
 void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
-#ifndef OPENSSL_NO_ENGINE
-  registry->Register(SetEngine);
-#endif  // !OPENSSL_NO_ENGINE
-
   registry->Register(GetFipsCrypto);
   registry->Register(GetFipsCryptoGeneration);
   registry->Register(SetupFipsIndicatorChannel);
diff --git a/src/crypto/crypto_util.h b/src/crypto/crypto_util.h
index 00ac9f6703a..d299bc7f55b 100644
--- a/src/crypto/crypto_util.h
+++ b/src/crypto/crypto_util.h
@@ -112,7 +112,6 @@ void Decode(const v8::FunctionCallbackInfo<v8::Value>& args,
   V(DERIVING_BITS_FAILED, "Deriving bits failed")                              \
   V(ECDH_FAILED, "ECDH key agreement failed")                                  \
   V(ENCAPSULATION_FAILED, "Encapsulation failed")                              \
-  V(ENGINE_NOT_FOUND, "Engine \"%s\" was not found")                           \
   V(HKDF_FAILED, "HKDF derivation failed")                                     \
   V(INVALID_KEY_TYPE, "Invalid key type")                                      \
   V(KEY_GENERATION_JOB_FAILED, "Key generation job failed")                    \
diff --git a/src/node_constants.cc b/src/node_constants.cc
index ee4eb04ba62..7e4347abdef 100644
--- a/src/node_constants.cc
+++ b/src/node_constants.cc
@@ -86,25 +86,6 @@
 #define DH_NOT_SUITABLE_GENERATOR 0x08
 #endif
 #endif
-#ifndef OPENSSL_NO_ENGINE
-#ifndef OPENSSL_IS_BORINGSSL
-// Engine constants remain public API while engine implementation lives in the
-// dedicated compatibility target.
-#define ENGINE_METHOD_RSA (unsigned int)0x0001
-#define ENGINE_METHOD_DSA (unsigned int)0x0002
-#define ENGINE_METHOD_DH (unsigned int)0x0004
-#define ENGINE_METHOD_RAND (unsigned int)0x0008
-#define ENGINE_METHOD_CIPHERS (unsigned int)0x0040
-#define ENGINE_METHOD_DIGESTS (unsigned int)0x0080
-#define ENGINE_METHOD_PKEY_METHS (unsigned int)0x0200
-#define ENGINE_METHOD_PKEY_ASN1_METHS (unsigned int)0x0400
-#define ENGINE_METHOD_EC (unsigned int)0x0800
-#define ENGINE_METHOD_ALL (unsigned int)0xFFFF
-#define ENGINE_METHOD_NONE (unsigned int)0x0000
-#else
-#include <openssl/engine.h>
-#endif
-#endif  // !OPENSSL_NO_ENGINE
 #endif  // HAVE_OPENSSL

 #if defined(__POSIX__)
@@ -972,54 +953,6 @@ void DefineCryptoConstants(Local<Object> target) {
     NODE_DEFINE_CONSTANT(target, SSL_OP_TLS_ROLLBACK_BUG);
 #endif

-# ifndef OPENSSL_NO_ENGINE
-
-# ifdef ENGINE_METHOD_RSA
-    NODE_DEFINE_CONSTANT(target, ENGINE_METHOD_RSA);
-# endif
-
-# ifdef ENGINE_METHOD_DSA
-    NODE_DEFINE_CONSTANT(target, ENGINE_METHOD_DSA);
-# endif
-
-# ifdef ENGINE_METHOD_DH
-    NODE_DEFINE_CONSTANT(target, ENGINE_METHOD_DH);
-# endif
-
-# ifdef ENGINE_METHOD_RAND
-    NODE_DEFINE_CONSTANT(target, ENGINE_METHOD_RAND);
-# endif
-
-# ifdef ENGINE_METHOD_EC
-    NODE_DEFINE_CONSTANT(target, ENGINE_METHOD_EC);
-# endif
-
-# ifdef ENGINE_METHOD_CIPHERS
-    NODE_DEFINE_CONSTANT(target, ENGINE_METHOD_CIPHERS);
-# endif
-
-# ifdef ENGINE_METHOD_DIGESTS
-    NODE_DEFINE_CONSTANT(target, ENGINE_METHOD_DIGESTS);
-# endif
-
-# ifdef ENGINE_METHOD_PKEY_METHS
-    NODE_DEFINE_CONSTANT(target, ENGINE_METHOD_PKEY_METHS);
-# endif
-
-# ifdef ENGINE_METHOD_PKEY_ASN1_METHS
-    NODE_DEFINE_CONSTANT(target, ENGINE_METHOD_PKEY_ASN1_METHS);
-# endif
-
-# ifdef ENGINE_METHOD_ALL
-    NODE_DEFINE_CONSTANT(target, ENGINE_METHOD_ALL);
-# endif
-
-# ifdef ENGINE_METHOD_NONE
-    NODE_DEFINE_CONSTANT(target, ENGINE_METHOD_NONE);
-# endif
-
-# endif  // !OPENSSL_NO_ENGINE
-
 #ifdef DH_CHECK_P_NOT_SAFE_PRIME
     NODE_DEFINE_CONSTANT(target, DH_CHECK_P_NOT_SAFE_PRIME);
 #endif
diff --git a/src/node_errors.h b/src/node_errors.h
index 8fcea26f6b6..2e44642fe1b 100644
--- a/src/node_errors.h
+++ b/src/node_errors.h
@@ -50,7 +50,6 @@ void OOMErrorHandler(const char* location, const v8::OOMDetails& details);
   V(ERR_CONSTRUCT_CALL_INVALID, TypeError)                                     \
   V(ERR_CPU_PROFILE_NOT_STARTED, Error)                                        \
   V(ERR_CPU_PROFILE_TOO_MANY, Error)                                           \
-  V(ERR_CRYPTO_CUSTOM_ENGINE_NOT_SUPPORTED, Error)                             \
   V(ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS, Error)                                \
   V(ERR_CRYPTO_INITIALIZATION_FAILED, Error)                                   \
   V(ERR_CRYPTO_INVALID_AUTH_TAG, TypeError)                                    \
diff --git a/test/addons/openssl-client-cert-engine/binding.gyp b/test/addons/openssl-client-cert-engine/binding.gyp
deleted file mode 100644
index 726f135a4ca..00000000000
--- a/test/addons/openssl-client-cert-engine/binding.gyp
+++ /dev/null
@@ -1,23 +0,0 @@
-{
-  'targets': [
-    {
-      'target_name': 'testengine',
-      'type': 'none',
-      'includes': ['../common.gypi'],
-      'conditions': [
-        ['OS=="mac" and '
-         'node_use_openssl=="true" and '
-         'node_shared=="false" and '
-         'node_shared_openssl=="false"', {
-          'type': 'shared_library',
-          'sources': [ 'testengine.cc' ],
-          'product_extension': 'engine',
-          'include_dirs': ['../../../deps/openssl/openssl/include'],
-          'xcode_settings': {
-            'OTHER_LDFLAGS': ['-undefined', 'dynamic_lookup'],
-          },
-        }],
-      ]
-    }
-  ]
-}
diff --git a/test/addons/openssl-client-cert-engine/test.js b/test/addons/openssl-client-cert-engine/test.js
deleted file mode 100644
index 77fef53e84f..00000000000
--- a/test/addons/openssl-client-cert-engine/test.js
+++ /dev/null
@@ -1,65 +0,0 @@
-'use strict';
-const common = require('../../common');
-const fixture = require('../../common/fixtures');
-
-if (!common.hasCrypto)
-  common.skip('missing crypto');
-
-const { hasOpenSSL } = require('../../common/crypto');
-
-if (hasOpenSSL(4))
-  common.skip('OpenSSL 4 does not support engines');
-
-const fs = require('fs');
-const path = require('path');
-
-const engine = path.join(__dirname,
-                         `/build/${common.buildType}/testengine.engine`);
-
-if (!fs.existsSync(engine))
-  common.skip('no client cert engine');
-
-const assert = require('assert');
-const https = require('https');
-
-const agentKey = fs.readFileSync(fixture.path('/keys/agent1-key.pem'));
-const agentCert = fs.readFileSync(fixture.path('/keys/agent1-cert.pem'));
-const agentCa = fs.readFileSync(fixture.path('/keys/ca1-cert.pem'));
-
-const serverOptions = {
-  key: agentKey,
-  cert: agentCert,
-  ca: agentCa,
-  requestCert: true,
-  rejectUnauthorized: true,
-};
-
-const server = https.createServer(serverOptions, common.mustCall((req, res) => {
-  res.writeHead(200);
-  res.end('hello world');
-})).listen(0, common.localhostIPv4, common.mustCall(() => {
-  const clientOptions = {
-    method: 'GET',
-    host: common.localhostIPv4,
-    port: server.address().port,
-    path: '/test',
-    clientCertEngine: engine,  // `engine` will provide key+cert
-    rejectUnauthorized: false, // Prevent failing on self-signed certificates
-    headers: {},
-  };
-
-  const req = https.request(clientOptions, common.mustCall((response) => {
-    let body = '';
-    response.setEncoding('utf8');
-    response.on('data', (chunk) => {
-      body += chunk;
-    });
-
-    response.on('end', common.mustCall(() => {
-      assert.strictEqual(body, 'hello world');
-      server.close();
-    }));
-  }));
-
-  req.end();
-}));
diff --git a/test/addons/openssl-client-cert-engine/testengine.cc b/test/addons/openssl-client-cert-engine/testengine.cc
deleted file mode 100644
index 95712901e69..00000000000
--- a/test/addons/openssl-client-cert-engine/testengine.cc
+++ /dev/null
@@ -1,106 +0,0 @@
-#include <openssl/engine.h>
-#include <openssl/pem.h>
-
-#include <assert.h>
-#include <string.h>
-#include <stdlib.h>
-
-#include <fstream>
-#include <iterator>
-#include <string>
-
-#ifndef ENGINE_CMD_BASE
-# error did not get engine.h
-#endif
-
-#define TEST_ENGINE_ID      "testengine"
-#define TEST_ENGINE_NAME    "dummy test engine"
-
-#define AGENT_KEY           "test/fixtures/keys/agent1-key.pem"
-#define AGENT_CERT          "test/fixtures/keys/agent1-cert.pem"
-
-#ifdef _WIN32
-# define DEFAULT_VISIBILITY __declspec(dllexport)
-#else
-# define DEFAULT_VISIBILITY __attribute__((visibility("default")))
-#endif
-
-namespace {
-
-int EngineInit(ENGINE* engine) {
-  return 1;
-}
-
-int EngineFinish(ENGINE* engine) {
-  return 1;
-}
-
-int EngineDestroy(ENGINE* engine) {
-  return 1;
-}
-
-std::string LoadFile(const char* filename) {
-  std::ifstream file(filename);
-  return std::string(std::istreambuf_iterator<char>(file),
-                     std::istreambuf_iterator<char>());
-}
-
-
-int EngineLoadSSLClientCert(ENGINE* engine,
-                            SSL* ssl,
-                            STACK_OF(X509_NAME)* ca_dn,
-                            X509** ppcert,
-                            EVP_PKEY** ppkey,
-                            STACK_OF(X509)** pother,
-                            UI_METHOD* ui_method,
-                            void* callback_data) {
-  if (ppcert != nullptr) {
-    std::string cert = LoadFile(AGENT_CERT);
-    if (cert.empty()) {
-      return 0;
-    }
-
-    BIO* bio = BIO_new_mem_buf(cert.data(), cert.size());
-    *ppcert = PEM_read_bio_X509(bio, nullptr, nullptr, nullptr);
-     BIO_vfree(bio);
-     if (*ppcert == nullptr) {
-       printf("Could not read certificate\n");
-       return 0;
-     }
-  }
-
-  if (ppkey != nullptr) {
-    std::string key = LoadFile(AGENT_KEY);
-    if (key.empty()) {
-      return 0;
-    }
-
-    BIO* bio = BIO_new_mem_buf(key.data(), key.size());
-    *ppkey = PEM_read_bio_PrivateKey(bio, nullptr, nullptr, nullptr);
-    BIO_vfree(bio);
-    if (*ppkey == nullptr) {
-      printf("Could not read private key\n");
-      return 0;
-    }
-  }
-
-  return 1;
-}
-
-int bind_fn(ENGINE* engine, const char* id) {
-  ENGINE_set_id(engine, TEST_ENGINE_ID);
-  ENGINE_set_name(engine, TEST_ENGINE_NAME);
-  ENGINE_set_init_function(engine, EngineInit);
-  ENGINE_set_finish_function(engine, EngineFinish);
-  ENGINE_set_destroy_function(engine, EngineDestroy);
-  ENGINE_set_load_ssl_client_cert_function(engine, EngineLoadSSLClientCert);
-
-  return 1;
-}
-
-extern "C" {
-  DEFAULT_VISIBILITY IMPLEMENT_DYNAMIC_CHECK_FN();
-  DEFAULT_VISIBILITY IMPLEMENT_DYNAMIC_BIND_FN(bind_fn);
-}
-
-}  // anonymous namespace
diff --git a/test/addons/openssl-key-engine/binding.gyp b/test/addons/openssl-key-engine/binding.gyp
deleted file mode 100644
index fc1fafa89ba..00000000000
--- a/test/addons/openssl-key-engine/binding.gyp
+++ /dev/null
@@ -1,23 +0,0 @@
-{
-  'targets': [
-    {
-      'target_name': 'testkeyengine',
-      'type': 'none',
-      'includes': ['../common.gypi'],
-      'conditions': [
-        ['OS=="mac" and '
-         'node_use_openssl=="true" and '
-         'node_shared=="false" and '
-         'node_shared_openssl=="false"', {
-          'type': 'shared_library',
-          'sources': [ 'testkeyengine.cc' ],
-          'product_extension': 'engine',
-          'include_dirs': ['../../../deps/openssl/openssl/include'],
-          'xcode_settings': {
-            'OTHER_LDFLAGS': ['-undefined', 'dynamic_lookup'],
-          },
-        }],
-      ]
-    }
-  ]
-}
diff --git a/test/addons/openssl-key-engine/test.js b/test/addons/openssl-key-engine/test.js
deleted file mode 100644
index 187f95b5141..00000000000
--- a/test/addons/openssl-key-engine/test.js
+++ /dev/null
@@ -1,67 +0,0 @@
-'use strict';
-const common = require('../../common');
-const fixture = require('../../common/fixtures');
-
-if (!common.hasCrypto)
-  common.skip('missing crypto');
-
-const { hasOpenSSL } = require('../../common/crypto');
-
-if (hasOpenSSL(4))
-  common.skip('OpenSSL 4 does not support engines');
-
-const fs = require('fs');
-const path = require('path');
-
-const engine = path.join(__dirname,
-                         `/build/${common.buildType}/testkeyengine.engine`);
-
-if (!fs.existsSync(engine))
-  common.skip('no client cert engine');
-
-const assert = require('assert');
-const https = require('https');
-
-const agentKey = fs.readFileSync(fixture.path('/keys/agent1-key.pem'));
-const agentCert = fs.readFileSync(fixture.path('/keys/agent1-cert.pem'));
-const agentCa = fs.readFileSync(fixture.path('/keys/ca1-cert.pem'));
-
-const serverOptions = {
-  key: agentKey,
-  cert: agentCert,
-  ca: agentCa,
-  requestCert: true,
-  rejectUnauthorized: true,
-};
-
-const server = https.createServer(serverOptions, common.mustCall((req, res) => {
-  res.writeHead(200);
-  res.end('hello world');
-})).listen(0, common.localhostIPv4, common.mustCall(() => {
-  const clientOptions = {
-    method: 'GET',
-    host: common.localhostIPv4,
-    port: server.address().port,
-    path: '/test',
-    privateKeyEngine: engine,
-    privateKeyIdentifier: 'dummykey',
-    cert: agentCert,
-    rejectUnauthorized: false, // Prevent failing on self-signed certificates
-    headers: {},
-  };
-
-  const req = https.request(clientOptions, common.mustCall((response) => {
-    let body = '';
-    response.setEncoding('utf8');
-    response.on('data', (chunk) => {
-      body += chunk;
-    });
-
-    response.on('end', common.mustCall(() => {
-      assert.strictEqual(body, 'hello world');
-      server.close();
-    }));
-  }));
-
-  req.end();
-}));
diff --git a/test/addons/openssl-key-engine/testkeyengine.cc b/test/addons/openssl-key-engine/testkeyengine.cc
deleted file mode 100644
index 704027ba5a4..00000000000
--- a/test/addons/openssl-key-engine/testkeyengine.cc
+++ /dev/null
@@ -1,79 +0,0 @@
-#include <openssl/engine.h>
-#include <openssl/pem.h>
-
-#include <assert.h>
-#include <string.h>
-#include <stdlib.h>
-
-#include <fstream>
-#include <iterator>
-#include <string>
-
-#ifndef ENGINE_CMD_BASE
-# error did not get engine.h
-#endif
-
-#define TEST_ENGINE_ID      "testkeyengine"
-#define TEST_ENGINE_NAME    "dummy test key engine"
-
-#define PRIVATE_KEY           "test/fixtures/keys/agent1-key.pem"
-
-#ifdef _WIN32
-# define DEFAULT_VISIBILITY __declspec(dllexport)
-#else
-# define DEFAULT_VISIBILITY __attribute__((visibility("default")))
-#endif
-
-namespace {
-
-int EngineInit(ENGINE* engine) {
-  return 1;
-}
-
-int EngineFinish(ENGINE* engine) {
-  return 1;
-}
-
-int EngineDestroy(ENGINE* engine) {
-  return 1;
-}
-
-std::string LoadFile(const char* filename) {
-  std::ifstream file(filename);
-  return std::string(std::istreambuf_iterator<char>(file),
-                     std::istreambuf_iterator<char>());
-}
-
-static EVP_PKEY* EngineLoadPrivkey(ENGINE* engine, const char* name,
-                                   UI_METHOD* ui_method, void* callback_data) {
-  if (strcmp(name, "dummykey") == 0) {
-    std::string key = LoadFile(PRIVATE_KEY);
-    BIO* bio = BIO_new_mem_buf(key.data(), key.size());
-    EVP_PKEY* ret = PEM_read_bio_PrivateKey(bio, nullptr, nullptr, nullptr);
-
-    BIO_vfree(bio);
-    if (ret != nullptr) {
-      return ret;
-    }
-  }
-
-  return nullptr;
-}
-
-int bind_fn(ENGINE* engine, const char* id) {
-  ENGINE_set_id(engine, TEST_ENGINE_ID);
-  ENGINE_set_name(engine, TEST_ENGINE_NAME);
-  ENGINE_set_init_function(engine, EngineInit);
-  ENGINE_set_finish_function(engine, EngineFinish);
-  ENGINE_set_destroy_function(engine, EngineDestroy);
-  ENGINE_set_load_privkey_function(engine, EngineLoadPrivkey);
-
-  return 1;
-}
-
-extern "C" {
-  DEFAULT_VISIBILITY IMPLEMENT_DYNAMIC_CHECK_FN();
-  DEFAULT_VISIBILITY IMPLEMENT_DYNAMIC_BIND_FN(bind_fn);
-}
-
-}  // anonymous namespace
diff --git a/test/addons/openssl-test-engine/binding.gyp b/test/addons/openssl-test-engine/binding.gyp
deleted file mode 100644
index fe18de701bb..00000000000
--- a/test/addons/openssl-test-engine/binding.gyp
+++ /dev/null
@@ -1,33 +0,0 @@
-{
-  'targets': [
-    {
-      'target_name': 'testsetengine',
-      'type': 'none',
-      'includes': ['../common.gypi'],
-      'conditions': [
-        ['(OS=="mac" or OS=="linux") and '
-         'node_use_openssl=="true" and '
-         'node_shared=="false" and '
-         'node_shared_openssl=="false"', {
-          'type': 'shared_library',
-          'sources': [ 'testsetengine.cc' ],
-          'product_extension': 'engine',
-          'include_dirs': ['../../../deps/openssl/openssl/include'],
-          'conditions': [
-            ['OS=="mac"', {
-              'xcode_settings': {
-                'OTHER_CFLAGS': ['-Wno-deprecated-declarations'],
-                'OTHER_LDFLAGS': ['-undefined', 'dynamic_lookup'],
-              },
-            }],
-            ['OS=="linux"', {
-              'cflags': [
-                '-Wno-deprecated-declarations',
-              ],
-            }],
-          ],
-        }],
-      ],
-    }
-  ]
-}
diff --git a/test/addons/openssl-test-engine/test.js b/test/addons/openssl-test-engine/test.js
deleted file mode 100644
index e4ce6b5b519..00000000000
--- a/test/addons/openssl-test-engine/test.js
+++ /dev/null
@@ -1,69 +0,0 @@
-'use strict';
-const common = require('../../common');
-
-// This tests crypto.setEngine().
-
-if (!common.hasCrypto)
-  common.skip('missing crypto');
-
-const assert = require('assert');
-const crypto = require('crypto');
-const fs = require('fs');
-const path = require('path');
-
-// Engine support in OpenSSL is checked later on.
-let hasEngineSupport = true;
-
-assert.throws(() => crypto.setEngine(true), /ERR_INVALID_ARG_TYPE|ERR_CRYPTO_CUSTOM_ENGINE_NOT_SUPPORTED/);
-assert.throws(() => crypto.setEngine('/path/to/engine', 'notANumber'),
-              /ERR_INVALID_ARG_TYPE/);
-
-{
-  const invalidEngineName = 'xxx';
-  assert.throws(() => crypto.setEngine(invalidEngineName),
-                /ERR_CRYPTO_ENGINE_UNKNOWN|ERR_CRYPTO_CUSTOM_ENGINE_NOT_SUPPORTED/);
-  assert.throws(() => crypto.setEngine(invalidEngineName,
-                                       crypto.constants.ENGINE_METHOD_RSA),
-                /ERR_CRYPTO_ENGINE_UNKNOWN|ERR_CRYPTO_CUSTOM_ENGINE_NOT_SUPPORTED/);
-}
-
-try {
-  crypto.setEngine('dynamic');
-  crypto.setEngine('dynamic');
-
-  crypto.setEngine('dynamic', crypto.constants.ENGINE_METHOD_RSA);
-  crypto.setEngine('dynamic', crypto.constants.ENGINE_METHOD_RSA);
-} catch (err) {
-  assert.strictEqual(err.code, 'ERR_CRYPTO_CUSTOM_ENGINE_NOT_SUPPORTED');
-  hasEngineSupport = false;
-}
-
-if (hasEngineSupport) {
-  const engine = path.join(__dirname,
-                           `/build/${common.buildType}/testsetengine.engine`);
-
-  if (!fs.existsSync(engine))
-    common.skip('no engine');
-
-  {
-    const engineId = path.parse(engine).name;
-    const execDir = path.parse(engine).dir;
-
-    crypto.setEngine(engine);
-    // OpenSSL 3.0.1 and 1.1.1m now throw errors if an engine is loaded again
-    // with a duplicate absolute path.
-    // TODO(richardlau): figure out why this fails on macOS but not Linux.
-    // crypto.setEngine(engine);
-
-    // crypto.setEngine(engine, crypto.constants.ENGINE_METHOD_RSA);
-    // crypto.setEngine(engine, crypto.constants.ENGINE_METHOD_RSA);
-
-    process.env.OPENSSL_ENGINES = execDir;
-
-    crypto.setEngine(engineId);
-    crypto.setEngine(engineId);
-
-    crypto.setEngine(engineId, crypto.constants.ENGINE_METHOD_RSA);
-    crypto.setEngine(engineId, crypto.constants.ENGINE_METHOD_RSA);
-  }
-}
diff --git a/test/addons/openssl-test-engine/testsetengine.cc b/test/addons/openssl-test-engine/testsetengine.cc
deleted file mode 100644
index 04f57ec4ba6..00000000000
--- a/test/addons/openssl-test-engine/testsetengine.cc
+++ /dev/null
@@ -1,44 +0,0 @@
-#include <openssl/engine.h>
-
-#ifndef ENGINE_CMD_BASE
-# error did not get engine.h
-#endif
-
-#define TEST_ENGINE_ID      "testsetengine"
-#define TEST_ENGINE_NAME    "dummy test engine"
-
-#ifdef _WIN32
-# define DEFAULT_VISIBILITY __declspec(dllexport)
-#else
-# define DEFAULT_VISIBILITY __attribute__((visibility("default")))
-#endif
-
-namespace {
-
-int EngineInit(ENGINE* engine) {
-  return 1;
-}
-
-int EngineFinish(ENGINE* engine) {
-  return 1;
-}
-
-int EngineDestroy(ENGINE* engine) {
-  return 1;
-}
-
-int bind_fn(ENGINE* engine, const char* id) {
-  ENGINE_set_id(engine, TEST_ENGINE_ID);
-  ENGINE_set_name(engine, TEST_ENGINE_NAME);
-  ENGINE_set_init_function(engine, EngineInit);
-  ENGINE_set_finish_function(engine, EngineFinish);
-  ENGINE_set_destroy_function(engine, EngineDestroy);
-  return 1;
-}
-
-extern "C" {
-  DEFAULT_VISIBILITY IMPLEMENT_DYNAMIC_CHECK_FN();
-  DEFAULT_VISIBILITY IMPLEMENT_DYNAMIC_BIND_FN(bind_fn);
-}
-
-}  // anonymous namespace
diff --git a/test/doctool/test-doc-api-json.mjs b/test/doctool/test-doc-api-json.mjs
index 83a0367bde0..ba0469da50a 100644
--- a/test/doctool/test-doc-api-json.mjs
+++ b/test/doctool/test-doc-api-json.mjs
@@ -159,4 +159,4 @@ for await (const dirent of await fs.opendir(new URL('../../out/doc/api/', import
 }

 assert.strictEqual(numberOfDeprecatedSections, 48); // Increase this number every time a new API is deprecated.
-assert.strictEqual(numberOfRemovedAPIs, 46); // Increase this number every time a section is marked as removed.
+assert.strictEqual(numberOfRemovedAPIs, 47); // Increase this number every time a section is marked as removed.
diff --git a/test/parallel/test-crypto-dep0183.js b/test/parallel/test-crypto-dep0183.js
new file mode 100644
index 00000000000..754b90d2de7
--- /dev/null
+++ b/test/parallel/test-crypto-dep0183.js
@@ -0,0 +1,96 @@
+// Flags: --expose-internals
+'use strict';
+
+const common = require('../common');
+if (!common.hasCrypto)
+  common.skip('missing crypto');
+
+const assert = require('assert');
+const crypto = require('crypto');
+const https = require('https');
+const tls = require('tls');
+const { internalBinding } = require('internal/test/binding');
+
+process.on('warning', (warning) => {
+  if (warning.code === 'DEP0183')
+    throw warning;
+});
+
+// DEP0183: OpenSSL engine-based APIs have reached End-of-Life.
+assert.strictEqual(Object.hasOwn(crypto, 'setEngine'), false);
+import('node:crypto').then(common.mustCall((esmCrypto) => {
+  assert.strictEqual(Object.hasOwn(esmCrypto, 'setEngine'), false);
+}));
+
+for (const name of [
+  'ENGINE_METHOD_RSA',
+  'ENGINE_METHOD_DSA',
+  'ENGINE_METHOD_DH',
+  'ENGINE_METHOD_RAND',
+  'ENGINE_METHOD_CIPHERS',
+  'ENGINE_METHOD_DIGESTS',
+  'ENGINE_METHOD_PKEY_METHS',
+  'ENGINE_METHOD_PKEY_ASN1_METHS',
+  'ENGINE_METHOD_EC',
+  'ENGINE_METHOD_ALL',
+  'ENGINE_METHOD_NONE',
+]) {
+  assert.strictEqual(Object.hasOwn(crypto.constants, name), false);
+}
+
+const binding = internalBinding('crypto');
+assert.strictEqual(Object.hasOwn(binding, 'setEngine'), false);
+const secureContext = new binding.SecureContext();
+assert.strictEqual('setEngineKey' in secureContext, false);
+assert.strictEqual('setClientCertEngine' in secureContext, false);
+
+const engineError = {
+  code: 'ERR_CRYPTO_CUSTOM_ENGINE_NOT_SUPPORTED',
+  message: 'Custom engines not supported by this version of Node.js',
+};
+const engineOptions = [
+  { clientCertEngine: 'engine' },
+  { clientCertEngine: 0 },
+  { privateKeyEngine: 'engine' },
+  { privateKeyEngine: false },
+  { privateKeyIdentifier: 'key' },
+  { privateKeyIdentifier: '' },
+  { privateKeyIdentifier: 'key', privateKeyEngine: 'engine' },
+];
+const existingContext = tls.createSecureContext();
+
+// The removed TLS options remain recognized so they cannot appear to work.
+for (const options of engineOptions) {
+  assert.throws(() => tls.createSecureContext(options), engineError);
+  assert.throws(() => tls.createServer(options), engineError);
+  assert.throws(
+    () => tls.connect({ port: 443, secureContext: existingContext, ...options }),
+    engineError,
+  );
+  assert.throws(
+    () => new tls.TLSSocket(undefined, { secureContext: existingContext, ...options }),
+    engineError,
+  );
+  assert.throws(
+    () => https.request({ host: 'localhost', port: 443, agent: false, ...options }),
+    engineError,
+  );
+}
+
+// HTTPS rejects the options before a pooled socket could hide their use.
+const agent = new https.Agent();
+const options = { host: 'example.com', port: 443 };
+for (const removedOption of [
+  'clientCertEngine',
+  'privateKeyEngine',
+  'privateKeyIdentifier',
+]) {
+  assert.throws(
+    () => new https.Agent({ [removedOption]: 'engine' }),
+    engineError,
+  );
+  assert.throws(
+    () => agent.getName({ ...options, [removedOption]: 'engine' }),
+    engineError,
+  );
+}
diff --git a/test/parallel/test-https-agent-getname.js b/test/parallel/test-https-agent-getname.js
index 8ead852b1df..27dca59fec6 100644
--- a/test/parallel/test-https-agent-getname.js
+++ b/test/parallel/test-https-agent-getname.js
@@ -13,13 +13,13 @@ const agent = new https.Agent();
 // empty argument
 assert.strictEqual(
   agent.getName(),
-  'localhost::::::::::::::::::::::'
+  'localhost:::::::::::::::::::'
 );

 // empty options
 assert.strictEqual(
   agent.getName({}),
-  'localhost::::::::::::::::::::::'
+  'localhost:::::::::::::::::::'
 );

 // Pass all options arguments
@@ -29,7 +29,6 @@ const options = {
   localAddress: '192.168.1.1',
   ca: 'ca',
   cert: 'cert',
-  clientCertEngine: 'dynamic',
   ciphers: 'ciphers',
   crl: [Buffer.from('c'), Buffer.from('r'), Buffer.from('l')],
   dhparam: 'dhparam',
@@ -43,15 +42,13 @@ const options = {
   servername: 'localhost',
   sessionIdContext: 'sessionIdContext',
   sigalgs: 'sigalgs',
-  privateKeyIdentifier: 'privateKeyIdentifier',
-  privateKeyEngine: 'privateKeyEngine',
 };

 assert.strictEqual(
   agent.getName(options),
-  '0.0.0.0:443:192.168.1.1:ca:cert:dynamic:ciphers:key:pfx:false:localhost:' +
+  '0.0.0.0:443:192.168.1.1:ca:cert:ciphers:key:pfx:false:localhost:' +
     '::secureProtocol:c,r,l:false:ecdhCurve:dhparam:0:sessionIdContext:' +
-    '"sigalgs":privateKeyIdentifier:privateKeyEngine'
+    '"sigalgs"'
 );

 {
diff --git a/test/parallel/test-tls-clientcertengine-invalid-arg-type.js b/test/parallel/test-tls-clientcertengine-invalid-arg-type.js
deleted file mode 100644
index 811e320b078..00000000000
--- a/test/parallel/test-tls-clientcertengine-invalid-arg-type.js
+++ /dev/null
@@ -1,15 +0,0 @@
-'use strict';
-const common = require('../common');
-
-if (!common.hasCrypto)
-  common.skip('missing crypto');
-
-const assert = require('assert');
-const tls = require('tls');
-
-{
-  assert.throws(
-    () => { tls.createSecureContext({ clientCertEngine: 0 }); },
-    { code: 'ERR_INVALID_ARG_TYPE',
-      message: / Received type number \(0\)/ });
-}
diff --git a/test/parallel/test-tls-clientcertengine-unsupported.js b/test/parallel/test-tls-clientcertengine-unsupported.js
deleted file mode 100644
index 0d24005dc0a..00000000000
--- a/test/parallel/test-tls-clientcertengine-unsupported.js
+++ /dev/null
@@ -1,30 +0,0 @@
-// Flags: --expose-internals
-'use strict';
-const common = require('../common');
-
-if (!common.hasCrypto)
-  common.skip('missing crypto');
-
-const assert = require('assert');
-// Monkey-patch SecureContext
-const { internalBinding } = require('internal/test/binding');
-const binding = internalBinding('crypto');
-const NativeSecureContext = binding.SecureContext;
-
-binding.SecureContext = function() {
-  const rv = new NativeSecureContext();
-  rv.setClientCertEngine = undefined;
-  return rv;
-};
-
-const tls = require('tls');
-
-{
-  assert.throws(
-    () => { tls.createSecureContext({ clientCertEngine: 'Cannonmouth' }); },
-    {
-      code: 'ERR_CRYPTO_CUSTOM_ENGINE_NOT_SUPPORTED',
-      message: 'Custom engines not supported by this OpenSSL'
-    }
-  );
-}
diff --git a/test/parallel/test-tls-error-stack.js b/test/parallel/test-tls-error-stack.js
deleted file mode 100644
index 02021b060ec..00000000000
--- a/test/parallel/test-tls-error-stack.js
+++ /dev/null
@@ -1,21 +0,0 @@
-'use strict';
-
-// This tests that the crypto error stack can be correctly converted.
-const common = require('../common');
-if (!common.hasCrypto)
-  common.skip('missing crypto');
-
-const assert = require('assert');
-const tls = require('tls');
-
-assert.throws(() => {
-  tls.createSecureContext({ clientCertEngine: 'x' });
-}, (err) => {
-  if (err.code === 'ERR_CRYPTO_CUSTOM_ENGINE_NOT_SUPPORTED')
-    common.skip('OpenSSL dropped engine support');
-
-  return err.name === 'Error' &&
-         /could not load the shared library/.test(err.message) &&
-         Array.isArray(err.opensslErrorStack) &&
-        err.opensslErrorStack.length > 0;
-});
diff --git a/test/parallel/test-tls-keyengine-invalid-arg-type.js b/test/parallel/test-tls-keyengine-invalid-arg-type.js
deleted file mode 100644
index 72fe526daff..00000000000
--- a/test/parallel/test-tls-keyengine-invalid-arg-type.js
+++ /dev/null
@@ -1,24 +0,0 @@
-'use strict';
-const common = require('../common');
-
-if (!common.hasCrypto)
-  common.skip('missing crypto');
-
-const assert = require('assert');
-const tls = require('tls');
-
-assert.throws(
-  () => {
-    tls.createSecureContext({ privateKeyEngine: 0,
-                              privateKeyIdentifier: 'key' });
-  },
-  { code: 'ERR_INVALID_ARG_TYPE',
-    message: / Received type number \(0\)$/ });
-
-assert.throws(
-  () => {
-    tls.createSecureContext({ privateKeyEngine: 'engine',
-                              privateKeyIdentifier: 0 });
-  },
-  { code: 'ERR_INVALID_ARG_TYPE',
-    message: / Received type number \(0\)$/ });
diff --git a/test/parallel/test-tls-keyengine-unsupported.js b/test/parallel/test-tls-keyengine-unsupported.js
deleted file mode 100644
index 5fcfe495d51..00000000000
--- a/test/parallel/test-tls-keyengine-unsupported.js
+++ /dev/null
@@ -1,35 +0,0 @@
-// Flags: --expose-internals
-'use strict';
-const common = require('../common');
-
-if (!common.hasCrypto)
-  common.skip('missing crypto');
-
-const assert = require('assert');
-// Monkey-patch SecureContext
-const { internalBinding } = require('internal/test/binding');
-const binding = internalBinding('crypto');
-const NativeSecureContext = binding.SecureContext;
-
-binding.SecureContext = function() {
-  const rv = new NativeSecureContext();
-  rv.setEngineKey = undefined;
-  return rv;
-};
-
-const tls = require('tls');
-
-{
-  assert.throws(
-    () => {
-      tls.createSecureContext({
-        privateKeyEngine: 'engine',
-        privateKeyIdentifier: 'key'
-      });
-    },
-    {
-      code: 'ERR_CRYPTO_CUSTOM_ENGINE_NOT_SUPPORTED',
-      message: 'Custom engines not supported by this OpenSSL'
-    }
-  );
-}
diff --git a/typings/internalBinding/constants.d.ts b/typings/internalBinding/constants.d.ts
index ce962a32e2d..3182b8e088e 100644
--- a/typings/internalBinding/constants.d.ts
+++ b/typings/internalBinding/constants.d.ts
@@ -217,17 +217,6 @@ export interface ConstantsBinding {
     SSL_OP_NO_TLSv1_3: 536870912;
     SSL_OP_PRIORITIZE_CHACHA: 2097152;
     SSL_OP_TLS_ROLLBACK_BUG: 8388608;
-    ENGINE_METHOD_RSA: 1;
-    ENGINE_METHOD_DSA: 2;
-    ENGINE_METHOD_DH: 4;
-    ENGINE_METHOD_RAND: 8;
-    ENGINE_METHOD_EC: 2048;
-    ENGINE_METHOD_CIPHERS: 64;
-    ENGINE_METHOD_DIGESTS: 128;
-    ENGINE_METHOD_PKEY_METHS: 512;
-    ENGINE_METHOD_PKEY_ASN1_METHS: 1024;
-    ENGINE_METHOD_ALL: 65535;
-    ENGINE_METHOD_NONE: 0;
     DH_CHECK_P_NOT_SAFE_PRIME: 2;
     DH_CHECK_P_NOT_PRIME: 1;
     DH_UNABLE_TO_CHECK_GENERATOR: 4;
diff --git a/typings/internalBinding/crypto.d.ts b/typings/internalBinding/crypto.d.ts
index 22ee303f599..3d5a9fceb2e 100644
--- a/typings/internalBinding/crypto.d.ts
+++ b/typings/internalBinding/crypto.d.ts
@@ -697,7 +697,6 @@ declare namespace InternalCryptoBinding {
     init(secureProtocol: string | undefined, minVersion: number, maxVersion: number): void;
     setKey(key: ByteSource, passphrase?: ByteSource): void;
     setSigalgs(sigalgs: string): void;
-    setEngineKey?(privateKeyIdentifier: string, privateKeyEngine: string): void;
     setCert(cert: ByteSource): void;
     setAllowPartialTrustChain(): void;
     addCACert(cert: ByteSource): void;
@@ -717,7 +716,6 @@ declare namespace InternalCryptoBinding {
     setCertificateCompression(algorithms: number): void;
     close(): void;
     loadPKCS12(pfx: ByteSource, passphrase?: ByteSource): void;
-    setClientCertEngine(clientCertEngine: string): void;
     getTicketKeys(): Buffer;
     setTicketKeys(keys: ByteSource): void;
     enableTicketKeyCallback(): void;
@@ -1006,7 +1004,6 @@ export interface CryptoBinding {
   resetRootCertStore(): void;
   secureBuffer(length: number): Uint8Array | undefined;
   secureHeapUsed(): bigint | undefined;
-  setEngine?(engine: string, flags: number): void;
   setupFipsIndicatorChannel(): void;
   setFipsCrypto(fips: boolean | number): void;
   startLoadingCertificatesOffThread(): void;