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