Example #1
0
File: kex.c Project: simonsj/libssh
/*
 * Key re-exchange (rekey) is triggered by this function.
 * It can not be called again after the rekey is initialized!
 */
int ssh_send_rekex(ssh_session session)
{
    int rc;

    if (session->dh_handshake_state != DH_STATE_FINISHED) {
        /* Rekey/Key exchange is already in progress */
        SSH_LOG(SSH_LOG_PACKET, "Attempting rekey in bad state");
        return SSH_ERROR;
    }

    if (session->current_crypto == NULL) {
        /* No current crypto used -- can not exchange it */
        SSH_LOG(SSH_LOG_PACKET, "No crypto to rekey");
        return SSH_ERROR;
    }

    if (session->client) {
        rc = ssh_set_client_kex(session);
        if (rc != SSH_OK) {
            SSH_LOG(SSH_LOG_PACKET, "Failed to set client kex");
            return rc;
        }
    } else {
#ifdef WITH_SERVER
        rc = server_set_kex(session);
        if (rc == SSH_ERROR) {
            SSH_LOG(SSH_LOG_PACKET, "Failed to set server kex");
            return rc;
        }
#else
        SSH_LOG(SSH_LOG_PACKET, "Invalid session state.");
        return SSH_ERROR;
#endif /* WITH_SERVER */
    }

    session->dh_handshake_state = DH_STATE_INIT;
    rc = ssh_send_kex(session, session->server);
    if (rc < 0) {
        SSH_LOG(SSH_LOG_PACKET, "Failed to send kex");
        return rc;
    }

    /* Reset the handshake state */
    session->dh_handshake_state = DH_STATE_INIT_SENT;
    return SSH_OK;
}
Example #2
0
/**
 * @internal
 *
 * @brief A function to be called each time a step has been done in the
 * connection.
 */
static void ssh_client_connection_callback(ssh_session session){
	int ssh1,ssh2;

	switch(session->session_state){
		case SSH_SESSION_STATE_NONE:
		case SSH_SESSION_STATE_CONNECTING:
			break;
		case SSH_SESSION_STATE_SOCKET_CONNECTED:
            /* If SSHv1 is disabled, we can send the banner immedietly */
            if (session->opts.ssh1 == 0) {
                ssh_set_fd_towrite(session);
                ssh_send_banner(session, 0);
            }
			break;
		case SSH_SESSION_STATE_BANNER_RECEIVED:
		  if (session->serverbanner == NULL) {
		    goto error;
		  }
		  set_status(session, 0.4f);
		  SSH_LOG(SSH_LOG_RARE,
		      "SSH server banner: %s", session->serverbanner);

		  /* Here we analyze the different protocols the server allows. */
		  if (ssh_analyze_banner(session, 0, &ssh1, &ssh2) < 0) {
		    goto error;
		  }
		  /* Here we decide which version of the protocol to use. */
		  if (ssh2 && session->opts.ssh2) {
		    session->version = 2;
#ifdef WITH_SSH1
		    } else if(ssh1 && session->opts.ssh1) {
		    session->version = 1;
#endif
		    } else if(ssh1 && !session->opts.ssh1){
#ifdef WITH_SSH1
		    ssh_set_error(session, SSH_FATAL,
		        "SSH-1 protocol not available (configure session to allow SSH-1)");
		    goto error;
#else
		    ssh_set_error(session, SSH_FATAL,
		        "SSH-1 protocol not available (libssh compiled without SSH-1 support)");
		    goto error;
#endif
		  } else {
		    ssh_set_error(session, SSH_FATAL,
		        "No version of SSH protocol usable (banner: %s)",
		        session->serverbanner);
		    goto error;
		  }
		  /* from now, the packet layer is handling incoming packets */
		  if (session->version == 2) {
		      ssh_packet_register_socket_callback(session, session->socket);
		  }
#ifdef WITH_SSH1
		  else
		    session->socket_callbacks.data=ssh_packet_socket_callback1;
#endif
		  ssh_packet_set_default_callbacks(session);
		  session->session_state=SSH_SESSION_STATE_INITIAL_KEX;
          if (session->opts.ssh1 == 1) {
              ssh_send_banner(session, 0);
          }
		  set_status(session, 0.5f);
		  break;
		case SSH_SESSION_STATE_INITIAL_KEX:
		/* TODO: This state should disappear in favor of get_key handle */
#ifdef WITH_SSH1
			if(session->version==1){
				if (ssh_get_kex1(session) < 0)
					goto error;
				set_status(session,0.6f);
				session->connected = 1;
				break;
			}
#endif
			break;
		case SSH_SESSION_STATE_KEXINIT_RECEIVED:
			set_status(session,0.6f);
			ssh_list_kex(&session->next_crypto->server_kex);
			if (ssh_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;
			}
			set_status(session,0.8f);
			session->session_state=SSH_SESSION_STATE_DH;
			if (dh_handshake(session) == SSH_ERROR) {
				goto error;
			}
            /* FALL THROUGH */
		case SSH_SESSION_STATE_DH:
			if(session->dh_handshake_state==DH_STATE_FINISHED){
				set_status(session,1.0f);
				session->connected = 1;
				if (session->flags & SSH_SESSION_FLAG_AUTHENTICATED)
				    session->session_state = SSH_SESSION_STATE_AUTHENTICATED;
				else
				    session->session_state=SSH_SESSION_STATE_AUTHENTICATING;
			}
			break;
		case SSH_SESSION_STATE_AUTHENTICATING:
			break;
		case SSH_SESSION_STATE_ERROR:
			goto error;
		default:
			ssh_set_error(session,SSH_FATAL,"Invalid state %d",session->session_state);
	}

	return;
error:
	ssh_socket_close(session->socket);
	session->alive = 0;
	session->session_state=SSH_SESSION_STATE_ERROR;

}
Example #3
0
/**
 * @internal
 *
 * @brief A function to be called each time a step has been done in the
 * connection.
 */
