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