Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Example of how to perform host key validation #1397

Closed
billchurch opened this issue Jun 14, 2024 · 2 comments
Closed

Example of how to perform host key validation #1397

billchurch opened this issue Jun 14, 2024 · 2 comments
Labels

Comments

@billchurch
Copy link

billchurch commented Jun 14, 2024

I'm sure this is probably obvious to others, but I'm struggling with it. My goal is to validate host keys in a similar method to ~./ssh/known_hosts the method doesn't have to be identical but obviously I want to know if someone is attempting to MITM.

In a perfect world, I would want to be able to import an existing known_hosts into an application and support that, but I'll do it however I can to support some sort of validation of host public keys. I'm currrently on ssh2 v1.5.0 and node v16.15.1.

Right now, here's my basic code for "interrogating" the hostkeys event:

  conn.on('hostkeys', (keys) => {
    checkHostKeys(keys, connectionID);
  });

and then the checkHostKeys function

// hostKeyChecker.js
/**
 * Logs the host keys.
 * @param {Array} keys - The host keys.
 * @param {string} connectionID - Unique connection ID.
 */
const { utils: { parseKey } } = require('ssh2');

function checkHostKeys(keys, connectionID) {
  keys.forEach((obj) => {
    console.log(obj.type);

    const publicKeyPEMSymbol = Object.getOwnPropertySymbols(obj).find(
      (sym) => sym.description === 'Public key PEM',
    );
    const publicKeyPEM = obj[publicKeyPEMSymbol];

    const parsedKey = parseKey(publicKeyPEM);
    const publicKeyKnownHosts = parsedKey.toString('base64');

    console.log(`${obj.type} ${publicKeyKnownHosts}`);
  });
}

module.exports = {
  checkHostKeys,
};

and here's what I get for console logs:

ssh-rsa
ssh-rsa Error: Unsupported key format
ecdsa-sha2-nistp256
ecdsa-sha2-nistp256 Error: Unsupported key format
ssh-ed25519
ssh-ed25519 Error: Unsupported key format

Am I just grabbing the wrong object or what? If I log the publicKeyPEM it looks "right". I've also tried this the Public key SSH object:

// hostKeyChecker.js
/**
 * Logs the host keys.
 * @param {Array} keys - The host keys.
 * @param {string} connectionID - Unique connection ID.
 */
const { utils: { parseKey } } = require('ssh2');

function checkHostKeys(keys, connectionID) {
  keys.forEach((obj) => {
    console.log(obj.type);

    const publicKeySSHSymbol = Object.getOwnPropertySymbols(obj).find(
      (sym) => sym.description === 'Public key SSH',
    );
    const publicKeySSH = obj[publicKeySSHSymbol];
    console.log(`publicKeySSH: ${publicKeySSH.toString('base64')}`);

    if (Buffer.isBuffer(publicKeySSH)) {
      const parsedKey = parseKey(publicKeySSH);
      console.log(`parsedKey: ${JSON.stringify(parsedKey)}`);
    } else {
      console.log(`Public key SSH is not a buffer for ${obj.type}`);
    }
  });
}

module.exports = {
  checkHostKeys,
};

Result:

ssh-rsa
publicKeySSH: AAAAB3NzaC1yc2EAAAADAQABAAABgQCgdXcp7P5SYDrIyHmoum4amWh1rqaW76Cn4RjffDSjZRgbzu65GcCQRw2iVndEzE1/puvgFb7MbK5/v9kRibEI3h7AkmL9vKJ+eCxRMUx+rbPRZUsjEw5+l4Wx89Yo+0B4PYNV2atn7VdoRHnFBu4nbU85sUZflq5/Pwm66XdxymjJgtmZM+wiG7CMQw/2x73gtH6FGb8n4jSjB5rs2OwAVL2tVTo6mZbk9UaXYq7gc5AZh3PSiH/q4wFyxmz2mcpGntyTMebE8i+avj+MRiPOK6CD6zFKS7KikF0KqeMCexIlP9X0JRF5xVdEDHFsrB3/4583qiM6l2DfrOGYc+7nYoKBQ7WHPpz4oJh78wmhmbv0vvVTLcKmnvmMECCq6HR0aRem0uP/ic9eI9Z6j5A0opBcj+hVhf9CO7ITTmGuwx8uzrCg+48GVouJGc8p+95Ij8VExODNFgy95x5HpftH+f5VYJbTpi57eK+wyYK65E3tfBycJtoGxI4h3DIHMzE=
parsedKey: {"type":"ssh-rsa","comment":""}
ecdsa-sha2-nistp256
publicKeySSH: AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBNZ4dxHTT8JUK7zPNfFheI3Ezw3PgnDfXsTtHyYU/Csiblzw8XDGkWqKKCsZSo7ECwEuYO4QoY5SvubUbzkFncU=
parsedKey: {"type":"ecdsa-sha2-nistp256","comment":""}
ssh-ed25519
publicKeySSH: AAAAC3NzaC1lZDI1NTE5AAAAIFVD//VThP9wwKxIYuuN9FgU+BBcLnLdCfXPLcczhHJP
parsedKey: {"type":"ssh-ed25519","comment":""}

I might be just missing something plainly obvious.

Thanks!

@mscdex
Copy link
Owner

mscdex commented Jun 14, 2024

The PEM files are for use with OpenSSL (since OpenSSL doesn't understand SSH key formats). You want the SSH public key for known_hosts. Also, there is key.getPublicSSH() to get at the SSH format public key (instead of prying into internal symbols).

@billchurch
Copy link
Author

Gotcha, I wasn't getting that for some reason... It's quite obvious now, thanks for pointing me in the right direction.

I ended up with this as my placeholder and it seems to return keys as expected.

// hostKeyChecker.js
/**
 * Processes the host keys and returns an array of objects
 * containing the key type and publicKeyKnownHosts.
 * @param {Array} keys - The host keys.
 * @returns {Array} An array of objects with key type and publicKeyKnownHosts.
 */
function checkHostKeys(keys) {
  return keys
    .map((obj) => {
      const publicKeySSH = obj.getPublicSSH();

      if (Buffer.isBuffer(publicKeySSH)) {
        return {
          type: obj.type,
          publicKeyKnownHosts: publicKeySSH.toString('base64'),
        };
      }
      console.error(`Public key SSH is not a buffer for ${obj.type}`);
      return null;
    })
    .filter(Boolean);
}

module.exports = {
  checkHostKeys,
};

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants