Blame src/packet.c

Packit Service 31306d
/*
Packit Service 31306d
 * packet.c - packet building functions
Packit Service 31306d
 *
Packit Service 31306d
 * This file is part of the SSH Library
Packit Service 31306d
 *
Packit Service 31306d
 * Copyright (c) 2003-2013 by Aris Adamantiadis
Packit Service 31306d
 *
Packit Service 31306d
 * The SSH Library is free software; you can redistribute it and/or modify
Packit Service 31306d
 * it under the terms of the GNU Lesser General Public License as published by
Packit Service 31306d
 * the Free Software Foundation; either version 2.1 of the License, or (at your
Packit Service 31306d
 * option) any later version.
Packit Service 31306d
 *
Packit Service 31306d
 * The SSH Library is distributed in the hope that it will be useful, but
Packit Service 31306d
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
Packit Service 31306d
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
Packit Service 31306d
 * License for more details.
Packit Service 31306d
 *
Packit Service 31306d
 * You should have received a copy of the GNU Lesser General Public License
Packit Service 31306d
 * along with the SSH Library; see the file COPYING.  If not, write to
Packit Service 31306d
 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
Packit Service 31306d
 * MA 02111-1307, USA.
Packit Service 31306d
 */
Packit Service 31306d
Packit Service 31306d
#include "config.h"
Packit Service 31306d
Packit Service 31306d
#include <stdlib.h>
Packit Service 31306d
#include <stdio.h>
Packit Service 31306d
#include <string.h>
Packit Service 31306d
#include <errno.h>
Packit Service 31306d
Packit Service 31306d
#ifndef _WIN32
Packit Service 31306d
#include <netinet/in.h>
Packit Service 31306d
#include <arpa/inet.h>
Packit Service 31306d
#endif
Packit Service 31306d
Packit Service 31306d
#include "libssh/priv.h"
Packit Service 31306d
#include "libssh/ssh2.h"
Packit Service 31306d
#include "libssh/crypto.h"
Packit Service 31306d
#include "libssh/buffer.h"
Packit Service 31306d
#include "libssh/packet.h"
Packit Service 31306d
#include "libssh/socket.h"
Packit Service 31306d
#include "libssh/channels.h"
Packit Service 31306d
#include "libssh/misc.h"
Packit Service 31306d
#include "libssh/session.h"
Packit Service 31306d
#include "libssh/messages.h"
Packit Service 31306d
#include "libssh/pcap.h"
Packit Service 31306d
#include "libssh/kex.h"
Packit Service 31306d
#include "libssh/auth.h"
Packit Service 31306d
#include "libssh/gssapi.h"
Packit Service 31306d
#include "libssh/bytearray.h"
Packit Service 31306d
#include "libssh/dh.h"
Packit Service 31306d
Packit Service 31306d
static ssh_packet_callback default_packet_handlers[]= {
Packit Service 31306d
  ssh_packet_disconnect_callback,          // SSH2_MSG_DISCONNECT                 1
Packit Service 31306d
  ssh_packet_ignore_callback,              // SSH2_MSG_IGNORE	                    2
Packit Service 31306d
  ssh_packet_unimplemented,                // SSH2_MSG_UNIMPLEMENTED              3
Packit Service 31306d
  ssh_packet_ignore_callback,              // SSH2_MSG_DEBUG	                    4
Packit Service 31306d
#if WITH_SERVER
Packit Service 31306d
  ssh_packet_service_request,              // SSH2_MSG_SERVICE_REQUEST	          5
Packit Service 31306d
#else
Packit Service 31306d
  NULL,
Packit Service 31306d
#endif
Packit Service 31306d
  ssh_packet_service_accept,               // SSH2_MSG_SERVICE_ACCEPT             6
Packit Service 31306d
  ssh_packet_ext_info,                     // SSH2_MSG_EXT_INFO                   7
Packit Service 31306d
  NULL, NULL, NULL, NULL, NULL, NULL,
Packit Service 31306d
  NULL, NULL, NULL, NULL, NULL, NULL,      //                                     8-19
Packit Service 31306d
  ssh_packet_kexinit,                      // SSH2_MSG_KEXINIT	                  20
Packit Service 31306d
  ssh_packet_newkeys,                      // SSH2_MSG_NEWKEYS                    21
Packit Service 31306d
  NULL, NULL, NULL, NULL, NULL, NULL, NULL,
Packit Service 31306d
  NULL,                                    //                                     22-29
Packit Service 31306d
#if WITH_SERVER
Packit Service 31306d
  ssh_packet_kexdh_init,                   // SSH2_MSG_KEXDH_INIT                 30
Packit Service 31306d
                                           // SSH2_MSG_KEX_DH_GEX_REQUEST_OLD     30
Packit Service 31306d
#else
Packit Service 31306d
  NULL,
Packit Service 31306d
#endif
Packit Service 31306d
  NULL,                                    // SSH2_MSG_KEXDH_REPLY                31
Packit Service 31306d
                                           // SSH2_MSG_KEX_DH_GEX_GROUP           31
Packit Service 31306d
  NULL,                                    // SSH2_MSG_KEX_DH_GEX_INIT            32
Packit Service 31306d
  NULL,                                    // SSH2_MSG_KEX_DH_GEX_REPLY           33
Packit Service 31306d
  NULL,                                    // SSH2_MSG_KEX_DH_GEX_REQUEST         34
Packit Service 31306d
  NULL, NULL, NULL, NULL, NULL, NULL,	NULL,
Packit Service 31306d
  NULL, NULL, NULL, NULL, NULL, NULL, NULL,
Packit Service 31306d
  NULL,                                    //                                     35-49
Packit Service 31306d
#if WITH_SERVER
Packit Service 31306d
  ssh_packet_userauth_request,             // SSH2_MSG_USERAUTH_REQUEST           50
Packit Service 31306d
#else
Packit Service 31306d
  NULL,
Packit Service 31306d
#endif
Packit Service 31306d
  ssh_packet_userauth_failure,             // SSH2_MSG_USERAUTH_FAILURE           51
Packit Service 31306d
  ssh_packet_userauth_success,             // SSH2_MSG_USERAUTH_SUCCESS           52
Packit Service 31306d
  ssh_packet_userauth_banner,              // SSH2_MSG_USERAUTH_BANNER            53
Packit Service 31306d
  NULL,NULL,NULL,NULL,NULL,NULL,           //                                     54-59
Packit Service 31306d
  ssh_packet_userauth_pk_ok,               // SSH2_MSG_USERAUTH_PK_OK             60
Packit Service 31306d
                                           // SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ  60
Packit Service 31306d
                                           // SSH2_MSG_USERAUTH_INFO_REQUEST	  60
Packit Service 31306d
                                           // SSH2_MSG_USERAUTH_GSSAPI_RESPONSE   60
Packit Service 31306d
  ssh_packet_userauth_info_response,       // SSH2_MSG_USERAUTH_INFO_RESPONSE     61
Packit Service 31306d
                                           // SSH2_MSG_USERAUTH_GSSAPI_TOKEN      61
Packit Service 31306d
  NULL,                                    //                                     62
Packit Service 31306d
  NULL,                             // SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE 63
Packit Service 31306d
  NULL,                                    // SSH2_MSG_USERAUTH_GSSAPI_ERROR      64
Packit Service 31306d
  NULL,                                    // SSH2_MSG_USERAUTH_GSSAPI_ERRTOK     65
Packit Service 31306d
#if defined(WITH_GSSAPI) && defined(WITH_SERVER)
Packit Service 31306d
  ssh_packet_userauth_gssapi_mic,          // SSH2_MSG_USERAUTH_GSSAPI_MIC        66
Packit Service 31306d
#else /* WITH_GSSAPI && WITH_SERVER */
Packit Service 31306d
  NULL,
Packit Service 31306d
#endif /* WITH_GSSAPI && WITH_SERVER */
Packit Service 31306d
  NULL, NULL,
Packit Service 31306d
  NULL, NULL, NULL, NULL, NULL, NULL, NULL,
Packit Service 31306d
  NULL, NULL, NULL, NULL,                  //                                     67-79
Packit Service 31306d
#ifdef WITH_SERVER
Packit Service 31306d
  ssh_packet_global_request,               // SSH2_MSG_GLOBAL_REQUEST             80
Packit Service 31306d
#else /* WITH_SERVER */
Packit Service 31306d
  NULL,
Packit Service 31306d
#endif /* WITH_SERVER */ 
Packit Service 31306d
  ssh_request_success,                     // SSH2_MSG_REQUEST_SUCCESS            81
Packit Service 31306d
  ssh_request_denied,                      // SSH2_MSG_REQUEST_FAILURE            82
Packit Service 31306d
  NULL, NULL, NULL, NULL, NULL, NULL, NULL,//                                     83-89
Packit Service 31306d
  ssh_packet_channel_open,                 // SSH2_MSG_CHANNEL_OPEN               90
Packit Service 31306d
  ssh_packet_channel_open_conf,            // SSH2_MSG_CHANNEL_OPEN_CONFIRMATION  91
Packit Service 31306d
  ssh_packet_channel_open_fail,            // SSH2_MSG_CHANNEL_OPEN_FAILURE       92
Packit Service 31306d
  channel_rcv_change_window,               // SSH2_MSG_CHANNEL_WINDOW_ADJUST      93
Packit Service 31306d
  channel_rcv_data,                        // SSH2_MSG_CHANNEL_DATA               94
Packit Service 31306d
  channel_rcv_data,                        // SSH2_MSG_CHANNEL_EXTENDED_DATA      95
Packit Service 31306d
  channel_rcv_eof,                         // SSH2_MSG_CHANNEL_EOF	              96
Packit Service 31306d
  channel_rcv_close,                       // SSH2_MSG_CHANNEL_CLOSE              97
Packit Service 31306d
  channel_rcv_request,                     // SSH2_MSG_CHANNEL_REQUEST            98
Packit Service 31306d
  ssh_packet_channel_success,              // SSH2_MSG_CHANNEL_SUCCESS            99
Packit Service 31306d
  ssh_packet_channel_failure,              // SSH2_MSG_CHANNEL_FAILURE            100
Packit Service 31306d
};
Packit Service 31306d
Packit Service 31306d
/** @internal
Packit Service 31306d
 * @brief check if the received packet is allowed for the current session state
Packit Service 31306d
 * @param session current ssh_session
Packit Service 31306d
 * @returns SSH_PACKET_ALLOWED if the packet is allowed; SSH_PACKET_DENIED
Packit Service 31306d
 * if the packet arrived in wrong state; SSH_PACKET_UNKNOWN if the packet type
Packit Service 31306d
 * is unknown
Packit Service 31306d
 */
