1
1

knownhosts: detect variations of ecdsa

Этот коммит содержится в:
Aris Adamantiadis 2014-02-04 22:28:30 +01:00
родитель 57418dd2cc
Коммит fdc660f313
5 изменённых файлов: 117 добавлений и 43 удалений

27
include/libssh/knownhosts.h Обычный файл
Просмотреть файл

@ -0,0 +1,27 @@
/*
* This file is part of the SSH Library
*
* Copyright (c) 20014 by Aris Adamantiadis <aris@badcode.be>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef KNOWNHOSTS_H_
#define KNOWNHOSTS_H_
char **ssh_knownhosts_algorithms(ssh_session session);
#endif /* KNOWNHOSTS_H_ */

Просмотреть файл

@ -517,7 +517,6 @@ LIBSSH_API int ssh_key_cmp(const ssh_key k1,
const ssh_key k2, const ssh_key k2,
enum ssh_keycmp_e what); enum ssh_keycmp_e what);
LIBSSH_API int ssh_knownhosts_algorithms(ssh_session session);
LIBSSH_API int ssh_pki_generate(enum ssh_keytypes_e type, int parameter, LIBSSH_API int ssh_pki_generate(enum ssh_keytypes_e type, int parameter,
ssh_key *pkey); ssh_key *pkey);
LIBSSH_API int ssh_pki_import_privkey_base64(const char *b64_key, LIBSSH_API int ssh_pki_import_privkey_base64(const char *b64_key,

Просмотреть файл

@ -35,6 +35,7 @@
#include "libssh/ssh2.h" #include "libssh/ssh2.h"
#include "libssh/string.h" #include "libssh/string.h"
#include "libssh/curve25519.h" #include "libssh/curve25519.h"
#include "libssh/knownhosts.h"
#ifdef HAVE_LIBGCRYPT #ifdef HAVE_LIBGCRYPT
# define BLOWFISH "blowfish-cbc," # define BLOWFISH "blowfish-cbc,"
@ -373,6 +374,51 @@ void ssh_list_kex(struct ssh_kex_struct *kex) {
} }
} }
/**
* @internal
* @brief selects the hostkey mechanisms to be chosen for the key exchange,
* as some hostkey mechanisms may be present in known_hosts file and preferred
* @returns a cstring containing a comma-separated list of hostkey methods.
* NULL if no method matches
*/
static char *ssh_client_select_hostkeys(ssh_session session){
char methods_buffer[128]={0};
static const char *preferred_hostkeys[]={"ecdsa-sha2-nistp521","ecdsa-sha2-nistp384",
"ecdsa-sha2-nistp256", "ssh-rsa", "ssh-dss", "ssh-rsa1", NULL};
char **methods;
int i,j;
int needcoma=0;
methods = ssh_knownhosts_algorithms(session);
if (methods == NULL || methods[0] == NULL)
return NULL;
for (i=0;preferred_hostkeys[i] != NULL; ++i){
for (j=0; methods[j] != NULL; ++j){
if(strcmp(preferred_hostkeys[i], methods[j]) == 0){
if (verify_existing_algo(SSH_HOSTKEYS, methods[j])){
if(needcoma)
strncat(methods_buffer,",",sizeof(methods_buffer)-strlen(methods_buffer)-1);
strncat(methods_buffer, methods[j], sizeof(methods_buffer)-strlen(methods_buffer)-1);
needcoma = 1;
}
}
}
}
for(i=0;methods[i]!= NULL; ++i){
SAFE_FREE(methods[i]);
}
SAFE_FREE(methods);
if(strlen(methods_buffer) > 0){
SSH_LOG(SSH_LOG_DEBUG, "Changing host key method to \"%s\"", methods_buffer);
return strdup(methods_buffer);
} else {
SSH_LOG(SSH_LOG_DEBUG, "No supported kex method for existing key in known_hosts file");
return NULL;
}
}
/** /**
* @brief sets the key exchange parameters to be sent to the server, * @brief sets the key exchange parameters to be sent to the server,
* in function of the options and available methods. * in function of the options and available methods.
@ -380,10 +426,7 @@ void ssh_list_kex(struct ssh_kex_struct *kex) {
int set_client_kex(ssh_session session){ int set_client_kex(ssh_session session){
struct ssh_kex_struct *client= &session->next_crypto->client_kex; struct ssh_kex_struct *client= &session->next_crypto->client_kex;
const char *wanted; const char *wanted;
char methods_buffer[128]={0}; int i;
int prefered_hostkeys[]={SSH_KEYTYPE_ECDSA, SSH_KEYTYPE_RSA,
SSH_KEYTYPE_DSS, SSH_KEYTYPE_RSA1, SSH_KEYTYPE_UNKNOWN};
int i, methods, needcoma=0;
ssh_get_random(client->cookie, 16, 0); ssh_get_random(client->cookie, 16, 0);
@ -391,25 +434,8 @@ int set_client_kex(ssh_session session){
/* first check if we have specific host key methods */ /* first check if we have specific host key methods */
if(session->opts.wanted_methods[SSH_HOSTKEYS] == NULL){ if(session->opts.wanted_methods[SSH_HOSTKEYS] == NULL){
/* Only if no override */ /* Only if no override */
methods = ssh_knownhosts_algorithms(session); session->opts.wanted_methods[SSH_HOSTKEYS] =
if (methods != SSH_ERROR && methods != 0){ ssh_client_select_hostkeys(session);
for(i=0; prefered_hostkeys[i] != SSH_KEYTYPE_UNKNOWN;++i){
if (methods & (1 << prefered_hostkeys[i])){
if (verify_existing_algo(SSH_HOSTKEYS, ssh_key_type_to_char(prefered_hostkeys[i]))){
if(needcoma)
strncat(methods_buffer,",",sizeof(methods_buffer)-strlen(methods_buffer)-1);
strncat(methods_buffer, ssh_key_type_to_char(prefered_hostkeys[i]), sizeof(methods_buffer)-strlen(methods_buffer)-1);
needcoma = 1;
}
}
}
if(strlen(methods_buffer) > 0){
SSH_LOG(SSH_LOG_DEBUG, "Changing host key method to \"%s\"", methods_buffer);
session->opts.wanted_methods[SSH_HOSTKEYS] = strdup(methods_buffer);
} else {
SSH_LOG(SSH_LOG_DEBUG, "No supported kex method for existing key in known_hosts file");
}
}
} }
for (i = 0; i < KEX_METHODS_SIZE; i++) { for (i = 0; i < KEX_METHODS_SIZE; i++) {

Просмотреть файл

@ -34,7 +34,7 @@
#include "libssh/misc.h" #include "libssh/misc.h"
#include "libssh/pki.h" #include "libssh/pki.h"
#include "libssh/options.h" #include "libssh/options.h"
#include "libssh/knownhosts.h"
/*todo: remove this include */ /*todo: remove this include */
#include "libssh/string.h" #include "libssh/string.h"
@ -647,29 +647,33 @@ int ssh_write_knownhost(ssh_session session) {
return 0; return 0;
} }
#define KNOWNHOSTS_MAXTYPES 10
/** /**
* @internal
* @brief Check which kind of host keys should be preferred for connection * @brief Check which kind of host keys should be preferred for connection
* by reading the known_hosts file. * by reading the known_hosts file.
* *
* @param[in] session The SSH session to use. * @param[in] session The SSH session to use.
* *
* @returns Bitfield of supported SSH hostkey algorithms * @returns array of supported key types
* SSH_ERROR on error * NULL on error
*/ */
int ssh_knownhosts_algorithms(ssh_session session) { char **ssh_knownhosts_algorithms(ssh_session session) {
FILE *file = NULL; FILE *file = NULL;
char **tokens; char **tokens;
char *host; char *host;
char *hostport; char *hostport;
const char *type; const char *type;
int match; int match;
int ret = 0; char **array;
int i=0, j;
if (session->opts.knownhosts == NULL) { if (session->opts.knownhosts == NULL) {
if (ssh_options_apply(session) < 0) { if (ssh_options_apply(session) < 0) {
ssh_set_error(session, SSH_REQUEST_DENIED, ssh_set_error(session, SSH_REQUEST_DENIED,
"Can't find a known_hosts file"); "Can't find a known_hosts file");
return SSH_ERROR; return NULL;
} }
} }
@ -683,8 +687,13 @@ int ssh_knownhosts_algorithms(ssh_session session) {
ssh_set_error_oom(session); ssh_set_error_oom(session);
SAFE_FREE(host); SAFE_FREE(host);
SAFE_FREE(hostport); SAFE_FREE(hostport);
return NULL;
}
return SSH_ERROR; array = malloc(sizeof(char *) * KNOWNHOSTS_MAXTYPES);
if (array==NULL){
ssh_set_error_oom(session);
return NULL;
} }
do { do {
@ -709,11 +718,24 @@ int ssh_knownhosts_algorithms(ssh_session session) {
/* We got a match. Now check the key type */ /* We got a match. Now check the key type */
SSH_LOG(SSH_LOG_DEBUG, "server %s:%d has %s in known_hosts", SSH_LOG(SSH_LOG_DEBUG, "server %s:%d has %s in known_hosts",
host, session->opts.port, type); host, session->opts.port, type);
ret |= 1 << ssh_key_type_from_name(type); /* don't copy more than once */
for(j=0;j<i && match;++j){
if(strcmp(array[j], type)==0)
match=0;
}
if (match){
array[i] = strdup(type);
i++;
if(i>= KNOWNHOSTS_MAXTYPES-1){
tokens_free(tokens);
break;
}
}
} }
tokens_free(tokens); tokens_free(tokens);
} while (1); } while (1);
array[i]=NULL;
SAFE_FREE(host); SAFE_FREE(host);
SAFE_FREE(hostport); SAFE_FREE(hostport);
if (file != NULL) { if (file != NULL) {
@ -721,7 +743,7 @@ int ssh_knownhosts_algorithms(ssh_session session) {
} }
/* Return the current state at end of file */ /* Return the current state at end of file */
return ret; return array;
} }
/** @} */ /** @} */

