From bbc43cb3337aebd36f8a484d296be268acd07d61 Mon Sep 17 00:00:00 2001 From: Sune Bredahl Date: Wed, 24 May 2017 19:15:53 +0200 Subject: [PATCH] Add support for SHA256 hostkey fingerprints (#180) Looks good, thanks! --- include/libssh2.h | 3 ++- src/hostkey.c | 7 +++++- src/kex.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++ src/libssh2_priv.h | 3 +++ 4 files changed, 66 insertions(+), 2 deletions(-) diff --git a/include/libssh2.h b/include/libssh2.h index 292e64e7..6a9177aa 100644 --- a/include/libssh2.h +++ b/include/libssh2.h @@ -403,7 +403,8 @@ typedef struct _LIBSSH2_POLLFD { /* Hash Types */ #define LIBSSH2_HOSTKEY_HASH_MD5 1 #define LIBSSH2_HOSTKEY_HASH_SHA1 2 - +#define LIBSSH2_HOSTKEY_HASH_SHA256 3 + /* Hostkey Types */ #define LIBSSH2_HOSTKEY_TYPE_UNKNOWN 0 #define LIBSSH2_HOSTKEY_TYPE_RSA 1 diff --git a/src/hostkey.c b/src/hostkey.c index 2a0a8f94..839ba163 100644 --- a/src/hostkey.c +++ b/src/hostkey.c @@ -505,7 +505,7 @@ libssh2_hostkey_methods(void) * Returns hash signature * Returned buffer should NOT be freed * Length of buffer is determined by hash type - * i.e. MD5 == 16, SHA1 == 20 + * i.e. MD5 == 16, SHA1 == 20, SHA256 == 32 */ LIBSSH2_API const char * libssh2_hostkey_hash(LIBSSH2_SESSION * session, int hash_type) @@ -523,6 +523,11 @@ libssh2_hostkey_hash(LIBSSH2_SESSION * session, int hash_type) ? (char *) session->server_hostkey_sha1 : NULL; break; + case LIBSSH2_HOSTKEY_HASH_SHA256: + return (session->server_hostkey_sha256_valid) + ? (char *) session->server_hostkey_sha256 + : NULL; + break; default: return NULL; } diff --git a/src/kex.c b/src/kex.c index 5e761e39..330b02de 100644 --- a/src/kex.c +++ b/src/kex.c @@ -305,6 +305,34 @@ static int diffie_hellman_sha1(LIBSSH2_SESSION *session, "Server's SHA1 Fingerprint: %s", fingerprint); } #endif /* LIBSSH2DEBUG */ + + { + libssh2_sha256_ctx fingerprint_ctx; + + if (libssh2_sha256_init(&fingerprint_ctx)) { + libssh2_sha256_update(fingerprint_ctx, session->server_hostkey, + session->server_hostkey_len); + libssh2_sha256_final(fingerprint_ctx, + session->server_hostkey_sha256); + session->server_hostkey_sha256_valid = TRUE; + } + else { + session->server_hostkey_sha256_valid = FALSE; + } + } +#ifdef LIBSSH2DEBUG + { + char *base64Fingerprint = NULL; + _libssh2_base64_encode(session, (const char*)session->server_hostkey_sha256, + SHA256_DIGEST_LENGTH, &base64Fingerprint); + if (base64Fingerprint != NULL) { + _libssh2_debug(session, LIBSSH2_TRACE_KEX, + "Server's SHA256 Fingerprint: %s", base64Fingerprint); + LIBSSH2_FREE(session, base64Fingerprint); + } + } +#endif /* LIBSSH2DEBUG */ + if (session->hostkey->init(session, session->server_hostkey, session->server_hostkey_len, @@ -931,6 +959,33 @@ static int diffie_hellman_sha256(LIBSSH2_SESSION *session, "Server's SHA1 Fingerprint: %s", fingerprint); } #endif /* LIBSSH2DEBUG */ + + { + libssh2_sha256_ctx fingerprint_ctx; + + if (libssh2_sha256_init(&fingerprint_ctx)) { + libssh2_sha256_update(fingerprint_ctx, session->server_hostkey, + session->server_hostkey_len); + libssh2_sha256_final(fingerprint_ctx, + session->server_hostkey_sha256); + session->server_hostkey_sha256_valid = TRUE; + } + else { + session->server_hostkey_sha256_valid = FALSE; + } + } +#ifdef LIBSSH2DEBUG + { + char *base64Fingerprint = NULL; + _libssh2_base64_encode(session, (const char*)session->server_hostkey_sha256, + SHA256_DIGEST_LENGTH, &base64Fingerprint); + if (base64Fingerprint != NULL) { + _libssh2_debug(session, LIBSSH2_TRACE_KEX, + "Server's SHA256 Fingerprint: %s", base64Fingerprint); + LIBSSH2_FREE(session, base64Fingerprint); + } + } +#endif /* LIBSSH2DEBUG */ if (session->hostkey->init(session, session->server_hostkey, session->server_hostkey_len, diff --git a/src/libssh2_priv.h b/src/libssh2_priv.h index 0114331c..2e3e6345 100644 --- a/src/libssh2_priv.h +++ b/src/libssh2_priv.h @@ -609,6 +609,9 @@ struct _LIBSSH2_SESSION unsigned char server_hostkey_sha1[SHA_DIGEST_LENGTH]; int server_hostkey_sha1_valid; + unsigned char server_hostkey_sha256[SHA256_DIGEST_LENGTH]; + int server_hostkey_sha256_valid; + /* (remote as source of data -- packet_read ) */ libssh2_endpoint_data remote;