Packit Service 31306d
static enum ssh_packet_filter_result_e ssh_packet_incoming_filter(ssh_session session)
Packit Service 31306d
{
Packit Service 31306d
    enum ssh_packet_filter_result_e rc;
Packit Service 31306d
Packit Service 31306d
#ifdef DEBUG_PACKET
Packit Service 31306d
    SSH_LOG(SSH_LOG_PACKET, "Filtering packet type %d",
Packit Service 31306d
            session->in_packet.type);
Packit Service 31306d
#endif
Packit Service 31306d
Packit Service 31306d
    switch(session->in_packet.type) {
Packit Service 31306d
    case SSH2_MSG_DISCONNECT:                         // 1
Packit Service 31306d
        /*
Packit Service 31306d
         * States required:
Packit Service 31306d
         * - None
Packit Service 31306d
         *
Packit Service 31306d
         * Transitions:
Packit Service 31306d
         * - session->socket->state = SSH_SOCKET_CLOSED
Packit Service 31306d
         * - session->session_state = SSH_SESSION_STATE_ERROR
Packit Service 31306d
         * */
Packit Service 31306d
Packit Service 31306d
        /* Always allowed */
Packit Service 31306d
        rc = SSH_PACKET_ALLOWED;
Packit Service 31306d
        break;
Packit Service 31306d
    case SSH2_MSG_IGNORE:                             // 2
Packit Service 31306d
        /*
Packit Service 31306d
         * States required:
Packit Service 31306d
         * - None
Packit Service 31306d
         *
Packit Service 31306d
         * Transitions:
Packit Service 31306d
         * - None
Packit Service 31306d
         * */
Packit Service 31306d
Packit Service 31306d
        /* Always allowed */
Packit Service 31306d
        rc = SSH_PACKET_ALLOWED;
Packit Service 31306d
        break;
Packit Service 31306d
    case SSH2_MSG_UNIMPLEMENTED:                      // 3
Packit Service 31306d
        /*
Packit Service 31306d
         * States required:
Packit Service 31306d
         * - None
Packit Service 31306d
         *
Packit Service 31306d
         * Transitions:
Packit Service 31306d
         * - None
Packit Service 31306d
         * */
Packit Service 31306d
Packit Service 31306d
        /* Always allowed */
Packit Service 31306d
        rc = SSH_PACKET_ALLOWED;
Packit Service 31306d
        break;
Packit Service 31306d
    case SSH2_MSG_DEBUG:                              // 4
Packit Service 31306d
        /*
Packit Service 31306d
         * States required:
Packit Service 31306d
         * - None
Packit Service 31306d
         *
Packit Service 31306d
         * Transitions:
Packit Service 31306d
         * - None
Packit Service 31306d
         * */
Packit Service 31306d
Packit Service 31306d
        /* Always allowed */
Packit Service 31306d
        rc = SSH_PACKET_ALLOWED;
Packit Service 31306d
        break;
Packit Service 31306d
    case SSH2_MSG_SERVICE_REQUEST:                    // 5
Packit Service 31306d
        /* Server only */
Packit Service 31306d
Packit Service 31306d
        /*
Packit Service 31306d
         * States required:
Packit Service 31306d
         * - session->session_state == SSH_SESSION_STATE_AUTHENTICATING
Packit Service 31306d
         *   or session->session_state == SSH_SESSION_STATE_AUTHENTICATED
Packit Service 31306d
         * - session->dh_handshake_state == DH_STATE_FINISHED
Packit Service 31306d
         *
Packit Service 31306d
         * Transitions:
Packit Service 31306d
         * - None
Packit Service 31306d
         * */
Packit Service 31306d
Packit Service 31306d
        /* If this is a client, reject the message */
Packit Service 31306d
        if (session->client) {
Packit Service 31306d
            rc = SSH_PACKET_DENIED;
Packit Service 31306d
            break;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        if ((session->session_state != SSH_SESSION_STATE_AUTHENTICATING) &&
Packit Service 31306d
            (session->session_state != SSH_SESSION_STATE_AUTHENTICATED))
Packit Service 31306d
        {
Packit Service 31306d
            rc = SSH_PACKET_DENIED;
Packit Service 31306d
            break;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        if (session->dh_handshake_state != DH_STATE_FINISHED) {
Packit Service 31306d
            rc = SSH_PACKET_DENIED;
Packit Service 31306d
            break;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        rc = SSH_PACKET_ALLOWED;
Packit Service 31306d
        break;
Packit Service 31306d
    case SSH2_MSG_SERVICE_ACCEPT:                     // 6
Packit Service 31306d
        /*
Packit Service 31306d
         * States required:
Packit Service 31306d
         * - session->session_state == SSH_SESSION_STATE_AUTHENTICATING
Packit Service 31306d
         *   or session->session_state == SSH_SESSION_STATE_AUTHENTICATED
Packit Service 31306d
         * - session->dh_handshake_state == DH_STATE_FINISHED
Packit Service 31306d
         * - session->auth.service_state == SSH_AUTH_SERVICE_SENT
Packit Service 31306d
         *
Packit Service 31306d
         * Transitions:
Packit Service 31306d
         * - auth.service_state = SSH_AUTH_SERVICE_ACCEPTED
Packit Service 31306d
         * */
Packit Service 31306d
Packit Service 31306d
        if ((session->session_state != SSH_SESSION_STATE_AUTHENTICATING) &&
Packit Service 31306d
            (session->session_state != SSH_SESSION_STATE_AUTHENTICATED))
Packit Service 31306d
        {
Packit Service 31306d
            rc = SSH_PACKET_DENIED;
Packit Service 31306d
            break;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        if (session->dh_handshake_state != DH_STATE_FINISHED) {
Packit Service 31306d
            rc = SSH_PACKET_DENIED;
Packit Service 31306d
            break;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        /* TODO check if only auth service can be requested */
Packit Service 31306d
        if (session->auth.service_state != SSH_AUTH_SERVICE_SENT) {
Packit Service 31306d
            rc = SSH_PACKET_DENIED;
Packit Service 31306d
            break;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        rc = SSH_PACKET_ALLOWED;
Packit Service 31306d
        break;
Packit Service 31306d
    case SSH2_MSG_EXT_INFO:                           // 7
Packit Service 31306d
        /*
Packit Service 31306d
         * States required:
Packit Service 31306d
         * - session_state == SSH_SESSION_STATE_AUTHENTICATING
Packit Service 31306d
         *   or session->session_state == SSH_SESSION_STATE_AUTHENTICATED
Packit Service 31306d
         *   (re-exchange)
Packit Service 31306d
         * - dh_handshake_state == DH_STATE_FINISHED
Packit Service 31306d
         *
Packit Service 31306d
         * Transitions:
Packit Service 31306d
         * - None
Packit Service 31306d
         * */
Packit Service 31306d
Packit Service 31306d
        if ((session->session_state != SSH_SESSION_STATE_AUTHENTICATING) &&
Packit Service 31306d
            (session->session_state != SSH_SESSION_STATE_AUTHENTICATED))
Packit Service 31306d
        {
Packit Service 31306d
            rc = SSH_PACKET_DENIED;
Packit Service 31306d
            break;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        if (session->dh_handshake_state != DH_STATE_FINISHED) {
Packit Service 31306d
            rc = SSH_PACKET_DENIED;
Packit Service 31306d
            break;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        rc = SSH_PACKET_ALLOWED;
Packit Service 31306d
        break;
Packit Service 31306d
    case SSH2_MSG_KEXINIT:                            // 20
Packit Service 31306d
        /*
Packit Service 31306d
         * States required:
Packit Service 31306d
         * - session_state == SSH_SESSION_STATE_AUTHENTICATED
Packit Service 31306d
         *   or session_state == SSH_SESSION_STATE_INITIAL_KEX
Packit Service 31306d
         * - dh_handshake_state == DH_STATE_INIT
Packit Service 31306d
         *   or dh_handshake_state == DH_STATE_INIT_SENT (re-exchange)
Packit Service 31306d
         *   or dh_handshake_state == DH_STATE_FINISHED (re-exchange)
Packit Service 31306d
         *
Packit Service 31306d
         * Transitions:
Packit Service 31306d
         * - session->dh_handshake_state = DH_STATE_INIT
Packit Service 31306d
         * - session->session_state = SSH_SESSION_STATE_KEXINIT_RECEIVED
Packit Service 31306d
         *
Packit Service 31306d
         * On server:
Packit Service 31306d
         * - session->session_state = SSH_SESSION_STATE_DH
Packit Service 31306d
         * */
Packit Service 31306d
Packit Service 31306d
        if ((session->session_state != SSH_SESSION_STATE_AUTHENTICATED) &&
Packit Service 31306d
            (session->session_state != SSH_SESSION_STATE_INITIAL_KEX))
Packit Service 31306d
        {
Packit Service 31306d
            rc = SSH_PACKET_DENIED;
Packit Service 31306d
            break;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        if ((session->dh_handshake_state != DH_STATE_INIT) &&
Packit Service 31306d
            (session->dh_handshake_state != DH_STATE_INIT_SENT) &&
Packit Service 31306d
            (session->dh_handshake_state != DH_STATE_FINISHED))
Packit Service 31306d
        {
Packit Service 31306d
            rc = SSH_PACKET_DENIED;
Packit Service 31306d
            break;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        rc = SSH_PACKET_ALLOWED;
Packit Service 31306d
        break;
Packit Service 31306d
    case SSH2_MSG_NEWKEYS:                            // 21
Packit Service 31306d
        /*
Packit Service 31306d
         * States required:
Packit Service 31306d
         * - session_state == SSH_SESSION_STATE_DH
Packit Service 31306d
         * - dh_handshake_state == DH_STATE_NEWKEYS_SENT
Packit Service 31306d
         *
Packit Service 31306d
         * Transitions:
Packit Service 31306d
         * - session->dh_handshake_state = DH_STATE_FINISHED
Packit Service 31306d
         * - session->session_state = SSH_SESSION_STATE_AUTHENTICATING
Packit Service 31306d
         * if session->flags & SSH_SESSION_FLAG_AUTHENTICATED
Packit Service 31306d
         * - session->session_state = SSH_SESSION_STATE_AUTHENTICATED
Packit Service 31306d
         * */
Packit Service 31306d
Packit Service 31306d
        /* If DH has not been started, reject message */
Packit Service 31306d
        if (session->session_state != SSH_SESSION_STATE_DH) {
Packit Service 31306d
            rc = SSH_PACKET_DENIED;
Packit Service 31306d
            break;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        /* Only allowed if dh_handshake_state is in NEWKEYS_SENT state */
Packit Service 31306d
        if (session->dh_handshake_state != DH_STATE_NEWKEYS_SENT) {
Packit Service 31306d
            rc = SSH_PACKET_DENIED;
Packit Service 31306d
            break;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        rc = SSH_PACKET_ALLOWED;
Packit Service 31306d
        break;
Packit Service 31306d
    case SSH2_MSG_KEXDH_INIT:                         // 30
Packit Service 31306d
      // SSH2_MSG_KEX_ECDH_INIT:                      // 30
Packit Service 31306d
      // SSH2_MSG_ECMQV_INIT:                         // 30
Packit Service 31306d
      // SSH2_MSG_KEX_DH_GEX_REQUEST_OLD:             // 30
Packit Service 31306d
Packit Service 31306d
        /* Server only */
Packit Service 31306d
Packit Service 31306d
        /*
Packit Service 31306d
         * States required:
Packit Service 31306d
         * - session_state == SSH_SESSION_STATE_DH
Packit Service 31306d
         * - dh_handshake_state == DH_STATE_INIT
Packit Service 31306d
         *
Packit Service 31306d
         * Transitions:
Packit Service 31306d
         * - session->dh_handshake_state = DH_STATE_INIT_SENT
Packit Service 31306d
         * then calls dh_handshake_server which triggers:
Packit Service 31306d
         * - session->dh_handhsake_state = DH_STATE_NEWKEYS_SENT
Packit Service 31306d
         * */
Packit Service 31306d
Packit Service 31306d
        if (session->session_state != SSH_SESSION_STATE_DH) {
Packit Service 31306d
            rc = SSH_PACKET_DENIED;
Packit Service 31306d
            break;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        /* Only allowed if dh_handshake_state is in initial state */
Packit Service 31306d
        if (session->dh_handshake_state != DH_STATE_INIT) {
Packit Service 31306d
            rc = SSH_PACKET_DENIED;
Packit Service 31306d
            break;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        rc = SSH_PACKET_ALLOWED;
Packit Service 31306d
        break;
Packit Service 31306d
    case SSH2_MSG_KEXDH_REPLY:                        // 31
Packit Service 31306d
      // SSH2_MSG_KEX_ECDH_REPLY:                     // 31
Packit Service 31306d
      // SSH2_MSG_ECMQV_REPLY:                        // 31
Packit Service 31306d
      // SSH2_MSG_KEX_DH_GEX_GROUP:                   // 31
Packit Service 31306d
Packit Service 31306d
        /*
Packit Service 31306d
         * States required:
Packit Service 31306d
         * - session_state == SSH_SESSION_STATE_DH
Packit Service 31306d
         * - dh_handshake_state == DH_STATE_INIT_SENT
Packit Service 31306d
         *   or dh_handshake_state == DH_STATE_REQUEST_SENT (dh-gex)
Packit Service 31306d
         *
Packit Service 31306d
         * Transitions:
Packit Service 31306d
         * - session->dh_handhsake_state = DH_STATE_NEWKEYS_SENT
Packit Service 31306d
         * */
Packit Service 31306d
Packit Service 31306d
        if (session->session_state != SSH_SESSION_STATE_DH) {
Packit Service 31306d
            rc = SSH_PACKET_DENIED;
Packit Service 31306d
            break;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        if (session->dh_handshake_state != DH_STATE_INIT_SENT &&
Packit Service 31306d
            session->dh_handshake_state != DH_STATE_REQUEST_SENT) {
Packit Service 31306d
            rc = SSH_PACKET_DENIED;
Packit Service 31306d
            break;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        rc = SSH_PACKET_ALLOWED;
Packit Service 31306d
        break;
Packit Service 31306d
    case SSH2_MSG_KEX_DH_GEX_INIT:                    // 32
Packit Service 31306d
        /* TODO Not filtered */
Packit Service 31306d
        rc = SSH_PACKET_ALLOWED;
Packit Service 31306d
        break;
Packit Service 31306d
    case SSH2_MSG_KEX_DH_GEX_REPLY:                   // 33
Packit Service 31306d
        /* TODO Not filtered */
Packit Service 31306d
        rc = SSH_PACKET_ALLOWED;
Packit Service 31306d
        break;
Packit Service 31306d
    case SSH2_MSG_KEX_DH_GEX_REQUEST:                 // 34
Packit Service 31306d
        /* TODO Not filtered */
Packit Service 31306d
        rc = SSH_PACKET_ALLOWED;
Packit Service 31306d
        break;
Packit Service 31306d
    case SSH2_MSG_USERAUTH_REQUEST:                   // 50
Packit Service 31306d
        /* Server only */
Packit Service 31306d
Packit Service 31306d
        /*
Packit Service 31306d
         * States required:
Packit Service 31306d
         * - session_state == SSH_SESSION_STATE_AUTHENTICATING
Packit Service 31306d
         * - dh_hanshake_state == DH_STATE_FINISHED
Packit Service 31306d
         *
Packit Service 31306d
         * Transitions:
Packit Service 31306d
         * - if authentication was successful:
Packit Service 31306d
         *   - session_state = SSH_SESSION_STATE_AUTHENTICATED
Packit Service 31306d
         * */
Packit Service 31306d
Packit Service 31306d
        /* If this is a client, reject the message */
Packit Service 31306d
        if (session->client) {
Packit Service 31306d
            rc = SSH_PACKET_DENIED;
Packit Service 31306d
            break;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        if (session->dh_handshake_state != DH_STATE_FINISHED) {
Packit Service 31306d
            rc = SSH_PACKET_DENIED;
Packit Service 31306d
            break;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        if (session->session_state != SSH_SESSION_STATE_AUTHENTICATING) {
Packit Service 31306d
            rc = SSH_PACKET_DENIED;
Packit Service 31306d
            break;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        rc = SSH_PACKET_ALLOWED;
Packit Service 31306d
        break;
Packit Service 31306d
    case SSH2_MSG_USERAUTH_FAILURE:                   // 51
Packit Service 31306d
        /*
Packit Service 31306d
         * States required:
Packit Service 31306d
         * - session_state == SSH_SESSION_STATE_AUTHENTICATING
Packit Service 31306d
         * - dh_hanshake_state == DH_STATE_FINISHED
Packit Service 31306d
         * - session->auth.state == SSH_AUTH_STATE_KBDINT_SENT
Packit Service 31306d
         *   or session->auth.state == SSH_AUTH_STATE_PUBKEY_OFFER_SENT
Packit Service 31306d
         *   or session->auth.state == SSH_AUTH_STATE_PUBKEY_AUTH_SENT
Packit Service 31306d
         *   or session->auth.state == SSH_AUTH_STATE_PASSWORD_AUTH_SENT
Packit Service 31306d
         *   or session->auth.state == SSH_AUTH_STATE_GSSAPI_MIC_SENT
Packit Service 31306d
         *
Packit Service 31306d
         * Transitions:
Packit Service 31306d
         * - if unpacking failed:
Packit Service 31306d
         *   - session->auth.state = SSH_AUTH_ERROR
Packit Service 31306d
         * - if failure was partial:
Packit Service 31306d
         *   - session->auth.state = SSH_AUTH_PARTIAL
Packit Service 31306d
         * - else:
Packit Service 31306d
         *   - session->auth.state = SSH_AUTH_STATE_FAILED
Packit Service 31306d
         * */
Packit Service 31306d
Packit Service 31306d
        /* If this is a server, reject the message */
Packit Service 31306d
        if (session->server) {
Packit Service 31306d
            rc = SSH_PACKET_DENIED;
Packit Service 31306d
            break;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        if (session->dh_handshake_state != DH_STATE_FINISHED) {
Packit Service 31306d
            rc = SSH_PACKET_DENIED;
Packit Service 31306d
            break;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        if (session->session_state != SSH_SESSION_STATE_AUTHENTICATING) {
Packit Service 31306d
            rc = SSH_PACKET_DENIED;
Packit Service 31306d
            break;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        rc = SSH_PACKET_ALLOWED;
Packit Service 31306d
        break;
Packit Service 31306d
    case SSH2_MSG_USERAUTH_SUCCESS:                   // 52
Packit Service 31306d
        /*
Packit Service 31306d
         * States required:
Packit Service 31306d
         * - session_state == SSH_SESSION_STATE_AUTHENTICATING
Packit Service 31306d
         * - dh_hanshake_state == DH_STATE_FINISHED
Packit Service 31306d
         * - session->auth.state == SSH_AUTH_STATE_KBDINT_SENT
Packit Service 31306d
         *   or session->auth.state == SSH_AUTH_STATE_PUBKEY_AUTH_SENT
Packit Service 31306d
         *   or session->auth.state == SSH_AUTH_STATE_PASSWORD_AUTH_SENT
Packit Service 31306d
         *   or session->auth.state == SSH_AUTH_STATE_GSSAPI_MIC_SENT
Packit Service 31306d
         *   or session->auth.state == SSH_AUTH_STATE_AUTH_NONE_SENT
Packit Service 31306d
         *
Packit Service 31306d
         * Transitions:
Packit Service 31306d
         * - session->auth.state = SSH_AUTH_STATE_SUCCESS
Packit Service 31306d
         * - session->session_state = SSH_SESSION_STATE_AUTHENTICATED
Packit Service 31306d
         * - session->flags |= SSH_SESSION_FLAG_AUTHENTICATED
Packit Service 31306d
         * - sessions->auth.current_method = SSH_AUTH_METHOD_UNKNOWN
Packit Service 31306d
         * */
Packit Service 31306d
Packit Service 31306d
        /* If this is a server, reject the message */
Packit Service 31306d
        if (session->server) {
Packit Service 31306d
            rc = SSH_PACKET_DENIED;
Packit Service 31306d
            break;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        if (session->dh_handshake_state != DH_STATE_FINISHED) {
Packit Service 31306d
            rc = SSH_PACKET_DENIED;
Packit Service 31306d
            break;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        if (session->session_state != SSH_SESSION_STATE_AUTHENTICATING) {
Packit Service 31306d
            rc = SSH_PACKET_DENIED;
Packit Service 31306d
            break;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        if ((session->auth.state != SSH_AUTH_STATE_KBDINT_SENT) &&
Packit Service 31306d
            (session->auth.state != SSH_AUTH_STATE_PUBKEY_AUTH_SENT) &&
Packit Service 31306d
            (session->auth.state != SSH_AUTH_STATE_PASSWORD_AUTH_SENT) &&
Packit Service 31306d
            (session->auth.state != SSH_AUTH_STATE_GSSAPI_MIC_SENT) &&
Packit Service 31306d
            (session->auth.state != SSH_AUTH_STATE_AUTH_NONE_SENT))
Packit Service 31306d
        {
Packit Service 31306d
            rc = SSH_PACKET_DENIED;
Packit Service 31306d
            break;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        rc = SSH_PACKET_ALLOWED;
Packit Service 31306d
        break;
Packit Service 31306d
    case SSH2_MSG_USERAUTH_BANNER:                    // 53
Packit Service 31306d
        /*
Packit Service 31306d
         * States required:
Packit Service 31306d
         * - session_state == SSH_SESSION_STATE_AUTHENTICATING
Packit Service 31306d
         *
Packit Service 31306d
         * Transitions:
Packit Service 31306d
         * - None
Packit Service 31306d
         * */
Packit Service 31306d
Packit Service 31306d
        if (session->session_state != SSH_SESSION_STATE_AUTHENTICATING) {
Packit Service 31306d
            rc = SSH_PACKET_DENIED;
Packit Service 31306d
            break;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        rc = SSH_PACKET_ALLOWED;
Packit Service 31306d
        break;
Packit Service 31306d
    case SSH2_MSG_USERAUTH_PK_OK:                     // 60
Packit Service 31306d
      // SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ:          // 60
Packit Service 31306d
      // SSH2_MSG_USERAUTH_INFO_REQUEST:              // 60
Packit Service 31306d
      // SSH2_MSG_USERAUTH_GSSAPI_RESPONSE:           // 60
Packit Service 31306d
Packit Service 31306d
        /*
Packit Service 31306d
         * States required:
Packit Service 31306d
         * - session_state == SSH_SESSION_STATE_AUTHENTICATING
Packit Service 31306d
         * - session->auth.state == SSH_AUTH_STATE_KBDINT_SENT
Packit Service 31306d
         *   or
Packit Service 31306d
         *   session->auth.state == SSH_AUTH_STATE_GSSAPI_REQUEST_SENT
Packit Service 31306d
         *   or
Packit Service 31306d
         *   session->auth.state == SSH_AUTH_STATE_PUBKEY_OFFER_SENT
Packit Service 31306d
         *
Packit Service 31306d
         * Transitions:
Packit Service 31306d
         * Depending on the current state, the message is treated
Packit Service 31306d
         * differently:
Packit Service 31306d
         * - session->auth.state == SSH_AUTH_STATE_KBDINT_SENT
Packit Service 31306d
         *   - session->auth.state = SSH_AUTH_STATE_INFO
Packit Service 31306d
         * - session->auth.state == SSH_AUTH_STATE_GSSAPI_REQUEST_SENT
Packit Service 31306d
         *   - session->auth.state = SSH_AUTH_STATE_GSSAPI_TOKEN
Packit Service 31306d
         * - session->auth.state == SSH_AUTH_STATE_PUBKEY_OFFER_SENT
Packit Service 31306d
         *   - session->auth.state = SSH_AUTH_STATE_PK_OK
Packit Service 31306d
         * */
Packit Service 31306d
Packit Service 31306d
        if (session->session_state != SSH_SESSION_STATE_AUTHENTICATING) {
Packit Service 31306d
            rc = SSH_PACKET_DENIED;
Packit Service 31306d
            break;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        if ((session->auth.state != SSH_AUTH_STATE_KBDINT_SENT) &&
Packit Service 31306d
            (session->auth.state != SSH_AUTH_STATE_PUBKEY_OFFER_SENT) &&
Packit Service 31306d
            (session->auth.state != SSH_AUTH_STATE_GSSAPI_REQUEST_SENT))
Packit Service 31306d
        {
Packit Service 31306d
            rc = SSH_PACKET_DENIED;
Packit Service 31306d
            break;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        rc = SSH_PACKET_ALLOWED;
Packit Service 31306d
        break;
Packit Service 31306d
    case SSH2_MSG_USERAUTH_INFO_RESPONSE:             // 61
Packit Service 31306d
      // SSH2_MSG_USERAUTH_GSSAPI_TOKEN:              // 61
Packit Service 31306d
Packit Service 31306d
        /*
Packit Service 31306d
         * States required:
Packit Service 31306d
         * - session_state == SSH_SESSION_STATE_AUTHENTICATING
Packit Service 31306d
         * - session_state->auth.state == SSH_SESSION_STATE_GSSAPI_TOKEN
Packit Service 31306d
         *   or
Packit Service 31306d
         *   session_state->auth.state == SSH_SESSION_STATE_INFO
Packit Service 31306d
         *
Packit Service 31306d
         * Transitions:
Packit Service 31306d
         * - None
Packit Service 31306d
         * */
Packit Service 31306d
Packit Service 31306d
        if (session->session_state != SSH_SESSION_STATE_AUTHENTICATING) {
Packit Service 31306d
            rc = SSH_PACKET_DENIED;
Packit Service 31306d
            break;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        if ((session->auth.state != SSH_AUTH_STATE_INFO) &&
Packit Service 31306d
            (session->auth.state != SSH_AUTH_STATE_GSSAPI_TOKEN))
Packit Service 31306d
        {
Packit Service 31306d
            rc = SSH_PACKET_DENIED;
Packit Service 31306d
            break;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        rc = SSH_PACKET_ALLOWED;
Packit Service 31306d
        break;
Packit Service 31306d
    case SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE:  // 63
Packit Service 31306d
        /* TODO Not filtered */
Packit Service 31306d
        rc = SSH_PACKET_ALLOWED;
Packit Service 31306d
        break;
Packit Service 31306d
    case SSH2_MSG_USERAUTH_GSSAPI_ERROR:              // 64
Packit Service 31306d
        /* TODO Not filtered */
Packit Service 31306d
        rc = SSH_PACKET_ALLOWED;
Packit Service 31306d
        break;
Packit Service 31306d
    case SSH2_MSG_USERAUTH_GSSAPI_ERRTOK:             // 65
Packit Service 31306d
        /* TODO Not filtered */
Packit Service 31306d
        rc = SSH_PACKET_ALLOWED;
Packit Service 31306d
        break;
Packit Service 31306d
    case SSH2_MSG_USERAUTH_GSSAPI_MIC:                // 66
Packit Service 31306d
        /* Server only */
Packit Service 31306d
Packit Service 31306d
        /*
Packit Service 31306d
         * States required:
Packit Service 31306d
         * - session_state == SSH_SESSION_STATE_AUTHENTICATING
Packit Service 31306d
         * - session->gssapi->state == SSH_GSSAPI_STATE_RCV_MIC
Packit Service 31306d
         *
Packit Service 31306d
         * Transitions:
Packit Service 31306d
         * Depending on the result of the verification, the states are
Packit Service 31306d
         * changed:
Packit Service 31306d
         * - SSH_AUTH_SUCCESS:
Packit Service 31306d
         *   - session->session_state = SSH_SESSION_STATE_AUTHENTICATED
Packit Service 31306d
         *   - session->flags != SSH_SESSION_FLAG_AUTHENTICATED
Packit Service 31306d
         * - SSH_AUTH_PARTIAL:
Packit Service 31306d
         *   - None
Packit Service 31306d
         * - any other case:
Packit Service 31306d
         *   - None
Packit Service 31306d
         * */
Packit Service 31306d
Packit Service 31306d
        /* If this is a client, reject the message */
Packit Service 31306d
        if (session->client) {
Packit Service 31306d
            rc = SSH_PACKET_DENIED;
Packit Service 31306d
            break;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        if (session->dh_handshake_state != DH_STATE_FINISHED) {
Packit Service 31306d
            rc = SSH_PACKET_DENIED;
Packit Service 31306d
            break;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        if (session->session_state != SSH_SESSION_STATE_AUTHENTICATING) {
Packit Service 31306d
            rc = SSH_PACKET_DENIED;
Packit Service 31306d
            break;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        rc = SSH_PACKET_ALLOWED;
Packit Service 31306d
        break;
Packit Service 31306d
    case SSH2_MSG_GLOBAL_REQUEST:                     // 80
Packit Service 31306d
        /*
Packit Service 31306d
         * States required:
Packit Service 31306d
         * - session_state == SSH_SESSION_STATE_AUTHENTICATED
Packit Service 31306d
         *
Packit Service 31306d
         * Transitions:
Packit Service 31306d
         * - None
Packit Service 31306d
         * */
Packit Service 31306d
Packit Service 31306d
        if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) {
Packit Service 31306d
            rc = SSH_PACKET_DENIED;
Packit Service 31306d
            break;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        rc = SSH_PACKET_ALLOWED;
Packit Service 31306d
        break;
Packit Service 31306d
    case SSH2_MSG_REQUEST_SUCCESS:                    // 81
Packit Service 31306d
        /*
Packit Service 31306d
         * States required:
Packit Service 31306d
         * - session_state == SSH_SESSION_STATE_AUTHENTICATED
Packit Service 31306d
         * - session->global_req_state == SSH_CHANNEL_REQ_STATE_PENDING
Packit Service 31306d
         *
Packit Service 31306d
         * Transitions:
Packit Service 31306d
         * - session->global_req_state == SSH_CHANNEL_REQ_STATE_ACCEPTED
Packit Service 31306d
         * */
Packit Service 31306d
Packit Service 31306d
        if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) {
Packit Service 31306d
            rc = SSH_PACKET_DENIED;
Packit Service 31306d
            break;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        if (session->global_req_state != SSH_CHANNEL_REQ_STATE_PENDING) {
Packit Service 31306d
            rc = SSH_PACKET_DENIED;
Packit Service 31306d
            break;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        rc = SSH_PACKET_ALLOWED;
Packit Service 31306d
        break;
Packit Service 31306d
    case SSH2_MSG_REQUEST_FAILURE:                    // 82
Packit Service 31306d
        /*
Packit Service 31306d
         * States required:
Packit Service 31306d
         * - session_state == SSH_SESSION_STATE_AUTHENTICATED
Packit Service 31306d
         * - session->global_req_state == SSH_CHANNEL_REQ_STATE_PENDING
Packit Service 31306d
         *
Packit Service 31306d
         * Transitions:
Packit Service 31306d
         * - session->global_req_state == SSH_CHANNEL_REQ_STATE_DENIED
Packit Service 31306d
         * */
Packit Service 31306d
Packit Service 31306d
        if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) {
Packit Service 31306d
            rc = SSH_PACKET_DENIED;
Packit Service 31306d
            break;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        if (session->global_req_state != SSH_CHANNEL_REQ_STATE_PENDING) {
Packit Service 31306d
            rc = SSH_PACKET_DENIED;
Packit Service 31306d
            break;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        rc = SSH_PACKET_ALLOWED;
Packit Service 31306d
        break;
Packit Service 31306d
    case SSH2_MSG_CHANNEL_OPEN:                       // 90
Packit Service 31306d
        /*
Packit Service 31306d
         * States required:
Packit Service 31306d
         * - session_state == SSH_SESSION_STATE_AUTHENTICATED
Packit Service 31306d
         *
Packit Service 31306d
         * Transitions:
Packit Service 31306d
         * - None
Packit Service 31306d
         * */
Packit Service 31306d
Packit Service 31306d
        if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) {
Packit Service 31306d
            rc = SSH_PACKET_DENIED;
Packit Service 31306d
            break;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        rc = SSH_PACKET_ALLOWED;
Packit Service 31306d
        break;
Packit Service 31306d
    case SSH2_MSG_CHANNEL_OPEN_CONFIRMATION:          // 91
Packit Service 31306d
        /*
Packit Service 31306d
         * States required:
Packit Service 31306d
         * - session_state == SSH_SESSION_STATE_AUTHENTICATED
Packit Service 31306d
         *
Packit Service 31306d
         * Transitions:
Packit Service 31306d
         * - channel->state = SSH_CHANNEL_STATE_OPEN
Packit Service 31306d
         * - channel->flags &= ~SSH_CHANNEL_FLAG_NOT_BOUND
Packit Service 31306d
         * */
Packit Service 31306d
Packit Service 31306d
        if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) {
Packit Service 31306d
            rc = SSH_PACKET_DENIED;
Packit Service 31306d
            break;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        rc = SSH_PACKET_ALLOWED;
Packit Service 31306d
        break;
Packit Service 31306d
    case SSH2_MSG_CHANNEL_OPEN_FAILURE:               // 92
Packit Service 31306d
        /*
Packit Service 31306d
         * States required:
Packit Service 31306d
         * - session_state == SSH_SESSION_STATE_AUTHENTICATED
Packit Service 31306d
         *
Packit Service 31306d
         * Transitions:
Packit Service 31306d
         * - channel->state = SSH_CHANNEL_STATE_OPEN_DENIED
Packit Service 31306d
         * */
Packit Service 31306d
Packit Service 31306d
        if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) {
Packit Service 31306d
            rc = SSH_PACKET_DENIED;
Packit Service 31306d
            break;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        rc = SSH_PACKET_ALLOWED;
Packit Service 31306d
        break;
Packit Service 31306d
    case SSH2_MSG_CHANNEL_WINDOW_ADJUST:              // 93
Packit Service 31306d
        /*
Packit Service 31306d
         * States required:
Packit Service 31306d
         * - session_state == SSH_SESSION_STATE_AUTHENTICATED
Packit Service 31306d
         *
Packit Service 31306d
         * Transitions:
Packit Service 31306d
         * - None
Packit Service 31306d
         * */
Packit Service 31306d
Packit Service 31306d
        if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) {
Packit Service 31306d
            rc = SSH_PACKET_DENIED;
Packit Service 31306d
            break;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        rc = SSH_PACKET_ALLOWED;
Packit Service 31306d
        break;
Packit Service 31306d
    case SSH2_MSG_CHANNEL_DATA:                       // 94
Packit Service 31306d
        /*
Packit Service 31306d
         * States required:
Packit Service 31306d
         * - session_state == SSH_SESSION_STATE_AUTHENTICATED
Packit Service 31306d
         *
Packit Service 31306d
         * Transitions:
Packit Service 31306d
         * - None
Packit Service 31306d
         * */
Packit Service 31306d
Packit Service 31306d
        if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) {
Packit Service 31306d
            rc = SSH_PACKET_DENIED;
Packit Service 31306d
            break;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        rc = SSH_PACKET_ALLOWED;
Packit Service 31306d
        break;
Packit Service 31306d
    case SSH2_MSG_CHANNEL_EXTENDED_DATA:              // 95
Packit Service 31306d
        /*
Packit Service 31306d
         * States required:
Packit Service 31306d
         * - session_state == SSH_SESSION_STATE_AUTHENTICATED
Packit Service 31306d
         *
Packit Service 31306d
         * Transitions:
Packit Service 31306d
         * - None
Packit Service 31306d
         * */
Packit Service 31306d
Packit Service 31306d
        if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) {
Packit Service 31306d
            rc = SSH_PACKET_DENIED;
Packit Service 31306d
            break;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        rc = SSH_PACKET_ALLOWED;
Packit Service 31306d
        break;
Packit Service 31306d
    case SSH2_MSG_CHANNEL_EOF:                        // 96
Packit Service 31306d
        /*
Packit Service 31306d
         * States required:
Packit Service 31306d
         * - session_state == SSH_SESSION_STATE_AUTHENTICATED
Packit Service 31306d
         *
Packit Service 31306d
         * Transitions:
Packit Service 31306d
         * - None
Packit Service 31306d
         * */
Packit Service 31306d
Packit Service 31306d
        if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) {
Packit Service 31306d
            rc = SSH_PACKET_DENIED;
Packit Service 31306d
            break;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        rc = SSH_PACKET_ALLOWED;
Packit Service 31306d
        break;
Packit Service 31306d
    case SSH2_MSG_CHANNEL_CLOSE:                      // 97
Packit Service 31306d
        /*
Packit Service 31306d
         * States required:
Packit Service 31306d
         * - session_state == SSH_SESSION_STATE_AUTHENTICATED
Packit Service 31306d
         *
Packit Service 31306d
         * Transitions:
Packit Service 31306d
         * - channel->state = SSH_CHANNEL_STATE_CLOSED
Packit Service 31306d
         * - channel->flags |= SSH_CHANNEL_FLAG_CLOSED_REMOTE
Packit Service 31306d
         * */
Packit Service 31306d
Packit Service 31306d
        if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) {
Packit Service 31306d
            rc = SSH_PACKET_DENIED;
Packit Service 31306d
            break;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        rc = SSH_PACKET_ALLOWED;
Packit Service 31306d
        break;
Packit Service 31306d
    case SSH2_MSG_CHANNEL_REQUEST:                    // 98
Packit Service 31306d
        /*
Packit Service 31306d
         * States required:
Packit Service 31306d
         * - session_state == SSH_SESSION_STATE_AUTHENTICATED
Packit Service 31306d
         *
Packit Service 31306d
         * Transitions:
Packit Service 31306d
         * - Depends on the request
Packit Service 31306d
         * */
Packit Service 31306d
Packit Service 31306d
        if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) {
Packit Service 31306d
            rc = SSH_PACKET_DENIED;
Packit Service 31306d
            break;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        rc = SSH_PACKET_ALLOWED;
Packit Service 31306d
        break;
Packit Service 31306d
    case SSH2_MSG_CHANNEL_SUCCESS:                    // 99
Packit Service 31306d
        /*
Packit Service 31306d
         * States required:
Packit Service 31306d
         * - session_state == SSH_SESSION_STATE_AUTHENTICATED
Packit Service 31306d
         * - channel->request_state == SSH_CHANNEL_REQ_STATE_PENDING
Packit Service 31306d
         *
Packit Service 31306d
         * Transitions:
Packit Service 31306d
         * - channel->request_state = SSH_CHANNEL_REQ_STATE_ACCEPTED
Packit Service 31306d
         * */
Packit Service 31306d
Packit Service 31306d
        if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) {
Packit Service 31306d
            rc = SSH_PACKET_DENIED;
Packit Service 31306d
            break;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        rc = SSH_PACKET_ALLOWED;
Packit Service 31306d
        break;
Packit Service 31306d
    case SSH2_MSG_CHANNEL_FAILURE:                    // 100
Packit Service 31306d
        /*
Packit Service 31306d
         * States required:
Packit Service 31306d
         * - session_state == SSH_SESSION_STATE_AUTHENTICATED
Packit Service 31306d
         * - channel->request_state == SSH_CHANNEL_REQ_STATE_PENDING
Packit Service 31306d
         *
Packit Service 31306d
         * Transitions:
Packit Service 31306d
         * - channel->request_state = SSH_CHANNEL_REQ_STATE_DENIED
Packit Service 31306d
         * */
Packit Service 31306d
Packit Service 31306d
        if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) {
Packit Service 31306d
            rc = SSH_PACKET_DENIED;
Packit Service 31306d
            break;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        rc = SSH_PACKET_ALLOWED;
Packit Service 31306d
        break;
Packit Service 31306d
    default:
Packit Service 31306d
        /* Unknown message, do not filter */
Packit Service 31306d
        rc = SSH_PACKET_UNKNOWN;
Packit Service 31306d
        goto end;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
end:
Packit Service 31306d
#ifdef DEBUG_PACKET
Packit Service 31306d
    if (rc == SSH_PACKET_DENIED) {
Packit Service 31306d
        SSH_LOG(SSH_LOG_PACKET, "REJECTED packet type %d: ",
Packit Service 31306d
                session->in_packet.type);
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if (rc == SSH_PACKET_UNKNOWN) {
Packit Service 31306d
        SSH_LOG(SSH_LOG_PACKET, "UNKNOWN packet type %d",
Packit Service 31306d
                session->in_packet.type);
Packit Service 31306d
    }
Packit Service 31306d
#endif
Packit Service 31306d
Packit Service 31306d
    return rc;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/* Returns current_crypto structure from the session.
Packit Service 31306d
 * During key exchange (or rekey), after one of the sides
Packit Service 31306d
 * sending NEWKEYS packet, this might return next_crypto for one
Packit Service 31306d
 * of the directions that is ahead to send already queued packets
Packit Service 31306d
 */
Packit Service 31306d
struct ssh_crypto_struct *
Packit Service 31306d
ssh_packet_get_current_crypto(ssh_session session,
Packit Service 31306d
                              enum ssh_crypto_direction_e direction)
Packit Service 31306d
{
Packit Service 31306d
    struct ssh_crypto_struct *crypto = NULL;
Packit Service 31306d
Packit Service 31306d
    if (session == NULL) {
Packit Service 31306d
        return NULL;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if (session->current_crypto != NULL &&
Packit Service 31306d
        session->current_crypto->used & direction) {
Packit Service 31306d
        crypto = session->current_crypto;
Packit Service 31306d
    } else if (session->next_crypto != NULL &&
Packit Service 31306d
               session->next_crypto->used & direction) {
Packit Service 31306d
        crypto = session->next_crypto;
Packit Service 31306d
    } else {
Packit Service 31306d
        return NULL;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    switch (direction) {
Packit Service 31306d
    case SSH_DIRECTION_IN:
Packit Service 31306d
        if (crypto->in_cipher != NULL) {
Packit Service 31306d
            return crypto;
Packit Service 31306d
        }
Packit Service 31306d
        break;
Packit Service 31306d
    case SSH_DIRECTION_OUT:
Packit Service 31306d
        if (crypto->out_cipher != NULL) {
Packit Service 31306d
            return crypto;
Packit Service 31306d
        }
Packit Service 31306d
        break;
Packit Service 31306d
    case SSH_DIRECTION_BOTH:
Packit Service 31306d
        if (crypto->in_cipher != NULL &&
Packit Service 31306d
            crypto->out_cipher != NULL) {
Packit Service 31306d
            return crypto;
Packit Service 31306d
        }
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    return NULL;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
#define MAX_PACKETS    (1UL<<31)
Packit Service 31306d
Packit Service 31306d
static bool ssh_packet_need_rekey(ssh_session session,
Packit Service 31306d
                                  const uint32_t payloadsize)
Packit Service 31306d
{
Packit Service 31306d
    bool data_rekey_needed = false;
Packit Service 31306d
    struct ssh_crypto_struct *crypto = NULL;
Packit Service 31306d
    struct ssh_cipher_struct *out_cipher = NULL, *in_cipher = NULL;
Packit Service 31306d
    uint32_t next_blocks;
Packit Service 31306d
Packit Service 31306d
    /* We can safely rekey only in authenticated state */
Packit Service 31306d
    if ((session->flags & SSH_SESSION_FLAG_AUTHENTICATED) == 0) {
Packit Service 31306d
        return false;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    /* Do not rekey if the rekey/key-exchange is in progress */
Packit Service 31306d
    if (session->dh_handshake_state != DH_STATE_FINISHED) {
Packit Service 31306d
        return false;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    crypto = ssh_packet_get_current_crypto(session, SSH_DIRECTION_BOTH);
Packit Service 31306d
    if (crypto == NULL) {
Packit Service 31306d
        return false;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    out_cipher = crypto->out_cipher;
Packit Service 31306d
    in_cipher = crypto->in_cipher;
Packit Service 31306d
Packit Service 31306d
    /* Make sure we can send at least something for very small limits */
Packit Service 31306d
    if ((out_cipher->packets == 0) && (in_cipher->packets == 0)) {
Packit Service 31306d
        return false;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    /* Time based rekeying */
Packit Service 31306d
    if (session->opts.rekey_time != 0 &&
Packit Service 31306d
        ssh_timeout_elapsed(&session->last_rekey_time,
Packit Service 31306d
                            session->opts.rekey_time)) {
Packit Service 31306d
        return true;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    /* RFC4344, Section 3.1 Recommends rekeying after 2^31 packets in either
Packit Service 31306d
     * direction to avoid possible information leakage through the MAC tag
Packit Service 31306d
     */
Packit Service 31306d
    if (out_cipher->packets > MAX_PACKETS ||
Packit Service 31306d
        in_cipher->packets > MAX_PACKETS) {
Packit Service 31306d
        return true;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    /* Data-based rekeying:
Packit Service 31306d
     *  * For outgoing packets we can still delay them
Packit Service 31306d
     *  * Incoming packets need to be processed anyway, but we can
Packit Service 31306d
     *    signalize our intention to rekey
Packit Service 31306d
     */
Packit Service 31306d
    next_blocks = payloadsize / out_cipher->blocksize;
Packit Service 31306d
    data_rekey_needed = (out_cipher->max_blocks != 0 &&
Packit Service 31306d
                         out_cipher->blocks + next_blocks > out_cipher->max_blocks) ||
Packit Service 31306d
                         (in_cipher->max_blocks != 0 &&
Packit Service 31306d
                         in_cipher->blocks + next_blocks > in_cipher->max_blocks);
Packit Service 31306d
Packit Service 31306d
    SSH_LOG(SSH_LOG_PACKET,
Packit Service 31306d
            "packet: [data_rekey_needed=%d, out_blocks=%" PRIu64 ", in_blocks=%" PRIu64,
Packit Service 31306d
            data_rekey_needed,
Packit Service 31306d
            out_cipher->blocks + next_blocks,
Packit Service 31306d
            in_cipher->blocks + next_blocks);
Packit Service 31306d
Packit Service 31306d
    return data_rekey_needed;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/* in nonblocking mode, socket_read will read as much as it can, and return */
Packit Service 31306d
/* SSH_OK if it has read at least len bytes, otherwise, SSH_AGAIN. */
Packit Service 31306d
/* in blocking mode, it will read at least len bytes and will block until it's ok. */
Packit Service 31306d
Packit Service 31306d
/** @internal
Packit Service 31306d
 * @handles a data received event. It then calls the handlers for the different packet types
Packit Service 31306d
 * or and exception handler callback.
Packit Service 31306d
 * @param user pointer to current ssh_session
Packit Service 31306d
 * @param data pointer to the data received
Packit Service 31306d
 * @len length of data received. It might not be enough for a complete packet
Packit Service 31306d
 * @returns number of bytes read and processed.
Packit Service 31306d
 */
Packit Service 31306d
int ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user)
Packit Service 31306d
{
Packit Service 31306d
    ssh_session session = (ssh_session)user;
Packit Service 31306d
    uint32_t blocksize = 8;
Packit Service 31306d
    uint32_t lenfield_blocksize = 8;
Packit Service 31306d
    size_t current_macsize = 0;
Packit Service 31306d
    uint8_t *ptr = NULL;
Packit Service 31306d
    int to_be_read;
Packit Service 31306d
    int rc;
Packit Service 31306d
    uint8_t *cleartext_packet = NULL;
Packit Service 31306d
    uint8_t *packet_second_block = NULL;
Packit Service 31306d
    uint8_t *mac = NULL;
Packit Service 31306d
    size_t packet_remaining;
Packit Service 31306d
    uint32_t packet_len, compsize, payloadsize;
Packit Service 31306d
    uint8_t padding;
Packit Service 31306d
    size_t processed = 0; /* number of byte processed from the callback */
Packit Service 31306d
    enum ssh_packet_filter_result_e filter_result;
Packit Service 31306d
    struct ssh_crypto_struct *crypto = NULL;
Packit Service 31306d
    bool etm = false;
Packit Service 31306d
    uint32_t etm_packet_offset = 0;
Packit Service 31306d
    bool ok;
Packit Service 31306d
Packit Service 31306d
    crypto = ssh_packet_get_current_crypto(session, SSH_DIRECTION_IN);
Packit Service 31306d
    if (crypto != NULL) {
Packit Service 31306d
        current_macsize = hmac_digest_len(crypto->in_hmac);
Packit Service 31306d
        blocksize = crypto->in_cipher->blocksize;
Packit Service 31306d
        lenfield_blocksize = crypto->in_cipher->lenfield_blocksize;
Packit Service 31306d
        etm = crypto->in_hmac_etm;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if (etm) {
Packit Service 31306d
        /* In EtM mode packet size is unencrypted. This means
Packit Service 31306d
         * we need to use this offset and set the block size
Packit Service 31306d
         * that is part of the encrypted part to 0.
Packit Service 31306d
         */
Packit Service 31306d
        etm_packet_offset = sizeof(uint32_t);
Packit Service 31306d
        lenfield_blocksize = 0;
Packit Service 31306d
    } else if (lenfield_blocksize == 0) {
Packit Service 31306d
        lenfield_blocksize = blocksize;
Packit Service 31306d
    }
Packit Service 31306d
    if (data == NULL) {
Packit Service 31306d
        goto error;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if (session->session_state == SSH_SESSION_STATE_ERROR) {
Packit Service 31306d
        goto error;
Packit Service 31306d
    }
Packit Service 31306d
#ifdef DEBUG_PACKET
Packit Service 31306d
    SSH_LOG(SSH_LOG_PACKET,
Packit Service 31306d
            "rcv packet cb (len=%zu, state=%s)",
Packit Service 31306d
            receivedlen,
Packit Service 31306d
            session->packet_state == PACKET_STATE_INIT ?
Packit Service 31306d
                "INIT" :
Packit Service 31306d
                session->packet_state == PACKET_STATE_SIZEREAD ?
Packit Service 31306d
                    "SIZE_READ" :
Packit Service 31306d
                    session->packet_state == PACKET_STATE_PROCESSING ?
Packit Service 31306d
                    "PROCESSING" : "unknown");
Packit Service 31306d
#endif
Packit Service 31306d
    switch(session->packet_state) {
Packit Service 31306d
        case PACKET_STATE_INIT:
Packit Service 31306d
            if (receivedlen < lenfield_blocksize + etm_packet_offset) {
Packit Service 31306d
                /*
Packit Service 31306d
                 * We didn't receive enough data to read either at least one
Packit Service 31306d
                 * block size or the unencrypted length in EtM mode.
Packit Service 31306d
                 */
Packit Service 31306d
#ifdef DEBUG_PACKET
Packit Service 31306d
                SSH_LOG(SSH_LOG_PACKET,
Packit Service 31306d
                        "Waiting for more data (%zu < %u)",
Packit Service 31306d
                        receivedlen,
Packit Service 31306d
                        lenfield_blocksize);
Packit Service 31306d
#endif
Packit Service 31306d
                return 0;
Packit Service 31306d
            }
Packit Service 31306d
Packit Service 31306d
            session->in_packet = (struct packet_struct) {
Packit Service 31306d
                .type = 0,
Packit Service 31306d
            };
Packit Service 31306d
Packit Service 31306d
            if (session->in_buffer) {
Packit Service 31306d
                rc = ssh_buffer_reinit(session->in_buffer);
Packit Service 31306d
                if (rc < 0) {
Packit Service 31306d
                    goto error;
Packit Service 31306d
                }
Packit Service 31306d
            } else {
Packit Service 31306d
                session->in_buffer = ssh_buffer_new();
Packit Service 31306d
                if (session->in_buffer == NULL) {
Packit Service 31306d
                    goto error;
Packit Service 31306d
                }
Packit Service 31306d
            }
Packit Service 31306d
Packit Service 31306d
            if (!etm) {
Packit Service 31306d
                ptr = ssh_buffer_allocate(session->in_buffer, lenfield_blocksize);
Packit Service 31306d
                if (ptr == NULL) {
Packit Service 31306d
                    goto error;
Packit Service 31306d
                }
Packit Service 31306d
                packet_len = ssh_packet_decrypt_len(session, ptr, (uint8_t *)data);
Packit Service 31306d
                to_be_read = packet_len - lenfield_blocksize + sizeof(uint32_t);
Packit Service 31306d
            } else {
Packit Service 31306d
                /* Length is unencrypted in case of Encrypt-then-MAC */
Packit Service 31306d
                packet_len = PULL_BE_U32(data, 0);
Packit Service 31306d
                to_be_read = packet_len - etm_packet_offset;
Packit Service 31306d
            }
Packit Service 31306d
Packit Service 31306d
            processed += lenfield_blocksize + etm_packet_offset;
Packit Service 31306d
            if (packet_len > MAX_PACKET_LEN) {
Packit Service 31306d
                ssh_set_error(session,
Packit Service 31306d
                              SSH_FATAL,
Packit Service 31306d
                              "read_packet(): Packet len too high(%u %.4x)",
Packit Service 31306d
                              packet_len, packet_len);
Packit Service 31306d
                goto error;
Packit Service 31306d
            }
Packit Service 31306d
            if (to_be_read < 0) {
Packit Service 31306d
                /* remote sshd sends invalid sizes? */
Packit Service 31306d
                ssh_set_error(session,
Packit Service 31306d
                              SSH_FATAL,
Packit Service 31306d
                              "Given numbers of bytes left to be read < 0 (%d)!",
Packit Service 31306d
                              to_be_read);
Packit Service 31306d
                goto error;
Packit Service 31306d
            }
Packit Service 31306d
Packit Service 31306d
            session->in_packet.len = packet_len;
Packit Service 31306d
            session->packet_state = PACKET_STATE_SIZEREAD;
Packit Service 31306d
            FALL_THROUGH;
Packit Service 31306d
        case PACKET_STATE_SIZEREAD:
Packit Service 31306d
            packet_len = session->in_packet.len;
Packit Service 31306d
            processed = lenfield_blocksize + etm_packet_offset;
Packit Service 31306d
            to_be_read = packet_len + sizeof(uint32_t) + current_macsize;
Packit Service 31306d
            /* if to_be_read is zero, the whole packet was blocksize bytes. */
Packit Service 31306d
            if (to_be_read != 0) {
Packit Service 31306d
                if (receivedlen  < (unsigned int)to_be_read) {
Packit Service 31306d
                    /* give up, not enough data in buffer */
Packit Service 31306d
                    SSH_LOG(SSH_LOG_PACKET,
Packit Service 31306d
                            "packet: partial packet (read len) "
Packit Service 31306d
                            "[len=%d, receivedlen=%d, to_be_read=%d]",
Packit Service 31306d
                            packet_len,
Packit Service 31306d
                            (int)receivedlen,
Packit Service 31306d
                            to_be_read);
Packit Service 31306d
                    return 0;
Packit Service 31306d
                }
Packit Service 31306d
Packit Service 31306d
                packet_second_block = (uint8_t*)data + lenfield_blocksize + etm_packet_offset;
Packit Service 31306d
                processed = to_be_read - current_macsize;
Packit Service 31306d
            }
Packit Service 31306d
Packit Service 31306d
            /* remaining encrypted bytes from the packet, MAC not included */
Packit Service 31306d
            packet_remaining =
Packit Service 31306d
                packet_len - (lenfield_blocksize - sizeof(uint32_t) + etm_packet_offset);
Packit Service 31306d
            cleartext_packet = ssh_buffer_allocate(session->in_buffer,
Packit Service 31306d
                                                   packet_remaining);
Packit Service 31306d
            if (cleartext_packet == NULL) {
Packit Service 31306d
                goto error;
Packit Service 31306d
            }
Packit Service 31306d
Packit Service 31306d
            if (packet_second_block != NULL) {
Packit Service 31306d
                if (crypto != NULL) {
Packit Service 31306d
                    mac = packet_second_block + packet_remaining;
Packit Service 31306d
Packit Service 31306d
                    if (etm) {
Packit Service 31306d
                        rc = ssh_packet_hmac_verify(session,
Packit Service 31306d
                                                    data,
Packit Service 31306d
                                                    processed,
Packit Service 31306d
                                                    mac,
Packit Service 31306d
                                                    crypto->in_hmac);
Packit Service 31306d
                        if (rc < 0) {
Packit Service 31306d
                            ssh_set_error(session, SSH_FATAL, "HMAC error");
Packit Service 31306d
                            goto error;
Packit Service 31306d
                        }
Packit Service 31306d
                    }
Packit Service 31306d
                    /*
Packit Service 31306d
                     * Decrypt the packet. In case of EtM mode, the length is already
Packit Service 31306d
                     * known as it's unencrypted. In the other case, lenfield_blocksize bytes
Packit Service 31306d
                     * already have been decrypted.
Packit Service 31306d
                     */
Packit Service 31306d
                    if (packet_remaining > 0) {
Packit Service 31306d
                        rc = ssh_packet_decrypt(session,
Packit Service 31306d
                                                cleartext_packet,
Packit Service 31306d
                                                (uint8_t *)data,
Packit Service 31306d
                                                lenfield_blocksize + etm_packet_offset,
Packit Service 31306d
                                                processed - (lenfield_blocksize + etm_packet_offset));
Packit Service 31306d
                        if (rc < 0) {
Packit Service 31306d
                            ssh_set_error(session,
Packit Service 31306d
                                          SSH_FATAL,
Packit Service 31306d
                                          "Decryption error");
Packit Service 31306d
                            goto error;
Packit Service 31306d
                        }
Packit Service 31306d
                    }
Packit Service 31306d
Packit Service 31306d
                    if (!etm) {
Packit Service 31306d
                        rc = ssh_packet_hmac_verify(session,
Packit Service 31306d
                                                    ssh_buffer_get(session->in_buffer),
Packit Service 31306d
                                                    ssh_buffer_get_len(session->in_buffer),
Packit Service 31306d
                                                    mac,
Packit Service 31306d
                                                    crypto->in_hmac);
Packit Service 31306d
                        if (rc < 0) {
Packit Service 31306d
                            ssh_set_error(session, SSH_FATAL, "HMAC error");
Packit Service 31306d
                            goto error;
Packit Service 31306d
                        }
Packit Service 31306d
                    }
Packit Service 31306d
                    processed += current_macsize;
Packit Service 31306d
                } else {
Packit Service 31306d
                    memcpy(cleartext_packet,
Packit Service 31306d
                           packet_second_block,
Packit Service 31306d
                           packet_remaining);
Packit Service 31306d
                }
Packit Service 31306d
            }
Packit Service 31306d
Packit Service 31306d
#ifdef WITH_PCAP
Packit Service 31306d
            if (session->pcap_ctx != NULL) {
Packit Service 31306d
                ssh_pcap_context_write(session->pcap_ctx,
Packit Service 31306d
                                       SSH_PCAP_DIR_IN,
Packit Service 31306d
                                       ssh_buffer_get(session->in_buffer),
Packit Service 31306d
                                       ssh_buffer_get_len(session->in_buffer),
Packit Service 31306d
                                       ssh_buffer_get_len(session->in_buffer));
Packit Service 31306d
            }
Packit Service 31306d
#endif
Packit Service 31306d
Packit Service 31306d
            if (!etm) {
Packit Service 31306d
                /* skip the size field which has been processed before */
Packit Service 31306d
                ssh_buffer_pass_bytes(session->in_buffer, sizeof(uint32_t));
Packit Service 31306d
            }
Packit Service 31306d
Packit Service 31306d
            rc = ssh_buffer_get_u8(session->in_buffer, &padding);
Packit Service 31306d
            if (rc == 0) {
Packit Service 31306d
                ssh_set_error(session,
Packit Service 31306d
                              SSH_FATAL,
Packit Service 31306d
                              "Packet too short to read padding");
Packit Service 31306d
                goto error;
Packit Service 31306d
            }
Packit Service 31306d
Packit Service 31306d
            if (padding > ssh_buffer_get_len(session->in_buffer)) {
Packit Service 31306d
                ssh_set_error(session,
Packit Service 31306d
                              SSH_FATAL,
Packit Service 31306d
                              "Invalid padding: %d (%d left)",
Packit Service 31306d
                              padding,
Packit Service 31306d
                              ssh_buffer_get_len(session->in_buffer));
Packit Service 31306d
                goto error;
Packit Service 31306d
            }
Packit Service 31306d
            ssh_buffer_pass_bytes_end(session->in_buffer, padding);
Packit Service 31306d
            compsize = ssh_buffer_get_len(session->in_buffer);
Packit Service 31306d
Packit Service 31306d
#ifdef WITH_ZLIB
Packit Service 31306d
            if (crypto && crypto->do_compress_in
Packit Service 31306d
                && ssh_buffer_get_len(session->in_buffer) > 0) {
Packit Service 31306d
                rc = decompress_buffer(session, session->in_buffer,MAX_PACKET_LEN);
Packit Service 31306d
                if (rc < 0) {
Packit Service 31306d
                    goto error;
Packit Service 31306d
                }
Packit Service 31306d
            }
Packit Service 31306d
#endif /* WITH_ZLIB */
Packit Service 31306d
            payloadsize = ssh_buffer_get_len(session->in_buffer);
Packit Service 31306d
            session->recv_seq++;
Packit Service 31306d
            if (crypto != NULL) {
Packit Service 31306d
                struct ssh_cipher_struct *cipher = NULL;
Packit Service 31306d
Packit Service 31306d
                cipher = crypto->in_cipher;
Packit Service 31306d
                cipher->packets++;
Packit Service 31306d
                cipher->blocks += payloadsize / cipher->blocksize;
Packit Service 31306d
            }
Packit Service 31306d
            if (session->raw_counter != NULL) {
Packit Service 31306d
                session->raw_counter->in_bytes += payloadsize;
Packit Service 31306d
                session->raw_counter->in_packets++;
Packit Service 31306d
            }
Packit Service 31306d
Packit Service 31306d
            /*
Packit Service 31306d
             * We don't want to rewrite a new packet while still executing the
Packit Service 31306d
             * packet callbacks
Packit Service 31306d
             */
Packit Service 31306d
            session->packet_state = PACKET_STATE_PROCESSING;
Packit Service 31306d
            ssh_packet_parse_type(session);
Packit Service 31306d
            SSH_LOG(SSH_LOG_PACKET,
Packit Service 31306d
                    "packet: read type %hhd [len=%d,padding=%hhd,comp=%d,payload=%d]",
Packit Service 31306d
                    session->in_packet.type, packet_len, padding, compsize, payloadsize);
Packit Service 31306d
Packit Service 31306d
            /* Check if the packet is expected */
Packit Service 31306d
            filter_result = ssh_packet_incoming_filter(session);
Packit Service 31306d
Packit Service 31306d
            switch(filter_result) {
Packit Service 31306d
            case SSH_PACKET_ALLOWED:
Packit Service 31306d
                /* Execute callbacks */
Packit Service 31306d
                ssh_packet_process(session, session->in_packet.type);
Packit Service 31306d
                break;
Packit Service 31306d
            case SSH_PACKET_DENIED:
Packit Service 31306d
                ssh_set_error(session,
Packit Service 31306d
                              SSH_FATAL,
Packit Service 31306d
                              "Packet filter: rejected packet (type %d)",
Packit Service 31306d
                              session->in_packet.type);
Packit Service 31306d
                goto error;
Packit Service 31306d
            case SSH_PACKET_UNKNOWN:
Packit Service 31306d
                ssh_packet_send_unimplemented(session, session->recv_seq - 1);
Packit Service 31306d
                break;
Packit Service 31306d
            }
Packit Service 31306d
Packit Service 31306d
            session->packet_state = PACKET_STATE_INIT;
Packit Service 31306d
            if (processed < receivedlen) {
Packit Service 31306d
                /* Handle a potential packet left in socket buffer */
Packit Service 31306d
                SSH_LOG(SSH_LOG_PACKET,
Packit Service 31306d
                        "Processing %" PRIdS " bytes left in socket buffer",
Packit Service 31306d
                        receivedlen-processed);
Packit Service 31306d
Packit Service 31306d
                ptr = ((uint8_t*)data) + processed;
Packit Service 31306d
Packit Service 31306d
                rc = ssh_packet_socket_callback(ptr, receivedlen - processed,user);
Packit Service 31306d
                processed += rc;
Packit Service 31306d
            }
Packit Service 31306d
Packit Service 31306d
            ok = ssh_packet_need_rekey(session, 0);
Packit Service 31306d
            if (ok) {
Packit Service 31306d
                SSH_LOG(SSH_LOG_PACKET, "Incoming packet triggered rekey");
Packit Service 31306d
                rc = ssh_send_rekex(session);
Packit Service 31306d
                if (rc != SSH_OK) {
Packit Service 31306d
                    SSH_LOG(SSH_LOG_PACKET, "Rekey failed: rc = %d", rc);
Packit Service 31306d
                    return rc;
Packit Service 31306d
                }
Packit Service 31306d
            }
Packit Service 31306d
Packit Service 31306d
            return processed;
Packit Service 31306d
        case PACKET_STATE_PROCESSING:
Packit Service 31306d
            SSH_LOG(SSH_LOG_PACKET, "Nested packet processing. Delaying.");
Packit Service 31306d
            return 0;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    ssh_set_error(session,
Packit Service 31306d
                  SSH_FATAL,
Packit Service 31306d
                  "Invalid state into packet_read2(): %d",
Packit Service 31306d
                  session->packet_state);
Packit Service 31306d
Packit Service 31306d
error:
Packit Service 31306d
    session->session_state= SSH_SESSION_STATE_ERROR;
Packit Service 31306d
    SSH_LOG(SSH_LOG_PACKET,"Packet: processed %" PRIdS " bytes", processed);
Packit Service 31306d
    return processed;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
static void ssh_packet_socket_controlflow_callback(int code, void *userdata)
Packit Service 31306d
{
Packit Service 31306d
    ssh_session session = userdata;
Packit Service 31306d
    struct ssh_iterator *it;
Packit Service 31306d
    ssh_channel channel;
Packit Service 31306d
Packit Service 31306d
    if (code == SSH_SOCKET_FLOW_WRITEWONTBLOCK) {
Packit Service 31306d
        SSH_LOG(SSH_LOG_TRACE, "sending channel_write_wontblock callback");
Packit Service 31306d
Packit Service 31306d
        /* the out pipe is empty so we can forward this to channels */
Packit Service 31306d
        it = ssh_list_get_iterator(session->channels);
Packit Service 31306d
        while (it != NULL) {
Packit Service 31306d
            channel = ssh_iterator_value(ssh_channel, it);
Packit Service 31306d
            ssh_callbacks_execute_list(channel->callbacks,
Packit Service 31306d
                                       ssh_channel_callbacks,
Packit Service 31306d
                                       channel_write_wontblock_function,
Packit Service 31306d
                                       session,
Packit Service 31306d
                                       channel,
Packit Service 31306d
                                       channel->remote_window);
Packit Service 31306d
            it = it->next;
Packit Service 31306d
        }
Packit Service 31306d
    }
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
void ssh_packet_register_socket_callback(ssh_session session, ssh_socket s){
Packit Service 31306d
	session->socket_callbacks.data=ssh_packet_socket_callback;
Packit Service 31306d
	session->socket_callbacks.connected=NULL;
Packit Service 31306d
    session->socket_callbacks.controlflow = ssh_packet_socket_controlflow_callback;
Packit Service 31306d
	session->socket_callbacks.userdata=session;
Packit Service 31306d
	ssh_socket_set_callbacks(s,&session->socket_callbacks);
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/** @internal
Packit Service 31306d
 * @brief sets the callbacks for the packet layer
Packit Service 31306d
 */
Packit Service 31306d
void ssh_packet_set_callbacks(ssh_session session, ssh_packet_callbacks callbacks){
Packit Service 31306d
  if(session->packet_callbacks == NULL){
Packit Service 31306d
    session->packet_callbacks = ssh_list_new();
Packit Service 31306d
  }
Packit Service 31306d
  if (session->packet_callbacks != NULL) {
Packit Service 31306d
    ssh_list_append(session->packet_callbacks, callbacks);
Packit Service 31306d
  }
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/** @internal
Packit Service 31306d
 * @brief remove the callbacks from the packet layer
Packit Service 31306d
 */
Packit Service 31306d
void ssh_packet_remove_callbacks(ssh_session session, ssh_packet_callbacks callbacks){
Packit Service 31306d
    struct ssh_iterator *it = NULL;
Packit Service 31306d
    it = ssh_list_find(session->packet_callbacks, callbacks);
Packit Service 31306d
    if (it != NULL) {
Packit Service 31306d
        ssh_list_remove(session->packet_callbacks, it);
Packit Service 31306d
    }
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/** @internal
Packit Service 31306d
 * @brief sets the default packet handlers
Packit Service 31306d
 */
Packit Service 31306d
void ssh_packet_set_default_callbacks(ssh_session session){
Packit Service 31306d
	session->default_packet_callbacks.start=1;
Packit Service 31306d
	session->default_packet_callbacks.n_callbacks=sizeof(default_packet_handlers)/sizeof(ssh_packet_callback);
Packit Service 31306d
	session->default_packet_callbacks.user=session;
Packit Service 31306d
	session->default_packet_callbacks.callbacks=default_packet_handlers;
Packit Service 31306d
	ssh_packet_set_callbacks(session, &session->default_packet_callbacks);
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/** @internal
Packit Service 31306d
 * @brief dispatch the call of packet handlers callbacks for a received packet
Packit Service 31306d
 * @param type type of packet
Packit Service 31306d
 */
Packit Service 31306d
void ssh_packet_process(ssh_session session, uint8_t type)
Packit Service 31306d
{
Packit Service 31306d
    struct ssh_iterator *i = NULL;
Packit Service 31306d
    int rc = SSH_PACKET_NOT_USED;
Packit Service 31306d
    ssh_packet_callbacks cb;
Packit Service 31306d
Packit Service 31306d
    SSH_LOG(SSH_LOG_PACKET, "Dispatching handler for packet type %d", type);
Packit Service 31306d
    if (session->packet_callbacks == NULL) {
Packit Service 31306d
        SSH_LOG(SSH_LOG_RARE, "Packet callback is not initialized !");
Packit Service 31306d
        return;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    i = ssh_list_get_iterator(session->packet_callbacks);
Packit Service 31306d
    while (i != NULL) {
Packit Service 31306d
        cb = ssh_iterator_value(ssh_packet_callbacks, i);
Packit Service 31306d
        i = i->next;
Packit Service 31306d
Packit Service 31306d
        if (!cb) {
Packit Service 31306d
            continue;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        if (cb->start > type) {
Packit Service 31306d
            continue;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        if (cb->start + cb->n_callbacks <= type) {
Packit Service 31306d
            continue;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        if (cb->callbacks[type - cb->start] == NULL) {
Packit Service 31306d
            continue;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        rc = cb->callbacks[type - cb->start](session, type, session->in_buffer,
Packit Service 31306d
                                             cb->user);
Packit Service 31306d
        if (rc == SSH_PACKET_USED) {
Packit Service 31306d
            break;
Packit Service 31306d
        }
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if (rc == SSH_PACKET_NOT_USED) {
Packit Service 31306d
        SSH_LOG(SSH_LOG_RARE, "Couldn't do anything with packet type %d", type);
Packit Service 31306d
        rc = ssh_packet_send_unimplemented(session, session->recv_seq - 1);
Packit Service 31306d
        if (rc != SSH_OK) {
Packit Service 31306d
            SSH_LOG(SSH_LOG_RARE, "Failed to send unimplemented: %s",
Packit Service 31306d
                    ssh_get_error(session));
Packit Service 31306d
        }
Packit Service 31306d
    }
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/** @internal
Packit Service 31306d
 * @brief sends a SSH_MSG_UNIMPLEMENTED answer to an unhandled packet
Packit Service 31306d
 * @param session the SSH session
Packit Service 31306d
 * @param seqnum the sequence number of the unknown packet
Packit Service 31306d
 * @return SSH_ERROR on error, else SSH_OK
Packit Service 31306d
 */
Packit Service 31306d
int ssh_packet_send_unimplemented(ssh_session session, uint32_t seqnum){
Packit Service 31306d
    int rc;
Packit Service 31306d
Packit Service 31306d
    rc = ssh_buffer_pack(session->out_buffer,
Packit Service 31306d
                         "bd",
Packit Service 31306d
                         SSH2_MSG_UNIMPLEMENTED,
Packit Service 31306d
                         seqnum);
Packit Service 31306d
    if (rc != SSH_OK) {
Packit Service 31306d
        ssh_set_error_oom(session);
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
    rc = ssh_packet_send(session);
Packit Service 31306d
Packit Service 31306d
    return rc;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/** @internal
Packit Service 31306d
 * @brief handles a SSH_MSG_UNIMPLEMENTED packet
Packit Service 31306d
 */
Packit Service 31306d
SSH_PACKET_CALLBACK(ssh_packet_unimplemented){
Packit Service 31306d
    uint32_t seq;
Packit Service 31306d
    int rc;
Packit Service 31306d
Packit Service 31306d
    (void)session; /* unused */
Packit Service 31306d
    (void)type;
Packit Service 31306d
    (void)user;
Packit Service 31306d
Packit Service 31306d
    rc = ssh_buffer_unpack(packet, "d", &seq;;
Packit Service 31306d
    if (rc != SSH_OK) {
Packit Service 31306d
        SSH_LOG(SSH_LOG_WARNING,
Packit Service 31306d
                "Could not unpack SSH_MSG_UNIMPLEMENTED packet");
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    SSH_LOG(SSH_LOG_RARE,
Packit Service 31306d
            "Received SSH_MSG_UNIMPLEMENTED (sequence number %d)",seq);
Packit Service 31306d
Packit Service 31306d
    return SSH_PACKET_USED;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/** @internal
Packit Service 31306d
 * @parse the "Type" header field of a packet and updates the session
Packit Service 31306d
 */
Packit Service 31306d
int ssh_packet_parse_type(struct ssh_session_struct *session)
Packit Service 31306d
{
Packit Service 31306d
    session->in_packet = (struct packet_struct) {
Packit Service 31306d
        .type = 0,
Packit Service 31306d
    };
Packit Service 31306d
Packit Service 31306d
    if (session->in_buffer == NULL) {
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if (ssh_buffer_get_u8(session->in_buffer, &session->in_packet.type) == 0) {
Packit Service 31306d
        ssh_set_error(session, SSH_FATAL, "Packet too short to read type");
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    session->in_packet.valid = 1;
Packit Service 31306d
Packit Service 31306d
    return SSH_OK;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/*
Packit Service 31306d
 * This function places the outgoing packet buffer into an outgoing
Packit Service 31306d
 * socket buffer
Packit Service 31306d
 */
Packit Service 31306d
static int ssh_packet_write(ssh_session session) {
Packit Service 31306d
  int rc = SSH_ERROR;
Packit Service 31306d
Packit Service 31306d
  rc=ssh_socket_write(session->socket,
Packit Service 31306d
      ssh_buffer_get(session->out_buffer),
Packit Service 31306d
      ssh_buffer_get_len(session->out_buffer));
Packit Service 31306d
Packit Service 31306d
  return rc;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
static int packet_send2(ssh_session session)
Packit Service 31306d
{
Packit Service 31306d
    unsigned int blocksize = 8;
Packit Service 31306d
    unsigned int lenfield_blocksize = 0;
Packit Service 31306d
    enum ssh_hmac_e hmac_type;
Packit Service 31306d
    uint32_t currentlen = ssh_buffer_get_len(session->out_buffer);
Packit Service 31306d
    struct ssh_crypto_struct *crypto = NULL;
Packit Service 31306d
    unsigned char *hmac = NULL;
Packit Service 31306d
    uint8_t padding_data[32] = { 0 };
Packit Service 31306d
    uint8_t padding_size;
Packit Service 31306d
    uint32_t finallen, payloadsize, compsize;
Packit Service 31306d
    uint8_t header[5] = {0};
Packit Service 31306d
    uint8_t type, *payload;
Packit Service 31306d
    int rc = SSH_ERROR;
Packit Service 31306d
    bool etm = false;
Packit Service 31306d
    int etm_packet_offset = 0;
Packit Service 31306d
Packit Service 31306d
    crypto = ssh_packet_get_current_crypto(session, SSH_DIRECTION_OUT);
Packit Service 31306d
    if (crypto) {
Packit Service 31306d
        blocksize = crypto->out_cipher->blocksize;
Packit Service 31306d
        lenfield_blocksize = crypto->out_cipher->lenfield_blocksize;
Packit Service 31306d
        hmac_type = crypto->out_hmac;
Packit Service 31306d
        etm = crypto->out_hmac_etm;
Packit Service 31306d
    } else {
Packit Service 31306d
        hmac_type = session->next_crypto->out_hmac;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    payload = (uint8_t *)ssh_buffer_get(session->out_buffer);
Packit Service 31306d
    type = payload[0]; /* type is the first byte of the packet now */
Packit Service 31306d
Packit Service 31306d
    payloadsize = currentlen;
Packit Service 31306d
    if (etm) {
Packit Service 31306d
        etm_packet_offset = sizeof(uint32_t);
Packit Service 31306d
        lenfield_blocksize = 0;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
#ifdef WITH_ZLIB
Packit Service 31306d
    if (crypto != NULL && crypto->do_compress_out &&
Packit Service 31306d
        ssh_buffer_get_len(session->out_buffer) > 0) {
Packit Service 31306d
        rc = compress_buffer(session,session->out_buffer);
Packit Service 31306d
        if (rc < 0) {
Packit Service 31306d
            goto error;
Packit Service 31306d
        }
Packit Service 31306d
        currentlen = ssh_buffer_get_len(session->out_buffer);
Packit Service 31306d
    }
Packit Service 31306d
#endif /* WITH_ZLIB */
Packit Service 31306d
    compsize = currentlen;
Packit Service 31306d
    /* compressed payload + packet len (4) + padding_size len (1) */
Packit Service 31306d
    /* totallen - lenfield_blocksize - etm_packet_offset must be equal to 0 (mod blocksize) */
Packit Service 31306d
    padding_size = (blocksize - ((blocksize - lenfield_blocksize - etm_packet_offset + currentlen + 5) % blocksize));
Packit Service 31306d
    if (padding_size < 4) {
Packit Service 31306d
        padding_size += blocksize;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if (crypto != NULL) {
Packit Service 31306d
        int ok;
Packit Service 31306d
Packit Service 31306d
        ok = ssh_get_random(padding_data, padding_size, 0);
Packit Service 31306d
        if (!ok) {
Packit Service 31306d
            ssh_set_error(session, SSH_FATAL, "PRNG error");
Packit Service 31306d
            goto error;
Packit Service 31306d
        }
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    finallen = currentlen - etm_packet_offset + padding_size + 1;
Packit Service 31306d
Packit Service 31306d
    PUSH_BE_U32(header, 0, finallen);
Packit Service 31306d
    PUSH_BE_U8(header, 4, padding_size);
Packit Service 31306d
Packit Service 31306d
    rc = ssh_buffer_prepend_data(session->out_buffer,
Packit Service 31306d
                                 header,
Packit Service 31306d
                                 sizeof(header));
Packit Service 31306d
    if (rc < 0) {
Packit Service 31306d
        goto error;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    rc = ssh_buffer_add_data(session->out_buffer, padding_data, padding_size);
Packit Service 31306d
    if (rc < 0) {
Packit Service 31306d
        goto error;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
#ifdef WITH_PCAP
Packit Service 31306d
    if (session->pcap_ctx != NULL) {
Packit Service 31306d
        ssh_pcap_context_write(session->pcap_ctx,
Packit Service 31306d
                               SSH_PCAP_DIR_OUT,
Packit Service 31306d
                               ssh_buffer_get(session->out_buffer),
Packit Service 31306d
                               ssh_buffer_get_len(session->out_buffer),
Packit Service 31306d
                               ssh_buffer_get_len(session->out_buffer));
Packit Service 31306d
    }
Packit Service 31306d
#endif
Packit Service 31306d
Packit Service 31306d
    hmac = ssh_packet_encrypt(session,
Packit Service 31306d
                              ssh_buffer_get(session->out_buffer),
Packit Service 31306d
                              ssh_buffer_get_len(session->out_buffer));
Packit Service 31306d
    if (hmac != NULL) {
Packit Service 31306d
        rc = ssh_buffer_add_data(session->out_buffer,
Packit Service 31306d
                                 hmac,
Packit Service 31306d
                                 hmac_digest_len(hmac_type));
Packit Service 31306d
        if (rc < 0) {
Packit Service 31306d
            goto error;
Packit Service 31306d
        }
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    rc = ssh_packet_write(session);
Packit Service 31306d
    if (rc == SSH_ERROR) {
Packit Service 31306d
        goto error;
Packit Service 31306d
    }
Packit Service 31306d
    session->send_seq++;
Packit Service 31306d
    if (crypto != NULL) {
Packit Service 31306d
        struct ssh_cipher_struct *cipher = NULL;
Packit Service 31306d
Packit Service 31306d
        cipher = crypto->out_cipher;
Packit Service 31306d
        cipher->packets++;
Packit Service 31306d
        cipher->blocks += payloadsize / cipher->blocksize;
Packit Service 31306d
    }
Packit Service 31306d
    if (session->raw_counter != NULL) {
Packit Service 31306d
        session->raw_counter->out_bytes += payloadsize;
Packit Service 31306d
        session->raw_counter->out_packets++;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    SSH_LOG(SSH_LOG_PACKET,
Packit Service 31306d
            "packet: wrote [type=%u, len=%u, padding_size=%hhd, comp=%u, "
Packit Service 31306d
            "payload=%u]",
Packit Service 31306d
            type,
Packit Service 31306d
            finallen,
Packit Service 31306d
            padding_size,
Packit Service 31306d
            compsize,
Packit Service 31306d
            payloadsize);
Packit Service 31306d
Packit Service 31306d
    rc = ssh_buffer_reinit(session->out_buffer);
Packit Service 31306d
    if (rc < 0) {
Packit Service 31306d
        rc = SSH_ERROR;
Packit Service 31306d
        goto error;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    /* We sent the NEWKEYS so any further packet needs to be encrypted
Packit Service 31306d
     * with the new keys. We can not switch both directions (need to decrypt
Packit Service 31306d
     * peer NEWKEYS) and we do not want to wait for the peer NEWKEYS
Packit Service 31306d
     * too, so we will switch only the OUT direction now.
Packit Service 31306d
     */
Packit Service 31306d
    if (type == SSH2_MSG_NEWKEYS) {
Packit Service 31306d
        rc = ssh_packet_set_newkeys(session, SSH_DIRECTION_OUT);
Packit Service 31306d
    }
Packit Service 31306d
error:
Packit Service 31306d
    return rc; /* SSH_OK, AGAIN or ERROR */
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
static bool
Packit Service 31306d
ssh_packet_is_kex(unsigned char type)
Packit Service 31306d
{
Packit Service 31306d
    return type >= SSH2_MSG_DISCONNECT &&
Packit Service 31306d
           type <= SSH2_MSG_KEX_DH_GEX_REQUEST &&
Packit Service 31306d
           type != SSH2_MSG_SERVICE_REQUEST &&
Packit Service 31306d
           type != SSH2_MSG_SERVICE_ACCEPT &&
Packit Service 31306d
           type != SSH2_MSG_IGNORE &&
Packit Service 31306d
           type != SSH2_MSG_EXT_INFO;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
static bool
Packit Service 31306d
ssh_packet_in_rekey(ssh_session session)
Packit Service 31306d
{
Packit Service 31306d
    /* We know we are rekeying if we are authenticated and the DH
Packit Service 31306d
     * status is not finished
Packit Service 31306d
     */
Packit Service 31306d
    return (session->flags & SSH_SESSION_FLAG_AUTHENTICATED) &&
Packit Service 31306d
           (session->dh_handshake_state != DH_STATE_FINISHED);
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
int ssh_packet_send(ssh_session session)
Packit Service 31306d
{
Packit Service 31306d
    uint32_t payloadsize;
Packit Service 31306d
    uint8_t type, *payload;
Packit Service 31306d
    bool need_rekey, in_rekey;
Packit Service 31306d
    int rc;
Packit Service 31306d
Packit Service 31306d
    payloadsize = ssh_buffer_get_len(session->out_buffer);
Packit Service 31306d
    if (payloadsize < 1) {
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    payload = (uint8_t *)ssh_buffer_get(session->out_buffer);
Packit Service 31306d
    type = payload[0]; /* type is the first byte of the packet now */
Packit Service 31306d
    need_rekey = ssh_packet_need_rekey(session, payloadsize);
Packit Service 31306d
    in_rekey = ssh_packet_in_rekey(session);
Packit Service 31306d
Packit Service 31306d
    /* The rekey is triggered here. After that, only the key exchange
Packit Service 31306d
     * packets can be sent, until we send our NEWKEYS.
Packit Service 31306d
     */
Packit Service 31306d
    if (need_rekey || (in_rekey && !ssh_packet_is_kex(type))) {
Packit Service 31306d
        if (need_rekey) {
Packit Service 31306d
            SSH_LOG(SSH_LOG_PACKET, "Outgoing packet triggered rekey");
Packit Service 31306d
        }
Packit Service 31306d
        /* Queue the current packet -- we will send it after the rekey */
Packit Service 31306d
        SSH_LOG(SSH_LOG_PACKET, "Queuing packet type %d", type);
Packit Service 31306d
        rc = ssh_list_append(session->out_queue, session->out_buffer);
Packit Service 31306d
        if (rc != SSH_OK) {
Packit Service 31306d
            return SSH_ERROR;
Packit Service 31306d
        }
Packit Service 31306d
        session->out_buffer = ssh_buffer_new();
Packit Service 31306d
        if (session->out_buffer == NULL) {
Packit Service 31306d
            ssh_set_error_oom(session);
Packit Service 31306d
            return SSH_ERROR;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        if (need_rekey) {
Packit Service 31306d
            /* Send the KEXINIT packet instead.
Packit Service 31306d
             * This recursivelly calls the packet_send(), but it should
Packit Service 31306d
             * not get into rekeying again.
Packit Service 31306d
             * After that we need to handle the key exchange responses
Packit Service 31306d
             * up to the point where we can send the rest of the queue.
Packit Service 31306d
             */
Packit Service 31306d
            return ssh_send_rekex(session);
Packit Service 31306d
        }
Packit Service 31306d
        return SSH_OK;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    /* Send the packet normally */
Packit Service 31306d
    rc = packet_send2(session);
Packit Service 31306d
Packit Service 31306d
    /* We finished the key exchange so we can try to send our queue now */
Packit Service 31306d
    if (rc == SSH_OK && type == SSH2_MSG_NEWKEYS) {
Packit Service 31306d
        struct ssh_iterator *it;
Packit Service 31306d
Packit Service 31306d
        for (it = ssh_list_get_iterator(session->out_queue);
Packit Service 31306d
             it != NULL;
Packit Service 31306d
             it = ssh_list_get_iterator(session->out_queue)) {
Packit Service 31306d
            struct ssh_buffer_struct *next_buffer = NULL;
Packit Service 31306d
Packit Service 31306d
            /* Peek only -- do not remove from queue yet */
Packit Service 31306d
            next_buffer = (struct ssh_buffer_struct *)it->data;
Packit Service 31306d
            payloadsize = ssh_buffer_get_len(next_buffer);
Packit Service 31306d
            if (ssh_packet_need_rekey(session, payloadsize)) {
Packit Service 31306d
                /* Sigh ... we still can not send this packet. Repeat. */
Packit Service 31306d
                SSH_LOG(SSH_LOG_PACKET, "Queued packet triggered rekey");
Packit Service 31306d
                return ssh_send_rekex(session);
Packit Service 31306d
            }
Packit Service 31306d
            SSH_BUFFER_FREE(session->out_buffer);
Packit Service 31306d
            session->out_buffer = ssh_list_pop_head(struct ssh_buffer_struct *,
Packit Service 31306d
                                                    session->out_queue);
Packit Service 31306d
            payload = (uint8_t *)ssh_buffer_get(session->out_buffer);
Packit Service 31306d
            type = payload[0];
Packit Service 31306d
            SSH_LOG(SSH_LOG_PACKET, "Dequeue packet type %d", type);
Packit Service 31306d
            rc = packet_send2(session);
Packit Service 31306d
            if (rc != SSH_OK) {
Packit Service 31306d
                return rc;
Packit Service 31306d
            }
Packit Service 31306d
        }
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    return rc;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
static void
Packit Service 31306d
ssh_init_rekey_state(struct ssh_session_struct *session,
Packit Service 31306d
                     struct ssh_cipher_struct *cipher)
Packit Service 31306d
{
Packit Service 31306d
    /* Reset the counters: should be NOOP */
Packit Service 31306d
    cipher->packets = 0;
Packit Service 31306d
    cipher->blocks = 0;
Packit Service 31306d
Packit Service 31306d
    /* Default rekey limits for ciphers as specified in RFC4344, Section 3.2 */
Packit Service 31306d
    if (cipher->blocksize >= 16) {
Packit Service 31306d
        /* For larger block size (L bits) use maximum of 2**(L/4) blocks */
Packit Service 31306d
        cipher->max_blocks = (uint64_t)1 << (cipher->blocksize*2);
Packit Service 31306d
    } else {
Packit Service 31306d
        /* For smaller blocks use limit of 1 GB as recommended in RFC4253 */
Packit Service 31306d
        cipher->max_blocks = ((uint64_t)1 << 30) / cipher->blocksize;
Packit Service 31306d
    }
Packit Service 31306d
    /* If we have limit provided by user, use the smaller one */
Packit Service 31306d
    if (session->opts.rekey_data != 0) {
Packit Service 31306d
        cipher->max_blocks = MIN(cipher->max_blocks,
Packit Service 31306d
                                 session->opts.rekey_data / cipher->blocksize);
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    SSH_LOG(SSH_LOG_PROTOCOL,
Packit Service 31306d
            "Set rekey after %" PRIu64 " blocks",
Packit Service 31306d
            cipher->max_blocks);
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/*
Packit Service 31306d
 * Once we got SSH2_MSG_NEWKEYS we can switch next_crypto and
Packit Service 31306d
 * current_crypto for our desired direction
Packit Service 31306d
 */
Packit Service 31306d
int
Packit Service 31306d
ssh_packet_set_newkeys(ssh_session session,
Packit Service 31306d
                       enum ssh_crypto_direction_e direction)
Packit Service 31306d
{
Packit Service 31306d
    int rc;
Packit Service 31306d
Packit Service 31306d
    SSH_LOG(SSH_LOG_TRACE,
Packit Service 31306d
            "called, direction =%s%s",
Packit Service 31306d
            direction & SSH_DIRECTION_IN ? " IN " : "",
Packit Service 31306d
            direction & SSH_DIRECTION_OUT ? " OUT " : "");
Packit Service 31306d
Packit Service 31306d
    if (session->next_crypto == NULL) {
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    session->next_crypto->used |= direction;
Packit Service 31306d
    if (session->current_crypto != NULL) {
Packit Service 31306d
        if (session->current_crypto->used & direction) {
Packit Service 31306d
            SSH_LOG(SSH_LOG_WARNING, "This direction isn't used anymore.");
Packit Service 31306d
        }
Packit Service 31306d
        /* Mark the current requested direction unused */
Packit Service 31306d
        session->current_crypto->used &= ~direction;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    /* Both sides switched: do the actual switch now */
Packit Service 31306d
    if (session->next_crypto->used == SSH_DIRECTION_BOTH) {
Packit Service 31306d
        size_t digest_len;
Packit Service 31306d
Packit Service 31306d
        if (session->current_crypto != NULL) {
Packit Service 31306d
            crypto_free(session->current_crypto);
Packit Service 31306d
            session->current_crypto = NULL;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        session->current_crypto = session->next_crypto;
Packit Service 31306d
        session->current_crypto->used = SSH_DIRECTION_BOTH;
Packit Service 31306d
Packit Service 31306d
        /* Initialize the next_crypto structure */
Packit Service 31306d
        session->next_crypto = crypto_new();
Packit Service 31306d
        if (session->next_crypto == NULL) {
Packit Service 31306d
            ssh_set_error_oom(session);
Packit Service 31306d
            return SSH_ERROR;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        digest_len = session->current_crypto->digest_len;
Packit Service 31306d
        session->next_crypto->session_id = malloc(digest_len);
Packit Service 31306d
        if (session->next_crypto->session_id == NULL) {
Packit Service 31306d
            ssh_set_error_oom(session);
Packit Service 31306d
            return SSH_ERROR;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        memcpy(session->next_crypto->session_id,
Packit Service 31306d
               session->current_crypto->session_id,
Packit Service 31306d
               digest_len);
Packit Service 31306d
Packit Service 31306d
        return SSH_OK;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    /* Initialize common structures so the next context can be used in
Packit Service 31306d
     * either direction */
Packit Service 31306d
    if (session->client) {
Packit Service 31306d
        /* The server has this part already done */
Packit Service 31306d
        rc = ssh_make_sessionid(session);
Packit Service 31306d
        if (rc != SSH_OK) {
Packit Service 31306d
            return SSH_ERROR;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        /*
Packit Service 31306d
         * Set the cryptographic functions for the next crypto
Packit Service 31306d
         * (it is needed for ssh_generate_session_keys for key lengths)
Packit Service 31306d
         */
Packit Service 31306d
        rc = crypt_set_algorithms_client(session);
Packit Service 31306d
        if (rc < 0) {
Packit Service 31306d
            return SSH_ERROR;
Packit Service 31306d
        }
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if (ssh_generate_session_keys(session) < 0) {
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if (session->next_crypto->in_cipher == NULL ||
Packit Service 31306d
        session->next_crypto->out_cipher == NULL) {
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    /* Initialize rekeying states */
Packit Service 31306d
    ssh_init_rekey_state(session,
Packit Service 31306d
                         session->next_crypto->out_cipher);
Packit Service 31306d
    ssh_init_rekey_state(session,
Packit Service 31306d
                         session->next_crypto->in_cipher);
Packit Service 31306d
    if (session->opts.rekey_time != 0) {
Packit Service 31306d
        ssh_timestamp_init(&session->last_rekey_time);
Packit Service 31306d
        SSH_LOG(SSH_LOG_PROTOCOL, "Set rekey after %" PRIu32 " seconds",
Packit Service 31306d
                session->opts.rekey_time/1000);
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    /* Initialize the encryption and decryption keys in next_crypto */
Packit Service 31306d
    rc = session->next_crypto->in_cipher->set_decrypt_key(
Packit Service 31306d
        session->next_crypto->in_cipher,
Packit Service 31306d
        session->next_crypto->decryptkey,
Packit Service 31306d
        session->next_crypto->decryptIV);
Packit Service 31306d
    if (rc < 0) {
Packit Service 31306d
        /* On error, make sure it is not used */
Packit Service 31306d
        session->next_crypto->used = 0;
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    rc = session->next_crypto->out_cipher->set_encrypt_key(
Packit Service 31306d
        session->next_crypto->out_cipher,
Packit Service 31306d
        session->next_crypto->encryptkey,
Packit Service 31306d
        session->next_crypto->encryptIV);
Packit Service 31306d
    if (rc < 0) {
Packit Service 31306d
        /* On error, make sure it is not used */
Packit Service 31306d
        session->next_crypto->used = 0;
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    return SSH_OK;
Packit Service 31306d
}