Просмотреть файл

@ -23,6 +23,7 @@
#include "torture.h" #include "torture.h"
#include "session.c" #include "session.c"
#include "known_hosts.c"
#define KNOWNHOSTFILES "libssh_torture_knownhosts" #define KNOWNHOSTFILES "libssh_torture_knownhosts"
#define BADRSA "AAAAB3NzaC1yc2EAAAADAQABAAABAQChm5" \ #define BADRSA "AAAAB3NzaC1yc2EAAAADAQABAAABAQChm5" \
@ -255,8 +256,7 @@ static void torture_knownhosts_precheck(void **state) {
ssh_session session = *state; ssh_session session = *state;
FILE *file; FILE *file;
int rc; int rc;
int dsa; char **kex;
int rsa;
rc = ssh_options_set(session, SSH_OPTIONS_HOST, "localhost"); rc = ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
assert_true(rc == SSH_OK); assert_true(rc == SSH_OK);
@ -270,14 +270,14 @@ static void torture_knownhosts_precheck(void **state) {
fprintf(file, "localhost ssh-dss %s\n", BADDSA); fprintf(file, "localhost ssh-dss %s\n", BADDSA);
fclose(file); fclose(file);
rc = ssh_knownhosts_algorithms(session); kex = ssh_knownhosts_algorithms(session);
assert_true(rc != SSH_ERROR); assert_true(kex != NULL);
dsa = 1 << SSH_KEYTYPE_DSS; assert_string_equal(kex[0],"ssh-rsa");
rsa = 1 << SSH_KEYTYPE_RSA; assert_string_equal(kex[1],"ssh-dss");
assert_true(rc & dsa); assert_true(kex[2]==NULL);
assert_true(rc & rsa); free(kex[1]);
/* nothing else than dsa and rsa */ free(kex[0]);
assert_true((rc & (dsa | rsa)) == rc); free(kex);
} }
int torture_run_tests(void) { int torture_run_tests(void) {