diff --git a/include/libssh/priv.h b/include/libssh/priv.h index 1f2a1216..1b0344e2 100644 --- a/include/libssh/priv.h +++ b/include/libssh/priv.h @@ -245,6 +245,9 @@ int gettimeofday(struct timeval *__p, void *__t); char *dir_expand_dup(ssh_session session, const char *value, int allowsshdir); int ssh_options_set_algo(ssh_session session, int algo, const char *list); +/* server.c */ +SSH_PACKET_CALLBACK(ssh_packet_kexdh_init); + /** Free memory space */ #define SAFE_FREE(x) do { if ((x) != NULL) {free(x); x=NULL;} } while(0) diff --git a/include/libssh/session.h b/include/libssh/session.h index dd13e700..900de0f9 100644 --- a/include/libssh/session.h +++ b/include/libssh/session.h @@ -43,6 +43,12 @@ enum ssh_session_state_e { SSH_SESSION_STATE_ERROR }; +enum ssh_dh_state_e { + DH_STATE_INIT, + DH_STATE_INIT_SENT, + DH_STATE_NEWKEYS_SENT, + DH_STATE_FINISHED +}; struct ssh_session_struct { struct error_struct error; diff --git a/libssh/client.c b/libssh/client.c index f0621fab..c3a46689 100644 --- a/libssh/client.c +++ b/libssh/client.c @@ -246,12 +246,7 @@ int ssh_send_banner(ssh_session session, int server) { return 0; } -enum ssh_dh_state_e { - DH_STATE_INIT, - DH_STATE_INIT_SENT, - DH_STATE_NEWKEYS_SENT, - DH_STATE_FINISHED -}; + SSH_PACKET_CALLBACK(ssh_packet_dh_reply){ ssh_string f = NULL; @@ -325,52 +320,57 @@ SSH_PACKET_CALLBACK(ssh_packet_newkeys){ session->session_state,session->dh_handshake_state); goto error; } - rc = make_sessionid(session); - if (rc != SSH_OK) { - goto error; + if(session->server){ + /* server things are done in server.c */ + session->dh_handshake_state=DH_STATE_FINISHED; + } else { + /* client */ + rc = make_sessionid(session); + if (rc != SSH_OK) { + goto error; + } + + /* + * Set the cryptographic functions for the next crypto + * (it is needed for generate_session_keys for key lengths) + */ + if (crypt_set_algorithms(session)) { + goto error; + } + + if (generate_session_keys(session) < 0) { + goto error; + } + + /* Verify the host's signature. FIXME do it sooner */ + signature = session->dh_server_signature; + session->dh_server_signature = NULL; + if (signature_verify(session, signature)) { + goto error; + } + + /* forget it for now ... */ + string_burn(signature); + string_free(signature); + signature=NULL; + /* + * Once we got SSH2_MSG_NEWKEYS we can switch next_crypto and + * current_crypto + */ + if (session->current_crypto) { + crypto_free(session->current_crypto); + session->current_crypto=NULL; + } + + /* FIXME later, include a function to change keys */ + session->current_crypto = session->next_crypto; + + session->next_crypto = crypto_new(); + if (session->next_crypto == NULL) { + ssh_set_error_oom(session); + goto error; + } } - - /* - * Set the cryptographic functions for the next crypto - * (it is needed for generate_session_keys for key lengths) - */ - if (crypt_set_algorithms(session)) { - goto error; - } - - if (generate_session_keys(session) < 0) { - goto error; - } - - /* Verify the host's signature. FIXME do it sooner */ - signature = session->dh_server_signature; - session->dh_server_signature = NULL; - if (signature_verify(session, signature)) { - goto error; - } - - /* forget it for now ... */ - string_burn(signature); - string_free(signature); - signature=NULL; - /* - * Once we got SSH2_MSG_NEWKEYS we can switch next_crypto and - * current_crypto - */ - if (session->current_crypto) { - crypto_free(session->current_crypto); - session->current_crypto=NULL; - } - - /* FIXME later, include a function to change keys */ - session->current_crypto = session->next_crypto; - - session->next_crypto = crypto_new(); - if (session->next_crypto == NULL) { - ssh_set_error_oom(session); - goto error; - } - session->dh_handshake_state = DH_STATE_FINISHED; ssh_connection_callback(session); return SSH_PACKET_USED; diff --git a/libssh/server.c b/libssh/server.c index 9a9bdc4b..efb3220c 100644 --- a/libssh/server.c +++ b/libssh/server.c @@ -351,30 +351,45 @@ static int server_set_kex(ssh_session session) { return 0; } -static int dh_handshake_server(ssh_session session) { +SSH_PACKET_CALLBACK(ssh_packet_kexdh_init){ ssh_string e; - ssh_string f; - ssh_string pubkey; - ssh_string sign; - ssh_public_key pub; - ssh_private_key prv; - - if (packet_wait(session, SSH2_MSG_KEXDH_INIT, 1) != SSH_OK) { - return -1; + (void)type; + (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(session->in_buffer); + 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"); - string_free(e); - return -1; + session->session_state=SSH_SESSION_STATE_ERROR; + } else { + session->dh_handshake_state=DH_STATE_INIT_SENT; } string_free(e); + error: + leave_function(); + return SSH_PACKET_USED; +} + +static int dh_handshake_server(ssh_session session) { + ssh_string f; + ssh_string pubkey; + ssh_string sign; + ssh_public_key pub; + ssh_private_key prv; + /* waiting for SSH_MSG_KEXDH_INIT */ + while(session->dh_handshake_state != DH_STATE_INIT_SENT){ + ssh_handle_packets(session); + } + /* received SSH_MSG_KEXDH_INIT */ + if (dh_generate_y(session) < 0) { ssh_set_error(session, SSH_FATAL, "Could not create y number"); return -1; @@ -458,7 +473,7 @@ static int dh_handshake_server(ssh_session session) { } string_free(f); string_free(sign); - + session->dh_handshake_state=DH_STATE_NEWKEYS_SENT; if (packet_send(session) != SSH_OK) { return -1; } @@ -473,10 +488,8 @@ static int dh_handshake_server(ssh_session session) { } ssh_log(session, SSH_LOG_PACKET, "SSH_MSG_NEWKEYS sent"); - if (packet_wait(session, SSH2_MSG_NEWKEYS, 1) != SSH_OK) { - return -1; - } - ssh_log(session, SSH_LOG_PACKET, "Got SSH_MSG_NEWKEYS"); + while(session->dh_handshake_state != DH_STATE_FINISHED) + ssh_handle_packets(session); if (generate_session_keys(session) < 0) { return -1;