Blame SOURCES/libssh-CVE-2018-10933.patch

3cd302
From e5f0e711b05c2ec4c2d016a6abaedae2959ddba2 Mon Sep 17 00:00:00 2001
3cd302
From: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
3cd302
Date: Wed, 19 Sep 2018 14:08:28 +0200
3cd302
Subject: [PATCH 1/8] CVE-2018-10933: Introduced new auth states
3cd302
3cd302
Introduced the states SSH_AUTH_STATE_PUBKEY_OFFER_SENT and
3cd302
SSH_AUTH_STATE_PUBKEY_AUTH_SENT to know when SSH2_MSG_USERAUTH_PK_OK and
3cd302
SSH2_MSG_USERAUTH_SUCCESS should be expected.
3cd302
3cd302
Fixes T101
3cd302
3cd302
Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
3cd302
---
3cd302
 include/libssh/auth.h |  4 ++++
3cd302
 src/auth.c            | 32 +++++++++++++++++++++-----------
3cd302
 2 files changed, 25 insertions(+), 11 deletions(-)
3cd302
3cd302
diff --git a/include/libssh/auth.h b/include/libssh/auth.h
3cd302
index 2c0012b0..05754460 100644
3cd302
--- a/include/libssh/auth.h
3cd302
+++ b/include/libssh/auth.h
3cd302
@@ -90,6 +90,10 @@ enum ssh_auth_state_e {
3cd302
   SSH_AUTH_STATE_GSSAPI_TOKEN,
3cd302
   /** We have sent the MIC and expecting to be authenticated */
3cd302
   SSH_AUTH_STATE_GSSAPI_MIC_SENT,
3cd302
+  /** We have offered a pubkey to check if it is supported */
3cd302
+  SSH_AUTH_STATE_PUBKEY_OFFER_SENT,
3cd302
+  /** We have sent pubkey and signature expecting to be authenticated */
3cd302
+  SSH_AUTH_STATE_PUBKEY_AUTH_SENT,
3cd302
 };
3cd302
 
3cd302
 /** @internal
3cd302
diff --git a/src/auth.c b/src/auth.c
3cd302
index b411f226..964e82a6 100755
3cd302
--- a/src/auth.c
3cd302
+++ b/src/auth.c
3cd302
@@ -85,6 +85,8 @@ static int ssh_auth_response_termination(void *user){
3cd302
     case SSH_AUTH_STATE_GSSAPI_REQUEST_SENT:
3cd302
     case SSH_AUTH_STATE_GSSAPI_TOKEN:
3cd302
     case SSH_AUTH_STATE_GSSAPI_MIC_SENT:
3cd302
+    case SSH_AUTH_STATE_PUBKEY_AUTH_SENT:
3cd302
+    case SSH_AUTH_STATE_PUBKEY_OFFER_SENT:
3cd302
       return 0;
3cd302
     default:
3cd302
       return 1;
3cd302
@@ -137,6 +139,8 @@ static int ssh_userauth_get_response(ssh_session session) {
3cd302
         case SSH_AUTH_STATE_GSSAPI_REQUEST_SENT:
3cd302
         case SSH_AUTH_STATE_GSSAPI_TOKEN:
3cd302
         case SSH_AUTH_STATE_GSSAPI_MIC_SENT:
3cd302
+        case SSH_AUTH_STATE_PUBKEY_OFFER_SENT:
3cd302
+        case SSH_AUTH_STATE_PUBKEY_AUTH_SENT:
3cd302
         case SSH_AUTH_STATE_NONE:
3cd302
             /* not reached */
3cd302
             rc = SSH_AUTH_ERROR;
