diff options
author | Aris Adamantiadis <aris@0xbadc0de.be> | 2011-09-16 23:36:20 +0200 |
---|---|---|
committer | Aris Adamantiadis <aris@0xbadc0de.be> | 2011-09-18 20:34:15 +0200 |
commit | 07abc3406df3b6b37471e10e495efb79003f5679 (patch) | |
tree | 73b635f912977b6d3cf5c8e3830d527eb3aef1ed | |
parent | 1b10b175fcd5c6f205168434cc5f6aca51b1d298 (diff) | |
download | libssh-07abc3406df3b6b37471e10e495efb79003f5679.tar.gz libssh-07abc3406df3b6b37471e10e495efb79003f5679.tar.xz libssh-07abc3406df3b6b37471e10e495efb79003f5679.zip |
kex: split key selection and sending
-rw-r--r-- | include/libssh/ecdh.h | 3 | ||||
-rw-r--r-- | include/libssh/kex.h | 7 | ||||
-rw-r--r-- | include/libssh/priv.h | 11 | ||||
-rw-r--r-- | include/libssh/session.h | 4 | ||||
-rw-r--r-- | src/client.c | 7 | ||||
-rw-r--r-- | src/ecdh.c | 8 | ||||
-rw-r--r-- | src/kex.c | 81 | ||||
-rw-r--r-- | src/server.c | 59 | ||||
-rw-r--r-- | src/session.c | 2 | ||||
-rw-r--r-- | src/wrapper.c | 14 |
10 files changed, 113 insertions, 83 deletions
diff --git a/include/libssh/ecdh.h b/include/libssh/ecdh.h index 5cc208ce..e86bbe82 100644 --- a/include/libssh/ecdh.h +++ b/include/libssh/ecdh.h @@ -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_ */ diff --git a/include/libssh/kex.h b/include/libssh/kex.h index ce2a102b..dbf69ab9 100644 --- a/include/libssh/kex.h +++ b/include/libssh/kex.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); diff --git a/include/libssh/priv.h b/include/libssh/priv.h index aa22d10f..80175ece 100644 --- a/include/libssh/priv.h +++ b/include/libssh/priv.h @@ -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); diff --git a/include/libssh/session.h b/include/libssh/session.h index a1b2a798..ac2ca76e 100644 --- a/include/libssh/session.h +++ b/include/libssh/session.h @@ -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; diff --git a/src/client.c b/src/client.c index c8500ba4..f3683079 100644 --- a/src/client.c +++ b/src/client.c @@ -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 */ @@ -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)) { + client->methods[i]=strdup(wanted); + } + leave_function(); + 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 */ - client->methods[i] = strdup(""); - if (client->methods[i] == NULL) { - return -1; - } - } + session->kex_methods[i] = strdup(""); } } - if(strcmp(client->methods[SSH_KEX], "diffie-hellman-group1-sha1") == 0){ + 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(client->methods[SSH_KEX], "ecdh-sha2-nistp256") == 0){ + } 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 0; + 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); diff --git a/src/server.c b/src/server.c index 97eb40f3..baab4f57 100644 --- a/src/server.c +++ b/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; - } - 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); + 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"); } - 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); diff --git a/src/session.c b/src/session.c index 55ff22a7..ba03a89b 100644 --- a/src/session.c +++ b/src/session.c @@ -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); diff --git a/src/wrapper.c b/src/wrapper.c index f1eebbc2..43648cb3 100644 --- a/src/wrapper.c +++ b/src/wrapper.c @@ -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; |