Esempio n. 1
0
/* Do the banner and key exchange */
int ssh_accept(SSH_SESSION *session) {
  if (ssh_send_banner(session, 1) < 0) {
    return -1;
  }

  session->alive = 1;

  session->clientbanner = ssh_get_banner(session);
  if (session->clientbanner == NULL) {
    return -1;
  }

  if (server_set_kex(session) < 0) {
    return -1;
  }

  if (ssh_send_kex(session, 1) < 0) {
    return -1;
  }

  if (ssh_get_kex(session,1) < 0) {
    return -1;
  }

  ssh_list_kex(session, &session->client_kex);
  crypt_set_algorithms_server(session);

  if (dh_handshake_server(session) < 0) {
    return -1;
  }

  session->connected = 1;

  return 0;
}
Esempio n. 2
0
int ssh_server_init_kex(ssh_session session) {
    int i;

    if (session->session_state > SSH_SESSION_STATE_BANNER_RECEIVED) {
        return SSH_ERROR;
    }

    /* free any currently-set methods: server_set_kex will allocate new ones */
    for (i = 0; i < 10 /* SSH_KEX_METHODS */; i++) {
        SAFE_FREE(session->next_crypto->server_kex.methods[i]);
    }

    return server_set_kex(session);
}
Esempio n. 3
0
/* do the banner and key exchange */
int ssh_accept(SSH_SESSION *session){
//    ssh_send_banner(session,1);		FIXME BAD HACK -- common
    ssh_crypto_init();
//    session->clientbanner=ssh_banner_get(session);FIXME BAD HACK -- common
    server_set_kex(session);
    ssh_send_kex(session,1);
    if(ssh_get_kex(session,1))
        return -1;
    ssh_list_kex(&session->client_kex);
    crypt_set_algorithms_server(session);
    if(dh_handshake_server(session))
        return -1;
    session->connected=1;
    return 0;
}
Esempio n. 4
0
File: kex.c Progetto: 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;
}
Esempio n. 5
0
/* Do the banner and key exchange */
int ssh_handle_key_exchange(ssh_session session) {
    int rc;

    rc = ssh_send_banner(session, 1);
    if (rc < 0) {
        return SSH_ERROR;
    }

    session->alive = 1;

    session->ssh_connection_callback = ssh_server_connection_callback;
    session->session_state = SSH_SESSION_STATE_SOCKET_CONNECTED;
    ssh_socket_set_callbacks(session->socket,&session->socket_callbacks);
    session->socket_callbacks.data=callback_receive_banner;
    session->socket_callbacks.exception=ssh_socket_exception_callback;
    session->socket_callbacks.userdata=session;

    rc = server_set_kex(session);
    if (rc < 0) {
        return SSH_ERROR;
    }

    while (session->session_state != SSH_SESSION_STATE_ERROR &&
           session->session_state != SSH_SESSION_STATE_AUTHENTICATING &&
           session->session_state != SSH_SESSION_STATE_DISCONNECTED) {
        /*
         * loop until SSH_SESSION_STATE_BANNER_RECEIVED or
         * SSH_SESSION_STATE_ERROR
         */
        ssh_handle_packets(session, -2);
        ssh_log(session,SSH_LOG_PACKET, "ssh_handle_key_exchange: Actual state : %d",
                session->session_state);
    }

    if (session->session_state == SSH_SESSION_STATE_ERROR ||
        session->session_state == SSH_SESSION_STATE_DISCONNECTED) {
        return SSH_ERROR;
    }

  return SSH_OK;
}
Esempio n. 6
0
/* Do the banner and key exchange */
int ssh_handle_key_exchange(ssh_session session) {
    int rc;
    if (session->session_state != SSH_SESSION_STATE_NONE)
      goto pending;
    rc = ssh_send_banner(session, 1);
    if (rc < 0) {
        return SSH_ERROR;
    }

    session->alive = 1;

    session->ssh_connection_callback = ssh_server_connection_callback;
    session->session_state = SSH_SESSION_STATE_SOCKET_CONNECTED;
    ssh_socket_set_callbacks(session->socket,&session->socket_callbacks);
    session->socket_callbacks.data=callback_receive_banner;
    session->socket_callbacks.exception=ssh_socket_exception_callback;
    session->socket_callbacks.userdata=session;

    rc = server_set_kex(session);
    if (rc < 0) {
        return SSH_ERROR;
    }
    pending:
    rc = ssh_handle_packets_termination(session, SSH_TIMEOUT_USER,
        ssh_server_kex_termination,session);
    SSH_LOG(SSH_LOG_PACKET, "ssh_handle_key_exchange: current state : %d",
        session->session_state);
    if (rc != SSH_OK)
      return rc;
    if (session->session_state == SSH_SESSION_STATE_ERROR ||
        session->session_state == SSH_SESSION_STATE_DISCONNECTED) {
      return SSH_ERROR;
    }

  return SSH_OK;
}
Esempio n. 7
0
/**
 * @internal
 *
 * @brief A function to be called each time a step has been done in the
 * connection.
 */
