{"record":{"id":"000de8ede495d963","repo":"denoland/deno","slug":"err-crypto-custom-engine-not-supported","errorCode":"ERR_CRYPTO_CUSTOM_ENGINE_NOT_SUPPORTED","errorMessage":"Custom engines not supported by this OpenSSL","messagePattern":"Custom engines not supported by this OpenSSL","errorType":"error_code","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"ext/node/polyfills/_tls_common.ts","lineNumber":544,"sourceCode":"      err.function = \"dlfcn_load\";\n      err.reason = \"could not load the shared library\";\n      err.code = \"ERR_OSSL_DSO_COULD_NOT_LOAD_THE_SHARED_LIBRARY\";\n      throw err;\n    }\n    if (options.privateKeyEngine != null) {\n      validateString(options.privateKeyEngine, \"options.privateKeyEngine\");\n    }\n    if (options.privateKeyIdentifier != null) {\n      validateString(\n        options.privateKeyIdentifier,\n        \"options.privateKeyIdentifier\",\n      );\n    }\n    if (\n      options.privateKeyEngine != null &&\n      options.privateKeyIdentifier != null\n    ) {\n      throw new ERR_CRYPTO_CUSTOM_ENGINE_NOT_SUPPORTED();\n    }\n    if (options.ecdhCurve != null) {\n      validateString(options.ecdhCurve, \"options.ecdhCurve\");\n    }\n    // Validate cert before key - Node.js processes cert first (SetCert before SetKey)\n    validateKeyCertOption(options.cert, \"options.cert\", false);\n    validateKeyCertOption(options.key, \"options.key\", true);\n    validateKeyCertOption(options.ca, \"options.ca\", false);\n\n    // Load PFX / PKCS#12 data: extract the cert + private key so they can\n    // be used by the underlying TLS implementation. Any additional certs\n    // present in the PFX are merged into `ca`. Caller-supplied `cert`/`key`\n    // (and `ca`) take precedence, matching Node, which loads PFX first and\n    // then layers explicit cert/key on top.\n    //\n    // Node accepts both a single <string>|<Buffer> and an\n    // <Array<string|Buffer|{ buf, passphrase? }>>; an empty array (which\n    // playwright passes when no PFX is configured) must be a no-op rather","sourceCodeStart":526,"sourceCodeEnd":562,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/node/polyfills/_tls_common.ts#L526-L562","documentation":"Node.js can load private keys from an OpenSSL engine/PKCS#11 provider via options.privateKeyIdentifier (the key label) plus options.privateKeyEngine (the engine name). Deno's TLS stack is rustls and has no OpenSSL engine support, so after validating both strings the polyfill throws ERR_CRYPTO_CUSTOM_ENGINE_NOT_SUPPORTED when both are set, failing fast instead of silently ignoring the HSM key.","triggerScenarios":"tls.createSecureContext({ privateKeyIdentifier: 'my-key', privateKeyEngine: 'pkcs11', ... }) — both options non-null at the same time. Any config written for Node with HSM/PKCS#11 keys reused under Deno.","commonSituations":"Porting Node services that use SoftHSM, cloud HSM, or cloud KMS via OpenSSL engines; enterprise mTLS where keys never leave hardware; migration to Deno without auditing TLS key loading.","solutions":["Drop privateKeyEngine/privateKeyIdentifier and supply key material directly as PEM (string/Buffer or { pem, passphrase } in a key array)","If the key must stay in the HSM, run that workload on a runtime with OpenSSL engine support or terminate TLS at a proxy in front of Deno","Feature-detect the config: if both options are present, branch to an alternative key-provisioning path before calling createSecureContext"],"exampleFix":"// before\nconst ctx = tls.createSecureContext({\n  privateKeyIdentifier: 'hsm-key-1',\n  privateKeyEngine: 'pkcs11',\n  cert,\n}); // throws ERR_CRYPTO_CUSTOM_ENGINE_NOT_SUPPORTED\n\n// after\nconst ctx = tls.createSecureContext({\n  key: [{ pem: process.env.TLS_KEY_PEM!, passphrase: process.env.TLS_KEY_PASS }],\n  cert,\n});","handlingStrategy":"validation","validationCode":"if (cfg.privateKeyEngine != null && cfg.privateKeyIdentifier != null) {\n  // Deno has no OpenSSL engine support; fail early with a clear message\n  throw new Error('HSM engine keys (privateKeyEngine/privateKeyIdentifier) are not supported; provide PEM key material instead');\n}\nconst ctx = tls.createSecureContext(cfg);","typeGuard":null,"tryCatchPattern":"try {\n  ctx = tls.createSecureContext(cfg);\n} catch (err) {\n  if ((err as NodeJS.ErrnoException).code === 'ERR_CRYPTO_CUSTOM_ENGINE_NOT_SUPPORTED') {\n    ctx = tls.createSecureContext({ ...cfg, privateKeyEngine: undefined, privateKeyIdentifier: undefined, key: pemKey });\n  } else throw err;\n}","preventionTips":["Audit TLS config for engine options before moving a Node service to Deno","Provision PEM key material (or a provider that exports PEM) as the portable baseline","Document runtime requirements: HSM-backed TLS pins the workload to OpenSSL-based runtimes"],"tags":["tls","crypto","hsm","pkcs11","node-compat","unsupported-feature"],"backgroundTag":"custom-crypto-engine-unsupported","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","contentChangedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}