3cd302
@@ -275,21 +279,27 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_success){
3cd302
 SSH_PACKET_CALLBACK(ssh_packet_userauth_pk_ok){
3cd302
 	int rc;
3cd302
 
3cd302
-  SSH_LOG(SSH_LOG_TRACE, "Received SSH_USERAUTH_PK_OK/INFO_REQUEST/GSSAPI_RESPONSE");
3cd302
+  SSH_LOG(SSH_LOG_TRACE,
3cd302
+          "Received SSH_USERAUTH_PK_OK/INFO_REQUEST/GSSAPI_RESPONSE");
3cd302
 
3cd302
-  if(session->auth_state==SSH_AUTH_STATE_KBDINT_SENT){
3cd302
+  if (session->auth_state == SSH_AUTH_STATE_KBDINT_SENT) {
3cd302
     /* Assuming we are in keyboard-interactive context */
3cd302
     SSH_LOG(SSH_LOG_TRACE,
3cd302
-            "keyboard-interactive context, assuming SSH_USERAUTH_INFO_REQUEST");
3cd302
-    rc=ssh_packet_userauth_info_request(session,type,packet,user);
3cd302
+            "keyboard-interactive context, "
3cd302
+            "assuming SSH_USERAUTH_INFO_REQUEST");
3cd302
+    rc = ssh_packet_userauth_info_request(session, type, packet, user);
3cd302
 #ifdef WITH_GSSAPI
3cd302
-  } else if (session->auth_state == SSH_AUTH_STATE_GSSAPI_REQUEST_SENT){
3cd302
+  } else if (session->auth_state == SSH_AUTH_STATE_GSSAPI_REQUEST_SENT) {
3cd302
     rc = ssh_packet_userauth_gssapi_response(session, type, packet, user);
3cd302
 #endif
3cd302
+  } else if (session->auth_state == SSH_AUTH_STATE_PUBKEY_OFFER_SENT) {
3cd302
+      session->auth_state = SSH_AUTH_STATE_PK_OK;
3cd302
+      SSH_LOG(SSH_LOG_TRACE, "Assuming SSH_USERAUTH_PK_OK");
3cd302
+      rc = SSH_PACKET_USED;
3cd302
   } else {
3cd302
-    session->auth_state=SSH_AUTH_STATE_PK_OK;
3cd302
-    SSH_LOG(SSH_LOG_TRACE, "Assuming SSH_USERAUTH_PK_OK");
3cd302
-    rc=SSH_PACKET_USED;
3cd302
+      session->auth_state = SSH_AUTH_STATE_ERROR;
3cd302
+      SSH_LOG(SSH_LOG_TRACE, "SSH_USERAUTH_PK_OK received in wrong state");
3cd302
+      rc = SSH_PACKET_USED;
3cd302
   }
3cd302
 
3cd302
   return rc;
3cd302
@@ -501,7 +511,7 @@ int ssh_userauth_try_publickey(ssh_session session,
3cd302
 
3cd302
     ssh_string_free(pubkey_s);
3cd302
 
3cd302
-    session->auth_state = SSH_AUTH_STATE_NONE;
3cd302
+    session->auth_state = SSH_AUTH_STATE_PUBKEY_OFFER_SENT;
3cd302
     session->pending_call_state = SSH_PENDING_CALL_AUTH_OFFER_PUBKEY;
3cd302
     rc = packet_send(session);
3cd302
     if (rc == SSH_ERROR) {
3cd302
@@ -622,7 +632,7 @@ int ssh_userauth_publickey(ssh_session session,
3cd302
         goto fail;
3cd302
     }
3cd302
 
3cd302
-    session->auth_state = SSH_AUTH_STATE_NONE;
3cd302
+    session->auth_state = SSH_AUTH_STATE_PUBKEY_AUTH_SENT;
3cd302
     session->pending_call_state = SSH_PENDING_CALL_AUTH_PUBKEY;
3cd302
     rc = packet_send(session);
3cd302
     if (rc == SSH_ERROR) {
3cd302
@@ -706,7 +716,7 @@ static int ssh_userauth_agent_publickey(ssh_session session,
3cd302
         goto fail;
3cd302
     }
3cd302
 
3cd302
-    session->auth_state = SSH_AUTH_STATE_NONE;
3cd302
+    session->auth_state = SSH_AUTH_STATE_PUBKEY_AUTH_SENT;
3cd302
     session->pending_call_state = SSH_PENDING_CALL_AUTH_AGENT;
3cd302
     rc = packet_send(session);
3cd302
     if (rc == SSH_ERROR) {
3cd302
-- 
3cd302
2.19.0
3cd302
3cd302
3cd302
From ddea46f890bd5d87669f23b26d676adedaa5f610 Mon Sep 17 00:00:00 2001
3cd302
From: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
3cd302
Date: Wed, 19 Sep 2018 14:12:56 +0200
3cd302
Subject: [PATCH 2/8] CVE-2018-10933: Introduce
3cd302
 SSH_AUTH_STATE_PASSWORD_AUTH_SENT
3cd302
3cd302
The introduced auth state allows to identify when authentication using
3cd302
password was tried.
3cd302
3cd302
Fixes T101
3cd302
3cd302
Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
3cd302
---
3cd302
 include/libssh/auth.h | 2 ++
3cd302
 src/auth.c            | 4 +++-
3cd302
 2 files changed, 5 insertions(+), 1 deletion(-)
3cd302
3cd302
diff --git a/include/libssh/auth.h b/include/libssh/auth.h
3cd302
index 05754460..1fc00e20 100644
3cd302
--- a/include/libssh/auth.h
3cd302
+++ b/include/libssh/auth.h
3cd302
@@ -94,6 +94,8 @@ enum ssh_auth_state_e {
3cd302
   SSH_AUTH_STATE_PUBKEY_OFFER_SENT,
3cd302
   /** We have sent pubkey and signature expecting to be authenticated */
3cd302
   SSH_AUTH_STATE_PUBKEY_AUTH_SENT,
3cd302
+  /** We have sent a password expecting to be authenticated */
3cd302
+  SSH_AUTH_STATE_PASSWORD_AUTH_SENT,
3cd302
 };
3cd302
 
3cd302
 /** @internal
3cd302
diff --git a/src/auth.c b/src/auth.c
3cd302
index 964e82a6..3719b18a 100755
3cd302
--- a/src/auth.c
3cd302
+++ b/src/auth.c
3cd302
@@ -87,6 +87,7 @@ static int ssh_auth_response_termination(void *user){
3cd302
     case SSH_AUTH_STATE_GSSAPI_MIC_SENT:
3cd302
     case SSH_AUTH_STATE_PUBKEY_AUTH_SENT:
3cd302
     case SSH_AUTH_STATE_PUBKEY_OFFER_SENT:
3cd302
+    case SSH_AUTH_STATE_PASSWORD_AUTH_SENT:
3cd302
       return 0;
3cd302
     default:
3cd302
       return 1;
3cd302
@@ -141,6 +142,7 @@ static int ssh_userauth_get_response(ssh_session session) {
3cd302
         case SSH_AUTH_STATE_GSSAPI_MIC_SENT:
3cd302
         case SSH_AUTH_STATE_PUBKEY_OFFER_SENT:
3cd302
         case SSH_AUTH_STATE_PUBKEY_AUTH_SENT:
3cd302
+        case SSH_AUTH_STATE_PASSWORD_AUTH_SENT:
3cd302
         case SSH_AUTH_STATE_NONE:
3cd302
             /* not reached */
3cd302
             rc = SSH_AUTH_ERROR;
3cd302
@@ -1173,7 +1175,7 @@ int ssh_userauth_password(ssh_session session,
3cd302
         goto fail;
3cd302
     }
3cd302
 
3cd302
-    session->auth_state = SSH_AUTH_STATE_NONE;
3cd302
+    session->auth_state = SSH_AUTH_STATE_PASSWORD_AUTH_SENT;
3cd302
     session->pending_call_state = SSH_PENDING_CALL_AUTH_OFFER_PUBKEY;
3cd302
     rc = packet_send(session);
3cd302
     if (rc == SSH_ERROR) {
3cd302
-- 
3cd302
2.19.0
3cd302
3cd302
3cd302
From acd6a1ca8a332a204b616ab6bef413bee5d3409d Mon Sep 17 00:00:00 2001
3cd302
From: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
3cd302
Date: Wed, 19 Sep 2018 15:55:43 +0200
3cd302
Subject: [PATCH 3/8] CVE-2018-10933: Introduce SSH_AUTH_STATE_AUTH_NONE_SENT
3cd302
3cd302
The introduced auth state allows to identify when a request without
3cd302
authentication information was sent.
3cd302
3cd302
Fixes T101
3cd302
3cd302
Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
3cd302
---
3cd302
 include/libssh/auth.h | 2 ++
3cd302
 src/auth.c            | 4 +++-
3cd302
 2 files changed, 5 insertions(+), 1 deletion(-)
3cd302
3cd302
diff --git a/include/libssh/auth.h b/include/libssh/auth.h
3cd302
index 1fc00e20..75bc7546 100644
3cd302
--- a/include/libssh/auth.h
3cd302
+++ b/include/libssh/auth.h
3cd302
@@ -96,6 +96,8 @@ enum ssh_auth_state_e {
3cd302
   SSH_AUTH_STATE_PUBKEY_AUTH_SENT,
3cd302
   /** We have sent a password expecting to be authenticated */
3cd302
   SSH_AUTH_STATE_PASSWORD_AUTH_SENT,
3cd302
+  /** We have sent a request without auth information (method 'none') */
3cd302
+  SSH_AUTH_STATE_AUTH_NONE_SENT,
3cd302
 };
3cd302
 
3cd302
 /** @internal
3cd302
diff --git a/src/auth.c b/src/auth.c
3cd302
index 3719b18a..2bc73760 100755
3cd302
--- a/src/auth.c
3cd302
+++ b/src/auth.c
3cd302
@@ -88,6 +88,7 @@ static int ssh_auth_response_termination(void *user){
3cd302
     case SSH_AUTH_STATE_PUBKEY_AUTH_SENT:
3cd302
     case SSH_AUTH_STATE_PUBKEY_OFFER_SENT:
3cd302
     case SSH_AUTH_STATE_PASSWORD_AUTH_SENT:
3cd302
+    case SSH_AUTH_STATE_AUTH_NONE_SENT:
3cd302
       return 0;
3cd302
     default:
3cd302
       return 1;
3cd302
@@ -143,6 +144,7 @@ static int ssh_userauth_get_response(ssh_session session) {
3cd302
         case SSH_AUTH_STATE_PUBKEY_OFFER_SENT:
3cd302
         case SSH_AUTH_STATE_PUBKEY_AUTH_SENT:
3cd302
         case SSH_AUTH_STATE_PASSWORD_AUTH_SENT:
3cd302
+        case SSH_AUTH_STATE_AUTH_NONE_SENT:
3cd302
         case SSH_AUTH_STATE_NONE:
3cd302
             /* not reached */
3cd302
             rc = SSH_AUTH_ERROR;
3cd302
@@ -401,7 +403,7 @@ int ssh_userauth_none(ssh_session session, const char *username) {
3cd302
         goto fail;
3cd302
     }
3cd302
 
3cd302
-    session->auth_state = SSH_AUTH_STATE_NONE;
3cd302
+    session->auth_state = SSH_AUTH_STATE_AUTH_NONE_SENT;
3cd302
     session->pending_call_state = SSH_PENDING_CALL_AUTH_NONE;
3cd302
     rc = packet_send(session);
3cd302
     if (rc == SSH_ERROR) {
3cd302
-- 
3cd302
2.19.0
3cd302
3cd302
3cd302
From 7985acb76842ebf27e32e4afddfef55555209e8e Mon Sep 17 00:00:00 2001
3cd302
From: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
3cd302
Date: Wed, 19 Sep 2018 14:23:35 +0200
3cd302
Subject: [PATCH 4/8] CVE-2018-10933: Set correct state after sending MIC
3cd302
3cd302
After sending the client token, the auth state is set as
3cd302
SSH_AUTH_STATE_GSSAPI_MIC_SENT.  Then this can be expected to be the
3cd302
state when a USERAUTH_FAILURE or USERAUTH_SUCCESS arrives.
3cd302
3cd302
Fixes T101
3cd302
3cd302
Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
3cd302
---
3cd302
 src/gssapi.c | 2 +-
3cd302
 1 file changed, 1 insertion(+), 1 deletion(-)
3cd302
3cd302
diff --git a/src/gssapi.c b/src/gssapi.c
3cd302
index c2b30f6d..9306672a 100644
3cd302
--- a/src/gssapi.c
3cd302
+++ b/src/gssapi.c
3cd302
@@ -943,8 +943,8 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_token_client){
3cd302
         packet_send(session);
3cd302
     }
3cd302
     if(maj_stat == GSS_S_COMPLETE){
3cd302
-        session->auth_state = SSH_AUTH_STATE_NONE;
3cd302
         ssh_gssapi_send_mic(session);
3cd302
+        session->auth_state = SSH_AUTH_STATE_GSSAPI_MIC_SENT;
3cd302
     }
3cd302
     return SSH_PACKET_USED;
3cd302
 }
3cd302
-- 
3cd302
2.19.0
3cd302
3cd302
3cd302
From 3837a0547f08b160749fed7496316a62d6c11dea Mon Sep 17 00:00:00 2001
3cd302
From: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
3cd302
Date: Wed, 19 Sep 2018 14:30:33 +0200
3cd302
Subject: [PATCH 5/8] CVE-2018-10933: Check channel state when
3cd302
 OPEN_CONFIRMATION arrives
3cd302
3cd302
When a SSH2_MSG_OPEN_CONFIRMATION arrives, the channel state is checked
3cd302
to be in SSH_CHANNEL_STATE_OPENING.
3cd302
3cd302
Fixes T101
3cd302
3cd302
Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
3cd302
---
3cd302
 src/channels.c | 9 +++++++++
3cd302
 1 file changed, 9 insertions(+)
3cd302
3cd302
diff --git a/src/channels.c b/src/channels.c
3cd302
index 30c31468..d5d36af5 100644
3cd302
--- a/src/channels.c
3cd302
+++ b/src/channels.c
3cd302
@@ -170,6 +170,15 @@ SSH_PACKET_CALLBACK(ssh_packet_channel_open_conf){
3cd302
       "Received a CHANNEL_OPEN_CONFIRMATION for channel %d:%d",
3cd302
       channel->local_channel,
3cd302
       channel->remote_channel);
3cd302
+
3cd302
+  if (channel->state != SSH_CHANNEL_STATE_OPENING) {
3cd302
+      SSH_LOG(SSH_LOG_RARE,
3cd302
+              "SSH2_MSG_CHANNEL_OPEN_CONFIRMATION received in incorrect "
3cd302
+              "channel state %d",
3cd302
+              channel->state);
3cd302
+      goto error;
3cd302
+  }
3cd302
+
3cd302
   SSH_LOG(SSH_LOG_PROTOCOL,
3cd302
       "Remote window : %lu, maxpacket : %lu",
3cd302
       (long unsigned int) channel->remote_window,
3cd302
-- 
3cd302
2.19.0
3cd302
3cd302
3cd302
From e5ff7aa410c23954a2963b52e7b721a2d41536f3 Mon Sep 17 00:00:00 2001
3cd302
From: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
3cd302
Date: Wed, 19 Sep 2018 14:37:40 +0200
3cd302
Subject: [PATCH 6/8] CVE-2018-10933: Check channel state when OPEN_FAILURE
3cd302
 arrives
3cd302
3cd302
When a SSH2_MSG_OPEN_FAILURE arrives, the channel state is checked
3cd302
to be in SSH_CHANNEL_STATE_OPENING.
3cd302
3cd302
Fixes T101
3cd302
3cd302
Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
3cd302
---
3cd302
 src/channels.c | 11 +++++++++++
3cd302
 1 file changed, 11 insertions(+)
3cd302
3cd302
diff --git a/src/channels.c b/src/channels.c
3cd302
index d5d36af5..538956dd 100644
3cd302
--- a/src/channels.c
3cd302
+++ b/src/channels.c
3cd302
@@ -219,6 +219,14 @@ SSH_PACKET_CALLBACK(ssh_packet_channel_open_fail){
3cd302
       return SSH_PACKET_USED;
3cd302
   }
3cd302
 
3cd302
+  if (channel->state != SSH_CHANNEL_STATE_OPENING) {
3cd302
+      SSH_LOG(SSH_LOG_RARE,
3cd302
+              "SSH2_MSG_CHANNEL_OPEN_FAILURE received in incorrect channel "
3cd302
+              "state %d",
3cd302
+              channel->state);
3cd302
+      goto error;
3cd302
+  }
3cd302
+
3cd302
   ssh_set_error(session, SSH_REQUEST_DENIED,
3cd302
       "Channel opening failure: channel %u error (%lu) %s",
3cd302
       channel->local_channel,
3cd302
@@ -226,6 +234,9 @@ SSH_PACKET_CALLBACK(ssh_packet_channel_open_fail){
3cd302
       error);
3cd302
   SAFE_FREE(error);
3cd302
   channel->state=SSH_CHANNEL_STATE_OPEN_DENIED;
3cd302
+
3cd302
+error:
3cd302
+  ssh_set_error(session, SSH_FATAL, "Invalid packet");
3cd302
   return SSH_PACKET_USED;
3cd302
 }
3cd302
 
3cd302
-- 
3cd302
2.19.0
3cd302
3cd302
3cd302
From b9033ad56a498d0642f3258a54a32251278a319e Mon Sep 17 00:00:00 2001
3cd302
From: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
3cd302
Date: Wed, 19 Sep 2018 15:04:31 +0200
3cd302
Subject: [PATCH 7/8] CVE-2018-10933: Introduced packet filtering
3cd302
3cd302
The packet filter checks required states for the incoming packets and
3cd302
reject them if they arrived in the wrong state.
3cd302
3cd302
Fixes T101
3cd302
3cd302
Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
3cd302
---
3cd302
 include/libssh/packet.h |   6 +
3cd302
 src/packet.c            | 787 +++++++++++++++++++++++++++++++++++++++-
3cd302
 2 files changed, 791 insertions(+), 2 deletions(-)
3cd302
3cd302
diff --git a/include/libssh/packet.h b/include/libssh/packet.h
3cd302
index d8ef35bb..206c0b21 100644
3cd302
--- a/include/libssh/packet.h
3cd302
+++ b/include/libssh/packet.h
3cd302
@@ -43,6 +43,12 @@ enum ssh_packet_state_e {
3cd302
   PACKET_STATE_PROCESSING
3cd302
 };
3cd302
 
3cd302
+enum ssh_packet_filter_result_e {
3cd302
+    SSH_PACKET_UNKNOWN,
3cd302
+    SSH_PACKET_ALLOWED,
3cd302
+    SSH_PACKET_DENIED
3cd302
+};
3cd302
+
3cd302
 int packet_send(ssh_session session);
3cd302
 
3cd302
 #ifdef WITH_SSH1
3cd302
diff --git a/src/packet.c b/src/packet.c
3cd302
index d16cd165..5a263328 100644
3cd302
--- a/src/packet.c
3cd302
+++ b/src/packet.c
3cd302
@@ -127,6 +127,775 @@ static ssh_packet_callback default_packet_handlers[]= {
3cd302
   ssh_packet_channel_failure,              // SSH2_MSG_CHANNEL_FAILURE            100
3cd302
 };
3cd302
 
3cd302
+/** @internal
3cd302
+ * @brief check if the received packet is allowed for the current session state
3cd302
+ * @param session current ssh_session
3cd302
+ * @returns SSH_PACKET_ALLOWED if the packet is allowed; SSH_PACKET_DENIED
3cd302
+ * if the packet arrived in wrong state; SSH_PACKET_UNKNOWN if the packet type
3cd302
+ * is unknown
3cd302
+ */
3cd302
+static enum ssh_packet_filter_result_e ssh_packet_incoming_filter(ssh_session session)
3cd302
+{
3cd302
+    enum ssh_packet_filter_result_e rc;
3cd302
+
3cd302
+#ifdef DEBUG_PACKET
3cd302
+    SSH_LOG(SSH_LOG_PACKET, "Filtering packet type %d",
3cd302
+            session->in_packet.type);
3cd302
+#endif
3cd302
+
3cd302
+    switch(session->in_packet.type) {
3cd302
+    case SSH2_MSG_DISCONNECT:                         // 1
3cd302
+        /*
3cd302
+         * States required:
3cd302
+         * - None
3cd302
+         *
3cd302
+         * Transitions:
3cd302
+         * - session->socket->state = SSH_SOCKET_CLOSED
3cd302
+         * - session->session_state = SSH_SESSION_STATE_ERROR
3cd302
+         * */
3cd302
+
3cd302
+        /* Always allowed */
3cd302
+        rc = SSH_PACKET_ALLOWED;
3cd302
+        break;
3cd302
+    case SSH2_MSG_IGNORE:                             // 2
3cd302
+        /*
3cd302
+         * States required:
3cd302
+         * - None
3cd302
+         *
3cd302
+         * Transitions:
3cd302
+         * - None
3cd302
+         * */
3cd302
+
3cd302
+        /* Always allowed */
3cd302
+        rc = SSH_PACKET_ALLOWED;
3cd302
+        break;
3cd302
+    case SSH2_MSG_UNIMPLEMENTED:                      // 3
3cd302
+        /*
3cd302
+         * States required:
3cd302
+         * - None
3cd302
+         *
3cd302
+         * Transitions:
3cd302
+         * - None
3cd302
+         * */
3cd302
+
3cd302
+        /* Always allowed */
3cd302
+        rc = SSH_PACKET_ALLOWED;
3cd302
+        break;
3cd302
+    case SSH2_MSG_DEBUG:                              // 4
3cd302
+        /*
3cd302
+         * States required:
3cd302
+         * - None
3cd302
+         *
3cd302
+         * Transitions:
3cd302
+         * - None
3cd302
+         * */
3cd302
+
3cd302
+        /* Always allowed */
3cd302
+        rc = SSH_PACKET_ALLOWED;
3cd302
+        break;
3cd302
+    case SSH2_MSG_SERVICE_REQUEST:                    // 5
3cd302
+        /* Server only */
3cd302
+
3cd302
+        /*
3cd302
+         * States required:
3cd302
+         * - session->session_state == SSH_SESSION_STATE_AUTHENTICATING
3cd302
+         *   or session->session_state == SSH_SESSION_STATE_AUTHENTICATED
3cd302
+         * - session->dh_handshake_state == DH_STATE_FINISHED
3cd302
+         *
3cd302
+         * Transitions:
3cd302
+         * - None
3cd302
+         * */
3cd302
+
3cd302
+        /* If this is a client, reject the message */
3cd302
+        if (session->client) {
3cd302
+            rc = SSH_PACKET_DENIED;
3cd302
+            break;
3cd302
+        }
3cd302
+
3cd302
+        if ((session->session_state != SSH_SESSION_STATE_AUTHENTICATING) &&
3cd302
+            (session->session_state != SSH_SESSION_STATE_AUTHENTICATED))
3cd302
+        {
3cd302
+            rc = SSH_PACKET_DENIED;
3cd302
+            break;
3cd302
+        }
3cd302
+
3cd302
+        if (session->dh_handshake_state != DH_STATE_FINISHED) {
3cd302
+            rc = SSH_PACKET_DENIED;
3cd302
+            break;
3cd302
+        }
3cd302
+
3cd302
+        rc = SSH_PACKET_ALLOWED;
3cd302
+        break;
3cd302
+    case SSH2_MSG_SERVICE_ACCEPT:                     // 6
3cd302
+        /*
3cd302
+         * States required:
3cd302
+         * - session->session_state == SSH_SESSION_STATE_AUTHENTICATING
3cd302
+         *   or session->session_state == SSH_SESSION_STATE_AUTHENTICATED
3cd302
+         * - session->dh_handshake_state == DH_STATE_FINISHED
3cd302
+         * - session->auth_service_state == SSH_AUTH_SERVICE_SENT
3cd302
+         *
3cd302
+         * Transitions:
3cd302
+         * - auth_service_state = SSH_AUTH_SERVICE_ACCEPTED
3cd302
+         * */
3cd302
+
3cd302
+        if ((session->session_state != SSH_SESSION_STATE_AUTHENTICATING) &&
3cd302
+            (session->session_state != SSH_SESSION_STATE_AUTHENTICATED))
3cd302
+        {
3cd302
+            rc = SSH_PACKET_DENIED;
3cd302
+            break;
3cd302
+        }
3cd302
+
3cd302
+        if (session->dh_handshake_state != DH_STATE_FINISHED) {
3cd302
+            rc = SSH_PACKET_DENIED;
3cd302
+            break;
3cd302
+        }
3cd302
+
3cd302
+        /* TODO check if only auth service can be requested */
3cd302
+        if (session->auth_service_state != SSH_AUTH_SERVICE_SENT) {
3cd302
+            rc = SSH_PACKET_DENIED;
3cd302
+            break;
3cd302
+        }
3cd302
+
3cd302
+        rc = SSH_PACKET_ALLOWED;
3cd302
+        break;
3cd302
+    case SSH2_MSG_KEXINIT:                            // 20
3cd302
+        /*
3cd302
+         * States required:
3cd302
+         * - session_state == SSH_SESSION_STATE_AUTHENTICATED
3cd302
+         *   or session_state == SSH_SESSION_STATE_INITIAL_KEX
3cd302
+         * - dh_handshake_state == DH_STATE_INIT
3cd302
+         *   or dh_handshake_state == DH_STATE_FINISHED (re-exchange)
3cd302
+         *
3cd302
+         * Transitions:
3cd302
+         * - session->dh_handshake_state = DH_STATE_INIT
3cd302
+         * - session->session_state = SSH_SESSION_STATE_KEXINIT_RECEIVED
3cd302
+         *
3cd302
+         * On server:
3cd302
+         * - session->session_state = SSH_SESSION_STATE_DH
3cd302
+         * */
3cd302
+
3cd302
+        if ((session->session_state != SSH_SESSION_STATE_AUTHENTICATED) &&
3cd302
+            (session->session_state != SSH_SESSION_STATE_INITIAL_KEX))
3cd302
+        {
3cd302
+            rc = SSH_PACKET_DENIED;
3cd302
+            break;
3cd302
+        }
3cd302
+
3cd302
+        if ((session->dh_handshake_state != DH_STATE_INIT) &&
3cd302
+            (session->dh_handshake_state != DH_STATE_FINISHED))
3cd302
+        {
3cd302
+            rc = SSH_PACKET_DENIED;
3cd302
+        }
3cd302
+
3cd302
+        rc = SSH_PACKET_ALLOWED;
3cd302
+        break;
3cd302
+    case SSH2_MSG_NEWKEYS:                            // 21
3cd302
+        /*
3cd302
+         * States required:
3cd302
+         * - session_state == SSH_SESSION_STATE_DH
3cd302
+         * - dh_handshake_state == DH_STATE_NEWKEYS_SENT
3cd302
+         *
3cd302
+         * Transitions:
3cd302
+         * - session->dh_handshake_state = DH_STATE_FINISHED
3cd302
+         * - session->session_state = SSH_SESSION_STATE_AUTHENTICATING
3cd302
+         * if session->flags & SSH_SESSION_FLAG_AUTHENTICATED
3cd302
+         * - session->session_state = SSH_SESSION_STATE_AUTHENTICATED
3cd302
+         * */
3cd302
+
3cd302
+        /* If DH has not been started, reject message */
3cd302
+        if (session->session_state != SSH_SESSION_STATE_DH) {
3cd302
+            rc = SSH_PACKET_DENIED;
3cd302
+            break;
3cd302
+        }
3cd302
+
3cd302
+        /* Only allowed if dh_handshake_state is in NEWKEYS_SENT state */
3cd302
+        if (session->dh_handshake_state != DH_STATE_NEWKEYS_SENT) {
3cd302
+            rc = SSH_PACKET_DENIED;
3cd302
+            break;
3cd302
+        }
3cd302
+
3cd302
+        rc = SSH_PACKET_ALLOWED;
3cd302
+        break;
3cd302
+    case SSH2_MSG_KEXDH_INIT:                         // 30
3cd302
+      // SSH2_MSG_KEX_ECDH_INIT:                      // 30
3cd302
+      // SSH2_MSG_ECMQV_INIT:                         // 30
3cd302
+      // SSH2_MSG_KEX_DH_GEX_REQUEST_OLD:             // 30
3cd302
+
3cd302
+        /* Server only */
3cd302
+
3cd302
+        /*
3cd302
+         * States required:
3cd302
+         * - session_state == SSH_SESSION_STATE_DH
3cd302
+         * - dh_handshake_state == DH_STATE_INIT
3cd302
+         *
3cd302
+         * Transitions:
3cd302
+         * - session->dh_handshake_state = DH_STATE_INIT_SENT
3cd302
+         * then calls dh_handshake_server which triggers:
3cd302
+         * - session->dh_handhsake_state = DH_STATE_NEWKEYS_SENT
3cd302
+         * */
3cd302
+
3cd302
+        if (session->session_state != SSH_SESSION_STATE_DH) {
3cd302
+            rc = SSH_PACKET_DENIED;
3cd302
+            break;
3cd302
+        }
3cd302
+
3cd302
+        /* Only allowed if dh_handshake_state is in initial state */
3cd302
+        if (session->dh_handshake_state != DH_STATE_INIT) {
3cd302
+            rc = SSH_PACKET_DENIED;
3cd302
+            break;
3cd302
+        }
3cd302
+
3cd302
+        rc = SSH_PACKET_ALLOWED;
3cd302
+        break;
3cd302
+    case SSH2_MSG_KEXDH_REPLY:                        // 31
3cd302
+      // SSH2_MSG_KEX_ECDH_REPLY:                     // 31
3cd302
+      // SSH2_MSG_ECMQV_REPLY:                        // 31
3cd302
+      // SSH2_MSG_KEX_DH_GEX_GROUP:                   // 31
3cd302
+
3cd302
+        /*
3cd302
+         * States required:
3cd302
+         * - session_state == SSH_SESSION_STATE_DH
3cd302
+         * - dh_handshake_state == DH_STATE_INIT_SENT
3cd302
+         *
3cd302
+         * Transitions:
3cd302
+         * - session->dh_handhsake_state = DH_STATE_NEWKEYS_SENT
3cd302
+         * */
3cd302
+
3cd302
+        if (session->session_state != SSH_SESSION_STATE_DH) {
3cd302
+            rc = SSH_PACKET_DENIED;
3cd302
+            break;
3cd302
+        }
3cd302
+
3cd302
+        if (session->dh_handshake_state != DH_STATE_INIT_SENT) {
3cd302
+            rc = SSH_PACKET_DENIED;
3cd302
+            break;
3cd302
+        }
3cd302
+
3cd302
+        rc = SSH_PACKET_ALLOWED;
3cd302
+        break;
3cd302
+    case SSH2_MSG_KEX_DH_GEX_INIT:                    // 32
3cd302
+        /* TODO Not filtered */
3cd302
+        rc = SSH_PACKET_ALLOWED;
3cd302
+        break;
3cd302
+    case SSH2_MSG_KEX_DH_GEX_REPLY:                   // 33
3cd302
+        /* TODO Not filtered */
3cd302
+        rc = SSH_PACKET_ALLOWED;
3cd302
+        break;
3cd302
+    case SSH2_MSG_KEX_DH_GEX_REQUEST:                 // 34
3cd302
+        /* TODO Not filtered */
3cd302
+        rc = SSH_PACKET_ALLOWED;
3cd302
+        break;
3cd302
+    case SSH2_MSG_USERAUTH_REQUEST:                   // 50
3cd302
+        /* Server only */
3cd302
+
3cd302
+        /*
3cd302
+         * States required:
3cd302
+         * - session_state == SSH_SESSION_STATE_AUTHENTICATING
3cd302
+         * - dh_hanshake_state == DH_STATE_FINISHED
3cd302
+         *
3cd302
+         * Transitions:
3cd302
+         * - if authentication was successful:
3cd302
+         *   - session_state = SSH_SESSION_STATE_AUTHENTICATED
3cd302
+         * */
3cd302
+
3cd302
+        /* If this is a client, reject the message */
3cd302
+        if (session->client) {
3cd302
+            rc = SSH_PACKET_DENIED;
3cd302
+            break;
3cd302
+        }
3cd302
+
3cd302
+        if (session->dh_handshake_state != DH_STATE_FINISHED) {
3cd302
+            rc = SSH_PACKET_DENIED;
3cd302
+            break;
3cd302
+        }
3cd302
+
3cd302
+        if (session->session_state != SSH_SESSION_STATE_AUTHENTICATING) {
3cd302
+            rc = SSH_PACKET_DENIED;
3cd302
+            break;
3cd302
+        }
3cd302
+
3cd302
+        rc = SSH_PACKET_ALLOWED;
3cd302
+        break;
3cd302
+    case SSH2_MSG_USERAUTH_FAILURE:                   // 51
3cd302
+        /*
3cd302
+         * States required:
3cd302
+         * - session_state == SSH_SESSION_STATE_AUTHENTICATING
3cd302
+         * - dh_hanshake_state == DH_STATE_FINISHED
3cd302
+         * - session->auth_state == SSH_AUTH_STATE_KBDINT_SENT
3cd302
+         *   or session->auth_state == SSH_AUTH_STATE_PUBKEY_OFFER_SENT
3cd302
+         *   or session->auth_state == SSH_AUTH_STATE_PUBKEY_AUTH_SENT
3cd302
+         *   or session->auth_state == SSH_AUTH_STATE_PASSWORD_AUTH_SENT
3cd302
+         *   or session->auth_state == SSH_AUTH_STATE_GSSAPI_MIC_SENT
3cd302
+         *
3cd302
+         * Transitions:
3cd302
+         * - if unpacking failed:
3cd302
+         *   - session->auth_state = SSH_AUTH_ERROR
3cd302
+         * - if failure was partial:
3cd302
+         *   - session->auth_state = SSH_AUTH_PARTIAL
3cd302
+         * - else:
3cd302
+         *   - session->auth_state = SSH_AUTH_STATE_FAILED
3cd302
+         * */
3cd302
+
3cd302
+        /* If this is a server, reject the message */
3cd302
+        if (session->server) {
3cd302
+            rc = SSH_PACKET_DENIED;
3cd302
+            break;
3cd302
+        }
3cd302
+
3cd302
+        if (session->dh_handshake_state != DH_STATE_FINISHED) {
3cd302
+            rc = SSH_PACKET_DENIED;
3cd302
+            break;
3cd302
+        }
3cd302
+
3cd302
+        if (session->session_state != SSH_SESSION_STATE_AUTHENTICATING) {
3cd302
+            rc = SSH_PACKET_DENIED;
3cd302
+            break;
3cd302
+        }
3cd302
+
3cd302
+        rc = SSH_PACKET_ALLOWED;
3cd302
+        break;
3cd302
+    case SSH2_MSG_USERAUTH_SUCCESS:                   // 52
3cd302
+        /*
3cd302
+         * States required:
3cd302
+         * - session_state == SSH_SESSION_STATE_AUTHENTICATING
3cd302
+         * - dh_hanshake_state == DH_STATE_FINISHED
3cd302
+         * - session->auth_state == SSH_AUTH_STATE_KBDINT_SENT
3cd302
+         *   or session->auth_state == SSH_AUTH_STATE_PUBKEY_AUTH_SENT
3cd302
+         *   or session->auth_state == SSH_AUTH_STATE_PASSWORD_AUTH_SENT
3cd302
+         *   or session->auth_state == SSH_AUTH_STATE_GSSAPI_MIC_SENT
3cd302
+         *   or session->auth_state == SSH_AUTH_STATE_AUTH_NONE_SENT
3cd302
+         *
3cd302
+         * Transitions:
3cd302
+         * - session->auth_state = SSH_AUTH_STATE_SUCCESS
3cd302
+         * - session->session_state = SSH_SESSION_STATE_AUTHENTICATED
3cd302
+         * - session->flags |= SSH_SESSION_FLAG_AUTHENTICATED
3cd302
+         * - sessions->auth.current_method = SSH_AUTH_METHOD_UNKNOWN
3cd302
+         * */
3cd302
+
3cd302
+        /* If this is a server, reject the message */
3cd302
+        if (session->server) {
3cd302
+            rc = SSH_PACKET_DENIED;
3cd302
+            break;
3cd302
+        }
3cd302
+
3cd302
+        if (session->dh_handshake_state != DH_STATE_FINISHED) {
3cd302
+            rc = SSH_PACKET_DENIED;
3cd302
+            break;
3cd302
+        }
3cd302
+
3cd302
+        if (session->session_state != SSH_SESSION_STATE_AUTHENTICATING) {
3cd302
+            rc = SSH_PACKET_DENIED;
3cd302
+            break;
3cd302
+        }
3cd302
+
3cd302
+        if ((session->auth_state != SSH_AUTH_STATE_KBDINT_SENT) &&
3cd302
+            (session->auth_state != SSH_AUTH_STATE_PUBKEY_AUTH_SENT) &&
3cd302
+            (session->auth_state != SSH_AUTH_STATE_PASSWORD_AUTH_SENT) &&
3cd302
+            (session->auth_state != SSH_AUTH_STATE_GSSAPI_MIC_SENT) &&
3cd302
+            (session->auth_state != SSH_AUTH_STATE_AUTH_NONE_SENT))
3cd302
+        {
3cd302
+            rc = SSH_PACKET_DENIED;
3cd302
+            break;
3cd302
+        }
3cd302
+
3cd302
+        rc = SSH_PACKET_ALLOWED;
3cd302
+        break;
3cd302
+    case SSH2_MSG_USERAUTH_BANNER:                    // 53
3cd302
+        /*
3cd302
+         * States required:
3cd302
+         * - session_state == SSH_SESSION_STATE_AUTHENTICATING
3cd302
+         *
3cd302
+         * Transitions:
3cd302
+         * - None
3cd302
+         * */
3cd302
+
3cd302
+        if (session->session_state != SSH_SESSION_STATE_AUTHENTICATING) {
3cd302
+            rc = SSH_PACKET_DENIED;
3cd302
+            break;
3cd302
+        }
3cd302
+
3cd302
+        rc = SSH_PACKET_ALLOWED;
3cd302
+        break;
3cd302
+    case SSH2_MSG_USERAUTH_PK_OK:                     // 60
3cd302
+      // SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ:          // 60
3cd302
+      // SSH2_MSG_USERAUTH_INFO_REQUEST:              // 60
3cd302
+      // SSH2_MSG_USERAUTH_GSSAPI_RESPONSE:           // 60
3cd302
+
3cd302
+        /*
3cd302
+         * States required:
3cd302
+         * - session_state == SSH_SESSION_STATE_AUTHENTICATING
3cd302
+         * - session->auth_state == SSH_AUTH_STATE_KBDINT_SENT
3cd302
+         *   or
3cd302
+         *   session->auth_state == SSH_AUTH_STATE_GSSAPI_REQUEST_SENT
3cd302
+         *   or
3cd302
+         *   session->auth_state == SSH_AUTH_STATE_PUBKEY_OFFER_SENT
3cd302
+         *
3cd302
+         * Transitions:
3cd302
+         * Depending on the current state, the message is treated
3cd302
+         * differently:
3cd302
+         * - session->auth_state == SSH_AUTH_STATE_KBDINT_SENT
3cd302
+         *   - session->auth_state = SSH_AUTH_STATE_INFO
3cd302
+         * - session->auth_state == SSH_AUTH_STATE_GSSAPI_REQUEST_SENT
3cd302
+         *   - session->auth_state = SSH_AUTH_STATE_GSSAPI_TOKEN
3cd302
+         * - session->auth_state == SSH_AUTH_STATE_PUBKEY_OFFER_SENT
3cd302
+         *   - session->auth_state = SSH_AUTH_STATE_PK_OK
3cd302
+         * */
3cd302
+
3cd302
+        if (session->session_state != SSH_SESSION_STATE_AUTHENTICATING) {
3cd302
+            rc = SSH_PACKET_DENIED;
3cd302
+            break;
3cd302
+        }
3cd302
+
3cd302
+        if ((session->auth_state != SSH_AUTH_STATE_KBDINT_SENT) &&
3cd302
+            (session->auth_state != SSH_AUTH_STATE_PUBKEY_OFFER_SENT) &&
3cd302
+            (session->auth_state != SSH_AUTH_STATE_GSSAPI_REQUEST_SENT))
3cd302
+        {
3cd302
+            rc = SSH_PACKET_DENIED;
3cd302
+            break;
3cd302
+        }
3cd302
+
3cd302
+        rc = SSH_PACKET_ALLOWED;
3cd302
+        break;
3cd302
+    case SSH2_MSG_USERAUTH_INFO_RESPONSE:             // 61
3cd302
+      // SSH2_MSG_USERAUTH_GSSAPI_TOKEN:              // 61
3cd302
+
3cd302
+        /*
3cd302
+         * States required:
3cd302
+         * - session_state == SSH_SESSION_STATE_AUTHENTICATING
3cd302
+         * - session_state->auth_state == SSH_SESSION_STATE_GSSAPI_TOKEN
3cd302
+         *   or
3cd302
+         *   session_state->auth_state == SSH_SESSION_STATE_INFO
3cd302
+         *
3cd302
+         * Transitions:
3cd302
+         * - None
3cd302
+         * */
3cd302
+
3cd302
+        if (session->session_state != SSH_SESSION_STATE_AUTHENTICATING) {
3cd302
+            rc = SSH_PACKET_DENIED;
3cd302
+            break;
3cd302
+        }
3cd302
+
3cd302
+        if ((session->auth_state != SSH_AUTH_STATE_INFO) &&
3cd302
+            (session->auth_state != SSH_AUTH_STATE_GSSAPI_TOKEN))
3cd302
+        {
3cd302
+            rc = SSH_PACKET_DENIED;
3cd302
+            break;
3cd302
+        }
3cd302
+
3cd302
+        rc = SSH_PACKET_ALLOWED;
3cd302
+        break;
3cd302
+    case SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE:  // 63
3cd302
+        /* TODO Not filtered */
3cd302
+        rc = SSH_PACKET_ALLOWED;
3cd302
+        break;
3cd302
+    case SSH2_MSG_USERAUTH_GSSAPI_ERROR:              // 64
3cd302
+        /* TODO Not filtered */
3cd302
+        rc = SSH_PACKET_ALLOWED;
3cd302
+        break;
3cd302
+    case SSH2_MSG_USERAUTH_GSSAPI_ERRTOK:             // 65
3cd302
+        /* TODO Not filtered */
3cd302
+        rc = SSH_PACKET_ALLOWED;
3cd302
+        break;
3cd302
+    case SSH2_MSG_USERAUTH_GSSAPI_MIC:                // 66
3cd302
+        /* Server only */
3cd302
+
3cd302
+        /*
3cd302
+         * States required:
3cd302
+         * - session_state == SSH_SESSION_STATE_AUTHENTICATING
3cd302
+         * - session->gssapi->state == SSH_GSSAPI_STATE_RCV_MIC
3cd302
+         *
3cd302
+         * Transitions:
3cd302
+         * Depending on the result of the verification, the states are
3cd302
+         * changed:
3cd302
+         * - SSH_AUTH_SUCCESS:
3cd302
+         *   - session->session_state = SSH_SESSION_STATE_AUTHENTICATED
3cd302
+         *   - session->flags != SSH_SESSION_FLAG_AUTHENTICATED
3cd302
+         * - SSH_AUTH_PARTIAL:
3cd302
+         *   - None
3cd302
+         * - any other case:
3cd302
+         *   - None
3cd302
+         * */
3cd302
+
3cd302
+        /* If this is a client, reject the message */
3cd302
+        if (session->client) {
3cd302
+            rc = SSH_PACKET_DENIED;
3cd302
+            break;
3cd302
+        }
3cd302
+
3cd302
+        if (session->dh_handshake_state != DH_STATE_FINISHED) {
3cd302
+            rc = SSH_PACKET_DENIED;
3cd302
+            break;
3cd302
+        }
3cd302
+
3cd302
+        if (session->session_state != SSH_SESSION_STATE_AUTHENTICATING) {
3cd302
+            rc = SSH_PACKET_DENIED;
3cd302
+            break;
3cd302
+        }
3cd302
+
3cd302
+        rc = SSH_PACKET_ALLOWED;
3cd302
+        break;
3cd302
+    case SSH2_MSG_GLOBAL_REQUEST:                     // 80
3cd302
+        /*
3cd302
+         * States required:
3cd302
+         * - session_state == SSH_SESSION_STATE_AUTHENTICATED
3cd302
+         *
3cd302
+         * Transitions:
3cd302
+         * - None
3cd302
+         * */
3cd302
+
3cd302
+        if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) {
3cd302
+            rc = SSH_PACKET_DENIED;
3cd302
+            break;
3cd302
+        }
3cd302
+
3cd302
+        rc = SSH_PACKET_ALLOWED;
3cd302
+        break;
3cd302
+    case SSH2_MSG_REQUEST_SUCCESS:                    // 81
3cd302
+        /*
3cd302
+         * States required:
3cd302
+         * - session_state == SSH_SESSION_STATE_AUTHENTICATED
3cd302
+         * - session->global_req_state == SSH_CHANNEL_REQ_STATE_PENDING
3cd302
+         *
3cd302
+         * Transitions:
3cd302
+         * - session->global_req_state == SSH_CHANNEL_REQ_STATE_ACCEPTED
3cd302
+         * */
3cd302
+
3cd302
+        if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) {
3cd302
+            rc = SSH_PACKET_DENIED;
3cd302
+            break;
3cd302
+        }
3cd302
+
3cd302
+        if (session->global_req_state != SSH_CHANNEL_REQ_STATE_PENDING) {
3cd302
+            rc = SSH_PACKET_DENIED;
3cd302
+            break;
3cd302
+        }
3cd302
+
3cd302
+        rc = SSH_PACKET_ALLOWED;
3cd302
+        break;
3cd302
+    case SSH2_MSG_REQUEST_FAILURE:                    // 82
3cd302
+        /*
3cd302
+         * States required:
3cd302
+         * - session_state == SSH_SESSION_STATE_AUTHENTICATED
3cd302
+         * - session->global_req_state == SSH_CHANNEL_REQ_STATE_PENDING
3cd302
+         *
3cd302
+         * Transitions:
3cd302
+         * - session->global_req_state == SSH_CHANNEL_REQ_STATE_DENIED
3cd302
+         * */
3cd302
+
3cd302
+        if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) {
3cd302
+            rc = SSH_PACKET_DENIED;
3cd302
+            break;
3cd302
+        }
3cd302
+
3cd302
+        if (session->global_req_state != SSH_CHANNEL_REQ_STATE_PENDING) {
3cd302
+            rc = SSH_PACKET_DENIED;
3cd302
+            break;
3cd302
+        }
3cd302
+
3cd302
+        rc = SSH_PACKET_ALLOWED;
3cd302
+        break;
3cd302
+    case SSH2_MSG_CHANNEL_OPEN:                       // 90
3cd302
+        /*
3cd302
+         * States required:
3cd302
+         * - session_state == SSH_SESSION_STATE_AUTHENTICATED
3cd302
+         *
3cd302
+         * Transitions:
3cd302
+         * - None
3cd302
+         * */
3cd302
+
3cd302
+        if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) {
3cd302
+            rc = SSH_PACKET_DENIED;
3cd302
+            break;
3cd302
+        }
3cd302
+
3cd302
+        rc = SSH_PACKET_ALLOWED;
3cd302
+        break;
3cd302
+    case SSH2_MSG_CHANNEL_OPEN_CONFIRMATION:          // 91
3cd302
+        /*
3cd302
+         * States required:
3cd302
+         * - session_state == SSH_SESSION_STATE_AUTHENTICATED
3cd302
+         *
3cd302
+         * Transitions:
3cd302
+         * - channel->state = SSH_CHANNEL_STATE_OPEN
3cd302
+         * - channel->flags &= ~SSH_CHANNEL_FLAG_NOT_BOUND
3cd302
+         * */
3cd302
+
3cd302
+        if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) {
3cd302
+            rc = SSH_PACKET_DENIED;
3cd302
+            break;
3cd302
+        }
3cd302
+
3cd302
+        rc = SSH_PACKET_ALLOWED;
3cd302
+        break;
3cd302
+    case SSH2_MSG_CHANNEL_OPEN_FAILURE:               // 92
3cd302
+        /*
3cd302
+         * States required:
3cd302
+         * - session_state == SSH_SESSION_STATE_AUTHENTICATED
3cd302
+         *
3cd302
+         * Transitions:
3cd302
+         * - channel->state = SSH_CHANNEL_STATE_OPEN_DENIED
3cd302
+         * */
3cd302
+
3cd302
+        if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) {
3cd302
+            rc = SSH_PACKET_DENIED;
3cd302
+            break;
3cd302
+        }
3cd302
+
3cd302
+        rc = SSH_PACKET_ALLOWED;
3cd302
+        break;
3cd302
+    case SSH2_MSG_CHANNEL_WINDOW_ADJUST:              // 93
3cd302
+        /*
3cd302
+         * States required:
3cd302
+         * - session_state == SSH_SESSION_STATE_AUTHENTICATED
3cd302
+         *
3cd302
+         * Transitions:
3cd302
+         * - None
3cd302
+         * */
3cd302
+
3cd302
+        if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) {
3cd302
+            rc = SSH_PACKET_DENIED;
3cd302
+            break;
3cd302
+        }
3cd302
+
3cd302
+        rc = SSH_PACKET_ALLOWED;
3cd302
+        break;
3cd302
+    case SSH2_MSG_CHANNEL_DATA:                       // 94
3cd302
+        /*
3cd302
+         * States required:
3cd302
+         * - session_state == SSH_SESSION_STATE_AUTHENTICATED
3cd302
+         *
3cd302
+         * Transitions:
3cd302
+         * - None
3cd302
+         * */
3cd302
+
3cd302
+        if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) {
3cd302
+            rc = SSH_PACKET_DENIED;
3cd302
+            break;
3cd302
+        }
3cd302
+
3cd302
+        rc = SSH_PACKET_ALLOWED;
3cd302
+        break;
3cd302
+    case SSH2_MSG_CHANNEL_EXTENDED_DATA:              // 95
3cd302
+        /*
3cd302
+         * States required:
3cd302
+         * - session_state == SSH_SESSION_STATE_AUTHENTICATED
3cd302
+         *
3cd302
+         * Transitions:
3cd302
+         * - None
3cd302
+         * */
3cd302
+
3cd302
+        if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) {
3cd302
+            rc = SSH_PACKET_DENIED;
3cd302
+            break;
3cd302
+        }
3cd302
+
3cd302
+        rc = SSH_PACKET_ALLOWED;
3cd302
+        break;
3cd302
+    case SSH2_MSG_CHANNEL_EOF:                        // 96
3cd302
+        /*
3cd302
+         * States required:
3cd302
+         * - session_state == SSH_SESSION_STATE_AUTHENTICATED
3cd302
+         *
3cd302
+         * Transitions:
3cd302
+         * - None
3cd302
+         * */
3cd302
+
3cd302
+        if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) {
3cd302
+            rc = SSH_PACKET_DENIED;
3cd302
+            break;
3cd302
+        }
3cd302
+
3cd302
+        rc = SSH_PACKET_ALLOWED;
3cd302
+        break;
3cd302
+    case SSH2_MSG_CHANNEL_CLOSE:                      // 97
3cd302
+        /*
3cd302
+         * States required:
3cd302
+         * - session_state == SSH_SESSION_STATE_AUTHENTICATED
3cd302
+         *
3cd302
+         * Transitions:
3cd302
+         * - channel->state = SSH_CHANNEL_STATE_CLOSED
3cd302
+         * - channel->flags |= SSH_CHANNEL_FLAG_CLOSED_REMOTE
3cd302
+         * */
3cd302
+
3cd302
+        if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) {
3cd302
+            rc = SSH_PACKET_DENIED;
3cd302
+            break;
3cd302
+        }
3cd302
+
3cd302
+        rc = SSH_PACKET_ALLOWED;
3cd302
+        break;
3cd302
+    case SSH2_MSG_CHANNEL_REQUEST:                    // 98
3cd302
+        /*
3cd302
+         * States required:
3cd302
+         * - session_state == SSH_SESSION_STATE_AUTHENTICATED
3cd302
+         *
3cd302
+         * Transitions:
3cd302
+         * - Depends on the request
3cd302
+         * */
3cd302
+
3cd302
+        if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) {
3cd302
+            rc = SSH_PACKET_DENIED;
3cd302
+            break;
3cd302
+        }
3cd302
+
3cd302
+        rc = SSH_PACKET_ALLOWED;
3cd302
+        break;
3cd302
+    case SSH2_MSG_CHANNEL_SUCCESS:                    // 99
3cd302
+        /*
3cd302
+         * States required:
3cd302
+         * - session_state == SSH_SESSION_STATE_AUTHENTICATED
3cd302
+         * - channel->request_state == SSH_CHANNEL_REQ_STATE_PENDING
3cd302
+         *
3cd302
+         * Transitions:
3cd302
+         * - channel->request_state = SSH_CHANNEL_REQ_STATE_ACCEPTED
3cd302
+         * */
3cd302
+
3cd302
+        if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) {
3cd302
+            rc = SSH_PACKET_DENIED;
3cd302
+            break;
3cd302
+        }
3cd302
+
3cd302
+        rc = SSH_PACKET_ALLOWED;
3cd302
+        break;
3cd302
+    case SSH2_MSG_CHANNEL_FAILURE:                    // 100
3cd302
+        /*
3cd302
+         * States required:
3cd302
+         * - session_state == SSH_SESSION_STATE_AUTHENTICATED
3cd302
+         * - channel->request_state == SSH_CHANNEL_REQ_STATE_PENDING
3cd302
+         *
3cd302
+         * Transitions:
3cd302
+         * - channel->request_state = SSH_CHANNEL_REQ_STATE_DENIED
3cd302
+         * */
3cd302
+
3cd302
+        if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) {
3cd302
+            rc = SSH_PACKET_DENIED;
3cd302
+            break;
3cd302
+        }
3cd302
+
3cd302
+        rc = SSH_PACKET_ALLOWED;
3cd302
+        break;
3cd302
+    default:
3cd302
+        /* Unknown message, do not filter */
3cd302
+        rc = SSH_PACKET_UNKNOWN;
3cd302
+        goto end;
3cd302
+    }
3cd302
+
3cd302
+end:
3cd302
+#ifdef DEBUG_PACKET
3cd302
+    if (rc == SSH_PACKET_DENIED) {
3cd302
+        SSH_LOG(SSH_LOG_PACKET, "REJECTED packet type %d: ",
3cd302
+                session->in_packet.type);
3cd302
+    }
3cd302
+
3cd302
+    if (rc == SSH_PACKET_UNKNOWN) {
3cd302
+        SSH_LOG(SSH_LOG_PACKET, "UNKNOWN packet type %d",
3cd302
+                session->in_packet.type);
3cd302
+    }
3cd302
+#endif
3cd302
+
3cd302
+    return rc;
3cd302
+}
3cd302
+
3cd302
 /* in nonblocking mode, socket_read will read as much as it can, and return */
