ssh_packet.c
Go to the documentation of this file.
1 /**
2  * @file ssh_packet.c
3  * @brief SSH packet encryption/decryption
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2019-2024 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.4.4
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_extensions.h"
37 #include "ssh/ssh_transport.h"
38 #include "ssh/ssh_auth.h"
39 #include "ssh/ssh_kex.h"
40 #include "ssh/ssh_connection.h"
41 #include "ssh/ssh_request.h"
42 #include "ssh/ssh_packet.h"
43 #include "debug.h"
44 
45 //Check SSH stack configuration
46 #if (SSH_SUPPORT == ENABLED)
47 
48 
49 /**
50  * @brief Send SSH packet
51  * @param[in] connection Pointer to the SSH connection
52  * @param[in] payload Pointer to the payload data
53  * @param[in] payloadLen Length of the payload data, in bytes
54  * @return Error code
55  **/
56 
58  size_t payloadLen)
59 {
60  error_t error;
61  size_t blockSize;
62  size_t packetLen;
63  size_t paddingLen;
64  SshContext *context;
65  SshEncryptionEngine *encryptionEngine;
66 
67  //Point to the SSH context
68  context = connection->context;
69  //Point to the encryption engine
70  encryptionEngine = &connection->encryptionEngine;
71 
72  //Check whether an SSH_MSG_NEWKEYS message has been sent
73  if(connection->newKeysSent)
74  {
75  //AEAD cipher?
76  if(encryptionEngine->cipherMode == CIPHER_MODE_GCM)
77  {
78  //When using AES-GCM, the packet_length field is to be treated as
79  //additional authenticated data, not as plaintext (refer to RFC 5647,
80  //section 7.3)
81  packetLen = payloadLen + sizeof(uint8_t);
82 
83  //The total length of the packet must be a multiple of the cipher block
84  //size or 8, whichever is larger (refer to RFC 4253, section 6)
85  blockSize = MAX(encryptionEngine->cipherAlgo->blockSize, 8);
86  }
87  else if(encryptionEngine->cipherMode == CIPHER_MODE_CHACHA20_POLY1305)
88  {
89  //When using ChaCha20Poly1305, the packet_length field is to be
90  //treated as additional authenticated data, not as plaintext
91  packetLen = payloadLen + sizeof(uint8_t);
92 
93  //The total length of the packet must be a multiple of 8
94  blockSize = 8;
95  }
96  else
97  {
98  //The payload is preceded by a 5-byte header
99  packetLen = payloadLen + SSH_PACKET_HEADER_SIZE;
100 
101  //The total length of the packet must be a multiple of the cipher block
102  //size or 8, whichever is larger (refer to RFC 4253, section 6)
103  blockSize = MAX(encryptionEngine->cipherAlgo->blockSize, 8);
104  }
105  }
106  else
107  {
108  //The payload is preceded by a 5-byte header
109  packetLen = payloadLen + SSH_PACKET_HEADER_SIZE;
110  //The total length of the packet must be a multiple of 8
111  blockSize = 8;
112  }
113 
114  //Calculate the length of the padding string
115  if(encryptionEngine->etm)
116  {
117  paddingLen = blockSize - ((packetLen + blockSize - 4) % blockSize);
118  }
119  else
120  {
121  paddingLen = blockSize - (packetLen % blockSize);
122  }
123 
124  //There must be at least four bytes of padding
125  if(paddingLen < 4)
126  {
127  paddingLen += blockSize;
128  }
129 
130  //The padding should consist of random bytes
131  error = context->prngAlgo->read(context->prngContext, payload + payloadLen,
132  paddingLen);
133 
134  //Check status code
135  if(!error)
136  {
137  //The length of the packet does not include the packet_length field itself
138  packetLen = payloadLen + paddingLen + sizeof(uint8_t);
139 
140  //Format SSH packet header
141  STORE32BE(packetLen, connection->buffer);
142  connection->buffer[4] = paddingLen;
143 
144  //Determine the total length of the packet
145  connection->txBufferLen = packetLen + sizeof(uint32_t);
146  connection->txBufferPos = 0;
147 
148  //Check whether an SSH_MSG_NEWKEYS message has been sent
149  if(connection->newKeysSent)
150  {
151  //All messages sent after this message must use the new keys and
152  //algorithms
153  error = sshEncryptPacket(connection, connection->buffer,
154  &connection->txBufferLen);
155  }
156  }
157 
158  //Check status code
159  if(!error)
160  {
161  //The sequence number is initialized to zero for the first packet, and is
162  //incremented after every packet (regardless of whether encryption or MAC
163  //is in use)
164  sshIncSequenceNumber(connection->encryptionEngine.seqNum);
165  }
166 
167  //Return status code
168  return error;
169 }
170 
171 
172 /**
173  * @brief Receive SSH packet
174  * @param[in] connection Pointer to the SSH connection
175  * @return Error code
176  **/
177 
179 {
180  error_t error;
181  size_t n;
182  size_t blockSize;
183  SshEncryptionEngine *decryptionEngine;
184 
185  //Initialize status code
186  error = NO_ERROR;
187 
188  //Point to the decryption engine
189  decryptionEngine = &connection->decryptionEngine;
190 
191  //Check the actual length of the packet
192  if(connection->rxBufferLen < SSH_BUFFER_SIZE)
193  {
194  //Limit the number of bytes to read at a time
195  n = SSH_BUFFER_SIZE - connection->rxBufferLen;
196 
197  //Check connection state
198  if(connection->state == SSH_CONN_STATE_CLIENT_ID ||
199  connection->state == SSH_CONN_STATE_SERVER_ID)
200  {
201  //The identification string is terminated by a CR and LF
202  error = socketReceive(connection->socket, connection->buffer +
203  connection->rxBufferLen, n, &n, SOCKET_FLAG_BREAK_CRLF);
204 
205  //Check status code
206  if(!error)
207  {
208  //Adjust the length of the buffer
209  connection->rxBufferLen += n;
210 
211  //Check whether the string is properly terminated
212  if(connection->rxBufferLen > 0 &&
213  connection->buffer[connection->rxBufferLen - 1] == '\n')
214  {
215  //Parse identification string
216  error = sshParseIdString(connection, connection->buffer,
217  connection->rxBufferLen);
218 
219  //Flush receive buffer
220  connection->rxBufferLen = 0;
221  connection->rxBufferPos = 0;
222  }
223  }
224  }
225  else
226  {
227  //Check whether an SSH_MSG_NEWKEYS message has been received
228  if(connection->newKeysReceived)
229  {
230  //Stream or AEAD cipher?
231  if(decryptionEngine->cipherMode == CIPHER_MODE_STREAM ||
232  decryptionEngine->cipherMode == CIPHER_MODE_GCM ||
233  decryptionEngine->cipherMode == CIPHER_MODE_CHACHA20_POLY1305)
234  {
235  //The packet_length field is to be treated as additional
236  //authenticated data, not as plaintext
237  blockSize = sizeof(uint32_t);
238  }
239  else
240  {
241  //Implementations should decrypt the length after receiving the
242  //first 8 (or cipher block size, whichever is larger) bytes of
243  //a packet
244  blockSize = decryptionEngine->cipherAlgo->blockSize;
245  }
246  }
247  else
248  {
249  //The packet_length field is not encrypted
250  blockSize = sizeof(uint32_t);
251  }
252 
253  //Receive an entire SSH packet
254  if(connection->rxBufferPos < blockSize)
255  {
256  //Read the packet_length field of the SSH packet
257  error = socketReceive(connection->socket, connection->buffer +
258  connection->rxBufferPos, blockSize - connection->rxBufferPos,
259  &n, 0);
260 
261  //Check status code
262  if(!error)
263  {
264  //Adjust the length of the buffer
265  connection->rxBufferPos += n;
266 
267  //The packet_length field may be encrypted, and processing it
268  //requires special care when receiving packets
269  if(connection->rxBufferPos >= blockSize)
270  {
271  //Check whether an SSH_MSG_NEWKEYS message has been received
272  if(connection->newKeysReceived)
273  {
274  //When receiving a packet, the length must be decrypted first
275  error = sshDecryptPacketLength(connection, connection->buffer);
276  }
277  else
278  {
279  //The packet_length field is not encrypted
280  error = sshParsePacketLength(connection, connection->buffer);
281  }
282  }
283  }
284  }
285  else
286  {
287  //Read the contents of the SSH packet
288  error = socketReceive(connection->socket,
289  connection->buffer + connection->rxBufferPos,
290  connection->rxBufferLen - connection->rxBufferPos, &n, 0);
291 
292  //Check status code
293  if(!error)
294  {
295  //Adjust the length of the buffer
296  connection->rxBufferPos += n;
297 
298  //Check whether a complete packet has been received
299  if(connection->rxBufferPos >= connection->rxBufferLen)
300  {
301  //Parse the received SSH packet
302  error = sshParsePacket(connection, connection->buffer,
303  connection->rxBufferLen);
304 
305  //Flush receive buffer
306  connection->rxBufferLen = 0;
307  connection->rxBufferPos = 0;
308  }
309  }
310  }
311  }
312  }
313  else
314  {
315  //The implementation limits the size of packets it accepts
316  error = ERROR_BUFFER_OVERFLOW;
317  }
318 
319  //Return status code
320  return error;
321 }
322 
323 
324 /**
325  * @brief Parse SSH packet
326  * @param[in] connection Pointer to the SSH connection
327  * @param[in] packet Pointer to the received SSH packet
328  * @param[in] length Length of the packet, in bytes
329  * @return Error code
330  **/
331 
332 error_t sshParsePacket(SshConnection *connection, uint8_t *packet,
333  size_t length)
334 {
335  error_t error;
336  size_t n;
337  size_t paddingLen;
338 
339  //Initialize status code
340  error = NO_ERROR;
341 
342  //Debug message
343  TRACE_DEBUG("SSH packet received (%" PRIuSIZE " bytes)...\r\n", length);
344  TRACE_VERBOSE_ARRAY(" ", packet, length);
345 
346  //Check whether an SSH_MSG_NEWKEYS message has been received
347  if(connection->newKeysReceived)
348  {
349  //All messages sent after this message must use the new keys and
350  //algorithms
351  error = sshDecryptPacket(connection, packet, &length);
352  }
353 
354  //Check status code
355  if(!error)
356  {
357  //Check the length of the received packet
359  {
360  //Parse SSH packet header
361  n = LOAD32BE(packet);
362  paddingLen = packet[4];
363 
364  //Sanity check
365  if(length == (n + sizeof(uint32_t)))
366  {
367  //Check the length of the padding string
368  if(n >= (paddingLen + sizeof(uint8_t)))
369  {
370  //Point to the payload
371  packet += SSH_PACKET_HEADER_SIZE;
372  //Retrieve the length of the payload
373  n -= paddingLen + sizeof(uint8_t);
374 
375  //Parse the received message
376  error = sshParseMessage(connection, packet, n);
377  }
378  else
379  {
380  //Invalid padding length
381  error = ERROR_INVALID_MESSAGE;
382  }
383  }
384  else
385  {
386  //Invalid length
387  error = ERROR_INVALID_MESSAGE;
388  }
389  }
390  else
391  {
392  //Invalid length
393  error = ERROR_INVALID_MESSAGE;
394  }
395  }
396 
397  //Any decoding error?
398  if(error)
399  {
400  //Terminate the connection with the relevant reason code
401  if(error == ERROR_INVALID_KEY)
402  {
403  //Failed to verify the peer's host key
405  "Host key not valid");
406  }
407  else if(error == ERROR_DECRYPTION_FAILED)
408  {
409  //A record has been received with an incorrect MAC
410  error = sshSendDisconnect(connection, SSH_DISCONNECT_MAC_ERROR,
411  "Invalid MAC");
412  }
413  else if(error == ERROR_UNEXPECTED_MESSAGE)
414  {
415  //An inappropriate message has been received
417  "Unexpected packet");
418  }
419  else if(error == ERROR_INVALID_MESSAGE)
420  {
421  //A malformed message has been received
423  "Malformed packet");
424  }
425  else if(error == ERROR_INVALID_CHANNEL)
426  {
427  //Invalid channel number
429  "Invalid channel number");
430  }
431  else if(error == ERROR_FLOW_CONTROL)
432  {
433  //Flow control error
435  "Flow control error");
436  }
437  else if(error == ERROR_INVALID_GROUP)
438  {
439  //Diffie-Hellman group out of range
441  "Diffie-Hellman group out of range");
442  }
443  else
444  {
445  //Generic protocol error
447  "Protocol error");
448  }
449  }
450 
451  //The sequence number is incremented after every packet
452  sshIncSequenceNumber(connection->decryptionEngine.seqNum);
453 
454  //Return status code
455  return error;
456 }
457 
458 
459 /**
460  * @brief Encrypt an outgoing SSH packet
461  * @param[in] connection Pointer to the SSH connection
462  * @param[in,out] packet SSH packet to be encrypted
463  * @param[in,out] length Actual length of the SSH packet
464  * @return Error code
465  **/
466 
467 error_t sshEncryptPacket(SshConnection *connection, uint8_t *packet,
468  size_t *length)
469 {
470  error_t error;
471  size_t n;
472  uint8_t *data;
473  size_t dataLen;
474  SshEncryptionEngine *encryptionEngine;
475 
476  //Point to the encryption engine
477  encryptionEngine = &connection->encryptionEngine;
478 
479  //Get the actual length of the packet
480  n = *length;
481 
482  //Debug message
483  TRACE_VERBOSE("Packet to be encrypted (%" PRIuSIZE " bytes):\r\n", n);
484  TRACE_VERBOSE_ARRAY(" ", packet, n);
485 
486 #if (SSH_HMAC_SUPPORT == ENABLED)
487  //MAC-then-encrypt mode?
488  if(encryptionEngine->hashAlgo != NULL && !encryptionEngine->etm)
489  {
490  //The packet_length field and the payload will be encrypted
491  data = packet;
492  dataLen = n;
493 
494  //Compute message authentication code
495  sshAppendMessageAuthCode(encryptionEngine, packet, n);
496  }
497  else
498 #endif
499  {
500  //Point to the plaintext data to be encrypted
501  data = packet + sizeof(uint32_t);
502  dataLen = n - sizeof(uint32_t);
503  }
504 
505 #if (SSH_STREAM_CIPHER_SUPPORT == ENABLED)
506  //Stream cipher?
507  if(encryptionEngine->cipherMode == CIPHER_MODE_STREAM)
508  {
509  const CipherAlgo *cipherAlgo;
510 
511  //Cipher algorithm used to encrypt the packet
512  cipherAlgo = encryptionEngine->cipherAlgo;
513 
514  //Encrypt the contents of the SSH packet
515  cipherAlgo->encryptStream(&encryptionEngine->cipherContext, data,
516  data, dataLen);
517 
518  //Successful encryption
519  error = NO_ERROR;
520  }
521  else
522 #endif
523 #if (SSH_CBC_CIPHER_SUPPORT == ENABLED)
524  //CBC cipher mode?
525  if(encryptionEngine->cipherMode == CIPHER_MODE_CBC)
526  {
527  //Perform CBC encryption
528  error = cbcEncrypt(encryptionEngine->cipherAlgo,
529  &encryptionEngine->cipherContext, encryptionEngine->iv, data,
530  data, dataLen);
531  }
532  else
533 #endif
534 #if (SSH_CTR_CIPHER_SUPPORT == ENABLED)
535  //CTR cipher mode?
536  if(encryptionEngine->cipherMode == CIPHER_MODE_CTR)
537  {
538  uint_t m;
539 
540  //Retrieve cipher block size, in bits
541  m = encryptionEngine->cipherAlgo->blockSize * 8;
542 
543  //Perform CTR encryption
544  error = ctrEncrypt(encryptionEngine->cipherAlgo,
545  &encryptionEngine->cipherContext, m, encryptionEngine->iv, data,
546  data, dataLen);
547  }
548  else
549 #endif
550 #if (SSH_GCM_CIPHER_SUPPORT == ENABLED || SSH_RFC5647_SUPPORT == ENABLED)
551  //GCM AEAD cipher?
552  if(encryptionEngine->cipherMode == CIPHER_MODE_GCM)
553  {
554  //When using AES-GCM, the packet_length field is to be treated as
555  //additional authenticated data, not as plaintext (refer to RFC 5647,
556  //section 7.3)
557  error = gcmEncrypt(&encryptionEngine->gcmContext, encryptionEngine->iv,
558  12, packet, 4, data, data, dataLen, packet + n,
559  encryptionEngine->macSize);
560 
561  //The invocation counter is treated as a 64-bit integer and is
562  //incremented after each invocation of AES-GCM to process a binary
563  //packet (refer to RFC 5647, section 7.1)
564  sshIncInvocationCounter(encryptionEngine->iv);
565  }
566  else
567 #endif
568 #if (SSH_CHACHA20_POLY1305_SUPPORT == ENABLED)
569  //ChaCha20Poly1305 AEAD cipher?
570  if(encryptionEngine->cipherMode == CIPHER_MODE_CHACHA20_POLY1305)
571  {
572  ChachaContext chachaContext;
573  Poly1305Context poly1305Context;
574  uint8_t nonce[8];
575  uint8_t key[32];
576 
577  //The nonce consists of the packet sequence number encoded as a uint64
578  osMemset(nonce, 0, 4);
579  osMemcpy(nonce + 4, encryptionEngine->seqNum, 4);
580 
581  //The ChaCha20 instance keyed by K_1 is a stream cipher that is used
582  //only to encrypt the 4 byte packet length field
583  error = chachaInit(&chachaContext, 20, encryptionEngine->encKey + 32, 32,
584  nonce, 8);
585 
586  //Check status code
587  if(!error)
588  {
589  //The packet_length field is encrypted using a zero block counter to
590  //obtain the ciphertext length
591  chachaCipher(&chachaContext, packet, packet, 4);
592 
593  //The second ChaCha20 instance, keyed by K_2, is used in conjunction
594  //with Poly1305 to build an AEAD that is used to decrypt and
595  //authenticate the entire packet
596  error = chachaInit(&chachaContext, 20, encryptionEngine->encKey, 32,
597  nonce, sizeof(nonce));
598  }
599 
600  //Check status code
601  if(!error)
602  {
603  //Generate a Poly1305 key by taking the first 256 bits of ChaCha20
604  //stream output generated using K_2
605  chachaCipher(&chachaContext, NULL, key, 32);
606 
607  //The other 256 bits of the ChaCha20 block are discarded
608  chachaCipher(&chachaContext, NULL, NULL, 32);
609 
610  //Encrypt the packet payload
611  chachaCipher(&chachaContext, data, data, dataLen);
612 
613  //Initialize the Poly1305 function with the key calculated above
614  poly1305Init(&poly1305Context, key);
615 
616  //Compute MAC over the ciphertext of the packet length and the
617  //payload together
618  poly1305Update(&poly1305Context, packet, n);
619  poly1305Final(&poly1305Context, packet + n);
620 
621  //Debug message
622  TRACE_VERBOSE("Write sequence number:\r\n");
623  TRACE_VERBOSE_ARRAY(" ", &encryptionEngine->seqNum, 4);
624  TRACE_VERBOSE("Computed MAC:\r\n");
625  TRACE_VERBOSE_ARRAY(" ", packet + n, encryptionEngine->macSize);
626  }
627  }
628  else
629 #endif
630  //Invalid cipher mode?
631  {
632  //The specified cipher mode is not supported
634  }
635 
636 #if (SSH_HMAC_SUPPORT == ENABLED)
637  //Check status code
638  if(!error)
639  {
640  //Encrypt-then-MAC mode?
641  if(encryptionEngine->hashAlgo != NULL && encryptionEngine->etm)
642  {
643  //Compute message authentication code
644  sshAppendMessageAuthCode(encryptionEngine, packet, n);
645  }
646  }
647 #endif
648 
649  //Check status code
650  if(!error)
651  {
652  //The value resulting from the MAC algorithm must be transmitted without
653  //encryption as the last part of the packet
654  n += encryptionEngine->macSize;
655 
656  //Debug message
657  TRACE_VERBOSE("Encrypted packet (%" PRIuSIZE " bytes):\r\n", n);
658  TRACE_VERBOSE_ARRAY(" ", packet, n);
659 
660  //Return the length of the encrypted packet
661  *length = n;
662  }
663 
664  //Return status code
665  return error;
666 }
667 
668 
669 /**
670  * @brief Decrypt an incoming SSH packet
671  * @param[in] connection Pointer to the SSH connection
672  * @param[in,out] packet SSH packet to be decrypted
673  * @param[in,out] length Actual length of the SSH packet
674  * @return Error code
675  **/
676 
677 error_t sshDecryptPacket(SshConnection *connection, uint8_t *packet,
678  size_t *length)
679 {
680  error_t error;
681  size_t n;
682  size_t blockSize;
683  SshEncryptionEngine *decryptionEngine;
684 
685  //Initialize status code
686  error = NO_ERROR;
687 
688  //Point to the decryption engine
689  decryptionEngine = &connection->decryptionEngine;
690 
691  //Block cipher algorithm?
692  if(decryptionEngine->cipherMode == CIPHER_MODE_CBC ||
693  decryptionEngine->cipherMode == CIPHER_MODE_CTR)
694  {
695  //Encrypt-then-MAC mode?
696  if(decryptionEngine->etm)
697  {
698  //The packet_length field is not encrypted
699  blockSize = 4;
700  }
701  else
702  {
703  //Retrieve the cipher block size
704  blockSize = decryptionEngine->cipherAlgo->blockSize;
705  }
706  }
707  else
708  {
709  //The packet_length field is a 32-bit integer
710  blockSize = 4;
711  }
712 
713  //Get the actual length of the packet
714  n = *length;
715 
716  //Debug message
717  TRACE_VERBOSE("Packet to be decrypted (%" PRIuSIZE " bytes):\r\n", n);
718  TRACE_VERBOSE_ARRAY(" ", packet, n);
719 
720  //Check the length of the incoming packet
721  if(n >= (blockSize + decryptionEngine->macSize))
722  {
723  //The value resulting from the MAC algorithm is transmitted without
724  //encryption as the last part of the packet
725  n -= decryptionEngine->macSize;
726 
727 #if (SSH_HMAC_SUPPORT == ENABLED)
728  //Encrypt-then-MAC mode?
729  if(decryptionEngine->hashAlgo != NULL && decryptionEngine->etm)
730  {
731  //Verify message authentication code
732  error = sshVerifyMessageAuthCode(decryptionEngine, packet, n);
733  }
734 #endif
735 
736  //Check status code
737  if(!error)
738  {
739 #if (SSH_STREAM_CIPHER_SUPPORT == ENABLED)
740  //Stream cipher?
741  if(decryptionEngine->cipherMode == CIPHER_MODE_STREAM)
742  {
743  const CipherAlgo *cipherAlgo;
744 
745  //Cipher algorithm used to encrypt the packet
746  cipherAlgo = decryptionEngine->cipherAlgo;
747 
748  //Decrypt the contents of the SSH packet
749  cipherAlgo->decryptStream(&decryptionEngine->cipherContext,
750  packet + blockSize, packet + blockSize, n - blockSize);
751  }
752  else
753 #endif
754 #if (SSH_CBC_CIPHER_SUPPORT == ENABLED)
755  //CBC cipher mode?
756  if(decryptionEngine->cipherMode == CIPHER_MODE_CBC)
757  {
758  //Perform CBC decryption
759  error = cbcDecrypt(decryptionEngine->cipherAlgo,
760  &decryptionEngine->cipherContext, decryptionEngine->iv,
761  packet + blockSize, packet + blockSize, n - blockSize);
762  }
763  else
764 #endif
765 #if (SSH_CTR_CIPHER_SUPPORT == ENABLED)
766  //CTR cipher mode?
767  if(decryptionEngine->cipherMode == CIPHER_MODE_CTR)
768  {
769  uint_t m;
770 
771  //Retrieve cipher block size, in bits
772  m = decryptionEngine->cipherAlgo->blockSize * 8;
773 
774  //Perform CTR decryption
775  error = ctrDecrypt(decryptionEngine->cipherAlgo,
776  &decryptionEngine->cipherContext, m, decryptionEngine->iv,
777  packet + blockSize, packet + blockSize, n - blockSize);
778  }
779  else
780 #endif
781 #if (SSH_GCM_CIPHER_SUPPORT == ENABLED || SSH_RFC5647_SUPPORT == ENABLED)
782  //GCM AEAD cipher?
783  if(decryptionEngine->cipherMode == CIPHER_MODE_GCM)
784  {
785  //When using AES-GCM, the packet_length field is to be treated as
786  //additional authenticated data, not as plaintext (refer to
787  //RFC 5647, section 7.3)
788  error = gcmDecrypt(&decryptionEngine->gcmContext,
789  decryptionEngine->iv, 12, packet, blockSize, packet + blockSize,
790  packet + blockSize, n - blockSize, packet + n,
791  decryptionEngine->macSize);
792 
793  //The invocation counter is treated as a 64-bit integer and is
794  //incremented after each invocation of AES-GCM to process a binary
795  //packet (refer to RFC 5647, section 7.1)
796  sshIncInvocationCounter(decryptionEngine->iv);
797  }
798  else
799 #endif
800 #if (SSH_CHACHA20_POLY1305_SUPPORT == ENABLED)
801  //ChaCha20Poly1305 AEAD cipher?
802  if(decryptionEngine->cipherMode == CIPHER_MODE_CHACHA20_POLY1305)
803  {
804  size_t i;
805  uint8_t mask;
806  uint8_t nonce[8];
807  uint8_t key[32];
808  uint8_t mac[16];
809  ChachaContext chachaContext;
810  Poly1305Context poly1305Context;
811 
812  //The nonce consists of the packet sequence number encoded as a
813  //uint64
814  osMemset(nonce, 0, 4);
815  osMemcpy(nonce + 4, decryptionEngine->seqNum, 4);
816 
817  //The second ChaCha20 instance, keyed by K_2, is used in conjunction
818  //with Poly1305 to build an AEAD that is used to decrypt and
819  //authenticate the entire packet
820  error = chachaInit(&chachaContext, 20, decryptionEngine->encKey, 32,
821  nonce, sizeof(nonce));
822 
823  //Check status code
824  if(!error)
825  {
826  //Generate a Poly1305 key by taking the first 256 bits of ChaCha20
827  //stream output generated using K_2
828  chachaCipher(&chachaContext, NULL, key, 32);
829 
830  //The other 256 bits of the ChaCha20 block are discarded
831  chachaCipher(&chachaContext, NULL, NULL, 32);
832 
833  //Initialize the Poly1305 function with the key calculated above
834  poly1305Init(&poly1305Context, key);
835 
836  //Compute MAC over the ciphertext of the packet length and the
837  //payload together
838  poly1305Update(&poly1305Context, decryptionEngine->aad, blockSize);
839  poly1305Update(&poly1305Context, packet + blockSize, n - blockSize);
840  poly1305Final(&poly1305Context, mac);
841 
842  //Decrypt the packet payload
843  chachaCipher(&chachaContext, packet + blockSize, packet + blockSize,
844  n - blockSize);
845 
846  //The calculated MAC is then compared in constant time with the
847  //one appended to the packet
848  for(mask = 0, i = 0; i < 16; i++)
849  {
850  mask |= mac[i] ^ packet[n + i];
851  }
852 
853  //The message is authenticated if and only if the tags match
854  error = (mask == 0) ? NO_ERROR : ERROR_FAILURE;
855  }
856  }
857  else
858 #endif
859  //Invalid cipher mode?
860  {
861  //The specified cipher mode is not supported
863  }
864  }
865  }
866  else
867  {
868  //The packet is malformed
869  error = ERROR_INVALID_PACKET;
870  }
871 
872  //Check status code
873  if(!error)
874  {
875  //Debug message
876  TRACE_VERBOSE("Decrypted packet (%" PRIuSIZE " bytes):\r\n", n);
877  TRACE_VERBOSE_ARRAY(" ", packet, n);
878 
879 #if (SSH_HMAC_SUPPORT == ENABLED)
880  //MAC-then-encrypt mode?
881  if(decryptionEngine->hashAlgo != NULL && !decryptionEngine->etm)
882  {
883  //Verify message authentication code
884  error = sshVerifyMessageAuthCode(decryptionEngine, packet, n);
885  }
886 #endif
887  }
888 
889  //Check status code
890  if(!error)
891  {
892  //Return the length of the decrypted packet
893  *length = n;
894  }
895  else
896  {
897  //Failed to decrypt SSH packet
898  error = ERROR_DECRYPTION_FAILED;
899  }
900 
901  //Return status code
902  return error;
903 }
904 
905 
906 /**
907  * @brief Retrieve the length of an incoming SSH packet
908  * @param[in] connection Pointer to the SSH connection
909  * @param[in] packet Pointer to the received SSH packet
910  * @return Error code
911  **/
912 
913 error_t sshParsePacketLength(SshConnection *connection, uint8_t *packet)
914 {
915  error_t error;
916  size_t packetLen;
917 
918  //Initialize status code
919  error = NO_ERROR;
920 
921  //Convert the packet length to host byte order
922  packetLen = LOAD32BE(packet);
923  //The length of the packet does not include the packet_length field itself
924  packetLen += sizeof(uint32_t);
925 
926  //Sanity check
927  if(packetLen <= SSH_BUFFER_SIZE && packetLen > LOAD32BE(packet))
928  {
929  //Save the total length of the packet
930  connection->rxBufferLen = packetLen;
931  }
932  else
933  {
934  //Report an error
935  error = ERROR_INVALID_LENGTH;
936  }
937 
938  //Return status code
939  return error;
940 }
941 
942 
943 /**
944  * @brief Decrypt the length field of an incoming SSH packet
945  * @param[in] connection Pointer to the SSH connection
946  * @param[in,out] packet Pointer to the first block of data
947  * @return Error code
948  **/
949 
950 error_t sshDecryptPacketLength(SshConnection *connection, uint8_t *packet)
951 {
952  error_t error;
953 #if (SSH_HMAC_SUPPORT == ENABLED || SSH_CHACHA20_POLY1305_SUPPORT == ENABLED)
954  size_t blockSize;
955 #endif
956  size_t packetLen;
957  SshEncryptionEngine *decryptionEngine;
958 
959  //Initialize status code
960  error = NO_ERROR;
961 
962  //Point to the decryption engine
963  decryptionEngine = &connection->decryptionEngine;
964 
965 #if (SSH_HMAC_SUPPORT == ENABLED || SSH_CHACHA20_POLY1305_SUPPORT == ENABLED)
966  //Block cipher algorithm?
967  if(decryptionEngine->cipherMode == CIPHER_MODE_CBC ||
968  decryptionEngine->cipherMode == CIPHER_MODE_CTR)
969  {
970  //Encrypt-then-MAC mode?
971  if(decryptionEngine->etm)
972  {
973  //The packet_length field is not encrypted
974  blockSize = 4;
975  }
976  else
977  {
978  //Retrieve the cipher block size
979  blockSize = decryptionEngine->cipherAlgo->blockSize;
980  }
981  }
982  else
983  {
984  //The packet_length field is a 32-bit integer
985  blockSize = 4;
986  }
987 
988  //Debug message
989  TRACE_VERBOSE("Block to be decrypted (%" PRIuSIZE " bytes):\r\n", blockSize);
990  TRACE_VERBOSE_ARRAY(" ", packet, blockSize);
991 #endif
992 
993 #if (SSH_STREAM_CIPHER_SUPPORT == ENABLED)
994  //Stream cipher?
995  if(decryptionEngine->cipherMode == CIPHER_MODE_STREAM)
996  {
997  //MAC-then-encrypt mode?
998  if(!decryptionEngine->etm)
999  {
1000  const CipherAlgo *cipherAlgo;
1001 
1002  //Cipher algorithm used to encrypt the packet
1003  cipherAlgo = decryptionEngine->cipherAlgo;
1004 
1005  //Decrypt packet_length field
1006  cipherAlgo->decryptStream(&decryptionEngine->cipherContext, packet,
1007  packet, blockSize);
1008  }
1009  }
1010  else
1011 #endif
1012 #if (SSH_CBC_CIPHER_SUPPORT == ENABLED)
1013  //CBC cipher mode?
1014  if(decryptionEngine->cipherMode == CIPHER_MODE_CBC)
1015  {
1016  //MAC-then-encrypt mode?
1017  if(!decryptionEngine->etm)
1018  {
1019  //Perform CBC decryption
1020  error = cbcDecrypt(decryptionEngine->cipherAlgo,
1021  &decryptionEngine->cipherContext, decryptionEngine->iv, packet,
1022  packet, blockSize);
1023  }
1024  }
1025  else
1026 #endif
1027 #if (SSH_CTR_CIPHER_SUPPORT == ENABLED)
1028  //CTR cipher mode?
1029  if(decryptionEngine->cipherMode == CIPHER_MODE_CTR)
1030  {
1031  //MAC-then-encrypt mode?
1032  if(!decryptionEngine->etm)
1033  {
1034  uint_t m;
1035 
1036  //Retrieve cipher block size, in bits
1037  m = decryptionEngine->cipherAlgo->blockSize * 8;
1038 
1039  //Perform CTR decryption
1040  error = ctrDecrypt(decryptionEngine->cipherAlgo,
1041  &decryptionEngine->cipherContext, m, decryptionEngine->iv,
1042  packet, packet, blockSize);
1043  }
1044  }
1045  else
1046 #endif
1047 #if (SSH_GCM_CIPHER_SUPPORT == ENABLED || SSH_RFC5647_SUPPORT == ENABLED)
1048  //GCM AEAD cipher?
1049  if(decryptionEngine->cipherMode == CIPHER_MODE_GCM)
1050  {
1051  //The packet_length field is not encrypted
1052  }
1053  else
1054 #endif
1055 #if (SSH_CHACHA20_POLY1305_SUPPORT == ENABLED)
1056  //ChaCha20Poly1305 AEAD cipher?
1057  if(decryptionEngine->cipherMode == CIPHER_MODE_CHACHA20_POLY1305)
1058  {
1059  ChachaContext chachaContext;
1060  uint8_t nonce[8];
1061 
1062  //The nonce consists of the packet sequence number encoded as a uint64
1063  osMemset(nonce, 0, 4);
1064  osMemcpy(nonce + 4, decryptionEngine->seqNum, 4);
1065 
1066  //Initialize ChaCha20 context
1067  error = chachaInit(&chachaContext, 20, decryptionEngine->encKey + 32, 32,
1068  nonce, 8);
1069 
1070  //Check status code
1071  if(!error)
1072  {
1073  //Save the ciphertext of the packet length
1074  osMemcpy(decryptionEngine->aad, packet, blockSize);
1075 
1076  //The packet_length field is decrypted using a zero block counter to
1077  //obtain the plaintext length
1078  chachaCipher(&chachaContext, packet, packet, blockSize);
1079  }
1080  }
1081  else
1082 #endif
1083  //Invalid cipher mode?
1084  {
1085  //The specified cipher mode is not supported
1087  }
1088 
1089  //Check status code
1090  if(!error)
1091  {
1092  //Debug message
1093  TRACE_VERBOSE("Decrypted block (%" PRIuSIZE " bytes):\r\n", blockSize);
1094  TRACE_VERBOSE_ARRAY(" ", packet, blockSize);
1095 
1096  //Convert the packet length to host byte order
1097  packetLen = LOAD32BE(packet);
1098 
1099  //The length of the packet does not include the mac field and the
1100  //packet_length field itself
1101  packetLen += decryptionEngine->macSize + sizeof(uint32_t);
1102 
1103  //Sanity check
1104  if(packetLen <= SSH_BUFFER_SIZE && packetLen > LOAD32BE(packet))
1105  {
1106  //Save the total length of the packet
1107  connection->rxBufferLen = packetLen;
1108  }
1109  else
1110  {
1111  //Report an error
1112  error = ERROR_DECRYPTION_FAILED;
1113  }
1114  }
1115 
1116  //Return status code
1117  return error;
1118 }
1119 
1120 
1121 /**
1122  * @brief Parse SSH message
1123  * @param[in] connection Pointer to the SSH connection
1124  * @param[in] message Pointer to received message
1125  * @param[in] length Length of the message, in bytes
1126  * @return Error code
1127  **/
1128 
1129 error_t sshParseMessage(SshConnection *connection, const uint8_t *message,
1130  size_t length)
1131 {
1132  error_t error;
1133  uint8_t type;
1134 
1135  //Check the length of the message
1136  if(length >= sizeof(uint8_t))
1137  {
1138  //The first byte of the payload indicates the message type
1139  type = message[0];
1140 
1141  //Check message type
1142  if(type == SSH_MSG_KEXINIT)
1143  {
1144  //Key exchange begins with an SSH_MSG_KEXINIT message
1145  error = sshParseKexInit(connection, message, length);
1146  }
1147  else if(type >= SSH_MSG_KEX_MIN && type <= SSH_MSG_KEX_MAX)
1148  {
1149  //Parse key exchange method-specific messages
1150  error = sshParseKexMessage(connection, type, message, length);
1151  }
1152  else if(type == SSH_MSG_NEWKEYS)
1153  {
1154  //Key exchange ends with an SSH_MSG_NEWKEYS message
1155  error = sshParseNewKeys(connection, message, length);
1156  }
1157  else if(type == SSH_MSG_SERVICE_REQUEST)
1158  {
1159  //After the key exchange, the client requests a service using a
1160  //SSH_MSG_SERVICE_REQUEST message
1161  error = sshParseServiceRequest(connection, message, length);
1162  }
1163  else if(type == SSH_MSG_SERVICE_ACCEPT)
1164  {
1165  //If the server supports the service (and permits the client to use
1166  //it), it must respond with an SSH_MSG_SERVICE_ACCEPT message
1167  error = sshParseServiceAccept(connection, message, length);
1168  }
1169  else if(type == SSH_MSG_USERAUTH_REQUEST)
1170  {
1171  //All authentication requests use an SSH_MSG_USERAUTH_REQUEST message
1172  error = sshParseUserAuthRequest(connection, message, length);
1173  }
1174  else if(type == SSH_MSG_USERAUTH_SUCCESS)
1175  {
1176  //When the server accepts authentication, it must respond with a
1177  //SSH_MSG_USERAUTH_SUCCESS message
1178  error = sshParseUserAuthSuccess(connection, message, length);
1179  }
1180  else if(type == SSH_MSG_USERAUTH_FAILURE)
1181  {
1182  //If the server rejects the authentication request, it must respond
1183  //with an SSH_MSG_USERAUTH_FAILURE message
1184  error = sshParseUserAuthFailure(connection, message, length);
1185  }
1186  else if(type == SSH_MSG_USERAUTH_BANNER)
1187  {
1188  //The SSH server may send an SSH_MSG_USERAUTH_BANNER message at any
1189  //time after this authentication protocol starts and before
1190  //authentication is successful
1191  error = sshParseUserAuthBanner(connection, message, length);
1192  }
1194  {
1195  //Parse authentication method-specific messages
1196  error = sshParseUserAuthMessage(connection, type, message, length);
1197  }
1198  else if(type == SSH_MSG_GLOBAL_REQUEST)
1199  {
1200  //Both the client and server may send global requests at any time
1201  //(refer to RFC 4254, section 4)
1202  error = sshParseGlobalRequest(connection, message, length);
1203  }
1204  else if(type == SSH_MSG_REQUEST_SUCCESS)
1205  {
1206  //The recipient responds with either SSH_MSG_REQUEST_SUCCESS or
1207  //SSH_MSG_REQUEST_FAILURE
1208  error = sshParseRequestSuccess(connection, message, length);
1209  }
1210  else if(type == SSH_MSG_REQUEST_FAILURE)
1211  {
1212  //The recipient responds with either SSH_MSG_REQUEST_SUCCESS or
1213  //SSH_MSG_REQUEST_FAILURE
1214  error = sshParseRequestFailure(connection, message, length);
1215  }
1216  else if(type == SSH_MSG_CHANNEL_OPEN)
1217  {
1218  //When either side wishes to open a new channel, it then sends a
1219  //SSH_MSG_CHANNEL_OPEN message to the other side
1220  error = sshParseChannelOpen(connection, message, length);
1221  }
1223  {
1224  //The recipient responds with either SSH_MSG_CHANNEL_OPEN_CONFIRMATION
1225  //or SSH_MSG_CHANNEL_OPEN_FAILURE
1226  error = sshParseChannelOpenConfirmation(connection, message, length);
1227  }
1229  {
1230  //The recipient responds with either SSH_MSG_CHANNEL_OPEN_CONFIRMATION
1231  //or SSH_MSG_CHANNEL_OPEN_FAILURE
1232  error = sshParseChannelOpenFailure(connection, message, length);
1233  }
1234  else if(type == SSH_MSG_CHANNEL_REQUEST)
1235  {
1236  //All channel-specific requests use an SSH_MSG_CHANNEL_REQUEST message
1237  error = sshParseChannelRequest(connection, message, length);
1238  }
1239  else if(type == SSH_MSG_CHANNEL_SUCCESS)
1240  {
1241  //The recipient responds with either SSH_MSG_CHANNEL_SUCCESS or
1242  //SSH_MSG_CHANNEL_FAILURE
1243  error = sshParseChannelSuccess(connection, message, length);
1244  }
1245  else if(type == SSH_MSG_CHANNEL_FAILURE)
1246  {
1247  //The recipient responds with either SSH_MSG_CHANNEL_SUCCESS or
1248  //SSH_MSG_CHANNEL_FAILURE
1249  error = sshParseChannelFailure(connection, message, length);
1250  }
1252  {
1253  //Both parties use the SSH_MSG_CHANNEL_WINDOW_ADJUST message to adjust
1254  //the window
1255  error = sshParseChannelWindowAdjust(connection, message, length);
1256  }
1257  else if(type == SSH_MSG_CHANNEL_DATA)
1258  {
1259  //Data transfer is done with SSH_MSG_CHANNEL_DATA message
1260  error = sshParseChannelData(connection, message, length);
1261  }
1263  {
1264  //Extended data can be passed with SSH_MSG_CHANNEL_EXTENDED_DATA
1265  //messages
1266  error = sshParseChannelExtendedData(connection, message, length);
1267  }
1268  else if(type == SSH_MSG_CHANNEL_EOF)
1269  {
1270  //When a party will no longer send more data to a channel, it should
1271  //send an SSH_MSG_CHANNEL_EOF message
1272  error = sshParseChannelEof(connection, message, length);
1273  }
1274  else if(type == SSH_MSG_CHANNEL_CLOSE)
1275  {
1276  //When either party wishes to terminate the channel, it sends an
1277  //SSH_MSG_CHANNEL_CLOSE message
1278  error = sshParseChannelClose(connection, message, length);
1279  }
1280  else if(type == SSH_MSG_IGNORE)
1281  {
1282  //The SSH_MSG_IGNORE message can be used as an additional protection
1283  //measure against advanced traffic analysis techniques
1284  error = sshParseIgnore(connection, message, length);
1285  }
1286  else if(type == SSH_MSG_DEBUG)
1287  {
1288  //The SSH_MSG_DEBUG message is used to transmit information that may
1289  //help debugging
1290  error = sshParseDebug(connection, message, length);
1291  }
1292  else if(type == SSH_MSG_DISCONNECT)
1293  {
1294  //The SSH_MSG_DISCONNECT message causes immediate termination of the
1295  //connection. All implementations must be able to process this message
1296  error = sshParseDisconnect(connection, message, length);
1297  }
1298  else if(type == SSH_MSG_UNIMPLEMENTED)
1299  {
1300  //An implementation must respond to all unrecognized messages with an
1301  //SSH_MSG_UNIMPLEMENTED message in the order in which the messages
1302  //were received
1303  error = sshParseUnimplemented(connection, message, length);
1304  }
1305 #if (SSH_EXT_INFO_SUPPORT == ENABLED)
1306  else if(type == SSH_MSG_EXT_INFO)
1307  {
1308  //If a client or server offers "ext-info-c" or "ext-info-s"
1309  //respectively, it must be prepared to accept an SSH_MSG_EXT_INFO
1310  //message from the peer (refer to RFC 8308, section 2.2)
1311  error = sshParseExtInfo(connection, message, length);
1312  }
1313 #endif
1314  else
1315  {
1316  //Unrecognized message received
1317  error = sshParseUnrecognized(connection, message, length);
1318  }
1319  }
1320  else
1321  {
1322  //Malformed message
1323  error = ERROR_INVALID_MESSAGE;
1324  }
1325 
1326  //Return status code
1327  return error;
1328 }
1329 
1330 
1331 /**
1332  * @brief Compute message authentication code
1333  * @param[in] encryptionEngine Pointer to the encryption engine
1334  * @param[in] packet Pointer to the packet to be authenticated
1335  * @param[in] length of the packet, in bytes
1336  **/
1337 
1339  uint8_t *packet, size_t length)
1340 {
1341 #if (SSH_HMAC_SUPPORT == ENABLED)
1342  //Initialize HMAC calculation
1343  hmacInit(encryptionEngine->hmacContext, encryptionEngine->hashAlgo,
1344  encryptionEngine->macKey, encryptionEngine->hashAlgo->digestSize);
1345 
1346  //Compute MAC(key, sequence_number || unencrypted_packet)
1347  hmacUpdate(encryptionEngine->hmacContext, encryptionEngine->seqNum, 4);
1348  hmacUpdate(encryptionEngine->hmacContext, packet, length);
1349  hmacFinal(encryptionEngine->hmacContext, packet + length);
1350 
1351  //Debug message
1352  TRACE_VERBOSE("Write sequence number:\r\n");
1353  TRACE_VERBOSE_ARRAY(" ", &encryptionEngine->seqNum, 4);
1354  TRACE_VERBOSE("Computed MAC:\r\n");
1355  TRACE_VERBOSE_ARRAY(" ", packet + length, encryptionEngine->macSize);
1356 #endif
1357 }
1358 
1359 
1360 /**
1361  * @brief Verify message authentication code
1362  * @param[in] decryptionEngine Pointer to the decryption engine
1363  * @param[in] packet Pointer to the packet to be authenticated
1364  * @param[in] length of the packet, in bytes
1365  * @return Error code
1366  **/
1367 
1369  const uint8_t *packet, size_t length)
1370 {
1371 #if (SSH_HMAC_SUPPORT == ENABLED)
1372  size_t i;
1373  uint8_t mask;
1374  uint8_t mac[SSH_MAX_HASH_DIGEST_SIZE];
1375 
1376  //Initialize HMAC calculation
1377  hmacInit(decryptionEngine->hmacContext, decryptionEngine->hashAlgo,
1378  decryptionEngine->macKey, decryptionEngine->hashAlgo->digestSize);
1379 
1380  //Compute MAC(key, sequence_number || unencrypted_packet)
1381  hmacUpdate(decryptionEngine->hmacContext, decryptionEngine->seqNum, 4);
1382  hmacUpdate(decryptionEngine->hmacContext, packet, length);
1383  hmacFinal(decryptionEngine->hmacContext, mac);
1384 
1385  //Debug message
1386  TRACE_VERBOSE("Read sequence number:\r\n");
1387  TRACE_VERBOSE_ARRAY(" ", &decryptionEngine->seqNum, 4);
1388  TRACE_VERBOSE("Computed MAC:\r\n");
1389  TRACE_VERBOSE_ARRAY(" ", mac, decryptionEngine->macSize);
1390 
1391  //The calculated MAC is bitwise compared to the received message
1392  //authentication code
1393  for(mask = 0, i = 0; i < decryptionEngine->macSize; i++)
1394  {
1395  mask |= mac[i] ^ packet[length + i];
1396  }
1397 
1398  //The message is authenticated if and only if the MAC values match
1399  return (mask == 0) ? NO_ERROR : ERROR_DECRYPTION_FAILED;
1400 #else
1401  //Not implemented
1402  return ERROR_DECRYPTION_FAILED;
1403 #endif
1404 }
1405 
1406 
1407 /**
1408  * @brief Increment sequence number
1409  * @param[in,out] seqNum Pointer to the 32-bit sequence number
1410  **/
1411 
1413 {
1414  uint16_t temp;
1415 
1416  //Sequence numbers are stored MSB first
1417  temp = seqNum[3] + 1;
1418  seqNum[3] = temp & 0xFF;
1419  temp = (temp >> 8) + seqNum[2];
1420  seqNum[2] = temp & 0xFF;
1421  temp = (temp >> 8) + seqNum[1];
1422  seqNum[1] = temp & 0xFF;
1423  temp = (temp >> 8) + seqNum[0];
1424  seqNum[0] = temp & 0xFF;
1425 }
1426 
1427 
1428 /**
1429  * @brief Increment invocation counter
1430  * @param[in,out] iv Pointer to the 12-octet initialization vector
1431  **/
1432 
1434 {
1435  uint16_t temp;
1436 
1437  //With AES-GCM, the 12-octet IV is broken into two fields: a 4-octet
1438  //fixed field and an 8-octet invocation counter field (refer to RFC 5647,
1439  //section 7.1)
1440  temp = iv[11] + 1;
1441  iv[11] = temp & 0xFF;
1442  temp = (temp >> 8) + iv[10];
1443  iv[10] = temp & 0xFF;
1444  temp = (temp >> 8) + iv[9];
1445  iv[9] = temp & 0xFF;
1446  temp = (temp >> 8) + iv[8];
1447  iv[8] = temp & 0xFF;
1448  temp = (temp >> 8) + iv[7];
1449  iv[7] = temp & 0xFF;
1450  temp = (temp >> 8) + iv[6];
1451  iv[6] = temp & 0xFF;
1452  temp = (temp >> 8) + iv[5];
1453  iv[5] = temp & 0xFF;
1454  temp = (temp >> 8) + iv[4];
1455  iv[4] = temp & 0xFF;
1456 }
1457 
1458 #endif
error_t sshDecryptPacketLength(SshConnection *connection, uint8_t *packet)
Decrypt the length field of an incoming SSH packet.
Definition: ssh_packet.c:950
void poly1305Init(Poly1305Context *context, const uint8_t *key)
Initialize Poly1305 message-authentication code computation.
Definition: poly1305.c:49
error_t sshParseUnimplemented(SshConnection *connection, const uint8_t *message, size_t length)
Parse SSH_MSG_UNIMPLEMENTED message.
error_t sshParseUserAuthBanner(SshConnection *connection, const uint8_t *message, size_t length)
Parse SSH_MSG_USERAUTH_BANNER message.
Definition: ssh_auth.c:640
SSH user authentication protocol.
@ CIPHER_MODE_CBC
Definition: crypto.h:966
#define LOAD32BE(p)
Definition: cpu_endian.h:210
error_t sshParseChannelFailure(SshConnection *connection, const uint8_t *message, size_t length)
Parse SSH_MSG_CHANNEL_FAILURE message.
Definition: ssh_request.c:1849
@ ERROR_BUFFER_OVERFLOW
Definition: error.h:142
uint8_t macKey[SSH_MAX_HASH_DIGEST_SIZE]
Integrity key.
Definition: ssh.h:1327
@ ERROR_DECRYPTION_FAILED
Definition: error.h:242
error_t sshParseNewKeys(SshConnection *connection, const uint8_t *message, size_t length)
Parse SSH_MSG_NEWKEYS message.
Definition: ssh_kex.c:995
uint8_t iv[SSH_MAX_CIPHER_BLOCK_SIZE]
Initialization vector.
Definition: ssh.h:1324
@ ERROR_UNEXPECTED_MESSAGE
Definition: error.h:194
@ CIPHER_MODE_GCM
Definition: crypto.h:971
const HashAlgo * hashAlgo
Hash algorithm for MAC operations.
Definition: ssh.h:1320
@ ERROR_INVALID_CHANNEL
Definition: error.h:274
uint8_t message[]
Definition: chap.h:154
SSH connection protocol.
__weak_func error_t cbcEncrypt(const CipherAlgo *cipher, void *context, uint8_t *iv, const uint8_t *p, uint8_t *c, size_t length)
CBC encryption.
Definition: cbc.c:61
uint8_t data[]
Definition: ethernet.h:222
@ SSH_DISCONNECT_MAC_ERROR
Definition: ssh.h:1000
error_t sshParseChannelClose(SshConnection *connection, const uint8_t *message, size_t length)
Parse SSH_MSG_CHANNEL_CLOSE message.
size_t digestSize
Definition: crypto.h:1052
Poly1305 context.
Definition: poly1305.h:48
@ SSH_MSG_CHANNEL_FAILURE
Definition: ssh.h:984
GcmContext gcmContext
GCM context.
Definition: ssh.h:1330
size_t macSize
Size of the MAC tag, in bytes.
Definition: ssh.h:1322
size_t blockSize
Definition: crypto.h:1072
SSH transport layer protocol.
uint8_t type
Definition: coap_common.h:176
error_t ctrDecrypt(const CipherAlgo *cipher, void *context, uint_t m, uint8_t *t, const uint8_t *c, uint8_t *p, size_t length)
CTR decryption.
Definition: ctr.c:122
@ SSH_MSG_CHANNEL_SUCCESS
Definition: ssh.h:983
@ SSH_DISCONNECT_HOST_KEY_NOT_VERIFIABLE
Definition: ssh.h:1004
error_t sshParseChannelExtendedData(SshConnection *connection, const uint8_t *message, size_t length)
Parse SSH_MSG_CHANNEL_EXTENDED_DATA message.
void sshAppendMessageAuthCode(SshEncryptionEngine *encryptionEngine, uint8_t *packet, size_t length)
Compute message authentication code.
Definition: ssh_packet.c:1338
@ SSH_MSG_CHANNEL_OPEN_CONFIRMATION
Definition: ssh.h:975
@ SSH_MSG_REQUEST_FAILURE
Definition: ssh.h:973
@ ERROR_INVALID_MESSAGE
Definition: error.h:105
error_t sshParseChannelWindowAdjust(SshConnection *connection, const uint8_t *message, size_t length)
Parse SSH_MSG_CHANNEL_WINDOW_ADJUST message.
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
@ CIPHER_MODE_CTR
Definition: crypto.h:969
error_t sshParseRequestSuccess(SshConnection *connection, const uint8_t *message, size_t length)
Parse SSH_MSG_REQUEST_SUCCESS message.
Definition: ssh_request.c:1210
error_t sshParseUserAuthSuccess(SshConnection *connection, const uint8_t *message, size_t length)
Parse SSH_MSG_USERAUTH_SUCCESS message.
Definition: ssh_auth.c:929
error_t sshSendPacket(SshConnection *connection, uint8_t *payload, size_t payloadLen)
Send SSH packet.
Definition: ssh_packet.c:57
Encryption engine.
Definition: ssh.h:1316
error_t sshParseChannelRequest(SshConnection *connection, const uint8_t *message, size_t length)
Parse SSH_MSG_CHANNEL_REQUEST message.
Definition: ssh_request.c:1280
error_t sshParseKexInit(SshConnection *connection, const uint8_t *message, size_t length)
Parse SSH_MSG_KEXINIT message.
Definition: ssh_kex.c:469
void chachaCipher(ChachaContext *context, const uint8_t *input, uint8_t *output, size_t length)
Encrypt/decrypt data with the ChaCha algorithm.
Definition: chacha.c:183
uint8_t seqNum[4]
Sequence number.
Definition: ssh.h:1328
error_t sshParseChannelSuccess(SshConnection *connection, const uint8_t *message, size_t length)
Parse SSH_MSG_CHANNEL_SUCCESS message.
Definition: ssh_request.c:1759
CipherAlgoEncryptStream encryptStream
Definition: crypto.h:1074
error_t sshParseUnrecognized(SshConnection *connection, const uint8_t *message, size_t length)
Parse unrecognized message.
#define SSH_MIN_PACKET_SIZE
Definition: ssh_packet.h:40
@ ERROR_INVALID_GROUP
Definition: error.h:275
@ SSH_MSG_CHANNEL_DATA
Definition: ssh.h:978
@ ERROR_UNSUPPORTED_CIPHER_MODE
Definition: error.h:128
error_t sshParseDisconnect(SshConnection *connection, const uint8_t *message, size_t length)
Parse SSH_MSG_DISCONNECT message.
error_t sshParsePacket(SshConnection *connection, uint8_t *packet, size_t length)
Parse SSH packet.
Definition: ssh_packet.c:332
error_t chachaInit(ChachaContext *context, uint_t nr, const uint8_t *key, size_t keyLen, const uint8_t *nonce, size_t nonceLen)
Initialize ChaCha context using the supplied key and nonce.
Definition: chacha.c:70
@ SSH_MSG_GLOBAL_REQUEST
Definition: ssh.h:971
#define SshContext
Definition: ssh.h:870
#define osMemcpy(dest, src, length)
Definition: os_port.h:141
@ SSH_MSG_NEWKEYS
Definition: ssh.h:944
error_t
Error codes.
Definition: error.h:43
uint32_t seqNum
Definition: tcp.h:341
CipherMode cipherMode
Cipher mode of operation.
Definition: ssh.h:1317
error_t socketReceive(Socket *socket, void *data, size_t size, size_t *received, uint_t flags)
Receive data from a connected socket.
Definition: socket.c:1692
@ SSH_MSG_CHANNEL_CLOSE
Definition: ssh.h:981
@ ERROR_FAILURE
Generic error code.
Definition: error.h:45
__weak_func error_t ctrEncrypt(const CipherAlgo *cipher, void *context, uint_t m, uint8_t *t, const uint8_t *p, uint8_t *c, size_t length)
CTR encryption.
Definition: ctr.c:62
const CipherAlgo * cipherAlgo
Cipher algorithm.
Definition: ssh.h:1318
uint8_t encKey[SSH_MAX_ENC_KEY_SIZE]
Encryption key.
Definition: ssh.h:1325
@ ERROR_INVALID_PACKET
Definition: error.h:140
@ SSH_MSG_SERVICE_REQUEST
Definition: ssh.h:939
@ ERROR_FLOW_CONTROL
Definition: error.h:278
CipherAlgoDecryptStream decryptStream
Definition: crypto.h:1075
@ ERROR_INVALID_LENGTH
Definition: error.h:111
bool_t etm
Encrypt-then-MAC.
Definition: ssh.h:1323
@ SSH_MSG_USERAUTH_REQUEST
Definition: ssh.h:961
CipherContext cipherContext
Cipher context.
Definition: ssh.h:1319
error_t sshParseIdString(SshConnection *connection, const uint8_t *id, size_t length)
Parse identification string.
error_t sshParseExtInfo(SshConnection *connection, const uint8_t *message, size_t length)
Parse SSH_MSG_EXT_INFO message.
error_t sshParseUserAuthMessage(SshConnection *connection, uint8_t type, const uint8_t *message, size_t length)
Parse authentication method specific method messages.
Definition: ssh_auth.c:1076
@ SSH_MSG_USERAUTH_FAILURE
Definition: ssh.h:962
@ SSH_MSG_DEBUG
Definition: ssh.h:938
uint8_t mask
Definition: web_socket.h:319
error_t sshSendDisconnect(SshConnection *connection, uint32_t reasonCode, const char_t *description)
Send SSH_MSG_DISCONNECT message.
uint8_t iv[]
Definition: ike.h:1502
@ SSH_CONN_STATE_CLIENT_ID
Definition: ssh.h:1034
@ SSH_MSG_CHANNEL_OPEN_FAILURE
Definition: ssh.h:976
@ SSH_MSG_USERAUTH_BANNER
Definition: ssh.h:964
@ SSH_MSG_DISCONNECT
Definition: ssh.h:935
uint8_t length
Definition: tcp.h:368
@ CIPHER_MODE_STREAM
Definition: crypto.h:964
error_t sshVerifyMessageAuthCode(SshEncryptionEngine *decryptionEngine, const uint8_t *packet, size_t length)
Verify message authentication code.
Definition: ssh_packet.c:1368
SSH key exchange.
error_t sshParseChannelOpen(SshConnection *connection, const uint8_t *message, size_t length)
Parse SSH_MSG_CHANNEL_OPEN message.
uint32_t dataLen
Definition: sftp_common.h:229
@ SSH_MSG_USERAUTH_SUCCESS
Definition: ssh.h:963
ChaCha algorithm context.
Definition: chacha.h:48
error_t sshParseIgnore(SshConnection *connection, const uint8_t *message, size_t length)
Parse SSH_MSG_IGNORE message.
error_t sshParseUserAuthRequest(SshConnection *connection, const uint8_t *message, size_t length)
Parse SSH_MSG_USERAUTH_REQUEST message.
Definition: ssh_auth.c:717
error_t sshParseUserAuthFailure(SshConnection *connection, const uint8_t *message, size_t length)
Parse SSH_MSG_USERAUTH_FAILURE message.
Definition: ssh_auth.c:980
#define SSH_MAX_HASH_DIGEST_SIZE
Definition: ssh.h:789
error_t sshParseServiceRequest(SshConnection *connection, const uint8_t *message, size_t length)
Parse SSH_MSG_SERVICE_REQUEST message.
__weak_func void hmacUpdate(HmacContext *context, const void *data, size_t length)
Update the HMAC context with a portion of the message being hashed.
Definition: hmac.c:201
@ SSH_DISCONNECT_PROTOCOL_ERROR
Definition: ssh.h:997
error_t sshParseChannelOpenConfirmation(SshConnection *connection, const uint8_t *message, size_t length)
Parse SSH_MSG_CHANNEL_OPEN_CONFIRMATION message.
#define TRACE_DEBUG(...)
Definition: debug.h:107
#define MAX(a, b)
Definition: os_port.h:67
error_t sshParseRequestFailure(SshConnection *connection, const uint8_t *message, size_t length)
Parse SSH_MSG_REQUEST_FAILURE message.
Definition: ssh_request.c:1245
error_t sshParseDebug(SshConnection *connection, const uint8_t *message, size_t length)
Parse SSH_MSG_DEBUG message.
@ SSH_MSG_CHANNEL_OPEN
Definition: ssh.h:974
error_t sshParseChannelOpenFailure(SshConnection *connection, const uint8_t *message, size_t length)
Parse SSH_MSG_CHANNEL_OPEN_FAILURE message.
@ SSH_CONN_STATE_SERVER_ID
Definition: ssh.h:1035
@ SSH_MSG_CHANNEL_REQUEST
Definition: ssh.h:982
uint8_t m
Definition: ndp.h:304
uint8_t n
uint8_t payload[]
Definition: ipv6.h:286
#define SshConnection
Definition: ssh.h:874
__weak_func void hmacFinal(HmacContext *context, uint8_t *digest)
Finish the HMAC calculation.
Definition: hmac.c:218
@ SSH_MSG_CHANNEL_EOF
Definition: ssh.h:980
uint8_t aad[4]
Additional authenticated data.
Definition: ssh.h:1333
@ SSH_MSG_CHANNEL_WINDOW_ADJUST
Definition: ssh.h:977
error_t sshParseGlobalRequest(SshConnection *connection, const uint8_t *message, size_t length)
Parse SSH_MSG_GLOBAL_REQUEST message.
Definition: ssh_request.c:989
__weak_func error_t cbcDecrypt(const CipherAlgo *cipher, void *context, uint8_t *iv, const uint8_t *c, uint8_t *p, size_t length)
CBC decryption.
Definition: cbc.c:108
error_t sshParseChannelEof(SshConnection *connection, const uint8_t *message, size_t length)
Parse SSH_MSG_CHANNEL_EOF message.
void sshIncSequenceNumber(uint8_t *seqNum)
Increment sequence number.
Definition: ssh_packet.c:1412
Common interface for encryption algorithms.
Definition: crypto.h:1068
void sshIncInvocationCounter(uint8_t *iv)
Increment invocation counter.
Definition: ssh_packet.c:1433
error_t sshDecryptPacket(SshConnection *connection, uint8_t *packet, size_t *length)
Decrypt an incoming SSH packet.
Definition: ssh_packet.c:677
error_t sshEncryptPacket(SshConnection *connection, uint8_t *packet, size_t *length)
Encrypt an outgoing SSH packet.
Definition: ssh_packet.c:467
SSH extension negotiation.
@ SSH_MSG_REQUEST_SUCCESS
Definition: ssh.h:972
@ SSH_MSG_IGNORE
Definition: ssh.h:936
void poly1305Final(Poly1305Context *context, uint8_t *tag)
Finalize Poly1305 message-authentication code computation.
Definition: poly1305.c:127
@ SSH_MSG_KEX_MAX
Definition: ssh.h:946
error_t sshReceivePacket(SshConnection *connection)
Receive SSH packet.
Definition: ssh_packet.c:178
@ SSH_MSG_SERVICE_ACCEPT
Definition: ssh.h:940
SSH packet encryption/decryption.
HmacContext * hmacContext
HMAC context.
Definition: ssh.h:1321
error_t sshParseChannelData(SshConnection *connection, const uint8_t *message, size_t length)
Parse SSH_MSG_CHANNEL_DATA message.
@ SSH_MSG_UNIMPLEMENTED
Definition: ssh.h:937
@ CIPHER_MODE_CHACHA20_POLY1305
Definition: crypto.h:972
void poly1305Update(Poly1305Context *context, const void *data, size_t length)
Update Poly1305 message-authentication code computation.
Definition: poly1305.c:89
uint16_t payloadLen
Definition: ipv6.h:281
error_t sshParseMessage(SshConnection *connection, const uint8_t *message, size_t length)
Parse SSH message.
Definition: ssh_packet.c:1129
@ SSH_MSG_USERAUTH_MAX
Definition: ssh.h:966
error_t sshParsePacketLength(SshConnection *connection, uint8_t *packet)
Retrieve the length of an incoming SSH packet.
Definition: ssh_packet.c:913
#define PRIuSIZE
unsigned int uint_t
Definition: compiler_port.h:50
@ SSH_MSG_EXT_INFO
Definition: ssh.h:941
#define osMemset(p, value, length)
Definition: os_port.h:135
@ SSH_MSG_USERAUTH_MIN
Definition: ssh.h:965
__weak_func error_t hmacInit(HmacContext *context, const HashAlgo *hash, const void *key, size_t keyLen)
Initialize HMAC calculation.
Definition: hmac.c:140
Secure Shell (SSH)
error_t sshParseKexMessage(SshConnection *connection, uint8_t type, const uint8_t *message, size_t length)
Parse key exchange method-specific messages.
Definition: ssh_kex.c:1095
__weak_func error_t gcmDecrypt(GcmContext *context, const uint8_t *iv, size_t ivLen, const uint8_t *a, size_t aLen, const uint8_t *c, uint8_t *p, size_t length, const uint8_t *t, size_t tLen)
Authenticated decryption using GCM.
Definition: gcm.c:361
@ SOCKET_FLAG_BREAK_CRLF
Definition: socket.h:141
#define SSH_BUFFER_SIZE
Definition: ssh.h:866
#define STORE32BE(a, p)
Definition: cpu_endian.h:286
Global request and channel request handling.
__weak_func error_t gcmEncrypt(GcmContext *context, const uint8_t *iv, size_t ivLen, const uint8_t *a, size_t aLen, const uint8_t *p, uint8_t *c, size_t length, uint8_t *t, size_t tLen)
Authenticated encryption using GCM.
Definition: gcm.c:214
uint8_t nonce[]
Definition: ntp_common.h:233
@ ERROR_INVALID_KEY
Definition: error.h:106
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
@ SSH_MSG_KEX_MIN
Definition: ssh.h:945
#define TRACE_VERBOSE(...)
Definition: debug.h:124
@ SSH_MSG_CHANNEL_EXTENDED_DATA
Definition: ssh.h:979
#define TRACE_VERBOSE_ARRAY(p, a, n)
Definition: debug.h:125
@ SSH_MSG_KEXINIT
Definition: ssh.h:943