ssh_transport.c
Go to the documentation of this file.
1 /**
2  * @file ssh_transport.c
3  * @brief SSH transport layer protocol
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2019-2026 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneSSH Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 2.6.6
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL SSH_TRACE_LEVEL
33 
34 //Dependencies
35 #include "ssh/ssh.h"
36 #include "ssh/ssh_transport.h"
37 #include "ssh/ssh_packet.h"
38 #include "ssh/ssh_misc.h"
39 #include "debug.h"
40 
41 //Check SSH stack configuration
42 #if (SSH_SUPPORT == ENABLED)
43 
44 
45 /**
46  * @brief Send identification string
47  * @param[in] connection Pointer to the SSH connection
48  * @return Error code
49  **/
50 
52 {
53  size_t n;
54 
55  //The identification string must be terminated by a single CR and a single
56  //LF character (refer to RFC 4253, section 4.2)
57  n = osSprintf((char_t *) connection->buffer, "%s\r\n", CYCLONE_SSH_ID);
58 
59  //Save the length of the identification string
60  connection->txBufferLen = n;
61  connection->txBufferPos = 0;
62 
63  //Check whether SSH operates as a client or a server
64  if(connection->context->mode == SSH_OPERATION_MODE_CLIENT)
65  {
66  //Debug message
67  TRACE_INFO("Sending client ID string (%" PRIuSIZE " bytes)...\r\n",
69 
70  //Dump identification string
71  TRACE_INFO(" %s\r\n", CYCLONE_SSH_ID);
72 
73  //Wait for the server's identification string
74  connection->state = SSH_CONN_STATE_SERVER_ID;
75  }
76  else
77  {
78  //Debug message
79  TRACE_INFO("Sending server ID string (%" PRIuSIZE " bytes)...\r\n",
81 
82  //Dump identification string
83  TRACE_INFO(" %s\r\n", CYCLONE_SSH_ID);
84 
85  //Wait for the client's identification string
86  connection->state = SSH_CONN_STATE_CLIENT_ID;
87  }
88 
89  //Successful processing
90  return NO_ERROR;
91 }
92 
93 
94 /**
95  * @brief Send SSH_MSG_SERVICE_REQUEST message
96  * @param[in] connection Pointer to the SSH connection
97  * @return Error code
98  **/
99 
101 {
102  error_t error;
103  size_t length;
104  uint8_t *message;
105 
106  //Point to the buffer where to format the message
107  message = connection->buffer + SSH_PACKET_HEADER_SIZE;
108 
109  //Format SSH_MSG_SERVICE_REQUEST message
110  error = sshFormatServiceRequest(connection, message, &length);
111 
112  //Check status code
113  if(!error)
114  {
115  //Debug message
116  TRACE_INFO("Sending SSH_MSG_SERVICE_REQUEST message (%" PRIuSIZE " bytes)...\r\n", length);
118 
119  //Send message
120  error = sshSendPacket(connection, message, length);
121  }
122 
123  //Check status code
124  if(!error)
125  {
126 #if (SSH_EXT_INFO_SUPPORT == ENABLED)
127  //If the client offers "ext-info-c", it must be prepared to accept an
128  //SSH_MSG_EXT_INFO message from the server
129  connection->state = SSH_CONN_STATE_SERVER_EXT_INFO_1;
130 #else
131  //If the server supports the service (and permits the client to use
132  //it), it must respond with an SSH_MSG_SERVICE_ACCEPT message
133  connection->state = SSH_CONN_STATE_SERVICE_ACCEPT;
134 #endif
135  }
136 
137  //Return status code
138  return error;
139 }
140 
141 
142 /**
143  * @brief Send SSH_MSG_SERVICE_ACCEPT message
144  * @param[in] connection Pointer to the SSH connection
145  * @param[in] serviceName NULL-terminating string that contains the service name
146  * @return Error code
147  **/
148 
150  const char_t *serviceName)
151 {
152  error_t error;
153  size_t length;
154  uint8_t *message;
155 
156  //Point to the buffer where to format the message
157  message = connection->buffer + SSH_PACKET_HEADER_SIZE;
158 
159  //Format SSH_MSG_SERVICE_ACCEPT message
160  error = sshFormatServiceAccept(connection, serviceName, message, &length);
161 
162  //Check status code
163  if(!error)
164  {
165  //Debug message
166  TRACE_INFO("Sending SSH_MSG_SERVICE_ACCEPT message (%" PRIuSIZE " bytes)...\r\n", length);
168 
169  //Send message
170  error = sshSendPacket(connection, message, length);
171  }
172 
173  //Check status code
174  if(!error)
175  {
176  //The authentication protocol is intended to be run over the SSH transport
177  //layer protocol (refer to RFC 4252, section 1)
178  connection->state = SSH_CONN_STATE_USER_AUTH_REQUEST;
179  }
180 
181  //Return status code
182  return error;
183 }
184 
185 
186 /**
187  * @brief Send SSH_MSG_DISCONNECT message
188  * @param[in] connection Pointer to the SSH connection
189  * @param[in] reasonCode Reason in a machine-readable format
190  * @param[in] description Specific explanation in a human-readable form
191  * @return Error code
192  **/
193 
195  uint32_t reasonCode, const char_t *description)
196 {
197  error_t error;
198  size_t length;
199  uint8_t *message;
200 
201  //Point to the buffer where to format the message
202  message = connection->buffer + SSH_PACKET_HEADER_SIZE;
203 
204  //Format SSH_MSG_DISCONNECT message
205  error = sshFormatDisconnect(connection, reasonCode, description, message,
206  &length);
207 
208  //Check status code
209  if(!error)
210  {
211  //Debug message
212  TRACE_INFO("Sending SSH_MSG_DISCONNECT message (%" PRIuSIZE " bytes)...\r\n", length);
214 
215  //Send message
216  error = sshSendPacket(connection, message, length);
217  }
218 
219  //Check status code
220  if(!error)
221  {
222  //An SSH_MSG_DISCONNECT message has been successfully sent
223  connection->disconnectSent = TRUE;
224 
225  //This message causes immediate termination of the connection
226  connection->state = SSH_CONN_STATE_DISCONNECT;
227  }
228 
229  //Return status code
230  return error;
231 }
232 
233 
234 /**
235  * @brief Send SSH_MSG_UNIMPLEMENTED message
236  * @param[in] connection Pointer to the SSH connection
237  * @param[in] packetSeqNum Packet sequence number of rejected message
238  * @return Error code
239  **/
240 
242  const uint8_t *packetSeqNum)
243 {
244  error_t error;
245  size_t length;
246  uint8_t *message;
247 
248  //Point to the buffer where to format the message
249  message = connection->buffer + SSH_PACKET_HEADER_SIZE;
250 
251  //Format SSH_MSG_UNIMPLEMENTED message
252  error = sshFormatUnimplemented(connection, packetSeqNum, message, &length);
253 
254  //Check status code
255  if(!error)
256  {
257  //Debug message
258  TRACE_INFO("Sending SSH_MSG_UNIMPLEMENTED message (%" PRIuSIZE " bytes)...\r\n", length);
260 
261  //Send message
262  error = sshSendPacket(connection, message, length);
263  }
264 
265  //Return status code
266  return error;
267 }
268 
269 
270 /**
271  * @brief Format SSH_MSG_SERVICE_REQUEST message
272  * @param[in] connection Pointer to the SSH connection
273  * @param[out] p Buffer where to format the message
274  * @param[out] length Length of the resulting message, in bytes
275  * @return Error code
276  **/
277 
279  size_t *length)
280 {
281  error_t error;
282  size_t n;
283 
284  //Total length of the message
285  *length = 0;
286 
287  //Set message type
289 
290  //Point to the first field of the message
291  p += sizeof(uint8_t);
292  *length += sizeof(uint8_t);
293 
294  //Copy service name
295  error = sshFormatString("ssh-userauth", p, &n);
296  //Any error to report?
297  if(error)
298  return error;
299 
300  //Total length of the message
301  *length += n;
302 
303  //Successful processing
304  return NO_ERROR;
305 }
306 
307 
308 /**
309  * @brief Format SSH_MSG_SERVICE_ACCEPT message
310  * @param[in] connection Pointer to the SSH connection
311  * @param[in] serviceName NULL-terminating string that contains the service name
312  * @param[out] p Buffer where to format the message
313  * @param[out] length Length of the resulting message, in bytes
314  * @return Error code
315  **/
316 
318  const char_t *serviceName, uint8_t *p, size_t *length)
319 {
320  error_t error;
321  size_t n;
322 
323  //Total length of the message
324  *length = 0;
325 
326  //Set message type
328 
329  //Point to the first field of the message
330  p += sizeof(uint8_t);
331  *length += sizeof(uint8_t);
332 
333  //Copy service name
334  error = sshFormatString(serviceName, p, &n);
335  //Any error to report?
336  if(error)
337  return error;
338 
339  //Total length of the message
340  *length += n;
341 
342  //Successful processing
343  return NO_ERROR;
344 }
345 
346 
347 /**
348  * @brief Format SSH_MSG_DISCONNECT message
349  * @param[in] connection Pointer to the SSH connection
350  * @param[in] reasonCode Reason in a machine-readable format
351  * @param[in] description Specific explanation in a human-readable form
352  * @param[out] p Buffer where to format the message
353  * @param[out] length Length of the resulting message, in bytes
354  * @return Error code
355  **/
356 
357 error_t sshFormatDisconnect(SshConnection *connection, uint32_t reasonCode,
358  const char_t *description, uint8_t *p, size_t *length)
359 {
360  error_t error;
361  size_t n;
362 
363  //Total length of the message
364  *length = 0;
365 
366  //Set message type
367  p[0] = SSH_MSG_DISCONNECT;
368 
369  //Point to the first field of the message
370  p += sizeof(uint8_t);
371  *length += sizeof(uint8_t);
372 
373  //Copy the reason code
374  STORE32BE(reasonCode, p);
375 
376  //Point to the next field
377  p += sizeof(uint32_t);
378  *length += sizeof(uint32_t);
379 
380  //Copy description string
381  error = sshFormatString(description, p, &n);
382  //Any error to report?
383  if(error)
384  return error;
385 
386  //Point to the next field
387  p += n;
388  *length += n;
389 
390  //Format language tag
391  error = sshFormatString("en", p, &n);
392  //Any error to report?
393  if(error)
394  return error;
395 
396  //Total length of the message
397  *length += n;
398 
399  //Successful processing
400  return NO_ERROR;
401 }
402 
403 
404 /**
405  * @brief Format SSH_MSG_UNIMPLEMENTED message
406  * @param[in] connection Pointer to the SSH connection
407  * @param[in] packetSeqNum Packet sequence number of rejected message
408  * @param[out] p Buffer where to format the message
409  * @param[out] length Length of the resulting message, in bytes
410  * @return Error code
411  **/
412 
414  const uint8_t *packetSeqNum, uint8_t *p, size_t *length)
415 {
416  //Total length of the message
417  *length = 0;
418 
419  //Set message type
421 
422  //Point to the first field of the message
423  p += sizeof(uint8_t);
424  *length += sizeof(uint8_t);
425 
426  //Copy the packet sequence number of the rejected message
427  osMemcpy(p, packetSeqNum, sizeof(uint32_t));
428 
429  //Total length of the message
430  *length += sizeof(uint32_t);
431 
432  //Successful processing
433  return NO_ERROR;
434 }
435 
436 
437 /**
438  * @brief Parse identification string
439  * @param[in] connection Pointer to the SSH connection
440  * @param[in] id Pointer to the identification string
441  * @param[in] length Length of the identification string
442  * @return Error code
443  **/
444 
445 error_t sshParseIdString(SshConnection *connection, const uint8_t *id,
446  size_t length)
447 {
448  //Check the length of the client's identification string
449  if(length < 2)
450  return ERROR_WRONG_IDENTIFIER;
451 
452  //The identification string must be terminated by a single CR and a single
453  //LF character (refer to RFC 4253, section 4.2). In practice, some SSH 2.0
454  //implementations terminate the string with a LF character only
455  if(id[length - 1] != '\n')
456  return ERROR_WRONG_IDENTIFIER;
457 
458  //Trim the trailing LF character from the string
459  length--;
460 
461  //Trim the trailing CR character from the string
462  if(id[length - 1] == '\r')
463  {
464  length--;
465  }
466 
467  //Sanity check
468  if(length > SSH_MAX_ID_LEN)
469  return ERROR_WRONG_IDENTIFIER;
470 
471  //Copy the peer's identification string
472  osMemcpy(connection->remoteId, id, length);
473  //Properly terminate the string with a NULL character
474  connection->remoteId[length] = '\0';
475 
476  //Check whether SSH operates as a client or a server
477  if(connection->context->mode == SSH_OPERATION_MODE_CLIENT)
478  {
479  //Debug message
480  TRACE_INFO("Server ID string received (%" PRIuSIZE " bytes)...\r\n",
481  length);
482  }
483  else
484  {
485  //Debug message
486  TRACE_INFO("Client ID string received (%" PRIuSIZE " bytes)...\r\n",
487  length);
488  }
489 
490  //Dump identification string
491  TRACE_INFO(" %s\r\n", connection->remoteId);
492 
493  //Clients using protocol 2.0 must be able to identify protocol version
494  //"1.99" as identical to "2.0" (refer to RFC 4253, section 5.1)
495  if(osStrncmp(connection->remoteId, "SSH-2.0-", 8) != 0 &&
496  osStrncmp(connection->remoteId, "SSH-1.99-", 9) != 0)
497  {
498  //The version advertised by the server is not supported
499  return ERROR_WRONG_IDENTIFIER;
500  }
501 
502  //Key exchange begins by each side sending a KEXINIT message
503  if(connection->context->mode == SSH_OPERATION_MODE_CLIENT)
504  {
505  connection->state = SSH_CONN_STATE_CLIENT_KEX_INIT;
506  }
507  else
508  {
509  connection->state = SSH_CONN_STATE_SERVER_KEX_INIT;
510  }
511 
512  //Successful processing
513  return NO_ERROR;
514 }
515 
516 
517 /**
518  * @brief Parse SSH_MSG_SERVICE_REQUEST message
519  * @param[in] connection Pointer to the SSH connection
520  * @param[in] message Pointer to message
521  * @param[in] length Length of the message, in bytes
522  * @return Error code
523  **/
524 
526  size_t length)
527 {
528 #if (SSH_SERVER_SUPPORT == ENABLED)
529  error_t error;
530  const uint8_t *p;
531  SshString serviceName;
532 
533  //Debug message
534  TRACE_INFO("SSH_MSG_SERVICE_REQUEST message received (%" PRIuSIZE " bytes)...\r\n", length);
536 
537  //Check operation mode
538  if(connection->context->mode != SSH_OPERATION_MODE_SERVER)
540 
541  //Check connection state
542  if(connection->state != SSH_CONN_STATE_CLIENT_EXT_INFO &&
543  connection->state != SSH_CONN_STATE_SERVICE_REQUEST)
544  {
546  }
547 
548  //Sanity check
549  if(length < sizeof(uint8_t))
550  return ERROR_INVALID_MESSAGE;
551 
552  //Point to the first field of the message
553  p = message + sizeof(uint8_t);
554  //Remaining bytes to process
555  length -= sizeof(uint8_t);
556 
557  //Decode the service name
558  error = sshParseString(p, length, &serviceName);
559  //Any error to report?
560  if(error)
561  return error;
562 
563  //Point to the next field
564  p += sizeof(uint32_t) + serviceName.length;
565  length -= sizeof(uint32_t) + serviceName.length;
566 
567  //Malformed message?
568  if(length != 0)
569  return ERROR_INVALID_MESSAGE;
570 
571  //The service is identified by a name
572  if(sshCompareString(&serviceName, "ssh-userauth"))
573  {
574  //If the server supports the service (and permits the client to use it),
575  //it must respond with an SSH_MSG_SERVICE_ACCEPT message
576  error = sshSendServiceAccept(connection, "ssh-userauth");
577  }
578  else
579  {
580  //If the server rejects the service request, it should send an
581  //appropriate SSH_MSG_DISCONNECT message and must disconnect
583  "Service not available");
584  }
585 
586  //Return status code
587  return error;
588 #else
589  //Server operation mode is not implemented
590  return ERROR_NOT_IMPLEMENTED;
591 #endif
592 }
593 
594 
595 /**
596  * @brief Parse SSH_MSG_SERVICE_ACCEPT message
597  * @param[in] connection Pointer to the SSH connection
598  * @param[in] message Pointer to message
599  * @param[in] length Length of the message, in bytes
600  * @return Error code
601  **/
602 
604  size_t length)
605 {
606 #if (SSH_CLIENT_SUPPORT == ENABLED)
607  error_t error;
608  const uint8_t *p;
609  SshString serviceName;
610 
611  //Debug message
612  TRACE_INFO("SSH_MSG_SERVICE_ACCEPT message received (%" PRIuSIZE " bytes)...\r\n", length);
614 
615  //Check operation mode
616  if(connection->context->mode != SSH_OPERATION_MODE_CLIENT)
618 
619  //Check connection state
620  if(connection->state != SSH_CONN_STATE_SERVER_EXT_INFO_1 &&
621  connection->state != SSH_CONN_STATE_SERVICE_ACCEPT)
622  {
624  }
625 
626  //Sanity check
627  if(length < sizeof(uint8_t))
628  return ERROR_INVALID_MESSAGE;
629 
630  //Point to the first field of the message
631  p = message + sizeof(uint8_t);
632  //Remaining bytes to process
633  length -= sizeof(uint8_t);
634 
635  //Decode service name
636  error = sshParseString(p, length, &serviceName);
637  //Any error to report?
638  if(error)
639  return error;
640 
641  //Point to the next field
642  p += sizeof(uint32_t) + serviceName.length;
643  length -= sizeof(uint32_t) + serviceName.length;
644 
645  //Malformed message?
646  if(length != 0)
647  return ERROR_INVALID_MESSAGE;
648 
649  //Check service name
650  if(!sshCompareString(&serviceName, "ssh-userauth"))
651  return ERROR_INVALID_MESSAGE;
652 
653  //The authentication protocol is intended to be run over the SSH transport
654  //layer protocol (refer to RFC 4252, section 1)
655  connection->state = SSH_CONN_STATE_USER_AUTH_REQUEST;
656 
657  //Successful processing
658  return NO_ERROR;
659 #else
660  //Client operation mode is not implemented
661  return ERROR_NOT_IMPLEMENTED;
662 #endif
663 }
664 
665 
666 /**
667  * @brief Parse SSH_MSG_IGNORE message
668  * @param[in] connection Pointer to the SSH connection
669  * @param[in] message Pointer to message
670  * @param[in] length Length of the message, in bytes
671  * @return Error code
672  **/
673 
674 error_t sshParseIgnore(SshConnection *connection, const uint8_t *message,
675  size_t length)
676 {
677  error_t error;
678  const uint8_t *p;
679  SshString data;
680 
681  //Debug message
682  TRACE_DEBUG("SSH_MSG_IGNORE message received (%" PRIuSIZE " bytes)...\r\n", length);
684 
685 #if (SSH_KEX_STRICT_SUPPORT == ENABLED)
686  //Strict key exchange?
687  if(!connection->newKeysReceived && connection->kexStrictReceived)
688  {
689  //During initial KEX, terminate the connection if any unexpected or
690  //out-of-sequence packet is received
692  }
693 #endif
694 
695  //Sanity check
696  if(length < sizeof(uint8_t))
697  return ERROR_INVALID_MESSAGE;
698 
699  //Point to the first field of the message
700  p = message + sizeof(uint8_t);
701  //Remaining bytes to process
702  length -= sizeof(uint8_t);
703 
704  //Decode data field
705  error = sshParseString(p, length, &data);
706  //Any error to report?
707  if(error)
708  return error;
709 
710  //Point to the next field
711  p += sizeof(uint32_t) + data.length;
712  length -= sizeof(uint32_t) + data.length;
713 
714  //Malformed message?
715  if(length != 0)
716  return ERROR_INVALID_MESSAGE;
717 
718  //All implementations must understand (and ignore) this message at any time
719  //after receiving the identification string. This message can be used as an
720  //additional protection measure against advanced traffic analysis techniques
721  return NO_ERROR;
722 }
723 
724 
725 /**
726  * @brief Parse SSH_MSG_DEBUG message
727  * @param[in] connection Pointer to the SSH connection
728  * @param[in] message Pointer to message
729  * @param[in] length Length of the message, in bytes
730  * @return Error code
731  **/
732 
733 error_t sshParseDebug(SshConnection *connection, const uint8_t *message,
734  size_t length)
735 {
736  error_t error;
737  const uint8_t *p;
738  SshBoolean alwaysDisplay;
739  SshString debugMessage;
740  SshString languageTag;
741 
742  //Debug message
743  TRACE_INFO("SSH_MSG_DEBUG message received (%" PRIuSIZE " bytes)...\r\n", length);
745 
746 #if (SSH_KEX_STRICT_SUPPORT == ENABLED)
747  //Strict key exchange?
748  if(!connection->newKeysReceived && connection->kexStrictReceived)
749  {
750  //During initial KEX, terminate the connection if any unexpected or
751  //out-of-sequence packet is received
753  }
754 #endif
755 
756  //Sanity check
757  if(length < sizeof(uint8_t))
758  return ERROR_INVALID_MESSAGE;
759 
760  //Point to the first field of the message
761  p = message + sizeof(uint8_t);
762  //Remaining bytes to process
763  length -= sizeof(uint8_t);
764 
765  //Malformed message?
766  if(length < sizeof(uint8_t))
767  return ERROR_INVALID_MESSAGE;
768 
769  //Decode always_display flag
770  alwaysDisplay = p[0];
771  //The value of this field is not used
772  (void) alwaysDisplay;
773 
774  //Point to the next field
775  p += sizeof(uint8_t);
776  length -= sizeof(uint8_t);
777 
778  //Decode message
779  error = sshParseString(p, length, &debugMessage);
780  //Any error to report?
781  if(error)
782  return error;
783 
784  //Point to the next field
785  p += sizeof(uint32_t) + debugMessage.length;
786  length -= sizeof(uint32_t) + debugMessage.length;
787 
788  //Decode language tag
789  error = sshParseString(p, length, &languageTag);
790  //Any error to report?
791  if(error)
792  return error;
793 
794  //Point to the next field
795  p += sizeof(uint32_t) + languageTag.length;
796  length -= sizeof(uint32_t) + languageTag.length;
797 
798  //Malformed message?
799  if(length != 0)
800  return ERROR_INVALID_MESSAGE;
801 
802  //All implementations must understand this message, but they are allowed
803  //to ignore it. This message is used to transmit information that may help
804  //debugging
805  return NO_ERROR;
806 }
807 
808 
809 /**
810  * @brief Parse SSH_MSG_DISCONNECT message
811  * @param[in] connection Pointer to the SSH connection
812  * @param[in] message Pointer to message
813  * @param[in] length Length of the message, in bytes
814  * @return Error code
815  **/
816 
817 error_t sshParseDisconnect(SshConnection *connection, const uint8_t *message,
818  size_t length)
819 {
820  error_t error;
821  const uint8_t *p;
822  uint32_t reasonCode;
824  SshString languageTag;
825 
826  //Debug message
827  TRACE_INFO("SSH_MSG_DISCONNECT message received (%" PRIuSIZE " bytes)...\r\n", length);
829 
830  //Sanity check
831  if(length < sizeof(uint8_t))
832  return ERROR_INVALID_MESSAGE;
833 
834  //Point to the first field of the message
835  p = message + sizeof(uint8_t);
836  //Remaining bytes to process
837  length -= sizeof(uint8_t);
838 
839  //Malformed message?
840  if(length < sizeof(uint32_t))
841  return ERROR_INVALID_MESSAGE;
842 
843  //Get reason code
844  reasonCode = LOAD32BE(p);
845  //The value of this field is not used
846  (void) reasonCode;
847 
848  //Point to the next field
849  p += sizeof(uint32_t);
850  length -= sizeof(uint32_t);
851 
852  //Decode description string
853  error = sshParseString(p, length, &description);
854  //Any error to report?
855  if(error)
856  return error;
857 
858  //Point to the next field
859  p += sizeof(uint32_t) + description.length;
860  length -= sizeof(uint32_t) + description.length;
861 
862  //Decode language tag
863  error = sshParseString(p, length, &languageTag);
864  //Any error to report?
865  if(error)
866  return error;
867 
868  //Point to the next field
869  p += sizeof(uint32_t) + languageTag.length;
870  length -= sizeof(uint32_t) + languageTag.length;
871 
872  //Malformed message?
873  if(length != 0)
874  return ERROR_INVALID_MESSAGE;
875 
876  //An SSH_MSG_DISCONNECT message has been successfully received
877  connection->disconnectReceived = TRUE;
878 
879  //This message causes immediate termination of the connection
880  connection->state = SSH_CONN_STATE_DISCONNECT;
881 
882  //Successful processing
883  return NO_ERROR;
884 }
885 
886 
887 /**
888  * @brief Parse SSH_MSG_UNIMPLEMENTED message
889  * @param[in] connection Pointer to the SSH connection
890  * @param[in] message Pointer to message
891  * @param[in] length Length of the message, in bytes
892  * @return Error code
893  **/
894 
896  size_t length)
897 {
898  const uint8_t *p;
899  uint32_t packetSeqNum;
900 
901  //Debug message
902  TRACE_INFO("SSH_MSG_UNIMPLEMENTED message received (%" PRIuSIZE " bytes)...\r\n", length);
904 
905  //Sanity check
906  if(length < sizeof(uint8_t))
907  return ERROR_INVALID_MESSAGE;
908 
909  //Point to the first field of the message
910  p = message + sizeof(uint8_t);
911  //Remaining bytes to process
912  length -= sizeof(uint8_t);
913 
914  //Malformed message?
915  if(length != sizeof(uint32_t))
916  return ERROR_INVALID_MESSAGE;
917 
918  //Get the packet sequence number of rejected message
919  packetSeqNum = LOAD32BE(p);
920  //The value of this field is not used
921  (void) packetSeqNum;
922 
923  //Ignore SSH_MSG_UNIMPLEMENTED messages
924  return NO_ERROR;
925 }
926 
927 
928 /**
929  * @brief Parse unrecognized message
930  * @param[in] connection Pointer to the SSH connection
931  * @param[in] message Pointer to message
932  * @param[in] length Length of the message, in bytes
933  * @return Error code
934  **/
935 
936 error_t sshParseUnrecognized(SshConnection *connection, const uint8_t *message,
937  size_t length)
938 {
939  error_t error;
940 
941  //Debug message
942  TRACE_INFO("Unrecognized message received (%" PRIuSIZE " bytes)...\r\n", length);
944 
945  //An implementation must respond to all unrecognized messages with an
946  //SSH_MSG_UNIMPLEMENTED message in the order in which the messages were
947  //received (refer to RFC 4253, section 11.4)
948  error = sshSendUnimplemented(connection, connection->decryptionEngine.seqNum);
949 
950  //Such messages must be otherwise ignored
951  return error;
952 }
953 
954 #endif
error_t sshFormatDisconnect(SshConnection *connection, uint32_t reasonCode, const char_t *description, uint8_t *p, size_t *length)
Format SSH_MSG_DISCONNECT message.
error_t sshParseUnimplemented(SshConnection *connection, const uint8_t *message, size_t length)
Parse SSH_MSG_UNIMPLEMENTED message.
#define LOAD32BE(p)
Definition: cpu_endian.h:210
@ ERROR_NOT_IMPLEMENTED
Definition: error.h:66
@ ERROR_UNEXPECTED_MESSAGE
Definition: error.h:195
uint8_t p
Definition: ndp.h:300
uint8_t message[]
Definition: chap.h:154
@ SSH_CONN_STATE_SERVICE_ACCEPT
Definition: ssh.h:1122
#define TRUE
Definition: os_port.h:50
uint8_t data[]
Definition: ethernet.h:224
error_t sshParseString(const uint8_t *p, size_t length, SshString *string)
Parse a string.
Definition: ssh_misc.c:1178
SSH transport layer protocol.
size_t length
Definition: ssh_types.h:58
@ ERROR_INVALID_MESSAGE
Definition: error.h:105
#define osStrlen(s)
Definition: os_port.h:171
error_t sshParseServiceAccept(SshConnection *connection, const uint8_t *message, size_t length)
Parse SSH_MSG_SERVICE_ACCEPT message.
#define SSH_PACKET_HEADER_SIZE
Definition: ssh_packet.h:38
@ SSH_CONN_STATE_SERVER_EXT_INFO_1
Definition: ssh.h:1119
bool_t sshCompareString(const SshString *string, const char_t *value)
Compare a binary string against the supplied value.
Definition: ssh_misc.c:1691
error_t sshSendPacket(SshConnection *connection, uint8_t *payload, size_t payloadLen)
Send SSH packet.
Definition: ssh_packet.c:57
@ SSH_CONN_STATE_DISCONNECT
Definition: ssh.h:1128
error_t sshFormatServiceAccept(SshConnection *connection, const char_t *serviceName, uint8_t *p, size_t *length)
Format SSH_MSG_SERVICE_ACCEPT message.
error_t sshParseUnrecognized(SshConnection *connection, const uint8_t *message, size_t length)
Parse unrecognized message.
error_t sshParseDisconnect(SshConnection *connection, const uint8_t *message, size_t length)
Parse SSH_MSG_DISCONNECT message.
#define osMemcpy(dest, src, length)
Definition: os_port.h:147
error_t
Error codes.
Definition: error.h:43
#define osSprintf(dest,...)
Definition: os_port.h:237
#define SSH_MAX_ID_LEN
Definition: ssh.h:251
@ SSH_OPERATION_MODE_SERVER
Definition: ssh.h:954
@ SSH_OPERATION_MODE_CLIENT
Definition: ssh.h:953
@ SSH_MSG_SERVICE_REQUEST
Definition: ssh.h:1000
error_t sshFormatServiceRequest(SshConnection *connection, uint8_t *p, size_t *length)
Format SSH_MSG_SERVICE_REQUEST message.
error_t sshParseIdString(SshConnection *connection, const uint8_t *id, size_t length)
Parse identification string.
#define CYCLONE_SSH_ID
Definition: ssh.h:86
error_t sshSendDisconnect(SshConnection *connection, uint32_t reasonCode, const char_t *description)
Send SSH_MSG_DISCONNECT message.
@ SSH_CONN_STATE_CLIENT_ID
Definition: ssh.h:1097
@ SSH_MSG_DISCONNECT
Definition: ssh.h:996
#define TRACE_INFO(...)
Definition: debug.h:105
uint8_t length
Definition: tcp.h:375
String.
Definition: ssh_types.h:56
error_t sshSendServiceAccept(SshConnection *connection, const char_t *serviceName)
Send SSH_MSG_SERVICE_ACCEPT message.
error_t sshSendIdString(SshConnection *connection)
Send identification string.
Definition: ssh_transport.c:51
error_t sshParseIgnore(SshConnection *connection, const uint8_t *message, size_t length)
Parse SSH_MSG_IGNORE message.
@ SSH_DISCONNECT_SERVICE_NOT_AVAILABLE
Definition: ssh.h:1065
bool_t SshBoolean
Boolean.
Definition: ssh_types.h:48
error_t sshParseServiceRequest(SshConnection *connection, const uint8_t *message, size_t length)
Parse SSH_MSG_SERVICE_REQUEST message.
#define TRACE_DEBUG(...)
Definition: debug.h:119
char char_t
Definition: compiler_port.h:55
error_t sshParseDebug(SshConnection *connection, const uint8_t *message, size_t length)
Parse SSH_MSG_DEBUG message.
error_t sshFormatUnimplemented(SshConnection *connection, const uint8_t *packetSeqNum, uint8_t *p, size_t *length)
Format SSH_MSG_UNIMPLEMENTED message.
@ SSH_CONN_STATE_SERVER_KEX_INIT
Definition: ssh.h:1100
@ SSH_CONN_STATE_SERVER_ID
Definition: ssh.h:1098
@ SSH_CONN_STATE_CLIENT_EXT_INFO
Definition: ssh.h:1118
error_t sshSendServiceRequest(SshConnection *connection)
Send SSH_MSG_SERVICE_REQUEST message.
uint8_t n
@ SSH_CONN_STATE_SERVICE_REQUEST
Definition: ssh.h:1121
#define SshConnection
Definition: ssh.h:935
@ SSH_CONN_STATE_USER_AUTH_REQUEST
Definition: ssh.h:1124
@ SSH_CONN_STATE_CLIENT_KEX_INIT
Definition: ssh.h:1099
SSH helper functions.
@ ERROR_WRONG_IDENTIFIER
Definition: error.h:89
#define osStrncmp(s1, s2, length)
Definition: os_port.h:183
@ SSH_MSG_SERVICE_ACCEPT
Definition: ssh.h:1001
SSH packet encryption/decryption.
@ SSH_MSG_UNIMPLEMENTED
Definition: ssh.h:998
error_t sshFormatString(const char_t *value, uint8_t *p, size_t *written)
Format a string.
Definition: ssh_misc.c:1410
#define PRIuSIZE
Secure Shell (SSH)
#define STORE32BE(a, p)
Definition: cpu_endian.h:286
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
error_t sshSendUnimplemented(SshConnection *connection, const uint8_t *packetSeqNum)
Send SSH_MSG_UNIMPLEMENTED message.
uint8_t description
Definition: tls.h:2041
#define TRACE_VERBOSE_ARRAY(p, a, n)
Definition: debug.h:140