aboutsummaryrefslogtreecommitdiffstats
path: root/framework/src/suricata/src/app-layer-ssh.c
diff options
context:
space:
mode:
Diffstat (limited to 'framework/src/suricata/src/app-layer-ssh.c')
-rw-r--r--framework/src/suricata/src/app-layer-ssh.c2607
1 files changed, 2607 insertions, 0 deletions
diff --git a/framework/src/suricata/src/app-layer-ssh.c b/framework/src/suricata/src/app-layer-ssh.c
new file mode 100644
index 00000000..879c7746
--- /dev/null
+++ b/framework/src/suricata/src/app-layer-ssh.c
@@ -0,0 +1,2607 @@
+/* Copyright (C) 2007-2014 Open Information Security Foundation
+ *
+ * You can copy, redistribute or modify this Program under the terms of
+ * the GNU General Public License version 2 as published by the Free
+ * Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+/**
+ * \file
+ *
+ * \author Pablo Rincon <pablo.rincon.crespo@gmail.com>
+ * \author Victor Julien <victor@inliniac.net>
+ *
+ * App-layer parser for SSH protocol
+ *
+ */
+
+#include "suricata-common.h"
+#include "debug.h"
+#include "decode.h"
+#include "threads.h"
+
+#include "util-print.h"
+#include "util-pool.h"
+
+#include "stream-tcp-private.h"
+#include "stream-tcp-reassemble.h"
+#include "stream-tcp.h"
+#include "stream.h"
+
+#include "app-layer-protos.h"
+#include "app-layer-parser.h"
+#include "app-layer-ssh.h"
+
+#include "conf.h"
+
+#include "util-spm.h"
+#include "util-unittest.h"
+#include "util-debug.h"
+#include "flow-private.h"
+
+#include "util-byte.h"
+#include "util-memcmp.h"
+
+/** \internal
+ * \brief Function to parse the SSH version string of the client
+ *
+ * The input to this function is a byte buffer starting with SSH-
+ *
+ * \param ssh_state Pointer the state in which the value to be stored
+ * \param input Pointer the received input data
+ * \param input_len Length in bytes of the received data
+ *
+ * \retval len remaining length in input
+ */
+static int SSHParseBanner(SshState *state, SshHeader *header, const uint8_t *input, uint32_t input_len)
+{
+ const uint8_t *line_ptr = input;
+ uint32_t line_len = input_len;
+
+ /* is it the version line? */
+ if (SCMemcmp("SSH-", line_ptr, 4) != 0) {
+ SCReturnInt(-1);
+ }
+
+ const uint8_t *banner_end = BasicSearch(line_ptr, line_len, (uint8_t*)"\r", 1);
+ if (banner_end == NULL) {
+ banner_end = BasicSearch(line_ptr, line_len, (uint8_t*)"\n", 1);
+ if (banner_end == NULL) {
+ SCLogDebug("No EOL at the end of banner buffer");
+ SCReturnInt(-1);
+ }
+ }
+
+ if ((banner_end - line_ptr) > 255) {
+ SCLogDebug("Invalid version string, it should be less than 255 "
+ "characters including <CR><NL>, input value is %"PRIuMAX,
+ (banner_end - line_ptr));
+ SCReturnInt(-1);
+ }
+
+ /* don't search things behind the end of banner */
+ line_len = banner_end - line_ptr;
+
+ /* ok, we have found the version line/string, skip it and parse proto version */
+ line_ptr += 4;
+ line_len -= 4;
+
+ uint8_t *proto_end = BasicSearch(line_ptr, line_len, (uint8_t*)"-", 1);
+ if (proto_end == NULL) {
+ /* Strings starting with SSH- are not allowed
+ * if they are not the real version string */
+ SCLogDebug("Info Version String for SSH (invalid usage of SSH- prefix)");
+ SCReturnInt(-1);
+ }
+ uint64_t proto_ver_len = (uint64_t)(proto_end - line_ptr);
+ header->proto_version = SCMalloc(proto_ver_len + 1);
+ if (header->proto_version == NULL) {
+ SCReturnInt(-1);
+ }
+ memcpy(header->proto_version, line_ptr, proto_ver_len);
+ header->proto_version[proto_ver_len] = '\0';
+
+ /* Now lets parse the software & version */
+ line_ptr += proto_ver_len + 1;
+ line_len -= proto_ver_len + 1;
+ if (line_len < 1) {
+ SCLogDebug("No software version specified (weird)");
+ header->flags |= SSH_FLAG_VERSION_PARSED;
+ /* Return the remaining length */
+ SCReturnInt(0);
+ }
+
+ uint64_t sw_ver_len = (uint64_t)(banner_end - line_ptr);
+ /* sanity check on this arithmetic */
+ if ((sw_ver_len <= 1) || (sw_ver_len >= input_len)) {
+ SCLogDebug("Should not have sw version length '%" PRIu64 "'", sw_ver_len);
+ SCReturnInt(-1);
+ }
+
+ header->software_version = SCMalloc(sw_ver_len + 1);
+ if (header->software_version == NULL) {
+ SCReturnInt(-1);
+ }
+ memcpy(header->software_version, line_ptr, sw_ver_len);
+ header->software_version[sw_ver_len] = '\0';
+ if (header->software_version[sw_ver_len - 1] == 0x0d)
+ header->software_version[sw_ver_len - 1] = '\0';
+
+ header->flags |= SSH_FLAG_VERSION_PARSED;
+
+ /* Return the remaining length */
+ int len = input_len - (banner_end - input);
+ SCReturnInt(len);
+}
+
+static int SSHParseRecordHeader(SshState *state, SshHeader *header,
+ const uint8_t *input, uint32_t input_len)
+{
+#ifdef DEBUG
+ BUG_ON(input_len != 6);
+#else
+ if (input_len < 6)
+ SCReturnInt(-1);
+#endif
+ /* input and input_len now point past initial line */
+ uint32_t pkt_len = 0;
+ int r = ByteExtractUint32(&pkt_len, BYTE_BIG_ENDIAN,
+ 4, input);
+ if (r != 4) {
+ SCLogDebug("xtract 4 bytes failed %d", r);
+ SCReturnInt(-1);
+ }
+ if (pkt_len < 2) {
+ SCReturnInt(-1);
+ }
+
+ header->pkt_len = pkt_len;
+ SCLogDebug("pkt len: %"PRIu32, pkt_len);
+
+ input += 4;
+ //input_len -= 4;
+
+ header->padding_len = *input;
+
+ input += 1;
+ //input_len -= 1;
+
+ SCLogDebug("padding: %u", header->padding_len);
+
+ header->msg_code = *input;
+
+ SCLogDebug("msg code: %u", header->msg_code);
+
+ if (header->msg_code == SSH_MSG_NEWKEYS) {
+ /* done */
+ SCLogDebug("done");
+ header->flags |= SSH_FLAG_PARSER_DONE;
+ } else {
+ /* not yet done */
+ SCLogDebug("not done");
+ }
+ SCReturnInt(0);
+}
+
+/** \internal
+ * \brief Function to parse the SSH field in packet received from the client
+ *
+ * Input to this function is a byte buffer starting with SSH- up to at least
+ * a \r or \n character.
+ *
+ * \param ssh_state Pointer the state in which the value to be stored
+ * \param input Pointer the received input data
+ * \param input_len Length in bytes of the received data
+ */
+static int SSHParseRecord(SshState *state, SshHeader *header, uint8_t *input, uint32_t input_len)
+{
+ SCEnter();
+ int ret = 0;
+
+ if (header->flags & SSH_FLAG_PARSER_DONE) {
+ SCReturnInt(0);
+ }
+
+ SCLogDebug("state %p, input %p,input_len %" PRIu32,
+ state, input, input_len);
+ //PrintRawDataFp(stdout, input, input_len);
+
+ if (!(header->flags & SSH_FLAG_VERSION_PARSED)) {
+ ret = SSHParseBanner(state, header, input, input_len);
+ if (ret < 0) {
+ SCLogDebug("Invalid version string");
+ SCReturnInt(-1);
+ } else if (header->flags & SSH_FLAG_VERSION_PARSED) {
+ SCLogDebug("Version string parsed, remaining length %d", ret);
+ input += input_len - ret;
+ input_len -= (input_len - ret);
+
+ uint32_t u = 0;
+ while (u < input_len && (input[u] == '\r' || input[u] == '\n')) {
+ u++;
+ }
+ SCLogDebug("skipping %u EOL bytes", u);
+ input += u;
+ input_len -= u;
+
+ if (input_len == 0)
+ SCReturnInt(0);
+
+ } else {
+ BUG_ON(1);// we only call this when we have enough data
+ SCLogDebug("Version string not parsed yet");
+ //pstate->parse_field = 0;
+ SCReturnInt(0);
+ }
+ } else {
+ SCLogDebug("Version string already parsed");
+ }
+
+ /* skip bytes from the current record if we have to */
+ if (header->record_left > 0) {
+ SCLogDebug("skipping bytes part of the current record");
+ if (header->record_left > input_len) {
+ header->record_left -= input_len;
+ SCLogDebug("all input skipped, %u left in record", header->record_left);
+ SCReturnInt(0);
+ } else {
+ input_len -= header->record_left;
+ input += header->record_left;
+ header->record_left = 0;
+
+ if (input_len == 0) {
+ SCLogDebug("all input skipped");
+ SCReturnInt(0);
+ }
+ }
+ }
+
+again:
+ /* input is too small, even when combined with stored bytes */
+ if (header->buf_offset + input_len < 6) {
+ memcpy(header->buf + header->buf_offset, input, input_len);
+ header->buf_offset += input_len;
+ SCReturnInt(0);
+
+ /* we have enough bytes to parse 6 bytes, lets see if we have
+ * previously stored some */
+ } else if (header->buf_offset > 0) {
+ uint8_t needed = 6 - header->buf_offset;
+
+ SCLogDebug("parse stored");
+ memcpy(header->buf + header->buf_offset, input, needed);
+ header->buf_offset = 6;
+
+ // parse the 6
+ if (SSHParseRecordHeader(state, header, header->buf, 6) < 0)
+ SCReturnInt(-1);
+ header->buf_offset = 0;
+
+ uint32_t record_left = header->pkt_len - 2;
+ input_len -= needed;
+ input += needed;
+
+ if (record_left > input_len) {
+ header->record_left = record_left - input_len;
+ } else {
+ input_len -= record_left;
+ if (input_len == 0)
+ SCReturnInt(0);
+
+ input += record_left;
+
+ SCLogDebug("we have %u left to parse", input_len);
+ goto again;
+
+ }
+
+ /* nothing stored, lets parse this directly */
+ } else {
+ SCLogDebug("parse direct");
+ //PrintRawDataFp(stdout, input, input_len);
+ if (SSHParseRecordHeader(state, header, input, 6) < 0)
+ SCReturnInt(-1);
+
+ uint32_t record_left = header->pkt_len - 2;
+ SCLogDebug("record left %u", record_left);
+ input_len -= 6;
+ input += 6;
+
+ if (record_left > input_len) {
+ header->record_left = record_left - input_len;
+ } else {
+ input_len -= record_left;
+ if (input_len == 0)
+ SCReturnInt(0);
+ input += record_left;
+ //PrintRawDataFp(stdout, input, input_len);
+
+ SCLogDebug("we have %u left to parse", input_len);
+ goto again;
+ }
+ }
+
+ SCReturnInt(0);
+}
+
+static int EnoughData(uint8_t *input, uint32_t input_len)
+{
+ uint32_t u;
+ for (u = 0; u < input_len; u++) {
+ if (input[u] == '\r' || input[u] == '\n')
+ return TRUE;
+ }
+ return FALSE;
+}
+
+#define MAX_BANNER_LEN 256
+
+static int SSHParseData(SshState *state, SshHeader *header,
+ uint8_t *input, uint32_t input_len)
+{
+ /* we're looking for the banner */
+ if (!(header->flags & SSH_FLAG_VERSION_PARSED))
+ {
+ int banner_eol = EnoughData(input, input_len);
+
+ /* fast track normal case: no buffering */
+ if (header->banner_buffer == NULL && banner_eol)
+ {
+ SCLogDebug("enough data, parse now");
+ // parse now
+ int r = SSHParseRecord(state, header, input, input_len);
+ SCReturnInt(r);
+
+ /* banner EOL with existing buffer present. Time for magic. */
+ } else if (banner_eol) {
+ SCLogDebug("banner EOL with existing buffer");
+
+ uint32_t tocopy = MAX_BANNER_LEN - header->banner_len;
+ if (tocopy > input_len)
+ tocopy = input_len;
+
+ SCLogDebug("tocopy %u input_len %u", tocopy, input_len);
+ memcpy(header->banner_buffer + header->banner_len, input, tocopy);
+ header->banner_len += tocopy;
+
+ SCLogDebug("header->banner_len %u", header->banner_len);
+ int r = SSHParseRecord(state, header,
+ header->banner_buffer, header->banner_len);
+ if (r == 0) {
+ input += tocopy;
+ input_len -= tocopy;
+ if (input_len > 0) {
+ SCLogDebug("handling remaining data %u", input_len);
+ r = SSHParseRecord(state, header, input, input_len);
+ }
+ }
+ SCReturnInt(r);
+
+ /* no banner EOL, so we need to buffer */
+ } else if (!banner_eol) {
+ if (header->banner_buffer == NULL) {
+ header->banner_buffer = SCMalloc(MAX_BANNER_LEN);
+ if (header->banner_buffer == NULL)
+ SCReturnInt(-1);
+ }
+
+ uint32_t tocopy = MAX_BANNER_LEN - header->banner_len;
+ if (tocopy > input_len)
+ tocopy = input_len;
+ SCLogDebug("tocopy %u", tocopy);
+
+ memcpy(header->banner_buffer + header->banner_len, input, tocopy);
+ header->banner_len += tocopy;
+ SCLogDebug("header->banner_len %u", header->banner_len);
+ }
+
+ /* we have a banner, the rest is just records */
+ } else {
+ int r = SSHParseRecord(state, header, input, input_len);
+ SCReturnInt(r);
+ }
+
+ //PrintRawDataFp(stdout, input, input_len);
+ return 0;
+}
+
+static int SSHParseRequest(Flow *f, void *state, AppLayerParserState *pstate,
+ uint8_t *input, uint32_t input_len,
+ void *local_data)
+{
+ SshState *ssh_state = (SshState *)state;
+ SshHeader *ssh_header = &ssh_state->cli_hdr;
+
+ if (input == NULL && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) {
+ SCReturnInt(1);
+ } else if (input == NULL || input_len == 0) {
+ SCReturnInt(-1);
+ }
+
+ int r = SSHParseData(ssh_state, ssh_header, input, input_len);
+
+ if (ssh_state->cli_hdr.flags & SSH_FLAG_PARSER_DONE &&
+ ssh_state->srv_hdr.flags & SSH_FLAG_PARSER_DONE) {
+ AppLayerParserStateSetFlag(pstate, APP_LAYER_PARSER_NO_INSPECTION);
+ AppLayerParserStateSetFlag(pstate, APP_LAYER_PARSER_NO_REASSEMBLY);
+ }
+
+ SCReturnInt(r);
+}
+
+static int SSHParseResponse(Flow *f, void *state, AppLayerParserState *pstate,
+ uint8_t *input, uint32_t input_len,
+ void *local_data)
+{
+ SshState *ssh_state = (SshState *)state;
+ SshHeader *ssh_header = &ssh_state->srv_hdr;
+
+ if (input == NULL && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) {
+ SCReturnInt(1);
+ } else if (input == NULL || input_len == 0) {
+ SCReturnInt(-1);
+ }
+
+ int r = SSHParseData(ssh_state, ssh_header, input, input_len);
+
+ if (ssh_state->cli_hdr.flags & SSH_FLAG_PARSER_DONE &&
+ ssh_state->srv_hdr.flags & SSH_FLAG_PARSER_DONE) {
+ AppLayerParserStateSetFlag(pstate, APP_LAYER_PARSER_NO_INSPECTION);
+ AppLayerParserStateSetFlag(pstate, APP_LAYER_PARSER_NO_REASSEMBLY);
+ }
+
+ SCReturnInt(r);
+}
+
+/** \brief Function to allocates the SSH state memory
+ */
+static void *SSHStateAlloc(void)
+{
+ void *s = SCMalloc(sizeof(SshState));
+ if (unlikely(s == NULL))
+ return NULL;
+
+ memset(s, 0, sizeof(SshState));
+ return s;
+}
+
+/** \brief Function to free the SSH state memory
+ */
+static void SSHStateFree(void *state)
+{
+ SshState *s = (SshState *)state;
+ if (s->cli_hdr.proto_version != NULL)
+ SCFree(s->cli_hdr.proto_version);
+ if (s->cli_hdr.software_version != NULL)
+ SCFree(s->cli_hdr.software_version);
+ if (s->cli_hdr.banner_buffer != NULL)
+ SCFree(s->cli_hdr.banner_buffer);
+
+ if (s->srv_hdr.proto_version != NULL)
+ SCFree(s->srv_hdr.proto_version);
+ if (s->srv_hdr.software_version != NULL)
+ SCFree(s->srv_hdr.software_version);
+ if (s->srv_hdr.banner_buffer != NULL)
+ SCFree(s->srv_hdr.banner_buffer);
+
+ SCFree(s);
+}
+
+static int SSHRegisterPatternsForProtocolDetection(void)
+{
+ if (AppLayerProtoDetectPMRegisterPatternCI(IPPROTO_TCP, ALPROTO_SSH,
+ "SSH-", 4, 0, STREAM_TOSERVER) < 0)
+ {
+ return -1;
+ }
+ if (AppLayerProtoDetectPMRegisterPatternCI(IPPROTO_TCP, ALPROTO_SSH,
+ "SSH-", 4, 0, STREAM_TOCLIENT) < 0)
+ {
+ return -1;
+ }
+ return 0;
+}
+
+/** \brief Function to register the SSH protocol parsers and other functions
+ */
+void RegisterSSHParsers(void)
+{
+ char *proto_name = "ssh";
+
+ if (AppLayerProtoDetectConfProtoDetectionEnabled("tcp", proto_name)) {
+ AppLayerProtoDetectRegisterProtocol(ALPROTO_SSH, proto_name);
+ if (SSHRegisterPatternsForProtocolDetection() < 0)
+ return;
+ }
+
+ if (AppLayerParserConfParserEnabled("tcp", proto_name)) {
+ AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_SSH, STREAM_TOSERVER,
+ SSHParseRequest);
+ AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_SSH, STREAM_TOCLIENT,
+ SSHParseResponse);
+ AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_SSH, SSHStateAlloc, SSHStateFree);
+ AppLayerParserRegisterParserAcceptableDataDirection(IPPROTO_TCP,
+ ALPROTO_SSH, STREAM_TOSERVER|STREAM_TOCLIENT);
+ } else {
+// SCLogInfo("Parsed disabled for %s protocol. Protocol detection"
+// "still on.", proto_name);
+ }
+
+#ifdef UNITTESTS
+ AppLayerParserRegisterProtocolUnittests(IPPROTO_TCP, ALPROTO_SSH, SSHParserRegisterTests);
+#endif
+}
+
+/* UNITTESTS */
+#ifdef UNITTESTS
+
+/** \test Send a version string in one chunk (client version str). */
+static int SSHParserTest01(void)
+{
+ int result = 0;
+ Flow f;
+ uint8_t sshbuf[] = "SSH-2.0-MySSHClient-0.5.1\n";
+ uint32_t sshlen = sizeof(sshbuf) - 1;
+ TcpSession ssn;
+ AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
+
+ memset(&f, 0, sizeof(f));
+ memset(&ssn, 0, sizeof(ssn));
+ f.protoctx = (void *)&ssn;
+
+ StreamTcpInitConfig(TRUE);
+
+ SCMutexLock(&f.m);
+ int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER|STREAM_EOF, sshbuf, sshlen);
+ if (r != 0) {
+ printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+
+ SshState *ssh_state = f.alstate;
+ if (ssh_state == NULL) {
+ printf("no ssh state: ");
+ goto end;
+ }
+
+ if ( !(ssh_state->cli_hdr.flags & SSH_FLAG_VERSION_PARSED)) {
+ printf("Client version string not parsed: ");
+ goto end;
+ }
+
+ if (ssh_state->cli_hdr.software_version == NULL) {
+ printf("Client version string not parsed: ");
+ goto end;
+ }
+
+ if (ssh_state->cli_hdr.proto_version == NULL) {
+ printf("Client version string not parsed: ");
+ goto end;
+ }
+
+ if (strncmp((char*)ssh_state->cli_hdr.software_version, "MySSHClient-0.5.1", strlen("MySSHClient-0.5.1")) != 0) {
+ printf("Client version string not parsed correctly: ");
+ goto end;
+ }
+
+ if (strncmp((char*)ssh_state->cli_hdr.proto_version, "2.0", strlen("2.0")) != 0) {
+ printf("Client version string not parsed correctly: ");
+ goto end;
+ }
+
+ result = 1;
+end:
+ if (alp_tctx != NULL)
+ AppLayerParserThreadCtxFree(alp_tctx);
+ StreamTcpFreeConfig(TRUE);
+ return result;
+}
+
+/** \test Send a version string in one chunk but multiple lines and comments.
+ * (client version str)
+ */
+static int SSHParserTest02(void)
+{
+ int result = 0;
+ Flow f;
+ uint8_t sshbuf[] = "SSH-2.0-MySSHClient-0.5.1 some comments...\n";
+ uint32_t sshlen = sizeof(sshbuf) - 1;
+ TcpSession ssn;
+ AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
+
+ memset(&f, 0, sizeof(f));
+ memset(&ssn, 0, sizeof(ssn));
+ f.protoctx = (void *)&ssn;
+
+ StreamTcpInitConfig(TRUE);
+
+ SCMutexLock(&f.m);
+ int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER|STREAM_EOF, sshbuf, sshlen);
+ if (r != 0) {
+ printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+
+ SshState *ssh_state = f.alstate;
+ if (ssh_state == NULL) {
+ printf("no ssh state: ");
+ goto end;
+ }
+
+ if ( !(ssh_state->cli_hdr.flags & SSH_FLAG_VERSION_PARSED)) {
+ printf("Client version string not parsed: ");
+ goto end;
+ }
+
+ if (ssh_state->cli_hdr.software_version == NULL) {
+ printf("Client version string not parsed: ");
+ goto end;
+ }
+
+ if (ssh_state->cli_hdr.proto_version == NULL) {
+ printf("Client version string not parsed: ");
+ goto end;
+ }
+
+ if (strncmp((char*)ssh_state->cli_hdr.software_version, "MySSHClient-0.5.1", strlen("MySSHClient-0.5.1")) != 0) {
+ printf("Client version string not parsed correctly: ");
+ goto end;
+ }
+
+ if (strncmp((char*)ssh_state->cli_hdr.proto_version, "2.0", strlen("2.0")) != 0) {
+ printf("Client version string not parsed correctly: ");
+ goto end;
+ }
+
+ result = 1;
+end:
+ if (alp_tctx != NULL)
+ AppLayerParserThreadCtxFree(alp_tctx);
+ StreamTcpFreeConfig(TRUE);
+ return result;
+}
+
+/** \test Send a invalid version string in one chunk but multiple lines and comments.
+ * (client version str)
+ */
+static int SSHParserTest03(void)
+{
+ int result = 0;
+ Flow f;
+ uint8_t sshbuf[] = "SSH-2.0 some comments...\n";
+ uint32_t sshlen = sizeof(sshbuf) - 1;
+ TcpSession ssn;
+ AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
+
+ memset(&f, 0, sizeof(f));
+ memset(&ssn, 0, sizeof(ssn));
+ f.protoctx = (void *)&ssn;
+
+ StreamTcpInitConfig(TRUE);
+
+ SCMutexLock(&f.m);
+ int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER|STREAM_EOF, sshbuf, sshlen);
+ if (r == 0) {
+ printf("toclient chunk 1 returned %" PRId32 ", expected != 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+
+ SshState *ssh_state = f.alstate;
+ if (ssh_state == NULL) {
+ printf("no ssh state: ");
+ goto end;
+ }
+
+ if (ssh_state->cli_hdr.flags & SSH_FLAG_VERSION_PARSED) {
+ printf("Client version string parsed? It's not a valid string: ");
+ goto end;
+ }
+
+ if (ssh_state->cli_hdr.proto_version != NULL) {
+ goto end;
+ }
+
+ if (ssh_state->cli_hdr.software_version != NULL) {
+ goto end;
+ }
+
+ result = 1;
+end:
+ if (alp_tctx != NULL)
+ AppLayerParserThreadCtxFree(alp_tctx);
+ StreamTcpFreeConfig(TRUE);
+ return result;
+}
+
+/** \test Send a version string in one chunk (server version str). */
+static int SSHParserTest04(void)
+{
+ int result = 0;
+ Flow f;
+ uint8_t sshbuf[] = "SSH-2.0-MySSHClient-0.5.1\n";
+ uint32_t sshlen = sizeof(sshbuf) - 1;
+ TcpSession ssn;
+ AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
+
+ memset(&f, 0, sizeof(f));
+ memset(&ssn, 0, sizeof(ssn));
+ f.protoctx = (void *)&ssn;
+
+ StreamTcpInitConfig(TRUE);
+
+ SCMutexLock(&f.m);
+ int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT|STREAM_EOF, sshbuf, sshlen);
+ if (r != 0) {
+ printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+
+ SshState *ssh_state = f.alstate;
+ if (ssh_state == NULL) {
+ printf("no ssh state: ");
+ goto end;
+ }
+
+ if (!(ssh_state->srv_hdr.flags & SSH_FLAG_VERSION_PARSED)) {
+ printf("Client version string not parsed: ");
+ goto end;
+ }
+
+ if (ssh_state->srv_hdr.software_version == NULL) {
+ printf("Client version string not parsed: ");
+ goto end;
+ }
+
+ if (ssh_state->srv_hdr.proto_version == NULL) {
+ printf("Client version string not parsed: ");
+ goto end;
+ }
+
+ if (strncmp((char*)ssh_state->srv_hdr.software_version, "MySSHClient-0.5.1", strlen("MySSHClient-0.5.1")) != 0) {
+ printf("Client version string not parsed correctly: ");
+ goto end;
+ }
+
+ if (strncmp((char*)ssh_state->srv_hdr.proto_version, "2.0", strlen("2.0")) != 0) {
+ printf("Client version string not parsed correctly: ");
+ goto end;
+ }
+
+ result = 1;
+
+end:
+ if (alp_tctx != NULL)
+ AppLayerParserThreadCtxFree(alp_tctx);
+ StreamTcpFreeConfig(TRUE);
+ return result;
+}
+
+/** \test Send a version string in one chunk (server version str)
+ */
+static int SSHParserTest05(void)
+{
+ int result = 0;
+ Flow f;
+ uint8_t sshbuf[] = "SSH-2.0-MySSHClient-0.5.1 some comments...\n";
+ uint32_t sshlen = sizeof(sshbuf) - 1;
+ TcpSession ssn;
+ AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
+
+ memset(&f, 0, sizeof(f));
+ memset(&ssn, 0, sizeof(ssn));
+ f.protoctx = (void *)&ssn;
+
+ StreamTcpInitConfig(TRUE);
+
+ SCMutexLock(&f.m);
+ int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT|STREAM_EOF, sshbuf, sshlen);
+ if (r != 0) {
+ printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+
+ SshState *ssh_state = f.alstate;
+ if (ssh_state == NULL) {
+ printf("no ssh state: ");
+ goto end;
+ }
+
+ if (!(ssh_state->srv_hdr.flags & SSH_FLAG_VERSION_PARSED)) {
+ printf("Client version string not parsed: ");
+ goto end;
+ }
+
+ if (ssh_state->srv_hdr.software_version == NULL) {
+ printf("Client version string not parsed: ");
+ goto end;
+ }
+
+ if (ssh_state->srv_hdr.proto_version == NULL) {
+ printf("Client version string not parsed: ");
+ goto end;
+ }
+
+ if (strncmp((char*)ssh_state->srv_hdr.software_version, "MySSHClient-0.5.1", strlen("MySSHClient-0.5.1")) != 0) {
+ printf("Client version string not parsed correctly: ");
+ goto end;
+ }
+
+ if (strncmp((char*)ssh_state->srv_hdr.proto_version, "2.0", strlen("2.0")) != 0) {
+ printf("Client version string not parsed correctly: ");
+ goto end;
+ }
+
+ result = 1;
+end:
+ if (alp_tctx != NULL)
+ AppLayerParserThreadCtxFree(alp_tctx);
+ StreamTcpFreeConfig(TRUE);
+ return result;
+}
+
+/** \test Send a invalid version string in one chunk (server version str)
+ */
+static int SSHParserTest06(void)
+{
+ int result = 0;
+ Flow f;
+ uint8_t sshbuf[] = "SSH-2.0 some comments...\n";
+ uint32_t sshlen = sizeof(sshbuf) - 1;
+ TcpSession ssn;
+ AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
+
+ memset(&f, 0, sizeof(f));
+ memset(&ssn, 0, sizeof(ssn));
+ f.protoctx = (void *)&ssn;
+
+ StreamTcpInitConfig(TRUE);
+
+ SCMutexLock(&f.m);
+ int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT|STREAM_EOF, sshbuf, sshlen);
+ if (r == 0) {
+ printf("toserver chunk 1 returned %" PRId32 ", expected != 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ /* Ok, it returned an error. Let's make sure we didn't parse the string at all */
+
+ SshState *ssh_state = f.alstate;
+ if (ssh_state == NULL) {
+ printf("no ssh state: ");
+ goto end;
+ }
+
+ if (ssh_state->srv_hdr.flags & SSH_FLAG_VERSION_PARSED) {
+ printf("Client version string parsed? It's not a valid string: ");
+ goto end;
+ }
+
+ if (ssh_state->srv_hdr.proto_version != NULL) {
+ goto end;
+ }
+
+ if (ssh_state->srv_hdr.software_version != NULL) {
+ goto end;
+ }
+
+ result = 1;
+end:
+ if (alp_tctx != NULL)
+ AppLayerParserThreadCtxFree(alp_tctx);
+ StreamTcpFreeConfig(TRUE);
+ return result;
+}
+
+static int SSHParserTest07(void)
+{
+ int result = 0;
+ Flow f;
+ uint8_t sshbuf1[] = "SSH-2.";
+ uint32_t sshlen1 = sizeof(sshbuf1) - 1;
+ uint8_t sshbuf2[] = { "0-MySSHClient-0.5.1\r\n"};
+ uint32_t sshlen2 = sizeof(sshbuf2) - 1;
+ TcpSession ssn;
+ AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
+
+ memset(&f, 0, sizeof(f));
+ memset(&ssn, 0, sizeof(ssn));
+ f.protoctx = (void *)&ssn;
+
+ StreamTcpInitConfig(TRUE);
+
+ SCMutexLock(&f.m);
+ int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1);
+ if (r != 0) {
+ printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf2, sshlen2);
+ if (r != 0) {
+ printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+
+ SshState *ssh_state = f.alstate;
+ if (ssh_state == NULL) {
+ printf("no ssh state: ");
+ goto end;
+ }
+
+ if ( !(ssh_state->cli_hdr.flags & SSH_FLAG_VERSION_PARSED)) {
+ printf("Client version string not parsed: ");
+ goto end;
+ }
+
+ if (ssh_state->cli_hdr.software_version == NULL) {
+ printf("Client version string not parsed: ");
+ goto end;
+ }
+
+ if (ssh_state->cli_hdr.proto_version == NULL) {
+ printf("Client version string not parsed: ");
+ goto end;
+ }
+
+ if (strncmp((char*)ssh_state->cli_hdr.software_version, "MySSHClient-0.5.1", strlen("MySSHClient-0.5.1")) != 0) {
+ printf("Client version string not parsed correctly: ");
+ goto end;
+ }
+
+ if (strncmp((char*)ssh_state->cli_hdr.proto_version, "2.0", strlen("2.0")) != 0) {
+ printf("Client version string not parsed correctly: ");
+ goto end;
+ }
+
+ result = 1;
+
+end:
+ if (alp_tctx != NULL)
+ AppLayerParserThreadCtxFree(alp_tctx);
+ StreamTcpFreeConfig(TRUE);
+ return result;
+}
+
+/** \test Send a version banner in three chunks. */
+static int SSHParserTest08(void)
+{
+ int result = 0;
+ Flow f;
+ uint8_t sshbuf1[] = "SSH-";
+ uint32_t sshlen1 = sizeof(sshbuf1) - 1;
+ uint8_t sshbuf2[] = "2.";
+ uint32_t sshlen2 = sizeof(sshbuf2) - 1;
+ uint8_t sshbuf3[] = { "0-MySSHClient-0.5.1\r\n"};
+ uint32_t sshlen3 = sizeof(sshbuf3) - 1;
+ TcpSession ssn;
+ AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
+
+ memset(&f, 0, sizeof(f));
+ memset(&ssn, 0, sizeof(ssn));
+ f.protoctx = (void *)&ssn;
+
+ StreamTcpInitConfig(TRUE);
+
+ SCMutexLock(&f.m);
+ int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1);
+ if (r != 0) {
+ printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf2, sshlen2);
+ if (r != 0) {
+ printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf3, sshlen3);
+ if (r != 0) {
+ printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+
+ SshState *ssh_state = f.alstate;
+ if (ssh_state == NULL) {
+ printf("no ssh state: ");
+ goto end;
+ }
+
+ if ( !(ssh_state->cli_hdr.flags & SSH_FLAG_VERSION_PARSED)) {
+ printf("Client version string not parsed: ");
+ goto end;
+ }
+
+ if (ssh_state->cli_hdr.software_version == NULL) {
+ printf("Client version string not parsed: ");
+ goto end;
+ }
+
+ if (ssh_state->cli_hdr.proto_version == NULL) {
+ printf("Client version string not parsed: ");
+ goto end;
+ }
+
+ if (strncmp((char*)ssh_state->cli_hdr.software_version, "MySSHClient-0.5.1", strlen("MySSHClient-0.5.1")) != 0) {
+ printf("Client version string not parsed correctly: ");
+ goto end;
+ }
+
+ if (strncmp((char*)ssh_state->cli_hdr.proto_version, "2.0", strlen("2.0")) != 0) {
+ printf("Client version string not parsed correctly: ");
+ goto end;
+ }
+
+ result = 1;
+end:
+ if (alp_tctx != NULL)
+ AppLayerParserThreadCtxFree(alp_tctx);
+ StreamTcpFreeConfig(TRUE);
+ return result;
+}
+
+static int SSHParserTest09(void)
+{
+ int result = 0;
+ Flow f;
+ uint8_t sshbuf1[] = "SSH-2.";
+ uint32_t sshlen1 = sizeof(sshbuf1) - 1;
+ uint8_t sshbuf2[] = { "0-MySSHClient-0.5.1\r\n"};
+ uint32_t sshlen2 = sizeof(sshbuf2) - 1;
+ TcpSession ssn;
+ AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
+
+ memset(&f, 0, sizeof(f));
+ memset(&ssn, 0, sizeof(ssn));
+ f.protoctx = (void *)&ssn;
+
+ StreamTcpInitConfig(TRUE);
+
+ SCMutexLock(&f.m);
+ int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf1, sshlen1);
+ if (r != 0) {
+ printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf2, sshlen2);
+ if (r != 0) {
+ printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+
+ SshState *ssh_state = f.alstate;
+ if (ssh_state == NULL) {
+ printf("no ssh state: ");
+ goto end;
+ }
+
+ if (!(ssh_state->srv_hdr.flags & SSH_FLAG_VERSION_PARSED)) {
+ printf("Client version string not parsed: ");
+ goto end;
+ }
+
+ if (ssh_state->srv_hdr.software_version == NULL) {
+ printf("Client version string not parsed: ");
+ goto end;
+ }
+
+ if (ssh_state->srv_hdr.proto_version == NULL) {
+ printf("Client version string not parsed: ");
+ goto end;
+ }
+
+ if (strncmp((char*)ssh_state->srv_hdr.software_version, "MySSHClient-0.5.1", strlen("MySSHClient-0.5.1")) != 0) {
+ printf("Client version string not parsed correctly: ");
+ goto end;
+ }
+
+ if (strncmp((char*)ssh_state->srv_hdr.proto_version, "2.0", strlen("2.0")) != 0) {
+ printf("Client version string not parsed correctly: ");
+ goto end;
+ }
+
+ result = 1;
+
+end:
+ if (alp_tctx != NULL)
+ AppLayerParserThreadCtxFree(alp_tctx);
+ StreamTcpFreeConfig(TRUE);
+ return result;
+}
+
+/** \test Send a version banner in three chunks. */
+static int SSHParserTest10(void)
+{
+ int result = 0;
+ Flow f;
+ uint8_t sshbuf1[] = "SSH-";
+ uint32_t sshlen1 = sizeof(sshbuf1) - 1;
+ uint8_t sshbuf2[] = "2.";
+ uint32_t sshlen2 = sizeof(sshbuf2) - 1;
+ uint8_t sshbuf3[] = { "0-MySSHClient-0.5.1\r\n"};
+ uint32_t sshlen3 = sizeof(sshbuf3) - 1;
+ TcpSession ssn;
+ AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
+
+ memset(&f, 0, sizeof(f));
+ memset(&ssn, 0, sizeof(ssn));
+ f.protoctx = (void *)&ssn;
+
+ StreamTcpInitConfig(TRUE);
+
+ SCMutexLock(&f.m);
+ int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf1, sshlen1);
+ if (r != 0) {
+ printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf2, sshlen2);
+ if (r != 0) {
+ printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf3, sshlen3);
+ if (r != 0) {
+ printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+
+ SshState *ssh_state = f.alstate;
+ if (ssh_state == NULL) {
+ printf("no ssh state: ");
+ goto end;
+ }
+
+ if (!(ssh_state->srv_hdr.flags & SSH_FLAG_VERSION_PARSED)) {
+ printf("Client version string not parsed: ");
+ goto end;
+ }
+
+ if (ssh_state->srv_hdr.software_version == NULL) {
+ printf("Client version string not parsed: ");
+ goto end;
+ }
+
+ if (ssh_state->srv_hdr.proto_version == NULL) {
+ printf("Client version string not parsed: ");
+ goto end;
+ }
+
+ if (strncmp((char*)ssh_state->srv_hdr.software_version, "MySSHClient-0.5.1", strlen("MySSHClient-0.5.1")) != 0) {
+ printf("Client version string not parsed correctly: ");
+ goto end;
+ }
+
+ if (strncmp((char*)ssh_state->srv_hdr.proto_version, "2.0", strlen("2.0")) != 0) {
+ printf("Client version string not parsed correctly: ");
+ goto end;
+ }
+
+ result = 1;
+end:
+ if (alp_tctx != NULL)
+ AppLayerParserThreadCtxFree(alp_tctx);
+ StreamTcpFreeConfig(TRUE);
+ return result;
+}
+
+/** \test Send a banner and record in three chunks. */
+static int SSHParserTest11(void)
+{
+ int result = 0;
+ Flow f;
+ uint8_t sshbuf1[] = "SSH-2.0-MySSHClient-0.5.1\r\n";
+ uint32_t sshlen1 = sizeof(sshbuf1) - 1;
+ uint8_t sshbuf2[] = { 0x00, 0x00, 0x00, 0x03, 0x01, 21, 0x00};
+ uint32_t sshlen2 = sizeof(sshbuf2);
+ TcpSession ssn;
+ AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
+
+ memset(&f, 0, sizeof(f));
+ memset(&ssn, 0, sizeof(ssn));
+ f.protoctx = (void *)&ssn;
+
+ StreamTcpInitConfig(TRUE);
+
+ SCMutexLock(&f.m);
+ int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1);
+ if (r != 0) {
+ printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf2, sshlen2);
+ if (r != 0) {
+ printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+
+ SshState *ssh_state = f.alstate;
+ if (ssh_state == NULL) {
+ printf("no ssh state: ");
+ goto end;
+ }
+
+ if ( !(ssh_state->cli_hdr.flags & SSH_FLAG_VERSION_PARSED)) {
+ printf("Client version string not parsed: ");
+ goto end;
+ }
+
+ if (ssh_state->cli_hdr.software_version == NULL) {
+ printf("Client version string not parsed: ");
+ goto end;
+ }
+
+ if (ssh_state->cli_hdr.proto_version == NULL) {
+ printf("Client version string not parsed: ");
+ goto end;
+ }
+
+ if (strncmp((char*)ssh_state->cli_hdr.software_version, "MySSHClient-0.5.1", strlen("MySSHClient-0.5.1")) != 0) {
+ printf("Client version string not parsed correctly: ");
+ goto end;
+ }
+
+ if (strncmp((char*)ssh_state->cli_hdr.proto_version, "2.0", strlen("2.0")) != 0) {
+ printf("Client version string not parsed correctly: ");
+ goto end;
+ }
+
+ if ( !(ssh_state->cli_hdr.flags & SSH_FLAG_PARSER_DONE)) {
+ printf("Didn't detect the msg code of new keys (ciphered data starts): ");
+ goto end;
+ }
+
+ result = 1;
+end:
+ if (alp_tctx != NULL)
+ AppLayerParserThreadCtxFree(alp_tctx);
+ StreamTcpFreeConfig(TRUE);
+ return result;
+}
+
+/** \test Send a banner and 2 records record in four chunks. */
+static int SSHParserTest12(void)
+{
+ int result = 0;
+ Flow f;
+ uint8_t sshbuf1[] = "SSH-2.0-MySSHClient-0.5.1\r\n";
+ uint32_t sshlen1 = sizeof(sshbuf1) - 1;
+ uint8_t sshbuf2[] = { 0x00, 0x00, 0x00, 0x03,0x01, 17, 0x00};
+ uint32_t sshlen2 = sizeof(sshbuf2);
+ uint8_t sshbuf3[] = { 0x00, 0x00, 0x00, 0x03,0x01, 21, 0x00};
+ uint32_t sshlen3 = sizeof(sshbuf3);
+ TcpSession ssn;
+ AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
+
+ memset(&f, 0, sizeof(f));
+ memset(&ssn, 0, sizeof(ssn));
+ f.protoctx = (void *)&ssn;
+
+ StreamTcpInitConfig(TRUE);
+
+ SCMutexLock(&f.m);
+ int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1);
+ if (r != 0) {
+ printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf2, sshlen2);
+ if (r != 0) {
+ printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf3, sshlen3);
+ if (r != 0) {
+ printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+
+ SshState *ssh_state = f.alstate;
+ if (ssh_state == NULL) {
+ printf("no ssh state: ");
+ goto end;
+ }
+
+ if ( !(ssh_state->cli_hdr.flags & SSH_FLAG_VERSION_PARSED)) {
+ printf("Client version string not parsed: ");
+ goto end;
+ }
+
+ if (ssh_state->cli_hdr.software_version == NULL) {
+ printf("Client version string not parsed: ");
+ goto end;
+ }
+
+ if (ssh_state->cli_hdr.proto_version == NULL) {
+ printf("Client version string not parsed: ");
+ goto end;
+ }
+
+ if (strncmp((char*)ssh_state->cli_hdr.software_version, "MySSHClient-0.5.1", strlen("MySSHClient-0.5.1")) != 0) {
+ printf("Client version string not parsed correctly: ");
+ goto end;
+ }
+
+ if (strncmp((char*)ssh_state->cli_hdr.proto_version, "2.0", strlen("2.0")) != 0) {
+ printf("Client version string not parsed correctly: ");
+ goto end;
+ }
+
+ if ( !(ssh_state->cli_hdr.flags & SSH_FLAG_PARSER_DONE)) {
+ printf("Didn't detect the msg code of new keys (ciphered data starts): ");
+ goto end;
+ }
+
+ result = 1;
+end:
+ if (alp_tctx != NULL)
+ AppLayerParserThreadCtxFree(alp_tctx);
+ StreamTcpFreeConfig(TRUE);
+ return result;
+}
+
+/** \test Send a banner and 2 records record in four chunks. */
+static int SSHParserTest13(void)
+{
+ int result = 0;
+ Flow f;
+ uint8_t sshbuf1[] = "SSH-2.0-MySSHClient-0.5.1\r\n";
+ uint32_t sshlen1 = sizeof(sshbuf1) - 1;
+ uint8_t sshbuf2[] = { 0x00, 0x00, 0x00, 0x02, 0x01, 17};
+ uint32_t sshlen2 = sizeof(sshbuf2);
+ uint8_t sshbuf3[] = { 0x00, 0x00, 0x00, 0x02, 0x01, 21};
+ uint32_t sshlen3 = sizeof(sshbuf3);
+ TcpSession ssn;
+ AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
+ uint32_t u;
+
+ memset(&f, 0, sizeof(f));
+ memset(&ssn, 0, sizeof(ssn));
+ f.protoctx = (void *)&ssn;
+
+ StreamTcpInitConfig(TRUE);
+
+ SCMutexLock(&f.m);
+ int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1);
+ if (r != 0) {
+ printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ for (u = 0; u < sshlen2; u++) {
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, &sshbuf2[u], 1);
+ if (r != 0) {
+ printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ }
+ for (u = 0; u < sshlen3; u++) {
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, &sshbuf3[u], 1);
+ if (r != 0) {
+ printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ }
+ SshState *ssh_state = f.alstate;
+ if (ssh_state == NULL) {
+ printf("no ssh state: ");
+ goto end;
+ }
+
+ if ( !(ssh_state->cli_hdr.flags & SSH_FLAG_VERSION_PARSED)) {
+ printf("Client version string not parsed: ");
+ goto end;
+ }
+
+ if (ssh_state->cli_hdr.software_version == NULL) {
+ printf("Client version string not parsed: ");
+ goto end;
+ }
+
+ if (ssh_state->cli_hdr.proto_version == NULL) {
+ printf("Client version string not parsed: ");
+ goto end;
+ }
+
+ if (strncmp((char*)ssh_state->cli_hdr.software_version, "MySSHClient-0.5.1", strlen("MySSHClient-0.5.1")) != 0) {
+ printf("Client version string not parsed correctly: ");
+ goto end;
+ }
+
+ if (strncmp((char*)ssh_state->cli_hdr.proto_version, "2.0", strlen("2.0")) != 0) {
+ printf("Client version string not parsed correctly: ");
+ goto end;
+ }
+
+ if ( !(ssh_state->cli_hdr.flags & SSH_FLAG_PARSER_DONE)) {
+ printf("Didn't detect the msg code of new keys (ciphered data starts): ");
+ goto end;
+ }
+
+ result = 1;
+end:
+ if (alp_tctx != NULL)
+ AppLayerParserThreadCtxFree(alp_tctx);
+ StreamTcpFreeConfig(TRUE);
+ return result;
+}
+
+/** \test Send a banner and 2 records record in four chunks. */
+static int SSHParserTest14(void)
+{
+ int result = 0;
+ Flow f;
+ uint8_t sshbuf1[] = "SSH-2.0-MySSHClient-0.5.1\r\n";
+ uint32_t sshlen1 = sizeof(sshbuf1) - 1;
+ uint8_t sshbuf2[] = { 0x00, 0x00, 0x00, 0x10, 0x01, 17, 0x00};
+ uint32_t sshlen2 = sizeof(sshbuf2);
+
+ uint8_t sshbuf3[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
+ uint32_t sshlen3 = sizeof(sshbuf3);
+ uint8_t sshbuf4[] = { 0x09, 0x10, 0x11, 0x12, 0x13, 0x00};
+ uint32_t sshlen4 = sizeof(sshbuf4);
+
+ /* first byte of this record in sshbuf4 */
+ uint8_t sshbuf5[] = { 0x00, 0x00, 0x02, 0x01, 21};
+ uint32_t sshlen5 = sizeof(sshbuf5);
+ TcpSession ssn;
+ AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
+
+ memset(&f, 0, sizeof(f));
+ memset(&ssn, 0, sizeof(ssn));
+ f.protoctx = (void *)&ssn;
+
+ StreamTcpInitConfig(TRUE);
+
+ SCMutexLock(&f.m);
+ int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1);
+ if (r != 0) {
+ printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf2, sshlen2);
+ if (r != 0) {
+ printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf3, sshlen3);
+ if (r != 0) {
+ printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf4, sshlen4);
+ if (r != 0) {
+ printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf5, sshlen5);
+ if (r != 0) {
+ printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+
+ SshState *ssh_state = f.alstate;
+ if (ssh_state == NULL) {
+ printf("no ssh state: ");
+ goto end;
+ }
+
+ if ( !(ssh_state->cli_hdr.flags & SSH_FLAG_VERSION_PARSED)) {
+ printf("Client version string not parsed: ");
+ goto end;
+ }
+
+ if (ssh_state->cli_hdr.software_version == NULL) {
+ printf("Client version string not parsed: ");
+ goto end;
+ }
+
+ if (ssh_state->cli_hdr.proto_version == NULL) {
+ printf("Client version string not parsed: ");
+ goto end;
+ }
+
+ if (strncmp((char*)ssh_state->cli_hdr.software_version, "MySSHClient-0.5.1", strlen("MySSHClient-0.5.1")) != 0) {
+ printf("Client version string not parsed correctly: ");
+ goto end;
+ }
+
+ if (strncmp((char*)ssh_state->cli_hdr.proto_version, "2.0", strlen("2.0")) != 0) {
+ printf("Client version string not parsed correctly: ");
+ goto end;
+ }
+
+ if ( !(ssh_state->cli_hdr.flags & SSH_FLAG_PARSER_DONE)) {
+ printf("Didn't detect the msg code of new keys (ciphered data starts): ");
+ goto end;
+ }
+
+ result = 1;
+end:
+ if (alp_tctx != NULL)
+ AppLayerParserThreadCtxFree(alp_tctx);
+ StreamTcpFreeConfig(TRUE);
+ return result;
+}
+
+/** \test Send a banner and 2 records record in four chunks. */
+static int SSHParserTest15(void)
+{
+ int result = 0;
+ Flow f;
+ uint8_t sshbuf1[] = "SSH-2.0-MySSHClient-0.5.1\r\n";
+ uint32_t sshlen1 = sizeof(sshbuf1) - 1;
+ uint8_t sshbuf2[] = { 0x00, 0x00, 0x00, 0x10, 0x01, 17, 0x00};
+ uint32_t sshlen2 = sizeof(sshbuf2);
+
+ uint8_t sshbuf3[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
+ uint32_t sshlen3 = sizeof(sshbuf3);
+ uint8_t sshbuf4[] = { 0x09, 0x10, 0x11, 0x12, 0x13, 0x00};
+ uint32_t sshlen4 = sizeof(sshbuf4);
+
+ /* first byte of this record in sshbuf4 */
+ uint8_t sshbuf5[] = { 0x00, 0x00, 0x02, 0x01, 20, 0x00, 0x00, 0x00, 0x02, 0x01, 21};
+ uint32_t sshlen5 = sizeof(sshbuf5);
+ TcpSession ssn;
+ AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
+
+ memset(&f, 0, sizeof(f));
+ memset(&ssn, 0, sizeof(ssn));
+ f.protoctx = (void *)&ssn;
+
+ StreamTcpInitConfig(TRUE);
+
+ SCMutexLock(&f.m);
+ int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1);
+ if (r != 0) {
+ printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf2, sshlen2);
+ if (r != 0) {
+ printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf3, sshlen3);
+ if (r != 0) {
+ printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf4, sshlen4);
+ if (r != 0) {
+ printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf5, sshlen5);
+ if (r != 0) {
+ printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+
+ SshState *ssh_state = f.alstate;
+ if (ssh_state == NULL) {
+ printf("no ssh state: ");
+ goto end;
+ }
+
+ if ( !(ssh_state->cli_hdr.flags & SSH_FLAG_VERSION_PARSED)) {
+ printf("Client version string not parsed: ");
+ goto end;
+ }
+
+ if (ssh_state->cli_hdr.software_version == NULL) {
+ printf("Client version string not parsed: ");
+ goto end;
+ }
+
+ if (ssh_state->cli_hdr.proto_version == NULL) {
+ printf("Client version string not parsed: ");
+ goto end;
+ }
+
+ if (strncmp((char*)ssh_state->cli_hdr.software_version, "MySSHClient-0.5.1", strlen("MySSHClient-0.5.1")) != 0) {
+ printf("Client version string not parsed correctly: ");
+ goto end;
+ }
+
+ if (strncmp((char*)ssh_state->cli_hdr.proto_version, "2.0", strlen("2.0")) != 0) {
+ printf("Client version string not parsed correctly: ");
+ goto end;
+ }
+
+ if ( !(ssh_state->cli_hdr.flags & SSH_FLAG_PARSER_DONE)) {
+ printf("Didn't detect the msg code of new keys (ciphered data starts): ");
+ goto end;
+ }
+
+ result = 1;
+end:
+ if (alp_tctx != NULL)
+ AppLayerParserThreadCtxFree(alp_tctx);
+ StreamTcpFreeConfig(TRUE);
+ return result;
+}
+
+/** \test Send toserver a banner and record in three chunks. */
+static int SSHParserTest16(void)
+{
+ int result = 0;
+ Flow f;
+ uint8_t sshbuf1[] = "SSH-";
+ uint32_t sshlen1 = sizeof(sshbuf1) - 1;
+ uint8_t sshbuf2[] = "2.0-MySSHClient-0.5.1\r\n";
+ uint32_t sshlen2 = sizeof(sshbuf2) - 1;
+ uint8_t sshbuf3[] = { 0x00, 0x00, 0x00, 0x03,0x01, 21, 0x00};
+ uint32_t sshlen3 = sizeof(sshbuf3);
+ TcpSession ssn;
+ AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
+
+ memset(&f, 0, sizeof(f));
+ memset(&ssn, 0, sizeof(ssn));
+ f.protoctx = (void *)&ssn;
+
+ StreamTcpInitConfig(TRUE);
+
+ SCMutexLock(&f.m);
+ int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf1, sshlen1);
+ if (r != 0) {
+ printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf2, sshlen2);
+ if (r != 0) {
+ printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf3, sshlen3);
+ if (r != 0) {
+ printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+
+ SshState *ssh_state = f.alstate;
+ if (ssh_state == NULL) {
+ printf("no ssh state: ");
+ goto end;
+ }
+
+ if (!(ssh_state->srv_hdr.flags & SSH_FLAG_VERSION_PARSED)) {
+ printf("Client version string not parsed: ");
+ goto end;
+ }
+
+ if (ssh_state->srv_hdr.software_version == NULL) {
+ printf("Client version string not parsed: ");
+ goto end;
+ }
+
+ if (ssh_state->srv_hdr.proto_version == NULL) {
+ printf("Client version string not parsed: ");
+ goto end;
+ }
+
+ if (strncmp((char*)ssh_state->srv_hdr.software_version, "MySSHClient-0.5.1", strlen("MySSHClient-0.5.1")) != 0) {
+ printf("Client version string not parsed correctly: ");
+ goto end;
+ }
+
+ if (strncmp((char*)ssh_state->srv_hdr.proto_version, "2.0", strlen("2.0")) != 0) {
+ printf("Client version string not parsed correctly: ");
+ goto end;
+ }
+
+ if ( !(ssh_state->srv_hdr.flags & SSH_FLAG_PARSER_DONE)) {
+ printf("Didn't detect the msg code of new keys (ciphered data starts): ");
+ goto end;
+ }
+
+ result = 1;
+end:
+ if (alp_tctx != NULL)
+ AppLayerParserThreadCtxFree(alp_tctx);
+ StreamTcpFreeConfig(TRUE);
+ return result;
+}
+
+/** \test Send toserver a banner and 2 records record in four chunks. */
+static int SSHParserTest17(void)
+{
+ int result = 0;
+ Flow f;
+ uint8_t sshbuf1[] = "SSH-";
+ uint32_t sshlen1 = sizeof(sshbuf1) - 1;
+ uint8_t sshbuf2[] = "2.0-MySSHClient-0.5.1\r\n";
+ uint32_t sshlen2 = sizeof(sshbuf2) - 1;
+ uint8_t sshbuf3[] = { 0x00, 0x00, 0x00, 0x03, 0x01, 17, 0x00};
+ uint32_t sshlen3 = sizeof(sshbuf3);
+ uint8_t sshbuf4[] = { 0x00, 0x00, 0x00, 0x03, 0x01, 21, 0x00};
+ uint32_t sshlen4 = sizeof(sshbuf4);
+ TcpSession ssn;
+ AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
+
+ memset(&f, 0, sizeof(f));
+ memset(&ssn, 0, sizeof(ssn));
+ f.protoctx = (void *)&ssn;
+
+ StreamTcpInitConfig(TRUE);
+
+ SCMutexLock(&f.m);
+ int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf1, sshlen1);
+ if (r != 0) {
+ printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf2, sshlen2);
+ if (r != 0) {
+ printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf3, sshlen3);
+ if (r != 0) {
+ printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf4, sshlen4);
+ if (r != 0) {
+ printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+
+ SshState *ssh_state = f.alstate;
+ if (ssh_state == NULL) {
+ printf("no ssh state: ");
+ goto end;
+ }
+
+ if (!(ssh_state->srv_hdr.flags & SSH_FLAG_VERSION_PARSED)) {
+ printf("Client version string not parsed: ");
+ goto end;
+ }
+
+ if (ssh_state->srv_hdr.software_version == NULL) {
+ printf("Client version string not parsed: ");
+ goto end;
+ }
+
+ if (ssh_state->srv_hdr.proto_version == NULL) {
+ printf("Client version string not parsed: ");
+ goto end;
+ }
+
+ if (strncmp((char*)ssh_state->srv_hdr.software_version, "MySSHClient-0.5.1", strlen("MySSHClient-0.5.1")) != 0) {
+ printf("Client version string not parsed correctly: ");
+ goto end;
+ }
+
+ if (strncmp((char*)ssh_state->srv_hdr.proto_version, "2.0", strlen("2.0")) != 0) {
+ printf("Client version string not parsed correctly: ");
+ goto end;
+ }
+
+ if ( !(ssh_state->srv_hdr.flags & SSH_FLAG_PARSER_DONE)) {
+ printf("Didn't detect the msg code of new keys (ciphered data starts): ");
+ goto end;
+ }
+
+ result = 1;
+end:
+ if (alp_tctx != NULL)
+ AppLayerParserThreadCtxFree(alp_tctx);
+ StreamTcpFreeConfig(TRUE);
+ return result;
+}
+
+/** \test 2 directional test */
+static int SSHParserTest18(void)
+{
+ int result = 0;
+ Flow f;
+
+ uint8_t server1[] = "SSH-2.0-OpenSSH_4.7p1 Debian-8ubuntu3\r\n";
+ uint32_t serverlen1 = sizeof(server1) - 1;
+
+ uint8_t sshbuf1[] = "SSH-";
+ uint32_t sshlen1 = sizeof(sshbuf1) - 1;
+ uint8_t sshbuf2[] = "2.0-MySSHClient-0.5.1\r\n";
+ uint32_t sshlen2 = sizeof(sshbuf2) - 1;
+
+ uint8_t server2[] = { 0x00, 0x00, 0x00, 0x03, 0x01, 21, 0x00 };
+ uint32_t serverlen2 = sizeof(server2) - 1;
+
+ uint8_t sshbuf3[] = { 0x00, 0x00, 0x00, 0x03, 0x01, 21, 0x00 };
+ uint32_t sshlen3 = sizeof(sshbuf3);
+
+
+ TcpSession ssn;
+ AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
+
+ memset(&f, 0, sizeof(f));
+ memset(&ssn, 0, sizeof(ssn));
+ f.protoctx = (void *)&ssn;
+
+ StreamTcpInitConfig(TRUE);
+
+ SCMutexLock(&f.m);
+ int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, server1, serverlen1);
+ if (r != 0) {
+ printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1);
+ if (r != 0) {
+ printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf2, sshlen2);
+ if (r != 0) {
+ printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, server2, serverlen2);
+ if (r != 0) {
+ printf("toclient chunk 2 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf3, sshlen3);
+ if (r != 0) {
+ printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+
+ SshState *ssh_state = f.alstate;
+ if (ssh_state == NULL) {
+ printf("no ssh state: ");
+ goto end;
+ }
+
+ if ( !(ssh_state->cli_hdr.flags & SSH_FLAG_PARSER_DONE)) {
+ printf("Didn't detect the msg code of new keys (ciphered data starts): ");
+ goto end;
+ }
+
+ if ( !(ssh_state->srv_hdr.flags & SSH_FLAG_PARSER_DONE)) {
+ printf("Didn't detect the msg code of new keys (ciphered data starts): ");
+ goto end;
+ }
+
+ if (!(AppLayerParserStateIssetFlag(f.alparser, APP_LAYER_PARSER_NO_INSPECTION))) {
+ printf("detection not disabled: ");
+ goto end;
+ }
+
+ result = 1;
+end:
+ if (alp_tctx != NULL)
+ AppLayerParserThreadCtxFree(alp_tctx);
+ StreamTcpFreeConfig(TRUE);
+ return result;
+}
+
+/** \test Really long banner handling: bannel exactly 255 */
+static int SSHParserTest19(void)
+{
+ int result = 0;
+ Flow f;
+ uint8_t sshbuf1[] = "SSH-";
+ uint32_t sshlen1 = sizeof(sshbuf1) - 1;
+ uint8_t sshbuf2[] = "2.0-";
+ uint32_t sshlen2 = sizeof(sshbuf2) - 1; // 8
+ uint8_t sshbuf3[] = "abcdefghijklmnopqrstuvwxyz"
+ "abcdefghijklmnopqrstuvwxyz"//60
+ "abcdefghijklmnopqrstuvwxyz"
+ "abcdefghijklmnopqrstuvwxyz"//112
+ "abcdefghijklmnopqrstuvwxyz"
+ "abcdefghijklmnopqrstuvwxyz"//164
+ "abcdefghijklmnopqrstuvwxyz"
+ "abcdefghijklmnopqrstuvwxyz"//216
+ "abcdefghijklmnopqrstuvwxyz"//242
+ "abcdefghijkl\r";//255
+ uint32_t sshlen3 = sizeof(sshbuf3) - 1;
+
+ uint8_t sshbuf4[] = { 0x00, 0x00, 0x00, 0x03, 0x01, 21, 0x00};
+ uint32_t sshlen4 = sizeof(sshbuf4);
+ TcpSession ssn;
+ AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
+
+ memset(&f, 0, sizeof(f));
+ memset(&ssn, 0, sizeof(ssn));
+ f.protoctx = (void *)&ssn;
+
+ StreamTcpInitConfig(TRUE);
+
+ SCMutexLock(&f.m);
+ int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf1, sshlen1);
+ if (r != 0) {
+ printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf2, sshlen2);
+ if (r != 0) {
+ printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf3, sshlen3);
+ if (r != 0) {
+ printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf4, sshlen4);
+ if (r != 0) {
+ printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+
+ SshState *ssh_state = f.alstate;
+ if (ssh_state == NULL) {
+ printf("no ssh state: ");
+ goto end;
+ }
+
+ if (!(ssh_state->srv_hdr.flags & SSH_FLAG_VERSION_PARSED)) {
+ printf("Client version string not parsed: ");
+ goto end;
+ }
+
+ if (ssh_state->srv_hdr.software_version == NULL) {
+ printf("Client version string not parsed: ");
+ goto end;
+ }
+
+ if (ssh_state->srv_hdr.proto_version == NULL) {
+ printf("Client version string not parsed: ");
+ goto end;
+ }
+
+ char *name = SCMalloc(256);
+ if (name == NULL)
+ goto end;
+ memset(name, 0x00, 256);
+ strlcpy(name, (char *)sshbuf3, strlen((char *)sshbuf3) - 1);
+
+ if (strncmp((char*)ssh_state->srv_hdr.software_version, name, strlen(name)) != 0) {
+ printf("Client version string not parsed correctly: ");
+ goto end;
+ }
+
+ if (strncmp((char*)ssh_state->srv_hdr.proto_version, "2.0", strlen("2.0")) != 0) {
+ printf("Client version string not parsed correctly: ");
+ goto end;
+ }
+
+ if ( !(ssh_state->srv_hdr.flags & SSH_FLAG_PARSER_DONE)) {
+ printf("Didn't detect the msg code of new keys (ciphered data starts): ");
+ goto end;
+ }
+
+ result = 1;
+end:
+ if (alp_tctx != NULL)
+ AppLayerParserThreadCtxFree(alp_tctx);
+ StreamTcpFreeConfig(TRUE);
+ return result;
+}
+
+/** \test Really long banner handling: banner exactly 255,
+ * followed by malformed record */
+static int SSHParserTest20(void)
+{
+ int result = 0;
+ Flow f;
+ uint8_t sshbuf1[] = "SSH-";
+ uint32_t sshlen1 = sizeof(sshbuf1) - 1;
+ uint8_t sshbuf2[] = "2.0-";
+ uint32_t sshlen2 = sizeof(sshbuf2) - 1; // 8
+ uint8_t sshbuf3[] = "abcdefghijklmnopqrstuvwxyz"
+ "abcdefghijklmnopqrstuvwxyz"//60
+ "abcdefghijklmnopqrstuvwxyz"
+ "abcdefghijklmnopqrstuvwxyz"//112
+ "abcdefghijklmnopqrstuvwxyz"
+ "abcdefghijklmnopqrstuvwxyz"//164
+ "abcdefghijklmnopqrstuvwxyz"
+ "abcdefghijklmnopqrstuvwxyz"//216
+ "abcdefghijklmnopqrstuvwxyz"//242
+ "abcdefghijklm\r";//256
+ uint32_t sshlen3 = sizeof(sshbuf3) - 1;
+ uint8_t sshbuf4[] = {'a','b','c','d','e','f', '\r',
+ 0x00, 0x00, 0x00, 0x06, 0x01, 21, 0x00, 0x00, 0x00};
+ uint32_t sshlen4 = sizeof(sshbuf4) - 1;
+
+ TcpSession ssn;
+ AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
+
+ memset(&f, 0, sizeof(f));
+ memset(&ssn, 0, sizeof(ssn));
+ f.protoctx = (void *)&ssn;
+
+ StreamTcpInitConfig(TRUE);
+
+ SCMutexLock(&f.m);
+ int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf1, sshlen1);
+ if (r != 0) {
+ printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf2, sshlen2);
+ if (r != 0) {
+ printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf3, sshlen3);
+ if (r != 0) {
+ printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+
+ SCLogDebug("chunk 4:");
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf4, sshlen4);
+ if (r != 0) {
+ printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+
+ SshState *ssh_state = f.alstate;
+ if (ssh_state == NULL) {
+ printf("no ssh state: ");
+ goto end;
+ }
+
+ if (!(ssh_state->srv_hdr.flags & SSH_FLAG_VERSION_PARSED)) {
+ printf("Client version string not parsed: ");
+ goto end;
+ }
+
+ if (ssh_state->srv_hdr.software_version == NULL) {
+ printf("Client version string not parsed: ");
+ goto end;
+ }
+
+ if (ssh_state->srv_hdr.proto_version == NULL) {
+ printf("Client version string not parsed: ");
+ goto end;
+ }
+
+ if (strncmp((char*)ssh_state->srv_hdr.proto_version, "2.0", strlen("2.0")) != 0) {
+ printf("Client version string not parsed correctly: ");
+ goto end;
+ }
+
+ if ((ssh_state->srv_hdr.flags & SSH_FLAG_PARSER_DONE)) {
+ printf("detected the msg code of new keys (ciphered data starts): ");
+ goto end;
+ }
+ result = 1;
+end:
+ if (alp_tctx != NULL)
+ AppLayerParserThreadCtxFree(alp_tctx);
+ StreamTcpFreeConfig(TRUE);
+ return result;
+}
+
+/** \test Fragmented banner handling: chunk has final part of bannel plus
+ * a record. */
+static int SSHParserTest21(void)
+{
+ int result = 0;
+ Flow f;
+ uint8_t sshbuf1[] = "SSH-";
+ uint32_t sshlen1 = sizeof(sshbuf1) - 1;
+ uint8_t sshbuf2[] = "2.0-";
+ uint32_t sshlen2 = sizeof(sshbuf2) - 1; // 8
+ uint8_t sshbuf3[] = "abcdefghijklmnopqrstuvwxyz"
+ "abcdefghijklmnopqrstuvwxyz"//60
+ "abcdefghijklmnopqrstuvwxyz"
+ "abcdefghijklmnopqrstuvwxyz"//112
+ "abcdefghijklmnopqrstuvwxyz"
+ "abcdefghijklmnopqrstuvwxyz"//164
+ "abcdefghijklmnopqrstuvwxyz"
+ "abcdefghijklmnopqrstuvwxyz"//216
+ "abcdefghijklmnopqrstuvwxy";//241
+ uint32_t sshlen3 = sizeof(sshbuf3) - 1;
+ uint8_t sshbuf4[] = {'l','i','b','s','s','h', '\r',
+ 0x00, 0x00, 0x00, 0x06, 0x01, 21, 0x00, 0x00, 0x00};
+ uint32_t sshlen4 = sizeof(sshbuf4) - 1;
+ TcpSession ssn;
+ AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
+
+ memset(&f, 0, sizeof(f));
+ memset(&ssn, 0, sizeof(ssn));
+ f.protoctx = (void *)&ssn;
+
+ StreamTcpInitConfig(TRUE);
+
+ SCMutexLock(&f.m);
+ int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf1, sshlen1);
+ if (r != 0) {
+ printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf2, sshlen2);
+ if (r != 0) {
+ printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf3, sshlen3);
+ if (r != 0) {
+ printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+
+ SCLogDebug("chunk 4:");
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf4, sshlen4);
+ if (r != 0) {
+ printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+
+ SshState *ssh_state = f.alstate;
+ if (ssh_state == NULL) {
+ printf("no ssh state: ");
+ goto end;
+ }
+
+ if (!(ssh_state->srv_hdr.flags & SSH_FLAG_VERSION_PARSED)) {
+ printf("Client version string not parsed: ");
+ goto end;
+ }
+
+ if (ssh_state->srv_hdr.software_version == NULL) {
+ printf("Client version string not parsed: ");
+ goto end;
+ }
+
+ if (ssh_state->srv_hdr.proto_version == NULL) {
+ printf("Client version string not parsed: ");
+ goto end;
+ }
+
+ if (strncmp((char*)ssh_state->srv_hdr.proto_version, "2.0", strlen("2.0")) != 0) {
+ printf("Client version string not parsed correctly: ");
+ goto end;
+ }
+
+ if ( !(ssh_state->srv_hdr.flags & SSH_FLAG_PARSER_DONE)) {
+ printf("Didn't detect the msg code of new keys (ciphered data starts): ");
+ goto end;
+ }
+
+ result = 1;
+end:
+ if (alp_tctx != NULL)
+ AppLayerParserThreadCtxFree(alp_tctx);
+ StreamTcpFreeConfig(TRUE);
+ return result;
+}
+
+/** \test Fragmented banner handling: chunk has final part of bannel plus
+ * a record. */
+static int SSHParserTest22(void)
+{
+ int result = 0;
+ Flow f;
+ uint8_t sshbuf1[] = "SSH-";
+ uint32_t sshlen1 = sizeof(sshbuf1) - 1;
+ uint8_t sshbuf2[] = "2.0-";
+ uint32_t sshlen2 = sizeof(sshbuf2) - 1; // 8
+ uint8_t sshbuf3[] = {
+ 'l', 'i', 'b', 's', 's', 'h', '\r', //7
+
+ 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, //50
+
+ 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, //100
+
+ 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, //150
+
+ 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, //200
+
+ 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, //250
+
+ 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x06, 0x01, 21, 0x00, 0x00, 0x00, 0x00, //300
+ };
+ uint32_t sshlen3 = sizeof(sshbuf3) - 1;
+ TcpSession ssn;
+ AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
+
+ memset(&f, 0, sizeof(f));
+ memset(&ssn, 0, sizeof(ssn));
+ f.protoctx = (void *)&ssn;
+
+ StreamTcpInitConfig(TRUE);
+
+ SCMutexLock(&f.m);
+ int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf1, sshlen1);
+ if (r != 0) {
+ printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf2, sshlen2);
+ if (r != 0) {
+ printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf3, sshlen3);
+ if (r != 0) {
+ printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+#if 0
+ SCLogDebug("chunk 4:");
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf4, sshlen4);
+ if (r != 0) {
+ printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+#endif
+ SshState *ssh_state = f.alstate;
+ if (ssh_state == NULL) {
+ printf("no ssh state: ");
+ goto end;
+ }
+
+ if (!(ssh_state->srv_hdr.flags & SSH_FLAG_VERSION_PARSED)) {
+ printf("Client version string not parsed: ");
+ goto end;
+ }
+
+ if (ssh_state->srv_hdr.software_version == NULL) {
+ printf("Client version string not parsed: ");
+ goto end;
+ }
+
+ if (ssh_state->srv_hdr.proto_version == NULL) {
+ printf("Client version string not parsed: ");
+ goto end;
+ }
+
+ if (strncmp((char*)ssh_state->srv_hdr.proto_version, "2.0", strlen("2.0")) != 0) {
+ printf("Client version string not parsed correctly: ");
+ goto end;
+ }
+
+ if ( !(ssh_state->srv_hdr.flags & SSH_FLAG_PARSER_DONE)) {
+ printf("Didn't detect the msg code of new keys (ciphered data starts): ");
+ goto end;
+ }
+
+ result = 1;
+end:
+ if (alp_tctx != NULL)
+ AppLayerParserThreadCtxFree(alp_tctx);
+ StreamTcpFreeConfig(TRUE);
+ return result;
+}
+
+/** \test Send a version string in one chunk (client version str). */
+static int SSHParserTest23(void)
+{
+ int result = 0;
+ Flow f;
+ uint8_t sshbuf[] = "SSH-2.0\r-MySSHClient-0.5.1\n";
+ uint32_t sshlen = sizeof(sshbuf) - 1;
+ TcpSession ssn;
+ AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
+
+ memset(&f, 0, sizeof(f));
+ memset(&ssn, 0, sizeof(ssn));
+ f.protoctx = (void *)&ssn;
+
+ StreamTcpInitConfig(TRUE);
+
+ SCMutexLock(&f.m);
+ int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER|STREAM_EOF, sshbuf, sshlen);
+ if (r == 0) {
+ printf("toclient chunk 1 returned 0 expected non null: ");
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+
+ result = 1;
+end:
+ if (alp_tctx != NULL)
+ AppLayerParserThreadCtxFree(alp_tctx);
+ StreamTcpFreeConfig(TRUE);
+ return result;
+}
+
+/** \test Send a version string in one chunk (client version str). */
+static int SSHParserTest24(void)
+{
+ int result = 0;
+ Flow f;
+ uint8_t sshbuf[] = "SSH-2.0-\rMySSHClient-0.5.1\n";
+ uint32_t sshlen = sizeof(sshbuf) - 1;
+ TcpSession ssn;
+ AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
+
+ memset(&f, 0, sizeof(f));
+ memset(&ssn, 0, sizeof(ssn));
+ f.protoctx = (void *)&ssn;
+
+ StreamTcpInitConfig(TRUE);
+
+ SCMutexLock(&f.m);
+ int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER|STREAM_EOF, sshbuf, sshlen);
+ if (r != 0) {
+ printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+
+ SshState *ssh_state = f.alstate;
+ if (ssh_state == NULL) {
+ printf("no ssh state: ");
+ goto end;
+ }
+
+ if ( !(ssh_state->cli_hdr.flags & SSH_FLAG_VERSION_PARSED)) {
+ printf("Client version string not parsed: ");
+ goto end;
+ }
+
+ if (ssh_state->cli_hdr.software_version) {
+ printf("Client version string should not be parsed: ");
+ goto end;
+ }
+
+ result = 1;
+end:
+ if (alp_tctx != NULL)
+ AppLayerParserThreadCtxFree(alp_tctx);
+ StreamTcpFreeConfig(TRUE);
+ return result;
+}
+
+
+#endif /* UNITTESTS */
+
+void SSHParserRegisterTests(void)
+{
+#ifdef UNITTESTS
+ UtRegisterTest("SSHParserTest01 - ToServer", SSHParserTest01, 1);
+ UtRegisterTest("SSHParserTest02 - ToServer", SSHParserTest02, 1);
+ UtRegisterTest("SSHParserTest03 - ToServer", SSHParserTest03, 1);
+ UtRegisterTest("SSHParserTest04 - ToClient", SSHParserTest04, 1);
+ UtRegisterTest("SSHParserTest05 - ToClient", SSHParserTest05, 1);
+ UtRegisterTest("SSHParserTest06 - ToClient", SSHParserTest06, 1);
+ UtRegisterTest("SSHParserTest07 - ToServer 2 chunks", SSHParserTest07, 1);
+ UtRegisterTest("SSHParserTest08 - ToServer 3 chunks", SSHParserTest08, 1);
+ UtRegisterTest("SSHParserTest09 - ToClient 2 chunks", SSHParserTest09, 1);
+ UtRegisterTest("SSHParserTest10 - ToClient 3 chunks", SSHParserTest10, 1);
+ UtRegisterTest("SSHParserTest11 - ToClient 4 chunks", SSHParserTest11, 1);
+ UtRegisterTest("SSHParserTest12 - ToClient 4 chunks", SSHParserTest12, 1);
+ UtRegisterTest("SSHParserTest13 - ToClient 4 chunks", SSHParserTest13, 1);
+ UtRegisterTest("SSHParserTest14 - ToClient 4 chunks", SSHParserTest14, 1);
+ UtRegisterTest("SSHParserTest15", SSHParserTest15, 1);
+ UtRegisterTest("SSHParserTest16", SSHParserTest16, 1);
+ UtRegisterTest("SSHParserTest17", SSHParserTest17, 1);
+ UtRegisterTest("SSHParserTest18", SSHParserTest18, 1);
+ UtRegisterTest("SSHParserTest19", SSHParserTest19, 1);
+ UtRegisterTest("SSHParserTest20", SSHParserTest20, 1);
+ UtRegisterTest("SSHParserTest21", SSHParserTest21, 1);
+ UtRegisterTest("SSHParserTest22", SSHParserTest22, 1);
+ UtRegisterTest("SSHParserTest23", SSHParserTest23, 1);
+ UtRegisterTest("SSHParserTest24", SSHParserTest24, 1);
+#endif /* UNITTESTS */
+}
+