static void ssh_client_connection_callback(ssh_session session)
{
    int rc;

    switch(session->session_state) {
        case SSH_SESSION_STATE_NONE:
        case SSH_SESSION_STATE_CONNECTING:
            break;
        case SSH_SESSION_STATE_SOCKET_CONNECTED:
            ssh_set_fd_towrite(session);
            ssh_send_banner(session, 0);

            break;
        case SSH_SESSION_STATE_BANNER_RECEIVED:
            if (session->serverbanner == NULL) {
                goto error;
            }
            set_status(session, 0.4f);
            SSH_LOG(SSH_LOG_RARE,
                    "SSH server banner: %s", session->serverbanner);

            /* Here we analyze the different protocols the server allows. */
            rc = ssh_analyze_banner(session, 0);
            if (rc < 0) {
                ssh_set_error(session, SSH_FATAL,
                        "No version of SSH protocol usable (banner: %s)",
                        session->serverbanner);
                goto error;
            }

            ssh_packet_register_socket_callback(session, session->socket);

            ssh_packet_set_default_callbacks(session);
            session->session_state = SSH_SESSION_STATE_INITIAL_KEX;
            rc = ssh_set_client_kex(session);
            if (rc != SSH_OK) {
                goto error;
            }
            rc = ssh_send_kex(session, 0);
            if (rc < 0) {
                goto error;
            }
            set_status(session, 0.5f);

            break;
        case SSH_SESSION_STATE_INITIAL_KEX:
            /* TODO: This state should disappear in favor of get_key handle */
            break;
        case SSH_SESSION_STATE_KEXINIT_RECEIVED:
            set_status(session,0.6f);
            ssh_list_kex(&session->next_crypto->server_kex);
            if (session->next_crypto->client_kex.methods[0] == NULL) {
                /* in rekeying state if next_crypto client_kex is empty */
                rc = ssh_set_client_kex(session);
                if (rc != SSH_OK) {
                    goto error;
                }
                rc = ssh_send_kex(session, 0);
                if (rc < 0) {
                    goto error;
                }
            }
            if (ssh_kex_select_methods(session) == SSH_ERROR)
                goto error;
            set_status(session,0.8f);
            session->session_state=SSH_SESSION_STATE_DH;
            if (dh_handshake(session) == SSH_ERROR) {
                goto error;
            }
            /* FALL THROUGH */
        case SSH_SESSION_STATE_DH:
            if(session->dh_handshake_state==DH_STATE_FINISHED){
                set_status(session,1.0f);
                session->connected = 1;
                if (session->flags & SSH_SESSION_FLAG_AUTHENTICATED)
                    session->session_state = SSH_SESSION_STATE_AUTHENTICATED;
                else
                    session->session_state=SSH_SESSION_STATE_AUTHENTICATING;
            }
            break;
        case SSH_SESSION_STATE_AUTHENTICATING:
            break;
        case SSH_SESSION_STATE_ERROR:
            goto error;
        default:
            ssh_set_error(session,SSH_FATAL,"Invalid state %d",session->session_state);
    }

    return;
error:
    ssh_socket_close(session->socket);
    session->alive = 0;
    session->session_state=SSH_SESSION_STATE_ERROR;

}