diff --git a/nodejs/services/bridge.js b/nodejs/services/bridge.js index eec9f4f..e1edec5 100644 --- a/nodejs/services/bridge.js +++ b/nodejs/services/bridge.js @@ -23,7 +23,7 @@ function counter(onBytes) { // Connect the upstream ssh2.Client, retrying once after a short pause if the // first attempt fails auth (SSSD/AuthorizedKeysCommand cache lag right after a // first-time key injection). -function connectUpstream({ host, port, username, privateKey, cert, onHostKey, uid, justInjected }) { +function connectUpstream({ host, port, username, privateKey, cert, onHostKey, uid, justInjected, expectedHostKeyFp }) { return new Promise((resolve, reject) => { let attempted = false; const dial = (allowRetry) => { @@ -48,7 +48,10 @@ function connectUpstream({ host, port, username, privateKey, cert, onHostKey, ui hostVerifier: (key) => { const fp = 'SHA256:' + crypto.createHash('sha256').update(key).digest('base64').replace(/=+$/, ''); if (onHostKey) onHostKey(fp); - return true; // v1: trust-on-use, fingerprint audited. Pinning = follow-up. + if (expectedHostKeyFp && expectedHostKeyFp !== fp) { + return false; + } + return true; // v1: trust-on-use if not pinned, fingerprint audited. }, }); }; diff --git a/nodejs/services/ssh_server.js b/nodejs/services/ssh_server.js index 6a47694..3f4d65e 100644 --- a/nodejs/services/ssh_server.js +++ b/nodejs/services/ssh_server.js @@ -150,6 +150,7 @@ async function resolveAndConnect(state, record, { onHostKey } = {}) { host: endpoint.address, port: endpoint.port, username: state.uid, privateKey: JUMP_KEYS.clientKey, cert, uid: state.uid, justInjected, onHostKey, + expectedHostKeyFp: host && host.metadata && host.metadata.sshHostKeyFp, }); } catch (err) { throw fail('upstream-unreachable', err.message, host ? host.slug : undefined); } @@ -261,6 +262,7 @@ async function runTuiSession(session, client, state) { host: endpoint.address, port: endpoint.port, username: state.uid, privateKey: JUMP_KEYS.clientKey, cert, uid: state.uid, justInjected, onHostKey: (fp) => record.patch({ hostKeyFp: fp }), + expectedHostKeyFp: tui.host && tui.host.metadata && tui.host.metadata.sshHostKeyFp, }); } catch (err) { try { tui.channel.write(`\r\n Could not reach ${endpoint.address}.\r\n`); tui.channel.close(); } catch (_) {}