3cd302
 /* SSH_OK if it has read at least len bytes, otherwise, SSH_AGAIN. */
3cd302
 /* in blocking mode, it will read at least len bytes and will block until it's ok. */
3cd302
@@ -153,6 +922,7 @@ int ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user)
3cd302
     uint32_t len, compsize, payloadsize;
3cd302
     uint8_t padding;
3cd302
     size_t processed = 0; /* number of byte processed from the callback */
3cd302
+    enum ssh_packet_filter_result_e filter_result;
3cd302
 
3cd302
     if(session->current_crypto != NULL) {
3cd302
       current_macsize = hmac_digest_len(session->current_crypto->in_hmac);
3cd302
@@ -328,8 +1098,21 @@ int ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user)
3cd302
                     "packet: read type %hhd [len=%d,padding=%hhd,comp=%d,payload=%d]",
3cd302
                     session->in_packet.type, len, padding, compsize, payloadsize);
3cd302
 
3cd302
-            /* Execute callbacks */
3cd302
-            ssh_packet_process(session, session->in_packet.type);
3cd302
+            /* Check if the packet is expected */
3cd302
+            filter_result = ssh_packet_incoming_filter(session);
3cd302
+
3cd302
+            switch(filter_result) {
3cd302
+            case SSH_PACKET_ALLOWED:
3cd302
+                /* Execute callbacks */
3cd302
+                ssh_packet_process(session, session->in_packet.type);
3cd302
+                break;
3cd302
+            case SSH_PACKET_DENIED:
3cd302
+                goto error;
3cd302
+            case SSH_PACKET_UNKNOWN:
3cd302
+                ssh_packet_send_unimplemented(session, session->recv_seq - 1);
3cd302
+                break;
3cd302
+            }
3cd302
+
3cd302
             session->packet_state = PACKET_STATE_INIT;
