kex: split key selection and sending
Этот коммит содержится в:
родитель
1b10b175fc
Коммит
07abc3406d
@ -35,5 +35,8 @@
|
||||
int ssh_client_ecdh_init(ssh_session session);
|
||||
int ssh_client_ecdh_reply(ssh_session session, ssh_buffer packet);
|
||||
|
||||
#ifdef WITH_SERVER
|
||||
int ssh_server_ecdh_init(ssh_session session, ssh_buffer packet);
|
||||
#endif /* WITH_SERVER */
|
||||
|
||||
#endif /* ECDH_H_ */
|
||||
|
@ -25,6 +25,13 @@
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/callbacks.h"
|
||||
|
||||
#define SSH_KEX_METHODS 10
|
||||
|
||||
typedef struct ssh_kex_struct {
|
||||
unsigned char cookie[16];
|
||||
char *methods[SSH_KEX_METHODS];
|
||||
} KEX;
|
||||
|
||||
SSH_PACKET_CALLBACK(ssh_packet_kexinit);
|
||||
#ifdef WITH_SSH1
|
||||
SSH_PACKET_CALLBACK(ssh_packet_publickey1);
|
||||
|
@ -121,11 +121,6 @@ extern "C" {
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
typedef struct kex_struct {
|
||||
unsigned char cookie[16];
|
||||
char **methods;
|
||||
} KEX;
|
||||
|
||||
struct error_struct {
|
||||
/* error handling */
|
||||
int error_code;
|
||||
@ -137,6 +132,7 @@ struct error_struct {
|
||||
|
||||
struct ssh_message_struct;
|
||||
struct ssh_common_struct;
|
||||
struct ssh_kex_struct;
|
||||
|
||||
/* server data */
|
||||
|
||||
@ -197,8 +193,9 @@ void ssh_sock_set_blocking(socket_t sock);
|
||||
/* in kex.c */
|
||||
extern const char *ssh_kex_nums[];
|
||||
int ssh_send_kex(ssh_session session, int server_kex);
|
||||
void ssh_list_kex(ssh_session session, KEX *kex);
|
||||
int set_kex(ssh_session session);
|
||||
void ssh_list_kex(ssh_session session, struct ssh_kex_struct *kex);
|
||||
int set_client_kex(ssh_session session);
|
||||
int ssh_kex_select_methods(ssh_session session);
|
||||
int verify_existing_algo(int algo, const char *name);
|
||||
char **space_tokenize(const char *chain);
|
||||
int ssh_get_kex1(ssh_session session);
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "libssh/auth.h"
|
||||
#include "libssh/channels.h"
|
||||
#include "libssh/poll.h"
|
||||
#include "libssh/kex.h"
|
||||
|
||||
/* These are the different states a SSH session can be into its life */
|
||||
enum ssh_session_state_e {
|
||||
@ -122,8 +123,11 @@ struct ssh_session_struct {
|
||||
struct ssh_agent_state_struct *agent_state;
|
||||
struct ssh_auth_auto_state_struct *auth_auto_state;
|
||||
|
||||
/* kex sent by server, client, and mutually elected methods */
|
||||
KEX server_kex;
|
||||
KEX client_kex;
|
||||
char *kex_methods[SSH_KEX_METHODS];
|
||||
|
||||
ssh_buffer in_hashbuf;
|
||||
ssh_buffer out_hashbuf;
|
||||
struct ssh_crypto_struct *current_crypto;
|
||||
|
@ -546,9 +546,11 @@ static void ssh_client_connection_callback(ssh_session session){
|
||||
case SSH_SESSION_STATE_KEXINIT_RECEIVED:
|
||||
set_status(session,0.6f);
|
||||
ssh_list_kex(session, &session->server_kex);
|
||||
if (set_kex(session) < 0) {
|
||||
if (set_client_kex(session) < 0) {
|
||||
goto error;
|
||||
}
|
||||
if (ssh_kex_select_methods(session) == SSH_ERROR)
|
||||
goto error;
|
||||
if (ssh_send_kex(session, 0) < 0) {
|
||||
goto error;
|
||||
}
|
||||
@ -819,8 +821,7 @@ error:
|
||||
SAFE_FREE(session->server_kex.methods[i]);
|
||||
}
|
||||
}
|
||||
SAFE_FREE(session->client_kex.methods);
|
||||
SAFE_FREE(session->server_kex.methods);
|
||||
|
||||
if(session->ssh_message_list){
|
||||
ssh_message msg;
|
||||
while((msg=ssh_list_pop_head(ssh_message ,session->ssh_message_list))
|
||||
|
@ -166,4 +166,12 @@ error:
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
#ifdef WITH_SERVER
|
||||
|
||||
int ssh_server_ecdh_init(ssh_session session, ssh_buffer packet){
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
#endif /* WITH_SERVER */
|
||||
|
||||
#endif /* HAVE_ECDH */
|
||||
|
91
src/kex.c
91
src/kex.c
@ -303,22 +303,10 @@ SSH_PACKET_CALLBACK(ssh_packet_kexinit){
|
||||
|
||||
/* copy the server kex info into an array of strings */
|
||||
if (server_kex) {
|
||||
session->client_kex.methods = malloc(10 * sizeof(char **));
|
||||
if (session->client_kex.methods == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
goto error;
|
||||
}
|
||||
|
||||
for (i = 0; i < 10; i++) {
|
||||
session->client_kex.methods[i] = strings[i];
|
||||
}
|
||||
} else { /* client */
|
||||
session->server_kex.methods = malloc(10 * sizeof(char **));
|
||||
if (session->server_kex.methods == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
goto error;
|
||||
}
|
||||
|
||||
for (i = 0; i < 10; i++) {
|
||||
session->server_kex.methods[i] = strings[i];
|
||||
}
|
||||
@ -355,52 +343,61 @@ void ssh_list_kex(ssh_session session, KEX *kex) {
|
||||
}
|
||||
}
|
||||
|
||||
/* set_kex basicaly look at the option structure of the session and set the output kex message */
|
||||
/* it must be aware of the server kex message */
|
||||
/* it can fail if option is null, not any user specified kex method matches the server one, if not any default kex matches */
|
||||
|
||||
int set_kex(ssh_session session){
|
||||
KEX *server = &session->server_kex;
|
||||
KEX *client=&session->client_kex;
|
||||
/**
|
||||
* @brief sets the key exchange parameters to be sent to the server,
|
||||
* in function of the options and available methods.
|
||||
*/
|
||||
int set_client_kex(ssh_session session){
|
||||
KEX *client= &session->client_kex;
|
||||
int i;
|
||||
const char *wanted;
|
||||
enter_function();
|
||||
ssh_get_random(client->cookie,16,0);
|
||||
client->methods=malloc(10 * sizeof(char **));
|
||||
if (client->methods == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
leave_function();
|
||||
return -1;
|
||||
}
|
||||
memset(client->methods,0,10*sizeof(char **));
|
||||
for (i=0;i<10;i++){
|
||||
if(!(wanted=session->wanted_methods[i]))
|
||||
wanted=session->wanted_methods[i];
|
||||
if(wanted == NULL)
|
||||
wanted=default_methods[i];
|
||||
client->methods[i]=ssh_find_matching(server->methods[i],wanted);
|
||||
if(!client->methods[i] && i < SSH_LANG_C_S){
|
||||
ssh_set_error(session,SSH_FATAL,"kex error : did not find one of algos %s in list %s for %s",
|
||||
wanted,server->methods[i],ssh_kex_nums[i]);
|
||||
leave_function();
|
||||
return -1;
|
||||
} else {
|
||||
if ((i >= SSH_LANG_C_S) && (client->methods[i] == NULL)) {
|
||||
/* we can safely do that for languages */
|
||||
client->methods[i] = strdup("");
|
||||
if (client->methods[i] == NULL) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(strcmp(client->methods[SSH_KEX], "diffie-hellman-group1-sha1") == 0){
|
||||
session->next_crypto->kex_type=SSH_KEX_DH_GROUP1_SHA1;
|
||||
} else if(strcmp(client->methods[SSH_KEX], "ecdh-sha2-nistp256") == 0){
|
||||
session->next_crypto->kex_type=SSH_KEX_ECDH_SHA2_NISTP256;
|
||||
client->methods[i]=strdup(wanted);
|
||||
}
|
||||
leave_function();
|
||||
return 0;
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
/** @brief Select the different methods on basis of client's and
|
||||
* server's kex messages, and watches out if a match is possible.
|
||||
*/
|
||||
int ssh_kex_select_methods (ssh_session session){
|
||||
KEX *server = &session->server_kex;
|
||||
KEX *client = &session->client_kex;
|
||||
int rc = SSH_ERROR;
|
||||
int i;
|
||||
|
||||
enter_function();
|
||||
|
||||
for (i=0;i<10;i++){
|
||||
session->kex_methods[i]=ssh_find_matching(server->methods[i],client->methods[i]);
|
||||
if(session->kex_methods[i] == NULL && i < SSH_LANG_C_S){
|
||||
ssh_set_error(session,SSH_FATAL,"kex error : no match for method %s: server [%s], client [%s]",
|
||||
ssh_kex_nums[i],server->methods[i],client->methods[i]);
|
||||
goto error;
|
||||
} else if ((i >= SSH_LANG_C_S) && (session->kex_methods[i] == NULL)) {
|
||||
/* we can safely do that for languages */
|
||||
session->kex_methods[i] = strdup("");
|
||||
}
|
||||
}
|
||||
if(strcmp(session->kex_methods[SSH_KEX], "diffie-hellman-group1-sha1") == 0){
|
||||
session->next_crypto->kex_type=SSH_KEX_DH_GROUP1_SHA1;
|
||||
} else if(strcmp(session->kex_methods[SSH_KEX], "ecdh-sha2-nistp256") == 0){
|
||||
session->next_crypto->kex_type=SSH_KEX_ECDH_SHA2_NISTP256;
|
||||
}
|
||||
rc = SSH_OK;
|
||||
error:
|
||||
leave_function();
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/* this function only sends the predefined set of kex methods */
|
||||
int ssh_send_kex(ssh_session session, int server_kex) {
|
||||
KEX *kex = (server_kex ? &session->server_kex : &session->client_kex);
|
||||
|
59
src/server.c
59
src/server.c
@ -104,11 +104,6 @@ static int server_set_kex(ssh_session session) {
|
||||
}
|
||||
}
|
||||
|
||||
server->methods = malloc(10 * sizeof(char *));
|
||||
if (server->methods == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < 10; i++) {
|
||||
if ((wanted = session->wanted_methods[i]) == NULL) {
|
||||
wanted = supported_methods[i];
|
||||
@ -118,7 +113,6 @@ static int server_set_kex(ssh_session session) {
|
||||
for (j = i - 1; j <= 0; j--) {
|
||||
SAFE_FREE(server->methods[j]);
|
||||
}
|
||||
SAFE_FREE(server->methods);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@ -126,29 +120,50 @@ static int server_set_kex(ssh_session session) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** @internal
|
||||
* @brief parse an incoming SSH_MSG_KEXDH_INIT packet and complete
|
||||
* key exchange
|
||||
**/
|
||||
static int ssh_server_kexdh_init(ssh_session session, ssh_buffer packet){
|
||||
ssh_string e;
|
||||
e = buffer_get_ssh_string(packet);
|
||||
if (e == NULL) {
|
||||
ssh_set_error(session, SSH_FATAL, "No e number in client request");
|
||||
return -1;
|
||||
}
|
||||
if (dh_import_e(session, e) < 0) {
|
||||
ssh_set_error(session, SSH_FATAL, "Cannot import e number");
|
||||
session->session_state=SSH_SESSION_STATE_ERROR;
|
||||
} else {
|
||||
session->dh_handshake_state=DH_STATE_INIT_SENT;
|
||||
dh_handshake_server(session);
|
||||
}
|
||||
ssh_string_free(e);
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
SSH_PACKET_CALLBACK(ssh_packet_kexdh_init){
|
||||
ssh_string e;
|
||||
int rc;
|
||||
(void)type;
|
||||
(void)user;enter_function();
|
||||
(void)user;
|
||||
enter_function();
|
||||
ssh_log(session,SSH_LOG_PACKET,"Received SSH_MSG_KEXDH_INIT");
|
||||
if(session->dh_handshake_state != DH_STATE_INIT){
|
||||
ssh_log(session,SSH_LOG_RARE,"Invalid state for SSH_MSG_KEXDH_INIT");
|
||||
goto error;
|
||||
}
|
||||
e = buffer_get_ssh_string(packet);
|
||||
if (e == NULL) {
|
||||
ssh_set_error(session, SSH_FATAL, "No e number in client request");
|
||||
return -1;
|
||||
switch(session->next_crypto->kex_type){
|
||||
case SSH_KEX_DH_GROUP1_SHA1:
|
||||
rc=ssh_server_kexdh_init(session, packet);
|
||||
break;
|
||||
#ifdef HAVE_ECDH
|
||||
case SSH_KEX_ECDH_SHA2_NISTP256:
|
||||
rc = ssh_server_ecdh_init(session, packet);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
ssh_set_error(session,SSH_FATAL,"Wrong kex type in ssh_packet_kexdh_init");
|
||||
}
|
||||
if (dh_import_e(session, e) < 0) {
|
||||
ssh_set_error(session, SSH_FATAL, "Cannot import e number");
|
||||
session->session_state=SSH_SESSION_STATE_ERROR;
|
||||
} else {
|
||||
session->dh_handshake_state=DH_STATE_INIT_SENT;
|
||||
dh_handshake_server(session);
|
||||
}
|
||||
ssh_string_free(e);
|
||||
|
||||
error:
|
||||
leave_function();
|
||||
return SSH_PACKET_USED;
|
||||
@ -343,7 +358,7 @@ static void ssh_server_connection_callback(ssh_session session){
|
||||
set_status(session,0.6f);
|
||||
ssh_list_kex(session, &session->client_kex); // log client kex
|
||||
crypt_set_algorithms_server(session);
|
||||
if (set_kex(session) < 0) {
|
||||
if (ssh_kex_select_methods(session) < 0) {
|
||||
goto error;
|
||||
}
|
||||
set_status(session,0.8f);
|
||||
|
@ -208,8 +208,6 @@ void ssh_free(ssh_session session) {
|
||||
SAFE_FREE(session->server_kex.methods[i]);
|
||||
}
|
||||
}
|
||||
SAFE_FREE(session->client_kex.methods);
|
||||
SAFE_FREE(session->server_kex.methods);
|
||||
|
||||
ssh_key_free(session->srv.dsa_key);
|
||||
ssh_key_free(session->srv.rsa_key);
|
||||
|
@ -159,14 +159,14 @@ static int crypt_set_algorithms2(ssh_session session){
|
||||
struct crypto_struct *ssh_ciphertab=ssh_get_ciphertab();
|
||||
/* we must scan the kex entries to find crypto algorithms and set their appropriate structure */
|
||||
/* out */
|
||||
wanted = session->client_kex.methods[SSH_CRYPT_C_S];
|
||||
wanted = session->kex_methods[SSH_CRYPT_C_S];
|
||||
while (ssh_ciphertab[i].name && strcmp(wanted, ssh_ciphertab[i].name)) {
|
||||
i++;
|
||||
}
|
||||
|
||||
if (ssh_ciphertab[i].name == NULL) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Crypt_set_algorithms2: no crypto algorithm function found for %s",
|
||||
"crypt_set_algorithms2: no crypto algorithm function found for %s",
|
||||
wanted);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
@ -180,7 +180,7 @@ static int crypt_set_algorithms2(ssh_session session){
|
||||
i = 0;
|
||||
|
||||
/* in */
|
||||
wanted = session->client_kex.methods[SSH_CRYPT_S_C];
|
||||
wanted = session->kex_methods[SSH_CRYPT_S_C];
|
||||
while (ssh_ciphertab[i].name && strcmp(wanted, ssh_ciphertab[i].name)) {
|
||||
i++;
|
||||
}
|
||||
@ -200,16 +200,16 @@ static int crypt_set_algorithms2(ssh_session session){
|
||||
}
|
||||
|
||||
/* compression */
|
||||
if (strcmp(session->client_kex.methods[SSH_COMP_C_S], "zlib") == 0) {
|
||||
if (strcmp(session->kex_methods[SSH_COMP_C_S], "zlib") == 0) {
|
||||
session->next_crypto->do_compress_out = 1;
|
||||
}
|
||||
if (strcmp(session->client_kex.methods[SSH_COMP_S_C], "zlib") == 0) {
|
||||
if (strcmp(session->kex_methods[SSH_COMP_S_C], "zlib") == 0) {
|
||||
session->next_crypto->do_compress_in = 1;
|
||||
}
|
||||
if (strcmp(session->client_kex.methods[SSH_COMP_C_S], "zlib@openssh.com") == 0) {
|
||||
if (strcmp(session->kex_methods[SSH_COMP_C_S], "zlib@openssh.com") == 0) {
|
||||
session->next_crypto->delayed_compress_out = 1;
|
||||
}
|
||||
if (strcmp(session->client_kex.methods[SSH_COMP_S_C], "zlib@openssh.com") == 0) {
|
||||
if (strcmp(session->kex_methods[SSH_COMP_S_C], "zlib@openssh.com") == 0) {
|
||||
session->next_crypto->delayed_compress_in = 1;
|
||||
}
|
||||
return SSH_OK;
|
||||
|
Загрузка…
x
Ссылка в новой задаче
Block a user