static void ssh_server_connection_callback(ssh_session session){
	int ssh1,ssh2;

	switch(session->session_state){
		case SSH_SESSION_STATE_NONE:
		case SSH_SESSION_STATE_CONNECTING:
		case SSH_SESSION_STATE_SOCKET_CONNECTED:
			break;
		case SSH_SESSION_STATE_BANNER_RECEIVED:
		  if (session->clientbanner == NULL) {
		    goto error;
		  }
		  set_status(session, 0.4f);
		  SSH_LOG(SSH_LOG_RARE,
		      "SSH client banner: %s", session->clientbanner);

		  /* Here we analyze the different protocols the server allows. */
		  if (ssh_analyze_banner(session, 1, &ssh1, &ssh2) < 0) {
		    goto error;
		  }
		  /* Here we decide which version of the protocol to use. */
		  if (ssh2 && session->opts.ssh2) {
		    session->version = 2;
		  } else if (ssh1 && session->opts.ssh1) {
		    session->version = 1;
		  } 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->clientbanner);
		    goto error;
		  }
		  /* from now, the packet layer is handling incoming packets */
		  if(session->version==2)
		    session->socket_callbacks.data=ssh_packet_socket_callback;
#ifdef WITH_SSH1
		  else
		    session->socket_callbacks.data=ssh_packet_socket_callback1;
#endif
		  ssh_packet_set_default_callbacks(session);
		  set_status(session, 0.5f);
		  session->session_state=SSH_SESSION_STATE_INITIAL_KEX;
          if (ssh_send_kex(session, 1) < 0) {
			goto error;
		  }
		  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);
			if(session->next_crypto->server_kex.methods[0]==NULL){
			      if(server_set_kex(session) == SSH_ERROR)
				goto error;
			      /* We are in a rekeying, so we need to send the server kex */
			      if(ssh_send_kex(session, 1) < 0)
				goto error;
			}
			ssh_list_kex(&session->next_crypto->client_kex); // log client kex
			if (ssh_kex_select_methods(session) < 0) {
				goto error;
			}
            if (crypt_set_algorithms_server(session) == SSH_ERROR)
                goto error;
			set_status(session,0.8f);
			session->session_state=SSH_SESSION_STATE_DH;
            break;
		case SSH_SESSION_STATE_DH:
			if(session->dh_handshake_state==DH_STATE_FINISHED){
                if (generate_session_keys(session) < 0) {
                  goto error;
                }

                /*
                 * Once we got SSH2_MSG_NEWKEYS we can switch next_crypto and
                 * current_crypto
                 */
                if (session->current_crypto) {
                  crypto_free(session->current_crypto);
                }

                /* FIXME TODO later, include a function to change keys */
                session->current_crypto = session->next_crypto;
                session->next_crypto = crypto_new();
                if (session->next_crypto == NULL) {
                  goto error;
                }
			session->next_crypto->session_id = malloc(session->current_crypto->digest_len);
			if (session->next_crypto->session_id == NULL) {
			  ssh_set_error_oom(session);
			  goto error;
			}
			memcpy(session->next_crypto->session_id, session->current_crypto->session_id,
			    session->current_crypto->digest_len);

			    set_status(session,1.0f);
			    session->connected = 1;
			    session->session_state=SSH_SESSION_STATE_AUTHENTICATING;
			    if (session->flags & SSH_SESSION_FLAG_AUTHENTICATED)
				    session->session_state = SSH_SESSION_STATE_AUTHENTICATED;
		}
			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;
}
Esempio n. 8
0
/**
 * @internal
 *
 * @brief A function to be called each time a step has been done in the
 * connection.
 */
