suricata
app-layer-ssh.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2014 Open Information Security Foundation
2  *
3  * You can copy, redistribute or modify this Program under the terms of
4  * the GNU General Public License version 2 as published by the Free
5  * Software Foundation.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * version 2 along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15  * 02110-1301, USA.
16  */
17 
18 /**
19  * \file
20  *
21  * \author Pablo Rincon <pablo.rincon.crespo@gmail.com>
22  * \author Victor Julien <victor@inliniac.net>
23  *
24  * App-layer parser for SSH protocol
25  *
26  */
27 
28 #include "suricata-common.h"
29 #include "debug.h"
30 #include "decode.h"
31 #include "threads.h"
32 
33 #include "util-print.h"
34 #include "util-pool.h"
35 
36 #include "stream-tcp-private.h"
37 #include "stream-tcp-reassemble.h"
38 #include "stream-tcp.h"
39 #include "stream.h"
40 
41 #include "app-layer-protos.h"
42 #include "app-layer-parser.h"
43 #include "app-layer-ssh.h"
44 
45 #include "conf.h"
46 
47 #include "util-spm.h"
48 #include "util-unittest.h"
49 #include "util-debug.h"
50 #include "flow-private.h"
51 
52 #include "util-byte.h"
53 #include "util-memcmp.h"
54 
55 /** \internal
56  * \brief Function to parse the SSH version string of the client
57  *
58  * The input to this function is a byte buffer starting with SSH-
59  *
60  * \param ssh_state Pointer the state in which the value to be stored
61  * \param input Pointer the received input data
62  * \param input_len Length in bytes of the received data
63  *
64  * \retval len remaining length in input
65  */
66 static int SSHParseBanner(SshState *state, SshHeader *header, const uint8_t *input, uint32_t input_len)
67 {
68  const uint8_t *line_ptr = input;
69  uint32_t line_len = input_len;
70 
71  /* is it the version line? */
72  if (line_len >= 4 && SCMemcmp("SSH-", line_ptr, 4) != 0) {
73  SCReturnInt(-1);
74  }
75 
76  const uint8_t *banner_end = BasicSearch(line_ptr, line_len, (uint8_t*)"\r", 1);
77  if (banner_end == NULL) {
78  banner_end = BasicSearch(line_ptr, line_len, (uint8_t*)"\n", 1);
79  if (banner_end == NULL) {
80  SCLogDebug("No EOL at the end of banner buffer");
81  SCReturnInt(-1);
82  }
83  }
84 
85  if ((banner_end - line_ptr) > 255) {
86  SCLogDebug("Invalid version string, it should be less than 255 "
87  "characters including <CR><NL>, input value is %"PRIuMAX,
88  (uintmax_t)(banner_end - line_ptr));
89  SCReturnInt(-1);
90  }
91 
92  /* don't search things behind the end of banner */
93  line_len = banner_end - line_ptr;
94 
95  /* ok, we have found the version line/string, skip it and parse proto version */
96  line_ptr += 4;
97  line_len -= 4;
98 
99  uint8_t *proto_end = BasicSearch(line_ptr, line_len, (uint8_t*)"-", 1);
100  if (proto_end == NULL) {
101  /* Strings starting with SSH- are not allowed
102  * if they are not the real version string */
103  SCLogDebug("Info Version String for SSH (invalid usage of SSH- prefix)");
104  SCReturnInt(-1);
105  }
106  uint64_t proto_ver_len = (uint64_t)(proto_end - line_ptr);
107  header->proto_version = SCMalloc(proto_ver_len + 1);
108  if (header->proto_version == NULL) {
109  SCReturnInt(-1);
110  }
111  memcpy(header->proto_version, line_ptr, proto_ver_len);
112  header->proto_version[proto_ver_len] = '\0';
113 
114  /* Now lets parse the software & version */
115  line_ptr += proto_ver_len + 1;
116  line_len -= proto_ver_len + 1;
117  if (line_len < 1) {
118  SCLogDebug("No software version specified (weird)");
119  header->flags |= SSH_FLAG_VERSION_PARSED;
120  /* Return the remaining length */
121  SCReturnInt(0);
122  }
123 
124  uint64_t sw_ver_len = (uint64_t)(banner_end - line_ptr);
125  /* sanity check on this arithmetic */
126  if ((sw_ver_len <= 1) || (sw_ver_len >= input_len)) {
127  SCLogDebug("Should not have sw version length '%" PRIu64 "'", sw_ver_len);
128  SCReturnInt(-1);
129  }
130 
131  header->software_version = SCMalloc(sw_ver_len + 1);
132  if (header->software_version == NULL) {
133  SCReturnInt(-1);
134  }
135  memcpy(header->software_version, line_ptr, sw_ver_len);
136  header->software_version[sw_ver_len] = '\0';
137  if (header->software_version[sw_ver_len - 1] == 0x0d)
138  header->software_version[sw_ver_len - 1] = '\0';
139 
140  header->flags |= SSH_FLAG_VERSION_PARSED;
141 
142  /* Return the remaining length */
143  int len = input_len - (banner_end - input);
144  SCReturnInt(len);
145 }
146 
147 static int SSHParseRecordHeader(SshState *state, SshHeader *header,
148  const uint8_t *input, uint32_t input_len)
149 {
150 #ifdef DEBUG
151  BUG_ON(input_len != 6);
152 #else
153  if (input_len < 6)
154  SCReturnInt(-1);
155 #endif
156  /* input and input_len now point past initial line */
157  uint32_t pkt_len = 0;
158  int r = ByteExtractUint32(&pkt_len, BYTE_BIG_ENDIAN,
159  4, input);
160  if (r != 4) {
161  SCLogDebug("xtract 4 bytes failed %d", r);
162  SCReturnInt(-1);
163  }
164  if (pkt_len < 2) {
165  SCReturnInt(-1);
166  }
167 
168  header->pkt_len = pkt_len;
169  SCLogDebug("pkt len: %"PRIu32, pkt_len);
170 
171  input += 4;
172  //input_len -= 4;
173 
174  header->padding_len = *input;
175 
176  input += 1;
177  //input_len -= 1;
178 
179  SCLogDebug("padding: %u", header->padding_len);
180 
181  header->msg_code = *input;
182 
183  SCLogDebug("msg code: %u", header->msg_code);
184 
185  if (header->msg_code == SSH_MSG_NEWKEYS) {
186  /* done */
187  SCLogDebug("done");
188  header->flags |= SSH_FLAG_PARSER_DONE;
189  } else {
190  /* not yet done */
191  SCLogDebug("not done");
192  }
193  SCReturnInt(0);
194 }
195 
196 /** \internal
197  * \brief Function to parse the SSH field in packet received from the client
198  *
199  * Input to this function is a byte buffer starting with SSH- up to at least
200  * a \r or \n character.
201  *
202  * \param ssh_state Pointer the state in which the value to be stored
203  * \param input Pointer the received input data
204  * \param input_len Length in bytes of the received data
205  */
206 static int SSHParseRecord(SshState *state, SshHeader *header, uint8_t *input, uint32_t input_len)
207 {
208  SCEnter();
209  int ret = 0;
210 
211  if (header->flags & SSH_FLAG_PARSER_DONE) {
212  SCReturnInt(0);
213  }
214 
215  SCLogDebug("state %p, input %p,input_len %" PRIu32,
216  state, input, input_len);
217  //PrintRawDataFp(stdout, input, input_len);
218 
219  if (!(header->flags & SSH_FLAG_VERSION_PARSED)) {
220  ret = SSHParseBanner(state, header, input, input_len);
221  if (ret < 0) {
222  SCLogDebug("Invalid version string");
223  SCReturnInt(-1);
224  } else if (header->flags & SSH_FLAG_VERSION_PARSED) {
225  SCLogDebug("Version string parsed, remaining length %d", ret);
226  input += input_len - ret;
227  input_len -= (input_len - ret);
228 
229  uint32_t u = 0;
230  while (u < input_len && (input[u] == '\r' || input[u] == '\n')) {
231  u++;
232  }
233  SCLogDebug("skipping %u EOL bytes", u);
234  input += u;
235  input_len -= u;
236 
237  if (input_len == 0)
238  SCReturnInt(0);
239 
240  } else {
241  BUG_ON(1);// we only call this when we have enough data
242  SCLogDebug("Version string not parsed yet");
243  //pstate->parse_field = 0;
244  SCReturnInt(0);
245  }
246  } else {
247  SCLogDebug("Version string already parsed");
248  }
249 
250  /* skip bytes from the current record if we have to */
251  if (header->record_left > 0) {
252  SCLogDebug("skipping bytes part of the current record");
253  if (header->record_left > input_len) {
254  header->record_left -= input_len;
255  SCLogDebug("all input skipped, %u left in record", header->record_left);
256  SCReturnInt(0);
257  } else {
258  input_len -= header->record_left;
259  input += header->record_left;
260  header->record_left = 0;
261 
262  if (input_len == 0) {
263  SCLogDebug("all input skipped");
264  SCReturnInt(0);
265  }
266  }
267  }
268 
269 again:
270  /* input is too small, even when combined with stored bytes */
271  if (header->buf_offset + input_len < 6) {
272  memcpy(header->buf + header->buf_offset, input, input_len);
273  header->buf_offset += input_len;
274  SCReturnInt(0);
275 
276  /* we have enough bytes to parse 6 bytes, lets see if we have
277  * previously stored some */
278  } else if (header->buf_offset > 0) {
279  uint8_t needed = 6 - header->buf_offset;
280 
281  SCLogDebug("parse stored");
282  memcpy(header->buf + header->buf_offset, input, needed);
283  header->buf_offset = 6;
284 
285  // parse the 6
286  if (SSHParseRecordHeader(state, header, header->buf, 6) < 0)
287  SCReturnInt(-1);
288  header->buf_offset = 0;
289 
290  uint32_t record_left = header->pkt_len - 2;
291  input_len -= needed;
292  input += needed;
293 
294  if (record_left > input_len) {
295  header->record_left = record_left - input_len;
296  } else {
297  input_len -= record_left;
298  if (input_len == 0)
299  SCReturnInt(0);
300 
301  input += record_left;
302 
303  SCLogDebug("we have %u left to parse", input_len);
304  goto again;
305 
306  }
307 
308  /* nothing stored, lets parse this directly */
309  } else {
310  SCLogDebug("parse direct");
311  //PrintRawDataFp(stdout, input, input_len);
312  if (SSHParseRecordHeader(state, header, input, 6) < 0)
313  SCReturnInt(-1);
314 
315  uint32_t record_left = header->pkt_len - 2;
316  SCLogDebug("record left %u", record_left);
317  input_len -= 6;
318  input += 6;
319 
320  if (record_left > input_len) {
321  header->record_left = record_left - input_len;
322  } else {
323  input_len -= record_left;
324  if (input_len == 0)
325  SCReturnInt(0);
326  input += record_left;
327  //PrintRawDataFp(stdout, input, input_len);
328 
329  SCLogDebug("we have %u left to parse", input_len);
330  goto again;
331  }
332  }
333 
334  SCReturnInt(0);
335 }
336 
337 static int EnoughData(uint8_t *input, uint32_t input_len)
338 {
339  uint32_t u;
340  for (u = 0; u < input_len; u++) {
341  if (input[u] == '\r' || input[u] == '\n')
342  return TRUE;
343  }
344  return FALSE;
345 }
346 
347 #define MAX_BANNER_LEN 256
348 
349 static int SSHParseData(SshState *state, SshHeader *header,
350  uint8_t *input, uint32_t input_len)
351 {
352  /* we're looking for the banner */
353  if (!(header->flags & SSH_FLAG_VERSION_PARSED))
354  {
355  int banner_eol = EnoughData(input, input_len);
356 
357  /* fast track normal case: no buffering */
358  if (header->banner_buffer == NULL && banner_eol)
359  {
360  SCLogDebug("enough data, parse now");
361  // parse now
362  int r = SSHParseRecord(state, header, input, input_len);
363  SCReturnInt(r);
364 
365  /* banner EOL with existing buffer present. Time for magic. */
366  } else if (banner_eol) {
367  SCLogDebug("banner EOL with existing buffer");
368 
369  uint32_t tocopy = MAX_BANNER_LEN - header->banner_len;
370  if (tocopy > input_len)
371  tocopy = input_len;
372 
373  SCLogDebug("tocopy %u input_len %u", tocopy, input_len);
374  memcpy(header->banner_buffer + header->banner_len, input, tocopy);
375  header->banner_len += tocopy;
376 
377  SCLogDebug("header->banner_len %u", header->banner_len);
378  int r = SSHParseRecord(state, header,
379  header->banner_buffer, header->banner_len);
380  if (r == 0) {
381  input += tocopy;
382  input_len -= tocopy;
383  if (input_len > 0) {
384  SCLogDebug("handling remaining data %u", input_len);
385  r = SSHParseRecord(state, header, input, input_len);
386  }
387  }
388  SCReturnInt(r);
389 
390  /* no banner EOL, so we need to buffer */
391  } else if (!banner_eol) {
392  if (header->banner_buffer == NULL) {
394  if (header->banner_buffer == NULL)
395  SCReturnInt(-1);
396  }
397 
398  uint32_t tocopy = MAX_BANNER_LEN - header->banner_len;
399  if (tocopy > input_len)
400  tocopy = input_len;
401  SCLogDebug("tocopy %u", tocopy);
402 
403  memcpy(header->banner_buffer + header->banner_len, input, tocopy);
404  header->banner_len += tocopy;
405  SCLogDebug("header->banner_len %u", header->banner_len);
406  }
407 
408  /* we have a banner, the rest is just records */
409  } else {
410  int r = SSHParseRecord(state, header, input, input_len);
411  SCReturnInt(r);
412  }
413 
414  //PrintRawDataFp(stdout, input, input_len);
415  return 0;
416 }
417 
418 static int SSHParseRequest(Flow *f, void *state, AppLayerParserState *pstate,
419  uint8_t *input, uint32_t input_len,
420  void *local_data, const uint8_t flags)
421 {
422  SshState *ssh_state = (SshState *)state;
423  SshHeader *ssh_header = &ssh_state->cli_hdr;
424 
425  if (input == NULL && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) {
426  SCReturnInt(1);
427  } else if (input == NULL || input_len == 0) {
428  SCReturnInt(-1);
429  }
430 
431  int r = SSHParseData(ssh_state, ssh_header, input, input_len);
432 
433  if (ssh_state->cli_hdr.flags & SSH_FLAG_PARSER_DONE &&
434  ssh_state->srv_hdr.flags & SSH_FLAG_PARSER_DONE) {
438  }
439 
440  SCReturnInt(r);
441 }
442 
443 static int SSHParseResponse(Flow *f, void *state, AppLayerParserState *pstate,
444  uint8_t *input, uint32_t input_len,
445  void *local_data, const uint8_t flags)
446 {
447  SshState *ssh_state = (SshState *)state;
448  SshHeader *ssh_header = &ssh_state->srv_hdr;
449 
450  if (input == NULL && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) {
451  SCReturnInt(1);
452  } else if (input == NULL || input_len == 0) {
453  SCReturnInt(-1);
454  }
455 
456  int r = SSHParseData(ssh_state, ssh_header, input, input_len);
457 
458  if (ssh_state->cli_hdr.flags & SSH_FLAG_PARSER_DONE &&
459  ssh_state->srv_hdr.flags & SSH_FLAG_PARSER_DONE) {
463  }
464 
465  SCReturnInt(r);
466 }
467 
468 /** \brief Function to allocates the SSH state memory
469  */
470 static void *SSHStateAlloc(void)
471 {
472  void *s = SCMalloc(sizeof(SshState));
473  if (unlikely(s == NULL))
474  return NULL;
475 
476  memset(s, 0, sizeof(SshState));
477  return s;
478 }
479 
480 /** \brief Function to free the SSH state memory
481  */
482 static void SSHStateFree(void *state)
483 {
484  SshState *s = (SshState *)state;
485  if (s->cli_hdr.proto_version != NULL)
487  if (s->cli_hdr.software_version != NULL)
489  if (s->cli_hdr.banner_buffer != NULL)
491 
492  if (s->srv_hdr.proto_version != NULL)
494  if (s->srv_hdr.software_version != NULL)
496  if (s->srv_hdr.banner_buffer != NULL)
498 
499  //AppLayerDecoderEventsFreeEvents(&s->decoder_events);
500 
501  if (s->de_state != NULL) {
503  }
504 
505  SCFree(s);
506 }
507 
508 static int SSHSetTxDetectState(void *vtx, DetectEngineState *de_state)
509 {
510  SshState *ssh_state = (SshState *)vtx;
511  ssh_state->de_state = de_state;
512  return 0;
513 }
514 
515 static DetectEngineState *SSHGetTxDetectState(void *vtx)
516 {
517  SshState *ssh_state = (SshState *)vtx;
518  return ssh_state->de_state;
519 }
520 
521 static void SSHStateTransactionFree(void *state, uint64_t tx_id)
522 {
523  /* do nothing */
524 }
525 
526 static void *SSHGetTx(void *state, uint64_t tx_id)
527 {
528  SshState *ssh_state = (SshState *)state;
529  return ssh_state;
530 }
531 
532 static uint64_t SSHGetTxCnt(void *state)
533 {
534  /* single tx */
535  return 1;
536 }
537 
538 static void SSHSetTxLogged(void *state, void *tx, LoggerId logged)
539 {
540  SshState *ssh_state = (SshState *)state;
541  if (ssh_state)
542  ssh_state->logged = logged;
543 }
544 
545 static LoggerId SSHGetTxLogged(void *state, void *tx)
546 {
547  SshState *ssh_state = (SshState *)state;
548  if (ssh_state) {
549  return ssh_state->logged;
550  }
551  return 0;
552 }
553 
554 static uint64_t SSHGetTxDetectFlags(void *vtx, uint8_t dir)
555 {
556  SshState *ssh_state = (SshState *)vtx;
557  if (dir & STREAM_TOSERVER) {
558  return ssh_state->detect_flags_ts;
559  } else {
560  return ssh_state->detect_flags_tc;
561  }
562 }
563 
564 static void SSHSetTxDetectFlags(void *vtx, uint8_t dir, uint64_t flags)
565 {
566  SshState *ssh_state = (SshState *)vtx;
567  if (dir & STREAM_TOSERVER) {
568  ssh_state->detect_flags_ts = flags;
569  } else {
570  ssh_state->detect_flags_tc = flags;
571  }
572 }
573 
574 static int SSHGetAlstateProgressCompletionStatus(uint8_t direction)
575 {
576  return SSH_STATE_FINISHED;
577 }
578 
579 static int SSHGetAlstateProgress(void *tx, uint8_t direction)
580 {
581  SshState *ssh_state = (SshState *)tx;
582 
583  if (ssh_state->cli_hdr.flags & SSH_FLAG_PARSER_DONE &&
584  ssh_state->srv_hdr.flags & SSH_FLAG_PARSER_DONE) {
585  return SSH_STATE_FINISHED;
586  }
587 
588  if (direction == STREAM_TOSERVER) {
589  if (ssh_state->cli_hdr.flags & SSH_FLAG_VERSION_PARSED) {
590  return SSH_STATE_BANNER_DONE;
591  }
592  } else {
593  if (ssh_state->srv_hdr.flags & SSH_FLAG_VERSION_PARSED) {
594  return SSH_STATE_BANNER_DONE;
595  }
596  }
597 
598  return SSH_STATE_IN_PROGRESS;
599 }
600 
601 static int SSHRegisterPatternsForProtocolDetection(void)
602 {
604  "SSH-", 4, 0, STREAM_TOSERVER) < 0)
605  {
606  return -1;
607  }
609  "SSH-", 4, 0, STREAM_TOCLIENT) < 0)
610  {
611  return -1;
612  }
613  return 0;
614 }
615 
616 /** \brief Function to register the SSH protocol parsers and other functions
617  */
619 {
620  const char *proto_name = "ssh";
621 
622  if (AppLayerProtoDetectConfProtoDetectionEnabled("tcp", proto_name)) {
624  if (SSHRegisterPatternsForProtocolDetection() < 0)
625  return;
626  }
627 
628  if (AppLayerParserConfParserEnabled("tcp", proto_name)) {
630  SSHParseRequest);
632  SSHParseResponse);
633  AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_SSH, SSHStateAlloc, SSHStateFree);
636 
637  AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_SSH, SSHStateTransactionFree);
638 
640  SSHGetTxDetectState, SSHSetTxDetectState);
641 
642  AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_SSH, SSHGetTx);
643 
644  AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_SSH, SSHGetTxCnt);
645 
646  AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_SSH, SSHGetAlstateProgress);
647 
648  AppLayerParserRegisterLoggerFuncs(IPPROTO_TCP, ALPROTO_SSH, SSHGetTxLogged, SSHSetTxLogged);
650  SSHGetTxDetectFlags, SSHSetTxDetectFlags);
651 
653  SSHGetAlstateProgressCompletionStatus);
654  } else {
655 // SCLogInfo("Parsed disabled for %s protocol. Protocol detection"
656 // "still on.", proto_name);
657  }
658 
659 #ifdef UNITTESTS
661 #endif
662 }
663 
664 /* UNITTESTS */
665 #ifdef UNITTESTS
666 #include "flow-util.h"
667 
668 /** \test Send a version string in one chunk (client version str). */
669 static int SSHParserTest01(void)
670 {
671  int result = 0;
672  Flow f;
673  uint8_t sshbuf[] = "SSH-2.0-MySSHClient-0.5.1\n";
674  uint32_t sshlen = sizeof(sshbuf) - 1;
675  TcpSession ssn;
677 
678  memset(&f, 0, sizeof(f));
679  memset(&ssn, 0, sizeof(ssn));
680  FLOW_INITIALIZE(&f);
681  f.protoctx = (void *)&ssn;
682 
684 
685  FLOWLOCK_WRLOCK(&f);
686  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH,
687  STREAM_TOSERVER | STREAM_EOF, sshbuf, sshlen);
688  if (r != 0) {
689  printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r);
690  FLOWLOCK_UNLOCK(&f);
691  goto end;
692  }
693  FLOWLOCK_UNLOCK(&f);
694 
695  SshState *ssh_state = f.alstate;
696  if (ssh_state == NULL) {
697  printf("no ssh state: ");
698  goto end;
699  }
700 
701  if ( !(ssh_state->cli_hdr.flags & SSH_FLAG_VERSION_PARSED)) {
702  printf("Client version string not parsed: ");
703  goto end;
704  }
705 
706  if (ssh_state->cli_hdr.software_version == NULL) {
707  printf("Client version string not parsed: ");
708  goto end;
709  }
710 
711  if (ssh_state->cli_hdr.proto_version == NULL) {
712  printf("Client version string not parsed: ");
713  goto end;
714  }
715 
716  if (strncmp((char*)ssh_state->cli_hdr.software_version, "MySSHClient-0.5.1", strlen("MySSHClient-0.5.1")) != 0) {
717  printf("Client version string not parsed correctly: ");
718  goto end;
719  }
720 
721  if (strncmp((char*)ssh_state->cli_hdr.proto_version, "2.0", strlen("2.0")) != 0) {
722  printf("Client version string not parsed correctly: ");
723  goto end;
724  }
725 
726  result = 1;
727 end:
728  if (alp_tctx != NULL)
729  AppLayerParserThreadCtxFree(alp_tctx);
731  FLOW_DESTROY(&f);
732  return result;
733 }
734 
735 /** \test Send a version string in one chunk but multiple lines and comments.
736  * (client version str)
737  */
738 static int SSHParserTest02(void)
739 {
740  int result = 0;
741  Flow f;
742  uint8_t sshbuf[] = "SSH-2.0-MySSHClient-0.5.1 some comments...\n";
743  uint32_t sshlen = sizeof(sshbuf) - 1;
744  TcpSession ssn;
746 
747  memset(&f, 0, sizeof(f));
748  memset(&ssn, 0, sizeof(ssn));
749  FLOW_INITIALIZE(&f);
750  f.protoctx = (void *)&ssn;
751 
753 
754  FLOWLOCK_WRLOCK(&f);
755  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH,
756  STREAM_TOSERVER | STREAM_EOF, sshbuf, sshlen);
757  if (r != 0) {
758  printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r);
759  FLOWLOCK_UNLOCK(&f);
760  goto end;
761  }
762  FLOWLOCK_UNLOCK(&f);
763 
764  SshState *ssh_state = f.alstate;
765  if (ssh_state == NULL) {
766  printf("no ssh state: ");
767  goto end;
768  }
769 
770  if ( !(ssh_state->cli_hdr.flags & SSH_FLAG_VERSION_PARSED)) {
771  printf("Client version string not parsed: ");
772  goto end;
773  }
774 
775  if (ssh_state->cli_hdr.software_version == NULL) {
776  printf("Client version string not parsed: ");
777  goto end;
778  }
779 
780  if (ssh_state->cli_hdr.proto_version == NULL) {
781  printf("Client version string not parsed: ");
782  goto end;
783  }
784 
785  if (strncmp((char*)ssh_state->cli_hdr.software_version, "MySSHClient-0.5.1", strlen("MySSHClient-0.5.1")) != 0) {
786  printf("Client version string not parsed correctly: ");
787  goto end;
788  }
789 
790  if (strncmp((char*)ssh_state->cli_hdr.proto_version, "2.0", strlen("2.0")) != 0) {
791  printf("Client version string not parsed correctly: ");
792  goto end;
793  }
794 
795  result = 1;
796 end:
797  if (alp_tctx != NULL)
798  AppLayerParserThreadCtxFree(alp_tctx);
800  FLOW_DESTROY(&f);
801  return result;
802 }
803 
804 /** \test Send a invalid version string in one chunk but multiple lines and comments.
805  * (client version str)
806  */
807 static int SSHParserTest03(void)
808 {
809  int result = 0;
810  Flow f;
811  uint8_t sshbuf[] = "SSH-2.0 some comments...\n";
812  uint32_t sshlen = sizeof(sshbuf) - 1;
813  TcpSession ssn;
815 
816  memset(&f, 0, sizeof(f));
817  memset(&ssn, 0, sizeof(ssn));
818  FLOW_INITIALIZE(&f);
819  f.protoctx = (void *)&ssn;
820 
822 
823  FLOWLOCK_WRLOCK(&f);
824  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH,
825  STREAM_TOSERVER | STREAM_EOF, sshbuf, sshlen);
826  if (r == 0) {
827  printf("toclient chunk 1 returned %" PRId32 ", expected != 0: ", r);
828  FLOWLOCK_UNLOCK(&f);
829  goto end;
830  }
831  FLOWLOCK_UNLOCK(&f);
832 
833  SshState *ssh_state = f.alstate;
834  if (ssh_state == NULL) {
835  printf("no ssh state: ");
836  goto end;
837  }
838 
839  if (ssh_state->cli_hdr.flags & SSH_FLAG_VERSION_PARSED) {
840  printf("Client version string parsed? It's not a valid string: ");
841  goto end;
842  }
843 
844  if (ssh_state->cli_hdr.proto_version != NULL) {
845  goto end;
846  }
847 
848  if (ssh_state->cli_hdr.software_version != NULL) {
849  goto end;
850  }
851 
852  result = 1;
853 end:
854  if (alp_tctx != NULL)
855  AppLayerParserThreadCtxFree(alp_tctx);
857  FLOW_DESTROY(&f);
858  return result;
859 }
860 
861 /** \test Send a version string in one chunk (server version str). */
862 static int SSHParserTest04(void)
863 {
864  int result = 0;
865  Flow f;
866  uint8_t sshbuf[] = "SSH-2.0-MySSHClient-0.5.1\n";
867  uint32_t sshlen = sizeof(sshbuf) - 1;
868  TcpSession ssn;
870 
871  memset(&f, 0, sizeof(f));
872  memset(&ssn, 0, sizeof(ssn));
873  FLOW_INITIALIZE(&f);
874  f.protoctx = (void *)&ssn;
875 
877 
878  FLOWLOCK_WRLOCK(&f);
879  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH,
880  STREAM_TOCLIENT | STREAM_EOF, sshbuf, sshlen);
881  if (r != 0) {
882  printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
883  FLOWLOCK_UNLOCK(&f);
884  goto end;
885  }
886  FLOWLOCK_UNLOCK(&f);
887 
888  SshState *ssh_state = f.alstate;
889  if (ssh_state == NULL) {
890  printf("no ssh state: ");
891  goto end;
892  }
893 
894  if (!(ssh_state->srv_hdr.flags & SSH_FLAG_VERSION_PARSED)) {
895  printf("Client version string not parsed: ");
896  goto end;
897  }
898 
899  if (ssh_state->srv_hdr.software_version == NULL) {
900  printf("Client version string not parsed: ");
901  goto end;
902  }
903 
904  if (ssh_state->srv_hdr.proto_version == NULL) {
905  printf("Client version string not parsed: ");
906  goto end;
907  }
908 
909  if (strncmp((char*)ssh_state->srv_hdr.software_version, "MySSHClient-0.5.1", strlen("MySSHClient-0.5.1")) != 0) {
910  printf("Client version string not parsed correctly: ");
911  goto end;
912  }
913 
914  if (strncmp((char*)ssh_state->srv_hdr.proto_version, "2.0", strlen("2.0")) != 0) {
915  printf("Client version string not parsed correctly: ");
916  goto end;
917  }
918 
919  result = 1;
920 
921 end:
922  if (alp_tctx != NULL)
923  AppLayerParserThreadCtxFree(alp_tctx);
925  FLOW_DESTROY(&f);
926  return result;
927 }
928 
929 /** \test Send a version string in one chunk (server version str)
930  */
931 static int SSHParserTest05(void)
932 {
933  int result = 0;
934  Flow f;
935  uint8_t sshbuf[] = "SSH-2.0-MySSHClient-0.5.1 some comments...\n";
936  uint32_t sshlen = sizeof(sshbuf) - 1;
937  TcpSession ssn;
939 
940  memset(&f, 0, sizeof(f));
941  memset(&ssn, 0, sizeof(ssn));
942  FLOW_INITIALIZE(&f);
943  f.protoctx = (void *)&ssn;
944 
946 
947  FLOWLOCK_WRLOCK(&f);
948  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH,
949  STREAM_TOCLIENT | STREAM_EOF, sshbuf, sshlen);
950  if (r != 0) {
951  printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
952  FLOWLOCK_UNLOCK(&f);
953  goto end;
954  }
955  FLOWLOCK_UNLOCK(&f);
956 
957  SshState *ssh_state = f.alstate;
958  if (ssh_state == NULL) {
959  printf("no ssh state: ");
960  goto end;
961  }
962 
963  if (!(ssh_state->srv_hdr.flags & SSH_FLAG_VERSION_PARSED)) {
964  printf("Client version string not parsed: ");
965  goto end;
966  }
967 
968  if (ssh_state->srv_hdr.software_version == NULL) {
969  printf("Client version string not parsed: ");
970  goto end;
971  }
972 
973  if (ssh_state->srv_hdr.proto_version == NULL) {
974  printf("Client version string not parsed: ");
975  goto end;
976  }
977 
978  if (strncmp((char*)ssh_state->srv_hdr.software_version, "MySSHClient-0.5.1", strlen("MySSHClient-0.5.1")) != 0) {
979  printf("Client version string not parsed correctly: ");
980  goto end;
981  }
982 
983  if (strncmp((char*)ssh_state->srv_hdr.proto_version, "2.0", strlen("2.0")) != 0) {
984  printf("Client version string not parsed correctly: ");
985  goto end;
986  }
987 
988  result = 1;
989 end:
990  if (alp_tctx != NULL)
991  AppLayerParserThreadCtxFree(alp_tctx);
993  FLOW_DESTROY(&f);
994  return result;
995 }
996 
997 /** \test Send a invalid version string in one chunk (server version str)
998  */
999 static int SSHParserTest06(void)
1000 {
1001  int result = 0;
1002  Flow f;
1003  uint8_t sshbuf[] = "SSH-2.0 some comments...\n";
1004  uint32_t sshlen = sizeof(sshbuf) - 1;
1005  TcpSession ssn;
1007 
1008  memset(&f, 0, sizeof(f));
1009  memset(&ssn, 0, sizeof(ssn));
1010  FLOW_INITIALIZE(&f);
1011  f.protoctx = (void *)&ssn;
1012 
1014 
1015  FLOWLOCK_WRLOCK(&f);
1016  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH,
1017  STREAM_TOCLIENT | STREAM_EOF, sshbuf, sshlen);
1018  if (r == 0) {
1019  printf("toserver chunk 1 returned %" PRId32 ", expected != 0: ", r);
1020  FLOWLOCK_UNLOCK(&f);
1021  goto end;
1022  }
1023  FLOWLOCK_UNLOCK(&f);
1024  /* Ok, it returned an error. Let's make sure we didn't parse the string at all */
1025 
1026  SshState *ssh_state = f.alstate;
1027  if (ssh_state == NULL) {
1028  printf("no ssh state: ");
1029  goto end;
1030  }
1031 
1032  if (ssh_state->srv_hdr.flags & SSH_FLAG_VERSION_PARSED) {
1033  printf("Client version string parsed? It's not a valid string: ");
1034  goto end;
1035  }
1036 
1037  if (ssh_state->srv_hdr.proto_version != NULL) {
1038  goto end;
1039  }
1040 
1041  if (ssh_state->srv_hdr.software_version != NULL) {
1042  goto end;
1043  }
1044 
1045  result = 1;
1046 end:
1047  if (alp_tctx != NULL)
1048  AppLayerParserThreadCtxFree(alp_tctx);
1050  FLOW_DESTROY(&f);
1051  return result;
1052 }
1053 
1054 static int SSHParserTest07(void)
1055 {
1056  int result = 0;
1057  Flow f;
1058  uint8_t sshbuf1[] = "SSH-2.";
1059  uint32_t sshlen1 = sizeof(sshbuf1) - 1;
1060  uint8_t sshbuf2[] = { "0-MySSHClient-0.5.1\r\n"};
1061  uint32_t sshlen2 = sizeof(sshbuf2) - 1;
1062  TcpSession ssn;
1064 
1065  memset(&f, 0, sizeof(f));
1066  memset(&ssn, 0, sizeof(ssn));
1067  FLOW_INITIALIZE(&f);
1068  f.protoctx = (void *)&ssn;
1069 
1071 
1072  FLOWLOCK_WRLOCK(&f);
1073  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH,
1074  STREAM_TOSERVER, sshbuf1, sshlen1);
1075  if (r != 0) {
1076  printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
1077  FLOWLOCK_UNLOCK(&f);
1078  goto end;
1079  }
1080  FLOWLOCK_UNLOCK(&f);
1081 
1082  FLOWLOCK_WRLOCK(&f);
1083  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER,
1084  sshbuf2, sshlen2);
1085  if (r != 0) {
1086  printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
1087  FLOWLOCK_UNLOCK(&f);
1088  goto end;
1089  }
1090  FLOWLOCK_UNLOCK(&f);
1091 
1092  SshState *ssh_state = f.alstate;
1093  if (ssh_state == NULL) {
1094  printf("no ssh state: ");
1095  goto end;
1096  }
1097 
1098  if ( !(ssh_state->cli_hdr.flags & SSH_FLAG_VERSION_PARSED)) {
1099  printf("Client version string not parsed: ");
1100  goto end;
1101  }
1102 
1103  if (ssh_state->cli_hdr.software_version == NULL) {
1104  printf("Client version string not parsed: ");
1105  goto end;
1106  }
1107 
1108  if (ssh_state->cli_hdr.proto_version == NULL) {
1109  printf("Client version string not parsed: ");
1110  goto end;
1111  }
1112 
1113  if (strncmp((char*)ssh_state->cli_hdr.software_version, "MySSHClient-0.5.1", strlen("MySSHClient-0.5.1")) != 0) {
1114  printf("Client version string not parsed correctly: ");
1115  goto end;
1116  }
1117 
1118  if (strncmp((char*)ssh_state->cli_hdr.proto_version, "2.0", strlen("2.0")) != 0) {
1119  printf("Client version string not parsed correctly: ");
1120  goto end;
1121  }
1122 
1123  result = 1;
1124 
1125 end:
1126  if (alp_tctx != NULL)
1127  AppLayerParserThreadCtxFree(alp_tctx);
1129  FLOW_DESTROY(&f);
1130  return result;
1131 }
1132 
1133 /** \test Send a version banner in three chunks. */
1134 static int SSHParserTest08(void)
1135 {
1136  int result = 0;
1137  Flow f;
1138  uint8_t sshbuf1[] = "SSH-";
1139  uint32_t sshlen1 = sizeof(sshbuf1) - 1;
1140  uint8_t sshbuf2[] = "2.";
1141  uint32_t sshlen2 = sizeof(sshbuf2) - 1;
1142  uint8_t sshbuf3[] = { "0-MySSHClient-0.5.1\r\n"};
1143  uint32_t sshlen3 = sizeof(sshbuf3) - 1;
1144  TcpSession ssn;
1146 
1147  memset(&f, 0, sizeof(f));
1148  memset(&ssn, 0, sizeof(ssn));
1149  FLOW_INITIALIZE(&f);
1150  f.protoctx = (void *)&ssn;
1151 
1153 
1154  FLOWLOCK_WRLOCK(&f);
1155  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH,
1156  STREAM_TOSERVER, sshbuf1, sshlen1);
1157  if (r != 0) {
1158  printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
1159  FLOWLOCK_UNLOCK(&f);
1160  goto end;
1161  }
1162  FLOWLOCK_UNLOCK(&f);
1163 
1164  FLOWLOCK_WRLOCK(&f);
1165  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER,
1166  sshbuf2, sshlen2);
1167  if (r != 0) {
1168  printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
1169  FLOWLOCK_UNLOCK(&f);
1170  goto end;
1171  }
1172  FLOWLOCK_UNLOCK(&f);
1173 
1174  FLOWLOCK_WRLOCK(&f);
1175  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER,
1176  sshbuf3, sshlen3);
1177  if (r != 0) {
1178  printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
1179  FLOWLOCK_UNLOCK(&f);
1180  goto end;
1181  }
1182  FLOWLOCK_UNLOCK(&f);
1183 
1184  SshState *ssh_state = f.alstate;
1185  if (ssh_state == NULL) {
1186  printf("no ssh state: ");
1187  goto end;
1188  }
1189 
1190  if ( !(ssh_state->cli_hdr.flags & SSH_FLAG_VERSION_PARSED)) {
1191  printf("Client version string not parsed: ");
1192  goto end;
1193  }
1194 
1195  if (ssh_state->cli_hdr.software_version == NULL) {
1196  printf("Client version string not parsed: ");
1197  goto end;
1198  }
1199 
1200  if (ssh_state->cli_hdr.proto_version == NULL) {
1201  printf("Client version string not parsed: ");
1202  goto end;
1203  }
1204 
1205  if (strncmp((char*)ssh_state->cli_hdr.software_version, "MySSHClient-0.5.1", strlen("MySSHClient-0.5.1")) != 0) {
1206  printf("Client version string not parsed correctly: ");
1207  goto end;
1208  }
1209 
1210  if (strncmp((char*)ssh_state->cli_hdr.proto_version, "2.0", strlen("2.0")) != 0) {
1211  printf("Client version string not parsed correctly: ");
1212  goto end;
1213  }
1214 
1215  result = 1;
1216 end:
1217  if (alp_tctx != NULL)
1218  AppLayerParserThreadCtxFree(alp_tctx);
1220  FLOW_DESTROY(&f);
1221  return result;
1222 }
1223 
1224 static int SSHParserTest09(void)
1225 {
1226  int result = 0;
1227  Flow f;
1228  uint8_t sshbuf1[] = "SSH-2.";
1229  uint32_t sshlen1 = sizeof(sshbuf1) - 1;
1230  uint8_t sshbuf2[] = { "0-MySSHClient-0.5.1\r\n"};
1231  uint32_t sshlen2 = sizeof(sshbuf2) - 1;
1232  TcpSession ssn;
1234 
1235  memset(&f, 0, sizeof(f));
1236  memset(&ssn, 0, sizeof(ssn));
1237  FLOW_INITIALIZE(&f);
1238  f.protoctx = (void *)&ssn;
1239 
1241 
1242  FLOWLOCK_WRLOCK(&f);
1243  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH,
1244  STREAM_TOCLIENT, sshbuf1, sshlen1);
1245  if (r != 0) {
1246  printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
1247  FLOWLOCK_UNLOCK(&f);
1248  goto end;
1249  }
1250  FLOWLOCK_UNLOCK(&f);
1251 
1252  FLOWLOCK_WRLOCK(&f);
1253  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT,
1254  sshbuf2, sshlen2);
1255  if (r != 0) {
1256  printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
1257  FLOWLOCK_UNLOCK(&f);
1258  goto end;
1259  }
1260  FLOWLOCK_UNLOCK(&f);
1261 
1262  SshState *ssh_state = f.alstate;
1263  if (ssh_state == NULL) {
1264  printf("no ssh state: ");
1265  goto end;
1266  }
1267 
1268  if (!(ssh_state->srv_hdr.flags & SSH_FLAG_VERSION_PARSED)) {
1269  printf("Client version string not parsed: ");
1270  goto end;
1271  }
1272 
1273  if (ssh_state->srv_hdr.software_version == NULL) {
1274  printf("Client version string not parsed: ");
1275  goto end;
1276  }
1277 
1278  if (ssh_state->srv_hdr.proto_version == NULL) {
1279  printf("Client version string not parsed: ");
1280  goto end;
1281  }
1282 
1283  if (strncmp((char*)ssh_state->srv_hdr.software_version, "MySSHClient-0.5.1", strlen("MySSHClient-0.5.1")) != 0) {
1284  printf("Client version string not parsed correctly: ");
1285  goto end;
1286  }
1287 
1288  if (strncmp((char*)ssh_state->srv_hdr.proto_version, "2.0", strlen("2.0")) != 0) {
1289  printf("Client version string not parsed correctly: ");
1290  goto end;
1291  }
1292 
1293  result = 1;
1294 
1295 end:
1296  if (alp_tctx != NULL)
1297  AppLayerParserThreadCtxFree(alp_tctx);
1299  FLOW_DESTROY(&f);
1300  return result;
1301 }
1302 
1303 /** \test Send a version banner in three chunks. */
1304 static int SSHParserTest10(void)
1305 {
1306  int result = 0;
1307  Flow f;
1308  uint8_t sshbuf1[] = "SSH-";
1309  uint32_t sshlen1 = sizeof(sshbuf1) - 1;
1310  uint8_t sshbuf2[] = "2.";
1311  uint32_t sshlen2 = sizeof(sshbuf2) - 1;
1312  uint8_t sshbuf3[] = { "0-MySSHClient-0.5.1\r\n"};
1313  uint32_t sshlen3 = sizeof(sshbuf3) - 1;
1314  TcpSession ssn;
1316 
1317  memset(&f, 0, sizeof(f));
1318  memset(&ssn, 0, sizeof(ssn));
1319  FLOW_INITIALIZE(&f);
1320  f.protoctx = (void *)&ssn;
1321 
1323 
1324  FLOWLOCK_WRLOCK(&f);
1325  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH,
1326  STREAM_TOCLIENT, sshbuf1, sshlen1);
1327  if (r != 0) {
1328  printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
1329  FLOWLOCK_UNLOCK(&f);
1330  goto end;
1331  }
1332  FLOWLOCK_UNLOCK(&f);
1333 
1334  FLOWLOCK_WRLOCK(&f);
1335  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT,
1336  sshbuf2, sshlen2);
1337  if (r != 0) {
1338  printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
1339  FLOWLOCK_UNLOCK(&f);
1340  goto end;
1341  }
1342  FLOWLOCK_UNLOCK(&f);
1343 
1344  FLOWLOCK_WRLOCK(&f);
1345  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT,
1346  sshbuf3, sshlen3);
1347  if (r != 0) {
1348  printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
1349  FLOWLOCK_UNLOCK(&f);
1350  goto end;
1351  }
1352  FLOWLOCK_UNLOCK(&f);
1353 
1354  SshState *ssh_state = f.alstate;
1355  if (ssh_state == NULL) {
1356  printf("no ssh state: ");
1357  goto end;
1358  }
1359 
1360  if (!(ssh_state->srv_hdr.flags & SSH_FLAG_VERSION_PARSED)) {
1361  printf("Client version string not parsed: ");
1362  goto end;
1363  }
1364 
1365  if (ssh_state->srv_hdr.software_version == NULL) {
1366  printf("Client version string not parsed: ");
1367  goto end;
1368  }
1369 
1370  if (ssh_state->srv_hdr.proto_version == NULL) {
1371  printf("Client version string not parsed: ");
1372  goto end;
1373  }
1374 
1375  if (strncmp((char*)ssh_state->srv_hdr.software_version, "MySSHClient-0.5.1", strlen("MySSHClient-0.5.1")) != 0) {
1376  printf("Client version string not parsed correctly: ");
1377  goto end;
1378  }
1379 
1380  if (strncmp((char*)ssh_state->srv_hdr.proto_version, "2.0", strlen("2.0")) != 0) {
1381  printf("Client version string not parsed correctly: ");
1382  goto end;
1383  }
1384 
1385  result = 1;
1386 end:
1387  if (alp_tctx != NULL)
1388  AppLayerParserThreadCtxFree(alp_tctx);
1390  FLOW_DESTROY(&f);
1391  return result;
1392 }
1393 
1394 /** \test Send a banner and record in three chunks. */
1395 static int SSHParserTest11(void)
1396 {
1397  int result = 0;
1398  Flow f;
1399  uint8_t sshbuf1[] = "SSH-2.0-MySSHClient-0.5.1\r\n";
1400  uint32_t sshlen1 = sizeof(sshbuf1) - 1;
1401  uint8_t sshbuf2[] = { 0x00, 0x00, 0x00, 0x03, 0x01, 21, 0x00};
1402  uint32_t sshlen2 = sizeof(sshbuf2);
1403  TcpSession ssn;
1405 
1406  memset(&f, 0, sizeof(f));
1407  memset(&ssn, 0, sizeof(ssn));
1408  FLOW_INITIALIZE(&f);
1409  f.protoctx = (void *)&ssn;
1410 
1412 
1413  FLOWLOCK_WRLOCK(&f);
1414  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH,
1415  STREAM_TOSERVER, sshbuf1, sshlen1);
1416  if (r != 0) {
1417  printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
1418  FLOWLOCK_UNLOCK(&f);
1419  goto end;
1420  }
1421  FLOWLOCK_UNLOCK(&f);
1422 
1423  FLOWLOCK_WRLOCK(&f);
1424  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER,
1425  sshbuf2, sshlen2);
1426  if (r != 0) {
1427  printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
1428  FLOWLOCK_UNLOCK(&f);
1429  goto end;
1430  }
1431  FLOWLOCK_UNLOCK(&f);
1432 
1433  SshState *ssh_state = f.alstate;
1434  if (ssh_state == NULL) {
1435  printf("no ssh state: ");
1436  goto end;
1437  }
1438 
1439  if ( !(ssh_state->cli_hdr.flags & SSH_FLAG_VERSION_PARSED)) {
1440  printf("Client version string not parsed: ");
1441  goto end;
1442  }
1443 
1444  if (ssh_state->cli_hdr.software_version == NULL) {
1445  printf("Client version string not parsed: ");
1446  goto end;
1447  }
1448 
1449  if (ssh_state->cli_hdr.proto_version == NULL) {
1450  printf("Client version string not parsed: ");
1451  goto end;
1452  }
1453 
1454  if (strncmp((char*)ssh_state->cli_hdr.software_version, "MySSHClient-0.5.1", strlen("MySSHClient-0.5.1")) != 0) {
1455  printf("Client version string not parsed correctly: ");
1456  goto end;
1457  }
1458 
1459  if (strncmp((char*)ssh_state->cli_hdr.proto_version, "2.0", strlen("2.0")) != 0) {
1460  printf("Client version string not parsed correctly: ");
1461  goto end;
1462  }
1463 
1464  if ( !(ssh_state->cli_hdr.flags & SSH_FLAG_PARSER_DONE)) {
1465  printf("Didn't detect the msg code of new keys (ciphered data starts): ");
1466  goto end;
1467  }
1468 
1469  result = 1;
1470 end:
1471  if (alp_tctx != NULL)
1472  AppLayerParserThreadCtxFree(alp_tctx);
1474  FLOW_DESTROY(&f);
1475  return result;
1476 }
1477 
1478 /** \test Send a banner and 2 records record in four chunks. */
1479 static int SSHParserTest12(void)
1480 {
1481  int result = 0;
1482  Flow f;
1483  uint8_t sshbuf1[] = "SSH-2.0-MySSHClient-0.5.1\r\n";
1484  uint32_t sshlen1 = sizeof(sshbuf1) - 1;
1485  uint8_t sshbuf2[] = { 0x00, 0x00, 0x00, 0x03,0x01, 17, 0x00};
1486  uint32_t sshlen2 = sizeof(sshbuf2);
1487  uint8_t sshbuf3[] = { 0x00, 0x00, 0x00, 0x03,0x01, 21, 0x00};
1488  uint32_t sshlen3 = sizeof(sshbuf3);
1489  TcpSession ssn;
1491 
1492  memset(&f, 0, sizeof(f));
1493  memset(&ssn, 0, sizeof(ssn));
1494  FLOW_INITIALIZE(&f);
1495  f.protoctx = (void *)&ssn;
1496 
1498 
1499  FLOWLOCK_WRLOCK(&f);
1500  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH,
1501  STREAM_TOSERVER, sshbuf1, sshlen1);
1502  if (r != 0) {
1503  printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
1504  FLOWLOCK_UNLOCK(&f);
1505  goto end;
1506  }
1507  FLOWLOCK_UNLOCK(&f);
1508 
1509  FLOWLOCK_WRLOCK(&f);
1510  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER,
1511  sshbuf2, sshlen2);
1512  if (r != 0) {
1513  printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
1514  FLOWLOCK_UNLOCK(&f);
1515  goto end;
1516  }
1517  FLOWLOCK_UNLOCK(&f);
1518 
1519  FLOWLOCK_WRLOCK(&f);
1520  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER,
1521  sshbuf3, sshlen3);
1522  if (r != 0) {
1523  printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
1524  FLOWLOCK_UNLOCK(&f);
1525  goto end;
1526  }
1527  FLOWLOCK_UNLOCK(&f);
1528 
1529  SshState *ssh_state = f.alstate;
1530  if (ssh_state == NULL) {
1531  printf("no ssh state: ");
1532  goto end;
1533  }
1534 
1535  if ( !(ssh_state->cli_hdr.flags & SSH_FLAG_VERSION_PARSED)) {
1536  printf("Client version string not parsed: ");
1537  goto end;
1538  }
1539 
1540  if (ssh_state->cli_hdr.software_version == NULL) {
1541  printf("Client version string not parsed: ");
1542  goto end;
1543  }
1544 
1545  if (ssh_state->cli_hdr.proto_version == NULL) {
1546  printf("Client version string not parsed: ");
1547  goto end;
1548  }
1549 
1550  if (strncmp((char*)ssh_state->cli_hdr.software_version, "MySSHClient-0.5.1", strlen("MySSHClient-0.5.1")) != 0) {
1551  printf("Client version string not parsed correctly: ");
1552  goto end;
1553  }
1554 
1555  if (strncmp((char*)ssh_state->cli_hdr.proto_version, "2.0", strlen("2.0")) != 0) {
1556  printf("Client version string not parsed correctly: ");
1557  goto end;
1558  }
1559 
1560  if ( !(ssh_state->cli_hdr.flags & SSH_FLAG_PARSER_DONE)) {
1561  printf("Didn't detect the msg code of new keys (ciphered data starts): ");
1562  goto end;
1563  }
1564 
1565  result = 1;
1566 end:
1567  if (alp_tctx != NULL)
1568  AppLayerParserThreadCtxFree(alp_tctx);
1570  FLOW_DESTROY(&f);
1571  return result;
1572 }
1573 
1574 /** \test Send a banner and 2 records record in four chunks. */
1575 static int SSHParserTest13(void)
1576 {
1577  int result = 0;
1578  Flow f;
1579  uint8_t sshbuf1[] = "SSH-2.0-MySSHClient-0.5.1\r\n";
1580  uint32_t sshlen1 = sizeof(sshbuf1) - 1;
1581  uint8_t sshbuf2[] = { 0x00, 0x00, 0x00, 0x02, 0x01, 17};
1582  uint32_t sshlen2 = sizeof(sshbuf2);
1583  uint8_t sshbuf3[] = { 0x00, 0x00, 0x00, 0x02, 0x01, 21};
1584  uint32_t sshlen3 = sizeof(sshbuf3);
1585  TcpSession ssn;
1587  uint32_t u;
1588 
1589  memset(&f, 0, sizeof(f));
1590  memset(&ssn, 0, sizeof(ssn));
1591  FLOW_INITIALIZE(&f);
1592  f.protoctx = (void *)&ssn;
1593 
1595 
1596  FLOWLOCK_WRLOCK(&f);
1597  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH,
1598  STREAM_TOSERVER, sshbuf1, sshlen1);
1599  if (r != 0) {
1600  printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
1601  FLOWLOCK_UNLOCK(&f);
1602  goto end;
1603  }
1604  FLOWLOCK_UNLOCK(&f);
1605  for (u = 0; u < sshlen2; u++) {
1606  FLOWLOCK_WRLOCK(&f);
1607  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH,
1608  STREAM_TOSERVER, &sshbuf2[u], 1);
1609  if (r != 0) {
1610  printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
1611  FLOWLOCK_UNLOCK(&f);
1612  goto end;
1613  }
1614  FLOWLOCK_UNLOCK(&f);
1615  }
1616  for (u = 0; u < sshlen3; u++) {
1617  FLOWLOCK_WRLOCK(&f);
1618  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH,
1619  STREAM_TOSERVER, &sshbuf3[u], 1);
1620  if (r != 0) {
1621  printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
1622  FLOWLOCK_UNLOCK(&f);
1623  goto end;
1624  }
1625  FLOWLOCK_UNLOCK(&f);
1626  }
1627  SshState *ssh_state = f.alstate;
1628  if (ssh_state == NULL) {
1629  printf("no ssh state: ");
1630  goto end;
1631  }
1632 
1633  if ( !(ssh_state->cli_hdr.flags & SSH_FLAG_VERSION_PARSED)) {
1634  printf("Client version string not parsed: ");
1635  goto end;
1636  }
1637 
1638  if (ssh_state->cli_hdr.software_version == NULL) {
1639  printf("Client version string not parsed: ");
1640  goto end;
1641  }
1642 
1643  if (ssh_state->cli_hdr.proto_version == NULL) {
1644  printf("Client version string not parsed: ");
1645  goto end;
1646  }
1647 
1648  if (strncmp((char*)ssh_state->cli_hdr.software_version, "MySSHClient-0.5.1", strlen("MySSHClient-0.5.1")) != 0) {
1649  printf("Client version string not parsed correctly: ");
1650  goto end;
1651  }
1652 
1653  if (strncmp((char*)ssh_state->cli_hdr.proto_version, "2.0", strlen("2.0")) != 0) {
1654  printf("Client version string not parsed correctly: ");
1655  goto end;
1656  }
1657 
1658  if ( !(ssh_state->cli_hdr.flags & SSH_FLAG_PARSER_DONE)) {
1659  printf("Didn't detect the msg code of new keys (ciphered data starts): ");
1660  goto end;
1661  }
1662 
1663  result = 1;
1664 end:
1665  if (alp_tctx != NULL)
1666  AppLayerParserThreadCtxFree(alp_tctx);
1668  FLOW_DESTROY(&f);
1669  return result;
1670 }
1671 
1672 /** \test Send a banner and 2 records record in four chunks. */
1673 static int SSHParserTest14(void)
1674 {
1675  int result = 0;
1676  Flow f;
1677  uint8_t sshbuf1[] = "SSH-2.0-MySSHClient-0.5.1\r\n";
1678  uint32_t sshlen1 = sizeof(sshbuf1) - 1;
1679  uint8_t sshbuf2[] = { 0x00, 0x00, 0x00, 0x10, 0x01, 17, 0x00};
1680  uint32_t sshlen2 = sizeof(sshbuf2);
1681 
1682  uint8_t sshbuf3[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
1683  uint32_t sshlen3 = sizeof(sshbuf3);
1684  uint8_t sshbuf4[] = { 0x09, 0x10, 0x11, 0x12, 0x13, 0x00};
1685  uint32_t sshlen4 = sizeof(sshbuf4);
1686 
1687  /* first byte of this record in sshbuf4 */
1688  uint8_t sshbuf5[] = { 0x00, 0x00, 0x02, 0x01, 21};
1689  uint32_t sshlen5 = sizeof(sshbuf5);
1690  TcpSession ssn;
1692 
1693  memset(&f, 0, sizeof(f));
1694  memset(&ssn, 0, sizeof(ssn));
1695  FLOW_INITIALIZE(&f);
1696  f.protoctx = (void *)&ssn;
1697 
1699 
1700  FLOWLOCK_WRLOCK(&f);
1701  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH,
1702  STREAM_TOSERVER, sshbuf1, sshlen1);
1703  if (r != 0) {
1704  printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
1705  FLOWLOCK_UNLOCK(&f);
1706  goto end;
1707  }
1708  FLOWLOCK_UNLOCK(&f);
1709  FLOWLOCK_WRLOCK(&f);
1710  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER,
1711  sshbuf2, sshlen2);
1712  if (r != 0) {
1713  printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
1714  FLOWLOCK_UNLOCK(&f);
1715  goto end;
1716  }
1717  FLOWLOCK_UNLOCK(&f);
1718  FLOWLOCK_WRLOCK(&f);
1719  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER,
1720  sshbuf3, sshlen3);
1721  if (r != 0) {
1722  printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
1723  FLOWLOCK_UNLOCK(&f);
1724  goto end;
1725  }
1726  FLOWLOCK_UNLOCK(&f);
1727  FLOWLOCK_WRLOCK(&f);
1728  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER,
1729  sshbuf4, sshlen4);
1730  if (r != 0) {
1731  printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
1732  FLOWLOCK_UNLOCK(&f);
1733  goto end;
1734  }
1735  FLOWLOCK_UNLOCK(&f);
1736  FLOWLOCK_WRLOCK(&f);
1737  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER,
1738  sshbuf5, sshlen5);
1739  if (r != 0) {
1740  printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
1741  FLOWLOCK_UNLOCK(&f);
1742  goto end;
1743  }
1744  FLOWLOCK_UNLOCK(&f);
1745 
1746  SshState *ssh_state = f.alstate;
1747  if (ssh_state == NULL) {
1748  printf("no ssh state: ");
1749  goto end;
1750  }
1751 
1752  if ( !(ssh_state->cli_hdr.flags & SSH_FLAG_VERSION_PARSED)) {
1753  printf("Client version string not parsed: ");
1754  goto end;
1755  }
1756 
1757  if (ssh_state->cli_hdr.software_version == NULL) {
1758  printf("Client version string not parsed: ");
1759  goto end;
1760  }
1761 
1762  if (ssh_state->cli_hdr.proto_version == NULL) {
1763  printf("Client version string not parsed: ");
1764  goto end;
1765  }
1766 
1767  if (strncmp((char*)ssh_state->cli_hdr.software_version, "MySSHClient-0.5.1", strlen("MySSHClient-0.5.1")) != 0) {
1768  printf("Client version string not parsed correctly: ");
1769  goto end;
1770  }
1771 
1772  if (strncmp((char*)ssh_state->cli_hdr.proto_version, "2.0", strlen("2.0")) != 0) {
1773  printf("Client version string not parsed correctly: ");
1774  goto end;
1775  }
1776 
1777  if ( !(ssh_state->cli_hdr.flags & SSH_FLAG_PARSER_DONE)) {
1778  printf("Didn't detect the msg code of new keys (ciphered data starts): ");
1779  goto end;
1780  }
1781 
1782  result = 1;
1783 end:
1784  if (alp_tctx != NULL)
1785  AppLayerParserThreadCtxFree(alp_tctx);
1787  FLOW_DESTROY(&f);
1788  return result;
1789 }
1790 
1791 /** \test Send a banner and 2 records record in four chunks. */
1792 static int SSHParserTest15(void)
1793 {
1794  int result = 0;
1795  Flow f;
1796  uint8_t sshbuf1[] = "SSH-2.0-MySSHClient-0.5.1\r\n";
1797  uint32_t sshlen1 = sizeof(sshbuf1) - 1;
1798  uint8_t sshbuf2[] = { 0x00, 0x00, 0x00, 0x10, 0x01, 17, 0x00};
1799  uint32_t sshlen2 = sizeof(sshbuf2);
1800 
1801  uint8_t sshbuf3[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
1802  uint32_t sshlen3 = sizeof(sshbuf3);
1803  uint8_t sshbuf4[] = { 0x09, 0x10, 0x11, 0x12, 0x13, 0x00};
1804  uint32_t sshlen4 = sizeof(sshbuf4);
1805 
1806  /* first byte of this record in sshbuf4 */
1807  uint8_t sshbuf5[] = { 0x00, 0x00, 0x02, 0x01, 20, 0x00, 0x00, 0x00, 0x02, 0x01, 21};
1808  uint32_t sshlen5 = sizeof(sshbuf5);
1809  TcpSession ssn;
1811 
1812  memset(&f, 0, sizeof(f));
1813  memset(&ssn, 0, sizeof(ssn));
1814  FLOW_INITIALIZE(&f);
1815  f.protoctx = (void *)&ssn;
1816 
1818 
1819  FLOWLOCK_WRLOCK(&f);
1820  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH,
1821  STREAM_TOSERVER, sshbuf1, sshlen1);
1822  if (r != 0) {
1823  printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
1824  FLOWLOCK_UNLOCK(&f);
1825  goto end;
1826  }
1827  FLOWLOCK_UNLOCK(&f);
1828  FLOWLOCK_WRLOCK(&f);
1829  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER,
1830  sshbuf2, sshlen2);
1831  if (r != 0) {
1832  printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
1833  FLOWLOCK_UNLOCK(&f);
1834  goto end;
1835  }
1836  FLOWLOCK_UNLOCK(&f);
1837  FLOWLOCK_WRLOCK(&f);
1838  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER,
1839  sshbuf3, sshlen3);
1840  if (r != 0) {
1841  printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
1842  FLOWLOCK_UNLOCK(&f);
1843  goto end;
1844  }
1845  FLOWLOCK_UNLOCK(&f);
1846  FLOWLOCK_WRLOCK(&f);
1847  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER,
1848  sshbuf4, sshlen4);
1849  if (r != 0) {
1850  printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
1851  FLOWLOCK_UNLOCK(&f);
1852  goto end;
1853  }
1854  FLOWLOCK_UNLOCK(&f);
1855  FLOWLOCK_WRLOCK(&f);
1856  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER,
1857  sshbuf5, sshlen5);
1858  if (r != 0) {
1859  printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
1860  FLOWLOCK_UNLOCK(&f);
1861  goto end;
1862  }
1863  FLOWLOCK_UNLOCK(&f);
1864 
1865  SshState *ssh_state = f.alstate;
1866  if (ssh_state == NULL) {
1867  printf("no ssh state: ");
1868  goto end;
1869  }
1870 
1871  if ( !(ssh_state->cli_hdr.flags & SSH_FLAG_VERSION_PARSED)) {
1872  printf("Client version string not parsed: ");
1873  goto end;
1874  }
1875 
1876  if (ssh_state->cli_hdr.software_version == NULL) {
1877  printf("Client version string not parsed: ");
1878  goto end;
1879  }
1880 
1881  if (ssh_state->cli_hdr.proto_version == NULL) {
1882  printf("Client version string not parsed: ");
1883  goto end;
1884  }
1885 
1886  if (strncmp((char*)ssh_state->cli_hdr.software_version, "MySSHClient-0.5.1", strlen("MySSHClient-0.5.1")) != 0) {
1887  printf("Client version string not parsed correctly: ");
1888  goto end;
1889  }
1890 
1891  if (strncmp((char*)ssh_state->cli_hdr.proto_version, "2.0", strlen("2.0")) != 0) {
1892  printf("Client version string not parsed correctly: ");
1893  goto end;
1894  }
1895 
1896  if ( !(ssh_state->cli_hdr.flags & SSH_FLAG_PARSER_DONE)) {
1897  printf("Didn't detect the msg code of new keys (ciphered data starts): ");
1898  goto end;
1899  }
1900 
1901  result = 1;
1902 end:
1903  if (alp_tctx != NULL)
1904  AppLayerParserThreadCtxFree(alp_tctx);
1906  FLOW_DESTROY(&f);
1907  return result;
1908 }
1909 
1910 /** \test Send toserver a banner and record in three chunks. */
1911 static int SSHParserTest16(void)
1912 {
1913  int result = 0;
1914  Flow f;
1915  uint8_t sshbuf1[] = "SSH-";
1916  uint32_t sshlen1 = sizeof(sshbuf1) - 1;
1917  uint8_t sshbuf2[] = "2.0-MySSHClient-0.5.1\r\n";
1918  uint32_t sshlen2 = sizeof(sshbuf2) - 1;
1919  uint8_t sshbuf3[] = { 0x00, 0x00, 0x00, 0x03,0x01, 21, 0x00};
1920  uint32_t sshlen3 = sizeof(sshbuf3);
1921  TcpSession ssn;
1923 
1924  memset(&f, 0, sizeof(f));
1925  memset(&ssn, 0, sizeof(ssn));
1926  FLOW_INITIALIZE(&f);
1927  f.protoctx = (void *)&ssn;
1928 
1930 
1931  FLOWLOCK_WRLOCK(&f);
1932  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH,
1933  STREAM_TOCLIENT, sshbuf1, sshlen1);
1934  if (r != 0) {
1935  printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
1936  FLOWLOCK_UNLOCK(&f);
1937  goto end;
1938  }
1939  FLOWLOCK_UNLOCK(&f);
1940 
1941  FLOWLOCK_WRLOCK(&f);
1942  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT,
1943  sshbuf2, sshlen2);
1944  if (r != 0) {
1945  printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
1946  FLOWLOCK_UNLOCK(&f);
1947  goto end;
1948  }
1949  FLOWLOCK_UNLOCK(&f);
1950 
1951  FLOWLOCK_WRLOCK(&f);
1952  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT,
1953  sshbuf3, sshlen3);
1954  if (r != 0) {
1955  printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
1956  FLOWLOCK_UNLOCK(&f);
1957  goto end;
1958  }
1959  FLOWLOCK_UNLOCK(&f);
1960 
1961  SshState *ssh_state = f.alstate;
1962  if (ssh_state == NULL) {
1963  printf("no ssh state: ");
1964  goto end;
1965  }
1966 
1967  if (!(ssh_state->srv_hdr.flags & SSH_FLAG_VERSION_PARSED)) {
1968  printf("Client version string not parsed: ");
1969  goto end;
1970  }
1971 
1972  if (ssh_state->srv_hdr.software_version == NULL) {
1973  printf("Client version string not parsed: ");
1974  goto end;
1975  }
1976 
1977  if (ssh_state->srv_hdr.proto_version == NULL) {
1978  printf("Client version string not parsed: ");
1979  goto end;
1980  }
1981 
1982  if (strncmp((char*)ssh_state->srv_hdr.software_version, "MySSHClient-0.5.1", strlen("MySSHClient-0.5.1")) != 0) {
1983  printf("Client version string not parsed correctly: ");
1984  goto end;
1985  }
1986 
1987  if (strncmp((char*)ssh_state->srv_hdr.proto_version, "2.0", strlen("2.0")) != 0) {
1988  printf("Client version string not parsed correctly: ");
1989  goto end;
1990  }
1991 
1992  if ( !(ssh_state->srv_hdr.flags & SSH_FLAG_PARSER_DONE)) {
1993  printf("Didn't detect the msg code of new keys (ciphered data starts): ");
1994  goto end;
1995  }
1996 
1997  result = 1;
1998 end:
1999  if (alp_tctx != NULL)
2000  AppLayerParserThreadCtxFree(alp_tctx);
2002  FLOW_DESTROY(&f);
2003  return result;
2004 }
2005 
2006 /** \test Send toserver a banner and 2 records record in four chunks. */
2007 static int SSHParserTest17(void)
2008 {
2009  int result = 0;
2010  Flow f;
2011  uint8_t sshbuf1[] = "SSH-";
2012  uint32_t sshlen1 = sizeof(sshbuf1) - 1;
2013  uint8_t sshbuf2[] = "2.0-MySSHClient-0.5.1\r\n";
2014  uint32_t sshlen2 = sizeof(sshbuf2) - 1;
2015  uint8_t sshbuf3[] = { 0x00, 0x00, 0x00, 0x03, 0x01, 17, 0x00};
2016  uint32_t sshlen3 = sizeof(sshbuf3);
2017  uint8_t sshbuf4[] = { 0x00, 0x00, 0x00, 0x03, 0x01, 21, 0x00};
2018  uint32_t sshlen4 = sizeof(sshbuf4);
2019  TcpSession ssn;
2021 
2022  memset(&f, 0, sizeof(f));
2023  memset(&ssn, 0, sizeof(ssn));
2024  FLOW_INITIALIZE(&f);
2025  f.protoctx = (void *)&ssn;
2026 
2028 
2029  FLOWLOCK_WRLOCK(&f);
2030  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH,
2031  STREAM_TOCLIENT, sshbuf1, sshlen1);
2032  if (r != 0) {
2033  printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
2034  FLOWLOCK_UNLOCK(&f);
2035  goto end;
2036  }
2037  FLOWLOCK_UNLOCK(&f);
2038 
2039  FLOWLOCK_WRLOCK(&f);
2040  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT,
2041  sshbuf2, sshlen2);
2042  if (r != 0) {
2043  printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
2044  FLOWLOCK_UNLOCK(&f);
2045  goto end;
2046  }
2047  FLOWLOCK_UNLOCK(&f);
2048 
2049  FLOWLOCK_WRLOCK(&f);
2050  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT,
2051  sshbuf3, sshlen3);
2052  if (r != 0) {
2053  printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
2054  FLOWLOCK_UNLOCK(&f);
2055  goto end;
2056  }
2057  FLOWLOCK_UNLOCK(&f);
2058 
2059  FLOWLOCK_WRLOCK(&f);
2060  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT,
2061  sshbuf4, sshlen4);
2062  if (r != 0) {
2063  printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r);
2064  FLOWLOCK_UNLOCK(&f);
2065  goto end;
2066  }
2067  FLOWLOCK_UNLOCK(&f);
2068 
2069  SshState *ssh_state = f.alstate;
2070  if (ssh_state == NULL) {
2071  printf("no ssh state: ");
2072  goto end;
2073  }
2074 
2075  if (!(ssh_state->srv_hdr.flags & SSH_FLAG_VERSION_PARSED)) {
2076  printf("Client version string not parsed: ");
2077  goto end;
2078  }
2079 
2080  if (ssh_state->srv_hdr.software_version == NULL) {
2081  printf("Client version string not parsed: ");
2082  goto end;
2083  }
2084 
2085  if (ssh_state->srv_hdr.proto_version == NULL) {
2086  printf("Client version string not parsed: ");
2087  goto end;
2088  }
2089 
2090  if (strncmp((char*)ssh_state->srv_hdr.software_version, "MySSHClient-0.5.1", strlen("MySSHClient-0.5.1")) != 0) {
2091  printf("Client version string not parsed correctly: ");
2092  goto end;
2093  }
2094 
2095  if (strncmp((char*)ssh_state->srv_hdr.proto_version, "2.0", strlen("2.0")) != 0) {
2096  printf("Client version string not parsed correctly: ");
2097  goto end;
2098  }
2099 
2100  if ( !(ssh_state->srv_hdr.flags & SSH_FLAG_PARSER_DONE)) {
2101  printf("Didn't detect the msg code of new keys (ciphered data starts): ");
2102  goto end;
2103  }
2104 
2105  result = 1;
2106 end:
2107  if (alp_tctx != NULL)
2108  AppLayerParserThreadCtxFree(alp_tctx);
2110  FLOW_DESTROY(&f);
2111  return result;
2112 }
2113 
2114 /** \test 2 directional test */
2115 static int SSHParserTest18(void)
2116 {
2117  int result = 0;
2118  Flow f;
2119 
2120  uint8_t server1[] = "SSH-2.0-OpenSSH_4.7p1 Debian-8ubuntu3\r\n";
2121  uint32_t serverlen1 = sizeof(server1) - 1;
2122 
2123  uint8_t sshbuf1[] = "SSH-";
2124  uint32_t sshlen1 = sizeof(sshbuf1) - 1;
2125  uint8_t sshbuf2[] = "2.0-MySSHClient-0.5.1\r\n";
2126  uint32_t sshlen2 = sizeof(sshbuf2) - 1;
2127 
2128  uint8_t server2[] = { 0x00, 0x00, 0x00, 0x03, 0x01, 21, 0x00 };
2129  uint32_t serverlen2 = sizeof(server2) - 1;
2130 
2131  uint8_t sshbuf3[] = { 0x00, 0x00, 0x00, 0x03, 0x01, 21, 0x00 };
2132  uint32_t sshlen3 = sizeof(sshbuf3);
2133 
2134 
2135  TcpSession ssn;
2137 
2138  memset(&f, 0, sizeof(f));
2139  memset(&ssn, 0, sizeof(ssn));
2140  FLOW_INITIALIZE(&f);
2141  f.protoctx = (void *)&ssn;
2142 
2144 
2145  FLOWLOCK_WRLOCK(&f);
2146  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH,
2147  STREAM_TOCLIENT, server1, serverlen1);
2148  if (r != 0) {
2149  printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r);
2150  FLOWLOCK_UNLOCK(&f);
2151  goto end;
2152  }
2153  FLOWLOCK_UNLOCK(&f);
2154 
2155  FLOWLOCK_WRLOCK(&f);
2156  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER,
2157  sshbuf1, sshlen1);
2158  if (r != 0) {
2159  printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
2160  FLOWLOCK_UNLOCK(&f);
2161  goto end;
2162  }
2163  FLOWLOCK_UNLOCK(&f);
2164 
2165  FLOWLOCK_WRLOCK(&f);
2166  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER,
2167  sshbuf2, sshlen2);
2168  if (r != 0) {
2169  printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
2170  FLOWLOCK_UNLOCK(&f);
2171  goto end;
2172  }
2173  FLOWLOCK_UNLOCK(&f);
2174 
2175  FLOWLOCK_WRLOCK(&f);
2176  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT,
2177  server2, serverlen2);
2178  if (r != 0) {
2179  printf("toclient chunk 2 returned %" PRId32 ", expected 0: ", r);
2180  FLOWLOCK_UNLOCK(&f);
2181  goto end;
2182  }
2183  FLOWLOCK_UNLOCK(&f);
2184 
2185  FLOWLOCK_WRLOCK(&f);
2186  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER,
2187  sshbuf3, sshlen3);
2188  if (r != 0) {
2189  printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
2190  FLOWLOCK_UNLOCK(&f);
2191  goto end;
2192  }
2193  FLOWLOCK_UNLOCK(&f);
2194 
2195  SshState *ssh_state = f.alstate;
2196  if (ssh_state == NULL) {
2197  printf("no ssh state: ");
2198  goto end;
2199  }
2200 
2201  if ( !(ssh_state->cli_hdr.flags & SSH_FLAG_PARSER_DONE)) {
2202  printf("Didn't detect the msg code of new keys (ciphered data starts): ");
2203  goto end;
2204  }
2205 
2206  if ( !(ssh_state->srv_hdr.flags & SSH_FLAG_PARSER_DONE)) {
2207  printf("Didn't detect the msg code of new keys (ciphered data starts): ");
2208  goto end;
2209  }
2210 
2212  printf("detection not disabled: ");
2213  goto end;
2214  }
2215 
2216  result = 1;
2217 end:
2218  if (alp_tctx != NULL)
2219  AppLayerParserThreadCtxFree(alp_tctx);
2221  FLOW_DESTROY(&f);
2222  return result;
2223 }
2224 
2225 /** \test Really long banner handling: bannel exactly 255 */
2226 static int SSHParserTest19(void)
2227 {
2228  int result = 0;
2229  Flow f;
2230  uint8_t sshbuf1[] = "SSH-";
2231  uint32_t sshlen1 = sizeof(sshbuf1) - 1;
2232  uint8_t sshbuf2[] = "2.0-";
2233  uint32_t sshlen2 = sizeof(sshbuf2) - 1; // 8
2234  uint8_t sshbuf3[] = "abcdefghijklmnopqrstuvwxyz"
2235  "abcdefghijklmnopqrstuvwxyz"//60
2236  "abcdefghijklmnopqrstuvwxyz"
2237  "abcdefghijklmnopqrstuvwxyz"//112
2238  "abcdefghijklmnopqrstuvwxyz"
2239  "abcdefghijklmnopqrstuvwxyz"//164
2240  "abcdefghijklmnopqrstuvwxyz"
2241  "abcdefghijklmnopqrstuvwxyz"//216
2242  "abcdefghijklmnopqrstuvwxyz"//242
2243  "abcdefghijkl\r";//255
2244  uint32_t sshlen3 = sizeof(sshbuf3) - 1;
2245 
2246  uint8_t sshbuf4[] = { 0x00, 0x00, 0x00, 0x03, 0x01, 21, 0x00};
2247  uint32_t sshlen4 = sizeof(sshbuf4);
2248  TcpSession ssn;
2250 
2251  memset(&f, 0, sizeof(f));
2252  memset(&ssn, 0, sizeof(ssn));
2253  FLOW_INITIALIZE(&f);
2254  f.protoctx = (void *)&ssn;
2255 
2257 
2258  FLOWLOCK_WRLOCK(&f);
2259  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH,
2260  STREAM_TOCLIENT, sshbuf1, sshlen1);
2261  if (r != 0) {
2262  printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
2263  FLOWLOCK_UNLOCK(&f);
2264  goto end;
2265  }
2266  FLOWLOCK_UNLOCK(&f);
2267 
2268  FLOWLOCK_WRLOCK(&f);
2269  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT,
2270  sshbuf2, sshlen2);
2271  if (r != 0) {
2272  printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
2273  FLOWLOCK_UNLOCK(&f);
2274  goto end;
2275  }
2276  FLOWLOCK_UNLOCK(&f);
2277 
2278  FLOWLOCK_WRLOCK(&f);
2279  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT,
2280  sshbuf3, sshlen3);
2281  if (r != 0) {
2282  printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
2283  FLOWLOCK_UNLOCK(&f);
2284  goto end;
2285  }
2286  FLOWLOCK_UNLOCK(&f);
2287 
2288  FLOWLOCK_WRLOCK(&f);
2289  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT,
2290  sshbuf4, sshlen4);
2291  if (r != 0) {
2292  printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r);
2293  FLOWLOCK_UNLOCK(&f);
2294  goto end;
2295  }
2296  FLOWLOCK_UNLOCK(&f);
2297 
2298  SshState *ssh_state = f.alstate;
2299  if (ssh_state == NULL) {
2300  printf("no ssh state: ");
2301  goto end;
2302  }
2303 
2304  if (!(ssh_state->srv_hdr.flags & SSH_FLAG_VERSION_PARSED)) {
2305  printf("Client version string not parsed: ");
2306  goto end;
2307  }
2308 
2309  if (ssh_state->srv_hdr.software_version == NULL) {
2310  printf("Client version string not parsed: ");
2311  goto end;
2312  }
2313 
2314  if (ssh_state->srv_hdr.proto_version == NULL) {
2315  printf("Client version string not parsed: ");
2316  goto end;
2317  }
2318 
2319  char *name = SCCalloc(1, 256);
2320  if (name == NULL)
2321  goto end;
2322  strlcpy(name, (char *)sshbuf3, 256);
2323  name[strlen(name) - 1] = '\0'; // strip \r
2324 
2325  if (strcmp((char*)ssh_state->srv_hdr.software_version, name) != 0) {
2326  printf("Client version string not parsed correctly: ");
2327  goto end;
2328  }
2329 
2330  if (strncmp((char*)ssh_state->srv_hdr.proto_version, "2.0", strlen("2.0")) != 0) {
2331  printf("Client version string not parsed correctly: ");
2332  goto end;
2333  }
2334 
2335  if ( !(ssh_state->srv_hdr.flags & SSH_FLAG_PARSER_DONE)) {
2336  printf("Didn't detect the msg code of new keys (ciphered data starts): ");
2337  goto end;
2338  }
2339 
2340  result = 1;
2341 end:
2342  if (alp_tctx != NULL)
2343  AppLayerParserThreadCtxFree(alp_tctx);
2345  FLOW_DESTROY(&f);
2346  return result;
2347 }
2348 
2349 /** \test Really long banner handling: banner exactly 255,
2350  * followed by malformed record */
2351 static int SSHParserTest20(void)
2352 {
2353  int result = 0;
2354  Flow f;
2355  uint8_t sshbuf1[] = "SSH-";
2356  uint32_t sshlen1 = sizeof(sshbuf1) - 1;
2357  uint8_t sshbuf2[] = "2.0-";
2358  uint32_t sshlen2 = sizeof(sshbuf2) - 1; // 8
2359  uint8_t sshbuf3[] = "abcdefghijklmnopqrstuvwxyz"
2360  "abcdefghijklmnopqrstuvwxyz"//60
2361  "abcdefghijklmnopqrstuvwxyz"
2362  "abcdefghijklmnopqrstuvwxyz"//112
2363  "abcdefghijklmnopqrstuvwxyz"
2364  "abcdefghijklmnopqrstuvwxyz"//164
2365  "abcdefghijklmnopqrstuvwxyz"
2366  "abcdefghijklmnopqrstuvwxyz"//216
2367  "abcdefghijklmnopqrstuvwxyz"//242
2368  "abcdefghijklm\r";//256
2369  uint32_t sshlen3 = sizeof(sshbuf3) - 1;
2370  uint8_t sshbuf4[] = {'a','b','c','d','e','f', '\r',
2371  0x00, 0x00, 0x00, 0x06, 0x01, 21, 0x00, 0x00, 0x00};
2372  uint32_t sshlen4 = sizeof(sshbuf4) - 1;
2373 
2374  TcpSession ssn;
2376 
2377  memset(&f, 0, sizeof(f));
2378  memset(&ssn, 0, sizeof(ssn));
2379  FLOW_INITIALIZE(&f);
2380  f.protoctx = (void *)&ssn;
2381 
2383 
2384  FLOWLOCK_WRLOCK(&f);
2385  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH,
2386  STREAM_TOCLIENT, sshbuf1, sshlen1);
2387  if (r != 0) {
2388  printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
2389  FLOWLOCK_UNLOCK(&f);
2390  goto end;
2391  }
2392  FLOWLOCK_UNLOCK(&f);
2393 
2394  FLOWLOCK_WRLOCK(&f);
2395  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT,
2396  sshbuf2, sshlen2);
2397  if (r != 0) {
2398  printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
2399  FLOWLOCK_UNLOCK(&f);
2400  goto end;
2401  }
2402  FLOWLOCK_UNLOCK(&f);
2403 
2404  FLOWLOCK_WRLOCK(&f);
2405  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT,
2406  sshbuf3, sshlen3);
2407  if (r != 0) {
2408  printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
2409  FLOWLOCK_UNLOCK(&f);
2410  goto end;
2411  }
2412  FLOWLOCK_UNLOCK(&f);
2413 
2414  SCLogDebug("chunk 4:");
2415  FLOWLOCK_WRLOCK(&f);
2416  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT,
2417  sshbuf4, sshlen4);
2418  if (r != 0) {
2419  printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r);
2420  FLOWLOCK_UNLOCK(&f);
2421  goto end;
2422  }
2423  FLOWLOCK_UNLOCK(&f);
2424 
2425  SshState *ssh_state = f.alstate;
2426  if (ssh_state == NULL) {
2427  printf("no ssh state: ");
2428  goto end;
2429  }
2430 
2431  if (!(ssh_state->srv_hdr.flags & SSH_FLAG_VERSION_PARSED)) {
2432  printf("Client version string not parsed: ");
2433  goto end;
2434  }
2435 
2436  if (ssh_state->srv_hdr.software_version == NULL) {
2437  printf("Client version string not parsed: ");
2438  goto end;
2439  }
2440 
2441  if (ssh_state->srv_hdr.proto_version == NULL) {
2442  printf("Client version string not parsed: ");
2443  goto end;
2444  }
2445 
2446  if (strncmp((char*)ssh_state->srv_hdr.proto_version, "2.0", strlen("2.0")) != 0) {
2447  printf("Client version string not parsed correctly: ");
2448  goto end;
2449  }
2450 
2451  if ((ssh_state->srv_hdr.flags & SSH_FLAG_PARSER_DONE)) {
2452  printf("detected the msg code of new keys (ciphered data starts): ");
2453  goto end;
2454  }
2455  result = 1;
2456 end:
2457  if (alp_tctx != NULL)
2458  AppLayerParserThreadCtxFree(alp_tctx);
2460  FLOW_DESTROY(&f);
2461  return result;
2462 }
2463 
2464 /** \test Fragmented banner handling: chunk has final part of bannel plus
2465  * a record. */
2466 static int SSHParserTest21(void)
2467 {
2468  int result = 0;
2469  Flow f;
2470  uint8_t sshbuf1[] = "SSH-";
2471  uint32_t sshlen1 = sizeof(sshbuf1) - 1;
2472  uint8_t sshbuf2[] = "2.0-";
2473  uint32_t sshlen2 = sizeof(sshbuf2) - 1; // 8
2474  uint8_t sshbuf3[] = "abcdefghijklmnopqrstuvwxyz"
2475  "abcdefghijklmnopqrstuvwxyz"//60
2476  "abcdefghijklmnopqrstuvwxyz"
2477  "abcdefghijklmnopqrstuvwxyz"//112
2478  "abcdefghijklmnopqrstuvwxyz"
2479  "abcdefghijklmnopqrstuvwxyz"//164
2480  "abcdefghijklmnopqrstuvwxyz"
2481  "abcdefghijklmnopqrstuvwxyz"//216
2482  "abcdefghijklmnopqrstuvwxy";//241
2483  uint32_t sshlen3 = sizeof(sshbuf3) - 1;
2484  uint8_t sshbuf4[] = {'l','i','b','s','s','h', '\r',
2485  0x00, 0x00, 0x00, 0x06, 0x01, 21, 0x00, 0x00, 0x00};
2486  uint32_t sshlen4 = sizeof(sshbuf4) - 1;
2487  TcpSession ssn;
2489 
2490  memset(&f, 0, sizeof(f));
2491  memset(&ssn, 0, sizeof(ssn));
2492  FLOW_INITIALIZE(&f);
2493  f.protoctx = (void *)&ssn;
2494 
2496 
2497  FLOWLOCK_WRLOCK(&f);
2498  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH,
2499  STREAM_TOCLIENT, sshbuf1, sshlen1);
2500  if (r != 0) {
2501  printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
2502  FLOWLOCK_UNLOCK(&f);
2503  goto end;
2504  }
2505  FLOWLOCK_UNLOCK(&f);
2506 
2507  FLOWLOCK_WRLOCK(&f);
2508  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT,
2509  sshbuf2, sshlen2);
2510  if (r != 0) {
2511  printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
2512  FLOWLOCK_UNLOCK(&f);
2513  goto end;
2514  }
2515  FLOWLOCK_UNLOCK(&f);
2516 
2517  FLOWLOCK_WRLOCK(&f);
2518  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT,
2519  sshbuf3, sshlen3);
2520  if (r != 0) {
2521  printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
2522  FLOWLOCK_UNLOCK(&f);
2523  goto end;
2524  }
2525  FLOWLOCK_UNLOCK(&f);
2526 
2527  SCLogDebug("chunk 4:");
2528  FLOWLOCK_WRLOCK(&f);
2529  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT,
2530  sshbuf4, sshlen4);
2531  if (r != 0) {
2532  printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r);
2533  FLOWLOCK_UNLOCK(&f);
2534  goto end;
2535  }
2536  FLOWLOCK_UNLOCK(&f);
2537 
2538  SshState *ssh_state = f.alstate;
2539  if (ssh_state == NULL) {
2540  printf("no ssh state: ");
2541  goto end;
2542  }
2543 
2544  if (!(ssh_state->srv_hdr.flags & SSH_FLAG_VERSION_PARSED)) {
2545  printf("Client version string not parsed: ");
2546  goto end;
2547  }
2548 
2549  if (ssh_state->srv_hdr.software_version == NULL) {
2550  printf("Client version string not parsed: ");
2551  goto end;
2552  }
2553 
2554  if (ssh_state->srv_hdr.proto_version == NULL) {
2555  printf("Client version string not parsed: ");
2556  goto end;
2557  }
2558 
2559  if (strncmp((char*)ssh_state->srv_hdr.proto_version, "2.0", strlen("2.0")) != 0) {
2560  printf("Client version string not parsed correctly: ");
2561  goto end;
2562  }
2563 
2564  if ( !(ssh_state->srv_hdr.flags & SSH_FLAG_PARSER_DONE)) {
2565  printf("Didn't detect the msg code of new keys (ciphered data starts): ");
2566  goto end;
2567  }
2568 
2569  result = 1;
2570 end:
2571  if (alp_tctx != NULL)
2572  AppLayerParserThreadCtxFree(alp_tctx);
2574  FLOW_DESTROY(&f);
2575  return result;
2576 }
2577 
2578 /** \test Fragmented banner handling: chunk has final part of bannel plus
2579  * a record. */
2580 static int SSHParserTest22(void)
2581 {
2582  int result = 0;
2583  Flow f;
2584  uint8_t sshbuf1[] = "SSH-";
2585  uint32_t sshlen1 = sizeof(sshbuf1) - 1;
2586  uint8_t sshbuf2[] = "2.0-";
2587  uint32_t sshlen2 = sizeof(sshbuf2) - 1; // 8
2588  uint8_t sshbuf3[] = {
2589  'l', 'i', 'b', 's', 's', 'h', '\r', //7
2590 
2591  0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
2592  0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
2593  0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
2594  0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
2595  0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, //50
2596 
2597  0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
2598  0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
2599  0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
2600  0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
2601  0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, //100
2602 
2603  0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
2604  0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
2605  0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
2606  0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
2607  0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, //150
2608 
2609  0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
2610  0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
2611  0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
2612  0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
2613  0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, //200
2614 
2615  0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
2616  0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
2617  0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
2618  0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
2619  0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00, //250
2620 
2621  0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
2622  0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
2623  0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
2624  0x00, 0x00, 0x00, 0x06, 0x01, 17, 0x00, 0x00, 0x00, 0x00,
2625  0x00, 0x00, 0x00, 0x06, 0x01, 21, 0x00, 0x00, 0x00, 0x00, //300
2626  };
2627  uint32_t sshlen3 = sizeof(sshbuf3) - 1;
2628  TcpSession ssn;
2630 
2631  memset(&f, 0, sizeof(f));
2632  memset(&ssn, 0, sizeof(ssn));
2633  FLOW_INITIALIZE(&f);
2634  f.protoctx = (void *)&ssn;
2635 
2637 
2638  FLOWLOCK_WRLOCK(&f);
2639  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH,
2640  STREAM_TOCLIENT, sshbuf1, sshlen1);
2641  if (r != 0) {
2642  printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
2643  FLOWLOCK_UNLOCK(&f);
2644  goto end;
2645  }
2646  FLOWLOCK_UNLOCK(&f);
2647 
2648  FLOWLOCK_WRLOCK(&f);
2649  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT,
2650  sshbuf2, sshlen2);
2651  if (r != 0) {
2652  printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
2653  FLOWLOCK_UNLOCK(&f);
2654  goto end;
2655  }
2656  FLOWLOCK_UNLOCK(&f);
2657 
2658  FLOWLOCK_WRLOCK(&f);
2659  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT,
2660  sshbuf3, sshlen3);
2661  if (r != 0) {
2662  printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
2663  FLOWLOCK_UNLOCK(&f);
2664  goto end;
2665  }
2666  FLOWLOCK_UNLOCK(&f);
2667 #if 0
2668  SCLogDebug("chunk 4:");
2669  FLOWLOCK_WRLOCK(&f);
2670  r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf4, sshlen4);
2671  if (r != 0) {
2672  printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r);
2673  FLOWLOCK_UNLOCK(&f);
2674  goto end;
2675  }
2676  FLOWLOCK_UNLOCK(&f);
2677 #endif
2678  SshState *ssh_state = f.alstate;
2679  if (ssh_state == NULL) {
2680  printf("no ssh state: ");
2681  goto end;
2682  }
2683 
2684  if (!(ssh_state->srv_hdr.flags & SSH_FLAG_VERSION_PARSED)) {
2685  printf("Client version string not parsed: ");
2686  goto end;
2687  }
2688 
2689  if (ssh_state->srv_hdr.software_version == NULL) {
2690  printf("Client version string not parsed: ");
2691  goto end;
2692  }
2693 
2694  if (ssh_state->srv_hdr.proto_version == NULL) {
2695  printf("Client version string not parsed: ");
2696  goto end;
2697  }
2698 
2699  if (strncmp((char*)ssh_state->srv_hdr.proto_version, "2.0", strlen("2.0")) != 0) {
2700  printf("Client version string not parsed correctly: ");
2701  goto end;
2702  }
2703 
2704  if ( !(ssh_state->srv_hdr.flags & SSH_FLAG_PARSER_DONE)) {
2705  printf("Didn't detect the msg code of new keys (ciphered data starts): ");
2706  goto end;
2707  }
2708 
2709  result = 1;
2710 end:
2711  if (alp_tctx != NULL)
2712  AppLayerParserThreadCtxFree(alp_tctx);
2714  FLOW_DESTROY(&f);
2715  return result;
2716 }
2717 
2718 /** \test Send a version string in one chunk (client version str). */
2719 static int SSHParserTest23(void)
2720 {
2721  int result = 0;
2722  Flow f;
2723  uint8_t sshbuf[] = "SSH-2.0\r-MySSHClient-0.5.1\n";
2724  uint32_t sshlen = sizeof(sshbuf) - 1;
2725  TcpSession ssn;
2727 
2728  memset(&f, 0, sizeof(f));
2729  memset(&ssn, 0, sizeof(ssn));
2730  FLOW_INITIALIZE(&f);
2731  f.protoctx = (void *)&ssn;
2732 
2734 
2735  FLOWLOCK_WRLOCK(&f);
2736  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH,
2737  STREAM_TOSERVER | STREAM_EOF, sshbuf, sshlen);
2738  if (r == 0) {
2739  printf("toclient chunk 1 returned 0 expected non null: ");
2740  FLOWLOCK_UNLOCK(&f);
2741  goto end;
2742  }
2743  FLOWLOCK_UNLOCK(&f);
2744 
2745  result = 1;
2746 end:
2747  if (alp_tctx != NULL)
2748  AppLayerParserThreadCtxFree(alp_tctx);
2750  FLOW_DESTROY(&f);
2751  return result;
2752 }
2753 
2754 /** \test Send a version string in one chunk (client version str). */
2755 static int SSHParserTest24(void)
2756 {
2757  int result = 0;
2758  Flow f;
2759  uint8_t sshbuf[] = "SSH-2.0-\rMySSHClient-0.5.1\n";
2760  uint32_t sshlen = sizeof(sshbuf) - 1;
2761  TcpSession ssn;
2763 
2764  memset(&f, 0, sizeof(f));
2765  memset(&ssn, 0, sizeof(ssn));
2766  FLOW_INITIALIZE(&f);
2767  f.protoctx = (void *)&ssn;
2768 
2770 
2771  FLOWLOCK_WRLOCK(&f);
2772  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH,
2773  STREAM_TOSERVER | STREAM_EOF, sshbuf, sshlen);
2774  if (r != 0) {
2775  printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r);
2776  FLOWLOCK_UNLOCK(&f);
2777  goto end;
2778  }
2779  FLOWLOCK_UNLOCK(&f);
2780 
2781  SshState *ssh_state = f.alstate;
2782  if (ssh_state == NULL) {
2783  printf("no ssh state: ");
2784  goto end;
2785  }
2786 
2787  if ( !(ssh_state->cli_hdr.flags & SSH_FLAG_VERSION_PARSED)) {
2788  printf("Client version string not parsed: ");
2789  goto end;
2790  }
2791 
2792  if (ssh_state->cli_hdr.software_version) {
2793  printf("Client version string should not be parsed: ");
2794  goto end;
2795  }
2796 
2797  result = 1;
2798 end:
2799  if (alp_tctx != NULL)
2800  AppLayerParserThreadCtxFree(alp_tctx);
2802  FLOW_DESTROY(&f);
2803  return result;
2804 }
2805 
2806 
2807 #endif /* UNITTESTS */
2808 
2810 {
2811 #ifdef UNITTESTS
2812  UtRegisterTest("SSHParserTest01 - ToServer", SSHParserTest01);
2813  UtRegisterTest("SSHParserTest02 - ToServer", SSHParserTest02);
2814  UtRegisterTest("SSHParserTest03 - ToServer", SSHParserTest03);
2815  UtRegisterTest("SSHParserTest04 - ToClient", SSHParserTest04);
2816  UtRegisterTest("SSHParserTest05 - ToClient", SSHParserTest05);
2817  UtRegisterTest("SSHParserTest06 - ToClient", SSHParserTest06);
2818  UtRegisterTest("SSHParserTest07 - ToServer 2 chunks", SSHParserTest07);
2819  UtRegisterTest("SSHParserTest08 - ToServer 3 chunks", SSHParserTest08);
2820  UtRegisterTest("SSHParserTest09 - ToClient 2 chunks", SSHParserTest09);
2821  UtRegisterTest("SSHParserTest10 - ToClient 3 chunks", SSHParserTest10);
2822  UtRegisterTest("SSHParserTest11 - ToClient 4 chunks", SSHParserTest11);
2823  UtRegisterTest("SSHParserTest12 - ToClient 4 chunks", SSHParserTest12);
2824  UtRegisterTest("SSHParserTest13 - ToClient 4 chunks", SSHParserTest13);
2825  UtRegisterTest("SSHParserTest14 - ToClient 4 chunks", SSHParserTest14);
2826  UtRegisterTest("SSHParserTest15", SSHParserTest15);
2827  UtRegisterTest("SSHParserTest16", SSHParserTest16);
2828  UtRegisterTest("SSHParserTest17", SSHParserTest17);
2829  UtRegisterTest("SSHParserTest18", SSHParserTest18);
2830  UtRegisterTest("SSHParserTest19", SSHParserTest19);
2831  UtRegisterTest("SSHParserTest20", SSHParserTest20);
2832  UtRegisterTest("SSHParserTest21", SSHParserTest21);
2833  UtRegisterTest("SSHParserTest22", SSHParserTest22);
2834  UtRegisterTest("SSHParserTest23", SSHParserTest23);
2835  UtRegisterTest("SSHParserTest24", SSHParserTest24);
2836 #endif /* UNITTESTS */
2837 }
2838 
uint32_t logged
Definition: app-layer-ssh.h:77
#define SSH_MSG_NEWKEYS
Definition: app-layer-ssh.h:36
uint16_t flags
#define SCMemcmp(a, b, c)
Definition: util-memcmp.h:490
SshHeader cli_hdr
Definition: app-layer-ssh.h:74
#define SCLogDebug(...)
Definition: util-debug.h:335
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: util-strlcpyu.c:43
void AppLayerParserRegisterGetStateProgressFunc(uint8_t ipproto, AppProto alproto, int(*StateGetProgress)(void *alstate, uint8_t direction))
#define BUG_ON(x)
#define FALSE
LoggerId
#define FLOWLOCK_UNLOCK(fb)
Definition: flow.h:235
int logged
#define unlikely(expr)
Definition: util-optimize.h:35
int AppLayerProtoDetectConfProtoDetectionEnabled(const char *ipproto, const char *alproto)
Given a protocol name, checks if proto detection is enabled in the conf file.
void AppLayerParserRegisterDetectFlagsFuncs(uint8_t ipproto, AppProto alproto, uint64_t(*GetTxDetectFlags)(void *tx, uint8_t dir), void(*SetTxDetectFlags)(void *tx, uint8_t dir, uint64_t))
int AppLayerParserStateIssetFlag(AppLayerParserState *pstate, uint8_t flag)
uint8_t * proto_version
Definition: app-layer-ssh.h:60
void AppLayerParserRegisterParserAcceptableDataDirection(uint8_t ipproto, AppProto alproto, uint8_t direction)
void AppLayerParserRegisterDetectStateFuncs(uint8_t ipproto, AppProto alproto, DetectEngineState *(*GetTxDetectState)(void *tx), int(*SetTxDetectState)(void *tx, DetectEngineState *))
void RegisterSSHParsers(void)
Function to register the SSH protocol parsers and other functions.
uint8_t msg_code
Definition: app-layer-ssh.h:54
#define APP_LAYER_PARSER_BYPASS_READY
void AppLayerParserThreadCtxFree(AppLayerParserThreadCtx *tctx)
Destroys the app layer parser thread context obtained using AppLayerParserThreadCtxAlloc().
void StreamTcpFreeConfig(char quiet)
Definition: stream-tcp.c:669
#define FLOWLOCK_WRLOCK(fb)
Definition: flow.h:232
uint32_t record_left
Definition: app-layer-ssh.h:59
void AppLayerParserRegisterLoggerFuncs(uint8_t ipproto, AppProto alproto, LoggerId(*StateGetTxLogged)(void *, void *), void(*StateSetTxLogged)(void *, void *, LoggerId))
#define TRUE
uint8_t * BasicSearch(const uint8_t *haystack, uint32_t haystack_len, const uint8_t *needle, uint16_t needle_len)
Basic search improved. Limits are better handled, so it doesn&#39;t start searches that wont fit in the r...
Definition: util-spm-bs.c:48
void * protoctx
Definition: flow.h:398
void * alstate
Definition: flow.h:436
#define APP_LAYER_PARSER_NO_REASSEMBLY
int AppLayerParserConfParserEnabled(const char *ipproto, const char *alproto_name)
check if a parser is enabled in the config Returns enabled always if: were running unittests and when...
#define SCCalloc(nm, a)
Definition: util-mem.h:205
int AppLayerParserRegisterParser(uint8_t ipproto, AppProto alproto, uint8_t direction, AppLayerParserFPtr Parser)
Register app layer parser for the protocol.
#define SSH_FLAG_VERSION_PARSED
Definition: app-layer-ssh.h:29
void AppLayerParserRegisterGetTx(uint8_t ipproto, AppProto alproto, void *(StateGetTx)(void *alstate, uint64_t tx_id))
SshHeader srv_hdr
Definition: app-layer-ssh.h:73
#define FLOW_DESTROY(f)
Definition: flow-util.h:115
#define STREAM_EOF
Definition: stream.h:30
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
#define APP_LAYER_PARSER_NO_INSPECTION
#define SCEnter(...)
Definition: util-debug.h:337
void StreamTcpInitConfig(char)
To initialize the stream global configuration data.
Definition: stream-tcp.c:365
uint8_t * software_version
Definition: app-layer-ssh.h:61
#define STREAM_TOCLIENT
Definition: stream.h:32
void AppLayerParserRegisterGetStateProgressCompletionStatus(AppProto alproto, int(*StateGetProgressCompletionStatus)(uint8_t direction))
AppLayerParserThreadCtx * AppLayerParserThreadCtxAlloc(void)
Gets a new app layer protocol&#39;s parser thread context.
#define MAX_BANNER_LEN
#define BYTE_BIG_ENDIAN
Definition: util-byte.h:29
void DetectEngineStateFree(DetectEngineState *state)
Frees a DetectEngineState object.
uint16_t banner_len
Definition: app-layer-ssh.h:55
uint64_t detect_flags_ts
Definition: app-layer-ssh.h:79
uint8_t * banner_buffer
Definition: app-layer-ssh.h:62
#define SCReturnInt(x)
Definition: util-debug.h:341
uint8_t flags
Definition: app-layer-ssh.h:58
DetectEngineState * de_state
Definition: app-layer-ssh.h:82
#define SCMalloc(a)
Definition: util-mem.h:174
uint8_t buf[6]
Definition: app-layer-ssh.h:56
void AppLayerProtoDetectRegisterProtocol(AppProto alproto, const char *alproto_name)
Registers a protocol for protocol detection phase.
#define SCFree(a)
Definition: util-mem.h:236
uint16_t tx_id
#define SSH_FLAG_PARSER_DONE
Definition: app-layer-ssh.h:33
void AppLayerParserRegisterProtocolUnittests(uint8_t ipproto, AppProto alproto, void(*RegisterUnittests)(void))
#define FLOW_INITIALIZE(f)
Definition: flow-util.h:39
#define STREAM_TOSERVER
Definition: stream.h:31
uint8_t buf_offset
Definition: app-layer-ssh.h:57
#define APP_LAYER_PARSER_EOF
int AppLayerProtoDetectPMRegisterPatternCI(uint8_t ipproto, AppProto alproto, const char *pattern, uint16_t depth, uint16_t offset, uint8_t direction)
Registers a case-insensitive pattern for protocol detection.
uint8_t padding_len
Definition: app-layer-ssh.h:53
void AppLayerParserRegisterGetTxCnt(uint8_t ipproto, AppProto alproto, uint64_t(*StateGetTxCnt)(void *alstate))
void AppLayerParserRegisterStateFuncs(uint8_t ipproto, AppProto alproto, void *(*StateAlloc)(void), void(*StateFree)(void *))
uint8_t len
uint32_t pkt_len
Definition: app-layer-ssh.h:52
uint64_t detect_flags_tc
Definition: app-layer-ssh.h:80
void SSHParserRegisterTests(void)
Flow data structure.
Definition: flow.h:327
void AppLayerParserStateSetFlag(AppLayerParserState *pstate, uint8_t flag)
AppLayerParserState * alparser
Definition: flow.h:435
int AppLayerParserParse(ThreadVars *tv, AppLayerParserThreadCtx *alp_tctx, Flow *f, AppProto alproto, uint8_t flags, uint8_t *input, uint32_t input_len)
int ByteExtractUint32(uint32_t *res, int e, uint16_t len, const uint8_t *bytes)
Definition: util-byte.c:95
void AppLayerParserRegisterTxFreeFunc(uint8_t ipproto, AppProto alproto, void(*StateTransactionFree)(void *, uint64_t))