From 508374219255bf7876acf5046d7b63f00f85a6e3 Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Sat, 17 Sep 2011 20:17:11 +0200 Subject: [PATCH] packet: Move packet callbacks to packet_cb.c. --- include/libssh/packet.h | 10 ++ include/libssh/priv.h | 11 -- src/CMakeLists.txt | 1 + src/client.c | 154 -------------------------- src/packet_cb.c | 236 ++++++++++++++++++++++++++++++++++++++++ src/session.c | 45 -------- 6 files changed, 247 insertions(+), 210 deletions(-) create mode 100644 src/packet_cb.c diff --git a/include/libssh/packet.h b/include/libssh/packet.h index 22138e49..9d934c61 100644 --- a/include/libssh/packet.h +++ b/include/libssh/packet.h @@ -56,6 +56,16 @@ int ssh_packet_socket_callback1(const void *data, size_t receivedlen, void *user #endif SSH_PACKET_CALLBACK(ssh_packet_unimplemented); +SSH_PACKET_CALLBACK(ssh_packet_disconnect_callback); +SSH_PACKET_CALLBACK(ssh_packet_ignore_callback); +SSH_PACKET_CALLBACK(ssh_packet_dh_reply); +SSH_PACKET_CALLBACK(ssh_packet_newkeys); +SSH_PACKET_CALLBACK(ssh_packet_service_accept); + +#ifdef WITH_SERVER +SSH_PACKET_CALLBACK(ssh_packet_kexdh_init); +#endif + int ssh_packet_send_unimplemented(ssh_session session, uint32_t seqnum); int ssh_packet_parse_type(ssh_session session); //int packet_flush(ssh_session session, int enforce_blocking); diff --git a/include/libssh/priv.h b/include/libssh/priv.h index 4ac33a62..2e323b9b 100644 --- a/include/libssh/priv.h +++ b/include/libssh/priv.h @@ -171,18 +171,9 @@ void _ssh_set_error_invalid(void *error, const char *function); -/* server data */ - - -SSH_PACKET_CALLBACK(ssh_packet_disconnect_callback); -SSH_PACKET_CALLBACK(ssh_packet_ignore_callback); - /* client.c */ int ssh_send_banner(ssh_session session, int is_server); -SSH_PACKET_CALLBACK(ssh_packet_dh_reply); -SSH_PACKET_CALLBACK(ssh_packet_newkeys); -SSH_PACKET_CALLBACK(ssh_packet_service_accept); /* connect.c */ socket_t ssh_connect_host(ssh_session session, const char *host,const char @@ -201,8 +192,6 @@ int decompress_buffer(ssh_session session,ssh_buffer buf, size_t maxlen); /* match.c */ int match_hostname(const char *host, const char *pattern, unsigned int len); -/* server.c */ -SSH_PACKET_CALLBACK(ssh_packet_kexdh_init); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c230ef6a..1e8aefb1 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -97,6 +97,7 @@ set(libssh_SRCS misc.c options.c packet.c + packet_cb.c packet_crypt.c pcap.c pki.c diff --git a/src/client.c b/src/client.c index d6923e43..2531dd92 100644 --- a/src/client.c +++ b/src/client.c @@ -180,143 +180,6 @@ end: return err; } -SSH_PACKET_CALLBACK(ssh_packet_dh_reply){ - int rc; - (void)type; - (void)user; - ssh_log(session,SSH_LOG_PROTOCOL,"Received SSH_KEXDH_REPLY"); - if(session->session_state!= SSH_SESSION_STATE_DH && - session->dh_handshake_state != DH_STATE_INIT_SENT){ - ssh_set_error(session,SSH_FATAL,"ssh_packet_dh_reply called in wrong state : %d:%d", - session->session_state,session->dh_handshake_state); - goto error; - } - switch(session->next_crypto->kex_type){ - case SSH_KEX_DH_GROUP1_SHA1: - rc=ssh_client_dh_reply(session, packet); - break; -#ifdef HAVE_ECDH - case SSH_KEX_ECDH_SHA2_NISTP256: - rc = ssh_client_ecdh_reply(session, packet); - break; -#endif - default: - ssh_set_error(session,SSH_FATAL,"Wrong kex type in ssh_packet_dh_reply"); - goto error; - } - if(rc==SSH_OK) { - session->dh_handshake_state = DH_STATE_NEWKEYS_SENT; - return SSH_PACKET_USED; - } -error: - session->session_state=SSH_SESSION_STATE_ERROR; - return SSH_PACKET_USED; -} - -SSH_PACKET_CALLBACK(ssh_packet_newkeys){ - ssh_string sig_blob = NULL; - int rc; - (void)packet; - (void)user; - (void)type; - ssh_log(session, SSH_LOG_PROTOCOL, "Received SSH_MSG_NEWKEYS"); - if(session->session_state!= SSH_SESSION_STATE_DH && - session->dh_handshake_state != DH_STATE_NEWKEYS_SENT){ - ssh_set_error(session,SSH_FATAL,"ssh_packet_newkeys called in wrong state : %d:%d", - session->session_state,session->dh_handshake_state); - goto error; - } - if(session->server){ - /* server things are done in server.c */ - session->dh_handshake_state=DH_STATE_FINISHED; - } else { - ssh_key key; - /* 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 */ - sig_blob = session->next_crypto->dh_server_signature; - session->next_crypto->dh_server_signature = NULL; - - /* get the server public key */ - rc = ssh_pki_import_pubkey_blob(session->next_crypto->server_pubkey, &key); - if (rc < 0) { - return SSH_ERROR; - } - - /* check if public key from server matches user preferences */ - if (session->wanted_methods[SSH_HOSTKEYS]) { - if(!ssh_match_group(session->wanted_methods[SSH_HOSTKEYS], - key->type_c)) { - ssh_set_error(session, - SSH_FATAL, - "Public key from server (%s) doesn't match user " - "preference (%s)", - key->type_c, - session->wanted_methods[SSH_HOSTKEYS]); - ssh_key_free(key); - return -1; - } - } - - rc = ssh_pki_signature_verify_blob(session, - sig_blob, - key, - session->next_crypto->session_id, - session->next_crypto->digest_len); - /* Set the server public key type for known host checking */ - session->next_crypto->server_pubkey_type = key->type_c; - - ssh_key_free(key); - ssh_string_burn(sig_blob); - ssh_string_free(sig_blob); - sig_blob = NULL; - if (rc == SSH_ERROR) { - goto error; - } - ssh_log(session,SSH_LOG_PROTOCOL,"Signature verified and valid"); - - /* - * 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; - session->ssh_connection_callback(session); - return SSH_PACKET_USED; -error: - session->session_state=SSH_SESSION_STATE_ERROR; - return SSH_PACKET_USED; -} - /** @internal * @brief launches the DH handshake state machine * @param session session handle @@ -371,23 +234,6 @@ error: return rc; } -/** - * @internal - * @brief handles a SSH_SERVICE_ACCEPT packet - * - */ -SSH_PACKET_CALLBACK(ssh_packet_service_accept){ - (void)packet; - (void)type; - (void)user; - enter_function(); - session->auth_service_state=SSH_AUTH_SERVICE_ACCEPTED; - ssh_log(session, SSH_LOG_PACKET, - "Received SSH_MSG_SERVICE_ACCEPT"); - leave_function(); - return SSH_PACKET_USED; -} - static int ssh_service_request_termination(void *s){ ssh_session session = (ssh_session)s; if(session->session_state == SSH_SESSION_STATE_ERROR || diff --git a/src/packet_cb.c b/src/packet_cb.c new file mode 100644 index 00000000..764f568a --- /dev/null +++ b/src/packet_cb.c @@ -0,0 +1,236 @@ +/* + * packet.c - packet building functions + * + * This file is part of the SSH Library + * + * Copyright (c) 2011 Aris Adamantiadis + * + * The SSH 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, or (at your + * option) any later version. + * + * The SSH 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 the SSH Library; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. + */ + +#include "config.h" + +#include + +#include "libssh/priv.h" +#include "libssh/buffer.h" +#include "libssh/crypto.h" +#include "libssh/dh.h" +#include "libssh/misc.h" +#include "libssh/packet.h" +#include "libssh/pki.h" +#include "libssh/session.h" +#include "libssh/socket.h" +#include "libssh/ssh2.h" + +/** + * @internal + * + * @brief Handle a SSH_DISCONNECT packet. + */ +SSH_PACKET_CALLBACK(ssh_packet_disconnect_callback){ + uint32_t code; + char *error=NULL; + ssh_string error_s; + (void)user; + (void)type; + buffer_get_u32(packet, &code); + error_s = buffer_get_ssh_string(packet); + if (error_s != NULL) { + error = ssh_string_to_char(error_s); + ssh_string_free(error_s); + } + ssh_log(session, SSH_LOG_PACKET, "Received SSH_MSG_DISCONNECT %d:%s",code, + error != NULL ? error : "no error"); + ssh_set_error(session, SSH_FATAL, + "Received SSH_MSG_DISCONNECT: %d:%s",code, + error != NULL ? error : "no error"); + SAFE_FREE(error); + + ssh_socket_close(session->socket); + session->alive = 0; + session->session_state= SSH_SESSION_STATE_ERROR; + /* TODO: handle a graceful disconnect */ + return SSH_PACKET_USED; +} + +/** + * @internal + * + * @brief Handle a SSH_IGNORE and SSH_DEBUG packet. + */ +SSH_PACKET_CALLBACK(ssh_packet_ignore_callback){ + (void)user; + (void)type; + (void)packet; + ssh_log(session,SSH_LOG_PROTOCOL,"Received %s packet",type==SSH2_MSG_IGNORE ? "SSH_MSG_IGNORE" : "SSH_MSG_DEBUG"); + /* TODO: handle a graceful disconnect */ + return SSH_PACKET_USED; +} + +SSH_PACKET_CALLBACK(ssh_packet_dh_reply){ + int rc; + (void)type; + (void)user; + ssh_log(session,SSH_LOG_PROTOCOL,"Received SSH_KEXDH_REPLY"); + if(session->session_state!= SSH_SESSION_STATE_DH && + session->dh_handshake_state != DH_STATE_INIT_SENT){ + ssh_set_error(session,SSH_FATAL,"ssh_packet_dh_reply called in wrong state : %d:%d", + session->session_state,session->dh_handshake_state); + goto error; + } + switch(session->next_crypto->kex_type){ + case SSH_KEX_DH_GROUP1_SHA1: + rc=ssh_client_dh_reply(session, packet); + break; +#ifdef HAVE_ECDH + case SSH_KEX_ECDH_SHA2_NISTP256: + rc = ssh_client_ecdh_reply(session, packet); + break; +#endif + default: + ssh_set_error(session,SSH_FATAL,"Wrong kex type in ssh_packet_dh_reply"); + goto error; + } + if(rc==SSH_OK) { + session->dh_handshake_state = DH_STATE_NEWKEYS_SENT; + return SSH_PACKET_USED; + } +error: + session->session_state=SSH_SESSION_STATE_ERROR; + return SSH_PACKET_USED; +} + +SSH_PACKET_CALLBACK(ssh_packet_newkeys){ + ssh_string sig_blob = NULL; + int rc; + (void)packet; + (void)user; + (void)type; + ssh_log(session, SSH_LOG_PROTOCOL, "Received SSH_MSG_NEWKEYS"); + if(session->session_state!= SSH_SESSION_STATE_DH && + session->dh_handshake_state != DH_STATE_NEWKEYS_SENT){ + ssh_set_error(session,SSH_FATAL,"ssh_packet_newkeys called in wrong state : %d:%d", + session->session_state,session->dh_handshake_state); + goto error; + } + if(session->server){ + /* server things are done in server.c */ + session->dh_handshake_state=DH_STATE_FINISHED; + } else { + ssh_key key; + /* 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 */ + sig_blob = session->next_crypto->dh_server_signature; + session->next_crypto->dh_server_signature = NULL; + + /* get the server public key */ + rc = ssh_pki_import_pubkey_blob(session->next_crypto->server_pubkey, &key); + if (rc < 0) { + return SSH_ERROR; + } + + /* check if public key from server matches user preferences */ + if (session->wanted_methods[SSH_HOSTKEYS]) { + if(!ssh_match_group(session->wanted_methods[SSH_HOSTKEYS], + key->type_c)) { + ssh_set_error(session, + SSH_FATAL, + "Public key from server (%s) doesn't match user " + "preference (%s)", + key->type_c, + session->wanted_methods[SSH_HOSTKEYS]); + ssh_key_free(key); + return -1; + } + } + + rc = ssh_pki_signature_verify_blob(session, + sig_blob, + key, + session->next_crypto->session_id, + session->next_crypto->digest_len); + /* Set the server public key type for known host checking */ + session->next_crypto->server_pubkey_type = key->type_c; + + ssh_key_free(key); + ssh_string_burn(sig_blob); + ssh_string_free(sig_blob); + sig_blob = NULL; + if (rc == SSH_ERROR) { + goto error; + } + ssh_log(session,SSH_LOG_PROTOCOL,"Signature verified and valid"); + + /* + * 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; + session->ssh_connection_callback(session); + return SSH_PACKET_USED; +error: + session->session_state=SSH_SESSION_STATE_ERROR; + return SSH_PACKET_USED; +} + +/** + * @internal + * @brief handles a SSH_SERVICE_ACCEPT packet + * + */ +SSH_PACKET_CALLBACK(ssh_packet_service_accept){ + (void)packet; + (void)type; + (void)user; + enter_function(); + session->auth_service_state=SSH_AUTH_SERVICE_ACCEPTED; + ssh_log(session, SSH_LOG_PACKET, + "Received SSH_MSG_SERVICE_ACCEPT"); + leave_function(); + return SSH_PACKET_USED; +} diff --git a/src/session.c b/src/session.c index 1a11ab58..b3ee193e 100644 --- a/src/session.c +++ b/src/session.c @@ -599,51 +599,6 @@ int ssh_get_version(ssh_session session) { return session->version; } -/** - * @internal - * - * @brief Handle a SSH_DISCONNECT packet. - */ -SSH_PACKET_CALLBACK(ssh_packet_disconnect_callback){ - uint32_t code; - char *error=NULL; - ssh_string error_s; - (void)user; - (void)type; - buffer_get_u32(packet, &code); - error_s = buffer_get_ssh_string(packet); - if (error_s != NULL) { - error = ssh_string_to_char(error_s); - ssh_string_free(error_s); - } - ssh_log(session, SSH_LOG_PACKET, "Received SSH_MSG_DISCONNECT %d:%s",code, - error != NULL ? error : "no error"); - ssh_set_error(session, SSH_FATAL, - "Received SSH_MSG_DISCONNECT: %d:%s",code, - error != NULL ? error : "no error"); - SAFE_FREE(error); - - ssh_socket_close(session->socket); - session->alive = 0; - session->session_state= SSH_SESSION_STATE_ERROR; - /* TODO: handle a graceful disconnect */ - return SSH_PACKET_USED; -} - -/** - * @internal - * - * @brief Handle a SSH_IGNORE and SSH_DEBUG packet. - */ -SSH_PACKET_CALLBACK(ssh_packet_ignore_callback){ - (void)user; - (void)type; - (void)packet; - ssh_log(session,SSH_LOG_PROTOCOL,"Received %s packet",type==SSH2_MSG_IGNORE ? "SSH_MSG_IGNORE" : "SSH_MSG_DEBUG"); - /* TODO: handle a graceful disconnect */ - return SSH_PACKET_USED; -} - /** * @internal * @brief Callback to be called when the socket received an exception code.