static void ssh_server_connection_callback(ssh_session session){
    int rc;

    switch(session->session_state){
        case SSH_SESSION_STATE_NONE:
        case SSH_SESSION_STATE_CONNECTING:
        case SSH_SESSION_STATE_SOCKET_CONNECTED:
            break;
        case SSH_SESSION_STATE_BANNER_RECEIVED:
            if (session->clientbanner == NULL) {
                goto error;
            }
            set_status(session, 0.4f);
            SSH_LOG(SSH_LOG_RARE,
                    "SSH client banner: %s", session->clientbanner);

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

            /* from now, the packet layer is handling incoming packets */
            session->socket_callbacks.data=ssh_packet_socket_callback;

            ssh_packet_set_default_callbacks(session);
            set_status(session, 0.5f);
            session->session_state=SSH_SESSION_STATE_INITIAL_KEX;
            if (ssh_send_kex(session, 1) < 0) {
                goto error;
            }
            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);
            if(session->next_crypto->server_kex.methods[0]==NULL){
                if(server_set_kex(session) == SSH_ERROR)
                    goto error;
                /* We are in a rekeying, so we need to send the server kex */
                if(ssh_send_kex(session, 1) < 0)
                    goto error;
            }
            ssh_list_kex(&session->next_crypto->client_kex); // log client kex
            if (ssh_kex_select_methods(session) < 0) {
                goto error;
            }
            if (crypt_set_algorithms_server(session) == SSH_ERROR)
                goto error;
            set_status(session,0.8f);
            session->session_state=SSH_SESSION_STATE_DH;
            break;
        case SSH_SESSION_STATE_DH:
            if(session->dh_handshake_state==DH_STATE_FINISHED){
                if (ssh_generate_session_keys(session) < 0) {
                    goto error;
                }

                /*
                 * Once we got SSH2_MSG_NEWKEYS we can switch next_crypto and
                 * current_crypto
                 */
                if (session->current_crypto) {
                    crypto_free(session->current_crypto);
                }

                /* FIXME TODO later, include a function to change keys */
                session->current_crypto = session->next_crypto;
                session->next_crypto = crypto_new();
                if (session->next_crypto == NULL) {
                    goto error;
                }
                session->next_crypto->session_id = malloc(session->current_crypto->digest_len);
                if (session->next_crypto->session_id == NULL) {
                    ssh_set_error_oom(session);
                    goto error;
                }
                memcpy(session->next_crypto->session_id, session->current_crypto->session_id,
                        session->current_crypto->digest_len);
                if (session->current_crypto->in_cipher->set_decrypt_key(session->current_crypto->in_cipher, session->current_crypto->decryptkey,
                            session->current_crypto->decryptIV) < 0) {
                    goto error;
                }
                if (session->current_crypto->out_cipher->set_encrypt_key(session->current_crypto->out_cipher, session->current_crypto->encryptkey,
                            session->current_crypto->encryptIV) < 0) {
                    goto error;
                }

                set_status(session,1.0f);
                session->connected = 1;
                session->session_state=SSH_SESSION_STATE_AUTHENTICATING;
                if (session->flags & SSH_SESSION_FLAG_AUTHENTICATED)
                    session->session_state = SSH_SESSION_STATE_AUTHENTICATED;
            }
            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;
}
Esempio n. 9
0
/**
 * @internal
 *
 * @brief A function to be called each time a step has been done in the
 * connection.
 */
static void ssh_server_connection_callback(ssh_session session){
    int rc;

    switch(session->session_state){
        case SSH_SESSION_STATE_NONE:
        case SSH_SESSION_STATE_CONNECTING:
        case SSH_SESSION_STATE_SOCKET_CONNECTED:
            break;
        case SSH_SESSION_STATE_BANNER_RECEIVED:
            if (session->clientbanner == NULL) {
                goto error;
            }
            set_status(session, 0.4f);
            SSH_LOG(SSH_LOG_RARE,
                    "SSH client banner: %s", session->clientbanner);

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

            /* from now, the packet layer is handling incoming packets */
            session->socket_callbacks.data=ssh_packet_socket_callback;
            ssh_packet_register_socket_callback(session, session->socket);

            ssh_packet_set_default_callbacks(session);
            set_status(session, 0.5f);
            session->session_state=SSH_SESSION_STATE_INITIAL_KEX;
            if (ssh_send_kex(session, 1) < 0) {
                goto error;
            }
            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);
            if(session->next_crypto->server_kex.methods[0]==NULL){
                if(server_set_kex(session) == SSH_ERROR)
                    goto error;
                /* We are in a rekeying, so we need to send the server kex */
                if(ssh_send_kex(session, 1) < 0)
                    goto error;
            }
            ssh_list_kex(&session->next_crypto->client_kex); // log client kex
            if (ssh_kex_select_methods(session) < 0) {
                goto error;
            }
            if (crypt_set_algorithms_server(session) == SSH_ERROR)
                goto error;
            set_status(session,0.8f);
            session->session_state=SSH_SESSION_STATE_DH;
            break;
        case SSH_SESSION_STATE_DH:
            if(session->dh_handshake_state==DH_STATE_FINISHED){

                rc = ssh_packet_set_newkeys(session, SSH_DIRECTION_IN);
                if (rc != SSH_OK) {
                    goto error;
                }

                /*
                 * If the client supports extension negotiation, we will send
                 * our supported extensions now. This is the first message after
                 * sending NEWKEYS message and after turning on crypto.
                 */
                if (session->extensions & SSH_EXT_NEGOTIATION &&
                    session->session_state != SSH_SESSION_STATE_AUTHENTICATED) {

                    /*
                     * Only send an SSH_MSG_EXT_INFO message the first time the client
                     * undergoes NEWKEYS.  It is unexpected for this message to be sent
                     * upon rekey, and may cause clients to log error messages.
                     *
                     * The session_state can not be used for this purpose because it is
                     * re-set to SSH_SESSION_STATE_KEXINIT_RECEIVED during rekey.  So,
                     * use the connected flag which transitions from non-zero below.
                     *
                     * See also:
                     * - https://bugzilla.mindrot.org/show_bug.cgi?id=2929
                     */
                    if (session->connected == 0) {
                        ssh_server_send_extensions(session);
                    }
                }

                set_status(session,1.0f);
                session->connected = 1;
                session->session_state=SSH_SESSION_STATE_AUTHENTICATING;
                if (session->flags & SSH_SESSION_FLAG_AUTHENTICATED)
                    session->session_state = SSH_SESSION_STATE_AUTHENTICATED;

            }
            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;
}