diff options
author | Andreas Schneider <mail@cynapses.org> | 2009-04-16 08:19:48 +0000 |
---|---|---|
committer | Andreas Schneider <mail@cynapses.org> | 2009-04-16 08:19:48 +0000 |
commit | 1ac6f38032eee95dd7a9516f384944b61a100beb (patch) | |
tree | eb5b68c39f3b9097f6f244dc7489fb8ec3b3f02c /libssh/client.c | |
parent | ea729492ecc6b9eadc5b6d9555c234006cfcb60d (diff) | |
download | libssh-1ac6f38032eee95dd7a9516f384944b61a100beb.tar.gz libssh-1ac6f38032eee95dd7a9516f384944b61a100beb.tar.xz libssh-1ac6f38032eee95dd7a9516f384944b61a100beb.zip |
Add more error checks to dh_handshake().
git-svn-id: svn+ssh://svn.berlios.de/svnroot/repos/libssh/trunk@485 7dcaeef0-15fb-0310-b436-a5af3365683c
Diffstat (limited to 'libssh/client.c')
-rw-r--r-- | libssh/client.c | 287 |
1 files changed, 171 insertions, 116 deletions
diff --git a/libssh/client.c b/libssh/client.c index e570b6f..b99baf8 100644 --- a/libssh/client.c +++ b/libssh/client.c @@ -174,122 +174,177 @@ int ssh_send_banner(SSH_SESSION *session, int server) { #define DH_STATE_NEWKEYS_TO_SEND 3 #define DH_STATE_NEWKEYS_SENT 4 #define DH_STATE_FINISHED 5 -static int dh_handshake(SSH_SESSION *session){ - STRING *e,*f,*pubkey,*signature; - int ret; - enter_function(); - switch(session->dh_handshake_state){ - case DH_STATE_INIT: - buffer_add_u8(session->out_buffer,SSH2_MSG_KEXDH_INIT); - dh_generate_x(session); - dh_generate_e(session); - e=dh_get_e(session); - buffer_add_ssh_string(session->out_buffer,e); - ret=packet_send(session); - free(e); - session->dh_handshake_state=DH_STATE_INIT_TO_SEND; - if(ret==SSH_ERROR){ - leave_function(); - return ret; - } - case DH_STATE_INIT_TO_SEND: - ret=packet_flush(session,0); - if(ret!=SSH_OK){ - leave_function(); - return ret; // SSH_ERROR or SSH_AGAIN - } - session->dh_handshake_state=DH_STATE_INIT_SENT; - case DH_STATE_INIT_SENT: - ret=packet_wait(session,SSH2_MSG_KEXDH_REPLY,1); - if(ret != SSH_OK){ - leave_function(); - return ret; - } - pubkey=buffer_get_ssh_string(session->in_buffer); - if(!pubkey){ - ssh_set_error(session,SSH_FATAL,"No public key in packet"); - leave_function(); - return SSH_ERROR; - } - dh_import_pubkey(session,pubkey); - f=buffer_get_ssh_string(session->in_buffer); - if(!f){ - ssh_set_error(session,SSH_FATAL,"No F number in packet"); - leave_function(); - return SSH_ERROR; - } - dh_import_f(session,f); - free(f); - if(!(signature=buffer_get_ssh_string(session->in_buffer))){ - ssh_set_error(session,SSH_FATAL,"No signature in packet"); - leave_function(); - return SSH_ERROR; - } - session->dh_server_signature=signature; - dh_build_k(session); - // send the MSG_NEWKEYS - buffer_add_u8(session->out_buffer,SSH2_MSG_NEWKEYS); - packet_send(session); - session->dh_handshake_state=DH_STATE_NEWKEYS_TO_SEND; - case DH_STATE_NEWKEYS_TO_SEND: - ret=packet_flush(session,0); - if(ret != SSH_OK){ - leave_function(); - return ret; - } - ssh_log(session, SSH_LOG_RARE, "SSH_MSG_NEWKEYS sent\n"); - session->dh_handshake_state=DH_STATE_NEWKEYS_SENT; - case DH_STATE_NEWKEYS_SENT: - ret=packet_wait(session,SSH2_MSG_NEWKEYS,1); - if(ret != SSH_OK){ - leave_function(); - return ret; - } - ssh_log(session, SSH_LOG_RARE, "Got SSH_MSG_NEWKEYS\n"); - ret = make_sessionid(session); - if (ret != SSH_OK) { - leave_function(); - return SSH_ERROR; - } - /* set the cryptographic functions for the next crypto */ - /* (it is needed for generate_session_keys for key lenghts) */ - if(crypt_set_algorithms(session)){ - leave_function(); - return SSH_ERROR; - } - generate_session_keys(session); - /* verify the host's signature. XXX do it sooner */ - signature=session->dh_server_signature; - session->dh_server_signature=NULL; - if(signature_verify(session,signature)){ - free(signature); - leave_function(); - return SSH_ERROR; - } - free(signature); /* forget it for now ... */ - /* once we got SSH2_MSG_NEWKEYS we can switch next_crypto and current_crypto */ - if(session->current_crypto) - crypto_free(session->current_crypto); - /* XXX later, include a function to change keys */ - session->current_crypto=session->next_crypto; - - session->next_crypto = crypto_new(); - if (session->next_crypto == NULL) { - leave_function(); - return SSH_ERROR; - } - - session->dh_handshake_state=DH_STATE_FINISHED; - leave_function(); - return SSH_OK; - default: - ssh_set_error(session,SSH_FATAL,"Invalid state in dh_handshake():%d",session->dh_handshake_state); - leave_function(); - return SSH_ERROR; - } - /* not reached */ - leave_function(); - return SSH_ERROR; +static int dh_handshake(SSH_SESSION *session) { + STRING *e = NULL; + STRING *f = NULL; + STRING *pubkey = NULL; + STRING *signature = NULL; + int rc = SSH_ERROR; + + enter_function(); + + switch (session->dh_handshake_state) { + case DH_STATE_INIT: + if (buffer_add_u8(session->out_buffer, SSH2_MSG_KEXDH_INIT) < 0) { + goto error; + } + + dh_generate_x(session); + dh_generate_e(session); + + e = dh_get_e(session); + if (e == NULL) { + goto error; + } + + if (buffer_add_ssh_string(session->out_buffer, e) < 0) { + goto error; + } + string_burn(e); + string_free(e); + + rc = packet_send(session); + if (rc == SSH_ERROR) { + goto error; + } + + session->dh_handshake_state = DH_STATE_INIT_TO_SEND; + case DH_STATE_INIT_TO_SEND: + rc = packet_flush(session, 0); + if (rc != SSH_OK) { + goto error; + } + session->dh_handshake_state = DH_STATE_INIT_SENT; + case DH_STATE_INIT_SENT: + rc = packet_wait(session, SSH2_MSG_KEXDH_REPLY, 1); + if (rc != SSH_OK) { + goto error; + } + + pubkey = buffer_get_ssh_string(session->in_buffer); + if (pubkey == NULL){ + ssh_set_error(session,SSH_FATAL, "No public key in packet"); + rc = SSH_ERROR; + goto error; + } + dh_import_pubkey(session, pubkey); + + f = buffer_get_ssh_string(session->in_buffer); + if (f == NULL) { + ssh_set_error(session,SSH_FATAL, "No F number in packet"); + rc = SSH_ERROR; + goto error; + } + dh_import_f(session, f); + string_burn(f); + string_free(f); + + signature = buffer_get_ssh_string(session->in_buffer); + if (signature == NULL) { + ssh_set_error(session, SSH_FATAL, "No signature in packet"); + rc = SSH_ERROR; + goto error; + } + session->dh_server_signature = signature; + dh_build_k(session); + + /* Send the MSG_NEWKEYS */ + if (buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS) < 0) { + rc = SSH_ERROR; + goto error; + } + + rc = packet_send(session); + if (rc == SSH_ERROR) { + goto error; + } + + session->dh_handshake_state = DH_STATE_NEWKEYS_TO_SEND; + case DH_STATE_NEWKEYS_TO_SEND: + rc = packet_flush(session, 0); + if (rc != SSH_OK) { + goto error; + } + ssh_log(session, SSH_LOG_RARE, "SSH_MSG_NEWKEYS sent\n"); + + session->dh_handshake_state = DH_STATE_NEWKEYS_SENT; + case DH_STATE_NEWKEYS_SENT: + rc = packet_wait(session, SSH2_MSG_NEWKEYS, 1); + if (rc != SSH_OK) { + goto error; + } + ssh_log(session, SSH_LOG_RARE, "Got SSH_MSG_NEWKEYS\n"); + + 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 lenghts) + */ + if (crypt_set_algorithms(session)) { + rc = SSH_ERROR; + goto error; + } + + generate_session_keys(session); + + /* Verify the host's signature. FIXME do it sooner */ + signature = session->dh_server_signature; + session->dh_server_signature = NULL; + if (signature_verify(session, signature)) { + rc = SSH_ERROR; + goto error; + } + + /* forget it for now ... */ + string_burn(signature); + string_free(signature); + + /* + * Once we got SSH2_MSG_NEWKEYS we can switch next_crypto and + * current_crypto + */ + if (session->current_crypto) { + crypto_free(session->current_crypto); + } + + /* FIXME later, include a function to change keys */ + session->current_crypto = session->next_crypto; + + session->next_crypto = crypto_new(); + if (session->next_crypto == NULL) { + rc = SSH_ERROR; + goto error; + } + + session->dh_handshake_state = DH_STATE_FINISHED; + + leave_function(); + return SSH_OK; + default: + ssh_set_error(session, SSH_FATAL, "Invalid state in dh_handshake(): %d", + session->dh_handshake_state); + + leave_function(); + return SSH_ERROR; + } + + /* not reached */ +error: + string_burn(e); + string_free(e); + string_burn(f); + string_free(f); + string_burn(pubkey); + string_free(pubkey); + string_burn(signature); + string_free(signature); + + leave_function(); + return rc; } int ssh_service_request(SSH_SESSION *session, const char *service) { |