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
This commit is contained in:
Andreas Schneider
2009-04-16 08:19:48 +00:00
parent ea729492ec
commit 1ac6f38032

View File

@@ -174,122 +174,177 @@ int ssh_send_banner(SSH_SESSION *session, int server) {
#define DH_STATE_NEWKEYS_TO_SEND 3 #define DH_STATE_NEWKEYS_TO_SEND 3
#define DH_STATE_NEWKEYS_SENT 4 #define DH_STATE_NEWKEYS_SENT 4
#define DH_STATE_FINISHED 5 #define DH_STATE_FINISHED 5
static int dh_handshake(SSH_SESSION *session){ static int dh_handshake(SSH_SESSION *session) {
STRING *e,*f,*pubkey,*signature; STRING *e = NULL;
int ret; STRING *f = NULL;
STRING *pubkey = NULL;
STRING *signature = NULL;
int rc = SSH_ERROR;
enter_function(); enter_function();
switch(session->dh_handshake_state){
switch (session->dh_handshake_state) {
case DH_STATE_INIT: case DH_STATE_INIT:
buffer_add_u8(session->out_buffer,SSH2_MSG_KEXDH_INIT); if (buffer_add_u8(session->out_buffer, SSH2_MSG_KEXDH_INIT) < 0) {
goto error;
}
dh_generate_x(session); dh_generate_x(session);
dh_generate_e(session); dh_generate_e(session);
e=dh_get_e(session);
buffer_add_ssh_string(session->out_buffer,e); e = dh_get_e(session);
ret=packet_send(session); if (e == NULL) {
free(e); goto error;
session->dh_handshake_state=DH_STATE_INIT_TO_SEND;
if(ret==SSH_ERROR){
leave_function();
return ret;
} }
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: case DH_STATE_INIT_TO_SEND:
ret=packet_flush(session,0); rc = packet_flush(session, 0);
if(ret!=SSH_OK){ if (rc != SSH_OK) {
leave_function(); goto error;
return ret; // SSH_ERROR or SSH_AGAIN
} }
session->dh_handshake_state=DH_STATE_INIT_SENT; session->dh_handshake_state = DH_STATE_INIT_SENT;
case DH_STATE_INIT_SENT: case DH_STATE_INIT_SENT:
ret=packet_wait(session,SSH2_MSG_KEXDH_REPLY,1); rc = packet_wait(session, SSH2_MSG_KEXDH_REPLY, 1);
if(ret != SSH_OK){ if (rc != SSH_OK) {
leave_function(); goto error;
return ret;
} }
pubkey=buffer_get_ssh_string(session->in_buffer);
if(!pubkey){ pubkey = buffer_get_ssh_string(session->in_buffer);
ssh_set_error(session,SSH_FATAL,"No public key in packet"); if (pubkey == NULL){
leave_function(); ssh_set_error(session,SSH_FATAL, "No public key in packet");
return SSH_ERROR; rc = SSH_ERROR;
goto error;
} }
dh_import_pubkey(session,pubkey); dh_import_pubkey(session, pubkey);
f=buffer_get_ssh_string(session->in_buffer);
if(!f){ f = buffer_get_ssh_string(session->in_buffer);
ssh_set_error(session,SSH_FATAL,"No F number in packet"); if (f == NULL) {
leave_function(); ssh_set_error(session,SSH_FATAL, "No F number in packet");
return SSH_ERROR; rc = SSH_ERROR;
goto error;
} }
dh_import_f(session,f); dh_import_f(session, f);
free(f); string_burn(f);
if(!(signature=buffer_get_ssh_string(session->in_buffer))){ string_free(f);
ssh_set_error(session,SSH_FATAL,"No signature in packet");
leave_function(); signature = buffer_get_ssh_string(session->in_buffer);
return SSH_ERROR; if (signature == NULL) {
ssh_set_error(session, SSH_FATAL, "No signature in packet");
rc = SSH_ERROR;
goto error;
} }
session->dh_server_signature=signature; session->dh_server_signature = signature;
dh_build_k(session); dh_build_k(session);
// send the MSG_NEWKEYS
buffer_add_u8(session->out_buffer,SSH2_MSG_NEWKEYS); /* Send the MSG_NEWKEYS */
packet_send(session); if (buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS) < 0) {
session->dh_handshake_state=DH_STATE_NEWKEYS_TO_SEND; 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: case DH_STATE_NEWKEYS_TO_SEND:
ret=packet_flush(session,0); rc = packet_flush(session, 0);
if(ret != SSH_OK){ if (rc != SSH_OK) {
leave_function(); goto error;
return ret;
} }
ssh_log(session, SSH_LOG_RARE, "SSH_MSG_NEWKEYS sent\n"); ssh_log(session, SSH_LOG_RARE, "SSH_MSG_NEWKEYS sent\n");
session->dh_handshake_state=DH_STATE_NEWKEYS_SENT;
session->dh_handshake_state = DH_STATE_NEWKEYS_SENT;
case DH_STATE_NEWKEYS_SENT: case DH_STATE_NEWKEYS_SENT:
ret=packet_wait(session,SSH2_MSG_NEWKEYS,1); rc = packet_wait(session, SSH2_MSG_NEWKEYS, 1);
if(ret != SSH_OK){ if (rc != SSH_OK) {
leave_function(); goto error;
return ret;
} }
ssh_log(session, SSH_LOG_RARE, "Got SSH_MSG_NEWKEYS\n"); ssh_log(session, SSH_LOG_RARE, "Got SSH_MSG_NEWKEYS\n");
ret = make_sessionid(session);
if (ret != SSH_OK) { rc = make_sessionid(session);
leave_function(); if (rc != SSH_OK) {
return SSH_ERROR; 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)){ * Set the cryptographic functions for the next crypto
leave_function(); * (it is needed for generate_session_keys for key lenghts)
return SSH_ERROR; */
if (crypt_set_algorithms(session)) {
rc = SSH_ERROR;
goto error;
} }
generate_session_keys(session); generate_session_keys(session);
/* verify the host's signature. XXX do it sooner */
signature=session->dh_server_signature; /* Verify the host's signature. FIXME do it sooner */
session->dh_server_signature=NULL; signature = session->dh_server_signature;
if(signature_verify(session,signature)){ session->dh_server_signature = NULL;
free(signature); if (signature_verify(session, signature)) {
leave_function(); rc = SSH_ERROR;
return SSH_ERROR; goto error;
} }
free(signature); /* forget it for now ... */
/* once we got SSH2_MSG_NEWKEYS we can switch next_crypto and current_crypto */ /* forget it for now ... */
if(session->current_crypto) 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); crypto_free(session->current_crypto);
/* XXX later, include a function to change keys */ }
session->current_crypto=session->next_crypto;
/* FIXME later, include a function to change keys */
session->current_crypto = session->next_crypto;
session->next_crypto = crypto_new(); session->next_crypto = crypto_new();
if (session->next_crypto == NULL) { 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(); leave_function();
return SSH_ERROR; 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 */ /* 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(); leave_function();
return SSH_ERROR; return rc;
} }
int ssh_service_request(SSH_SESSION *session, const char *service) { int ssh_service_request(SSH_SESSION *session, const char *service) {