3cd302
             if (processed < receivedlen) {
3cd302
                 /* Handle a potential packet left in socket buffer */
3cd302
-- 
3cd302
2.19.0
3cd302
3cd302
3cd302
From f1d57223dbc0dae99a783dd61fd679c56d7dfce5 Mon Sep 17 00:00:00 2001
3cd302
From: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
3cd302
Date: Wed, 19 Sep 2018 16:37:13 +0200
3cd302
Subject: [PATCH 8/8] CVE-2018-10933: Add tests for packet filtering
3cd302
3cd302
Created the test torture_packet_filter.c which tests if packets are
3cd302
being correctly filtered.
3cd302
3cd302
Fixes T101
3cd302
3cd302
Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
3cd302
---
3cd302
 tests/unittests/CMakeLists.txt          |   1 +
3cd302
 tests/unittests/torture_packet_filter.c | 500 ++++++++++++++++++++++++
3cd302
 2 files changed, 501 insertions(+)
3cd302
 create mode 100644 tests/unittests/torture_packet_filter.c
3cd302
3cd302
diff --git a/tests/unittests/CMakeLists.txt b/tests/unittests/CMakeLists.txt
3cd302
index 21825978..80d7e604 100644
3cd302
--- a/tests/unittests/CMakeLists.txt
3cd302
+++ b/tests/unittests/CMakeLists.txt
3cd302
@@ -10,6 +10,7 @@ add_cmocka_test(torture_misc torture_misc.c ${TORTURE_LIBRARY})
3cd302
 add_cmocka_test(torture_options torture_options.c ${TORTURE_LIBRARY})
3cd302
 add_cmocka_test(torture_isipaddr torture_isipaddr.c ${TORTURE_LIBRARY})
3cd302
 add_cmocka_test(torture_pki_ed25519 torture_pki_ed25519.c ${TORTURE_LIBRARY})
3cd302
+add_cmocka_test(torture_packet_filter torture_packet_filter.c ${TORTURE_LIBRARY})
3cd302
 if (UNIX AND NOT WIN32)
3cd302
     # requires ssh-keygen
3cd302
     add_cmocka_test(torture_keyfiles torture_keyfiles.c ${TORTURE_LIBRARY})
3cd302
diff --git a/tests/unittests/torture_packet_filter.c b/tests/unittests/torture_packet_filter.c
3cd302
new file mode 100644
3cd302
index 00000000..006be40a
3cd302
--- /dev/null
3cd302
+++ b/tests/unittests/torture_packet_filter.c
3cd302
@@ -0,0 +1,500 @@
3cd302
+/*
3cd302
+ * This file is part of the SSH Library
3cd302
+ *
3cd302
+ * Copyright (c) 2018 by Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
3cd302
+ *
3cd302
+ * The SSH Library is free software; you can redistribute it and/or modify
3cd302
+ * it under the terms of the GNU Lesser General Public License as published by
3cd302
+ * the Free Software Foundation; either version 2.1 of the License, or (at your
3cd302
+ * option) any later version.
3cd302
+ *
3cd302
+ * The SSH Library is distributed in the hope that it will be useful, but
3cd302
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
3cd302
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
3cd302
+ * License for more details.
3cd302
+ *
3cd302
+ * You should have received a copy of the GNU Lesser General Public License
3cd302
+ * along with the SSH Library; see the file COPYING.  If not, write to
3cd302
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
3cd302
+ * MA 02111-1307, USA.
3cd302
+ */
3cd302
+
3cd302
+/*
3cd302
+ * This test checks if the messages accepted by the packet filter were intented
3cd302
+ * to be accepted.
3cd302
+ *
3cd302
+ * The process consists in 2 steps:
3cd302
+ *   - Try the filter with a message type in an arbitrary state
3cd302
+ *   - If the message is accepted by the filter, check if the message is in the
3cd302
+ *     set of accepted states.
3cd302
+ *
3cd302
+ * Only the values selected by the flag (COMPARE_*) are considered.
3cd302
+ * */
3cd302
+
3cd302
+#include "config.h"
3cd302
+
3cd302
+#define LIBSSH_STATIC
3cd302
+
3cd302
+#include "torture.h"
3cd302
+#include "libssh/priv.h"
3cd302
+#include "libssh/libssh.h"
3cd302
+#include "libssh/session.h"
3cd302
+#include "libssh/auth.h"
3cd302
+#include "libssh/ssh2.h"
3cd302
+#include "libssh/packet.h"
3cd302
+
3cd302
+#include "packet.c"
3cd302
+
3cd302
+#define COMPARE_SESSION_STATE       1
3cd302
+#define COMPARE_ROLE                (1 << 1)
3cd302
+#define COMPARE_DH_STATE            (1 << 2)
3cd302
+#define COMPARE_AUTH_STATE          (1 << 3)
3cd302
+#define COMPARE_GLOBAL_REQ_STATE    (1 << 4)
3cd302
+
3cd302
+#define SESSION_STATE_COUNT 11
3cd302
+#define DH_STATE_COUNT 4
3cd302
+#define AUTH_STATE_COUNT 14
3cd302
+#define GLOBAL_REQ_STATE_COUNT 5
3cd302
+#define MESSAGE_COUNT 100 // from 1 to 100
3cd302
+
3cd302
+#define ROLE_CLIENT 0
3cd302
+#define ROLE_SERVER 1
3cd302
+
3cd302
+/*
3cd302
+ * This is the list of currently unfiltered message types.
3cd302
+ * Only unrecognized types should be in this list.
3cd302
+ * */
3cd302
+static uint8_t unfiltered[] = {
3cd302
+    7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
3cd302
+    22, 23, 24, 25, 26, 27, 28, 29,
3cd302
+    35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
3cd302
+    54, 55, 56, 57, 58, 59,
3cd302
+    62,
3cd302
+    67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
3cd302
+    83, 84, 85, 86, 87, 88, 89,
3cd302
+};
3cd302
+
3cd302
+typedef struct global_state_st {
3cd302
+    /* If the bit in this flag is zero, the corresponding state is not
3cd302
+     * considered, working as a wildcard (meaning any value is accepted) */
3cd302
+    uint32_t flags;
3cd302
+    uint8_t role;
3cd302
+    enum ssh_session_state_e session;
3cd302
+    enum ssh_dh_state_e dh;
3cd302
+    enum ssh_auth_state_e auth;
3cd302
+    enum ssh_channel_request_state_e global_req;
3cd302
+} global_state;
3cd302
+
3cd302
+static int cmp_state(const void *e1, const void *e2)
3cd302
+{
3cd302
+    global_state *s1 = (global_state *) e1;
3cd302
+    global_state *s2 = (global_state *) e2;
3cd302
+
3cd302
+    /* Compare role (client == 0 or server == 1)*/
3cd302
+    if (s1->role < s2->role) {
3cd302
+        return -1;
3cd302
+    }
3cd302
+    else if (s1->role > s2->role) {
3cd302
+        return 1;
3cd302
+    }
3cd302
+
3cd302
+    /* Compare session state */
3cd302
+    if (s1->session < s2->session) {
3cd302
+        return -1;
3cd302
+    }
3cd302
+    else if (s1->session > s2->session) {
3cd302
+        return 1;
3cd302
+    }
3cd302
+
3cd302
+    /* Compare DH state */
3cd302
+    if (s1->dh < s2->dh) {
3cd302
+        return -1;
3cd302
+    }
3cd302
+    else if (s1->dh > s2->dh) {
3cd302
+        return 1;
3cd302
+    }
3cd302
+
3cd302
+    /* Compare auth */
3cd302
+    if (s1->auth < s2->auth) {
3cd302
+        return -1;
3cd302
+    }
3cd302
+    else if (s1->auth > s2->auth) {
3cd302
+        return 1;
3cd302
+    }
3cd302
+
3cd302
+    /* Compare global_req */
3cd302
+    if (s1->global_req < s2->global_req) {
3cd302
+        return -1;
3cd302
+    }
3cd302
+    else if (s1->global_req > s2->global_req) {
3cd302
+        return 1;
3cd302
+    }
3cd302
+
3cd302
+    /* If all equal, they are equal */
3cd302
+    return 0;
3cd302
+}
3cd302
+
3cd302
+static int cmp_state_search(const void *key, const void *array_element)
3cd302
+{
3cd302
+    global_state *s1 = (global_state *) key;
3cd302
+    global_state *s2 = (global_state *) array_element;
3cd302
+
3cd302
+    int result = 0;
3cd302
+
3cd302
+    if (s2->flags & COMPARE_ROLE) {
3cd302
+        /* Compare role (client == 0 or server == 1)*/
3cd302
+        if (s1->role < s2->role) {
3cd302
+            return -1;
3cd302
+        }
3cd302
+        else if (s1->role > s2->role) {
3cd302
+            return 1;
3cd302
+        }
3cd302
+    }
3cd302
+
3cd302
+    if (s2->flags & COMPARE_SESSION_STATE) {
3cd302
+        /* Compare session state */
3cd302
+        if (s1->session < s2->session) {
3cd302
+            result = -1;
3cd302
+            goto end;
3cd302
+        }
3cd302
+        else if (s1->session > s2->session) {
3cd302
+            result = 1;
3cd302
+            goto end;
3cd302
+        }
3cd302
+    }
3cd302
+
3cd302
+    if (s2->flags & COMPARE_DH_STATE) {
3cd302
+        /* Compare DH state */
3cd302
+        if (s1->dh < s2->dh) {
3cd302
+            result = -1;
3cd302
+            goto end;
3cd302
+        }
3cd302
+        else if (s1->dh > s2->dh) {
3cd302
+            result = 1;
3cd302
+            goto end;
3cd302
+        }
3cd302
+    }
3cd302
+
3cd302
+    if (s2->flags & COMPARE_AUTH_STATE) {
3cd302
+        /* Compare auth */
3cd302
+        if (s1->auth < s2->auth) {
3cd302
+            result = -1;
3cd302
+            goto end;
3cd302
+        }
3cd302
+        else if (s1->auth > s2->auth) {
3cd302
+            result = 1;
3cd302
+            goto end;
3cd302
+        }
3cd302
+    }
3cd302
+
3cd302
+    if (s2->flags & COMPARE_GLOBAL_REQ_STATE) {
3cd302
+        /* Compare global_req */
3cd302
+        if (s1->global_req < s2->global_req) {
3cd302
+            result = -1;
3cd302
+            goto end;
3cd302
+        }
3cd302
+        else if (s1->global_req > s2->global_req) {
3cd302
+            result = 1;
3cd302
+            goto end;
3cd302
+        }
3cd302
+    }
3cd302
+
3cd302
+end:
3cd302
+    return result;
3cd302
+}
3cd302
+
3cd302
+static int is_state_accepted(global_state *tested, global_state *accepted,
3cd302
+                             int accepted_len)
3cd302
+{
3cd302
+    global_state *found = NULL;
3cd302
+
3cd302
+    found = bsearch(tested, accepted, accepted_len, sizeof(global_state),
3cd302
+                    cmp_state_search);
3cd302
+
3cd302
+    if (found != NULL) {
3cd302
+        return 1;
3cd302
+    }
3cd302
+
3cd302
+    return 0;
3cd302
+}
3cd302
+
3cd302
+static int cmp_uint8(const void *i, const void *j)
3cd302
+{
3cd302
+    uint8_t e1 = *((uint8_t *)i);
3cd302
+    uint8_t e2 = *((uint8_t *)j);
3cd302
+
3cd302
+    if (e1 < e2) {
3cd302
+        return -1;
3cd302
+    }
3cd302
+    else if (e1 > e2) {
3cd302
+        return 1;
3cd302
+    }
3cd302
+
3cd302
+    return 0;
3cd302
+}
3cd302
+
3cd302
+static int check_unfiltered(uint8_t msg_type)
3cd302
+{
3cd302
+    uint8_t *found;
3cd302
+
3cd302
+    found = bsearch(&msg_type, unfiltered, sizeof(unfiltered)/sizeof(uint8_t),
3cd302
+                    sizeof(uint8_t), cmp_uint8);
3cd302
+
3cd302
+    if (found != NULL) {
3cd302
+        return 1;
3cd302
+    }
3cd302
+
3cd302
+    return 0;
3cd302
+}
3cd302
+
3cd302
+static void torture_packet_filter_check_unfiltered(void **state)
3cd302
+{
3cd302
+    ssh_session session;
3cd302
+
3cd302
+    int role_c;
3cd302
+    int auth_c;
3cd302
+    int session_c;
3cd302
+    int dh_c;
3cd302
+    int global_req_c;
3cd302
+
3cd302
+    uint8_t msg_type;
3cd302
+
3cd302
+    enum ssh_packet_filter_result_e rc;
3cd302
+    int in_unfiltered;
3cd302
+
3cd302
+    session = ssh_new();
3cd302
+
3cd302
+    for (msg_type = 1; msg_type <= MESSAGE_COUNT; msg_type++) {
3cd302
+        session->in_packet.type = msg_type;
3cd302
+        for (role_c = 0; role_c < 2; role_c++) {
3cd302
+            session->server = role_c;
3cd302
+            for (session_c = 0; session_c < SESSION_STATE_COUNT; session_c++) {
3cd302
+                session->session_state = session_c;
3cd302
+                for (dh_c = 0; dh_c < DH_STATE_COUNT; dh_c++) {
3cd302
+                    session->dh_handshake_state = dh_c;
3cd302
+                    for (auth_c = 0; auth_c < AUTH_STATE_COUNT; auth_c++) {
3cd302
+                        session->auth_state = auth_c;
3cd302
+                        for (global_req_c = 0;
3cd302
+                                global_req_c < GLOBAL_REQ_STATE_COUNT;
3cd302
+                                global_req_c++)
3cd302
+                        {
3cd302
+                            session->global_req_state = global_req_c;
3cd302
+
3cd302
+                            rc = ssh_packet_incoming_filter(session);
3cd302
+
3cd302
+                            if (rc == SSH_PACKET_UNKNOWN) {
3cd302
+                                in_unfiltered = check_unfiltered(msg_type);
3cd302
+
3cd302
+                                if (!in_unfiltered) {
3cd302
+                                    fprintf(stderr, "Message type %d UNFILTERED "
3cd302
+                                            "in state: role %d, session %d, dh %d, auth %d\n",
3cd302
+                                            msg_type, role_c, session_c, dh_c, auth_c);
3cd302
+                                }
3cd302
+                                assert_int_equal(in_unfiltered, 1);
3cd302
+                            }
3cd302
+                            else {
3cd302
+                                in_unfiltered = check_unfiltered(msg_type);
3cd302
+
3cd302
+                                if (in_unfiltered) {
3cd302
+                                    fprintf(stderr, "Message type %d NOT UNFILTERED "
3cd302
+                                            "in state: role %d, session %d, dh %d, auth %d\n",
3cd302
+                                            msg_type, role_c, session_c, dh_c, auth_c);
3cd302
+                                }
3cd302
+                                assert_int_equal(in_unfiltered, 0);
3cd302
+                            }
3cd302
+                        }
3cd302
+                    }
3cd302
+                }
3cd302
+            }
3cd302
+        }
3cd302
+    }
3cd302
+    ssh_free(session);
3cd302
+}
3cd302
+
3cd302
+static int check_message_in_all_states(global_state accepted[],
3cd302
+                                       int accepted_count, uint8_t msg_type)
3cd302
+{
3cd302
+    ssh_session session;
3cd302
+
3cd302
+    int role_c;
3cd302
+    int auth_c;
3cd302
+    int session_c;
3cd302
+    int dh_c;
3cd302
+    int global_req_c;
3cd302
+
3cd302
+    enum ssh_packet_filter_result_e rc;
3cd302
+    int in_accepted;
3cd302
+
3cd302
+    global_state key;
3cd302
+
3cd302
+    session = ssh_new();
3cd302
+
3cd302
+    /* Sort the accepted array so that the elements can be searched using
3cd302
+     * bsearch */
3cd302
+    qsort(accepted, accepted_count, sizeof(global_state), cmp_state);
3cd302
+
3cd302
+    session->in_packet.type = msg_type;
3cd302
+
3cd302
+    for (role_c = 0; role_c < 2; role_c++) {
3cd302
+        session->server = role_c;
3cd302
+        key.role = role_c;
3cd302
+        for (session_c = 0; session_c < SESSION_STATE_COUNT; session_c++) {
3cd302
+            session->session_state = session_c;
3cd302
+            key.session = session_c;
3cd302
+            for (dh_c = 0; dh_c < DH_STATE_COUNT; dh_c++) {
3cd302
+                session->dh_handshake_state = dh_c;
3cd302
+                key.dh = dh_c;
3cd302
+                for (auth_c = 0; auth_c < AUTH_STATE_COUNT; auth_c++) {
3cd302
+                    session->auth_state = auth_c;
3cd302
+                    key.auth = auth_c;
3cd302
+                    for (global_req_c = 0;
3cd302
+                         global_req_c < GLOBAL_REQ_STATE_COUNT;
3cd302
+                         global_req_c++)
3cd302
+                    {
3cd302
+                        session->global_req_state = global_req_c;
3cd302
+                        key.global_req = global_req_c;
3cd302
+
3cd302
+                        rc = ssh_packet_incoming_filter(session);
3cd302
+
3cd302
+                        if (rc == SSH_PACKET_ALLOWED) {
3cd302
+                            in_accepted = is_state_accepted(&key, accepted,
3cd302
+                                                         accepted_count);
3cd302
+
3cd302
+                            if (!in_accepted) {
3cd302
+                                fprintf(stderr, "Message type %d ALLOWED "
3cd302
+                                        "in state: role %d, session %d, dh %d, auth %d\n",
3cd302
+                                        msg_type, role_c, session_c, dh_c, auth_c);
3cd302
+                            }
3cd302
+                            assert_int_equal(in_accepted, 1);
3cd302
+                        }
3cd302
+                        else if (rc == SSH_PACKET_DENIED) {
3cd302
+                            in_accepted = is_state_accepted(&key, accepted, accepted_count);
3cd302
+
3cd302
+                            if (in_accepted) {
3cd302
+                                fprintf(stderr, "Message type %d DENIED "
3cd302
+                                    "in state: role %d, session %d, dh %d, auth %d\n",
3cd302
+                                    msg_type, role_c, session_c, dh_c, auth_c);
3cd302
+                            }
3cd302
+                            assert_int_equal(in_accepted, 0);
3cd302
+                        }
3cd302
+                        else {
3cd302
+                            fprintf(stderr, "Message type %d UNFILTERED "
3cd302
+                                    "in state: role %d, session %d, dh %d, auth %d\n",
3cd302
+                                    msg_type, role_c, session_c, dh_c, auth_c);
3cd302
+                        }
3cd302
+                    }
3cd302
+                }
3cd302
+            }
3cd302
+        }
3cd302
+    }
3cd302
+
3cd302
+    ssh_free(session);
3cd302
+    return 0;
3cd302
+}
3cd302
+
3cd302
+static void torture_packet_filter_check_auth_success(void **state)
3cd302
+{
3cd302
+    int rc;
3cd302
+
3cd302
+    global_state accepted[] = {
3cd302
+        {
3cd302
+            .flags = (COMPARE_SESSION_STATE |
3cd302
+                    COMPARE_ROLE |
3cd302
+                    COMPARE_AUTH_STATE |
3cd302
+                    COMPARE_DH_STATE),
3cd302
+            .role = ROLE_CLIENT,
3cd302
+            .session = SSH_SESSION_STATE_AUTHENTICATING,
3cd302
+            .dh = DH_STATE_FINISHED,
3cd302
+            .auth = SSH_AUTH_STATE_PUBKEY_AUTH_SENT,
3cd302
+        },
3cd302
+        {
3cd302
+            .flags = (COMPARE_SESSION_STATE |
3cd302
+                    COMPARE_ROLE |
3cd302
+                    COMPARE_AUTH_STATE |
3cd302
+                    COMPARE_DH_STATE),
3cd302
+            .role = ROLE_CLIENT,
3cd302
+            .session = SSH_SESSION_STATE_AUTHENTICATING,
3cd302
+            .dh = DH_STATE_FINISHED,
3cd302
+            .auth = SSH_AUTH_STATE_PASSWORD_AUTH_SENT,
3cd302
+        },
3cd302
+        {
3cd302
+            .flags = (COMPARE_SESSION_STATE |
3cd302
+                    COMPARE_ROLE |
3cd302
+                    COMPARE_AUTH_STATE |
3cd302
+                    COMPARE_DH_STATE),
3cd302
+            .role = ROLE_CLIENT,
3cd302
+            .session = SSH_SESSION_STATE_AUTHENTICATING,
3cd302
+            .dh = DH_STATE_FINISHED,
3cd302
+            .auth = SSH_AUTH_STATE_GSSAPI_MIC_SENT,
3cd302
+        },
3cd302
+        {
3cd302
+            .flags = (COMPARE_SESSION_STATE |
3cd302
+                    COMPARE_ROLE |
3cd302
+                    COMPARE_AUTH_STATE |
3cd302
+                    COMPARE_DH_STATE),
3cd302
+            .role = ROLE_CLIENT,
3cd302
+            .session = SSH_SESSION_STATE_AUTHENTICATING,
3cd302
+            .dh = DH_STATE_FINISHED,
3cd302
+            .auth = SSH_AUTH_STATE_KBDINT_SENT,
3cd302
+        },
3cd302
+        {
3cd302
+            .flags = (COMPARE_SESSION_STATE |
3cd302
+                    COMPARE_ROLE |
3cd302
+                    COMPARE_AUTH_STATE |
3cd302
+                    COMPARE_DH_STATE),
3cd302
+            .role = ROLE_CLIENT,
3cd302
+            .session = SSH_SESSION_STATE_AUTHENTICATING,
3cd302
+            .dh = DH_STATE_FINISHED,
3cd302
+            .auth = SSH_AUTH_STATE_AUTH_NONE_SENT,
3cd302
+        }
3cd302
+    };
3cd302
+
3cd302
+    int accepted_count = 5;
3cd302
+
3cd302
+    /* Unused */
3cd302
+    (void) state;
3cd302
+
3cd302
+    rc = check_message_in_all_states(accepted, accepted_count,
3cd302
+            SSH2_MSG_USERAUTH_SUCCESS);
3cd302
+
3cd302
+    assert_int_equal(rc, 0);
3cd302
+}
3cd302
+
3cd302
+static void torture_packet_filter_check_channel_open(void **state)
3cd302
+{
3cd302
+    int rc;
3cd302
+
3cd302
+    /* The only condition to accept a CHANNEL_OPEN is to be authenticated */
3cd302
+    global_state accepted[] = {
3cd302
+        {
3cd302
+            .flags = COMPARE_SESSION_STATE,
3cd302
+            .session = SSH_SESSION_STATE_AUTHENTICATED,
3cd302
+        }
3cd302
+    };
3cd302
+
3cd302
+    int accepted_count = 1;
3cd302
+
3cd302
+    /* Unused */
3cd302
+    (void) state;
3cd302
+
3cd302
+    rc = check_message_in_all_states(accepted, accepted_count,
3cd302
+            SSH2_MSG_CHANNEL_OPEN);
3cd302
+
3cd302
+    assert_int_equal(rc, 0);
3cd302
+}
3cd302
+
3cd302
+int torture_run_tests(void)
3cd302
+{
3cd302
+    int rc;
3cd302
+    UnitTest tests[] = {
3cd302
+        unit_test(torture_packet_filter_check_auth_success),
3cd302
+        unit_test(torture_packet_filter_check_channel_open),
3cd302
+        unit_test(torture_packet_filter_check_unfiltered),
3cd302
+    };
3cd302
+
3cd302
+    ssh_init();
3cd302
+    torture_filter_tests(tests);
3cd302
+    rc = run_tests(tests);
3cd302
+    ssh_finalize();
3cd302
+    return rc;
3cd302
+}
3cd302
-- 
3cd302
2.19.0
3cd302