Some checks failed
build-packages / resolve bundled mosh-client (push) Has been cancelled
build-packages / resolve bundled et-client (push) Has been cancelled
build-packages / build-macos (push) Has been cancelled
build-packages / build-windows (push) Has been cancelled
build-packages / build-linux-x64 (push) Has been cancelled
build-packages / build-linux-arm64 (push) Has been cancelled
build-packages / release (push) Has been cancelled
build-packages / update Nix release metadata (push) Has been cancelled
build-packages / bump homebrew tap (push) Has been cancelled
test / lint-and-test (push) Has been cancelled
AI automation / Route event (push) Has been cancelled
AI automation / Hand reopened issue to maintainers (push) Has been cancelled
AI automation / Clean source issue state (push) Has been cancelled
AI automation / Reconcile handoffs (push) Has been cancelled
AI automation / Classify issue (push) Has been cancelled
AI automation / Claude Code smoke (push) Has been cancelled
AI automation / Review issue follow-up (push) Has been cancelled
AI automation / Publish issue follow-up (push) Has been cancelled
AI automation / Implement with Claude Code (push) Has been cancelled
AI automation / Publish implement PR (push) Has been cancelled
AI automation / Continue queued issue comments (push) Has been cancelled
AI automation / Codex review loop (push) Has been cancelled
AI automation / Publish Codex fix (push) Has been cancelled
AI automation / Clear Codex dispatch marker (push) Has been cancelled
AI automation / Own PR re-request Codex (push) Has been cancelled
AI automation / External PR re-request Codex (push) Has been cancelled
AI automation / Poll Codex reaction / retry (push) Has been cancelled
build-et-binaries / build-linux-x64 (push) Has been cancelled
build-et-binaries / build-linux-arm64 (push) Has been cancelled
build-et-binaries / build-macos-universal (push) Has been cancelled
build-et-binaries / build-windows-x64 (push) Has been cancelled
build-et-binaries / release (push) Has been cancelled
84 lines
3.3 KiB
JavaScript
84 lines
3.3 KiB
JavaScript
/**
|
|
* BoringSSL Diffie-Hellman group compatibility shim.
|
|
*
|
|
* Electron ships with BoringSSL, which no longer exposes some standard MODP
|
|
* groups through the *named* `crypto.createDiffieHellmanGroup()` API — notably
|
|
* the 1024-bit Oakley Group 2 ("modp2") that backs the SSH
|
|
* `diffie-hellman-group1-sha1` key exchange. ssh2 calls
|
|
* `createDiffieHellmanGroup('modp2')` for that kex, so on Electron it throws
|
|
* "Unknown DH group" and legacy network devices that only speak group1-sha1
|
|
* cannot be reached (issue #1035).
|
|
*
|
|
* The underlying DH math still works on BoringSSL via `createDiffieHellman()`
|
|
* with an explicit prime, so this shim wraps `createDiffieHellmanGroup` to fall
|
|
* back to the well-known prime constants when (and only when) the runtime can't
|
|
* resolve a group by name. On OpenSSL builds the original call succeeds and the
|
|
* fallback is never used, so behavior is unchanged there.
|
|
*
|
|
* IMPORTANT: ssh2 destructures `createDiffieHellmanGroup` at module load, so this
|
|
* must be installed BEFORE ssh2 (or any bridge that requires it) is loaded.
|
|
*/
|
|
const crypto = require("node:crypto");
|
|
|
|
// Standard MODP groups (RFC 2409 / RFC 3526), generator 2. These primes are
|
|
// public constants and are byte-identical to Node's built-in groups, so the
|
|
// fallback produces the exact same key exchange the named group would have.
|
|
// Only groups that a runtime might drop yet ssh2 still requests need to live
|
|
// here; modp14/16/18 remain available on BoringSSL so they are intentionally
|
|
// omitted.
|
|
const MODP_GROUP_PRIMES = {
|
|
// Oakley Group 2 — RFC 2409, 1024-bit. ssh2: diffie-hellman-group1-sha1.
|
|
modp2:
|
|
"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" +
|
|
"29024E088A67CC74020BBEA63B139B22514A08798E3404DD" +
|
|
"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" +
|
|
"E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" +
|
|
"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381" +
|
|
"FFFFFFFFFFFFFFFF",
|
|
};
|
|
const MODP_GENERATOR = Buffer.from([0x02]);
|
|
|
|
function createGroupFromPrime(name) {
|
|
const primeHex = MODP_GROUP_PRIMES[name];
|
|
if (!primeHex) return null;
|
|
return crypto.createDiffieHellman(Buffer.from(primeHex, "hex"), MODP_GENERATOR);
|
|
}
|
|
|
|
/**
|
|
* Wrap `target.createDiffieHellmanGroup` so missing named groups fall back to an
|
|
* explicit-prime DiffieHellman. Idempotent. Returns true if it installed the
|
|
* shim, false if it was already installed (or there was nothing to wrap).
|
|
* @param {{ createDiffieHellmanGroup?: Function }} [target] defaults to the crypto module
|
|
*/
|
|
function installBoringSslDhCompat(target = crypto) {
|
|
const original = target.createDiffieHellmanGroup;
|
|
if (typeof original !== "function" || original.__boringSslDhCompat) {
|
|
return false;
|
|
}
|
|
|
|
const wrapped = function createDiffieHellmanGroup(name) {
|
|
try {
|
|
return original(name);
|
|
} catch (err) {
|
|
const fallback = createGroupFromPrime(name);
|
|
if (!fallback) throw err;
|
|
return fallback;
|
|
}
|
|
};
|
|
wrapped.__boringSslDhCompat = true;
|
|
|
|
try {
|
|
target.createDiffieHellmanGroup = wrapped;
|
|
} catch {
|
|
// The property may be read-only on some runtimes; force it via defineProperty.
|
|
Object.defineProperty(target, "createDiffieHellmanGroup", {
|
|
value: wrapped,
|
|
configurable: true,
|
|
writable: true,
|
|
});
|
|
}
|
|
return true;
|
|
}
|
|
|
|
module.exports = { installBoringSslDhCompat, createGroupFromPrime, MODP_GROUP_PRIMES };
|