-
Notifications
You must be signed in to change notification settings - Fork 32
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
getHostKey returns an empty string #66
Comments
I would suggest the following plan of investigation:
|
Thanks. I ran my code against https://hub.docker.com/r/atmoz/sftp which has both an RSA and an ED25519 host key. I also find an empty string as the host key. Going further, I adapted the SFTP example from libss2 into a minimal example to fetch the host key in C (code below). This code also returns an empty string, but does print a finger print:
I added a function to get the finger print on Haskell and can confirm that even though the host key is an empty string, I can get a finger print. At this point, I suspect that /*
* "sftp 192.168.0.1 22 user password"
*/
#include "libssh2_config.h"
#include <libssh2.h>
#include <libssh2_sftp.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
const char *username = "username";
const char *password = "password";
short port = 22;
static const char *const hostkey_method_ssh_ed25519 = "ssh-ed25519";
static const char *const hostkey_method_ssh_rsa = "ssh-rsa";
static const char *const hostkey_method_ssh_dss = "ssh-dss";
static const char *const hostkey_method_ssh_all = "ssh-ed25519,ssh-rsa,ssh-dss";
int main(int argc, char *argv[])
{
unsigned long hostaddr;
int sock;
struct sockaddr_in sin;
const char *fingerprint;
LIBSSH2_SESSION *session;
int rc;
LIBSSH2_SFTP *sftp_session;
if(argc != 5) {
fprintf(stderr, "%s host port user pass\n", argv[0]);
return 1;
}
hostaddr = inet_addr(argv[1]);
port = atoi(argv[2]);
username = argv[3];
password = argv[4];
rc = libssh2_init(0);
if(rc != 0) {
fprintf(stderr, "libssh2 initialization failed (%d)\n", rc);
return 1;
}
/*
* The application code is responsible for creating the socket
* and establishing the connection
*/
sock = socket(AF_INET, SOCK_STREAM, 0);
sin.sin_family = AF_INET;
sin.sin_port = htons(port);
sin.sin_addr.s_addr = hostaddr;
if(connect(sock, (struct sockaddr*)(&sin),
sizeof(struct sockaddr_in)) != 0) {
fprintf(stderr, "failed to connect!\n");
return -1;
}
/* Create a session instance
*/
session = libssh2_session_init();
if(!session)
return -1;
/* Since we have set non-blocking, tell libssh2 we are blocking */
libssh2_session_set_blocking(session, 1);
rc = libssh2_session_method_pref(session, LIBSSH2_METHOD_HOSTKEY, hostkey_method_ssh_all); //"ssh-ed25519,ssh-rsa,ssh-dss");
if(rc) {
fprintf(stderr, "Failure setting method prefs: %d\n", rc);
return -1;
}
/* ... start it up. This will trade welcome banners, exchange keys,
* and setup crypto, compression, and MAC layers
*/
rc = libssh2_session_handshake(session, sock);
if(rc) {
fprintf(stderr, "Failure establishing SSH session: %d\n", rc);
return -1;
}
/* At this point we havn't yet authenticated. The first thing to do
* is check the hostkey's fingerprint against our known hosts Your app
* may have it hard coded, may go to a file, may present it to the
* user, that's your call
*/
fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1);
fprintf(stderr, "Fingerprint: ");
for(int i = 0; i < 20; i++) {
fprintf(stderr, "%02X ", (unsigned char)fingerprint[i]);
}
fprintf(stderr, "\n");
int hostkey_type = 0;
const char *hostkey = libssh2_session_hostkey(session, NULL, &hostkey_type);
fprintf(stderr, "Host key: \"%s\"\nHost key type: %d\n", hostkey, hostkey_type);
/* Authenticate via password */
if(libssh2_userauth_password(session, username, password)) {
fprintf(stderr, "Authentication by password failed.\n");
goto shutdown;
}
sftp_session = libssh2_sftp_init(session);
if(!sftp_session) {
fprintf(stderr, "Unable to init SFTP session\n");
goto shutdown;
}
libssh2_sftp_shutdown(sftp_session);
shutdown:
libssh2_session_disconnect(session, "Normal Shutdown");
libssh2_session_free(session);
close(sock);
fprintf(stderr, "all done\n");
libssh2_exit();
return 0;
} |
In libssh2-hs, Unfortunately I am not a big libssh2 expert :) Personally I use only a couple of features of this library (keys-based auth, execute commands + scp). So if you need to know which libssh2's functions must be called and in which order (and can't find it in documentation or examples), you probably have to consult with libssh2's developers. Last time I checked the main place of communication was the mailing list, but now it seems that github issue tracker is also alive. |
Thanks; I wrote to the mailing list. I'll post the answer if/when I have it :) |
refs #66 Although this is a bug fix, this changes Haskell type signatures of exported functions.
Haha :)
The funny thing is, it appears that I implemented a fix in the PR #67. Please review. Since Haskell type signatures of exported functions are changed (String -> ByteString), this may be a breaking change, so I'll have to publish a new "major" version on hackage — 0.2.1.0, for example. |
Haha yea it was quite the "D'oh" moment :)
Please do! It would make my life easier not having to carry this in my custom implementation. That said, I'll quickly open a PR to add some ciphers :) |
The C function libssh2_session_hostkey returns a const char* where the first byte is (often) a NULL byte. This causes the Haskell FFI to return an empty String. Hence, we create a new FFI to libssh2_session_hostkey that returns a Ptr CChar, that we then wrap in a function that returns a base64 encoded String. This way we can capture the host key, including its NULL byte, in a proper Haskell type. Although this is a bug fix, this changes Haskell type signatures of exported functions. See portnov#66.
The user needs to be able to specify the format of the hostname, key and key type. Although this is a bug fix, this changes Haskell type signatures of exported functions. See portnov#66.
The C function libssh2_session_hostkey returns a const char* where the first byte is (often) a NULL byte. This causes the Haskell FFI to return an empty String. Hence, we create a new FFI to libssh2_session_hostkey that returns a Ptr CChar, that we then wrap in a function that returns a base64 encoded String. This way we can capture the host key, including its NULL byte, in a proper Haskell type. Although this is a bug fix, this changes Haskell type signatures of exported functions. See portnov#66.
The user needs to be able to specify the format of the hostname, key and key type. Although this is a bug fix, this changes Haskell type signatures of exported functions. See portnov#66.
The C function libssh2_session_hostkey returns a const char* where the first byte is (often) a NULL byte. This causes the Haskell FFI to return an empty String. Hence, we create a new FFI to libssh2_session_hostkey that returns a Ptr CChar, that we then wrap in a function that returns a base64 encoded String. This way we can capture the host key, including its NULL byte, in a proper Haskell type. Although this is a bug fix, this changes Haskell type signatures of exported functions. See portnov#66.
The user needs to be able to specify the format of the hostname, key and key type. Although this is a bug fix, this changes Haskell type signatures of exported functions. See portnov#66.
The C function libssh2_session_hostkey returns a const char* where the first byte is (often) a NULL byte. This causes the Haskell FFI to return an empty String. Hence, we create a new FFI to libssh2_session_hostkey that returns a Ptr CChar, that we then wrap in a function that returns a base64 encoded String. This way we can capture the host key, including its NULL byte, in a proper Haskell type. Although this is a bug fix, this changes Haskell type signatures of exported functions. See portnov#66.
The user needs to be able to specify the format of the hostname, key and key type. Although this is a bug fix, this changes Haskell type signatures of exported functions. See portnov#66.
Hello,
I am running into the case where
getHostKey
always returns an empty string. This happens on two very distinct SFTP servers, one of which is an AWS Transfer Family SFTP server; the other is an old mainframe-like SFTP server.In both cases, the host key type returned is
1
, which I assume to beTYPE_PLAIN
as perlibssh2-hs/libssh2/src/Network/SSH/Client/LibSSH2/Foreign.chs
Line 114 in 58f5a34
Below is the code I use to initialise my SFTP session:
As far as I can see, the FFI in libssh2-hs for
getHostKey
is correct. Am I missing something?The text was updated successfully, but these errors were encountered: